Add to git. master
authorRichard W.M. Jones <rjones@redhat.com>
Fri, 25 Apr 2014 10:39:16 +0000 (11:39 +0100)
committerRichard W.M. Jones <rjones@redhat.com>
Fri, 25 Apr 2014 10:39:16 +0000 (11:39 +0100)
72 files changed:
.cvsignore [new file with mode: 0644]
AUTHORS [new file with mode: 0644]
Build [new file with mode: 0755]
Build.local [new file with mode: 0755]
COPYING [new file with mode: 0644]
Changelog [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Makefile+ [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
Makefile.in [new file with mode: 0644]
README [new file with mode: 0644]
acconfig.h [new file with mode: 0644]
aclocal.m4 [new file with mode: 0644]
archproc.fig [new file with mode: 0644]
archproc.gif [new file with mode: 0644]
archref.html [new file with mode: 0644]
cell.c [new file with mode: 0644]
cell.h [new file with mode: 0644]
client.conf [new file with mode: 0644]
config.cache [new file with mode: 0644]
config.h.in [new file with mode: 0644]
config.log [new file with mode: 0644]
configure [new file with mode: 0755]
configure.in [new file with mode: 0644]
crc.c [new file with mode: 0644]
crc.h [new file with mode: 0644]
debian/changelog [new file with mode: 0644]
debian/conffiles [new file with mode: 0644]
debian/control [new file with mode: 0644]
debian/copyright [new file with mode: 0644]
debian/cron.d [new file with mode: 0644]
debian/dirs [new file with mode: 0644]
debian/docs [new file with mode: 0644]
debian/files [new file with mode: 0644]
debian/init.d [new file with mode: 0644]
debian/postinst.debhelper [new file with mode: 0644]
debian/postrm.debhelper [new file with mode: 0644]
debian/prerm.debhelper [new file with mode: 0644]
debian/rules [new file with mode: 0755]
debian/substvars [new file with mode: 0644]
dlife.rc [new file with mode: 0644]
dlife.spec.in [new file with mode: 0644]
dlife_asm.pl [new file with mode: 0644]
dlife_client.cron [new file with mode: 0644]
dlife_client.pl.in [new file with mode: 0644]
dlife_disasm.pl [new file with mode: 0755]
dlife_server.pl.in [new file with mode: 0644]
dlink.h [new file with mode: 0644]
exec.c [new file with mode: 0644]
god.dla [new file with mode: 0644]
god.dlo [new file with mode: 0644]
image.c [new file with mode: 0644]
image.h [new file with mode: 0644]
index.html.in [new file with mode: 0644]
install-sh [new symlink]
load.c [new file with mode: 0644]
load.h [new file with mode: 0644]
machineref.html [new file with mode: 0644]
main.c [new file with mode: 0644]
missing [new symlink]
mkinstalldirs [new symlink]
params.h [new file with mode: 0644]
random.c [new file with mode: 0644]
random.h [new file with mode: 0644]
servers.txt [new file with mode: 0644]
soup.c [new file with mode: 0644]
soup.conf [new file with mode: 0644]
soup.h [new file with mode: 0644]
stamp-h.in [new file with mode: 0644]
state.c [new file with mode: 0644]
state.h [new file with mode: 0644]
types.h [new file with mode: 0644]

diff --git a/.cvsignore b/.cvsignore
new file mode 100644 (file)
index 0000000..d43da9b
--- /dev/null
@@ -0,0 +1,22 @@
+Makefile.in
+acinclude.m4
+aclocal.m4
+config.h.in
+configure
+dlife.spec
+dlife-*.tar.gz
+index.html
+dlife_client.pl
+dlife_server.pl
+install-sh
+missing
+mkinstalldirs
+stamp-h.in
+config.cache
+config.h
+config.log
+config.status
+dlife_soup
+stamp-h
+Makefile
+.deps
diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..a576e60
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,5 @@
+Richard Jones <rich@annexia.org>
+       * Main author and maintainer.
+
+Falk Hueffner <falk.hueffner@student.uni-tuebingen.de>
+       * Contributed Debian package.
diff --git a/Build b/Build
new file mode 100755 (executable)
index 0000000..36526ba
--- /dev/null
+++ b/Build
@@ -0,0 +1,57 @@
+#!/bin/sh -
+# DLIFE (C) 2000 Richard W.M. Jones <rich@annexia.org>
+# and other authors listed in the ``AUTHORS'' file.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+# $Id: Build,v 1.1 2002/04/05 17:02:25 rich Exp $
+
+# This is a highly specialized build script for my machine. You will
+# probably need to change this substantially to be appropriate for
+# your environment.
+#
+# Please note also that you normally only ever run this script if you
+# have changed something about the build process itself -- for example
+# if you have changed ``configure.in'' or one of the ``Makefile.am''
+# files. If you just want to do a normal rebuild after changing a
+# source file, all you need to do is:
+#
+# make && make install
+#
+#   - RWMJ 1999/12/27.
+
+set -e
+set -v
+
+: Make clean
+make distclean ||:
+
+: Rebuilding autoconf/automake files
+aclocal
+autoheader
+automake
+autoconf
+
+mkdir -p $HOME/.build/{usr/share/doc,etc/cron.d,etc/init.d,var} ||:
+
+: Configure.
+CFLAGS="-O" \
+./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var \
+    --disable-user-check
+
+: Build.
+make
+
+: Now run 'make install' as root.
diff --git a/Build.local b/Build.local
new file mode 100755 (executable)
index 0000000..98f2fa5
--- /dev/null
@@ -0,0 +1,62 @@
+#!/bin/sh -
+# DLIFE (C) 2000 Richard W.M. Jones <rich@annexia.org>
+# and other authors listed in the ``AUTHORS'' file.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+# $Id: Build.local,v 1.2 2002/04/05 17:02:25 rich Exp $
+
+# This is a highly specialized build script for my machine. You will
+# probably need to change this substantially to be appropriate for
+# your environment.
+#
+# Please note also that you normally only ever run this script if you
+# have changed something about the build process itself -- for example
+# if you have changed ``configure.in'' or one of the ``Makefile.am''
+# files. If you just want to do a normal rebuild after changing a
+# source file, all you need to do is:
+#
+# make && make install
+#
+#   - RWMJ 1999/12/27.
+
+set -e
+set -v
+
+: Make clean
+make distclean ||:
+
+: Rebuilding autoconf/automake files
+aclocal
+autoheader
+automake
+autoconf
+
+mkdir -p $HOME/.build/{usr/share/doc,etc/cron.d,etc/init.d,var} ||:
+
+: Configure.
+CFLAGS="-O" \
+./configure \
+    --prefix=$HOME/.build/usr \
+    --sysconfdir=$HOME/.build/etc \
+    --localstatedir=$HOME/.build/var
+
+: Build.
+make
+
+: Install in local build directory
+make NO_CHOWN=1 install
+
+: Now run it with: $HOME/.build/usr/bin/dlife_soup
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..eeb586b
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    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
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Changelog b/Changelog
new file mode 100644 (file)
index 0000000..77f7547
--- /dev/null
+++ b/Changelog
@@ -0,0 +1,9 @@
+2002-12-10  Nix  <nix@esperi.demon.co.uk>
+
+       * main.c (main): Use LOG_DAEMON, not LOG_USER.
+       * main.c (detect_nr_cpus): New for SPARC/Linux.
+
+       * cell.c (run_thread): Use syslog(), not printf().
+       * cell.c (cell_state_load): Likewise.
+       * cell.c (_cell_fixup_soup_ref): Likewise.
+       * cell.c (save_cell_in_outgoing): Likewise.
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..a8b6661
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,106 @@
+Distributed Artificial Life (DLIFE) Installation Instructions
+-------------------------------------------------------------
+
+Prerequisites
+-------------
+
+For security reasons, all programs run as user/group dlife/dlife. Therefore
+in order to be able to install this program, you must first create a user
+and group called `dlife'. On a typical Linux system you will need to
+do this, as root, before installing:
+
+       /usr/sbin/groupadd dlife
+       /usr/sbin/useradd -g dlife -M dlife
+
+You will need the following Perl packages installed. Get them from
+CPAN (http://www.cpan.org/) or one of its mirrors, or else get RPMs
+from http://dlife.annexia.org/files/ .
+
+       libnet, HTML-Parser, URI, MIME-Base64, Digest-MD5, libwww-perl,
+       Getopt-Long
+
+Warning to non-Red Hat users
+----------------------------
+
+The current installation is very Red Hat / Debian specific. It
+installs files under /etc/cron.d/ and /etc/init.d/ directories, which
+probably only exist on Red Hat or Debian machines. It would be nice to
+have a way to determine where these directories are and to
+automagically install cron jobs and rc files in the appropriate
+places. Can anyone help me with this?
+
+Building and installing the client from source
+----------------------------------------------
+
+Configure the software:
+
+       ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var
+
+Check that the software is going to be installed in the right
+places. On my Red Hat Linux boxen, I get:
+
+       checking for crontab directory... /etc/cron.d
+       checking for rc directory... /etc/init.d
+       checking spool directory... /var/spool/dlife
+       checking config directory... /etc/dlife
+
+Build it:
+
+       make
+
+Install it (as root):
+
+       make install
+
+To start up the software, run the following command as root:
+
+       /etc/init.d/dlife.rc
+
+If all went well, then you should see one of more ``dlife_soup''
+processes running in top. (There should be one process for each
+CPU on your machine).
+
+To make the dlife client start up every time you reboot the
+computer, do as root:
+
+       /sbin/chkconfig --add dlife.rc
+
+A cron job is set to run every hour which exchanges cells with
+your local dlife server. By default it runs at 5 minutes past
+the hour, but to avoid causing load spikes on dlife servers at
+this time, it's best to edit the cron script and change the
+time at which it runs. This script is here:
+
+       /etc/cron.d/dlife_client.cron
+
+If you're running behind a firewall, then you may want to run a
+server (see next section). In that case, you need to edit the
+following file to list the location of your server(s):
+
+       /etc/dlife/client.conf
+
+Building and installing the server from source
+----------------------------------------------
+
+Follow the process above, as if you were installing the client.
+
+Edit /etc/inetd.conf and add the following line:
+
+       5904 stream tcp nowait root /usr/sbin/tcpd /usr/bin/dlife_server.pl
+
+Restart inetd:
+
+       killall -HUP inetd
+
+Building RPMs
+-------------
+
+To build RPMs from the sources:
+
+       ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var \
+               --disable-user-check
+       make
+       make dist
+       rpm -ta --clean dlife-X.Y.Z.tar.gz
+
+(where X.Y.Z is the current version of dlife).
diff --git a/Makefile+ b/Makefile+
new file mode 100644 (file)
index 0000000..25e364b
--- /dev/null
+++ b/Makefile+
@@ -0,0 +1,108 @@
+# -*- Makefile -*-
+#
+# This is a make+ file. Make+ is a set of scripts which enhance GNU
+# make and let you build RPMs, and other package types with just one
+# control file.  To build this package you will need to download make+
+# from this site: http://www.annexia.org/freeware/makeplus/
+
+PACKAGE                := dlife
+VERSION_MAJOR  := 1
+VERSION_MINOR  := 1.0
+VERSION                := $(VERSION_MAJOR).$(VERSION_MINOR)
+
+SUMMARY                := Distributed artificial life
+COPYRIGHT      := GPL
+AUTHOR         := Richard W.M. Jones <rich@annexia.org>
+
+define DESCRIPTION
+Distributed Artificial Life is a package for joining your
+computer to a network of computers running a large artificial
+life simulation.
+endef
+
+RPM_REQUIRES   := perl-libwww-perl, perl >= 5.004, vixie-cron, SysVinit
+RPM_GROUP      := Applications/Internet
+
+spooldir = $(localstatedir)/spool/dlife
+confdir        = $(sysconfdir)/dlife
+crondir        = $(sysconfdir)/cron.d
+rcdir  = $(sysconfdir)/init.d
+
+CFLAGS         += -Wall -Werror -g -O2 \
+                  -DCONFDIR=\"$(confdir)\" \
+                  -DSPOOLDIR=\"$(spooldir)\"
+#LIBS          +=
+
+ifdef ENABLE_CHECK
+CFLAGS         += -DCHECK=1
+endif
+
+ifdef ENABLE_PROFILE
+CFLAGS         += -pg
+endif
+
+DOCS   := $(srcdir)/AUTHORS $(srcdir)/INSTALL $(srcdir)/README \
+          $(srcdir)/archproc.gif $(srcdir)/archproc.fig \
+          $(srcdir)/archref.html $(srcdir)/index.html \
+          $(srcdir)/machineref.html
+
+OBJS   := cell.o crc.o exec.o image.o load.o main.o random.o soup.o state.o
+
+all:   build
+
+configure:
+       $(MP_CONFIGURE_START)
+       $(MP_CHECK_HEADERS) assert.h dirent.h errno.h fcntl.h grp.h pwd.h \
+         signal.h stddef.h stdint.h string.h sys/param.h sys/types.h \
+         syslog.h time.h unistd.h
+       $(MP_CHECK_FUNCS) closedir getpwnam getuid initgroups nice opendir \
+         openlog readdir setgid setuid syslog
+ifndef DISABLE_USER_CHECK
+#      $(MP_CHECK_USER_GROUP) dlife dlife
+endif
+       $(MP_CONFIGURE_END)
+
+build: dlife_soup
+
+dlife_soup: $(OBJS)
+       $(CC) $(CFLAGS) $^ $(LIBS) -o $@
+
+test:
+
+install:
+       install -d $(DESTDIR)$(bindir)
+       install -d $(DESTDIR)$(docdir)
+       install -d $(DESTDIR)$(spooldir)
+       install -d $(DESTDIR)$(spooldir)/incoming
+       install -d $(DESTDIR)$(spooldir)/outgoing
+       install -d $(DESTDIR)$(spooldir)/saved
+       install -d $(DESTDIR)$(spooldir)/store
+       install -d $(DESTDIR)$(confdir)
+       install -d $(DESTDIR)$(crondir)
+       install -d $(DESTDIR)$(rcdir)
+
+       install -m 0755 dlife_soup $(srcdir)/dlife_client.pl \
+         $(srcdir)/dlife_server.pl $(DESTDIR)$(bindir)
+       install -m 0644 $(DOCS) $(DESTDIR)$(docdir)
+       install -m 0644 god.dlo $(DESTDIR)$(spooldir)
+       install -m 0644 $(srcdir)/client.conf $(srcdir)/soup.conf \
+         $(DESTDIR)$(confdir)
+       install -m 0644 $(srcdir)/dlife_client.cron $(DESTDIR)$(crondir)
+       install -m 0644 $(srcdir)/dlife.rc $(DESTDIR)$(rcdir)
+
+       chown -R dlife.dlife $(DESTDIR)$(spooldir) ||:
+
+define WEBSITE
+<html>
+XXX PUT YOUR WEBSITE HERE. IF YOU DON\'T WANT TO MANAGE A WEBSITE WITH
+XXX MAKE+ THEN JUST DELETE THIS SECTION AND THE upload_website RULE.
+</html>
+endef
+
+upload_website:
+       scp $(PACKAGE)-$(VERSION).tar.gz $(PACKAGE)-$(VERSION)-1.*.rpm \
+       $(PACKAGE)-$(VERSION).bin.tar.gz \
+       you@yourmachine.example.com:/var/www/html/$(PACKAGE)/files
+       scp index.html you@yourmachine.example.com:/var/www/html/$(PACKAGE)/
+
+.PHONY:        build configure test upload_website
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..a30745f
--- /dev/null
@@ -0,0 +1,117 @@
+# DLIFE (C) 2000 Richard W.M. Jones <rich@annexia.org>
+# and other authors listed in the ``AUTHORS'' file.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+# $Id: Makefile.am,v 1.3 2002/04/05 17:20:11 rich Exp $
+
+AUTOMAKE_OPTIONS = foreign
+
+EXTRA_DIST     = .cvsignore \
+                 Build \
+                 Build.local \
+                 dlife_asm.pl \
+                 dlife_client.pl.in \
+                 dlife_disasm.pl \
+                 dlife_server.pl.in \
+                 dlife.spec \
+                 dlife.spec.in \
+                 god.dla \
+                 index.html.in \
+                 servers.txt \
+                 debian/changelog \
+                 debian/conffiles \
+                 debian/control \
+                 debian/copyright \
+                 debian/cron.d \
+                 debian/dirs \
+                 debian/docs \
+                 debian/files \
+                 debian/init.d \
+                 debian/postinst.debhelper \
+                 debian/postrm.debhelper \
+                 debian/prerm.debhelper \
+                 debian/rules \
+                 debian/substvars \
+                 $(bin_SCRIPTS) \
+                 $(conf_DATA) \
+                 $(cron_DATA) \
+                 $(doc_DATA) \
+                 $(rc_SCRIPTS) \
+                 $(spool_DATA)
+
+docdir         = @DOCDIR@
+doc_DATA       = AUTHORS \
+                 INSTALL \
+                 README \
+                 archproc.gif \
+                 archproc.fig \
+                 archref.html \
+                 index.html \
+                 machineref.html
+
+spooldir       = @SPOOLDIR@
+spool_DATA     = god.dlo
+
+confdir                = @CONFDIR@
+conf_DATA      = client.conf soup.conf
+
+if INSTALL_CRON
+crondir                = @CRONDIR@
+else
+crondir                = /tmp
+endif
+cron_DATA      = dlife_client.cron
+
+if INSTALL_RC
+rcdir          = @RCDIR@
+else
+rcdir          = /tmp
+endif
+rc_SCRIPTS     = dlife.rc
+
+bin_PROGRAMS   = dlife_soup
+
+bin_SCRIPTS    = dlife_client.pl dlife_server.pl
+
+dlife_soup_SOURCES = \
+               cell.c \
+               cell.h \
+               crc.c \
+               crc.h \
+               dlink.h \
+               exec.c \
+               image.c \
+               image.h \
+               load.c \
+               load.h \
+               main.c \
+               params.h \
+               random.c \
+               random.h \
+               soup.c \
+               soup.h \
+               state.c \
+               state.h \
+               types.h
+
+install-data-hook:
+               $(mkinstalldirs) $(DESTDIR)$(spooldir)/incoming
+               $(mkinstalldirs) $(DESTDIR)$(spooldir)/outgoing
+               $(mkinstalldirs) $(DESTDIR)$(spooldir)/saved
+               $(mkinstalldirs) $(DESTDIR)$(spooldir)/store
+  ifndef NO_CHOWN
+               chown -R dlife.dlife $(DESTDIR)$(spooldir)
+  endif
diff --git a/Makefile.in b/Makefile.in
new file mode 100644 (file)
index 0000000..7bef584
--- /dev/null
@@ -0,0 +1,590 @@
+# Makefile.in generated automatically by automake 1.4-p6 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+# DLIFE (C) 2000 Richard W.M. Jones <rich@annexia.org>
+# and other authors listed in the ``AUTHORS'' file.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+# $Id: Makefile.am,v 1.3 2002/04/05 17:20:11 rich Exp $
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = .
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+CC = @CC@
+CONFDIR = @CONFDIR@
+CRONDIR = @CRONDIR@
+DOCDIR = @DOCDIR@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+RCDIR = @RCDIR@
+RELEASEDATE = @RELEASEDATE@
+SPOOLDIR = @SPOOLDIR@
+VERSION = @VERSION@
+
+AUTOMAKE_OPTIONS = foreign
+
+EXTRA_DIST = .cvsignore                  Build                   Build.local             dlife_asm.pl            dlife_client.pl.in              dlife_disasm.pl                 dlife_server.pl.in              dlife.spec              dlife.spec.in                   god.dla                 index.html.in                   servers.txt             debian/changelog                debian/conffiles                debian/control                  debian/copyright                debian/cron.d                   debian/dirs             debian/docs             debian/files            debian/init.d                   debian/postinst.debhelper               debian/postrm.debhelper                 debian/prerm.debhelper                  debian/rules            debian/substvars                $(bin_SCRIPTS)                  $(conf_DATA)            $(cron_DATA)            $(doc_DATA)             $(rc_SCRIPTS)                   $(spool_DATA)
+
+
+docdir = @DOCDIR@
+doc_DATA = AUTHORS               INSTALL                 README                  archproc.gif            archproc.fig            archref.html            index.html              machineref.html
+
+
+spooldir = @SPOOLDIR@
+spool_DATA = god.dlo
+
+confdir = @CONFDIR@
+conf_DATA = client.conf soup.conf
+@INSTALL_CRON_TRUE@crondir = @CRONDIR@
+@INSTALL_CRON_FALSE@crondir = /tmp
+cron_DATA = dlife_client.cron
+@INSTALL_RC_TRUE@rcdir = @RCDIR@
+@INSTALL_RC_FALSE@rcdir = /tmp
+rc_SCRIPTS = dlife.rc
+
+bin_PROGRAMS = dlife_soup
+
+bin_SCRIPTS = dlife_client.pl dlife_server.pl
+
+dlife_soup_SOURCES =           cell.c          cell.h          crc.c           crc.h           dlink.h                 exec.c          image.c                 image.h                 load.c          load.h          main.c          params.h                random.c                random.h                soup.c          soup.h          state.c                 state.h                 types.h
+
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES =  dlife_client.pl dlife_server.pl dlife.spec \
+index.html
+PROGRAMS =  $(bin_PROGRAMS)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I.
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+dlife_soup_OBJECTS =  cell.o crc.o exec.o image.o load.o main.o random.o \
+soup.o state.o
+dlife_soup_LDADD = $(LDADD)
+dlife_soup_DEPENDENCIES = 
+dlife_soup_LDFLAGS = 
+SCRIPTS =  $(bin_SCRIPTS) $(rc_SCRIPTS)
+
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+DATA =  $(conf_DATA) $(cron_DATA) $(doc_DATA) $(spool_DATA)
+
+DIST_COMMON =  README ./stamp-h.in AUTHORS COPYING INSTALL Makefile.am \
+Makefile.in acconfig.h aclocal.m4 config.h.in configure configure.in \
+dlife.spec.in dlife_client.pl.in dlife_server.pl.in index.html.in \
+install-sh missing mkinstalldirs
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP_ENV = --best
+DEP_FILES =  .deps/cell.P .deps/crc.P .deps/exec.P .deps/image.P \
+.deps/load.P .deps/main.P .deps/random.P .deps/soup.P .deps/state.P
+SOURCES = $(dlife_soup_SOURCES)
+OBJECTS = $(dlife_soup_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+       cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status $(BUILT_SOURCES)
+       cd $(top_builddir) \
+         && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+$(ACLOCAL_M4):  configure.in 
+       cd $(srcdir) && $(ACLOCAL)
+
+config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       $(SHELL) ./config.status --recheck
+$(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES)
+       cd $(srcdir) && $(AUTOCONF)
+
+config.h: stamp-h
+       @if test ! -f $@; then \
+               rm -f stamp-h; \
+               $(MAKE) stamp-h; \
+       else :; fi
+stamp-h: $(srcdir)/config.h.in $(top_builddir)/config.status
+       cd $(top_builddir) \
+         && CONFIG_FILES= CONFIG_HEADERS=config.h \
+            $(SHELL) ./config.status
+       @echo timestamp > stamp-h 2> /dev/null
+$(srcdir)/config.h.in: $(srcdir)/stamp-h.in
+       @if test ! -f $@; then \
+               rm -f $(srcdir)/stamp-h.in; \
+               $(MAKE) $(srcdir)/stamp-h.in; \
+       else :; fi
+$(srcdir)/stamp-h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4) acconfig.h
+       cd $(top_srcdir) && $(AUTOHEADER)
+       @echo timestamp > $(srcdir)/stamp-h.in 2> /dev/null
+
+mostlyclean-hdr:
+
+clean-hdr:
+
+distclean-hdr:
+       -rm -f config.h
+
+maintainer-clean-hdr:
+dlife_client.pl: $(top_builddir)/config.status dlife_client.pl.in
+       cd $(top_builddir) && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
+dlife_server.pl: $(top_builddir)/config.status dlife_server.pl.in
+       cd $(top_builddir) && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
+dlife.spec: $(top_builddir)/config.status dlife.spec.in
+       cd $(top_builddir) && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
+index.html: $(top_builddir)/config.status index.html.in
+       cd $(top_builddir) && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+mostlyclean-binPROGRAMS:
+
+clean-binPROGRAMS:
+       -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+
+distclean-binPROGRAMS:
+
+maintainer-clean-binPROGRAMS:
+
+install-binPROGRAMS: $(bin_PROGRAMS)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(bindir)
+       @list='$(bin_PROGRAMS)'; for p in $$list; do \
+         if test -f $$p; then \
+           echo "  $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \
+            $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+         else :; fi; \
+       done
+
+uninstall-binPROGRAMS:
+       @$(NORMAL_UNINSTALL)
+       list='$(bin_PROGRAMS)'; for p in $$list; do \
+         rm -f $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+       done
+
+.s.o:
+       $(COMPILE) -c $<
+
+.S.o:
+       $(COMPILE) -c $<
+
+mostlyclean-compile:
+       -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+       -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+dlife_soup: $(dlife_soup_OBJECTS) $(dlife_soup_DEPENDENCIES)
+       @rm -f dlife_soup
+       $(LINK) $(dlife_soup_LDFLAGS) $(dlife_soup_OBJECTS) $(dlife_soup_LDADD) $(LIBS)
+
+install-binSCRIPTS: $(bin_SCRIPTS)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(bindir)
+       @list='$(bin_SCRIPTS)'; for p in $$list; do \
+         if test -f $$p; then \
+           echo " $(INSTALL_SCRIPT) $$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`"; \
+           $(INSTALL_SCRIPT) $$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \
+         else if test -f $(srcdir)/$$p; then \
+           echo " $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`"; \
+           $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \
+         else :; fi; fi; \
+       done
+
+uninstall-binSCRIPTS:
+       @$(NORMAL_UNINSTALL)
+       list='$(bin_SCRIPTS)'; for p in $$list; do \
+         rm -f $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \
+       done
+
+install-rcSCRIPTS: $(rc_SCRIPTS)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(rcdir)
+       @list='$(rc_SCRIPTS)'; for p in $$list; do \
+         if test -f $$p; then \
+           echo " $(INSTALL_SCRIPT) $$p $(DESTDIR)$(rcdir)/`echo $$p|sed '$(transform)'`"; \
+           $(INSTALL_SCRIPT) $$p $(DESTDIR)$(rcdir)/`echo $$p|sed '$(transform)'`; \
+         else if test -f $(srcdir)/$$p; then \
+           echo " $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(rcdir)/`echo $$p|sed '$(transform)'`"; \
+           $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(rcdir)/`echo $$p|sed '$(transform)'`; \
+         else :; fi; fi; \
+       done
+
+uninstall-rcSCRIPTS:
+       @$(NORMAL_UNINSTALL)
+       list='$(rc_SCRIPTS)'; for p in $$list; do \
+         rm -f $(DESTDIR)$(rcdir)/`echo $$p|sed '$(transform)'`; \
+       done
+
+install-confDATA: $(conf_DATA)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(confdir)
+       @list='$(conf_DATA)'; for p in $$list; do \
+         if test -f $(srcdir)/$$p; then \
+           echo " $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(confdir)/$$p"; \
+           $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(confdir)/$$p; \
+         else if test -f $$p; then \
+           echo " $(INSTALL_DATA) $$p $(DESTDIR)$(confdir)/$$p"; \
+           $(INSTALL_DATA) $$p $(DESTDIR)$(confdir)/$$p; \
+         fi; fi; \
+       done
+
+uninstall-confDATA:
+       @$(NORMAL_UNINSTALL)
+       list='$(conf_DATA)'; for p in $$list; do \
+         rm -f $(DESTDIR)$(confdir)/$$p; \
+       done
+
+install-cronDATA: $(cron_DATA)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(crondir)
+       @list='$(cron_DATA)'; for p in $$list; do \
+         if test -f $(srcdir)/$$p; then \
+           echo " $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(crondir)/$$p"; \
+           $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(crondir)/$$p; \
+         else if test -f $$p; then \
+           echo " $(INSTALL_DATA) $$p $(DESTDIR)$(crondir)/$$p"; \
+           $(INSTALL_DATA) $$p $(DESTDIR)$(crondir)/$$p; \
+         fi; fi; \
+       done
+
+uninstall-cronDATA:
+       @$(NORMAL_UNINSTALL)
+       list='$(cron_DATA)'; for p in $$list; do \
+         rm -f $(DESTDIR)$(crondir)/$$p; \
+       done
+
+install-docDATA: $(doc_DATA)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(docdir)
+       @list='$(doc_DATA)'; for p in $$list; do \
+         if test -f $(srcdir)/$$p; then \
+           echo " $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(docdir)/$$p"; \
+           $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(docdir)/$$p; \
+         else if test -f $$p; then \
+           echo " $(INSTALL_DATA) $$p $(DESTDIR)$(docdir)/$$p"; \
+           $(INSTALL_DATA) $$p $(DESTDIR)$(docdir)/$$p; \
+         fi; fi; \
+       done
+
+uninstall-docDATA:
+       @$(NORMAL_UNINSTALL)
+       list='$(doc_DATA)'; for p in $$list; do \
+         rm -f $(DESTDIR)$(docdir)/$$p; \
+       done
+
+install-spoolDATA: $(spool_DATA)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(spooldir)
+       @list='$(spool_DATA)'; for p in $$list; do \
+         if test -f $(srcdir)/$$p; then \
+           echo " $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(spooldir)/$$p"; \
+           $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(spooldir)/$$p; \
+         else if test -f $$p; then \
+           echo " $(INSTALL_DATA) $$p $(DESTDIR)$(spooldir)/$$p"; \
+           $(INSTALL_DATA) $$p $(DESTDIR)$(spooldir)/$$p; \
+         fi; fi; \
+       done
+
+uninstall-spoolDATA:
+       @$(NORMAL_UNINSTALL)
+       list='$(spool_DATA)'; for p in $$list; do \
+         rm -f $(DESTDIR)$(spooldir)/$$p; \
+       done
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+       list='$(SOURCES) $(HEADERS)'; \
+       unique=`for i in $$list; do echo $$i; done | \
+         awk '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       here=`pwd` && cd $(srcdir) \
+         && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) $(LISP)
+       tags=; \
+       here=`pwd`; \
+       list='$(SOURCES) $(HEADERS)'; \
+       unique=`for i in $$list; do echo $$i; done | \
+         awk '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       test -z "$(ETAGS_ARGS)config.h.in$$unique$(LISP)$$tags" \
+         || (cd $(srcdir) && etags -o $$here/TAGS $(ETAGS_ARGS) $$tags config.h.in $$unique $(LISP))
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+       -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+
+# This target untars the dist file and tries a VPATH configuration.  Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+       -rm -rf $(distdir)
+       GZIP=$(GZIP_ENV) $(TAR) zxf $(distdir).tar.gz
+       mkdir $(distdir)/=build
+       mkdir $(distdir)/=inst
+       dc_install_base=`cd $(distdir)/=inst && pwd`; \
+       cd $(distdir)/=build \
+         && ../configure --srcdir=.. --prefix=$$dc_install_base \
+         && $(MAKE) $(AM_MAKEFLAGS) \
+         && $(MAKE) $(AM_MAKEFLAGS) dvi \
+         && $(MAKE) $(AM_MAKEFLAGS) check \
+         && $(MAKE) $(AM_MAKEFLAGS) install \
+         && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+         && $(MAKE) $(AM_MAKEFLAGS) dist
+       -rm -rf $(distdir)
+       @banner="$(distdir).tar.gz is ready for distribution"; \
+       dashes=`echo "$$banner" | sed s/./=/g`; \
+       echo "$$dashes"; \
+       echo "$$banner"; \
+       echo "$$dashes"
+dist: distdir
+       -chmod -R a+r $(distdir)
+       GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
+       -rm -rf $(distdir)
+dist-all: distdir
+       -chmod -R a+r $(distdir)
+       GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
+       -rm -rf $(distdir)
+distdir: $(DISTFILES)
+       -rm -rf $(distdir)
+       mkdir $(distdir)
+       -chmod 777 $(distdir)
+       here=`cd $(top_builddir) && pwd`; \
+       top_distdir=`cd $(distdir) && pwd`; \
+       distdir=`cd $(distdir) && pwd`; \
+       cd $(top_srcdir) \
+         && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --foreign Makefile
+       $(mkinstalldirs) $(distdir)/debian
+       @for file in $(DISTFILES); do \
+         d=$(srcdir); \
+         if test -d $$d/$$file; then \
+           cp -pr $$d/$$file $(distdir)/$$file; \
+         else \
+           test -f $(distdir)/$$file \
+           || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+           || cp -p $$d/$$file $(distdir)/$$file || :; \
+         fi; \
+       done
+
+DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
+
+-include $(DEP_FILES)
+
+mostlyclean-depend:
+
+clean-depend:
+
+distclean-depend:
+       -rm -rf .deps
+
+maintainer-clean-depend:
+
+%.o: %.c
+       @echo '$(COMPILE) -c $<'; \
+       $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+       @-cp .deps/$(*F).pp .deps/$(*F).P; \
+       tr ' ' '\012' < .deps/$(*F).pp \
+         | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+           >> .deps/$(*F).P; \
+       rm .deps/$(*F).pp
+
+%.lo: %.c
+       @echo '$(LTCOMPILE) -c $<'; \
+       $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+       @-sed -e 's/^\([^:]*\)\.o[      ]*:/\1.lo \1.o :/' \
+         < .deps/$(*F).pp > .deps/$(*F).P; \
+       tr ' ' '\012' < .deps/$(*F).pp \
+         | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+           >> .deps/$(*F).P; \
+       rm -f .deps/$(*F).pp
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+all-recursive-am: config.h
+       $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+install-exec-am: install-binPROGRAMS install-binSCRIPTS
+install-exec: install-exec-am
+
+install-data-am: install-rcSCRIPTS install-confDATA install-cronDATA \
+               install-docDATA install-spoolDATA
+       @$(NORMAL_INSTALL)
+       $(MAKE) $(AM_MAKEFLAGS) install-data-hook
+install-data: install-data-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS \
+               uninstall-rcSCRIPTS uninstall-confDATA \
+               uninstall-cronDATA uninstall-docDATA \
+               uninstall-spoolDATA
+uninstall: uninstall-am
+all-am: Makefile $(PROGRAMS) $(SCRIPTS) $(DATA) config.h
+all-redirect: all-am
+install-strip:
+       $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+       $(mkinstalldirs)  $(DESTDIR)$(bindir) $(DESTDIR)$(bindir) \
+               $(DESTDIR)$(rcdir) $(DESTDIR)$(confdir) \
+               $(DESTDIR)$(crondir) $(DESTDIR)$(docdir) \
+               $(DESTDIR)$(spooldir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -rm -f Makefile $(CONFIG_CLEAN_FILES)
+       -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-hdr mostlyclean-binPROGRAMS \
+               mostlyclean-compile mostlyclean-tags mostlyclean-depend \
+               mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-hdr clean-binPROGRAMS clean-compile clean-tags \
+               clean-depend clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-hdr distclean-binPROGRAMS distclean-compile \
+               distclean-tags distclean-depend distclean-generic \
+               clean-am
+
+distclean: distclean-am
+       -rm -f config.status
+
+maintainer-clean-am:  maintainer-clean-hdr maintainer-clean-binPROGRAMS \
+               maintainer-clean-compile maintainer-clean-tags \
+               maintainer-clean-depend maintainer-clean-generic \
+               distclean-am
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+       -rm -f config.status
+
+.PHONY: mostlyclean-hdr distclean-hdr clean-hdr maintainer-clean-hdr \
+mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \
+maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile uninstall-binSCRIPTS install-binSCRIPTS \
+uninstall-rcSCRIPTS install-rcSCRIPTS uninstall-confDATA \
+install-confDATA uninstall-cronDATA install-cronDATA uninstall-docDATA \
+install-docDATA uninstall-spoolDATA install-spoolDATA tags \
+mostlyclean-tags distclean-tags clean-tags maintainer-clean-tags \
+distdir mostlyclean-depend distclean-depend clean-depend \
+maintainer-clean-depend info-am info dvi-am dvi check check-am \
+installcheck-am installcheck all-recursive-am install-exec-am \
+install-exec install-data-am install-data install-am install \
+uninstall-am uninstall all-redirect all-am all installdirs \
+mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+install-data-hook:
+               $(mkinstalldirs) $(DESTDIR)$(spooldir)/incoming
+               $(mkinstalldirs) $(DESTDIR)$(spooldir)/outgoing
+               $(mkinstalldirs) $(DESTDIR)$(spooldir)/saved
+               $(mkinstalldirs) $(DESTDIR)$(spooldir)/store
+  ifndef NO_CHOWN
+               chown -R dlife.dlife $(DESTDIR)$(spooldir)
+  endif
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..c43cf96
--- /dev/null
+++ b/README
@@ -0,0 +1,22 @@
+Distributed Artificial Life (DLIFE)
+-----------------------------------
+By Richard W.M. Jones <rich@annexia.org>
+
+What is DLIFE?
+--------------
+
+DLIFE is a distributed version of Tom S. Ray's Tierra artificial life
+program. Note that the machine language used is similar to but not
+compatible with Tierra. Tom Ray talks about his work (as far as I
+know, never completed) to create a ``Digital Reserve''. The DLIFE
+project is a development of this.
+
+In other words, it's an alternative to the tedious process of cracking
+RC5 keys or searching for aliens. You've got a supercomputer on your
+desk, let's go and create some life ...
+
+It consists of a highly optimized engine for running the artificial
+life cells in a virtual machine, written in C, and some Perl scripts
+which can upload and download cells from central ``cell-bank''
+servers.
+
diff --git a/acconfig.h b/acconfig.h
new file mode 100644 (file)
index 0000000..b0193eb
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef DLIFE_CONFIG_H
+#define DLIFE_CONFIG_H
+@TOP@
+
+/*
+ *   Defaults for configuration settings
+ */
+
+#undef PACKAGE
+#undef VERSION
+#undef SPOOLDIR
+#undef CONFDIR
+
+@BOTTOM@
+
+#endif /* DLIFE_CONFIG_H */
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644 (file)
index 0000000..2361d00
--- /dev/null
@@ -0,0 +1,170 @@
+dnl aclocal.m4 generated automatically by aclocal 1.4-p6
+
+dnl Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+dnl PARTICULAR PURPOSE.
+
+# Do all the work for Automake.  This macro actually does too much --
+# some checks are only needed if your package does certain things.
+# But this isn't really a big deal.
+
+# serial 1
+
+dnl Usage:
+dnl AM_INIT_AUTOMAKE(package,version, [no-define])
+
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])
+PACKAGE=[$1]
+AC_SUBST(PACKAGE)
+VERSION=[$2]
+AC_SUBST(VERSION)
+dnl test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
+  AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+fi
+ifelse([$3],,
+AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package]))
+AC_REQUIRE([AM_SANITY_CHECK])
+AC_REQUIRE([AC_ARG_PROGRAM])
+dnl FIXME This is truly gross.
+missing_dir=`cd $ac_aux_dir && pwd`
+AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}, $missing_dir)
+AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir)
+AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}, $missing_dir)
+AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir)
+AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir)
+AC_REQUIRE([AC_PROG_MAKE_SET])])
+
+# Copyright 2002  Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# 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
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+AC_DEFUN([AM_AUTOMAKE_VERSION],[am__api_version="1.4"])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION so it can be traced.
+# This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+        [AM_AUTOMAKE_VERSION([1.4-p6])])
+
+#
+# Check to make sure that the build environment is sane.
+#
+
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftestfile
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
+   if test "[$]*" = "X"; then
+      # -L didn't work.
+      set X `ls -t $srcdir/configure conftestfile`
+   fi
+   if test "[$]*" != "X $srcdir/configure conftestfile" \
+      && test "[$]*" != "X conftestfile $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      AC_MSG_ERROR([ls -t appears to fail.  Make sure there is not a broken
+alias in your environment])
+   fi
+
+   test "[$]2" = conftestfile
+   )
+then
+   # Ok.
+   :
+else
+   AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+rm -f conftest*
+AC_MSG_RESULT(yes)])
+
+dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY)
+dnl The program must properly implement --version.
+AC_DEFUN([AM_MISSING_PROG],
+[AC_MSG_CHECKING(for working $2)
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if ($2 --version) < /dev/null > /dev/null 2>&1; then
+   $1=$2
+   AC_MSG_RESULT(found)
+else
+   $1="$3/missing $2"
+   AC_MSG_RESULT(missing)
+fi
+AC_SUBST($1)])
+
+# Like AC_CONFIG_HEADER, but automatically create stamp file.
+
+AC_DEFUN([AM_CONFIG_HEADER],
+[AC_PREREQ([2.12])
+AC_CONFIG_HEADER([$1])
+dnl When config.status generates a header, we must update the stamp-h file.
+dnl This file resides in the same directory as the config header
+dnl that is generated.  We must strip everything past the first ":",
+dnl and everything past the last "/".
+AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl
+ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>,
+<<test -z "<<$>>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>,
+<<am_indx=1
+for am_file in <<$1>>; do
+  case " <<$>>CONFIG_HEADERS " in
+  *" <<$>>am_file "*<<)>>
+    echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx
+    ;;
+  esac
+  am_indx=`expr "<<$>>am_indx" + 1`
+done<<>>dnl>>)
+changequote([,]))])
+
+# Define a conditional.
+
+AC_DEFUN([AM_CONDITIONAL],
+[AC_SUBST($1_TRUE)
+AC_SUBST($1_FALSE)
+if $2; then
+  $1_TRUE=
+  $1_FALSE='#'
+else
+  $1_TRUE='#'
+  $1_FALSE=
+fi])
+
diff --git a/archproc.fig b/archproc.fig
new file mode 100644 (file)
index 0000000..eb6819a
--- /dev/null
@@ -0,0 +1,152 @@
+#FIG 3.2
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+6 2100 825 2775 2025
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+        2100 825 2775 825 2775 2025 2100 2025 2100 825
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+        2100 975 2550 975 2550 2025 2100 2025 2100 975
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+        2550 1200 2775 1200 2775 1275 2550 1275 2550 1200
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+        2550 1275 2775 1275 2775 1350 2550 1350 2550 1275
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+        2550 1350 2775 1350 2775 1425 2550 1425 2550 1350
+-6
+6 5850 825 6525 2025
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+        5850 825 6525 825 6525 2025 5850 2025 5850 825
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+        5850 975 6300 975 6300 2025 5850 2025 5850 975
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+        6300 1200 6525 1200 6525 1275 6300 1275 6300 1200
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+        6300 1275 6525 1275 6525 1350 6300 1350 6300 1275
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+        6300 1350 6525 1350 6525 1425 6300 1425 6300 1350
+-6
+6 675 5400 1650 6330
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+        808 5400 1517 5400 1517 6020 808 6020 808 5400
+2 4 0 1 0 7 50 0 -1 0.000 0 0 4 0 0 5
+        1473 5931 1473 5489 852 5489 852 5931 1473 5931
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+        808 6109 1517 6109 1650 6330 675 6330 808 6109
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+        853 6135 1337 6135 1428 6286 762 6286 853 6135
+-6
+6 1950 6450 2925 7380
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+        2083 6450 2792 6450 2792 7070 2083 7070 2083 6450
+2 4 0 1 0 7 50 0 -1 0.000 0 0 4 0 0 5
+        2748 6981 2748 6539 2127 6539 2127 6981 2748 6981
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+        2083 7159 2792 7159 2925 7380 1950 7380 2083 7159
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+        2128 7185 2612 7185 2703 7336 2037 7336 2128 7185
+-6
+6 3525 5775 4500 6705
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+        3658 5775 4367 5775 4367 6395 3658 6395 3658 5775
+2 4 0 1 0 7 50 0 -1 0.000 0 0 4 0 0 5
+        4323 6306 4323 5864 3702 5864 3702 6306 4323 6306
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+        3658 6484 4367 6484 4500 6705 3525 6705 3658 6484
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+        3703 6510 4187 6510 4278 6661 3612 6661 3703 6510
+-6
+6 3525 5175 4500 5456
+1 4 0 1 0 7 50 0 -1 0.000 1 0.0000 3666 5326 39 39 3633 5305 3698 5348
+1 4 0 1 0 7 50 0 -1 0.000 1 0.0000 3774 5326 39 39 3742 5305 3807 5348
+1 4 0 1 0 7 50 0 -1 0.000 1 0.0000 3882 5326 39 39 3850 5305 3915 5348
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+        3525 5175 4500 5175 4500 5456 3525 5456 3525 5175
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+        4110 5326 4153 5326 4153 5456 4110 5456 4110 5326
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+        4197 5326 4240 5326 4240 5456 4197 5456 4197 5326
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+        4283 5326 4327 5326 4327 5456 4283 5456 4283 5326
+-6
+6 5100 6075 6075 7005
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+        5233 6075 5942 6075 5942 6695 5233 6695 5233 6075
+2 4 0 1 0 7 50 0 -1 0.000 0 0 4 0 0 5
+        5898 6606 5898 6164 5277 6164 5277 6606 5898 6606
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+        5233 6784 5942 6784 6075 7005 5100 7005 5233 6784
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+        5278 6810 5762 6810 5853 6961 5187 6961 5278 6810
+-6
+6 900 4725 2100 5175
+4 0 0 50 0 0 12 0.0000 4 180 1170 900 4875 (runs from cron\001
+4 0 0 50 0 0 12 0.0000 4 180 870 900 5100 every hour)\001
+-6
+6 1875 5775 3075 6225
+4 0 0 50 0 0 12 0.0000 4 180 1170 1875 5925 (runs from cron\001
+4 0 0 50 0 0 12 0.0000 4 180 870 1875 6150 every hour)\001
+-6
+6 5025 5475 6225 5925
+4 0 0 50 0 0 12 0.0000 4 180 1170 5025 5625 (runs from cron\001
+4 0 0 50 0 0 12 0.0000 4 180 870 5025 5850 every hour)\001
+-6
+6 6825 4800 8025 5250
+4 0 0 50 0 0 12 0.0000 4 180 1170 6825 4950 (runs from cron\001
+4 0 0 50 0 0 12 0.0000 4 180 870 6825 5175 every hour)\001
+-6
+6 6975 5370 7950 6300
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+        7108 5370 7817 5370 7817 5990 7108 5990 7108 5370
+2 4 0 1 0 7 50 0 -1 0.000 0 0 4 0 0 5
+        7773 5901 7773 5459 7152 5459 7152 5901 7773 5901
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+        7108 6079 7817 6079 7950 6300 6975 6300 7108 6079
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+        7153 6105 7637 6105 7728 6256 7062 6256 7153 6105
+-6
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 1 2
+       0 0 1.00 60.00 120.00
+       0 0 1.00 60.00 120.00
+        2475 5325 2475 2550
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 1 2
+       0 0 1.00 60.00 120.00
+       0 0 1.00 60.00 120.00
+        3600 4200 2850 2475
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 1 2
+       0 0 1.00 60.00 120.00
+       0 0 1.00 60.00 120.00
+        4425 4125 5700 2475
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 1 2
+       0 0 1.00 60.00 120.00
+       0 0 1.00 60.00 120.00
+        5700 5100 6075 2550
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 1 2
+       0 0 1.00 60.00 120.00
+       0 0 1.00 60.00 120.00
+        7275 4425 6450 2475
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 1 2
+       0 0 1.00 60.00 120.00
+       0 0 1.00 60.00 120.00
+        1425 4275 2100 2475
+4 0 0 50 0 0 12 0.0000 4 180 1080 2025 2400 dlife_server.pl\001
+4 0 0 50 0 0 12 0.0000 4 180 1080 5625 2325 dlife_server.pl\001
+4 0 0 50 0 0 12 0.0000 4 180 1020 900 4500 dlife_client.pl\001
+4 0 0 50 0 0 12 0.0000 4 180 1020 2025 5625 dlife_client.pl\001
+4 0 0 50 0 0 12 0.0000 4 180 1020 3525 4425 dlife_client.pl\001
+4 0 0 50 0 0 12 0.0000 4 180 1020 5100 5325 dlife_client.pl\001
+4 0 0 50 0 0 12 0.0000 4 180 1020 6900 4650 dlife_client.pl\001
+4 0 0 50 0 0 12 0.0000 4 180 795 3375 4725 (runs from\001
+4 0 0 50 0 0 12 0.0000 4 180 1545 3375 4950 /etc/ppp/ip-up.local)\001
+4 0 0 50 0 0 12 0.0000 4 135 540 3675 5700 modem\001
+4 0 0 50 0 0 12 0.0000 4 180 780 675 6750 dlife_soup\001
+4 0 0 50 0 0 12 0.0000 4 180 780 2025 7650 dlife_soup\001
+4 0 0 50 0 0 12 0.0000 4 180 780 2025 7875 dlife_soup\001
+4 0 0 50 0 0 12 0.0000 4 180 780 3600 7050 dlife_soup\001
+4 0 0 50 0 0 12 0.0000 4 180 780 5250 7350 dlife_soup\001
+4 0 0 50 0 0 12 0.0000 4 180 780 7125 6675 dlife_soup\001
diff --git a/archproc.gif b/archproc.gif
new file mode 100644 (file)
index 0000000..7c5eabc
Binary files /dev/null and b/archproc.gif differ
diff --git a/archref.html b/archref.html
new file mode 100644 (file)
index 0000000..5e5c20b
--- /dev/null
@@ -0,0 +1,489 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+  <head>
+    <title>DLIFE distributed architecture reference</title>
+  </head>
+
+  <body bgcolor="#ffffff">
+    <h1>DLIFE distributed architecture reference</h1>
+
+    <p>
+      DLIFE is distributed, meaning that many people
+      may allocate their spare computing cycles and
+      memory in order to form something which approximates
+      a very large single soup. Actually modelling a
+      very large soup, however, would be very difficult:
+      such a program would have a high communication
+      overhead, would be totally unsuitable to run on
+      the Internet, and adding nodes to this would bring
+      diminishing returns. Therefore DLIFE uses a simpler
+      model: individual computers run small soups, and
+      from time to time, soups exchange a few cells at
+      random with each other. In effect we form a series
+      of islands connected by archipelagoes.
+    </p>
+
+    <h2>Processes</h2>
+
+    <p>
+      There are currently three processes involved:
+    </p>
+
+    <ul>
+      <li> <b>dlife_soup</b>: This program runs continuously,
+       one on each client CPU, simulating a single soup.
+       It is written in C and designed to be as small and
+       fast as possible. This is the only part of DLIFE which
+       clients need to run all the time.
+      <li> <b>dlife_client.pl</b>: This is a Perl script which
+       runs infrequently (normally once per hour, but it
+       could be more or less often, or it could be run
+       on-demand when a PPP connection is brought up). The Perl script is
+       responsible for exchanging cells with the DLIFE server.
+      <li> <b>dlife_server.pl</b>: This is the DLIFE server
+       script. It only runs on servers (obviously). It acts
+       as a repository for cells being exchanged between
+       clients.
+    </ul>
+
+    <p>
+      The following diagram shows the interaction between these
+      three programs.
+    </p>
+
+    <img src="archproc.gif"
+      alt="[Diagram] Interaction between DLIFE processes"
+      width=491 height=475>
+
+    <p>
+      As shown, there are five client computers and two
+      servers. The second client computer has two CPUs,
+      and runs dlife_soup continuously on both. The
+      third client computer is connected to the Internet
+      by a modem, and so runs dlife_client.pl from
+      <tt>/etc/ppp/ip-up.local</tt> (this script runs whenever
+      the Internet connection is brought up). All the
+      other computers are permanently connected to the
+      Internet, and dlife_client.pl runs periodically
+      from <tt>cron</tt>. Clients may connect and exchange
+      cells with more than one server. In the diagram
+      above, the third client computer connects to
+      both servers.
+    </p>
+
+    <h2>Cells in files</h2>
+
+    <p>
+      The long-running dlife_soup program does not
+      contain any network code. All network communications
+      are handled by dlife_client.pl. Instead, dlife_soup
+      contains code to save and load cells to files.
+    </p>
+
+    <p>
+      dlife_soup saves (by default) six cells per hour,
+      at random, into the directory:
+    </p>
+
+    <p>
+      <tt>/var/spool/dlife/outgoing/</tt>
+    </p>
+
+    <p>
+      dlife_soup loads (by default) four cells per hour,
+      at random, from the directory:
+    </p>
+
+    <p>
+      <tt>/var/spool/dlife/incoming/</tt>
+    </p>
+
+    <p>
+      The dlife_client.pl program takes some cells at
+      random from the <tt>outgoing</tt> spool
+      directory and uploads them to one or more servers
+      (see the <a href="#conf">configuration section</a>
+      below). It then asks the server(s) to send some
+      cells, and it saves these in the <tt>incoming</tt>
+      spool directory.
+    </p>
+
+    <p>
+      The dlife_server.pl program listens for client
+      connections, and uploads or downloads cells. It
+      saves its cells in the directory:
+    </p>
+
+    <p>
+      <tt>/var/spool/dlife/store/</tt>
+    </p>
+
+    <h2>DLIFE network protocol</h2>
+
+    <p>
+      The DLIFE network protocol is a very simple
+      ASCII based protocol, similar to (but much
+      more limited than) FTP.
+    </p>
+
+    <p>
+      Servers listen for connections on port 5904.
+      When a client connects, they send back the following
+      identifying string:
+    </p>
+
+<pre>
+DLIFE SERVER &lt;version&gt; &lt;protocol&gt; &lt;CR&gt; &lt;LF&gt;
+</pre>
+
+    <p>
+      <tt>&lt;version&gt;</tt> is the server version, for
+      information only.
+    </p>
+
+    <p>
+      <tt>&lt;protocol&gt;</tt> is the protocol version. The
+      protocol described below is version 1.x (for some digit
+      ``x''). If a server reports a different major version
+      number (eg. 2.x) then this is an indication that the
+      protocol has changed dramatically and current clients
+      should give up and abort.
+    </p>
+
+    <p>
+      Clients connect to servers on port 5904 and
+      issue a series of simple four letter commands.
+      Each command should take the form:
+    </p>
+
+<pre>
+&lt;command&gt; [ &lt;space&gt; &lt;arguments ...&gt; ] &lt;CR&gt; &lt;LF&gt;
+</pre>
+
+    <p>
+      There are currently four commands: <tt>HELO</tt>,
+      <tt>STOR</tt>, <tt>RETR</tt> and <tt>QUIT</tt>.
+    </p>
+
+    <p>
+      Servers respond to commands with a three digit
+      response code and some optional human-readable text:
+    </p>
+
+<pre>
+XYZ [ &lt;space&gt; text ... ] &lt;CR&gt; &lt;LF&gt;
+</pre>
+
+    <p>
+      Of the response code, only the first digit (``<tt>X</tt>'')
+      is meaningful to clients. As for FTP, this digit can
+      have the following meanings:
+    </p>
+
+    <table border=1>
+      <tr>
+       <th> Response code </th> <th> Meaning </th>
+      </tr>
+      <tr>
+       <td> 1xx </td>
+       <td> Command OK. Ready to send data, <i>or</i> ready
+         to receive data.
+       </td>
+      </tr>
+      <tr>
+       <td> 2xx </td>
+       <td> Command OK. Ready for your next command.
+       </td>
+      </tr>
+      <tr>
+       <td> 4xx </td>
+       <td> Temporary error. The client can retry the last command
+         without modification and it may well succeed next time.
+       </td>
+      </tr>
+      <tr>
+       <td> 5xx </td>
+       <td> Error. The client should not just retry the same
+         command, but needs to reformulate the command or
+         cancel the operation and report an error back to the
+         user.
+       </td>
+      </tr>
+    </table>
+
+    <h3>The HELO command</h3>
+
+    <p>
+      The <tt>HELO</tt> command has the following form:
+    </p>
+
+<pre>
+HELO &lt;space&gt; &lt;client_hostname&gt;
+          &lt;space&gt; &lt;client_version&gt; &lt;CR&gt; &lt;LF&gt;
+</pre>
+
+    <p>
+      where &lt;client_hostname&gt; is the client
+      hostname (or the client may just send "-" character)
+      and &lt;client_version&gt; is the client version
+      number, used just for information only.
+    </p>
+
+    <p>
+      The server should always respond with 2xx to
+      this command.
+    </p>
+
+    <p>
+      A typical interaction:
+    </p>
+
+<pre>
+&gt; HELO - 0.0.12
+&lt; 200 Hello.
+</pre>
+
+    <h3>The STOR command</h3>
+
+    <p>
+      The <tt>STOR</tt> command is used to upload a single
+      cell to the server.
+    </p>
+
+    <p>
+      The format of the command is:
+    </p>
+
+<pre>
+STOR &lt;CR&gt; &lt;LF&gt;
+</pre>
+
+    <p>
+      If the server accepts the command and is ready to
+      upload a cell, it will reply with a 1xx response.
+      The client should then send the cell as a series
+      of hex nybbles, terminated by the sequence
+      <tt>&lt;CR&gt; &lt;LF&gt; . &lt;CR&gt; &lt;LF&gt;</tt>.
+    </p>
+
+    <p>
+      A typical interaction:
+    </p>
+
+<pre>
+&gt; STOR
+&lt; 100 Send me the cell, terminated by ".".
+&gt; 00000000010901010100002227
+&gt; 0000000100FFFFFFFFFFFFFFFF
+&gt;      :      :
+&gt;      :      :
+&gt; 00010000002402020202020202022027
+&gt; 0001010101
+&gt; .
+&lt; 200 Cell was uploaded OK.
+</pre>
+
+    <p>
+      Servers will typically have limitations on the
+      number and type of cells that they will accept.
+      Generally they will only accept a small number
+      of uploads per session, and each cell will be
+      limited to 8192 bytes or less.
+    </p>
+
+    <h3>The RETR command</h3>
+
+    <p>
+      The <tt>RETR</tt> command is used to download
+      a cell from the cell bank. The format of the command
+      is:
+    </p>
+
+<pre>
+RETR &lt;CR&gt; &lt;LF&gt;
+</pre>
+
+    <p>
+      If the server is ready to serve a cell, it will
+      reply with a 1xx response, followed by a series
+      of hex nybbles and terminated by the
+      sequence
+      <tt>&lt;CR&gt; &lt;LF&gt; . &lt;CR&gt; &lt;LF&gt;</tt>
+      and immediately followed by a 2xx response.
+    </p>
+
+    <p>
+      A typical interaction:
+    </p>
+
+<pre>
+&gt; RETR
+&lt; 100 OK. Sending you a cell.
+&lt; 00000000010901010100002227
+&lt; 0000000100FFFFFFFFFFFFFFFF
+&lt;      :      :
+&lt;      :      :
+&lt; 00010000002402020202020202022027
+&lt; 0001010101
+&lt; .
+&lt; 200 Cell was sent OK.
+</pre>
+
+    <h3>The QUIT command</h3>
+
+    <p>
+      The <tt>QUIT</tt> command terminates a session
+      (clients may also just close a session).
+    </p>
+
+    <p>
+      The format of the command is:
+    </p>
+
+<pre>
+QUIT &lt;CR&gt; &lt;LF&gt;
+</pre>
+
+    <p>
+      The server responds with a 2xx message and then
+      closes its end of the connection.
+    </p>
+
+    <p>
+      A typical interaction:
+    </p>
+
+<pre>
+&gt; QUIT
+&lt; 200 Goodbye.
+<i>(socket is closed)</i>
+</pre>
+
+    <a name="conf"><h2>Configuration files</h2></a>
+
+    <h3>/etc/dlife/client.conf</h3>
+
+    <p>
+      This file is used to configure the network client.
+      The file tells the client which server or servers
+      to connect to.
+    </p>
+
+    <p>
+      The client can be configured to:
+    </p>
+
+    <ul>
+      <li> Download a list of servers from a web page.
+      <li> Contact only servers in the current ``zone'' (eg.
+       only servers in the UK or Europe). And/or:
+      <li> Contact servers directly by name.
+    </ul>
+
+    <h4>server_url command</h4>
+
+    <p>
+      The <tt>server_url</tt> command may be optionally
+      given. It directs the client to download the web
+      page given in the URL. The web page should contain
+      a master list of servers.
+    </p>
+
+<pre>
+server_url <a href="http://dlife.annexia.org/servers.txt">http://dlife.annexia.org/servers.txt</a>
+</pre>
+
+    <h4>server_zone command</h4>
+
+    <p>
+      The <tt>server_zone</tt> command is optional. It
+      should be used in conjunction with the
+      <tt>server_url</tt> command. It
+      directs the client to only consider servers
+      in the particular zone or zones listed.
+    </p>
+
+    <p>
+      The general form is:
+    </p>
+
+<pre>
+server_zone &lt;zone&gt; [&lt;zone&gt; [...]]
+</pre>
+
+    <p>
+      Each <tt>&lt;zone&gt;</tt> argument should have the
+      form:
+    </p>
+
+    <ul>
+      <li> An ISO3166 country code, eg. <tt>uk</tt>, <tt>us</tt>. Or:
+      <li> A geographical continent, eg. <tt>eu</tt>. Or:
+      <li> A domain name, preceeded by a dot ("."),
+       eg. <tt>.bibliotech.net</tt>.
+    </ul>
+
+    <h4>server command</h4>
+
+    <p>
+      The <tt>server</tt> command directs the client to
+      connect directly the server or servers listed.
+    </p>
+
+<pre>
+server dlife1.bibliotech.co.uk dlife2.bibliotech.co.uk
+</pre>
+
+    <h4>max_cells_upload_per_pass command</h4>
+
+    <p>
+      The <tt>max_cells_upload_per_pass</tt> directs
+      the client to attempt to upload this many cells
+      in a pass. Note that the server probably imposes
+      its own limit.
+    </p>
+
+    <h4>max_cells_download_per_pass command</h4>
+
+    <p>
+      The <tt>max_cells_download_per_pass</tt> directs
+      the client to attempt to download this many cells
+      in a pass. Note that the server probably imposes
+      its own limit. It is a good idea to ensure that
+      <tt>max_cells_upload_per_pass</tt> &gt;
+      <tt>max_cells_download_per_pass</tt>.
+    </p>
+
+    <h3>/etc/dlife/soup.conf</h3>
+
+    <p>
+      The <tt>soup.conf</tt> file configures various
+      internal aspects of the DLIFE virtual machine.
+      For full documentation, please see the example
+      file provided with the source distribution.
+    </p>
+
+    <h2>Typical configurations</h2>
+
+    <h3>Default configuration</h3>
+
+
+
+
+
+
+    <!-- default,
+    modem,
+    behind firewall
+    -->
+
+
+
+    <hr>
+    <address><a href="mailto:rich@annexia.org">Richard Jones</a></address>
+<!-- Created: Sat Oct  7 10:12:59 BST 2000 -->
+<!-- hhmts start -->
+Last modified: Wed Oct 11 23:19:19 BST 2000
+<!-- hhmts end -->
+  </body>
+</html>
diff --git a/cell.c b/cell.c
new file mode 100644 (file)
index 0000000..c7f1f1a
--- /dev/null
+++ b/cell.c
@@ -0,0 +1,703 @@
+/* DLIFE Copyright (C) 2000 Richard W.M. Jones <rich@annexia.org>
+ * and other authors listed in the ``AUTHORS'' file.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * $Id: cell.c,v 1.3 2002/12/11 17:16:21 rich Exp $
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#endif
+
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
+#include "cell.h"
+#include "soup.h"
+#include "random.h"
+#include "params.h"
+#include "dlink.h"
+#include "image.h"
+#include "load.h"
+
+#define PRINT_SIMULATION_STATS 0
+
+static volatile int quit = 0, save = 0, outgoing = 0, incoming = 0, info = 0;
+static void save_cell_in_outgoing (struct state *, const struct cell *);
+
+/* Initialize the common fields of a cell. */
+static inline void
+init_cell (struct cell *cell)
+{
+  /* Public fields are subject to initialization errors. */
+  if (! chance (cell_initialization_failure))
+    {
+      cell->a = cell->b = cell->i = cell->p = 0;
+      memset (cell->stack, 0, sizeof cell->stack);
+    }
+  else
+    {
+      int i;
+
+      cell->a = get_rand_short ();
+      cell->b = get_rand_short ();
+      cell->i = get_rand_short ();
+      cell->p = 0;             /* Cell would be non-viable otherwise. */
+
+      for (i = 0; i < STACK_SIZE; ++i)
+       cell->stack[i] = get_rand_short ();
+    }
+  cell->next = cell->prev = 0;
+  cell->worse = cell->better = 0;
+  cell->sp = 0;
+  cell->errors = 0;
+  cell->state = state_exec;
+  cell->dir = 0;
+  cell->plen = 0;
+  cell->lim = 0;
+  cell->frag = 0;
+  cell->daughter = 0;
+  cell->cycle = 0;
+  cell->crc = 0;               /* Initialize these at DIVIDE. */
+  cell->mother_crc = 0;
+}
+
+struct cell *
+cell_malloc (struct state *state,
+            const struct cell *mother,
+            struct soup_frag *daughter_frag)
+{
+  struct cell *cell;
+
+  cell = malloc (sizeof (struct cell));
+  if (cell == 0) { perror ("malloc"); abort (); }
+
+  init_cell (cell);
+  cell->frag = daughter_frag;
+
+  state->nr_cells_allocated++;
+
+  return cell;
+}
+
+void
+cell_divide (struct state *state,
+            const struct cell *mother,
+            struct cell *daughter)
+{
+  /* Initialize CRC fields. */
+  daughter->mother_crc = mother->crc;
+  daughter->crc = soup_frag_compute_crc32 (state, daughter->frag);
+
+  /* If the outgoing signal has just gone, then this cell is the
+   * lucky cell which has been nominated to be written into the
+   * outgoing queue.
+   */
+  if (outgoing)
+    {
+      outgoing = 0;
+      save_cell_in_outgoing (state, daughter);
+    }
+
+#if 0
+  printf ("DIVIDE: 0x%08X/%d -> 0x%08X/%d\n",
+         daughter->mother_crc, mother->frag->len,
+         daughter->crc, daughter->frag->len);
+#endif
+}
+
+/* Put a cell onto the alive list. */
+void
+cell_activate (struct state *state, struct cell *cell)
+{
+  insert_before_first (cell, &state->alive_list);
+
+  /* We assume that cells start off with no errors. */
+  assert (cell->errors == 0);
+  insert_before_first (cell, &state->best_list);
+
+  state->nr_cells_alive++;
+}
+
+/* This function is called after the INC_ERRORS macro has incremented
+ * the number of errors in a cell and found that the cell should be
+ * moved up in the linked list by one or more places.
+ */
+void
+_cell_move_worse (struct state *state, struct cell *cell)
+{
+  while (cell->worse && cell->errors > cell->worse->errors)
+    move_towards_last (cell, &state->best_list);
+}
+
+/* Kill a cell (and undivided offspring, if any). */
+void
+cell_kill (struct state *state, struct cell *cell)
+{
+  remove_element (cell, &state->alive_list);
+  remove_element (cell, &state->best_list);
+
+  soup_frag_free (state, cell->frag);
+
+  /* Pro-life programmers may wish to look away at this point ... */
+  if (cell->daughter)
+    {
+      soup_frag_free (state, cell->daughter->frag);
+      cell->daughter->errors = -1;
+      free (cell->daughter);
+
+      state->nr_cells_allocated--;
+    }
+
+  cell->errors = -1;
+  free (cell);
+
+  state->nr_cells_allocated--;
+  state->nr_cells_alive--;
+}
+
+/* Run the grim reaper, culling cells until the amount of free soup
+ * left is less than the appropriate threshold.
+ */
+static inline void
+reaper (struct state *state)
+{
+  int bytes_to_free;
+
+  /* How many bytes do we need to free up? */
+  bytes_to_free = (100 - reaper_reap_threshold) * state->soup_size
+    / 100 - state->soup_free;
+  assert (bytes_to_free > 0);
+
+#if 0
+  printf ("\ninvoking reaper to save %d bytes of soup ...\n", bytes_to_free);
+#endif
+
+  while (bytes_to_free > 0)
+    {
+      struct cell *cell;
+
+      /* Pick the most error-prone cell and kill it. */
+      cell = (struct cell *) state->best_list.last;
+      bytes_to_free -= cell->frag->len;
+      if (cell->daughter) bytes_to_free -= cell->daughter->frag->len;
+
+#if 0
+      printf ("  killing cell with %d errors\n", cell->errors);
+#endif
+
+      cell_kill (state, cell);
+    }
+}
+
+/* Remove any cells with more than MAX_ERRORS errors. */
+static inline void
+reap_error_prone_cells (struct state *state)
+{
+  struct cell *cell;
+
+  /* Just go down the list of cells, killing them until we
+   * reach a cell with < MAX_ERRORS errors.
+   */
+  while ((cell = (struct cell *) state->best_list.last) &&
+        cell->errors >= MAX_ERRORS)
+    {
+#if 0
+      printf ("killing cell with %d errors (>= MAX_ERRORS)\n", cell->errors);
+#endif
+
+      cell_kill (state, cell);
+    }
+}
+
+static void
+check_one_cell (struct state *state, const struct cell *cell, int is_daughter)
+{
+  assert (cell->sp >= 0 && cell->sp < STACK_SIZE);
+  assert (cell->errors >= 0);
+  assert (cell->state == state_exec || cell->state == state_find);
+  assert (cell->dir >= -1 && cell->dir <= 1);
+  assert (cell->frag != 0);
+
+  if (cell->daughter)
+    {
+      assert (is_daughter == 0);
+      check_one_cell (state, cell->daughter, 1);
+    }
+}
+
+/* Check the consistency of each cell. This is only used when we are
+ * debugging the simulation.
+ */
+void
+cell_check (struct state *state)
+{
+  const struct cell *p;
+  int alive = 0, allocated = 0, errors = 0;
+
+  /* Check the alive list and each cell on it. */
+  for (p = (struct cell *) state->alive_list.first; p; p = p->next)
+    {
+      check_one_cell (state, p, 0);
+      alive++; allocated++;
+      if (p->daughter) allocated++;
+    }
+
+  assert (alive == state->nr_cells_alive);
+  assert (allocated == state->nr_cells_allocated);
+
+  /* Check the best list. */
+  alive = allocated = 0;
+  for (p = (struct cell *) state->best_list.first; p; p = p->worse)
+    {
+      assert (errors <= p->errors);
+      errors = p->errors;
+      alive++; allocated++;
+      if (p->daughter) allocated++;
+    }
+
+  assert (alive == state->nr_cells_alive);
+  assert (allocated == state->nr_cells_allocated);
+}
+
+/* Take a complete checkpoint of the state and save it onto disk. */
+static void
+save_me (struct state *state)
+{
+  char filename2[256], filename3[256];
+
+  sprintf (filename2, "%s.new", state->filename);
+
+  if (image_save (state, filename2) == 0)
+    {
+      sprintf (filename3, "%s~", state->filename);
+
+      rename (state->filename, filename3);
+      rename (filename2, state->filename);
+
+      if (verbose)
+       printf ("CPU %d: Saved soup image to file.\n", state->thread_num);
+    }
+  else
+    {
+      sprintf (filename3, "/tmp/%s", state->filename);
+
+      if (image_save (state, filename3) == 0)
+       {
+         fprintf (stderr,
+                  "save directory is unwritable! saved to %s instead\n",
+                  filename3);
+       }
+      else
+       {
+         fprintf (stderr, "could not save state!\n");
+       }
+    }
+}
+
+/* Check the incoming queue. */
+static void
+check_incoming (struct state *state)
+{
+  DIR *dir;
+  struct dirent *d;
+  char filename[256];
+  int cells_read = 0;
+
+#ifndef HAVE_OPENDIR
+#error "require working opendir/readdir/closedir"
+#endif
+
+  dir = opendir ("incoming");
+  if (dir == NULL) { perror ("incoming"); return; }
+
+  while ((d = readdir (dir)) != 0)
+    {
+      int len = strlen (d->d_name);
+
+      if (len >= 4 &&
+         d->d_name[len-4] == '.' &&
+         d->d_name[len-3] == 'd' &&
+         d->d_name[len-2] == 'l' &&
+         d->d_name[len-1] == 'o')
+       {
+         if (cells_read < max_cells_incoming_per_pass)
+           {
+             struct cell *cell;
+
+             sprintf (filename, "incoming/%s", d->d_name);
+
+             /* Read the contents of the file. */
+             cell = load_cell (state, filename);
+
+             if (cell)
+               {
+                 cell_activate (state, cell);
+                 cells_read++;
+               }
+           }
+
+         /* Remove the file - we've finished with it now. */
+         unlink (filename);
+       }
+    }
+}
+
+static void
+info_to_syslog (const struct state *state)
+{
+  int soup_used_percent
+    = 100 * (state->soup_size - state->soup_free) / state->soup_size;
+
+#ifdef HAVE_SYSLOG
+  syslog (LOG_INFO,
+         "#%d: cycles: %LuB cells: %d [+%d] soup: %d%% (%d/%d)",
+         state->thread_num,
+         state->cell_cycle / 1000000000,
+         state->nr_cells_alive,
+         state->nr_cells_allocated - state->nr_cells_alive,
+         soup_used_percent,
+         state->soup_size - state->soup_free,
+         state->soup_size);
+#endif
+}
+
+static void
+catch_quit (int sig)
+{
+  quit = 1;
+}
+
+static void
+catch_alarm (int sig)
+{
+  static int minutes = 0;
+
+  minutes++;
+
+  if ((minutes % save_period) == 0)
+    {
+      save = 1;
+    }
+
+  if ((minutes % outgoing_period) == 0)
+    {
+      outgoing = 1;
+    }
+
+  if ((minutes % incoming_period) == 0)
+    {
+      incoming = 1;
+    }
+
+  if ((minutes % info_period) == 0)
+    {
+      info = 1;
+    }
+
+  alarm (60);
+}
+
+void
+run_thread (struct state *state)
+{
+  int start_time = time (NULL), end_time;
+  unsigned long long start_cycle = state->cell_cycle;
+  struct sigaction sigact;
+
+  /* Set up signal handlers to save the soup periodically and
+   * handle exits gracefully.
+   */
+  memset (&sigact, 0, sizeof sigact);
+  sigact.sa_handler = catch_quit;
+  sigact.sa_flags = 0;
+
+  sigaction (SIGINT, &sigact, 0);
+  sigaction (SIGQUIT, &sigact, 0);
+  sigaction (SIGTERM, &sigact, 0);
+
+  sigact.sa_handler = catch_alarm;
+  sigact.sa_flags = SA_RESTART;
+  sigaction (SIGALRM, &sigact, 0);
+
+  alarm (60);
+
+  while (!quit)
+    {
+      struct cell *p;
+      int soup_used_percent;
+
+      /* Iterate over the list of alive cells, executing a single
+       * intruction of each.
+       */
+      for (p = (struct cell *) state->alive_list.first; p; p = p->next)
+       {
+         exec_insn (state, p);
+       }
+
+      /* Print some statistics. */
+      soup_used_percent
+       = 100 * (state->soup_size - state->soup_free) / state->soup_size;
+
+#if PRINT_SIMULATION_STATS
+      printf ("cycles: %LuB  cells: %d [+%d]  soup: %d%%  \r",
+             state->cell_cycle / 1000000000,
+             state->nr_cells_alive,
+             state->nr_cells_allocated - state->nr_cells_alive,
+             soup_used_percent);
+      fflush (stdout);
+#endif
+
+      /* Do we need to invoke the grim reaper? */
+      if (soup_used_percent >= reaper_invoke_threshold)
+       {
+         reaper (state);
+       }
+
+      /* Do we need to reap any remaining cells with more than
+       * MAX_ERRORS errors?
+       */
+      reap_error_prone_cells (state);
+
+#if CHECK
+      soup_check (state);
+      cell_check (state);
+#endif
+
+      /* Save image every so often. */
+      if (save)
+       {
+         save = 0;
+         save_me (state);
+       }
+
+      /* Check incoming queue? */
+      if (incoming)
+       {
+         incoming = 0;
+         check_incoming (state);
+       }
+
+      /* Dump status information to syslog? */
+      if (info)
+       {
+         info = 0;
+         info_to_syslog (state);
+       }
+    }
+
+  end_time = time (NULL);
+
+  syslog (LOG_INFO, "CPU %d: Cycles processed: %LuB  Time: %dH  Cycles/second: %d\n",
+         state->thread_num,
+         (state->cell_cycle - start_cycle) / 1000000000,
+         (end_time - start_time) / (60 * 60),
+         (int) ((state->cell_cycle - start_cycle)
+                / (end_time - start_time)));
+
+  /* Each thread is responsible for saving its own state. */
+  save_me (state);
+}
+
+/* Something of a hack: get any fragment and return it. */
+struct soup_frag *
+_cell_get_any_frag (struct state *state)
+{
+  return ((struct cell *) state->alive_list.first)->frag;
+}
+
+/* Save the current state of the cell table to a file. This function
+ * is non-destructive.
+ */
+void
+cell_state_save (struct state *state, FILE *fp)
+{
+  struct cell *p;
+
+  /* Write out the number of cells. */
+  fwrite (&state->nr_cells_allocated, sizeof state->nr_cells_allocated, 1, fp);
+  fwrite (&state->nr_cells_alive, sizeof state->nr_cells_alive, 1, fp);
+
+  /* Write the cells out in order to the file. */
+  for (p = (struct cell *) state->alive_list.first; p; p = p->next)
+    {
+      p->fbase = p->frag->base;
+      fwrite (p, sizeof (struct cell), 1, fp);
+      if (p->daughter)
+       {
+         p->daughter->fbase = p->daughter->frag->base;
+         fwrite (p->daughter, sizeof (struct cell), 1, fp);
+       }
+    }
+}
+
+static int
+compare_nr_errors (const void *cv1, const void *cv2)
+{
+  const struct cell **cp1 = (const struct cell **) cv1;
+  const struct cell **cp2 = (const struct cell **) cv2;
+
+  return (*cp1)->errors - (*cp2)->errors;
+}
+
+/* Load the cells from a previously saved file. */
+void
+cell_state_load (struct state *state, FILE *fp)
+{
+  int i;
+  struct cell *p;
+  struct cell **cellptr_list;
+
+  assert (state->nr_cells_allocated == 0);
+  assert (state->nr_cells_alive == 0);
+
+  /* Read in the number of cells. */
+  if (fread (&state->nr_cells_allocated,
+            sizeof state->nr_cells_allocated, 1, fp) != 1)
+    {
+      syslog (LOG_ERR, "error in cell state\n");
+      abort ();
+    }
+  if (fread (&state->nr_cells_alive,
+            sizeof state->nr_cells_alive, 1, fp) != 1)
+    {
+      syslog (LOG_ERR, "error in cell state\n");
+      abort ();
+    }
+
+  assert (state->nr_cells_alive <= state->nr_cells_allocated);
+
+  cellptr_list = malloc (sizeof (struct cell *) * state->nr_cells_alive);
+
+  /* Read each cell in from the file. */
+  for (i = 0; i < state->nr_cells_alive; ++i)
+    {
+      p = malloc (sizeof (struct cell));
+      if (p == 0) { perror ("malloc"); abort (); }
+
+      if (fread (p, sizeof (struct cell), 1, fp) != 1)
+       {
+         syslog (LOG_ERR, "error in cell state\n");
+         abort ();
+       }
+
+      cellptr_list[i] = p;
+
+      insert_before_last (p, &state->alive_list);
+
+      if (p->daughter)
+       {
+         p->daughter = malloc (sizeof (struct cell));
+         if (p->daughter == 0) { perror ("malloc"); abort (); }
+
+         if (fread (p->daughter, sizeof (struct cell), 1, fp) != 1)
+           {
+             syslog (LOG_ERR, "error in cell state\n");
+             abort ();
+           }
+       }
+    }
+
+  /* Order the living cells from best to worst, and from this
+   * reconstruct the best list.
+   */
+  qsort (cellptr_list, state->nr_cells_alive, sizeof (struct cell *),
+        compare_nr_errors);
+
+  for (i = 0; i < state->nr_cells_alive; ++i)
+    {
+      insert_before_last (cellptr_list[i], &state->best_list);
+    }
+}
+
+/* This function is used when loading the soup (just after loading the
+ * cells) to fix up references from the cells to soup fragments. It
+ * uses the hidden ``fbase'' member of struct cell to save the reference.
+ */
+void
+_cell_fixup_soup_ref (struct state *state,
+                     addr_t fbase, struct soup_frag *frag)
+{
+  struct cell *p;
+
+  for (p = (struct cell *) state->alive_list.first; p; p = p->next)
+    {
+      if (p->fbase == fbase)
+       {
+         p->frag = frag;
+         return;
+       }
+      else if (p->daughter && p->daughter->fbase == fbase)
+       {
+         p->daughter->frag = frag;
+         return;
+       }
+    }
+
+  syslog (LOG_ERR, "cell fixup not found (fbase = %d)\n", fbase);
+  abort ();
+}
+
+/* Save a single cell in the outgoing queue. */
+static void
+save_cell_in_outgoing (struct state *state,
+                      const struct cell *cell)
+{
+  char filename[256];
+  FILE *fp;
+  int i;
+
+  /* Choose a random name. */
+  sprintf (filename, "outgoing/%d.dlo", get_rand_int());
+
+  fp = fopen (filename, "w");
+  if (fp == NULL) { perror (filename); return; } /* Fail silently. */
+
+  for (i = 0; i < cell->frag->len; ++i)
+    fprintf (fp, "%02X", get_soup (state, cell->frag, i));
+
+  fclose (fp);
+}
diff --git a/cell.h b/cell.h
new file mode 100644 (file)
index 0000000..847fcf5
--- /dev/null
+++ b/cell.h
@@ -0,0 +1,122 @@
+/* DLIFE Copyright (C) 2000 Richard W.M. Jones <rich@annexia.org>
+ * and other authors listed in the ``AUTHORS'' file.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * $Id: cell.h,v 1.1 2002/04/05 14:40:25 rich Exp $
+ */
+
+#ifndef cell_h
+#define cell_h
+
+#include "config.h"
+
+#include <stdio.h>
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>         /* For MAXHOSTNAMELEN. */
+#endif
+
+#include "types.h"
+#include "dlink.h"
+#include "state.h"
+#include "crc.h"
+
+struct soup_frag;
+
+#define STACK_SIZE 16
+
+/* These two parameters define the maximum cell size. The first parameter
+ * is the maximum length of searches permitted by the FINDB/FINDF
+ * commands. It stops those commands from running wild if a label is
+ * missing. The second one limits the maximum cell size that may be
+ * allocated by MALLOC - and hence directly the maximum cell size
+ * overall. There is also a minimum cell size, although we keep this
+ * small.
+ */
+#define FIND_LENGTH_LIMIT 512
+#define MAX_CELL_SIZE     512
+#define MIN_CELL_SIZE      10
+
+/* The maximum number of errors that a cell may get before we
+ * automatically blow it away (even if the soup isn't full and
+ * doesn't need reaping). This prevents us wasting valuable CPU
+ * time on cells which have gone completely AWOL.
+ */
+#define MAX_ERRORS        100
+
+enum cell_state
+{
+  state_exec,
+  state_find
+};
+
+struct cell
+{
+  struct cell *next;           /* Alive cells are linked thru this list. */
+  struct cell *prev;           /* Alive cells are linked thru this list. */
+  struct cell *worse;          /* Cells are kept in error order on this list*/
+  struct cell *better;         /* Cells are kept in error order on this list*/
+  reg_t a, b, i, p;            /* Registers. */
+  reg_t stack[STACK_SIZE];     /* Stack. */
+  int sp;                      /* Stack pointer. */
+  int errors;                  /* Cumulative number of errors encountered */
+  enum cell_state state;       /* Executing or finding. */
+  int dir;                     /* [Find] -1 = back, 1 = forwards */
+  int plen;                    /* [Find] length of pattern */
+  int lim;                     /* [Find] search limit (counts down to 0) */
+  struct soup_frag *frag;      /* Fragment in the soup */
+  struct cell *daughter;       /* Daughter (after MALLOC, before DIVIDE) */
+  unsigned long long cycle;    /* Number of cycles of runtime. */
+  crc_t crc;                   /* CRC at birth (after mother's DIVIDE). */
+  crc_t mother_crc;            /* CRC of mother. */
+  addr_t fbase;                        /* Used when saving/loading soup image only. */
+};
+
+extern int verbose;
+
+extern struct cell *cell_malloc (struct state *state,
+                                const struct cell *mother,
+                                struct soup_frag *daughter_frag);
+extern void cell_divide (struct state *state,
+                        const struct cell *mother,
+                        struct cell *daughter);
+extern void cell_activate (struct state *state,
+                          struct cell *cell);
+extern void cell_kill (struct state *state,
+                      struct cell *cell);
+
+extern void cell_state_load (struct state *state, FILE *fp);
+extern void cell_state_save (struct state *state, FILE *fp);
+
+extern void cell_check (struct state *state);
+
+extern void exec_insn (struct state *state, struct cell *cell);
+
+extern void run_thread (struct state *state);
+
+/* This macro is used to increment the error count in a cell. It
+ * ensures that the cell ``worst-to-best'' list is kept up to date.
+ */
+#define INC_ERRORS(state,cell) do { (cell)->errors++; if ((cell)->worse && (cell)->errors > (cell)->worse->errors) _cell_move_worse ((state), (cell)); } while (0)
+
+extern void _cell_move_worse (struct state *state, struct cell *cell);
+
+extern struct soup_frag *_cell_get_any_frag (struct state *state);
+
+extern void _cell_fixup_soup_ref (struct state *state,
+                                 addr_t fbase, struct soup_frag *frag);
+
+#endif /* cell_h */
diff --git a/client.conf b/client.conf
new file mode 100644 (file)
index 0000000..5bcb134
--- /dev/null
@@ -0,0 +1,46 @@
+# DLIFE network client configuration file.
+
+# Note: You should either set ``server_url'' or set ``server''
+# (possibly both).
+
+#----------------------------------------------------------------------
+# If set, then the client will download the given web page looking
+# for servers to connect to.
+
+server_url     http://dlife.annexia.org/servers.txt
+
+# If you want the client to only connect to servers in a given
+# geographical zone (in order to reduce network traffic), then
+# set this to a list of ISO 3166 country codes and/or geographical
+# continent codes and/or domain names.
+#
+# Example (1): The client will only connect to servers in the
+# United Kingdom, France and the Netherlands.
+#
+# server_zone  uk fr nl
+#
+# Example (2): The client will only connect to servers in the
+# US or European Union.
+#
+# server_zone  us eu
+#
+# Example (3): The client will only connect to servers in the
+# domain bibliotech.net.
+#
+# server_zone  .bibliotech.net
+
+#----------------------------------------------------------------------
+# This causes the client to connect directly to the servers listed.
+#
+# Example: Connect to dlife1.bibliotech.net or dlife2.bibliotech.net.
+#
+# server       dlife1.bibliotech.net  dlife2.bibliotech.net
+
+#----------------------------------------------------------------------
+# How many cells to upload each pass (normally each hour).
+#
+max_cells_upload_per_pass      6
+
+# How many cells to download each pass (normally each hour).
+#
+max_cells_download_per_pass    4
diff --git a/config.cache b/config.cache
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/config.h.in b/config.h.in
new file mode 100644 (file)
index 0000000..d86b37c
--- /dev/null
@@ -0,0 +1,95 @@
+/* config.h.in.  Generated automatically from configure.in by autoheader 2.13.  */
+#ifndef DLIFE_CONFIG_H
+#define DLIFE_CONFIG_H
+
+#undef PACKAGE
+#undef VERSION
+#undef SPOOLDIR
+#undef CONFDIR
+
+/* Define if you have the closedir function.  */
+#undef HAVE_CLOSEDIR
+
+/* Define if you have the getpwnam function.  */
+#undef HAVE_GETPWNAM
+
+/* Define if you have the getuid function.  */
+#undef HAVE_GETUID
+
+/* Define if you have the initgroups function.  */
+#undef HAVE_INITGROUPS
+
+/* Define if you have the nice function.  */
+#undef HAVE_NICE
+
+/* Define if you have the opendir function.  */
+#undef HAVE_OPENDIR
+
+/* Define if you have the openlog function.  */
+#undef HAVE_OPENLOG
+
+/* Define if you have the readdir function.  */
+#undef HAVE_READDIR
+
+/* Define if you have the setgid function.  */
+#undef HAVE_SETGID
+
+/* Define if you have the setuid function.  */
+#undef HAVE_SETUID
+
+/* Define if you have the syslog function.  */
+#undef HAVE_SYSLOG
+
+/* Define if you have the <assert.h> header file.  */
+#undef HAVE_ASSERT_H
+
+/* Define if you have the <dirent.h> header file.  */
+#undef HAVE_DIRENT_H
+
+/* Define if you have the <errno.h> header file.  */
+#undef HAVE_ERRNO_H
+
+/* Define if you have the <fcntl.h> header file.  */
+#undef HAVE_FCNTL_H
+
+/* Define if you have the <grp.h> header file.  */
+#undef HAVE_GRP_H
+
+/* Define if you have the <pwd.h> header file.  */
+#undef HAVE_PWD_H
+
+/* Define if you have the <signal.h> header file.  */
+#undef HAVE_SIGNAL_H
+
+/* Define if you have the <stddef.h> header file.  */
+#undef HAVE_STDDEF_H
+
+/* Define if you have the <stdint.h> header file.  */
+#undef HAVE_STDINT_H
+
+/* Define if you have the <string.h> header file.  */
+#undef HAVE_STRING_H
+
+/* Define if you have the <sys/param.h> header file.  */
+#undef HAVE_SYS_PARAM_H
+
+/* Define if you have the <sys/types.h> header file.  */
+#undef HAVE_SYS_TYPES_H
+
+/* Define if you have the <syslog.h> header file.  */
+#undef HAVE_SYSLOG_H
+
+/* Define if you have the <time.h> header file.  */
+#undef HAVE_TIME_H
+
+/* Define if you have the <unistd.h> header file.  */
+#undef HAVE_UNISTD_H
+
+/* Name of package */
+#undef PACKAGE
+
+/* Version number of package */
+#undef VERSION
+
+
+#endif /* DLIFE_CONFIG_H */
diff --git a/config.log b/config.log
new file mode 100644 (file)
index 0000000..42174ee
--- /dev/null
@@ -0,0 +1,20 @@
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+configure:577: checking for a BSD compatible install
+configure:630: checking whether build environment is sane
+configure:687: checking whether make sets ${MAKE}
+configure:733: checking for working aclocal-1.4
+configure:746: checking for working autoconf
+configure:759: checking for working automake-1.4
+configure:772: checking for working autoheader
+configure:785: checking for working makeinfo
+configure:805: checking for gcc
+configure:918: checking whether the C compiler (gcc  ) works
+configure:934: gcc -o conftest    conftest.c  1>&5
+configure:960: checking whether the C compiler (gcc  ) is a cross-compiler
+configure:965: checking whether we are using GNU C
+configure:974: gcc -E conftest.c
+configure:993: checking whether gcc accepts -g
+configure:1036: checking for a BSD compatible install
+configure:1089: checking whether make sets ${MAKE}
diff --git a/configure b/configure
new file mode 100755 (executable)
index 0000000..37fa179
--- /dev/null
+++ b/configure
@@ -0,0 +1,1902 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13 
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+  --enable-check          Enable extra internal consistency checks (slow)"
+ac_help="$ac_help
+  --enable-profile        Enable code profiling"
+ac_help="$ac_help
+  --disable-user-check    Do not check for existance of dlife account"
+ac_help="$ac_help
+  --enable-cron[=layout]  Install cron script to run dlife net client
+                          'layout' may be 'auto' (default), 'standard',
+                          or a path to crontab directory starting with /
+  --disable-cron          Do not install cron script"
+ac_help="$ac_help
+  --enable-rc[=layout]    Install rc script (runs dlife_soup at boot)
+                          'layout' may be 'auto' (default), 'standard',
+                          or a path to local rc directory starting with /
+  --disable-rc            Do not install rc script"
+ac_help="$ac_help
+  --with-spool=DIR        Spool directory (default typically /var/spool/dlife)"
+ac_help="$ac_help
+  --with-conf=DIR         Config directory (default typically /etc/dlife)"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval "$ac_prev=\$ac_option"
+    ac_prev=
+    continue
+  fi
+
+  case "$ac_option" in
+  -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) ac_optarg= ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case "$ac_option" in
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir="$ac_optarg" ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build="$ac_optarg" ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file="$ac_optarg" ;;
+
+  -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+  | --da=*)
+    datadir="$ac_optarg" ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    eval "enable_${ac_feature}=no" ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix="$ac_optarg" ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he)
+    # Omit some internal or obsolete options to make the list less imposing.
+    # This message is too long to be a string in the A/UX 3.1 sh.
+    cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+  --cache-file=FILE       cache test results in FILE
+  --help                  print this message
+  --no-create             do not create output files
+  --quiet, --silent       do not print \`checking...' messages
+  --version               print the version of autoconf that created configure
+Directory and file names:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [same as prefix]
+  --bindir=DIR            user executables in DIR [EPREFIX/bin]
+  --sbindir=DIR           system admin executables in DIR [EPREFIX/sbin]
+  --libexecdir=DIR        program executables in DIR [EPREFIX/libexec]
+  --datadir=DIR           read-only architecture-independent data in DIR
+                          [PREFIX/share]
+  --sysconfdir=DIR        read-only single-machine data in DIR [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data in DIR
+                          [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data in DIR [PREFIX/var]
+  --libdir=DIR            object code libraries in DIR [EPREFIX/lib]
+  --includedir=DIR        C header files in DIR [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc in DIR [/usr/include]
+  --infodir=DIR           info documentation in DIR [PREFIX/info]
+  --mandir=DIR            man documentation in DIR [PREFIX/man]
+  --srcdir=DIR            find the sources in DIR [configure dir or ..]
+  --program-prefix=PREFIX prepend PREFIX to installed program names
+  --program-suffix=SUFFIX append SUFFIX to installed program names
+  --program-transform-name=PROGRAM
+                          run sed PROGRAM on installed program names
+EOF
+    cat << EOF
+Host type:
+  --build=BUILD           configure for building on BUILD [BUILD=HOST]
+  --host=HOST             configure for HOST [guessed]
+  --target=TARGET         configure for TARGET [TARGET=HOST]
+Features and packages:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --x-includes=DIR        X include files are in DIR
+  --x-libraries=DIR       X library files are in DIR
+EOF
+    if test -n "$ac_help"; then
+      echo "--enable and --with options recognized:$ac_help"
+    fi
+    exit 0 ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host="$ac_optarg" ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir="$ac_optarg" ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir="$ac_optarg" ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir="$ac_optarg" ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir="$ac_optarg" ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst \
+  | --locals | --local | --loca | --loc | --lo)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+  | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+    localstatedir="$ac_optarg" ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir="$ac_optarg" ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir="$ac_optarg" ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix="$ac_optarg" ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix="$ac_optarg" ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix="$ac_optarg" ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name="$ac_optarg" ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir="$ac_optarg" ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir="$ac_optarg" ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site="$ac_optarg" ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir="$ac_optarg" ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir="$ac_optarg" ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target="$ac_optarg" ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers)
+    echo "configure generated by autoconf version 2.13"
+    exit 0 ;;
+
+  -with-* | --with-*)
+    ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "with_${ac_package}='$ac_optarg'" ;;
+
+  -without-* | --without-*)
+    ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    eval "with_${ac_package}=no" ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes="$ac_optarg" ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries="$ac_optarg" ;;
+
+  -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+    ;;
+
+  *)
+    if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+      echo "configure: warning: $ac_option: invalid host type" 1>&2
+    fi
+    if test "x$nonopt" != xNONE; then
+      { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+    fi
+    nonopt="$ac_option"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+  exec 6>/dev/null
+else
+  exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+  case "$ac_arg" in
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c) ;;
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+  *" "*|*"     "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+  ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+  *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+  esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set.  These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}"    = set; then LC_CTYPE=C;    export LC_CTYPE;    fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=cell.c
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then its parent.
+  ac_prog=$0
+  ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+  test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+  srcdir=$ac_confdir
+  if test ! -r $srcdir/$ac_unique_file; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+  if test "$ac_srcdir_defaulted" = yes; then
+    { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+  else
+    { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+  fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+  if test "x$prefix" != xNONE; then
+    CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+  else
+    CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+  fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+  if test -r "$ac_site_file"; then
+    echo "loading site script $ac_site_file"
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  echo "loading cache $cache_file"
+  . $cache_file
+else
+  echo "creating cache $cache_file"
+  > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+  # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+  if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+    ac_n= ac_c='
+' ac_t='       '
+  else
+    ac_n=-n ac_c= ac_t=
+  fi
+else
+  ac_n= ac_c='\c' ac_t=
+fi
+
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+  if test -f $ac_dir/install-sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f $ac_dir/install.sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+am__api_version="1.4"
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:577: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    IFS="${IFS=        }"; ac_save_IFS="$IFS"; IFS=":"
+  for ac_dir in $PATH; do
+    # Account for people who put trailing slashes in PATH elements.
+    case "$ac_dir/" in
+    /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+    *)
+      # OSF1 and SCO ODT 3.0 have their own names for install.
+      # Don't use installbsd from OSF since it installs stuff as root
+      # by default.
+      for ac_prog in ginstall scoinst install; do
+        if test -f $ac_dir/$ac_prog; then
+         if test $ac_prog = install &&
+            grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+           # AIX install.  It has an incompatible calling convention.
+           :
+         else
+           ac_cv_path_install="$ac_dir/$ac_prog -c"
+           break 2
+         fi
+       fi
+      done
+      ;;
+    esac
+  done
+  IFS="$ac_save_IFS"
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL="$ac_cv_path_install"
+  else
+    # As a last resort, use the slow shell script.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    INSTALL="$ac_install_sh"
+  fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6
+echo "configure:630: checking whether build environment is sane" >&5
+# Just in case
+sleep 1
+echo timestamp > conftestfile
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
+   if test "$*" = "X"; then
+      # -L didn't work.
+      set X `ls -t $srcdir/configure conftestfile`
+   fi
+   if test "$*" != "X $srcdir/configure conftestfile" \
+      && test "$*" != "X conftestfile $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      { echo "configure: error: ls -t appears to fail.  Make sure there is not a broken
+alias in your environment" 1>&2; exit 1; }
+   fi
+
+   test "$2" = conftestfile
+   )
+then
+   # Ok.
+   :
+else
+   { echo "configure: error: newly created file is older than distributed files!
+Check your system clock" 1>&2; exit 1; }
+fi
+rm -f conftest*
+echo "$ac_t""yes" 1>&6
+if test "$program_transform_name" = s,x,x,; then
+  program_transform_name=
+else
+  # Double any \ or $.  echo might interpret backslashes.
+  cat <<\EOF_SED > conftestsed
+s,\\,\\\\,g; s,\$,$$,g
+EOF_SED
+  program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
+  rm -f conftestsed
+fi
+test "$program_prefix" != NONE &&
+  program_transform_name="s,^,${program_prefix},; $program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+  program_transform_name="s,\$\$,${program_suffix},; $program_transform_name"
+
+# sed with no file args requires a program.
+test "$program_transform_name" = "" && program_transform_name="s,x,x,"
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:687: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftestmake <<\EOF
+all:
+       @echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+  eval ac_cv_prog_make_${ac_make}_set=yes
+else
+  eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  SET_MAKE=
+else
+  echo "$ac_t""no" 1>&6
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+
+PACKAGE=dlife
+
+VERSION=1.0.0
+
+if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
+  { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; }
+fi
+cat >> confdefs.h <<EOF
+#define PACKAGE "$PACKAGE"
+EOF
+
+cat >> confdefs.h <<EOF
+#define VERSION "$VERSION"
+EOF
+
+
+
+missing_dir=`cd $ac_aux_dir && pwd`
+echo $ac_n "checking for working aclocal-${am__api_version}""... $ac_c" 1>&6
+echo "configure:733: checking for working aclocal-${am__api_version}" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (aclocal-${am__api_version} --version) < /dev/null > /dev/null 2>&1; then
+   ACLOCAL=aclocal-${am__api_version}
+   echo "$ac_t""found" 1>&6
+else
+   ACLOCAL="$missing_dir/missing aclocal-${am__api_version}"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working autoconf""... $ac_c" 1>&6
+echo "configure:746: checking for working autoconf" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (autoconf --version) < /dev/null > /dev/null 2>&1; then
+   AUTOCONF=autoconf
+   echo "$ac_t""found" 1>&6
+else
+   AUTOCONF="$missing_dir/missing autoconf"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working automake-${am__api_version}""... $ac_c" 1>&6
+echo "configure:759: checking for working automake-${am__api_version}" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (automake-${am__api_version} --version) < /dev/null > /dev/null 2>&1; then
+   AUTOMAKE=automake-${am__api_version}
+   echo "$ac_t""found" 1>&6
+else
+   AUTOMAKE="$missing_dir/missing automake-${am__api_version}"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working autoheader""... $ac_c" 1>&6
+echo "configure:772: checking for working autoheader" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (autoheader --version) < /dev/null > /dev/null 2>&1; then
+   AUTOHEADER=autoheader
+   echo "$ac_t""found" 1>&6
+else
+   AUTOHEADER="$missing_dir/missing autoheader"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6
+echo "configure:785: checking for working makeinfo" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (makeinfo --version) < /dev/null > /dev/null 2>&1; then
+   MAKEINFO=makeinfo
+   echo "$ac_t""found" 1>&6
+else
+   MAKEINFO="$missing_dir/missing makeinfo"
+   echo "$ac_t""missing" 1>&6
+fi
+
+
+
+
+
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:805: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="gcc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:835: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_prog_rejected=no
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+        ac_prog_rejected=yes
+       continue
+      fi
+      ac_cv_prog_CC="cc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# -gt 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    set dummy "$ac_dir/$ac_word" "$@"
+    shift
+    ac_cv_prog_CC="$@"
+  fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+  if test -z "$CC"; then
+    case "`uname -s`" in
+    *win32* | *WIN32*)
+      # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:886: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="cl"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+ ;;
+    esac
+  fi
+  test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:918: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 929 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:934: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  ac_cv_prog_cc_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cc_cross=no
+  else
+    ac_cv_prog_cc_cross=yes
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+  { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:960: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:965: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.c <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:974: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gcc=yes
+else
+  ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:993: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+  ac_cv_prog_cc_g=yes
+else
+  ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:1036: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    IFS="${IFS=        }"; ac_save_IFS="$IFS"; IFS=":"
+  for ac_dir in $PATH; do
+    # Account for people who put trailing slashes in PATH elements.
+    case "$ac_dir/" in
+    /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+    *)
+      # OSF1 and SCO ODT 3.0 have their own names for install.
+      # Don't use installbsd from OSF since it installs stuff as root
+      # by default.
+      for ac_prog in ginstall scoinst install; do
+        if test -f $ac_dir/$ac_prog; then
+         if test $ac_prog = install &&
+            grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+           # AIX install.  It has an incompatible calling convention.
+           :
+         else
+           ac_cv_path_install="$ac_dir/$ac_prog -c"
+           break 2
+         fi
+       fi
+      done
+      ;;
+    esac
+  done
+  IFS="$ac_save_IFS"
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL="$ac_cv_path_install"
+  else
+    # As a last resort, use the slow shell script.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    INSTALL="$ac_install_sh"
+  fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:1089: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftestmake <<\EOF
+all:
+       @echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+  eval ac_cv_prog_make_${ac_make}_set=yes
+else
+  eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  SET_MAKE=
+else
+  echo "$ac_t""no" 1>&6
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+
+if test "$CC" = "gcc"; then
+       CFLAGS="$CFLAGS -Wall -Werror"
+fi
+
+# Check whether --enable-check or --disable-check was given.
+if test "${enable_check+set}" = set; then
+  enableval="$enable_check"
+  CFLAGS="$CFLAGS -DCHECK=1"
+
+fi
+
+
+# Check whether --enable-profile or --disable-profile was given.
+if test "${enable_profile+set}" = set; then
+  enableval="$enable_profile"
+  CFLAGS="$CFLAGS -pg"
+
+fi
+
+
+# Check whether --enable-user-check or --disable-user-check was given.
+if test "${enable_user_check+set}" = set; then
+  enableval="$enable_user_check"
+  user_check="no"
+else
+  user_check="yes"
+
+fi
+
+
+# Check whether --enable-cron or --disable-cron was given.
+if test "${enable_cron+set}" = set; then
+  enableval="$enable_cron"
+  install_cron="$enableval"
+else
+  install_cron="yes"
+
+fi
+
+
+# Check whether --enable-rc or --disable-rc was given.
+if test "${enable_rc+set}" = set; then
+  enableval="$enable_rc"
+  install_rc="$enableval"
+else
+  install_rc="yes"
+
+fi
+
+
+# Check whether --with-spool or --without-spool was given.
+if test "${with_spool+set}" = set; then
+  withval="$with_spool"
+  SPOOLDIR="$withval"
+else
+  FC_EXPAND_DIR(SPOOLDIR, '${localstatedir}/spool/dlife')
+
+fi
+
+
+# Check whether --with-conf or --without-conf was given.
+if test "${with_conf+set}" = set; then
+  withval="$with_conf"
+  CONFDIR="$withval"
+else
+  FC_EXPAND_DIR(CONFDIR, '${sysconfdir}/dlife')
+
+fi
+
+
+if test "$user_check" = "yes"; then
+       echo $ac_n "checking for dlife group""... $ac_c" 1>&6
+echo "configure:1188: checking for dlife group" >&5
+       if ! grep '^dlife:' /etc/group >/dev/null; then
+               { echo "configure: error: there is no 'dlife' group in /etc/group" 1>&2; exit 1; }
+       fi
+       echo "$ac_t""found" 1>&6
+
+       echo $ac_n "checking for dlife user""... $ac_c" 1>&6
+echo "configure:1195: checking for dlife user" >&5
+       if ! grep '^dlife:' /etc/passwd >/dev/null; then
+               { echo "configure: error: there is no 'dlife' user in /etc/passwd" 1>&2; exit 1; }
+       fi
+       echo "$ac_t""found" 1>&6
+fi
+
+for ac_func in \
+       closedir \
+       getpwnam \
+       getuid \
+       initgroups \
+       nice \
+       opendir \
+       openlog \
+       readdir \
+       setgid \
+       setuid \
+       syslog \
+       
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:1217: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1222 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1245: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:1271: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    # This must be in double quotes, not single quotes, because CPP may get
+  # substituted into the Makefile and "${CC-cc}" will confuse make.
+  CPP="${CC-cc} -E"
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp.
+  cat > conftest.$ac_ext <<EOF
+#line 1286 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1292: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -E -traditional-cpp"
+  cat > conftest.$ac_ext <<EOF
+#line 1303 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1309: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -nologo -E"
+  cat > conftest.$ac_ext <<EOF
+#line 1320 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1326: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+  ac_cv_prog_CPP="$CPP"
+fi
+  CPP="$ac_cv_prog_CPP"
+else
+  ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+for ac_hdr in \
+       assert.h \
+       dirent.h \
+       errno.h \
+       fcntl.h \
+       grp.h \
+       pwd.h \
+       signal.h \
+       stddef.h \
+       stdint.h \
+       string.h \
+       sys/param.h \
+       sys/types.h \
+       syslog.h \
+       time.h \
+       unistd.h \
+       
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1370: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1375 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1380: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+
+
+echo $ac_n "checking crontab directory""... $ac_c" 1>&6
+echo "configure:1409: checking crontab directory" >&5
+
+case "$install_cron" in
+yes|auto)
+       if test -d $sysconfdir/cron.d; then
+               install_cron=$sysconfdir/cron.d
+       else
+               { echo "configure: error: failed to find a directory to put crontabs in; try --help" 1>&2; exit 1; }
+       fi
+       ;;
+standard)
+       install_cron=/etc/cron.d
+       ;;
+/*)
+               ;;
+no)
+               ;;
+*)
+       { echo "configure: error: unknown parameter given to --enable-cron" 1>&2; exit 1; }
+       ;;
+esac
+
+echo "$ac_t""$install_cron" 1>&6
+CRONDIR=$install_cron
+
+
+
+if test "$install_cron" != "no"; then
+  INSTALL_CRON_TRUE=
+  INSTALL_CRON_FALSE='#'
+else
+  INSTALL_CRON_TRUE='#'
+  INSTALL_CRON_FALSE=
+fi
+
+
+echo $ac_n "checking rc directory""... $ac_c" 1>&6
+echo "configure:1446: checking rc directory" >&5
+
+case "$install_rc" in
+yes|auto)
+       if test -d $sysconfdir/init.d; then
+               install_rc=$sysconfdir/init.d
+       else
+               { echo "configure: error: failed to find a directory to put rc scripts in; try --help" 1>&2; exit 1; }
+       fi
+       ;;
+standard)
+       install_rc=/etc/init.d
+       ;;
+/*)
+               ;;
+no)
+               ;;
+*)
+       { echo "configure: error: unknown parameter given to --enable-rc" 1>&2; exit 1; }
+       ;;
+esac
+
+echo "$ac_t""$install_rc" 1>&6
+RCDIR=$install_rc
+
+
+
+if test "$install_rc" != "no"; then
+  INSTALL_RC_TRUE=
+  INSTALL_RC_FALSE='#'
+else
+  INSTALL_RC_TRUE='#'
+  INSTALL_RC_FALSE=
+fi
+
+echo $ac_n "checking spool directory""... $ac_c" 1>&6
+echo "configure:1482: checking spool directory" >&5
+echo "$ac_t""$SPOOLDIR" 1>&6
+
+echo $ac_n "checking config directory""... $ac_c" 1>&6
+echo "configure:1486: checking config directory" >&5
+echo "$ac_t""$CONFDIR" 1>&6
+
+echo $ac_n "checking for a place to install documentation""... $ac_c" 1>&6
+echo "configure:1490: checking for a place to install documentation" >&5
+if test -d $prefix/share/doc; then
+        DOCDIR=$prefix/share/doc/$PACKAGE-$VERSION
+else
+        DOCDIR=/tmp
+fi
+echo "$ac_t""$DOCDIR" 1>&6
+
+RELEASEDATE=`date +"%d %b %Y"`
+
+
+
+
+
+
+
+
+cat >> confdefs.h <<EOF
+#define SPOOLDIR "$SPOOLDIR"
+EOF
+
+cat >> confdefs.h <<EOF
+#define CONFDIR "$CONFDIR"
+EOF
+
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs.  It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already.  You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+  case `(ac_space=' '; set | grep ac_space) 2>&1` in
+  *ac_space=\ *)
+    # `set' does not quote correctly, so add quotes (double-quote substitution
+    # turns \\\\ into \\, and sed turns \\ into \).
+    sed -n \
+      -e "s/'/'\\\\''/g" \
+      -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+    ;;
+  *)
+    # `set' quotes correctly as required by POSIX, so do not add quotes.
+    sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+    ;;
+  esac >> confcache
+if cmp -s $cache_file confcache; then
+  :
+else
+  if test -w $cache_file; then
+    echo "updating cache $cache_file"
+    cat confcache > $cache_file
+  else
+    echo "not updating unwritable cache $cache_file"
+  fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[        ]*VPATH[        ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+  case "\$ac_option" in
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+    exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+  -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+    echo "$CONFIG_STATUS generated by autoconf version 2.13"
+    exit 0 ;;
+  -help | --help | --hel | --he | --h)
+    echo "\$ac_cs_usage"; exit 0 ;;
+  *) echo "\$ac_cs_usage"; exit 1 ;;
+  esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "
+       Makefile
+       dlife_client.pl
+       dlife_server.pl
+       dlife.spec
+       index.html
+        config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@PACKAGE@%$PACKAGE%g
+s%@VERSION@%$VERSION%g
+s%@ACLOCAL@%$ACLOCAL%g
+s%@AUTOCONF@%$AUTOCONF%g
+s%@AUTOMAKE@%$AUTOMAKE%g
+s%@AUTOHEADER@%$AUTOHEADER%g
+s%@MAKEINFO@%$MAKEINFO%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@CC@%$CC%g
+s%@CPP@%$CPP%g
+s%@INSTALL_CRON_TRUE@%$INSTALL_CRON_TRUE%g
+s%@INSTALL_CRON_FALSE@%$INSTALL_CRON_FALSE%g
+s%@INSTALL_RC_TRUE@%$INSTALL_RC_TRUE%g
+s%@INSTALL_RC_FALSE@%$INSTALL_RC_FALSE%g
+s%@CRONDIR@%$CRONDIR%g
+s%@RCDIR@%$RCDIR%g
+s%@SPOOLDIR@%$SPOOLDIR%g
+s%@CONFDIR@%$CONFDIR%g
+s%@DOCDIR@%$DOCDIR%g
+s%@RELEASEDATE@%$RELEASEDATE%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+  if test $ac_beg -gt 1; then
+    sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+  else
+    sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+  fi
+  if test ! -s conftest.s$ac_file; then
+    ac_more_lines=false
+    rm -f conftest.s$ac_file
+  else
+    if test -z "$ac_sed_cmds"; then
+      ac_sed_cmds="sed -f conftest.s$ac_file"
+    else
+      ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+    fi
+    ac_file=`expr $ac_file + 1`
+    ac_beg=$ac_end
+    ac_end=`expr $ac_end + $ac_max_sed_cmds`
+  fi
+done
+if test -z "$ac_sed_cmds"; then
+  ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile
+       dlife_client.pl
+       dlife_server.pl
+       dlife.spec
+       index.html
+       "}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+  # Remove last slash and all that follows it.  Not all systems have dirname.
+  ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+  if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+    # The file is in a subdirectory.
+    test ! -d "$ac_dir" && mkdir "$ac_dir"
+    ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+    # A "../" for each directory in $ac_dir_suffix.
+    ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+  else
+    ac_dir_suffix= ac_dots=
+  fi
+
+  case "$ac_given_srcdir" in
+  .)  srcdir=.
+      if test -z "$ac_dots"; then top_srcdir=.
+      else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+  /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+  *) # Relative path.
+    srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+    top_srcdir="$ac_dots$ac_given_srcdir" ;;
+  esac
+
+  case "$ac_given_INSTALL" in
+  [/$]*) INSTALL="$ac_given_INSTALL" ;;
+  *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+  esac
+
+  echo creating "$ac_file"
+  rm -f "$ac_file"
+  configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+  case "$ac_file" in
+  *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+  *) ac_comsub= ;;
+  esac
+
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([  ]*\)#\([        ]*define[       ][      ]*\)'
+ac_dB='\([     ][      ]*\)[^  ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([  ]*\)#\([        ]*\)undef\([    ][      ]*\)'
+ac_uB='\([     ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([  ]*\)#\([        ]*\)undef\([    ][      ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+  CONFIG_HEADERS="config.h"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  echo creating $ac_file
+
+  rm -f conftest.frag conftest.in conftest.out
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h.  And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments.  This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[   ]*#[    ]*undef[        ][      ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+  ac_lines=`grep -c . conftest.vals`
+  # grep -c gives empty output for an empty file on some AIX systems.
+  if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+  # Write a limited-size here document to conftest.frag.
+  echo '  cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+  sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+  echo 'CEOF
+  sed -f conftest.frag conftest.in > conftest.out
+  rm -f conftest.in
+  mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+  sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+  rm -f conftest.vals
+  mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+  rm -f conftest.frag conftest.h
+  echo "/* $ac_file.  Generated automatically by configure.  */" > conftest.h
+  cat conftest.in >> conftest.h
+  rm -f conftest.in
+  if cmp -s $ac_file conftest.h 2>/dev/null; then
+    echo "$ac_file is unchanged"
+    rm -f conftest.h
+  else
+    # Remove last slash and all that follows it.  Not all systems have dirname.
+      ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+      if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+      # The file is in a subdirectory.
+      test ! -d "$ac_dir" && mkdir "$ac_dir"
+    fi
+    rm -f $ac_file
+    mv conftest.h $ac_file
+  fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
diff --git a/configure.in b/configure.in
new file mode 100644 (file)
index 0000000..25b6ac0
--- /dev/null
@@ -0,0 +1,252 @@
+# DLIFE (C) 2000 Richard W.M. Jones <rich@annexia.org>
+# and other authors listed in the ``AUTHORS'' file.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+# $Id: configure.in,v 1.3 2002/04/05 17:02:25 rich Exp $
+
+AC_INIT(cell.c)
+AM_INIT_AUTOMAKE(dlife, 1.0.0)
+AM_CONFIG_HEADER(config.h)
+
+dnl Check for the basic compile environment.
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_MAKE_SET
+
+dnl Enable compiler warnings.
+if test "$CC" = "gcc"; then
+       CFLAGS="$CFLAGS -Wall -Werror"
+fi
+
+dnl Check for arguments to configure.
+AC_ARG_ENABLE(
+  check,
+  [  --enable-check          Enable extra internal consistency checks (slow)],
+  CFLAGS="$CFLAGS -DCHECK=1"
+)
+
+AC_ARG_ENABLE(
+  profile,
+  [  --enable-profile        Enable code profiling],
+  CFLAGS="$CFLAGS -pg"
+)
+
+AC_ARG_ENABLE(
+  user-check,
+  [  --disable-user-check    Do not check for existance of dlife account],
+  user_check="no",
+  user_check="yes"
+)
+
+AC_ARG_ENABLE(
+  cron,
+  [  --enable-cron[=layout]  Install cron script to run dlife net client
+                          'layout' may be 'auto' (default), 'standard',
+                          or a path to crontab directory starting with /
+  --disable-cron          Do not install cron script],
+  install_cron="$enableval",
+  install_cron="yes"
+)
+
+AC_ARG_ENABLE(
+  rc,
+  [  --enable-rc[=layout]    Install rc script (runs dlife_soup at boot)
+                          'layout' may be 'auto' (default), 'standard',
+                          or a path to local rc directory starting with /
+  --disable-rc            Do not install rc script],
+  install_rc="$enableval",
+  install_rc="yes"
+)
+
+AC_ARG_WITH(
+  spool,
+  [  --with-spool=DIR        Spool directory (default typically /var/spool/dlife)],
+  SPOOLDIR="$withval",
+  FC_EXPAND_DIR(SPOOLDIR, '${localstatedir}/spool/dlife')
+)
+
+AC_ARG_WITH(
+  conf,
+  [  --with-conf=DIR         Config directory (default typically /etc/dlife)],
+  CONFDIR="$withval",
+  FC_EXPAND_DIR(CONFDIR, '${sysconfdir}/dlife')
+)
+
+dnl Check for ``dlife'' account.
+if test "$user_check" = "yes"; then
+       AC_MSG_CHECKING([for dlife group])
+       if ! grep '^dlife:' /etc/group >/dev/null; then
+               AC_MSG_ERROR([there is no 'dlife' group in /etc/group])
+       fi
+       AC_MSG_RESULT([found])
+
+       AC_MSG_CHECKING([for dlife user])
+       if ! grep '^dlife:' /etc/passwd >/dev/null; then
+               AC_MSG_ERROR([there is no 'dlife' user in /etc/passwd])
+       fi
+       AC_MSG_RESULT([found])
+fi
+
+dnl Check for available functions.
+AC_CHECK_FUNCS( \
+       closedir \
+       getpwnam \
+       getuid \
+       initgroups \
+       nice \
+       opendir \
+       openlog \
+       readdir \
+       setgid \
+       setuid \
+       syslog \
+       )
+
+dnl Check for header files.
+AC_CHECK_HEADERS( \
+       assert.h \
+       dirent.h \
+       errno.h \
+       fcntl.h \
+       grp.h \
+       pwd.h \
+       signal.h \
+       stddef.h \
+       stdint.h \
+       string.h \
+       sys/param.h \
+       sys/types.h \
+       syslog.h \
+       time.h \
+       unistd.h \
+       )
+
+dnl Check for a place to install the crontab.
+dnl The $install_cron variable will have one of the following possible
+dnl values:
+dnl   yes / auto      Try to determine cron dir by automatic means
+dnl   no              Do not install crontab
+dnl   standard        Use FSSTND layout (/etc/cron.d)
+dnl   /path/to/dir/   Use given directory
+dnl After this, $install_cron will contain either a path (beginning
+dnl with /) or "no".
+
+AC_MSG_CHECKING([crontab directory])
+
+case "$install_cron" in
+yes|auto)
+       if test -d $sysconfdir/cron.d; then
+               install_cron=$sysconfdir/cron.d
+       else
+               AC_MSG_ERROR([failed to find a directory to put crontabs in; try --help])
+       fi
+       ;;
+standard)
+       install_cron=/etc/cron.d
+       ;;
+/*)
+       dnl Do nothing.
+       ;;
+no)
+       dnl Do nothing.
+       ;;
+*)
+       AC_MSG_ERROR([unknown parameter given to --enable-cron])
+       ;;
+esac
+
+AC_MSG_RESULT($install_cron)
+CRONDIR=$install_cron
+
+AM_CONDITIONAL(INSTALL_CRON,[test "$install_cron" != "no"])
+
+dnl Check for a place to install rc scripts
+dnl The $install_rc variable will have one of the following possible
+dnl values:
+dnl   yes / auto      Try to determine rc dir by automatic means
+dnl   no              Do not install rc script
+dnl   standard        Use red hat / debian / FSSTND layout (/etc/init.d)
+dnl   /path/to/dir/   Use given directory
+dnl After this, $install_rc will contain either a path (beginning
+dnl with /) or "no".
+
+AC_MSG_CHECKING([rc directory])
+
+case "$install_rc" in
+yes|auto)
+       if test -d $sysconfdir/init.d; then
+               install_rc=$sysconfdir/init.d
+       else
+               AC_MSG_ERROR([failed to find a directory to put rc scripts in; try --help])
+       fi
+       ;;
+standard)
+       install_rc=/etc/init.d
+       ;;
+/*)
+       dnl Do nothing.
+       ;;
+no)
+       dnl Do nothing.
+       ;;
+*)
+       AC_MSG_ERROR([unknown parameter given to --enable-rc])
+       ;;
+esac
+
+AC_MSG_RESULT($install_rc)
+RCDIR=$install_rc
+
+AM_CONDITIONAL(INSTALL_RC,[test "$install_rc" != "no"])
+
+AC_MSG_CHECKING([spool directory])
+AC_MSG_RESULT($SPOOLDIR)
+
+AC_MSG_CHECKING([config directory])
+AC_MSG_RESULT($CONFDIR)
+
+dnl Check for a place to install documentation.
+AC_MSG_CHECKING([for a place to install documentation])
+if test -d $prefix/share/doc; then
+        DOCDIR=$prefix/share/doc/$PACKAGE-$VERSION
+else
+        DOCDIR=/tmp
+fi
+AC_MSG_RESULT($DOCDIR)
+
+dnl Release date.
+RELEASEDATE=`date +"%d %b %Y"`
+
+dnl Variables to be substituted.
+AC_SUBST(CRONDIR)
+AC_SUBST(RCDIR)
+AC_SUBST(SPOOLDIR)
+AC_SUBST(CONFDIR)
+AC_SUBST(DOCDIR)
+AC_SUBST(RELEASEDATE)
+
+dnl Variables to be placed in config.h.
+AC_DEFINE_UNQUOTED(SPOOLDIR, "$SPOOLDIR")
+AC_DEFINE_UNQUOTED(CONFDIR, "$CONFDIR")
+
+dnl Generate output files.
+AC_OUTPUT([
+       Makefile
+       dlife_client.pl
+       dlife_server.pl
+       dlife.spec
+       index.html
+       ])
diff --git a/crc.c b/crc.c
new file mode 100644 (file)
index 0000000..4694400
--- /dev/null
+++ b/crc.c
@@ -0,0 +1,142 @@
+/* DLIFE Copyright (C) 2000 Richard W.M. Jones <rich@annexia.org>
+ * and other authors listed in the ``AUTHORS'' file.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * $Id: crc.c,v 1.1 2002/04/05 14:40:25 rich Exp $
+ */
+
+#include "config.h"
+
+#include "crc.h"
+
+/* Code to do 32-bit CRCs.
+ * Derived from code by Julian Seward (sewardj@cs.man.ac.uk)
+ * Written by Richard W.M. Jones (rich@annexia.org)
+ * Note original copyright messages below ...
+ */
+
+/*--
+  Copyright (C) 1996 by Julian Seward.
+     Department of Computer Science, University of Manchester,
+     Oxford Road, Manchester M13 9PL, UK.
+     email: sewardj@cs.man.ac.uk
+--*/
+
+/*---------------------------------------------------*/
+/*--- 32-bit CRC grunge                           ---*/
+/*---------------------------------------------------*/
+
+/*--
+  I think this is an implementation of the AUTODIN-II,
+  Ethernet & FDDI 32-bit CRC standard.  Vaguely derived
+  from code by Rob Warnock, in Section 51 of the 
+  comp.compression FAQ.
+--*/
+
+static crc_t crc32Table[256] = {
+
+   /*-- Ugly, innit? --*/
+
+   0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L,
+   0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L,
+   0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L,
+   0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL,
+   0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L,
+   0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L,
+   0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L,
+   0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL,
+   0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L,
+   0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L,
+   0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L,
+   0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL,
+   0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L,
+   0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L,
+   0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L,
+   0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL,
+   0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL,
+   0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L,
+   0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L,
+   0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL,
+   0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL,
+   0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L,
+   0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L,
+   0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL,
+   0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL,
+   0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L,
+   0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L,
+   0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL,
+   0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL,
+   0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L,
+   0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L,
+   0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL,
+   0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L,
+   0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL,
+   0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL,
+   0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L,
+   0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L,
+   0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL,
+   0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL,
+   0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L,
+   0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L,
+   0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL,
+   0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL,
+   0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L,
+   0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L,
+   0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL,
+   0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL,
+   0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L,
+   0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L,
+   0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL,
+   0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L,
+   0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L,
+   0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L,
+   0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL,
+   0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L,
+   0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L,
+   0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L,
+   0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL,
+   0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L,
+   0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L,
+   0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L,
+   0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL,
+   0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L,
+   0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L
+};
+
+#define UPDATE_CRC(crcVar,cha)                 \
+{                                              \
+   crcVar = (crcVar << 8) ^                    \
+            crc32Table[(crcVar >> 24) ^        \
+                       (cha)];                 \
+}
+
+inline crc_t
+incr_compute_crc32 (crc_t crc, byte_t *p, size_t len)
+{
+  while (len)
+    {
+      UPDATE_CRC (crc, *p);
+      p ++;
+      len --;
+    }
+  return crc;
+}
+
+crc_t
+compute_crc32 (byte_t *p, size_t len)
+{
+  return incr_compute_crc32 (0xffffffffUL, p, len);
+}
diff --git a/crc.h b/crc.h
new file mode 100644 (file)
index 0000000..08db92b
--- /dev/null
+++ b/crc.h
@@ -0,0 +1,33 @@
+/* DLIFE Copyright (C) 2000 Richard W.M. Jones <rich@annexia.org>
+ * and other authors listed in the ``AUTHORS'' file.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * $Id: crc.h,v 1.1 2002/04/05 14:40:26 rich Exp $
+ */
+
+#ifndef crc_h
+#define crc_h
+
+#include <stdlib.h>
+
+#include "types.h"
+
+typedef uint32_t crc_t;
+
+extern crc_t compute_crc32 (byte_t *p, size_t len);
+extern crc_t incr_compute_crc32 (crc_t old_crc, byte_t *p, size_t len);
+
+#endif /* crc_h */
diff --git a/debian/changelog b/debian/changelog
new file mode 100644 (file)
index 0000000..55a81db
--- /dev/null
@@ -0,0 +1,9 @@
+dlife (0.0.15-1) unstable; urgency=low
+
+  * Initial Release.
+
+ -- Falk Hueffner <falk@debian.org>  Fri, 13 Oct 2000 05:49:22 +0200
+
+Local variables:
+mode: debian-changelog
+End:
diff --git a/debian/conffiles b/debian/conffiles
new file mode 100644 (file)
index 0000000..94fdfa9
--- /dev/null
@@ -0,0 +1,4 @@
+/etc/init.d/dlife
+/etc/dlife/client.conf
+/etc/dlife/soup.conf
+/etc/ppp/ip-up.d/9dlife
diff --git a/debian/control b/debian/control
new file mode 100644 (file)
index 0000000..b833da7
--- /dev/null
@@ -0,0 +1,24 @@
+Source: dlife
+Section: misc
+Priority: optional
+Maintainer: Falk Hueffner <falk@debian.org>
+Standards-Version: 3.0.1
+
+Package: dlife
+Architecture: any
+Depends: ${shlibs:Depends}, perl5, libnet-perl, libhtml-parser-perl, liburi-perl, libmime-base64-perl, libdigest-md5-perl, libwww-perl
+Description: Distributed Artificial Life client
+ DLIFE is a distributed version of Tom S. Ray's Tierra artificial life
+ program. Note that the machine language used is similar to but not
+ compatible with Tierra. Tom Ray talks about his work (as far as I
+ know, never completed) to create a ``Digital Reserve''. The DLIFE
+ project is a development of this.
+ .
+ In other words, it's an alternative to the tedious process of cracking
+ RC5 keys or searching for aliens. You've got a supercomputer on your
+ desk, let's go and create some life ...
+ .
+ It consists of a highly optimized engine for running the artificial
+ life cells in a virtual machine, written in C, and some Perl scripts
+ which can upload and download cells from central ``cell-bank''
+ servers.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644 (file)
index 0000000..022b670
--- /dev/null
@@ -0,0 +1,11 @@
+Distributed Artificial Life was debianized by Falk Hüffner
+<falk@debian.org>.
+
+It was originally downloaded from <fill in ftp site>. There's a web
+site for it at http://dlife.annexia.org/.
+
+The copyright belongs to its author Richard W.M. Jones
+<rich@annexia.org>.
+
+It is distributed under the terms of the GNU Public License. The full
+text can be found on Debian systems in /usr/share/common-licenses/GPL.
diff --git a/debian/cron.d b/debian/cron.d
new file mode 100644 (file)
index 0000000..bd3cf16
--- /dev/null
@@ -0,0 +1,2 @@
+# Run the client to upload cells periodically.
+5      *       *       *       *       dlife   /usr/bin/dlife_client.pl
diff --git a/debian/dirs b/debian/dirs
new file mode 100644 (file)
index 0000000..e27bc8b
--- /dev/null
@@ -0,0 +1,3 @@
+usr/bin
+usr/sbin
+etc/ppp/ip-up.d
diff --git a/debian/docs b/debian/docs
new file mode 100644 (file)
index 0000000..3c9ddd2
--- /dev/null
@@ -0,0 +1,7 @@
+AUTHORS
+README
+archproc.gif
+archref.html
+index.html
+machineref.html
+servers.txt
diff --git a/debian/files b/debian/files
new file mode 100644 (file)
index 0000000..2596e77
--- /dev/null
@@ -0,0 +1 @@
+dlife_0.0.12-1_alpha.deb misc optional
diff --git a/debian/init.d b/debian/init.d
new file mode 100644 (file)
index 0000000..2bc0fa6
--- /dev/null
@@ -0,0 +1,42 @@
+#! /bin/sh
+#
+# adapted from the dh_make template by Falk Hueffner <falk@debian.org>
+#
+# using a pidfile doesn't work unfortunately, since dlife_soup forks
+#
+
+PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
+DAEMON=/usr/bin/dlife_soup
+NAME=dlife
+DESC='distributed artificial life client'
+
+test -f $DAEMON || exit 0
+
+set -e
+
+case "$1" in
+  start)
+       echo -n "Starting $DESC: "
+       start-stop-daemon --start --quiet --exec $DAEMON
+       echo "$NAME."
+       ;;
+  stop)
+       echo -n "Stopping $DESC: "
+       start-stop-daemon --stop --quiet --exec $DAEMON
+       echo "$NAME."
+       ;;
+  restart|force-reload)
+       echo -n "Restarting $DESC: "
+       start-stop-daemon --stop --quiet --exec $DAEMON
+       sleep 1
+       start-stop-daemon --start --quiet --exec $DAEMON
+       echo "$NAME."
+       ;;
+  *)
+       N=/etc/init.d/$NAME
+       echo "Usage: $N {start|stop|restart|force-reload}" >&2
+       exit 1
+       ;;
+esac
+
+exit 0
diff --git a/debian/postinst.debhelper b/debian/postinst.debhelper
new file mode 100644 (file)
index 0000000..6d6c912
--- /dev/null
@@ -0,0 +1,11 @@
+# Automatically added by dh_installdocs
+if [ "$1" = "configure" ]; then
+       if [ -d /usr/doc -a ! -e /usr/doc/dlife -a -d /usr/share/doc/dlife ]; then
+               ln -sf ../share/doc/dlife /usr/doc/dlife
+       fi
+fi
+# End automatically added section
+# Automatically added by dh_installinit
+update-rc.d dlife defaults >/dev/null
+/etc/init.d/dlife start
+# End automatically added section
diff --git a/debian/postrm.debhelper b/debian/postrm.debhelper
new file mode 100644 (file)
index 0000000..a7d2004
--- /dev/null
@@ -0,0 +1,5 @@
+# Automatically added by dh_installinit
+if [ "$1" = "purge" ] ; then
+       update-rc.d dlife remove >/dev/null
+fi
+# End automatically added section
diff --git a/debian/prerm.debhelper b/debian/prerm.debhelper
new file mode 100644 (file)
index 0000000..ad508d3
--- /dev/null
@@ -0,0 +1,8 @@
+# Automatically added by dh_installdocs
+if [ \( "$1" = "upgrade" -o "$1" = "remove" \) -a -L /usr/doc/dlife ]; then
+       rm -f /usr/doc/dlife
+fi
+# End automatically added section
+# Automatically added by dh_installinit
+/etc/init.d/dlife stop
+# End automatically added section
diff --git a/debian/rules b/debian/rules
new file mode 100755 (executable)
index 0000000..2e3ef94
--- /dev/null
@@ -0,0 +1,64 @@
+#!/usr/bin/make -f
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+# This is the debhelper compatability version to use.
+export DH_COMPAT=1
+
+build: build-stamp
+build-stamp:
+       dh_testdir
+
+       ./configure --prefix=/usr --localstatedir=/var --sysconfdir=/etc \
+                   --disable-cron --disable-rc --disable-user-check
+       $(MAKE)
+
+       touch build-stamp
+
+clean:
+       dh_testdir
+       dh_testroot
+       rm -f build-stamp
+
+       -$(MAKE) distclean
+
+       dh_clean
+
+install: build
+       dh_testdir
+       dh_testroot
+       dh_clean -k
+       dh_installdirs
+
+       $(MAKE) DESTDIR=`pwd`/debian/tmp install
+       rm debian/tmp/tmp/*     # kludge; installation leaves cruft in /tmp
+       cp debian/9dlife debian/tmp/etc/ppp/ip-up.d
+       chmod a+x debian/tmp/etc/ppp/ip-up.d/9dlife
+
+# Build architecture-independent files here.
+binary-indep: build install
+# We have nothing to do by default.
+
+# Build architecture-dependent files here.
+binary-arch: build install
+       dh_testdir
+       dh_testroot
+       dh_installdocs
+       dh_installinit
+       dh_installcron
+#      dh_installmanpages
+       dh_undocumented
+       dh_installchangelogs 
+       dh_link
+       dh_strip
+       dh_compress
+       dh_fixperms
+       dh_installdeb
+       dh_shlibdeps
+       dh_gencontrol
+       dh_md5sums
+       dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install
diff --git a/debian/substvars b/debian/substvars
new file mode 100644 (file)
index 0000000..e530b66
--- /dev/null
@@ -0,0 +1 @@
+shlibs:Depends=libc6.1 (>= 2.1.2-1)
diff --git a/dlife.rc b/dlife.rc
new file mode 100644 (file)
index 0000000..8b9328f
--- /dev/null
+++ b/dlife.rc
@@ -0,0 +1,49 @@
+#!/bin/sh
+#
+# dlife.rc      This shell script takes care of starting and stopping
+#               the dlife client.
+#
+# chkconfig: 2345 80 30
+# description: The Distributed Artificial Life client.
+# processname: dlife_soup
+# config: /etc/dlife/soup.conf
+
+# Source function library.
+. /etc/init.d/functions
+
+# Source networking configuration.
+. /etc/sysconfig/network
+
+# Check that networking is up.
+[ ${NETWORKING} = "no" ] && exit 0
+
+[ -f /usr/bin/dlife_soup ] || exit 0
+
+# See how we were called.
+case "$1" in
+  start)
+       # Start daemons.
+       echo -n "Starting dlife: "
+       daemon /usr/bin/dlife_soup
+       echo
+       ;;
+  stop)
+       # Stop daemons.
+       echo -n "Shutting down dlife: "
+       killproc dlife_soup
+       echo
+       ;;
+  restart)
+       $0 stop
+       $0 start
+       ;;
+  status)
+       status dlife_soup
+       ;;
+  *)
+       echo "Usage: dlife.rc {start|stop|restart|status}"
+       exit 1
+esac
+
+exit 0
+
diff --git a/dlife.spec.in b/dlife.spec.in
new file mode 100644 (file)
index 0000000..0c32c83
--- /dev/null
@@ -0,0 +1,91 @@
+# @configure_input@
+# $Id: dlife.spec.in,v 1.3 2002/04/05 17:07:25 rich Exp $
+
+Summary: Distributed Artificial Life (DLIFE)
+Name: @PACKAGE@
+Version: @VERSION@
+Release: 1
+Copyright: GPL
+Group: Applications/Internet
+Source: @PACKAGE@-@VERSION@.tar.gz
+BuildRoot: /var/tmp/%{name}-%{version}-root
+Requires: perl-libwww-perl
+Requires: perl >= 5.004
+Requires: vixie-cron
+Requires: SysVinit
+
+
+%description
+Distributed Artificial Life is a package for joining your
+computer to a network of computers running a large artificial
+life simulation.
+
+
+%package server
+Summary: Distributed Artificial Life (DLIFE) server
+Group: Applications/Internet
+
+
+%description server
+This package contains the server code for DLIFE.
+
+
+%prep
+%setup -q
+
+
+%build
+CFLAGS="-O" \
+./configure \
+       --prefix=/usr --sysconfdir=/etc --localstatedir=/var \
+       --disable-user-check
+make
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir -p $RPM_BUILD_ROOT
+make NO_CHOWN=1 DESTDIR=$RPM_BUILD_ROOT install
+
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+
+%pre
+grep '^dlife:' /etc/group >/dev/null || {
+       echo "There is no 'dlife' group in /etc/group"
+       exit 1;
+}
+grep '^dlife:' /etc/passwd >/dev/null || {
+       echo "There is no 'dlife' user in /etc/passwd"
+       exit 1;
+}
+
+
+%pre server
+grep '^dlife:' /etc/group >/dev/null || {
+       echo "There is no 'dlife' group in /etc/group"
+       exit 1;
+}
+grep '^dlife:' /etc/passwd >/dev/null || {
+       echo "There is no 'dlife' user in /etc/passwd"
+       exit 1;
+}
+
+
+%files
+%defattr(-,root,root)
+%doc /usr/share/doc/@PACKAGE@-@VERSION@/
+@prefix@/bin/dlife_soup
+@prefix@/bin/dlife_client.pl
+%attr(0775,dlife,dlife) @SPOOLDIR@/
+@CONFDIR@/
+%config @CRONDIR@/dlife_client.cron
+@RCDIR@/dlife.rc
+
+
+%files server
+%defattr(-,root,root)
+@prefix@/bin/dlife_server.pl
+%attr(0775,dlife,dlife) @SPOOLDIR@/store/
diff --git a/dlife_asm.pl b/dlife_asm.pl
new file mode 100644 (file)
index 0000000..1a245c9
--- /dev/null
@@ -0,0 +1,356 @@
+#!/usr/bin/perl -w
+
+# DLIFE assembler.
+# By Richard W.M. Jones.
+#
+# $Id: dlife_asm.pl,v 1.1 2002/04/05 14:40:26 rich Exp $
+
+use strict;
+
+use Getopt::Long;
+
+my $help;
+
+GetOptions ("help|?" => \$help);
+
+if ($help)
+  {
+    print STDERR "dlife_asm.pl [--help] file.dla [file.dla [...]]\n";
+    exit 1;
+  }
+
+# Read input file(s) and assemble each one. Each input file has the
+# form ``filename.dla'' and we will write a file called ``filename.dlo''.
+foreach my $filename (@ARGV)
+  {
+    my $output = $filename . ".dlo";
+
+    if ($filename =~ m/(.*)\.dla$/)
+      {
+       $output = $1 . ".dlo";
+      }
+
+    open FILE, "<$filename" or die "$filename: $!";
+    open OUT, ">$output" or die "$output: $!";
+
+    while (<FILE>)
+      {
+       # Remove terminating CRs and LFs.
+       s/[\n\r]+//;
+
+       # Ignore blank lines and comments.
+       s/;.*$//;
+       s/^[ \t]*$//;
+       next if m/^$/;
+
+       # Parse the instruction.
+       parse_insn ($_);
+      }
+
+    close FILE;
+    print OUT "\n";
+    close OUT;
+  }
+
+sub parse_insn
+  {
+    my $insn = shift;
+
+    # Trim leading and trailing whitespace.
+    $insn =~ s/^[ \t]+//g;
+    $insn =~ s/[ \t]+$//g;
+
+    # Leading label?
+    if ($insn =~ m/^([01]+):(.*)$/)
+      {
+       my $label = $1;
+       my $rest = $2;
+
+       foreach (split //, $label)
+         {
+           if (m/0/) { print OUT "00" }
+           if (m/1/) { print OUT "01" }
+         }
+
+       parse_insn ($rest);
+       return;
+      }
+
+    # IFZ instruction prefix?
+    if ($insn =~ m/^IFZ[ \t]+(.*)$/i)
+      {
+       my $rest = $1;
+
+       print OUT "07\n";
+
+       parse_insn ($rest);
+       return;
+      }
+    # Empty instruction?
+    elsif ($insn =~ m/^$/)
+      {
+       return;
+      }
+    # Other instruction?
+    elsif ($insn =~ m/^NOP0$/i)
+      {
+       print OUT "00\n";
+      }
+    elsif ($insn =~ m/^NOP1$/i)
+      {
+       print OUT "01\n";
+      }
+    elsif ($insn =~ m/^INC[ \t]+A$/i)
+      {
+       print OUT "02\n";
+      }
+    elsif ($insn =~ m/^DEC[ \t]+A$/i)
+      {
+       print OUT "03\n";
+      }
+    elsif ($insn =~ m/^SHL[ \t]+A$/i)
+      {
+       print OUT "04\n";
+      }
+    elsif ($insn =~ m/^FINDB[ \t](.*)$/i)
+      {
+       print OUT "08\n";
+       parse_pattern ($1);
+      }
+    elsif ($insn =~ m/^FINDF[ \t](.*)$/i)
+      {
+       print OUT "09\n";
+       parse_pattern ($1);
+      }
+    elsif ($insn =~ m/^MALLOC$/i)
+      {
+       print OUT "0A\n";
+      }
+    elsif ($insn =~ m/^DIVIDE$/i)
+      {
+       print OUT "0B\n";
+      }
+    elsif ($insn =~ m/^MOVE[ \t]+\[I\],A$/i)
+      {
+       print OUT "0C\n";
+      }
+    elsif ($insn =~ m/^MOVE[ \t]+A,\[I\]$/i)
+      {
+       print OUT "0D\n";
+      }
+    elsif ($insn =~ m/^DMOVE[ \t]+\[I\],A$/i)
+      {
+       print OUT "0E\n";
+      }
+    elsif ($insn =~ m/^DMOVE[ \t]+A,\[I\]$/i)
+      {
+       print OUT "0F\n";
+      }
+    elsif ($insn =~ m/^XOR[ \t]+([ABIP]),([ABIP])$/i)
+      {
+       my $reg1 = reg2bin ($1);
+       my $reg2 = reg2bin ($2);
+
+       printf OUT ("%02X\n", 16 + ($reg2 << 2) + $reg1);
+      }
+    elsif ($insn =~ m/^PUSH[ \t]+([ABIP])$/i)
+      {
+       my $reg = reg2bin ($1);
+
+       printf OUT ("%02X\n", 32 + $reg);
+      }
+    elsif ($insn =~ m/^POP[ \t]+([ABIP])$/i)
+      {
+       my $reg = reg2bin ($1);
+
+       printf OUT ("%02X\n", 36 + $reg);
+      }
+    # Instruction set macros.
+    elsif ($insn =~ m/MOVE[ \t]+([ABIP]),([ABIP])$/i)
+      {
+       my $reg1 = reg2bin ($1);
+       my $reg2 = reg2bin ($2);
+
+       printf OUT ("%02X", 32 + $reg1); # PUSH reg1
+       printf OUT ("%02X\n", 36 + $reg2); # POP reg2
+      }
+    elsif ($insn =~ m/SWAP[ \t]+([ABIP]),([ABIP])$/i)
+      {
+       my $reg1 = reg2bin ($1);
+       my $reg2 = reg2bin ($2);
+
+       printf OUT ("%02X", 16 + ($reg2 << 2) + $reg1); # XOR reg1, reg2
+       printf OUT ("%02X", 16 + ($reg1 << 2) + $reg2); # XOR reg2, reg1
+       printf OUT ("%02X", 16 + ($reg2 << 2) + $reg1); # XOR reg1, reg2
+       printf OUT ("%02X\n", 16 + ($reg1 << 2) + $reg2); # XOR reg2, reg1
+      }
+    elsif ($insn =~ m/ZERO[ \t]+([ABIP])$/i)
+      {
+       my $reg = reg2bin ($1);
+
+       printf OUT ("%02X\n", 16 + ($reg << 2) + $reg); # XOR reg, reg
+      }
+    elsif ($insn =~ m/ADD[ \t]+([0-9]+),A$/i)
+      {
+       my $n = $1;
+
+       for (my $i = 0; $i < $n; ++$i)
+         {
+           print OUT "02";
+         }
+       print OUT "\n";
+      }
+    elsif ($insn =~ m/MOVE[ \t]+([0-9]+),A$/i)
+      {
+       my $n = $1;
+
+       print OUT "10";         # XOR A,A
+       while ($n > 0)
+         {
+           if (($n & 1) == 1)
+             {
+               print OUT "0402"; # SHL A; INC A
+             }
+           else
+             {
+               print OUT "04"; # SHL A
+             }
+           $n >>= 1;
+         }
+       print OUT "\n";
+      }
+    elsif ($insn =~ m/LOAD[ \t]+([0-9]+),A$/i)
+      {
+       my $n = $1;
+
+       print OUT "222124";     # PUSH I; PUSH B; POP A
+       for (my $i = 0; $i < $n * 2; ++$i)
+         {
+           print OUT "02";     # INC A
+         }
+       print OUT "20260E26\n"; # PUSH A; POP I; DMOVE [I],A; POP I
+      }
+    elsif ($insn =~ m/STORE[ \t]+A,([0-9]+)$/i)
+      {
+       my $n = $1;
+
+       print OUT "22202124";   # PUSH I; PUSH A; PUSH B; POP A
+       for (my $i = 0; $i < $n * 2; ++$i)
+         {
+           print OUT "02";     # INC A
+         }
+       print OUT "2026240F26\n"; # PUSH A; POP I; POP A; DMOVE A,[I]; POP I
+      }
+    elsif ($insn =~ m/^JMP[ \t]+I$/i)
+      {
+       print OUT "2227\n";     # PUSH I; POP P
+      }
+    elsif ($insn =~ m/^JMPF[ \t](.*)$/i)
+      {
+       print OUT "09";         # FINDF
+       parse_pattern ($1);
+       print OUT "2227\n";     # PUSH I; POP P
+      }
+    elsif ($insn =~ m/^JMPB[ \t](.*)$/i)
+      {
+       print OUT "08";         # FINDB
+       parse_pattern ($1);
+       print OUT "2227\n";     # PUSH I; POP P
+      }
+    elsif ($insn =~ m/^JMPZF[ \t](.*)$/i)
+      {
+       print OUT "09";         # FINDF
+       parse_pattern ($1);
+       print OUT "22072726\n"; # PUSH I; IFZ POP P; POP I
+      }
+    elsif ($insn =~ m/^JMPZB[ \t](.*)$/i)
+      {
+       print OUT "08";         # FINDB
+       parse_pattern ($1);
+       print OUT "22072726\n"; # PUSH I; IFZ POP P; POP I
+      }
+    elsif ($insn =~ m/^CALLF[ \t](.*)$/i)
+      {
+       print OUT "2309";       # PUSH P; FINDF
+       parse_pattern ($1);
+       print OUT "2227\n";     # PUSH I; POP P
+      }
+    elsif ($insn =~ m/^CALLB[ \t](.*)$/i)
+      {
+       print OUT "2308";       # PUSH P; FINDB
+       parse_pattern ($1);
+       print OUT "2227\n";     # PUSH I; POP P
+      }
+    elsif ($insn =~ m/^RET[ \t]+([0-9]+)$/i)
+      {
+       my $n = $1;
+       print OUT "24";         # POP A
+       for (my $i = 0; $i < $n + 3; ++$i)
+         {
+           print OUT "02";     # INC A
+         }
+       print OUT "2027\n";     # PUSH A; POP P
+      }
+    elsif ($insn =~ m/^DB[ \t]+([0-9]+)$/i)
+      {
+       my $n = $1;
+       for (my $i = 0; $i < $n; ++$i)
+         {
+           print OUT "FF";
+         }
+       print OUT "\n";
+      }
+    elsif ($insn =~ m/^DW[ \t]+([0-9]+)$/i)
+      {
+       my $n = $1;
+       for (my $i = 0; $i < $n * 2; ++$i)
+         {
+           print OUT "FF";
+         }
+       print OUT "\n";
+      }
+    else
+      {
+       die "$insn: unknown instruction";
+      }
+  }
+
+sub parse_pattern
+  {
+    my $pattern = shift;
+
+    if ($pattern =~ m/^([01]+)$/)
+      {
+       foreach (split //, $1)
+         {
+           if (m/0/) { print OUT "00" }
+           if (m/1/) { print OUT "01" }
+         }
+      }
+    elsif ($pattern =~ m/^~([01]+)$/) # Complemented pattern.
+      {
+       foreach (split //, $1)
+         {
+           if (m/0/) { print OUT "01" }
+           if (m/1/) { print OUT "00" }
+         }
+      }
+    else
+      {
+       die "$pattern: unrecognized pattern argument";
+      }
+  }
+
+sub reg2bin
+  {
+    my $reg = shift;
+
+    if (uc($reg) eq "A") { return 0 }
+    elsif (uc($reg) eq "B") { return 1 }
+    elsif (uc($reg) eq "I") { return 2 }
+    elsif (uc($reg) eq "P") { return 3 }
+    else
+      {
+       die "$reg: unknown register name";
+      }
+  }
diff --git a/dlife_client.cron b/dlife_client.cron
new file mode 100644 (file)
index 0000000..bd3cf16
--- /dev/null
@@ -0,0 +1,2 @@
+# Run the client to upload cells periodically.
+5      *       *       *       *       dlife   /usr/bin/dlife_client.pl
diff --git a/dlife_client.pl.in b/dlife_client.pl.in
new file mode 100644 (file)
index 0000000..bf34757
--- /dev/null
@@ -0,0 +1,397 @@
+#!/usr/bin/perl -w -T
+# -*- perl -*-
+# @configure_input@
+
+use strict;
+
+use Getopt::Long;
+use LWP::UserAgent;
+use Socket;
+use IO::Socket;
+use Sys::Hostname;
+use Sys::Syslog qw(:DEFAULT setlogsock);
+
+my $help;
+my $verbose;
+my $config_filename = "@CONFDIR@/client.conf";
+my $spooldir = "@SPOOLDIR@";
+my $client_version = "@VERSION@";
+
+GetOptions ("help|?" => \$help,
+           "verbose" => \$verbose,
+           "config=s" => \$config_filename,
+           "spooldir=s" => \$spooldir);
+
+if ($help)
+  {
+    print STDERR <<EOF;
+dlife_client.pl [--help] [--verbose] \
+                [--spooldir=spooldir] [--config=config_file]
+
+Options:
+  --help               Displays this help text.
+  --verbose            Lots of messages.
+  --spooldir=spooldir  Set spool directory (default is @SPOOLDIR@).
+  --config=config_file Use named configuration file (default is to use
+                       @CONFDIR@/client.conf).
+EOF
+  exit 1;
+  }
+
+# Open a connection to syslog.
+setlogsock ("unix");
+openlog ("dlife_client", "", "user");
+
+syslog ("info", "version $client_version starting [conf=$config_filename, spool=$spooldir]");
+
+# Default configuration values.
+my $server_url;
+my @server_zones = ();
+my @servers = ();
+my $max_cells_upload_per_pass = 6;
+my $max_cells_download_per_pass = 4;
+
+# Read configuration file.
+open CONFIG, "<$config_filename" or die "$config_filename: $!";
+
+while (<CONFIG>)
+  {
+    s/[\n\r]*$//;
+    next if /^\s*\#/;
+    next if /^\s*$/;
+
+    if (/^\s*server_url\s+(\S+)\s*$/)
+      {
+       $server_url = $1;
+       print "server_url=$server_url\n" if $verbose;
+      }
+    elsif (/^\s*server_zone\s+(.*)\s*$/)
+      {
+       @server_zones = split /\s+/, $1;
+       print "server_zones=", join (" ", @server_zones), "\n" if $verbose;
+      }
+    elsif (/^\s*server\s+(.*)\s*$/)
+      {
+       @servers = split /\s+/, $1;
+       print "servers=", join (" ", @servers), "\n" if $verbose;
+      }
+    elsif (/^\s*max_cells_upload_per_pass\s+([1-9][0-9]*)\s*$/)
+      {
+       $max_cells_upload_per_pass = $1;
+      }
+    elsif (/^\s*max_cells_download_per_pass\s+([1-9][0-9]*)\s*$/)
+      {
+       $max_cells_download_per_pass = $1;
+      }
+    else
+      {
+       die "unknown configuration option: $_";
+      }
+  }
+
+close CONFIG;
+
+# Load @server_zones into a hash for rapid searching.
+my %server_zones;
+foreach (@server_zones) { $server_zones{$_} = 1; }
+
+# Server URL set or @servers not empty?
+unless ($server_url || @servers)
+  {
+    die "neither server_url and servers was set: cannot do anything";
+  }
+
+# Go to spool directory.
+chdir $spooldir or die "$spooldir: $!";
+
+# Find the list of cells to upload and arrange into a random order.
+my @all_upload_cells = randomize_list (glob_outgoing ());
+
+unless (@all_upload_cells)
+  {
+    syslog ("info", "no cells to upload (is the dlife_soup process running?)");
+    exit;
+  }
+
+# Only upload the first few cells.
+my @upload_cells = @all_upload_cells;
+splice @upload_cells, $max_cells_upload_per_pass;
+
+# If server URL set, then go and download the webpage. Load appropriate
+# server names into @servers.
+if ($server_url)
+  {
+    syslog ("info", "contacting $server_url");
+    print "Contacting $server_url\n" if $verbose;
+
+    my $ua = LWP::UserAgent->new;
+    my $req = HTTP::Request->new ("GET", $server_url);
+    my $rep = $ua->request ($req);
+
+    if ($rep->is_success)
+      {
+       print "Fetched page. Parsing page ...\n" if $verbose;
+
+       # Parse the page.
+       my @lines = split /[\n\r]+/, $rep->content;
+
+       foreach (@lines)
+         {
+           if (/^\s*server\s+(\S*)\s+(.*)\s*$/)
+             {
+               my $server = $1;
+               my @zones = split /\s+/, $2;
+
+               # Is this server in one of our zones?
+               if (@server_zones)
+                 {
+                   foreach (@zones)
+                     {
+                       if (exists $server_zones{$_})
+                         {
+                           push @servers, $server;
+                           last;
+                         }
+                     }
+                 }
+               else
+                 {
+                   push @servers, $server;
+                 }
+             }
+         }
+
+       print "Finished parsing page. \@servers = ",
+         join (" ", @servers), "\n"
+         if $verbose;
+      }
+    else
+      {
+       syslog ("error", "could not contact $server_url");
+       print "Could not contact server.\n" if $verbose;
+      }
+  }
+
+# Sort the server list into a random order.
+@servers = randomize_list (@servers);
+
+# Contact each server in turn until we succeed with one of them.
+my $server;
+
+foreach $server (@servers)
+  {
+    alarm 0;
+
+    print "Attempting to connect to $server port 5904\n" if $verbose;
+    syslog ("info", "exchanging cells with $server");
+
+    my $socket = new IO::Socket::INET (PeerAddr => $server,
+                                      PeerPort => "5904",
+                                      Proto => "tcp");
+
+    unless ($socket)
+      {
+       syslog ("error", "could not connect to $server");
+       print "Failed to connect.\n" if $verbose;
+       next;
+      }
+
+    print "Connected.\n" if $verbose;
+
+    # Read server and protocol version.
+    alarm 60;
+    $_ = $socket->getline;
+
+    unless (/^DLIFE SERVER\s+([0-9]+\.[0-9]+)\s+([0-9]+\.[0-9]+)/)
+      {
+       print "Unrecognized server greeting.\n" if $verbose;
+       next;
+      }
+
+    my $server_version = $1;
+    my $protocol_version = $2;
+
+    # The only protocol we recognize right now is version 1.x. These
+    # x (minor) revisions will be backwards compatible. If an
+    # incompatibility is introduced in the future, then that will
+    # become version 2.x, 3.x, etc.
+    unless ($protocol_version =~ /^1\./)
+      {
+       print "Unsupported protocol version.\n" if $verbose;
+       next;
+      }
+
+    # Send our client greeting string.
+    $socket->print ("HELO - $client_version\r\n");
+
+    # Wait for OK response.
+    alarm 60;
+    $_ = $socket->getline;
+
+    unless (/^2[0-9][0-9]\s/)
+      {
+       print "Error response from server during HELO.\n" if $verbose;
+       next;
+      }
+
+    # Check for cells to upload, and upload the first few.
+    my $cell_filename;
+
+    foreach $cell_filename (@upload_cells)
+      {
+       print "Uploading $cell_filename ...\n" if $verbose;
+
+       $socket->print ("STOR\r\n");
+
+       # Wait for OK to send response.
+       alarm 60;
+       $_ = $socket->getline;
+
+       unless (/^1[0-9][0-9]\s/)
+         {
+           print "Error response from server during STOR.\n" if $verbose;
+           next;
+         }
+
+       # Send the cell.
+       open CELL, "<$cell_filename" or die "$cell_filename: $!";
+
+       while (<CELL>)
+         {
+           s/[\n\r]*$//;
+           $socket->print ($_, "\r\n");
+         }
+
+       close CELL;
+
+       $socket->print (".\r\n");
+
+       # Wait for OK response from server.
+       alarm 60;
+       $_ = $socket->getline;
+
+       unless (/^2[0-9][0-9]\s/)
+         {
+           print "Error response from server after STOR.\n" if $verbose;
+           next;
+         }
+      }
+
+    # Remove all upload cells in the queue.
+    foreach $cell_filename (@all_upload_cells)
+      {
+       unlink $cell_filename;
+      }
+
+    # Check for cells to download.
+    for (my $i = 0; $i < $max_cells_download_per_pass; ++$i)
+      {
+       print "Downloading ...\n" if $verbose;
+
+       $socket->print ("RETR\r\n");
+
+       # Wait for OK to retrieve response.
+       alarm 60;
+       $_ = $socket->getline;
+
+       unless (/^1[0-9][0-9]\s/)
+         {
+           print "Error response from server during RETR.\n" if $verbose;
+           next;
+         }
+
+       # Retrieve the cell.
+       my $cell = "";
+
+       while (length ($cell) < 8192)
+         {
+           alarm 10;
+           $_ = $socket->getline;
+           alarm 0;
+
+           s/[\n\r]*$//;
+
+           last if $_ eq ".";
+
+           $cell .= $_ . "\n";
+         }
+
+       # Wait for OK response.
+       alarm 60;
+       $_ = $socket->getline;
+
+       unless (/^2[0-9][0-9]\s/)
+         {
+           print "Error response from server after RETR.\n" if $verbose;
+           next;
+         }
+
+       # Save the cell to a file.
+       my $rand = int (rand 1000000000);
+       open CELL, ">incoming/$rand.dlo" or die "incoming/$rand.dlo: $!";
+
+       print CELL $cell;
+
+       close CELL;
+      }
+
+    print "Disconnecting ...\n" if $verbose;
+
+    # Say goodbye.
+    $socket->print ("QUIT\r\n");
+
+    # Wait for OK response from server.
+    alarm 60;
+    $_ = $socket->getline;
+
+    unless (/^2[0-9][0-9]\s/)
+      {
+       print "Error response from server during QUIT.\n" if $verbose;
+       next;
+      }
+
+    # Close socket.
+    $socket->close;
+
+    alarm 0;
+    last;
+  }
+
+syslog ("info", "exit");
+
+exit;
+
+sub randomize_list
+  {
+    for (my $i = 0; $i < @_; ++$i)
+      {
+       my $r = int (rand (@_ - $i));
+
+       if ($r > 0)
+         {
+           # Swap elements $i and $i+$r.
+           my $t = $_[$i+$r];
+           $_[$i+$r] = $_[$i];
+           $_[$i] = $t;
+         }
+      }
+
+    return @_;
+  }
+
+# This function is equivalent to glob ("outgoing/*.dlo"), except that
+# the glob function doesn't work when tainting is enabled, alas.
+sub glob_outgoing
+  {
+    opendir DIR, "outgoing" or die "outgoing: $!";
+    my @names = map { untaint_string ($_) } map { "outgoing/$_" } grep { /\.dlo$/ } readdir DIR;
+    closedir DIR;
+    return @names;
+  }
+
+sub untaint_string
+  {
+    my $s = shift;
+    $s =~ /^(.*)$/;
+    return $1;
+  }
diff --git a/dlife_disasm.pl b/dlife_disasm.pl
new file mode 100755 (executable)
index 0000000..a9c305e
--- /dev/null
@@ -0,0 +1,147 @@
+#!/usr/bin/perl -w
+
+# DLIFE disassembler.
+# By Richard W.M. Jones.
+#
+# $Id: dlife_disasm.pl,v 1.1 2002/04/05 14:40:26 rich Exp $
+
+use strict;
+
+use Getopt::Long;
+
+my $help;
+
+GetOptions ("help|?" => \$help);
+
+if ($help)
+  {
+    printf STDERR "dlife_disasm.pl [--help] [file.dlo] > file.dla\n";
+    exit 1;
+  }
+
+# Read the entire input file into memory so that we can do some
+# clever stuff with string regexes.
+my $code = "";
+
+while (<>)
+  {
+    $code .= $_;
+  }
+
+# Remove anything which isn't [0-9a-f].
+$code =~ tr/0-9a-fA-F//cd;
+$code =~ tr/a-f/A-F/;
+
+# Convert code to <xx>.
+$code =~ s/(..)/<$1>/g;
+
+# NOTE: The order of this substitutions IS important.
+
+# CALLB and CALLF macros.
+$code =~ s/<23>(<08>|<09>)((<00>|<01>)+)<22><27>/convert_call ($1, $2)/ge;
+
+# JMPB and JMPF macros.
+$code =~ s/(<08>|<09>)((<00>|<01>)+)<22><27>/convert_jmp ($1, $2)/ge;
+
+# JMPBZ and JMPFZ macros.
+$code =~ s/(<08>|<09>)((<00>|<01>)+)<22><07><27><26>/convert_jmpz ($1, $2)/ge;
+
+# Basic FINDF and FINDB commands.
+$code =~ s/(<08>|<09>)((<00>|<01>)+)/convert_find ($1, $2)/ge;
+
+# Any other patterns are labels.
+$code =~ s/((<00>|<01>)+)/convert_label ($1)/ge;
+
+# MOVE macro.
+$code =~ s/(<2[0-3]>)(<2[4-7]>)/convert_move ($1, $2)/ge;
+
+# SWAP macro. XXX Difficult ...
+
+
+
+
+
+
+
+print $code;
+
+sub convert_call
+  {
+    my $find_code = shift;
+    my $pattern = shift;
+
+    my $insn = $find_code eq "<08>" ? "CALLB" : "CALLF";
+
+    $pattern =~ s/<00>/1/g;    # Pattern is complemented.
+    $pattern =~ s/<01>/0/g;
+
+    return "\n\t$insn ~$pattern\n";
+  }
+
+sub convert_jmp
+  {
+    my $find_code = shift;
+    my $pattern = shift;
+
+    my $insn = $find_code eq "<08>" ? "JMPB" : "JMPF";
+
+    $pattern =~ s/<00>/1/g;    # Pattern is complemented.
+    $pattern =~ s/<01>/0/g;
+
+    return "\n\t$insn ~$pattern\n";
+  }
+
+sub convert_jmpz
+  {
+    my $find_code = shift;
+    my $pattern = shift;
+
+    my $insn = $find_code eq "<08>" ? "JMPBZ" : "JMPFZ";
+
+    $pattern =~ s/<00>/1/g;    # Pattern is complemented.
+    $pattern =~ s/<01>/0/g;
+
+    return "\n\t$insn ~$pattern\n";
+  }
+
+sub convert_find
+  {
+    my $find_code = shift;
+    my $pattern = shift;
+
+    my $insn = $find_code eq "<08>" ? "FINDB" : "FINDF";
+
+    $pattern =~ s/<00>/1/g;    # Pattern is complemented.
+    $pattern =~ s/<01>/0/g;
+
+    return "\n\t$insn ~$pattern\n";
+  }
+
+sub convert_label
+  {
+    my $pattern = shift;
+
+    $pattern =~ s/<00>/0/g;
+    $pattern =~ s/<01>/1/g;
+
+    return "\n$pattern:\n";
+  }
+
+sub convert_move
+  {
+    my $push_code = shift;
+    my $pop_code = shift;
+
+    my ($src, $dst);
+    if ($push_code eq "<20>") { $src = "A" }
+    elsif ($push_code eq "<21>") { $src = "B" }
+    elsif ($push_code eq "<22>") { $src = "I" }
+    elsif ($push_code eq "<23>") { $src = "P" }
+    if ($pop_code eq "<24>") { $dst = "A" }
+    elsif ($pop_code eq "<25>") { $dst = "B" }
+    elsif ($pop_code eq "<26>") { $dst = "I" }
+    elsif ($pop_code eq "<27>") { $dst = "P" }
+
+    return "\n\tMOVE $src,$dst\n";
+  }
+
diff --git a/dlife_server.pl.in b/dlife_server.pl.in
new file mode 100644 (file)
index 0000000..9596888
--- /dev/null
@@ -0,0 +1,222 @@
+#!/usr/bin/perl -w -T
+# -*- perl -*-
+# @configure_input@
+
+BEGIN {
+  # Close stderr, else inetd sends this back to the client.
+  close STDERR;
+};
+
+use strict;
+
+use Socket;
+use IO::Socket;
+use Sys::Hostname;
+use Sys::Syslog qw(:DEFAULT setlogsock);
+
+$ENV{PATH} = "/usr/bin:/bin";
+delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
+
+my $spooldir = "@SPOOLDIR@";
+my $user = "dlife";
+my $server_version = "@VERSION@";
+my $protocol_version = "1.0";
+my $cells_uploaded = 0;
+my $cells_downloaded = 0;
+my $max_cells_upload_per_pass = 8;
+my $max_cells_download_per_pass = 8;
+
+my $hostname = hostname ();
+
+# Open a connection to syslog.
+setlogsock ("unix");
+openlog ("dlife_server", "pid,ndelay", "user");
+
+# Chroot into the spool directory and change our UID/GID so we are safe.
+my ($login, $pass, $uid, $gid) = getpwnam ($user)
+  or die "$user: user not found in password file";
+
+chroot $spooldir or die "chroot $spooldir: $!";
+
+$) = $gid;
+$> = $uid;
+
+die "could not change UID successfully: $!" unless $> == $uid && $) == $gid;
+
+chdir "/store" or die "$spooldir/store: $!";
+
+# Pull out connection information.
+my $peername = getpeername STDIN;
+my ($peerport, $peeraddr) = unpack_sockaddr_in ($peername);
+my $peeraddrstring = inet_ntoa ($peeraddr);
+
+my $peerhostname;
+
+my $revhostname = gethostbyaddr ($peeraddr, AF_INET);
+if ($revhostname)
+  {
+    my $ipaddr = gethostbyname ($revhostname);
+
+    if ($ipaddr && inet_ntoa ($ipaddr) eq $peeraddrstring)
+      {
+       $peerhostname = $revhostname;
+      }
+  }
+
+# Log connection information.
+syslog ("info", "received connection from $peeraddrstring:$peerport" .
+       ($peerhostname ? " ($peerhostname)" : ""));
+
+$| = 1;
+
+# Send greeting to client.
+print "DLIFE SERVER $server_version $protocol_version\r\n";
+
+# Loop, waiting for commands from the client.
+for (;;)
+  {
+    alarm 60;
+    $_ = <STDIN>;
+
+    # Remove trailing \r\n.
+    s/[\r\n]+$//;
+
+    if (/^HELO\s+(.*)\s+(.*)$/)
+      {
+       do_HELO_command ($1, $2);
+      }
+    elsif (/^STOR$/)
+      {
+       do_STOR_command ();
+      }
+    elsif (/^RETR$/)
+      {
+       do_RETR_command ();
+      }
+    elsif (/^QUIT$/)
+      {
+       print "200 Goodbye.\r\n";
+       last;                   # Exit the loop.
+      }
+    else
+      {
+       # Unknown command. Return an error message.
+       print "500 Unknown command.\r\n";
+      }
+  }
+
+exit 0;
+
+sub do_HELO_command
+  {
+    my $remote_hostname = shift;
+    my $remote_client_version = shift;
+
+    syslog ("info", "client software version: $remote_client_version");
+
+    # Do nothing with this information for now.
+    print "200 Hello.\r\n";
+  }
+
+sub do_STOR_command
+  {
+    if ($cells_uploaded > $max_cells_upload_per_pass)
+      {
+       print "500 Too many cells uploaded in this pass.\r\n";
+       return;
+      }
+
+    print "100 OK. Send the cell, terminated by . <CR> <LF> on a line of its own.\r\n";
+
+    # Read in the cell.
+    my $cell = "";
+
+    while (length ($cell) < 8192)
+      {
+       alarm 10;
+       $_ = <STDIN>;
+       alarm 0;
+
+       s/[\n\r]*$//;
+
+       last if $_ eq ".";
+
+       $cell .= $_ . "\n";
+      }
+
+    # Save the cell to a file.
+    my $rand = int (rand 1000000000);
+    open CELL, ">$rand.dlo" or die "$rand.dlo: $!";
+
+    print CELL $cell;
+
+    close CELL;
+
+    syslog ("info", "received cell $rand.dlo");
+
+    $cells_uploaded ++;
+    print "200 Cell uploaded OK.\r\n";
+  }
+
+sub do_RETR_command
+  {
+    if ($cells_downloaded > $max_cells_download_per_pass)
+      {
+       print "500 Too many cells downloaded in this pass.\r\n";
+       return;
+      }
+
+    # Find a cell at random.
+    my @cells = glob_cells ();
+    if (@cells == 0)
+      {
+       print "400 I have no cells to send you. Try again later.\r\n";
+       return;
+      }
+
+    my $r = rand @cells;
+    my $cell_filename = $cells[$r];
+
+    unless (open CELL, "<$cell_filename")
+      {
+       print "400 Another process grabbed that cell before I could send it. Try again.\r\n";
+       return;
+      }
+
+    # Send it.
+    print "100 OK. Sending you a cell now.\r\n";
+
+    syslog ("info", "sending cell $cell_filename");
+
+    while (<CELL>)
+      {
+       s/[\n\r]+$//;
+       print $_, "\r\n";
+      }
+
+    close CELL;
+
+    unlink $cell_filename;
+
+    print ".\r\n";
+
+    $cells_downloaded ++;
+    print "200 Finished sending the cell.\r\n";
+  }
+
+# This function is equivalent to glob ("*.dlo"), except that
+# the glob function doesn't work when tainting is enabled, alas.
+sub glob_cells
+  {
+    opendir DIR, "." or die "$spooldir/store: $!";
+    my @names = map { untaint_string ($_) } grep { /\.dlo$/ } readdir DIR;
+    closedir DIR;
+    return @names;
+  }
+
+sub untaint_string
+  {
+    my $s = shift;
+    $s =~ /^(.*)$/;
+    return $1;
+  }
diff --git a/dlink.h b/dlink.h
new file mode 100644 (file)
index 0000000..2d4f061
--- /dev/null
+++ b/dlink.h
@@ -0,0 +1,146 @@
+/* DLIFE Copyright (C) 2000 Richard W.M. Jones <rich@annexia.org>
+ * and other authors listed in the ``AUTHORS'' file.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * $Id: dlink.h,v 1.1 2002/04/05 14:40:26 rich Exp $
+ */
+
+#ifndef dlink_h
+#define dlink_h
+
+/* This was snarfed from the source for Python 1.5. */
+#ifdef HAVE_STDDEF_H
+#include <stddef.h>
+#endif
+
+#ifndef offsetof
+#define offsetof(type, member) ( (int) & ((type*)0) -> member )
+#endif
+
+typedef struct dlink_list_element
+{
+  void *next;
+  void *prev;
+} dlink_list_element_t;
+
+typedef struct dlink_list
+{
+  void *first;
+  void *last;
+  int offset;
+} dlink_list_t;
+
+#define DLINK_LIST_INIT(offset) { 0, 0, (offset) }
+
+#define _DLINK_ELEMENT_PTRS(element,list) ((dlink_list_element_t *) ((element) + (list)->offset))
+#define _DLINK_FIRST_PTRS(list) _DLINK_ELEMENT_PTRS((list)->first,(list))
+#define _DLINK_LAST_PTRS(list) _DLINK_ELEMENT_PTRS((list)->last,(list))
+
+extern inline void
+dlink_list_init (dlink_list_t *list, int offset)
+{
+  list->first = list->last = 0;
+  list->offset = offset;
+}
+
+extern inline void
+insert_before_first (void *element, dlink_list_t *list)
+{
+  dlink_list_element_t *eptrs = _DLINK_ELEMENT_PTRS (element, list);
+
+  eptrs->prev = 0;
+  eptrs->next = list->first;
+  if (list->first)
+    _DLINK_FIRST_PTRS(list)->prev = element;
+  else
+    list->last = element;
+  list->first = element;
+}
+
+extern inline void
+insert_before_last (void *element, dlink_list_t *list)
+{
+  dlink_list_element_t *eptrs = _DLINK_ELEMENT_PTRS (element, list);
+
+  eptrs->next = 0;
+  eptrs->prev = list->last;
+  if (list->last)
+    _DLINK_LAST_PTRS(list)->next = element;
+  else
+    list->first = element;
+  list->last = element;
+}
+
+extern inline void
+move_towards_last (void *e, dlink_list_t *list)
+{
+  dlink_list_element_t *eptrs = _DLINK_ELEMENT_PTRS (e, list);
+
+  void *e0 = eptrs->prev;
+  dlink_list_element_t *e0ptrs = _DLINK_ELEMENT_PTRS (e0, list);
+
+  void *e1 = eptrs->next;
+  dlink_list_element_t *e1ptrs = _DLINK_ELEMENT_PTRS (e1, list);
+
+  void *e2 = e1ptrs->next;
+  dlink_list_element_t *e2ptrs = _DLINK_ELEMENT_PTRS (e2, list);
+
+  /* The elements are:   e0 <---> e <---> e1 <---> e2.
+   *
+   * We know that e and e1 exist, but e0 and e2 may or may not exist.
+   *
+   * We want the arrangement to be:
+   *                     e0 <---> e1 <---> e <---> e2.
+   */
+  e1ptrs->prev = e0;
+  if (e0)
+    e0ptrs->next = e1;
+  else
+    list->first = e1;
+
+  e1ptrs->next = e;
+  eptrs->prev = e1;
+
+  eptrs->next = e2;
+  if (e2)
+    e2ptrs->prev = e;
+  else
+    list->last = e;
+}
+
+extern inline void
+remove_element (void *element, dlink_list_t *list)
+{
+  dlink_list_element_t *eptrs = _DLINK_ELEMENT_PTRS (element, list);
+
+  void *eprev = eptrs->prev;
+  dlink_list_element_t *eprevptrs = _DLINK_ELEMENT_PTRS (eprev, list);
+
+  void *enext = eptrs->next;
+  dlink_list_element_t *enextptrs = _DLINK_ELEMENT_PTRS (enext, list);
+
+  if (eptrs->next)
+    enextptrs->prev = eprev;
+  else
+    list->last = eprev;
+
+  if (eptrs->prev)
+    eprevptrs->next = enext;
+  else
+    list->first = enext;
+}
+
+#endif /* dlink_h */
diff --git a/exec.c b/exec.c
new file mode 100644 (file)
index 0000000..2f8b6a3
--- /dev/null
+++ b/exec.c
@@ -0,0 +1,556 @@
+/* DLIFE Copyright (C) 2000 Richard W.M. Jones <rich@annexia.org>
+ * and other authors listed in the ``AUTHORS'' file.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * $Id: exec.c,v 1.2 2002/04/05 16:47:12 rich Exp $
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+
+#include "cell.h"
+#include "random.h"
+#include "params.h"
+#include "soup.h"
+
+#define TRACE 0
+
+#if TRACE
+static void trace (const struct cell *cell, int insn);
+#endif
+
+unsigned long long cell_cycle = 0;
+
+static inline int
+get_pattern_length (struct state *state, const struct cell *cell)
+{
+  int p = cell->p;
+  int c;
+
+  /* XXX Maximum pattern length? */
+  /* XXX What if pattern exceeds limits of the cell? */
+  while ((c = get_soup (state, cell->frag, p) & 0x3F) == 0 || c == 1)
+    {
+      p++;
+    }
+
+  return p - cell->p;
+}
+
+static inline int
+check_access (struct state *state, const struct cell *cell, reg_t raddr)
+{
+  if (raddr >= 0 && raddr < cell->frag->len) /* In mother? */
+    return 1;
+  if (cell->daughter)          /* In daughter? */
+    {
+      int offset = cell->daughter->frag->base - cell->frag->base;
+
+      /* Be careful with the wrap-around case here. */
+      if (((raddr - offset) & (state->soup_size - 1)) >= 0 &&
+         ((raddr - offset) & (state->soup_size - 1)) < cell->daughter->frag->len)
+       return 1;
+    }
+  return 0;
+}
+
+static inline int
+check_exec_access (struct state *state, const struct cell *cell, reg_t raddr)
+{
+  if (raddr >= 0 && raddr < cell->frag->len) /* In mother? */
+    return 1;
+  return 0;
+}
+
+static inline void
+push (struct cell *cell, reg_t v)
+{
+  cell->sp = (cell->sp+1) & (STACK_SIZE-1);
+  cell->stack[cell->sp] = v;
+}
+
+static inline void
+pop (struct cell *cell, reg_t *va)
+{
+  *va = cell->stack[cell->sp];
+  cell->sp = (cell->sp-1) & (STACK_SIZE-1);
+}
+
+void
+exec_insn (struct state *state, struct cell *cell)
+{
+  /* Increment cycle counters. */
+  state->cell_cycle++;
+  cell->cycle++;
+
+  /* State? */
+  if (cell->state == state_exec)
+    {
+      int insn, error;
+
+    next:
+      /* Fetch next insn. */
+      if (check_exec_access (state, cell, cell->p) ||
+         chance (access_control_failure))
+       {
+         insn = get_soup (state, cell->frag, cell->p);
+       }
+      else
+       {
+         INC_ERRORS (state, cell);
+
+         /* Increment PC */
+         cell->p++;
+
+         return;
+       }
+
+      /* By doing this we allow the cell to use the top two bits of
+       * each instruction byte for its own purposes. DNA uses a similar
+       * technique - it can mark up basic sequences by adding its
+       * own arbitrary chemical markers to each base.
+       */
+      insn &= 0x3f;
+
+#if TRACE
+      trace (cell, insn);
+#endif
+
+      if (chance (soup_fetch_failure))
+       {
+         insn = get_rand_byte () & 0x3f;
+       }
+
+      /* Increment PC */
+      if (!chance (inc_pc_failure))
+       {
+         cell->p++;
+       }
+
+      /* Is this insn going to generate an error? Handle that case
+       * separately (don't disturb the fast path).
+       */
+      error = chance (insn_exec_failure);
+
+      if (!error)
+       {
+         switch (insn)
+           {
+           case 0:             /* NOP0 */
+           case 1:             /* NOP1 */
+             return;           /* Ignore. */
+           case 2:             /* INC A */
+             cell->a++;
+             return;
+           case 3:             /* DEC A */
+             cell->a--;
+             return;
+           case 4:             /* SHL A */
+             cell->a <<= 1;
+             return;
+           case 7:             /* IFZ */
+             if (cell->a == 0)
+               goto next;      /* Fetch and execute next instruction. */
+             /* Else skip next insn. */
+             cell->p++;
+             return;
+           case 8:             /* FINDB */
+             if ((cell->plen = get_pattern_length (state, cell)) > 0)
+               {
+                 cell->state = state_find;
+                 cell->dir = -1;
+                 cell->i = cell->p - 2;
+                 cell->lim = FIND_LENGTH_LIMIT;
+               }
+             else
+               {
+                 INC_ERRORS (state, cell);
+                 cell->i = 0;
+               }
+             return;
+           case 9:             /* FINDF */
+             if ((cell->plen = get_pattern_length (state, cell)) > 0)
+               {
+                 cell->state = state_find;
+                 cell->dir = 1;
+                 cell->i = cell->p + cell->plen + 1;
+                 cell->lim = FIND_LENGTH_LIMIT;
+               }
+             else
+               {
+                 INC_ERRORS (state, cell);
+                 cell->i = 0;
+               }
+             return;
+           case 0x0a:          /* MALLOC */
+             if (!cell->daughter &&
+                 cell->a >= MIN_CELL_SIZE && cell->a <= MAX_CELL_SIZE)
+               {
+                 struct soup_frag *frag
+                   = soup_frag_malloc (state, cell->frag, cell->a);
+                 if (frag)
+                   {
+                     cell->daughter
+                       = cell_malloc (state, cell, frag);
+                     /* Calculate relative address of daughter */
+                     cell->i
+                       = cell->daughter->frag->base
+                       - cell->frag->base;
+#if 0
+                     printf ("MALLOC: dfb = %d, fb = %d, i = %d\n",
+                             cell->daughter->frag->base,
+                             cell->frag->base,
+                             cell->i);
+#endif
+                   }
+                 else
+                   {
+                     /* INC_ERRORS (state, cell); -- Dubious? */
+                     cell->i = 0;
+                   }
+               }
+             else
+               {
+                 INC_ERRORS (state, cell);
+                 cell->i = 0;
+               }
+             return;
+           case 0x0b:          /* DIVIDE */
+             if (cell->daughter)
+               {
+                 cell_divide (state, cell, cell->daughter);
+                 cell_activate (state, cell->daughter);
+                 cell->daughter = 0;
+               }
+             else
+               {
+                 INC_ERRORS (state, cell);
+                 cell->i = 0;
+               }
+             return;
+           case 0x0c:          /* MOVE [I],A */
+             cell->a = get_soup (state, cell->frag, cell->i);
+             return;
+           case 0x0d:          /* MOVE A,[I] */
+             if (check_access (state, cell, cell->i) ||
+                 chance (access_control_failure))
+               {
+                 set_soup (state, cell->frag, cell->a, cell->i);
+               }
+             else
+               {
+                 INC_ERRORS (state, cell);
+               }
+             return;
+           case 0x0e:          /* DMOVE [I],A */
+             cell->a = get_soup (state, cell->frag, cell->i) << 8;
+             cell->a |= get_soup (state, cell->frag, cell->i+1);
+             return;
+           case 0x0f:          /* DMOVE A,[I] */
+             if ((check_access (state, cell, cell->i) &&
+                  check_access (state, cell, cell->i+1)) ||
+                 chance (access_control_failure))
+               {
+                 set_soup (state, cell->frag, cell->a >> 8, cell->i);
+                 set_soup (state, cell->frag, cell->a & 0xff, cell->i+1);
+               }
+             else
+               {
+                 INC_ERRORS (state, cell);
+               }
+             return;
+           case 0x10:          /* XOR A,A (ie. ZERO A) */
+             cell->a = 0; return;
+           case 0x11:          /* XOR B,A */
+             cell->a ^= cell->b; return;
+           case 0x12:          /* XOR I,A */
+             cell->a ^= cell->i; return;
+           case 0x13:          /* XOR P,A */
+             cell->a ^= cell->p; return;
+           case 0x14:          /* XOR A,B */
+             cell->b ^= cell->a; return;
+           case 0x15:          /* XOR B,B (ie. ZERO B) */
+             cell->b = 0; return;
+           case 0x16:          /* XOR I,B */
+             cell->b ^= cell->i; return;
+           case 0x17:          /* XOR P,B */
+             cell->b ^= cell->p; return;
+           case 0x18:          /* XOR A,I */
+             cell->i ^= cell->a; return;
+           case 0x19:          /* XOR B,I */
+             cell->i ^= cell->b; return;
+           case 0x1a:          /* XOR I,I (ie. ZERO I) */
+             cell->i = 0; return;
+           case 0x1b:          /* XOR P,I */
+             cell->i ^= cell->p; return;
+             /* Surely these next three instructions will never be used ... */
+           case 0x1c:          /* XOR A,P */
+             cell->p ^= cell->a; return;
+           case 0x1d:          /* XOR B,P */
+             cell->p ^= cell->b; return;
+           case 0x1e:          /* XOR I,P */
+             cell->p ^= cell->i; return;
+           case 0x1f:          /* XOR P,P (ie. ZERO P) */
+             cell->p = 0; return;
+           case 0x20:          /* PUSH A */
+             push (cell, cell->a);
+             return;
+           case 0x21:          /* PUSH B */
+             push (cell, cell->b);
+             return;
+           case 0x22:          /* PUSH I */
+             push (cell, cell->i);
+             return;
+           case 0x23:          /* PUSH P */
+             push (cell, cell->p);
+             return;
+           case 0x24:          /* POP A */
+             pop (cell, &cell->a);
+             return;
+           case 0x25:          /* POP B */
+             pop (cell, &cell->b);
+             return;
+           case 0x26:          /* POP I */
+             pop (cell, &cell->i);
+             return;
+           case 0x27:          /* POP P */
+             pop (cell, &cell->p);
+             return;
+
+           default:            /* Unknown instruction. */
+             INC_ERRORS (state, cell);
+             return;
+           }
+       }
+      else
+       {
+         /* Slow path: insn will execute in error. */
+         switch (insn)
+           {
+           case 2:             /* INC A */
+             if (chance (2))
+               cell->a += 2;
+             return;
+           case 3:             /* DEC A */
+             if (chance (2))
+               cell->a -= 2;
+             return;
+           case 4:             /* SHL A */
+             if (chance (2))
+               cell->a <<= 2;
+             return;
+           case 7:             /* IFZ */
+             if (chance (2))
+               goto next;      /* Fetch and execute next instruction. */
+             /* Else skip next insn. */
+             cell->p++;
+             return;
+           case 8:             /* FINDB */
+             if (chance (2))
+               cell->i = 0;
+             return;
+           case 9:             /* FINDF */
+             if (chance (2))
+               cell->i = 0;
+             return;
+           case 0x0c:          /* MOVE [I],A */
+             cell->a = get_soup (state, cell->frag, cell->i);
+             if (chance (2))
+               cell->a++;
+             else
+               cell->a--;
+             return;
+           case 0x0d:          /* MOVE A,[I] */
+             {
+               int i = chance (4);
+               switch (i)
+                 {
+                 case 0:
+                   set_soup (state, cell->frag, cell->a+1, cell->i);
+                   return;
+                 case 1:
+                   set_soup (state, cell->frag, cell->a-1, cell->i);
+                   return;
+                 case 2:
+                   set_soup (state, cell->frag, cell->a, cell->i+1);
+                   return;
+                 case 3:
+                   set_soup (state, cell->frag, cell->a, cell->i-1);
+                   return;
+                 }
+               return;
+             }
+           case 0x0e:          /* DMOVE [I],A */
+             cell->a = get_soup (state, cell->frag, cell->i) << 8;
+             cell->a |= get_soup (state, cell->frag, cell->i+1);
+             if (chance (2))
+               cell->a++;
+             else
+               cell->a--;
+             return;
+           case 0x0f:          /* DMOVE A,[I] */
+             {
+               int i = chance (4);
+               switch (i)
+                 {
+                 case 0:
+                   set_soup (state, cell->frag, (cell->a+1) >> 8, cell->i);
+                   set_soup (state, cell->frag, (cell->a+1) & 0xFF, cell->i+1);
+                   return;
+                 case 1:
+                   set_soup (state, cell->frag, (cell->a-1) >> 8, cell->i);
+                   set_soup (state, cell->frag, (cell->a-1) & 0xFF, cell->i+1);
+                   return;
+                 case 2:
+                   set_soup (state, cell->frag, cell->a >> 8, cell->i+1);
+                   set_soup (state, cell->frag, cell->a & 0xFF, cell->i+2);
+                   return;
+                 case 3:
+                   set_soup (state, cell->frag, cell->a >> 8, cell->i-1);
+                   set_soup (state, cell->frag, cell->a & 0xFF, cell->i);
+                   return;
+                 }
+               return;
+             }
+           case 0x10:          /* XOR ... */
+             return;
+           case 0x11:
+             cell->a = cell->b; return;
+           case 0x12:
+             cell->a = cell->i; return;
+           case 0x13:
+             cell->a = cell->p; return;
+           case 0x14:
+             cell->b = cell->a; return;
+           case 0x15:
+             return;
+           case 0x16:
+             cell->b = cell->i; return;
+           case 0x17:
+             cell->b = cell->p; return;
+           case 0x18:
+             cell->i = cell->a; return;
+           case 0x19:
+             cell->i = cell->b; return;
+           case 0x1a:
+             return;
+           case 0x1b:
+             cell->i = cell->p; return;
+           case 0x1c:
+             cell->p = cell->a; return;
+           case 0x1d:
+             cell->p = cell->b; return;
+           case 0x1e:
+             cell->p = cell->i; return;
+           case 0x1f:
+             return;
+           }
+       }
+    }
+  else /* cell->state == state_find */
+    {
+      /* During finds,
+       * cell->p     == address of pattern complement to match
+       * cell->plen  == length of pattern
+       * cell->i     == current address of search
+       * cell->dir   == direction of search (-1 or 1)
+       * cell->lim   == number of steps before we give up
+       */
+      int i;
+
+#if TRACE
+      trace (cell, -1);
+#endif
+
+      for (i = 0; i < cell->plen; ++i)
+       {
+         int pat = get_soup (state, cell->frag, cell->p+i);
+         int mat = get_soup (state, cell->frag, cell->i+i);
+         if (pat > 1 || mat > 1 || pat == mat)
+           {
+             /* Not matched: continue searching. */
+             cell->i += cell->dir;
+             cell->lim--;
+             if (cell->lim == 0)
+               {
+                 /* Give up. */
+                 cell->i = 0;
+                 INC_ERRORS (state, cell);
+                 cell->state = state_exec;
+                 cell->p += cell->plen;
+                 return;
+               }
+             return;
+           }
+       } /* for */
+
+      /* Pattern matched! */
+      cell->p += cell->plen;
+      cell->state = state_exec;
+      return;
+    }
+}
+
+#if TRACE
+static void
+trace (const struct cell *cell, int insn)
+{
+  if (cell->state == state_exec)
+    {
+      printf ("x %p A:%d B:%d I:%d P:%d St:[%d %d %d..] e:%d [%p] ",
+             cell, cell->a, cell->b, cell->i, cell->p,
+             cell->stack[cell->sp],
+             cell->stack[(cell->sp-1) & (STACK_SIZE-1)],
+             cell->stack[(cell->sp-2) & (STACK_SIZE-1)],
+             cell->errors,
+             cell->daughter);
+      switch (insn)
+       {
+       case 0: printf ("NOP0"); break;
+       case 1: printf ("NOP1"); break;
+       case 2: printf ("INC A"); break;
+       case 3: printf ("DEC A"); break;
+       case 4: printf ("SHL A"); break;
+       case 7: printf ("IFZ"); break;
+       case 8: printf ("FINDB"); break;
+       case 9: printf ("FINDF"); break;
+       case 10: printf ("MALLOC"); break;
+       case 11: printf ("DIVIDE"); break;
+       case 12: printf ("MOVE [I],A"); break;
+       case 13: printf ("MOVE A,[I]"); break;
+       case 14: printf ("DMOVE [I],A"); break;
+       case 15: printf ("DMOVE A,[I]"); break;
+       case 16: case 17: case 18: case 19:
+       case 20: case 21: case 22: case 23:
+       case 24: case 25: case 26: case 27:
+       case 28: case 29: case 30: case 31:
+         printf ("XOR %c,%c", "ABIP"[insn&3], "ABIP"[(insn>>2)&3]); break;
+       case 32: case 33: case 34: case 35:
+         printf ("PUSH %c", "ABIP"[insn&3]); break;
+       case 36: case 37: case 38: case 39:
+         printf ("POP %c", "ABIP"[insn&3]); break;
+       default: printf ("unknown %d", insn); break;
+       }
+      printf ("\n");
+    }
+  else
+    {
+      printf ("f %p I:%d P:%d dir:%d plen:%d lim:%d\n",
+             cell, cell->i, cell->p, cell->dir, cell->plen, cell->lim);
+    }
+}
+#endif
diff --git a/god.dla b/god.dla
new file mode 100644 (file)
index 0000000..467538e
--- /dev/null
+++ b/god.dla
@@ -0,0 +1,90 @@
+;; GOD CELL
+;; BY RICHARD W.M. JONES
+
+00001:                                 ; Marks beginning of the cell.
+
+       JMPF ~00011                     ; Jump to start of the cell code
+                                       ; proper.
+
+00010:                                 ; Marks start of local variables.
+       DW 4                            ; Local variable storage.
+
+       ; This is the main cell program.
+
+00011:                                 ; Marks the start of the cell code.
+
+       ; When debugging, use this canard to detect stack underflows.
+       ;MOVE 65535,A
+       ;PUSH A
+
+       FINDB ~00010                    ; Find beginning of local variables.
+       MOVE I,A                        ; Add length of label.
+       ADD 5,A
+       MOVE A,B                        ; Initialize base register.
+       FINDB ~00001                    ; Find beginning address of cell.
+       MOVE I,A
+       STORE A,0                       ; Save it for later.
+       FINDF ~01111                    ; Find end address of cell.
+       MOVE I,A
+       ADD 5,A                         ; Add length of final label.
+       STORE A,1                       ; Save it for later.
+
+       CALLF ~00100                    ; Call subroutine to subtract
+                                       ; var 0 from var 1 and store in var 2.
+
+       LOAD 2,A                        ; Load the computed length.
+       MALLOC                          ; Allocate memory for the daughter.
+       MOVE I,A
+       JMPZB ~00011                    ; If allocation failed, start again.
+       STORE A,3                       ; Store the daughter's address in 3.
+
+       CALLF ~00110                    ; Call subroutine to do the copy.
+
+       DIVIDE                          ; Break off the daughter cell.
+
+       JMPB ~00011                     ; Repeat forever!
+
+       ; This subroutine subtracts var 0 from var 1 and stores the
+       ; resulting value in var 2.
+
+00100:
+       LOAD 1,A                        ; Copy var 1 into var 2
+       STORE A,2
+       LOAD 0,A                        ; A <- amount to subtract
+00101: JMPZF ~01001                    ; Loop until A == 0
+       PUSH A
+       LOAD 2,A                        ; Subtract 1 from var 2.
+       DEC A
+       STORE A,2
+       POP A
+       DEC A
+       JMPB ~00101
+01001: RET 5
+
+       ; This subroutine copies var 2 bytes from [var 0] to [var 3] (ie.
+       ; from the mother to the daughter).
+
+00110:
+       LOAD 2,A                        ; Number of bytes to copy.
+00111: JMPZF ~01000                    ; Leave loop when A == 0.
+       PUSH A
+       LOAD 0,A                        ; Get source address.
+       MOVE A,I
+       MOVE [I],A                      ; Get item to copy from source.
+       PUSH A
+       LOAD 3,A                        ; Get destination address.
+       MOVE A,I
+       POP A
+       MOVE A,[I]                      ; Store item at destination addr.
+       LOAD 0,A                        ; Increment source address.
+       INC A
+       STORE A,0
+       LOAD 3,A                        ; Increment destination address.
+       INC A
+       STORE A,3
+       POP A
+       DEC A
+       JMPB ~00111
+01000: RET 5
+
+01111:                                 ; Marks end of the cell.
diff --git a/god.dlo b/god.dlo
new file mode 100644 (file)
index 0000000..da9c6a2
--- /dev/null
+++ b/god.dlo
@@ -0,0 +1,56 @@
+00000000010901010100002227
+0000000100FFFFFFFFFFFFFFFF
+000000010108
+01010100012224
+0202020202
+2025
+08
+01010101002224
+222021242026240F26
+09
+01000000002224
+0202020202
+2220212402022026240F26
+230901010001012227
+2221240202020220260E26
+0A
+2224
+08010101000022072726
+222021240202020202022026240F26
+230901010000012227
+0B
+0801010100002227
+0000010000222124020220260E26
+22202124020202022026240F26
+22212420260E26
+000001000109010001010022072726
+20
+2221240202020220260E26
+03
+22202124020202022026240F26
+24
+03
+0801010001002227
+00010000012402020202020202022027
+00000101002221240202020220260E26
+000001010109010001010122072726
+20
+22212420260E26
+2026
+0C
+20
+22212402020202020220260E26
+2026
+24
+0D
+22212420260E26
+02
+222021242026240F26
+22212402020202020220260E26
+02
+222021240202020202022026240F26
+24
+03
+0801010000002227
+00010000002402020202020202022027
+0001010101
diff --git a/image.c b/image.c
new file mode 100644 (file)
index 0000000..ed632fd
--- /dev/null
+++ b/image.c
@@ -0,0 +1,106 @@
+/* DLIFE Copyright (C) 2000 Richard W.M. Jones <rich@annexia.org>
+ * and other authors listed in the ``AUTHORS'' file.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * $Id: image.c,v 1.2 2002/04/05 16:47:12 rich Exp $
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "image.h"
+#include "state.h"
+#include "cell.h"
+#include "soup.h"
+
+#define FILE_SAVE_VERSION 1
+
+static void global_state_save (struct state *state, FILE *fp);
+static void global_state_load (struct state *state, FILE *fp);
+
+struct state *
+image_load (const char *filename, int _soup_size, int thread_num)
+{
+  FILE *fp;
+  struct state *state;
+
+  fp = fopen (filename, "r");
+  if (fp == 0) { perror (filename); return 0; }
+
+  state = state_malloc (_soup_size, thread_num);
+
+  global_state_load (state, fp);
+  cell_state_load (state, fp);
+  soup_state_load (state, fp);
+
+  fclose (fp);
+
+  return state;
+}
+
+int
+image_save (struct state *state, const char *filename)
+{
+  FILE *fp;
+
+  fp = fopen (filename, "w");
+  if (fp == 0) { perror (filename); return -1; }
+
+  global_state_save (state, fp);
+  cell_state_save (state, fp);
+  soup_state_save (state, fp);
+
+  fclose (fp);
+
+  return 0;
+}
+
+static void
+global_state_save (struct state *state, FILE *fp)
+{
+  int version = FILE_SAVE_VERSION;
+
+  fwrite (&version, sizeof version, 1, fp);
+  fwrite (&state->cell_cycle, sizeof state->cell_cycle, 1, fp);
+}
+
+static void
+global_state_load (struct state *state, FILE *fp)
+{
+  int version;
+
+  if (fread (&version, sizeof version, 1, fp) != 1)
+    {
+      fprintf (stderr, "error in global state\n");
+      abort ();
+    }
+  if (version != FILE_SAVE_VERSION)
+    {
+      fprintf (stderr, "soup image version numbers do not match\n");
+      abort ();
+    }
+
+  if (fread (&state->cell_cycle, sizeof state->cell_cycle, 1, fp) != 1)
+    {
+      fprintf (stderr, "error in global state\n");
+      abort ();
+    }
+
+  if (verbose) printf ("Total number of cycles executed so far: %LuB\n",
+                      state->cell_cycle / 1000000000);
+}
diff --git a/image.h b/image.h
new file mode 100644 (file)
index 0000000..d127a6b
--- /dev/null
+++ b/image.h
@@ -0,0 +1,30 @@
+/* DLIFE Copyright (C) 2000 Richard W.M. Jones <rich@annexia.org>
+ * and other authors listed in the ``AUTHORS'' file.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * $Id: image.h,v 1.1 2002/04/05 14:40:27 rich Exp $
+ */
+
+#ifndef image_h
+#define image_h
+
+#include "state.h"
+
+extern struct state *image_load (const char *filename, int _soup_size,
+                                int thread_num);
+extern int image_save (struct state *state, const char *filename);
+
+#endif /* image_h */
diff --git a/index.html.in b/index.html.in
new file mode 100644 (file)
index 0000000..9b31ff0
--- /dev/null
@@ -0,0 +1,111 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<!-- -*- html -*- -->
+<html>
+  <head>
+    <title>Distributed Artificial Life</title>
+  </head>
+
+  <body bgcolor="#ffffff">
+    <h1 align="center">Distributed Artificial Life</h1>
+
+    <p>
+      DLIFE is a distributed version of <a
+      href="http://www.hip.atr.co.jp/~ray/">Tom S. Ray's</a> <a
+      href="http://www.hip.atr.co.jp/~ray/tierra/">Tierra</a>
+      artificial life program. Note that the machine language used is
+      similar to but not compatible with Tierra. Tom Ray talks about
+      his work (as far as I know, never completed) to create a <a
+      href="http://www.hip.atr.co.jp/~ray/pubs/reserves/">``Digital
+      Reserve''</a>. The DLIFE project is a development of this.
+    </p>
+
+    <p>
+      In other words, it's an alternative to the tedious process
+      of <a href="http://www.distributed.net/">cracking RC5 keys</a>
+      or <a href="http://setiathome.ssl.berkeley.edu/">searching
+       for aliens</a>. You've got a supercomputer on your desk,
+      let's go and create some life ...
+    </p>
+
+    <h2>News</h2>
+
+    <p><b>Fri Apr  5 23:03:27 BST 2002</b></p>
+
+    <p>
+      Version 1.0.0: Various fixes for Red Hat Linux 7.2.
+    </p>
+
+    <p><b>Mon Oct 16 23:11:13 BST 2000</b></p>
+
+    <p>
+      Version 0.0.16: Added another patch from Falk
+      Hueffner which improves the Debian package
+      handling.
+    </p>
+
+    <p><b>Sat Oct 14 15:44:27 BST 2000</b></p>
+
+    <p>
+      Version 0.0.15: Debian package (thanks to Falk Hueffner).
+      Client and soup processes now log status information to syslog.
+    </p>
+
+    <h2>Download</h2>
+
+    <p>
+      All software is distributed under the terms of the
+      <a href="files/COPYING">GNU General Public License (GPL)</a>.
+    </p>
+
+    <p>
+      The latest version is @VERSION@, released @RELEASEDATE@.
+    </p>
+
+    <table>
+      <tr>
+       <td> Source code for client and server </td>
+       <td> <a href="files/dlife-@VERSION@.tar.gz">dlife-@VERSION@.tar.gz</a> </td>
+      </tr>
+      <tr>
+       <td> Client: Binary RPM (for Red Hat, i686) </td>
+       <td> <a href="files/dlife-@VERSION@-1.i686.rpm">dlife-@VERSION@-1.i686.rpm</a> </td>
+      </tr>
+      <tr>
+       <td> Server: Binary RPM (for Red Hat, i686) </td>
+       <td> <a href="files/dlife-server-@VERSION@-1.i686.rpm">dlife-server-@VERSION@-1.i686.rpm</a> </td>
+      </tr>
+      <tr>
+       <td> Source RPM </td>
+       <td> <a href="files/dlife-@VERSION@-1.src.rpm">dlife-server-@VERSION@-1.src.rpm</a> </td>
+      </tr>
+      <tr>
+       <td> Perl RPMs </td>
+       <td> <a href="files/">Various Perl RPMs which you may require ...</a> </td>
+      </tr>
+    </table>
+
+    <p align="right"><a href="http://www.annexia.org/cgi-bin/autopatch.pl?dir=dlife">Patches from previous versions ...</a></p>
+    <p align="right"><a href="files/">Previous versions ...</a></p>
+
+    <h2>Documentation</h2>
+
+    <ul>
+      <li> <a href="machineref.html">DLIFE machine language reference</a> <br>
+       Documents the machine language implemented in the DLIFE
+       VM, the underlying philosophy, and how it differs from
+       the original Tierra machine language.
+      <li> <a href="archref.html">DLIFE distributed architecture reference</a>
+       <br>
+       Documents the distributed architecture of DLIFE, how
+       the VM runs, how cells get distributed between soups,
+       and how the C VM code and Perl network code interact.
+    </ul>
+
+    <hr>
+    <address><a href="mailto:rich@annexia.org">rich@annexia.org</a></address>
+<!-- Created: Fri Oct  6 14:35:11 BST 2000 -->
+<!-- hhmts start -->
+Last modified: Mon Oct 16 23:11:50 BST 2000
+<!-- hhmts end -->
+  </body>
+</html>
diff --git a/install-sh b/install-sh
new file mode 120000 (symlink)
index 0000000..e534836
--- /dev/null
@@ -0,0 +1 @@
+/usr/share/automake-1.4/install-sh
\ No newline at end of file
diff --git a/load.c b/load.c
new file mode 100644 (file)
index 0000000..68b9128
--- /dev/null
+++ b/load.c
@@ -0,0 +1,116 @@
+/* DLIFE Copyright (C) 2000 Richard W.M. Jones <rich@annexia.org>
+ * and other authors listed in the ``AUTHORS'' file.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * $Id: load.c,v 1.2 2002/04/05 16:47:12 rich Exp $
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "types.h"
+#include "load.h"
+#include "cell.h"
+#include "soup.h"
+#include "state.h"
+
+struct cell *
+load_cell (struct state *state, const char *filename)
+{
+  FILE *fp;
+  int allocated = 0;
+  int len = 0;
+  char line[256];
+  byte_t *code = 0;
+  int n = 0, i, c = 0;
+  struct cell *cell;
+  struct soup_frag *frag;
+
+  fp = fopen (filename, "r");
+  if (fp == 0) { perror (filename); return 0; }
+
+  while (fgets (line, sizeof line, fp) != 0 && len < MAX_CELL_SIZE)
+    {
+      for (i = 0; i < strlen (line); ++i)
+       {
+         if (line[i] >= '0' && line[i] <= '9')
+           {
+             n *= 16;
+             n += line[i] - '0';
+             c++;
+           }
+         else if (line[i] >= 'a' && line[i] <= 'f')
+           {
+             n *= 16;
+             n += line[i] - 'a' + 10;
+             c++;
+           }
+         else if (line[i] >= 'A' && line[i] <= 'F')
+           {
+             n *= 16;
+             n += line[i] - 'A' + 10;
+             c++;
+           }
+         if (c == 2)
+           {
+             if (allocated - len <= 0)
+               {
+                 code = realloc (code, allocated += 256);
+                 if (code == 0) { perror ("realloc"); abort (); }
+               }
+             code[len++] = n;
+             n = c = 0;
+           }
+       }
+    }
+
+  if (c != 0)
+    {
+      fprintf (stderr, "%s: error in input file\n", filename);
+      fclose (fp);
+      free (code);
+      return 0;
+    }
+
+  fclose (fp);
+
+  /* Refuse any cells which are too small or too large. */
+  if (len < MIN_CELL_SIZE || len > MAX_CELL_SIZE)
+    {
+      fprintf (stderr, "%s: cell is too small or too large (len = %d)\n",
+              filename, len);
+      free (code);
+      return 0;
+    }
+
+  /* Allocate soup fragment. */
+  frag = soup_frag_malloc (state, 0, len);
+  if (frag == 0) { free (code); return 0; }
+
+  /* Allocate cell. */
+  cell = cell_malloc (state, 0, frag);
+  if (cell == 0) { free (code); return 0; }
+
+  /* Populate cell. */
+  for (i = 0; i < len; ++i)
+    set_soup (state, cell->frag, code[i], i);
+  free (code);
+
+  return cell;
+}
diff --git a/load.h b/load.h
new file mode 100644 (file)
index 0000000..9343cf3
--- /dev/null
+++ b/load.h
@@ -0,0 +1,29 @@
+/* DLIFE Copyright (C) 2000 Richard W.M. Jones <rich@annexia.org>
+ * and other authors listed in the ``AUTHORS'' file.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * $Id: load.h,v 1.1 2002/04/05 14:40:27 rich Exp $
+ */
+
+#ifndef load_h
+#define load_h
+
+#include "config.h"
+#include "state.h"
+
+extern struct cell *load_cell (struct state *state, const char *filename);
+
+#endif /* load_h */
diff --git a/machineref.html b/machineref.html
new file mode 100644 (file)
index 0000000..2ed3d98
--- /dev/null
@@ -0,0 +1,746 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+  <head>
+    <title>DLIFE machine language reference</title>
+  </head>
+
+  <body bgcolor="#ffffff">
+    <h1>DLIFE machine language reference</h1>
+
+    <h2>General overview</h2>
+
+    <p>
+      I'm going to assume that you're mostly familiar
+      with <a href="http://www.hip.atr.co.jp/~ray/tierra/">Tierra</a>,
+      but I'll also give you a short introduction.
+    </p>
+
+    <p>
+      In DLIFE/Tierra, life forms consist of small
+      machine language programs called ``cells''.
+      Each cell has its own program counter and hence
+      its own thread of execution, and runs independently
+      of any other cell. Cells live in a virtual machine
+      (VM) called the ``soup''. The soup is just a big
+      piece of byte-addressed memory, 128 Kbytes in size
+      by default.
+    </p>
+
+    <p>
+      The soup contains an interpreter which interprets
+      the machine language. For DLIFE cells, the soup
+      is their entire universe. They cannot address or
+      access anything outside their own soup. (Although
+      they can occasionally jump from one soup to another
+      -- but more of that later).
+    </p>
+
+    <p>
+      All the cells sharing the soup are run timesliced
+      in a simple round-robin scheme, and hence each
+      cell will get roughly the same amount of actual CPU
+      dedicated to it.
+    </p>
+
+    <p>
+      The cell machine language is not 8086 assembler. In
+      fact, it's a special purpose machine language written
+      just to run cells. It has some similarities with
+      more traditional machine languages -- for example,
+      registers, indirect addressing, jumps, a stack,
+      and so on -- but also some strange features that
+      you wouldn't expect to find in a real machine
+      language. The most important feature of the
+      language is termed (in a term coined by Tom
+      Ray) its ``non-brittleness''. This means that
+      the language is robust against small corruptions,
+      changes, and the insertion or deletion of a few
+      bytes here and there. In a real machine language,
+      inserting a few bytes into a piece of code requires
+      that you relink the code so that all jump and call
+      target addresses change. If you didn't relink the code,
+      then the insertion would be fatal -- the code wouldn't
+      function at all. Real machine languages are said to
+      be ``brittle''. In the DLIFE machine language, insertions
+      and deletions are tolerated -- the code will continue to
+      work much as before. The main way in which this works
+      is that absolute addresses have been replaced by
+      explicit labels in the code:
+    </p>
+
+<pre>
+  code
+  : :
+  code
+  label 123
+  code
+  : :   <---
+  code
+  jump to label 123
+  code
+  : :
+  code
+</pre>
+
+    <p>
+      Suppose in the example above that an accidental
+      insertion or deletion occurs at the point marked by the arrow.
+      The chances are that the code will continue to work,
+      because the ``jump'' command will still be able to
+      find and jump to the correct label.
+    </p>
+
+    <p>
+      Another important and unusual feature of the machine
+      language is that it allows cells to reproduce. Through
+      the use of the <tt>MALLOC</tt> and <tt>DIVIDE</tt>
+      instructions, a cell may produce a daughter cell,
+      populate it with code, and then divide (set it running
+      as an independent cell).
+    </p>
+
+    <p>
+      The soup interpreter is error-prone. Most instructions
+      will run as intended, but occasionally instructions
+      fail in certain ways. For example, an instruction to
+      increment the accumulator might, one in a hundred thousand times,
+      increment the accumulator <i>twice</i>, or even not at
+      all. The soup memory is also error-prone. So-called
+      cosmic rays hit the soup very occasionally, flipping
+      bits at random. By these means, cells may occasionally
+      mutate. Note that because the machine language is
+      very deliberately chosen to be non-brittle, mutations
+      often result in cells which still work, but perhaps
+      work in slightly different (better?) ways. Hence
+      cells evolve.
+    </p>
+
+    <p>
+      There is one initial cell, which was written by hand. This
+      cell is called the ``god cell'' (although perhaps Adam
+      or Eve might have been a better biblical parallel). This
+      cell simply copies itself repeatedly.
+    </p>
+
+    <p>
+      Cells which execute instructions incorrectly (for
+      example, they do not fill the accumulator register
+      with a suitable value before calling <tt>MALLOC</tt>)
+      accumulate errors. As the soup becomes more and more
+      full, a special process called the ``grim reaper''
+      is invoked. The grim reaper kills off the cells
+      with the largest error count until the soup pressure
+      is eased.
+    </p>
+
+    <p>
+      The DLIFE model is one of pure natural selection. There
+      are no artificial pressures placed on cells to become,
+      for example, good at executing some particular algorithm.
+      Instead, cells compete simply for space in the soup
+      and time on the virtual CPU.
+    </p>
+
+    <h2>Cell virtual machine</h2>
+
+    <p>
+      The cell VM consists of 4 registers, some local
+      storage, a stack and stack pointer, an error counter
+      and possibly an attached daughter cell.
+    </p>
+
+    <h3>Registers</h3>
+
+    <p>
+      The 4 visible registers are:
+    </p>
+
+    <table>
+      <tr>
+       <th> Register </th> <th> Purpose </th>
+      </tr>
+      <tr>
+       <td> A </td> <td> The accumulator, for mathematical
+         operations and general purpose use. </td>
+      </tr>
+      <tr>
+       <td> B </td> <td> Base address, for addressing local variables. </td>
+      </tr>
+      <tr>
+       <td> I </td> <td> Index address. </td>
+      </tr>
+      <tr>
+       <td> P </td> <td> Program counter. </td>
+      </tr>
+    </table>
+
+    <p>
+      All registers are 16 bit signed integers, storing
+      any value between -32768 and 32767 inclusive.
+    </p>
+
+    <p>
+      All addresses are stored relative to the start
+      address of the cell. Hence if P is set to zero,
+      then execution jumps to the beginning of the cell's
+      code.
+    </p>
+
+    <p>
+      When a cell is created, all registers are initialized
+      to zero.
+    </p>
+
+    <h3>Local storage</h3>
+
+    <p>
+      The cell has a fragment of soup memory. Because addresses
+      are relative, to the cell the memory appears to stretch from
+      address 0 to address N-1, where N is the total number
+      of bytes allocated to the cell by her mother's call
+      to <tt>MALLOC</tt>. It is not possible for
+      the cell to find out the value of N (we assume that
+      the mother allocated enough memory for the cell).
+    </p>
+
+    <p>
+      A cell may store code or data at any memory address
+      within itself. There is no distinction made in the
+      VM between code and data.
+    </p>
+
+    <p>
+      A cell may not write to memory outside the range 0 to N-1.
+      Doing so will incur an error. Cells may, however, read
+      any memory outside this range.
+    </p>
+
+    <p>
+      After calling <tt>MALLOC</tt>, the I register is
+      initialized with the start address of the daughter
+      cell. Between the <tt>MALLOC</tt> and the next call
+      to <tt>DIVIDE</tt>, the cell may additionally write
+      to addresses I through I + A - 1, in order to initialize
+      the daughter.
+    </p>
+
+    <h3>Stack</h3>
+
+    <p>
+      The cell has a stack of 16 words. Each stack entry is
+      a 16 bit signed integer.
+    </p>
+
+    <p>
+      A stack pointer stores the current position in the
+      stack.
+    </p>
+
+    <p>
+      The stack can only be accessed through one of the <tt>PUSH</tt>
+      or <tt>POP</tt> instructions. <tt>PUSH x</tt> (where ``x'' is
+      the name of a register) increments the value of the
+      stack pointer and copies the value in register x onto
+      the stack at the position addressed by the stack pointer.
+      <tt>POP x</tt> copies the value on the stack addressed
+      by the stack pointer into register x and decrements the
+      value of the stack pointer.
+    </p>
+
+    <p>
+      The stack is circular, in that pushing more than 16 numbers
+      onto the stack causes the stack to wrap around and overwrite
+      the top entry. Thus it is not possible to underflow or
+      overflow the stack.
+    </p>
+
+    <p>
+      The stack pointer register is not visible to the cell
+      VM. In other words, the cell cannot directly read or write
+      to the stack pointer (except implicitly through use of
+      the <tt>PUSH</tt> or <tt>POP</tt> instructions). Because
+      of this, it is not possible for the cell to tell if the
+      stack is implemented as grows-down or grows-up, nor
+      whether the implementation pushes first and changes the
+      stack pointer second or vice versa.
+    </p>
+
+    <p>
+      When the cell is created, all stack entries and the stack
+      pointer are initialized to zero.
+    </p>
+
+    <h3>Error counter</h3>
+
+    <p>
+      The error counter starts off at zero, and is incremented
+      by one every time the cell makes a mistake when
+      executing an instruction. Typical mistakes are:
+    </p>
+
+    <ul>
+      <li> Incorrectly initializing the A register before
+       calling <tt>MALLOC</tt>.
+      <li> Not calling <tt>MALLOC</tt> before calling <tt>DIVIDE</tt>.
+      <li> Not calling <tt>DIVIDE</tt> before calling <tt>MALLOC</tt>.
+      <li> Executing <tt>FINDF</tt> or <tt>FINDB</tt> and not
+       finding a matching label.
+    </ul>
+
+    <h2>Basic instruction set</h2>
+
+    <p>
+      The basic instruction set consists of just 17 commands
+      encoded in just 38 different numeric values.
+    </p>
+
+    <p>
+      Each instruction is encoded in a single byte.
+    </p>
+
+    <p>
+      Two instructions, <tt>FINDB</tt> and <tt>FINDF</tt>
+      might be considered to be multi-byte instructions.
+      See the description below for details.
+    </p>
+
+    <p>
+      There is one instruction prefix, <tt>IFZ</tt>, but
+      in the discussion below, we will just consider it
+      as if it was a single byte instruction (which, in
+      fact, it is).
+    </p>
+
+    <p>
+      The VM makes no distinction between code and data.
+      Any byte which is addressable as part of the mother
+      cell can be considered to be either executable
+      code or a data byte (or both).
+    </p>
+
+    <p>
+      Instructions are encoded into soup bytes as follows:
+    </p>
+
+<pre>
+ Most                              Least
+ significant                 significant
+ bit                                 bit
++----+----+----+----+----+----+----+----+
+|    |    |    |    |    |    |    |    |
+| 7  | 6  | 5  | 4  | 3  | 2  | 1  | 0  |
+|    |    |    |    |    |    |    |    |
++----+----+----+----+----+----+----+----+
+ \_______/ \___________________________/
+     |                   |
+  Ignored       Instruction encoding
+             (values 0-4,7-39 correspond to
+              instructions, values 40-63
+              are unknown and result in
+              cell errors)
+</pre>
+
+    <p>
+      The lower 6 bits are interpreted as follows:
+    </p>
+
+    <table border=1>
+      <tr>
+       <th> Dec </th>
+       <th> Hex </th>
+       <th> Bin </th>
+       <th> Mnemonic </th>
+       <th> Meaning </th>
+      </tr>
+      <tr>
+       <td> 0 </td> <td> 00 </td> <td> 00 0000 </td>
+       <td> <tt>NOP0</tt> </td>
+       <td> No-op. This instruction does nothing when executed
+         but is used as a pattern matching label by <tt>FINDB</tt>
+         and <tt>FINDF</tt>. </td>
+      </tr>
+      <tr>
+       <td> 1 </td> <td> 01 </td> <td> 00 0001 </td>
+       <td> <tt>NOP1</tt> </td>
+       <td> No-op. This instruction does nothing when executed
+         but is used as a pattern matching label by <tt>FINDB</tt>
+         and <tt>FINDF</tt>. </td>
+      </tr>
+      <tr>
+       <td> 2 </td> <td> 02 </td> <td> 00 0010 </td>
+       <td> <tt>INC A</tt> </td>
+       <td> A &lt;- A + 1 </td>
+      </tr>
+      <tr>
+       <td> 3 </td> <td> 03 </td> <td> 00 0011 </td>
+       <td> <tt>DEC A</tt> </td>
+       <td> A &lt;- A - 1 </td>
+      </tr>
+      <tr>
+       <td> 4 </td> <td> 04 </td> <td> 00 0100 </td>
+       <td> <tt>SHL A</tt> </td>
+       <td> A &lt;- A << 1 </td>
+      </tr>
+      <tr>
+       <td> 7 </td> <td> 07 </td> <td> 00 0111 </td>
+       <td> <tt>IFZ</tt> </td>
+       <td> <tt>IFZ</tt> is normally used as an instruction
+         prefix, ie. <tt>IFZ</tt> &lt;instruction&gt;.
+         If A == 0, execute the next instruction,
+         otherwise skip the next instruction. </td>
+      </tr>
+      <tr>
+       <td> 8 </td> <td> 08 </td> <td> 00 1000 </td>
+       <td> <tt>FINDB</tt> </td>
+       <td> <tt>FINDB</tt> should be followed by a pattern
+         (a series of one or more NOP0 and NOP1 bytes). The
+         <tt>FINDB</tt> instruction searches backwards
+         from the current program counter until it finds
+         the <tt>inverse</tt> pattern of NOP0 and NOP1 bytes.
+         It returns the relative address of the found pattern
+         in register I. If the pattern is not found, it
+         sets I == 0.
+       </td>
+      </tr>
+      <tr>
+       <td> 9 </td> <td> 09 </td> <td> 00 1001 </td>
+       <td> <tt>FINDF</tt> </td>
+       <td> <tt>FINDF</tt> should be followed by a pattern
+         (a series of one or more NOP0 and NOP1 bytes). The
+         <tt>FINDF</tt> instruction searches forwards
+         from the current program counter until it finds
+         the <tt>inverse</tt> pattern of NOP0 and NOP1 bytes.
+         It returns the relative address of the found pattern
+         in register I. If the pattern is not found, it
+         sets I &lt;- 0.
+       </td>
+      </tr>
+      <tr>
+       <td> 10 </td> <td> 0A </td> <td> 00 1010 </td>
+       <td> <tt>MALLOC</tt> </td>
+       <td> <tt>MALLOC</tt> allocates a daughter
+         cell of size A bytes. It returns the address
+         of the daughter cell in register I, or if the
+         memory could not be allocated, it sets I &lt;- 0.
+         Only one daughter cell may be allocated at a
+         time. Therefore, calling <tt>MALLOC</tt> twice
+         without calling <tt>DIVIDE</tt> in between is an
+         error. Register A must be between 10 and 512.
+       </td>
+      </tr>
+      <tr>
+       <td> 11 </td> <td> 0B </td> <td> 00 1011 </td>
+       <td> <tt>DIVIDE</tt> </td>
+       <td> <tt>DIVIDE</tt> splits off the current daughter
+         cell and starts it running as a fully independent
+         cell. The daughter cell must first have been allocated
+         by <tt>MALLOC</tt> and populated with code, so
+         calling <tt>DIVIDE</tt> twice without calling
+         <tt>MALLOC</tt> in between is an error.
+       </td>
+      </tr>
+      <tr>
+       <td> 12 </td> <td> 0C </td> <td> 00 1100 </td>
+       <td> <tt>MOVE [I],A</tt> </td>
+       <td> Load the unsigned byte at relative address I into
+         register A.
+       </td>
+      </tr>
+      <tr>
+       <td> 13 </td> <td> 0D </td> <td> 00 1101 </td>
+       <td> <tt>MOVE A,[I]</tt> </td>
+       <td> Store the value of register A in the soup byte
+         at relative address I. If A is less than 0 or
+         greater than 255 then the effects are undefined.
+         If I lies outside the boundaries of the mother
+         or daughter cells, then this is a cell error.
+       </td>
+      </tr>
+      <tr>
+       <td> 14 </td> <td> 0E </td> <td> 00 1110 </td>
+       <td> <tt>DMOVE [I],A</tt> </td>
+       <td> Load the signed word (two bytes) at relative address I
+         into register A. The VM is big endian (Motorola ordering).
+       </td>
+      </tr>
+      <tr>
+       <td> 15 </td> <td> 0F </td> <td> 00 1111 </td>
+       <td> <tt>DMOVE A,[I]</tt> </td>
+       <td> Store the value of register A in the soup
+         bytes at relative address I and I+1. If (I, I+1)
+         lies outside the boundaries of the mother or
+         daughter cells, then this is a cell error.
+         The VM is big endian (Motorola ordering).
+       </td>
+      </tr>
+      <tr>
+       <td> 16-31 </td> <td> 10-1F </td> <td> 01 r2r1 </td>
+       <td> <tt>XOR &lt;reg1&gt;,&lt;reg2&gt; </tt> </td>
+       <td> &lt;reg2&gt; &lt;- &lt;reg1&gt; XOR &lt;reg2&gt;
+         for any registers in A (00), B (01), I (10) or P (11).
+       </td>
+      </tr>
+      <tr>
+       <td> 32-35 </td> <td> 20-23 </td> <td> 10 00rr </td>
+       <td> <tt>PUSH &lt;reg&gt; </tt> </td>
+       <td> Push the register onto the stack for any
+         registers in A (00), B (01), I (10) or P (11).
+       </td>
+      </tr>
+      <tr>
+       <td> 36-39 </td> <td> 24-27 </td> <td> 10 01rr </td>
+       <td> <tt>POP &lt;reg&gt; </tt> </td>
+       <td> Pop the top of the stack into the register for
+         any registers in A (00), B (01), I (10) or P (11).
+       </td>
+      </tr>
+    </table>
+
+    <p>
+      Note that instruction encodings 5, 6 and 40-63 are
+      not used. Attempting to execute one of these unknown
+      instructions results in a cell error.
+    </p>
+
+    <h2>Instruction set timings</h2>
+
+    <p>
+      This table shows the number of (virtual) CPU cycles
+      taken to execute each instruction.
+    </p>
+
+    <table border=1>
+      <tr>
+       <th> Instruction </th>
+       <th> Cycles </th>
+       <th> Notes </th>
+      </tr>
+      <tr> <td> <tt>NOP0</tt> </td> <td> 1 </td> </tr>
+      <tr> <td> <tt>NOP1</tt> </td> <td> 1 </td> </tr>
+      <tr> <td> <tt>INC A</tt> </td> <td> 1 </td> </tr>
+      <tr> <td> <tt>DEC A</tt> </td> <td> 1 </td> </tr>
+      <tr> <td> <tt>SHL A</tt> </td> <td> 1 </td> </tr>
+      <tr> <td> <tt>IFZ</tt> </td> <td> 1 </td> </tr>
+      <tr> <td> <tt>FINDB</tt> </td> <td> 1 + n </td>
+       <td> ``n'' is the distance between the current
+         program counter and the start of the matched
+         pattern. </td>
+      </tr>
+      <tr> <td> <tt>FINDF</tt> </td> <td> 1 + n</td>
+       <td> ``n'' is the distance between the current
+         program counter and the start of the matched
+         pattern. </td>
+      </tr>
+      <tr> <td> <tt>MALLOC</tt> </td> <td> 1 </td> </tr>
+      <tr> <td> <tt>DIVIDE</tt> </td> <td> 1 </td> </tr>
+      <tr> <td> <tt>MOVE [I],A</tt> </td> <td> 1 </td> </tr>
+      <tr> <td> <tt>MOVE A,[I]</tt> </td> <td> 1 </td> </tr>
+      <tr> <td> <tt>DMOVE [I],A</tt> </td> <td> 1 </td> </tr>
+      <tr> <td> <tt>DMOVE A,[I]</tt> </td> <td> 1 </td> </tr>
+      <tr> <td> <tt>XOR &lt;reg1&gt;,&lt;reg2&gt;</tt> </td> <td> 1 </td> </tr>
+      <tr> <td> <tt>PUSH &lt;reg&gt;</tt> </td> <td> 1 </td> </tr>
+      <tr> <td> <tt>POP &lt;reg&gt;</tt> </td> <td> 1 </td> </tr>
+    </table>
+
+    <h2>Instruction set macros</h2>
+
+    <p>
+      The basic instruction set is augmented with macros
+      which allow common programming paradigms to be
+      written. Macros are just a short-hand used in
+      the assembler / disassembler, and are not implemented
+      in any way by the VM.
+    </p>
+
+    <table border=1>
+      <tr>
+       <th> Macro </th>
+       <th> Expands to </th>
+       <th> Meaning </th>
+       <th> Side effects? </th>
+      </tr>
+      <tr>
+       <th colspan=4> Basic register operations ... </th>
+      </tr>
+      <tr>
+       <td> <tt>MOVE &lt;reg1&gt;,&lt;reg2&gt;</tt> </td>
+       <td> <tt>PUSH &lt;reg1&gt;<br>POP &lt;reg2&gt;</tt> </td>
+       <td> Move the contents of register 1 into register 2. </td>
+       <td> None. </td>
+      </tr>
+      <tr>
+       <td> <tt>SWAP &lt;reg1&gt;,&lt;reg2&gt;</tt> </td>
+       <td> <tt>XOR &lt;reg1&gt;,&lt;reg2&gt;<br>
+           XOR &lt;reg2&gt;,&lt;reg1&gt;<br>
+           XOR &lt;reg1&gt;,&lt;reg2&gt;<br>
+           XOR &lt;reg2&gt;,&lt;reg1&gt;</tt> </td>
+       <td> This has the effect of swapping the contents of
+         registers 1 and 2. </td>
+       <td> None. </td>
+      </tr>
+      <tr>
+       <td> <tt>ZERO &lt;reg&gt;</tt> </td>
+       <td> <tt>XOR &lt;reg&gt;,&lt;reg&gt;</tt> </td>
+       <td> A &lt;- 0 </td>
+       <td> None. </td>
+      </tr>
+      <tr>
+       <td> <tt>ADD &lt;n&gt;, A</tt> </td>
+       <td> <tt>INC A</tt> repeated n times. This is only
+       really suitable for small values of n. </td>
+       <td> A &lt;- A + n </td>
+       <td> None. </td>
+      </tr>
+      <tr>
+       <td> <tt>MOVE &lt;n&gt;, A</tt> </td>
+       <td> <tt>ZERO A</tt> followed by a series of
+         <tt>SHL A</tt> and <tt>INC A</tt> operations
+         required to initialize A to n. (n &gt;= 0) </td>
+       <td> A &lt;- n </td>
+       <td> None. </td>
+      </tr>
+      <tr>
+       <th colspan=4> Access local (word-sized) variables, relative
+         to the base address register B ... </th>
+      </tr>
+      <tr>
+       <td> <tt>LOAD &lt;n&gt;, A</tt> </td>
+       <td> <tt>PUSH I<br>MOVE B,A<br>ADD n*2,A<br>MOVE A,I<br>
+           DMOVE [I],A<br>POP I</tt> </td>
+       <td> Load variable number n into register A. </td>
+       <td> Destroys contents of I register. </td>
+      </tr>
+      <tr>
+       <td> <tt>STORE A,&lt;n&gt;</tt> </td>
+       <td> <tt>PUSH I<br>PUSH A<br>MOVE B,A<br>ADD n*2,A<br>MOVE A,I<br>
+           POP A<br>DMOVE A,[I]<br>POP I</tt> </td>
+       <td> Store register A in variable number n. </td>
+       <td> Destroys contents of I register. </td>
+      </tr>
+      <tr>
+       <th colspan=4> Jumps and subroutines ... </th>
+      </tr>
+      <tr>
+       <td> <tt>JMP I</tt> </td>
+       <td> <tt>PUSH I<br>POP P</tt> </td>
+       <td> Jump to address I. </td>
+       <td> None. </td>
+      </tr>
+      <tr>
+       <td> <tt>JMPF &lt;pattern&gt;</tt> </td>
+       <td> <tt>FINDF &lt;pattern&gt;<br>PUSH I<br>POP P</tt> </td>
+       <td> Jump forwards to pattern. </td>
+       <td> Destroys contents of I register. </td>
+      </tr>
+      <tr>
+       <td> <tt>JMPB &lt;pattern&gt;</tt> </td>
+       <td> <tt>FINDB &lt;pattern&gt;<br>PUSH I<br>POP P</tt> </td>
+       <td> Jump backwards to pattern. </td>
+       <td> Destroys contents of I register. </td>
+      </tr>
+      <tr>
+       <td> <tt>JMPZF &lt;pattern&gt;</tt> </td>
+       <td> <tt>FINDF &lt;pattern&gt;<br>PUSH I<br>IFZ POP P<br>
+           POP I</tt> </td>
+       <td> If A == 0, jump forwards to pattern. </td>
+       <td> Destroys contents of I register. </td>
+      </tr>
+      <tr>
+       <td> <tt>JMPZB &lt;pattern&gt;</tt> </td>
+       <td> <tt>FINDB &lt;pattern&gt;<br>PUSH I<br>IFZ POP P<br>
+           POP I</tt> </td>
+       <td> If A == 0, jump backwards to pattern. </td>
+       <td> Destroys contents of I register. </td>
+      </tr>
+      <tr>
+       <td> <tt>CALLF &lt;pattern&gt;</tt> </td>
+       <td> <tt>PUSH P<br>FINDF &lt;pattern&gt;<br>PUSH I<br>POP P</tt> </td>
+       <td> Call forwards to a subroutine at pattern. The current
+         address is saved on the stack. </td>
+       <td> Destroys contents of I register. </td>
+      </tr>
+      <tr>
+       <td> <tt>CALLB &lt;pattern&gt;</tt> </td>
+       <td> <tt>PUSH P<br>FINDB &lt;pattern&gt;<br>PUSH I<br>POP P</tt> </td>
+       <td> Call backwards to a subroutine at pattern. The current
+         address is saved on the stack. </td>
+       <td> Destroys contents of I register. </td>
+      </tr>
+      <tr>
+       <td> <tt>RET &lt;n&gt;</tt> </td>
+       <td> <tt>POP A<br>ADD n+3,A<br>MOVE A,P</tt> </td>
+       <td> Return from subroutine. n is the length of the
+         pattern in the corresponding <tt>CALLF</tt>/<tt>CALLB</tt>
+         instruction. The return address should be the top
+         address on the stack. </td>
+       <td> Destroys contents of A register. </td>
+      </tr>
+      <tr>
+       <th colspan=4> Assembler directives ... </th>
+      </tr>
+      <tr>
+       <td> <tt>DB &lt;n&gt;</tt> </td>
+       <td> &nbsp; </td>
+       <td> Define n bytes of scratch space. The scratch
+         space is initialized with 0xFF bytes (<strong>not</strong>
+         with zero bytes, since those clash with pattern symbols). </td>
+       <td> None. </td>
+      </tr>
+    </table>
+
+    <h2>Patterns</h2>
+
+    <p>
+      The assembler recognizes patterns and writes out
+      a series of <tt>NOP0</tt> and <tt>NOP1</tt> bytes.
+    </p>
+
+    <table border=1>
+      <tr>
+       <th> Mnemonic </th> <th> Expands to </th>
+      </tr>
+      <tr>
+       <td> <tt>&lt;pattern&gt;:</tt> </td>
+       <td> Each 0 and 1 in the pattern is translated into
+         a NOP0 and NOP1 on output. </td>
+      </tr>
+      <tr>
+       <td> <tt>~&lt;pattern&gt;:</tt> </td>
+       <td> Each 0 and 1 in the pattern is translated into
+         a NOP1 and NOP0 on output (note the inversion). </td>
+      </tr>
+      <tr>
+       <td> instruction <tt>&lt;pattern&gt;:</tt> </td>
+       <td> Each 0 and 1 in the pattern is translated into
+         a NOP0 and NOP1 on output. </td>
+      </tr>
+      <tr>
+       <td> instruction <tt>~&lt;pattern&gt;:</tt> </td>
+       <td> Each 0 and 1 in the pattern is translated into
+         a NOP1 and NOP0 on output (note the inversion). </td>
+      </tr>
+    </table>
+
+    <p>
+      Since the <tt>FINDB</tt> and <tt>FINDF</tt> patterns
+      search for the <i>inverse</i> of a pattern, a typical
+      instruction sequence will look like this:
+    </p>
+
+<pre>
+0011:
+  ; : :
+  ; : :
+
+  FINDB ~0011
+  ; I contains address of 0011 pattern.
+</pre>
+
+    <hr>
+    <address><a href="mailto:rich@annexia.org">Richard Jones</a></address>
+<!-- Created: Sat Oct  7 10:09:40 BST 2000 -->
+<!-- hhmts start -->
+Last modified: Sat Oct  7 13:49:42 BST 2000
+<!-- hhmts end -->
+  </body>
+</html>
diff --git a/main.c b/main.c
new file mode 100644 (file)
index 0000000..8122d7e
--- /dev/null
+++ b/main.c
@@ -0,0 +1,483 @@
+/* DLIFE Copyright (C) 2000 Richard W.M. Jones <rich@annexia.org>
+ * and other authors listed in the ``AUTHORS'' file.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * $Id: main.c,v 1.3 2002/12/11 17:16:21 rich Exp $
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+
+#ifdef HAVE_GRP_H
+#include <grp.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
+#include "cell.h"
+#include "soup.h"
+#include "load.h"
+#include "params.h"
+#include "random.h"
+#include "state.h"
+#include "image.h"
+
+unsigned soup_fetch_failure          = 1000000;
+unsigned inc_pc_failure              = 1000000;
+unsigned insn_exec_failure           = 1000000;
+unsigned access_control_failure      =      10;
+unsigned cell_initialization_failure = 1000000;
+int reaper_invoke_threshold          = 80;
+int reaper_reap_threshold            = 79;
+int save_period                      = 5;
+int outgoing_period                  = 10;
+int incoming_period                  = 60;
+int info_period                      = 60;
+int max_cells_incoming_per_pass      = 4;
+
+int verbose = 0;
+
+static int soup_size = 128*1024; /* Read from configuration file. */
+
+static const char *conf_file = CONFDIR "/soup.conf";
+static const char *save_dir = SPOOLDIR;
+
+static void parse_args (int argc, char *argv[]);
+static void read_config_file (void);
+static int detect_nr_cpus (void);
+
+int
+main (int argc, char *argv[])
+{
+  char filename[256];
+  int nr_cpus, i;
+
+  /* Parse the command line. */
+  parse_args (argc, argv);
+
+  /* Read the configuration file. */
+  read_config_file ();
+
+  /* Initialize stuff. */
+  random_init ();
+
+#ifdef HAVE_OPENLOG
+  /* Open connection to syslog. */
+  openlog ("dlife_soup", LOG_PID, LOG_DAEMON);
+#endif
+
+  /* Find out how many processors are available. */
+  nr_cpus = detect_nr_cpus ();
+
+  /* Find existing saves directory. If there is a soup image in there,
+   * then we will load it. Otherwise we will start with the god cell.
+   */
+  if (chdir (save_dir) < 0)
+    {
+      perror (save_dir);
+      exit (1);
+    }
+
+#ifdef HAVE_NICE
+  /* Reduce our priority down to the minimum. */
+  nice (64);
+#endif
+
+#if defined(HAVE_GETUID) && defined(HAVE_SETUID) && defined(HAVE_SETGID) && defined(HAVE_GETPWNAM) && defined(HAVE_INITGROUPS)
+  /* If we are running as root, change to user dlife. */
+  if (getuid () == 0)
+    {
+      struct passwd *pw = getpwnam ("dlife");
+
+      if (pw)
+       {
+         initgroups ("dlife", pw->pw_gid);
+         setgid (pw->pw_gid);
+         setuid (pw->pw_uid);
+       }
+      else
+       {
+         fprintf (stderr, "cannot change to user/group dlife");
+       }
+    }
+#endif
+
+#ifdef HAVE_SYSLOG
+  syslog (LOG_INFO,
+         "version " VERSION " starting [conf="
+         CONFDIR ", spool=" SPOOLDIR ", cpus=%d]", nr_cpus);
+#endif
+
+  /* Fork once for each processor. */
+  for (i = 0; i < nr_cpus; ++i)
+    {
+      int pid;
+
+      pid = fork ();
+      if (pid < 0)
+       {
+         perror ("fork");
+         abort ();
+       }
+
+      if (pid == 0)
+       {
+         /* This is the child process. */
+         struct state *cpu_state;
+
+         /* Try to load the previous soup image. If the soup image
+          * cannot be found, then instead load the god cell.
+          */
+         sprintf (filename, "saved/soup%d.img", i);
+
+         cpu_state = image_load (filename, soup_size, i);
+
+         if (cpu_state)
+           {
+             if (verbose)
+               printf ("CPU %d: starting from previous image file.\n", i);
+           }
+         else
+           {
+             struct cell *god;
+
+             if (verbose)
+               printf ("CPU %d: no soup image found, loading god cell\n", i);
+
+             cpu_state = state_malloc (soup_size, i);
+
+             if ((god = load_cell (cpu_state, "god.dlo")) == 0)
+               {
+                 fprintf (stderr, "dlife_soup: cannot load god cell god.dlo\n");
+#ifdef HAVE_SYSLOG
+                 syslog (LOG_ERR,
+                         "cannot load god cell " SPOOLDIR
+                         "/god.dlo -- exiting");
+#endif
+                 abort ();
+               }
+             cell_activate (cpu_state, god);
+           }
+
+         cpu_state->filename = strdup (filename);
+
+         /* Detach from the terminal. */
+         close (0);
+         close (1);
+         close (2);
+         setsid ();
+
+         /* Start running. */
+         run_thread (cpu_state);
+
+         exit (0);
+       }
+    }
+
+  /* Parent process exits. The children will automatically be
+   * cleaned up by init(8).
+   */
+  exit (0);
+}
+
+/* Parse the command line arguments. */
+static void
+parse_args (int argc, char *argv[])
+{
+  int c;
+
+  while ((c = getopt (argc, argv, "f:r:v")) != -1)
+    {
+      switch (c)
+       {
+       case 'f':
+         conf_file = optarg;
+         break;
+       case 'r':
+         save_dir = optarg;
+         break;
+       case 'v':
+         verbose = 1;
+         break;
+       default:
+         fprintf (stderr,
+              "usage: dlife_soup [-f conf-file] [-r save-dir] [-v]\n");
+         exit (1);
+       }
+    }
+}
+
+/* Return true if n is a power of 2. */
+static int
+is_power_2 (int n)
+{
+  while ((n & 1) == 0)
+    n >>= 1;
+  return n == 1;
+}
+
+static void
+read_config_file (void)
+{
+  FILE *fp;
+  char buffer[256], *t;
+
+  fp = fopen (conf_file, "r");
+  if (fp == 0)
+    {
+      if (verbose) printf ("No configuration file found.\n");
+      return;
+    }
+
+  while (fgets (buffer, sizeof buffer, fp) != 0)
+    {
+      /* Remove trailing \n and \r. */
+      t = buffer + strlen (buffer) - 1;
+      while (t >= buffer && (*t == '\n' || *t == '\r'))
+       *t-- = '\0';
+
+      /* Remove any comments (after a ``#'' character). */
+      t = strchr (buffer, '#');
+      if (t)
+       *t = '\0';
+
+      /* Look for lines which we understand. */
+      if (sscanf (buffer, "soup_fetch_failure %u", &soup_fetch_failure) == 1)
+       {
+         /* No checks required. */
+         continue;
+       }
+      if (sscanf (buffer, "inc_pc_failure %u", &inc_pc_failure) == 1)
+       {
+         /* No checks required. */
+         continue;
+       }
+      if (sscanf (buffer, "insn_exec_failure %u", &insn_exec_failure) == 1)
+       {
+         /* No checks required. */
+         continue;
+       }
+      if (sscanf (buffer, "access_control_failure %u", &access_control_failure) == 1)
+       {
+         /* No checks required. */
+         continue;
+       }
+      if (sscanf (buffer, "cell_initialization_failure %u", &cell_initialization_failure) == 1)
+       {
+         /* No checks required. */
+         continue;
+       }
+      if (sscanf (buffer, "reaper_invoke_threshold %d", &reaper_invoke_threshold) == 1)
+       {
+         if (reaper_invoke_threshold < 0 || reaper_invoke_threshold > 100)
+           {
+             fprintf (stderr, "reaper_invoke_threshold is a percentage: it must be 0 - 100\n");
+             exit (1);
+           }
+         continue;
+       }
+      if (sscanf (buffer, "reaper_reap_threshold %d", &reaper_reap_threshold) == 1)
+       {
+         if (reaper_reap_threshold < 0 || reaper_reap_threshold > 100)
+           {
+             fprintf (stderr, "reaper_reap_threshold is a percentage: it must be 0 - 100\n");
+             exit (1);
+           }
+         continue;
+       }
+      if (sscanf (buffer, "soup_size %d", &soup_size) == 1)
+       {
+         if (soup_size <= 0 || ! is_power_2 (soup_size))
+           {
+             fprintf (stderr, "soup_size must be a power of 2\n");
+             exit (1);
+           }
+         continue;
+       }
+      if (sscanf (buffer, "save_period %d", &save_period) == 1)
+       {
+         /* No checks required. */
+         continue;
+       }
+      if (sscanf (buffer, "outgoing_period %d", &outgoing_period) == 1)
+       {
+         /* No checks required. */
+         continue;
+       }
+      if (sscanf (buffer, "incoming_period %d", &incoming_period) == 1)
+       {
+         /* No checks required. */
+         continue;
+       }
+      if (sscanf (buffer, "info_period %d", &info_period) == 1)
+       {
+         /* No checks required. */
+         continue;
+       }
+    }
+}
+
+/* Detect the number of CPUs available. This is very operating system
+ * specific.
+ */
+
+#ifdef linux
+
+#ifdef __alpha__
+
+static int
+detect_nr_cpus ()
+{
+  FILE *fp;
+  int n = -1;
+  char line[256];
+
+  fp = fopen ("/proc/cpuinfo", "r");
+  if (fp == 0)
+    {
+      perror ("/proc/cpuinfo");
+      fprintf (stderr, "warning: cannot detect number of CPUs available\n");
+      return 1;
+    }
+
+  while (fgets (line, sizeof line, fp))
+    {
+      if (sscanf (line, "cpus detected           : %d", &n) == 1)
+       break;
+    }
+
+  fclose (fp);
+
+  if (verbose)
+    printf ("number of CPUs detected: %d\n", n);
+
+  if (n <= 0)
+    {
+      fprintf (stderr, "warning: cannot detect number of CPUs available\n");
+      return 1;
+    }
+
+  return n;
+}
+
+#elif __sparc__
+
+static int
+detect_nr_cpus ()
+{
+  FILE *fp;
+  int n = -1;
+  char line[256];
+
+  fp = fopen ("/proc/cpuinfo", "r");
+  if (fp == 0)
+    {
+      perror ("/proc/cpuinfo");
+      fprintf (stderr, "warning: cannot detect number of CPUs available\n");
+      return 1;
+    }
+
+  while (fgets (line, sizeof line, fp))
+    {
+      if (sscanf (line, "ncpus active            : %d", &n) == 1)
+       break;
+    }
+
+  fclose (fp);
+
+  if (verbose)
+    printf ("number of CPUs detected: %d\n", n);
+
+  if (n <= 0)
+    {
+      fprintf (stderr, "warning: cannot detect number of CPUs available\n");
+      return 1;
+    }
+
+  return n;
+}
+
+#else /* !__alpha__ || __sparc__ */
+
+static int
+detect_nr_cpus ()
+{
+  FILE *fp;
+  int n, c = 0;
+  char line[256];
+
+  fp = fopen ("/proc/cpuinfo", "r");
+  if (fp == 0)
+    {
+      perror ("/proc/cpuinfo");
+      fprintf (stderr, "warning: cannot detect number of CPUs available\n");
+      return 1;
+    }
+
+  while (fgets (line, sizeof line, fp))
+    {
+      if (sscanf (line, "processor : %d", &n) == 1 && n+1 > c)
+       {
+         c = n+1;
+       }
+    }
+
+  fclose (fp);
+
+  if (verbose)
+    printf ("number of CPUs detected: %d\n", c);
+
+  if (c <= 0)
+    {
+      fprintf (stderr, "warning: cannot detect number of CPUs available\n");
+      return 1;
+    }
+
+  return c;
+}
+
+#endif /* !__alpha__ */
+
+#else /* !linux */
+
+static void
+detect_nr_cpus ()
+{
+  fprintf (stderr, "warning: cannot detect number of CPUs available on this platform\n");
+  return 1;
+}
+
+#endif
diff --git a/missing b/missing
new file mode 120000 (symlink)
index 0000000..551440f
--- /dev/null
+++ b/missing
@@ -0,0 +1 @@
+/usr/share/automake-1.4/missing
\ No newline at end of file
diff --git a/mkinstalldirs b/mkinstalldirs
new file mode 120000 (symlink)
index 0000000..4b6a76d
--- /dev/null
@@ -0,0 +1 @@
+/usr/share/automake-1.4/mkinstalldirs
\ No newline at end of file
diff --git a/params.h b/params.h
new file mode 100644 (file)
index 0000000..1c74658
--- /dev/null
+++ b/params.h
@@ -0,0 +1,44 @@
+/* DLIFE Copyright (C) 2000 Richard W.M. Jones <rich@annexia.org>
+ * and other authors listed in the ``AUTHORS'' file.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * $Id: params.h,v 1.1 2002/04/05 14:40:27 rich Exp $
+ */
+
+#ifndef params_h
+#define params_h
+
+#include "config.h"
+
+/* Probabilities. (ie. 1 in N). */
+extern unsigned soup_fetch_failure;
+extern unsigned inc_pc_failure;
+extern unsigned insn_exec_failure;
+extern unsigned access_control_failure;
+extern unsigned cell_initialization_failure;
+
+/* Percentages. (0-100). */
+extern int reaper_invoke_threshold;
+extern int reaper_reap_threshold;
+
+/* Save / load parameters. */
+extern int save_period;
+extern int outgoing_period;
+extern int incoming_period;
+extern int info_period;
+extern int max_cells_incoming_per_pass;
+
+#endif /* params_h */
diff --git a/random.c b/random.c
new file mode 100644 (file)
index 0000000..6d11d23
--- /dev/null
+++ b/random.c
@@ -0,0 +1,50 @@
+/* DLIFE Copyright (C) 2000 Richard W.M. Jones <rich@annexia.org>
+ * and other authors listed in the ``AUTHORS'' file.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * $Id: random.c,v 1.1 2002/04/05 14:40:27 rich Exp $
+ */
+
+/* This module should generate high quality random numbers. It
+ * doesn't at the moment, but hopefully someone should be able to
+ * fix that. XXX
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+
+#include "types.h"
+#include "random.h"
+
+void
+random_init ()
+{
+#if PERFECT_CPU
+  fprintf (stderr, "warning: PERFECT_CPU is defined in <random.h>\n");
+#endif
+
+  srandom (time (NULL));
+}
diff --git a/random.h b/random.h
new file mode 100644 (file)
index 0000000..988b1bc
--- /dev/null
+++ b/random.h
@@ -0,0 +1,69 @@
+/* DLIFE Copyright (C) 2000 Richard W.M. Jones <rich@annexia.org>
+ * and other authors listed in the ``AUTHORS'' file.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * $Id: random.h,v 1.1 2002/04/05 14:40:28 rich Exp $
+ */
+
+#ifndef random_h
+#define random_h
+
+#include "config.h"
+
+#include <stdlib.h>
+
+extern void random_init (void);
+
+/* Define this to run on a fault-free ``perfect'' CPU. (Use this
+ * only when debugging).
+ */
+#define PERFECT_CPU 0
+
+/* Return true 1 in PROBABILITY times. The argument PROBABILITY
+ * is not limited to just powers of 2, but it must be an integer.
+ */
+extern inline int
+chance (unsigned probability)
+{
+#if !PERFECT_CPU
+  return ((unsigned)random() % probability) == 0;
+#else
+  return 0;
+#endif
+}
+
+/* Return 32 bits of randomness. */
+extern inline unsigned
+get_rand_int ()
+{
+  return (unsigned)random();
+}
+
+/* Return 16 bits of randomness. */
+extern inline unsigned
+get_rand_short ()
+{
+  return (unsigned)random() & 0xffff;
+}
+
+/* Return 8 bits of randomness. */
+extern inline unsigned
+get_rand_byte ()
+{
+  return (unsigned)random() & 0xff;
+}
+
+#endif /* random_h */
diff --git a/servers.txt b/servers.txt
new file mode 100644 (file)
index 0000000..9ad063e
--- /dev/null
@@ -0,0 +1,3 @@
+# Copy of servers.txt.
+
+server   dlife.annexia.org     eu uk
diff --git a/soup.c b/soup.c
new file mode 100644 (file)
index 0000000..fb4a4d5
--- /dev/null
+++ b/soup.c
@@ -0,0 +1,440 @@
+/* DLIFE Copyright (C) 2000 Richard W.M. Jones <rich@annexia.org>
+ * and other authors listed in the ``AUTHORS'' file.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * $Id: soup.c,v 1.2 2002/04/05 16:47:13 rich Exp $
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#endif
+
+#include "types.h"
+#include "soup.h"
+#include "cell.h"
+#include "random.h"
+#include "state.h"
+#include "crc.h"
+
+#define TRACE_SOUP_ALLOCATIONS 0
+
+void
+soup_init (struct state *state, int _soup_size)
+{
+  int i;
+
+  state->soup_size = _soup_size;
+  state->soup_free = _soup_size;
+  state->soup = malloc (_soup_size);
+  if (state->soup == 0) { perror ("malloc"); abort (); }
+
+  /* Fill the soup with entropy. */
+  for (i = 0; i < _soup_size; ++i)
+    {
+      state->soup[i] = get_rand_byte ();
+    }
+}
+
+/* Allocate a new fragment of soup. */
+struct soup_frag *
+soup_frag_malloc (struct state *state,
+                 struct soup_frag *mother_frag, reg_t len)
+{
+  struct soup_frag *p, *t;
+  int offset;
+  int is_first_cell = state->soup_free == state->soup_size;
+
+#if TRACE_SOUP_ALLOCATIONS
+  printf ("soup alloc: want %d bytes ", len);
+#endif
+
+  p = malloc (sizeof (struct soup_frag));
+  if (p == 0) { perror ("malloc"); abort (); }
+
+  /* Common fields. */
+  p->len = len;
+  state->soup_free -= len;
+
+  /* The first cell is allocated specially. */
+  if (is_first_cell)
+    {
+      p->next = p;
+      p->prev = p;
+      p->base = 0;
+
+#if TRACE_SOUP_ALLOCATIONS
+      printf ("first cell 0 OK\n");
+#endif
+
+      return p;
+    }
+
+  /* If a cell has no parent, we can insert it anywhere. */
+  if (mother_frag == 0)
+    {
+      /* Need to go and grab a cell at random, then search indefinitely
+       * for a free space.
+       */
+      mother_frag = _cell_get_any_frag (state);
+      t = mother_frag;
+      offset = 0;
+
+      do
+       {
+         int diff;
+
+#if TRACE_SOUP_ALLOCATIONS
+         printf ("[%d,%d:%d,%d] ",
+                 t->base, t->base + t->len,
+                 t->next->base, t->next->base + t->next->len);
+#endif
+
+         /* Handle the wrap-around case gracefully. */
+         if (t->next->base > t->base)
+           diff = t->next->base - (t->base + t->len);
+         else
+           diff = t->next->base - (t->base + t->len) + state->soup_size;
+
+         /* Is there space after this fragment? */
+         if (diff >= len)
+           {
+             /* Yes: insert the cell here. */
+             p->prev = t;
+             p->next = t->next;
+             p->base = (t->base + t->len) & (state->soup_size-1);
+             t->next->prev = p;
+             t->next = p;
+
+#if TRACE_SOUP_ALLOCATIONS
+             printf ("%d OK\n", p->base);
+#endif
+
+             return p;
+           }
+
+         offset += diff + t->len;
+         t = t->next;
+       }
+      while (offset <= state->soup_size && t != mother_frag);
+
+      /* No space for it. */
+      state->soup_free += len;
+      free (p);
+
+#if TRACE_SOUP_ALLOCATIONS
+      printf ("FAILED\n");
+#endif
+
+      return 0;
+    }
+
+  /* Find a suitable fragment near the mother. */
+
+  /* Search forwards first. */
+  t = mother_frag;
+  offset = 0;
+  do
+    {
+      int diff;
+
+#if TRACE_SOUP_ALLOCATIONS
+      printf ("[%d,%d:%d,%d] ",
+             t->base, t->base + t->len,
+             t->next->base, t->next->base + t->next->len);
+#endif
+
+      /* Handle the wrap-around case gracefully. */
+      if (t->next->base > t->base)
+       diff = t->next->base - (t->base + t->len);
+      else
+       diff = t->next->base - (t->base + t->len) + state->soup_size;
+
+      /* Is there space after this fragment? */
+      if (diff >= len)
+       {
+         /* Yes: insert the cell here. */
+         p->prev = t;
+         p->next = t->next;
+         p->base = (t->base + t->len) & (state->soup_size-1);
+         t->next->prev = p;
+         t->next = p;
+
+#if TRACE_SOUP_ALLOCATIONS
+  printf ("%d OK\n", p->base);
+#endif
+
+         return p;
+       }
+
+      offset += diff + t->len;
+      t = t->next;
+    }
+  while (offset <= MAX_SPAWN_DISTANCE && t != mother_frag);
+
+  /* Search backwards. */
+  t = mother_frag;
+  offset = 0;
+  do
+    {
+      int diff;
+
+#if TRACE_SOUP_ALLOCATIONS
+      printf ("[%d,%d:%d,%d] ",
+             t->prev->base, t->prev->base + t->prev->len,
+             t->base, t->base + t->len);
+#endif
+
+      /* Handle the wrap-around case gracefully. */
+      if (t->prev->base < t->base)
+       diff = t->base - (t->prev->base + t->prev->len);
+      else
+       diff = t->base - (t->prev->base + t->prev->len) + state->soup_size;
+
+      /* Is there space before this fragment? */
+      if (diff >= len)
+       {
+         /* Yes: insert the cell here. */
+         p->prev = t->prev;
+         p->next = t;
+         p->base = (t->base - len) & (state->soup_size-1);
+         p->len = len;
+         t->prev->next = p;
+         t->prev = p;
+
+#if TRACE_SOUP_ALLOCATIONS
+  printf ("%d OK\n", p->base);
+#endif
+
+         return p;
+       }
+
+      offset += diff + t->prev->len;
+      t = t->prev;
+    }
+  while (offset <= MAX_SPAWN_DISTANCE && t != mother_frag);
+
+  /* No space for it. */
+  state->soup_free += len;
+  free (p);
+
+#if TRACE_SOUP_ALLOCATIONS
+  printf ("FAILED\n");
+#endif
+
+  return 0;
+}
+
+/* Free up a soup fragment. */
+void
+soup_frag_free (struct state *state,
+               struct soup_frag *frag)
+{
+  /* NB. We ignore the case of freeing up the single last remaining
+   * fragment, since that should never happen in real life.
+   */
+  frag->next->prev = frag->prev;
+  frag->prev->next = frag->next;
+
+  state->soup_free += frag->len;
+
+  free (frag);
+}
+
+/* Compute the CRC for a frag. */
+crc_t
+soup_frag_compute_crc32 (const struct state *state,
+                        const struct soup_frag *frag)
+{
+  /* Take care of the case where a cell straddles the end of the soup. */
+  if (frag->base + frag->len <= state->soup_size)
+    {
+      return compute_crc32 (state->soup + frag->base, frag->len);
+    }
+  else
+    {
+      crc_t crc = compute_crc32 (state->soup + frag->base,
+                                state->soup_size - frag->base);
+      return incr_compute_crc32 (crc, state->soup,
+                                frag->len - (state->soup_size - frag->base));
+    }
+
+}
+
+/* This function checks that the soup is consistent. We are passed
+ * one fragment (at random) and walk the circular linked list,
+ * examining the fragments to ensure they are in order and do not
+ * overlap.
+ */
+void
+soup_check (struct state *state)
+{
+  const struct soup_frag *start_frag = _cell_get_any_frag (state);
+  const struct soup_frag *frag = start_frag;
+  int nr_frags = 0;
+  int soup_free = state->soup_size;
+
+  do
+    {
+      assert (0 <= frag->base && frag->base < state->soup_size);
+      assert (frag->len > 0);
+
+      assert (frag->next->prev == frag);
+      assert (frag->prev->next == frag);
+
+      if (frag->prev->base < frag->base)
+       assert (frag->prev->base + frag->prev->len <= frag->base);
+      else
+       assert (frag->prev->base + frag->prev->len <= frag->base + state->soup_size);
+
+      if (frag->base < frag->next->base)
+       assert (frag->base + frag->len <= frag->next->base);
+      else
+       assert (frag->base + frag->len <= frag->next->base + state->soup_size);
+
+      soup_free -= frag->len;
+
+      frag = frag->next;
+      nr_frags++;
+    }
+  while (frag != start_frag);
+
+  assert (nr_frags == state->nr_cells_allocated);
+  assert (soup_free == state->soup_free);
+}
+
+/* Dump the soup and soup structures out to a file. This function is
+ * non-destructive.
+ */
+void
+soup_state_save (struct state *state, FILE *fp)
+{
+  struct soup_frag *start_frag, *frag;
+
+  /* Write out the size of the soup. */
+  fwrite (&state->soup_size, sizeof state->soup_size, 1, fp);
+  fwrite (&state->soup_free, sizeof state->soup_free, 1, fp);
+
+  /* Write out the soup itself. */
+  fwrite (state->soup, 1, state->soup_size, fp);
+
+  /* Write out the number of fragments. Note that this is the same
+   * as the number of allocated cells.
+   */
+  fwrite (&state->nr_cells_allocated,
+         sizeof state->nr_cells_allocated, 1, fp);
+
+  /* Write out the fragment list. */
+  frag = start_frag = _cell_get_any_frag (state);
+  do
+    {
+      fwrite (frag, sizeof (struct soup_frag), 1, fp);
+
+      frag = frag->next;
+    }
+  while (frag != start_frag);
+}
+
+/* Load the soup state from a previously saved file. */
+void
+soup_state_load (struct state *state, FILE *fp)
+{
+  int _soup_size, nr_frags, i;
+  struct soup_frag *first_frag = 0, *prev_frag = 0;
+
+  /* Load the size of the soup expected. */
+  if (fread (&_soup_size, sizeof _soup_size, 1, fp) != 1)
+    {
+      fprintf (stderr, "error in soup state\n");
+      abort ();
+    }
+  if (state->soup_size != _soup_size)
+    {
+      fprintf (stderr, "soup size doesn't match - can't load this soup image\n");
+      abort ();
+    }
+  if (fread (&state->soup_free, sizeof state->soup_free, 1, fp) != 1)
+    {
+      fprintf (stderr, "error in soup state\n");
+      abort ();
+    }
+  if (state->soup_free > state->soup_size)
+    {
+      fprintf (stderr, "soup free > soup_size - can't load this soup image\n");
+      abort ();
+    }
+
+  /* Load the soup itself. */
+  if (fread (state->soup, 1, _soup_size, fp) != _soup_size)
+    {
+      fprintf (stderr, "error in soup state\n");
+      abort ();
+    }
+
+  /* Load the number of fragments expected. */
+  if (fread (&nr_frags, sizeof nr_frags, 1, fp) != 1)
+    {
+      fprintf (stderr, "error in soup state\n");
+      abort ();
+    }
+  if (nr_frags != state->nr_cells_allocated)
+    {
+      fprintf (stderr, "nr_frags != nr_cells_allocated - can't load this soup image\n");
+      abort ();
+    }
+
+  /* Load each fragment. */
+  for (i = 0; i < nr_frags; ++i)
+    {
+      struct soup_frag *p;
+
+      p = malloc (sizeof (struct soup_frag));
+      if (p == 0) { perror ("malloc"); abort (); }
+
+      if (fread (p, sizeof (struct soup_frag), 1, fp) != 1)
+       {
+         fprintf (stderr, "error in soup state\n");
+         abort ();
+       }
+
+      if (i == 0)
+       first_frag = p;
+
+      /* Find the cell which references this fragment and fix it up. */
+      _cell_fixup_soup_ref (state, p->base, p);
+
+      /* Join the fragments to form a circular linked list. */
+      if (prev_frag)
+       {
+         p->prev = prev_frag;
+         p->prev->next = p;
+       }
+
+      prev_frag = p;
+    }
+
+  /* Finish off the circular linked list. */
+  first_frag->prev = prev_frag;
+  prev_frag->next = first_frag;
+}
diff --git a/soup.conf b/soup.conf
new file mode 100644 (file)
index 0000000..338cc72
--- /dev/null
+++ b/soup.conf
@@ -0,0 +1,65 @@
+# DLIFE soup configuration file.
+
+#----------------------------------------------------------------------
+# The size of the soup (in bytes).
+#
+# This parameter must be a power of 2. If you change this parameter,
+# then you will have to reinitialize the soup image. You cannot load
+# a soup image from one version of the program into another version
+# with a different soup size.
+
+soup_size                   131072
+
+#----------------------------------------------------------------------
+# Failure probabilities.
+#
+# All probabilities are expressed in the form ``1 in N'' where N is
+# an integer between 1 and about 4 billion. Larger values of N means
+# the event is rarer. You can dramatically change the behaviour of
+# the environment by changing these parameters - from a highly-
+# irradiated soup similar to the early earth (and NOT supporting
+# life) - to an almost completely stable soup free from almost any
+# mutation.
+
+# The probability that fetching a value from the soup will fail.
+
+soup_fetch_failure          1000000
+
+# The probability that the program counter will fail to increment
+# after an instruction has been executed.
+
+inc_pc_failure              1000000
+
+# The overall probability that an instruction will fail to execute
+# correctly.
+
+insn_exec_failure           1000000
+
+# The probability that the access control mechanisms (which govern
+# what addresses a cell may write to) will fail. It is OK to have
+# this probability quite large (ie. small N) so that cells may try
+# to ``invade'' other cells.
+
+access_control_failure      10
+
+# The probability that a newly created cell isn't initialized correctly -
+# ie. that the registers and stack don't start off at zero.
+
+cell_initialization_failure 1000000
+
+#----------------------------------------------------------------------
+# Grim reaper configuration.
+#
+# These parameters control when and for how long the grim reaper
+# comes to life and kills off sick cells. These two parameters are
+# expressed as percentages of soup used (ie. ``80'' means the soup
+# is 80% full).
+
+# The grim reaper is invoked when the soup is this full.
+
+reaper_invoke_threshold     80
+
+# The grim reaper runs until the soup is this full (and then
+# goes back to sleep again).
+
+reaper_reap_threshold       79
diff --git a/soup.h b/soup.h
new file mode 100644 (file)
index 0000000..e9cceed
--- /dev/null
+++ b/soup.h
@@ -0,0 +1,79 @@
+/* DLIFE Copyright (C) 2000 Richard W.M. Jones <rich@annexia.org>
+ * and other authors listed in the ``AUTHORS'' file.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * $Id: soup.h,v 1.1 2002/04/05 14:40:28 rich Exp $
+ */
+
+#ifndef soup_h
+#define soup_h
+
+#include "config.h"
+
+#include "types.h"
+#include "state.h"
+#include "crc.h"
+
+/* How far away can a daughter be from its mother? */
+#define MAX_SPAWN_DISTANCE 8192
+
+struct soup_frag
+{
+  addr_t base;                 /* Base address of this fragment. */
+  int len;                     /* Length of this fragment. */
+
+  /* These are kept on a circular doubly-linked list. */
+  struct soup_frag *next, *prev;
+};
+
+extern inline addr_t
+raddr_to_addr (const struct state *state,
+              const struct soup_frag *frag, reg_t raddr)
+{
+  return (frag->base + raddr) & (state->soup_size - 1);
+}
+
+extern inline int
+get_soup (const struct state *state,
+         const struct soup_frag *frag, reg_t raddr)
+{
+  addr_t addr = raddr_to_addr (state, frag, raddr);
+  return state->soup[addr];
+}
+
+extern inline void
+set_soup (struct state *state,
+         const struct soup_frag *frag, int v, reg_t raddr)
+{
+  addr_t addr = raddr_to_addr (state, frag, raddr);
+  state->soup[addr] = v;
+}
+
+extern void soup_init (struct state *state, int _soup_size);
+
+extern struct soup_frag *soup_frag_malloc (struct state *state,
+                                          struct soup_frag *, reg_t);
+extern void soup_frag_free (struct state *state, struct soup_frag *);
+
+extern void soup_state_save (struct state *state, FILE *fp);
+extern void soup_state_load (struct state *state, FILE *fp);
+
+extern void soup_check (struct state *state);
+
+extern crc_t soup_frag_compute_crc32 (const struct state *state,
+                                     const struct soup_frag *frag);
+
+#endif /* soup_h */
diff --git a/stamp-h.in b/stamp-h.in
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/state.c b/state.c
new file mode 100644 (file)
index 0000000..fa7a8f1
--- /dev/null
+++ b/state.c
@@ -0,0 +1,67 @@
+/* DLIFE Copyright (C) 2000 Richard W.M. Jones <rich@annexia.org>
+ * and other authors listed in the ``AUTHORS'' file.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * $Id: state.c,v 1.2 2002/04/05 16:47:13 rich Exp $
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "state.h"
+#include "soup.h"
+#include "cell.h"
+
+struct state *
+state_malloc (int _soup_size, int thread_num)
+{
+  struct state *p = malloc (sizeof (struct state));
+  if (p == 0) { perror ("malloc"); abort (); }
+
+  p->cell_cycle = 0;
+  p->nr_cells_alive = 0;
+  p->nr_cells_allocated = 0;
+  dlink_list_init (&p->alive_list, offsetof (struct cell, next));
+  dlink_list_init (&p->best_list, offsetof (struct cell, worse));
+  soup_init (p, _soup_size);
+  p->filename = 0;
+  p->thread_num = thread_num;
+
+  return p;
+}
+
+void
+state_free (struct state *state)
+{
+  struct cell *p;
+
+  /* Free up cells. This also cleans up soup frags. */
+  for (p = (struct cell *) state->alive_list.first; p; p = p->next)
+    {
+      cell_kill (state, p);
+    }
+
+  /* Free up soup. */
+  free (state->soup);
+
+  /* Free up soup image filename. */
+  if (state->filename) free (state->filename);
+
+  /* Free up structure. */
+  free (state);
+}
diff --git a/state.h b/state.h
new file mode 100644 (file)
index 0000000..ce242b4
--- /dev/null
+++ b/state.h
@@ -0,0 +1,66 @@
+/* DLIFE Copyright (C) 2000 Richard W.M. Jones <rich@annexia.org>
+ * and other authors listed in the ``AUTHORS'' file.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * $Id: state.h,v 1.1 2002/04/05 14:40:28 rich Exp $
+ */
+
+#ifndef state_h
+#define state_h
+
+#include "dlink.h"
+#include "types.h"
+
+struct state
+{
+  /* The number of cycles we have been running for. */
+  unsigned long long cell_cycle;
+
+  /* The number of cells alive (running and on the alive list). */
+  int nr_cells_alive;
+
+  /* The number of cells allocated (alive + undivided daughters). */
+  int nr_cells_allocated;
+
+  /* The list of cells currently alive (running). Some cells may also
+   * exist in an undivided state.
+   */
+  dlink_list_t alive_list;
+
+  /* The same list of cells, kept in order of best (fewest errors) to
+   * worse (most errors). This allows the grim reaper to quickly remove
+   * dying cells.
+   */
+  dlink_list_t best_list;
+
+  /* The soup. */
+  byte_t *soup;
+
+  /* Number of bytes in soup, and number of bytes free in soup. */
+  int soup_size;
+  int soup_free;
+
+  /* Filename of the soup image (for this thread). */
+  char *filename;
+
+  /* Thread number (first thread is number 0). */
+  int thread_num;
+};
+
+extern struct state *state_malloc (int _soup_size, int thread_num);
+extern void state_free (struct state *);
+
+#endif /* state_h */
diff --git a/types.h b/types.h
new file mode 100644 (file)
index 0000000..504c633
--- /dev/null
+++ b/types.h
@@ -0,0 +1,43 @@
+/* DLIFE Copyright (C) 2000 Richard W.M. Jones <rich@annexia.org>
+ * and other authors listed in the ``AUTHORS'' file.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * $Id: types.h,v 1.1 2002/04/05 14:40:28 rich Exp $
+ */
+
+#ifndef types_h
+#define types_h
+
+#include "config.h"
+
+/* Apparently these are now defined by the ISO C 9x standard. */
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#else
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+
+typedef signed char int8_t;
+typedef short int16_t;
+typedef int int32_t;
+#endif
+
+typedef uint8_t byte_t;
+typedef int32_t addr_t;
+typedef int16_t reg_t;
+
+#endif /* types_h */