#!/bin/sh
# This is a shell archive (shar 3.47)
# made 09/02/1993 16:09 UTC by boyns@hercules
# Source directory /home/boyns/src/sound
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#   6683 -rw-r--r-- rplay-3.1.0/README
#   4520 -rw-r--r-- rplay-3.1.0/INSTALL
#  12233 -rw-r--r-- rplay-3.1.0/CHANGES
#   2031 -rw-r--r-- rplay-3.1.0/Makefile
#   3860 -rw-r--r-- rplay-3.1.0/rplay/rplay.c
#   1135 -rw-r--r-- rplay-3.1.0/rplay/Makefile
#   6693 -rw-r--r-- rplay-3.1.0/include/rplay.h
#   3715 -rw-r--r-- rplay-3.1.0/include/conf.h
#   1062 -rw-r--r-- rplay-3.1.0/include/version.h
#    932 -rw-r--r-- rplay-3.1.0/include/Makefile
#   1514 -rw-r--r-- rplay-3.1.0/librplay/Makefile
#  18877 -rw-r--r-- rplay-3.1.0/librplay/rplay.c
#   7339 -rw-r--r-- rplay-3.1.0/librplay/rptp.c
#   2844 -rw-r--r-- rplay-3.1.0/Makefile.config
#   1381 -rw-r--r-- rplay-3.1.0/contrib/mailsound/Makefile
#   7395 -rw-r--r-- rplay-3.1.0/contrib/mailsound/mailsound.c
#   3525 -rw-r--r-- rplay-3.1.0/contrib/mailsound/man1/mailsound.1
#    178 -rw-r--r-- rplay-3.1.0/contrib/xtank/README
#    135 -rw-r--r-- rplay-3.1.0/contrib/xpilot/README
#    221 -rw-r--r-- rplay-3.1.0/contrib/olvwm/README
#    212 -rw-r--r-- rplay-3.1.0/contrib/crossfire/README
#  14797 -rw-r--r-- rplay-3.1.0/contrib/jukebox1.2/jukebox.c
#    891 -rw-r--r-- rplay-3.1.0/contrib/jukebox1.2/Makefile
#   4341 -rw-r--r-- rplay-3.1.0/contrib/jukebox1.2/man1/jukebox.1
#   4680 -rw-r--r-- rplay-3.1.0/rplayd/audio.c
#  10175 -rw-r--r-- rplay-3.1.0/rplayd/command.c
#   1431 -rw-r--r-- rplay-3.1.0/rplayd/host.h
#   2274 -rw-r--r-- rplay-3.1.0/rplayd/hash.c
#  12374 -rw-r--r-- rplay-3.1.0/rplayd/rplayd.c
#  10104 -rw-r--r-- rplay-3.1.0/rplayd/sound.c
#   5774 -rw-r--r-- rplay-3.1.0/rplayd/spool.c
#   1063 -rw-r--r-- rplay-3.1.0/rplayd/audio.h
#   2446 -rw-r--r-- rplay-3.1.0/rplayd/command.h
#   1354 -rw-r--r-- rplay-3.1.0/rplayd/hash.h
#   2186 -rw-r--r-- rplay-3.1.0/rplayd/rplayd.h
#   3412 -rw-r--r-- rplay-3.1.0/rplayd/server.c
#   2622 -rw-r--r-- rplay-3.1.0/rplayd/sound.h
#   1953 -rw-r--r-- rplay-3.1.0/rplayd/spool.h
#   1384 -rw-r--r-- rplay-3.1.0/rplayd/Makefile
#   6233 -rw-r--r-- rplay-3.1.0/rplayd/cache.c
#  36066 -rw-r--r-- rplay-3.1.0/rplayd/ulaw.c
#   1655 -rw-r--r-- rplay-3.1.0/rplayd/cache.h
#   1196 -rw-r--r-- rplay-3.1.0/rplayd/ulaw.h
#  30672 -rw-r--r-- rplay-3.1.0/rplayd/connection.c
#   4592 -rw-r--r-- rplay-3.1.0/rplayd/connection.h
#   1148 -rw-r--r-- rplay-3.1.0/rplayd/server.h
#   5676 -rw-r--r-- rplay-3.1.0/rplayd/host.c
# 161990 -rw-r--r-- rplay-3.1.0/rplayd/regex.c
#  18765 -rw-r--r-- rplay-3.1.0/rplayd/regex.h
#   2165 -rw-r--r-- rplay-3.1.0/rplayd/misc.c
#   1228 -rw-r--r-- rplay-3.1.0/rplayd/misc.h
#   1661 -rw-r--r-- rplay-3.1.0/rplayd/buffer.c
#   1444 -rw-r--r-- rplay-3.1.0/rplayd/buffer.h
#   3114 -rw-r--r-- rplay-3.1.0/rplayd/search.c
#    455 -rw-r--r-- rplay-3.1.0/rplayd/search.h
#  17976 -rw-r--r-- rplay-3.1.0/COPYING
#    593 -rw-r--r-- rplay-3.1.0/doc/man5/rplay.conf.5
#   1488 -rw-r--r-- rplay-3.1.0/doc/man5/rplay.hosts.5
#    781 -rw-r--r-- rplay-3.1.0/doc/man5/rplay.servers.5
#  15580 -rw-r--r-- rplay-3.1.0/doc/README.LIBRPLAY
#    985 -rw-r--r-- rplay-3.1.0/doc/Makefile
#   4804 -rw-r--r-- rplay-3.1.0/doc/README.RPTP
#   2417 -rw-r--r-- rplay-3.1.0/doc/man1/rplay.1
#   3046 -rw-r--r-- rplay-3.1.0/doc/man1/rplayd.1
#   3013 -rw-r--r-- rplay-3.1.0/doc/man1/rptp.1
#   1132 -rw-r--r-- rplay-3.1.0/rptp/Makefile
#  11488 -rw-r--r-- rplay-3.1.0/rptp/rptp.c
#    609 -rw-r--r-- rplay-3.1.0/TODO
#    494 -rw-r--r-- rplay-3.1.0/ANNOUNCE
#
# ============= rplay-3.1.0/README ==============
if test ! -d 'rplay-3.1.0'; then
    echo 'x - creating directory rplay-3.1.0'
    mkdir 'rplay-3.1.0'
fi
if test -f 'rplay-3.1.0/README' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/README (File already exists)'
else
echo 'x - extracting rplay-3.1.0/README (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/README' &&
X
rplay release 3.1.0
X
COPYRIGHT:
----------
rplay is now distributed under the GNU General Public License Version 2 and
Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu).  See the COPYING file for 
further rplay copyright information.
X
This distribution also contains:
X
* The extended regular expression matching and search library version 0.12
X  which is Copyright (C) 1993 Free Software Foundation, Inc.
X  See rplayd/regex.[ch] for further information.
X
* An hsearch replacement which is Copyright (c) August 5, 1993 by Darren Senn.
X  The hsearch implementation was written by Darren Senn when he was porting
X  rplay to Linux.  Darren's hsearch is now used exclusively since it is more
X  portable and it includes a DELETE action which is not supported in the 
X  standard hsearch.  Thanks Darren!
X  See rplayd/search.[ch] for further information.
X
DIRECTIONS:
-----------
* See the CHANGES file for documented changes since the last version.
X
* See the INSTALL file for rplay installation instructions.
X
* Continue reading this README file for more information.
X
WHAT IS RPLAY?
--------------
rplay is a sound package that supports both local and remote sound control.
rplay is based on client/server communication using two protocols.  The first
protocol that can be used is RPLAY, which is UDP based and allows sounds to
be played, paused, continued, and stopped.  The second protocol is RPTP
(the Remote Play Transfer Protocol) which is TCP based and allows sounds to be
played, paused, continued, stopped, and transferred.
X
The rplay system can be described as follows.  An rplay client sends an RPLAY
UDP packet to an rplay server.  The RPLAY packet sent contains the name of a
sound file and various other sound attributes.  The rplay server receives the
RPLAY packet and looks up the sound in a sound file database.  If the sound
is found in the database it will be immediately played on the host the rplay
server is running on.  If the sound is not found in the database the rplay
server can be configured to search other rplay servers for the desired sound
file.   rplay servers communicate using the RPTP protocol.  rplay clients can
also use RPTP to upload sounds to an rplay server.  When an rplay server
receives sounds from a server or a client the sounds are stored in a sound 
cache directory.  The size in bytes of the cache directory can be limited
by the rplay server.  When the cache is full, the rplay server will remove
sounds using a "least recently used" algorithm.  Sound files that are larger
than the maximum cache size will not be accepted by the rplay server.
X
rplay can be used to easily add sound to any application.  For example,
if you want to play a sound when a button is pressed, all you need to do
is this:
X
X	rplay_local("sound_name.au");
X
Or, if you want to specify a hostname:
X
X	rplay_host("bozo.sdsu.edu", "sound_name.au");
X
The above routines along with many others are included in the rplay library.
See the KNOWN RPLAY APPLICATIONS section of this file for a list of applications
that use the rplay library.
X
Currently the rplay server only supports u-law 8000hz sound files.
X
CONTENTS:
---------
This rplay release contains the following:
X
* rplayd - The remote play sound server which supports both the RPLAY and
X	   RPTP protocols.
X
* rplay - A sample RPLAY client.
X
* rptp - A sample RPTP client.
X
* librplay - The rplay library which contains support routines for both
X	     the RPLAY and RPTP protocols.
X
* doc - A directory containing rplay documentation and manual pages.
X
* contrib - A directory containing rplay applications and references to
X	    other rplay applications.
X
KNOWN RPLAY APPLICATIONS:
-------------------------
rplay has been used to add sound to several applications.  Below is a list
of rplay applications that I know about.  If you know of more, please let
me know.
X
* XTank - A multiplayer X11 game.
X
* XPilot - A multiplayer gravity war game for X11.
X
* olvwm - The OPEN LOOK Virtual Window Manager for X11 and OpenWindows.
X
* Crossfire - A multiplayer graphical arcade and adventure game made for
X              the X-Windows environment. 
X
* XBoing - I have heard that version 1.7 will include rplay support.
X
Also included with this distribution in the contrib directory are the following
custom rplay applications:
X
* Jukebox - A program that is very useful for playing multiple sound files. 
X
* Mailsound - An e-mail notification program that can play different sounds 
X	      depending on who the message is from.
X
PORTING:
--------
rplay is known to work on the following systems:
X
X   * Sun SPARCstations running SunOS 4.1.x
X
X   * Sun SPARCstations running Solaris 2.x
X
X   * HP-UX
X
X   * Linux
X
X   * BSDI/386
X
X   * 386bsd using Steve Haehnichen's soundblaster driver version 1.5
X
X   * SGI Indigo
X
All rplay requires is an audio device where sounds can be played using the 
write system call.  For example, if you can "cat sound_file > /dev/audio",
then rplay should work.  If your system has an audio device that does not work 
with the above "cat" command, there is still hope but you might need to do some
programming.  You will probably only need to modify rplayd/audio.c.
If you port rplay to another system please send me patches.
X
OBTAINING SOUND FILES:
----------------------
* Anonymous FTP - Sound files are available via anonymous ftp at sounds.sdsu.edu
X                  which currently has about 1.1 gigabytes of sounds.  Login as 
X                  ftp or anonymous and use your e-mail address for the password.
X		  Remember to use binary mode when ftping sounds.
X
* Gopher - The sounds.sdsu.edu sound archive is also available via gopher at:
X
X           Name=SDSU Sound Archive (sounds.sdsu.edu)
X           Type=1
X           Port=71
X           Path=
X           Host=sounds.sdsu.edu
X
* RPTP - Sound files can also be obtained using RPTP at sounds.sdsu.edu port
X         55556.  You can put sounds.sdsu.edu:55556 in your rplay.servers file
X         or use the rptp client.
X         
THANKS:
-------
Below is a list of people who have gone above and beyond the rplay call of duty:
X
* Andrew "Ender" Scherpbier (turtle@sciences.sdsu.edu)
X
* John "Shorty" Denune (jdenune@sciences.sdsu.edu)
X
* Raphael Quinet (quinet@montefiore.ulg.ac.be)
X
* Darren Senn (sinster@scintilla.santa-clara.ca.us)
X
* Markus Gyger (mgyger@itr.ch)
X
* Kjetil Wiekhorst J{\o}rgensen (jorgens@pvv.unit.no)
X
* Richard Lloyd (rkl@csc.liv.ac.uk)
X
* Mike Halderman (mrh@io.nosc.mil)
X
* Mike Hoffmann (Mike.Hoffmann@mch.sni.de)
X
Thank you all for your comments, suggestions, and contributions.
X
RPLAY SUPPORT:
--------------
Feel free to send any questions or comments to Mark Boyns (boyns@sdsu.edu).
X
Thank you for using rplay!
SHAR_EOF
chmod 0644 rplay-3.1.0/README ||
echo 'restore of rplay-3.1.0/README failed'
Wc_c="`wc -c < 'rplay-3.1.0/README'`"
test 6683 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/README: original size 6683, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/INSTALL ==============
if test -f 'rplay-3.1.0/INSTALL' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/INSTALL (File already exists)'
else
echo 'x - extracting rplay-3.1.0/INSTALL (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/INSTALL' &&
This file contains a list of installation instructions for rplay.  Please read
this file very carefully and don't skip any steps unless you think you know
what you are doing.  If you haven't read the README file, please do so before
going any further.  If you get confused at any time during the installation
please read the manual pages in the doc directory.  
X
Feel free to send e-mail to boyns@sdsu.edu if you have any problems.
X
* Edit Makefile.config to choose the correct compiler, compiler options,
X  and installation pathnames.  The Makefile.config contains comments which
X  suggest what options should be used for various systems.
X
* If you are using HP-UX you will also have to edit librplay/Makefile to
X  comment some lines and uncomment others. 
X
* Edit include/conf.h to change rplay configuration parameters.
X
* This step is optional.  Execute "make depend" to create dependencies in the 
X  Makefiles.
X
* Execute "make".  This will compile the rplay library and programs.
X  If rplay does not compile successfully then you might need to change either
X  the Makefile.conf or include/conf.h.
X
* When rplay successfully compiles execute "make world".  This will verify that
X  rplay has been compiled successfully, install rplay, and then ask you if
X  you would like to send me an e-mail message.  I would appreciate an e-mail
X  message because I would like to get a feel for exactly how many people are
X  using rplay.
X
* Read the man pages.
X
* Create your rplay.conf file.  I run a cron job that creates my rplay.conf
X  every hour.  "find *.au" or "find / -name *.au -print" can used to find all
X  the sound files that are available.
X
* Create your rplay.hosts file if AUTH was defined in include/conf.h.
X  AUTH is defined by default.
X
* Create your rplay.servers file.  You might want to use sounds.sdsu.edu
X  port 55556 as an RPTP server.
X
* If you plan on using inetd to invoke rplayd become root and add the 
X  following to /etc/services:
X
X        rplay 55555/udp
X
X  and this to inetd.conf (you make need to change the pathname):
X
X        rplay dgram udp wait nobody /usr/local/bin/rplayd rplayd
X
X  If you are running NIS or YP you will need to update the services map.
X  "cd /var/yp; make" will probably do the trick for SunOS 4.1.x users.
X  The NIS update must be done on the NIS server.  You can type "ypwhich"
X  to locate your NIS server.
X
X  Now you need to restart inetd.
X        > ps aux | grep inetd
X        (result will be something like this)
X        root       174  0.0  0.0   48    0 ?  IW   13:25   0:04 inetd
X        > kill -1 174
X
X  Check /var/adm/messages for any errors.
X
* If you do not plan on using inetd you need to start rplayd by hand whenever
X  you want to use it.  Try "rplayd -n" or "rplayd -n -t0".  Read the rplayd
X  man page and try "rplayd -h" for more information.
X
* Now see if rplay works.  Execute "rplay soundname", where soundname is the
X  name of a sound in the rplay.conf.  If soundname is played then rplay is 
X  working.  However, if a sound is not played then I recommend you run rplayd 
X  in debug mode to see exactly what is wrong.
X  
X  When using rplayd in debug mode you must remove the rplayd entry from the
X  inetd.conf file and kill any old rplayds that might be running.
X
X  Try running "rplayd -n -d -t0" and then "rplay soundname".
X  You should see output like:
X
X  rplayd: play sound=bogus.au volume=127 from 130.191.224.8
X  rplayd: opening /dev/audio
X  rplayd: closing /dev/audio
X
X  If you still don't hear any sound check the following things:
X
X     * Is the volume of the audio device very low or zero?
X       Sun users can use audiotool to change the volume easily.
X
X     * Is another program is using the audio device?
X       There are several programs around that hog the audio device.
X       These programs include soundtool, audiotool, play, x_soundtool,
X       any many others.  Note that rplay is audio device friendly and will
X       close the audio device when it is not being used.
X     
X     * Are you running another audio server like Aserver?  rplay does not
X       work with Aserver and probably won't work with other servers.
X       If you want to use rplay make sure other audio servers are not running.
X
X     * If you see errors like "/dev/audio open: Device busy" then another
X       program is using the audio device.
X
X  If you are still having problems send e-mail to boyns@sdsu.edu and I will do
X  my best to help you out.
X
* You are done installing rplay.  You now might want to browse through the 
X  contrib directory.  Have fun!
X
SHAR_EOF
chmod 0644 rplay-3.1.0/INSTALL ||
echo 'restore of rplay-3.1.0/INSTALL failed'
Wc_c="`wc -c < 'rplay-3.1.0/INSTALL'`"
test 4520 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/INSTALL: original size 4520, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/CHANGES ==============
if test -f 'rplay-3.1.0/CHANGES' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/CHANGES (File already exists)'
else
echo 'x - extracting rplay-3.1.0/CHANGES (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/CHANGES' &&
--------------------------------------------------------------------------------
X
rplay 3.1.0 major improvements and changes from rplay 3.1 (BETA3):
X
* Added SGI Indigo patches from Mike.Hoffmann@mch.sni.de.
X
* Added a newer version of Raphael's jukebox 1.2 which includes a man page.
X
* Added patches from Raphael to support DEC 3100's running Ultrix 4.2,
X  with cc or gcc-2.4.5.
X  These patches do not include audio support, however, a DEC can be used as
X  a sound server.
X
* Added more idle information to the "list connections" display. 
X
--------------------------------------------------------------------------------
X
rplay 3.1 (BETA3) major improvements and changes from rplay 3.1 (BETA2):
X
* RPTP commands "play", "pause", "continue", and "stop" now accept the following
X  options (similar to the rplay client):
X     -P <int>  Sound priority.
X     -N <int>  Number of times to play the sound list.
X     -n <int>  Number of times to play each sound.
X     -v <int>  Volume.
X
* Fixed bug which caused sounds to get stuck in the spool when the first RPTP
X  server was unavailable. (mgyger@itr.ch)
X
* Fixed bug which caused sounds to get stuck in the spool when the TCP
X  connection was lost during a sound transfer.  (quinet@montefiore.ulg.ac.be)
X
* The volume of low priority sounds is lowered when higher priority sounds
X  are in the sound spool.  Each sound's volume is lowered depending on it's
X  priority relative to the highest priority.
X
* sound_delete now deletes sound files.
X
* Sounds that are transferred by rplayd are stored in the cache using the name
X  that the remote rplayd sends.  (quinet@montefiore.ulg.ac.be)
X
* Sound cleanup will no longer cleanup sounds that have events associated
X  with them.  It took a long time to find this one!  Thanks for your slow
X  network connection Raphael.
X
* Added SOUND_CLEANUP_TIMEOUT to include/conf.h so the cleanup timeout can be
X  configured.
X
* Added a newer version of mailsound to the contrib directory.  The new version
X  has a lot of new options.  Thanks Andrew.
X
* Changed PORTABLE_LONG macro to use (unsigned char *).  (mrh@io.nosc.mil)
X
* Added more Solaris 2.x suggestions from Kjetil Wiekhorst J{\o}rgensen
X  <jorgens@pvv.unit.no>.
X
* Added 386bsd patches to audio.c from Mike Halderman (mrh@io.nosc.mil).
X  The 386bsd patches require the soundblaster driver version 1.5 written by
X  Steve Haehnichen (shaehnic@ucsd.edu).
X
--------------------------------------------------------------------------------
X
rplay 3.1 (BETA2) major improvements and changes from rplay 3.1 (BETA):
X
* Fixed bug in rplayd's "put" implementation. (quinet@montefiore.ulg.ac.be)
X
* Fixed segmentation violation when rplayd had no rplay.servers.
X  (quinet@montefiore.ulg.ac.be)
X
* The rptp client now handles IP addresses correctly and deals with
X  connections being closed and timed out much better.
X
* Corrected many mistakes in the documentation.
X  (quinet@montefiore.ulg.ac.be) (mgyger@itr.ch)
X
* Added '!' (RPTP_TIMEOUT) as an RPTP response type.  
X
* Added RPTP_ERROR_TIMEOUT to the possible rptp_errno values.
X
* Fixed server timeout handling in rplayd.
X
* Fixed a nasty bug in rptp_getline.
X
* Added the use of the RPLAY_HOST environment variable.  The host defined by
X  RPLAY_HOST specifies a default rplay host.  When RPLAY_HOST is not defined
X  localhost will be used.  The new rplay library routine
X  char *rplay_default_host(void) can be used to obtain the default rplay host.
X
* Changed the -h option in the rplay client.  -h is now used to specify an
X  rplay host.  Now a hostname does not have to be specified.  For example:
X
X     "rplay bogus.au" uses RPLAY_HOST or localhost.
X
X     "rplay -h bozo bogus.au" uses bozo.
X
* Changed the -h option in the rptp client.  -h is now used to specify an
X  rptp host.  Now a hostname does not have to be specified.  For example:
X
X     "rptp" uses RPLAY_HOST or localhost port 55556.
X
X     "rptp -h bozo" uses RPLAY_HOST port 55556.
X
* Removed the -h option from rplayd to be consistent with the other programs.
X  -h will still display the usage information in all the programs since
X  either an option is required or the option is not valid.
X
* Added int rplay_default(char *sound) to the rplay library.
X
* Cleaned up rplayd's memory usage.  Sounds are now unmapped when the audio
X  device is closed.
X
* Fixed a bug in rplayd's event handling routines.  Now sounds that are
X  being transferred don't get stuck in the spool.
X
* Comments were moved in Makefile.config to avoid bugs in some versions of
X  make.  (sinster@scintilla.santa-clara.ca.us)
X
* The mail command used by "make mail" is now defined in Makefile.conf.
X
* Added more fixes for HP-UX. (mgyger@itr.ch)
X
* Added int rplay_open_default(void) to the rplay library.
X
* Added jukebox version 1.2 to the contrib directory.  Thanks again Raphael.
X
--------------------------------------------------------------------------------
X
rplay 3.1 (BETA) major improvements and changes from rplay 3.0 PL2:
X
(This release has many changes so I probably have forgotten some of them.)
X
* Completely re-organized the rplay source tree.
X
* Designed and implemented RPTP.  This includes writing the RPTP client and
X  adding RPTP support to rplayd.  Please read doc/README.RPTP if you want
X  to learn more about RPTP.
X
* Added the following routines to librplay:
X
X  int rplay_host_volume(char *host, char *sound, int volume)
X  int rplay_open_sockaddr_in(struct sockaddr_in *saddr)
X  int rplay_ping(char *host)
X  int rplay_ping_sockfd(int rplay_fd)
X  int rplay_ping_sockaddr_in(struct sockaddr_in *saddr)
X  int rptp_open(char *host, int port, char *response, int response_size)
X  int rptp_read(int rptp_fd, char *ptr, int nbytes)
X  int rptp_write(int rptp_fd, char *ptr, int nbytes)
X  int rptp_putline(int rptp_fd, char *fmt, ...)
X  int rptp_getline(int rptp_fd, char *buf, int nbytes)
X  int rptp_command(int rptp_fd, char *command, char *response,int response_size)
X  int rptp_close(int rptp_fd)
X  void rptp_perror(char *message)
X
* Added the RPLAY_PING attribute to the RPLAY protocol.  This attribute is used
X  by RPTP to wakeup rplayd since inetd can invoke one program using two ports.
X
* Now using the GNU General Public License Version 2.
X
* Add the rplay.servers file which lists the rplay servers that rplayd should
X  contact to obtain sound files.
X
* Implemented the sound cache where rplayd will store sound files it obtains.
X
* Changed the format of the rplay.hosts file to accept wildcards and access
X  permissions.
X
* Fixed a bug that caused some rplay packets to incorrectly have permission
X  denied.
X
* Changed rplayd to accept sounds which are not in the rplay.conf and are
X  available locally.  For example, is /tmp/foo.au is not in the rplay.conf
X  it can still be played using 'rplay hostname /tmp/foo.au".
X
* Changed include/conf.h to '#define AUTH' by default.
X
* Switched to Darren Senn's hsearch implementation.
X
* Included Darren Senn's PORTABLE_LONG macro which is useful when examining
X  ulaw file headers on multiple architectures.
X
* Wrote some manual pages which are in the doc directory.
X
* Updated doc/README.LIBRPLAY to included the new RPTP extensions.
X
* Added a NEW version of mailsound to the contrib directory.  The new version
X  has a lot of new options.  Thanks Andrew.
X
* Added crossfire to the contrib directory.
X
* Added HP-UX patches from rkl@csc.liv.ac.uk (Richard Lloyd) and
X  Markus Gyger <mgyger@itr.ch>.
X
* Conversion tables are now used for both ulaw->linear and linear->ulaw.
X  The tables were contributed by Markus Gyger <mgyger@itr.ch>.
X
* Headerless ulaw files can still be played if their filename extension is
X  either .au, .u, or .ul as suggested by Markus Gyger <mgyger@itr.ch>.
X
* Added Solaris 2.x patches from Kjetil Wiekhorst J{\o}rgensen
X  <jorgens@pvv.unit.no>.
X
--------------------------------------------------------------------------------
X
rplay 3.0 PL2 major improvements and changes from rplay 3.0 PL1:
X
* Use strchr and strrchr instead of index and rindex.
X
* Added -r (random pick) option to the rplay client.
X
* Added RPLAY_RANDOM_SOUND attribute which will pick a sound randomly from
X  a sound list.  See README.LIBRPLAY for an example.
X
* Added jukebox to the contrib directory.  See contrib/jukebox1.1/README for
X  more details.  (Thanks quinet@montefiore.ulg.ac.be)
X
* Changed rplayd to handle filenames with spaces correctly.
X
* Fixed librplay.c and rplayd.c prototypes to support non ANSI C compilers.
X  (Thanks infmx!cheetah!dranney@uunet.UU.NET)
X
* Added the following to the rplay library to make playing sounds even easier:
X  (See README.LIBRPLAY for more information)
X
X  int rplay_open_display(void);
X  int rplay_display(char *sound);
X  int rplay_local(char *sound);
X  int rplay_host(char *host, char *sound);
X  int rplay_sound(int rplay_fd, char *sound);
X
--------------------------------------------------------------------------------
X
rplay 3.0 PL1 major improvements and changes from rplay 3.0:
X
* Changed conf.h to '#undef AUTH' (host authentication).
X
* Changed rplay_set to strdup() sound filenames.
X
* Added -n (count), -N (list count), and -P (priority) options to the rplay
X  client.
X
* Added RPLAY_PRIORITY attribute.  Priorities range from 0 to 255 (0 being
X  the lowest priority).  Sounds with higher priorities will replace lower
X  priority sounds when the sound spool is full.
X
* Sounds can be referenced using complete pathnames.  This helps to avoid
X  problems when different sound files have the same name.
X
* Sound filename extensions are now optional.  If extensions are used they
X  are enforced.
X
* Added RPLAY_LIST_COUNT attribute.  The sound list will be played count
X  number of times.
X
* Added RPLAY_COUNT attribute.  Each sound in a sound list will be played
X  count number of times.
X
* Fixed select's usage of timeval struct.  (sinster@scintilla.santa-clara.ca.us)
X
* Cleaned up the code a little.  Added better ANSI C support and put in
X  a little more documentation.
X
* Fixed some spelling mistakes.
X
* Removed -V option from the rplay client.
X
--------------------------------------------------------------------------------
X
rplay 3.0 major improvements and changes from rplay 2.0:
X
* rplayd is no longer based on Sun's lwp library.  This will make rplay
X  portable to machines other than SPARCstations.  Hopefully soon rplay will
X  work with BSDI, Linux, and maybe 386bsd.  Only 8 bit ulaw audio files are 
X  currently supported.
X
* The rplay library has been rewritten and is now much more flexible for rplay
X  additions.  This new library is not compatible with the rplay2.0 library,
X  what I mean is that old rplay programs will not compile.
X  See WARNING and README.LIBRPLAY for conversion help.  
X
* A more flexible rplay protocol is used.  The rplay2.0 protocol can still 
X  be supported.  See conf.h.
X
* Host authentication can be used to allow only certain machines access to
X  play sounds.  See conf.h and INSTALL.
X
* Compile time option to use mmap or malloc and read to load sound files.
X  See conf.h.
X
* inetd support can be disabled with a command line option
X
* rplayd timeouts can be changed or disabled with command line options
X
* rplayd has many other options, run rplay -h to see them.
X
* rplayd speed enhancements
X
--------------------------------------------------------------------------------
X
rplay 2.0 major improvements and changes from rplay 1.2:
X
* Sounds are no longer indexed by id, the sound names are now used.
X
* Sounds can be played, paused, continued, and stopped.
X
* Each sound can have a volume associated with it.  A volume is
X  a number between 0 and 255 and it is relative to the actual volume
X  of the audio device.
X
* Sequences of sounds are supported.  This is useful for playing
X  sentences or sounds that need to be played sequentially.
X
* mmap is now used to read sounds.  This increases performance
X  and saves a lot of memory.  Thanks to stripes@pix.com for this
X  suggestion.
X
* Broadcasting sounds.  To use this just use a broadcast address
X  instead of a hostname.  For example, I use:
X  rplay 130.191.255.255 burp.au
X  to play burp.au on all our machines running rplayd on our subnet.
X
* The Sun audio stuff is no longer used.  Thanks to libst.c and 
X  libst.h from Sound Tools.  See these files for more information.
X
SHAR_EOF
chmod 0644 rplay-3.1.0/CHANGES ||
echo 'restore of rplay-3.1.0/CHANGES failed'
Wc_c="`wc -c < 'rplay-3.1.0/CHANGES'`"
test 12233 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/CHANGES: original size 12233, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/Makefile ==============
if test -f 'rplay-3.1.0/Makefile' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/Makefile (File already exists)'
else
echo 'x - extracting rplay-3.1.0/Makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/Makefile' &&
# 
# Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
#
# This file is part of rplay.
#
# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
#
X
include Makefile.config
X
TARGETS=	librplay rplayd rplay rptp include doc
X
all:
X		@for i in $(TARGETS); \
X		do \
X			(echo making in $$i...; cd $$i; $(MAKE) $(MFLAGS) all); \
X		done;
X
depend:
X		@for i in $(TARGETS); \
X		do \
X			(echo make depend in $$i...; cd $$i; $(MAKE) $(MFLAGS) depend); \
X		done;
X
install:
X		@for i in $(TARGETS); \
X		do \
X			(echo installing in $$i...; cd $$i; $(MAKE) $(MFLAGS) install); \
X		done;
X
clean:
X		$(RM) a.out core *~ *.bak *.orig
X		@for i in $(TARGETS); \
X		do \
X			(echo cleaning in $$i...; cd $$i; $(MAKE) $(MFLAGS) clean); \
X		done;
X
world:		all install mail
X
mail:
X		@echo; echo -n 'Do you want send a message to the author ($(MAIL_TO)) (y/n) [y]? '; \
X		read answer; \
X		if [ "$$answer" = "y" -o "$$answer" = "" ]; \
X		then \
X			echo; echo 'Enter your message terminated by Control-D:'; echo; \
X			rm -f /tmp/rpm.$$$$; \
X			cat > /tmp/rpm.$$$$; \
X			echo; \
X			$(MAILER) '$(MAIL_SUBJECT)' $(MAIL_TO) < /tmp/rpm.$$$$; \
X			rm -f /tmp/rpm.$$$$; \
X			echo 'The message has been sent.'; \
X		fi; \
X		echo; echo 'Thank you for using rplay.'; echo
X
tar:
X		cd ..; rm -f rplay-3.1.0.tar.Z; gnutar Zcf rplay-3.1.0.tar.Z rplay-3.1.0
X
shar:
X		cd ..; rm -f rplay.??; shar -L60 -a -c -s $(MAIL_TO) -n rplay-3.1.0 -o rplay rplay-3.1.0
SHAR_EOF
chmod 0644 rplay-3.1.0/Makefile ||
echo 'restore of rplay-3.1.0/Makefile failed'
Wc_c="`wc -c < 'rplay-3.1.0/Makefile'`"
test 2031 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/Makefile: original size 2031, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplay/rplay.c ==============
if test ! -d 'rplay-3.1.0/rplay'; then
    echo 'x - creating directory rplay-3.1.0/rplay'
    mkdir 'rplay-3.1.0/rplay'
fi
if test -f 'rplay-3.1.0/rplay/rplay.c' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplay/rplay.c (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplay/rplay.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplay/rplay.c' &&
X
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#include "conf.h"
#include "version.h"
#include <stdio.h>
#include <string.h>
#include "rplay.h"
X
#ifdef __STDC__
main(int argc, char **argv)
#else
main(argc, argv)
int	argc;
char	**argv;
#endif
{
X	int		rplay_fd, c, command, volume, val;
X	int		list_count, count, priority, do_random;
X	char		*hosts = NULL, *p, *q;
X	RPLAY		*rp;  
X	extern char	*optarg; 
X	extern int	optind;
X
X	if (argc < 2)
X	{
X		usage();
X	}
X
X	command = RPLAY_PLAY;
X	volume = RPLAY_DEFAULT_VOLUME;
X	count = RPLAY_DEFAULT_COUNT;
X	list_count = RPLAY_DEFAULT_LIST_COUNT;
X	priority = RPLAY_DEFAULT_PRIORITY;
X	do_random = 0;
X
X	while ((c = getopt(argc, argv, "P:N:n:v:spch:r")) != -1)
X	{
X		switch (c)
X		{
X		case 'v':
X			volume = atoi(optarg);
X			break;
X
X		case 'n':
X			count = atoi(optarg);
X			break;
X
X		case 'N':
X			list_count = atoi(optarg);
X			break;
X
X		case 'P':
X			priority = atoi(optarg);
X			break;
X
X		case 's':   
X			command = RPLAY_STOP;
X			break;
X
X		case 'p': 
X			command = RPLAY_PAUSE;
X			break;
X
X		case 'c':  
X			command = RPLAY_CONTINUE;
X			break;
X		
X		case 'r':   
X			do_random++;
X			break;
X
X		case 'h':
X			hosts = optarg;
X			break;
X
X		case '?':
X			usage();
X		} 
X	}
X		     
X	if (argc == optind)
X	{
X		usage();
X	}
X
X	if (hosts == NULL)
X	{
X		hosts = rplay_default_host();
X	}
X
X	rp = rplay_create(command);
X	if (rp == NULL)
X	{
X		rplay_perror("rplay_create");
X		exit(1);
X	}
X	  
X	if (rplay_set(rp, RPLAY_LIST_COUNT, list_count, NULL) < 0)
X	{
X		rplay_perror("rplay_set");
X		exit(1);
X	}
X
X	if (rplay_set(rp, RPLAY_PRIORITY, priority, NULL) < 0)
X	{
X		rplay_perror("rplay_set");
X		exit(1);
X	}
X
X	while (argv[optind] != NULL)
X	{
X		val = rplay_set(rp, RPLAY_APPEND,
X			RPLAY_SOUND,	argv[optind++],
X			RPLAY_VOLUME,	volume,
X			RPLAY_COUNT,	count,
X			NULL);
X		if (val < 0)
X		{
X			rplay_perror("rplay_set");
X			exit(1);
X		}
X	}
X
X	if (do_random)
X	{
X		val = rplay_set(rp, RPLAY_RANDOM_SOUND, NULL);
X		if (val < 0)
X		{
X			rplay_perror("rplay_set");
X			exit(1);
X		}
X	}
X
X	q = hosts;
X	do
X	{
X		p = q;
X		q = strchr(p, ':');
X		if (q != NULL)
X		{
X			*q++ = '\0';
X		}
X		rplay_fd = rplay_open(p);
X		if (rplay_fd < 0)
X		{
X			rplay_perror(p);
X			exit(1);
X		}
X		if (rplay(rplay_fd, rp) < 0)
X		{
X			rplay_perror(p);
X			exit(1);
X		}
X		rplay_close(rplay_fd);
X	}
X	while (q != NULL);
X
X	exit(0);
}
X
usage()
{
X	printf("\n%s\n\n", rplay_version);
X	printf("usage: rplay [options] sound ...\n");
X	printf("\t-c      Continue.\n");
X	printf("\t-h host Specify the rplay host, default = %s.\n", rplay_default_host());
X	printf("\t-n n    Number of times to play each sound, default = %d.\n",
X		RPLAY_DEFAULT_COUNT); 
X	printf("\t-N n    Number of times to play the sound list, default = %d.\n",
X		RPLAY_DEFAULT_LIST_COUNT);
X	printf("\t-P n    Sound priority n (%d <= n <= %d), default = %d.\n",
X		RPLAY_MIN_PRIORITY,
X		RPLAY_MAX_PRIORITY,
X		RPLAY_DEFAULT_PRIORITY);
X	printf("\t-p      Pause.\n");
X	printf("\t-r      Randomly choose one of the given sounds.\n");
X	printf("\t-s      Stop.\n");
X	printf("\t-v n    Volume n (%d <= n <= %d), default = %d.\n",
X		RPLAY_MIN_VOLUME,
X		RPLAY_MAX_VOLUME,
X		RPLAY_DEFAULT_VOLUME);
X	printf("\n");
X	exit(1);
}
SHAR_EOF
chmod 0644 rplay-3.1.0/rplay/rplay.c ||
echo 'restore of rplay-3.1.0/rplay/rplay.c failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplay/rplay.c'`"
test 3860 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplay/rplay.c: original size 3860, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplay/Makefile ==============
if test -f 'rplay-3.1.0/rplay/Makefile' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplay/Makefile (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplay/Makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplay/Makefile' &&
# 
# Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
#
# This file is part of rplay.
#
# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
#
X
include ../Makefile.config
X
TARGET=		rplay
SRCS=		rplay.c
OBJS=		rplay.o
X
all:		$(TARGET)
X
$(TARGET):	$(OBJS) $(LIBRPLAY_DIR)/$(LIBRPLAY_NAME)
X		$(CC) $(CFLAGS) -o $@ $(OBJS) $(LDFLAGS)
X
install:	$(TARGET)
X		$(BIN_INSTALL) $(TARGET) $(INSTALL_BIN_DIR)
X
clean:
X		$(RM) $(TARGET) $(OBJS) core a.out *~ *.bak *.orig
X
depend:
X		$(MAKEDEPEND) -- $(CFLAGS) -- $(SRCS)
SHAR_EOF
chmod 0644 rplay-3.1.0/rplay/Makefile ||
echo 'restore of rplay-3.1.0/rplay/Makefile failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplay/Makefile'`"
test 1135 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplay/Makefile: original size 1135, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/include/rplay.h ==============
if test ! -d 'rplay-3.1.0/include'; then
    echo 'x - creating directory rplay-3.1.0/include'
    mkdir 'rplay-3.1.0/include'
fi
if test -f 'rplay-3.1.0/include/rplay.h' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/include/rplay.h (File already exists)'
else
echo 'x - extracting rplay-3.1.0/include/rplay.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/include/rplay.h' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#ifndef _rplay_h
#define _rplay_h
X
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
X
#define RPLAY_PORT		55555
#define RPTP_PORT		55556
X
#define RPLAY_NULL		0
#define RPLAY_PLAY		1
#define RPLAY_STOP		2
#define RPLAY_PAUSE		3
#define RPLAY_CONTINUE		4
#define RPLAY_SOUND		5
#define RPLAY_VOLUME		6
#define RPLAY_NSOUNDS		7
#define RPLAY_COMMAND		8
#define RPLAY_APPEND		9
#define RPLAY_INSERT		10
#define RPLAY_DELETE		11
#define RPLAY_CHANGE		12
#define RPLAY_COUNT		13
#define RPLAY_LIST_COUNT	14
#define RPLAY_PRIORITY		15
#define RPLAY_RANDOM_SOUND	16
#define RPLAY_PING		17
X
#define RPLAY_MIN_VOLUME	0
#define RPLAY_DEFAULT_VOLUME	127
#define RPLAY_MAX_VOLUME	255
X
#define RPLAY_DEFAULT_COUNT		1
#define RPLAY_DEFAULT_LIST_COUNT	1
X
#define RPLAY_MIN_PRIORITY		0
#define RPLAY_DEFAULT_PRIORITY		0
#define RPLAY_MAX_PRIORITY		255
X
#define RPLAY_DEFAULT_RANDOM_SOUND	-1
X
/*
X * rplay errors used by rplay_errno
X */
#define RPLAY_ERROR_NONE	0
#define RPLAY_ERROR_MEMORY	1
#define RPLAY_ERROR_HOST	2
#define RPLAY_ERROR_CONNECT	3
#define RPLAY_ERROR_SOCKET	4
#define RPLAY_ERROR_WRITE	5
#define RPLAY_ERROR_CLOSE	6 
#define RPLAY_ERROR_PACKET_SIZE	7
#define RPLAY_ERROR_BROADCAST	8
#define RPLAY_ERROR_ATTRIBUTE	9
#define RPLAY_ERROR_COMMAND	10
#define RPLAY_ERROR_INDEX	11
#define RPLAY_ERROR_MODIFIER	12
X
/*
X * RPTP errors used by rptp_errno
X */
#define RPTP_ERROR_NONE		0
#define RPTP_ERROR_MEMORY	1
#define RPTP_ERROR_HOST		2
#define RPTP_ERROR_CONNECT	3
#define RPTP_ERROR_SOCKET	4
#define RPTP_ERROR_OPEN		5
#define RPTP_ERROR_READ		6
#define RPTP_ERROR_WRITE	7
#define RPTP_ERROR_PING		8
#define RPTP_ERROR_TIMEOUT	9
X
/*
X * RPTP response types
X */
#define RPTP_ERROR		'-'
#define RPTP_OK			'+'
#define RPTP_TIMEOUT		'!'
X
/*
X * rplay 2.0 support
X */
#define OLD_RPLAY_PLAY		1
#define OLD_RPLAY_STOP		2
#define OLD_RPLAY_PAUSE		3
#define OLD_RPLAY_CONTINUE	4
X
/*
X * rplay attributes
X */
typedef struct _rplay_attrs
{
X	struct _rplay_attrs	*next;
X	char			*sound;
X	int			volume;
X	int			count;
} RPLAY_ATTRS;
X
/*
X * the rplay object
X */
typedef struct _rplay
{
X	struct _rplay_attrs	*attrs;
X	struct _rplay_attrs	**attrsp;
X	char			*buf;
X	int			len;
X	int			size;
X	int			command;
X	int			nsounds;
X	int			count;
X	int			priority;
X	int			random_sound;
} RPLAY;
X
#define RPTP_MAX_LINE	1024
#define RPTP_MAX_ARGS	32
X
extern int	rplay_errno;
extern int	rptp_errno;
extern char	*rplay_errlist[];
extern char	*rptp_errlist[];
X
#ifdef __cplusplus
#ifndef __STDC__
#define __STDC__
#endif
extern "C" {
#endif
X
#ifdef __STDC__
extern RPLAY	*rplay_create(int rplay_command);
extern char	*rplay_convert(char *buf);
extern int	rplay_pack(RPLAY *rp);
extern RPLAY	*rplay_unpack(char *buf);
extern void	rplay_destroy(RPLAY *rp);
extern int	rplay_set(RPLAY *, ...);
extern int	rplay_get(RPLAY *, ...);
extern int	rplay_open(char *host);
extern int	rplay_open_sockaddr_in(struct sockaddr_in *saddr);
extern int	rplay(int, RPLAY *rp);
extern int	rplay_close(int rplay_fd);
extern void	rplay_perror(char *message);
extern int	rplay_open_display(void);
extern int	rplay_display(char *sound);
extern int	rplay_local(char *sound);
extern int	rplay_host(char *host, char *sound);
extern int	rplay_host_volume(char *host, char *sound, int volume);
extern int	rplay_sound(int rplay_fd, char *sound);
extern int	rplay_ping(char *host);
extern int	rplay_ping_sockaddr_in(struct sockaddr_in *saddr);
extern int	rplay_ping_sockfd(int sock_fd);
extern char	*rplay_default_host(void);
extern int	rplay_default(char *sound);
extern int	rplay_open_default(void);
extern int	rptp_open(char *host, int port, char *response, int response_size);
extern int	rptp_read(int rptp_fd, char *buf, int nbytes);
extern int	rptp_write(int rptp_fd, char *buf, int nbytes);
extern int	rptp_close(int rptp_fd);
extern void	rptp_perror(char *message);
extern int	rptp_putline(int rptp_fd, char *fmt, ...);
extern int	rptp_getline(int rptp_fd, char *buf, int nbytes);
extern int	rptp_command(int rptp_fd, char *command, char *response, int response_size);
#else
extern RPLAY	*rplay_create(/* int rplay_command */);
extern char	*rplay_convert(/* char *buf */);
extern int	rplay_pack(/* RPLAY *rp */);
extern RPLAY	*rplay_unpack(/* char *buf */);
extern void	rplay_destroy(/* RPLAY *rp */);
extern int	rplay_set(/* RPLAY *, ... */);
extern int	rplay_get(/* RPLAY *, ... */);
extern int	rplay_open(/* char *host */);
extern int	rplay_open_sockaddr_in(/* struct sockaddr_in *saddr */);
extern int	rplay(/* int, RPLAY *rp */);
extern int	rplay_close(/* int rplay_fd */);
extern void	rplay_perror(/* char *message */);
extern int	rplay_open_display();
extern int	rplay_display(/* char *sound */);
extern int	rplay_local(/* char *sound */);
extern int	rplay_host(/* char *host, char *sound */);
extern int	rplay_host_volume(/* char *host, char *sound, int volume */);
extern int	rplay_sound(/* int rplay_fd, char *sound */);
extern int	rplay_ping(/* char *host */);
extern int	rplay_ping_sockaddr_in(/* struct sockaddr_in *saddr */);
extern int	rplay_ping_sockfd(/* int sock_fd */);
extern char	*rplay_default_host();
extern int	rplay_default(/* char *sound */);
extern int	rplay_open_default();
extern int	rptp_open(/* char *host, int port, char *response, int response_size */);
extern int	rptp_read(/* int rptp_fd, char *buf, int nbytes */);
extern int	rptp_write(/* int rptp_fd, char *buf, int nbytes */);
extern int	rptp_close(/* int rptp_fd */);
extern void	rptp_perror(/* char *message */);
extern int	rptp_putline(/* int rptp_fd, char *fmt, ... */);
extern int	rptp_getline(/* int rptp_fd, char *buf, int nbytes */);
extern int	rptp_command(/* int rptp_fd, char *command, char *response, int response_size */);
#endif
X
#ifdef __cplusplus
}
#endif
X
#ifdef NEED_STRDUP
#ifdef __STDC__
extern char	*strdup(char *str);
#else
extern char	*strdup(/* char *str */);
#endif
#endif /* NEED_STRDUP */
X
#endif /* _rplay_h */
SHAR_EOF
chmod 0644 rplay-3.1.0/include/rplay.h ||
echo 'restore of rplay-3.1.0/include/rplay.h failed'
Wc_c="`wc -c < 'rplay-3.1.0/include/rplay.h'`"
test 6693 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/include/rplay.h: original size 6693, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/include/conf.h ==============
if test -f 'rplay-3.1.0/include/conf.h' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/include/conf.h (File already exists)'
else
echo 'x - extracting rplay-3.1.0/include/conf.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/include/conf.h' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#ifndef _conf_h
#define _conf_h
X
/*
X * rplay configuration options and settings
X *
X * Toggle options using #define and #undef.
X */
X
/*
X * mmap sound files instead of malloc
X */
#define MMAP
X
/*
X * host authentication
X */
#define AUTH	
X
/*
X * support rplay 2.0 packets, defining this won't hurt much
X */
#define OLD_RPLAY
X
/*
X * maximum number of simultaneous sounds
X */
#define SPOOL_SIZE	12
X
/*
X * do you need usleep?
X *
X * This must be defined for Solaris 2.x, HP-UX, and SGI
X */
#undef NEED_USLEEP
X
/*
X * do you need strdup?
X *
X * This must be defined for Ultrix.
X */
#undef NEED_STRDUP
X
/*
X * size of rplayd's hash table
X */
#define MAX_SOUNDS	4001	/* yes that is a prime number */
X
/*
X * rplay configuration file
X */
#define RPLAY_CONF	"/usr/local/etc/rplay.conf"
X
/*
X * rplay host authentication file to use if AUTH is enabled
X */
#ifdef AUTH
#define RPLAY_HOSTS	"/usr/local/etc/rplay.hosts"
#endif /* AUTH */
X
/*
X * rplay servers file
X */
#define RPLAY_SERVERS	"/usr/local/etc/rplay.servers"
X
/*
X * rplay cache directory
X */
#define RPLAY_CACHE	"/tmp/rplay.cache"
X
/*
X * maximum packet size
X */
#define MAX_PACKET		8192
X
/*
X * exit after 360 idle seconds (disabled with zero)
X */
#define RPLAYD_TIMEOUT		360
X
/*
X * name of the audio device (SGI users can ignore this)
X */
#define AUDIO_DEVICE		"/dev/audio"
X
/*
X * close the audio device after 5 idle seconds (disabled with zero)
X */
#define AUDIO_TIMEOUT		5
X
/*
X * maximum size of the rplay.cache directory
X *
X * 100k is good for debugging.
X *
X * The size you choose should at least be big enough to hold the
X * largest sound you plan on playing.
X */
#define RPLAY_CACHE_SIZE	(1024*1024)
X
/*
X * delay time between RPTP server pings
X */
#define RPTP_PING_DELAY		5
X
/*
X * number of times to try and connect to an RPTP server
X */
#define RPTP_CONNECT_ATTEMPTS	3
X
/*
X * close RPTP connections after 300 idle seconds
X */
#define RPTP_CONNECTION_TIMEOUT	300
X
/*
X * maximum number of RPTP client connections (disabled with zero)
X */
#define RPTP_MAX_CONNECTIONS	16
X
/*
X * free memory used by sounds after 60 idle seconds
X */
#define SOUND_CLEANUP_TIMEOUT	60
X
/*************** EVERYTHING BELOW THIS LINE SHOULD BE OK *********************/
X
/*
X * Use the correct PORTABLE_LONG definition depending on your machine's
X * architecture.
X */
#ifdef i386
/*
X * Little endian architectures
X */
#define PORTABLE_LONG(buf) (unsigned long )(((( \
X	((((unsigned long )((unsigned char *)(buf))[0]) << 8) | \
X	(unsigned long )((unsigned char *)(buf))[1]) << 8) | \
X	(unsigned long )((unsigned char *)(buf))[2]) << 8) | \
X	(unsigned long )((unsigned char *)(buf))[3])
#else
/*
X * Big endian architectures
X */
#define PORTABLE_LONG(buf) *(unsigned long *)(buf)
#endif
X
/*
X * Solaris 2.x using gcc or SunPro cc and HP-UX
X */
#if (defined(sun) && (defined(__svr4__) || defined(SVR4))) || defined(__hpux)
#define random()	lrand48()
#define srandom(x)	srand48(x)
#endif
X
#endif /* _conf_h */
SHAR_EOF
chmod 0644 rplay-3.1.0/include/conf.h ||
echo 'restore of rplay-3.1.0/include/conf.h failed'
Wc_c="`wc -c < 'rplay-3.1.0/include/conf.h'`"
test 3715 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/include/conf.h: original size 3715, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/include/version.h ==============
if test -f 'rplay-3.1.0/include/version.h' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/include/version.h (File already exists)'
else
echo 'x - extracting rplay-3.1.0/include/version.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/include/version.h' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#ifndef _version_h
#define _version_h
X
#define RPLAY_MAJOR_VERSION	3
#define RPLAY_MINOR_VERSION	1
#define RPLAY_PATCHLEVEL	0
X
#define RPLAY_VERSION		30	/* version number sent with rplay packets */
X
static char	*rplay_version = "rplay 3.1.0"; 
X
#endif /* _version_h */
SHAR_EOF
chmod 0644 rplay-3.1.0/include/version.h ||
echo 'restore of rplay-3.1.0/include/version.h failed'
Wc_c="`wc -c < 'rplay-3.1.0/include/version.h'`"
test 1062 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/include/version.h: original size 1062, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/include/Makefile ==============
if test -f 'rplay-3.1.0/include/Makefile' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/include/Makefile (File already exists)'
else
echo 'x - extracting rplay-3.1.0/include/Makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/include/Makefile' &&
# 
# Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
#
# This file is part of rplay.
#
# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
#
X
include ../Makefile.config
X
TARGET=		rplay.h
X
all:
X
install:	$(TARGET)
X		$(INSTALL) $(TARGET) $(INSTALL_INCLUDE_DIR)
X
clean:
X		$(RM) *~ *.bak *.orig
X
depend:
X
SHAR_EOF
chmod 0644 rplay-3.1.0/include/Makefile ||
echo 'restore of rplay-3.1.0/include/Makefile failed'
Wc_c="`wc -c < 'rplay-3.1.0/include/Makefile'`"
test 932 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/include/Makefile: original size 932, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/librplay/Makefile ==============
if test ! -d 'rplay-3.1.0/librplay'; then
    echo 'x - creating directory rplay-3.1.0/librplay'
    mkdir 'rplay-3.1.0/librplay'
fi
if test -f 'rplay-3.1.0/librplay/Makefile' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/librplay/Makefile (File already exists)'
else
echo 'x - extracting rplay-3.1.0/librplay/Makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/librplay/Makefile' &&
# 
# Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
#
# This file is part of rplay.
#
# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
#
X
include ../Makefile.config
X
TARGET=		$(LIBRPLAY_NAME)
SRCS=		rplay.c rptp.c
OBJS=		rplay.o rptp.o
X
all:		$(TARGET)
X
#
# SunOS 4.1.x, Solaris 2.x, Linux
#
$(TARGET):	$(OBJS)
X		$(AR) rcv $@ $?
X		$(RANLIB) $@
X
install:	$(TARGET)
X		$(INSTALL) $(TARGET) $(INSTALL_LIB_DIR)
X		$(RANLIB) $(INSTALL_LIB_DIR)/$(TARGET)
X
#
# For HP-UX comment above and uncomment below.
#
#CFLAGS=	+z $(CC_OPTIONS) -I$(INCLUDE_DIR)
#
#$(TARGET):	$(OBJS)
#		ld -b -s +FPD -o $@ $(OBJS)
#		if [ ! -d $(INSTALL_LIB_DIR) ]; then mkdir $(INSTALL_LIB_DIR); fi
#		$(INSTALL) $@ $(INSTALL_LIB_DIR)
#		chmod a+rx $(INSTALL_LIB_DIR) $(INSTALL_LIB_DIR)/$@
#
#install:
#
X
clean:
X		$(RM) $(TARGET) $(OBJS) core a.out *~ *.bak *.orig
X
depend:
X		$(MAKEDEPEND) -- $(CFLAGS) -- $(SRCS)
SHAR_EOF
chmod 0644 rplay-3.1.0/librplay/Makefile ||
echo 'restore of rplay-3.1.0/librplay/Makefile failed'
Wc_c="`wc -c < 'rplay-3.1.0/librplay/Makefile'`"
test 1514 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/librplay/Makefile: original size 1514, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/librplay/rplay.c ==============
if test -f 'rplay-3.1.0/librplay/rplay.c' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/librplay/rplay.c (File already exists)'
else
echo 'x - extracting rplay-3.1.0/librplay/rplay.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/librplay/rplay.c' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#include "conf.h"
#include "version.h"
#include "rplay.h"
#include <sys/param.h>
#include <netdb.h>
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <memory.h>
X
int 	rplay_errno;
X
char	*rplay_errlist[] =
{
X	"no error",			/* RPLAY_ERROR_NONE */
X	"out of memory",		/* RPLAY_ERROR_MEMORY */
X	"host not found",		/* RPLAY_ERROR_HOST */
X	"cannot connect to socket",	/* RPLAY_ERROR_CONNECT */
X	"cannot create socket",		/* RPLAY_ERROR_SOCKET */
X	"error writing to socket",	/* RPLAY_ERROR_WRITE */
X	"error closing socket",		/* RPLAY_ERROR_CLOSE */ 
X	"max packet size exceeded",	/* RPLAY_ERROR_PACKET_SIZE */
X	"cannot enable broadcast",	/* RPLAY_ERROR_BROADCAST */
X	"unknown rplay attribute",	/* RPLAY_ERROR_ATTRIBUTE */
X	"unknown rplay command",	/* RPLAY_ERROR_COMMAND */
X	"illegal rplay index value",	/* RPLAY_ERROR_INDEX */
X	"unknown rplay modifier",	/* RPLAY_ERROR_MODIFIER */
};
X
#ifdef __STDC__
unsigned long	inet_addr(char *rp);
#else
unsigned long	inet_addr();
#endif
X
#ifdef NEED_STRDUP
#ifdef __STDC__
char	*strdup(char *str)
#else
char	*strdup(str)
char	*str;
#endif
{
X	char	*p;
X
X	p = (char *)malloc(strlen(str)+1);
X	strcpy(p, str);
X
X	return p;
}
#endif /* NEED_STRDUP */
X
/*
X * create an rplay attributes object
X */
#ifdef __STDC__
static RPLAY_ATTRS	*rplay_attrs_create(void)
#else
static RPLAY_ATTRS	*rplay_attrs_create()
#endif
{
X	RPLAY_ATTRS	*attrs;
X
X	attrs = (RPLAY_ATTRS *)malloc(sizeof(RPLAY_ATTRS));
X	if (attrs == NULL)
X	{
X		return NULL;
X	}
X	attrs->next = NULL;
X	attrs->sound = NULL;
X	attrs->volume = RPLAY_DEFAULT_VOLUME;
X	attrs->count = RPLAY_DEFAULT_COUNT;
X
X	return attrs;
}
X
/*
X * free memory used by an rplay attributes object
X */
#ifdef __STDC__
static void	rplay_attrs_destroy(RPLAY_ATTRS *attrs)
#else
static void	rplay_attrs_destroy(attrs)
RPLAY_ATTRS	*attrs;
#endif
{
X	free((char *)attrs->sound);
X	free((char *)attrs);
}
X
#define COPY_SIZE	128
#define COPY(rp, p, n) \
X	grow = 0; \
X	while (rp->len + n > rp->size) \
X	{ \
X		grow++; \
X		rp->size += COPY_SIZE; \
X		if (rp->size > MAX_PACKET) \
X		{ \
X			rplay_errno = RPLAY_ERROR_PACKET_SIZE; \
X			return -1; \
X		} \
X	} \
X	if (grow) \
X	{ \
X		rp->buf = realloc(rp->buf, rp->size); \
X		if (rp->buf == NULL) \
X		{ \
X			rplay_errno = RPLAY_ERROR_MEMORY; \
X			return -1; \
X		} \
X	} \
X	memcpy((char *)rp->buf + rp->len, (char *)p, n); \
X	rp->len += n; \
X
/*
X * pack the rplay object into the internal buffer
X *
X * this routine is called everytime rplay_set is used
X */
#ifdef __STDC__
int	rplay_pack(RPLAY *rp)
#else
int	rplay_pack(rp)
RPLAY	*rp;
#endif
{
X	RPLAY_ATTRS	*attrs;
X	int		len, grow = 0, i;
X	unsigned char	val;
X	
X	rp->len = 0;
X	val = RPLAY_VERSION;
X	COPY(rp, &val, sizeof(val));
X	val = rp->command;
X	COPY(rp, &val, sizeof(val));
X
X	if (rp->count != RPLAY_DEFAULT_LIST_COUNT)
X	{
X		val = RPLAY_LIST_COUNT;
X		COPY(rp, &val, sizeof(val));
X		val = rp->count;
X		COPY(rp, &val, sizeof(val));
X	}
X
X	if (rp->priority != RPLAY_DEFAULT_PRIORITY)
X	{
X		val = RPLAY_PRIORITY;
X		COPY(rp, &val, sizeof(val));
X		val = rp->priority;
X		COPY(rp, &val, sizeof(val));
X	}
X
X	for (i = 0, attrs = rp->attrs; attrs; attrs = attrs->next, i++)
X	{
X		if (rp->random_sound != RPLAY_DEFAULT_RANDOM_SOUND)
X		{
X			if (i != rp->random_sound)
X			{
X				continue;
X			}
X		}
X
X		val = RPLAY_SOUND;
X		COPY(rp, &val, sizeof(val));
X		len = strlen(attrs->sound)+1;
X		COPY(rp, attrs->sound, len);
X
X		if (attrs->volume != RPLAY_DEFAULT_VOLUME)
X		{
X			val = RPLAY_VOLUME;
X			COPY(rp, &val, sizeof(val));
X			val = attrs->volume;
X			COPY(rp, &val, sizeof(val));
X		}
X
X		if (attrs->count != RPLAY_DEFAULT_COUNT)
X		{
X			val = RPLAY_COUNT;
X			COPY(rp, &val, sizeof(val));
X			val = attrs->count;
X			COPY(rp, &val, sizeof(val));
X		}
X
X		val = RPLAY_NULL;
X		COPY(rp, &val, sizeof(val));
X	}
X
X	if (i == 0)
X	{
X		val = RPLAY_NULL;
X		COPY(rp, &val, sizeof(val));
X	}
X	
X	val = RPLAY_NULL;
X	COPY(rp, &val, sizeof(val));
X
X	return 0;
}
X
/*
X * unpack an rplay packet into an rplay object
X */
#ifdef __STDC__
RPLAY	*rplay_unpack(char *packet)
#else
RPLAY	*rplay_unpack(packet)
char	*packet;
#endif
{
X	RPLAY		*rp;
X	int		still_going = 1;
X	int		version;
X
X	rplay_errno = RPLAY_ERROR_NONE;
X
X	version = *packet++;
X	rp = rplay_create(*packet++);
X	if (rp == NULL)
X	{
X		rplay_errno = RPLAY_ERROR_MEMORY;
X		return NULL;
X	}
X
X	*(rp->attrsp) = rplay_attrs_create();
X	if (*(rp->attrsp) == NULL)
X	{
X		rplay_errno = RPLAY_ERROR_MEMORY;
X		return NULL;
X	}
X
X	while (still_going)
X	{
X		switch (*packet++)
X		{
X		case RPLAY_LIST_COUNT:
X			rp->count = (unsigned char)*packet++;
X			break;
X
X		case RPLAY_PRIORITY:
X			rp->priority = (unsigned char)*packet++;
X			break;
X
X		case RPLAY_SOUND:
X			(*rp->attrsp)->sound = strdup(packet);
X			packet += strlen(packet)+1;
X			break;
X
X		case RPLAY_VOLUME:
X			(*rp->attrsp)->volume = (unsigned char)*packet++;
X			break;
X			
X		case RPLAY_COUNT:
X			(*rp->attrsp)->count = (unsigned char)*packet++;
X			break;
X			
X		case RPLAY_NULL:
X			rp->nsounds++;
X			rp->attrsp = &(*rp->attrsp)->next;
X			if (*packet == RPLAY_NULL)
X			{
X				still_going = 0;
X			}
X			else
X			{
X				*(rp->attrsp) = rplay_attrs_create();
X				if (*(rp->attrsp) == NULL)
X				{
X					rplay_errno = RPLAY_ERROR_MEMORY;
X					return NULL;
X				}
X			}
X			break;
X
X		default:
X			rplay_errno = RPLAY_ERROR_ATTRIBUTE;
X			return NULL;
X		}
X	}
X
X	return rp;
}
X
/*
X * create an rplay object for the given command
X *
X * currently all commands use the same internal representation but this can
X * be changed in the future
X */
#ifdef __STDC__
RPLAY	*rplay_create(int command)
#else
RPLAY	*rplay_create(command)
int	command;
#endif
{
X	RPLAY	*rp;
X
X	rplay_errno = RPLAY_ERROR_NONE;
X
X	rp = (RPLAY *)malloc(sizeof(RPLAY));
X	if (rp == NULL)
X	{
X		rplay_errno = RPLAY_ERROR_MEMORY;
X		return NULL;
X	}
X
X	rp->attrs = NULL;
X	rp->attrsp = &rp->attrs;
X	rp->buf = (char *)malloc(COPY_SIZE);
X	if (rp->buf == NULL)
X	{
X		rplay_errno = RPLAY_ERROR_MEMORY;
X		return NULL;
X	}
X
X	rp->len = 0;
X	rp->size = 0;
X	rp->command = RPLAY_NULL;
X	rp->nsounds = 0;
X	rp->count = RPLAY_DEFAULT_LIST_COUNT;
X	rp->priority = RPLAY_DEFAULT_PRIORITY;
X	rp->random_sound = RPLAY_DEFAULT_RANDOM_SOUND;
X
X	switch (command)
X	{
X	case RPLAY_PLAY:
X	case RPLAY_STOP:
X	case RPLAY_PAUSE:
X	case RPLAY_CONTINUE:
X	case RPLAY_PING:
X		rp->command = command;
X		break;
X
X	default:
X		rplay_errno = RPLAY_ERROR_COMMAND;
X		return NULL;
X	}
X
X	return rp;
}
X
/*
X * return the rplay attributes for the given index
X */
#ifdef __STDC__
static RPLAY_ATTRS	*get_attrs(RPLAY_ATTRS *attrs, int index)
#else
static RPLAY_ATTRS	*get_attrs(attrs, index)
RPLAY_ATTRS	*attrs;
int		index;
#endif
{
X	int	i;
X
X	if (index < 0)
X	{
X		return NULL;
X	}
X
X	for (i = 0; i < index && attrs; i++, attrs = attrs->next);
X
X	return attrs;
}
X
/*
X * set rplay attributes for the give rplay object
X *
X * The argument list should be NULL terminated but this is
X * not always checked.
X */
#ifdef __STDC__
int	rplay_set(RPLAY *rp, ...)
#else
int	rplay_set(va_alist)
va_dcl
#endif
{
X	va_list		args;
X	RPLAY_ATTRS	*attrs = NULL, *prev = NULL, *curr;
X	int		index, i, modifier;
X	time_t		seed;
X
#ifdef __STDC__
X	va_start(args, rp);
#else
X	RPLAY		*rp;
X	va_start(args);
X	rp = va_arg(args, RPLAY *);
#endif
X
X	rplay_errno = RPLAY_ERROR_NONE;
X
X	modifier = va_arg(args, int);
X
X	switch (modifier)
X	{
X	case RPLAY_APPEND:
X		*(rp->attrsp) = attrs = rplay_attrs_create();
X		if (attrs == NULL)
X		{
X			rplay_errno = RPLAY_ERROR_MEMORY;
X			return -1;
X		}
X		rp->attrsp = &attrs->next;
X		rp->nsounds++;
X		break;
X		
X	case RPLAY_INSERT:
X		index = va_arg(args, int);
X		if (index < 0)
X		{
X			rplay_errno = RPLAY_ERROR_INDEX;
X			return -1;
X		}
X		for (i = 0, curr = rp->attrs; i < index && curr; i++)
X		{
X			prev = curr;
X			curr = curr->next;
X		}
X		if (curr == NULL && i != index)
X		{
X			rplay_errno = RPLAY_ERROR_INDEX;
X			return -1;
X		}
X		attrs = rplay_attrs_create();
X		if (attrs == NULL)
X		{
X			rplay_errno = RPLAY_ERROR_MEMORY;
X			return -1;
X		}
X		if (prev)
X		{
X			prev->next = attrs;
X		}
X		else
X		{
X			*(rp->attrsp) = attrs;
X		}
X		attrs->next = curr;
X		if (attrs->next == NULL)
X		{
X			rp->attrsp = &attrs->next;
X		}
X		rp->nsounds++;
X		break;
X
X	case RPLAY_DELETE:
X		index = va_arg(args, int);
X		if (index < 0)
X		{
X			rplay_errno = RPLAY_ERROR_INDEX;
X			return -1;
X		}
X		for (i = 0, curr = rp->attrs; i < index && curr; i++)
X		{
X			prev = curr;
X			curr = curr->next;
X		}
X		if (curr == NULL)
X		{
X			rplay_errno = RPLAY_ERROR_INDEX;
X			return -1;
X		}
X		if (prev)
X		{
X			prev->next = curr->next;
X			if (prev->next == NULL)
X			{
X				rp->attrsp = &prev->next;
X			}
X		}
X		else
X		{
X			rp->attrs = curr->next;
X			if (rp->attrs == NULL)
X			{
X				rp->attrsp = &rp->attrs;
X			}
X		}
X		rplay_attrs_destroy(curr);
X		rp->nsounds--;
X		break;
X
X	case RPLAY_CHANGE:
X		index = va_arg(args, int);
X		attrs = get_attrs(rp->attrs, index);
X		if (attrs == NULL)
X		{
X			rplay_errno = RPLAY_ERROR_INDEX;
X			return -1;
X		}
X		break;
X
X	case RPLAY_LIST_COUNT:
X		rp->count = va_arg(args, int);
X		break;
X
X	case RPLAY_PRIORITY:
X		rp->priority = va_arg(args, int);
X		break;
X
X	case RPLAY_RANDOM_SOUND:
X		seed = time(0);
X		srandom((int)seed);
X		rp->random_sound = (int)(random() % rp->nsounds);
X		break;
X
X	default:
X		rplay_errno = RPLAY_ERROR_MODIFIER;
X		return -1;
X	}
X
X	if (attrs)
X	{
X		int	attribute;
X
X		while (attribute = va_arg(args, int))
X		{
X			switch (attribute)
X			{
X			case RPLAY_SOUND:
X				attrs->sound = strdup(va_arg(args, char *));
X				break;
X
X			case RPLAY_VOLUME:
X				attrs->volume = va_arg(args, int);
X				break;
X
X			case RPLAY_COUNT:
X				attrs->count = va_arg(args, int);
X				break;
X
X			case RPLAY_LIST_COUNT:
X				rp->count = va_arg(args, int);
X				break;
X
X			case RPLAY_PRIORITY:
X				rp->priority = va_arg(args, int);
X				break;
X
X			default:
X				rplay_errno = RPLAY_ERROR_ATTRIBUTE;
X				return -1;
X			}
X		}
X	}
X
X	return rplay_pack(rp);
}
X
/*
X * retrieve rplay attributes from the given rplay object
X */
#ifdef __STDC__
int	rplay_get(RPLAY *rp, ...)
#else
int	rplay_get(va_alist)
va_dcl
#endif
{
X	va_list		args;
X	RPLAY_ATTRS	*attrs;
X	int		get, index;
X
#ifdef __STDC__
X	va_start(args, rp);
#else
X	RPLAY		*rp;
X	va_start(args);
X	rp = va_arg(args, RPLAY *);
#endif
X	rplay_errno = RPLAY_ERROR_NONE;
X
X	get = va_arg(args, int);
X
X	switch (get)
X	{
X	case RPLAY_NSOUNDS:
X		return rp->nsounds;
X
X	case RPLAY_COMMAND:
X		return rp->command;
X
X	case RPLAY_LIST_COUNT:
X		return rp->count;
X
X	case RPLAY_PRIORITY:
X		return rp->priority;
X
X	case RPLAY_RANDOM_SOUND:
X		return rp->random_sound;
X
X	case RPLAY_SOUND:
X		index = va_arg(args, int);
X		attrs = get_attrs(rp->attrs, index);
X		if (attrs == NULL)
X		{
X			rplay_errno = RPLAY_ERROR_INDEX;
X			return -1;
X		}
X		return (int)attrs->sound;
X		
X	case RPLAY_VOLUME:
X		index = va_arg(args, int);
X		attrs = get_attrs(rp->attrs, index);
X		if (attrs == NULL)
X		{
X			rplay_errno = RPLAY_ERROR_INDEX;
X			return -1;
X		}
X		return attrs->volume;
X
X	case RPLAY_COUNT:
X		index = va_arg(args, int);
X		attrs = get_attrs(rp->attrs, index);
X		if (attrs == NULL)
X		{
X			rplay_errno = RPLAY_ERROR_INDEX;
X			return -1;
X		}
X		return attrs->count;
X
X	default:
X		rplay_errno = RPLAY_ERROR_ATTRIBUTE;
X		return -1;
X	}
}
X
/*
X * free memory used by the given rplay object
X */
#ifdef __STDC__
void	rplay_destroy(RPLAY *rp)
#else
void	rplay_destroy(rp)
RPLAY	*rp;
#endif
{
X	RPLAY_ATTRS	*p, *q;
X
X	rplay_errno = RPLAY_ERROR_NONE;
X
X	for (p = rp->attrs; p; q = p, p = p->next, rplay_attrs_destroy(q));
X	free((char *)rp->buf);
X	free((char *)rp);
}
X
/*
X * support routine to convert rplay2.0 packets to rplay3.0
X */
#ifdef OLD_RPLAY
#ifdef __STDC__
char	*rplay_convert(char *p)
#else
char	*rplay_convert(p)
char	*p;
#endif
{
X	static char	buf[MAX_PACKET];
X	char		*q = buf;
X	int		len;
X
X	*q++ = RPLAY_VERSION;
X	switch (*p++)
X	{
X	case OLD_RPLAY_PLAY:
X		*q++ = RPLAY_PLAY;
X		break;
X
X	case OLD_RPLAY_STOP:
X		*q++ = RPLAY_STOP;
X		break;
X
X	case OLD_RPLAY_PAUSE:
X		*q++ = RPLAY_PAUSE;
X		break;
X
X	case OLD_RPLAY_CONTINUE:
X		*q++ = RPLAY_CONTINUE;
X		break;
X	}
X
X	do
X	{
X		*q++ = RPLAY_SOUND;
X		strcpy(q, p);
X		len = strlen(p)+1;
X		p += len;
X		q += len;
X		*q++ = RPLAY_VOLUME;
X		*q++ = *p++;
X		*q++ = RPLAY_NULL;
X	}
X	while (*p);
X
X	*q++ = RPLAY_NULL;
X
X	return buf;
}
#endif /* OLD_RPLAY */
X
/*
X * open a UDP socket for the given host.
X *
X * The host can be either a name or an IP address.
X */
#ifdef __STDC__
int	rplay_open(char *host)
#else
int	rplay_open(host)
char	*host;
#endif
{
X	struct hostent		*hp;
X	struct servent		*sp;
X	u_long			addr;
X	struct sockaddr_in	s;
X
X	rplay_errno = RPLAY_ERROR_NONE;
X
X	memset((char *)&s, 0, sizeof(s));
X
X	addr = inet_addr(host);
X	if (addr == 0xffffffff)
X	{
X		hp = gethostbyname(host);
X		if (hp == NULL)
X		{
X			rplay_errno = RPLAY_ERROR_HOST;
X			return -1;
X		}
X		memcpy((char *)&s.sin_addr.s_addr, (char *)hp->h_addr, hp->h_length);
X	}
X	else
X	{
X		memcpy((char *)&s.sin_addr.s_addr, (char *)&addr, sizeof(addr));
X	}
X
X	sp = getservbyname("rplay", "udp");
X	if (sp)
X	{
X		s.sin_port = sp->s_port;
X	}
X	else
X	{
X		s.sin_port = htons(RPLAY_PORT);
X	}
X	s.sin_family = AF_INET;
X
X	return rplay_open_sockaddr_in(&s);
}
X
#ifdef __STDC__
int	rplay_open_sockaddr_in(struct sockaddr_in *saddr)
#else
int	rplay_open_sockaddr_in(saddr)
struct sockaddr_in	*saddr;
#endif
{
X	int	rplay_fd;
X	int	on = 1;
X	
X	rplay_fd = socket(AF_INET, SOCK_DGRAM, 0);
X	if (rplay_fd < 0)
X	{
X		rplay_errno = RPLAY_ERROR_SOCKET;
X		return -1;
X	}
X
X	if (connect(rplay_fd, (struct sockaddr *)saddr, sizeof(*saddr)) < 0)
X	{
X		rplay_errno = RPLAY_ERROR_CONNECT;
X		return -1;
X	}
X
X	/*
X	 * enable broadcasting
X	 */
X	if (setsockopt(rplay_fd, SOL_SOCKET, SO_BROADCAST, (char *)&on, sizeof(on)) < 0)
X	{
X		rplay_errno = RPLAY_ERROR_BROADCAST;
X		return -1;
X	}
X
X	return rplay_fd;
}
X
/*
X * send an rplay packet to a host
X */
#ifdef __STDC__
int	rplay(int rplay_fd, RPLAY *rp)
#else
int	rplay(rplay_fd, rp)
int	rplay_fd;
RPLAY	*rp;
#endif
{
X	rplay_errno = RPLAY_ERROR_NONE;
X
X	if (write(rplay_fd, rp->buf, rp->len) != rp->len)
X	{
X		rplay_errno = RPLAY_ERROR_WRITE;
X		return -1;
X	}
X
X	return 0;
}
X
/*
X * close the socket
X */
#ifdef __STDC__
int	rplay_close(int rplay_fd)
#else
int	rplay_close(rplay_fd)
int	rplay_fd;
#endif
{
X	rplay_errno = RPLAY_ERROR_NONE;
X
X	if (close(rplay_fd) < 0)
X	{
X		rplay_errno = RPLAY_ERROR_CLOSE;
X		return -1;
X	}
X
X	return 0;
}
X
/*
X * report rplay error messages
X */
#ifdef __STDC__
void	rplay_perror(char *s)
#else
void	rplay_perror(s)
char	*s;
#endif
{
X	fprintf(stderr, "%s: %s\n", s, rplay_errlist[rplay_errno]);
}
X
/*
X * open a socket using the current X display
X * (uses the DISPLAY environment variable)
X */
#ifdef __STDC__
int	rplay_open_display(void)
#else
int	rplay_open_display()
#endif
{
X	char	*display, *p;
X	char	host[MAXHOSTNAMELEN];
X
X	display = getenv("DISPLAY");
X	if (display == NULL || display[0] == ':')
X	{
X		strcpy(host, "localhost");
X	}
X	else
X	{
X		strcpy(host, display);
X		p = strchr(host, ':');
X		if (p)
X		{
X			*p = '\0';
X		}
X		if (strcmp(host, "unix") == 0 || strcmp(host, "local") == 0 || strcmp(host, "X") == 0)
X		{
X			strcpy(host, "localhost");
X		}
X	}
X
X	return rplay_open(host);
}
X
/*
X * play a sound on the current X display
X */
#ifdef __STDC__
int	rplay_display(char *sound)
#else
int	rplay_display(sound)
char	*sound;
#endif
{
X	int	rplay_fd;
X
X	rplay_fd = rplay_open_display();
X	if (rplay_fd < 0)
X	{
X		return -1;
X	}
X
X	return rplay_sound(rplay_fd, sound);
}
X
/*
X * play a sound on the localhost
X */
#ifdef __STDC__
int	rplay_local(char *sound)
#else
int	rplay_local(sound)
char	*sound;
#endif
{
X	return rplay_host("localhost", sound);
}
X
/*
X * play a sound on a host
X */
#ifdef __STDC__
int	rplay_host(char *host, char *sound)
#else
int	rplay_host(host, sound)
char	*host;
char	*sound;
#endif
{
X	int	rplay_fd;
X
X	rplay_fd = rplay_open(host);
X	if (rplay_fd < 0)
X	{
X		return -1;
X	}
X
X	return rplay_sound(rplay_fd, sound);
}
X
/*
X * play a sound given a socket
X */
#ifdef __STDC__
int	rplay_sound(int rplay_fd, char *sound)
#else
int	rplay_sound(rplay_fd, sound)
int	rplay_fd;
char	*sound;
#endif
{
X	RPLAY	*rp;
X
X	rp = rplay_create(RPLAY_PLAY);
X	if (rp == NULL)
X	{
X		return -1;
X	}
X
X	if (rplay_set(rp, RPLAY_APPEND, RPLAY_SOUND, sound, NULL) < 0)
X	{
X		return -1;
X	}
X
X	if (rplay(rplay_fd, rp) < 0)
X	{
X		return -1;
X	}
X
X	rplay_destroy(rp);
X
X	return 0;
}
X
/*
X * ping an rplay server
X */
#ifdef __STDC__
int	rplay_ping(char *host)
#else
int	rplay_ping(host)
char	*host;
#endif
{
X	int	rplay_fd;
X
X	rplay_fd = rplay_open(host);
X	if (rplay_fd < 0)
X	{
X		return -1;
X	}
X
X	return rplay_ping_sockfd(rplay_fd);
}
X
#ifdef __STDC__
int	rplay_ping_sockfd(int rplay_fd)
#else
int	rplay_ping_sockfd(rplay_fd)
int	rplay_fd;
#endif
{
X	RPLAY	*rp;
X	
X	rp = rplay_create(RPLAY_PING);
X	if (rp == NULL)
X	{
X		return -1;
X	}
X
X	if (rplay_pack(rp) < 0)
X	{
X		return -1;
X	}
X
X	if (rplay(rplay_fd, rp) < 0)
X	{
X		return -1;
X	}
X
X	rplay_close(rplay_fd);
X	rplay_destroy(rp);
X
X	return 0;
}
X
#ifdef __STDC__
int	rplay_ping_sockaddr_in(struct sockaddr_in *saddr)
#else
int	rplay_ping_sockaddr_in(saddr)
struct sockaddr_in	*saddr;
#endif
{
X	int	rplay_fd;
X	
X	rplay_fd = rplay_open_sockaddr_in(saddr);
X	if (rplay_fd < 0)
X	{
X		return -1;
X	}
X	
X	return rplay_ping_sockfd(rplay_fd);
}	
X
/*
X * play a sound on a host with a specific volume
X */
#ifdef __STDC__
int	rplay_host_volume(char *host, char *sound, int volume)
#else
int	rplay_host_volume(host, sound, volume)
char	*host;
char	*sound;
int	volume;
#endif
{
X	int	rplay_fd;
X	RPLAY	*rp;
X
X	rplay_fd = rplay_open(host);
X	if (rplay_fd < 0)
X	{
X		return -1;
X	}
X
X	rp = rplay_create(RPLAY_PLAY);
X	if (rp == NULL)
X	{
X		return -1;
X	}
X
X	if (rplay_set(rp, RPLAY_APPEND, RPLAY_SOUND, sound, RPLAY_VOLUME, volume, NULL) < 0)
X	{
X		return -1;
X	}
X
X	if (rplay(rplay_fd, rp) < 0)
X	{
X		return -1;
X	}
X
X	rplay_destroy(rp);
X
X	return 0;
}
X
/*
X * obtain the default rplay host
X */
#ifdef __STDC__
char	*rplay_default_host(void)
#else
char	*rplay_default_host()
#endif
{
X	char	*host;
X
X	host = getenv("RPLAY_HOST");
X
X	return host ? host : "localhost";
}
X
/*
X * play a sound on the default rplay host
X */
#ifdef __STDC__
int	rplay_default(char *sound)
#else
int	rplay_default(sound)
char	*sound;
#endif
{
X	return rplay_host(rplay_default_host(), sound);
}
X
/*
X * open the default host
X */
#ifdef __STDC__
int	rplay_open_default(void)
#else
int	rplay_open_default()
#endif
{
X	return rplay_open(rplay_default_host());
}
SHAR_EOF
chmod 0644 rplay-3.1.0/librplay/rplay.c ||
echo 'restore of rplay-3.1.0/librplay/rplay.c failed'
Wc_c="`wc -c < 'rplay-3.1.0/librplay/rplay.c'`"
test 18877 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/librplay/rplay.c: original size 18877, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/librplay/rptp.c ==============
if test -f 'rplay-3.1.0/librplay/rptp.c' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/librplay/rptp.c (File already exists)'
else
echo 'x - extracting rplay-3.1.0/librplay/rptp.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/librplay/rptp.c' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#include "conf.h"
#include "version.h"
#include "rplay.h"
#include <sys/errno.h>
#ifdef ultrix
#include <fcntl.h>
#else
#include <sys/fcntl.h>
#endif
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include <errno.h>
X
int	rptp_errno = RPTP_ERROR_NONE;
X
char	*rptp_errlist[] =
{
X	"no error",			/* RPTP_ERROR_NONE */
X	"out of memory",		/* RPTP_ERROR_MEMORY */
X	"host not found",		/* RPTP_ERROR_HOST */
X	"connection failed",		/* RPTP_ERROR_CONNECT */
X	"cannot create socket",		/* RPTP_ERROR_SOCKET */
X	"cannot open socket",		/* RPTP_ERROR_OPEN */
X	"cannot read from socket",	/* RPTP_ERROR_READ */
X	"cannot write to socket",	/* RPTP_ERROR_WRITE */
X	"cannot ping rplay server",	/* RPTP_ERROR_PING */
X	"connection timeout",		/* RPTP_ERROR_TIMEOUT */
};
X
#ifdef __STDC__
unsigned long	inet_addr(char *rp);
#else
unsigned long	inet_addr();
#endif
X
/*
X * open an RPTP connection to host using port
X * the connection response will be stored in the response buffer
X */
#ifdef __STDC__
int	rptp_open(char *host, int port, char *response, int response_size)
#else
int	rptp_open(host, port, response, response_size)
char	*host;
int	port;
char	*response;
int	response_size;
#endif
{
X	u_long			addr;
X	struct sockaddr_in	s;
X	struct hostent		*hp;
X	int			rptp_fd;
X	int			i, n;
X	
X	rptp_errno = RPTP_ERROR_NONE;
X
X	memset((char *)&s, 0, sizeof(s));
X
X	addr = inet_addr(host);
X	if (addr == 0xffffffff)
X	{
X		hp = gethostbyname(host);
X		if (hp == NULL)
X		{
X			rptp_errno = RPTP_ERROR_HOST;
X			return -1;
X		}
X		memcpy((char *)&s.sin_addr.s_addr, (char *)hp->h_addr, hp->h_length);
X	}
X	else
X	{
X		memcpy((char *)&s.sin_addr.s_addr, (char *)&addr, sizeof(addr));
X	}
X
X	s.sin_port = htons(port);
X	s.sin_family = AF_INET;
X
X	for (i = 0; i < RPTP_CONNECT_ATTEMPTS; i++)
X	{
X		if (rplay_ping(host) < 0)
X		{
X			rptp_errno = RPTP_ERROR_PING;
X			return -1;
X		}
X
X		rptp_fd = socket(AF_INET, SOCK_STREAM, 0);
X		if (rptp_fd < 0)
X		{
X			rptp_errno = RPTP_ERROR_SOCKET;
X			return -1;
X		}
X
X		n = connect(rptp_fd, (struct sockaddr *)&s, sizeof(s));
X		if (n == 0)
X		{
X			/*
X			 * successful connection
X			 */
X			rptp_getline(rptp_fd, response, response_size);
X			if (response[0] == RPTP_ERROR)
X			{
X				rptp_errno = RPTP_ERROR_OPEN;
X				return -1;
X			}
X			return rptp_fd;
X		}
X
X		switch (errno)
X		{
X		case ECONNREFUSED:
X		case EINTR:
X			close(rptp_fd);
X			if (i+1 != RPTP_CONNECT_ATTEMPTS)
X			{
X				sleep(RPTP_PING_DELAY);
X			}
X			break;
X
X		default:
X			rptp_errno = RPTP_ERROR_CONNECT;
X			return -1;
X		}
X	}
X
X	rptp_errno = RPTP_ERROR_CONNECT;
X	
X	return -1;
}
X
/*
X * read nbytes from the RPTP connection
X *
X * return the number of bytes actually read
X *
X * The routine was adapted from the readn() in "Unix Network Programming"
X * by W. Richard Stevens, page 279.
X */
#ifdef __STDC__
int	rptp_read(int rptp_fd, char *ptr, int nbytes)
#else
int	rptp_read(rptp_fd, ptr, nbytes)
int	rptp_fd;
char	*ptr;
int	nbytes;
#endif
{
X	int	nleft, nread;
X
X	rptp_errno = RPTP_ERROR_NONE;
X
X	nleft = nbytes;
X
X	while (nleft > 0)
X	{
X		nread = read(rptp_fd, ptr, nleft);
X		if (nread < 0)
X		{
X			rptp_errno = RPTP_ERROR_READ;
X			return -1;
X		}
X		if (nread == 0)
X		{
X			break;
X		}
X		nleft -= nread;
X		ptr += nread;
X	}
X
X	return nbytes - nleft;
}
X
/*
X * write nbytes to the RPTP connection
X *
X * return the number of bytes actually written
X *
X * The routine was adapted from the writen() in "Unix Network Programming"
X * by W. Richard Stevens, page 279-80.
X */
#ifdef __STDC__
int	rptp_write(int rptp_fd, char *ptr, int nbytes)
#else
int	rptp_write(rptp_fd, ptr, nbytes)
int	rptp_fd;
char	*ptr;
int	nbytes;
#endif
{
X	int	nleft, nwritten;
X	
X	rptp_errno = RPTP_ERROR_NONE;
X
X	nleft = nbytes;
X
X	while (nleft > 0)
X	{
X		nwritten = write(rptp_fd, ptr, nleft);
X		if (nwritten <= 0)
X		{
X			rptp_errno = RPTP_ERROR_WRITE;
X			return -1;
X		}
X		nleft -= nwritten;
X		ptr += nwritten;
X	}
X
X	return nbytes - nleft;
}
X
/*
X * write a line to the RPTP connection
X *
X * "\r\n" is appened to the string
X */
#ifdef __STDC__
int	rptp_putline(int rptp_fd, char *fmt, ...)
#else
int	rptp_putline(va_alist)
va_dcl
#endif
{
X	va_list	args;
X	char	buf[RPTP_MAX_LINE];
X
#ifdef __STDC__
X	va_start(args, fmt);
#else
X	int	rptp_fd;
X	char	*fmt;
X	va_start(args);
X	rptp_fd = va_arg(args, int);
X	fmt = va_arg(args, char *);
#endif
X
X	rptp_errno = RPTP_ERROR_NONE;
X
X	vsprintf(buf, fmt, args);
X	va_end(args);
X	strcat(buf, "\r\n");
X
X	return rptp_write(rptp_fd, buf, strlen(buf)) != strlen(buf) ? -1 : 0;
}
X
/*
X * read a line from the RPTP connection
X *
X * "\r\n" is removed from the line
X */
#ifdef __STDC__
int	rptp_getline(int rptp_fd, char *buf, int nbytes)
#else
int	rptp_getline(rptp_fd, buf, nbytes)
int	rptp_fd;
char	*buf;
int	nbytes;
#endif
{
X	int	i, n, nleft, x;
X	char	*ptr;
X	char	tmp_buf[RPTP_MAX_LINE];
X	
X	rptp_errno = RPTP_ERROR_NONE;
X
X	nleft = nbytes;
X	ptr = buf;
X	
X	while (nleft > 0)
X	{
X		/*
X		 * peek at the message so only the necessary data
X		 * is actually read
X		 */
X		n = recv(rptp_fd, ptr, nleft, MSG_PEEK);
X		if (n <= 0)
X		{
X			rptp_errno = RPTP_ERROR_READ;
X			return -1;
X		}
X		nleft -= n;
X		for (i = 0; i < n; i++)
X		{
X			if (ptr[i] == '\r')
X			{
X				ptr[i] = '\0';
X			}
X			else if (ptr[i] == '\n')
X			{
X				ptr[i] = '\0';
X				break;
X			}
X		}
X		x = read(rptp_fd, tmp_buf, i == n ? n : i+1);
X		if (x <= 0)
X		{
X			rptp_errno = RPTP_ERROR_READ;
X			return -1;
X		}
X		else if (i < n)
X		{
X			return 0;
X		}
X		else
X		{
X			ptr += n;
X		}
X	}
X
X	rptp_errno = RPTP_ERROR_READ;
X
X	return -1;
}
X
/*
X * send the RPTP command to the RPTP connection storing the response in the
X * response buffer
X */
#ifdef __STDC__
int	rptp_command(int rptp_fd, char *command, char *response, int response_size)
#else
int	rptp_command(rptp_fd, command, response, response_size)
int	rptp_fd;
char	*command;
char	*response;
int	response_size;
#endif
{
X	rptp_errno = RPTP_ERROR_NONE;
X
X	if (rptp_putline(rptp_fd, command) < 0)
X	{
X		return -1;
X	}
X	if (rptp_getline(rptp_fd, response, response_size) < 0)
X	{
X		return -1;
X	}
X	switch (response[0])
X	{
X	case RPTP_TIMEOUT:
X		rptp_errno = RPTP_ERROR_TIMEOUT;
X		return -1;
X
X	case RPTP_ERROR:
X		return 1;
X		
X	case RPTP_OK:
X		return 0;
X
X	default:
X		return -1;
X	}
}
X
/*
X * close the RPTP connection
X */
#ifdef __STDC__
int	rptp_close(int rptp_fd)
#else
int	rptp_close(rptp_fd)
int	rptp_fd;
#endif
{
X	rptp_errno = RPTP_ERROR_NONE;
X
X	close(rptp_fd);
X
X	return 0;
}
X
/*
X * report RPTP errors
X */
#ifdef __STDC__
void	rptp_perror(char *message)
#else
void	rptp_perror(message)
char	*message;
#endif
{
X	fprintf(stderr, "%s: %s\n", message, rptp_errlist[rptp_errno]);
}
SHAR_EOF
chmod 0644 rplay-3.1.0/librplay/rptp.c ||
echo 'restore of rplay-3.1.0/librplay/rptp.c failed'
Wc_c="`wc -c < 'rplay-3.1.0/librplay/rptp.c'`"
test 7339 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/librplay/rptp.c: original size 7339, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/Makefile.config ==============
if test -f 'rplay-3.1.0/Makefile.config' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/Makefile.config (File already exists)'
else
echo 'x - extracting rplay-3.1.0/Makefile.config (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/Makefile.config' &&
# 
# Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
#
# This file is part of rplay.
#
# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
#
X
SHELL=		/bin/sh
X
#
# Installation directory for rplayd, rplay, and rptp
#
INSTALL_BIN_DIR=	/usr/local/bin
X
#
# Installation directory for librplay
#
INSTALL_LIB_DIR=	/usr/local/lib
X
#
# Installation directory for rplay.h
#
INSTALL_INCLUDE_DIR=	/usr/local/include
X
#
# Installation directory for the manual pages
#
INSTALL_MAN_DIR=	/usr/local/man
X
#
# Choose the right compiler to use
#
CC=		gcc	# GNU ANSI C compiler
#CC=		acc	# Sun's ANSI C compiler
#CC=		cc	# Generic C compiler, SGI
X
#
# Compiler options
#
CC_OPTIONS=	-O2 -fstrength-reduce		# gcc
#CC_OPTIONS=	-fast				# acc
#CC_OPTIONS=	-O -DSVR4			# Solaris 2.x using SunPro C
#CC_OPTIONS=	-Aa -D_HPUX_SOURCE +O3 -J +ESlit +Obb850 +FPD	# HP-UX
#CC_OPTIONS=	-O -cckr			# SGI 
#CC_OPTIONS=	-O				# generic
#CC_OPTIONS=	-g				# debug 
X
#
# Linker options
#
LD_OPTIONS=		
#LD_OPTIONS=	-lsocket -lnsl			# Solaris 2.x
#LD_OPTIONS=	-s -L$(INSTALL_LIB_DIR)		# HP-UX
#LD_OPTIONS=	-laudio				# SGI
X
#
# rm command
#
RM=		rm -f
X
#
# library archive command
#
AR=		ar 
#AR=						# HP-UX
X
#
# ranlib command
#
RANLIB=		ranlib
#RANLIB=	/bin/true			# Solaris 2.x/SYSV
#RANLIB=					# HP-UX
X
#
# binary install command
#
BIN_INSTALL=	install -s -c
#BIN_INSTALL=	cp				# SGI
#BIN_INSTALL=	cp -i				# HP-UX
X
#
# install command
#
INSTALL=	cp
#INSTALL=	install -c
#INSTALL=	cp -i				# HP-UX
X
#
# makedepend command
#
MAKEDEPEND=	makedepend
X
#
# Name of the rplay library to build
#
LIBRPLAY_NAME=	librplay.a
#LIBRPLAY_NAME=	librplay.sl			# HP-UX
X
#
# Name of your mail program with the subject option.
# MAILER is used to send mail to the author using "make mail".
# "make world" invokes "make mail" by default.
#
MAILER=		Mail -s
#MAILER=	elm -s
#MAILER=	mailx -s			# Solaris 2.x without BSD compat.
#MAILER=
X
X
################### DON'T CHANGE ANYTHING BELOW THIS LINE ######################
X
RPLAY_DIR=	../rplay
RPLAYD_DIR=	../rplayd
LIBRPLAY_DIR=	../librplay
INCLUDE_DIR=	../include
X
CFLAGS=		$(CC_OPTIONS) -I$(INCLUDE_DIR)
LDFLAGS=	$(LD_OPTIONS) -L$(LIBRPLAY_DIR) -lrplay
X
MAIL_SUBJECT=	rplay 3.1.0 message
MAIL_TO=	boyns@sdsu.edu
SHAR_EOF
chmod 0644 rplay-3.1.0/Makefile.config ||
echo 'restore of rplay-3.1.0/Makefile.config failed'
Wc_c="`wc -c < 'rplay-3.1.0/Makefile.config'`"
test 2844 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/Makefile.config: original size 2844, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/contrib/mailsound/Makefile ==============
if test ! -d 'rplay-3.1.0/contrib'; then
    echo 'x - creating directory rplay-3.1.0/contrib'
    mkdir 'rplay-3.1.0/contrib'
fi
if test ! -d 'rplay-3.1.0/contrib/mailsound'; then
    echo 'x - creating directory rplay-3.1.0/contrib/mailsound'
    mkdir 'rplay-3.1.0/contrib/mailsound'
fi
if test -f 'rplay-3.1.0/contrib/mailsound/Makefile' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/contrib/mailsound/Makefile (File already exists)'
else
echo 'x - extracting rplay-3.1.0/contrib/mailsound/Makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/contrib/mailsound/Makefile' &&
CC	      = acc
DEST	      = /usr/local/bin
MANDEST	      = /usr/local/man
EXTHDRS	      = /usr/include/ctype.h \
X		/usr/include/pwd.h \
X		/usr/include/stdio.h \
X		/usr/include/stdlib.h \
X		/usr/include/string.h \
X		/usr/include/sys/stdtypes.h \
X		/usr/include/sys/sysmacros.h \
X		/usr/include/sys/types.h
HDRS	      =
CFLAGS	      = -O -I/usr/local/include
LDFLAGS	      = -L/usr/local/lib
LIBS	      = -lrplay
LINKER	      = acc
MAKEFILE      = Makefile
OBJS	      = mailsound.o
PRINT	      = pr
PROGRAM	      = mailsound
MANPAGE	      = man1/mailsound.1
SRCS	      = mailsound.c
X
all:		$(PROGRAM)
X
$(PROGRAM):     $(OBJS)
X		@echo -n "Loading $(PROGRAM) ... "
X		@$(LINKER) $(LDFLAGS) $(OBJS) $(LIBS) -o $(PROGRAM)
X		@echo "done"
X
clean:;		@rm -f $(OBJS) *.bak $(PROGRAM) man1/*.bak
X
depend:;	@mkmf -f $(MAKEFILE) PROGRAM=$(PROGRAM) DEST=$(DEST)
X
index:;		@ctags -wx $(HDRS) $(SRCS)
X
install:	$(PROGRAM)
X		@echo Installing $(PROGRAM) in $(DEST)
X		@install -s $(PROGRAM) $(DEST)
X		@echo Installing the man page in $(MANDEST)/man1
X		@install $(MANPAGE) $(MANDEST)/man1
X
print:;		@$(PRINT) $(HDRS) $(SRCS)
X
program:        $(PROGRAM)
X
tags:           $(HDRS) $(SRCS); @ctags $(HDRS) $(SRCS)
X
update:		$(DEST)/$(PROGRAM)
X
shar:
X		shar Makefile $(SRCS) $(HDRS) $(MANPAGE) > $(PROGRAM).shar
X
$(DEST)/$(PROGRAM): $(SRCS) $(HDRS) $(EXTHDRS)
X		@make -f $(MAKEFILE) DEST=$(DEST) install
###
SHAR_EOF
chmod 0644 rplay-3.1.0/contrib/mailsound/Makefile ||
echo 'restore of rplay-3.1.0/contrib/mailsound/Makefile failed'
Wc_c="`wc -c < 'rplay-3.1.0/contrib/mailsound/Makefile'`"
test 1381 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/contrib/mailsound/Makefile: original size 1381, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/contrib/mailsound/mailsound.c ==============
if test -f 'rplay-3.1.0/contrib/mailsound/mailsound.c' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/contrib/mailsound/mailsound.c (File already exists)'
else
echo 'x - extracting rplay-3.1.0/contrib/mailsound/mailsound.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/contrib/mailsound/mailsound.c' &&
/**********************************************************************/
/*                                                                    */
/*  File:          mailsound.c                                        */
/*  Author:        Andrew W. Scherpbier                               */
/*  Version:       1.00                                               */
/*  Created:       26 Oct 1992                     		      */
/*                                                                    */
/*  Copyright (c) 1992, 1993 Andrew Scherpbier                        */
/*                All Rights Reserved.                                */
/*                                                                    */
/*                                                                    */
/*--------------------------------------------------------------------*/
/*  Description:  Play different sounds depending on where mail from  */
/*                                                                    */
/**********************************************************************/
X
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <rplay.h>
#include <pwd.h>
X
#define	PUBLIC
#define	PRIVATE		static
X
#define	TRUE		(1)
#define	FALSE		(0)
X
#define	OK		(0)
#define	NOTOK		(-1)
X
#define	when		break;case
#define	orwhen		case
#define	otherwise	break;default
X
/* Private routines
X * ================
X */
PRIVATE void dump_state();
PRIVATE void parse_args(int ac, char **av, int size);
PRIVATE compare(char *buffer, char *from, long size);
PRIVATE play_sound(char *sound, long size);
X
/* Private variables
X * =================
X */
PRIVATE char	hostname[200] = "localhost";
PRIVATE int	volume = 127;
PRIVATE int	use_random = FALSE;
PRIVATE int	use_size_volume = FALSE;
PRIVATE int	use_size_sound = FALSE;
PRIVATE int	min_size = 0;
PRIVATE int	max_size = 10000;
PRIVATE int	min_volume = 10;
PRIVATE int	max_volume = 200;
PRIVATE char	*sound = "youvegotmail";
PRIVATE char	*subject_re = NULL;
PRIVATE char	subject[200];
PRIVATE int	debug = FALSE;
X
X
/* Public routines
X * ===============
X */
X
/* Public variables
X * ================
X */
X
/**************************************************************************
X * PUBLIC main(int ac, char **av)
X * PURPOSE:
X *   None
X */
PUBLIC main(int ac, char **av)
{
X	char		buffer[1000];
X	char		path[200];
X	char		address[1000];
X	char		*p;
X	FILE		*fl;
X	int		size = 0;
X	struct passwd	*pw;
X
X	/*
X	 *   Read  the  first  line of the message. This is what we will use
X	 *   to find out what sound to play.
X	 */
X	gets(buffer);
X	size = strlen(buffer) + 1;
X	if (!strtok(buffer, " "))
X		exit(1);
X	p = strtok(NULL, " \t\n");
X	strcpy(address, p);
X	subject[0] = '\0';
X
X	/*
X	 *   We  now  need  to read the rest of the message to determine its
X	 *   size.
X	 */
X	while (gets(buffer))
X	{
X		if (strncmp(buffer, "Subject: ", 9) == 0)
X		{
X			strcpy(subject, buffer + 9);
X		}
X		size += strlen(buffer) + 1;
X	}
X
X	/*
X	 *   Deal with the command line arguments to be used as defaults.
X	 */
X	parse_args(ac, av, size);
X
X	if (debug)
X		dump_state();
X
X	/*
X	 *   Find the configuration file in the home directory
X	 */
X	pw = getpwuid(getuid());
X	sprintf(path, "%s/.mailsounds", pw->pw_dir);
X	fl = fopen(path, "r");
X	if (fl == NULL)
X		exit(0);
X
X	/*
X	 *   Search  through  this  file to find a line which will match the
X	 *   address
X	 */
X	while (fgets(buffer, 1000, fl) != NULL)
X	{
X		compare(buffer, address, size);
X	}
X
X	play_sound(av[1], 0);
X	fclose(fl);
X	exit(0);
}
X
X
/**************************************************************************
X * PRIVATE compare(char *buffer, char *from, long size)
X * PURPOSE:
X *   None
X * PARAMETERS:
X *   None
X */
PRIVATE compare(char *buffer, char *from, long size)
{
X	char	*pattern, *sound_args;
X	char	*p;
X
X	pattern = strtok(buffer, " \t");
X	sound_args = strtok(NULL, "\t\n");
X	if (re_comp(pattern) != NULL)
X		return;
X	if (re_exec(from))
X	{
X		if (debug)
X			printf("Normal sound is played\n");
X		if (play_sound(sound_args, size) == OK)
X			exit(0);
X	}
}
X
X
/**************************************************************************
X * PRIVATE play_sound(char *sound_args, long size)
X * PURPOSE:
X *   None
X * PARAMETERS:
X *   None
X */
PRIVATE play_sound(char *sound_args, long size)
{
X	int	ac;
X	char	*av[50];
X	char	*token;
X
X	/*
X	 *   We need to build an argument list from the sound_args string.
X	 */
X	ac = 1;
X	av[0] = "xxxx";
X	token = strtok(sound_args, " \t");
X	while (token && ac < 50)
X	{
X		av[ac++] = token;
X		token = strtok(NULL, " \t");
X	}
X
X	subject_re = NULL;
X
X	parse_args(ac, av, size);
X
X	if (subject_re)
X	{
X		if (re_comp(subject_re) != NULL)
X			return NOTOK;
X		if (!re_exec(subject))
X			return NOTOK;
X	}
X
X	if (debug)
X		dump_state();
X
X	/*
X	 *   Play the sound on each of the hosts listed in the hostname.
X	 */
X	token = strtok(hostname, ":");
X	while (token)
X	{
X		rplay_host_volume(token, sound, volume);
X		token = strtok(NULL, ":");
X	}
X	return OK;
}
X
X
/**************************************************************************
X * PRIVATE void parse_args(int ac, char **av, int size)
X * PURPOSE:
X *   Take  arguments  and  extract data from them. The arguments are
X *   assumed  to  be  in  the  same  format as what is passed to the
X *   main() program.
X */
PRIVATE void parse_args(int ac, char **av, int size)
{
X	int		c;
X	int		i, count;
X	extern char	*optarg;
X	extern int	optind;
X	char		*sounds[50];
X
X	optind = 1;
X	subject_re = NULL;
X	while ((c = getopt(ac, av, "s:h:rz:Z:v:d")) != NOTOK)
X	{
X		switch (c)
X		{
X			when 'h':
X				strcpy(hostname, optarg);
X			when 'r':
X				use_random = TRUE;
X			when 's':
X				subject_re = strdup(optarg);
X			when 'z':
X				sscanf(optarg, "%d:%d,%d:%d", &min_size, &min_volume, &max_size, &max_volume);
X				use_size_volume = TRUE;
X			when 'Z':
X				sscanf(optarg, "%d,%d", &min_size, &max_size);
X				use_size_sound = TRUE;
X			when 'v':
X				volume = atoi(optarg);
X			when 'd':
X				debug = TRUE;
X		}
X	}
X
X	/*
X	 *   The rest of the arguments are assumed to be sounds.
X	 */
X	count = 0;
X	for (i = optind; i < ac && count < 50; i++)
X	{
X		sounds[count++] = av[i];
X	}
X
X	/*
X	 * By default we will pick the first sound in the list
X	 */
X	sound = sounds[0];
X
X	/*
X	 *   Now pick the sound and the volume.
X	 */
X	if (use_random)
X	{
X		srandom(time(NULL));
X		sound = sounds[random() % count];
X	}
X	else if (use_size_sound)
X	{
X		if (size < min_size)
X			sound = sounds[0];
X		if (size > max_size)
X			sound = sounds[count - 1];
X		else
X		{
X			sound = sounds[(size - min_size) * count / (max_size - min_size)];
X		}
X	}
X
X	if (use_size_volume)
X	{
X		if (size < min_size)
X			volume = min_volume;
X		else if (size > max_size)
X			volume = max_volume;
X		else
X			volume = (size - min_size) * (max_volume - min_volume) / (max_size - min_size) + min_volume;
X	}
}
X
X
X
/**************************************************************************
X * PRIVATE void dump_state()
X * PURPOSE:
X *   Produce  debug  output  of  all the global variables which make
X *   up the state of the program
X */
PRIVATE void dump_state()
{
X	printf("host: '%s', volume: %d, random: %d, size_volume: %d, size_sound: %d\n",
X		hostname,
X		volume,
X		use_random,
X		use_size_volume,
X		use_size_sound);
X	printf("range data: v: (%d, %d), s: (%d, %d)\n",
X		min_volume, max_volume,
X		min_size, max_size);
X	printf("sound: '%s'\n", sound);
X	if (subject_re)
X		printf("Subject regular expression: '%s'\n", subject_re);
X	printf("Subject: '%s'\n", subject);
}
X
X
X
SHAR_EOF
chmod 0644 rplay-3.1.0/contrib/mailsound/mailsound.c ||
echo 'restore of rplay-3.1.0/contrib/mailsound/mailsound.c failed'
Wc_c="`wc -c < 'rplay-3.1.0/contrib/mailsound/mailsound.c'`"
test 7395 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/contrib/mailsound/mailsound.c: original size 7395, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/contrib/mailsound/man1/mailsound.1 ==============
if test ! -d 'rplay-3.1.0/contrib/mailsound/man1'; then
    echo 'x - creating directory rplay-3.1.0/contrib/mailsound/man1'
    mkdir 'rplay-3.1.0/contrib/mailsound/man1'
fi
if test -f 'rplay-3.1.0/contrib/mailsound/man1/mailsound.1' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/contrib/mailsound/man1/mailsound.1 (File already exists)'
else
echo 'x - extracting rplay-3.1.0/contrib/mailsound/man1/mailsound.1 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/contrib/mailsound/man1/mailsound.1' &&
.TH MAILSOUND 1 "11 August 1993"
.SH NAME
mailsound \- play sounds when mail is received
.SH SYNOPSIS
.B mailsound
[-hszZvrd] soundname \.\.\.
.SH DESCRIPTION
mailsound allows a user to play sounds when new mail arrives.
It reads a mail message from stdin and uses Mark Boyns'
.B rplay
library to play sounds.
The sound that is played is determined by a configuration file in the user's home directory
called
.B .mailsounds.
Each line in this file has two parts.  The first part is a regular expression which will be used to match
the from address from a mail message.  The second part describes what to do when a match is found.
The options in the second part are identical to the options on the command line.
The command line options will set defaults which will be used if they are not specified in the
configuration file.
.br
If not specified, the
.B mailsound
program will use the following defaults:
.IP
default sound:	youvegotmail.au
.br
default volume:	127 (50%)
X
.RE
If the mail address does not match any of the regular expressions in the
.B .mailsounds
file, no sound will be played.
.SH OPTIONS
.TP
.B \-h hostname:[hostname\.\.\.]
Play sounds on all of these hosts.
.TP
.B \-z <minsize>:<minvolume>,<maxsize>:<maxvolume>
The volume the sound will be played at will be determined by the size of the mail message.
The sound for a message with a size smaller than
.B <minsize>
will be played at volume
.B <minvolume>.
The sound for a message with a size larger than
.B <maxsize>
will be played at volume
.B <maxvolume>.
The sound for a message with a size between
.B <minsize>
and
.B <maxsize>
will be played at a volume
which is a linear interpolation between
.B <minvolume>
and
.B <maxvolume>.
.TP
.B \-Z <minsize>,<maxsize>
The sound to be played is determined by the size of the mail message.
If the message is smaller than
.B <minsize>,
the first listed sound is played.
If the message is larger than
.B <maxsize>,
the last listed sound is played.
If the message size is between those two values, the appropriate sound from the list is played.
.TP
.B \-s <subject re>
The regular expression supplied will have to match the subject of the message.
If this option is not there, the subject of the message is completely ignored.
Be careful that the regular expression does not contain spaces.  Due to laziness of the
author of this program, this will hopelessly confuse the program.
.TP
.B \-v <int>
Set the volume at which the sound should be played.  The range is 0-255.
.TP
.B \-r
Pick a sound at random from the list of sounds provided.
.TP
.B \-d
Turn on debugging.  This will produce diagnostic output to stdout.
.SH EXAMPLE
.LP
The following could appear in the .forward file in your home directory:
(This assumes that your username is pickard)
.IP
\\pickard, |"/usr/local/bin/mailsound"
.LP
Here is a sample $HOME/.mailsounds file:
.IP
.nf
Andrew.*	-r Passing_Train riot arrp flinstones
root.*		out!
daemon.*	-v 220 sci_fi_fun
MAILER.*	-S 1000,10000 cuckoo pig  Oomph
*.		pigs
.fi
.SH FILES
$HOME/.mailsounds
.SH "SEE ALSO"
.BR rplay.conf (5),
.BR rplayd (1)
.SH AUTHOR
This program was written by Andrew Scherpbier at San Diego State University.
He can be reached by E-mail as follows:
.RS
X
.B Andrew@SDSU.Edu
X
.RE
The
.B mailsound
program makes use of Mark Boyns'
.B rplay
package which can play multiple sounds on remote machines.
.br
He can be reached by E-mail as follows:
.RS
X
.B boyns@sdsu.edu
.RE
.SH BUGS
The code does very little error checking.  No range checking on any of the values is done.
SHAR_EOF
chmod 0644 rplay-3.1.0/contrib/mailsound/man1/mailsound.1 ||
echo 'restore of rplay-3.1.0/contrib/mailsound/man1/mailsound.1 failed'
Wc_c="`wc -c < 'rplay-3.1.0/contrib/mailsound/man1/mailsound.1'`"
test 3525 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/contrib/mailsound/man1/mailsound.1: original size 3525, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/contrib/xtank/README ==============
if test ! -d 'rplay-3.1.0/contrib/xtank'; then
    echo 'x - creating directory rplay-3.1.0/contrib/xtank'
    mkdir 'rplay-3.1.0/contrib/xtank'
fi
if test -f 'rplay-3.1.0/contrib/xtank/README' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/contrib/xtank/README (File already exists)'
else
echo 'x - extracting rplay-3.1.0/contrib/xtank/README (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/contrib/xtank/README' &&
X
Sound patches are available for xtank1.3f.tar.Z and rplay2.0.
The next version of xtank should include rplay3.0 support.
X
xtank is available at mojo.eng.umd.edu in /pub/xtank.
X
SHAR_EOF
chmod 0644 rplay-3.1.0/contrib/xtank/README ||
echo 'restore of rplay-3.1.0/contrib/xtank/README failed'
Wc_c="`wc -c < 'rplay-3.1.0/contrib/xtank/README'`"
test 178 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/contrib/xtank/README: original size 178, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/contrib/xpilot/README ==============
if test ! -d 'rplay-3.1.0/contrib/xpilot'; then
    echo 'x - creating directory rplay-3.1.0/contrib/xpilot'
    mkdir 'rplay-3.1.0/contrib/xpilot'
fi
if test -f 'rplay-3.1.0/contrib/xpilot/README' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/contrib/xpilot/README (File already exists)'
else
echo 'x - extracting rplay-3.1.0/contrib/xpilot/README (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/contrib/xpilot/README' &&
X
XXPilot versions 2.0betaPL2 and up include rplay sound support and are available
at ftp.cs.uit.no in the /pub/games/xpilot directory.
X
SHAR_EOF
chmod 0644 rplay-3.1.0/contrib/xpilot/README ||
echo 'restore of rplay-3.1.0/contrib/xpilot/README failed'
Wc_c="`wc -c < 'rplay-3.1.0/contrib/xpilot/README'`"
test 135 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/contrib/xpilot/README: original size 135, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/contrib/olvwm/README ==============
if test ! -d 'rplay-3.1.0/contrib/olvwm'; then
    echo 'x - creating directory rplay-3.1.0/contrib/olvwm'
    mkdir 'rplay-3.1.0/contrib/olvwm'
fi
if test -f 'rplay-3.1.0/contrib/olvwm/README' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/contrib/olvwm/README (File already exists)'
else
echo 'x - extracting rplay-3.1.0/contrib/olvwm/README (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/contrib/olvwm/README' &&
X
olvwm3.3 rplay2.0 support was added by Andrew Scherpbier.  The patches
along with a sun4 binary are available at sounds.sdsu.edu in the
/pub directory.  You probably also want to get olvwmtool.shar or
olvwmtool.sun4.Z.
X
SHAR_EOF
chmod 0644 rplay-3.1.0/contrib/olvwm/README ||
echo 'restore of rplay-3.1.0/contrib/olvwm/README failed'
Wc_c="`wc -c < 'rplay-3.1.0/contrib/olvwm/README'`"
test 221 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/contrib/olvwm/README: original size 221, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/contrib/crossfire/README ==============
if test ! -d 'rplay-3.1.0/contrib/crossfire'; then
    echo 'x - creating directory rplay-3.1.0/contrib/crossfire'
    mkdir 'rplay-3.1.0/contrib/crossfire'
fi
if test -f 'rplay-3.1.0/contrib/crossfire/README' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/contrib/crossfire/README (File already exists)'
else
echo 'x - extracting rplay-3.1.0/contrib/crossfire/README (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/contrib/crossfire/README' &&
X
crossfire can be obtained via anonymous ftp a ifi.uio.no, look for the crossfire
directory.  You might also need to get the crossfire-0.89.2-sound-diffs.Z and 
the sound files until version 0.89.3 is released.
X
SHAR_EOF
chmod 0644 rplay-3.1.0/contrib/crossfire/README ||
echo 'restore of rplay-3.1.0/contrib/crossfire/README failed'
Wc_c="`wc -c < 'rplay-3.1.0/contrib/crossfire/README'`"
test 212 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/contrib/crossfire/README: original size 212, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/contrib/jukebox1.2/jukebox.c ==============
if test ! -d 'rplay-3.1.0/contrib/jukebox1.2'; then
    echo 'x - creating directory rplay-3.1.0/contrib/jukebox1.2'
    mkdir 'rplay-3.1.0/contrib/jukebox1.2'
fi
if test -f 'rplay-3.1.0/contrib/jukebox1.2/jukebox.c' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/contrib/jukebox1.2/jukebox.c (File already exists)'
else
echo 'x - extracting rplay-3.1.0/contrib/jukebox1.2/jukebox.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/contrib/jukebox1.2/jukebox.c' &&
/*
X * Copyright (c) 1993 by Raphael Quinet (quinet@montefiore.ulg.ac.be)
X * Bits of code from "rplay.c" :  Copyright (c) 1992-93 by Mark Boyns
X *                                                   (boyns@sdsu.edu)
X *
X * Permission to use, copy, modify, and distribute this software and its
X * documentation for any purpose and without fee is hereby granted, provided
X * that the above copyright notice appear in all copies and that both that
X * copyright notice and this permission notice appear in supporting
X * documentation.  This software is provided "as is" without express or
X * implied warranty.
X */
X
static char *jukebox_version = "JUKEBOX 1.2";
X
#include <rplay.h>
#include <stdio.h>
#include <strings.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <signal.h>
X
extern char *optarg; 
extern int   optind;
X
/* Structure used in the "songs" table. */
typedef struct
X  {
X    int   idx;
X    char *name;
X    int   length;
X  } song;
X
/* Global variables. */
song          *songs;
int            nsongs = 0;
char          *progname;
int            stop_song = 0;
unsigned long  total_time = 0;
int            opt_quiet;
X
X
/*****************************************************************************
X * usage()                                                                   *
X *---------------------------------------------------------------------------*
X * Displays a help message.                                                  *
X *****************************************************************************/
usage()
{
X  printf("\n%s - Copyright (c) 1993 by Raphael Quinet (quinet@montefiore.ulg.ac.be)\n\n", jukebox_version);
X  printf("usage: %s [options] [directory ...]\n", progname);
X  printf("\t-a\tplay songs in alphabetical order (file names)\n");
X  printf("\t-f name\tload the list of songs from a file\n");
X  printf("\t-h host\tuse this instead of the default host (%s)\n",
X	 rplay_default_host());
X  printf("\t-l\tloop mode - no exit\n");
X  printf("\t-q\tquiet - only error messages\n");
X  printf("\t-r\tplay songs in a random order\n");
X  printf("\t-s n\tsleep n milliseconds between songs (n may be negative)\n");
X  printf("\t-v n\tvolume n (%d <= n <= %d), default = %d\n",
X	 RPLAY_MIN_VOLUME, RPLAY_MAX_VOLUME, RPLAY_DEFAULT_VOLUME);
X  printf("No options will play all songs (*.au) from the current\n");
X  printf("directory at the default volume\n\n");
X  exit(1);
}
X
X
/*****************************************************************************
X * set_timer()                                                               *
X *---------------------------------------------------------------------------*
X * Sets the real-time timer to "msec" milliseconds.  A SIGALRM signal is     *
X * delivered when this timer expires.                                        *
X *****************************************************************************/
#ifdef __STDC__
set_timer(int msec)
#else
set_timer(msec)
X     int  msec;
#endif
{
X  struct itimerval it;
X
X  it.it_value.tv_sec = msec / 1000;
X  it.it_value.tv_usec = (msec % 1000) * 1000;
X  it.it_interval.tv_sec = 0;
X  it.it_interval.tv_usec = 0;
X  setitimer(ITIMER_REAL, &it);
}
X
X
/*****************************************************************************
X * catch_sigtstp()                                                           *
X *---------------------------------------------------------------------------*
X * SIGTSTP handler : If the user wants to stop the jukebox (Ctrl-Z).         *
X *****************************************************************************/
catch_sigtstp()
{
X  stop_song = 2; /* Stop current song and call the default SIGTSTP handler. */
}
X
X
/*****************************************************************************
X * catch_sigint()                                                            *
X *---------------------------------------------------------------------------*
X * SIGINT handler : If the user wants another song (Ctrl-C).                 *
X *****************************************************************************/
catch_sigint()
{
X  stop_song = 1; /* Stop current song and play the next one. */
}
X
X
/*****************************************************************************
X * catch_sigalrm()                                                           *
X *---------------------------------------------------------------------------*
X * SIGALRM handler : It's time to play the next song...                      *
X *****************************************************************************/
catch_sigalrm()
{
X  stop_song = 0; /* Play the next song. */
}
X
X
/*****************************************************************************
X * readsongs(char *dirname)                                                  *
X *---------------------------------------------------------------------------*
X * Looks for "*.au" files in the "dirname" directory and stores the names    *
X * and lengths of the files in the "songs" table.                            *
X *****************************************************************************/
#ifdef __STDC__
readsongs(char *dirname)
#else
readsongs(dirname)
X     char *dirname;
#endif
{
X  DIR           *dirp;
X  struct dirent *dp;
X  struct stat    statbuf;
X  char           filename[MAXPATHLEN];
X
X  strcpy(filename, dirname);
X  strcat(filename, "/");
X
X  dirp = opendir(dirname);
X  if (dirp == NULL)
X    {
X      fprintf(stderr, "%s: can't open directory %s\n", progname, dirname);
X      exit(1);
X    }
X
X  for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp))
X    if ((strlen(dp->d_name) > 3) &&
X	!strcmp(dp->d_name + strlen(dp->d_name) - 3, ".au"))
X      {
X	/* "stat()" needs the full path to the files, so it is built in
X	 * the "filename" buffer.  As "rplayd" doesn't need the paths, only
X	 * the file name is stored in the "songs" table.
X         */
X	strcat(filename, dp->d_name);
X	if (stat(filename, &statbuf) == -1)
X	  {
X	    if (!opt_quiet)
X	      fprintf(stderr, "%s warning: can't stat %s\n",
X		      progname, filename);
X	    continue;
X	  }
X	filename[strlen(filename) - dp->d_namlen] = '\0';
X
X	if (nsongs == 0)
X	  songs = (song *)malloc(sizeof(song) * ++nsongs);
X	else
X	  songs = (song *)realloc(songs, sizeof(song) * ++nsongs);
X	if (songs == NULL)
X	  {
X	    fprintf(stderr, "%s: out of memory\n", progname);
X	    exit(1);
X	  }
X
X	songs[nsongs - 1].name = (char *)malloc(dp->d_namlen + 1);
X	if (songs[nsongs - 1].name == NULL)
X	  {
X	    fprintf(stderr, "%s: out of memory\n", progname);
X	    exit(1);
X	  }
X
X	strcpy(songs[nsongs - 1].name, dp->d_name);
X	songs[nsongs - 1].length = statbuf.st_size / 8 - 10;
X	total_time += songs[nsongs - 1].length;
X      }
X  closedir (dirp);   
}
X
X
/*****************************************************************************
X * readlist(char *listname)                                                  *
X *---------------------------------------------------------------------------*
X * Reads a list of songs from the file "listname".                           *
X *****************************************************************************/
#ifdef __STDC__
readlist(char *listname)
#else
readlist(listname)
X     char *listname;
#endif
{
X  FILE          *fp;
X  struct stat    statbuf;
X  char           buf[MAXPATHLEN], filename[MAXPATHLEN], *s;
X
X  fp = fopen(listname, "r");
X  if (fp == NULL)
X    {
X      fprintf(stderr, "%s: cannot open %s\n", progname, listname);
X      exit(1);
X    }
X
X  while (fgets(buf, sizeof(buf), fp) != NULL)
X    {
X      switch (buf[0])
X	{
X	case '#':
X	case ' ':
X	case '\t':
X	case '\n':
X	  continue;
X	}
X
X      sscanf(buf, "%[^\n]", filename);
X      if (stat(filename, &statbuf) == -1)
X	{
X	  if (!opt_quiet)
X	    fprintf(stderr, "%s warning: can't stat %s\n",
X		    progname, filename);
X	  continue;
X	}
X
X      if (nsongs == 0)
X	songs = (song *)malloc(sizeof(song) * ++nsongs);
X      else
X	songs = (song *)realloc(songs, sizeof(song) * ++nsongs);
X      if (songs == NULL)
X	{
X	  fprintf(stderr, "%s: out of memory\n", progname);
X	  exit(1);
X	}
X
X      if (s = (char *)strrchr(filename, '/'))
X	s++;
X      else
X	s = filename;
X
X      songs[nsongs - 1].name = (char *)malloc(strlen(s) + 1);
X      if (songs[nsongs - 1].name == NULL)
X	{
X	  fprintf(stderr, "%s: out of memory\n", progname);
X	  exit(1);
X	}
X
X      strcpy(songs[nsongs - 1].name, s);
X      songs[nsongs - 1].length = statbuf.st_size / 8 - 10;
X      total_time += songs[nsongs - 1].length;
X    }
X  fclose(fp);
}
X
X
/*****************************************************************************
X * idxcompare(song *i, song *j)                                              *
X *---------------------------------------------------------------------------*
X * Compares two song's indexes (used by "qsort()" - random order).           *
X *****************************************************************************/
#ifdef __STDC__
idxcompare(song *i, song *j)
#else
idxcompare(i,j)
X     song *i, *j;
#endif
{
X  return (i->idx - j->idx);
}
X
X
/*****************************************************************************
X * alphacompare(song *i, song *j)                                            *
X *---------------------------------------------------------------------------*
X * Compares two song's names (used by "qsort()" - alphabetical order).       *
X *****************************************************************************/
#ifdef __STDC__
alphacompare(song *i, song *j)
#else
alphacompare(i,j)
X     song *i, *j;
#endif
{
X  return strcmp(i->name, j->name);
}
X
X
/*****************************************************************************
X * main(int argc, char **argv)                                               *
X *---------------------------------------------------------------------------*
X * Come on, don't tell me that you don't know why I wrote a function named   *
X * "main()" !  My compiler told me it was really useful...                   *
X *****************************************************************************/
#ifdef __STDC__
main(int argc, char **argv)
#else
main(argc, argv)
X     int    argc;
X     char **argv;
#endif
{
X  int     rplay_fd, c, i;
X  int     opt_volume, opt_sleep, opt_loop, opt_random, opt_sort;
X  char   *host;
X  RPLAY  *rpp, *rps;
X
X  if (progname = (char *)strrchr(*argv, '/'))
X    progname++;
X  else
X    progname = *argv;
X
X  host = rplay_default_host();
X
X  opt_loop = 0;
X  opt_quiet = 0;
X  opt_random = 0;
X  opt_sort = 0;
X  opt_sleep = 0;
X  opt_volume = RPLAY_DEFAULT_VOLUME;
X  
X  while ((c = getopt(argc, argv, "af:h:lqrs:v:")) != -1)
X    {
X      switch(c)
X	{
X	case 'a':
X	  if (opt_random && !opt_quiet)
X	    fprintf(stderr, "%s warning: option -a overrides previous option -r\n", progname);
X	  opt_sort = 1;
X	  break;
X
X	case 'f':
X	  readlist(optarg);
X	  break;
X
X	case 'h':
X	  host = optarg;
X	  if (host[0] == '-')
X	    usage();
X	  break;
X	  
X	case 'l':
X	  opt_loop = 1;
X	  break;
X	  
X	case 'q':
X	  opt_quiet = 1;
X	  break;
X	  
X	case 'r':
X	  if (opt_sort && !opt_quiet)
X	    fprintf(stderr, "%s warning: option -r overrides previous option -a\n", progname);
X	  opt_random = 1;
X	  srandom(getpid());
X	  break;
X	  
X	case 's':
X	  opt_sleep = atoi(optarg);
X	  break;
X	  
X	case 'v':
X	  opt_volume = atoi(optarg);
X
X	default:
X	  usage();
X	  exit(1);
X	} 
X    }
X
X  if (argc == optind)
X    readsongs(".");
X  else
X    while (optind < argc)
X      readsongs(argv[optind++]);
X
X  if (nsongs == 0)
X    {
X      fprintf(stderr, "%s: no songs (*.au) to play\n", progname);
X      exit(1);
X    }
X
X  rplay_fd = rplay_open(host);
X  if (rplay_fd < 0)
X    {
X      rplay_perror(host);
X      exit(1);
X    }
X
X  rpp = rplay_create(RPLAY_PLAY);
X  if (rpp == NULL)
X    {
X      rplay_perror("rplay_create");
X      exit(1);
X    }
X
X  c = rplay_set(rpp, RPLAY_APPEND,
X		RPLAY_SOUND, "",
X		RPLAY_VOLUME, opt_volume,
X		NULL);
X  if (c < 0)
X    {
X      rplay_perror("rplay_set");
X      exit(1);
X    }
X
X  rps = rplay_create(RPLAY_STOP);
X  if (rps == NULL)
X    {
X      rplay_perror("rplay_create");
X      exit(1);
X    }
X
X  c = rplay_set(rps, RPLAY_APPEND,
X		RPLAY_SOUND, "",
X		NULL);
X  if (c < 0)
X    {
X      rplay_perror("rplay_set");
X      exit(1);
X    }
X
X  /* Use Ctrl-Z (SIGTSTP) if you want to stop the program then send a SIGTERM
X   * or SIGHUP if you want to kill it.  Ctrl-C (SIGINT) will only stop the
X   * current song and play the next one.
X   */
X  signal(SIGINT, catch_sigint);
X  signal(SIGTSTP, catch_sigtstp);
X  signal(SIGALRM, catch_sigalrm);
X
X  if (!opt_quiet)
X    {
X      printf("\n%s - Welcome !\n\n", jukebox_version);
X      printf("I will play %d songs just for you.\n", nsongs);
X      if (opt_sleep)
X	  printf("(Estimated total time : %lu%+ld seconds).\n\n",
X		 total_time / 1000L, ((long)opt_sleep * (long)nsongs) / 1000L);
X	else
X	  printf("(Estimated total time : %lu seconds).\n\n",
X		 total_time / 1000L);
X    }
X
X  if (opt_sort)
X    qsort((char *)songs, nsongs, sizeof(song), alphacompare);
X
X  do
X    {
X
X      if (opt_random)
X	{
X	  if (!opt_quiet && opt_loop)
X	    printf("Building random list ...\n\n");
X	  for (i = 0; i < nsongs; i++)
X	    songs[i].idx = (int)random();
X	  qsort((char *)songs, nsongs, sizeof(song), idxcompare);
X	}
X
X      for (i = 0; i < nsongs; i++)
X	{
X	  if (!opt_quiet)
X	    {
X	      if (opt_sleep)
X		printf("Playing %s ...  (%d%+d seconds)\n", songs[i].name,
X		       songs[i].length / 1000, opt_sleep / 1000);
X	      else
X		printf("Playing %s ...  (%d seconds)\n", songs[i].name,
X		       songs[i].length / 1000);
X	    }
X	  c = rplay_set(rpp, RPLAY_CHANGE, 0,
X			RPLAY_SOUND, songs[i].name,
X			NULL);
X	  if (c < 0)
X	    {
X	      rplay_perror("rplay_set");
X	      exit(1);
X	    }
X
X	  if (rplay(rplay_fd, rpp) < 0)
X	    {
X	      rplay_perror(host);
X	      exit(1);
X	    }
X
X	  if (songs[i].length + opt_sleep > 100)
X	    set_timer(songs[i].length + opt_sleep);
X	  else
X	    set_timer(100);
X
X	  /* Wait until the next signal.  This may be a SIGALRM delivered
X	   * by the timer (just play the next song) or another signal from
X	   * the user (stop the current song).
X	   */
X	  pause();
X
X	  if (stop_song != 0) /* Stop the current song. */
X	    {
X	      if (!opt_quiet)
X		printf(" Ouch !\n");
X	      c = rplay_set(rps, RPLAY_CHANGE, 0,
X			    RPLAY_SOUND, songs[i].name,
X			    NULL);
X	      if (c < 0)
X		{
X		  rplay_perror("rplay_set");
X		  exit(1);
X		}
X
X	      if (rplay(rplay_fd, rps) < 0)
X		{
X		  rplay_perror(host);
X		  exit(1);
X		}
X
X	      if (stop_song == 2) /* And stop the jukebox too. */
X		{
X		  signal(SIGTSTP, SIG_DFL);
X		  kill(getpid(), SIGTSTP); /* Stop now ! */
X		  if (!opt_quiet)
X		    printf("\nI still have %d songs to play.\n",
X			   nsongs - i - 1);
X		  signal(SIGTSTP, catch_sigtstp);
X		}
X	    }
X	}
X
X    } while (opt_loop > 0);
X
X  if (!opt_quiet)
X    printf("\nPlease insert coins to play another song.\n");
X
X  rplay_close(rplay_fd);
X  exit(0);
}
X
SHAR_EOF
chmod 0644 rplay-3.1.0/contrib/jukebox1.2/jukebox.c ||
echo 'restore of rplay-3.1.0/contrib/jukebox1.2/jukebox.c failed'
Wc_c="`wc -c < 'rplay-3.1.0/contrib/jukebox1.2/jukebox.c'`"
test 14797 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/contrib/jukebox1.2/jukebox.c: original size 14797, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/contrib/jukebox1.2/Makefile ==============
if test -f 'rplay-3.1.0/contrib/jukebox1.2/Makefile' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/contrib/jukebox1.2/Makefile (File already exists)'
else
echo 'x - extracting rplay-3.1.0/contrib/jukebox1.2/Makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/contrib/jukebox1.2/Makefile' &&
#
# Makefile for JUKEBOX 1.2
# (C) 1993 Raphael Quinet (quinet@montefiore.ulg.ac.be)
#
X
#include <std_disclaimer.h>
X
include ../../Makefile.config
LIBRPLAY_DIR=   ../../librplay
INCLUDE_DIR=    ../../include
X
TARGET=	jukebox
X
SRCS = jukebox.c
X
OBJS = jukebox.o
X
X
all: 		$(TARGET)
X
$(TARGET): 	$(OBJS)
X		$(CC) $(CFLAGS) -o $@ $(OBJS) $(LDFLAGS)
X
install:	$(TARGET)
X		@echo Installing $(TARGET) in $(INSTALL_BIN_DIR)
X		$(BIN_INSTALL) $(TARGET) $(INSTALL_BIN_DIR)
X
install.man:
X		@echo Installing the man page in $(INSTALL_BIN_DIR)
X		$(INSTALL) man1/$(TARGET).1 $(INSTALL_MAN_DIR)/man1
X
world: 		all install install.man
X
clean:
X		$(RM) $(TARGET) $(OBJS) core a.out *~ *.bak man1/*.bak man1/*~ 
X
depend:
X		$(MAKEDEPEND) -- $(CFLAGS) -- $(SRCS)
X
tar: 		clean
X		(cd .. ; tar -cvf $(TARGET).tar $(TARGET) ; gzip -9 $(TARGET).tar )
X
zip: 		clean
X		(cd .. ; zip -9 -o -y -r $(TARGET).zip $(TARGET) )
SHAR_EOF
chmod 0644 rplay-3.1.0/contrib/jukebox1.2/Makefile ||
echo 'restore of rplay-3.1.0/contrib/jukebox1.2/Makefile failed'
Wc_c="`wc -c < 'rplay-3.1.0/contrib/jukebox1.2/Makefile'`"
test 891 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/contrib/jukebox1.2/Makefile: original size 891, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/contrib/jukebox1.2/man1/jukebox.1 ==============
if test ! -d 'rplay-3.1.0/contrib/jukebox1.2/man1'; then
    echo 'x - creating directory rplay-3.1.0/contrib/jukebox1.2/man1'
    mkdir 'rplay-3.1.0/contrib/jukebox1.2/man1'
fi
if test -f 'rplay-3.1.0/contrib/jukebox1.2/man1/jukebox.1' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/contrib/jukebox1.2/man1/jukebox.1 (File already exists)'
else
echo 'x - extracting rplay-3.1.0/contrib/jukebox1.2/man1/jukebox.1 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/contrib/jukebox1.2/man1/jukebox.1' &&
.TH JUKEBOX 1 "27 August 1993"
.SH NAME
jukebox \- play a list of sounds (songs)
.SH SYNOPSIS
.B jukebox
[-afhlqrsv] [directory\.\.\.]
.SH DESCRIPTION
X
Jukebox is a small program that plays a list of songs on the host of your
choice, using Mark Boyns'
.B rplay
library.  This allows you to listen to some background music while you are working or doing anything else.
X
There are two ways to build a list of songs : you may use the
.B \-f
option followed by a file name which contains a list of song
names (like rplay.conf), or you may simply give the name of a directory.
All the \.au files in this directory will be added to the list.
X
While the jukebox is playing, you may skip a song with
.I Ctrl\-C.
This will stop the current song and play the next one.  You may also use
.I Ctrl\-Z,
which will stop both the current song and the jukebox.  Once the jukebox
has been stopped with a
.I Ctrl\-Z,
you may continue with the next song : use
.B fg
or whatever your shell needs to restart a stopped process.  If you want
to terminate the process, use
.B kill XXX
or
.B kill \-HUP XXX,
where XXX is the process number of the jukebox.
.SH OPTIONS
.TP
.B \-h hostname[:hostname\.\.\.]
Play sounds on this or all of these hosts.
This option will override the default host defined by the
.B RPLAY_HOST
environment variable.
.TP
.B \-f <name>
Take a list of sounds from the file
.B <name>.
This file should contain one sound name per line.  You may supply several
lists of songs, each one preceded by the \-f flag.
.TP
.B \-l
Loop mode.  The jukebox will keep on playing until stopped with a
Ctrl-Z or another signal.
.TP
.B \-a
Play the songs in alphabetical order (file names).
This might be useful if the file names begin with the name of
the artist or group, for example.
.TP
.B \-r
Play the songs in a random order.  If the jukebox is in loop mode,
a new list (in a different order) will be created each time the jukebox
reaches the last song.
.TP
.B \-q
Quiet mode.  Suppresses output except for error messages.
.TP
.B \-s <n>
Sleep between songs (
.B <n>
is in milliseconds and may be negative).
If you give a negative number, the two songs will be superimposed.
You may use this option to create a "fade in / fade out" effect (see examples below).
.TP
.B \-v <n>
Change the default play volume.
.SH EXAMPLES
.LP
Suppose you have several directories named "songs/XXX", where "XXX" is
the name of some artist or group.  If you want to play some music on
"verif1" (replace this with the name of your host), you might type
something like this :
.IP
.B "jukebox -h verif1 -r -s -4000 songs/*"
.PP
This will play all the songs from these directories, taken in a random
order.  There is also a "negative delay" of 4 seconds.  If all the songs
begin with a "fade in" and end with a "fade out", you will get a pretty
good effect.
X
If you want to play your favourite songs over and over on the default host,
you could type :
.IP
.B "jukebox -l -q songs/kate_bush songs/queen songs/rem ..."
.PP
(By the way, it is simpler to go in the "songs" directory to type these
commands as the paths would be shorter, but this is only an example).
Here, the 
.B \-q
option is used to suppress all normal output.  You can then use the jukebox
as a background job if you are short of terminals.
X
You may also put the names of your favorite songs in a file, and use this
file with the
.B \-f
option.  You may even create several files and use them in any
order, like this :
.IP
.B "jukebox -f rock_n_roll -f pop_music songs/rap ..."
.PP
In this example, the songs are taken from the files "rock_n_roll" and
"pop_music", but also from the directory "songs/rap".
X
.SH "SEE ALSO"
.BR rplay (1),
.BR rplayd (1),
.BR rplay.conf (5)
.SH AUTHOR
This program was written by Raphael Quinet (University of Liege, Belgium)
He can be reached by E-mail as follows:
.RS
X
.B quinet@montefiore.ULg.ac.Be
X
.RE
The
.B jukebox
program makes use of Mark Boyns'
.B rplay
package which can play multiple sounds on remote machines.
.br
He can be reached by E-mail as follows:
.RS
X
.B boyns@SDSU.edu
.RE
.SH BUGS
You have to supply the full pathnames in the sound lists.
X
The program's timer doesn't expect the sounds to be delayed in
any way while they are playing.  This leads to disastrous effects
if the song has to be fetched from another server or if someone
pauses the audio device.
X
SHAR_EOF
chmod 0644 rplay-3.1.0/contrib/jukebox1.2/man1/jukebox.1 ||
echo 'restore of rplay-3.1.0/contrib/jukebox1.2/man1/jukebox.1 failed'
Wc_c="`wc -c < 'rplay-3.1.0/contrib/jukebox1.2/man1/jukebox.1'`"
test 4341 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/contrib/jukebox1.2/man1/jukebox.1: original size 4341, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/audio.c ==============
if test ! -d 'rplay-3.1.0/rplayd'; then
    echo 'x - creating directory rplay-3.1.0/rplayd'
    mkdir 'rplay-3.1.0/rplayd'
fi
if test -f 'rplay-3.1.0/rplayd/audio.c' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/audio.c (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/audio.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/audio.c' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#include "conf.h"
#include <sys/types.h>
#include <sys/file.h>
#ifdef ultrix
#include <fcntl.h>
#else
#include <sys/fcntl.h>
#endif
#include <stdio.h>
#include <unistd.h>
#include "audio.h"
#include "rplayd.h"
#include "spool.h"
#include "sound.h"
#include "ulaw.h"
#ifdef __386BSD__
#include <machine/sblast.h>
#endif
#ifdef sgi
#include <audio.h>
#endif
X
#undef MAX
#define MAX(a,b)	((a)>(b)?(a):(b))
X
#ifdef sgi
static ALport	audio_fd = (ALport)-1;
static ALconfig	sgitheconfig;
static short	audio_buf[AUDIO_BUFSIZE];
#else
static int	audio_fd = -1;
static char	audio_buf[AUDIO_BUFSIZE];
#endif
static int	audio_size;
int		audio_timeout = AUDIO_TIMEOUT;
X
/*
X * initialize the audio device
X */
void	audio_init()
{
#ifdef sgi
X	long	sgisampfmt	= AL_SAMPLE_16;
X	long	sginchannels	= AL_MONO;
X	long	sgipvbuf[4];
X	long	sgipvbuflen;
X
X	sgipvbuf[0] = AL_INPUT_RATE;
X	sgipvbuf[1] = AL_RATE_8000;
X	sgipvbuf[2] = AL_OUTPUT_RATE;
X	sgipvbuf[3] = AL_RATE_8000;
X	sgipvbuflen = 4;
X
X	ALsetparams(AL_DEFAULT_DEVICE, sgipvbuf, sgipvbuflen);
X
X	sgitheconfig = ALnewconfig();
X	ALsetwidth(sgitheconfig, sgisampfmt);
X	ALsetchannels(sgitheconfig, sginchannels);
#endif
}
X
/*
X * open the audio device
X */
void	audio_open()
{
X	if (debug)
X	{
X		report("opening %s\n", AUDIO_DEVICE);
X	}
#ifdef sgi
X	audio_fd = ALopenport("rplay", "w", sgitheconfig);
X	if ((int)audio_fd < 0 && debug)
#else
X	audio_fd = open(AUDIO_DEVICE, O_WRONLY|O_NDELAY, 0);
X	if (audio_fd < 0 && debug)
#endif
X	{
X		report("%s open: %s\n", AUDIO_DEVICE, sys_errlist[errno]);
X	}
}
X
/*
X * close the audio device
X */
void	audio_close()
{
#ifdef sgi
X	if ((int)audio_fd != -1)
X	{
X		ALcloseport(audio_fd);
X	}
X	audio_fd = (ALport)-1;
#else
X	if (audio_fd > 0)
X	{
X		if (debug)
X		{
X			report("closing %s\n", AUDIO_DEVICE);
X		}
X		close(audio_fd);
X	}
X	audio_fd = -1;
#endif
}
X
/*
X * write a buffer from the spool to the audio device
X */
void	audio_write()
{
X	int		i, n;
X	int		total, val, vol;
X	SPOOL		*sp;
X
X	while (audio_size != AUDIO_BUFSIZE && spool_size)
X	{
X		total = 0;
X		for (i = 0; i < SPOOL_SIZE && audio_size != AUDIO_BUFSIZE; i++)
X		{
X			sp = &spool[i];
X			if (sp->state == SPOOL_PLAY)
X			{
X				vol = sp->curr_attrs->volume;
X				if (spool_prio && spool_size > 1)
X				{
X					vol -= (spool_prio - sp->rp->priority) >> 1;
X					vol = MAX(vol, RPLAY_MIN_VOLUME);
X				}
X				val = ulaw_to_linear((unsigned char)*sp->ptr)*vol;
X				total += val >> 7;
X				if (sp->ptr == sp->end)
X				{
X					if (sp->curr_count > 1)
X					{
X						sp->curr_count--;
X					}
X					else
X					{
X						sp->curr_sound++;
X						if (sp->curr_sound == sp->rp->nsounds)
X						{
X							if (sp->list_count > 1)
X							{
X								sp->list_count--;
X								sp->curr_attrs = sp->rp->attrs;
X								sp->curr_sound = 0;
X							}
X							else
X							{
X								spool_clear(sp);
X								spool_size--;
X								continue;
X							}
X						}
X						else
X						{
X							sp->curr_attrs = sp->curr_attrs->next;
X						}
X						sp->curr_count = sp->curr_attrs->count;
X					}
X					sp->ptr = sp->sound[sp->curr_sound]->start;
X					sp->end = sp->sound[sp->curr_sound]->stop;
X				}
X				else
X				{
X					sp->ptr++;
X				}
X			}
X		}
#ifdef __386BSD__
X		/*
X		 * convert signed short to unsigned 8 bit value.
X		 */
X		audio_buf[audio_size++] = (total ^ 0x8000) >> 8;
#else
#ifdef sgi
X		audio_buf[audio_size++] = total;
#else
X		audio_buf[audio_size++] = linear_to_ulaw(total);
#endif
#endif
X	}
#ifdef sgi
X	if ((int)audio_fd < 0 && audio_size)
#else
X	if (audio_fd < 0 && audio_size)
#endif
X	{
X		audio_open();
X	}
#ifdef sgi
X	if ((int)audio_fd > 0)
#else
X	if (audio_fd > 0)
#endif
X	{
#ifdef sgi
X		ALwritesamps(audio_fd, audio_buf, audio_size);
#else /* sgi */
X		n = write(audio_fd, audio_buf, audio_size);
#ifdef __386BSD__
X		if (spool_size == 0)
X		{
X			ioctl(audio_fd, DSP_IOCTL_FLUSH, 0);
X		}
#endif /* __386BSD__ */
X		if (n < 0 && debug)
X		{
X			report("write: %s\n", sys_errlist[errno]);
X		}
#endif /* sgi */
X	}
X	audio_size = 0;
}
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/audio.c ||
echo 'restore of rplay-3.1.0/rplayd/audio.c failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/audio.c'`"
test 4680 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/audio.c: original size 4680, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/command.c ==============
if test -f 'rplay-3.1.0/rplayd/command.c' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/command.c (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/command.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/command.c' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#include "conf.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include "rplayd.h"
#include "command.h"
#include "connection.h"
#include "server.h"
#include "host.h"
#include "spool.h"
#include "cache.h"
#include "sound.h"
X
static COMMAND	commands[] =
{
/*	
X *	command		min	max	usage				function
X */
X	"access",	-1,	-1,	"" ,				command_access,
X	"continue",	1,	-1,	"[-PNnv] sound ...",		command_play,
X	"find",		1,	1,	"sound",			command_find,
X	"get",		1,	1,	"sound",			command_get,
X	"help",		-1,	-1,	"",				command_help,
#ifdef AUTH
X	"list",		0,	1,	"[connections|hosts|servers|spool|sounds]",	command_list,
#else
X	"list",		0,	1,	"[connections|servers|sounds}",		command_list,
#endif /* AUTH */
X	"pause",	1,	-1,	"[-PNnv] sound ...",		command_play,
X	"play",		1,	-1,	"[-PNnv] sound ...",		command_play,
X	"put",		2,	2,	"sound size",			command_put,
X	"stop",		1,	-1,	"[-PNnv] sound ...",		command_play,
X	"quit",		0,	0,	"",				command_quit,
};
#define NCOMMANDS	(sizeof(commands)/sizeof(COMMAND))
X
#ifdef __STDC__
int	command(CONNECTION *c, char *buf)
#else
int	command(c, buf)
CONNECTION	*c;
char		*buf;
#endif
{
X	char	*argv[RPTP_MAX_ARGS], *p;
X	int	argc = 0, first = 1, i;
X
X	while (p = strtok(first ? buf : NULL, " \t"))
X	{
X		argv[argc++] = p;
X		first = 0;
X	}
X	argv[argc] = NULL;
X
X	for (i = 0; i < NCOMMANDS; i++)
X	{
X		if (strcmp(commands[i].name, argv[0]) == 0)
X		{
X			if (commands[i].min_args >= 0 && argc-1 < commands[i].min_args
X				|| commands[i].max_args >= 0 && argc-1 > commands[i].max_args)
X			{
X				connection_reply(c, "%cUsage: %s %s",
X					RPTP_ERROR, commands[i].name, commands[i].usage);
X				return 0;
X			}
X			else
X			{
X				return (*commands[i].func)(c, argc, argv);
X			}
X		}
X	}
X
X	return command_unknown(c, argc, argv);
}
X
#ifdef __STDC__
int	command_quit(CONNECTION *c, int argc, char **argv)
#else
int	command_quit(c, argc, argv)
CONNECTION	*c;
int		argc;
char		**argv;
#endif
{
X	connection_close(c);
X	return -1;
}
X
#ifdef __STDC__
int	command_unknown(CONNECTION *c, int argc, char **argv)
#else
int	command_unknown(c, argc, argv)
CONNECTION	*c;
int		argc;
char		**argv;
#endif
{
X        connection_reply(c, "%cunknown command '%s'", RPTP_ERROR, argv[0]);
X
X	return 0;
}
X
#ifdef __STDC__
int	command_help(CONNECTION *c, int argc, char **argv)
#else
int	command_help(c, argc, argv)
CONNECTION	*c;
int		argc;
char		**argv;
#endif
{
X	int		i;
X	char		fmt[64];
X	EVENT		*e;
X	static BUFFER  	*b;
X	
X	
X	if (b == NULL)
X	{	
X		b = buffer_create();
X		b->status = BUFFER_KEEP;
X		sprintf(b->buf, "%ccommand summary\r\n", RPTP_OK);
X		for (i = 0; i < NCOMMANDS; i++)
X		{
X			sprintf(fmt, "%-8s %s\r\n", commands[i].name, commands[i].usage);
X			strcat(b->buf, fmt);
X		}
X		strcat(b->buf, ".\r\n");
X		b->nbytes = strlen(b->buf);
X	}
X
X	e = event_create(EVENT_WRITE, b);
X	event_insert(c, e);
X	
X	return 0;
}
X
#ifdef __STDC__
int	command_get(CONNECTION *c, int argc, char **argv)
#else
int	command_get(c, argc, argv)
CONNECTION	*c;
int		argc;
char		**argv;
#endif
{
X	SOUND	*s;
X	EVENT	*e;
X	
#ifdef AUTH
X	if (!host_access(c->sin, HOST_READ))
X	{
X		connection_reply(c, "%cread access denied", RPTP_ERROR);
X		return 0;
X	}
#endif /* AUTH */
X	
X	s = sound_lookup(argv[1], SOUND_DONT_FIND);
X	if (s == NULL || s->status != SOUND_READY)
X	{
X		connection_reply(c, "%c%s not found", RPTP_ERROR, argv[1]);
X	}
X	else
X	{
X		connection_reply(c, "%c%s %d", RPTP_OK, s->name, s->size);
X		e = event_create(EVENT_WRITE_SOUND, s);
X		event_insert(c, e);
X	}
X	
X	return 0;
}
X
#ifdef __STDC__
int	command_put(CONNECTION *c, int argc, char **argv)
#else
int	command_put(c, argc, argv)
CONNECTION	*c;
int		argc;
char		**argv;
#endif
{
X	EVENT	*e;
X	int	size;
X	char	*name, *p, *sound_name;
X	SOUND	*s;
#ifndef MMAP
X	int	fd;
#endif
X	
#ifdef AUTH
X	if (!host_access(c->sin, HOST_WRITE))
X	{
X		connection_reply(c, "%cwrite access denied", RPTP_ERROR);
X		return 0;
X	}
#endif /* AUTH */
X	
X	/*
X	 * strip pathnames, files can only be put in the cache directory
X	 */
X	sound_name = strrchr(argv[1], '/');
X	if (sound_name == NULL)
X	{
X	        sound_name = argv[1];
X	}
X	else
X	{
X		sound_name++;
X	}
X	name = cache_name(sound_name);
X
X	s = sound_lookup(name, SOUND_DONT_FIND);
X	if (s != NULL)
X	{
X		connection_reply(c, "%c%s already is in the cache", RPTP_ERROR, sound_name);
X		return 0;
X	}
X
X	size = atoi(argv[2]);
X
X	if (cache_free(size) < 0)
X	{
X		connection_reply(c, "%cthe cache is full", RPTP_ERROR);
X	}
X	else
X	{
#ifdef MMAP
X		p = cache_create(name, size);
X		if (p == NULL)
#else
X		fd = cache_create(name, size);
X		if (fd < 0)
#endif /* MMAP */
X		{
X			connection_reply(c, "%ccache error", RPTP_ERROR);
X		}
X		else
X		{
X			s = sound_insert(name, SOUND_NOT_READY);
X			if (debug)
X			{
X				report("%s putting %s size %d\n", inet_ntoa(c->sin.sin_addr),
X				       sound_name, size);
X			}
X			connection_reply(c, "%c%s %d bytes", RPTP_OK, sound_name, size);
#ifdef MMAP
X			e = event_create(EVENT_READ_SOUND, p, size, s);
#else
X			e = event_create(EVENT_READ_SOUND, fd, buffer_create(), size, s);
#endif /* MMAP */
X			event_insert(c, e);
X		}
X	}
X
X	return 0;
}
X
#ifdef __STDC__
int	command_list(CONNECTION *c, int argc, char **argv)
#else
int	command_list(c, argc, argv)
CONNECTION	*c;
int		argc;
char		**argv;
#endif
{
X	EVENT	*e;
X
X	if (argv[1] == NULL || strcmp(argv[1], "sounds") == 0)
X	{
X		e = event_create(EVENT_WRITE, sound_list_create());
X		event_insert(c, e);
X	}
X	else if (strcmp(argv[1], "connections") == 0)
X	{
X		e = event_create(EVENT_WRITE, connection_list_create());
X		event_insert(c, e);
X	}		
X	else if (strcmp(argv[1], "servers") == 0)
X	{
X		e = event_create(EVENT_WRITE, server_list);
X		event_insert(c, e);
X	}
X	else if (strcmp(argv[1], "spool") == 0)
X	{
X		e = event_create(EVENT_WRITE, spool_list_create());
X		event_insert(c, e);
X	}
#ifdef AUTH
X	else if (strcmp(argv[1], "hosts") == 0)
X	{
X		e = event_create(EVENT_WRITE, host_list);
X		event_insert(c, e);
X	}
#endif /* AUTH */
X	else
X	{
X		connection_reply(c, "%ccannot list %s", RPTP_ERROR, argv[1]);
X	}
X
X	return 0;
}
X
#ifdef __STDC__
int	command_find(CONNECTION *c, int argc, char **argv)
#else
int	command_find(c, argc, argv)
CONNECTION	*c;
int		argc;
char		**argv;
#endif
{
X	SOUND	*s;
X
X	s = sound_lookup(argv[1], SOUND_DONT_FIND);
X	if (s == NULL || s->status != SOUND_READY)
X	{
X		connection_reply(c, "%c%s not found", RPTP_ERROR, argv[1]);
X	}
X	else
X	{
X		connection_reply(c, "%c%s %d", RPTP_OK, s->name, s->size);
X	}
X
X	return 0;
}
X
#ifdef __STDC__
int	command_access(CONNECTION *c, int argc, char **argv)
#else
int	command_access(c, argc, argv)
CONNECTION	*c;
int		argc;
char		**argv;
#endif
{
X	char	buf[4];
X	
X	buf[0] = '\0';
#ifdef AUTH
X	if (host_access(c->sin, HOST_READ))
X	{
X		strcat(buf, "r");
X	}
X	if (host_access(c->sin, HOST_WRITE))
X	{
X		strcat(buf, "w");
X	}
X	if (host_access(c->sin, HOST_EXECUTE))
X	{
X		strcat(buf, "x");
X	}
#else /* AUTH */
X	strcat(buf, "rwx");
#endif /* AUTH */
X	
X	connection_reply(c, "%c%s", RPTP_OK, buf);
X	
X	return 0;
}
X
#ifdef __STDC__
int	command_play(CONNECTION *c, int argc, char **argv)
#else
int	command_play(c, argc, argv)
CONNECTION	*c;
int		argc;
char		**argv;
#endif
{
X	int		i, n, command, val;
X	RPLAY		*rp;  
X	int		volume, list_count, count, priority;
X	extern char	*optarg;
X	extern int	optind;
X
#ifdef AUTH
X	if (!host_access(c->sin, HOST_EXECUTE))
X	{
X		connection_reply(c, "%cexecute access denied", RPTP_ERROR);
X		return 0;
X	}
#endif /* AUTH */
X
X	if (strcmp(argv[0], "play") == 0)
X	{
X		command = RPLAY_PLAY;
X	}
X	else if (strcmp(argv[0], "stop") == 0)
X	{
X		command = RPLAY_STOP;
X	}
X	else if (strcmp(argv[0], "pause") == 0)
X	{
X		command = RPLAY_PAUSE;
X	}
X	else if (strcmp(argv[0], "continue") == 0)
X	{
X		command = RPLAY_CONTINUE;
X	}
X
X	volume = RPLAY_DEFAULT_VOLUME;
X	count = RPLAY_DEFAULT_COUNT;
X	list_count = RPLAY_DEFAULT_LIST_COUNT;
X	priority = RPLAY_DEFAULT_PRIORITY;
X
X	optind = 1;
X	while ((n = getopt(argc, argv, "P:N:n:v:")) != -1)
X	{
X		switch (n)
X		{
X		case 'v':
X			volume = atoi(optarg);
X			break;
X
X		case 'n':
X			count = atoi(optarg);
X			break;
X
X		case 'N':
X			list_count = atoi(optarg);
X			break;
X
X		case 'P':
X			priority = atoi(optarg);
X			break;
X
X		default:
X			argc = optind;
X			break;
X		}
X	}
X
X	if (argc == optind)
X	{
X		for (i = 0; i < NCOMMANDS; i++)
X		{
X			if (strcmp(commands[i].name, argv[0]) == 0)
X			{
X				connection_reply(c, "%cUsage: %s %s",
X					RPTP_ERROR, commands[i].name, commands[i].usage);
X				return 0;
X			}
X		}
X	}
X
X	rp = rplay_create(command);
X	if (rp == NULL)
X	{
X		connection_reply(c, "%c%s failed", RPTP_ERROR, argv[0]);
X		return 0;
X	}
X	  
X	if (rplay_set(rp, RPLAY_LIST_COUNT, list_count, NULL) < 0)
X	{
X		connection_reply(c, "%c%s failed", RPTP_ERROR, argv[0]);
X		return 0;
X	}
X
X	if (rplay_set(rp, RPLAY_PRIORITY, priority, NULL) < 0)
X	{
X		connection_reply(c, "%c%s failed", RPTP_ERROR, argv[0]);
X		return 0;
X	}
X
X	while (argv[optind] != NULL)
X	{
X		val = rplay_set(rp, RPLAY_APPEND,
X			RPLAY_SOUND,	argv[optind++],
X			RPLAY_VOLUME,	volume,
X			RPLAY_COUNT,	count,
X			NULL);
X		if (val < 0)
X		{
X			connection_reply(c, "%c%s failed", RPTP_ERROR, argv[0]);
X			return 0;
X		}
X	}
X
X	switch (command)
X	{
X	case RPLAY_PLAY:
X		val = rplayd_play(rp, c->sin);
X		break;
X
X	case RPLAY_STOP:
X		val = rplayd_stop(rp, c->sin);
X		break;
X
X	case RPLAY_PAUSE:
X		val = rplayd_pause(rp, c->sin);
X		break;
X
X	case RPLAY_CONTINUE:
X		val = rplayd_continue(rp, c->sin);
X		break;
X	}
X
X	if (val < 0)
X	{
X		connection_reply(c, "%c%s failed", RPTP_ERROR, argv[0]);
X	}
X	else
X	{
X		connection_reply(c, "%c%s successful", RPTP_OK, argv[0]);
X	}
X
X	return 0;
}
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/command.c ||
echo 'restore of rplay-3.1.0/rplayd/command.c failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/command.c'`"
test 10175 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/command.c: original size 10175, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/host.h ==============
if test -f 'rplay-3.1.0/rplayd/host.h' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/host.h (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/host.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/host.h' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#ifndef _host_h
#define _host_h
X
#include "conf.h"
#include "buffer.h"
X
#ifdef AUTH
X
#define HOST_EXPR_SIZE		1024
#define HOST_READ		'r'
#define HOST_WRITE		'w'
#define HOST_EXECUTE		'x'
#define HOST_DEFAULT_ACCESS	"rx"
X
extern BUFFER	*host_list;
X
#ifdef __STDC__
extern void	host_read(char *filename);
extern char	*host_ip_to_regex(char *ip_addr);
extern int	host_access(struct sockaddr_in sin, char access_mode);
#else
extern void	host_read(/* char *filename */);
extern char	*host_ip_to_regex(/* char *ip_addr */);
extern int	host_access(/* struct sockaddr_in sin, char access_mode */);
#endif
X
#endif /* AUTH */
X
#endif /* _host_h */
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/host.h ||
echo 'restore of rplay-3.1.0/rplayd/host.h failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/host.h'`"
test 1431 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/host.h: original size 1431, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/hash.c ==============
if test -f 'rplay-3.1.0/rplayd/hash.c' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/hash.c (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/hash.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/hash.c' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#include "conf.h"
#include <sys/types.h>
#include <sys/param.h>
#include <stdio.h>
#include <string.h>
#include "hash.h"
#include "search.h"
#include "rplayd.h"
X
#ifdef __STDC__
void	hash_init(int hash_table_size)
#else
void	hash_init(hash_table_size)
int	hash_table_size;
#endif
{
X	if (hcreate(hash_table_size) == 0)
X	{
X		report("cannot create hash table\n");
X		done(1);
X	}
}
X
#ifdef __STDC__
char	*hash_get(char *hash_key)
#else
char	*hash_get(hash_key)
char	*hash_key;
#endif
{
X	ENTRY	e, *ep;
X
X	e.key = hash_key;
X	ep = hsearch(e, FIND);
X
X	return ep ? (char *)ep->data : NULL;
}
X
#ifdef __STDC__
void	hash_put(char *hash_key, char *data)
#else
void	hash_put(hash_key, data)
char	*hash_key;
char	*data;
#endif
{
X	ENTRY	e;
X
X	e.key = hash_key;
X	e.data = data;
X
X	if (hsearch(e, ENTER) == NULL)
X	{
X		report("hash_put: the hash table is full\n");
X		done(1);
X	}
}
X
#ifdef __STDC__
void	hash_delete(char *hash_key)
#else
void	hash_delete(hash_key)
char	*hash_key;
#endif
{
X	ENTRY	e;
X	
X	e.key = hash_key;
X
X	if (hsearch(e, DELETE) == NULL)
X	{
X		report("hash_delete: %s not in the hash table\n", hash_key);
X		done(1);
X	}
}
X
/*
X * create a hash key name for the given sound
X */
#ifdef __STDC__
char	*hash_name(char *pathname)
#else
char	*hash_name(pathname)
char	*pathname;
#endif
{
X	static char	name[MAXPATHLEN];
X	char		*extension;
X
X	if (pathname[0] == '/')
X	{
X		pathname = strrchr(pathname, '/') + 1;
X	}
X
X	strcpy(name, pathname);
X	extension = strrchr(name, '.');
X	if (extension)
X	{
X		*extension = '\0';
X	}
X
X	return name;
}
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/hash.c ||
echo 'restore of rplay-3.1.0/rplayd/hash.c failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/hash.c'`"
test 2274 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/hash.c: original size 2274, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/rplayd.c ==============
if test -f 'rplay-3.1.0/rplayd/rplayd.c' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/rplayd.c (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/rplayd.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/rplayd.c' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#include "conf.h"
#include "version.h"
#include "rplay.h"
#include <sys/param.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netdb.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include "rplayd.h"
#include "connection.h"
#include "audio.h"
#include "spool.h"
#include "sound.h"
#ifdef AUTH
#include "host.h"
#endif /* AUTH */
#include "server.h"
#include "hash.h"
#include "misc.h"
#include "cache.h"
X
fd_set		read_mask;
fd_set		write_mask;
X
int		debug = 0;
int		inetd = 1;
int		rplayd_timeout = RPLAYD_TIMEOUT;
int		rptp_timeout = RPTP_CONNECTION_TIMEOUT;
int	       	sound_cleanup_timeout = SOUND_CLEANUP_TIMEOUT;
X
static char	*progname;
static char	*sounds_file = RPLAY_CONF;
#ifdef AUTH
static char	*hosts_file = RPLAY_HOSTS;
#endif /* AUTH */
static char	*servers_file = RPLAY_SERVERS;
static char	*cache_dir = RPLAY_CACHE;
X
extern char	*sys_errlist[];
extern char	*optarg;
extern int	optind;
X
char		hostname[MAXHOSTNAMELEN];
X
int		rplay_fd, rptp_fd;
X
#ifdef sparc
#ifdef __STDC__
extern int	gethostname(char *name, int namelen);
#else
extern int	gethostname(/* char *name, int namelen */);
#endif
#endif
X
#ifdef __STDC__
main(int argc, char **argv)
#else
main(argc, argv)
int	argc;
char	**argv;
#endif
{
X	int		nfds, tcount = 0, c;
X	struct timeval	select_timeout;
X	fd_set		rfds, wfds;
X
X	progname = argv[0];
X
#ifdef AUTH
X	while ((c = getopt(argc, argv, "C:D:H:S:c:dns:t:T:v")) != -1)
#else /* AUTH */
X	while ((c = getopt(argc, argv, "C:D:S:c:dns:t:T:v")) != -1)
#endif /* AUTH */
X	{
X		switch (c)
X		{
X		case 'C':
X			sounds_file = optarg;
X			break;
X		
X		case 'D':
X			cache_dir = optarg;
X			break;
X
#ifdef AUTH
X		case 'H':
X			hosts_file = optarg;
X			break;
#endif /* AUTH */
X		
X		case 'S':
X			servers_file = optarg;
X			break;
X
X		case 'c':
X			audio_timeout = atoi(optarg);
X			break;
X
X		case 'd':
X			debug = 1;
X			break;
X
X		case 'n':
X			inetd = 0;
X			break;
X
X		case 's':
X			cache_max_size = atoi(optarg);
X			break;
X
X		case 't':
X			rplayd_timeout = atoi(optarg);
X			break;
X
X		case 'T':
X			rptp_timeout = atoi(optarg);
X			break;
X
X		case 'v':
X			printf("%s\n", rplay_version);
X			done(0);
X			break;
X
X		case '?':
X			usage();
X			done(1);
X		}
X	}
X
X	if (gethostname(hostname, sizeof(hostname)) < 0)
X	{
X		report("gethostname: %s\n", sys_errlist[errno]);
X		done(1);
X	}
X
X	/*
X	 * ingore SIGPIPE since read will handled closed TCP connections
X	 */
X	signal(SIGPIPE, SIG_IGN);
X
X	rplayd_init();
X	hash_init(MAX_SOUNDS);
X	sound_read(sounds_file);
X	cache_init(cache_dir);
X	cache_read();
#ifdef AUTH
X	host_read(hosts_file);
#endif /* AUTH */
X	server_read(servers_file);
X	spool_init();
X	audio_init();
X
X	FD_ZERO(&rfds);
X	FD_ZERO(&wfds);
X	FD_ZERO(&read_mask);
X	FD_ZERO(&write_mask);
X	FD_SET(rplay_fd, &read_mask);
X	FD_SET(rptp_fd, &read_mask);
X
X	if (debug)
X	{
X		report("%s rplayd ready.\n", hostname);
X	}
X	
X	for (;;)
X	{
X		if (spool_size)
X		{
X			rplayd_read();
X			audio_write();
X			connection_update((fd_set *)NULL, (fd_set *)NULL);
X		}
X		else
X		{
X			select_timeout.tv_sec = 1;
X			select_timeout.tv_usec = 0;
X			rfds = read_mask;
X			wfds = write_mask;
#ifdef __hpux
X			nfds = select(FD_SETSIZE, (int *)&rfds, (int *)&wfds, 0, &select_timeout);
#else
X			nfds = select(FD_SETSIZE, &rfds, &wfds, 0, &select_timeout);
#endif
X			switch (nfds)
X			{
X			case -1:
X				report("select: %s\n", sys_errlist[errno]);
X				done(1);
X
X			case 0:
X				tcount++;
X				if (audio_timeout && tcount == audio_timeout)
X				{
/*
X * SGI does not need to close the audio device
X */
#ifndef sgi
X					audio_close();
#endif
X				}
X				
X				if (rplayd_timeout && tcount == rplayd_timeout)
X				{
X					done(0);
X				}
X				if (rptp_timeout && connections)
X				{
X					connection_check_timeout();
X				}
X				if (sound_cleanup_timeout && tcount == sound_cleanup_timeout)
X				{
X					sound_cleanup();
X				}
X				break;
X
X			default:
X				tcount = 0;
X				if (FD_ISSET(rplay_fd, &rfds))
X				{
X					rplayd_read();
X				}
X				if (spool_size)
X				{
X					audio_write();
X				}
X				connection_update(&rfds, &wfds);
X				break;
X			}
X		}
X	}
}
X
/*
X * set up the sockets to receive rplay packets and connection connections
X */
void	rplayd_init()
{
X	struct sockaddr_in	s;
X	int			on = 1;
X	
X	if (inetd)
X	{
X		rplay_fd = 0;
X	}
X	else
X	{
X		rplay_fd = socket(AF_INET, SOCK_DGRAM, 0);
X		if (rplay_fd < 0)
X		{
X			report("socket: %s\n", sys_errlist[errno]);
X			done(1);
X		}
X
X		s.sin_family = AF_INET;
X		s.sin_port = htons(RPLAY_PORT);
X		s.sin_addr.s_addr = INADDR_ANY;
X
X		if (bind(rplay_fd, (struct sockaddr *)&s, sizeof(s)) < 0)
X		{
X			report("bind: %s\n", sys_errlist[errno]);
X			done(1);
X		}
X	}
X
X	socket_nonblock(rplay_fd);
X
X	rptp_fd = socket(AF_INET, SOCK_STREAM, 0);
X	if (rptp_fd < 0)
X	{
X		report("socket: %s\n", sys_errlist[errno]);
X		done(1);
X	}
X
X	if (setsockopt(rptp_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
X	{
X		report("setsockopt SO_REUSEADDR: %s\n", sys_errlist[errno]);
X		done(1);
X	}
X
X	s.sin_family = AF_INET;
X	s.sin_port = htons(RPTP_PORT);
X	s.sin_addr.s_addr = INADDR_ANY;
X
X	if (bind(rptp_fd, (struct sockaddr *)&s, sizeof(s)) < 0)
X	{
X		report("bind: %s\n", sys_errlist[errno]);
X		done(1);
X	}
X
X	if (listen(rptp_fd, 5) < 0)
X	{
X		report("listen: %s\n", sys_errlist[errno]);
X		done(1);
X	}
}
X
/*
X * read rplay packets from the rplay_fd UDP socket
X */
#ifdef __STDC__
void	rplayd_read(void)
#else
void	rplayd_read()
#endif
{
X	static char		recv_buf[MAX_PACKET];
X	char			*packet;
X	struct sockaddr_in	f;
X	int			j, n, flen;
X	RPLAY			*rp;
X
X	for (j = 0; j < SPOOL_SIZE; j++)
X	{
X		flen = sizeof(f);
X		
X		n = recvfrom(rplay_fd, recv_buf, sizeof(recv_buf), 0, (struct sockaddr *)&f, &flen);
X		if (n <= 0)
X		{
X			usleep(1); /* believe me this helps xtank a lot */
X			continue;
X		}
#ifdef AUTH
X		if (!host_access(f, HOST_EXECUTE))
X		{
X			if (debug && !host_access(f, HOST_READ) && !host_access(f, HOST_WRITE))
X			{
X				report("%s permission denied\n", inet_ntoa(f.sin_addr));
X			}
X			continue;
X		}
#endif /* AUTH */
X
X		packet = recv_buf;
X
X		switch (*packet)
X		{
#ifdef OLD_RPLAY
X		case OLD_RPLAY_PLAY:
X		case OLD_RPLAY_STOP:
X		case OLD_RPLAY_PAUSE:
X		case OLD_RPLAY_CONTINUE:
X			packet = rplay_convert(recv_buf);
#endif /* OLD_RPLAY */
X				
X		case RPLAY_VERSION:
X			rp = rplay_unpack(packet);
X			if (rp == NULL)
X			{
X				report("%s\n", rplay_errlist[rplay_errno]);
X				break;
X			}
X
X			switch (rp->command)
X			{
X			case RPLAY_PING:
X				if (debug)
X				{
X					report("received a ping packet\n");
X				}
X				rplay_destroy(rp);
X				break;
X
X			case RPLAY_PLAY:
X				if (debug)
X				{
X					report("play sound=%s volume=%d from %s\n",
X						(char *)rplay_get(rp, RPLAY_SOUND, 0),
X						rplay_get(rp, RPLAY_VOLUME, 0),
X						inet_ntoa(f.sin_addr));
X				}
X				rplayd_play(rp, f);
X				break;
X
X			case RPLAY_STOP:
X				if (debug)
X				{
X					report("stop sound=%s volume=%d from %s\n",
X						(char *)rplay_get(rp, RPLAY_SOUND, 0),
X						rplay_get(rp, RPLAY_VOLUME, 0),
X						inet_ntoa(f.sin_addr));
X				}
X				rplayd_stop(rp, f);
X				break;
X
X			case RPLAY_PAUSE:
X				if (debug)
X				{
X					report("pause sound=%s volume=%d from %s\n",
X						(char *)rplay_get(rp, RPLAY_SOUND, 0),
X						rplay_get(rp, RPLAY_VOLUME, 0),
X						inet_ntoa(f.sin_addr));
X				}
X				rplayd_pause(rp, f);
X				break;
X
X			case RPLAY_CONTINUE:
X				if (debug)
X				{
X					report("continue sound=%s volume=%d from %s\n",
X						(char *)rplay_get(rp, RPLAY_SOUND, 0),
X						rplay_get(rp, RPLAY_VOLUME, 0),
X						inet_ntoa(f.sin_addr));
X				}
X				rplayd_continue(rp, f);
X				break;
X			}
X			break;
X				
X		default:
X			if (debug)
X			{
X				report("unknown packet received from %s\n", inet_ntoa(f.sin_addr));
X			}
X			break;
X		}
X	}
}
X
#ifdef __STDC__
int	rplayd_play(RPLAY *rp, struct sockaddr_in sin)
#else
int	rplayd_play(rp, sin)
RPLAY			*rp;
struct sockaddr_in	sin;
#endif
{
X	SPOOL	*sp;
X	int	i, n;
X
X	sp = spool_next(rp->priority);
X	if (!sp)
X	{
X		if (debug)
X		{
X			report("spool full\n");
X		}
X		return -1;
X	}
X	n = 0;
X	for (i = 0; i < rp->nsounds; i++)
X	{
X		sp->sound[i] = sound_lookup((char *)rplay_get(rp, RPLAY_SOUND, i), SOUND_FIND);
X		if (sp->sound[i] == NULL)
X		{
X			rplay_destroy(rp);
X			return -1;
X		}
X		if (sp->sound[i]->status != SOUND_READY)
X		{
X			n++;
X		}
X	}
X
X	sp->rp = rp;
X	sp->curr_attrs = rp->attrs;
X	sp->curr_sound = 0;
X	sp->curr_count = sp->curr_attrs->count;
X	sp->list_count = rp->count;
X	sp->sin = sin;
X
X	if (n)
X	{
X		sp->state = SPOOL_WAIT;
X	}
X	else
X	{
X		sp->ptr = sp->sound[0]->start;
X		sp->end = sp->sound[0]->stop;
X		sp->state = SPOOL_PLAY;
X		spool_size++;
X		spool_setprio();
X	}
X
X	return 0;
}
X
#ifdef __STDC__
int	rplayd_stop(RPLAY *rp, struct sockaddr_in sin)
#else
int	rplayd_stop(rp, sin)
RPLAY			*rp;
struct sockaddr_in	sin;
#endif
{
X	SPOOL	*sp;
X
X	sp = spool_match(rp);
X	if (sp == NULL || sp->state == SPOOL_WAIT)
X	{
X		return -1;
X	}
X
X	sp->sin = sin;
X	rplay_destroy(rp);
X	if (sp)
X	{
X		if (sp->state == SPOOL_PLAY)
X		{
X			spool_size--;
X		}
X		spool_clear(sp);
X		return 0;
X	}
X	else if (debug)
X	{
X		report("stop sound not found\n");
X		return -1;
X	}
}
X
#ifdef __STDC__
int	rplayd_pause(RPLAY *rp, struct sockaddr_in sin)
#else
int	rplayd_pause(rp, sin)
RPLAY			*rp;
struct sockaddr_in	sin;
#endif
{
X	SPOOL	*sp;
X
X	sp = spool_match(rp);
X	if (sp == NULL || sp->state == SPOOL_WAIT)
X	{
X		return -1;
X	}
X
X	sp->sin = sin;
X	rplay_destroy(rp);
X	if (sp)
X	{
X		if (sp->state == SPOOL_PLAY)
X		{
X			spool_size--;		/* sort of remove it from the spool! */
X		}
X		sp->state = SPOOL_PAUSE;
X		return 0;
X	}
X	else if (debug)
X	{
X		report("pause sound not found\n");
X		return -1;
X	}
}
X
#ifdef __STDC__
int	rplayd_continue(RPLAY *rp, struct sockaddr_in sin)
#else
int	rplayd_continue(rp, sin)
RPLAY			*rp;
struct sockaddr_in	sin;
#endif
{
X	SPOOL	*sp;
X
X	sp = spool_match(rp);
X	if (sp == NULL || sp->state == SPOOL_WAIT)
X	{
X		return -1;
X	}
X
X	sp->sin = sin;
X	rplay_destroy(rp);
X	if (sp)
X	{
X		if (sp->state == SPOOL_PAUSE)
X		{
X			spool_size++;		/* put it back in the spool! */
X		}
X		sp->state = SPOOL_PLAY;
X		return 0;
X	}
X	else if (debug)
X	{
X		report("continue sound not found\n");
X		return -1;
X	}
}
X
void	usage()
{
X	printf("\n");
X	printf("%s\n", rplay_version);
X	printf("\n");
X	printf("usage: %s [options]\n", progname);
X	printf("\t-c n    Close %s after n idle seconds, disabled with 0 (%d).\n", AUDIO_DEVICE, audio_timeout);
X	printf("\t-C file Use file for alternate rplay.conf (%s).\n", RPLAY_CONF);
X	printf("\t-d      Debug mode (%s).\n", debug ? "on" : "off");
X	printf("\t-D dir  Use dir for alternate rplay.cache (%s).\n", RPLAY_CACHE);
#ifdef AUTH
X	printf("\t-H file Use file for alternate rplay.hosts (%s).\n", RPLAY_HOSTS);
#endif /* AUTH */
X	printf("\t-n      Disable inetd mode (%s).\n", inetd ? "enabled" : "disabled");
X	printf("\t-s n    Maximum size in bytes of the rplay cache, disabled with 0 (%d).\n", RPLAY_CACHE_SIZE);
X	printf("\t-S file Use file for alternate rplay.servers (%s).\n", RPLAY_SERVERS);
X	printf("\t-t n    Exit after n idle seconds, disabled with 0 (%d).\n", rplayd_timeout);
X	printf("\t-T n    Close idle RPTP connections after n seconds, disabled with 0 (%d).\n", rptp_timeout);
X	printf("\t-v      Print rplay version and exit.\n");
X	printf("\n");
}
X
#ifdef __STDC__
void	done(int exit_value)
#else
void	done(exit_value)
int	exit_value;
#endif
{
X	connection_cleanup();
X	audio_close();
X	close(rplay_fd);
X	close(rptp_fd);
X	if (debug)
X	{
X		report("done(%d)\n", exit_value);
X	}
X	exit(exit_value);
}
X
#ifdef __STDC__
void	report(char *fmt, ...)
#else
void	report(va_alist)
va_dcl
#endif
{
X	va_list	args;
X
#ifdef __STDC__
X	va_start(args, fmt);
#else
X	char	*fmt;
X	va_start(args);
X	fmt = va_arg(args, char *);
#endif
X
X	fprintf(stderr, "%s: ", progname);
X	vfprintf(stderr, fmt, args);
X	va_end(args);
}
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/rplayd.c ||
echo 'restore of rplay-3.1.0/rplayd/rplayd.c failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/rplayd.c'`"
test 12374 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/rplayd.c: original size 12374, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/sound.c ==============
if test -f 'rplay-3.1.0/rplayd/sound.c' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/sound.c (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/sound.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/sound.c' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#include "conf.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#ifdef ultrix
#include <fcntl.h>
#else
#include <sys/fcntl.h>
#endif
#include <sys/param.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "sound.h"
#include "rplayd.h"
#include "cache.h"
#ifdef MMAP
#include <sys/mman.h>
#endif /* MMAP */
#include "ulaw.h"
#include "hash.h"
#include "server.h"
#include "buffer.h"
#include "connection.h"
X
SOUND		*sounds = NULL;
int		sound_count = 0;
X
/*
X * read the rplay configuration file and load the hash table
X */
#ifdef __STDC__
void	sound_read(char *filename)
#else
void	sound_read(filename)
char	*filename;
#endif
{
X	FILE	*fp;
X	char	buf[MAXPATHLEN], *p;
X
X	fp = fopen(filename, "r");
X	if (fp == NULL)
X	{
X		report("warning: cannot open %s\n", filename);
X		/*
X		 * I guess it's ok to not have any local sounds
X		 */
X		return;
X	}
X
X	while (fgets(buf, sizeof(buf), fp) != NULL)
X	{
X		switch (buf[0])
X		{
X		case '#':
X		case ' ':
X		case '\t':
X		case '\n':
X			continue;
X		}
X		p = strchr(buf, '\n');
X		if (p)
X		{
X			*p = '\0';
X		}
X		sound_insert(buf, SOUND_READY);
X	}
X
X	fclose(fp);
}
X
BUFFER	*sound_list_create()
{
X	SOUND	*s;
X	int	n;
X	BUFFER	*start, *b;
X
X	b = buffer_create();
X	start = b;
X	strcat(b->buf, "+sounds\r\n");
X	b->nbytes += strlen(b->buf);
X
X	for (s = sounds; s; s = s->list)
X	{
X		if (s->status != SOUND_READY)
X		{
X			continue;
X		}
X		n = strlen(s->name) + 2;
X		if (b->nbytes + n > BUFFER_SIZE)
X		{
X			b->next = buffer_create();
X			b = b->next;
X		}
X		strcat(b->buf, s->name);
X		strcat(b->buf, "\r\n");
X		b->nbytes += n;
X	}
X
X	if (b->nbytes + 3 > BUFFER_SIZE)
X	{
X		b->next = buffer_create();
X		b = b->next;
X	}
X	strcat(b->buf, ".\r\n");
X	b->nbytes += 3;
X	
X	return start;
}
X
#ifdef __STDC__
SOUND	*sound_insert(char *path, int status)
#else
SOUND	*sound_insert(path, status)
char	*path;
int	status;
#endif
{
X	SOUND	*s;
X	char	*hash_val;
X
X	s = sound_create();
X	if (s == NULL)
X	{
X		report("out of memory\n");
X		done(1);
X	}
X
X	s->path = strdup(path);
X	s->hash_key = strdup(hash_name(s->path));
X	s->name = s->path[0] == '/' ? strrchr(s->path, '/') + 1 : s->path;
X	s->status = status;
X
X	hash_val = hash_get(s->hash_key);
X	if (hash_val == NULL)
X	{
X		hash_put(s->hash_key, (char *)s);
X
X		s->list_prev = NULL;
X		s->list = sounds;
X		if (sounds)
X		{
X			sounds->list_prev = s;
X		}
X		sounds = s;
X	}
X	else
X	{
X		SOUND	*ss, *prev = NULL;
X
X		for (ss = (SOUND *)hash_val; ss; prev = ss, ss = ss->next)
X		{
X			if (strcmp(ss->path, s->path) == 0)
X			{
X				free((char *)s);
X				return ss;
X			}
X		}
X		prev->next = s;
X		s->prev = prev;
X	}
X
X	return s;
}
X
/*
X * create a sound
X */
#ifdef __STDC__
SOUND	*sound_create(void)
#else
SOUND	*sound_create()
#endif
{
X	SOUND	*s;
X
X	s = (SOUND *)malloc(sizeof(SOUND));
X	if (s == NULL)
X	{
X		return s;
X	}
X	s->path = NULL;
X	s->name = NULL;
X	s->hash_key = NULL;
X	s->buf = NULL;
X	s->start = NULL;
X	s->stop = NULL;
X	s->size = 0;
X	s->next = NULL;
X	s->prev = NULL;
X	s->list = NULL;
X	s->list_prev = NULL;
X	s->status = SOUND_NULL;
X	s->count = 0;
X
X	return s;
}
X
/*
X * lookup the sound name in the hash table and load
X * the sound file if necessary
X */
#ifdef __STDC__
SOUND	*sound_lookup(char *name, int mode)
#else
SOUND	*sound_lookup(name, mode)
char	*name;
int	mode;
#endif
{
X	SOUND		*s;
X	int		has_extension = 0, has_pathname = 0;
X	struct stat	st;
X	
X	s = (SOUND *)hash_get(hash_name(name));
X	if (s == NULL)
X	{
X		if (debug)
X		{
X			report("%s not found\n", name);
X		}
X		
X		if (mode == SOUND_DONT_FIND || mode == SOUND_DONT_COUNT)
X		{
X			return NULL;
X		}
X		
X		/*
X		 * see if a local file can be loaded
X		 */
X		if (stat(name, &st) == 0)
X		{
X			if (debug)
X			{
X				report("loading local file %s\n", name);
X			}
X			s = sound_insert(name, SOUND_READY);
X		}
X		else if (mode == SOUND_FIND)
X		{
X			if (name[0] == '/')
X			{
X				if (debug)
X				{
X					report("not searching for %s\n", name);
X				}
X				return NULL;
X			}
X			if (servers)
X			{
X				if (debug)
X				{
X					report("searching for %s\n", name);
X				}
X				s = sound_insert(cache_name(name), SOUND_SEARCH);
X				connection_server_open(servers, s);
X			}
X			else
X			{
X				return NULL;
X			}
X		}
X	}
X	else
X	{
X		/*
X	 	 * make sure the sound found has the correct path
X	 	 * and dot extension
X	 	 */
X		if (name[0] == '/')
X		{
X			has_pathname++;
X		}
X		else if (strrchr(name, '.'))
X		{
X			has_extension++;
X		}
X		for (; s; s = s->next)
X		{
X			if (has_pathname && strcmp(name, s->path))
X			{
X				continue;
X			}
X			if (has_extension && strcmp(name, s->name))
X			{
X				continue;
X			}
X			break;
X		}
X		if (s == NULL)
X		{
X			if (has_pathname)
X			{
X				report("pathname %s not in hash table\n", name);
X				if (stat(name, &st) == 0)
X				{
X					if (debug)
X					{
X						report("loading local file %s\n", name);
X					}
X					s = sound_insert(name, SOUND_READY);
X				}
X				else
X				{
X					return NULL;
X				}
X			}
X			else if (has_extension)
X			{
X				report("sound with extension %s not in hash table\n", name);
X				return NULL;
X			}
X		}
X	}
X	
X	if (mode == SOUND_DONT_COUNT)
X	{
X		return s;
X	}
X	else
X	{
X		sound_count++;
X		s->count = sound_count;
X	}
X
X	switch (s->status)
X	{
X	case SOUND_NOT_READY:
X	case SOUND_SEARCH:
X		return s;
X	}
X
X	if (s->buf == NULL)
X	{
X		return sound_load(s) == 0 ? s : NULL;
X	}
X	else
X	{
X		return s;
X	}
}
X
/*
X * load the sound using mmap or malloc
X */
#ifdef __STDC__
int	sound_load(SOUND *s)
#else
int	sound_load(s)
SOUND	*s;
#endif
{
X	int		fd;
X	struct stat	st;
X	char		*buf;
#ifndef MMAP
X	int		n;
#endif /* MMAP */
X
X	if (s->buf != NULL)
X	{
X		return 0;
X	}
X
X	fd = open(s->path, O_RDONLY, 0);
X	if (fd < 0)
X	{
X		if (debug)
X		{
X			report("open %s: %s\n", s->path, sys_errlist[errno]);
X		}
X		return -1;
X	}
X
X	if (fstat(fd, &st) < 0)
X	{
X		if (debug)
X		{
X			report("fstat %s: %s\n", s->path, sys_errlist[errno]);
X		}
X		return -1;
X	}
X
#ifdef MMAP
X	buf = mmap(0, (int)st.st_size, PROT_READ, MAP_SHARED, fd, 0);
X	if (buf == (caddr_t)-1)
X	{
X		if (debug)
X		{
X			report("file=%s size=%s mmap: %s\n", s->path, st.st_size, sys_errlist[errno]);
X		}
X		return -1;
X	}
#else /* MMAP */
X	buf = (char *)malloc((int)st.st_size);
X	if (buf == NULL)
X	{
X		report("out of memory\n");
X		done(1);
X	}
X	n = read(fd, buf, st.st_size);
X	if (n != st.st_size)
X	{
X		if (debug)
X		{
X			report("read %s (%d): %s\n", s->path, st.st_size, sys_errlist[errno]);
X		}
X		return -1;
X	}
#endif /* MMAP */
X
X	close(fd);
X	
X	return sound_map(s, buf, (int)st.st_size);
}
X
#ifdef __STDC__
void	sound_unmap(SOUND *s)
#else
void	sound_unmap(s)
SOUND	*s;
#endif
{
X	if (s->buf)
X	{
#ifdef MMAP
X		if (munmap(s->buf, s->size) < 0)
X		{
X			report("munmap: %s\n", sys_errlist[errno]);
X			done(1);
X		}
#else /* MMAP */
X		free(s->buf);
#endif /* MMAP */
X	}
X
X	s->buf = NULL;
X	s->size = 0;
}
X
#ifdef __STDC__
int	sound_map(SOUND *s, char *buf, int size)
#else
int	sound_map(s, buf, size)
SOUND	*s;
char	*buf;
int	size;
#endif
{
X	long	ulaw_hdr_size;
X	char	*p;
X
X	s->buf = buf;
X	s->size = size;
X	
X	/*
X	 * make sure it is a ulaw audio file
X	 */
X	if (PORTABLE_LONG(s->buf) != ULAW_MAGIC)
X	{
X		if (debug)
X		{
X			report("%s no ulaw header\n", s->path);
X		}
X		p = strrchr(s->path, '.');
X		if (!p || strcmp(p, ".au") && strcmp(p, ".u") && strcmp(p, ".ul"))
X		{
X			if (debug)
X			{
X				report("%s no sound extension\n", s->path);
X			}
X			return -1;
X		}
X		ulaw_hdr_size = 0;
X	}
X	else
X	{
X		/*
X		 * ignore most of the header
X		 */
X		ulaw_hdr_size = PORTABLE_LONG(&s->buf[4]);
X		if (ulaw_hdr_size < ULAW_HDRSIZE)
X		{
X			if (debug)
X			{
X				report("%s not a ulaw file\n", s->path);
X			}
X			return -1;
X		}
X	}
X
X	s->start = s->buf + ulaw_hdr_size;
X	s->stop = s->buf + s->size - 1;
X
X	return 0;
}
X
#ifdef __STDC__
void	sound_delete(SOUND *s)
#else
void	sound_delete(s)
SOUND	*s;
#endif
{
X	sound_unmap(s);
X
X	if (s->next == NULL)
X	{
X		hash_delete(s->hash_key);
X		if (s->list_prev)
X		{
X			s->list_prev->list = s->list;
X		}
X		else
X		{
X			sounds = s->list;
X		}
X		if (s->list)
X		{
X			s->list->list_prev = s->list_prev;
X		}
X	}
X	else
X	{
X		if (s->prev)
X		{
X			s->prev->next = s->next;
X			if (s->next)
X			{
X				s->next->prev = s->prev;
X			}
X		}
X		else if (s->next)
X		{
X			if (s->list_prev)
X			{
X				s->list_prev->list = s->next;
X			}
X			if (s->list)
X			{
X				s->list->list_prev = s->next;
X			}
X			hash_put(s->next->hash_key, (char *)s->next);
X		}
X		else
X		{
X			if (s->list_prev)
X			{
X				s->list_prev->list = s->list;
X			}
X			if (s->list)
X			{
X				s->list->list_prev = s->list_prev;
X			}
X		}
X	}
X
X	if (unlink(s->path) < 0)
X	{
X		if (debug)
X		{
X			report("sound_delete: unlink %s: %s\n", s->path,
X				sys_errlist[errno]);
X		}
X	}
X
X	free((char *)s);
}
X
/*
X * free memory used by all sounds except the ones that have
X * events associated with them
X */
void	sound_cleanup()
{
X	SOUND		*s1, *s2;
X	EVENT		*e;
X	CONNECTION	*c;
X	int		n;
X
X	if (debug)
X	{
X		report("cleaning up sounds\n");
X	}
X	
X	for (s1 = sounds; s1; s1 = s1->list)
X	{
X		for (s2 = s1; s2; s2 = s2->next)
X		{
X			if (s2->status == SOUND_READY && s2->buf)
X			{	
X				n = 0;
X				for (c = connections; c && n == 0; c = c->next)
X				{
X					for (e = c->event; e && n == 0; e = e->next)
X					{
X						switch (e->type)
X						{
X						case EVENT_WRITE_FIND:
X						case EVENT_READ_FIND_REPLY:
X						case EVENT_WRITE_GET:
X						case EVENT_READ_GET_REPLY:
X						case EVENT_READ_SOUND:
X						case EVENT_WRITE_SOUND:
X							if (e->sound == s2)
X							{
X								n++;
X							}
X							break;
X						}
X					}
X				}
X				if (n == 0)
X				{
X					sound_unmap(s2);
X				}
X			}
X		}
X	}
}
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/sound.c ||
echo 'restore of rplay-3.1.0/rplayd/sound.c failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/sound.c'`"
test 10104 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/sound.c: original size 10104, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/spool.c ==============
if test -f 'rplay-3.1.0/rplayd/spool.c' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/spool.c (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/spool.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/spool.c' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#include "conf.h"
#include <stdio.h>
#include <string.h>
#include "rplayd.h"
#include "rplay.h"
#include "spool.h"
#include "sound.h"
#include "buffer.h"
X
#undef MAX
#define MAX(a,b)	((a)>(b)?(a):(b))
X
int	spool_size = 0;
int	spool_prio = 0;
SPOOL	spool[SPOOL_SIZE];
X
/*
X * initialize the sound spool
X */
void	spool_init()
{
X	int	i;
X
X	 for(i = 0; i < SPOOL_SIZE; i++)
X	 { 
X		 spool_clear(&spool[i]);
X	 }
}
X
/*
X * return the next available spool entry
X * 
X * 'priority' is the priority of a new sound and it is used to replace
X * lower priority spool entries if the spool is full.
X */
#ifdef __STDC__
SPOOL	*spool_next(int priority)
#else
SPOOL	*spool_next(priority)
int	priority;
#endif
{
X	int	i;
X	int	min_priority = RPLAY_MAX_PRIORITY, index = -1;
X
X	for (i = 0; i < SPOOL_SIZE; i++)
X	{
X		if (spool[i].state == SPOOL_NULL)
X		{
X			return &spool[i];
X		}
X		else if (spool[i].rp->priority < min_priority)
X		{
X			min_priority = spool[i].rp->priority;
X			index = i;
X		}
X	}
X
X	/*
X	 * replace a spool entry with a lower priority if possible
X	 */
X	if (priority > min_priority && index >= 0)
X	{
X		if (debug)
X		{
X			report("spool[%d] priority %d replaced with priority %d\n", index, min_priority, priority);
X		}
X		spool_clear(&spool[index]);
X		spool_size--;
X		return &spool[index];
X	}
X	else
X	{
X		return NULL;
X	}
}
X
#ifdef __STDC__
void	spool_clear(SPOOL *sp)
#else
void	spool_clear(sp)
SPOOL	*sp;
#endif
{
X	sp->curr_sound = 0;
X	sp->curr_count = 0;
X	sp->list_count = 0;
X	if (sp->rp)
X	{
X		rplay_destroy(sp->rp);
X	}
X	sp->rp = NULL;
X	sp->ptr = NULL;
X	sp->end = NULL;
X	sp->state = SPOOL_NULL;
X	spool_setprio();
}
X
#ifdef __STDC__
void	spool_setprio(void)
#else
void	spool_setprio()
#endif
{
X	int	i;
X
X	spool_prio = 0;
X	for (i = 0; i < SPOOL_SIZE; i++)
X	{
X		if (spool[i].state == SPOOL_PLAY)
X		{
X			spool_prio = MAX(spool_prio, spool[i].rp->priority);
X		}
X	}
#ifdef DEBUG
X	printf("spool_prio=%d\n", spool_prio);
#endif
}
X
/*
X * find the given RPLAY object in the spool
X */
#ifdef __STDC__
SPOOL	*spool_match(RPLAY *match)
#else
SPOOL	*spool_match(match)
RPLAY	*match;
#endif
{
X	int		i;
X	RPLAY		*rp;
X	RPLAY_ATTRS	*a1, *a2;
X
X	for (i = 0; i < SPOOL_SIZE; i++)
X	{
X		if (spool[i].state == SPOOL_NULL)
X		{
X			continue;
X		}
X
X		rp = spool[i].rp;
X		if (rp->nsounds == match->nsounds && rp->count == match->count && rp->priority == match->priority)
X		{
X			for (a1 = rp->attrs, a2 = match->attrs; a1 && a2; a1 = a1->next, a2 = a2->next)
X			{
X				if (strcmp(a1->sound, a2->sound))
X				{
X					break;
X				}
X				if (a1->volume != a2->volume)
X				{
X					break;
X				}
X				if (a1->count != a2->count)
X				{
X					break;
X				}
X			}
X			if (!a1 && !a2)
X			{
X				return &spool[i];
X			}
X		}
X	}
X
X	return NULL;
}
X
#ifdef __STDC__
void	spool_remove(SOUND *sound)
#else
void	spool_remove(sound)
SOUND	*sound;
#endif
{
X	int	i, j, n;
X
X	for (i = 0; i < SPOOL_SIZE; i++)
X	{
X		if (spool[i].state == SPOOL_NULL)
X		{
X			continue;
X		}
X		n = 0;
X		for (j = 0; j < spool[i].rp->nsounds; j++)
X		{
X			if (spool[i].sound[j] == sound)
X			{
X				n++;
X			}
X		}
X		if (n)
X		{
X			if (spool[i].state == SPOOL_PLAY)
X			{
X				spool_size--;
X			}
X			spool_clear(&spool[i]);
X		}
X	}
}
X
/*
X * make all spool entries waiting for this sound ready
X */
#ifdef __STDC__
void	spool_ready(SOUND *sound)
#else
void	spool_ready(sound)
SOUND	*sound;
#endif
{
X	int	i, j, n;
X
X	for (i = 0; i < SPOOL_SIZE; i++)
X	{
X		if (spool[i].state == SPOOL_WAIT)
X		{
X			n = 0;
X			for (j = 0; j < spool[i].rp->nsounds; j++)
X			{
X				if (spool[i].sound[j]->status != SOUND_READY)
X				{
X					n++;
X					if (spool[i].sound[j] == sound)
X					{
X						n--;
X					}
X				}
X			}
X			if (n == 0)
X			{
X				for (j = 0; j < spool[i].rp->nsounds; j++)
X				{
X					sound_load(spool[i].sound[j]);
X				}
X				spool[i].ptr = spool[i].sound[0]->start;
X				spool[i].end = spool[i].sound[0]->stop;
X				spool[i].state = SPOOL_PLAY;
X				spool_size++;
X				spool_setprio();
X			}
X		}
X	}
}
X
BUFFER	*spool_list_create()
{
X	BUFFER	*spool_list, *b;
X	int	i, n;
X	char	buf[RPTP_MAX_LINE];
X	SOUND	*s;
X	
X	b = buffer_create();
X	spool_list = b;
X	sprintf(b->buf, "+spool\r\nHOST            STATE  VOL PRI SECONDS REMAIN SOUND\r\n");
X	b->nbytes += strlen(b->buf);
X
X	for (i = 0; i < SPOOL_SIZE; i++)
X	{
X		sprintf(buf, "%-15s ", inet_ntoa(spool[i].sin.sin_addr));
X		switch (spool[i].state)
X		{
X		case SPOOL_PLAY:
X			strcat(buf, "play   ");
X			break;
X			
X		case SPOOL_PAUSE:
X			strcat(buf, "pause  ");
X			break;
X			
X		case SPOOL_WAIT:
X			strcat(buf, "(wait) ");
X			break;
X			
X		default:
X			continue;
X		}
X
X		s = spool[i].sound[spool[i].curr_sound];
X		
X		sprintf(buf+23, "%3d %3d %7d %6d %s\r\n",
X			spool[i].curr_attrs->volume,
X			spool[i].rp->priority,
X			s->size / 8000,
X			(spool[i].end - spool[i].ptr) / 8000,
X			s->name);
X
X		n = strlen(buf);
X		if (b->nbytes + n > BUFFER_SIZE)
X		{
X			b->next = buffer_create();
X			b = b->next;
X		}
X		strcat(b->buf, buf);
X		b->nbytes += n;
X	}
X
X	if (b->nbytes + 3 > BUFFER_SIZE)
X	{
X		b->next = buffer_create();
X		b = b->next;
X	}
X	strcat(b->buf, ".\r\n");
X	b->nbytes += 3;
X	
X	return spool_list;
}
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/spool.c ||
echo 'restore of rplay-3.1.0/rplayd/spool.c failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/spool.c'`"
test 5774 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/spool.c: original size 5774, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/audio.h ==============
if test -f 'rplay-3.1.0/rplayd/audio.h' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/audio.h (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/audio.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/audio.h' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#ifndef _audio_h
#define _audio_h
X
#include "conf.h"
X
#define AUDIO_BUFSIZE	8000		/* size of the audio buffer */
X
extern void	audio_open();
extern void	audio_close();
extern void	audio_write();
extern void	audio_init();
X
extern int	audio_timeout;
X
#endif /* _audio_h */
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/audio.h ||
echo 'restore of rplay-3.1.0/rplayd/audio.h failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/audio.h'`"
test 1063 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/audio.h: original size 1063, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/command.h ==============
if test -f 'rplay-3.1.0/rplayd/command.h' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/command.h (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/command.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/command.h' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#ifndef _command_h
#define _command_h
X
#include "conf.h"
#include "connection.h"
X
typedef struct
{
X	char	*name;
X	int	min_args;
X	int	max_args;
X	char	*usage;
#ifdef __STDC__
X	int	(*func)(CONNECTION *c, int argc, char **argv);
#else
X	int	(*func)(/* CONNECTION *c, int argc, char **argv */);
#endif
} COMMAND;
X
#ifdef __STDC__
extern int	command(CONNECTION *c, char *buf);
extern int	command_quit(CONNECTION *c, int argc, char **argv);
extern int	command_unknown(CONNECTION *c, int argc, char **argv);
extern int	command_help(CONNECTION *c, int argc, char **argv);
extern int	command_get(CONNECTION *c, int argc, char **argv);
extern int	command_put(CONNECTION *c, int argc, char **argv);
extern int	command_list(CONNECTION *c, int argc, char **argv);
extern int	command_find(CONNECTION *c, int argc, char **argv);
extern int	command_play(CONNECTION *c, int argc, char **argv);
extern int	command_access(CONNECTION *c, int argc, char **argv);
#else
extern int	command(/* CONNECTION *c, char *buf */);
extern int	command_quit(/* CONNECTION *c, int argc, char **argv */);
extern int	command_unknown(/* CONNECTION *c, int argc, char **argv */);
extern int	command_help(/* CONNECTION *c, int argc, char **argv */);
extern int	command_get(/* CONNECTION *c, int argc, char **argv */);
extern int	command_put(/* CONNECTION *c, int argc, char **argv */);
extern int	command_list(/* CONNECTION *c, int argc, char **argv */);
extern int	command_find(/* CONNECTION *c, int argc, char **argv */);
extern int	command_play(/* CONNECTION *c, int argc, char **argv */);
extern int	command_access(/* CONNECTION *c, int argc, char **argv */);
#endif
X
#endif /* _command_h */
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/command.h ||
echo 'restore of rplay-3.1.0/rplayd/command.h failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/command.h'`"
test 2446 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/command.h: original size 2446, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/hash.h ==============
if test -f 'rplay-3.1.0/rplayd/hash.h' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/hash.h (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/hash.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/hash.h' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#ifndef _hash_h
#define _hash_h
X
#include "conf.h"
X
#ifdef __STDC__
extern void	hash_init(int hash_table_size);
extern char	*hash_get(char *hash_key);
extern void	hash_put(char *hash_key, char *data);
extern void	hash_delete(char *hash_key);
extern char	*hash_name(char *pathname);
#else
extern void	hash_init(/* int hash_table_size */);
extern char	*hash_get(/* char *hash_key */);
extern void	hash_put(/* char *hash_key, char *data */);
extern void	hash_delete(/* char *hash_key */);
extern char	*hash_name(/* char *pathname */);
#endif
X
#endif /* _hash_h */
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/hash.h ||
echo 'restore of rplay-3.1.0/rplayd/hash.h failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/hash.h'`"
test 1354 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/hash.h: original size 1354, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/rplayd.h ==============
if test -f 'rplay-3.1.0/rplayd/rplayd.h' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/rplayd.h (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/rplayd.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/rplayd.h' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#ifndef _rplayd_h
#define _rplayd_h
X
#include "conf.h"
#include <rplay.h>
#include "misc.h"
X
extern int	spool_size;
extern fd_set	read_mask;
extern fd_set	write_mask;
extern int	debug;
extern int	inetd;
extern int	rptp_timeout;
extern char	hostname[];
extern int	rplay_fd;
extern int	rptp_fd;
extern int	errno;
extern char	*sys_errlist[];
X
#ifdef __STDC__
extern void		usage();
extern void		done(int exit_value);
extern unsigned long	inet_addr(char *);
extern char		*inet_ntoa(struct in_addr);
extern void		report(char *fmt, ...);
extern void		rplayd_read();
extern void		rplayd_init();
extern int		rplayd_play(RPLAY *rp, struct sockaddr_in sin);
extern int		rplayd_stop(RPLAY *rp, struct sockaddr_in sin);
extern int		rplayd_pause(RPLAY *rp, struct sockaddr_in sin);
extern int		rplayd_continue(RPLAY *rp, struct sockaddr_in sin);
#else
extern void		usage();
extern void		done(/* int exit_value */);
extern unsigned long	inet_addr(/* char * */);
extern char		*inet_ntoa(/* struct in_addr */);
extern void		report(/* char *fmt, ... */);
extern void		rplayd_read();
extern void		rplayd_init();
extern int		rplayd_play(/* RPLAY *rp, struct sockaddr_in sin */);
extern int		rplayd_stop(/* RPLAY *rp, struct sockaddr_in sin */);
extern int		rplayd_pause(/* RPLAY *rp, struct sockaddr_in sin */);
extern int		rplayd_continue(/* RPLAY *rp, struct sockaddr_in sin */);
#endif
X
#endif /* _rplayd_h */
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/rplayd.h ||
echo 'restore of rplay-3.1.0/rplayd/rplayd.h failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/rplayd.h'`"
test 2186 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/rplayd.h: original size 2186, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/server.c ==============
if test -f 'rplay-3.1.0/rplayd/server.c' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/server.c (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/server.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/server.c' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#include "conf.h"
#include "rplay.h"
#include <sys/param.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include "rplayd.h"
#include "server.h"
#include "connection.h"
#include "buffer.h"
X
BUFFER	*server_list = NULL;
SERVER	*servers = NULL;
X
#ifdef __STDC__
void	server_read(char *filename)
#else
void	server_read(filename)
char	*filename;
#endif
{
X	FILE			*fp;
X	char			buf[BUFSIZ], *p;
X	char			name[MAXHOSTNAMELEN+6];
X	struct hostent		*hp, *local_hp;
X	unsigned long		addr, local_addr;
X	struct sockaddr_in	sin;
X	int			port, n;
X	SERVER			**s = &servers;
X	BUFFER			*b;
X
X	fp = fopen(filename, "r");
X	if (fp == NULL)
X	{
X		/*
X		 * I guess it's ok to not have any servers
X		 */
X		report("warning: cannot open %s\n", filename);
X		return;
X	}
X
X	local_hp = gethostbyname(hostname);
X	if (local_hp == NULL)
X	{
X		report("%s unknown host?!\n", hostname);
X		done(1);
X
X	}
X	memcpy((char *)&local_addr, (char *)local_hp->h_addr, local_hp->h_length);
X	
X	b = buffer_create();
X	strcpy(b->buf, "+servers\r\n");
X	b->nbytes += strlen(b->buf);
X	b->status = BUFFER_KEEP;
X	server_list = b;
X
X	while (fgets(buf, sizeof(buf), fp))
X	{
X		switch (buf[0])
X		{
X		case '#':
X		case ' ':
X		case '\t':
X		case '\n':
X			continue;
X		}
X
X		p = strchr(buf, '\n');
X		*p = '\0';
X		p = strchr(buf, ':');
X		if (p)
X		{
X			*p = '\0';
X			port = atoi(p+1);
X		}
X		else
X		{
X			port = RPTP_PORT;
X		}
X		addr = inet_addr(buf);
X		memset((char *)&sin, 0, sizeof(sin));
X		if (addr == 0xffffffff)
X		{
X			hp = gethostbyname(buf);
X			if (hp == NULL)
X			{
X				report("%s unknown host in %s\n", buf, filename);
X				done(1);
X			}
X			memcpy((char *)&sin.sin_addr.s_addr, (char *)hp->h_addr, hp->h_length);
X		}
X		else
X		{
X			memcpy((char *)&sin.sin_addr.s_addr, (char *)&addr, sizeof(addr));
X		}
X
X		if (memcmp((char *)&sin.sin_addr.s_addr, (char *)&local_addr, sizeof(local_addr)) == 0)
X		{
X			/*
X			 * ignore the server if it's the local host
X			 */
X			continue;
X		}
X		
X		*s = (SERVER *)malloc(sizeof(SERVER));
X		if (*s == NULL)
X		{
X			report("out of memory\n");
X			done(1);
X		}
X		sin.sin_family = AF_INET;
X		sin.sin_port = htons(port);
X
X		sprintf(name, "%s:%d\r\n", buf, port);
X		n = strlen(name);
X
X		if (b->nbytes + n > BUFFER_SIZE)
X		{
X			b->next = buffer_create();
X			b = b->next;
X			b->status = BUFFER_KEEP;
X		}
X		strcat(b->buf, name);
X		b->nbytes += n;
X
X		(*s)->sin = sin;
X		s = &(*s)->next;
X
X		if (debug)
X		{
X			report("server: %s port %d\n", inet_ntoa(sin.sin_addr), port);
X		}
X	}
X
X	*s = NULL;
X	fclose(fp);
X
X	if (b->nbytes + 3 > BUFFER_SIZE)
X	{
X		b->next = buffer_create();
X		b = b->next;
X		b->status = BUFFER_KEEP;
X	}
X	strcat(b->buf, ".\r\n");
X	b->nbytes += 3;
}
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/server.c ||
echo 'restore of rplay-3.1.0/rplayd/server.c failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/server.c'`"
test 3412 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/server.c: original size 3412, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/sound.h ==============
if test -f 'rplay-3.1.0/rplayd/sound.h' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/sound.h (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/sound.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/sound.h' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#ifndef _sound_h
#define _sound_h
X
#include "conf.h"
#include "buffer.h"
X
#define SOUND_LIST_SIZE	256	/* maximum size of a sound list */
X
/*
X * sound status values
X */
#define SOUND_NULL	0
#define SOUND_READY	1	/* sound is ready to be played */
#define SOUND_NOT_READY	2	/* sound is being transferred */
#define SOUND_SEARCH	3	/* sound is searched for */
X
/*
X * sound lookup modes
X */
#define SOUND_FIND		1
#define SOUND_DONT_FIND		2
#define SOUND_DONT_COUNT	3
X
typedef struct _sound
{
X	struct _sound	*list;		/* next pointer for entire sound list */
X	struct _sound	*list_prev;	/* prev pointer for entire sound list */
X	struct _sound	*next;		/* list for sounds with the same hash key */
X	struct _sound	*prev;		/* prev pointer for the next list */
X	char		*name;
X	char		*hash_key;
X	char		*path;
X	char		*buf;
X	char		*start;
X	char		*stop;
X	int		size;
X	int		status;
X	int		count;
} SOUND;
X
extern SOUND	*sounds;
extern int	sound_count;
extern BUFFER	*sound_list;
X
#ifdef __STDC__
extern void	sound_read(char *filename);
extern SOUND	*sound_lookup(char *sound_name, int mode);
extern SOUND	*sound_create();
extern SOUND	*sound_insert(char *, int);
extern int	sound_load(SOUND *s);
extern void	sound_delete(SOUND *s);
extern int	sound_map(SOUND *s, char *buf, int size);
extern BUFFER	*sound_list_create();
extern void	sound_unmap(SOUND *s);
extern void	sound_cleanup();
#else
extern void	sound_read(/* char *filename */);
extern SOUND	*sound_lookup(/* char *sound_name, int mode */);
extern SOUND	*sound_create();
extern SOUND	*sound_insert(/* char *, int */);
extern int	sound_load(/* SOUND *s */);
extern void	sound_delete(/* SOUND *s */);
extern int	sound_map(/* SOUND *s, char *buf, int size */);
extern BUFFER	*sound_list_create();
extern void	sound_unmap(/* SOUND *s */);
extern void	sound_cleanup();
#endif
X
#endif /* _sound_h */
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/sound.h ||
echo 'restore of rplay-3.1.0/rplayd/sound.h failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/sound.h'`"
test 2622 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/sound.h: original size 2622, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/spool.h ==============
if test -f 'rplay-3.1.0/rplayd/spool.h' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/spool.h (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/spool.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/spool.h' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#ifndef _spool_h
#define _spool_h
X
#include "conf.h"
#include "rplay.h"
#include "sound.h"
#include "buffer.h"
X
#define SPOOL_NULL	0
#define SPOOL_PLAY	1
#define SPOOL_PAUSE	2
#define SPOOL_WAIT	3
X
typedef struct _spool
{
X	int			state;
X	int			curr_sound;
X	int			curr_count;
X	int			list_count;
X	SOUND			*sound[SOUND_LIST_SIZE];
X	char			*ptr;
X	char			*end;
X	RPLAY			*rp;
X	RPLAY_ATTRS		*curr_attrs;
X	struct sockaddr_in	sin;
} SPOOL;
X
extern SPOOL	spool[SPOOL_SIZE];
extern int	spool_size;
extern int	spool_prio;
X
#ifdef __STDC__
extern void	spool_init();
extern SPOOL	*spool_match(RPLAY *);
extern SPOOL	*spool_next(int priority);
extern void	spool_ready(SOUND *sound);
extern void	spool_remove(SOUND *sound);
extern BUFFER	*spool_list_create();
extern void	spool_clear(SPOOL *sp);
extern void	spool_setprio(void);
#else
extern void	spool_init();
extern SPOOL	*spool_match(/* RPLAY * */);
extern SPOOL	*spool_next(/* int priority */);
extern void	spool_ready(/* SOUND *sound */);
extern void	spool_remove(/* SOUND *sound */);
extern BUFFER	*spool_list_create();
extern void	spool_clear(/* SPOOL *sp */);
extern void	spool_setprio();
#endif
X
#endif /* _spool_h */
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/spool.h ||
echo 'restore of rplay-3.1.0/rplayd/spool.h failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/spool.h'`"
test 1953 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/spool.h: original size 1953, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/Makefile ==============
if test -f 'rplay-3.1.0/rplayd/Makefile' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/Makefile (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/Makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/Makefile' &&
# 
# Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
#
# This file is part of rplay.
#
# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
#
X
include ../Makefile.config
X
TARGET=		rplayd
X
SRCS=		audio.c buffer.c cache.c command.c connection.c hash.c host.c \
X		misc.c regex.c rplayd.c search.c server.c sound.c spool.c ulaw.c
X
OBJS=		audio.o buffer.o cache.o command.o connection.o hash.o host.o \
X		misc.o regex.o rplayd.o search.o server.o sound.o spool.o ulaw.o
X
all:		$(TARGET)
X
$(TARGET):	$(OBJS) $(LIBRPLAY_DIR)/$(LIBRPLAY_NAME)
X		$(CC) $(CFLAGS) -o $@ $(OBJS) $(LDFLAGS)
X
install:	$(TARGET)
X		$(BIN_INSTALL) $(TARGET) $(INSTALL_BIN_DIR)
X
clean:
X		$(RM) $(TARGET) $(OBJS) core a.out *~ *.bak *.orig
X
depend:
X		$(MAKEDEPEND) -- $(CFLAGS) -- $(SRCS)
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/Makefile ||
echo 'restore of rplay-3.1.0/rplayd/Makefile failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/Makefile'`"
test 1384 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/Makefile: original size 1384, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/cache.c ==============
if test -f 'rplay-3.1.0/rplayd/cache.c' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/cache.c (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/cache.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/cache.c' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#include "conf.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/file.h>
#ifdef ultrix
#include <fcntl.h>
#else
#include <sys/fcntl.h>
#endif
#include <sys/mman.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include "rplayd.h"
#include "version.h"
#include "sound.h"
#include "spool.h"
#include "cache.h"
X
#undef MIN
#define MIN(a,b)   ((a)<(b)?(a):(b))
X
static DIR	*cache_dir;
static char	cache_path[MAXPATHLEN];
static char	cache_directory[MAXPATHLEN];
X
int		cache_max_size = RPLAY_CACHE_SIZE;
X
/*
X * initialize the cache
X */
#ifdef __STDC__
void	cache_init(char *dir_name)
#else
void	cache_init(dir_name)
char	*dir_name;
#endif
{
X	struct stat	st;
X
X	strcpy(cache_directory, dir_name);
X	if (stat(cache_directory, &st) < 0)
X	{
X		if (debug)
X		{
X			report("creating cache directory '%s'\n", cache_directory);
X		}
X		if (mkdir(cache_directory, 0755) < 0)
X		{
X			if (debug)
X			{
X				report("cannot create cache directory '%s'\n", cache_directory);
X			}
X		}
X	}
X	else if (!S_ISDIR(st.st_mode))
X	{
X		report("%s not a directory\n", cache_directory);
X		done(1);
X	}
}
X
/*
X * return the name of the first cache entry
X */
char	*cache_first()
{
X	if (cache_dir)
X	{
X		rewinddir(cache_dir);
X	}
X	else
X	{
X		cache_dir = opendir(cache_directory);
X		if (cache_dir == NULL)
X		{
X			if (debug)
X			{
X				report("opendir %s: %s\n", cache_directory, sys_errlist[errno]);
X			}
X			return NULL;
X		}
X	}
X
X	return cache_next();
}
X
/*
X * return the name of the next cache entry
X */
char	*cache_next()
{
X	struct dirent	*dp;
X
X	do
X	{
X		dp = readdir(cache_dir);
X		if (dp == NULL)
X		{
X			closedir(cache_dir);
X			cache_dir = NULL;
X			return "";
X		}
X	}
X	while (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0);
X
X	sprintf(cache_path, "%s/%s", cache_directory, dp->d_name);
X
X	return cache_path;
}
X
/*
X * calculate the size of the cache
X */
int	cache_size()
{
X	struct stat	st;
X	int		size = 0;
X	char		*file;
X
X	for (file = cache_first(); file && *file; file = cache_next())
X	{
X		if (stat(file, &st) < 0)
X		{
X			report("stat %s: %s\n", file, sys_errlist[errno]);
X			return -1;
X		}
X		size += (int)st.st_size;
X	}
X
X	return (int)size;
}
X
/*
X * load files that are already in the cache
X */
void	cache_read()
{
X	char	*file;
X
X	for (file = cache_first(); file && *file; file = cache_next())
X	{
X		sound_insert(file, SOUND_READY);
X	}
}
X
/*
X * prepend the cache path to the sound
X *
X * this returns static data!
X */
#ifdef __STDC__
char	*cache_name(char *sound)
#else
char	*cache_name(sound)
char	*sound;
#endif
{
X	static char	_cache_path[MAXPATHLEN];
X	
X	sprintf(_cache_path, "%s/%s", cache_directory, sound);
X
X	return _cache_path;
}
X
/*
X * free enough space in the cache for size bytes
X */
#ifdef __STDC__
int	cache_free(int size)
#else
int	cache_free(size)
int	size;
#endif
{
X	int		curr_size, limit;
X	char		*file;
X	SOUND		*s;
X	struct stat	st;
X	int		n;
X
X	if (cache_max_size == 0)
X	{
X		return 0;
X	}
X
X	if (size > cache_max_size)
X	{
X		if (debug)
X		{
X			report("%d bytes cannot fit in the cache\n", size);
X		}
X		return -1;
X	}
X	
X	curr_size = cache_size();
X
X	if (debug)
X	{
X		report("sound_count = %d, current cache size = %d bytes\n",
X			sound_count, curr_size);
X	}
X
X	if (size + curr_size <= cache_max_size)
X	{
X		return 0;
X	}
X
X	/*
X	 * set the initial limit
X	 */
X	limit = sound_count / 2;
X
X	for (;;) 
X	{
X		if (debug)
X		{
X			report("removing cache entries (limit = %d)\n", limit);
X		}
X
X		for (file = cache_first(); file && *file; file = cache_next())
X		{
X			s = sound_lookup(file, SOUND_DONT_COUNT);
X			if (s == NULL || s->status != SOUND_READY)
X			{
X				continue;
X			}
X			if (s->count < limit)
X			{
X				if (stat(file, &st) < 0)
X				{
X					if (debug)
X					{
X						report("stat %s: %s\n", file, sys_errlist[errno]);
X					}
X					continue;
X				}
X				curr_size -= (int)st.st_size;
X				spool_remove(s);
X				sound_delete(s);
X				if (debug)
X				{
X					report("removed %s size=%d count=%d\n", file, st.st_size, s->count);
X				}
X			}
X		}
X
X		if (size + curr_size <= cache_max_size)
X		{
X			break;
X		}
X		else if (limit == sound_count)
X		{
X			report("cannot make room for %d bytes in the cache\n", size);
X			return -1;
X		}
X		else
X		{
X			n = limit/4;
X			limit += n ? n : 1;
X			limit = MIN(limit, sound_count);
X		}
X	}
X
X	return 0;
}
X
/*
X * create room in the cache for the file of size bytes
X */
#ifdef MMAP
#ifdef __STDC__
char	*cache_create(char *name, int size)
#else
char	*cache_create(name, size)
char	*name;
int	size;
#endif
#else /* MMAP */
#ifdef __STDC__
int	cache_create(char *name, int size)
#else
int	cache_create(name, size)
char	*name;
#endif
#endif /* MMAP */
{
X	int	fd;
X	char	*p;
X
X	fd = open(name, O_RDWR|O_CREAT, 0644);
X	if (fd < 0)
X	{
X		if (debug)
X		{
X			report("open: %s\n", sys_errlist[errno]);
X		}
X		return NULL;
X	}
X
X	if (lseek(fd, size-1, SEEK_SET) < 0)
X	{
X		if (debug)
X		{
X			report("cache_create: lseek: %d %s\n", sys_errlist[errno]);
X		}
X		return NULL;
X	}
X	
X	if (write(fd, "", 1) != 1)
X	{
X		if (debug)
X		{
X			report("cache_create: write: %s\n", sys_errlist[errno]);
X		}
X		return NULL;
X	}
X	
X	if (lseek(fd, 0, SEEK_SET) < 0)
X	{
X		if (debug)
X		{
X			report("cache_create: lseek: 0 %s\n", sys_errlist[errno]);
X		}
X		unlink(name);
X		return NULL;
X	}
X
#ifdef MMAP
X	p = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
X	if (p == (caddr_t)-1)
X	{
X		if (debug)
X		{
X			report("mmap: %s\n", sys_errlist[errno]);
X		}
X		close(fd);
X		return NULL;
X	}
X	close(fd);
X	return p;
#else /* MMAP */
X	return fd;
#endif /* MMAP */
}
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/cache.c ||
echo 'restore of rplay-3.1.0/rplayd/cache.c failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/cache.c'`"
test 6233 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/cache.c: original size 6233, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/ulaw.c ==============
if test -f 'rplay-3.1.0/rplayd/ulaw.c' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/ulaw.c (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/ulaw.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/ulaw.c' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#include "conf.h"
#include "ulaw.h"
X
short _uLaw2Linear[256] = {
-32256,-31228,-30200,-29172,-28143,-27115,-26087,-25059,
-24031,-23002,-21974,-20946,-19918,-18889,-17861,-16833,
-16062,-15548,-15033,-14519,-14005,-13491,-12977,-12463,
-11949,-11435,-10920,-10406, -9892, -9378, -8864, -8350,
X -7964, -7707, -7450, -7193, -6936, -6679, -6422, -6165,
X -5908, -5651, -5394, -5137, -4880, -4623, -4365, -4108,
X -3916, -3787, -3659, -3530, -3402, -3273, -3144, -3016,
X -2887, -2759, -2630, -2502, -2373, -2245, -2116, -1988,
X -1891, -1827, -1763, -1698, -1634, -1570, -1506, -1441,
X -1377, -1313, -1249, -1184, -1120, -1056,  -992,  -927,
X  -879,  -847,  -815,  -783,  -751,  -718,  -686,  -654,
X  -622,  -590,  -558,  -526,  -494,  -461,  -429,  -397,
X  -373,  -357,  -341,  -325,  -309,  -293,  -277,  -261,
X  -245,  -228,  -212,  -196,  -180,  -164,  -148,  -132,
X  -120,  -112,  -104,   -96,   -88,   -80,   -72,   -64,
X   -56,   -48,   -40,   -32,   -24,   -16,    -8,     0,
X 32256, 31228, 30200, 29172, 28143, 27115, 26087, 25059,
X 24031, 23002, 21974, 20946, 19918, 18889, 17861, 16833,
X 16062, 15548, 15033, 14519, 14005, 13491, 12977, 12463,
X 11949, 11435, 10920, 10406,  9892,  9378,  8864,  8350,
X  7964,  7707,  7450,  7193,  6936,  6679,  6422,  6165,
X  5908,  5651,  5394,  5137,  4880,  4623,  4365,  4108,
X  3916,  3787,  3659,  3530,  3402,  3273,  3144,  3016,
X  2887,  2759,  2630,  2502,  2373,  2245,  2116,  1988,
X  1891,  1827,  1763,  1698,  1634,  1570,  1506,  1441,
X  1377,  1313,  1249,  1184,  1120,  1056,   992,   927,
X   879,   847,   815,   783,   751,   718,   686,   654,
X   622,   590,   558,   526,   494,   461,   429,   397,
X   373,   357,   341,   325,   309,   293,   277,   261,
X   245,   228,   212,   196,   180,   164,   148,   132,
X   120,   112,   104,    96,    88,    80,    72,    64,
X    56,    48,    40,    32,    24,    16,     8,     0 };
X
X
static unsigned char _uLinear2ULaw[8192] = {
X  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
X  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
X  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
X  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
X  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
X  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
X  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
X  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
X  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
X  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
X  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
X  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
X  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
X  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
X  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
X  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
X  1,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
X  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
X  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
X  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
X  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
X  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
X  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
X  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
X  2,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
X  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
X  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
X  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
X  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
X  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
X  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
X  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
X  3,  3,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
X  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
X  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
X  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
X  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
X  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
X  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
X  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
X  4,  4,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
X  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
X  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
X  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
X  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
X  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
X  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
X  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
X  5,  5,  5,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
X  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
X  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
X  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
X  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
X  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
X  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
X  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
X  6,  6,  6,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
X  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
X  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
X  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
X  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
X  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
X  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
X  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
X  7,  7,  7,  7,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
X  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
X  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
X  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
X  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
X  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
X  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
X  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
X  8,  8,  8,  8,  8,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
X  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
X  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
X  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
X  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
X  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
X  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
X  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
X  9,  9,  9,  9,  9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
X 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
X 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
X 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
X 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
X 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
X 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
X 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
X 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
X 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
X 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
X 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
X 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
X 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
X 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
X 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
X 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
X 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
X 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
X 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
X 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
X 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
X 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
X 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
X 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13,
X 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
X 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
X 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
X 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
X 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
X 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
X 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
X 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14,
X 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
X 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
X 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
X 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
X 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
X 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
X 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
X 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
X 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
X 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
X 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
X 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
X 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
X 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
X 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
X 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
X 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
X 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
X 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
X 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17,
X 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
X 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
X 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
X 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18,
X 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
X 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
X 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
X 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19,
X 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
X 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
X 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
X 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20,
X 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
X 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
X 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
X 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21,
X 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
X 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
X 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
X 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22,
X 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
X 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
X 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
X 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23,
X 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
X 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
X 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
X 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24,
X 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
X 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
X 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
X 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25,
X 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
X 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
X 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
X 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26,
X 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
X 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
X 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
X 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27,
X 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
X 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
X 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
X 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28,
X 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
X 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
X 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
X 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29,
X 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
X 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
X 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
X 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30,
X 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
X 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
X 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
X 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31,
X 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
X 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
X 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
X 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 32, 32, 32, 32,
X 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
X 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 33, 33, 33,
X 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
X 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 34, 34, 34,
X 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
X 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 35, 35, 35,
X 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
X 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 36, 36, 36,
X 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
X 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 37, 37, 37,
X 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
X 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 38, 38, 38,
X 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
X 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39,
X 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
X 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 40, 40,
X 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
X 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 41, 41,
X 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
X 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 42, 42,
X 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
X 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 43, 43,
X 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
X 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 44, 44,
X 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
X 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 45, 45,
X 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
X 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 46, 46,
X 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
X 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 47, 47,
X 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
X 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 48,
X 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 49,
X 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 50,
X 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 51,
X 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 52,
X 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 53,
X 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 54,
X 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 55,
X 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 56,
X 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 57,
X 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 58,
X 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 59,
X 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 60,
X 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 61,
X 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
X 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
X 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
X 64, 64, 64, 64, 64, 64, 64, 64, 65, 65, 65, 65, 65, 65, 65, 65,
X 66, 66, 66, 66, 66, 66, 66, 66, 67, 67, 67, 67, 67, 67, 67, 67,
X 68, 68, 68, 68, 68, 68, 68, 68, 69, 69, 69, 69, 69, 69, 69, 69,
X 70, 70, 70, 70, 70, 70, 70, 70, 71, 71, 71, 71, 71, 71, 71, 71,
X 72, 72, 72, 72, 72, 72, 72, 72, 73, 73, 73, 73, 73, 73, 73, 73,
X 74, 74, 74, 74, 74, 74, 74, 74, 75, 75, 75, 75, 75, 75, 75, 75,
X 76, 76, 76, 76, 76, 76, 76, 76, 77, 77, 77, 77, 77, 77, 77, 77,
X 78, 78, 78, 78, 78, 78, 78, 78, 79, 79, 79, 79, 79, 79, 79, 79,
X 80, 80, 80, 80, 81, 81, 81, 81, 82, 82, 82, 82, 83, 83, 83, 83,
X 84, 84, 84, 84, 85, 85, 85, 85, 86, 86, 86, 86, 87, 87, 87, 87,
X 88, 88, 88, 88, 89, 89, 89, 89, 90, 90, 90, 90, 91, 91, 91, 91,
X 92, 92, 92, 92, 93, 93, 93, 93, 94, 94, 94, 94, 95, 95, 95, 95,
X 96, 96, 97, 97, 98, 98, 99, 99,100,100,101,101,102,102,103,103,
104,104,104,105,105,106,106,107,107,108,108,109,109,110,110,111,
111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,
255,254,253,252,251,250,249,248,247,246,245,244,243,242,241,240,
239,239,238,238,237,237,236,236,235,235,234,234,233,233,232,232,
231,231,230,230,229,229,228,228,227,227,226,226,225,225,224,224,
223,223,223,223,222,222,222,222,221,221,221,221,220,220,220,220,
219,219,219,219,218,218,218,218,217,217,217,217,216,216,216,216,
215,215,215,215,214,214,214,214,213,213,213,213,212,212,212,212,
211,211,211,211,210,210,210,210,209,209,209,209,208,208,208,208,
207,207,207,207,207,207,207,207,206,206,206,206,206,206,206,206,
205,205,205,205,205,205,205,205,204,204,204,204,204,204,204,204,
203,203,203,203,203,203,203,203,202,202,202,202,202,202,202,202,
201,201,201,201,201,201,201,201,200,200,200,200,200,200,200,200,
199,199,199,199,199,199,199,199,198,198,198,198,198,198,198,198,
197,197,197,197,197,197,197,197,196,196,196,196,196,196,196,196,
195,195,195,195,195,195,195,195,195,194,194,194,194,194,194,194,
194,193,193,193,193,193,193,193,193,192,192,192,192,192,192,192,
192,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,
191,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,
190,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,
189,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,
188,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,
187,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,
186,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,
185,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,
184,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,
183,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,
182,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,
181,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,
180,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,
179,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,
178,178,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
177,177,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
176,176,175,175,175,175,175,175,175,175,175,175,175,175,175,175,
175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,
175,175,174,174,174,174,174,174,174,174,174,174,174,174,174,174,
174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,
174,174,173,173,173,173,173,173,173,173,173,173,173,173,173,173,
173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,
173,173,172,172,172,172,172,172,172,172,172,172,172,172,172,172,
172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,
172,172,171,171,171,171,171,171,171,171,171,171,171,171,171,171,
171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,
171,171,170,170,170,170,170,170,170,170,170,170,170,170,170,170,
170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,
170,170,169,169,169,169,169,169,169,169,169,169,169,169,169,169,
169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,
169,169,169,168,168,168,168,168,168,168,168,168,168,168,168,168,
168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,
168,168,168,167,167,167,167,167,167,167,167,167,167,167,167,167,
167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,
167,167,167,166,166,166,166,166,166,166,166,166,166,166,166,166,
166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,
166,166,166,165,165,165,165,165,165,165,165,165,165,165,165,165,
165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,
165,165,165,164,164,164,164,164,164,164,164,164,164,164,164,164,
164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,
164,164,164,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,162,162,162,162,162,162,162,162,162,162,162,162,162,
162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,
162,162,162,162,161,161,161,161,161,161,161,161,161,161,161,161,
161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
161,161,161,161,160,160,160,160,160,160,160,160,160,160,160,160,
160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
160,160,160,160,159,159,159,159,159,159,159,159,159,159,159,159,
159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,
159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,
159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,
159,159,159,159,158,158,158,158,158,158,158,158,158,158,158,158,
158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,
158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,
158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,
158,158,158,158,157,157,157,157,157,157,157,157,157,157,157,157,
157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,
157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,
157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,
157,157,157,157,157,156,156,156,156,156,156,156,156,156,156,156,
156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,
156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,
156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,
156,156,156,156,156,155,155,155,155,155,155,155,155,155,155,155,
155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,
155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,
155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,
155,155,155,155,155,154,154,154,154,154,154,154,154,154,154,154,
154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,
154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,
154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,
154,154,154,154,154,153,153,153,153,153,153,153,153,153,153,153,
153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,
153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,
153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,
153,153,153,153,153,153,152,152,152,152,152,152,152,152,152,152,
152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,
152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,
152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,
152,152,152,152,152,152,151,151,151,151,151,151,151,151,151,151,
151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,
151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,
151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,
151,151,151,151,151,151,150,150,150,150,150,150,150,150,150,150,
150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,
150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,
150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,
150,150,150,150,150,150,149,149,149,149,149,149,149,149,149,149,
149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,
149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,
149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,
149,149,149,149,149,149,149,148,148,148,148,148,148,148,148,148,
148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,
148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,
148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,
148,148,148,148,148,148,148,147,147,147,147,147,147,147,147,147,
147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,
147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,
147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,
147,147,147,147,147,147,147,146,146,146,146,146,146,146,146,146,
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,
146,146,146,146,146,146,146,145,145,145,145,145,145,145,145,145,
145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
145,145,145,145,145,145,145,145,144,144,144,144,144,144,144,144,
144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
144,144,144,144,144,144,144,144,143,143,143,143,143,143,143,143,
143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,
143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,
143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,
143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,
143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,
143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,
143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,
143,143,143,143,143,143,143,143,143,142,142,142,142,142,142,142,
142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,
142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,
142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,
142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,
142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,
142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,
142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,
142,142,142,142,142,142,142,142,142,141,141,141,141,141,141,141,
141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,
141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,
141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,
141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,
141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,
141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,
141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,
141,141,141,141,141,141,141,141,141,141,140,140,140,140,140,140,
140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,
140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,
140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,
140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,
140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,
140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,
140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,
140,140,140,140,140,140,140,140,140,140,139,139,139,139,139,139,
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,
139,139,139,139,139,139,139,139,139,139,139,138,138,138,138,138,
138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,
138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,
138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,
138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,
138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,
138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,
138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,
138,138,138,138,138,138,138,138,138,138,138,137,137,137,137,137,
137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,
137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,
137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,
137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,
137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,
137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,
137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,
137,137,137,137,137,137,137,137,137,137,137,137,136,136,136,136,
136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
136,136,136,136,136,136,136,136,136,136,136,136,135,135,135,135,
135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,
135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,
135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,
135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,
135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,
135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,
135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,
135,135,135,135,135,135,135,135,135,135,135,135,135,134,134,134,
134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,
134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,
134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,
134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,
134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,
134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,
134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,
134,134,134,134,134,134,134,134,134,134,134,134,134,133,133,133,
133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,
133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,
133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,
133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,
133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,
133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,
133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,
133,133,133,133,133,133,133,133,133,133,133,133,133,133,132,132,
132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
132,132,132,132,132,132,132,132,132,132,132,132,132,132,131,131,
131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,
131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,
131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,
131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,
131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,
131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,
131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,
131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,130,
130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,
130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,
130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,
130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,
130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,
130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,
130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,
130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,129,
129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128 };
X
unsigned char *_linear2ULaw = _uLinear2ULaw + 4096;
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/ulaw.c ||
echo 'restore of rplay-3.1.0/rplayd/ulaw.c failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/ulaw.c'`"
test 36066 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/ulaw.c: original size 36066, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/cache.h ==============
if test -f 'rplay-3.1.0/rplayd/cache.h' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/cache.h (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/cache.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/cache.h' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#ifndef _cache_h
#define _cache_h
X
#include "conf.h"
X
extern int	cache_max_size;
X
#ifdef __STDC__
extern void	cache_init(char *dir_name);
extern char	*cache_first();
extern char	*cache_next();
extern int	cache_size();
extern void	cache_read();
extern char	*cache_name(char *sound);
extern int	cache_free(int size);
#ifdef MMAP
extern char	*cache_create(char *name, int size);
#else
extern int	cache_create(char *name, int size);
#endif /* MMAP */
#else
extern void	cache_init(/* char *dir_name */);
extern char	*cache_first();
extern char	*cache_next();
extern int	cache_size();
extern void	cache_read();
extern char	*cache_name(/* char *sound */);
extern int	cache_free(/* int size */);
#ifdef MMAP
extern char	*cache_create(/* char *name, int size */);
#else
extern int	cache_create(/* char *name, int size */);
#endif /* MMAP */
#endif
X
#endif /* _cache_h */
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/cache.h ||
echo 'restore of rplay-3.1.0/rplayd/cache.h failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/cache.h'`"
test 1655 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/cache.h: original size 1655, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/ulaw.h ==============
if test -f 'rplay-3.1.0/rplayd/ulaw.h' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/ulaw.h (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/ulaw.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/ulaw.h' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#ifndef _ulaw_h
#define _ulaw_h
X
#include "conf.h"
X
extern short           _uLaw2Linear[];
extern unsigned char  *_linear2ULaw;
X
#define ULAW_MAGIC	0x2e736e64	/* ".snd" ulaw file header */
#define ULAW_HDRSIZE	24		/* minimum ulaw header size */
X
#define ulaw_to_linear(ulaw8) (_uLaw2Linear[(unsigned char)(ulaw8)])
#define linear_to_ulaw(lin16) (_linear2ULaw[(short)(lin16) >> 3])
X
#endif /* _ulaw_h */
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/ulaw.h ||
echo 'restore of rplay-3.1.0/rplayd/ulaw.h failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/ulaw.h'`"
test 1196 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/ulaw.h: original size 1196, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/connection.c ==============
if test -f 'rplay-3.1.0/rplayd/connection.c' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/connection.c (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/connection.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/connection.c' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#include "conf.h"
#include <sys/time.h>
#include <sys/errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include "rplayd.h"
#include "connection.h"
#include "command.h"
#include "version.h"
#include "sound.h"
#include "server.h"
#include "host.h"
#include "cache.h"
#include "rplay.h"
#include "spool.h"
#include "buffer.h"
X
#undef MIN
#define MIN(a,b)	((a)<(b)?(a):(b))
X
CONNECTION	*connections = NULL;
static int	nconnections = 0;
X
/*
X * create a connection object
X * types are CONNECTION_CLIENT and CONNECTION_SERVER
X */
#ifdef __STDC__
CONNECTION	*connection_create(int type)
#else
CONNECTION	*connection_create(type)
int		type;
#endif
{
X	CONNECTION	*c;
X
X	c = (CONNECTION *)malloc(sizeof(CONNECTION));
X	if (c == NULL)
X	{
X		report("out of memory\n");
X		done(1);
X	}
X	c->type = type;
X	c->fd = -1;
X	c->event = NULL;
X	c->ep = &c->event;
X	c->server = NULL;
X	c->time = time(0);
X			
X	/*
X	 * insert new connection into the connection list
X	 */
X	c->prev = NULL;
X	c->next = connections;
X	if (connections)
X	{
X		connections->prev = c;
X	}
X	connections = c;
X
X	if (type == CONNECTION_CLIENT)
X	{
X		nconnections++;
X	}
X	
X	return c;
}
X
/*
X * destroy the connection and remove it from the connection list
X */
#ifdef __STDC__
void	connection_destroy(CONNECTION *c)
#else
void	connection_destroy(c)
CONNECTION	*c;
#endif
{
X	if (c->type == CONNECTION_CLIENT)
X	{
X		nconnections--;
X	}
X	if (c->prev)
X	{
X		c->prev->next = c->next;
X	}
X	else
X	{
X		connections = c->next;
X	}
X	if (c->next)
X	{
X		c->next->prev = c->prev;
X	}
X	free((char *)c);
}
X
/*
X * start a server connection to try and find the given sound
X *
X * The sound can be NULL which means that events have already
X * been created and will be forwarded to this server.
X */
#ifdef __STDC__
CONNECTION	*connection_server_open(SERVER *server, SOUND *sound)
#else
CONNECTION	*connection_server_open(server, sound)
SERVER	*server;
SOUND	*sound;
#endif
{
X	int		n;
X	CONNECTION	*c;
X	EVENT		*e;
X	
X	/*
X	 * see if there is already a connection to that server
X	 */
X	for (c = connections; c; c = c->next)
X	{
X		if (c->type == CONNECTION_SERVER && c->server == server)
X		{
X			break;
X		}
X	}
X	if (c == NULL)
X	{
X		c = connection_create(CONNECTION_SERVER);
X		c->server = server;
X		c->sin = server->sin;
X	}
X	if (c->fd == -1)
X	{
X		c->fd = socket(AF_INET, SOCK_STREAM, 0);
X		if (c->fd < 0)
X		{
X			report("socket: %s\n", sys_errlist[errno]);
X			done(1);
X		}
X		socket_nonblock(c->fd);
X
X		/*
X		 * ping the server
X		 */
X		connection_server_ping(c);
X		
X		/* 
X		 * try to connect to the server immediately
X		 */
X		if (debug)
X		{
X			report("%s server connection attempt\n", inet_ntoa(c->server->sin.sin_addr));
X		}
X		n = connect(c->fd, (struct sockaddr *)&c->server->sin, sizeof(c->server->sin));
X		e = event_create(EVENT_CONNECT);
X		e->time = time(0);
X		event_insert(c, e);
X	}
X
X	/*
X	 * create events to try and find the sound
X	 */
X	if (sound)
X	{
X		BUFFER	*b;
X		
X		b = buffer_create();
X		sprintf(b->buf, "find %s\r\n", sound->name);
X		b->nbytes = strlen(b->buf);
X		e = event_create(EVENT_WRITE_FIND, b, sound);
X		event_insert(c, e);
X	}
X
X	return c;
}
X
#ifdef __STDC__
void	connection_server_reopen(CONNECTION *c)
#else
void	connection_server_reopen(c)
CONNECTION	*c;
#endif
{
X	EVENT		*e;
X	CONNECTION	*server;
X	
X	close(c->fd);
X	c->fd = -1;
X	e = c->event;
X	c->event = NULL;
X	c->ep = &c->event;
X	
X	server = connection_server_open(c->server, NULL);
X	if (server != c)
X	{
X		report("connection_server_reopen: server != c\n");
X		done(1);
X	}
X	event_insert(server, e);
}
X
/*
X * send a ping packet to the server
X */
#ifdef __STDC__
void	connection_server_ping(CONNECTION *c)
#else
void	connection_server_ping(c)
CONNECTION	*c;
#endif
{
X	struct sockaddr_in	ping_addr;
X	
X	memcpy((char *)&ping_addr, (char *)&c->server->sin, sizeof(ping_addr));
X	ping_addr.sin_port = htons(RPLAY_PORT);
X	rplay_ping_sockaddr_in(&ping_addr);
}
X
/*
X * open a client connection
X */
void	connection_client_open()
{
X	struct sockaddr_in	f;
X	int			fd, flen = sizeof(f);
X	CONNECTION		*c;
X	static char		message[RPTP_MAX_LINE];
X
X	fd = accept(rptp_fd, (struct sockaddr *)&f, &flen);
X	if (fd < 0)
X	{
X		report("accept: %s\n", sys_errlist[errno]);
X		return;
X	}
X
X	if (debug)
X	{
X		report("%s client connection request\n", inet_ntoa(f.sin_addr));
X	}
X
#ifdef AUTH
X	/*
X	 * see if this host has any access
X	 */
X	if (!host_access(f, HOST_READ) && !host_access(f, HOST_WRITE)
X	    && !host_access(f, HOST_WRITE))
X	{
X		if (debug)
X		{
X			report("%s permission denied\n", inet_ntoa(f.sin_addr));
X		}
X		write(fd, "-permission denied\r\n", 20);
X		close(fd);
X		return;
X	}
#endif /* AUTH */
X
X	/*
X	 * see if there are too many connections
X	 */
X	if (nconnections+1 == RPTP_MAX_CONNECTIONS)
X	{
X		write(fd, "-too many connections\r\n", 23);
X		close(fd);
X	}
X	
X	c = connection_create(CONNECTION_CLIENT);
X	c->fd = fd;
X	socket_nonblock(c->fd);
X	c->sin = f;
X
X	if (debug)
X	{
X		report("%s client connection established\n", inet_ntoa(c->sin.sin_addr));
X	}
X
X	connection_reply(c, "%c%s RPTP server rplayd %d.%d.%d ready.",
X		RPTP_OK, hostname, RPLAY_MAJOR_VERSION, RPLAY_MINOR_VERSION,
X		RPLAY_PATCHLEVEL);
}
X
/*
X * update connections by monitoring the read and write fd_sets
X *
X * if the given fd_sets are NULL then select must be called to update
X * the fd_sets
X */
#ifdef __STDC__
void	connection_update(fd_set *read_fds, fd_set *write_fds)
#else
void	connection_update(read_fds, write_fds)
fd_set	*read_fds;
fd_set	*write_fds;
#endif
{
X	int		i, n, nfds;
X	CONNECTION	*c, *next;
X	struct timeval	tv;
X	fd_set		rfds, wfds;
X	long		t;
X	char		buf[RPTP_MAX_LINE];
X
X	if (read_fds == NULL && write_fds == NULL)
X	{
X		tv.tv_sec = 0;
X		tv.tv_usec = 0;
X		rfds = read_mask;
X		wfds = write_mask;
X		FD_CLR(rplay_fd, &rfds);
#ifdef __hpux
X		nfds = select(FD_SETSIZE, (int *)&rfds, (int *)&wfds, 0, &tv);
#else
X		nfds = select(FD_SETSIZE, &rfds, &wfds, 0, &tv);
#endif
X	}
X	else
X	{
X		rfds = *read_fds;
X		wfds = *write_fds;
X		nfds = 1;
X	}
X
X	/*
X	 * check for idle connections
X	 */
X	connection_check_timeout();
X
X	if (nfds == 0)
X	{
X		/*
X		 * nothing to do...
X		 */
X		return;
X	}
X	else if (nfds < 0)
X	{
X		report("select: %s\n", sys_errlist[errno]);
X		done(1);
X	}
X
X	/*
X	 * check for new connections
X	 */
X	if (FD_ISSET(rptp_fd, &rfds))
X	{
X		connection_client_open();
X	}
X
X	t = time(0);
X	
X	for (c = connections; c; c = next)
X	{
X		next = c->next;	/* just in case c is destroyed */
X
X		/*
X		 * connection has no events
X		 */
X		if (c->event == NULL)
X		{
X			continue;
X		}
X
X		/*
X		 * read events
X		 */
X		if (FD_ISSET(c->fd, &rfds))
X		{
X			c->time = t;
X
X			switch (c->event->type)
X			{
X			case EVENT_READ_SOUND:
#ifdef MMAP
X				n = read(c->fd, c->event->ptr, c->event->nleft);
#else /* MMAP */
X				n = read(c->fd, c->event->buffer->buf,
X					MIN(c->event->nleft, sizeof(c->event->buffer->buf)));
#endif /* MMAP */
X				if (debug)
X				{
X					report("%s read %d (%d), errno=%d\n",
X					       inet_ntoa(c->sin.sin_addr),
X					       n, c->event->nleft, errno);
X				}
X				if (n <= 0)
X				{
X					event_update(c);
X				}
X				else
X				{
#ifdef MMAP
X					c->event->ptr += n;
X					c->event->nleft -= n;
#else /* MMAP */
X					write(c->event->fd, c->event->buffer->buf, n);
X					c->event->nleft -= n;
#endif /* MMAP */
X					if (c->event->nleft == 0)
X					{
X						c->event->success++;
X						event_update(c);
X					}
X				}
X				break;
X					
X			default:
X				/*
X				 * read a line
X				 */
X				n = recv(c->fd, c->event->ptr, c->event->nleft, MSG_PEEK);
X				if (debug)
X				{
X					report("%s recv %d (%d), errno=%d\n", 
X					       inet_ntoa(c->sin.sin_addr),
X					       n, c->event->nleft, errno);
X				}
X				if (n <= 0)
X				{
X					event_update(c);
X				}
X				else
X				{
X					/*
X				 	 * search for a newline and replace \r and \n with \0
X				 	 */
X					for (i = 0; i < n; i++)
X					{
X						if (c->event->ptr[i] == '\r')
X						{
X							c->event->ptr[i] = '\0';
X						}
X						else if (c->event->ptr[i] == '\n')
X						{
X							c->event->ptr[i] = '\0';
X							c->event->success++;
X							break;
X						}
X					}
X					n = read(c->fd, buf, i == n ? n : i+1);
X					if (n <= 0)
X					{
X						c->event->success = 0;
X						event_update(c);
X					}
X					else
X					{
X						c->event->ptr += n;
X						c->event->nleft -= n;
X					}
X					if (c->event->success || c->event->nleft == 0)
X					{
X						event_update(c);
X					}
X				}
X				break;
X			}
X		}
X		/*
X		 * write events
X		 */
X		else if (FD_ISSET(c->fd, &wfds))
X		{
X			c->time = t;
X
X			switch (c->event->type)
X			{
X			case EVENT_CONNECT:
X				event_update(c);
X				break;
X				
X			default:
X				n = write(c->fd, c->event->ptr, c->event->nleft);
X				if (debug)
X				{
X					report("%s write %d (%d), errno=%d\n",
X					       inet_ntoa(c->sin.sin_addr), n,
X					       c->event->nleft, errno);
X				}
X				if (n <= 0)
X				{
X					event_update(c);
X				}
X				else
X				{
X					c->event->ptr += n;
X					c->event->nleft -= n;
X					if (c->event->nleft == 0)
X					{
X						c->event->success++;
X						event_update(c);
X					}
X				}
X				break;
X			}
X		}
X	}
}
X
/*
X * close and destroy the connection
X */
#ifdef __STDC__
void	connection_close(CONNECTION *c)
#else
void	connection_close(c)
CONNECTION	*c;
#endif
{
X	EVENT	*e, *next;
X	
X	if (debug)
X	{
X		switch (c->type)
X		{
X		case CONNECTION_CLIENT:
X			report("%s client connection closed\n", inet_ntoa(c->sin.sin_addr));
X			break;
X			
X		case CONNECTION_SERVER:
X			report("%s server connection closed\n", inet_ntoa(c->sin.sin_addr));
X			break;
X		}
X	}
X
X	FD_CLR(c->fd, &read_mask);
X	FD_CLR(c->fd, &write_mask);
X
X	close(c->fd);
X
X	/*
X	 * destroy any events that are left
X	 */
X	for (e = c->event; e; e = next)
X	{
X		next = e->next;
X		switch (e->type)
X		{
X		case EVENT_WRITE_FIND:
X		case EVENT_READ_FIND_REPLY:
X		case EVENT_WRITE_GET:
X		case EVENT_READ_GET_REPLY:
X		case EVENT_READ_SOUND:
X			spool_remove(e->sound);
X			sound_delete(e->sound);
X			break;
X		}
X		event_destroy(e);
X	}
X
X	c->event = NULL;
X	c->ep = &c->event;
X
X	connection_destroy(c);
}
X
/*
X * update the fd_sets for the connect
X */
#ifdef __STDC__
void	connection_update_fdset(CONNECTION *c)
#else
void	connection_update_fdset(c)
CONNECTION	*c;
#endif
{
X	FD_CLR(c->fd, &read_mask);
X	FD_CLR(c->fd, &write_mask);
X
X	if (c->event == NULL)
X	{
X		return;
X	}
X	
X	switch (c->event->type)
X	{
X	case EVENT_READ_COMMAND:
X	case EVENT_READ_SOUND:
X	case EVENT_READ_CONNECT_REPLY:
X	case EVENT_READ_FIND_REPLY:
X	case EVENT_READ_GET_REPLY:
X		FD_SET(c->fd, &read_mask);
X		break;
X
X	case EVENT_WRITE:
X	case EVENT_WRITE_SOUND:
X	case EVENT_WRITE_FIND:
X	case EVENT_WRITE_GET:
X	case EVENT_CONNECT:
X	case EVENT_WRITE_TIMEOUT:
X		FD_SET(c->fd, &write_mask);
X		break;
X
X	default:
X		report("unknown event type '%d'\n", c->event->type);
X		done(1);
X	}
X
#ifdef DEBUG
X	event_print(c);
#endif
}
X
/*
X * send the connection a reply message
X */
#ifdef __STDC__
void	connection_reply(CONNECTION *c, char *fmt, ...)
#else
void	connection_reply(va_alist)
va_dcl
#endif
{
X	va_list	args;
X	EVENT	*e;
X	BUFFER	*b;
X
#ifdef __STDC__
X	va_start(args, fmt);
#else
X	CONNECTION	*c;
X	char		*fmt;
X	va_start(args);
X	c = va_arg(args, CONNECTION *);
X	fmt = va_arg(args, char *);
#endif
X
X	b = buffer_create();
X
X	vsprintf(b->buf, fmt, args);
X	va_end(args);
X	strcat(b->buf, "\r\n");
X
X	b->nbytes += strlen(b->buf);
X	
X	e = event_create(EVENT_WRITE, b);
X	event_insert(c, e);
}
X
/*
X * close all connections
X */
void	connection_cleanup()
{
X	CONNECTION	*c;
X
X	for (c = connections; c; c = c->next)
X	{
X		connection_close(c);
X	}
}
X
/*
X * timeout all idle connections
X */
void	connection_check_timeout()
{
X	long		t;
X	CONNECTION	*c, *next;
X	
X	if (!rptp_timeout)
X	{
X		return;
X	}
X
X	t = time(0);
X	for (c = connections; c; c = next)
X	{
X		next = c->next;
X		if (t - c->time >= rptp_timeout)
X		{
X			connection_timeout(c);
X		}
X	}
}
X
/*
X * timeout an idle connection
X */
#ifdef __STDC__
void	connection_timeout(CONNECTION *c)
#else
void	connection_timeout(c)
CONNECTION	*c;
#endif
{
X	BUFFER	*b;
X	EVENT	*e;
X
X	if (c->type == CONNECTION_SERVER)
X	{		
X		if (debug)
X		{
X			report("%s server connection timeout\n", inet_ntoa(c->sin.sin_addr));
X		}
X		connection_close(c);
X	}
X	else
X	{
X		b = buffer_create();
X		sprintf(b->buf, "%cConnection timed out after %d idle seconds.\r\n",
X			RPTP_TIMEOUT, rptp_timeout);
X		b->nbytes += strlen(b->buf);
X		e = event_create(EVENT_WRITE_TIMEOUT, b);
X		event_replace(c, e);
X	}
}
X
/*
X * forward the sound request to the next server
X */
#ifdef __STDC__
void	connection_server_forward_sound(CONNECTION *c, SOUND *s)
#else
void	connection_server_forward_sound(c, s)
CONNECTION	*c;
SOUND		*s;
#endif
{
X	CONNECTION	*server;
X	
X	if (c->server->next)
X	{
X		server = connection_server_open(c->server->next, s);
X	}
X	else
X	{
X		spool_remove(s);
X		sound_delete(s);
X	}
}
X
/*
X * forward all events to the next server
X */
#ifdef __STDC__
void	connection_server_forward(CONNECTION *c)
#else
void	connection_server_forward(c)
CONNECTION	*c;
#endif
{
X	EVENT		*e, *next;
X	CONNECTION	*server;
X	
X	if (c->server->next)
X	{
X		server = connection_server_open(c->server->next, NULL);
X		event_insert(server, c->event);
X	}
X	else
X	{
X		for (e = c->event; e; e = next)
X		{
X			next = e->next;
X			switch (e->type)
X			{
X			case EVENT_WRITE_FIND:
X			case EVENT_READ_FIND_REPLY:
X			case EVENT_WRITE_GET:
X			case EVENT_READ_GET_REPLY:
X			case EVENT_READ_SOUND:
X				spool_remove(e->sound);
X				sound_delete(e->sound);
X				break;
X			}
X			event_destroy(e);
X		}
X	}
X	c->event = NULL;
X	c->ep = &c->event;
}
X
BUFFER	*connection_list_create()
{
X	CONNECTION	*c;
X	BUFFER		*b, *connection_list;
X	char		buf[RPTP_MAX_LINE];
X	char		idle_buf[16];
X	char		what_buf[512];
X	int		n;
X	long		t, idle, days, hours, mins;
X	
X	b = buffer_create();
X	connection_list = b;
X	sprintf(b->buf, "+connections\r\nHOST            TYPE    IDLE WHAT\r\n");
X	b->nbytes += strlen(b->buf);
X	
X	t = time(0);
X
X	for (c = connections; c; c = c->next)
X	{
X		sprintf(buf, "%-15s ", inet_ntoa(c->sin.sin_addr));
X		switch (c->type)
X		{
X		case CONNECTION_SERVER:
X			strcat(buf, "server ");
X			break;
X			
X		case CONNECTION_CLIENT:
X			strcat(buf, "client ");
X			break;
X		}
X		
X		idle = t - c->time;
X		days = idle / (60*60*24);
X		idle %= (60*60*24); 
X		hours = idle / (60*60);
X		idle %= (60*60);
X		mins = idle / 60;
X
X		if (days > 0)
X		{
X			sprintf(idle_buf, "%dday%s", days, days > 1 ? "s" : "");
X		}
X		else if (hours > 0 && mins > 0)
X		{
X			sprintf(idle_buf, "%2d:%2d", hours, mins);
X		}
X		else 
X		{
X			if (hours > 0)
X			{
X				sprintf(idle_buf, "%dhr%s", hours,
X					hours > 1 ? "s" : "");
X			}
X			else if (mins > 0)
X			{
X				sprintf(idle_buf, "%d", mins);
X			}
X			else
X			{
X				sprintf(idle_buf, "");
X			}
X		}
X
X		if (c->event == NULL)
X		{
X			sprintf(what_buf, "(idle)");
X		}
X		else
X		{
X			switch (c->event->type)
X			{
X			case EVENT_READ_COMMAND:
X				sprintf(what_buf, "(idle)");
X				break;
X				
X			case EVENT_CONNECT:
X			case EVENT_READ_CONNECT_REPLY:
X				sprintf(what_buf, "(connect)");
X				break;
X				
X			case EVENT_WRITE_FIND:
X			case EVENT_READ_FIND_REPLY:
X				sprintf(what_buf, "find %s", c->event->sound->name);
X				break;
X				
X			case EVENT_WRITE_GET:
X			case EVENT_READ_GET_REPLY:
X				sprintf(what_buf, "get %s", c->event->sound->name);
X				break;
X
X			case EVENT_READ_SOUND:
X				if (c->type == CONNECTION_SERVER)
X					sprintf(what_buf, "get %s", c->event->sound->name);
X				else
X					sprintf(what_buf, "put %s", c->event->sound->name);
X				break;
X				
X			case EVENT_WRITE:
X				sprintf(what_buf, "(write)");
X				break;
X				
X			case EVENT_WRITE_SOUND:
X				sprintf(what_buf, "get %s", c->event->sound->name);
X				break;
X			}
X		}
X
X		sprintf(buf+23, "%5s %s\r\n", idle_buf, what_buf);
X
X		n = strlen(buf);
X		if (b->nbytes + n > BUFFER_SIZE)
X		{
X			b->next = buffer_create();
X			b = b->next;
X		}
X		strcat(b->buf, buf);
X		b->nbytes += n;
X	}
X	
X	if (b->nbytes + 3 > BUFFER_SIZE)
X	{
X		b->next = buffer_create();
X		b = b->next;
X	}
X	strcat(b->buf, ".\r\n");
X	b->nbytes += 3;
X	
X	return connection_list;
}
X
#ifdef __STDC__
void	event_update(CONNECTION *c)
#else
void	event_update(c)
CONNECTION	*c;
#endif
{
X	int		n, size;
#ifndef MMAP
X	int		fd;
#endif
X	EVENT		*e;
X	CONNECTION	*server;
X	long		t;
X	char		*p;
X	BUFFER		*b;
X	
X	switch (c->event->type)
X	{
X	case EVENT_READ_COMMAND:
X		if (c->event->success)
X		{
X			if (debug)
X			{
X				report("%s command=%s\n", inet_ntoa(c->sin.sin_addr), c->event->start);
X			}
X			if (c->event->start[0] == '\0')
X			{
X				event_delete(c);
X			}
X			else if (command(c, c->event->start) == 0)
X			{
X				event_delete(c);
X			}
X		}
X		else
X		{
X			connection_close(c);
X		}
X		break;
X
X	case EVENT_CONNECT:
X		/*
X		 * check the time to delay between connect attempts
X		 */
X		t = time(0);
X		if (t - c->event->time < RPTP_PING_DELAY)
X		{
X			break;
X		}
X		c->event->time = t;
X		
X		/*
X		 * check the socket to see if it is connected
X		 */
X		n = connect(c->fd, (struct sockaddr *)&c->server->sin, sizeof(c->server->sin));
X		if (n == 0 || errno == EISCONN)
X		{	
X			/*
X			 * got a connection
X			 */
X			if (debug)
X			{
X				report("%s server connection established\n", inet_ntoa(c->server->sin.sin_addr));
X			}
X			/*
X			 * prepare to read the connect reply, this must replace the
X			 * connect event
X			 */
X			e = event_create(EVENT_READ_CONNECT_REPLY, buffer_create());
X			event_replace(c, e);
X		}
X		else
X		{
X			/*
X			 * socket is not connected
X			 */
X			c->event->nconnects++;
X			if (debug)
X			{
X				report("%s server connection failed attempt #%d\n", 
X				       inet_ntoa(c->server->sin.sin_addr), 
X				       c->event->nconnects);
X			}
X			if (c->event->nconnects < RPTP_CONNECT_ATTEMPTS)
X			{
X				switch (errno)
X				{
X				case ECONNREFUSED:
X				case EINTR:
X				case EINVAL:
X				case EPIPE:
X					/*
X					 * ping the server again
X					 */
X					connection_server_ping(c);
X					
X					FD_CLR(c->fd, &read_mask);
X					FD_CLR(c->fd, &write_mask);
X					close(c->fd);
X					c->fd = socket(AF_INET, SOCK_STREAM, 0);
X					socket_nonblock(c->fd);
X					
X					/*
X					 * try and connect again
X					 */
X					connect(c->fd, (struct sockaddr *)&c->server->sin, sizeof(c->server->sin));
X					connection_update_fdset(c);
X					return;
X
X				default:
X					break;
X				}
X			}
X			
X			/*
X			 * connection failed, remove connect event and forward all other
X			 * events to the next server
X			 */
X			if (debug)
X			{
X				report("%s server connection failed\n", inet_ntoa(c->server->sin.sin_addr));
X			}
X			event_delete(c);
X			connection_server_forward(c);
X			connection_close(c);
X		}
X		break;
X
X	case EVENT_READ_CONNECT_REPLY:
X		if (c->event->success)
X		{
X			if (c->event->start[0] == RPTP_OK)
X			{
X				event_delete(c);
X			}
X			else
X			{
X				event_delete(c);
X				connection_server_forward(c);
X				connection_close(c);
X			}
X		}
X		else
X		{
X			if (debug)
X			{
X				report("cannot read connect reply from %s\n",
X				       inet_ntoa(c->server->sin.sin_addr));
X			}
X			event_delete(c);
X			connection_server_forward(c);
X			connection_close(c);
X		}
X		break;
X
X	case EVENT_WRITE_FIND:
X		if (c->event->success)
X		{
X			e = event_create(EVENT_READ_FIND_REPLY, buffer_create(), c->event->sound);
X			event_replace(c, e);
X		}
X		else
X		{
X			connection_server_forward(c);
X			connection_close(c);
X		}
X		break;
X
X	case EVENT_READ_FIND_REPLY:
X		if (c->event->success)
X		{
X			switch (c->event->start[0])
X			{
X			case RPTP_OK:
X				p = strtok(c->event->start, " ");
X				size = atoi(strtok(NULL, "\r\n"));
X				/*
X				 * see if the sound will fit in the cache
X				 */
X				if (cache_free(size) < 0)
X				{
X					/*
X					 * the sound is too big for the cache
X					 */
X					spool_remove(c->event->sound);
X					sound_delete(c->event->sound);
X					event_delete(c);
X					break;
X				}
X				b = buffer_create();
X				sprintf(b->buf, "get %s\r\n", c->event->sound->name);
X				b->nbytes = strlen(b->buf);
X				e = event_create(EVENT_WRITE_GET, b, c->event->sound);
X				event_replace(c, e);
X				break;
X				
X			case RPTP_ERROR:
X				if (debug)
X				{
X					report("%s server does not have %s\n",
X						inet_ntoa(c->sin.sin_addr), c->event->sound->name);
X				}
X				connection_server_forward_sound(c, c->event->sound);
X				event_delete(c);
X				break;
X				
X			case RPTP_TIMEOUT:
X				if (debug)
X				{
X					report("%s server connection timed out\n",
X					       inet_ntoa(c->sin.sin_addr));
X				}
X				b = buffer_create();
X				sprintf(b->buf, "find %s\r\n", c->event->sound->name);
X				b->nbytes = strlen(b->buf);
X				e = event_create(EVENT_WRITE_FIND, b, c->event->sound);
X				event_replace(c, e);
X				connection_server_reopen(c);
X				break;
X
X			default:
X				report("unknown find reply '%c'\n", c->event->start[0]);
X				done(1);
X			}
X		}
X		else
X		{
X			if (debug)
X			{
X				report("cannot read find reply from %s\n",
X				       inet_ntoa(c->sin.sin_addr));
X			}
X			b = buffer_create();
X			sprintf(b->buf, "find %s\r\n", c->event->sound->name);
X			b->nbytes = strlen(b->buf);
X			e = event_create(EVENT_WRITE_FIND, b, c->event->sound);
X			event_replace(c, e);
X			connection_server_forward(c);
X			connection_close(c);
X		}
X		break;
X			
X	case EVENT_WRITE_GET:
X		if (c->event->success)
X		{
X			e = event_create(EVENT_READ_GET_REPLY, buffer_create(), c->event->sound);
X			event_replace(c, e);
X		}
X		else
X		{
X			b = buffer_create();
X			sprintf(b->buf, "find %s\r\n", c->event->sound->name);
X			b->nbytes = strlen(b->buf);
X			e = event_create(EVENT_WRITE_FIND, b, c->event->sound);
X			event_replace(c, e);
X			connection_server_forward(c);
X			connection_close(c);
X		}
X		break;
X		
X	case EVENT_READ_GET_REPLY:
X		if (c->event->success)
X		{
X			switch (c->event->start[0])
X			{
X			case RPTP_OK:
X				p = strtok(c->event->start, " ");
X				p++;
X				free((char *)c->event->sound->path);
X				c->event->sound->path = strdup(cache_name(p));
X				c->event->sound->name = c->event->sound->path[0] == '/' ? 
X					strrchr(c->event->sound->path, '/') + 1 :
X					c->event->sound->path;
X				size = atoi(strtok(NULL, "\r\n"));
#ifdef MMAP
X				p = cache_create(c->event->sound->path, size);
X				if (p == NULL)
#else /* MMAP */
X				fd = cache_create(c->event->sound->path, size);
X				if (fd < 0)
#endif /* MMAP */
X				{
X					spool_remove(c->event->sound);
X					sound_delete(c->event->sound);
X					event_delete(c);
X				}
X				else
X				{
#ifdef MMAP
X					e = event_create(EVENT_READ_SOUND, p, size, c->event->sound);
#else /* MMAP */
X					e = event_create(EVENT_READ_SOUND, fd, buffer_create(), size, c->event->sound);
#endif /* MMAP */
X					c->event->sound->status = SOUND_NOT_READY;
X					event_replace(c, e);
X				}
X				break;
X				
X			case RPTP_ERROR:
X				if (debug)
X				{
X					report("%s server does not have %s\n",
X						inet_ntoa(c->sin.sin_addr), c->event->sound->name);
X				}
X				connection_server_forward_sound(c, c->event->sound);
X				event_delete(c);
X				break;
X				
X			case RPTP_TIMEOUT:
X				if (debug)
X				{
X					report("%s server connection timed out\n",
X					       inet_ntoa(c->sin.sin_addr));
X				}
X				b = buffer_create();
X				sprintf(b->buf, "get %s\r\n", c->event->sound->name);
X				b->nbytes = strlen(b->buf);
X				e = event_create(EVENT_WRITE_GET, b, c->event->sound);
X				event_replace(c, e);
X				connection_server_reopen(c);
X				break;
X				
X			default:
X				report("unknown get reply '%c'\n", c->event->start[0]);
X				done(1);
X			}
X		}
X		else
X		{
X			if (debug)
X			{
X				report("cannot read get reply from %s\n",
X				       inet_ntoa(c->server->sin.sin_addr));
X			}
X			b = buffer_create();
X			sprintf(b->buf, "find %s\r\n", c->event->sound->name);
X			b->nbytes = strlen(b->buf);
X			e = event_create(EVENT_WRITE_FIND, b, c->event->sound);
X			event_replace(c, e);
X			connection_server_forward(c);
X			connection_close(c);
X		}
X		break;
X		
X	case EVENT_READ_SOUND:
X		if (c->event->success)
X		{
#ifdef MMAP
X			sound_map(c->event->sound, c->event->start, c->event->nbytes);
#else /* MMAP */
X			close(c->event->fd);
X			sound_load(c->event->sound);
#endif /* MMAP */
X			spool_ready(c->event->sound);
X			c->event->sound->status = SOUND_READY;
X			if (debug)
X			{
X				report("sound %s is ready\n", c->event->sound->name);
X			}
X			event_delete(c);
X		}
X		else
X		{
X			if (debug)
X			{
X				report("cannot read sound %s from %s\n", c->event->sound->name,
X				       inet_ntoa(c->sin.sin_addr));
X			}
X			if (c->type == CONNECTION_SERVER)
X			{
X				b = buffer_create();
X				sprintf(b->buf, "find %s\r\n", c->event->sound->name);
X				b->nbytes = strlen(b->buf);
X				e = event_create(EVENT_WRITE_FIND, b, c->event->sound);
X				event_replace(c, e);
X				connection_server_forward(c);
X			}
X			connection_close(c);
X		}
X		break;
X		
X	case EVENT_WRITE_SOUND:
X		if (c->event->success)
X		{
X			event_delete(c);
X		}
X		else
X		{
X			connection_close(c);
X		}
X		break;
X
X	case EVENT_WRITE:
X		if (c->event->success)
X		{
X			b = c->event->buffer;
X			c->event->buffer = c->event->buffer->next;
X			if (b->status == BUFFER_FREE)
X			{
X				buffer_destroy(b);
X			}
X			if (c->event->buffer)
X			{
X				c->event->start = c->event->buffer->buf;
X				c->event->ptr = c->event->start;
X				c->event->nleft = c->event->buffer->nbytes;
X				c->event->nbytes = c->event->nleft;
X				c->event->success = 0;
X			}
X			else
X			{
X				event_delete(c);
X			}
X		}
X		else
X		{
X			connection_close(c);
X		}
X		break;
X
X	case EVENT_WRITE_TIMEOUT:
X		if (debug)
X		{
X			report("%s client connection timeout\n", inet_ntoa(c->sin.sin_addr));
X		}
X		connection_close(c);
X		break;
X
X	default:
X		report("event_update: unknown event type %d\n", c->event->type);
X		done(1);
X	}
}
X
#ifdef __STDC__
void	event_insert(CONNECTION *c, EVENT *e)
#else
void	event_insert(c, e)
CONNECTION	*c;
EVENT		*e;
#endif
{
X	EVENT	*tail;
X
X	for (tail = e; tail->next; tail = tail->next);
X	
X	*c->ep = e;
X	c->ep = &tail->next;
X
X	if (c->event == e)
X	{
X		connection_update_fdset(c);
X	}
}
X
#ifdef __STDC__
void	event_replace(CONNECTION *c, EVENT *e)
#else
void	event_replace(c, e)
CONNECTION	*c;
EVENT		*e;
#endif
{
X	if (c->event)
X	{
X		e->next = c->event->next;
X		event_destroy(c->event);
X	}
X	c->event = e;
X	if (c->event->next == NULL)
X	{
X		c->ep = &c->event->next;
X	}
X	connection_update_fdset(c);
}
X
#ifdef __STDC__
void	event_delete(CONNECTION *c)
#else
void	event_delete(c)
CONNECTION	*c;
#endif
{
X	EVENT	*e;
X	
X	if (c->event == NULL)
X	{
X		connection_update_fdset(c);
X		return;
X	}
X
X	e = c->event;
X	c->event = c->event->next;
X
X	event_destroy(e);
X	
X	if (c->event == NULL)
X	{
X		c->ep = &c->event;
X		switch (c->type)
X		{
X		case CONNECTION_CLIENT:
X			e = event_create(EVENT_READ_COMMAND, buffer_create());
X			event_insert(c, e);
X			break;
X
X		case CONNECTION_SERVER:
X			break;
X		}
X	}
X
X	connection_update_fdset(c);
}
X
/*
X *	EVENT_READ_COMMAND, BUFFER *b
X *	EVENT_CONNECT
X *	EVENT_READ_CONNECT_REPLY, BUFFER *b
X *	EVENT_WRITE_FIND, BUFFER *b, SOUND *sound
X *	EVENT_READ_FIND_REPLY, BUFFER *b, SOUND *sound
X *	EVENT_WRITE_GET, BUFFER *b, SOUND *sound
X *	EVENT_READ_GET_REPLY, BUFFER *b, SOUND *sound
X *	EVENT_READ_SOUND, char *start, int nbytes, SOUND *sound (MMAP)
X *		or
X *	EVENT_READ_SOUND, int fd, BUFFER *b, int nbytes, SOUND *sound
X *	EVENT_WRITE, BUFFER *buffer
X *	EVENT_WRITE_SOUND, SOUND *sound
X */
#ifdef __STDC__
EVENT	*event_create(int type, ...)
#else
EVENT	*event_create(va_alist)
va_dcl
#endif
{
X	EVENT	*e;
X	va_list	args;
X
#ifdef __STDC__
X	va_start(args, type);
#else
X	int	type;
X	va_start(args);
X	type = va_arg(args, int);
#endif
X
X	e = (EVENT *)malloc(sizeof(EVENT));
X	if (e == NULL)
X	{
X		report("out of memory");
X		done(1);
X	}
X       
X	/*
X	 * defaults
X	 */
X	e->next = NULL;
X	e->type = type;
X	e->nleft = 0;
X	e->nbytes = 0;
X	e->start = NULL;
X	e->ptr = NULL;
X	e->sound = NULL;
X	e->fd = -1;
X	e->nconnects = 0;
X	e->time = 0;
X	e->success = 0;
X	e->buffer = NULL;
X	
X	switch (e->type)
X	{
X	case EVENT_READ_COMMAND:
X	case EVENT_READ_CONNECT_REPLY:
X		e->buffer = va_arg(args, BUFFER *);
X		e->nleft = RPTP_MAX_LINE;
X		e->nbytes = e->nleft;
X		e->ptr = e->buffer->buf;
X		e->start = e->ptr;
X		break;
X
X	case EVENT_CONNECT:
X		break;
X		
X	case EVENT_WRITE_FIND:
X	case EVENT_WRITE_GET:
X		e->buffer = va_arg(args, BUFFER *);
X		e->nleft = e->buffer->nbytes;
X		e->nbytes = e->nleft;
X		e->ptr = e->buffer->buf;
X		e->start = e->ptr;
X		e->sound = va_arg(args, SOUND *);
X		break;
X		
X	case EVENT_READ_FIND_REPLY:
X	case EVENT_READ_GET_REPLY:
X		e->buffer = va_arg(args, BUFFER *);
X		e->nleft = RPTP_MAX_LINE;
X		e->nbytes = e->nleft;
X		e->ptr = e->buffer->buf;
X		e->start = e->ptr;
X		e->sound = va_arg(args, SOUND *);
X		break;
X
X	case EVENT_READ_SOUND:
#ifdef MMAP
X		e->ptr = va_arg(args, char *);
X		e->start = e->ptr;
X		e->nleft = va_arg(args, int);
X		e->nbytes = e->nleft;
X		e->sound = va_arg(args, SOUND *);
#else /* MMAP */
X		e->fd = va_arg(args, int);
X		e->buffer = va_arg(args, BUFFER *);
X		e->nbytes = va_arg(args, int);
X		e->nleft = e->nbytes;
X		e->sound = va_arg(args, SOUND *);
#endif /* MMAP */
X		break;
X	   
X	case EVENT_WRITE_SOUND:
X		e->sound = va_arg(args, SOUND *);
X		e->nleft = e->sound->size;
X		e->nbytes = e->nleft;
X		e->ptr = e->sound->buf;
X		e->start = e->ptr;
X		break;
X
X	case EVENT_WRITE:
X	case EVENT_WRITE_TIMEOUT:
X		e->buffer = va_arg(args, BUFFER *);
X		e->ptr = e->buffer->buf;
X		e->start = e->ptr;
X		e->nleft = e->buffer->nbytes;
X		e->nbytes = e->nleft;
X		break;
X	}
X
X	va_end(args);
X	
X	return e;
}
X
#ifdef __STDC__
void	event_destroy(EVENT *e)
#else
void	event_destroy(e)
EVENT	*e;
#endif
{
X	if (e->buffer && e->buffer->status == BUFFER_FREE)
X	{
X		buffer_destroy(e->buffer);
X	}
X	free((char *)e);
}
X
#ifdef DEBUG
event_print(CONNECTION *c)
{
X	EVENT	*e;
X	
X	printf("%s events: ", inet_ntoa(c->sin.sin_addr));
X	e = c->event;
X	for (; e; e = e->next)
X	{
X		switch (e->type)
X		{
X		case EVENT_READ_COMMAND:
X			printf("read_command ");
X			break;
X			
X		case EVENT_CONNECT:
X			printf("connect ");
X			break;
X			
X		case EVENT_READ_CONNECT_REPLY:
X			printf("read_connect_reply ");
X			break;
X			
X		case EVENT_WRITE_FIND:
X			printf("write_find ");
X			break;
X
X		case EVENT_READ_FIND_REPLY:
X			printf("read_find_reply ");
X			break;
X			
X		case EVENT_WRITE_GET:
X			printf("write_get ");
X			break;
X			
X		case EVENT_READ_GET_REPLY:
X			printf("read_get_reply ");
X			break;
X			
X		case EVENT_READ_SOUND:
X			printf("read_sound ");
X			break;
X			
X		case EVENT_WRITE:
X			printf("write ");
X			break;
X			
X		case EVENT_WRITE_SOUND:
X			printf("write_sound ");
X			break;
X			
X		case EVENT_WRITE_TIMEOUT:
X			printf("write_timeout ");
X			break;
X			
X		default:
X			printf("%d ", e->type);
X			break;
X		}
X	}
X	printf("\n");
}
#endif
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/connection.c ||
echo 'restore of rplay-3.1.0/rplayd/connection.c failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/connection.c'`"
test 30672 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/connection.c: original size 30672, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/connection.h ==============
if test -f 'rplay-3.1.0/rplayd/connection.h' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/connection.h (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/connection.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/connection.h' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#ifndef _connection_h
#define _connection_h
X
#include "conf.h"
#include <sys/param.h>
#include "sound.h"
#include "server.h"
#include "buffer.h"
X
/*
X * event types
X */
#define EVENT_NULL			0
#define EVENT_READ_COMMAND	        1 /* read an RPTP command (client) */
#define EVENT_CONNECT			2 /* connect to a server (server) */
#define EVENT_READ_CONNECT_REPLY	3 /* read a connect reply (server) */
#define EVENT_WRITE_FIND		4 /* write a find command (server) */
#define EVENT_READ_FIND_REPLY		5 /* read a find reply (server) */
#define EVENT_WRITE_GET			6 /* write a get command (server) */
#define EVENT_READ_GET_REPLY		7 /* read a get reply (server) */
#define EVENT_READ_SOUND		8 /* read a sound (both) */
#define EVENT_WRITE			9 /* write buffers (client) */
#define EVENT_WRITE_SOUND		10 /* write a sound (client) */
#define EVENT_WRITE_TIMEOUT		11 /* write connection timeout message (both) */
X
/*
X * connection types
X */
#define CONNECTION_NULL			0
#define CONNECTION_CLIENT		1
#define CONNECTION_SERVER		2
X
typedef struct _event
{
X	struct _event	*next;
X	int		type;
X	int		nleft;
X	int		nbytes;
X	char		*start;
X	char		*ptr;
X	BUFFER		*buffer;
X	SOUND		*sound;
X	int		fd;
X	int		nconnects;
X	long		time;
X	int		success;
} EVENT;
X
typedef struct _connection
{
X	struct _connection	*next;
X	struct _connection	*prev;
X	struct sockaddr_in	sin;
X	int			type;
X	int			fd;
X	EVENT			*event;
X	EVENT			**ep;
X	SERVER			*server;
X	long			time;
} CONNECTION;
X
extern CONNECTION	*connections;
X
#ifdef __STDC__
extern CONNECTION	*connection_create(int type);
extern void		connection_destroy(CONNECTION *c);
extern void		connection_client_open();
extern void		connection_update(fd_set *read_fds, fd_set *write_fds);
extern void		connection_close(CONNECTION *c);
extern void		connection_cleanup();
extern void		connection_update_fdset(CONNECTION *c);
extern void		connection_reply(CONNECTION *c, char *fmt, ...);
extern CONNECTION	*connection_server_open(SERVER *server, SOUND *sound);
extern void		connection_server_reopen(CONNECTION *c);
extern void		connection_server_ping(CONNECTION *c);
extern void		connection_check_timeout();
extern void		connection_timeout(CONNECTION *c);
extern void		connection_server_forward_sound(CONNECTION *c, SOUND *s);
extern void		connection_server_foward(CONNECTION *c);
extern BUFFER		*connection_list_create();
extern EVENT		*event_create(int event_type, ...);
extern void		event_insert(CONNECTION *c, EVENT *e);
extern void		event_delete(CONNECTION *c);
extern void		event_update(CONNECTION *c);
extern void		event_destroy(EVENT *e);
extern void		event_replace(CONNECTION *c, EVENT *e);
#else
extern CONNECTION	*connection_create(/* int type */);
extern void		connection_destroy(/* CONNECTION *c */);
extern void		connection_client_open();
extern void		connection_update(/* fd_set *read_fds, fd_set *write_fds */);
extern void		connection_close(/* CONNECTION *c */);
extern void		connection_cleanup();
extern void		connection_update_fdset(/* CONNECTION *c */);
extern void		connection_reply(/* CONNECTION *c, char *fmt, ... */);
extern CONNECTION	*connection_server_open(/* SERVER *server, SOUND *sound */);
extern void		connection_server_ping(/* CONNECTION *c */);
extern void		connection_check_timeout();
extern void		connection_timeout(/* CONNECTION *c */);
extern void		connection_server_forward_sound(/* CONNECTION *c, SOUND *s */);
extern void		connection_server_foward(/* CONNECTION *c */);
extern BUFFER		*connection_list_create();
extern EVENT		*event_create(/* int event_type, ... */);
extern void		event_insert(/* CONNECTION *c, EVENT *e */);
extern void		event_delete(/* CONNECTION *c */);
extern void		event_update(/* CONNECTION *c */);
extern void		event_destroy(/* EVENT *e */);
extern void		event_replace(/* CONNECTION *c, EVENT *e */);
#endif
X
#endif /* _connection_h */
X
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/connection.h ||
echo 'restore of rplay-3.1.0/rplayd/connection.h failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/connection.h'`"
test 4592 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/connection.h: original size 4592, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/server.h ==============
if test -f 'rplay-3.1.0/rplayd/server.h' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/server.h (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/server.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/server.h' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#ifndef _server_h
#define _server_h
X
#include "conf.h"
#include "buffer.h"
X
typedef struct _server
{
X	struct _server		*next;
X	struct sockaddr_in	sin;
} SERVER;
X
extern BUFFER	*server_list;
extern SERVER	*servers;
X
#ifdef __STDC__
extern void	server_read(char *filename);
#else
extern void	server_read(/* char *filename */);
#endif
X
#endif /* _server_h */
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/server.h ||
echo 'restore of rplay-3.1.0/rplayd/server.h failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/server.h'`"
test 1148 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/server.h: original size 1148, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/host.c ==============
if test -f 'rplay-3.1.0/rplayd/host.c' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/host.c (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/host.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/host.c' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#include "conf.h"
#include "rplayd.h"
#include <netdb.h>
#include <string.h>
#include "host.h"
#include "regex.h"
#include "buffer.h"
X
#ifdef AUTH
X
static struct re_pattern_buffer	access_read, access_write, access_execute;
X
BUFFER	*host_list = NULL;
X
/*
X * read the rplay hosts file
X *
X * This routine will build a regular expression for each type of access.
X * The expressions are of the form:
X * 	\(130\.191\.224\.2\|130\.191\..*\)
X * See regex.[ch] for more details.
X */
#ifdef __STDC__
void	host_read(char *filename)
#else
void	host_read(filename)
char	*filename;
#endif
{
X	FILE		*fp;
X	char		buf[BUFSIZ], *perms, *name, *p;
X	unsigned long	addr;
X	struct in_addr	addr_in;
X	struct hostent	*hp;
X	int		n;
X	char		expr_read[HOST_EXPR_SIZE];
X	char		expr_write[HOST_EXPR_SIZE];
X	char		expr_execute[HOST_EXPR_SIZE];
X	BUFFER		*b;
X
X	fp = fopen(filename, "r");
X	if (fp == NULL)
X	{
X		report("cannot open %s\n", filename);
X		done(1);
X	}
X	
X	b = buffer_create();
X	b->status = BUFFER_KEEP;
X	strcpy(b->buf, "+hosts\r\n");
X	b->nbytes += strlen(b->buf);
X	host_list = b;
X
X	memset((char *)&access_read, 0, sizeof(access_read));
X	memset((char *)&access_write, 0, sizeof(access_write));
X	memset((char *)&access_execute, 0, sizeof(access_execute));
X
X	strcpy(expr_read, "\\(");
X	strcpy(expr_write, "\\(");
X	strcpy(expr_execute, "\\(");
X
X	while (fgets(buf, sizeof(buf), fp))
X	{
X		switch (buf[0])
X		{
X		case '#':
X		case ' ':
X		case '\t':
X		case '\n':
X			continue;
X		}
X
X		p = strchr(buf, '\n');
X		*p = '\0';
X
X		name = buf;
X		perms = strchr(buf, ':');
X		if (perms)
X		{
X			*perms = '\0';
X			perms++;
X		}
X		else
X		{
X			perms = HOST_DEFAULT_ACCESS;
X		}
X
X		n = strlen(buf) + strlen(perms) + 3; /* room for : \r\n */
X
X		if (b->nbytes + n > BUFFER_SIZE)
X		{
X			b->next = buffer_create();
X			b = b->next;
X			b->status = BUFFER_KEEP;
X		}
X
X		strcat(b->buf, name);
X		strcat(b->buf, ":");
X		strcat(b->buf, perms);
X		strcat(b->buf, "\r\n");
X		b->nbytes += n;
X
X		if (strchr(name, '*'))
X		{
X			name = host_ip_to_regex(name);
X		}
X		else
X		{
X			addr = inet_addr(name);
X			if (addr == 0xffffffff)
X			{
X				hp = gethostbyname(name);
X				if (hp == NULL)
X				{
X					report("%s unknown host\n", name);
X					done(1);
X				}
X				memcpy((char *)&addr, (char *)hp->h_addr, hp->h_length);
X			}
X			memcpy((char *)&addr_in, (char *)&addr, sizeof(addr_in));
X			name = host_ip_to_regex(inet_ntoa(addr_in));
X		}
X		
X		for (p = perms; *p; p++)
X		{
X			switch (*p)
X			{
X			case HOST_READ:
X				strcat(expr_read, name);
X				strcat(expr_read, "\\|");
X				break;
X				
X			case HOST_WRITE:
X				strcat(expr_write, name);
X				strcat(expr_write, "\\|");
X				break;
X				
X			case HOST_EXECUTE:
X				strcat(expr_execute, name);
X				strcat(expr_execute, "\\|");
X				break;
X
X			default:
X				report("'%c' unknown host access permission\n", *p);
X				done(1);
X			}
X		}
X	}
X
X	fclose(fp);
X	
X	if (b->nbytes + 3 > BUFFER_SIZE) /* room for .\r\n */
X	{
X		b->next = buffer_create();
X		b = b->next;
X		b->status = BUFFER_KEEP;
X	}
X	strcat(b->buf, ".\r\n");
X	b->nbytes += 3;
X
X	if (strlen(expr_read) == 2)
X	{
X		strcat(expr_read, "\\)");
X	}
X	else
X	{
X		expr_read[strlen(expr_read)-1] = ')';
X	}
X	if (strlen(expr_write) == 2)
X	{
X		strcat(expr_write, "\\)");
X	}
X	else
X	{
X		expr_write[strlen(expr_write)-1] = ')';
X	}
X	if (strlen(expr_execute) == 2)
X	{
X		strcat(expr_execute, "\\)");
X	}
X	else
X	{
X		expr_execute[strlen(expr_execute)-1] = ')';
X	}
X
#ifdef DEBUG
X	printf("expr_read: %s\n", expr_read);
X	printf("expr_write: %s\n", expr_write);
X	printf("expr_execute: %s\n", expr_execute);
#endif
X
X	p = re_compile_pattern(expr_read, strlen(expr_read), &access_read);
X	if (p != NULL)
X	{
X		report("re_compile_pattern: %s\n", p);
X		done(1);
X	}
X
X	p = re_compile_pattern(expr_write, strlen(expr_write), &access_write);
X	if (p != NULL)
X	{
X		report("re_compile_pattern: %s\n", p);
X		done(1);
X	}
X	
X	p = re_compile_pattern(expr_execute, strlen(expr_execute), &access_execute);
X	if (p != NULL)
X	{
X		report("re_compile_pattern: %s\n", p);
X		done(1);
X	}
}
X
#ifdef __STDC__
int	host_access(struct sockaddr_in sin, char access_mode)
#else
int	host_access(sin, access_mode)
struct sockaddr_in	sin;
char			access_mode;
#endif
{
X	char				*p;
X	struct re_pattern_buffer	*re;
X
X	p = inet_ntoa(sin.sin_addr);
X	
X	switch (access_mode)
X	{
X	case HOST_READ:
X		re = &access_read;
X		break;
X		
X	case HOST_WRITE:
X		re = &access_write;
X		break;
X		
X	case HOST_EXECUTE:
X		re = &access_execute;
X		break;
X
X	default:
X		report("host_access: unknown access mode '%s'\n", access_mode);
X		done(1);
X	}
X
X	return re_match(re, p, strlen(p), 0, 0) > 0 ? 1 : 0;
}
X
#ifdef __STDC__
char	*host_ip_to_regex(char *p)
#else
char	*host_ip_to_regex(p)
char	*p;
#endif
{
X	static char	buf[64];
X	char		*q;
X	
X	for (q = buf; *p; p++, q++)
X	{
X		switch (*p)
X		{
X		case '.':
X			*q++ = '\\';
X			*q = '.';
X			break;
X			
X		case '*':
X			*q++ = '.';
X			*q = '*';
X			break;
X			
X		default:
X			*q = *p;
X		}
X	}
X	
X	*q = '\0';
X	
X	return buf;
}
X
#endif /* AUTH */
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/host.c ||
echo 'restore of rplay-3.1.0/rplayd/host.c failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/host.c'`"
test 5676 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/host.c: original size 5676, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/regex.c ==============
if test -f 'rplay-3.1.0/rplayd/regex.c' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/regex.c (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/regex.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/regex.c' &&
/* Extended regular expression matching and search library,
X   version 0.12.
X   (Implements POSIX draft P10003.2/D11.2, except for
X   internationalization features.)
X
X   Copyright (C) 1993 Free Software Foundation, Inc.
X
X   This program is free software; you can redistribute it and/or modify
X   it under the terms of the GNU General Public License as published by
X   the Free Software Foundation; either version 2, or (at your option)
X   any later version.
X
X   This program is distributed in the hope that it will be useful,
X   but WITHOUT ANY WARRANTY; without even the implied warranty of
X   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X   GNU General Public License for more details.
X
X   You should have received a copy of the GNU General Public License
X   along with this program; if not, write to the Free Software
X   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
X
#include "conf.h"
#define _CONST_
#define REGEX_MALLOC
#define HAVE_STRING_H
#define STDC_HEADERS
X
/* AIX requires this to be the first thing in the file. */
#if defined (_AIX) && !defined (REGEX_MALLOC)
X  #pragma alloca
#endif
X
#define _GNU_SOURCE
X
/* We need this for `regex.h', and perhaps for the Emacs include files.  */
#include <sys/types.h>
X
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
X
/* The `emacs' switch turns on certain matching commands
X   that make sense only in Emacs. */
#ifdef emacs
X
#include "lisp.h"
#include "buffer.h"
#include "syntax.h"
X
/* Emacs uses `NULL' as a predicate.  */
#undef NULL
X
#else  /* not emacs */
X
/* We used to test for `BSTRING' here, but only GCC and Emacs define
X   `BSTRING', as far as I know, and neither of them use this code.  */
#ifdef HAVE_STRING_H
#ifdef STDC_HEADERS
#include <string.h>
#ifndef bcmp
#define bcmp(s1, s2, n)	memcmp ((char *)(s1), (char *)(s2), (n))
#endif
#ifndef bcopy
#define bcopy(s, d, n)	memcpy ((char *)(d), (char *)(s), (n))
#endif
#ifndef bzero
#define bzero(s, n)	memset ((char *)(s), 0, (n))
#endif
#else
#include <strings.h>
#endif
#endif
X
#ifdef STDC_HEADERS
#include <stdlib.h>
#else
char *malloc ();
char *realloc ();
#endif
X
/* Define the syntax stuff for \<, \>, etc.  */
X
/* This must be nonzero for the wordchar and notwordchar pattern
X   commands in re_match_2.  */
#ifndef Sword 
#define Sword 1
#endif
X
#ifdef SYNTAX_TABLE
X
extern char *re_syntax_table;
X
#else /* not SYNTAX_TABLE */
X
/* How many characters in the character set.  */
#define CHAR_SET_SIZE 256
X
static char re_syntax_table[CHAR_SET_SIZE];
X
static void
init_syntax_once ()
{
X   register int c;
X   static int done = 0;
X
X   if (done)
X     return;
X
X   bzero (re_syntax_table, sizeof re_syntax_table);
X
X   for (c = 'a'; c <= 'z'; c++)
X     re_syntax_table[c] = Sword;
X
X   for (c = 'A'; c <= 'Z'; c++)
X     re_syntax_table[c] = Sword;
X
X   for (c = '0'; c <= '9'; c++)
X     re_syntax_table[c] = Sword;
X
X   re_syntax_table['_'] = Sword;
X
X   done = 1;
}
X
#endif /* not SYNTAX_TABLE */
X
#define SYNTAX(c) re_syntax_table[c]
X
#endif /* not emacs */
X
/* Get the interface, including the syntax bits.  */
#include "regex.h"
X
/* isalpha etc. are used for the character classes.  */
#include <ctype.h>
X
#ifndef isascii
#define isascii(c) 1
#endif
X
#ifdef isblank
#define ISBLANK(c) (isascii (c) && isblank (c))
#else
#define ISBLANK(c) ((c) == ' ' || (c) == '\t')
#endif
#ifdef isgraph
#define ISGRAPH(c) (isascii (c) && isgraph (c))
#else
#define ISGRAPH(c) (isascii (c) && isprint (c) && !isspace (c))
#endif
X
#define ISPRINT(c) (isascii (c) && isprint (c))
#define ISDIGIT(c) (isascii (c) && isdigit (c))
#define ISALNUM(c) (isascii (c) && isalnum (c))
#define ISALPHA(c) (isascii (c) && isalpha (c))
#define ISCNTRL(c) (isascii (c) && iscntrl (c))
#define ISLOWER(c) (isascii (c) && islower (c))
#define ISPUNCT(c) (isascii (c) && ispunct (c))
#define ISSPACE(c) (isascii (c) && isspace (c))
#define ISUPPER(c) (isascii (c) && isupper (c))
#define ISXDIGIT(c) (isascii (c) && isxdigit (c))
X
#ifndef NULL
#define NULL 0
#endif
X
/* We remove any previous definition of `SIGN_EXTEND_CHAR',
X   since ours (we hope) works properly with all combinations of
X   machines, compilers, `char' and `unsigned char' argument types.
X   (Per Bothner suggested the basic approach.)  */
#undef SIGN_EXTEND_CHAR
#if __STDC__
#define SIGN_EXTEND_CHAR(c) ((signed char) (c))
#else  /* not __STDC__ */
/* As in Harbison and Steele.  */
#define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128)
#endif
X
/* Should we use malloc or alloca?  If REGEX_MALLOC is not defined, we
X   use `alloca' instead of `malloc'.  This is because using malloc in
X   re_search* or re_match* could cause memory leaks when C-g is used in
X   Emacs; also, malloc is slower and causes storage fragmentation.  On
X   the other hand, malloc is more portable, and easier to debug.  
X   
X   Because we sometimes use alloca, some routines have to be macros,
X   not functions -- `alloca'-allocated space disappears at the end of the
X   function it is called in.  */
X
#ifdef REGEX_MALLOC
X
#define REGEX_ALLOCATE malloc
#define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize)
X
#else /* not REGEX_MALLOC  */
X
/* Emacs already defines alloca, sometimes.  */
#ifndef alloca
X
/* Make alloca work the best possible way.  */
#ifdef __GNUC__
#define alloca __builtin_alloca
#else /* not __GNUC__ */
#if HAVE_ALLOCA_H
#include <alloca.h>
#else /* not __GNUC__ or HAVE_ALLOCA_H */
#ifndef _AIX /* Already did AIX, up at the top.  */
char *alloca ();
#endif /* not _AIX */
#endif /* not HAVE_ALLOCA_H */ 
#endif /* not __GNUC__ */
X
#endif /* not alloca */
X
#define REGEX_ALLOCATE alloca
X
/* Assumes a `char *destination' variable.  */
#define REGEX_REALLOCATE(source, osize, nsize)				\
X  (destination = (char *) alloca (nsize),				\
X   bcopy (source, destination, osize),					\
X   destination)
X
#endif /* not REGEX_MALLOC */
X
X
/* True if `size1' is non-NULL and PTR is pointing anywhere inside
X   `string1' or just past its end.  This works if PTR is NULL, which is
X   a good thing.  */
#define FIRST_STRING_P(ptr) 					\
X  (size1 && string1 <= (ptr) && (ptr) <= string1 + size1)
X
/* (Re)Allocate N items of type T using malloc, or fail.  */
#define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t)))
#define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t)))
#define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t)))
X
#define BYTEWIDTH 8 /* In bits.  */
X
#define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
X
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
X
typedef char boolean;
#define false 0
#define true 1
X
/* These are the command codes that appear in compiled regular
X   expressions.  Some opcodes are followed by argument bytes.  A
X   command code can specify any interpretation whatsoever for its
X   arguments.  Zero bytes may appear in the compiled regular expression.
X
X   The value of `exactn' is needed in search.c (search_buffer) in Emacs.
X   So regex.h defines a symbol `RE_EXACTN_VALUE' to be 1; the value of
X   `exactn' we use here must also be 1.  */
X
typedef enum
{
X  no_op = 0,
X
X        /* Followed by one byte giving n, then by n literal bytes.  */
X  exactn = 1,
X
X        /* Matches any (more or less) character.  */
X  anychar,
X
X        /* Matches any one char belonging to specified set.  First
X           following byte is number of bitmap bytes.  Then come bytes
X           for a bitmap saying which chars are in.  Bits in each byte
X           are ordered low-bit-first.  A character is in the set if its
X           bit is 1.  A character too large to have a bit in the map is
X           automatically not in the set.  */
X  charset,
X
X        /* Same parameters as charset, but match any character that is
X           not one of those specified.  */
X  charset_not,
X
X        /* Start remembering the text that is matched, for storing in a
X           register.  Followed by one byte with the register number, in
X           the range 0 to one less than the pattern buffer's re_nsub
X           field.  Then followed by one byte with the number of groups
X           inner to this one.  (This last has to be part of the
X           start_memory only because we need it in the on_failure_jump
X           of re_match_2.)  */
X  start_memory,
X
X        /* Stop remembering the text that is matched and store it in a
X           memory register.  Followed by one byte with the register
X           number, in the range 0 to one less than `re_nsub' in the
X           pattern buffer, and one byte with the number of inner groups,
X           just like `start_memory'.  (We need the number of inner
X           groups here because we don't have any easy way of finding the
X           corresponding start_memory when we're at a stop_memory.)  */
X  stop_memory,
X
X        /* Match a duplicate of something remembered. Followed by one
X           byte containing the register number.  */
X  duplicate,
X
X        /* Fail unless at beginning of line.  */
X  begline,
X
X        /* Fail unless at end of line.  */
X  endline,
X
X        /* Succeeds if at beginning of buffer (if emacs) or at beginning
X           of string to be matched (if not).  */
X  begbuf,
X
X        /* Analogously, for end of buffer/string.  */
X  endbuf,
X 
X        /* Followed by two byte relative address to which to jump.  */
X  jump, 
X
X	/* Same as jump, but marks the end of an alternative.  */
X  jump_past_alt,
X
X        /* Followed by two-byte relative address of place to resume at
X           in case of failure.  */
X  on_failure_jump,
X	
X        /* Like on_failure_jump, but pushes a placeholder instead of the
X           current string position when executed.  */
X  on_failure_keep_string_jump,
X  
X        /* Throw away latest failure point and then jump to following
X           two-byte relative address.  */
X  pop_failure_jump,
X
X        /* Change to pop_failure_jump if know won't have to backtrack to
X           match; otherwise change to jump.  This is used to jump
X           back to the beginning of a repeat.  If what follows this jump
X           clearly won't match what the repeat does, such that we can be
X           sure that there is no use backtracking out of repetitions
X           already matched, then we change it to a pop_failure_jump.
X           Followed by two-byte address.  */
X  maybe_pop_jump,
X
X        /* Jump to following two-byte address, and push a dummy failure
X           point. This failure point will be thrown away if an attempt
X           is made to use it for a failure.  A `+' construct makes this
X           before the first repeat.  Also used as an intermediary kind
X           of jump when compiling an alternative.  */
X  dummy_failure_jump,
X
X	/* Push a dummy failure point and continue.  Used at the end of
X	   alternatives.  */
X  push_dummy_failure,
X
X        /* Followed by two-byte relative address and two-byte number n.
X           After matching N times, jump to the address upon failure.  */
X  succeed_n,
X
X        /* Followed by two-byte relative address, and two-byte number n.
X           Jump to the address N times, then fail.  */
X  jump_n,
X
X        /* Set the following two-byte relative address to the
X           subsequent two-byte number.  The address *includes* the two
X           bytes of number.  */
X  set_number_at,
X
X  wordchar,	/* Matches any word-constituent character.  */
X  notwordchar,	/* Matches any char that is not a word-constituent.  */
X
X  wordbeg,	/* Succeeds if at word beginning.  */
X  wordend,	/* Succeeds if at word end.  */
X
X  wordbound,	/* Succeeds if at a word boundary.  */
X  notwordbound	/* Succeeds if not at a word boundary.  */
X
#ifdef emacs
X  ,before_dot,	/* Succeeds if before point.  */
X  at_dot,	/* Succeeds if at point.  */
X  after_dot,	/* Succeeds if after point.  */
X
X	/* Matches any character whose syntax is specified.  Followed by
X           a byte which contains a syntax code, e.g., Sword.  */
X  syntaxspec,
X
X	/* Matches any character whose syntax is not that specified.  */
X  notsyntaxspec
#endif /* emacs */
} re_opcode_t;
X
/* Common operations on the compiled pattern.  */
X
/* Store NUMBER in two contiguous bytes starting at DESTINATION.  */
X
#define STORE_NUMBER(destination, number)				\
X  do {									\
X    (destination)[0] = (number) & 0377;					\
X    (destination)[1] = (number) >> 8;					\
X  } while (0)
X
/* Same as STORE_NUMBER, except increment DESTINATION to
X   the byte after where the number is stored.  Therefore, DESTINATION
X   must be an lvalue.  */
X
#define STORE_NUMBER_AND_INCR(destination, number)			\
X  do {									\
X    STORE_NUMBER (destination, number);					\
X    (destination) += 2;							\
X  } while (0)
X
/* Put into DESTINATION a number stored in two contiguous bytes starting
X   at SOURCE.  */
X
#define EXTRACT_NUMBER(destination, source)				\
X  do {									\
X    (destination) = *(source) & 0377;					\
X    (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8;		\
X  } while (0)
X
#ifdef DEBUG
static void
extract_number (dest, source)
X    int *dest;
X    unsigned char *source;
{
X  int temp = SIGN_EXTEND_CHAR (*(source + 1)); 
X  *dest = *source & 0377;
X  *dest += temp << 8;
}
X
#ifndef EXTRACT_MACROS /* To debug the macros.  */
#undef EXTRACT_NUMBER
#define EXTRACT_NUMBER(dest, src) extract_number (&dest, src)
#endif /* not EXTRACT_MACROS */
X
#endif /* DEBUG */
X
/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number.
X   SOURCE must be an lvalue.  */
X
#define EXTRACT_NUMBER_AND_INCR(destination, source)			\
X  do {									\
X    EXTRACT_NUMBER (destination, source);				\
X    (source) += 2; 							\
X  } while (0)
X
#ifdef DEBUG
static void
extract_number_and_incr (destination, source)
X    int *destination;
X    unsigned char **source;
{ 
X  extract_number (destination, *source);
X  *source += 2;
}
X
#ifndef EXTRACT_MACROS
#undef EXTRACT_NUMBER_AND_INCR
#define EXTRACT_NUMBER_AND_INCR(dest, src) \
X  extract_number_and_incr (&dest, &src)
#endif /* not EXTRACT_MACROS */
X
#endif /* DEBUG */
X
/* If DEBUG is defined, Regex prints many voluminous messages about what
X   it is doing (if the variable `debug' is nonzero).  If linked with the
X   main program in `iregex.c', you can enter patterns and strings
X   interactively.  And if linked with the main program in `main.c' and
X   the other test files, you can run the already-written tests.  */
X
#ifdef DEBUG
X
/* We use standard I/O for debugging.  */
#include <stdio.h>
X
/* It is useful to test things that ``must'' be true when debugging.  */
#include <assert.h>
X
static int debug = 0;
X
#define DEBUG_STATEMENT(e) e
#define DEBUG_PRINT1(x) if (debug) printf (x)
#define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2)
#define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3)
#define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4)
#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) 				\
X  if (debug) print_partial_compiled_pattern (s, e)
#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)			\
X  if (debug) print_double_string (w, s1, sz1, s2, sz2)
X
X
extern void printchar ();
X
/* Print the fastmap in human-readable form.  */
X
void
print_fastmap (fastmap)
X    char *fastmap;
{
X  unsigned was_a_range = 0;
X  unsigned i = 0;  
X  
X  while (i < (1 << BYTEWIDTH))
X    {
X      if (fastmap[i++])
X	{
X	  was_a_range = 0;
X          printchar (i - 1);
X          while (i < (1 << BYTEWIDTH)  &&  fastmap[i])
X            {
X              was_a_range = 1;
X              i++;
X            }
X	  if (was_a_range)
X            {
X              printf ("-");
X              printchar (i - 1);
X            }
X        }
X    }
X  putchar ('\n'); 
}
X
X
/* Print a compiled pattern string in human-readable form, starting at
X   the START pointer into it and ending just before the pointer END.  */
X
void
print_partial_compiled_pattern (start, end)
X    unsigned char *start;
X    unsigned char *end;
{
X  int mcnt, mcnt2;
X  unsigned char *p = start;
X  unsigned char *pend = end;
X
X  if (start == NULL)
X    {
X      printf ("(null)\n");
X      return;
X    }
X    
X  /* Loop over pattern commands.  */
X  while (p < pend)
X    {
X      switch ((re_opcode_t) *p++)
X	{
X        case no_op:
X          printf ("/no_op");
X          break;
X
X	case exactn:
X	  mcnt = *p++;
X          printf ("/exactn/%d", mcnt);
X          do
X	    {
X              putchar ('/');
X	      printchar (*p++);
X            }
X          while (--mcnt);
X          break;
X
X	case start_memory:
X          mcnt = *p++;
X          printf ("/start_memory/%d/%d", mcnt, *p++);
X          break;
X
X	case stop_memory:
X          mcnt = *p++;
X	  printf ("/stop_memory/%d/%d", mcnt, *p++);
X          break;
X
X	case duplicate:
X	  printf ("/duplicate/%d", *p++);
X	  break;
X
X	case anychar:
X	  printf ("/anychar");
X	  break;
X
X	case charset:
X        case charset_not:
X          {
X            register int c;
X
X            printf ("/charset%s",
X	            (re_opcode_t) *(p - 1) == charset_not ? "_not" : "");
X            
X            assert (p + *p < pend);
X
X            for (c = 0; c < *p; c++)
X              {
X                unsigned bit;
X                unsigned char map_byte = p[1 + c];
X                
X                putchar ('/');
X
X		for (bit = 0; bit < BYTEWIDTH; bit++)
X                  if (map_byte & (1 << bit))
X                    printchar (c * BYTEWIDTH + bit);
X              }
X	    p += 1 + *p;
X	    break;
X	  }
X
X	case begline:
X	  printf ("/begline");
X          break;
X
X	case endline:
X          printf ("/endline");
X          break;
X
X	case on_failure_jump:
X          extract_number_and_incr (&mcnt, &p);
X  	  printf ("/on_failure_jump/0/%d", mcnt);
X          break;
X
X	case on_failure_keep_string_jump:
X          extract_number_and_incr (&mcnt, &p);
X  	  printf ("/on_failure_keep_string_jump/0/%d", mcnt);
X          break;
X
X	case dummy_failure_jump:
X          extract_number_and_incr (&mcnt, &p);
X  	  printf ("/dummy_failure_jump/0/%d", mcnt);
X          break;
X
X	case push_dummy_failure:
X          printf ("/push_dummy_failure");
X          break;
X          
X        case maybe_pop_jump:
X          extract_number_and_incr (&mcnt, &p);
X  	  printf ("/maybe_pop_jump/0/%d", mcnt);
X	  break;
X
X        case pop_failure_jump:
X	  extract_number_and_incr (&mcnt, &p);
X  	  printf ("/pop_failure_jump/0/%d", mcnt);
X	  break;          
X          
X        case jump_past_alt:
X	  extract_number_and_incr (&mcnt, &p);
X  	  printf ("/jump_past_alt/0/%d", mcnt);
X	  break;          
X          
X        case jump:
X	  extract_number_and_incr (&mcnt, &p);
X  	  printf ("/jump/0/%d", mcnt);
X	  break;
X
X        case succeed_n: 
X          extract_number_and_incr (&mcnt, &p);
X          extract_number_and_incr (&mcnt2, &p);
X 	  printf ("/succeed_n/0/%d/0/%d", mcnt, mcnt2);
X          break;
X        
X        case jump_n: 
X          extract_number_and_incr (&mcnt, &p);
X          extract_number_and_incr (&mcnt2, &p);
X 	  printf ("/jump_n/0/%d/0/%d", mcnt, mcnt2);
X          break;
X        
X        case set_number_at: 
X          extract_number_and_incr (&mcnt, &p);
X          extract_number_and_incr (&mcnt2, &p);
X 	  printf ("/set_number_at/0/%d/0/%d", mcnt, mcnt2);
X          break;
X        
X        case wordbound:
X	  printf ("/wordbound");
X	  break;
X
X	case notwordbound:
X	  printf ("/notwordbound");
X          break;
X
X	case wordbeg:
X	  printf ("/wordbeg");
X	  break;
X          
X	case wordend:
X	  printf ("/wordend");
X          
#ifdef emacs
X	case before_dot:
X	  printf ("/before_dot");
X          break;
X
X	case at_dot:
X	  printf ("/at_dot");
X          break;
X
X	case after_dot:
X	  printf ("/after_dot");
X          break;
X
X	case syntaxspec:
X          printf ("/syntaxspec");
X	  mcnt = *p++;
X	  printf ("/%d", mcnt);
X          break;
X	  
X	case notsyntaxspec:
X          printf ("/notsyntaxspec");
X	  mcnt = *p++;
X	  printf ("/%d", mcnt);
X	  break;
#endif /* emacs */
X
X	case wordchar:
X	  printf ("/wordchar");
X          break;
X	  
X	case notwordchar:
X	  printf ("/notwordchar");
X          break;
X
X	case begbuf:
X	  printf ("/begbuf");
X          break;
X
X	case endbuf:
X	  printf ("/endbuf");
X          break;
X
X        default:
X          printf ("?%d", *(p-1));
X	}
X    }
X  printf ("/\n");
}
X
X
void
print_compiled_pattern (bufp)
X    struct re_pattern_buffer *bufp;
{
X  unsigned char *buffer = bufp->buffer;
X
X  print_partial_compiled_pattern (buffer, buffer + bufp->used);
X  printf ("%d bytes used/%d bytes allocated.\n", bufp->used, bufp->allocated);
X
X  if (bufp->fastmap_accurate && bufp->fastmap)
X    {
X      printf ("fastmap: ");
X      print_fastmap (bufp->fastmap);
X    }
X
X  printf ("re_nsub: %d\t", bufp->re_nsub);
X  printf ("regs_alloc: %d\t", bufp->regs_allocated);
X  printf ("can_be_null: %d\t", bufp->can_be_null);
X  printf ("newline_anchor: %d\n", bufp->newline_anchor);
X  printf ("no_sub: %d\t", bufp->no_sub);
X  printf ("not_bol: %d\t", bufp->not_bol);
X  printf ("not_eol: %d\t", bufp->not_eol);
X  printf ("syntax: %d\n", bufp->syntax);
X  /* Perhaps we should print the translate table?  */
}
X
X
void
print_double_string (where, string1, size1, string2, size2)
X    _CONST_ char *where;
X    _CONST_ char *string1;
X    _CONST_ char *string2;
X    int size1;
X    int size2;
{
X  unsigned this_char;
X  
X  if (where == NULL)
X    printf ("(null)");
X  else
X    {
X      if (FIRST_STRING_P (where))
X        {
X          for (this_char = where - string1; this_char < size1; this_char++)
X            printchar (string1[this_char]);
X
X          where = string2;    
X        }
X
X      for (this_char = where - string2; this_char < size2; this_char++)
X        printchar (string2[this_char]);
X    }
}
X
#else /* not DEBUG */
X
#undef assert
#define assert(e)
X
#define DEBUG_STATEMENT(e)
#define DEBUG_PRINT1(x)
#define DEBUG_PRINT2(x1, x2)
#define DEBUG_PRINT3(x1, x2, x3)
#define DEBUG_PRINT4(x1, x2, x3, x4)
#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e)
#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)
X
#endif /* not DEBUG */
X
/* Set by `re_set_syntax' to the current regexp syntax to recognize.  Can
X   also be assigned to arbitrarily: each pattern buffer stores its own
X   syntax, so it can be changed between regex compilations.  */
reg_syntax_t re_syntax_options = RE_SYNTAX_EMACS;
X
X
/* Specify the precise syntax of regexps for compilation.  This provides
X   for compatibility for various utilities which historically have
X   different, incompatible syntaxes.
X
X   The argument SYNTAX is a bit mask comprised of the various bits
X   defined in regex.h.  We return the old syntax.  */
X
reg_syntax_t
re_set_syntax (syntax)
X    reg_syntax_t syntax;
{
X  reg_syntax_t ret = re_syntax_options;
X  
X  re_syntax_options = syntax;
X  return ret;
}
X
/* This table gives an error message for each of the error codes listed
X   in regex.h.  Obviously the order here has to be same as there.  */
X
static _CONST_ char *re_error_msg[] =
X  { NULL,					/* REG_NOERROR */
X    "No match",					/* REG_NOMATCH */
X    "Invalid regular expression",		/* REG_BADPAT */
X    "Invalid collation character",		/* REG_ECOLLATE */
X    "Invalid character class name",		/* REG_ECTYPE */
X    "Trailing backslash",			/* REG_EESCAPE */
X    "Invalid back reference",			/* REG_ESUBREG */
X    "Unmatched [ or [^",			/* REG_EBRACK */
X    "Unmatched ( or \\(",			/* REG_EPAREN */
X    "Unmatched \\{",				/* REG_EBRACE */
X    "Invalid content of \\{\\}",		/* REG_BADBR */
X    "Invalid range end",			/* REG_ERANGE */
X    "Memory exhausted",				/* REG_ESPACE */
X    "Invalid preceding regular expression",	/* REG_BADRPT */
X    "Premature end of regular expression",	/* REG_EEND */
X    "Regular expression too big",		/* REG_ESIZE */
X    "Unmatched ) or \\)",			/* REG_ERPAREN */
X  };
X
/* Subroutine declarations and macros for regex_compile.  */
X
static void store_op1 (), store_op2 ();
static void insert_op1 (), insert_op2 ();
static boolean at_begline_loc_p (), at_endline_loc_p ();
static boolean group_in_compile_stack ();
static reg_errcode_t compile_range ();
X
/* Fetch the next character in the uncompiled pattern---translating it 
X   if necessary.  Also cast from a signed character in the constant
X   string passed to us by the user to an unsigned char that we can use
X   as an array index (in, e.g., `translate').  */
#define PATFETCH(c)							\
X  do {if (p == pend) return REG_EEND;					\
X    c = (unsigned char) *p++;						\
X    if (translate) c = translate[c]; 					\
X  } while (0)
X
/* Fetch the next character in the uncompiled pattern, with no
X   translation.  */
#define PATFETCH_RAW(c)							\
X  do {if (p == pend) return REG_EEND;					\
X    c = (unsigned char) *p++; 						\
X  } while (0)
X
/* Go backwards one character in the pattern.  */
#define PATUNFETCH p--
X
X
/* If `translate' is non-null, return translate[D], else just D.  We
X   cast the subscript to translate because some data is declared as
X   `char *', to avoid warnings when a string constant is passed.  But
X   when we use a character as a subscript we must make it unsigned.  */
#define TRANSLATE(d) (translate ? translate[(unsigned char) (d)] : (d))
X
X
/* Macros for outputting the compiled pattern into `buffer'.  */
X
/* If the buffer isn't allocated when it comes in, use this.  */
#define INIT_BUF_SIZE  32
X
/* Make sure we have at least N more bytes of space in buffer.  */
#define GET_BUFFER_SPACE(n)						\
X    while (b - bufp->buffer + (n) > bufp->allocated)			\
X      EXTEND_BUFFER ()
X
/* Make sure we have one more byte of buffer space and then add C to it.  */
#define BUF_PUSH(c)							\
X  do {									\
X    GET_BUFFER_SPACE (1);						\
X    *b++ = (unsigned char) (c);						\
X  } while (0)
X
X
/* Ensure we have two more bytes of buffer space and then append C1 and C2.  */
#define BUF_PUSH_2(c1, c2)						\
X  do {									\
X    GET_BUFFER_SPACE (2);						\
X    *b++ = (unsigned char) (c1);					\
X    *b++ = (unsigned char) (c2);					\
X  } while (0)
X
X
/* As with BUF_PUSH_2, except for three bytes.  */
#define BUF_PUSH_3(c1, c2, c3)						\
X  do {									\
X    GET_BUFFER_SPACE (3);						\
X    *b++ = (unsigned char) (c1);					\
X    *b++ = (unsigned char) (c2);					\
X    *b++ = (unsigned char) (c3);					\
X  } while (0)
X
X
/* Store a jump with opcode OP at LOC to location TO.  We store a
X   relative address offset by the three bytes the jump itself occupies.  */
#define STORE_JUMP(op, loc, to) \
X  store_op1 (op, loc, (to) - (loc) - 3)
X
/* Likewise, for a two-argument jump.  */
#define STORE_JUMP2(op, loc, to, arg) \
X  store_op2 (op, loc, (to) - (loc) - 3, arg)
X
/* Like `STORE_JUMP', but for inserting.  Assume `b' is the buffer end.  */
#define INSERT_JUMP(op, loc, to) \
X  insert_op1 (op, loc, (to) - (loc) - 3, b)
X
/* Like `STORE_JUMP2', but for inserting.  Assume `b' is the buffer end.  */
#define INSERT_JUMP2(op, loc, to, arg) \
X  insert_op2 (op, loc, (to) - (loc) - 3, arg, b)
X
X
/* This is not an arbitrary limit: the arguments which represent offsets
X   into the pattern are two bytes long.  So if 2^16 bytes turns out to
X   be too small, many things would have to change.  */
#define MAX_BUF_SIZE (1L << 16)
X
X
/* Extend the buffer by twice its current size via realloc and
X   reset the pointers that pointed into the old block to point to the
X   correct places in the new one.  If extending the buffer results in it
X   being larger than MAX_BUF_SIZE, then flag memory exhausted.  */
#define EXTEND_BUFFER()							\
X  do { 									\
X    unsigned char *old_buffer = bufp->buffer;				\
X    if (bufp->allocated == MAX_BUF_SIZE) 				\
X      return REG_ESIZE;							\
X    bufp->allocated <<= 1;						\
X    if (bufp->allocated > MAX_BUF_SIZE)					\
X      bufp->allocated = MAX_BUF_SIZE; 					\
X    bufp->buffer = (unsigned char *) realloc (bufp->buffer, bufp->allocated);\
X    if (bufp->buffer == NULL)						\
X      return REG_ESPACE;						\
X    /* If the buffer moved, move all the pointers into it.  */		\
X    if (old_buffer != bufp->buffer)					\
X      {									\
X        b = (b - old_buffer) + bufp->buffer;				\
X        begalt = (begalt - old_buffer) + bufp->buffer;			\
X        if (fixup_alt_jump)						\
X          fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer;\
X        if (laststart)							\
X          laststart = (laststart - old_buffer) + bufp->buffer;		\
X        if (pending_exact)						\
X          pending_exact = (pending_exact - old_buffer) + bufp->buffer;	\
X      }									\
X  } while (0)
X
X
/* Since we have one byte reserved for the register number argument to
X   {start,stop}_memory, the maximum number of groups we can report
X   things about is what fits in that byte.  */
#define MAX_REGNUM 255
X
/* But patterns can have more than `MAX_REGNUM' registers.  We just
X   ignore the excess.  */
typedef unsigned regnum_t;
X
X
/* Macros for the compile stack.  */
X
/* Since offsets can go either forwards or backwards, this type needs to
X   be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1.  */
typedef int pattern_offset_t;
X
typedef struct
{
X  pattern_offset_t begalt_offset;
X  pattern_offset_t fixup_alt_jump;
X  pattern_offset_t inner_group_offset;
X  pattern_offset_t laststart_offset;  
X  regnum_t regnum;
} compile_stack_elt_t;
X
X
typedef struct
{
X  compile_stack_elt_t *stack;
X  unsigned size;
X  unsigned avail;			/* Offset of next open position.  */
} compile_stack_type;
X
X
#define INIT_COMPILE_STACK_SIZE 32
X
#define COMPILE_STACK_EMPTY  (compile_stack.avail == 0)
#define COMPILE_STACK_FULL  (compile_stack.avail == compile_stack.size)
X
/* The next available element.  */
#define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail])
X
X
/* Set the bit for character C in a list.  */
#define SET_LIST_BIT(c)                               \
X  (b[((unsigned char) (c)) / BYTEWIDTH]               \
X   |= 1 << (((unsigned char) c) % BYTEWIDTH))
X
X
/* Get the next unsigned number in the uncompiled pattern.  */
#define GET_UNSIGNED_NUMBER(num) 					\
X  { if (p != pend)							\
X     {									\
X       PATFETCH (c); 							\
X       while (ISDIGIT (c)) 						\
X         { 								\
X           if (num < 0)							\
X              num = 0;							\
X           num = num * 10 + c - '0'; 					\
X           if (p == pend) 						\
X              break; 							\
X           PATFETCH (c);						\
X         } 								\
X       } 								\
X    }		
X
#define CHAR_CLASS_MAX_LENGTH  6 /* Namely, `xdigit'.  */
X
#define IS_CHAR_CLASS(string)						\
X   (STREQ (string, "alpha") || STREQ (string, "upper")			\
X    || STREQ (string, "lower") || STREQ (string, "digit")		\
X    || STREQ (string, "alnum") || STREQ (string, "xdigit")		\
X    || STREQ (string, "space") || STREQ (string, "print")		\
X    || STREQ (string, "punct") || STREQ (string, "graph")		\
X    || STREQ (string, "cntrl") || STREQ (string, "blank"))
X
/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX.
X   Returns one of error codes defined in `regex.h', or zero for success.
X
X   Assumes the `allocated' (and perhaps `buffer') and `translate'
X   fields are set in BUFP on entry.
X
X   If it succeeds, results are put in BUFP (if it returns an error, the
X   contents of BUFP are undefined):
X     `buffer' is the compiled pattern;
X     `syntax' is set to SYNTAX;
X     `used' is set to the length of the compiled pattern;
X     `fastmap_accurate' is zero;
X     `re_nsub' is the number of subexpressions in PATTERN;
X     `not_bol' and `not_eol' are zero;
X   
X   The `fastmap' and `newline_anchor' fields are neither
X   examined nor set.  */
X
static reg_errcode_t
regex_compile (pattern, size, syntax, bufp)
X     _CONST_ char *pattern;
X     int size;
X     reg_syntax_t syntax;
X     struct re_pattern_buffer *bufp;
{
X  /* We fetch characters from PATTERN here.  Even though PATTERN is
X     `char *' (i.e., signed), we declare these variables as unsigned, so
X     they can be reliably used as array indices.  */
X  register unsigned char c, c1;
X  
X  /* A random tempory spot in PATTERN.  */
X  _CONST_ char *p1;
X
X  /* Points to the end of the buffer, where we should append.  */
X  register unsigned char *b;
X  
X  /* Keeps track of unclosed groups.  */
X  compile_stack_type compile_stack;
X
X  /* Points to the current (ending) position in the pattern.  */
X  _CONST_ char *p = pattern;
X  _CONST_ char *pend = pattern + size;
X  
X  /* How to translate the characters in the pattern.  */
X  char *translate = bufp->translate;
X
X  /* Address of the count-byte of the most recently inserted `exactn'
X     command.  This makes it possible to tell if a new exact-match
X     character can be added to that command or if the character requires
X     a new `exactn' command.  */
X  unsigned char *pending_exact = 0;
X
X  /* Address of start of the most recently finished expression.
X     This tells, e.g., postfix * where to find the start of its
X     operand.  Reset at the beginning of groups and alternatives.  */
X  unsigned char *laststart = 0;
X
X  /* Address of beginning of regexp, or inside of last group.  */
X  unsigned char *begalt;
X
X  /* Place in the uncompiled pattern (i.e., the {) to
X     which to go back if the interval is invalid.  */
X  _CONST_ char *beg_interval;
X                
X  /* Address of the place where a forward jump should go to the end of
X     the containing expression.  Each alternative of an `or' -- except the
X     last -- ends with a forward jump of this sort.  */
X  unsigned char *fixup_alt_jump = 0;
X
X  /* Counts open-groups as they are encountered.  Remembered for the
X     matching close-group on the compile stack, so the same register
X     number is put in the stop_memory as the start_memory.  */
X  regnum_t regnum = 0;
X
#ifdef DEBUG
X  DEBUG_PRINT1 ("\nCompiling pattern: ");
X  if (debug)
X    {
X      unsigned debug_count;
X      
X      for (debug_count = 0; debug_count < size; debug_count++)
X        printchar (pattern[debug_count]);
X      putchar ('\n');
X    }
#endif /* DEBUG */
X
X  /* Initialize the compile stack.  */
X  compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t);
X  if (compile_stack.stack == NULL)
X    return REG_ESPACE;
X
X  compile_stack.size = INIT_COMPILE_STACK_SIZE;
X  compile_stack.avail = 0;
X
X  /* Initialize the pattern buffer.  */
X  bufp->syntax = syntax;
X  bufp->fastmap_accurate = 0;
X  bufp->not_bol = bufp->not_eol = 0;
X
X  /* Set `used' to zero, so that if we return an error, the pattern
X     printer (for debugging) will think there's no pattern.  We reset it
X     at the end.  */
X  bufp->used = 0;
X  
X  /* Always count groups, whether or not bufp->no_sub is set.  */
X  bufp->re_nsub = 0;				
X
#if !defined (emacs) && !defined (SYNTAX_TABLE)
X  /* Initialize the syntax table.  */
X   init_syntax_once ();
#endif
X
X  if (bufp->allocated == 0)
X    {
X      if (bufp->buffer)
X	{ /* If zero allocated, but buffer is non-null, try to realloc
X             enough space.  This loses if buffer's address is bogus, but
X             that is the user's responsibility.  */
X          RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char);
X        }
X      else
X        { /* Caller did not allocate a buffer.  Do it for them.  */
X          bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char);
X        }
X      if (!bufp->buffer) return REG_ESPACE;
X
X      bufp->allocated = INIT_BUF_SIZE;
X    }
X
X  begalt = b = bufp->buffer;
X
X  /* Loop through the uncompiled pattern until we're at the end.  */
X  while (p != pend)
X    {
X      PATFETCH (c);
X
X      switch (c)
X        {
X        case '^':
X          {
X            if (   /* If at start of pattern, it's an operator.  */
X                   p == pattern + 1
X                   /* If context independent, it's an operator.  */
X                || syntax & RE_CONTEXT_INDEP_ANCHORS
X                   /* Otherwise, depends on what's come before.  */
X                || at_begline_loc_p (pattern, p, syntax))
X              BUF_PUSH (begline);
X            else
X              goto normal_char;
X          }
X          break;
X
X
X        case '$':
X          {
X            if (   /* If at end of pattern, it's an operator.  */
X                   p == pend 
X                   /* If context independent, it's an operator.  */
X                || syntax & RE_CONTEXT_INDEP_ANCHORS
X                   /* Otherwise, depends on what's next.  */
X                || at_endline_loc_p (p, pend, syntax))
X               BUF_PUSH (endline);
X             else
X               goto normal_char;
X           }
X           break;
X
X
X	case '+':
X        case '?':
X          if ((syntax & RE_BK_PLUS_QM)
X              || (syntax & RE_LIMITED_OPS))
X            goto normal_char;
X        handle_plus:
X        case '*':
X          /* If there is no previous pattern... */
X          if (!laststart)
X            {
X              if (syntax & RE_CONTEXT_INVALID_OPS)
X                return REG_BADRPT;
X              else if (!(syntax & RE_CONTEXT_INDEP_OPS))
X                goto normal_char;
X            }
X
X          {
X            /* Are we optimizing this jump?  */
X            boolean keep_string_p = false;
X            
X            /* 1 means zero (many) matches is allowed.  */
X            char zero_times_ok = 0, many_times_ok = 0;
X
X            /* If there is a sequence of repetition chars, collapse it
X               down to just one (the right one).  We can't combine
X               interval operators with these because of, e.g., `a{2}*',
X               which should only match an even number of `a's.  */
X
X            for (;;)
X              {
X                zero_times_ok |= c != '+';
X                many_times_ok |= c != '?';
X
X                if (p == pend)
X                  break;
X
X                PATFETCH (c);
X
X                if (c == '*'
X                    || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?')))
X                  ;
X
X                else if (syntax & RE_BK_PLUS_QM  &&  c == '\\')
X                  {
X                    if (p == pend) return REG_EESCAPE;
X
X                    PATFETCH (c1);
X                    if (!(c1 == '+' || c1 == '?'))
X                      {
X                        PATUNFETCH;
X                        PATUNFETCH;
X                        break;
X                      }
X
X                    c = c1;
X                  }
X                else
X                  {
X                    PATUNFETCH;
X                    break;
X                  }
X
X                /* If we get here, we found another repeat character.  */
X               }
X
X            /* Star, etc. applied to an empty pattern is equivalent
X               to an empty pattern.  */
X            if (!laststart)  
X              break;
X
X            /* Now we know whether or not zero matches is allowed
X               and also whether or not two or more matches is allowed.  */
X            if (many_times_ok)
X              { /* More than one repetition is allowed, so put in at the
X                   end a backward relative jump from `b' to before the next
X                   jump we're going to put in below (which jumps from
X                   laststart to after this jump).  
X
X                   But if we are at the `*' in the exact sequence `.*\n',
X                   insert an unconditional jump backwards to the .,
X                   instead of the beginning of the loop.  This way we only
X                   push a failure point once, instead of every time
X                   through the loop.  */
X                assert (p - 1 > pattern);
X
X                /* Allocate the space for the jump.  */
X                GET_BUFFER_SPACE (3);
X
X                /* We know we are not at the first character of the pattern,
X                   because laststart was nonzero.  And we've already
X                   incremented `p', by the way, to be the character after
X                   the `*'.  Do we have to do something analogous here
X                   for null bytes, because of RE_DOT_NOT_NULL?  */
X                if (TRANSLATE (*(p - 2)) == TRANSLATE ('.')
X		    && zero_times_ok
X                    && p < pend && TRANSLATE (*p) == TRANSLATE ('\n')
X                    && !(syntax & RE_DOT_NEWLINE))
X                  { /* We have .*\n.  */
X                    STORE_JUMP (jump, b, laststart);
X                    keep_string_p = true;
X                  }
X                else
X                  /* Anything else.  */
X                  STORE_JUMP (maybe_pop_jump, b, laststart - 3);
X
X                /* We've added more stuff to the buffer.  */
X                b += 3;
X              }
X
X            /* On failure, jump from laststart to b + 3, which will be the
X               end of the buffer after this jump is inserted.  */
X            GET_BUFFER_SPACE (3);
X            INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump
X                                       : on_failure_jump,
X                         laststart, b + 3);
X            pending_exact = 0;
X            b += 3;
X
X            if (!zero_times_ok)
X              {
X                /* At least one repetition is required, so insert a
X                   `dummy_failure_jump' before the initial
X                   `on_failure_jump' instruction of the loop. This
X                   effects a skip over that instruction the first time
X                   we hit that loop.  */
X                GET_BUFFER_SPACE (3);
X                INSERT_JUMP (dummy_failure_jump, laststart, laststart + 6);
X                b += 3;
X              }
X            }
X	  break;
X
X
X	case '.':
X          laststart = b;
X          BUF_PUSH (anychar);
X          break;
X
X
X        case '[':
X          {
X            boolean had_char_class = false;
X
X            if (p == pend) return REG_EBRACK;
X
X            /* Ensure that we have enough space to push a charset: the
X               opcode, the length count, and the bitset; 34 bytes in all.  */
X	    GET_BUFFER_SPACE (34);
X
X            laststart = b;
X
X            /* We test `*p == '^' twice, instead of using an if
X               statement, so we only need one BUF_PUSH.  */
X            BUF_PUSH (*p == '^' ? charset_not : charset); 
X            if (*p == '^')
X              p++;
X
X            /* Remember the first position in the bracket expression.  */
X            p1 = p;
X
X            /* Push the number of bytes in the bitmap.  */
X            BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH);
X
X            /* Clear the whole map.  */
X            bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH);
X
X            /* charset_not matches newline according to a syntax bit.  */
X            if ((re_opcode_t) b[-2] == charset_not
X                && (syntax & RE_HAT_LISTS_NOT_NEWLINE))
X              SET_LIST_BIT ('\n');
X
X            /* Read in characters and ranges, setting map bits.  */
X            for (;;)
X              {
X                if (p == pend) return REG_EBRACK;
X
X                PATFETCH (c);
X
X                /* \ might escape characters inside [...] and [^...].  */
X                if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\')
X                  {
X                    if (p == pend) return REG_EESCAPE;
X
X                    PATFETCH (c1);
X                    SET_LIST_BIT (c1);
X                    continue;
X                  }
X
X                /* Could be the end of the bracket expression.  If it's
X                   not (i.e., when the bracket expression is `[]' so
X                   far), the ']' character bit gets set way below.  */
X                if (c == ']' && p != p1 + 1)
X                  break;
X
X                /* Look ahead to see if it's a range when the last thing
X                   was a character class.  */
X                if (had_char_class && c == '-' && *p != ']')
X                  return REG_ERANGE;
X
X                /* Look ahead to see if it's a range when the last thing
X                   was a character: if this is a hyphen not at the
X                   beginning or the end of a list, then it's the range
X                   operator.  */
X                if (c == '-' 
X                    && !(p - 2 >= pattern && p[-2] == '[') 
X                    && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^')
X                    && *p != ']')
X                  {
X                    reg_errcode_t ret
X                      = compile_range (&p, pend, translate, syntax, b);
X                    if (ret != REG_NOERROR) return ret;
X                  }
X
X                else if (p[0] == '-' && p[1] != ']')
X                  { /* This handles ranges made up of characters only.  */
X                    reg_errcode_t ret;
X
X		    /* Move past the `-'.  */
X                    PATFETCH (c1);
X                    
X                    ret = compile_range (&p, pend, translate, syntax, b);
X                    if (ret != REG_NOERROR) return ret;
X                  }
X
X                /* See if we're at the beginning of a possible character
X                   class.  */
X
X                else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':')
X                  { /* Leave room for the null.  */
X                    char str[CHAR_CLASS_MAX_LENGTH + 1];
X
X                    PATFETCH (c);
X                    c1 = 0;
X
X                    /* If pattern is `[[:'.  */
X                    if (p == pend) return REG_EBRACK;
X
X                    for (;;)
X                      {
X                        PATFETCH (c);
X                        if (c == ':' || c == ']' || p == pend
X                            || c1 == CHAR_CLASS_MAX_LENGTH)
X                          break;
X                        str[c1++] = c;
X                      }
X                    str[c1] = '\0';
X
X                    /* If isn't a word bracketed by `[:' and:`]':
X                       undo the ending character, the letters, and leave 
X                       the leading `:' and `[' (but set bits for them).  */
X                    if (c == ':' && *p == ']')
X                      {
X                        int ch;
X                        boolean is_alnum = STREQ (str, "alnum");
X                        boolean is_alpha = STREQ (str, "alpha");
X                        boolean is_blank = STREQ (str, "blank");
X                        boolean is_cntrl = STREQ (str, "cntrl");
X                        boolean is_digit = STREQ (str, "digit");
X                        boolean is_graph = STREQ (str, "graph");
X                        boolean is_lower = STREQ (str, "lower");
X                        boolean is_print = STREQ (str, "print");
X                        boolean is_punct = STREQ (str, "punct");
X                        boolean is_space = STREQ (str, "space");
X                        boolean is_upper = STREQ (str, "upper");
X                        boolean is_xdigit = STREQ (str, "xdigit");
X                        
X                        if (!IS_CHAR_CLASS (str)) return REG_ECTYPE;
X
X                        /* Throw away the ] at the end of the character
X                           class.  */
X                        PATFETCH (c);					
X
X                        if (p == pend) return REG_EBRACK;
X
X                        for (ch = 0; ch < 1 << BYTEWIDTH; ch++)
X                          {
X                            if (   (is_alnum  && ISALNUM (ch))
X                                || (is_alpha  && ISALPHA (ch))
X                                || (is_blank  && ISBLANK (ch))
X                                || (is_cntrl  && ISCNTRL (ch))
X                                || (is_digit  && ISDIGIT (ch))
X                                || (is_graph  && ISGRAPH (ch))
X                                || (is_lower  && ISLOWER (ch))
X                                || (is_print  && ISPRINT (ch))
X                                || (is_punct  && ISPUNCT (ch))
X                                || (is_space  && ISSPACE (ch))
X                                || (is_upper  && ISUPPER (ch))
X                                || (is_xdigit && ISXDIGIT (ch)))
X                            SET_LIST_BIT (ch);
X                          }
X                        had_char_class = true;
X                      }
X                    else
X                      {
X                        c1++;
X                        while (c1--)    
X                          PATUNFETCH;
X                        SET_LIST_BIT ('[');
X                        SET_LIST_BIT (':');
X                        had_char_class = false;
X                      }
X                  }
X                else
X                  {
X                    had_char_class = false;
X                    SET_LIST_BIT (c);
X                  }
X              }
X
X            /* Discard any (non)matching list bytes that are all 0 at the
X               end of the map.  Decrease the map-length byte too.  */
X            while ((int) b[-1] > 0 && b[b[-1] - 1] == 0) 
X              b[-1]--; 
X            b += b[-1];
X          }
X          break;
X
X
X	case '(':
X          if (syntax & RE_NO_BK_PARENS)
X            goto handle_open;
X          else
X            goto normal_char;
X
X
X        case ')':
X          if (syntax & RE_NO_BK_PARENS)
X            goto handle_close;
X          else
X            goto normal_char;
X
X
X        case '\n':
X          if (syntax & RE_NEWLINE_ALT)
X            goto handle_alt;
X          else
X            goto normal_char;
X
X
X	case '|':
X          if (syntax & RE_NO_BK_VBAR)
X            goto handle_alt;
X          else
X            goto normal_char;
X
X
X        case '{':
X           if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES)
X             goto handle_interval;
X           else
X             goto normal_char;
X
X
X        case '\\':
X          if (p == pend) return REG_EESCAPE;
X
X          /* Do not translate the character after the \, so that we can
X             distinguish, e.g., \B from \b, even if we normally would
X             translate, e.g., B to b.  */
X          PATFETCH_RAW (c);
X
X          switch (c)
X            {
X            case '(':
X              if (syntax & RE_NO_BK_PARENS)
X                goto normal_backslash;
X
X            handle_open:
X              bufp->re_nsub++;
X              regnum++;
X
X              if (COMPILE_STACK_FULL)
X                { 
X                  RETALLOC (compile_stack.stack, compile_stack.size << 1,
X                            compile_stack_elt_t);
X                  if (compile_stack.stack == NULL) return REG_ESPACE;
X
X                  compile_stack.size <<= 1;
X                }
X
X              /* These are the values to restore when we hit end of this
X                 group.  They are all relative offsets, so that if the
X                 whole pattern moves because of realloc, they will still
X                 be valid.  */
X              COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer;
X              COMPILE_STACK_TOP.fixup_alt_jump 
X                = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0;
X              COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer;
X              COMPILE_STACK_TOP.regnum = regnum;
X
X              /* We will eventually replace the 0 with the number of
X                 groups inner to this one.  But do not push a
X                 start_memory for groups beyond the last one we can
X                 represent in the compiled pattern.  */
X              if (regnum <= MAX_REGNUM)
X                {
X                  COMPILE_STACK_TOP.inner_group_offset = b - bufp->buffer + 2;
X                  BUF_PUSH_3 (start_memory, regnum, 0);
X                }
X                
X              compile_stack.avail++;
X
X              fixup_alt_jump = 0;
X              laststart = 0;
X              begalt = b;
X	      /* If we've reached MAX_REGNUM groups, then this open
X		 won't actually generate any code, so we'll have to
X		 clear pending_exact explicitly.  */
X	      pending_exact = 0;
X              break;
X
X
X            case ')':
X              if (syntax & RE_NO_BK_PARENS) goto normal_backslash;
X
X              if (COMPILE_STACK_EMPTY)
X                if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
X                  goto normal_backslash;
X                else
X                  return REG_ERPAREN;
X
X            handle_close:
X              if (fixup_alt_jump)
X                { /* Push a dummy failure point at the end of the
X                     alternative for a possible future
X                     `pop_failure_jump' to pop.  See comments at
X                     `push_dummy_failure' in `re_match_2'.  */
X                  BUF_PUSH (push_dummy_failure);
X                  
X                  /* We allocated space for this jump when we assigned
X                     to `fixup_alt_jump', in the `handle_alt' case below.  */
X                  STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1);
X                }
X
X              /* See similar code for backslashed left paren above.  */
X              if (COMPILE_STACK_EMPTY)
X                if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
X                  goto normal_char;
X                else
X                  return REG_ERPAREN;
X
X              /* Since we just checked for an empty stack above, this
X                 ``can't happen''.  */
X              assert (compile_stack.avail != 0);
X              {
X                /* We don't just want to restore into `regnum', because
X                   later groups should continue to be numbered higher,
X                   as in `(ab)c(de)' -- the second group is #2.  */
X                regnum_t this_group_regnum;
X
X                compile_stack.avail--;		
X                begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset;
X                fixup_alt_jump
X                  = COMPILE_STACK_TOP.fixup_alt_jump
X                    ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1 
X                    : 0;
X                laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset;
X                this_group_regnum = COMPILE_STACK_TOP.regnum;
X		/* If we've reached MAX_REGNUM groups, then this open
X		   won't actually generate any code, so we'll have to
X		   clear pending_exact explicitly.  */
X		pending_exact = 0;
X
X                /* We're at the end of the group, so now we know how many
X                   groups were inside this one.  */
X                if (this_group_regnum <= MAX_REGNUM)
X                  {
X                    unsigned char *inner_group_loc
X                      = bufp->buffer + COMPILE_STACK_TOP.inner_group_offset;
X                    
X                    *inner_group_loc = regnum - this_group_regnum;
X                    BUF_PUSH_3 (stop_memory, this_group_regnum,
X                                regnum - this_group_regnum);
X                  }
X              }
X              break;
X
X
X            case '|':					/* `\|'.  */
X              if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR)
X                goto normal_backslash;
X            handle_alt:
X              if (syntax & RE_LIMITED_OPS)
X                goto normal_char;
X
X              /* Insert before the previous alternative a jump which
X                 jumps to this alternative if the former fails.  */
X              GET_BUFFER_SPACE (3);
X              INSERT_JUMP (on_failure_jump, begalt, b + 6);
X              pending_exact = 0;
X              b += 3;
X
X              /* The alternative before this one has a jump after it
X                 which gets executed if it gets matched.  Adjust that
X                 jump so it will jump to this alternative's analogous
X                 jump (put in below, which in turn will jump to the next
X                 (if any) alternative's such jump, etc.).  The last such
X                 jump jumps to the correct final destination.  A picture:
X                          _____ _____ 
X                          |   | |   |   
X                          |   v |   v 
X                         a | b   | c   
X
X                 If we are at `b', then fixup_alt_jump right now points to a
X                 three-byte space after `a'.  We'll put in the jump, set
X                 fixup_alt_jump to right after `b', and leave behind three
X                 bytes which we'll fill in when we get to after `c'.  */
X
X              if (fixup_alt_jump)
X                STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
X
X              /* Mark and leave space for a jump after this alternative,
X                 to be filled in later either by next alternative or
X                 when know we're at the end of a series of alternatives.  */
X              fixup_alt_jump = b;
X              GET_BUFFER_SPACE (3);
X              b += 3;
X
X              laststart = 0;
X              begalt = b;
X              break;
X
X
X            case '{': 
X              /* If \{ is a literal.  */
X              if (!(syntax & RE_INTERVALS)
X                     /* If we're at `\{' and it's not the open-interval 
X                        operator.  */
X                  || ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
X                  || (p - 2 == pattern  &&  p == pend))
X                goto normal_backslash;
X
X            handle_interval:
X              {
X                /* If got here, then the syntax allows intervals.  */
X
X                /* At least (most) this many matches must be made.  */
X                int lower_bound = -1, upper_bound = -1;
X
X                beg_interval = p - 1;
X
X                if (p == pend)
X                  {
X                    if (syntax & RE_NO_BK_BRACES)
X                      goto unfetch_interval;
X                    else
X                      return REG_EBRACE;
X                  }
X
X                GET_UNSIGNED_NUMBER (lower_bound);
X
X                if (c == ',')
X                  {
X                    GET_UNSIGNED_NUMBER (upper_bound);
X                    if (upper_bound < 0) upper_bound = RE_DUP_MAX;
X                  }
X                else
X                  /* Interval such as `{1}' => match exactly once. */
X                  upper_bound = lower_bound;
X
X                if (lower_bound < 0 || upper_bound > RE_DUP_MAX
X                    || lower_bound > upper_bound)
X                  {
X                    if (syntax & RE_NO_BK_BRACES)
X                      goto unfetch_interval;
X                    else 
X                      return REG_BADBR;
X                  }
X
X                if (!(syntax & RE_NO_BK_BRACES)) 
X                  {
X                    if (c != '\\') return REG_EBRACE;
X
X                    PATFETCH (c);
X                  }
X
X                if (c != '}')
X                  {
X                    if (syntax & RE_NO_BK_BRACES)
X                      goto unfetch_interval;
X                    else 
X                      return REG_BADBR;
X                  }
X
X                /* We just parsed a valid interval.  */
X
X                /* If it's invalid to have no preceding re.  */
X                if (!laststart)
X                  {
X                    if (syntax & RE_CONTEXT_INVALID_OPS)
X                      return REG_BADRPT;
X                    else if (syntax & RE_CONTEXT_INDEP_OPS)
X                      laststart = b;
X                    else
X                      goto unfetch_interval;
X                  }
X
X                /* If the upper bound is zero, don't want to succeed at
X                   all; jump from `laststart' to `b + 3', which will be
X                   the end of the buffer after we insert the jump.  */
X                 if (upper_bound == 0)
X                   {
X                     GET_BUFFER_SPACE (3);
X                     INSERT_JUMP (jump, laststart, b + 3);
X                     b += 3;
X                   }
X
X                 /* Otherwise, we have a nontrivial interval.  When
X                    we're all done, the pattern will look like:
X                      set_number_at <jump count> <upper bound>
X                      set_number_at <succeed_n count> <lower bound>
X                      succeed_n <after jump addr> <succed_n count>
X                      <body of loop>
X                      jump_n <succeed_n addr> <jump count>
X                    (The upper bound and `jump_n' are omitted if
X                    `upper_bound' is 1, though.)  */
X                 else 
X                   { /* If the upper bound is > 1, we need to insert
X                        more at the end of the loop.  */
X                     unsigned nbytes = 10 + (upper_bound > 1) * 10;
X
X                     GET_BUFFER_SPACE (nbytes);
X
X                     /* Initialize lower bound of the `succeed_n', even
X                        though it will be set during matching by its
X                        attendant `set_number_at' (inserted next),
X                        because `re_compile_fastmap' needs to know.
X                        Jump to the `jump_n' we might insert below.  */
X                     INSERT_JUMP2 (succeed_n, laststart,
X                                   b + 5 + (upper_bound > 1) * 5,
X                                   lower_bound);
X                     b += 5;
X
X                     /* Code to initialize the lower bound.  Insert 
X                        before the `succeed_n'.  The `5' is the last two
X                        bytes of this `set_number_at', plus 3 bytes of
X                        the following `succeed_n'.  */
X                     insert_op2 (set_number_at, laststart, 5, lower_bound, b);
X                     b += 5;
X
X                     if (upper_bound > 1)
X                       { /* More than one repetition is allowed, so
X                            append a backward jump to the `succeed_n'
X                            that starts this interval.
X                            
X                            When we've reached this during matching,
X                            we'll have matched the interval once, so
X                            jump back only `upper_bound - 1' times.  */
X                         STORE_JUMP2 (jump_n, b, laststart + 5,
X                                      upper_bound - 1);
X                         b += 5;
X
X                         /* The location we want to set is the second
X                            parameter of the `jump_n'; that is `b-2' as
X                            an absolute address.  `laststart' will be
X                            the `set_number_at' we're about to insert;
X                            `laststart+3' the number to set, the source
X                            for the relative address.  But we are
X                            inserting into the middle of the pattern --
X                            so everything is getting moved up by 5.
X                            Conclusion: (b - 2) - (laststart + 3) + 5,
X                            i.e., b - laststart.
X                            
X                            We insert this at the beginning of the loop
X                            so that if we fail during matching, we'll
X                            reinitialize the bounds.  */
X                         insert_op2 (set_number_at, laststart, b - laststart,
X                                     upper_bound - 1, b);
X                         b += 5;
X                       }
X                   }
X                pending_exact = 0;
X                beg_interval = NULL;
X              }
X              break;
X
X            unfetch_interval:
X              /* If an invalid interval, match the characters as literals.  */
X               assert (beg_interval);
X               p = beg_interval;
X               beg_interval = NULL;
X
X               /* normal_char and normal_backslash need `c'.  */
X               PATFETCH (c);	
X
X               if (!(syntax & RE_NO_BK_BRACES))
X                 {
X                   if (p > pattern  &&  p[-1] == '\\')
X                     goto normal_backslash;
X                 }
X               goto normal_char;
X
#ifdef emacs
X            /* There is no way to specify the before_dot and after_dot
X               operators.  rms says this is ok.  --karl  */
X            case '=':
X              BUF_PUSH (at_dot);
X              break;
X
X            case 's':	
X              laststart = b;
X              PATFETCH (c);
X              BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]);
X              break;
X
X            case 'S':
X              laststart = b;
X              PATFETCH (c);
X              BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]);
X              break;
#endif /* emacs */
X
X
X            case 'w':
X              laststart = b;
X              BUF_PUSH (wordchar);
X              break;
X
X
X            case 'W':
X              laststart = b;
X              BUF_PUSH (notwordchar);
X              break;
X
X
X            case '<':
X              BUF_PUSH (wordbeg);
X              break;
X
X            case '>':
X              BUF_PUSH (wordend);
X              break;
X
X            case 'b':
X              BUF_PUSH (wordbound);
X              break;
X
X            case 'B':
X              BUF_PUSH (notwordbound);
X              break;
X
X            case '`':
X              BUF_PUSH (begbuf);
X              break;
X
X            case '\'':
X              BUF_PUSH (endbuf);
X              break;
X
X            case '1': case '2': case '3': case '4': case '5':
X            case '6': case '7': case '8': case '9':
X              if (syntax & RE_NO_BK_REFS)
X                goto normal_char;
X
X              c1 = c - '0';
X
X              if (c1 > regnum)
X                return REG_ESUBREG;
X
X              /* Can't back reference to a subexpression if inside of it.  */
X              if (group_in_compile_stack (compile_stack, c1))
X                goto normal_char;
X
X              laststart = b;
X              BUF_PUSH_2 (duplicate, c1);
X              break;
X
X
X            case '+':
X            case '?':
X              if (syntax & RE_BK_PLUS_QM)
X                goto handle_plus;
X              else
X                goto normal_backslash;
X
X            default:
X            normal_backslash:
X              /* You might think it would be useful for \ to mean
X                 not to translate; but if we don't translate it
X                 it will never match anything.  */
X              c = TRANSLATE (c);
X              goto normal_char;
X            }
X          break;
X
X
X	default:
X        /* Expects the character in `c'.  */
X	normal_char:
X	      /* If no exactn currently being built.  */
X          if (!pending_exact 
X
X              /* If last exactn not at current position.  */
X              || pending_exact + *pending_exact + 1 != b
X              
X              /* We have only one byte following the exactn for the count.  */
X	      || *pending_exact == (1 << BYTEWIDTH) - 1
X
X              /* If followed by a repetition operator.  */
X              || *p == '*' || *p == '^'
X	      || ((syntax & RE_BK_PLUS_QM)
X		  ? *p == '\\' && (p[1] == '+' || p[1] == '?')
X		  : (*p == '+' || *p == '?'))
X	      || ((syntax & RE_INTERVALS)
X                  && ((syntax & RE_NO_BK_BRACES)
X		      ? *p == '{'
X                      : (p[0] == '\\' && p[1] == '{'))))
X	    {
X	      /* Start building a new exactn.  */
X              
X              laststart = b;
X
X	      BUF_PUSH_2 (exactn, 0);
X	      pending_exact = b - 1;
X            }
X            
X	  BUF_PUSH (c);
X          (*pending_exact)++;
X	  break;
X        } /* switch (c) */
X    } /* while p != pend */
X
X  
X  /* Through the pattern now.  */
X  
X  if (fixup_alt_jump)
X    STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
X
X  if (!COMPILE_STACK_EMPTY) 
X    return REG_EPAREN;
X
X  free (compile_stack.stack);
X
X  /* We have succeeded; set the length of the buffer.  */
X  bufp->used = b - bufp->buffer;
X
#ifdef DEBUG
X  if (debug)
X    {
X      DEBUG_PRINT1 ("\nCompiled pattern: ");
X      print_compiled_pattern (bufp);
X    }
#endif /* DEBUG */
X
X  return REG_NOERROR;
} /* regex_compile */
X
/* Subroutines for `regex_compile'.  */
X
/* Store OP at LOC followed by two-byte integer parameter ARG.  */
X
static void
store_op1 (op, loc, arg)
X    re_opcode_t op;
X    unsigned char *loc;
X    int arg;
{
X  *loc = (unsigned char) op;
X  STORE_NUMBER (loc + 1, arg);
}
X
X
/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2.  */
X
static void
store_op2 (op, loc, arg1, arg2)
X    re_opcode_t op;
X    unsigned char *loc;
X    int arg1, arg2;
{
X  *loc = (unsigned char) op;
X  STORE_NUMBER (loc + 1, arg1);
X  STORE_NUMBER (loc + 3, arg2);
}
X
X
/* Copy the bytes from LOC to END to open up three bytes of space at LOC
X   for OP followed by two-byte integer parameter ARG.  */
X
static void
insert_op1 (op, loc, arg, end)
X    re_opcode_t op;
X    unsigned char *loc;
X    int arg;
X    unsigned char *end;    
{
X  register unsigned char *pfrom = end;
X  register unsigned char *pto = end + 3;
X
X  while (pfrom != loc)
X    *--pto = *--pfrom;
X    
X  store_op1 (op, loc, arg);
}
X
X
/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2.  */
X
static void
insert_op2 (op, loc, arg1, arg2, end)
X    re_opcode_t op;
X    unsigned char *loc;
X    int arg1, arg2;
X    unsigned char *end;    
{
X  register unsigned char *pfrom = end;
X  register unsigned char *pto = end + 5;
X
X  while (pfrom != loc)
X    *--pto = *--pfrom;
X    
X  store_op2 (op, loc, arg1, arg2);
}
X
X
/* P points to just after a ^ in PATTERN.  Return true if that ^ comes
X   after an alternative or a begin-subexpression.  We assume there is at
X   least one character before the ^.  */
X
static boolean
at_begline_loc_p (pattern, p, syntax)
X    _CONST_ char *pattern, *p;
X    reg_syntax_t syntax;
{
X  _CONST_ char *prev = p - 2;
X  boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\';
X  
X  return
X       /* After a subexpression?  */
X       (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash))
X       /* After an alternative?  */
X    || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash));
}
X
X
/* The dual of at_begline_loc_p.  This one is for $.  We assume there is
X   at least one character after the $, i.e., `P < PEND'.  */
X
static boolean
at_endline_loc_p (p, pend, syntax)
X    _CONST_ char *p, *pend;
X    int syntax;
{
X  _CONST_ char *next = p;
X  boolean next_backslash = *next == '\\';
X  _CONST_ char *next_next = p + 1 < pend ? p + 1 : NULL;
X  
X  return
X       /* Before a subexpression?  */
X       (syntax & RE_NO_BK_PARENS ? *next == ')'
X        : next_backslash && next_next && *next_next == ')')
X       /* Before an alternative?  */
X    || (syntax & RE_NO_BK_VBAR ? *next == '|'
X        : next_backslash && next_next && *next_next == '|');
}
X
X
/* Returns true if REGNUM is in one of COMPILE_STACK's elements and 
X   false if it's not.  */
X
static boolean
group_in_compile_stack (compile_stack, regnum)
X    compile_stack_type compile_stack;
X    regnum_t regnum;
{
X  int this_element;
X
X  for (this_element = compile_stack.avail - 1;  
X       this_element >= 0; 
X       this_element--)
X    if (compile_stack.stack[this_element].regnum == regnum)
X      return true;
X
X  return false;
}
X
X
/* Read the ending character of a range (in a bracket expression) from the
X   uncompiled pattern *P_PTR (which ends at PEND).  We assume the
X   starting character is in `P[-2]'.  (`P[-1]' is the character `-'.)
X   Then we set the translation of all bits between the starting and
X   ending characters (inclusive) in the compiled pattern B.
X   
X   Return an error code.
X   
X   We use these short variable names so we can use the same macros as
X   `regex_compile' itself.  */
X
static reg_errcode_t
compile_range (p_ptr, pend, translate, syntax, b)
X    _CONST_ char **p_ptr, *pend;
X    char *translate;
X    reg_syntax_t syntax;
X    unsigned char *b;
{
X  unsigned this_char;
X
X  _CONST_ char *p = *p_ptr;
X  int range_start, range_end;
X  
X  if (p == pend)
X    return REG_ERANGE;
X
X  /* Even though the pattern is a signed `char *', we need to fetch
X     with unsigned char *'s; if the high bit of the pattern character
X     is set, the range endpoints will be negative if we fetch using a
X     signed char *.
X
X     We also want to fetch the endpoints without translating them; the 
X     appropriate translation is done in the bit-setting loop below.  */
X  range_start = ((unsigned char *) p)[-2];
X  range_end   = ((unsigned char *) p)[0];
X
X  /* Have to increment the pointer into the pattern string, so the
X     caller isn't still at the ending character.  */
X  (*p_ptr)++;
X
X  /* If the start is after the end, the range is empty.  */
X  if (range_start > range_end)
X    return syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR;
X
X  /* Here we see why `this_char' has to be larger than an `unsigned
X     char' -- the range is inclusive, so if `range_end' == 0xff
X     (assuming 8-bit characters), we would otherwise go into an infinite
X     loop, since all characters <= 0xff.  */
X  for (this_char = range_start; this_char <= range_end; this_char++)
X    {
X      SET_LIST_BIT (TRANSLATE (this_char));
X    }
X  
X  return REG_NOERROR;
}
X
/* Failure stack declarations and macros; both re_compile_fastmap and
X   re_match_2 use a failure stack.  These have to be macros because of
X   REGEX_ALLOCATE.  */
X   
X
/* Number of failure points for which to initially allocate space
X   when matching.  If this number is exceeded, we allocate more
X   space, so it is not a hard limit.  */
#ifndef INIT_FAILURE_ALLOC
#define INIT_FAILURE_ALLOC 5
#endif
X
/* Roughly the maximum number of failure points on the stack.  Would be
X   exactly that if always used MAX_FAILURE_SPACE each time we failed.
X   This is a variable only so users of regex can assign to it; we never
X   change it ourselves.  */
int re_max_failures = 2000;
X
typedef _CONST_ unsigned char *fail_stack_elt_t;
X
typedef struct
{
X  fail_stack_elt_t *stack;
X  unsigned size;
X  unsigned avail;			/* Offset of next open position.  */
} fail_stack_type;
X
#define FAIL_STACK_EMPTY()     (fail_stack.avail == 0)
#define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0)
#define FAIL_STACK_FULL()      (fail_stack.avail == fail_stack.size)
#define FAIL_STACK_TOP()       (fail_stack.stack[fail_stack.avail])
X
X
/* Initialize `fail_stack'.  Do `return -2' if the alloc fails.  */
X
#define INIT_FAIL_STACK()						\
X  do {									\
X    fail_stack.stack = (fail_stack_elt_t *)				\
X      REGEX_ALLOCATE (INIT_FAILURE_ALLOC * sizeof (fail_stack_elt_t));	\
X									\
X    if (fail_stack.stack == NULL)					\
X      return -2;							\
X									\
X    fail_stack.size = INIT_FAILURE_ALLOC;				\
X    fail_stack.avail = 0;						\
X  } while (0)
X
X
/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items.
X
X   Return 1 if succeeds, and 0 if either ran out of memory
X   allocating space for it or it was already too large.  
X   
X   REGEX_REALLOCATE requires `destination' be declared.   */
X
#define DOUBLE_FAIL_STACK(fail_stack)					\
X  ((fail_stack).size > re_max_failures * MAX_FAILURE_ITEMS		\
X   ? 0									\
X   : ((fail_stack).stack = (fail_stack_elt_t *)				\
X        REGEX_REALLOCATE ((fail_stack).stack, 				\
X          (fail_stack).size * sizeof (fail_stack_elt_t),		\
X          ((fail_stack).size << 1) * sizeof (fail_stack_elt_t)),	\
X									\
X      (fail_stack).stack == NULL					\
X      ? 0								\
X      : ((fail_stack).size <<= 1, 					\
X         1)))
X
X
/* Push PATTERN_OP on FAIL_STACK. 
X
X   Return 1 if was able to do so and 0 if ran out of memory allocating
X   space to do so.  */
#define PUSH_PATTERN_OP(pattern_op, fail_stack)				\
X  ((FAIL_STACK_FULL ()							\
X    && !DOUBLE_FAIL_STACK (fail_stack))					\
X    ? 0									\
X    : ((fail_stack).stack[(fail_stack).avail++] = pattern_op,		\
X       1))
X
/* This pushes an item onto the failure stack.  Must be a four-byte
X   value.  Assumes the variable `fail_stack'.  Probably should only
X   be called from within `PUSH_FAILURE_POINT'.  */
#define PUSH_FAILURE_ITEM(item)						\
X  fail_stack.stack[fail_stack.avail++] = (fail_stack_elt_t) item
X
/* The complement operation.  Assumes `fail_stack' is nonempty.  */
#define POP_FAILURE_ITEM() fail_stack.stack[--fail_stack.avail]
X
/* Used to omit pushing failure point id's when we're not debugging.  */
#ifdef DEBUG
#define DEBUG_PUSH PUSH_FAILURE_ITEM
#define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_ITEM ()
#else
#define DEBUG_PUSH(item)
#define DEBUG_POP(item_addr)
#endif
X
X
/* Push the information about the state we will need
X   if we ever fail back to it.  
X   
X   Requires variables fail_stack, regstart, regend, reg_info, and
X   num_regs be declared.  DOUBLE_FAIL_STACK requires `destination' be
X   declared.
X   
X   Does `return FAILURE_CODE' if runs out of memory.  */
X
#define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code)	\
X  do {									\
X    char *destination;							\
X    /* Must be int, so when we don't save any registers, the arithmetic	\
X       of 0 + -1 isn't done as unsigned.  */				\
X    int this_reg;							\
X    									\
X    DEBUG_STATEMENT (failure_id++);					\
X    DEBUG_STATEMENT (nfailure_points_pushed++);				\
X    DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id);		\
X    DEBUG_PRINT2 ("  Before push, next avail: %d\n", (fail_stack).avail);\
X    DEBUG_PRINT2 ("                     size: %d\n", (fail_stack).size);\
X									\
X    DEBUG_PRINT2 ("  slots needed: %d\n", NUM_FAILURE_ITEMS);		\
X    DEBUG_PRINT2 ("     available: %d\n", REMAINING_AVAIL_SLOTS);	\
X									\
X    /* Ensure we have enough space allocated for what we will push.  */	\
X    while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS)			\
X      {									\
X        if (!DOUBLE_FAIL_STACK (fail_stack))			\
X          return failure_code;						\
X									\
X        DEBUG_PRINT2 ("\n  Doubled stack; size now: %d\n",		\
X		       (fail_stack).size);				\
X        DEBUG_PRINT2 ("  slots available: %d\n", REMAINING_AVAIL_SLOTS);\
X      }									\
X									\
X    /* Push the info, starting with the registers.  */			\
X    DEBUG_PRINT1 ("\n");						\
X									\
X    for (this_reg = lowest_active_reg; this_reg <= highest_active_reg;	\
X         this_reg++)							\
X      {									\
X	DEBUG_PRINT2 ("  Pushing reg: %d\n", this_reg);			\
X        DEBUG_STATEMENT (num_regs_pushed++);				\
X									\
X	DEBUG_PRINT2 ("    start: 0x%x\n", regstart[this_reg]);		\
X        PUSH_FAILURE_ITEM (regstart[this_reg]);				\
X                                                                        \
X	DEBUG_PRINT2 ("    end: 0x%x\n", regend[this_reg]);		\
X        PUSH_FAILURE_ITEM (regend[this_reg]);				\
X									\
X	DEBUG_PRINT2 ("    info: 0x%x\n      ", reg_info[this_reg]);	\
X        DEBUG_PRINT2 (" match_null=%d",					\
X                      REG_MATCH_NULL_STRING_P (reg_info[this_reg]));	\
X        DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg]));	\
X        DEBUG_PRINT2 (" matched_something=%d",				\
X                      MATCHED_SOMETHING (reg_info[this_reg]));		\
X        DEBUG_PRINT2 (" ever_matched=%d",				\
X                      EVER_MATCHED_SOMETHING (reg_info[this_reg]));	\
X	DEBUG_PRINT1 ("\n");						\
X        PUSH_FAILURE_ITEM (reg_info[this_reg].word);			\
X      }									\
X									\
X    DEBUG_PRINT2 ("  Pushing  low active reg: %d\n", lowest_active_reg);\
X    PUSH_FAILURE_ITEM (lowest_active_reg);				\
X									\
X    DEBUG_PRINT2 ("  Pushing high active reg: %d\n", highest_active_reg);\
X    PUSH_FAILURE_ITEM (highest_active_reg);				\
X									\
X    DEBUG_PRINT2 ("  Pushing pattern 0x%x: ", pattern_place);		\
X    DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend);		\
X    PUSH_FAILURE_ITEM (pattern_place);					\
X									\
X    DEBUG_PRINT2 ("  Pushing string 0x%x: `", string_place);		\
X    DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2,   \
X				 size2);				\
X    DEBUG_PRINT1 ("'\n");						\
X    PUSH_FAILURE_ITEM (string_place);					\
X									\
X    DEBUG_PRINT2 ("  Pushing failure id: %u\n", failure_id);		\
X    DEBUG_PUSH (failure_id);						\
X  } while (0)
X
/* This is the number of items that are pushed and popped on the stack
X   for each register.  */
#define NUM_REG_ITEMS  3
X
/* Individual items aside from the registers.  */
#ifdef DEBUG
#define NUM_NONREG_ITEMS 5 /* Includes failure point id.  */
#else
#define NUM_NONREG_ITEMS 4
#endif
X
/* We push at most this many items on the stack.  */
#define MAX_FAILURE_ITEMS ((num_regs - 1) * NUM_REG_ITEMS + NUM_NONREG_ITEMS)
X
/* We actually push this many items.  */
#define NUM_FAILURE_ITEMS						\
X  ((highest_active_reg - lowest_active_reg + 1) * NUM_REG_ITEMS 	\
X    + NUM_NONREG_ITEMS)
X
/* How many items can still be added to the stack without overflowing it.  */
#define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail)
X
X
/* Pops what PUSH_FAIL_STACK pushes.
X
X   We restore into the parameters, all of which should be lvalues:
X     STR -- the saved data position.
X     PAT -- the saved pattern position.
X     LOW_REG, HIGH_REG -- the highest and lowest active registers.
X     REGSTART, REGEND -- arrays of string positions.
X     REG_INFO -- array of information about each subexpression.
X   
X   Also assumes the variables `fail_stack' and (if debugging), `bufp',
X   `pend', `string1', `size1', `string2', and `size2'.  */
X
#define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\
{									\
X  DEBUG_STATEMENT (fail_stack_elt_t failure_id;)			\
X  int this_reg;								\
X  _CONST_ unsigned char *string_temp;					\
X									\
X  assert (!FAIL_STACK_EMPTY ());					\
X									\
X  /* Remove failure points and point to how many regs pushed.  */	\
X  DEBUG_PRINT1 ("POP_FAILURE_POINT:\n");				\
X  DEBUG_PRINT2 ("  Before pop, next avail: %d\n", fail_stack.avail);	\
X  DEBUG_PRINT2 ("                    size: %d\n", fail_stack.size);	\
X									\
X  assert (fail_stack.avail >= NUM_NONREG_ITEMS);			\
X									\
X  DEBUG_POP (&failure_id);						\
X  DEBUG_PRINT2 ("  Popping failure id: %u\n", failure_id);		\
X									\
X  /* If the saved string location is NULL, it came from an		\
X     on_failure_keep_string_jump opcode, and we want to throw away the	\
X     saved NULL, thus retaining our current position in the string.  */	\
X  string_temp = POP_FAILURE_ITEM ();					\
X  if (string_temp != NULL)						\
X    str = (_CONST_ char *) string_temp;					\
X									\
X  DEBUG_PRINT2 ("  Popping string 0x%x: `", str);			\
X  DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2);	\
X  DEBUG_PRINT1 ("'\n");							\
X									\
X  pat = (unsigned char *) POP_FAILURE_ITEM ();				\
X  DEBUG_PRINT2 ("  Popping pattern 0x%x: ", pat);			\
X  DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend);			\
X									\
X  /* Restore register info.  */						\
X  high_reg = (unsigned) POP_FAILURE_ITEM ();				\
X  DEBUG_PRINT2 ("  Popping high active reg: %d\n", high_reg);		\
X									\
X  low_reg = (unsigned) POP_FAILURE_ITEM ();				\
X  DEBUG_PRINT2 ("  Popping  low active reg: %d\n", low_reg);		\
X									\
X  for (this_reg = high_reg; this_reg >= low_reg; this_reg--)		\
X    {									\
X      DEBUG_PRINT2 ("    Popping reg: %d\n", this_reg);			\
X									\
X      reg_info[this_reg].word = POP_FAILURE_ITEM ();			\
X      DEBUG_PRINT2 ("      info: 0x%x\n", reg_info[this_reg]);		\
X									\
X      regend[this_reg] = (_CONST_ char *) POP_FAILURE_ITEM ();		\
X      DEBUG_PRINT2 ("      end: 0x%x\n", regend[this_reg]);		\
X									\
X      regstart[this_reg] = (_CONST_ char *) POP_FAILURE_ITEM ();		\
X      DEBUG_PRINT2 ("      start: 0x%x\n", regstart[this_reg]);		\
X    }									\
X									\
X  DEBUG_STATEMENT (nfailure_points_popped++);				\
} /* POP_FAILURE_POINT */
X
/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in
X   BUFP.  A fastmap records which of the (1 << BYTEWIDTH) possible
X   characters can start a string that matches the pattern.  This fastmap
X   is used by re_search to skip quickly over impossible starting points.
X
X   The caller must supply the address of a (1 << BYTEWIDTH)-byte data
X   area as BUFP->fastmap.
X   
X   We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in
X   the pattern buffer.
X
X   Returns 0 if we succeed, -2 if an internal error.   */
X
int
re_compile_fastmap (bufp)
X     struct re_pattern_buffer *bufp;
{
X  int j, k;
X  fail_stack_type fail_stack;
#ifndef REGEX_MALLOC
X  char *destination;
#endif
X  /* We don't push any register information onto the failure stack.  */
X  unsigned num_regs = 0;
X  
X  register char *fastmap = bufp->fastmap;
X  unsigned char *pattern = bufp->buffer;
X  unsigned long size = bufp->used;
X  _CONST_ unsigned char *p = pattern;
X  register unsigned char *pend = pattern + size;
X
X  /* Assume that each path through the pattern can be null until
X     proven otherwise.  We set this false at the bottom of switch
X     statement, to which we get only if a particular path doesn't
X     match the empty string.  */
X  boolean path_can_be_null = true;
X
X  /* We aren't doing a `succeed_n' to begin with.  */
X  boolean succeed_n_p = false;
X
X  assert (fastmap != NULL && p != NULL);
X  
X  INIT_FAIL_STACK ();
X  bzero (fastmap, 1 << BYTEWIDTH);  /* Assume nothing's valid.  */
X  bufp->fastmap_accurate = 1;	    /* It will be when we're done.  */
X  bufp->can_be_null = 0;
X      
X  while (p != pend || !FAIL_STACK_EMPTY ())
X    {
X      if (p == pend)
X        {
X          bufp->can_be_null |= path_can_be_null;
X          
X          /* Reset for next path.  */
X          path_can_be_null = true;
X          
X          p = fail_stack.stack[--fail_stack.avail];
X	}
X
X      /* We should never be about to go beyond the end of the pattern.  */
X      assert (p < pend);
X      
#ifdef SWITCH_ENUM_BUG
X      switch ((int) ((re_opcode_t) *p++))
#else
X      switch ((re_opcode_t) *p++)
#endif
X	{
X
X        /* I guess the idea here is to simply not bother with a fastmap
X           if a backreference is used, since it's too hard to figure out
X           the fastmap for the corresponding group.  Setting
X           `can_be_null' stops `re_search_2' from using the fastmap, so
X           that is all we do.  */
X	case duplicate:
X	  bufp->can_be_null = 1;
X          return 0;
X
X
X      /* Following are the cases which match a character.  These end
X         with `break'.  */
X
X	case exactn:
X          fastmap[p[1]] = 1;
X	  break;
X
X
X        case charset:
X          for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
X	    if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))
X              fastmap[j] = 1;
X	  break;
X
X
X	case charset_not:
X	  /* Chars beyond end of map must be allowed.  */
X	  for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++)
X            fastmap[j] = 1;
X
X	  for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
X	    if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))))
X              fastmap[j] = 1;
X          break;
X
X
X	case wordchar:
X	  for (j = 0; j < (1 << BYTEWIDTH); j++)
X	    if (SYNTAX (j) == Sword)
X	      fastmap[j] = 1;
X	  break;
X
X
X	case notwordchar:
X	  for (j = 0; j < (1 << BYTEWIDTH); j++)
X	    if (SYNTAX (j) != Sword)
X	      fastmap[j] = 1;
X	  break;
X
X
X        case anychar:
X          /* `.' matches anything ...  */
X	  for (j = 0; j < (1 << BYTEWIDTH); j++)
X            fastmap[j] = 1;
X
X          /* ... except perhaps newline.  */
X          if (!(bufp->syntax & RE_DOT_NEWLINE))
X            fastmap['\n'] = 0;
X
X          /* Return if we have already set `can_be_null'; if we have,
X             then the fastmap is irrelevant.  Something's wrong here.  */
X	  else if (bufp->can_be_null)
X	    return 0;
X
X          /* Otherwise, have to check alternative paths.  */
X	  break;
X
X
#ifdef emacs
X        case syntaxspec:
X	  k = *p++;
X	  for (j = 0; j < (1 << BYTEWIDTH); j++)
X	    if (SYNTAX (j) == (enum syntaxcode) k)
X	      fastmap[j] = 1;
X	  break;
X
X
X	case notsyntaxspec:
X	  k = *p++;
X	  for (j = 0; j < (1 << BYTEWIDTH); j++)
X	    if (SYNTAX (j) != (enum syntaxcode) k)
X	      fastmap[j] = 1;
X	  break;
X
X
X      /* All cases after this match the empty string.  These end with
X         `continue'.  */
X
X
X	case before_dot:
X	case at_dot:
X	case after_dot:
X          continue;
#endif /* not emacs */
X
X
X        case no_op:
X        case begline:
X        case endline:
X	case begbuf:
X	case endbuf:
X	case wordbound:
X	case notwordbound:
X	case wordbeg:
X	case wordend:
X        case push_dummy_failure:
X          continue;
X
X
X	case jump_n:
X        case pop_failure_jump:
X	case maybe_pop_jump:
X	case jump:
X        case jump_past_alt:
X	case dummy_failure_jump:
X          EXTRACT_NUMBER_AND_INCR (j, p);
X	  p += j;	
X	  if (j > 0)
X	    continue;
X            
X          /* Jump backward implies we just went through the body of a
X             loop and matched nothing.  Opcode jumped to should be
X             `on_failure_jump' or `succeed_n'.  Just treat it like an
X             ordinary jump.  For a * loop, it has pushed its failure
X             point already; if so, discard that as redundant.  */
X          if ((re_opcode_t) *p != on_failure_jump
X	      && (re_opcode_t) *p != succeed_n)
X	    continue;
X
X          p++;
X          EXTRACT_NUMBER_AND_INCR (j, p);
X          p += j;		
X	  
X          /* If what's on the stack is where we are now, pop it.  */
X          if (!FAIL_STACK_EMPTY () 
X	      && fail_stack.stack[fail_stack.avail - 1] == p)
X            fail_stack.avail--;
X
X          continue;
X
X
X        case on_failure_jump:
X        case on_failure_keep_string_jump:
X	handle_on_failure_jump:
X          EXTRACT_NUMBER_AND_INCR (j, p);
X
X          /* For some patterns, e.g., `(a?)?', `p+j' here points to the
X             end of the pattern.  We don't want to push such a point,
X             since when we restore it above, entering the switch will
X             increment `p' past the end of the pattern.  We don't need
X             to push such a point since we obviously won't find any more
X             fastmap entries beyond `pend'.  Such a pattern can match
X             the null string, though.  */
X          if (p + j < pend)
X            {
X              if (!PUSH_PATTERN_OP (p + j, fail_stack))
X                return -2;
X            }
X          else
X            bufp->can_be_null = 1;
X
X          if (succeed_n_p)
X            {
X              EXTRACT_NUMBER_AND_INCR (k, p);	/* Skip the n.  */
X              succeed_n_p = false;
X	    }
X
X          continue;
X
X
X	case succeed_n:
X          /* Get to the number of times to succeed.  */
X          p += 2;		
X
X          /* Increment p past the n for when k != 0.  */
X          EXTRACT_NUMBER_AND_INCR (k, p);
X          if (k == 0)
X	    {
X              p -= 4;
X  	      succeed_n_p = true;  /* Spaghetti code alert.  */
X              goto handle_on_failure_jump;
X            }
X          continue;
X
X
X	case set_number_at:
X          p += 4;
X          continue;
X
X
X	case start_memory:
X        case stop_memory:
X	  p += 2;
X	  continue;
X
X
X	default:
X          abort (); /* We have listed all the cases.  */
X        } /* switch *p++ */
X
X      /* Getting here means we have found the possible starting
X         characters for one path of the pattern -- and that the empty
X         string does not match.  We need not follow this path further.
X         Instead, look at the next alternative (remembered on the
X         stack), or quit if no more.  The test at the top of the loop
X         does these things.  */
X      path_can_be_null = false;
X      p = pend;
X    } /* while p */
X
X  /* Set `can_be_null' for the last path (also the first path, if the
X     pattern is empty).  */
X  bufp->can_be_null |= path_can_be_null;
X  return 0;
} /* re_compile_fastmap */
X
/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
X   ENDS.  Subsequent matches using PATTERN_BUFFER and REGS will use
X   this memory for recording register information.  STARTS and ENDS
X   must be allocated using the malloc library routine, and must each
X   be at least NUM_REGS * sizeof (regoff_t) bytes long.
X
X   If NUM_REGS == 0, then subsequent matches should allocate their own
X   register data.
X
X   Unless this function is called, the first search or match using
X   PATTERN_BUFFER will allocate its own register data, without
X   freeing the old data.  */
X
void
re_set_registers (bufp, regs, num_regs, starts, ends)
X    struct re_pattern_buffer *bufp;
X    struct re_registers *regs;
X    unsigned num_regs;
X    regoff_t *starts, *ends;
{
X  if (num_regs)
X    {
X      bufp->regs_allocated = REGS_REALLOCATE;
X      regs->num_regs = num_regs;
X      regs->start = starts;
X      regs->end = ends;
X    }
X  else
X    {
X      bufp->regs_allocated = REGS_UNALLOCATED;
X      regs->num_regs = 0;
X      regs->start = regs->end = (regoff_t) 0;
X    }
}
X
/* Searching routines.  */
X
/* Like re_search_2, below, but only one string is specified, and
X   doesn't let you say where to stop matching. */
X
int
re_search (bufp, string, size, startpos, range, regs)
X     struct re_pattern_buffer *bufp;
X     _CONST_ char *string;
X     int size, startpos, range;
X     struct re_registers *regs;
{
X  return re_search_2 (bufp, NULL, 0, string, size, startpos, range, 
X		      regs, size);
}
X
X
/* Using the compiled pattern in BUFP->buffer, first tries to match the
X   virtual concatenation of STRING1 and STRING2, starting first at index
X   STARTPOS, then at STARTPOS + 1, and so on.
X   
X   STRING1 and STRING2 have length SIZE1 and SIZE2, respectively.
X   
X   RANGE is how far to scan while trying to match.  RANGE = 0 means try
X   only at STARTPOS; in general, the last start tried is STARTPOS +
X   RANGE.
X   
X   In REGS, return the indices of the virtual concatenation of STRING1
X   and STRING2 that matched the entire BUFP->buffer and its contained
X   subexpressions.
X   
X   Do not consider matching one past the index STOP in the virtual
X   concatenation of STRING1 and STRING2.
X
X   We return either the position in the strings at which the match was
X   found, -1 if no match, or -2 if error (such as failure
X   stack overflow).  */
X
int
re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
X     struct re_pattern_buffer *bufp;
X     _CONST_ char *string1, *string2;
X     int size1, size2;
X     int startpos;
X     int range;
X     struct re_registers *regs;
X     int stop;
{
X  int val;
X  register char *fastmap = bufp->fastmap;
X  register char *translate = bufp->translate;
X  int total_size = size1 + size2;
X  int endpos = startpos + range;
X
X  /* Check for out-of-range STARTPOS.  */
X  if (startpos < 0 || startpos > total_size)
X    return -1;
X    
X  /* Fix up RANGE if it might eventually take us outside
X     the virtual concatenation of STRING1 and STRING2.  */
X  if (endpos < -1)
X    range = -1 - startpos;
X  else if (endpos > total_size)
X    range = total_size - startpos;
X
X  /* If the search isn't to be a backwards one, don't waste time in a
X     search for a pattern that must be anchored.  */
X  if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == begbuf && range > 0)
X    {
X      if (startpos > 0)
X	return -1;
X      else
X	range = 1;
X    }
X
X  /* Update the fastmap now if not correct already.  */
X  if (fastmap && !bufp->fastmap_accurate)
X    if (re_compile_fastmap (bufp) == -2)
X      return -2;
X  
X  /* Loop through the string, looking for a place to start matching.  */
X  for (;;)
X    { 
X      /* If a fastmap is supplied, skip quickly over characters that
X         cannot be the start of a match.  If the pattern can match the
X         null string, however, we don't need to skip characters; we want
X         the first null string.  */
X      if (fastmap && startpos < total_size && !bufp->can_be_null)
X	{
X	  if (range > 0)	/* Searching forwards.  */
X	    {
X	      register _CONST_ char *d;
X	      register int lim = 0;
X	      int irange = range;
X
X              if (startpos < size1 && startpos + range >= size1)
X                lim = range - (size1 - startpos);
X
X	      d = (startpos >= size1 ? string2 - size1 : string1) + startpos;
X   
X              /* Written out as an if-else to avoid testing `translate'
X                 inside the loop.  */
X	      if (translate)
X                while (range > lim
X                       && !fastmap[(unsigned char)
X				   translate[(unsigned char) *d++]])
X                  range--;
X	      else
X                while (range > lim && !fastmap[(unsigned char) *d++])
X                  range--;
X
X	      startpos += irange - range;
X	    }
X	  else				/* Searching backwards.  */
X	    {
X	      register char c = (size1 == 0 || startpos >= size1
X                                 ? string2[startpos - size1] 
X                                 : string1[startpos]);
X
X	      if (!fastmap[(unsigned char) TRANSLATE (c)])
X		goto advance;
X	    }
X	}
X
X      /* If can't match the null string, and that's all we have left, fail.  */
X      if (range >= 0 && startpos == total_size && fastmap
X          && !bufp->can_be_null)
X	return -1;
X
X      val = re_match_2 (bufp, string1, size1, string2, size2,
X	                startpos, regs, stop);
X      if (val >= 0)
X	return startpos;
X        
X      if (val == -2)
X	return -2;
X
X    advance:
X      if (!range) 
X        break;
X      else if (range > 0) 
X        {
X          range--; 
X          startpos++;
X        }
X      else
X        {
X          range++; 
X          startpos--;
X        }
X    }
X  return -1;
} /* re_search_2 */
X
/* Declarations and macros for re_match_2.  */
X
static int bcmp_translate ();
static boolean alt_match_null_string_p (),
X               common_op_match_null_string_p (),
X               group_match_null_string_p ();
X
/* Structure for per-register (a.k.a. per-group) information.
X   This must not be longer than one word, because we push this value
X   onto the failure stack.  Other register information, such as the
X   starting and ending positions (which are addresses), and the list of
X   inner groups (which is a bits list) are maintained in separate
X   variables.  
X   
X   We are making a (strictly speaking) nonportable assumption here: that
X   the compiler will pack our bit fields into something that fits into
X   the type of `word', i.e., is something that fits into one item on the
X   failure stack.  */
typedef union
{
X  fail_stack_elt_t word;
X  struct
X  {
X      /* This field is one if this group can match the empty string,
X         zero if not.  If not yet determined,  `MATCH_NULL_UNSET_VALUE'.  */
#define MATCH_NULL_UNSET_VALUE 3
X    unsigned match_null_string_p : 2;
X    unsigned is_active : 1;
X    unsigned matched_something : 1;
X    unsigned ever_matched_something : 1;
X  } bits;
} register_info_type;
X
#define REG_MATCH_NULL_STRING_P(R)  ((R).bits.match_null_string_p)
#define IS_ACTIVE(R)  ((R).bits.is_active)
#define MATCHED_SOMETHING(R)  ((R).bits.matched_something)
#define EVER_MATCHED_SOMETHING(R)  ((R).bits.ever_matched_something)
X
X
/* Call this when have matched a real character; it sets `matched' flags
X   for the subexpressions which we are currently inside.  Also records
X   that those subexprs have matched.  */
#define SET_REGS_MATCHED()						\
X  do									\
X    {									\
X      unsigned r;							\
X      for (r = lowest_active_reg; r <= highest_active_reg; r++)		\
X        {								\
X          MATCHED_SOMETHING (reg_info[r])				\
X            = EVER_MATCHED_SOMETHING (reg_info[r])			\
X            = 1;							\
X        }								\
X    }									\
X  while (0)
X
X
/* This converts PTR, a pointer into one of the search strings `string1'
X   and `string2' into an offset from the beginning of that string.  */
#define POINTER_TO_OFFSET(ptr)						\
X  (FIRST_STRING_P (ptr) ? (ptr) - string1 : (ptr) - string2 + size1)
X
/* Registers are set to a sentinel when they haven't yet matched.  */
#define REG_UNSET_VALUE ((char *) -1)
#define REG_UNSET(e) ((e) == REG_UNSET_VALUE)
X
X
/* Macros for dealing with the split strings in re_match_2.  */
X
#define MATCHING_IN_FIRST_STRING  (dend == end_match_1)
X
/* Call before fetching a character with *d.  This switches over to
X   string2 if necessary.  */
#define PREFETCH()							\
X  while (d == dend)						    	\
X    {									\
X      /* End of string2 => fail.  */					\
X      if (dend == end_match_2) 						\
X        goto fail;							\
X      /* End of string1 => advance to string2.  */ 			\
X      d = string2;						        \
X      dend = end_match_2;						\
X    }
X
X
/* Test if at very beginning or at very end of the virtual concatenation
X   of `string1' and `string2'.  If only one string, it's `string2'.  */
#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2)
#define AT_STRINGS_END(d) ((d) == end2)	
X
X
/* Test if D points to a character which is word-constituent.  We have
X   two special cases to check for: if past the end of string1, look at
X   the first character in string2; and if before the beginning of
X   string2, look at the last character in string1.  */
#define WORDCHAR_P(d)							\
X  (SYNTAX ((d) == end1 ? *string2					\
X           : (d) == string2 - 1 ? *(end1 - 1) : *(d))			\
X   == Sword)
X
/* Test if the character before D and the one at D differ with respect
X   to being word-constituent.  */
#define AT_WORD_BOUNDARY(d)						\
X  (AT_STRINGS_BEG (d) || AT_STRINGS_END (d)				\
X   || WORDCHAR_P (d - 1) != WORDCHAR_P (d))
X
X
/* Free everything we malloc.  */
#ifdef REGEX_MALLOC
#define FREE_VAR(var) if (var) free (var); var = NULL
#define FREE_VARIABLES()						\
X  do {									\
X    FREE_VAR (fail_stack.stack);					\
X    FREE_VAR (regstart);						\
X    FREE_VAR (regend);							\
X    FREE_VAR (old_regstart);						\
X    FREE_VAR (old_regend);						\
X    FREE_VAR (best_regstart);						\
X    FREE_VAR (best_regend);						\
X    FREE_VAR (reg_info);						\
X    FREE_VAR (reg_dummy);						\
X    FREE_VAR (reg_info_dummy);						\
X  } while (0)
#else /* not REGEX_MALLOC */
/* Some MIPS systems (at least) want this to free alloca'd storage.  */
#define FREE_VARIABLES() alloca (0)
#endif /* not REGEX_MALLOC */
X
X
/* These values must meet several constraints.  They must not be valid
X   register values; since we have a limit of 255 registers (because
X   we use only one byte in the pattern for the register number), we can
X   use numbers larger than 255.  They must differ by 1, because of
X   NUM_FAILURE_ITEMS above.  And the value for the lowest register must
X   be larger than the value for the highest register, so we do not try
X   to actually save any registers when none are active.  */
#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH)
#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1)
X
/* Matching routines.  */
X
#ifndef emacs   /* Emacs never uses this.  */
/* re_match is like re_match_2 except it takes only a single string.  */
X
int
re_match (bufp, string, size, pos, regs)
X     struct re_pattern_buffer *bufp;
X     _CONST_ char *string;
X     int size, pos;
X     struct re_registers *regs;
X {
X  return re_match_2 (bufp, NULL, 0, string, size, pos, regs, size); 
}
#endif /* not emacs */
X
X
/* re_match_2 matches the compiled pattern in BUFP against the
X   the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1
X   and SIZE2, respectively).  We start matching at POS, and stop
X   matching at STOP.
X   
X   If REGS is non-null and the `no_sub' field of BUFP is nonzero, we
X   store offsets for the substring each group matched in REGS.  See the
X   documentation for exactly how many groups we fill.
X
X   We return -1 if no match, -2 if an internal error (such as the
X   failure stack overflowing).  Otherwise, we return the length of the
X   matched substring.  */
X
int
re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
X     struct re_pattern_buffer *bufp;
X     _CONST_ char *string1, *string2;
X     int size1, size2;
X     int pos;
X     struct re_registers *regs;
X     int stop;
{
X  /* General temporaries.  */
X  int mcnt;
X  unsigned char *p1;
X
X  /* Just past the end of the corresponding string.  */
X  _CONST_ char *end1, *end2;
X
X  /* Pointers into string1 and string2, just past the last characters in
X     each to consider matching.  */
X  _CONST_ char *end_match_1, *end_match_2;
X
X  /* Where we are in the data, and the end of the current string.  */
X  _CONST_ char *d, *dend;
X  
X  /* Where we are in the pattern, and the end of the pattern.  */
X  unsigned char *p = bufp->buffer;
X  register unsigned char *pend = p + bufp->used;
X
X  /* We use this to map every character in the string.  */
X  char *translate = bufp->translate;
X
X  /* Failure point stack.  Each place that can handle a failure further
X     down the line pushes a failure point on this stack.  It consists of
X     restart, regend, and reg_info for all registers corresponding to
X     the subexpressions we're currently inside, plus the number of such
X     registers, and, finally, two char *'s.  The first char * is where
X     to resume scanning the pattern; the second one is where to resume
X     scanning the strings.  If the latter is zero, the failure point is
X     a ``dummy''; if a failure happens and the failure point is a dummy,
X     it gets discarded and the next next one is tried.  */
X  fail_stack_type fail_stack;
#ifdef DEBUG
X  static unsigned failure_id = 0;
X  unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0;
#endif
X
X  /* We fill all the registers internally, independent of what we
X     return, for use in backreferences.  The number here includes
X     an element for register zero.  */
X  unsigned num_regs = bufp->re_nsub + 1;
X  
X  /* The currently active registers.  */
X  unsigned lowest_active_reg = NO_LOWEST_ACTIVE_REG;
X  unsigned highest_active_reg = NO_HIGHEST_ACTIVE_REG;
X
X  /* Information on the contents of registers. These are pointers into
X     the input strings; they record just what was matched (on this
X     attempt) by a subexpression part of the pattern, that is, the
X     regnum-th regstart pointer points to where in the pattern we began
X     matching and the regnum-th regend points to right after where we
X     stopped matching the regnum-th subexpression.  (The zeroth register
X     keeps track of what the whole pattern matches.)  */
X  _CONST_ char **regstart, **regend;
X
X  /* If a group that's operated upon by a repetition operator fails to
X     match anything, then the register for its start will need to be
X     restored because it will have been set to wherever in the string we
X     are when we last see its open-group operator.  Similarly for a
X     register's end.  */
X  _CONST_ char **old_regstart, **old_regend;
X
X  /* The is_active field of reg_info helps us keep track of which (possibly
X     nested) subexpressions we are currently in. The matched_something
X     field of reg_info[reg_num] helps us tell whether or not we have
X     matched any of the pattern so far this time through the reg_num-th
X     subexpression.  These two fields get reset each time through any
X     loop their register is in.  */
X  register_info_type *reg_info; 
X
X  /* The following record the register info as found in the above
X     variables when we find a match better than any we've seen before. 
X     This happens as we backtrack through the failure points, which in
X     turn happens only if we have not yet matched the entire string. */
X  unsigned best_regs_set = false;
X  _CONST_ char **best_regstart, **best_regend;
X  
X  /* Logically, this is `best_regend[0]'.  But we don't want to have to
X     allocate space for that if we're not allocating space for anything
X     else (see below).  Also, we never need info about register 0 for
X     any of the other register vectors, and it seems rather a kludge to
X     treat `best_regend' differently than the rest.  So we keep track of
X     the end of the best match so far in a separate variable.  We
X     initialize this to NULL so that when we backtrack the first time
X     and need to test it, it's not garbage.  */
X  _CONST_ char *match_end = NULL;
X
X  /* Used when we pop values we don't care about.  */
X  _CONST_ char **reg_dummy;
X  register_info_type *reg_info_dummy;
X
#ifdef DEBUG
X  /* Counts the total number of registers pushed.  */
X  unsigned num_regs_pushed = 0; 	
#endif
X
X  DEBUG_PRINT1 ("\n\nEntering re_match_2.\n");
X  
X  INIT_FAIL_STACK ();
X  
X  /* Do not bother to initialize all the register variables if there are
X     no groups in the pattern, as it takes a fair amount of time.  If
X     there are groups, we include space for register 0 (the whole
X     pattern), even though we never use it, since it simplifies the
X     array indexing.  We should fix this.  */
X  if (bufp->re_nsub)
X    {
X      regstart = REGEX_TALLOC (num_regs, _CONST_ char *);
X      regend = REGEX_TALLOC (num_regs, _CONST_ char *);
X      old_regstart = REGEX_TALLOC (num_regs, _CONST_ char *);
X      old_regend = REGEX_TALLOC (num_regs, _CONST_ char *);
X      best_regstart = REGEX_TALLOC (num_regs, _CONST_ char *);
X      best_regend = REGEX_TALLOC (num_regs, _CONST_ char *);
X      reg_info = REGEX_TALLOC (num_regs, register_info_type);
X      reg_dummy = REGEX_TALLOC (num_regs, _CONST_ char *);
X      reg_info_dummy = REGEX_TALLOC (num_regs, register_info_type);
X
X      if (!(regstart && regend && old_regstart && old_regend && reg_info 
X            && best_regstart && best_regend && reg_dummy && reg_info_dummy)) 
X        {
X          FREE_VARIABLES ();
X          return -2;
X        }
X    }
#ifdef REGEX_MALLOC
X  else
X    {
X      /* We must initialize all our variables to NULL, so that
X         `FREE_VARIABLES' doesn't try to free them.  */
X      regstart = regend = old_regstart = old_regend = best_regstart
X        = best_regend = reg_dummy = NULL;
X      reg_info = reg_info_dummy = (register_info_type *) NULL;
X    }
#endif /* REGEX_MALLOC */
X
X  /* The starting position is bogus.  */
X  if (pos < 0 || pos > size1 + size2)
X    {
X      FREE_VARIABLES ();
X      return -1;
X    }
X    
X  /* Initialize subexpression text positions to -1 to mark ones that no
X     start_memory/stop_memory has been seen for. Also initialize the
X     register information struct.  */
X  for (mcnt = 1; mcnt < num_regs; mcnt++)
X    {
X      regstart[mcnt] = regend[mcnt] 
X        = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE;
X        
X      REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE;
X      IS_ACTIVE (reg_info[mcnt]) = 0;
X      MATCHED_SOMETHING (reg_info[mcnt]) = 0;
X      EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0;
X    }
X  
X  /* We move `string1' into `string2' if the latter's empty -- but not if
X     `string1' is null.  */
X  if (size2 == 0 && string1 != NULL)
X    {
X      string2 = string1;
X      size2 = size1;
X      string1 = 0;
X      size1 = 0;
X    }
X  end1 = string1 + size1;
X  end2 = string2 + size2;
X
X  /* Compute where to stop matching, within the two strings.  */
X  if (stop <= size1)
X    {
X      end_match_1 = string1 + stop;
X      end_match_2 = string2;
X    }
X  else
X    {
X      end_match_1 = end1;
X      end_match_2 = string2 + stop - size1;
X    }
X
X  /* `p' scans through the pattern as `d' scans through the data. 
X     `dend' is the end of the input string that `d' points within.  `d'
X     is advanced into the following input string whenever necessary, but
X     this happens before fetching; therefore, at the beginning of the
X     loop, `d' can be pointing at the end of a string, but it cannot
X     equal `string2'.  */
X  if (size1 > 0 && pos <= size1)
X    {
X      d = string1 + pos;
X      dend = end_match_1;
X    }
X  else
X    {
X      d = string2 + pos - size1;
X      dend = end_match_2;
X    }
X
X  DEBUG_PRINT1 ("The compiled pattern is: ");
X  DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend);
X  DEBUG_PRINT1 ("The string to match is: `");
X  DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2);
X  DEBUG_PRINT1 ("'\n");
X  
X  /* This loops over pattern commands.  It exits by returning from the
X     function if the match is complete, or it drops through if the match
X     fails at this starting point in the input data.  */
X  for (;;)
X    {
X      DEBUG_PRINT2 ("\n0x%x: ", p);
X
X      if (p == pend)
X	{ /* End of pattern means we might have succeeded.  */
X          DEBUG_PRINT1 ("end of pattern ... ");
X          
X	  /* If we haven't matched the entire string, and we want the
X             longest match, try backtracking.  */
X          if (d != end_match_2)
X	    {
X              DEBUG_PRINT1 ("backtracking.\n");
X              
X              if (!FAIL_STACK_EMPTY ())
X                { /* More failure points to try.  */
X                  boolean same_str_p = (FIRST_STRING_P (match_end) 
X	        	                == MATCHING_IN_FIRST_STRING);
X
X                  /* If exceeds best match so far, save it.  */
X                  if (!best_regs_set
X                      || (same_str_p && d > match_end)
X                      || (!same_str_p && !MATCHING_IN_FIRST_STRING))
X                    {
X                      best_regs_set = true;
X                      match_end = d;
X                      
X                      DEBUG_PRINT1 ("\nSAVING match as best so far.\n");
X                      
X                      for (mcnt = 1; mcnt < num_regs; mcnt++)
X                        {
X                          best_regstart[mcnt] = regstart[mcnt];
X                          best_regend[mcnt] = regend[mcnt];
X                        }
X                    }
X                  goto fail;	       
X                }
X
X              /* If no failure points, don't restore garbage.  */
X              else if (best_regs_set)   
X                {
X  	        restore_best_regs:
X                  /* Restore best match.  It may happen that `dend ==
X                     end_match_1' while the restored d is in string2.
X                     For example, the pattern `x.*y.*z' against the
X                     strings `x-' and `y-z-', if the two strings are
X                     not consecutive in memory.  */
X                  DEBUG_PRINT1 ("Restoring best registers.\n");
X                  
X                  d = match_end;
X                  dend = ((d >= string1 && d <= end1)
X		           ? end_match_1 : end_match_2);
X
X		  for (mcnt = 1; mcnt < num_regs; mcnt++)
X		    {
X		      regstart[mcnt] = best_regstart[mcnt];
X		      regend[mcnt] = best_regend[mcnt];
X		    }
X                }
X            } /* d != end_match_2 */
X
X          DEBUG_PRINT1 ("Accepting match.\n");
X
X          /* If caller wants register contents data back, do it.  */
X          if (regs && !bufp->no_sub)
X	    {
X              /* Have the register data arrays been allocated?  */
X              if (bufp->regs_allocated == REGS_UNALLOCATED)
X                { /* No.  So allocate them with malloc.  We need one
X                     extra element beyond `num_regs' for the `-1' marker
X                     GNU code uses.  */
X                  regs->num_regs = MAX (RE_NREGS, num_regs + 1);
X                  regs->start = TALLOC (regs->num_regs, regoff_t);
X                  regs->end = TALLOC (regs->num_regs, regoff_t);
X                  if (regs->start == NULL || regs->end == NULL)
X                    return -2;
X                  bufp->regs_allocated = REGS_REALLOCATE;
X                }
X              else if (bufp->regs_allocated == REGS_REALLOCATE)
X                { /* Yes.  If we need more elements than were already
X                     allocated, reallocate them.  If we need fewer, just
X                     leave it alone.  */
X                  if (regs->num_regs < num_regs + 1)
X                    {
X                      regs->num_regs = num_regs + 1;
X                      RETALLOC (regs->start, regs->num_regs, regoff_t);
X                      RETALLOC (regs->end, regs->num_regs, regoff_t);
X                      if (regs->start == NULL || regs->end == NULL)
X                        return -2;
X                    }
X                }
X              else
X                assert (bufp->regs_allocated == REGS_FIXED);
X
X              /* Convert the pointer data in `regstart' and `regend' to
X                 indices.  Register zero has to be set differently,
X                 since we haven't kept track of any info for it.  */
X              if (regs->num_regs > 0)
X                {
X                  regs->start[0] = pos;
X                  regs->end[0] = (MATCHING_IN_FIRST_STRING ? d - string1
X			          : d - string2 + size1);
X                }
X              
X              /* Go through the first `min (num_regs, regs->num_regs)'
X                 registers, since that is all we initialized.  */
X	      for (mcnt = 1; mcnt < MIN (num_regs, regs->num_regs); mcnt++)
X		{
X                  if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt]))
X                    regs->start[mcnt] = regs->end[mcnt] = -1;
X                  else
X                    {
X		      regs->start[mcnt] = POINTER_TO_OFFSET (regstart[mcnt]);
X                      regs->end[mcnt] = POINTER_TO_OFFSET (regend[mcnt]);
X                    }
X		}
X              
X              /* If the regs structure we return has more elements than
X                 were in the pattern, set the extra elements to -1.  If
X                 we (re)allocated the registers, this is the case,
X                 because we always allocate enough to have at least one
X                 -1 at the end.  */
X              for (mcnt = num_regs; mcnt < regs->num_regs; mcnt++)
X                regs->start[mcnt] = regs->end[mcnt] = -1;
X	    } /* regs && !bufp->no_sub */
X
X          FREE_VARIABLES ();
X          DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n",
X                        nfailure_points_pushed, nfailure_points_popped,
X                        nfailure_points_pushed - nfailure_points_popped);
X          DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed);
X
X          mcnt = d - pos - (MATCHING_IN_FIRST_STRING 
X			    ? string1 
X			    : string2 - size1);
X
X          DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt);
X
X          return mcnt;
X        }
X
X      /* Otherwise match next pattern command.  */
#ifdef SWITCH_ENUM_BUG
X      switch ((int) ((re_opcode_t) *p++))
#else
X      switch ((re_opcode_t) *p++)
#endif
X	{
X        /* Ignore these.  Used to ignore the n of succeed_n's which
X           currently have n == 0.  */
X        case no_op:
X          DEBUG_PRINT1 ("EXECUTING no_op.\n");
X          break;
X
X
X        /* Match the next n pattern characters exactly.  The following
X           byte in the pattern defines n, and the n bytes after that
X           are the characters to match.  */
X	case exactn:
X	  mcnt = *p++;
X          DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt);
X
X          /* This is written out as an if-else so we don't waste time
X             testing `translate' inside the loop.  */
X          if (translate)
X	    {
X	      do
X		{
X		  PREFETCH ();
X		  if (translate[(unsigned char) *d++] != (char) *p++)
X                    goto fail;
X		}
X	      while (--mcnt);
X	    }
X	  else
X	    {
X	      do
X		{
X		  PREFETCH ();
X		  if (*d++ != (char) *p++) goto fail;
X		}
X	      while (--mcnt);
X	    }
X	  SET_REGS_MATCHED ();
X          break;
X
X
X        /* Match any character except possibly a newline or a null.  */
X	case anychar:
X          DEBUG_PRINT1 ("EXECUTING anychar.\n");
X
X          PREFETCH ();
X
X          if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n')
X              || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000'))
X	    goto fail;
X
X          SET_REGS_MATCHED ();
X          DEBUG_PRINT2 ("  Matched `%d'.\n", *d);
X          d++;
X	  break;
X
X
X	case charset:
X	case charset_not:
X	  {
X	    register unsigned char c;
X	    boolean not = (re_opcode_t) *(p - 1) == charset_not;
X
X            DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : "");
X
X	    PREFETCH ();
X	    c = TRANSLATE (*d); /* The character to match.  */
X
X            /* Cast to `unsigned' instead of `unsigned char' in case the
X               bit list is a full 32 bytes long.  */
X	    if (c < (unsigned) (*p * BYTEWIDTH)
X		&& p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
X	      not = !not;
X
X	    p += 1 + *p;
X
X	    if (!not) goto fail;
X            
X	    SET_REGS_MATCHED ();
X            d++;
X	    break;
X	  }
X
X
X        /* The beginning of a group is represented by start_memory.
X           The arguments are the register number in the next byte, and the
X           number of groups inner to this one in the next.  The text
X           matched within the group is recorded (in the internal
X           registers data structure) under the register number.  */
X        case start_memory:
X	  DEBUG_PRINT3 ("EXECUTING start_memory %d (%d):\n", *p, p[1]);
X
X          /* Find out if this group can match the empty string.  */
X	  p1 = p;		/* To send to group_match_null_string_p.  */
X          
X          if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE)
X            REG_MATCH_NULL_STRING_P (reg_info[*p]) 
X              = group_match_null_string_p (&p1, pend, reg_info);
X
X          /* Save the position in the string where we were the last time
X             we were at this open-group operator in case the group is
X             operated upon by a repetition operator, e.g., with `(a*)*b'
X             against `ab'; then we want to ignore where we are now in
X             the string in case this attempt to match fails.  */
X          old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
X                             ? REG_UNSET (regstart[*p]) ? d : regstart[*p]
X                             : regstart[*p];
X	  DEBUG_PRINT2 ("  old_regstart: %d\n", 
X			 POINTER_TO_OFFSET (old_regstart[*p]));
X
X          regstart[*p] = d;
X	  DEBUG_PRINT2 ("  regstart: %d\n", POINTER_TO_OFFSET (regstart[*p]));
X
X          IS_ACTIVE (reg_info[*p]) = 1;
X          MATCHED_SOMETHING (reg_info[*p]) = 0;
X          
X          /* This is the new highest active register.  */
X          highest_active_reg = *p;
X          
X          /* If nothing was active before, this is the new lowest active
X             register.  */
X          if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
X            lowest_active_reg = *p;
X
X          /* Move past the register number and inner group count.  */
X          p += 2;
X          break;
X
X
X        /* The stop_memory opcode represents the end of a group.  Its
X           arguments are the same as start_memory's: the register
X           number, and the number of inner groups.  */
X	case stop_memory:
X	  DEBUG_PRINT3 ("EXECUTING stop_memory %d (%d):\n", *p, p[1]);
X             
X          /* We need to save the string position the last time we were at
X             this close-group operator in case the group is operated
X             upon by a repetition operator, e.g., with `((a*)*(b*)*)*'
X             against `aba'; then we want to ignore where we are now in
X             the string in case this attempt to match fails.  */
X          old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
X                           ? REG_UNSET (regend[*p]) ? d : regend[*p]
X			   : regend[*p];
X	  DEBUG_PRINT2 ("      old_regend: %d\n", 
X			 POINTER_TO_OFFSET (old_regend[*p]));
X
X          regend[*p] = d;
X	  DEBUG_PRINT2 ("      regend: %d\n", POINTER_TO_OFFSET (regend[*p]));
X
X          /* This register isn't active anymore.  */
X          IS_ACTIVE (reg_info[*p]) = 0;
X          
X          /* If this was the only register active, nothing is active
X             anymore.  */
X          if (lowest_active_reg == highest_active_reg)
X            {
X              lowest_active_reg = NO_LOWEST_ACTIVE_REG;
X              highest_active_reg = NO_HIGHEST_ACTIVE_REG;
X            }
X          else
X            { /* We must scan for the new highest active register, since
X                 it isn't necessarily one less than now: consider
X                 (a(b)c(d(e)f)g).  When group 3 ends, after the f), the
X                 new highest active register is 1.  */
X              unsigned char r = *p - 1;
X              while (r > 0 && !IS_ACTIVE (reg_info[r]))
X                r--;
X              
X              /* If we end up at register zero, that means that we saved
X                 the registers as the result of an `on_failure_jump', not
X                 a `start_memory', and we jumped to past the innermost
X                 `stop_memory'.  For example, in ((.)*) we save
X                 registers 1 and 2 as a result of the *, but when we pop
X                 back to the second ), we are at the stop_memory 1.
X                 Thus, nothing is active.  */
X	      if (r == 0)
X                {
X                  lowest_active_reg = NO_LOWEST_ACTIVE_REG;
X                  highest_active_reg = NO_HIGHEST_ACTIVE_REG;
X                }
X              else
X                highest_active_reg = r;
X            }
X          
X          /* If just failed to match something this time around with a
X             group that's operated on by a repetition operator, try to
X             force exit from the ``loop'', and restore the register
X             information for this group that we had before trying this
X             last match.  */
X          if ((!MATCHED_SOMETHING (reg_info[*p])
X               || (re_opcode_t) p[-3] == start_memory)
X	      && (p + 2) < pend)              
X            {
X              boolean is_a_jump_n = false;
X              
X              p1 = p + 2;
X              mcnt = 0;
X              switch ((re_opcode_t) *p1++)
X                {
X                  case jump_n:
X		    is_a_jump_n = true;
X                  case pop_failure_jump:
X		  case maybe_pop_jump:
X		  case jump:
X		  case dummy_failure_jump:
X                    EXTRACT_NUMBER_AND_INCR (mcnt, p1);
X		    if (is_a_jump_n)
X		      p1 += 2;
X                    break;
X                  
X                  default:
X                    /* do nothing */ ;
X                }
X	      p1 += mcnt;
X        
X              /* If the next operation is a jump backwards in the pattern
X	         to an on_failure_jump right before the start_memory
X                 corresponding to this stop_memory, exit from the loop
X                 by forcing a failure after pushing on the stack the
X                 on_failure_jump's jump in the pattern, and d.  */
X              if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump
X                  && (re_opcode_t) p1[3] == start_memory && p1[4] == *p)
X		{
X                  /* If this group ever matched anything, then restore
X                     what its registers were before trying this last
X                     failed match, e.g., with `(a*)*b' against `ab' for
X                     regstart[1], and, e.g., with `((a*)*(b*)*)*'
X                     against `aba' for regend[3].
X                     
X                     Also restore the registers for inner groups for,
X                     e.g., `((a*)(b*))*' against `aba' (register 3 would
X                     otherwise get trashed).  */
X                     
X                  if (EVER_MATCHED_SOMETHING (reg_info[*p]))
X		    {
X		      unsigned r; 
X        
X                      EVER_MATCHED_SOMETHING (reg_info[*p]) = 0;
X                      
X		      /* Restore this and inner groups' (if any) registers.  */
X                      for (r = *p; r < *p + *(p + 1); r++)
X                        {
X                          regstart[r] = old_regstart[r];
X
X                          /* xx why this test?  */
X                          if ((int) old_regend[r] >= (int) regstart[r])
X                            regend[r] = old_regend[r];
X                        }     
X                    }
X		  p1++;
X                  EXTRACT_NUMBER_AND_INCR (mcnt, p1);
X                  PUSH_FAILURE_POINT (p1 + mcnt, d, -2);
X
X                  goto fail;
X                }
X            }
X          
X          /* Move past the register number and the inner group count.  */
X          p += 2;
X          break;
X
X
X	/* \<digit> has been turned into a `duplicate' command which is
X           followed by the numeric value of <digit> as the register number.  */
X        case duplicate:
X	  {
X	    register _CONST_ char *d2, *dend2;
X	    int regno = *p++;   /* Get which register to match against.  */
X	    DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno);
X
X	    /* Can't back reference a group which we've never matched.  */
X            if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno]))
X              goto fail;
X              
X            /* Where in input to try to start matching.  */
X            d2 = regstart[regno];
X            
X            /* Where to stop matching; if both the place to start and
X               the place to stop matching are in the same string, then
X               set to the place to stop, otherwise, for now have to use
X               the end of the first string.  */
X
X            dend2 = ((FIRST_STRING_P (regstart[regno]) 
X		      == FIRST_STRING_P (regend[regno]))
X		     ? regend[regno] : end_match_1);
X	    for (;;)
X	      {
X		/* If necessary, advance to next segment in register
X                   contents.  */
X		while (d2 == dend2)
X		  {
X		    if (dend2 == end_match_2) break;
X		    if (dend2 == regend[regno]) break;
X
X                    /* End of string1 => advance to string2. */
X                    d2 = string2;
X                    dend2 = regend[regno];
X		  }
X		/* At end of register contents => success */
X		if (d2 == dend2) break;
X
X		/* If necessary, advance to next segment in data.  */
X		PREFETCH ();
X
X		/* How many characters left in this segment to match.  */
X		mcnt = dend - d;
X                
X		/* Want how many consecutive characters we can match in
X                   one shot, so, if necessary, adjust the count.  */
X                if (mcnt > dend2 - d2)
X		  mcnt = dend2 - d2;
X                  
X		/* Compare that many; failure if mismatch, else move
X                   past them.  */
X		if (translate 
X                    ? bcmp_translate (d, d2, mcnt, translate) 
X                    : bcmp (d, d2, mcnt))
X		  goto fail;
X		d += mcnt, d2 += mcnt;
X	      }
X	  }
X	  break;
X
X
X        /* begline matches the empty string at the beginning of the string
X           (unless `not_bol' is set in `bufp'), and, if
X           `newline_anchor' is set, after newlines.  */
X	case begline:
X          DEBUG_PRINT1 ("EXECUTING begline.\n");
X          
X          if (AT_STRINGS_BEG (d))
X            {
X              if (!bufp->not_bol) break;
X            }
X          else if (d[-1] == '\n' && bufp->newline_anchor)
X            {
X              break;
X            }
X          /* In all other cases, we fail.  */
X          goto fail;
X
X
X        /* endline is the dual of begline.  */
X	case endline:
X          DEBUG_PRINT1 ("EXECUTING endline.\n");
X
X          if (AT_STRINGS_END (d))
X            {
X              if (!bufp->not_eol) break;
X            }
X          
X          /* We have to ``prefetch'' the next character.  */
X          else if ((d == end1 ? *string2 : *d) == '\n'
X                   && bufp->newline_anchor)
X            {
X              break;
X            }
X          goto fail;
X
X
X	/* Match at the very beginning of the data.  */
X        case begbuf:
X          DEBUG_PRINT1 ("EXECUTING begbuf.\n");
X          if (AT_STRINGS_BEG (d))
X            break;
X          goto fail;
X
X
X	/* Match at the very end of the data.  */
X        case endbuf:
X          DEBUG_PRINT1 ("EXECUTING endbuf.\n");
X	  if (AT_STRINGS_END (d))
X	    break;
X          goto fail;
X
X
X        /* on_failure_keep_string_jump is used to optimize `.*\n'.  It
X           pushes NULL as the value for the string on the stack.  Then
X           `pop_failure_point' will keep the current value for the
X           string, instead of restoring it.  To see why, consider
X           matching `foo\nbar' against `.*\n'.  The .* matches the foo;
X           then the . fails against the \n.  But the next thing we want
X           to do is match the \n against the \n; if we restored the
X           string value, we would be back at the foo.
X           
X           Because this is used only in specific cases, we don't need to
X           check all the things that `on_failure_jump' does, to make
X           sure the right things get saved on the stack.  Hence we don't
X           share its code.  The only reason to push anything on the
X           stack at all is that otherwise we would have to change
X           `anychar's code to do something besides goto fail in this
X           case; that seems worse than this.  */
X        case on_failure_keep_string_jump:
X          DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump");
X          
X          EXTRACT_NUMBER_AND_INCR (mcnt, p);
X          DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt);
X
X          PUSH_FAILURE_POINT (p + mcnt, NULL, -2);
X          break;
X
X
X	/* Uses of on_failure_jump:
X        
X           Each alternative starts with an on_failure_jump that points
X           to the beginning of the next alternative.  Each alternative
X           except the last ends with a jump that in effect jumps past
X           the rest of the alternatives.  (They really jump to the
X           ending jump of the following alternative, because tensioning
X           these jumps is a hassle.)
X
X           Repeats start with an on_failure_jump that points past both
X           the repetition text and either the following jump or
X           pop_failure_jump back to this on_failure_jump.  */
X	case on_failure_jump:
X        on_failure:
X          DEBUG_PRINT1 ("EXECUTING on_failure_jump");
X
X          EXTRACT_NUMBER_AND_INCR (mcnt, p);
X          DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt);
X
X          /* If this on_failure_jump comes right before a group (i.e.,
X             the original * applied to a group), save the information
X             for that group and all inner ones, so that if we fail back
X             to this point, the group's information will be correct.
X             For example, in \(a*\)*\1, we need the preceding group,
X             and in \(\(a*\)b*\)\2, we need the inner group.  */
X
X          /* We can't use `p' to check ahead because we push
X             a failure point to `p + mcnt' after we do this.  */
X          p1 = p;
X
X          /* We need to skip no_op's before we look for the
X             start_memory in case this on_failure_jump is happening as
X             the result of a completed succeed_n, as in \(a\)\{1,3\}b\1
X             against aba.  */
X          while (p1 < pend && (re_opcode_t) *p1 == no_op)
X            p1++;
X
X          if (p1 < pend && (re_opcode_t) *p1 == start_memory)
X            {
X              /* We have a new highest active register now.  This will
X                 get reset at the start_memory we are about to get to,
X                 but we will have saved all the registers relevant to
X                 this repetition op, as described above.  */
X              highest_active_reg = *(p1 + 1) + *(p1 + 2);
X              if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
X                lowest_active_reg = *(p1 + 1);
X            }
X
X          DEBUG_PRINT1 (":\n");
X          PUSH_FAILURE_POINT (p + mcnt, d, -2);
X          break;
X
X
X        /* A smart repeat ends with `maybe_pop_jump'.
X	   We change it to either `pop_failure_jump' or `jump'.  */
X        case maybe_pop_jump:
X          EXTRACT_NUMBER_AND_INCR (mcnt, p);
X          DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt);
X          {
X	    register unsigned char *p2 = p;
X
X            /* Compare the beginning of the repeat with what in the
X               pattern follows its end. If we can establish that there
X               is nothing that they would both match, i.e., that we
X               would have to backtrack because of (as in, e.g., `a*a')
X               then we can change to pop_failure_jump, because we'll
X               never have to backtrack.
X               
X               This is not true in the case of alternatives: in
X               `(a|ab)*' we do need to backtrack to the `ab' alternative
X               (e.g., if the string was `ab').  But instead of trying to
X               detect that here, the alternative has put on a dummy
X               failure point which is what we will end up popping.  */
X
X	    /* Skip over open/close-group commands.  */
X	    while (p2 + 2 < pend
X		   && ((re_opcode_t) *p2 == stop_memory
X		       || (re_opcode_t) *p2 == start_memory))
X	      p2 += 3;			/* Skip over args, too.  */
X
X            /* If we're at the end of the pattern, we can change.  */
X            if (p2 == pend)
X	      {
X		/* Consider what happens when matching ":\(.*\)"
X		   against ":/".  I don't really understand this code
X		   yet.  */
X  	        p[-3] = (unsigned char) pop_failure_jump;
X                DEBUG_PRINT1
X                  ("  End of pattern: change to `pop_failure_jump'.\n");
X              }
X
X            else if ((re_opcode_t) *p2 == exactn
X		     || (bufp->newline_anchor && (re_opcode_t) *p2 == endline))
X	      {
X		register unsigned char c
X                  = *p2 == (unsigned char) endline ? '\n' : p2[2];
X		p1 = p + mcnt;
X
X                /* p1[0] ... p1[2] are the `on_failure_jump' corresponding
X                   to the `maybe_finalize_jump' of this case.  Examine what 
X                   follows.  */
X                if ((re_opcode_t) p1[3] == exactn && p1[5] != c)
X                  {
X  		    p[-3] = (unsigned char) pop_failure_jump;
X                    DEBUG_PRINT3 ("  %c != %c => pop_failure_jump.\n",
X                                  c, p1[5]);
X                  }
X                  
X		else if ((re_opcode_t) p1[3] == charset
X			 || (re_opcode_t) p1[3] == charset_not)
X		  {
X		    int not = (re_opcode_t) p1[3] == charset_not;
X                    
X		    if (c < (unsigned char) (p1[4] * BYTEWIDTH)
X			&& p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
X		      not = !not;
X
X                    /* `not' is equal to 1 if c would match, which means
X                        that we can't change to pop_failure_jump.  */
X		    if (!not)
X                      {
X  		        p[-3] = (unsigned char) pop_failure_jump;
X                        DEBUG_PRINT1 ("  No match => pop_failure_jump.\n");
X                      }
X		  }
X	      }
X	  }
X	  p -= 2;		/* Point at relative address again.  */
X	  if ((re_opcode_t) p[-1] != pop_failure_jump)
X	    {
X	      p[-1] = (unsigned char) jump;
X              DEBUG_PRINT1 ("  Match => jump.\n");
X	      goto unconditional_jump;
X	    }
X        /* Note fall through.  */
X
X
X	/* The end of a simple repeat has a pop_failure_jump back to
X           its matching on_failure_jump, where the latter will push a
X           failure point.  The pop_failure_jump takes off failure
X           points put on by this pop_failure_jump's matching
X           on_failure_jump; we got through the pattern to here from the
X           matching on_failure_jump, so didn't fail.  */
X        case pop_failure_jump:
X          {
X            /* We need to pass separate storage for the lowest and
X               highest registers, even though we don't care about the
X               actual values.  Otherwise, we will restore only one
X               register from the stack, since lowest will == highest in
X               `pop_failure_point'.  */
X            unsigned dummy_low_reg, dummy_high_reg;
X            unsigned char *pdummy;
X            _CONST_ char *sdummy;
X
X            DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n");
X            POP_FAILURE_POINT (sdummy, pdummy,
X                               dummy_low_reg, dummy_high_reg,
X                               reg_dummy, reg_dummy, reg_info_dummy);
X          }
X          /* Note fall through.  */
X
X          
X        /* Unconditionally jump (without popping any failure points).  */
X        case jump:
X	unconditional_jump:
X	  EXTRACT_NUMBER_AND_INCR (mcnt, p);	/* Get the amount to jump.  */
X          DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt);
X	  p += mcnt;				/* Do the jump.  */
X          DEBUG_PRINT2 ("(to 0x%x).\n", p);
X	  break;
X
X	
X        /* We need this opcode so we can detect where alternatives end
X           in `group_match_null_string_p' et al.  */
X        case jump_past_alt:
X          DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n");
X          goto unconditional_jump;
X
X
X        /* Normally, the on_failure_jump pushes a failure point, which
X           then gets popped at pop_failure_jump.  We will end up at
X           pop_failure_jump, also, and with a pattern of, say, `a+', we
X           are skipping over the on_failure_jump, so we have to push
X           something meaningless for pop_failure_jump to pop.  */
X        case dummy_failure_jump:
X          DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n");
X          /* It doesn't matter what we push for the string here.  What
X             the code at `fail' tests is the value for the pattern.  */
X          PUSH_FAILURE_POINT (0, 0, -2);
X          goto unconditional_jump;
X
X
X        /* At the end of an alternative, we need to push a dummy failure
X           point in case we are followed by a `pop_failure_jump', because
X           we don't want the failure point for the alternative to be
X           popped.  For example, matching `(a|ab)*' against `aab'
X           requires that we match the `ab' alternative.  */
X        case push_dummy_failure:
X          DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n");
X          /* See comments just above at `dummy_failure_jump' about the
X             two zeroes.  */
X          PUSH_FAILURE_POINT (0, 0, -2);
X          break;
X
X        /* Have to succeed matching what follows at least n times.
X           After that, handle like `on_failure_jump'.  */
X        case succeed_n: 
X          EXTRACT_NUMBER (mcnt, p + 2);
X          DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt);
X
X          assert (mcnt >= 0);
X          /* Originally, this is how many times we HAVE to succeed.  */
X          if (mcnt > 0)
X            {
X               mcnt--;
X	       p += 2;
X               STORE_NUMBER_AND_INCR (p, mcnt);
X               DEBUG_PRINT3 ("  Setting 0x%x to %d.\n", p, mcnt);
X            }
X	  else if (mcnt == 0)
X            {
X              DEBUG_PRINT2 ("  Setting two bytes from 0x%x to no_op.\n", p+2);
X	      p[2] = (unsigned char) no_op;
X              p[3] = (unsigned char) no_op;
X              goto on_failure;
X            }
X          break;
X        
X        case jump_n: 
X          EXTRACT_NUMBER (mcnt, p + 2);
X          DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt);
X
X          /* Originally, this is how many times we CAN jump.  */
X          if (mcnt)
X            {
X               mcnt--;
X               STORE_NUMBER (p + 2, mcnt);
X	       goto unconditional_jump;	     
X            }
X          /* If don't have to jump any more, skip over the rest of command.  */
X	  else      
X	    p += 4;		     
X          break;
X        
X	case set_number_at:
X	  {
X            DEBUG_PRINT1 ("EXECUTING set_number_at.\n");
X
X            EXTRACT_NUMBER_AND_INCR (mcnt, p);
X            p1 = p + mcnt;
X            EXTRACT_NUMBER_AND_INCR (mcnt, p);
X            DEBUG_PRINT3 ("  Setting 0x%x to %d.\n", p1, mcnt);
X	    STORE_NUMBER (p1, mcnt);
X            break;
X          }
X
X        case wordbound:
X          DEBUG_PRINT1 ("EXECUTING wordbound.\n");
X          if (AT_WORD_BOUNDARY (d))
X	    break;
X          goto fail;
X
X	case notwordbound:
X          DEBUG_PRINT1 ("EXECUTING notwordbound.\n");
X	  if (AT_WORD_BOUNDARY (d))
X	    goto fail;
X          break;
X
X	case wordbeg:
X          DEBUG_PRINT1 ("EXECUTING wordbeg.\n");
X	  if (WORDCHAR_P (d) && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1)))
X	    break;
X          goto fail;
X
X	case wordend:
X          DEBUG_PRINT1 ("EXECUTING wordend.\n");
X	  if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1)
X              && (!WORDCHAR_P (d) || AT_STRINGS_END (d)))
X	    break;
X          goto fail;
X
#ifdef emacs
#ifdef emacs19
X  	case before_dot:
X          DEBUG_PRINT1 ("EXECUTING before_dot.\n");
X 	  if (PTR_CHAR_POS ((unsigned char *) d) >= point)
X  	    goto fail;
X  	  break;
X  
X  	case at_dot:
X          DEBUG_PRINT1 ("EXECUTING at_dot.\n");
X 	  if (PTR_CHAR_POS ((unsigned char *) d) != point)
X  	    goto fail;
X  	  break;
X  
X  	case after_dot:
X          DEBUG_PRINT1 ("EXECUTING after_dot.\n");
X          if (PTR_CHAR_POS ((unsigned char *) d) <= point)
X  	    goto fail;
X  	  break;
#else /* not emacs19 */
X	case at_dot:
X          DEBUG_PRINT1 ("EXECUTING at_dot.\n");
X	  if (PTR_CHAR_POS ((unsigned char *) d) + 1 != point)
X	    goto fail;
X	  break;
#endif /* not emacs19 */
X
X	case syntaxspec:
X          DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt);
X	  mcnt = *p++;
X	  goto matchsyntax;
X
X        case wordchar:
X          DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n");
X	  mcnt = (int) Sword;
X        matchsyntax:
X	  PREFETCH ();
X	  if (SYNTAX (*d++) != (enum syntaxcode) mcnt)
X            goto fail;
X          SET_REGS_MATCHED ();
X	  break;
X
X	case notsyntaxspec:
X          DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt);
X	  mcnt = *p++;
X	  goto matchnotsyntax;
X
X        case notwordchar:
X          DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n");
X	  mcnt = (int) Sword;
X        matchnotsyntax:
X	  PREFETCH ();
X	  if (SYNTAX (*d++) == (enum syntaxcode) mcnt)
X            goto fail;
X	  SET_REGS_MATCHED ();
X          break;
X
#else /* not emacs */
X	case wordchar:
X          DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n");
X	  PREFETCH ();
X          if (!WORDCHAR_P (d))
X            goto fail;
X	  SET_REGS_MATCHED ();
X          d++;
X	  break;
X	  
X	case notwordchar:
X          DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n");
X	  PREFETCH ();
X	  if (WORDCHAR_P (d))
X            goto fail;
X          SET_REGS_MATCHED ();
X          d++;
X	  break;
#endif /* not emacs */
X          
X        default:
X          abort ();
X	}
X      continue;  /* Successfully executed one pattern command; keep going.  */
X
X
X    /* We goto here if a matching operation fails. */
X    fail:
X      if (!FAIL_STACK_EMPTY ())
X	{ /* A restart point is known.  Restore to that state.  */
X          DEBUG_PRINT1 ("\nFAIL:\n");
X          POP_FAILURE_POINT (d, p,
X                             lowest_active_reg, highest_active_reg,
X                             regstart, regend, reg_info);
X
X          /* If this failure point is a dummy, try the next one.  */
X          if (!p)
X	    goto fail;
X
X          /* If we failed to the end of the pattern, don't examine *p.  */
X	  assert (p <= pend);
X          if (p < pend)
X            {
X              boolean is_a_jump_n = false;
X              
X              /* If failed to a backwards jump that's part of a repetition
X                 loop, need to pop this failure point and use the next one.  */
X              switch ((re_opcode_t) *p)
X                {
X                case jump_n:
X                  is_a_jump_n = true;
X                case maybe_pop_jump:
X                case pop_failure_jump:
X                case jump:
X                  p1 = p + 1;
X                  EXTRACT_NUMBER_AND_INCR (mcnt, p1);
X                  p1 += mcnt;	
X
X                  if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n)
X                      || (!is_a_jump_n
X                          && (re_opcode_t) *p1 == on_failure_jump))
X                    goto fail;
X                  break;
X                default:
X                  /* do nothing */ ;
X                }
X            }
X
X          if (d >= string1 && d <= end1)
X	    dend = end_match_1;
X        }
X      else
X        break;   /* Matching at this starting point really fails.  */
X    } /* for (;;) */
X
X  if (best_regs_set)
X    goto restore_best_regs;
X
X  FREE_VARIABLES ();
X
X  return -1;         			/* Failure to match.  */
} /* re_match_2 */
X
/* Subroutine definitions for re_match_2.  */
X
X
/* We are passed P pointing to a register number after a start_memory.
X   
X   Return true if the pattern up to the corresponding stop_memory can
X   match the empty string, and false otherwise.
X   
X   If we find the matching stop_memory, sets P to point to one past its number.
X   Otherwise, sets P to an undefined byte less than or equal to END.
X
X   We don't handle duplicates properly (yet).  */
X
static boolean
group_match_null_string_p (p, end, reg_info)
X    unsigned char **p, *end;
X    register_info_type *reg_info;
{
X  int mcnt;
X  /* Point to after the args to the start_memory.  */
X  unsigned char *p1 = *p + 2;
X  
X  while (p1 < end)
X    {
X      /* Skip over opcodes that can match nothing, and return true or
X	 false, as appropriate, when we get to one that can't, or to the
X         matching stop_memory.  */
X      
X      switch ((re_opcode_t) *p1)
X        {
X        /* Could be either a loop or a series of alternatives.  */
X        case on_failure_jump:
X          p1++;
X          EXTRACT_NUMBER_AND_INCR (mcnt, p1);
X          
X          /* If the next operation is not a jump backwards in the
X	     pattern.  */
X
X	  if (mcnt >= 0)
X	    {
X              /* Go through the on_failure_jumps of the alternatives,
X                 seeing if any of the alternatives cannot match nothing.
X                 The last alternative starts with only a jump,
X                 whereas the rest start with on_failure_jump and end
X                 with a jump, e.g., here is the pattern for `a|b|c':
X
X                 /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6
X                 /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3
X                 /exactn/1/c						
X
X                 So, we have to first go through the first (n-1)
X                 alternatives and then deal with the last one separately.  */
X
X
X              /* Deal with the first (n-1) alternatives, which start
X                 with an on_failure_jump (see above) that jumps to right
X                 past a jump_past_alt.  */
X
X              while ((re_opcode_t) p1[mcnt-3] == jump_past_alt)
X                {
X                  /* `mcnt' holds how many bytes long the alternative
X                     is, including the ending `jump_past_alt' and
X                     its number.  */
X
X                  if (!alt_match_null_string_p (p1, p1 + mcnt - 3, 
X				                      reg_info))
X                    return false;
X
X                  /* Move to right after this alternative, including the
X		     jump_past_alt.  */
X                  p1 += mcnt;	
X
X                  /* Break if it's the beginning of an n-th alternative
X                     that doesn't begin with an on_failure_jump.  */
X                  if ((re_opcode_t) *p1 != on_failure_jump)
X                    break;
X		
X		  /* Still have to check that it's not an n-th
X		     alternative that starts with an on_failure_jump.  */
X		  p1++;
X                  EXTRACT_NUMBER_AND_INCR (mcnt, p1);
X                  if ((re_opcode_t) p1[mcnt-3] != jump_past_alt)
X                    {
X		      /* Get to the beginning of the n-th alternative.  */
X                      p1 -= 3;
X                      break;
X                    }
X                }
X
X              /* Deal with the last alternative: go back and get number
X                 of the `jump_past_alt' just before it.  `mcnt' contains
X                 the length of the alternative.  */
X              EXTRACT_NUMBER (mcnt, p1 - 2);
X
X              if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info))
X                return false;
X
X              p1 += mcnt;	/* Get past the n-th alternative.  */
X            } /* if mcnt > 0 */
X          break;
X
X          
X        case stop_memory:
X	  assert (p1[1] == **p);
X          *p = p1 + 2;
X          return true;
X
X        
X        default: 
X          if (!common_op_match_null_string_p (&p1, end, reg_info))
X            return false;
X        }
X    } /* while p1 < end */
X
X  return false;
} /* group_match_null_string_p */
X
X
/* Similar to group_match_null_string_p, but doesn't deal with alternatives:
X   It expects P to be the first byte of a single alternative and END one
X   byte past the last. The alternative can contain groups.  */
X   
static boolean
alt_match_null_string_p (p, end, reg_info)
X    unsigned char *p, *end;
X    register_info_type *reg_info;
{
X  int mcnt;
X  unsigned char *p1 = p;
X  
X  while (p1 < end)
X    {
X      /* Skip over opcodes that can match nothing, and break when we get 
X         to one that can't.  */
X      
X      switch ((re_opcode_t) *p1)
X        {
X	/* It's a loop.  */
X        case on_failure_jump:
X          p1++;
X          EXTRACT_NUMBER_AND_INCR (mcnt, p1);
X          p1 += mcnt;
X          break;
X          
X	default: 
X          if (!common_op_match_null_string_p (&p1, end, reg_info))
X            return false;
X        }
X    }  /* while p1 < end */
X
X  return true;
} /* alt_match_null_string_p */
X
X
/* Deals with the ops common to group_match_null_string_p and
X   alt_match_null_string_p.  
X   
X   Sets P to one after the op and its arguments, if any.  */
X
static boolean
common_op_match_null_string_p (p, end, reg_info)
X    unsigned char **p, *end;
X    register_info_type *reg_info;
{
X  int mcnt;
X  boolean ret;
X  int reg_no;
X  unsigned char *p1 = *p;
X
X  switch ((re_opcode_t) *p1++)
X    {
X    case no_op:
X    case begline:
X    case endline:
X    case begbuf:
X    case endbuf:
X    case wordbeg:
X    case wordend:
X    case wordbound:
X    case notwordbound:
#ifdef emacs
X    case before_dot:
X    case at_dot:
X    case after_dot:
#endif
X      break;
X
X    case start_memory:
X      reg_no = *p1;
X      assert (reg_no > 0 && reg_no <= MAX_REGNUM);
X      ret = group_match_null_string_p (&p1, end, reg_info);
X      
X      /* Have to set this here in case we're checking a group which
X         contains a group and a back reference to it.  */
X
X      if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE)
X        REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret;
X
X      if (!ret)
X        return false;
X      break;
X          
X    /* If this is an optimized succeed_n for zero times, make the jump.  */
X    case jump:
X      EXTRACT_NUMBER_AND_INCR (mcnt, p1);
X      if (mcnt >= 0)
X        p1 += mcnt;
X      else
X        return false;
X      break;
X
X    case succeed_n:
X      /* Get to the number of times to succeed.  */
X      p1 += 2;		
X      EXTRACT_NUMBER_AND_INCR (mcnt, p1);
X
X      if (mcnt == 0)
X        {
X          p1 -= 4;
X          EXTRACT_NUMBER_AND_INCR (mcnt, p1);
X          p1 += mcnt;
X        }
X      else
X        return false;
X      break;
X
X    case duplicate: 
X      if (!REG_MATCH_NULL_STRING_P (reg_info[*p1]))
X        return false;
X      break;
X
X    case set_number_at:
X      p1 += 4;
X
X    default:
X      /* All other opcodes mean we cannot match the empty string.  */
X      return false;
X  }
X
X  *p = p1;
X  return true;
} /* common_op_match_null_string_p */
X
X
/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN
X   bytes; nonzero otherwise.  */
X   
static int
bcmp_translate (s1, s2, len, translate)
X     unsigned char *s1, *s2;
X     register int len;
X     char *translate;
{
X  register unsigned char *p1 = s1, *p2 = s2;
X  while (len)
X    {
X      if (translate[*p1++] != translate[*p2++]) return 1;
X      len--;
X    }
X  return 0;
}
X
/* Entry points for GNU code.  */
X
/* re_compile_pattern is the GNU regular expression compiler: it
X   compiles PATTERN (of length SIZE) and puts the result in BUFP.
X   Returns 0 if the pattern was valid, otherwise an error string.
X   
X   Assumes the `allocated' (and perhaps `buffer') and `translate' fields
X   are set in BUFP on entry.
X   
X   We call regex_compile to do the actual compilation.  */
X
_CONST_ char *
re_compile_pattern (pattern, length, bufp)
X     _CONST_ char *pattern;
X     int length;
X     struct re_pattern_buffer *bufp;
{
X  reg_errcode_t ret;
X  
X  /* GNU code is written to assume at least RE_NREGS registers will be set
X     (and at least one extra will be -1).  */
X  bufp->regs_allocated = REGS_UNALLOCATED;
X  
X  /* And GNU code determines whether or not to get register information
X     by passing null for the REGS argument to re_match, etc., not by
X     setting no_sub.  */
X  bufp->no_sub = 0;
X  
X  /* Match anchors at newline.  */
X  bufp->newline_anchor = 1;
X  
X  ret = regex_compile (pattern, length, re_syntax_options, bufp);
X
X  return re_error_msg[(int) ret];
}     
X
/* Entry points compatible with 4.2 BSD regex library.  We don't define
X   them if this is an Emacs or POSIX compilation.  */
X
#if !defined (emacs) && !defined (_POSIX_SOURCE)
X
/* BSD has one and only one pattern buffer.  */
static struct re_pattern_buffer re_comp_buf;
X
char *
re_comp (s)
X    _CONST_ char *s;
{
X  reg_errcode_t ret;
X  
X  if (!s)
X    {
X      if (!re_comp_buf.buffer)
X	return "No previous regular expression";
X      return 0;
X    }
X
X  if (!re_comp_buf.buffer)
X    {
X      re_comp_buf.buffer = (unsigned char *) malloc (200);
X      if (re_comp_buf.buffer == NULL)
X        return "Memory exhausted";
X      re_comp_buf.allocated = 200;
X
X      re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH);
X      if (re_comp_buf.fastmap == NULL)
X	return "Memory exhausted";
X    }
X
X  /* Since `re_exec' always passes NULL for the `regs' argument, we
X     don't need to initialize the pattern buffer fields which affect it.  */
X
X  /* Match anchors at newlines.  */
X  re_comp_buf.newline_anchor = 1;
X
X  ret = regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf);
X  
X  /* Yes, we're discarding `const' here.  */
X  return (char *) re_error_msg[(int) ret];
}
X
X
int
re_exec (s)
X    _CONST_ char *s;
{
X  _CONST_ int len = strlen (s);
X  return
X    0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0);
}
#endif /* not emacs and not _POSIX_SOURCE */
X
/* POSIX.2 functions.  Don't define these for Emacs.  */
X
#ifndef emacs
X
/* regcomp takes a regular expression as a string and compiles it.
X
X   PREG is a regex_t *.  We do not expect any fields to be initialized,
X   since POSIX says we shouldn't.  Thus, we set
X
X     `buffer' to the compiled pattern;
X     `used' to the length of the compiled pattern;
X     `syntax' to RE_SYNTAX_POSIX_EXTENDED if the
X       REG_EXTENDED bit in CFLAGS is set; otherwise, to
X       RE_SYNTAX_POSIX_BASIC;
X     `newline_anchor' to REG_NEWLINE being set in CFLAGS;
X     `fastmap' and `fastmap_accurate' to zero;
X     `re_nsub' to the number of subexpressions in PATTERN.
X
X   PATTERN is the address of the pattern string.
X
X   CFLAGS is a series of bits which affect compilation.
X
X     If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we
X     use POSIX basic syntax.
X
X     If REG_NEWLINE is set, then . and [^...] don't match newline.
X     Also, regexec will try a match beginning after every newline.
X
X     If REG_ICASE is set, then we considers upper- and lowercase
X     versions of letters to be equivalent when matching.
X
X     If REG_NOSUB is set, then when PREG is passed to regexec, that
X     routine will report only success or failure, and nothing about the
X     registers.
X
X   It returns 0 if it succeeds, nonzero if it doesn't.  (See regex.h for
X   the return codes and their meanings.)  */
X
int
regcomp (preg, pattern, cflags)
X    regex_t *preg;
X    _CONST_ char *pattern; 
X    int cflags;
{
X  reg_errcode_t ret;
X  unsigned syntax
X    = (cflags & REG_EXTENDED) ?
X      RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC;
X
X  /* regex_compile will allocate the space for the compiled pattern.  */
X  preg->buffer = 0;
X  preg->allocated = 0;
X  
X  /* Don't bother to use a fastmap when searching.  This simplifies the
X     REG_NEWLINE case: if we used a fastmap, we'd have to put all the
X     characters after newlines into the fastmap.  This way, we just try
X     every character.  */
X  preg->fastmap = 0;
X  
X  if (cflags & REG_ICASE)
X    {
X      unsigned i;
X      
X      preg->translate = (char *) malloc (CHAR_SET_SIZE);
X      if (preg->translate == NULL)
X        return (int) REG_ESPACE;
X
X      /* Map uppercase characters to corresponding lowercase ones.  */
X      for (i = 0; i < CHAR_SET_SIZE; i++)
X        preg->translate[i] = ISUPPER (i) ? tolower (i) : i;
X    }
X  else
X    preg->translate = NULL;
X
X  /* If REG_NEWLINE is set, newlines are treated differently.  */
X  if (cflags & REG_NEWLINE)
X    { /* REG_NEWLINE implies neither . nor [^...] match newline.  */
X      syntax &= ~RE_DOT_NEWLINE;
X      syntax |= RE_HAT_LISTS_NOT_NEWLINE;
X      /* It also changes the matching behavior.  */
X      preg->newline_anchor = 1;
X    }
X  else
X    preg->newline_anchor = 0;
X
X  preg->no_sub = !!(cflags & REG_NOSUB);
X
X  /* POSIX says a null character in the pattern terminates it, so we 
X     can use strlen here in compiling the pattern.  */
X  ret = regex_compile (pattern, strlen (pattern), syntax, preg);
X  
X  /* POSIX doesn't distinguish between an unmatched open-group and an
X     unmatched close-group: both are REG_EPAREN.  */
X  if (ret == REG_ERPAREN) ret = REG_EPAREN;
X  
X  return (int) ret;
}
X
X
/* regexec searches for a given pattern, specified by PREG, in the
X   string STRING.
X   
X   If NMATCH is zero or REG_NOSUB was set in the cflags argument to
X   `regcomp', we ignore PMATCH.  Otherwise, we assume PMATCH has at
X   least NMATCH elements, and we set them to the offsets of the
X   corresponding matched substrings.
X   
X   EFLAGS specifies `execution flags' which affect matching: if
X   REG_NOTBOL is set, then ^ does not match at the beginning of the
X   string; if REG_NOTEOL is set, then $ does not match at the end.
X   
X   We return 0 if we find a match and REG_NOMATCH if not.  */
X
int
regexec (preg, string, nmatch, pmatch, eflags)
X    _CONST_ regex_t *preg;
X    _CONST_ char *string; 
X    size_t nmatch; 
X    regmatch_t pmatch[]; 
X    int eflags;
{
X  int ret;
X  struct re_registers regs;
X  regex_t private_preg;
X  int len = strlen (string);
X  boolean want_reg_info = !preg->no_sub && nmatch > 0;
X
X  private_preg = *preg;
X  
X  private_preg.not_bol = !!(eflags & REG_NOTBOL);
X  private_preg.not_eol = !!(eflags & REG_NOTEOL);
X  
X  /* The user has told us exactly how many registers to return
X     information about, via `nmatch'.  We have to pass that on to the
X     matching routines.  */
X  private_preg.regs_allocated = REGS_FIXED;
X  
X  if (want_reg_info)
X    {
X      regs.num_regs = nmatch;
X      regs.start = TALLOC (nmatch, regoff_t);
X      regs.end = TALLOC (nmatch, regoff_t);
X      if (regs.start == NULL || regs.end == NULL)
X        return (int) REG_NOMATCH;
X    }
X
X  /* Perform the searching operation.  */
X  ret = re_search (&private_preg, string, len,
X                   /* start: */ 0, /* range: */ len,
X                   want_reg_info ? &regs : (struct re_registers *) 0);
X  
X  /* Copy the register information to the POSIX structure.  */
X  if (want_reg_info)
X    {
X      if (ret >= 0)
X        {
X          unsigned r;
X
X          for (r = 0; r < nmatch; r++)
X            {
X              pmatch[r].rm_so = regs.start[r];
X              pmatch[r].rm_eo = regs.end[r];
X            }
X        }
X
X      /* If we needed the temporary register info, free the space now.  */
X      free (regs.start);
X      free (regs.end);
X    }
X
X  /* We want zero return to mean success, unlike `re_search'.  */
X  return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH;
}
X
X
/* Returns a message corresponding to an error code, ERRCODE, returned
X   from either regcomp or regexec.   We don't use PREG here.  */
X
size_t
regerror (errcode, preg, errbuf, errbuf_size)
X    int errcode;
X    _CONST_ regex_t *preg;
X    char *errbuf;
X    size_t errbuf_size;
{
X  _CONST_ char *msg;
X  size_t msg_size;
X
X  if (errcode < 0
X      || errcode >= (sizeof (re_error_msg) / sizeof (re_error_msg[0])))
X    /* Only error codes returned by the rest of the code should be passed 
X       to this routine.  If we are given anything else, or if other regex
X       code generates an invalid error code, then the program has a bug.
X       Dump core so we can fix it.  */
X    abort ();
X
X  msg = re_error_msg[errcode];
X
X  /* POSIX doesn't require that we do anything in this case, but why
X     not be nice.  */
X  if (! msg)
X    msg = "Success";
X
X  msg_size = strlen (msg) + 1; /* Includes the null.  */
X  
X  if (errbuf_size != 0)
X    {
X      if (msg_size > errbuf_size)
X        {
X          strncpy (errbuf, msg, errbuf_size - 1);
X          errbuf[errbuf_size - 1] = 0;
X        }
X      else
X        strcpy (errbuf, msg);
X    }
X
X  return msg_size;
}
X
X
/* Free dynamically allocated space used by PREG.  */
X
void
regfree (preg)
X    regex_t *preg;
{
X  if (preg->buffer != NULL)
X    free (preg->buffer);
X  preg->buffer = NULL;
X  
X  preg->allocated = 0;
X  preg->used = 0;
X
X  if (preg->fastmap != NULL)
X    free (preg->fastmap);
X  preg->fastmap = NULL;
X  preg->fastmap_accurate = 0;
X
X  if (preg->translate != NULL)
X    free (preg->translate);
X  preg->translate = NULL;
}
X
#endif /* not emacs  */
X
/*
Local variables:
make-backup-files: t
version-control: t
trim-versions-without-asking: nil
End:
*/
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/regex.c ||
echo 'restore of rplay-3.1.0/rplayd/regex.c failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/regex.c'`"
test 161990 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/regex.c: original size 161990, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/regex.h ==============
if test -f 'rplay-3.1.0/rplayd/regex.h' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/regex.h (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/regex.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/regex.h' &&
/* Definitions for data structures and routines for the regular
X   expression library, version 0.12.
X
X   Copyright (C) 1985, 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
X
X   This program is free software; you can redistribute it and/or modify
X   it under the terms of the GNU General Public License as published by
X   the Free Software Foundation; either version 2, or (at your option)
X   any later version.
X
X   This program is distributed in the hope that it will be useful,
X   but WITHOUT ANY WARRANTY; without even the implied warranty of
X   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X   GNU General Public License for more details.
X
X   You should have received a copy of the GNU General Public License
X   along with this program; if not, write to the Free Software
X   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
X
#include "conf.h"
#define _CONST_
X
#ifndef __REGEXP_LIBRARY_H__
#define __REGEXP_LIBRARY_H__
X
/* POSIX says that <sys/types.h> must be included (by the caller) before
X   <regex.h>.  */
X
#ifdef VMS
/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it
X   should be there.  */
#include <stddef.h>
#endif
X
X
/* The following bits are used to determine the regexp syntax we
X   recognize.  The set/not-set meanings are chosen so that Emacs syntax
X   remains the value 0.  The bits are given in alphabetical order, and
X   the definitions shifted by one from the previous bit; thus, when we
X   add or remove a bit, only one other definition need change.  */
typedef unsigned reg_syntax_t;
X
/* If this bit is not set, then \ inside a bracket expression is literal.
X   If set, then such a \ quotes the following character.  */
#define RE_BACKSLASH_ESCAPE_IN_LISTS (1)
X
/* If this bit is not set, then + and ? are operators, and \+ and \? are
X     literals. 
X   If set, then \+ and \? are operators and + and ? are literals.  */
#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
X
/* If this bit is set, then character classes are supported.  They are:
X     [:alpha:], [:upper:], [:lower:],  [:digit:], [:alnum:], [:xdigit:],
X     [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
X   If not set, then character classes are not supported.  */
#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
X
/* If this bit is set, then ^ and $ are always anchors (outside bracket
X     expressions, of course).
X   If this bit is not set, then it depends:
X        ^  is an anchor if it is at the beginning of a regular
X           expression or after an open-group or an alternation operator;
X        $  is an anchor if it is at the end of a regular expression, or
X           before a close-group or an alternation operator.  
X
X   This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
X   POSIX draft 11.2 says that * etc. in leading positions is undefined.
X   We already implemented a previous draft which made those constructs
X   invalid, though, so we haven't changed the code back.  */
#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
X
/* If this bit is set, then special characters are always special
X     regardless of where they are in the pattern.
X   If this bit is not set, then special characters are special only in
X     some contexts; otherwise they are ordinary.  Specifically, 
X     * + ? and intervals are only special when not after the beginning,
X     open-group, or alternation operator.  */
#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
X
/* If this bit is set, then *, +, ?, and { cannot be first in an re or
X     immediately after an alternation or begin-group operator.  */
#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
X
/* If this bit is set, then . matches newline.
X   If not set, then it doesn't.  */
#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
X
/* If this bit is set, then . doesn't match NUL.
X   If not set, then it does.  */
#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
X
/* If this bit is set, nonmatching lists [^...] do not match newline.
X   If not set, they do.  */
#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
X
/* If this bit is set, either \{...\} or {...} defines an
X     interval, depending on RE_NO_BK_BRACES. 
X   If not set, \{, \}, {, and } are literals.  */
#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
X
/* If this bit is set, +, ? and | aren't recognized as operators.
X   If not set, they are.  */
#define RE_LIMITED_OPS (RE_INTERVALS << 1)
X
/* If this bit is set, newline is an alternation operator.
X   If not set, newline is literal.  */
#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
X
/* If this bit is set, then `{...}' defines an interval, and \{ and \}
X     are literals.
X  If not set, then `\{...\}' defines an interval.  */
#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
X
/* If this bit is set, (...) defines a group, and \( and \) are literals.
X   If not set, \(...\) defines a group, and ( and ) are literals.  */
#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
X
/* If this bit is set, then \<digit> matches <digit>.
X   If not set, then \<digit> is a back-reference.  */
#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
X
/* If this bit is set, then | is an alternation operator, and \| is literal. 
X   If not set, then \| is an alternation operator, and | is literal.  */
#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
X
/* If this bit is set, then an ending range point collating higher
X     than the starting range point, as in [z-a], is invalid.
X   If not set, then when ending range point collates higher than the
X     starting range point, the range is ignored.  */
#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
X
/* If this bit is set, then an unmatched ) is ordinary.
X   If not set, then an unmatched ) is invalid.  */
#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
X
/* This global variable defines the particular regexp syntax to use (for
X   some interfaces).  When a regexp is compiled, the syntax used is
X   stored in the pattern buffer, so changing this does not affect
X   already-compiled regexps.  */
extern reg_syntax_t re_syntax_options;
X
/* Define combinations of the above bits for the standard possibilities.
X   (The [[[ comments delimit what gets put into the Texinfo file, so
X   don't delete them!)  */ 
/* [[[begin syntaxes]]] */
#define RE_SYNTAX_EMACS 0
X
#define RE_SYNTAX_AWK							\
X  (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL			\
X   | RE_NO_BK_PARENS            | RE_NO_BK_REFS				\
X   | RE_NO_BK_VBAR               | RE_NO_EMPTY_RANGES			\
X   | RE_UNMATCHED_RIGHT_PAREN_ORD)
X
#define RE_SYNTAX_POSIX_AWK 						\
X  (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS)
X
#define RE_SYNTAX_GREP							\
X  (RE_BK_PLUS_QM              | RE_CHAR_CLASSES				\
X   | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS				\
X   | RE_NEWLINE_ALT)
X
#define RE_SYNTAX_EGREP							\
X  (RE_CHAR_CLASSES        | RE_CONTEXT_INDEP_ANCHORS			\
X   | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE			\
X   | RE_NEWLINE_ALT       | RE_NO_BK_PARENS				\
X   | RE_NO_BK_VBAR)
X
#define RE_SYNTAX_POSIX_EGREP						\
X  (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES)
X
/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff.  */
#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC
X
#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
X
/* Syntax bits common to both basic and extended POSIX regex syntax.  */
#define _RE_SYNTAX_POSIX_COMMON						\
X  (RE_CHAR_CLASSES | RE_DOT_NEWLINE      | RE_DOT_NOT_NULL		\
X   | RE_INTERVALS  | RE_NO_EMPTY_RANGES)
X
#define RE_SYNTAX_POSIX_BASIC						\
X  (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM)
X
/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
X   RE_LIMITED_OPS, i.e., \? \+ \| are not recognized.  Actually, this
X   isn't minimal, since other operators, such as \`, aren't disabled.  */
#define RE_SYNTAX_POSIX_MINIMAL_BASIC					\
X  (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
X
#define RE_SYNTAX_POSIX_EXTENDED					\
X  (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS			\
X   | RE_CONTEXT_INDEP_OPS  | RE_NO_BK_BRACES				\
X   | RE_NO_BK_PARENS       | RE_NO_BK_VBAR				\
X   | RE_UNMATCHED_RIGHT_PAREN_ORD)
X
/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS
X   replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added.  */
#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED				\
X  (_RE_SYNTAX_POSIX_COMMON  | RE_CONTEXT_INDEP_ANCHORS			\
X   | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES				\
X   | RE_NO_BK_PARENS        | RE_NO_BK_REFS				\
X   | RE_NO_BK_VBAR	    | RE_UNMATCHED_RIGHT_PAREN_ORD)
/* [[[end syntaxes]]] */
X
/* Maximum number of duplicates an interval can allow.  Some systems
X   (erroneously) define this in other header files, but we want our
X   value, so remove any previous define.  */
#ifdef RE_DUP_MAX
#undef RE_DUP_MAX
#endif
#define RE_DUP_MAX ((1 << 15) - 1) 
X
X
/* POSIX `cflags' bits (i.e., information for `regcomp').  */
X
/* If this bit is set, then use extended regular expression syntax.
X   If not set, then use basic regular expression syntax.  */
#define REG_EXTENDED 1
X
/* If this bit is set, then ignore case when matching.
X   If not set, then case is significant.  */
#define REG_ICASE (REG_EXTENDED << 1)
X 
/* If this bit is set, then anchors do not match at newline
X     characters in the string.
X   If not set, then anchors do match at newlines.  */
#define REG_NEWLINE (REG_ICASE << 1)
X
/* If this bit is set, then report only success or fail in regexec.
X   If not set, then returns differ between not matching and errors.  */
#define REG_NOSUB (REG_NEWLINE << 1)
X
X
/* POSIX `eflags' bits (i.e., information for regexec).  */
X
/* If this bit is set, then the beginning-of-line operator doesn't match
X     the beginning of the string (presumably because it's not the
X     beginning of a line).
X   If not set, then the beginning-of-line operator does match the
X     beginning of the string.  */
#define REG_NOTBOL 1
X
/* Like REG_NOTBOL, except for the end-of-line.  */
#define REG_NOTEOL (1 << 1)
X
X
/* If any error codes are removed, changed, or added, update the
X   `re_error_msg' table in regex.c.  */
typedef enum
{
X  REG_NOERROR = 0,	/* Success.  */
X  REG_NOMATCH,		/* Didn't find a match (for regexec).  */
X
X  /* POSIX regcomp return error codes.  (In the order listed in the
X     standard.)  */
X  REG_BADPAT,		/* Invalid pattern.  */
X  REG_ECOLLATE,		/* Not implemented.  */
X  REG_ECTYPE,		/* Invalid character class name.  */
X  REG_EESCAPE,		/* Trailing backslash.  */
X  REG_ESUBREG,		/* Invalid back reference.  */
X  REG_EBRACK,		/* Unmatched left bracket.  */
X  REG_EPAREN,		/* Parenthesis imbalance.  */ 
X  REG_EBRACE,		/* Unmatched \{.  */
X  REG_BADBR,		/* Invalid contents of \{\}.  */
X  REG_ERANGE,		/* Invalid range end.  */
X  REG_ESPACE,		/* Ran out of memory.  */
X  REG_BADRPT,		/* No preceding re for repetition op.  */
X
X  /* Error codes we've added.  */
X  REG_EEND,		/* Premature end.  */
X  REG_ESIZE,		/* Compiled pattern bigger than 2^16 bytes.  */
X  REG_ERPAREN		/* Unmatched ) or \); not returned from regcomp.  */
} reg_errcode_t;
X
/* This data structure represents a compiled pattern.  Before calling
X   the pattern compiler, the fields `buffer', `allocated', `fastmap',
X   `translate', and `no_sub' can be set.  After the pattern has been
X   compiled, the `re_nsub' field is available.  All other fields are
X   private to the regex routines.  */
X
struct re_pattern_buffer
{
/* [[[begin pattern_buffer]]] */
X	/* Space that holds the compiled pattern.  It is declared as
X          `unsigned char *' because its elements are
X           sometimes used as array indexes.  */
X  unsigned char *buffer;
X
X	/* Number of bytes to which `buffer' points.  */
X  unsigned long allocated;
X
X	/* Number of bytes actually used in `buffer'.  */
X  unsigned long used;	
X
X        /* Syntax setting with which the pattern was compiled.  */
X  reg_syntax_t syntax;
X
X        /* Pointer to a fastmap, if any, otherwise zero.  re_search uses
X           the fastmap, if there is one, to skip over impossible
X           starting points for matches.  */
X  char *fastmap;
X
X        /* Either a translate table to apply to all characters before
X           comparing them, or zero for no translation.  The translation
X           is applied to a pattern when it is compiled and to a string
X           when it is matched.  */
X  char *translate;
X
X	/* Number of subexpressions found by the compiler.  */
X  size_t re_nsub;
X
X        /* Zero if this pattern cannot match the empty string, one else.
X           Well, in truth it's used only in `re_search_2', to see
X           whether or not we should use the fastmap, so we don't set
X           this absolutely perfectly; see `re_compile_fastmap' (the
X           `duplicate' case).  */
X  unsigned can_be_null : 1;
X
X        /* If REGS_UNALLOCATED, allocate space in the `regs' structure
X             for `max (RE_NREGS, re_nsub + 1)' groups.
X           If REGS_REALLOCATE, reallocate space if necessary.
X           If REGS_FIXED, use what's there.  */
#define REGS_UNALLOCATED 0
#define REGS_REALLOCATE 1
#define REGS_FIXED 2
X  unsigned regs_allocated : 2;
X
X        /* Set to zero when `regex_compile' compiles a pattern; set to one
X           by `re_compile_fastmap' if it updates the fastmap.  */
X  unsigned fastmap_accurate : 1;
X
X        /* If set, `re_match_2' does not return information about
X           subexpressions.  */
X  unsigned no_sub : 1;
X
X        /* If set, a beginning-of-line anchor doesn't match at the
X           beginning of the string.  */ 
X  unsigned not_bol : 1;
X
X        /* Similarly for an end-of-line anchor.  */
X  unsigned not_eol : 1;
X
X        /* If true, an anchor at a newline matches.  */
X  unsigned newline_anchor : 1;
X
/* [[[end pattern_buffer]]] */
};
X
typedef struct re_pattern_buffer regex_t;
X
X
/* search.c (search_buffer) in Emacs needs this one opcode value.  It is
X   defined both in `regex.c' and here.  */
#define RE_EXACTN_VALUE 1
X
/* Type for byte offsets within the string.  POSIX mandates this.  */
typedef int regoff_t;
X
X
/* This is the structure we store register match data in.  See
X   regex.texinfo for a full description of what registers match.  */
struct re_registers
{
X  unsigned num_regs;
X  regoff_t *start;
X  regoff_t *end;
};
X
X
/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
X   `re_match_2' returns information about at least this many registers
X   the first time a `regs' structure is passed.  */
#ifndef RE_NREGS
#define RE_NREGS 30
#endif
X
X
/* POSIX specification for registers.  Aside from the different names than
X   `re_registers', POSIX uses an array of structures, instead of a
X   structure of arrays.  */
typedef struct
{
X  regoff_t rm_so;  /* Byte offset from string's start to substring's start.  */
X  regoff_t rm_eo;  /* Byte offset from string's start to substring's end.  */
} regmatch_t;
X
/* Declarations for routines.  */
X
/* To avoid duplicating every routine declaration -- once with a
X   prototype (if we are ANSI), and once without (if we aren't) -- we
X   use the following macro to declare argument types.  This
X   unfortunately clutters up the declarations a bit, but I think it's
X   worth it.  */
X
#if __STDC__
X
#define _RE_ARGS(args) args
X
#else /* not __STDC__ */
X
#define _RE_ARGS(args) ()
X
#endif /* not __STDC__ */
X
/* Sets the current default syntax to SYNTAX, and return the old syntax.
X   You can also simply assign to the `re_syntax_options' variable.  */
extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax));
X
/* Compile the regular expression PATTERN, with length LENGTH
X   and syntax given by the global `re_syntax_options', into the buffer
X   BUFFER.  Return NULL if successful, and an error string if not.  */
extern _CONST_ char *re_compile_pattern
X  _RE_ARGS ((_CONST_ char *pattern, int length,
X             struct re_pattern_buffer *buffer));
X
X
/* Compile a fastmap for the compiled pattern in BUFFER; used to
X   accelerate searches.  Return 0 if successful and -2 if was an
X   internal error.  */
extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer));
X
X
/* Search in the string STRING (with length LENGTH) for the pattern
X   compiled into BUFFER.  Start searching at position START, for RANGE
X   characters.  Return the starting position of the match, -1 for no
X   match, or -2 for an internal error.  Also return register
X   information in REGS (if REGS and BUFFER->no_sub are nonzero).  */
extern int re_search
X  _RE_ARGS ((struct re_pattern_buffer *buffer, _CONST_ char *string,
X            int length, int start, int range, struct re_registers *regs));
X
X
/* Like `re_search', but search in the concatenation of STRING1 and
X   STRING2.  Also, stop searching at index START + STOP.  */
extern int re_search_2
X  _RE_ARGS ((struct re_pattern_buffer *buffer, _CONST_ char *string1,
X             int length1, _CONST_ char *string2, int length2,
X             int start, int range, struct re_registers *regs, int stop));
X
X
/* Like `re_search', but return how many characters in STRING the regexp
X   in BUFFER matched, starting at position START.  */
extern int re_match
X  _RE_ARGS ((struct re_pattern_buffer *buffer, _CONST_ char *string,
X             int length, int start, struct re_registers *regs));
X
X
/* Relates to `re_match' as `re_search_2' relates to `re_search'.  */
extern int re_match_2 
X  _RE_ARGS ((struct re_pattern_buffer *buffer, _CONST_ char *string1,
X             int length1, _CONST_ char *string2, int length2,
X             int start, struct re_registers *regs, int stop));
X
X
/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
X   ENDS.  Subsequent matches using BUFFER and REGS will use this memory
X   for recording register information.  STARTS and ENDS must be
X   allocated with malloc, and must each be at least `NUM_REGS * sizeof
X   (regoff_t)' bytes long.
X
X   If NUM_REGS == 0, then subsequent matches should allocate their own
X   register data.
X
X   Unless this function is called, the first search or match using
X   PATTERN_BUFFER will allocate its own register data, without
X   freeing the old data.  */
extern void re_set_registers
X  _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
X             unsigned num_regs, regoff_t *starts, regoff_t *ends));
X
/* 4.2 bsd compatibility.  */
extern char *re_comp _RE_ARGS ((_CONST_ char *));
extern int re_exec _RE_ARGS ((_CONST_ char *));
X
/* POSIX compatibility.  */
extern int regcomp _RE_ARGS ((regex_t *preg, _CONST_ char *pattern, int cflags));
extern int regexec
X  _RE_ARGS ((_CONST_ regex_t *preg, _CONST_ char *string, size_t nmatch,
X             regmatch_t pmatch[], int eflags));
extern size_t regerror
X  _RE_ARGS ((int errcode, _CONST_ regex_t *preg, char *errbuf,
X             size_t errbuf_size));
extern void regfree _RE_ARGS ((regex_t *preg));
X
#endif /* not __REGEXP_LIBRARY_H__ */
X
/*
Local variables:
make-backup-files: t
version-control: t
trim-versions-without-asking: nil
End:
*/
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/regex.h ||
echo 'restore of rplay-3.1.0/rplayd/regex.h failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/regex.h'`"
test 18765 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/regex.h: original size 18765, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/misc.c ==============
if test -f 'rplay-3.1.0/rplayd/misc.c' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/misc.c (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/misc.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/misc.c' &&
/*
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#include "conf.h"
#include "rplayd.h"
#include <sys/file.h>
#ifdef ultrix
#include <fcntl.h>
#else
#include <sys/fcntl.h>
#endif
#include <sys/param.h>
#include <sys/time.h>
#include <sys/signal.h>
X
#ifdef NEED_USLEEP
#ifdef __STDC__
int	usleep(unsigned long usec)
#else
int	usleep(usec)
unsigned long	usec;
#endif
{
X	struct timeval	tv;
X
X	tv.tv_sec = usec/1000000;
X	tv.tv_usec = usec%1000000;
X	select(0, 0, 0, 0, &tv);
X
X	return 0;
}
#endif /* NEED_USLEEP */
X
/*
X * make a socket non-blocking
X */
#ifdef __STDC__
void	socket_nonblock(int sock_fd)
#else
void	socket_nonblock(sock_fd)
int	sock_fd;
#endif
{
X	int	flags;
X
X	flags = fcntl(sock_fd, F_GETFL, 0);
X	if (flags < 0)
X	{
X		report("F_GETFL fcntl: %s\n", sys_errlist[errno]);
X		done(1);
X	}
#ifdef linux
X	flags |= O_NONBLOCK;
#else
X	flags |= FNDELAY;
#endif
X	if (fcntl(sock_fd, F_SETFL, flags) < 0)
X	{
X		report("F_SETFL fcntl: %s\n", sys_errlist[errno]);
X		done(1);
X	}
}
X
/*
X * make a socket blocking
X */
#ifdef __STDC__
void	socket_block(int sock_fd)
#else
void	socket_block(sock_fd)
int	sock_fd;
#endif
{
X	int	flags;
X
X	flags = fcntl(sock_fd, F_GETFL, 0);
X	if (flags < 0)
X	{
X		report("F_GETFL fcntl: %s\n", sys_errlist[errno]);
X		done(1);
X	}
#ifdef linux
X	flags &= ~O_NONBLOCK;
#else
X	flags |= FNDELAY;
#endif
X	if (fcntl(sock_fd, F_SETFL, flags) < 0)
X	{
X		report("F_SETFL fcntl: %s\n", sys_errlist[errno]);
X		done(1);
X	}
}
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/misc.c ||
echo 'restore of rplay-3.1.0/rplayd/misc.c failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/misc.c'`"
test 2165 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/misc.c: original size 2165, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/misc.h ==============
if test -f 'rplay-3.1.0/rplayd/misc.h' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/misc.h (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/misc.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/misc.h' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#ifndef _misc_h
#define _misc_h
X
#include "conf.h"
X
#ifdef NEED_USLEEP
#ifdef __STDC__
extern int	usleep(unsigned long usec);
#else
extern int	usleep(/* unsigned long usec */);
#endif
#endif /* NEED_USLEEP */
X
#ifdef __STDC__
extern void	socket_nonblock(int sock_fd);
extern void	socket_block(int sock_fd);
#else
extern void	socket_nonblock(/* int sock_fd */);
extern void	socket_block(/* int sock_fd */);
#endif
X
#endif /* _misc_h */
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/misc.h ||
echo 'restore of rplay-3.1.0/rplayd/misc.h failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/misc.h'`"
test 1228 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/misc.h: original size 1228, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/buffer.c ==============
if test -f 'rplay-3.1.0/rplayd/buffer.c' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/buffer.c (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/buffer.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/buffer.c' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#include "conf.h"
#include <stdio.h>
#include <stdlib.h>
#include "rplayd.h"
#include "buffer.h"
X
static BUFFER	*buffers = NULL;
static int	nbuffers;	/* number of buffers on the free list */
X
#ifdef __STDC__
BUFFER	*buffer_create(void)
#else
BUFFER	*buffer_create()
#endif
{
X	BUFFER	*b;
X
X	if (buffers == NULL)
X	{
X		b = (BUFFER *)malloc(sizeof(BUFFER));
X		if (b == NULL)
X		{
X			report("buffer_create: out of memory\n");
X			done(1);
X		}
X	}
X	else
X	{
X		nbuffers--;
X		b = buffers;
X		buffers = buffers->next;
X	}
X	
X	b->nbytes = 0;
X	b->buf[0] = '\0';
X	b->status = BUFFER_FREE;
X	b->next = NULL;
X
X	return b;
}
X
#ifdef __STDC__
void	buffer_destroy(BUFFER *b)
#else
void	buffer_destroy(b)
BUFFER	*b;
#endif
{
X	if (b->status != BUFFER_FREE)
X	{
X		return;
X	}
X
X	if (nbuffers == BUFFER_MAX_FREE)
X	{
X		free((char *)b);
X	}
X	else
X	{
X		nbuffers++;
X		b->next = buffers;
X		buffers = b;
X	}
}
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/buffer.c ||
echo 'restore of rplay-3.1.0/rplayd/buffer.c failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/buffer.c'`"
test 1661 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/buffer.c: original size 1661, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/buffer.h ==============
if test -f 'rplay-3.1.0/rplayd/buffer.h' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/buffer.h (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/buffer.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/buffer.h' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#ifndef _buffer_h
#define _buffer_h
X
#include "conf.h"
X
#define BUFFER_SIZE	1024	/* must be >= RPTP_MAX_LINE */
X
/*
X * Maximum number of buffers to have on the free list.
X * The number should really depend on the value of BUFFER_SIZE.
X */
#define BUFFER_MAX_FREE	16
X
#define BUFFER_FREE	0	/* a temporary buffer */
#define BUFFER_KEEP	1	/* a permanent buffer */
X
typedef struct _buffer
{
X	struct _buffer	*next;
X	int		nbytes;
X	char		buf[BUFFER_SIZE];
X	int		status;
} BUFFER;
X
#ifdef __STDC__
BUFFER	*buffer_create(void);
void	buffer_destroy(BUFFER *b);
#else
BUFFER	*buffer_create();
void	buffer_destroy(/* BUFFER *b */);
#endif
X
#endif /* _buffer_h */
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/buffer.h ||
echo 'restore of rplay-3.1.0/rplayd/buffer.h failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/buffer.h'`"
test 1444 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/buffer.h: original size 1444, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/search.c ==============
if test -f 'rplay-3.1.0/rplayd/search.c' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/search.c (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/search.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/search.c' &&
/* search.c: Exterior hash table implementation.
X *	Copyright (c) August 5, 1993 by Darren Senn
X *					(sinster@scintilla.santa-clara.ca.us)
X *	Permission granted for any use.
X */
X
#include "conf.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "search.h"
X
#define PRIME 1993		/*  That's right!  This is a prime year!  :)  */
/* Other "prime" choices:
X   1993    1997    1999    2003    2011    2017    2027    2029    2039    2053 
X   2063    2069    2081    2083    2087    2089    2099    2111    2113    2129 
X   2131    2137    2141    2143    2153    2161    2179    2203    2207    2213 
X   2221    2237    2239    2243    2251    2267    2269    2273    2281    2287 
X   2293    2297    2309    2311    2333    2339    2341    2347    2351    2357 
X   2371    2377    2381    2383    2389    2393    2399    2411    2417    2423 
X   2437    2441    2447    2459    2467    2473    2477    2503    2521    2531 
X   2539    2543    2549    2551    2557    2579    2591    2593    2609    2617 
X   2621    2633    2647    2657    2659    2663    2671    2677    2683    2687 
X   2689    2693    2699    2707    2711    2713    2719    2729    2731    2741 
X   2749    2753    2767    2777    2789    2791    2797    2801    2803    2819 
X   2833    2837    2843    2851    2857    2861    2879    2887    2897    2903 
X   2909    2917    2927    2939    2953    2957    2963    2969    2971    2999 
*/
X
struct node {
X	ENTRY data;
X	struct node *next;
};
X
static struct node *__hs_array[PRIME];
static struct node *__hs_head = NULL;
static struct node *__hs_cache = NULL;
X
#ifdef __STDC__
static int hash(ENTRY e)
#else
static int hash(e)
ENTRY e;
#endif
{
X	int sum;
X	char *p;
X
X	for (sum = 0, p = (char *)e.key; *p; sum += *p++);
X	return(sum % PRIME);
}
X
#ifdef __STDC__
static struct node *newnode(void)
#else
static struct node *newnode()
#endif
{
X	struct node *f = NULL;
X
X	if (__hs_head) {
X		f = __hs_head;
X		__hs_head = __hs_head->next;
X	}
X	return(f);
}
X
#ifdef __STDC__
int hcreate(int num)
#else
int hcreate(num)
int num;
#endif
{
X	register int i;
X
X	if (__hs_cache) {
X		free((char *)__hs_cache);
X		__hs_cache = NULL;
X	}
X
X	if (!num) return(0);
X	__hs_cache = (struct node *)calloc(num, sizeof(struct node));
X	if (!__hs_cache) return(0);
X
X	memset((char *)__hs_array, 0, sizeof(__hs_array));
X	for (i = 1; i < num; i++)
X		__hs_cache[i-1].next = &__hs_cache[i];
X	__hs_cache[num - 1].next = NULL;
X	__hs_head = __hs_cache;
X
X	return(num);
}
X
#ifdef __STDC__
ENTRY *hsearch(ENTRY e, ACTION a)
#else
ENTRY *hsearch(e, a)
ENTRY e;
ACTION a;
#endif
{
X	int i;
X	struct node *f, *g;
X
X	for (g = NULL, f = __hs_array[(i = hash(e))];
X		f && strcmp((char *)f->data.key, (char *)e.key);
X		g = f, f = f->next);
X	if (a == ENTER) {
X		if (!f)	{
X			f = __hs_array[i];
X			__hs_array[i] = newnode();
X			if (!__hs_array[i]) {
X				__hs_array[i] = f;
X				return(NULL);
X			}
X			__hs_array[i]->next = f;
X			f = __hs_array[i];
X		}
X		f->data = e;
X	} else if (a == DELETE && f) {
X		if (g)
X			g->next = f->next;
X		else	__hs_array[i] = f->next;
X		f->next = __hs_head;
X		__hs_head = f;
X	}
X	return(f ? &f->data : NULL);
}
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/search.c ||
echo 'restore of rplay-3.1.0/rplayd/search.c failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/search.c'`"
test 3114 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/search.c: original size 3114, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rplayd/search.h ==============
if test -f 'rplay-3.1.0/rplayd/search.h' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rplayd/search.h (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rplayd/search.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rplayd/search.h' &&
/* search.h: Header file for exterior hash table implementation.
X *	Copyright (c) August 5, 1993 by Darren Senn
X *					(sinster@scintilla.santa-clara.ca.us)
X *	Permission granted for any use.
X */
X
#include "conf.h"
X
typedef enum {
X	FIND,
X	ENTER,
X	DELETE
} ACTION;
typedef struct {
X	void *key;
X	void *data;
} ENTRY;
X
#ifdef __STDC__
extern int hcreate(int);
extern ENTRY *hsearch(ENTRY, ACTION);
#else
extern int hcreate();
extern ENTRY *hsearch();
#endif
SHAR_EOF
chmod 0644 rplay-3.1.0/rplayd/search.h ||
echo 'restore of rplay-3.1.0/rplayd/search.h failed'
Wc_c="`wc -c < 'rplay-3.1.0/rplayd/search.h'`"
test 455 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rplayd/search.h: original size 455, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/COPYING ==============
if test -f 'rplay-3.1.0/COPYING' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/COPYING (File already exists)'
else
echo 'x - extracting rplay-3.1.0/COPYING (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/COPYING' &&
X		    GNU GENERAL PUBLIC LICENSE
X		       Version 2, June 1991
X
X Copyright (C) 1989, 1991 Free Software Foundation, Inc.
X                          675 Mass Ave, Cambridge, MA 02139, USA
X Everyone is permitted to copy and distribute verbatim copies
X of this license document, but changing it is not allowed.
X
X			    Preamble
X
X  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.
X
X  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.
X
X  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.
X
X  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.
X
X  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.
X
X  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.
X
X  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.
X
X  The precise terms and conditions for copying, distribution and
modification follow.
X
X		    GNU GENERAL PUBLIC LICENSE
X   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
X
X  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".
X
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.
X
X  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.
X
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.
X
X  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:
X
X    a) You must cause the modified files to carry prominent notices
X    stating that you changed the files and the date of any change.
X
X    b) You must cause any work that you distribute or publish, that in
X    whole or in part contains or is derived from the Program or any
X    part thereof, to be licensed as a whole at no charge to all third
X    parties under the terms of this License.
X
X    c) If the modified program normally reads commands interactively
X    when run, you must cause it, when started running for such
X    interactive use in the most ordinary way, to print or display an
X    announcement including an appropriate copyright notice and a
X    notice that there is no warranty (or else, saying that you provide
X    a warranty) and that users may redistribute the program under
X    these conditions, and telling the user how to view a copy of this
X    License.  (Exception: if the Program itself is interactive but
X    does not normally print such an announcement, your work based on
X    the Program is not required to print an announcement.)
X
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.
X
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.
X
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.
X
X  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:
X
X    a) Accompany it with the complete corresponding machine-readable
X    source code, which must be distributed under the terms of Sections
X    1 and 2 above on a medium customarily used for software interchange; or,
X
X    b) Accompany it with a written offer, valid for at least three
X    years, to give any third party, for a charge no more than your
X    cost of physically performing source distribution, a complete
X    machine-readable copy of the corresponding source code, to be
X    distributed under the terms of Sections 1 and 2 above on a medium
X    customarily used for software interchange; or,
X
X    c) Accompany it with the information you received as to the offer
X    to distribute corresponding source code.  (This alternative is
X    allowed only for noncommercial distribution and only if you
X    received the program in object code or executable form with such
X    an offer, in accord with Subsection b above.)
X
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.
X
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.
X
X  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.
X
X  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.
X
X  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.
X
X  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.
X
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.
X
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.
X
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
X
X  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.
X
X  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.
X
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.
X
X  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.
X
X			    NO WARRANTY
X
X  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.
X
X  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.
X
X		     END OF TERMS AND CONDITIONS
X
X	    How to Apply These Terms to Your New Programs
X
X  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.
X
X  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.
X
X    <one line to give the program's name and a brief idea of what it does.>
X    Copyright (C) 19yy  <name of author>
X
X    This program is free software; you can redistribute it and/or modify
X    it under the terms of the GNU General Public License as published by
X    the Free Software Foundation; either version 2 of the License, or
X    (at your option) any later version.
X
X    This program is distributed in the hope that it will be useful,
X    but WITHOUT ANY WARRANTY; without even the implied warranty of
X    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X    GNU General Public License for more details.
X
X    You should have received a copy of the GNU General Public License
X    along with this program; if not, write to the Free Software
X    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X
Also add information on how to contact you by electronic and paper mail.
X
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
X
X    Gnomovision version 69, Copyright (C) 19yy name of author
X    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
X    This is free software, and you are welcome to redistribute it
X    under certain conditions; type `show c' for details.
X
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.
X
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:
X
X  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
X  `Gnomovision' (which makes passes at compilers) written by James Hacker.
X
X  <signature of Ty Coon>, 1 April 1989
X  Ty Coon, President of Vice
X
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.
SHAR_EOF
chmod 0644 rplay-3.1.0/COPYING ||
echo 'restore of rplay-3.1.0/COPYING failed'
Wc_c="`wc -c < 'rplay-3.1.0/COPYING'`"
test 17976 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/COPYING: original size 17976, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/doc/man5/rplay.conf.5 ==============
if test ! -d 'rplay-3.1.0/doc'; then
    echo 'x - creating directory rplay-3.1.0/doc'
    mkdir 'rplay-3.1.0/doc'
fi
if test ! -d 'rplay-3.1.0/doc/man5'; then
    echo 'x - creating directory rplay-3.1.0/doc/man5'
    mkdir 'rplay-3.1.0/doc/man5'
fi
if test -f 'rplay-3.1.0/doc/man5/rplay.conf.5' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/doc/man5/rplay.conf.5 (File already exists)'
else
echo 'x - extracting rplay-3.1.0/doc/man5/rplay.conf.5 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/doc/man5/rplay.conf.5' &&
.TH RPLAY.CONF 5 "10 July 1993"
.SH NAME
rplay.conf \- remote play sound database
.SH SYNOPSIS
.B /usr/local/etc/rplay.conf
.SH DESCRIPTION
The
.I rplay.conf
file contains a list of sound files that are available locally to
.I rplayd. 
Each line must contain the complete pathname of one sound file.
.SH EXAMPLE
/usr/local/lib/sounds/bark.au
.br
/usr/local/lib/sounds/bogus.au
.br
/usr/local/lib/sounds/Puke.au
.SH FILES
.B /usr/local/etc/rplay.conf
.SH "SEE ALSO"
.BR rplayd (1)
.SH BUGS
The name of this file should really be rplay.sounds, but 
.I rplay.conf
is used for historical reasons.
SHAR_EOF
chmod 0644 rplay-3.1.0/doc/man5/rplay.conf.5 ||
echo 'restore of rplay-3.1.0/doc/man5/rplay.conf.5 failed'
Wc_c="`wc -c < 'rplay-3.1.0/doc/man5/rplay.conf.5'`"
test 593 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/doc/man5/rplay.conf.5: original size 593, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/doc/man5/rplay.hosts.5 ==============
if test -f 'rplay-3.1.0/doc/man5/rplay.hosts.5' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/doc/man5/rplay.hosts.5 (File already exists)'
else
echo 'x - extracting rplay-3.1.0/doc/man5/rplay.hosts.5 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/doc/man5/rplay.hosts.5' &&
.TH RPLAY.HOSTS 5 "10 July 1993"
.SH NAME
rplay.hosts \- remote play host authentication database
.SH SYNOPSIS
.B /usr/local/etc/rplay.hosts
.SH DESCRIPTION
The
.I rplay.hosts
file contains a list of hosts and access permissions which
.I rplayd
uses to validate incoming connections.  Each line is of
the form:
.IP
hostname[:permission]
.PP
where
.TP 15
.B hostname
is the name of a remote host or a host's IP address.
Wildcards can be used within IP addresses to match
multiple hosts.  The wildcard character is "*".
.TP 15
.B permission
is an optional field containing any combination of the following
characters:
.RS
.TP 3
.B r
the host can read sounds.
.TP 3
.B w
the host can write sounds.
.TP 3
.B x
the host can play, stop, pause, and continue sounds.  This
is normally called execute permission.
.RE
.TP
"rx" permissions are used when no permissions are specified.
.SH EXAMPLE
.LP
.ft B
.nf
#
# All hosts have read access:
#
*:r
X
#
# Trusted hosts:
#
nice-guy.sdsu.edu:rwx
friend.sdsu.edu:rwx
amigo.sdsu.edu:rwx
130.191.224.224:rwx
X
#
# Hosts which can read and execute:
#
foo.bar.com:rx
130.190.*:rx
146.244.234.*:rx
using.default.perms.edu
.fi
.ft R
.LP
.SH FILES
.B /usr/local/etc/rplay.hosts
.SH "SEE ALSO"
.BR rplayd (1)
.SH BUGS
The permissions for an "*" entry apply to
.B all
matching hosts.
The order of this file does not matter.
Specific hosts can have access disabled with entries like:
.LP
.nf
bad.guy.edu:
.fi
.LP
however, any matching "*" entries will still apply.
SHAR_EOF
chmod 0644 rplay-3.1.0/doc/man5/rplay.hosts.5 ||
echo 'restore of rplay-3.1.0/doc/man5/rplay.hosts.5 failed'
Wc_c="`wc -c < 'rplay-3.1.0/doc/man5/rplay.hosts.5'`"
test 1488 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/doc/man5/rplay.hosts.5: original size 1488, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/doc/man5/rplay.servers.5 ==============
if test -f 'rplay-3.1.0/doc/man5/rplay.servers.5' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/doc/man5/rplay.servers.5 (File already exists)'
else
echo 'x - extracting rplay-3.1.0/doc/man5/rplay.servers.5 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/doc/man5/rplay.servers.5' &&
.TH RPLAY.SERVERS 5 "10 July 1993"
.SH NAME
rplay.servers \- remote play servers database
.SH SYNOPSIS
.B /usr/local/etc/rplay.servers
.SH DESCRIPTION
The
.I rplay.servers
file contains a list of hosts that
.I rplayd
will contact to obtain sound files that are not available locally.
Servers are contacted sequentially, so the best servers should be
listed first.  Each line is of the form:
.IP
hostname[:port]
.LP
where
.TP 15
.B hostname
is the name of a remote host or a host's IP address.
.TP 15
.B port
is an optional field containing the port to connect to.
Port 55556 is used when the port is not specified.
.SH EXAMPLE
sounds.sdsu.edu
.br
130.191.224.8
.br
bozo.nowhere.com
.br
soundhost.foo.com:9999
.SH FILES
.B /usr/local/etc/rplay.servers
.SH "SEE ALSO"
.BR rplayd (1)
SHAR_EOF
chmod 0644 rplay-3.1.0/doc/man5/rplay.servers.5 ||
echo 'restore of rplay-3.1.0/doc/man5/rplay.servers.5 failed'
Wc_c="`wc -c < 'rplay-3.1.0/doc/man5/rplay.servers.5'`"
test 781 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/doc/man5/rplay.servers.5: original size 781, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/doc/README.LIBRPLAY ==============
if test -f 'rplay-3.1.0/doc/README.LIBRPLAY' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/doc/README.LIBRPLAY (File already exists)'
else
echo 'x - extracting rplay-3.1.0/doc/README.LIBRPLAY (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/doc/README.LIBRPLAY' &&
X
This file describes how to use the rplay library and should be considered
the RPLAY/RPTP Programmer's Manual.
X
The rplay library includes routines for both the RPLAY and RPTP protocols.
Routines that begin with rplay_ are for RPLAY and rptp_ for RPTP.  Programs 
that wish to use the rplay library must include the rplay header file rplay.h
and link with the rplay library librplay.a.
X
All library routines return either NULL or -1 on error conditions.  For
error conditions it is useful to use rplay_perror and rptp_perror.
X
--------------------------------------------------------------------------------
RPLAY routines:
--------------------------------------------------------------------------------
Prototype: RPLAY   *rplay_create(int command)
Summary:   Create an RPLAY object for a command.
Input:     The command argument can be one of the following:
X           * RPLAY_PLAY - play sounds
X           * RPLAY_STOP	- stop sounds
X           * RPLAY_PAUSE - pause sounds
X           * RPLAY_CONTINUE - continue sounds
X	   * RPLAY_PING - wakeup a server
Output:    A pointer to an RPLAY object or NULL.
Example:
X	RPLAY *rp;
X
X	rp = rplay_create(RPLAY_PLAY);
X	if (rp == NULL)
X	{
X		rplay_perror("rplay_create");
X		exit(1);
X	}
--------------------------------------------------------------------------------
Prototype: int rplay_set(RPLAY *rp, ...)
Summary:   Modify attributes of an RPLAY object.
Input:     A modifier followed by a NULL terminated list of attributes.
X           Valid modifiers are:
X           * RPLAY_APPEND - append attributes
X           * RPLAY_INSERT - insert attributes at index
X           * RPLAY_DELETE - delete attributes at index
X           * RPLAY_CHANGE - change attributes at index
X	   Valid attributes are:
X           * RPLAY_SOUND - sound name
X           * RPLAY_VOLUME - sound volume
X           * RPLAY_COUNT - number of times to play the sound
X           * RPLAY_LIST_COUNT - number of times to play the sound list
X           * RPLAY_PRIORITY - sound priority
X           * RPLAY_RANDOM_SOUND - pick a random sound from the sound list
Output:    0 meaning success or -1 for errors.
Example:
X	/*
X	 * play a sound with volume 200
X	 */
X	rplay_set(rp, RPLAY_APPEND,
X		RPLAY_SOUND,	"bogus.au",
X		RPLAY_VOLUME,	200,
X		NULL);
X
X	/*
X	 * play a sound with volume 200
X	 */
X	rplay_set(rp, RPLAY_INSERT, 0,
X		RPLAY_SOUND,	"bogus.au",
X		RPLAY_VOLUME,	200,
X		NULL);
X
X	/*
X	 * stop a sound with volume 200
X	 */
X	rp = rplay_create(RPLAY_STOP);
X	rplay_set(rp, RPLAY_APPEND,
X		RPLAY_SOUND,	"excellent.au",
X		RPLAY_VOLUME,	200,
X		NULL);
X
X	/*
X	 * delete sound 1
X	 */
X	rplay_set(rp, RPLAY_DELETE, 1, NULL);
X
X	/*
X	 * count and list count example
X	 *
X	 * result = gong.au gong.au drip.au drip.au
X	 *          gong.au gong.au drip.au drip.au
X	 *
X	 */
X	rplay_set(rp, RPLAY_LIST_COUNT, 2, NULL);
X	rplay_set(rp, RPLAY_APPEND,
X		RPLAY_SOUND,	"gong.au",
X		RPLAY_COUNT,	2,
X		NULL);
X	rplay_set(rp, RPLAY_APPEND,
X		RPLAY_SOUND,	"drip.au",
X		RPLAY_COUNT,	2,
X		NULL);
X
X	/*
X	 * random example (I assume there is already a sound list)
X	 */
X	rplay_set(rp, RPLAY_RANDOM_SOUND, NULL); /* pick a sound randomly */
X	rplay_set(rp, RPLAY_RANDOM_SOUND, NULL); /* pick another sound */
--------------------------------------------------------------------------------
Prototype: int rplay_get(RPLAY *rp, ...)
Summary:   Retrieve attributes from an RPLAY object.
Input:     Any one of the following attributes:
X           * RPLAY_SOUND - sound name
X           * RPLAY_VOLUME - sound volume
X           * RPLAY_NSOUNDS - number of sounds
X           * RPLAY_COMMAND - rplay command
X           * RPLAY_COUNT - number of times to play the sound
X           * RPLAY_LIST_COUNT - number of times to play the sound list
X           * RPLAY_PRIORITY - sound priority
X           * RPLAY_RANDOM_SOUND - index of the random sound
Output:    The output is dependent upon the input as follows:
X           * RPLAY_SOUND -> <char *>
X           * RPLAY_VOLUME -> <int>
X           * RPLAY_NSOUNDS -> <int>
X           * RPLAY_COMMAND -> <int>
X           * RPLAY_COUNT -> <int>
X           * RPLAY_LIST_COUNT -> <int>
X           * RPLAY_PRIORITY -> <int>
X           * RPLAY_RANDOM_SOUND -> <int>
Example:
X	/*
X	 * get the number of sounds
X	 */
X	n = rplay_get(rp, RPLAY_NSOUNDS);
X
X	/*
X	 * get the name of sound 0
X	 */
X	p = (char *)rplay_get(rp, RPLAY_SOUND, 0);
X
X	/*
X	 * get the volume of sound 1
X	 */
X	v = rplay_get(rp, RPLAY_VOLUME, 1);
X
X	/*
X	 * get the rplay command
X	 */
X	x = rplay_get(rp, RPLAY_COMMAND);
--------------------------------------------------------------------------------
Prototype: void rplay_destroy(RPLAY *rp)
Summary:   Free memory used by the RPLAY object.
Input:     A pointer to an RPLAY object.
Output:    None.
Example:
X	rplay_destroy(rp);
--------------------------------------------------------------------------------
Prototype: int rplay_open(char *hostname)
Summary:   Create a UDP socket to send rplay packets to hostname.
Input:     A valid hostname or IP address.  The IP address can also be a subnet
X	   mask which is used to broadcast rplay packets.
Output:    A socket descriptor or -1 for errors.
Example:
X	int	rplay_fd;
X
X	rplay_fd = rplay_open("bozo.sdsu.edu");
X	if (rplay_fd < 0)
X	{
X		rplay_perror("rplay_open");
X		exit(1);
X	}
--------------------------------------------------------------------------------
Prototype: int rplay(int rplay_fd, RPLAY *rp)
Summary:   Send an rplay packet.
Input:     A socket created with rplay_open() and an RPLAY object.
Output:    0 meaning success or -1 for errors.
Example:
X	if (rplay(rplay_fd, rp) < 0)
X	{
X		rplay_perror("rplay");
X		exit(1);
X	}
--------------------------------------------------------------------------------
Prototype: int rplay_close(int rplay_fd)
Summary:   Close the rplay socket.
Input:     A socket created with rplay_open();
Output:    0 meaning success or -1 for errors.
Example:
X	rplay_close(rplay_fd);
--------------------------------------------------------------------------------
Prototype: void rplay_perror(char *message)
Summary:   Print errors from the rplay library routines using rplay_errno
X           and rplay_errlist.  Errors can be detected when routines return
X	   NULL or -1.
Input:     A message that will prefix the error message that will be printed.
Output:    None.
Example:
X	rplay_perror("rplay_set");
--------------------------------------------------------------------------------
Prototype: int rplay_open_display(void)
Summary:   Open an rplay socket using the current X display.  This routine
X	   uses the DISPLAY environment variable to obtain the X display
X	   and defaults to "localhost".
Input:     None.
Output:    A socket descriptor or -1 for errors.
Example:
X	int	rplay_fd;
X
X	rplay_fd = rplay_open_display();
X	if (rplay_fd < 0)
X	{
X		rplay_perror("rplay_open_display");
X		exit(1);
X	}
--------------------------------------------------------------------------------
Prototype: int rplay_display(char *sound)
Summary:   Play a sound on the current X display.  This routine uses
X	   rplay_open_display() to open the current X display.
Input:     A sound name.
Output:    0 meaning success or -1 for errors.
Example:
X	if (rplay_display("bogus.au") < 0)
X	{
X		rplay_perror("rplay_display");
X		exit(1);
X	}
--------------------------------------------------------------------------------
Prototype: int rplay_local(char *sound)
Summary:   Play a sound on the localhost.
Input:     A sound name.
Output:    0 meaning success or -1 for errors.
Example:
X	if (rplay_local("bogus.au") < 0)
X	{
X		rplay_perror("rplay_local");
X		exit(1);
X	}
--------------------------------------------------------------------------------
Prototype: int rplay_host(char *host, char *sound)
Summary:   Play a sound on a host.
Input:     A valid hostname or IP address and a sound name.
Output:    0 meaning success or -1 for errors.
Example:
X	if (rplay_host("bozo.sdsu.edu", "bogus.au") < 0)
X	{
X		rplay_perror("rplay_host");
X		exit(1);
X	}
--------------------------------------------------------------------------------
Prototype: int rplay_host_volume(char *host, char *sound, int volume)
Summary:   Play a sound on a host with a specific volume.
Input:     A valid hostname or IP address, a sound name, and a volume.
Output:    0 meaning success or -1 for errors.
Example:
X	if (rplay_host_volume("bozo.sdsu.edu", "bogus.au", 255) < 0)
X	{
X		rplay_perror("rplay_host");
X		exit(1);
X	}
--------------------------------------------------------------------------------
Prototype: int rplay_sound(int rplay_fd, char *sound)
Summary:   Play a sound given a socket.
Input:     A UDP socket and a sound name.
Output:    0 meaning success or -1 for errors.
Example:
X	if (rplay_sound(sock_fd, "bogus.au") < 0)
X	{
X		rplay_perror("rplay_sound");
X		exit(1);
X	}
--------------------------------------------------------------------------------
Prototype: int rplay_ping(char *host)
Summary:   Wakeup the rplay server running on the specified host.
Input:     A valid hostname or IP address.
Output:    0 meaning success or -1 for errors.
Example:
X	if (rplay_ping("bozo.sdsu.edu") < 0)
X	{
X		rplay_perror("rplay_ping");
X		exit(1);
X	}
--------------------------------------------------------------------------------
Prototype: int rplay_ping_sockfd(int sock_fd)
Summary:   Wakeup the rplay server that the sock_fd is connected to.
Input:     A UDP socket descriptor.
Output:    0 meaning success or -1 for errors.
Example:
X	if (rplay_ping_sockfd(sock_fd) < 0)
X	{
X		rplay_perror("rplay_ping_sockfd");
X		exit(1);
X	}
--------------------------------------------------------------------------------
Prototype: int rplay_ping_sockaddr_in(struct sockaddr_in *saddr)
Summary:   Wakeup the rplay server as described in the struct sockaddr_in.
Input:     A pointer to a struct sockaddr_in.
Output:    0 meaning success or -1 for errors.
Example:
X	struct sockaddr_in	saddr;
X
X	/* ... saddr initialization ...*/
X
X	if (rplay_ping_sockaddr_in(&saddr) < 0)
X	{
X		rplay_perror("rplay_ping_sockfd");
X		exit(1);
X	}
--------------------------------------------------------------------------------
Prototype: char *rplay_default_host(void)
Summary:   Obtain the user's default rplay host using the RPLAY_HOST environment
X           variable.  If RPLAY_HOST is not defined, localhost will be used.
Input:     none.
Output:    The name of an rplay host.
Example:
X	char	*host;
X
X	host = rplay_default_host();
--------------------------------------------------------------------------------
Prototype: int rplay_default(char *sound)
Summary:   Play a sound on the default rplay host.  rplay_default_host is used
X	   to obtain the default rplay host.
Input:     A sound name.
Output:    0 meaning success or -1 for errors.
Example:
X	if (rplay_default("bogus.au") < 0)
X	{
X		rplay_perror("rplay_default");
X		exit(1);
X	}
--------------------------------------------------------------------------------
Prototype: int rplay_open_default(void)
Summary:   Open an rplay socket using the default rplay host.
X	   rplay_default_host is used to obtain the default rplay host.
Input:     None.
Output:    A socket descriptor or -1 for errors.
Example:
X	int	rplay_fd;
X
X	rplay_fd = rplay_open_default();
X	if (rplay_fd < 0)
X	{
X		rplay_perror("rplay_open_default");
X		exit(1);
X	}
--------------------------------------------------------------------------------
RPTP routines:
--------------------------------------------------------------------------------
Prototype: int rptp_open(char *host, int port, char *response, int response_size)
Summary:   Open an RPTP connection to the specified host.
Input:     * host - a valid hostname or IP address
X	   * port - the port to connect to at the host, 55556 is the
X		    standard port and is defined as RPTP_PORT in rplay.h
X	   * response - a buffer of size response_size which will contain the
X                        connection response.
Output:    A TCP socket descriptor or -1 for errors.
Example:
X	int	rptp_fd;
X	char	buf[RPTP_MAX_LINE];	/* defined in rplay.h */
X
X	rptp_fd = rptp_open("bozo.sdsu.edu", RPTP_PORT, buf, sizeof(buf));
X	if (rptp_fd < 0)
X	{
X		rptp_perror("bozo.sdsu.edu");
X		exit(1);
X	}
--------------------------------------------------------------------------------
Prototype: int rptp_read(int rptp_fd, char *ptr, int nbytes)
Summary:   Read nbytes into ptr from the RPTP connection.
Input:     A TCP socket, buffer, and the number of bytes to read.
Output:    The number of bytes actually read, -1 for errors.
Example:
X	if (rptp_read(rptp_fd, buf, sizeof(buf)) != sizeof(buf))
X	{
X		rptp_perror("rptp_read");
X		exit(1);
X	}
--------------------------------------------------------------------------------
Prototype: int rptp_write(int rptp_fd, char *ptr, int nbytes)
Summary:   Write nbytes from ptr to the RPTP connection.
Input:     A TCP socket, buffer, and the number of bytes to write.
Output:    The number of bytes actually written, -1 for errors.
Example:
X	if (rptp_write(rptp_fd, buf, sizeof(buf)) != sizeof(buf))
X	{
X		rptp_perror("rptp_write");
X		exit(1);
X	}
--------------------------------------------------------------------------------
Prototype: int rptp_putline(int rptp_fd, char *fmt, ...)
Summary:   Send a line to the RPTP connection.  "\r\n" will be appended to the
X	   line sent so do not included either of them in the given string.
Input:     A TCP socket and arguments similar to printf().
Output:    0 meaning success or -1 for errors.
Example:
X	if (rptp_putline(rptp_fd, "find %s", "bogus.au") < 0)
X	{
X		rptp_perror("rptp_putline");
X		exit(1);
X	}
--------------------------------------------------------------------------------
Prototype: int rptp_getline(int rptp_fd, char *buf, int nbytes)
Summary:   Read a line from the RPTP connection.  "\r\n" will be removed from
X	   the line read.
Input:     A TCP socket, a buffer, and the number of bytes to read into the
X	   buffer.
Output:    The number of bytes actually read, or -1 for errors.
Example:
X	if (rptp_getline(rptp_fd, buf, sizeof(buf)) < 0)
X	{
X		rptp_perror("rptp_getline");
X		exit(1);
X	}
--------------------------------------------------------------------------------
Prototype: int rptp_command(int rptp_fd, char *command, char *response,
X			    int response_size)
Summary:   Send an RPTP command to the RPTP connection, the command response
X	   will be stored in the repsonse buffer.
Input:     A TCP socket, a buffer with an RPTP command, and a buffer of size
X	   response_size to store the command response in.
Output:    0 meaning the response begins with '+', 1 meaning the response
X	   begins with '-', and -1 for errors.  A response that begins with
X	   '!' (connection timeout) will also return -1.
Example:
X	switch (rptp_command(rptp_fd, command, response, sizeof(response)))
X	{
X	case -1:
X		rptp_perror(command);
X		break;
X
X	case 1:
X		printf("error message: %s\n", repsonse);
X		break;
X
X	case 0:
X		/*
X		 * success!  do something...
X		 */
X		break;
X	}
--------------------------------------------------------------------------------
Prototype: int rptp_close(int rptp_fd)
Summary:   Close a RPTP connection.
Input:     A TCP socket descriptor.
Output:    0 meaning success, -1 for errors.
Example:
X	rptp_close(rptp_fd);
--------------------------------------------------------------------------------
Prototype: int rptp_perror(char *message)
Summary:   Print errors from the rplay library routines using rptp_errno
X           and rptp_errlist.  Errors can be detected when routines return
X	   NULL or -1.
Input:     A message that will prefix the error message that will be printed.
Output:    None.
Example:
X	rptp_perror("rptp_open");
--------------------------------------------------------------------------------
SHAR_EOF
chmod 0644 rplay-3.1.0/doc/README.LIBRPLAY ||
echo 'restore of rplay-3.1.0/doc/README.LIBRPLAY failed'
Wc_c="`wc -c < 'rplay-3.1.0/doc/README.LIBRPLAY'`"
test 15580 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/doc/README.LIBRPLAY: original size 15580, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/doc/Makefile ==============
if test -f 'rplay-3.1.0/doc/Makefile' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/doc/Makefile (File already exists)'
else
echo 'x - extracting rplay-3.1.0/doc/Makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/doc/Makefile' &&
# 
# Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
#
# This file is part of rplay.
#
# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
#
X
include ../Makefile.config
X
all:
X
install:
X	$(INSTALL) man1/*.1 $(INSTALL_MAN_DIR)/man1
X	$(INSTALL) man5/*.5 $(INSTALL_MAN_DIR)/man5
X
clean:
X	$(RM) man1/*.bak man1/*~ man5/*.bak man5/*~ *~ *.bak *.orig
X
depend:
X
SHAR_EOF
chmod 0644 rplay-3.1.0/doc/Makefile ||
echo 'restore of rplay-3.1.0/doc/Makefile failed'
Wc_c="`wc -c < 'rplay-3.1.0/doc/Makefile'`"
test 985 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/doc/Makefile: original size 985, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/doc/README.RPTP ==============
if test -f 'rplay-3.1.0/doc/README.RPTP' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/doc/README.RPTP (File already exists)'
else
echo 'x - extracting rplay-3.1.0/doc/README.RPTP (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/doc/README.RPTP' &&
X
The file describes the Remote Play Transfer Protocol, otherwise known as RPTP.
RPTP is based on a small set of commands which return at least one line that
can begin with a '+', '-', or '!'.  The '+' is considered a successful command
execution, '-' is considered an error, and '!' is a connection timeout.  These
characters are defined in rplay.h as RPTP_OK, RPTP_ERROR, and RPTP_TIMEOUT
respectively.  All lines are terminated with "\r\n".
X
The rplay library includes several RPTP support routines.
X
Below is a description of each RPTP command in detail.
X
Commands "continue", "pause", "play", and "stop" accept the following options:
X   -P <int>  Sound priority.
X   -N <int>  Number of times to play the sound list.
X   -n <int>  Number of times to play each sound.
X   -v <int>  Volume.
X
--------------------------------------------------------------------------------
Command: access
Usage:   access
Summary: Display client access permissions.
Result:  One line which can contain any combination of the characters "rwx".
X         r - Read access, the client can download sound files (get).
X         w - Write access, the client can upload sound files (put).
X         x - Execute access, the client can play, stop, pause, and continue
X             sounds.
Example: access
X	 +rwx
--------------------------------------------------------------------------------
Command: continue
Usage:   continue [-PNnv] sound ...
Summary: Continue a sound that had been previously paused.
Result:  One line describing whether or not the continue was successful.
Example: continue bogus.au
X	 +continue successful
X	 or
X	 -continue failed
--------------------------------------------------------------------------------
Command: find
Usage:   find sound
Summary: Search for a sound by name.
Result:  One line containing the sound name and it's size or an error message.
Example: find bogus.au
X	 +bogus.au 9574
X	 or
X	 -bogus.au not found
--------------------------------------------------------------------------------
Command: get
Usage:   get sound
Summary: Retrieve a sound.
Result:  One line containing the sound name and it's size followed by size
X	 binary bytes, or an error message.
Example: get bogus.au
X	 +bogus.au 9574
X	 <... 9574 bytes of binary data...>
X	 or
X	 -bogus.au not found
--------------------------------------------------------------------------------
Command: list [connections|hosts|servers|spool|sounds]
Usage:   list [connections|hosts|servers|spool|sounds]
Summary: Display various server information.
Result:  One line describing whether or not the list command was successful.
X         If the command was successful then a series of lines terminated by a 
X	 line that only contains a '.' will follow.
Example: 
X         list connections
X	 +connections
X	 HOST            TYPE   WHAT
X	 130.191.225.64  client (idle)
X         .
X
X	 or
X
X	 list hosts
X	 +hosts
X	 mojo:rwx
X	 athena:rwx
X	 hercules:rx
X	 sciences:rx
X	 kiwi:rx
X	 127.0.0.1:rwx
X	 .
X
X	 or
X
X	 list servers
X	 sounds.sdsu.edu:55556
X	 .
X
X	 or
X
X	 list spool
X	 HOST            STATE  VOL PRI SECONDS REMAIN SOUND
X	 130.191.225.64  play   127   0       6      3 spacemusic.au
X	 .
X
X	 or
X
X	 list sounds
X         +sound
X	 bogus.au
X	 ring.au
X	 burp.au
X	 .
X
X	 or
X
X	 list foo
X	 -cannot list foo
--------------------------------------------------------------------------------
Command: pause
Usage:   pause [-PNnv] sound ...
Summary: Pause a sound that is currently playing.
Result:  One line describing whether or not the pause was successful.
Example: pause bogus.au
X	 +pause successful
X	 or
X	 -pause failed
--------------------------------------------------------------------------------
Command: play
Usage:   play [-PNnv] sound ...
Summary: Play sounds.
Result:  One line describing whether or not the play was successful.
Example: play bogus.au
X	 +play successful
X	 or
X	 -play failed
--------------------------------------------------------------------------------
Command: put
Usage:   put sound size
Summary: Upload a sound.
Result:  One line describing whether or not put access is allowed.
X         If access is granted the server expects to receive size bytes of
X	 sound data.
Example: put bogus.au 9574
X         +bogus.au 9574
X	 or
X	 -bogus.au already exists
--------------------------------------------------------------------------------
Command: stop
Usage:   stop [-PNnv] sound ...
Summary: Stop sounds that are currently playing.
Result:  One line describing whether or not the stop was successful.
Example: stop bogus.au
X	 +stop successful
X	 or
X	 -stop failed
--------------------------------------------------------------------------------
Command: quit
Usage:   quit
Summary: Disconnect from the RPTP connection gracefully.
Result:  none
Example: quit
--------------------------------------------------------------------------------
SHAR_EOF
chmod 0644 rplay-3.1.0/doc/README.RPTP ||
echo 'restore of rplay-3.1.0/doc/README.RPTP failed'
Wc_c="`wc -c < 'rplay-3.1.0/doc/README.RPTP'`"
test 4804 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/doc/README.RPTP: original size 4804, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/doc/man1/rplay.1 ==============
if test ! -d 'rplay-3.1.0/doc/man1'; then
    echo 'x - creating directory rplay-3.1.0/doc/man1'
    mkdir 'rplay-3.1.0/doc/man1'
fi
if test -f 'rplay-3.1.0/doc/man1/rplay.1' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/doc/man1/rplay.1 (File already exists)'
else
echo 'x - extracting rplay-3.1.0/doc/man1/rplay.1 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/doc/man1/rplay.1' &&
.TH RPLAY 1 "9 August 1993"
.SH NAME
rplay \- play sound files on local and remote hosts
.SH SYNOPSIS
.B rplay
[\-chnNpPrsv] soundname \.\.\.
.SH DESCRIPTION
rplay is a sample rplay client which communicates with the
rplay server
.I (rplayd)
using the RPLAY protocol.  This client can be used
to play, pause, continue, and stop sounds.  The sound names that
are specified can be either the name of a sound including the dot extension,
the name of a sound without the dot extension, or the complete pathname of
a sound file.
.SH OPTIONS
.TP
.B \-c
Continue sounds that are currently paused.
.TP
.B \-h <host>
Specify an rplay host.  The hostname specified can be a colon separated list
of hosts.  The host(s) specified will override the default host defined by
the
.B RPLAY_HOST
environment variable.
.TP
.B \-n <int>
Number of times to play each sound.
.TP
.B \-N <int>
Number of times to play the sound list.
.TP
.B \-p
Pause sounds that are currently playing.
.TP
.B \-P <int>
Specify the sound priority.  Valid priorities range from 0 to 255 with 0 being 
the default and lowest priority.  Sounds with higher priorities will replace 
lower priority sounds when 
.I rplayd's
sound spool is full.
.TP
.B \-r
Randomly choose one of the given sounds.
.TP
.B \-s
Stop sounds that are currently playing.
.TP
.B \-v <int>
Specify the sound volume.  Valid volumes range from 0 to 255
with 127 being the default.
.SH ENVIRONMENT
The
.B RPLAY_HOST
environment variable can be used to specify the default rplay host.
If
.B RPLAY_HOST
is not defined in the environment and there are no hosts specified
using the
.B -h
option, localhost will be used.
.SH EXAMPLES
.LP
Play the sound bogus.au on a host named bozo:
.IP
.B "rplay -h bozo bogus.au"
.PP
Broadcast the sound bogus.au to all hosts on a subnet:
.IP
.B "rplay -h 130.191.255.255 bogus.au"
.PP
Play a sound on multiple hosts:
.IP
.B "rplay -h host1:host2:host3 bogus.au"
.PP
Stop the sound bogus.au playing on host bozo:
.IP
.B "rplay -h bozo -s bogus.au"
.PP
Play a sound without using the sound extension:
.IP
.B "rplay -h bozo bogus"
.PP
Play a sound using a complete pathname:
.IP
.B "rplay /tmp/song.au"
.PP
Play a list of sounds at a specific volume:
.IP
.B "rplay -v 200 burp bogus excellent ouch"
.PP
Play the same list of sounds at a specific volume and repeat it three times:
.IP
.B "rplay -v 200 -N 3 burp bogus excellent ouch"
.SH "SEE ALSO"
.BR rplayd (1)
SHAR_EOF
chmod 0644 rplay-3.1.0/doc/man1/rplay.1 ||
echo 'restore of rplay-3.1.0/doc/man1/rplay.1 failed'
Wc_c="`wc -c < 'rplay-3.1.0/doc/man1/rplay.1'`"
test 2417 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/doc/man1/rplay.1: original size 2417, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/doc/man1/rplayd.1 ==============
if test -f 'rplay-3.1.0/doc/man1/rplayd.1' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/doc/man1/rplayd.1 (File already exists)'
else
echo 'x - extracting rplay-3.1.0/doc/man1/rplayd.1 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/doc/man1/rplayd.1' &&
.TH RPLAYD 1 "9 August 1993"
.SH NAME
rplayd \- remote play sound server
.SH SYNOPSIS
.B rplayd
[\-cCdHnsStTv]
.SH DESCRIPTION
.I rplayd
is the sound server that rplay clients communicate with using either the
RPLAY or RPTP protocol.  
.I rplayd
must be running for sounds to be played, paused, stopped, continued,
transferred, etc.  The nicest way to invoke 
.I rplayd
is with 
.I inetd. 
When using 
.I inetd
an entry similar to the following must be included in the
.I inetd.conf
file:
.LP
.B "rplay dgram udp wait nobody /usr/local/bin/rplayd rplayd"
.LP
along with the following in /etc/services:
.LP
.B "rplay 55555/udp"
.LP
.I rplayd 
can also be invoked from any shell prompt.  This is useful for users
who do not have root access and is invaluable for debugging.
X
Once
.I rplayd
is running it reads the
.I rplay.conf, rplay.hosts,
and
.I rplay.servers
files.   After these files are read 
.I rplayd
is ready to accept RPLAY and RPTP client requests.  Each client request
is authenticated using the 
.I rplay.hosts
file.
X
When
.I rplayd
cannot find a sound in it's local sound database
.I (rplay.conf)
it sequentially contacts the rplay servers listed in the 
.I rplay.servers
file.  If the sound is found at another rplay server, 
.I rplayd 
will download the sound and store it in the 
.I rplay.cache
directory.  Sounds that are larger than the maximum cache size
will not be accepted.  Sounds will be removed using a "least recently used" 
algorithm when the cache is full.
.SH OPTIONS
.TP
.B \-c <int>
Close the audio device when sounds have not been played for the specified 
number of seconds. 
.TP
.B \-C <filename>
Specify an alternate
.I rplay.conf.
.TP
.B \-d
Enable output of debugging information.  Use this option along with -n.
.TP
.B \-D <directory>
Specify an alternate
.I rplay.cache
directory.
.TP
.B \-H <filename>
Specify an alternate
.I rplay.hosts.
.TP
.B \-n
Disable inetd mode which is enabled by default.  Use this option when using
the -d option.
.TP
.B \-s <int>
Specify the maximum size of the 
.I rplay.cache.
.TP
.B \-S <filename>
Specify an alternate
.I rplay.servers.
.TP
.B \-t <int>
Exit after the specified number of idle seconds.
.TP
.B \-T <int>
Close idle RPTP connections after the specified number of seconds.
.TP
.B \-v
Print version information.
.SH EXAMPLE
.LP
Start
.I rplayd
in debug mode and make sure it doesn't timeout:
.IP
.B "rplayd -n -d -t0"
.PP
Start
.I rplayd
without any local sounds (all sounds will be obtained from
other rplay servers and stored in the cache):
.IP
.B "rplayd -n -t0 -T0 -C/dev/null"
.SH FILES
.PD 0
.TP
.B /usr/local/etc/rplay.conf
.TP
.B /usr/local/etc/rplay.hosts
.TP
.B /usr/local/etc/rplay.servers
.TP
.B /tmp/rplay.cache
.TP
.B /etc/inetd.conf
.TP
.B /etc/services
.PD
.SH "SEE ALSO"
.BR rplay.conf (5),
.BR rplay.hosts (5),
.BR rplay.servers (5),
.BR inetd (8C),
.BR inetd.conf (5),
.BR services (5)
.SH BUGS
The 
.I rplay.cache
directory must be readable and writable to the user that rplayd will run as.
The directory will be created if it doesn't exist.
SHAR_EOF
chmod 0644 rplay-3.1.0/doc/man1/rplayd.1 ||
echo 'restore of rplay-3.1.0/doc/man1/rplayd.1 failed'
Wc_c="`wc -c < 'rplay-3.1.0/doc/man1/rplayd.1'`"
test 3046 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/doc/man1/rplayd.1: original size 3046, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/doc/man1/rptp.1 ==============
if test -f 'rplay-3.1.0/doc/man1/rptp.1' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/doc/man1/rptp.1 (File already exists)'
else
echo 'x - extracting rplay-3.1.0/doc/man1/rptp.1 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/doc/man1/rptp.1' &&
.TH RPTP 1 "9 August 1993"
.SH NAME
rptp \- A Remote Play Transfer Protocol (RPTP) client
.SH SYNOPSIS
.B rptp
[\-hpv]
.SH DESCRIPTION
.I rptp
is a sample 
.B RPTP
client which communicates with the 
rplay server
.I (rplayd)
using the RPTP protocol.  This client can be used to play, pause, 
continue, stop, and transfer sounds.  The client accepts the following commands:
.RS
.TP 3
.B access
Display remote access permissions.  The access permissions can be
any combination of the following characters:
.RS
.TP 3
.B r
Client can download sound files using
.B get.
.TP 3
.B w
Client can upload sound files using
.B put.
.TP 3
.B x
Client can play, pause, continue, and stop sounds.
.RE
.TP 3
.B close
Close the current server connection.
.TP 3
.B continue
Continue paused sounds.  The sound name arguments specified
must be the names of sounds that are currently paused.
.TP 3
.B find
Search for a sound.  This command requires one sound name
as an argument.
.TP 3
.B get
Download a sound.  This command can have a maximum of two
arguments.  The first argument is the name of the sound
to be downloaded from the server, and the second is an 
optional filename that the sound will be saved as.
By default the sound will be saved using the name
of the first argument.
.TP 3
.B help
Display help information.
.TP 3
.B list
Display various server information.  The following arguments
are accepted:
.RS
.TP 3
.B connections
List all the server's RPTP connections.
.TP 3
.B hosts
List the server's
.I rplay.hosts
file.
.TP 3
.B servers
List the server's 
.I rplay.servers
file.
.TP 3
.B spool
List the server's sound spool.  This is an easy way to see what
sounds are playing or paused.
.TP 3
.B sounds
List all the sounds that the server has available.
.RE
.TP 3
.B open
Connect to an RPTP server.  The command accepts a hostname and
an optional port as arguments.
.TP 3
.B pause
Pause sounds that are playing.
.TP 3
.B play
Play sounds.
.TP 3
.B put
Upload a sound.  The pathname of a sound file is expected as
an argument.
.TP 3
.B quit
Terminate the RPTP session.
.TP 3
.B stop
Stop sounds that are playing.
.RE
X
Included with the rplay distribution is a file called
.I README.RPTP
which contains a more detailed description of the RPTP
command set.  Please see this file for more information.
.SH OPTIONS
.TP
.B \-h <host>
Specify an RPTP host.  The host specified will override the
default host defined by the
.B RPLAY_HOST
environment variable.
.TP
.B \-p <int>
Specify the port to connect to.  If a port is not specified then
55556 will be used.  
.TP
.B \-v
Display rplay version information.
.SH ENVIRONMENT
The
.B RPLAY_HOST
environment variable can be used to specify the default RPTP host.
If
.B RPLAY_HOST
is not defined in the environment and there are no hosts specified using the
.B -h
option, localhost will be used.
.SH FILES
.PD 0
.TP
.B README.RPTP
.TP
.B /usr/local/etc/rplay.hosts
.TP
.B /usr/local/etc/rplay.servers
.PD
.SH "SEE ALSO"
.BR rplayd (1),
.BR rplay.hosts (5),
.BR rplay.servers (5)
SHAR_EOF
chmod 0644 rplay-3.1.0/doc/man1/rptp.1 ||
echo 'restore of rplay-3.1.0/doc/man1/rptp.1 failed'
Wc_c="`wc -c < 'rplay-3.1.0/doc/man1/rptp.1'`"
test 3013 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/doc/man1/rptp.1: original size 3013, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rptp/Makefile ==============
if test ! -d 'rplay-3.1.0/rptp'; then
    echo 'x - creating directory rplay-3.1.0/rptp'
    mkdir 'rplay-3.1.0/rptp'
fi
if test -f 'rplay-3.1.0/rptp/Makefile' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rptp/Makefile (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rptp/Makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rptp/Makefile' &&
# 
# Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
#
# This file is part of rplay.
#
# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
#
X
include ../Makefile.config
X
TARGET=		rptp
SRCS=		rptp.c
OBJS=		rptp.o
X
all:		$(TARGET)
X
$(TARGET):	$(OBJS) $(LIBRPLAY_DIR)/$(LIBRPLAY_NAME)
X		$(CC) $(CFLAGS) -o $@ $(OBJS) $(LDFLAGS)
X
install:	$(TARGET)
X		$(BIN_INSTALL) $(TARGET) $(INSTALL_BIN_DIR)
X
clean:
X		$(RM) $(TARGET) $(OBJS) core a.out *~ *.bak *.orig
X
depend:
X		$(MAKEDEPEND) -- $(CFLAGS) -- $(SRCS)
SHAR_EOF
chmod 0644 rplay-3.1.0/rptp/Makefile ||
echo 'restore of rplay-3.1.0/rptp/Makefile failed'
Wc_c="`wc -c < 'rplay-3.1.0/rptp/Makefile'`"
test 1132 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rptp/Makefile: original size 1132, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/rptp/rptp.c ==============
if test -f 'rplay-3.1.0/rptp/rptp.c' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/rptp/rptp.c (File already exists)'
else
echo 'x - extracting rplay-3.1.0/rptp/rptp.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/rptp/rptp.c' &&
/* 
X * Copyright (C) 1993 Mark Boyns (boyns@sdsu.edu)
X *
X * This file is part of rplay.
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X */
X
#include "conf.h"
#include "version.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include "rplay.h"
X
typedef struct
{
X	char	*name;
X	int	min_args;
X	int	max_args;
X	char	*usage;
#ifdef __STDC__
X	void	(*func)(int argc, char **argv);
#else
X	void	(*func)();
#endif
} COMMAND;
X
#ifdef __STDC__
void	command_open(int argc, char **argv);
void	command_close(int argc, char **argv);
void	command_play(int argc, char **argv);
void	command_find(int argc, char **argv);
void	command_help(int argc, char **argv);
void	command_list(int argc, char **argv);
void	command_quit(int argc, char **argv);
void	command_put(int argc, char **argv);
void	command_get(int argc, char **argv);
void	command_access(int argc, char **argv);
void	command_unknown(int argc, char **argv);
void	argv_to_command(char **argv);
int	connected();
void	done(int exit_value);
void	usage();
#else
void	command_open(/* int argc, char **argv */);
void	command_close(/* int argc, char **argv */);
void	command_play(/* int argc, char **argv */);
void	command_find(/* int argc, char **argv */);
void	command_help(/* int argc, char **argv */);
void	command_list(/* int argc, char **argv */);
void	command_quit(/* int argc, char **argv */);
void	command_put(/* int argc, char **argv */);
void	command_get(/* int argc, char **argv */);
void	command_access(/* int argc, char **argv */);
void	command_unknown(/* int argc, char **argv */);
void	argv_to_command(/* char **argv */);
int	connected();
void	done(/* int exit_value */);
void	usage();
#endif
X
COMMAND	commands[] =
{
X	"access",	0,	0,	"",				command_access,
X	"close",	0,	0,	"",				command_close,
X	"continue",	1,	-1,	"[-PNnv] sound ...",		command_play,
X	"find",		1,	1,	"sound",			command_find,
X	"get",		1,	2,	"sound [filename]",		command_get,
X	"help",		0,	1,	"[command]",		       	command_help,
X	"list",		0,	1,	"[connections|hosts|servers|spool|sounds]",		command_list,
X	"open",		1,	2,	"hostname [port]",		command_open,
X	"pause",	1,	-1,	"[-PNnv] sound ...",		command_play,
X	"play",		1,	-1,	"[-PNnv] sound ...",		command_play,
X	"put",		1,	1,	"sound",			command_put,
X	"quit",		0,	0,	"",				command_quit,
X	"stop",		1,	-1,	"[-PNnv] sound ...",		command_play,
};
X
#define NCOMMANDS	(sizeof(commands)/sizeof(COMMAND))
#undef MIN
#define MIN(a,b)	((a)>(b)?(b):(a))
X
int	rptp_fd = -1;
char	rptp_buf[4096];
char	command[RPTP_MAX_LINE];
char	response[RPTP_MAX_LINE];
X
extern int	optind;
extern char	*optarg;
X
#ifdef __STDC__
main(int argc, char **argv)
#else
main(argc, argv)
int	argc;
char	**argv;
#endif
{
X	char	buf[256];
X	int	i;
X	int	port = RPTP_PORT;
X	int	c;
X	char	*av[RPTP_MAX_ARGS], *p, *host = NULL;
X	int	ac, first;
X
X	while ((c = getopt(argc, argv, "h:p:v")) != -1)
X	{
X		switch (c)
X		{
X		case 'h':
X			host = optarg;
X			break;
X
X		case 'p':
X			port = atoi(optarg);
X			break;
X		
X		case 'v':
X			printf("%s\n", rplay_version);
X			done(0);
X
X		case '?':
X			usage();
X			done(0);
X		}
X	}
X
X	if (optind != argc)
X	{
X		usage();
X		done(1);
X	}
X
X	if (host == NULL)
X	{
X		host = rplay_default_host();
X	}
X
X	rptp_fd = rptp_open(host, port, response, sizeof(response));
X	if (rptp_fd < 0)
X	{
X		rptp_perror("open");
X	}
X	else
X	{
X		printf("Connected to %s port %d.\n", host, port);
X		printf("%s\n", response+1);
X	}
X
X	for (;;)
X	{
X		printf("rptp> ");
X		fflush(stdout);
X		if (fgets(buf, sizeof(buf), stdin) == NULL)
X		{
X			done(0);
X		}
X		first = 1;
X		ac = 0;
X		while (p = strtok(first ? buf : NULL, " \t\r\n"))
X		{
X			av[ac++] = p;
X			first = 0;
X		}
X		av[ac] = NULL;
X
X		if (av[0] == NULL)
X		{
X			continue;
X		}
X
X		for (i = 0; i < NCOMMANDS; i++)
X		{
X			if (strcasecmp(commands[i].name, av[0]) == 0)
X			{
X				if (commands[i].min_args >= 0 && ac-1 < commands[i].min_args
X					|| commands[i].max_args >= 0 && ac-1 > commands[i].max_args)
X				{
X					printf("Usage: %s %s\n", commands[i].name, commands[i].usage);
X				}
X				else
X				{
X					(*commands[i].func)(ac, av);
X				}
X				break;
X			}
X		}
X		if (i == NCOMMANDS)
X		{
X			command_unknown(ac, av);
X		}
X	}
}
X
#ifdef __STDC__
void	argv_to_command(char **argv)
#else
void	argv_to_command(argv)
char	**argv;
#endif
{
X	command[0] = '\0';
X	for (; *argv; argv++)
X	{
X		strcat(command, *argv);
X		if (*(argv+1))
X		{
X			strcat(command, " ");
X		}
X	}
}
X
int	connected()
{
X	if (rptp_fd != -1)
X	{
X		return 1;
X	}
X	else
X	{
X		printf("You're not connected, use open first.\n");
X		return 0;
X	}
}
X
#ifdef __STDC__
void	command_open(int argc, char **argv)
#else
void	command_open(argc, argv)
int	argc;
char	**argv;
#endif
{
X	int	port;
X
X	if (rptp_fd != -1)
X	{
X		printf("You're already connected, use close first.\n");
X	}
X	else
X	{
X		port = argc == 3 ? atoi(argv[2]) : RPTP_PORT;
X		rptp_fd = rptp_open(argv[1], port, response, sizeof(response));
X		if (rptp_fd < 0)
X		{
X			rptp_perror("open");
X		}
X		else
X		{
X			printf("Connected to %s port %d.\n", argv[1], port);
X			printf("%s\n", response+1);
X		}
X	}
}
X
#ifdef __STDC__
void	command_close(int argc, char **argv)
#else
void	command_close(argc, argv)
int	argc;
char	**argv;
#endif
{
X	if (connected())
X	{
X		rptp_close(rptp_fd);
X		rptp_fd = -1;
X		printf("Connection closed.\n");
X	}
}
X
#ifdef __STDC__
void	command_play(int argc, char **argv)
#else
void	command_play(argc, argv)
int	argc;
char	**argv;
#endif
{
X	argv_to_command(argv);
X
X	if (!connected())
X	{
X		return;
X	}
X
X	switch (rptp_command(rptp_fd, command, response, sizeof(response)))
X	{
X	case -1:
X		rptp_perror(argv[0]);
X		command_close(argc, argv);
X		return;
X
X	case 1:
X		printf("%s\n", response+1);
X		return;
X
X	case 0:
X		break;
X	}
}
X
#ifdef __STDC__
void	command_find(int argc, char **argv)
#else
void	command_find(argc, argv)
int	argc;
char	**argv;
#endif
{
X	argv_to_command(argv);
X
X	switch (rptp_command(rptp_fd, command, response, sizeof(response)))
X	{
X	case -1:
X		rptp_perror(argv[0]);
X		command_close(argc, argv);
X		return;
X
X	case 1:
X		printf("%s\n", response+1);
X		return;
X
X	case 0:
X		break;
X	}
X
X	printf("%s\n", response+1);
}
X
#ifdef __STDC__
void	command_access(int argc, char **argv)
#else
void	command_access(argc, argv)
int	argc;
char	**argv;
#endif
{
X	argv_to_command(argv);
X	switch (rptp_command(rptp_fd, command, response, sizeof(response)))
X	{
X	case -1:
X		rptp_perror(argv[0]);
X		command_close(argc, argv);
X		return;
X		
X	case 1:
X		printf("%s\n", response+1);
X		return;
X		
X	case 0:
X		break;
X	}
X	
X	printf("%s\n", response+1);
}
X
#ifdef __STDC__
void	command_help(int argc, char **argv)
#else
void	command_help(argc, argv)
int	argc;
char	**argv;
#endif
{
X	int	i;
X	
X	if (argc == 2)
X	{
X		for (i = 0; i < NCOMMANDS; i++)
X		{
X			if (strcasecmp(commands[i].name, argv[1]) == 0)
X			{
X				printf("Usage: %s %s\n", commands[i].name, commands[i].usage);
X				return;
X			}
X		}
X		command_unknown(argc, argv);
X	}
X	else
X	{
X		printf("access   Display remote access permissions.\n");
X		printf("close    Close the current server connection.\n");
X		printf("continue Continue paused sounds.\n");
X		printf("find     Search for a sound.\n");
X		printf("get      Retrieve a sound.\n");
X		printf("help     Display help information.\n");
X		printf("list     Display various server information.\n");
X		printf("open     Connect to a server.\n");
X		printf("pause    Pause sounds that are playing.\n");
X		printf("play     Play sounds\n");
X		printf("put      Send a sound.\n");
X		printf("quit     Terminate the rptp session.\n");
X		printf("stop     Stop sounds that are playing.\n");
X	}
}
X
#ifdef __STDC__
void	command_list(int argc, char **argv)
#else
void	command_list(argc, argv)
int	argc;
char	**argv;
#endif
{
X	int	n;
X
X	if (!connected())
X	{
X		return;
X	}
X
X	argv_to_command(argv);
X
X	switch (rptp_command(rptp_fd, command, response, sizeof(response)))
X	{
X	case -1:
X		rptp_perror(argv[0]);
X		command_close(argc, argv);
X		return;
X
X	case 1:
X		printf("%s\n", response+1);
X		return;
X
X	case 0:
X		break;
X	}
X
X	for (;;)
X	{
X		n = rptp_getline(rptp_fd, rptp_buf, sizeof(rptp_buf));
X		if (n < 0)
X		{
X			rptp_perror("list");
X			command_close(argc, argv);
X			break;
X		}
X		if (strcmp(rptp_buf, ".") == 0) 
X		{
X			break;
X		}
X		printf("%s\n", rptp_buf);
X	}
}
X
#ifdef __STDC__
void	command_quit(int argc, char **argv)
#else
void	command_quit(argc, argv)
int	argc;
char	**argv;
#endif
{
X	if (rptp_fd != -1)
X	{
X		rptp_close(rptp_fd);
X		printf("Connection closed.\n");
X	}
X	done(0);
}
X
#ifdef __STDC__
void	command_put(int argc, char **argv)
#else
void	command_put(argc, argv)
int	argc;
char	**argv;
#endif
{
X	FILE		*fp;
X	int		size, n, nwritten;
X	struct stat	st;
X	char		buf[32];
X
X	if (!connected())
X	{
X		return;
X	}
X
X	if (stat(argv[1], &st) < 0)
X	{
X		perror(argv[1]);
X		return;
X	}
X	fp = fopen(argv[1], "r");
X	if (fp == NULL)
X	{
X		perror(argv[1]);
X		return;
X	}
X	size = st.st_size;
X
X	sprintf(buf, "%d", size);
X
X	argv[2] = buf;
X	argv[3] = NULL;
X
X	argv_to_command(argv);
X
X	switch (rptp_command(rptp_fd, command, response, sizeof(response)))
X	{
X	case -1:
X		rptp_perror(argv[0]);
X		command_close(argc, argv);
X		return;
X
X	case 1:
X		printf("%s\n", response+1);
X		return;
X
X	case 0:
X		break;
X	}
X
X	while (size > 0)
X	{
X		n = fread(rptp_buf, 1, sizeof(rptp_buf), fp);
X		nwritten = rptp_write(rptp_fd, rptp_buf, n);
X		if (nwritten != n)
X		{
X			rptp_perror("put");
X			command_close(argc, argv);
X			break;
X		}
X		size -= n;
X	}
X
X	fclose(fp);
}
X
#ifdef __STDC__
void	command_get(int argc, char **argv)
#else
void	command_get(argc, argv)
int	argc;
char	**argv;
#endif
{
X	FILE	*fp;
X	char	*filename;
X	char	*p;
X	int	size, n, nread;
X	
X	if (!connected())
X	{
X		return;
X	}
X
X	if (argc == 3)
X	{
X		filename = argv[2];
X		argv[2] = NULL;
X	}
X	else
X	{
X		filename = argv[1];
X	}
X
X	argv_to_command(argv);
X
X	switch (rptp_command(rptp_fd, command, response, sizeof(response)))
X	{
X	case -1:
X		rptp_perror(argv[0]);
X		command_close(argc, argv);
X		return;
X
X	case 1:
X		printf("%s\n", response+1);
X		return;
X
X	case 0:
X		break;
X	}
X
X	fp = fopen(filename, "w");
X	if (fp == NULL)
X	{
X		perror(filename);
X		return;
X	}
X
X	p = strtok(response+1, " ");
X	size = atoi(strtok(NULL, "\r\n"));
X	
X	while (size > 0)
X	{
X		n = MIN(sizeof(rptp_buf), size);
X		nread = rptp_read(rptp_fd, rptp_buf, n);
X		if (nread != n)
X		{
X			rptp_perror("get");
X			break;
X		}
X		fwrite(rptp_buf, 1, n, fp);
X		size -= n;
X	}
X
X	fclose(fp);
}
X
#ifdef __STDC__
void	command_unknown(int argc, char **argv)
#else
void	command_unknown(argc, argv)
int	argc;
char	**argv;
#endif
{
X	printf("Unknown command '%s'.\n", argv[0]);
}
X
void	usage()
{
X	printf("\n%s\n\n", rplay_version);
X	printf("usage: rptp [options]\n");
X	printf("\t-h host   Specify the RPTP host, default = %s.\n",
X		rplay_default_host());
X	printf("\t-p port   Use port instead of the default RPTP port, default = %d.\n", RPTP_PORT);
X	printf("\t-v        Display rplay version information.\n");
X	printf("\n");
}
X
#ifdef __STDC__
void	done(int exit_value)
#else
void	done(exit_value)
int	exit_value;
#endif
{
X	exit(exit_value);
}
SHAR_EOF
chmod 0644 rplay-3.1.0/rptp/rptp.c ||
echo 'restore of rplay-3.1.0/rptp/rptp.c failed'
Wc_c="`wc -c < 'rplay-3.1.0/rptp/rptp.c'`"
test 11488 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/rptp/rptp.c: original size 11488, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/TODO ==============
if test -f 'rplay-3.1.0/TODO' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/TODO (File already exists)'
else
echo 'x - extracting rplay-3.1.0/TODO (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/TODO' &&
X
* Support a way to stop all sounds besides sending various signals to rplayd.
X  Maybe using a special sound name "*".
X
* Support different sample rates.
X
* Support different sound file formats.
X
* rplayd tends to peg the cpu when it is trying to connect to another rplayd.
X  This needs to be fixed.
X
* rplayd should play sounds while receiving them.  The reason I am not doing this
X  currently is that audio headers have to be checked at some point.
X
* Fix regex.[ch] to compile with a C++ compiler.
X
* Add an attribute so rplay packets can send sound data.  This would be useful 
X  for radio broadcasting.
X
SHAR_EOF
chmod 0644 rplay-3.1.0/TODO ||
echo 'restore of rplay-3.1.0/TODO failed'
Wc_c="`wc -c < 'rplay-3.1.0/TODO'`"
test 609 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/TODO: original size 609, current size' "$Wc_c"
fi
# ============= rplay-3.1.0/ANNOUNCE ==============
if test -f 'rplay-3.1.0/ANNOUNCE' -a X"$1" != X"-c"; then
	echo 'x - skipping rplay-3.1.0/ANNOUNCE (File already exists)'
else
echo 'x - extracting rplay-3.1.0/ANNOUNCE (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'rplay-3.1.0/ANNOUNCE' &&
X
I am pleased to announce the release of rplay 3.1.0.  This release can be
obtained via anonymous ftp at sounds.sdsu.edu (130.191.224.8) in 
/pub/rplay/rplay-3.1.0.tar.Z and /pub/rplay/rplay-3.1.0.tar.gz.
If you do not have access to anonymous ftp I can mail rplay to you.
X
This version is known to work on SunOS 4.1.x, Solaris 2.x, HP-UX, Linux,
386bsd, BSDI/386, and SGI Indigo.
X
The README file is included below if you want to find out more about rplay.
X
Enjoy.
X
Mark Boyns
boyns@sdsu.edu
X
SHAR_EOF
chmod 0644 rplay-3.1.0/ANNOUNCE ||
echo 'restore of rplay-3.1.0/ANNOUNCE failed'
Wc_c="`wc -c < 'rplay-3.1.0/ANNOUNCE'`"
test 494 -eq "$Wc_c" ||
	echo 'rplay-3.1.0/ANNOUNCE: original size 494, current size' "$Wc_c"
fi
exit 0
