aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilliam Harrington <kb0iic@berzerkula.org>2025-01-14 16:06:02 -0600
committerWilliam Harrington <kb0iic@berzerkula.org>2025-01-14 16:06:02 -0600
commit0cc9b20c15460213e488bf5e70963b941482f628 (patch)
treebb0143245583ec846630f39bfa2258dba640ccd7
parent0e084ade5069756d487b5c948c48b777e37c00c9 (diff)
Add source.
-rw-r--r--CHANGES107
-rw-r--r--LICENSE36
-rw-r--r--Makefile.in75
-rw-r--r--README.FIRST65
-rw-r--r--TODO25
-rwxr-xr-xconfig175
-rw-r--r--config.diag5
-rw-r--r--config.dist12
-rw-r--r--config.pkg9
-rw-r--r--html/README4
-rw-r--r--html/index.html10
-rwxr-xr-xhtml/toc.html35
-rwxr-xr-xsdk/bin/clean22
-rwxr-xr-xsdk/bin/config175
-rwxr-xr-xsdk/bin/config.sub38
-rwxr-xr-xsdk/bin/diag171
-rwxr-xr-xsdk/bin/dist63
-rwxr-xr-xsdk/bin/disthtml31
-rwxr-xr-xsdk/bin/install.bind55
-rwxr-xr-xsdk/bin/install.help12
-rwxr-xr-xsdk/bin/install.make112
-rwxr-xr-xsdk/bin/instinit61
-rwxr-xr-xsdk/bin/instman32
-rwxr-xr-xsdk/bin/instso39
-rwxr-xr-xsdk/bin/instsvc27
-rwxr-xr-xsdk/bin/rootsudo6
-rw-r--r--sdk/config.h16
-rw-r--r--sdk/dev/Makefile.in19
-rw-r--r--sdk/dev/bind.conf0
-rw-r--r--sdk/dev/empty.c15
-rw-r--r--sdk/dev/flowctrl.c47
-rw-r--r--sdk/dev/format.c64
-rw-r--r--sdk/dev/inkey.c76
-rw-r--r--sdk/dev/input.c34
-rw-r--r--sdk/dev/interactive.c35
-rw-r--r--sdk/dev/make.conf5
-rw-r--r--sdk/dev/speed.c75
-rw-r--r--sdk/dev/stty.c29
-rw-r--r--sdk/dev/termcap.h17
-rw-r--r--sdk/dev/tty.h72
-rw-r--r--sdk/dev/waitfor.c39
-rw-r--r--sdk/dev/waitsync.c32
-rw-r--r--sdk/dev/xmit.c31
-rw-r--r--sdk/net/Makefile.in19
-rw-r--r--sdk/net/bind.conf0
-rw-r--r--sdk/net/gethost.c39
-rw-r--r--sdk/net/getservice.c45
-rw-r--r--sdk/net/getsocket.c43
-rw-r--r--sdk/net/init.c20
-rw-r--r--sdk/net/make.conf4
-rw-r--r--sdk/net/msgport.c84
-rw-r--r--sdk/net/msgport.h47
-rw-r--r--sdk/net/netaddr.c28
-rw-r--r--sdk/net/snmptrap.c165
-rw-r--r--sdk/net/socket.h61
-rw-r--r--sdk/net/sockname.c62
-rw-r--r--sdk/net/stream.h45
-rw-r--r--sdk/net/tcpsocket.c42
-rw-r--r--sdk/net/tcpstream.c88
-rw-r--r--sdk/net/trap.h30
-rw-r--r--sdk/net/udpsocket.c36
-rw-r--r--sdk/other/Makefile.in22
-rw-r--r--sdk/other/atob.c47
-rw-r--r--sdk/other/bcd.c125
-rw-r--r--sdk/other/bind.conf1
-rw-r--r--sdk/other/ccount.c45
-rw-r--r--sdk/other/confdir.c105
-rw-r--r--sdk/other/config.c437
-rw-r--r--sdk/other/config.h67
-rw-r--r--sdk/other/env.c36
-rw-r--r--sdk/other/env.h31
-rw-r--r--sdk/other/expand.c36
-rw-r--r--sdk/other/fatal.c23
-rw-r--r--sdk/other/filename.c74
-rw-r--r--sdk/other/files.h52
-rw-r--r--sdk/other/fncat.c30
-rw-r--r--sdk/other/getargv.c57
-rw-r--r--sdk/other/hex.c44
-rw-r--r--sdk/other/isftype.c22
-rw-r--r--sdk/other/make.conf2
-rw-r--r--sdk/other/memalloc.c35
-rw-r--r--sdk/other/memdup.c22
-rw-r--r--sdk/other/memfree.c38
-rw-r--r--sdk/other/memory.h103
-rw-r--r--sdk/other/mempool.c49
-rw-r--r--sdk/other/memrelease.c43
-rw-r--r--sdk/other/memreq.c59
-rw-r--r--sdk/other/picture.c112
-rw-r--r--sdk/other/search.c46
-rw-r--r--sdk/other/strblank.c24
-rw-r--r--sdk/other/strcopy.c61
-rw-r--r--sdk/other/strcvt.h56
-rw-r--r--sdk/other/strdiff.c24
-rw-r--r--sdk/other/string.h65
-rw-r--r--sdk/other/strint.c51
-rw-r--r--sdk/other/strpos.c46
-rw-r--r--sdk/other/strreq.c39
-rw-r--r--sdk/other/strtrim.c45
-rw-r--r--sdk/other/token.c50
-rw-r--r--sdk/other/xval.c28
-rw-r--r--sdk/proc/Makefile.in18
-rw-r--r--sdk/proc/bind.conf1
-rw-r--r--sdk/proc/make.conf5
-rw-r--r--sdk/proc/pdetach.c78
-rw-r--r--sdk/proc/priority.c73
-rw-r--r--sdk/proc/process.h57
-rw-r--r--sdk/proc/spawn.c92
-rw-r--r--sdk/std/Makefile.in18
-rw-r--r--sdk/std/bind.conf69
-rw-r--r--sdk/std/files.h47
-rw-r--r--sdk/std/help.conf4
-rw-r--r--sdk/std/limits.h97
-rw-r--r--sdk/std/make.conf102
-rw-r--r--sdk/std/math.h31
-rw-r--r--sdk/std/poll.h21
-rw-r--r--sdk/std/posix1_lim.h92
-rw-r--r--sdk/std/process.h99
-rw-r--r--sdk/std/select.h21
-rw-r--r--sdk/std/signal.h11
-rw-r--r--sdk/std/string.c110
-rw-r--r--sdk/std/string.h75
-rw-r--r--sdk/std/sysexits.h118
-rw-r--r--sdk/std/time.h23
-rw-r--r--sdk/std/types.h54
-rw-r--r--sdk/std/utmp.c49
-rw-r--r--sdk/std/utmp.h31
-rw-r--r--speak.lsm23
-rw-r--r--spktrapd/README.NOW8
-rw-r--r--spo256/Makefile.in34
-rw-r--r--spo256/README24
-rw-r--r--spo256/chars.c339
-rw-r--r--spo256/client.c40
-rw-r--r--spo256/currency.c43
-rw-r--r--spo256/getidx.c98
-rw-r--r--spo256/getspo.c68
-rw-r--r--spo256/number.c132
-rw-r--r--spo256/speak.146
-rw-r--r--spo256/speak.839
-rw-r--r--spo256/speak.c86
-rw-r--r--spo256/speak.conf.772
-rw-r--r--spo256/speak.h48
-rw-r--r--spo256/speak.init54
-rw-r--r--spo256/spo.c161
-rw-r--r--spo256/spo256.898
-rw-r--r--spo256/word.c38
-rw-r--r--spo256/words.c34
-rw-r--r--utils/Makefile.in31
-rw-r--r--utils/README9
-rw-r--r--utils/down.844
-rw-r--r--utils/down.c129
-rw-r--r--utils/say.135
-rw-r--r--utils/say.c34
-rw-r--r--utils/vmon.865
-rw-r--r--utils/vmon.c442
154 files changed, 8788 insertions, 0 deletions
diff --git a/CHANGES b/CHANGES
new file mode 100644
index 0000000..7a6638a
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,107 @@
+0.2 Initial Release 1/13/97
+
+ Includes spo256-al2 server. Maintained by David Sugar
+ <dyfet@tycho.com>.
+
+0.2pl1 Patch Update 1/16/97
+
+ Updated build/dist and added config.dist. This should make for
+ better control of distribution sets off a live production system.
+ This also solves 'second level' production problems off a
+ distribution set.
+
+ Updated build/instinit to allow automatic linkage of the speak.init
+ service script to a free 'S' slot in rc3.d. Instinit is now smarter
+ about how it handles startup script installation, especially for
+ Linux. Care with speak.init should still be taken for non-Linux
+ systems.
+
+ Replaced missing config.c in sdk/std.
+
+ Fixed vstat bug where it would fall-through into vmon code.
+
+ Updated vmon to use more portable utent() routines instead of
+ directly accessing the utmp file. This was to improve portability.
+
+ Updated vmon to use utmp routines to determine uptime if
+ /proc/uptime does not exist. This should help with porting
+ to non-Linux systems, or with Linux systems when 'proc' is
+ not installed.
+
+ Made statfs() dependent code conditional, and active only
+ for linux, to prevent problems when compiling on non-Linux
+ operating systems. Code will need to be added to drive
+ external "df" image if no statfs() service is supported.
+
+0.2pl2 Patch Update 1/27/97
+
+ Found problem in tcpsocket.c, which would not compile correctly
+ on some sites.
+
+ Added diag build script "Make diag" target to re-mail system
+ diagnostic reports.
+
+ Added "config.diag" for "Make diag".
+
+0.3 Second Release 2/14/97
+
+ Changed sdk 'dev' stty support to improve stty setup operations.
+ This involved minor code changes to getspo.c.
+
+ Changed sdk 'net' binding code to standardize handling of network
+ addresses passed as strings using getnetaddr().
+
+ The [interface] bind = option may now be used to restrict the
+ speak port to a specific subnet interface address. This
+ should keep the rest of the internet out of speak ports!
+
+ Changed spo256 server to use a "character-state" parser in place
+ of the prior simplified token scanning routines. This is closer
+ to the original WorldVU server, and is implimented much more
+ cleanly.
+
+ The server now also recognizes special "server" specific commands
+ that may be embedded in the output stream. These server commands
+ are prefixed with an <ESC> and appear inside <>'s. Server
+ commands allow some direct interaction with the server, such as
+ being able to force specific pronouniation rules. More advanced
+ devices (beyond the SPO) may someday make use of server commands
+ to force change of tone, inflection, or volume.
+
+ The [vmon] settings in speak.conf have changes to support control
+ of timer intervals for monitoring system status. The new interval
+ option is meant for when we add mailbox and user login tracking.
+ This controls the interval for such short duration events, in
+ minutes. The 'frequency' option indicates how many times per
+ hour you want vmon to announce. Once is usually quite enough.
+ If you are upgrading, you will want to check the speak.conf
+ file in the distribution.
+
+ Vmon can now watch for and notify when new mail arrives in
+ specified user accounts. This behavior is controlled with
+ the new [vmon] entries in speak.conf for 'maildir=' and
+ 'mailbox='. Maildir should point the mail spool directory
+ (typically /var/spool/mail) and one or more mailbox lines
+ can be used to list those user accounts you want to have
+ verbal mail notification for.
+
+1.0
+
+ The entire build and sdk process has been redone and unified for
+ improved portability. No functional changes have been made in the
+ application. The major difference, initially, is that, instead of
+ performing a "make config", one now executes ./config to start the
+ build process going for the package.
+
+ We have also standardized 'config' around a hybrid file structure
+ that is fully consistent with the Linux file naming standard, can
+ comply with BSD file layouts, is compatible with most UNIX's,
+ and automatically recognizes secure TSW "Linux" release 1 and gnu/
+ glib 2.x introduced file naming and ownership conventions.
+ Support for TSW-LR1 html documentation and software package
+ redistribution conventions are implied in the new 'config'. This
+ release will be available in source and binary rpm format for any
+ rpm managed Linux system.
+
+
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..61dbe05
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,36 @@
+Copyright (c) 1997 Tycho Softworks. All rights reserved.
+
+This source is made freely available for public use, and may be
+redistributed in source and/or binary forms, with or without
+modification, provided that the following conditions are met:
+
+1. Redistributions of modified source code must retain all
+ original copyright notices when present.
+
+2. Redistributions of modified source code or binary archives
+ must include this license agreement unmodified.
+
+3. Neither the name of Tycho Softworks nor the names of it's
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+4. Where Berkeley (BSD) licensed source or header files may be used
+ within this distribution, such use is hereby acknowledged and
+ subject to the original terms and conditions as specified in
+ the comments of said specific source files.
+
+THIS SOFTWARE IS PROVIDED BY THE TYCHO SOFTWORKS ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TYCHO SOFTWORKS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+Any comments or questions in regards to this license or that arise
+from it's use may be addressed to "dyfet@tycho.com".
+
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 0000000..55dfe1b
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,75 @@
+#
+# Top level project Makefile for "speak".
+# $ProjectHeader: speak 0.4 Mon, 24 Mar 1997 12:25:37 -0500 dyfet $
+# Copyright (c) 1997 by Tycho Softworks.
+#
+# Targets:
+# [none] default as 'make all'
+# [all] create config if missing, then build all
+# [install] build and install spo server and utils
+# [dist] create distribution archive
+# [web] build online (web) published distribution
+# [clean] clean up a build
+# [config] build initial configuration
+# [reconfig] rebuild changed configuration
+# [diag] send diagnostic e-mail
+# [get] and [put] replicate source tree
+
+# Insert any default configuration values in CONFIGURE.
+
+CONFIGURE=
+
+# Internal use for source tree replication
+
+SOURCES = /mnt/share/source/shared/speak
+EXCLUDE = --exclude Makefile --exclude config.cache
+RSYNC = rsync -auSC $(EXCLUDE)
+
+all: config
+ @cd sdk/std ; make
+ @cd sdk/dev ; make
+ @cd sdk/net ; make
+ @cd sdk/other ; make
+ @cd sdk/proc ; make
+ @cd spo256 ; make
+ @cd utils ; make
+
+get:
+ $(RSYNC) $(SOURCES)/* .
+ ./config
+
+put:
+ $(RSYNC) * $(SOURCES)
+
+install:
+ @cd spo256 ; make install
+ @cd utils ; make install
+
+dist:
+ @cp -f /etc/speak.conf spo256
+ @sdk/bin/dist $(DISTDIR)
+
+web:
+ @sdk/bin/disthtml $(HTMLDIR) $(MANDIR)
+
+clean:
+ @cd sdk/std ; make clean
+ @cd sdk/net ; make clean
+ @cd sdk/dev ; make clean
+ @cd sdk/other ; make clean
+ @cd sdk/proc ; make clean
+ @cd spo256 ; make clean
+ @cd utils ; make clean
+ @build/clean
+
+config:
+ @echo "Creating Speak Project Configuration ---"
+ @sdk/bin/config
+
+reconfig:
+ -@rm config.cache
+ @sdk/bin/config
+
+diag:
+ @sdk/bin/diag | mail -s "Speak Diagnostic Report" dyfet@tycho.com
+
diff --git a/README.FIRST b/README.FIRST
new file mode 100644
index 0000000..37403ab
--- /dev/null
+++ b/README.FIRST
@@ -0,0 +1,65 @@
+SPO256-AL2 based Text-to-Speech Network Services Version 0.2
+
+This package comprises a new stand-alone release of the standard 'text to
+speech' interface service and tools as first covered in the SPO article
+appearing in Linux Journal, January 1997. Generic support for using the
+SPO256-AL2 based board, and potentially other alternate network accessible
+text-to-speech resources, is now more cleanly supported in a portable manner
+that should allow use under virtually any UNIX'oid OS. This release
+supersedes the initial WorldVU based source release originally described
+in Linux Journal.
+
+This new release includes a new and portable SPO256 text-to-speech server,
+some glue scripts for init.d in Linux to use the SPO as a normal system
+'service', and many of the standard utilities re-written in a more
+generic form. The new server should do a better job of parsing textual
+documents into natural sounding speech as new rules for handling common
+abbreviations and to improve word pacing have been added.
+
+The source for the SPO256-AL2 server is now more modular and more fully
+documented. The utilities now include standard man pages. The server
+now supports alternate forms of operation for use in client scripts.
+
+If you do not have the Linux Journal article in question, the SPO256 is
+essentially a serial based text-to-speech board of limited utility. The
+SPO256-AL2 (Vocoder) chip was originally used in many products, including
+the Matel speak-and-spell(tm) toy, and offers limited text-to-speech
+translation services. The SPO256 server augments the limited translation
+capabilities of the SPO256 chipset and offers a network accessible resource
+for text-to-speech notifications, such as system alerts, user logins, etc.
+
+This new server assumes a standard TCP 'service' has been defined in
+/etc/services. You should edit the /etc/services file to include an entry
+like the following (though a different port number may be used):
+
+speak 800/tcp # SPO256 text-to-speech network resource
+
+You will also need to copy speak.conf to /etc and modify it as needed.
+
+While the SPO256-AL2 is the primary hardware interface supported in this
+package, other alternate text-to-speech devices may be added later that
+will also use the "speak" port service. In particular, a re-implementation
+of rsynth is being considered. Since the utilities talk to a standard
+tcp port interface, they remain unchanged regardless of the underlying
+hardware used to produce text-to-speech output.
+
+To build the software package, first run ./config. Config will genorate
+the Makefiles. Config will then start 'make'. The configuration system
+will attempt to identify the OS it is running under, compiler options, etc.
+This may work under most UNIX operating systems, so the SPO package should
+not be assumed to be a Linux-only utility. Once make completes successfully,
+perform a 'make install'. This will update the /etc/services file and install
+the application binaries. If you have difficulty with the new source
+configuration tool, please review build/config.doc.
+
+Please examine the speak.conf and speak.init files, and relocate them as
+needed. Further documentation may be found within the supplied man pages.
+Comments may be addressed to David Sugar <dyfet@tycho.com>. The SPO256-
+AL2 Text-to-Speech board ("Computalker") may be ordered through B&G Micro,
+P.O. Box 280298, Dallas, TX 75228 (214) 271-5546. Linux Journal may be
+found http://www.ssc.com/lj.
+
+
+
+
+
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..5fba52f
--- /dev/null
+++ b/TODO
@@ -0,0 +1,25 @@
+Many things...
+
+* Build a "rsynth" based server. Change primary 'make' to request
+ server type, as in 'make rsynth', 'make spo256', or 'make utils',
+ the latter to build utilities only on a machine without it's own
+ server.
+
+* Add support for retrieving "index" status and time-sync rondeveus
+ by supporting a "inquire" sequence for the server to respond to.
+ Time-sync would be with "<drain>" server tag, which would force
+ the server to 'tcdrain' the port and then return a response. The
+ "<index>" tag would retrieve an index. Other 'tag' options for
+ volume control, pitch, inflection, etc, may also need to be added
+ for rsynth, although the SPO does not support these features.
+
+* Build spksnmpd for rule based verbalization of specific snmp trap
+ events.
+
+* Add user login monitoring to vmon.
+
+* Add external "df" code to vmon for systems that have no statfs()
+ call.
+
+* Build rpm package for speak.
+
diff --git a/config b/config
new file mode 100755
index 0000000..a701bc8
--- /dev/null
+++ b/config
@@ -0,0 +1,175 @@
+#!/bin/sh
+
+#
+# Reload defaults
+#
+
+BUILD=sdk
+CONFIG=sdk/config.h
+
+if test -f config.cache ; then
+ . ./config.cache
+fi
+echo -n >config.cache
+
+if test -f config.pkg ; then
+ . ./config.pkg
+fi
+
+#
+# Load bindings
+#
+
+if test -f config.pkg ; then
+ . ./config.pkg
+fi
+
+if test -f config.make ; then
+ echo -n >config.make
+fi
+
+if test -f $CONFIG ; then
+ echo -n >$CONFIG
+fi
+
+if test -f $BUILD/bin/config.sub ; then
+ . $BUILD/bin/config.sub
+fi
+
+BIND_OPTS='host'
+
+if test -z "$CONFIG_HOST" ; then
+ if test -d /usr/local/include ; then
+ CONFIG_HOST=/usr/local
+ fi
+ if test -d /usr/include ; then
+ CONFIG_HOST=/usr
+ fi
+fi
+
+opt_host() {
+ CONFIG_HOST="$1"
+ return 0
+}
+
+if test ! -z "$BIND" ; then
+ for bind in $BIND ; do
+ if test -d $BUILD/$bind ; then
+ . $BUILD/$bind/bind.conf
+ else
+ . $BUILD/bin/$bind.bind
+ fi
+ done
+fi
+
+#
+# Parse command line arguments.
+#
+err=''
+
+if test ! -z "$CONFIG_FLAGS" ; then
+ for arg in $CONFIG_FLAGS ; do
+ for opt in $BIND_OPTS ; do
+ case "$arg" in
+ $opt=* | -$opt=* | --$opt=* )
+ opt_$opt `echo "$arg" | sed 's/[-_a-zA-Z0-9]*=//'`
+ break
+ ;;
+ esac
+ done
+ done
+fi
+
+
+if test ! -z "$*" ; then
+ for arg in $* ; do
+ err=$arg
+ for opt in $BIND_OPTS ; do
+ case "$arg" in
+ $opt=* | -$opt=* | --$opt=* )
+ opt_$opt `echo "$arg" | sed 's/[-_a-zA-Z0-9]*=//'`
+ err=''
+ break
+ ;;
+ esac
+ done
+ if test ! -z "$err" ; then
+ break
+ fi
+ done
+fi
+
+CONFIG_FLAGS=''
+
+if test ! -z "$err" ; then
+ echo "config: $err: invalid option."
+ echo
+ echo "Valid Options:"
+ echo -n >config.help
+ if test ! -z "$BIND" ; then
+ for use in $BIND ; do
+ if test -f $BUILD/$use/help.conf ; then
+ cat $BUILD/$use/help.conf >>config.help
+ fi
+ if test -f $BUILD/bin/$use.help ; then
+ cat $BUILD/bin/$use.help >>config.help
+ fi
+ done
+ sort <config.help
+ rm -f config.help
+ fi
+ exit -1
+fi
+
+echo "#ifndef __CONFIG_H__" >>$CONFIG
+echo "#define __CONFIG_H__" >>$CONFIG
+
+CONFIG_LIBS=""
+
+if test ! -z "$BIND" ; then
+ for bind in $BIND ; do
+ if test -d $BUILD/$bind ; then
+ . $BUILD/$bind/make.conf
+ CONFIG_LIBS='-l'$bind' '"$CONFIG_LIBS"
+ MAKEFILES="$MAKEFILES"' '$BUILD/$bind/Makefile
+ else
+ . $BUILD/bin/$bind.make
+ fi
+ done
+fi
+
+if test ! -z "$CONFIG_LIBS" ; then
+ echo "LIBS=$CONFIG_LIBS" >>config.make
+fi
+
+if test ! -z "$MAKEFILES" ; then
+ for makefile in $MAKEFILES ; do
+ cat config.make >$makefile
+ cat $makefile.in >>$makefile
+ done
+fi
+
+echo "#endif" >>$CONFIG
+
+
+if test -z "$CONFIG_CACHE" ; then
+ CONFIG_CACHE='config.cache'
+ CONFIG_FLAGS=''
+else
+ CONFIG_FIRST=''
+fi
+
+echo "CONFIG_CACHE="$CONFIG_CACHE >>config.cache
+
+if test -f conftest.c ; then
+ rm -f conftest.c
+fi
+
+if test -f conftest.o ; then
+ rm conftest.o
+fi
+
+if test ! -z "$CONFIG_FIRST" ; then
+ $CONFIG_FIRST
+fi
+
diff --git a/config.diag b/config.diag
new file mode 100644
index 0000000..15a36f3
--- /dev/null
+++ b/config.diag
@@ -0,0 +1,5 @@
+# Gather startup services info
+
+startup='yes'
+files='/etc/rc.d/rc.serial'
+
diff --git a/config.dist b/config.dist
new file mode 100644
index 0000000..2ec39c8
--- /dev/null
+++ b/config.dist
@@ -0,0 +1,12 @@
+version="1.0"
+package="speak"
+examine="utils sdk spo256 spktrapd html"
+config="config.pkg config.dist config.diag config sdk/bin/*"
+include="Makefile.in README.FIRST CHANGES TODO LICENSE speak.lsm"
+
+manpages="down.8 say.1 speak.1 speak.conf.7 spo256.8 vmon.8"
+txtpages="CHANGES LICENSE README.FIRST TARGETS TODO"
+lsmpages="speak.lsm"
+htmlpages="index.html toc.html"
+htmlhome=packages/speak
+
diff --git a/config.pkg b/config.pkg
new file mode 100644
index 0000000..9c7aa53
--- /dev/null
+++ b/config.pkg
@@ -0,0 +1,9 @@
+#
+# Denote package bindings
+#
+BIND='install std proc other net dev'
+MAKEFILES='Makefile spo256/Makefile utils/Makefile'
+CONFIG_FLAGS=$CONFIG_FLAGS
+CONFIG_FIRST='make'
+CONFIG_INSTALL='make install'
+
diff --git a/html/README b/html/README
new file mode 100644
index 0000000..5a4f414
--- /dev/null
+++ b/html/README
@@ -0,0 +1,4 @@
+This directory holds html templates used as part of make 'web' when
+building a html redistribution directory. Otherwise, this directory may
+be ignored.
+
diff --git a/html/index.html b/html/index.html
new file mode 100644
index 0000000..ad54365
--- /dev/null
+++ b/html/index.html
@@ -0,0 +1,10 @@
+<html>
+<head>
+<title>UNIX Speak Server 0.2pl2</title>
+</head>
+
+<frameset COLS="27%,73%">
+<frame SRC="toc.html" NAME="contents">
+<frame SRC="speak.lsm.html" NAME="main">
+</frameset>
+</html>
diff --git a/html/toc.html b/html/toc.html
new file mode 100755
index 0000000..429ec78
--- /dev/null
+++ b/html/toc.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+
+<html>
+
+<head>
+<title>TOC</title>
+<meta name="GENERATOR" content="Microsoft FrontPage 1.1">
+<base target="main">
+</head>
+
+<body>
+<p><font size=4><em><strong>General</strong></em></font></p>
+<dir>
+<li><a href="speak.lsm.html" target="main"><em>About</em></a></li>
+<li><a href="CHANGES.txt" target="main"><em>Changes</em></a></li>
+<li><a href="ftp://ftp.tycho.com/dist/speak-1.0.tar.gz" target="main"><em>Download</em></a></li>
+<li><a href="mailto:dyfet@tycho.com" target="main"><em>Feedback</em></a></li>
+<li><a href="LICENSE.txt" target="main"><em>License</em></a></li>
+<li><a href="README.FIRST.txt" target="main"><em>Readme</em></a></li>
+<li><a href="TARGETS.txt" target="main"><em>Targets</em></a></li>
+<li><a href="TODO.txt" target="main"><em>Todo</em></a></li>
+</dir>
+<p><font size=4><em><strong>Manpages</strong></em></font></p>
+<dir>
+<li><a href="down.html" target="main"><em>down.8</em></a></li>
+<li><a href="say.html" target="main"><em>say.1</em></a></li>
+<li><a href="speak.html" target="main"><em>speak.1</em></a></li>
+<li><a href="speak.conf.html" target="main"><em>speak.conf.7</em></a></li>
+<li><a href="spo256.html" target="main"><em>spo256.8</em></a></li>
+<li><a href="vmon.html" target="main"><em>vmon.8</em></a></li>
+</dir>
+<p>&#160;</p>
+</body>
+
+</html>
diff --git a/sdk/bin/clean b/sdk/bin/clean
new file mode 100755
index 0000000..2667461
--- /dev/null
+++ b/sdk/bin/clean
@@ -0,0 +1,22 @@
+#!/bin/sh
+flist=`find . -name core -follow -print`
+if [ ! -z "$flist" ] ; then
+ rm $flist
+fi
+
+flist=`find . -name "*~" -follow -print`
+if [ ! -z "$flist" ] ; then
+ rm $flist
+fi
+
+flist=`find . -name "*.tar.gz" -follow -print`
+if [ ! -z "$flist" ] ; then
+ rm $flist
+fi
+
+flist=`find . -name "config.c*" -follow -print`
+if [ ! -z "$flist" ] ; then
+ rm $flist
+fi
+
+
diff --git a/sdk/bin/config b/sdk/bin/config
new file mode 100755
index 0000000..a701bc8
--- /dev/null
+++ b/sdk/bin/config
@@ -0,0 +1,175 @@
+#!/bin/sh
+
+#
+# Reload defaults
+#
+
+BUILD=sdk
+CONFIG=sdk/config.h
+
+if test -f config.cache ; then
+ . ./config.cache
+fi
+echo -n >config.cache
+
+if test -f config.pkg ; then
+ . ./config.pkg
+fi
+
+#
+# Load bindings
+#
+
+if test -f config.pkg ; then
+ . ./config.pkg
+fi
+
+if test -f config.make ; then
+ echo -n >config.make
+fi
+
+if test -f $CONFIG ; then
+ echo -n >$CONFIG
+fi
+
+if test -f $BUILD/bin/config.sub ; then
+ . $BUILD/bin/config.sub
+fi
+
+BIND_OPTS='host'
+
+if test -z "$CONFIG_HOST" ; then
+ if test -d /usr/local/include ; then
+ CONFIG_HOST=/usr/local
+ fi
+ if test -d /usr/include ; then
+ CONFIG_HOST=/usr
+ fi
+fi
+
+opt_host() {
+ CONFIG_HOST="$1"
+ return 0
+}
+
+if test ! -z "$BIND" ; then
+ for bind in $BIND ; do
+ if test -d $BUILD/$bind ; then
+ . $BUILD/$bind/bind.conf
+ else
+ . $BUILD/bin/$bind.bind
+ fi
+ done
+fi
+
+#
+# Parse command line arguments.
+#
+err=''
+
+if test ! -z "$CONFIG_FLAGS" ; then
+ for arg in $CONFIG_FLAGS ; do
+ for opt in $BIND_OPTS ; do
+ case "$arg" in
+ $opt=* | -$opt=* | --$opt=* )
+ opt_$opt `echo "$arg" | sed 's/[-_a-zA-Z0-9]*=//'`
+ break
+ ;;
+ esac
+ done
+ done
+fi
+
+
+if test ! -z "$*" ; then
+ for arg in $* ; do
+ err=$arg
+ for opt in $BIND_OPTS ; do
+ case "$arg" in
+ $opt=* | -$opt=* | --$opt=* )
+ opt_$opt `echo "$arg" | sed 's/[-_a-zA-Z0-9]*=//'`
+ err=''
+ break
+ ;;
+ esac
+ done
+ if test ! -z "$err" ; then
+ break
+ fi
+ done
+fi
+
+CONFIG_FLAGS=''
+
+if test ! -z "$err" ; then
+ echo "config: $err: invalid option."
+ echo
+ echo "Valid Options:"
+ echo -n >config.help
+ if test ! -z "$BIND" ; then
+ for use in $BIND ; do
+ if test -f $BUILD/$use/help.conf ; then
+ cat $BUILD/$use/help.conf >>config.help
+ fi
+ if test -f $BUILD/bin/$use.help ; then
+ cat $BUILD/bin/$use.help >>config.help
+ fi
+ done
+ sort <config.help
+ rm -f config.help
+ fi
+ exit -1
+fi
+
+echo "#ifndef __CONFIG_H__" >>$CONFIG
+echo "#define __CONFIG_H__" >>$CONFIG
+
+CONFIG_LIBS=""
+
+if test ! -z "$BIND" ; then
+ for bind in $BIND ; do
+ if test -d $BUILD/$bind ; then
+ . $BUILD/$bind/make.conf
+ CONFIG_LIBS='-l'$bind' '"$CONFIG_LIBS"
+ MAKEFILES="$MAKEFILES"' '$BUILD/$bind/Makefile
+ else
+ . $BUILD/bin/$bind.make
+ fi
+ done
+fi
+
+if test ! -z "$CONFIG_LIBS" ; then
+ echo "LIBS=$CONFIG_LIBS" >>config.make
+fi
+
+if test ! -z "$MAKEFILES" ; then
+ for makefile in $MAKEFILES ; do
+ cat config.make >$makefile
+ cat $makefile.in >>$makefile
+ done
+fi
+
+echo "#endif" >>$CONFIG
+
+
+if test -z "$CONFIG_CACHE" ; then
+ CONFIG_CACHE='config.cache'
+ CONFIG_FLAGS=''
+else
+ CONFIG_FIRST=''
+fi
+
+echo "CONFIG_CACHE="$CONFIG_CACHE >>config.cache
+
+if test -f conftest.c ; then
+ rm -f conftest.c
+fi
+
+if test -f conftest.o ; then
+ rm conftest.o
+fi
+
+if test ! -z "$CONFIG_FIRST" ; then
+ $CONFIG_FIRST
+fi
+
diff --git a/sdk/bin/config.sub b/sdk/bin/config.sub
new file mode 100755
index 0000000..81a7488
--- /dev/null
+++ b/sdk/bin/config.sub
@@ -0,0 +1,38 @@
+fn_find_fpath() {
+ save_ifs="$IFS"
+ IFS="${IFS}:"
+ for dir in $3 ; do
+ if test $1 $dir/$2 ; then
+ IFS="$save_ifs"
+ return 0
+ fi
+ done
+ IFS="$save_ifs"
+ return 1
+}
+
+fn_find_type() {
+ fail=$1
+ shift
+ text=$1
+ shift
+ for fn in $* ; do
+ if test -f "$fn" ; then
+ grep "$text" <$fn >/dev/null
+ if test ! $? = 1 ; then
+ return 1
+ fi
+ fi
+ done
+ echo "#define "$fail >>$CONFIG
+ return 0
+}
+
+fn_find_file() {
+ if test ! -f $2 ; then
+ echo "#define "$1 >>$CONFIG
+ return 1
+ fi
+ return 0
+}
+
diff --git a/sdk/bin/diag b/sdk/bin/diag
new file mode 100755
index 0000000..aa56844
--- /dev/null
+++ b/sdk/bin/diag
@@ -0,0 +1,171 @@
+#!/bin/sh
+
+files=''
+ldd='no'
+gcc='no'
+hardware='no'
+startup='no'
+drivers='no'
+symbols='no'
+tracer=''
+
+if [ -f /usr/bin/strace ] ; then
+ tracer='strace'
+fi
+
+if [ -f /bin/strace ] ; then
+ tracer='strace'
+fi
+
+if [ -f /sbin/strace ] ; then
+ tracer='strace'
+fi
+
+if [ -f /bin/ldd ] ; then
+ ldd='yes'
+fi
+
+if [ -f /usr/bin/ldd ] ; then
+ ldd='yes'
+fi
+
+if [ -f /usr/bin/gcc ] ; then
+ gcc='yes'
+fi
+
+if [ -f /usr/local/bin/gcc ] ; then
+ gcc='yes'
+fi
+
+if [ -f config.diag ] ; then
+ . ./config.diag
+fi
+
+if [ ! -z "$title" ] ; then
+ echo $title
+fi
+
+if [ ! -z "$strace" ] ; then
+ for trace in $strace ; do
+ echo
+ ls -l $trace
+ if [ $ldd = 'yes' ] ; then
+ echo
+ echo "Library map for " $trace
+ ldd $trace
+ fi
+ if [ $symbols = 'yes' ] ; then
+ echo
+ nm $trace
+ fi
+ if [ ! -z "$tracer" ] ; then
+ echo
+ $tracer $opts $trace 2>&1
+ fi
+ done
+fi
+
+echo
+echo -n "System Type: "
+uname -s
+
+echo -n "Achitecture: "
+uname -m
+
+echo -n "Release: "
+uname -r
+
+if [ $gcc = 'yes' ] ; then
+ echo
+ echo "GCC Information:"
+ gcc -v 2>&1
+fi
+
+if [ -f /proc/meminfo ] ; then
+ echo
+ echo "Memory:"
+ cat /proc/meminfo
+fi
+
+echo ""
+echo "Disks:"
+df
+
+if [ $startup = 'yes' ] ; then
+
+ if [ -d /etc/rc.d ] ; then
+ echo
+ echo "Services:"
+ ls -l /etc/rc.d
+ if [ -d /etc/rc.d/rc3.d ] ; then
+ echo
+ echo "Startup:"
+ ls /etc/rc.d/rc3.d
+ fi
+ fi
+fi
+
+if [ -f config.cache ] ; then
+ echo
+ echo "Configuration:"
+ cat config.cache
+fi
+
+if [ -f config.cc ] ; then
+ echo
+ echo "Compiler:"
+ cat config.cc
+fi
+
+if [ ! -z "$files" ] ; then
+ for file in $files ; do
+ if [ -f $file ] ; then
+ echo
+ echo "Found: " $file
+ echo
+ cat $file
+ fi
+ done
+fi
+
+if [ $drivers = 'yes' ] ; then
+
+ if [ -f /proc/modules ] ; then
+ echo
+ echo "Modules:"
+ cat /proc/modules
+ fi
+fi
+
+if [ $hardware = 'yes' ] ; then
+
+ if [ -f /proc/devices ] ; then
+ echo
+ echo "Devices:"
+ cat /proc/devices
+ fi
+
+ if [ -f /proc/ioports ] ; then
+ echo
+ echo "Ports:"
+ cat /proc/ioports
+ fi
+
+ if [ -f /proc/interrupts ] ; then
+ echo
+ echo "Interrupts:"
+ cat /proc/interrupts
+ fi
+
+ if [ -f /proc/dma ] ; then
+ echo
+ echo "DMA:"
+ cat /proc/dma
+ fi
+
+ if [ -f /proc/cpuinfo ] ; then
+ echo
+ cat /proc/cpuinfo
+ fi
+fi
+
diff --git a/sdk/bin/dist b/sdk/bin/dist
new file mode 100755
index 0000000..43c6ef9
--- /dev/null
+++ b/sdk/bin/dist
@@ -0,0 +1,63 @@
+#!/bin/sh
+
+if test ! -f config.dist ; then
+ echo "dist: config.dist missing!"
+fi
+
+# defaults!
+
+distdir=$1
+config="config.dist config.pkg build"
+exclude="*.o *.a config.cc config.cache config *.tar.gz *~ core Makefile"
+exclude_exe="true"
+exclude_files=".EXCLUDE"
+
+. ./config.dist
+
+root=`pwd`
+dist=$package'-'$version
+cd ..
+
+if test ! $dist = $root ; then
+ rm -f $dist
+ ln -s $root $dist
+fi
+
+xlist=$dist/.EXCLUDE
+echo -n >$xlist
+for file in $exclude_files ; do
+ echo $dist/$file >>$xlist
+done
+
+flist=""
+
+for cfg in $include $config ; do
+ flist=$flist' '$dist/$cfg
+done
+
+for dir in $examine ; do
+ flist=$flist' '$dist/$dir
+ if test $exclude_exe = "true" ; then
+ find $dist/$dir -perm +1 -type f -follow -print >>$xlist
+ fi
+ for deny in $exclude ; do
+ find $dist/$dir -follow -name $deny -print >>$xlist
+ done
+done
+
+target=$dist/$dist.tar.gz
+if test -d $distdir ; then
+ rm -f $distdir/${package}*.tar.gz
+ target=$distdir/$dist.tar.gz
+ if test -f $dist/$package'.lsm' ; then
+ cp -f $dist/$package'.lsm' $distdir
+ fi
+fi
+
+tar -X $xlist -cvhzf $target $flist
+
+if [ ! $dist = $root ] ; then
+ rm $dist
+fi
+
+
diff --git a/sdk/bin/disthtml b/sdk/bin/disthtml
new file mode 100755
index 0000000..4caa151
--- /dev/null
+++ b/sdk/bin/disthtml
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+manprefix=$2
+
+if test -f config.dist ; then
+ . ./config.dist
+fi
+
+if test -z $htmlhome ; then
+ htmlhome=$1/$package
+else
+ htmlhome=$1/$htmlhome
+fi
+
+man2html $manprefix $manpages $htmlhome
+
+for lsmpage in $lsmpages ; do
+ echo "Creating $lsmpage.html..."
+ lsm2html $lsmpage >$htmlhome/$lsmpage.html
+done
+
+for txtpage in $txtpages ; do
+ echo "Creating $txtpage.txt"
+ cp $txtpage $htmlhome/$txtpage.txt
+done
+
+for htmlpage in $htmlpages ; do
+ echo "Copying $htmlpage"
+ cp -f html/$htmlpage $htmlhome/$htmlpage
+done
+
diff --git a/sdk/bin/install.bind b/sdk/bin/install.bind
new file mode 100755
index 0000000..1a00236
--- /dev/null
+++ b/sdk/bin/install.bind
@@ -0,0 +1,55 @@
+BIND_OPTS=$BIND_OPTS' prefix eprefix share bindir sbindir confdir mandir infodir libdir slibdir root htmldir distdir'
+
+opt_prefix() {
+ CONFIG_PREFIX="$1"
+}
+
+opt_eprefix() {
+ CONFIG_EPREFIX="$1"
+}
+
+opt_share() {
+ CONFIG_SHARE="$1"
+}
+
+opt_bindir() {
+ CONFIG_BINDIR="$1"
+}
+
+opt_sbindir() {
+ CONFIG_SBINDIR="$1"
+}
+
+opt_confdir() {
+ CONFIG_CONFDIR="$1"
+}
+
+opt_root() {
+ CONFIG_ROOT="$1"
+}
+
+opt_libdir() {
+ CONFIG_LIBDIR="$1"
+}
+
+opt_slibdir() {
+ CONFIG_SLIBDIR="$1"
+}
+
+opt_mandir() {
+ CONFIG_MANDIR="$1"
+}
+
+opt_infodir() {
+ CONFIG_INFODIR="$1"
+}
+
+opt_htmldir() {
+ CONFIG_HTMLDIR="$1"
+}
+
+opt_distdir() {
+ CONFIG_DISTDIR="$1"
+}
+
+
diff --git a/sdk/bin/install.help b/sdk/bin/install.help
new file mode 100755
index 0000000..6907439
--- /dev/null
+++ b/sdk/bin/install.help
@@ -0,0 +1,12 @@
+--root= Installation root offset (NONE)
+--prefix= Default installation prefix (/usr)
+--eprefix= Execution installation prefix (/usr)
+--bindir= Bin directory ($exec-prefix/bin)
+--sbindir= System bin directory ($exec-prefix/sbin)
+--libdir= Library directory ($exec-prefix/lib)
+--slibdir= System library directory ($exec-prefix/lib)
+--confdir= Config file directory (/etc)
+--share= Shared data directory ($prefix/share)
+--mandir= Manual directory ($share/man)
+--infodir= Info file directory ($share/info)
+--htmldir= HTML Documentation ($share/html)
diff --git a/sdk/bin/install.make b/sdk/bin/install.make
new file mode 100755
index 0000000..fc63cc6
--- /dev/null
+++ b/sdk/bin/install.make
@@ -0,0 +1,112 @@
+echo "root="$CONFIG_ROOT >>config.make
+
+if test -z "$CONFIG_PREFIX" ; then
+ echo 'prefix=$(root)'$CONFIG_HOST >>config.make
+else
+ echo 'prefix=$(root)'$CONFIG_PREFIX >>config.make
+fi
+
+if test -z "$CONFIG_EPREFIX" ; then
+ echo 'eprefix=$(prefix)' >>config.make
+else
+ echo 'eprefix=$(root)'$CONFIG_EPREFIX >>config.make
+fi
+
+if test -z "$CONFIG_SHARE" ; then
+ if test -d $CONFIG_HOST/share ; then
+ echo 'share=$(prefix)/share' >>config.make
+ else
+ echo 'share=$(prefix)' >>config.make
+ fi
+else
+ echo 'share=$(root)'$CONFIG_SHARE >>config.make
+fi
+
+
+if test -z "$CONFIG_CONFDIR" ; then
+ echo 'SYSCONFDIR=$(root)/etc' >>config.make
+else
+ echo 'SYSCONFDIR=$(root)'$CONFIG_CONFDIR >>config.make
+fi
+
+if test -z "$CONFIG_BINDIR" ; then
+ echo 'BINDIR=$(eprefix)/bin' >>config.make
+else
+ echo 'BINDIR=$(root)'$CONFIG_BINDIR >>config.make
+fi
+
+if test -z "$CONFIG_SBINDIR" ; then
+ if test -d $CONFIG_HOST/sbin ; then
+ echo 'SBINDIR=$(eprefix)/sbin' >>config.make
+ else
+ echo 'SBINDIR=$(root)/etc' >>config.make
+ fi
+else
+ echo 'SBINDIR=$(root)'$CONFIG_SBINDIR >>config.make
+fi
+
+if test -z "$CONFIG_LIBDIR" ; then
+ echo 'LIBDIR=$(eprefix)/lib' >>config.make
+else
+ echo 'LIBDIR=$(root)'$CONFIG_LIBDIR >>config.make
+fi
+
+if test -z "$CONFIG_SLIBDIR" ; then
+ echo 'SLIBDIR=$(root)/lib' >>config.make
+else
+ echo 'SLIBDIR=$(root)'$CONFIG_SLIBDIR >>config.make
+fi
+
+if test -z "$CONFIG_MANDIR" ; then
+ if test -d $CONFIG_HOST/share/man ; then
+ echo 'MANDIR=$(share)/man' >>config.make
+ else
+ echo 'MANDIR=$(prefix)/man' >>config.make
+ fi
+else
+ echo 'MANDIR=$(root)'$CONFIG_MANDIR >>config.make
+fi
+
+if test -z "$CONFIG_INFODIR" ; then
+ if test -d $CONFIG_HOST/share/info ; then
+ echo 'INFODIR=$(share)/info' >>config.make
+ else
+ echo 'INFODIR=$(prefix)/info' >>config.make
+ fi
+else
+ echo 'INFODIR=$(root)'$CONFIG_INFODIR >>config.make
+fi
+
+if test -z "$CONFIG_HTMLDIR" ; then
+ if test -d $CONFIG_HOST/share/html ; then
+ echo 'HTMLDIR=$(share)/html' >>config.make
+ else
+ echo 'HTMLDIR=$(prefix)/html' >>config.make
+ fi
+else
+ echo 'HTMLDIR=$(root)'$CONFIG_HTMLDIR >>config.make
+fi
+
+if test -z "$CONFIG_DISTDIR" ; then
+ if test -d $CONFIG_HOST/share/dist ; then
+ echo 'DISTDIR=$(share)/dist' >>config.make
+ else
+ echo 'DISTDIR=$(prefix)/dist' >>config.make
+ fi
+else
+ echo 'DISTDIR=$(root)'$CONFIG_DISTDIR >>config.make
+fi
+
+echo "CONFIG_ROOT="$CONFIG_ROOT >>config.cache
+echo "CONFIG_PREFIX="$CONFIG_PREFIX >>config.cache
+echo "CONFIG_EPREFIX="$CONFIG_EPREFIX >>config.cache
+echo "CONFIG_SHARE="$CONFIG_SHARE >>config.cache
+echo "CONFIG_CONFDIR="$CONFIG_CONFDIR >>config.cache
+echo "CONFIG_BINDIR="$CONFIG_BINDIR >>config.cache
+echo "CONFIG_SBINDIR="$CONFIG_SBINDIR >>config.cache
+echo "CONFIG_LIBDIR="$CONFIG_LIBDIR >>config.cache
+echo "CONFIG_SLIBDIR="$CONFIG_SLIBDIR >>config.cache
+echo "CONFIG_INFODIR="$CONFIG_INFODIR >>config.cache
+echo "CONFIG_MANDIR="$CONFIG_MANDIR >>config.cache
+echo "CONFIG_HTMLDIR="$CONFIG_HTMLDIR >>config.cache
+echo "CONFIG_DISTDIR="$CONFIG_DISTDIR >>config.cache
diff --git a/sdk/bin/instinit b/sdk/bin/instinit
new file mode 100755
index 0000000..fdd0899
--- /dev/null
+++ b/sdk/bin/instinit
@@ -0,0 +1,61 @@
+#!/bin/sh
+run=/etc/rc.d
+levels=""
+base=$1
+
+if [ ! -d $run ] ; then
+ exit 0
+fi
+
+if [ -d $run/init.d ] ; then
+ levels=$run
+ init='../init.d/'$1'.init'
+ run=$run/init.d
+ target=$1'.init'
+else
+ target='rc.'$1
+ levels='false'
+fi
+
+source=$1'.init'
+shift
+
+if [ ! -f "$run/$target" ] ; then
+ echo 'Adding '$target' to '$run
+ if [ -f /etc/sudo.conf ] ; then
+ sudo root install -o root -m 0700 $source $run/$target
+ else
+ su root -c "install -o root -m 0700 $source $run/$target"
+ fi
+else
+ exit 0
+fi
+
+if [ -z "$BASH" ] ; then
+ exit 0
+fi
+
+if [ -z "$levels" ] ; then
+ exit 0
+fi
+
+initial=$1
+shift
+
+for level in $* ; do
+ runlvl=$levels'/rc'$level'.d'
+ if [ ! -d $runlvl ] ; then
+ continue
+ fi
+ cd $runlvl
+ count=$initial
+ while [ -f *$count* ] ; do
+ count=$[count + 1]
+ done
+ target='S'$count$base
+ echo 'Adding '$target' to '$runlvl
+ ln -s $init $target
+done
+
+
+
diff --git a/sdk/bin/instman b/sdk/bin/instman
new file mode 100755
index 0000000..d8ca6f7
--- /dev/null
+++ b/sdk/bin/instman
@@ -0,0 +1,32 @@
+#!/bin/sh
+prefix=$1
+set=$2
+shift
+shift
+
+for page in $* ; do
+ source=$page'.'$set
+ target=""
+ if [ -d $prefix/man$set ] ; then
+ mandir=$prefix/man$set
+ target=$mandir/$page'.'$set
+ fi
+ if [ -z $target ] ; then
+ roff=nroff
+ if [ -f /usr/lib/groff ] ; then
+ roff="groff -Tascii"
+ fi
+ if [ -f /usr/local/lib/groff ] ; then
+ roff="groff -Tascii"
+ fi
+ if [ -d $prefix/cat$set ] ; then
+ mandir=$prefix/cat$set
+ target=$mandir/$page.set
+ $roff -man <$source >$page'.man'
+ source=$page'.man'
+ fi
+ fi
+ echo 'Adding '$page' to '$mandir
+ install -g man -m 0664 $source $target
+done
+
diff --git a/sdk/bin/instso b/sdk/bin/instso
new file mode 100755
index 0000000..148a82a
--- /dev/null
+++ b/sdk/bin/instso
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+prefix=$1
+libname=$2
+version=$3
+
+# find project root.
+
+root=`dirname $0`
+root=`dirname $root`
+
+# fetch package 'version' level from project root (config.dist).
+
+if [ -f $root/config.dist ] ; then
+ . $root/config.dist
+fi
+
+if [ ! -d $(prefix)/lib ] ; then
+ prefix=$/usr
+ if [ ! -d /usr/lib ] ; then
+ exit 0
+ fi
+fi
+
+prefix=$prefix/lib
+echo 'Installing '$libname'.so to '$prefix
+cp -f $libname'.so' $(prefix)/$(libname)'.so.'$version
+ldconfig -n $(prefix)
+
+liblist=`find $(prefix) -name "$(libname).so.*" -type f -print`
+for lib in $liblist ; do
+ if [ ! $lib = $libname'.so.'$version ] ; then
+ rm $lib
+ fi
+done
+
+ldconfig -n $(prefix)
+
+
diff --git a/sdk/bin/instsvc b/sdk/bin/instsvc
new file mode 100755
index 0000000..468fe2a
--- /dev/null
+++ b/sdk/bin/instsvc
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+etc='/etc'
+
+if [ ! -d "$etc" ] ; then
+ etc=''
+ if [ -d /config ] ; then
+ etc='/config'
+ fi
+fi
+
+if [ -z "$etc" ] ; then
+ exit 0
+fi
+
+svc=$etc/$1
+shift
+base=$1
+shift
+line=$base" $*"
+
+grep "^$base" <$svc >/dev/null
+if [ $? = 1 ] ; then
+ echo "Adding $base to $svc"
+ echo $line >>$svc
+fi
+
diff --git a/sdk/bin/rootsudo b/sdk/bin/rootsudo
new file mode 100755
index 0000000..3ff65f1
--- /dev/null
+++ b/sdk/bin/rootsudo
@@ -0,0 +1,6 @@
+#!/bin/sh
+if [ -f /etc/sudo.conf ] ; then
+ sudo root $*
+else
+ su root -c "$*"
+fi
diff --git a/sdk/config.h b/sdk/config.h
new file mode 100644
index 0000000..6af2aa5
--- /dev/null
+++ b/sdk/config.h
@@ -0,0 +1,16 @@
+#ifndef __CONFIG_H__
+#define __CONFIG_H__
+#define EMPTY 0
+#define UCHAR_T_MISSING
+#define FD_T_MISSING
+#define STRLWR_F_MISSING
+#define STRISTR_F_MISSING
+#define PROCESS_H_MISSING
+#define SYS_SELECT_H_MISSING
+#define SELECT_H_MISSING
+#define POLL_H_MISSING
+#define SYS_POLL_H_MISSING
+#define SYSCONF_H_MISSING
+#define ENV_H_MISSING
+#define IO_H_MISSING
+#endif
diff --git a/sdk/dev/Makefile.in b/sdk/dev/Makefile.in
new file mode 100644
index 0000000..1375154
--- /dev/null
+++ b/sdk/dev/Makefile.in
@@ -0,0 +1,19 @@
+#
+# Template to build device interface library.
+# $Id$
+# Copyright (c) 1997 by Tycho Softworks.
+#
+
+OBJS = inkey.o empty.o input.o waitfor.o waitsync.o xmit.o \
+ speed.o format.o flowctrl.o interactive.o stty.o
+
+.c.o:
+ $(CC) $(CFLAGS) $(OPTIMIZE) -I.. -o $@ -c $<
+ $(AR) r ../lib/libdev.a $@
+
+all: $(OBJS)
+ ranlib ../lib/libdev.a
+
+clean:
+ rm *.o
+
diff --git a/sdk/dev/bind.conf b/sdk/dev/bind.conf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/sdk/dev/bind.conf
diff --git a/sdk/dev/empty.c b/sdk/dev/empty.c
new file mode 100644
index 0000000..87114a3
--- /dev/null
+++ b/sdk/dev/empty.c
@@ -0,0 +1,15 @@
+/*
+ * Empty the serial input fifo buffer.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <dev/tty.h>
+
+void empty(int fd)
+{
+ while(inkey(fd, 0) > -1)
+ continue;
+}
+
diff --git a/sdk/dev/flowctrl.c b/sdk/dev/flowctrl.c
new file mode 100644
index 0000000..7977b1c
--- /dev/null
+++ b/sdk/dev/flowctrl.c
@@ -0,0 +1,47 @@
+/*
+ * Serial line flow control option settings.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <dev/tty.h>
+#ifndef TERMIOS_H_MISSING
+#include <termios.h>
+#endif
+
+#ifndef CRTSCTS
+#ifdef CTSFLOW
+#define CRTSCTS CTSFLOW | CRTSFL
+#endif
+#endif
+
+int setflowctrl(stty_t stty, FLOWCONTROL flow)
+{
+#ifndef TERMIOS_H_MISSING
+
+ struct termios *tios = stty;
+ tios->c_cflag &= ~CRTSCTS;
+ tios->c_iflag &= ~(IXON | IXOFF | IXANY);
+
+ switch(flow)
+ {
+ case FC_HARD:
+ tios->c_cflag |= CRTSCTS;
+ break;
+ case FC_SOFT:
+ tios->c_iflag |= (IXON | IXOFF | IXANY);
+ break;
+ case FC_FULL:
+ tios->c_cflag |= CRTSCTS;
+ tios->c_iflag |= (IXON | IXOFF | IXANY);
+ break;
+ }
+#endif
+ return 0;
+}
+
+
+
+
+
diff --git a/sdk/dev/format.c b/sdk/dev/format.c
new file mode 100644
index 0000000..508ec6c
--- /dev/null
+++ b/sdk/dev/format.c
@@ -0,0 +1,64 @@
+/*
+ * Specify serial port data line format.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <dev/tty.h>
+#ifndef TERMIOS_H_MISSING
+#include <termios.h>
+#endif
+
+int setformat(stty_t stty, char *format)
+{
+#ifndef TERMIOS_H_MISSING
+ struct termios *tios = stty;
+
+ tios->c_cflag &= ~CSIZE;
+ if(format[2] == '1')
+ tios->c_cflag &= ~CSTOPB;
+ else
+ tios->c_cflag |= CSTOPB;
+
+ switch(format[0])
+ {
+ case '5':
+ tios->c_cflag |= CS5;
+ break;
+ case '6':
+ tios->c_cflag |= CS6;
+ break;
+ case '7':
+ tios->c_cflag |= CS7;
+ break;
+ case '8':
+ tios->c_cflag |= CS8;
+ break;
+ }
+
+ switch(format[1])
+ {
+ case 'n':
+ case 'N':
+ tios->c_cflag &= ~(PARODD | PARENB);
+ break;
+ case 'e':
+ case 'E':
+ tios->c_cflag |= PARENB;
+ tios->c_cflag &= ~PARODD;
+ break;
+ case 'o':
+ case 'O':
+ tios->c_cflag |= (PARENB | PARODD);
+ break;
+ }
+
+#endif
+ return 0;
+}
+
+
+
+
+
diff --git a/sdk/dev/inkey.c b/sdk/dev/inkey.c
new file mode 100644
index 0000000..1003905
--- /dev/null
+++ b/sdk/dev/inkey.c
@@ -0,0 +1,76 @@
+/*
+ * Wait and read single byte input from device.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <dev/tty.h>
+#include <std/select.h>
+#include <std/poll.h>
+
+#ifndef SYS_POLL_H_MISSING
+#define USE_POLL
+#endif
+
+#ifndef POLL_H_MISSING
+#define USE_POLL
+#endif
+
+#ifdef USE_POLL
+
+int inkey(fd_t fd, int timeout)
+{
+ struct pollfd poller;
+ uchar buf;
+
+ poller.fd = fd;
+ poller.revents = 0;
+ poller.events = POLLIN ;
+
+ if(!poll(&poller, 1, timeout))
+ return -1;
+
+ if(poller.revents & (POLLERR | POLLHUP))
+ return -1;
+
+ if(read(fd, &buf, 1) != 1)
+ return -1;
+
+ return buf;
+}
+
+#else
+
+int inkey(fd_t fd, int timeout)
+{
+ fd_set inp,out,exc;
+ struct timeval timer;
+ uchar buf;
+
+ FD_ZERO(&inp);
+ FD_ZERO(&out);
+ FD_ZERO(&exc);
+
+ FD_SET(fd, &inp);
+ FD_SET(fd, &exc);
+
+ timer.tv_sec = timeout / 1000;
+ timer.tv_usec = timeout % 1000;
+
+ if(!select(fd + 1, &inp, &out, &exc, &timer))
+ return -1;
+
+ if(FD_ISSET(fd, &exc))
+ return -1;
+
+ if(FD_ISSET(fd, &inp))
+ {
+ if(read(fd, &buf, 1) != 1)
+ return -1;
+ return buf;
+ }
+ return -1;
+}
+
+#endif
diff --git a/sdk/dev/input.c b/sdk/dev/input.c
new file mode 100644
index 0000000..95494d3
--- /dev/null
+++ b/sdk/dev/input.c
@@ -0,0 +1,34 @@
+/*
+ * Read a line of input from device.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <std/string.h>
+#include <dev/tty.h>
+
+int input(int fd, uchar *buf, size_t len, int timeout, const uchar *term)
+{
+ int key;
+ int idx = 0;
+
+ while(idx < len)
+ {
+ key = inkey(fd, timeout);
+ if(key < 0)
+ return idx;
+
+ if(!key)
+ continue;
+
+ buf[idx++] = (uchar)(key & 0xff);
+ if(strchr((char *)term, key))
+ break;
+ }
+ buf[idx] = 0;
+ return idx;
+}
+
+
+
diff --git a/sdk/dev/interactive.c b/sdk/dev/interactive.c
new file mode 100644
index 0000000..be998e6
--- /dev/null
+++ b/sdk/dev/interactive.c
@@ -0,0 +1,35 @@
+/*
+ * Select raw or "interactive" terminal mode for device.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <dev/tty.h>
+#ifndef TERMIOS_H_MISSING
+#include <termios.h>
+#endif
+
+bool interactive(stty_t stty, bool mode)
+{
+#ifndef TERMIOS_H_MISSING
+
+ struct termios *tios = stty;
+
+ if(mode)
+ {
+
+ }
+ else
+ {
+ tios->c_oflag = 0;
+ tios->c_lflag = 0;
+ }
+#endif
+ return mode;
+}
+
+
+
+
+
diff --git a/sdk/dev/make.conf b/sdk/dev/make.conf
new file mode 100644
index 0000000..8a396ea
--- /dev/null
+++ b/sdk/dev/make.conf
@@ -0,0 +1,5 @@
+inc=$CONFIG_HOST/include
+fn_find_file TERMIOS_H_MISSING $inc/termios.h
+fn_find_file TERMIO_H_MISSING $inc/termio.h
+fn_find_file TERMCAP_H_MISSING $inc/termcap.h
+
diff --git a/sdk/dev/speed.c b/sdk/dev/speed.c
new file mode 100644
index 0000000..f9fee56
--- /dev/null
+++ b/sdk/dev/speed.c
@@ -0,0 +1,75 @@
+/*
+ * Specify serial communications speed.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <dev/tty.h>
+#ifndef TERMIOS_H_MISSING
+#include <termios.h>
+#endif
+
+int setspeed(stty_t tios, ulong speed)
+{
+
+#ifdef B38400
+ int rate = B38400;
+#else
+ int rate = B19200;
+#endif
+
+ switch(speed)
+ {
+ case 110:
+ rate = B110;
+ break;
+ case 300:
+ rate = B300;
+ break;
+ case 600:
+ rate = B600;
+ break;
+ case 1200:
+ rate = B1200;
+ break;
+ case 2400:
+ rate = B2400;
+ break;
+ case 4800:
+ rate = B4800;
+ break;
+ case 9600:
+ rate = B9600;
+ break;
+ case 19200:
+ rate = B19200;
+ break;
+#ifdef B38400
+ case 38400:
+ rate = B38400;
+ break;
+#endif
+#ifdef B57600
+ case 57600:
+ rate = B57600;
+ break;
+#endif
+#ifdef B115200
+ case 115200:
+ rate = B115200;
+ break;
+#endif
+ }
+
+#ifndef TERMIOS_H_MISSING
+ cfsetospeed(tios, rate);
+ cfsetispeed(tios, rate);
+#endif
+ return rate;
+}
+
+
+
+
+
diff --git a/sdk/dev/stty.c b/sdk/dev/stty.c
new file mode 100644
index 0000000..9a465da
--- /dev/null
+++ b/sdk/dev/stty.c
@@ -0,0 +1,29 @@
+/*
+ * Portable routines to get and set serial device attributes.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <dev/tty.h>
+
+#ifndef TERMIOS_H_MISSING
+#include <termios.h>
+
+stty_t getstty(fd_t fd)
+{
+ stty_t stty = (stty_t)malloc(sizeof(struct termios));
+ tcgetattr(fd, stty);
+ return stty;
+}
+
+void putstty(fd_t fd, stty_t stty, bool now)
+{
+ if(now)
+ tcsetattr(fd, TCSANOW, stty);
+ else
+ tcsetattr(fd, TCSADRAIN, stty);
+ free(stty);
+}
+#endif
+
diff --git a/sdk/dev/termcap.h b/sdk/dev/termcap.h
new file mode 100644
index 0000000..e2cbb5b
--- /dev/null
+++ b/sdk/dev/termcap.h
@@ -0,0 +1,17 @@
+/*
+ * Portable termcap header.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions on distribution and reuse see product license.
+ */
+
+#ifndef __DEV_TERMCAP_H__
+#define __DEV_TERMCAP_H__
+
+#ifndef TERMCAP_H_MISSING
+#include <termcap.h>
+#else
+#endif
+
+#endif
+
diff --git a/sdk/dev/tty.h b/sdk/dev/tty.h
new file mode 100644
index 0000000..3ff02ca
--- /dev/null
+++ b/sdk/dev/tty.h
@@ -0,0 +1,72 @@
+/*
+ * Portable serial interface control and operation.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#ifndef __DEV_TTY_H__
+#define __DEV_TTY_H__
+
+#ifndef __STD_TYPES_H__
+#include <std/types.h>
+#endif
+
+#ifndef __STD_FILES_H__
+#include <std/files.h>
+#endif
+
+typedef void *stty_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ulock_device(lck) ulock_file(lck)
+
+typedef enum
+{
+ FC_NONE,
+ FC_HARD,
+ FC_SOFT,
+ FC_FULL
+} FLOWCONTROL;
+
+#ifdef __NAMESPACE
+#define lock_device __NAMESPACE(lock_device)
+#define setspeed __NAMESPACE(setspeed)
+#define setformat __NAMESPACE(setformat)
+#define setflowctrl __NAMESPACE(setflowctrl)
+#define waitfor __NAMESPACE(waitfor)
+#define waitsync __NAMESPACE(waitsync)
+#define input __NAMESPACE(input)
+#define dropdtr __NAMESPACE(dropdtr)
+#define inkey __NAMESPACE(inkey)
+#define interactive __NAMESPACE(interactive)
+#define readcrc __NAMESPACE(readcrc)
+#define writecrc __NAMESPACE(writecrc)
+#define readcsum __NAMESPACE(readcsum)
+#define writecsum __NAMESPACE(writecsum)
+#define xmit __NAMESPACE(xmit)
+#define empty __NAMESPACE(empty)
+#endif
+
+stty_t getstty(fd_t fd);
+void putstty(fd_t fd, stty_t stty, bool now);
+int setspeed(stty_t stty, ulong speed);
+int setformat(stty_t stty, char *format);
+int setflowctrl(stty_t stty, FLOWCONTROL flow);
+int waitfor(fd_t fd, uchar *str, size_t len, int timeout, ulong maxbytes);
+int waitsync(fd_t fd, uchar *list, size_t len, int timeout, ulong maxbytes);
+int input(fd_t fd, uchar *buf, size_t len, int timeout, const uchar *term);
+int dropdtr(fd_t fd);
+int inkey(fd_t fd, int timeout);
+bool interactive(stty_t stty, bool mode);
+int xmit(fd_t fd, char *str);
+void empty(fd_t fd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sdk/dev/waitfor.c b/sdk/dev/waitfor.c
new file mode 100644
index 0000000..36fabec
--- /dev/null
+++ b/sdk/dev/waitfor.c
@@ -0,0 +1,39 @@
+/*
+ * Wait for specified input from device.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions on redistribution and reuse see product license.
+ */
+
+#include <dev/tty.h>
+#include <std/string.h>
+
+int waitfor(int fd, uchar *list, size_t len, int timeout, ulong max)
+{
+ int key;
+ int idx = 0;
+ uchar *mem = (uchar *)malloc(len);
+
+ while(max--)
+ {
+ key = inkey(fd, timeout);
+ if(key < 0)
+ return key;
+
+ if(idx < len)
+ mem[idx++] = (uchar)(key & 0xff);
+ else
+ {
+ for(idx = 0; idx < len; ++idx)
+ mem[idx] = mem[idx + 1];
+
+ mem[len - 1] = (uchar)(key & 0xff);
+ }
+ if(!memcmp(mem, list, len))
+ return 0;
+ }
+ return -1;
+}
+
+
+
diff --git a/sdk/dev/waitsync.c b/sdk/dev/waitsync.c
new file mode 100644
index 0000000..f4596e1
--- /dev/null
+++ b/sdk/dev/waitsync.c
@@ -0,0 +1,32 @@
+/*
+ * Wait for a sync input value from a device.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <dev/tty.h>
+
+int waitsync(int fd, uchar *list, size_t len, int timeout, ulong max)
+{
+ int key;
+ int idx;
+ uchar buf;
+
+ while(max--)
+ {
+ key = inkey(fd, timeout);
+ if(key < 0)
+ return key;
+
+ buf = (uchar)(key & 0xff);
+
+ for(idx = 0; idx < len; ++idx)
+ if(list[idx] == buf)
+ return buf;
+ }
+ return -1;
+}
+
+
+
diff --git a/sdk/dev/xmit.c b/sdk/dev/xmit.c
new file mode 100644
index 0000000..471736d
--- /dev/null
+++ b/sdk/dev/xmit.c
@@ -0,0 +1,31 @@
+/*
+ * Write output to a device and ignore any incoming (echo) data.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <dev/tty.h>
+
+int xmit(int fd, char *str)
+{
+ int len = strlen(str);
+ int stat;
+
+ while(inkey(fd, 2) > -1)
+ continue;
+
+ stat = write(fd, str, len);
+ if(stat < 0)
+ return stat;
+
+ len = stat;
+ while(len--)
+ if(inkey(fd, 0) < 0)
+ break;
+
+ return stat;
+}
+
+
+
diff --git a/sdk/net/Makefile.in b/sdk/net/Makefile.in
new file mode 100644
index 0000000..bc890f5
--- /dev/null
+++ b/sdk/net/Makefile.in
@@ -0,0 +1,19 @@
+#
+# Template to build net makefile.
+# $Id$
+# Copyright (c) 1997 by Tycho Softworks.
+#
+
+OBJS = snmptrap.o gethost.o getservice.o getsocket.o sockname.o \
+ tcpsocket.o udpsocket.o init.o tcpstream.o msgport.o netaddr.o
+
+.c.o:
+ $(CC) $(CFLAGS) $(OPTIMIZE) -I.. -o $@ -c $<
+ $(AR) r ../lib/libnet.a $@
+
+all: $(OBJS)
+ ranlib ../lib/libnet.a
+
+clean:
+ rm *.o
+
diff --git a/sdk/net/bind.conf b/sdk/net/bind.conf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/sdk/net/bind.conf
diff --git a/sdk/net/gethost.c b/sdk/net/gethost.c
new file mode 100644
index 0000000..f74997c
--- /dev/null
+++ b/sdk/net/gethost.c
@@ -0,0 +1,39 @@
+/*
+ * Portable and simple host name lookup fuction.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <net/socket.h>
+
+struct hostent *gethost(const char *hostname)
+{
+ static struct in_addr saddr;
+ struct hostent *hp;
+ static struct hostent np;
+ static char host[24];
+ static char *alias[] = {NULL};
+ static struct in_addr *alist[] = {&saddr, NULL};
+
+ if(!hostname)
+ return NULL;
+
+ if(isdigit(*hostname))
+ {
+ saddr.s_addr = inet_addr(hostname);
+ hp = gethostbyaddr((void *)&saddr, sizeof(struct in_addr), AF_INET);
+ if(hp)
+ return hp;
+
+ strcpy(host, hostname);
+ np.h_name = host;
+ np.h_aliases = alias;
+ np.h_addrtype = AF_INET;
+ np.h_length = 4;
+ np.h_addr_list = (char **)alist;
+ return &np;
+ }
+ else
+ return gethostbyname(hostname);
+}
diff --git a/sdk/net/getservice.c b/sdk/net/getservice.c
new file mode 100644
index 0000000..fed448e
--- /dev/null
+++ b/sdk/net/getservice.c
@@ -0,0 +1,45 @@
+/*
+ * Simple portable service name lookup.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <net/socket.h>
+#include <std/string.h>
+
+int getservice(const char *service)
+{
+ char servname[32];
+ char *p;
+ struct servent *svc;
+ struct protoent *proto;
+
+ if(isdigit(*service))
+ return atoi(service);
+
+ strcpy(servname, service);
+ p = strchr(servname, '/');
+ if(!p)
+ strcat(servname, "/tcp");
+
+ p = strchr(servname, '/');
+ *(p++) = 0;
+ if(isdigit(*p))
+ {
+ proto = getprotobynumber(atoi(p));
+ if(!proto)
+ return 0;
+
+ p = proto->p_name;
+ }
+ svc = getservbyname(servname, p);
+ if(!svc)
+ return 0;
+
+ return ntohs(svc->s_port);
+}
+
+
+
+
diff --git a/sdk/net/getsocket.c b/sdk/net/getsocket.c
new file mode 100644
index 0000000..83ca68a
--- /dev/null
+++ b/sdk/net/getsocket.c
@@ -0,0 +1,43 @@
+#include <net/socket.h>
+#include <std/string.h>
+
+SOCKET getsocket(const char *host, int port, int socktype)
+{
+ SOCKET so;
+ struct hostent *hp;
+ struct sockaddr_in saddr;
+ struct in_addr *aptr;
+ char *sp, *p;
+ char *dup = strdup(host);
+
+ so = socket(AF_INET, socktype, 0);
+ if(so == INVALID_SOCKET)
+ {
+ free(dup);
+ return so;
+ }
+
+ sp = dup;
+ while(NULL != (p = strtok(sp, " ;:\t")))
+ {
+ sp = NULL;
+ hp = gethost(p);
+ if(!hp)
+ continue;
+
+ saddr.sin_family = hp->h_addrtype;
+ saddr.sin_port = htons(port);
+ while( (aptr = (struct in_addr *)*(hp->h_addr_list)++) != NULL)
+ saddr.sin_addr = *aptr;
+
+ if(connect(so, (struct sockaddr *)&saddr, sizeof(saddr)))
+ continue;
+
+ free(dup);
+ return so;
+ }
+ endsocket(so);
+ free(dup);
+ return INVALID_SOCKET;
+}
+
diff --git a/sdk/net/init.c b/sdk/net/init.c
new file mode 100644
index 0000000..02575a7
--- /dev/null
+++ b/sdk/net/init.c
@@ -0,0 +1,20 @@
+/*
+ * Needed for "winsock" compatibility only.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <net/socket.h>
+
+bool init_socket(void)
+{
+ return TRUE;
+}
+
+void endsocket(SOCKET so)
+{
+ shutdown(so, 2);
+ close(so);
+}
+
diff --git a/sdk/net/make.conf b/sdk/net/make.conf
new file mode 100644
index 0000000..36fbb70
--- /dev/null
+++ b/sdk/net/make.conf
@@ -0,0 +1,4 @@
+if test -f $CONFIG_HOST/lib/libsocket.a ; then
+ CONFIG_LIBS=$CONFIG_LIBS' -lsocket'
+fi
+
diff --git a/sdk/net/msgport.c b/sdk/net/msgport.c
new file mode 100644
index 0000000..39c1109
--- /dev/null
+++ b/sdk/net/msgport.c
@@ -0,0 +1,84 @@
+/*
+ * Portable network messaging routines.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <net/msgport.h>
+#include <std/time.h>
+
+static ushort sequence = 0;
+
+SOCKET create_msgport(char *mask, int port, int backlog)
+{
+ if(backlog)
+ return tcpsocket(mask, port, backlog);
+ else
+ return udpsocket(mask, port);
+}
+
+size_t send_msgport(SOCKET so, SOCKMSG *buf, size_t len, bool flag)
+{
+ size_t stat;
+
+ memset(buf, 0, sizeof(SOCKMSG));
+ if(flag)
+ ++sequence;
+ buf->header.len = htonl(len);
+ buf->sequence = sequence;
+
+ stat = send(so, buf, len + sizeof(SOCKMSG), 0);
+ if (stat > 0)
+ return stat - sizeof(SOCKMSG);
+ return stat;
+}
+
+size_t recv_msgport(SOCKET so, SOCKMSG *buf, size_t len, bool any)
+{
+ int alen;
+ size_t mlen;
+ size_t stat;
+ SOCKMSG saddr;
+
+ for(;;)
+ {
+ alen = recv(so, &saddr, sizeof(saddr), MSG_PEEK);
+ if(alen < 0)
+ return stat;
+
+ mlen = ntohl(saddr.header.len);
+ if (mlen > len)
+ mlen = len;
+
+ stat = recvfrom(so, buf, mlen + sizeof(saddr), 0, (struct sockaddr *)&saddr, &alen);
+ memcpy(buf, &saddr, alen);
+ if (stat > 0)
+ {
+ if(any && buf->sequence != sequence)
+ continue;
+
+ return stat - sizeof(SOCKMSG);
+ }
+ return stat;
+ }
+}
+
+size_t reply_msgport(SOCKET so, SOCKMSG *buf, SOCKMSG *org, size_t len)
+{
+ size_t stat;
+ SOCKMSG saddr;
+
+ if(!org)
+ org = buf;
+
+ memcpy(&saddr, org, sizeof(saddr));
+ buf->header.len = htonl(len);
+ stat = sendto(so, buf, len + sizeof(SOCKMSG), 0, (struct sockaddr *)&saddr, sizeof(saddr));
+ if (stat > 0)
+ return stat - sizeof(SOCKMSG);
+ return stat;
+}
+
+
+
diff --git a/sdk/net/msgport.h b/sdk/net/msgport.h
new file mode 100644
index 0000000..f7817e4
--- /dev/null
+++ b/sdk/net/msgport.h
@@ -0,0 +1,47 @@
+/*
+ * Portable network messaging routines.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#ifndef __NET_MSGPORT_H__
+#define __NET_MSGPORT_H__
+
+#ifndef __NET_SOCKET_H__
+#include <net/socket.h>
+#endif
+
+typedef struct
+{
+ union
+ {
+ struct sockaddr_in addr;
+ long len;
+ } header;
+ ushort sequence;
+ uchar body[ EMPTY ];
+} SOCKMSG;
+
+/* msgport control options */
+
+enum
+{
+ MSGPORT_TIMEOUT
+};
+
+#define attach_tcp(host, port) getsocket(host, port, SOCK_STREAM)
+#define attach_udp(host, port) getsocket(host, port, SOCK_DGRAM)
+
+#ifdef __NAMESPACE
+#define create_msgport __NAMESPACE(create_msgport)
+#define send_msgport __NAMESPACE(send_msgport)
+#define recv_msgport __NAMESPACE(recv_msgport)
+#define reply_msgport __NAMESPACE(reply_msgport)
+#endif
+
+SOCKET create_msgport(char *mask, int port, int backlog);
+size_t send_msgport(SOCKET so, SOCKMSG *buf, size_t len, bool inc);
+size_t recv_msgport(SOCKET so, SOCKMSG *buf, size_t maxlen, bool any);
+size_t reply_msgport(SOCKET so, SOCKMSG *buf, SOCKMSG *org, size_t len);
+#endif
diff --git a/sdk/net/netaddr.c b/sdk/net/netaddr.c
new file mode 100644
index 0000000..c156505
--- /dev/null
+++ b/sdk/net/netaddr.c
@@ -0,0 +1,28 @@
+/*
+ * Convert network mask or address string into a "BIND" filter mask.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <net/socket.h>
+#include <std/string.h>
+
+struct in_addr *getnetaddr(const char *mask)
+{
+ static struct in_addr addr;
+ struct in_addr *aptr;
+ struct hostent *hp;
+
+ if(!mask)
+ mask = "0.0.0.0";
+
+ hp = gethost(mask);
+ if(!hp)
+ return NULL;
+
+ while((aptr = (struct in_addr *)*(hp->h_addr_list)++) != NULL)
+ addr = *aptr;
+
+ return &addr;
+}
diff --git a/sdk/net/snmptrap.c b/sdk/net/snmptrap.c
new file mode 100644
index 0000000..17c9f7c
--- /dev/null
+++ b/sdk/net/snmptrap.c
@@ -0,0 +1,165 @@
+/*
+ * Generic snmp trap generation routine.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <net/trap.h>
+#include <std/string.h>
+
+int snmptrap(char *host, char *agent, char *community, int id, char *enterprise, char *describe, long ut)
+{
+ static uchar sysvar[] = {0x06, 0x08, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x01, 0x00, 0x04};
+
+ uchar pkt[256] = {0x30, 0x82, 0x00, 0x00, 0x02, 0x01, 0x00, 0x04};
+ char console[129];
+ int len;
+ int pos;
+ int l1 = 45;
+ int l2 = 39;
+ int l3 = 16;
+ int l2pos;
+ int l3pos;
+ int v1;
+ char *p;
+ int v2;
+ ulong hostip;
+ struct hostent *hp;
+ struct sockaddr_in target;
+ struct in_addr *aptr;
+ int i1, i2;
+ SOCKET so;
+
+ if(!describe)
+ describe = "";
+
+ if(!host)
+ host = "localhost";
+
+ if(!agent)
+ agent = "localhost";
+
+ hp = gethost(agent);
+ if(!hp)
+ return -1;
+
+ while( (aptr = (struct in_addr *)*(hp->h_addr_list)++) != NULL)
+ memcpy(&hostip, aptr, 4);
+
+ if(!community)
+ community = "PUBLIC";
+
+ if(!enterprise)
+ enterprise = "1.3.6.1.4.1.3.1.1";
+
+
+ so = socket(AF_INET, SOCK_DGRAM, 0);
+ if(so == INVALID_SOCKET)
+ return -1;
+
+ len = strlen(community);
+ l1 = l1 + len + 1;
+ pkt[8] = (uchar)len;
+ strcpy((char *)pkt + 9, community);
+ pos = 9 + len;
+ pkt[pos++] = 0xa4;
+ l2pos = pos++;
+ pkt[pos++] = 0x06;
+ len = 0;
+
+ v1 = atoi(enterprise);
+ enterprise = strchr(enterprise, '.');
+ v2 = atoi(++enterprise);
+ len = 1;
+ pkt[pos + len] = (uchar)(v1 * 40 + v2);
+
+ while(NULL !=(enterprise = strchr(enterprise, '.')))
+ pkt[pos + (++len)] = (uchar)atoi(++enterprise);
+
+ pkt[pos] = len;
+ pos += len + 1;
+ l1 += len;
+ l2 += len;
+
+ pkt[pos++] = 0x40;
+ pkt[pos++] = 0x04;
+ memcpy(pkt + pos, &hostip, 4);
+ pos += 4;
+
+ i2 = 0;
+ i1 = id;
+ if(id > 5 || id < 0)
+ {
+ i1 = 6;
+ i2 = abs(id);
+ }
+
+ pkt[pos++] = 0x02;
+ pkt[pos++] = 0x01;
+ pkt[pos++] = (uchar)i1;
+ pkt[pos++] = 0x02;
+ if(i2 > -1 && i2 < 128)
+ {
+ pkt[pos++] = 0x01;
+ pkt[pos++] = (uchar)i2;
+ }
+ else
+ {
+ pkt[pos++] = 0x02;
+ pkt[pos++] = (uchar)(i2 / 256);
+ pkt[pos++] = (uchar)(i2 % 256);
+ ++l1;
+ ++l2;
+ }
+ pkt[pos++] = 0x43;
+ pkt[pos++] = 0x03;
+ pkt[pos++] = (uchar)((ut / 0x10000) % 256);
+ pkt[pos++] = (uchar)((ut / 0x100) % 256);
+ pkt[pos++] = (uchar)(ut % 256);
+ pkt[pos++] = 0x30;
+ pkt[pos++] = 0x82;
+ pkt[pos++] = 0;
+ l3pos = pos++;
+
+ len = strlen(describe);
+ pkt[pos++] = 0x30;
+ pkt[pos++] = 0x82;
+ pkt[pos++] = 0x00;
+ pkt[pos++] = len + 12;
+ memcpy(pkt + pos, sysvar, 11);
+ pos += 11;
+ pkt[pos++] = (uchar)len;
+ strcpy((char *)pkt + pos, describe);
+
+ l1 += len;
+ l2 += len;
+ l3 += len;
+ pos += len;
+
+ pkt[2] = (uchar)(l1 / 256);
+ pkt[3] = (uchar)(l1 % 256);
+ pkt[l2pos] = (uchar)l2;
+ pkt[l3pos] = (uchar)l3;
+
+
+ strcpy(console, host);
+ host = strtok(console, ":\t; \t\n");
+ while(NULL != host)
+ {
+ hp = gethost(host);
+ if(!hp)
+ return -1;
+
+ while( (aptr = (struct in_addr *)*(hp->h_addr_list)++) != NULL)
+ target.sin_addr = *aptr;
+
+ target.sin_family = hp->h_addrtype;
+ target.sin_port = htons(SNMP_TRAP_PORT);
+ host = strtok(NULL, ":\t;");
+ sendto(so, pkt, pos, 0, (struct sockaddr *)&target, sizeof(struct sockaddr));
+ }
+ endsocket(so);
+ return 0;
+}
+
diff --git a/sdk/net/socket.h b/sdk/net/socket.h
new file mode 100644
index 0000000..b9bd190
--- /dev/null
+++ b/sdk/net/socket.h
@@ -0,0 +1,61 @@
+/*
+ * Portable include for access of socket services.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#ifndef __NET_SOCKET_H__
+#define __NET_SOCKET_H__
+
+#ifndef __STD_FILES_H__
+#include <std/files.h>
+#endif
+
+#ifndef __STD_TYPES_H__
+#include <std/types.h>
+#endif
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+typedef int SOCKET;
+#define INVALID_SOCKET -1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __NAMESPACE
+#define init_sockets __NAMESPACE(init_sockets)
+#define gethost __NAMESPACE(gethost)
+#define getservice __NAMESPACE(getservice)
+#define peername __NAMESPACE(peername)
+#define peeraddr __NAMESPACE(peeraddr)
+#define homename __NAMESPACE(homename)
+#define homeaddr __NAMESPACE(homeaddr)
+#define endsocket __NAMESPACE(endsocket)
+#define udpsocket __NAMESPACE(udpsocket)
+#define tcpsocket __NAMESPACE(tcpsocket)
+#define getsocket __NAMESPACE(getsocket)
+#endif
+
+bool init_sockets(void);
+struct hostent *gethost(const char *host);
+struct in_addr *getnetaddr(const char *addr);
+int getservice(const char *service);
+char *peername(SOCKET so);
+char *peeraddr(SOCKET so);
+char *homename(SOCKET so);
+char *homeaddr(SOCKET so);
+void endsocket(SOCKET so);
+SOCKET udpsocket(char *mask, int port);
+SOCKET tcpsocket(char *mask, int port, int backlog);
+SOCKET getsocket(const char *host, int port, int socktype);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sdk/net/sockname.c b/sdk/net/sockname.c
new file mode 100644
index 0000000..a8e9aad
--- /dev/null
+++ b/sdk/net/sockname.c
@@ -0,0 +1,62 @@
+/*
+ * Portable socket and peer name services.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <net/socket.h>
+
+char *homename(SOCKET so)
+{
+ struct hostent *hp;
+ struct sockaddr_in sin;
+ int len = sizeof(sin);
+
+ if(getsockname(so, (struct sockaddr *)&sin, &len) < 0)
+ return NULL;
+
+ hp = gethostbyaddr((char *)&sin.sin_addr, sizeof(struct in_addr), AF_INET);
+ if(hp)
+ return (char *)hp->h_name;
+ else
+ return inet_ntoa(sin.sin_addr);
+}
+
+char *homeaddr(SOCKET so)
+{
+ struct sockaddr_in sin;
+ int len = sizeof(sin);
+
+ if(getsockname(so, (struct sockaddr *)&sin, &len) < 0)
+ return NULL;
+
+ return inet_ntoa(sin.sin_addr);
+}
+
+char *peername(SOCKET so)
+{
+ struct hostent *hp;
+ struct sockaddr_in sin;
+ int len = sizeof(sin);
+
+ if(getpeername(so, (struct sockaddr *)&sin, &len) < 0)
+ return NULL;
+
+ hp = gethostbyaddr((char *)&sin.sin_addr, sizeof(struct in_addr), AF_INET);
+ if(hp)
+ return (char *)hp->h_name;
+ else
+ return inet_ntoa(sin.sin_addr);
+}
+
+char *peeraddr(SOCKET so)
+{
+ struct sockaddr_in sin;
+ int len = sizeof(sin);
+
+ if(getpeername(so, (struct sockaddr *)&sin, &len) < 0)
+ return NULL;
+
+ return inet_ntoa(sin.sin_addr);
+}
diff --git a/sdk/net/stream.h b/sdk/net/stream.h
new file mode 100644
index 0000000..268d881
--- /dev/null
+++ b/sdk/net/stream.h
@@ -0,0 +1,45 @@
+/*
+ * Stream oriented TCP session routines.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#ifndef __NET_STREAM_H__
+#define __NET_STREAM_H__
+
+#ifndef __NET_SOCKET_H__
+#include <net/socket.h>
+#endif
+
+#define tcppeer(fp) peername(fileno(fp))
+#define tcphome(fp) homename(fileno(fp))
+
+typedef FILE *STREAM;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __NAMESPACE
+#define opentcp __NAMESPACE(opentcp)
+#define accepttcp __NAMESPACE(accepttcp)
+#define gettcp __NAMESPACE(gettcp)
+#define puttcp __NAMESPACE(puttcp)
+#define closetcp __NAMESPACE(closetcp)
+#define buftcp __NAMESPACE(buftcp)
+#endif
+
+STREAM opentcp(const char *hostname, int port);
+STREAM accepttcp(SOCKET so);
+char *gettcp(char *buf, size_t count, STREAM fp);
+int puttcp(char *str, STREAM fp);
+void closetcp(STREAM fp);
+int buftcp(STREAM fp, int size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/sdk/net/tcpsocket.c b/sdk/net/tcpsocket.c
new file mode 100644
index 0000000..b5e61bf
--- /dev/null
+++ b/sdk/net/tcpsocket.c
@@ -0,0 +1,42 @@
+/*
+ * Create and bind a tcp socket for a server.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <net/socket.h>
+
+SOCKET tcpsocket(char *mask, int port, int backlog)
+{
+ SOCKET so;
+ struct sockaddr_in saddr;
+ struct in_addr *aptr;
+
+ so = socket(AF_INET, SOCK_STREAM, 0);
+ if(so == INVALID_SOCKET)
+ return so;
+
+ memset(&saddr, 0, sizeof(saddr));
+ saddr.sin_family = AF_INET;
+ saddr.sin_port = htons(port);
+ aptr = getnetaddr(mask);
+ if(!aptr)
+ {
+ endsocket(so);
+ return INVALID_SOCKET;
+ }
+ saddr.sin_addr = *aptr;
+
+ if(bind(so, (struct sockaddr *)&saddr, sizeof(saddr)))
+ {
+ endsocket(so);
+ return INVALID_SOCKET;
+ }
+ if(listen(so, backlog))
+ {
+ endsocket(so);
+ return INVALID_SOCKET;
+ }
+ return so;
+}
diff --git a/sdk/net/tcpstream.c b/sdk/net/tcpstream.c
new file mode 100644
index 0000000..b39645d
--- /dev/null
+++ b/sdk/net/tcpstream.c
@@ -0,0 +1,88 @@
+/*
+ * Portable TCP session stream functions.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <net/stream.h>
+#include <std/string.h>
+
+STREAM opentcp(const char *host, int port)
+{
+ SOCKET so = getsocket(host, port, SOCK_STREAM);
+ FILE *fp;
+
+ if(so == INVALID_SOCKET)
+ return NULL;
+
+ fp = fdopen(so, "r+");
+ if(!fp)
+ {
+ endsocket(so);
+ return NULL;
+ }
+ buftcp(fp, 0);
+ return fp;
+}
+
+char *gettcp(char *buf, size_t count, STREAM fp)
+{
+ memset(buf, 0, count);
+ if(!fgets(buf, count, fp))
+ return NULL;
+
+ return buf;
+}
+
+int puttcp(char *buf, STREAM fp)
+{
+ int err;
+ err = fputs(buf, fp);
+ fflush(fp);
+ return err;
+}
+
+void closetcp(STREAM fp)
+{
+ SOCKET so = fileno(fp);
+
+ fflush(fp);
+ shutdown(so, 2);
+ fclose(fp);
+}
+
+int buftcp(STREAM fp, int size)
+{
+ fflush(fp);
+
+ if(!size)
+ return setvbuf(fp, NULL, _IOLBF, 1024);
+ else
+ return setvbuf(fp, NULL, _IOFBF, size);
+}
+
+STREAM accepttcp(SOCKET so)
+{
+ struct sockaddr addr;
+ int len;
+ int si;
+ FILE *fp;
+
+ len = sizeof(addr);
+ si = accept(so, &addr, &len);
+ if(si < 0)
+ return NULL;
+
+ fp = fdopen(si, "r+");
+ if(!fp)
+ {
+ shutdown(si, 2);
+ close(si);
+ return NULL;
+ }
+
+ buftcp(fp, 0);
+ return fp;
+}
+
diff --git a/sdk/net/trap.h b/sdk/net/trap.h
new file mode 100644
index 0000000..b903d5d
--- /dev/null
+++ b/sdk/net/trap.h
@@ -0,0 +1,30 @@
+/*
+ * Define SNMP Traps.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#ifndef __NET_TRAP_H__
+
+#ifndef __NET_SOCKET_H__
+#include <net/socket.h>
+#endif
+
+#define SNMP_TRAP_PORT 162
+#define SNMP_TRAP_COLDSTART 0
+#define SNMP_TRAP_WARMSTART 1
+#define SNMP_TRAP_LINKDOWN 2
+#define SNMP_TRAP_LINKUP 3
+#define SNMP_TRAP_AUTHFAIL 4
+#define SNMP_TRAP_EGPNEIGHBORLOSS 5
+#define SNMP_TRAP_ENTERPRISESPECIFIC 6
+
+#ifdef __NAMESPACE
+#define snmptrap __NAMESPACE(snmptrap)
+#endif
+
+int snmptrap(char *target, char *host, char *community, int id, char *enterprise, char *describe, long uptime);
+
+
+#endif
diff --git a/sdk/net/udpsocket.c b/sdk/net/udpsocket.c
new file mode 100644
index 0000000..2127ac3
--- /dev/null
+++ b/sdk/net/udpsocket.c
@@ -0,0 +1,36 @@
+/*
+ * Create and bind a udp socket for a server.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <net/socket.h>
+
+SOCKET udpsocket(char *mask, int port)
+{
+ SOCKET so;
+ struct sockaddr_in saddr;
+ struct in_addr *aptr;
+
+ so = socket(AF_INET, SOCK_DGRAM, 0);
+ if(so == INVALID_SOCKET)
+ return so;
+
+ saddr.sin_family = AF_INET;
+ saddr.sin_port = htons(port);
+ aptr = getnetaddr(mask);
+ if(!aptr)
+ {
+ endsocket(so);
+ return INVALID_SOCKET;
+ }
+ saddr.sin_addr = *aptr;
+
+ if(bind(so, (struct sockaddr *)&saddr, sizeof(saddr)))
+ {
+ endsocket(so);
+ return INVALID_SOCKET;
+ }
+ return so;
+}
diff --git a/sdk/other/Makefile.in b/sdk/other/Makefile.in
new file mode 100644
index 0000000..17dd18a
--- /dev/null
+++ b/sdk/other/Makefile.in
@@ -0,0 +1,22 @@
+#
+# Template to build our "other" object modules(libother.a)
+# $Id: Makefile.in 1.2 Wed, 19 Mar 1997 12:44:53 -0500 dyfet $
+# Copyright (c) 1997 by Tycho Softworks.
+#
+
+OBJS = memalloc.o memdup.o memfree.o mempool.o memrelease.o \
+ memreq.o config.o confdir.o bcd.o env.o atob.o strint.o \
+ expand.o picture.o xval.o hex.o strcopy.o strdiff.o \
+ strblank.o strpos.o strreq.o strtrim.o ccount.o filename.o \
+ isftype.o getargv.o search.o token.o fatal.o fncat.o
+
+.c.o:
+ $(CC) $(CFLAGS) $(OPTIMIZE) -I.. -o $@ -c $<
+ $(AR) r ../lib/libother.a $@
+
+all: $(OBJS)
+ ranlib ../lib/libother.a
+
+clean:
+ rm *.o
+
diff --git a/sdk/other/atob.c b/sdk/other/atob.c
new file mode 100644
index 0000000..1535f7a
--- /dev/null
+++ b/sdk/other/atob.c
@@ -0,0 +1,47 @@
+/*
+ * Convert ASCII text into binary value.
+ * $Id: atob.c 1.2 Wed, 19 Mar 1997 12:44:53 -0500 dyfet $
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and use, see product license.
+ *
+ * Functions:
+ * atob() - convert null terminated ASCII string to boolean value.
+ */
+
+#include <other/strcvt.h>
+
+/*
+ * Convert null terminated ASCII string to boolean value.
+ *
+ * Abstract:
+ * The input string can be numeric; such as "0" or "1", or alpha;
+ * such as "T" for true, "F" for false, or "Y" or "N". Only the
+ * first character of the string is examined. Upper/lower case is
+ * ignored.
+ *
+ * Parameters:
+ * str - null terminated ASCII string.
+ *
+ * Returns:
+ * logical value of input string.
+ *
+ * Exceptions:
+ * Any unrecognized string value, or a NULL string, return FALSE.
+ */
+
+bool atob(const char *str)
+{
+ if(!str)
+ return FALSE;
+
+ switch(*str)
+ {
+ case '0':
+ case 'f':
+ case 'F':
+ case 'n':
+ case 'N':
+ return FALSE;
+ }
+ return TRUE;
+}
diff --git a/sdk/other/bcd.c b/sdk/other/bcd.c
new file mode 100644
index 0000000..3bd6144
--- /dev/null
+++ b/sdk/other/bcd.c
@@ -0,0 +1,125 @@
+/*
+ * Convert ASCII numbers to or from BCD representations.
+ * $Id: bcd.c 1.2 Wed, 19 Mar 1997 12:44:53 -0500 dyfet $
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For condititions of distribution and use, see product license.
+ *
+ * Abstract:
+ * BCD is a format for storing packed decimal data within a nibble.
+ * We assume "big endian" BCD, in that the high nibble contains the
+ * first digit within a byte. Any unused digits are filled with the
+ * nibble value of $F. This module provides the services needed to
+ * convert BCD data to and from ASCII strings.
+ *
+ * Functions:
+ * str2bcd() - convert ASCII string to packed bcd.
+ * bcd2str() - convert packed bcd to ASCII string.
+ */
+
+#include <other/strcvt.h>
+
+/*
+ * Convert null terminated ASCII string to packed bcd data.
+ *
+ * Abstract:
+ * An ASCII input string is converted to binary packed decimal
+ * data. Any unused digits are filled with $f. The size specified
+ * for digits is filled, either with available digits from the input
+ * string, or with $f nibbles once no more digits are available.
+ *
+ * Paramaters:
+ * bcd - pointer to start of bcd data to store.
+ * str - null terminated input string.
+ * max - maximum number of digits in bcd data.
+ *
+ * Returns:
+ * pointer to first non-BCD digit in input string.
+ *
+ * Exceptions:
+ * If NULL input string, returns NULL. If more digits exist in
+ * the input string than are available in bcd storage (data
+ * overflow), the remaining digits are ignored.
+ */
+
+char *str2bcd(uchar *bcd, char *str, int max)
+{
+ uchar packed = 0xff;
+ bool low = FALSE;
+
+ if(!str)
+ return NULL;
+
+ while(isdigit(*str))
+ {
+ packed = packed / 16;
+ packed |= ((*(str++) - '0') * 16);
+ if(low)
+ {
+ *(bcd++) = packed;
+ packed = 0xff;
+ if(!--max)
+ return str;
+
+ low = FALSE;
+ }
+ else
+ low = TRUE;
+ }
+ if(low)
+ {
+ *(bcd++) = packed;
+ --max;
+ }
+ while(max--)
+ *(bcd++) = 0xff;
+
+ return str;
+}
+
+/*
+ * Convert binary coded data to ASCII text.
+ *
+ * Abstract:
+ * A block of bcd data of up to a specified length is read, each
+ * digit being converted to an ASCII character code. If a $f is
+ * found before 'len' digits are examined, then the program
+ * completes with a shorter number.
+ *
+ * Paramaters:
+ * str - start of output string to receive converted data.
+ * bcd - bcd data input.
+ * len - maximum number of bcd digits.
+ *
+ * Return:
+ * pointer to next available bcd number in memory (or past end of
+ * bcd data block). The output string (str) is also given a null
+ * terminating byte.
+ *
+ * Exceptions:
+ * A NULL bcd pointer returns a NULL string.
+ */
+
+uchar *bcd2str(char *str, uchar *bcd, int len)
+{
+ uchar nib1, nib2;
+ if(!bcd)
+ return NULL;
+
+ while(len--)
+ {
+ nib1 = *bcd / 16;
+ nib2 = *bcd % 16;
+ if(nib1 < 16)
+ *(str++) = nib1 + '0';
+ else
+ break;
+ if(nib2 < 16)
+ *(str++) = nib2 + '0';
+ else
+ break;
+ ++bcd;
+ }
+ *str = 0;
+ return bcd;
+}
+
diff --git a/sdk/other/bind.conf b/sdk/other/bind.conf
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/sdk/other/bind.conf
@@ -0,0 +1 @@
+
diff --git a/sdk/other/ccount.c b/sdk/other/ccount.c
new file mode 100644
index 0000000..ec53a98
--- /dev/null
+++ b/sdk/other/ccount.c
@@ -0,0 +1,45 @@
+/*
+ * Count character occurances in string.
+ * $Id: ccount.c 1.2 Wed, 19 Mar 1997 12:44:53 -0500 dyfet $
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and use see product license.
+ *
+ * Functions:
+ * ccount() - count characters in string.
+ */
+
+#include <other/string.h>
+
+/*
+ * Count character occurances in ASCII string.
+ *
+ * Abstract:
+ * A list of possible characters to look for is passed to ccount,
+ * along with the null terminated ASCII string to look for those
+ * characters within.
+ *
+ * Parameters:
+ * str - string to examine and count occurances in.
+ * list - list (null terminated) of characters to search for.
+ *
+ * Exceptions:
+ * Either a NULL list or string is considered to hold no found
+ * characters (returns 0).
+ */
+
+int ccount(const char *str, const char *list)
+{
+ int count = 0;
+
+ if(!str || !list)
+ return 0;
+
+ while(NULL != (str = strpbrk(str, list)))
+ {
+ ++count;
+ ++str;
+ }
+ return count;
+}
+
+
diff --git a/sdk/other/confdir.c b/sdk/other/confdir.c
new file mode 100644
index 0000000..cabc475
--- /dev/null
+++ b/sdk/other/confdir.c
@@ -0,0 +1,105 @@
+/*
+ * Routines to access directory of section names in a config file.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and use see product license.
+ *
+ * Abstract:
+ * These routines may be used to scan the 'directory' of [] section
+ * names within a config file, much like the MS-DOS find_first() and
+ * find_next() directory routines.
+ *
+ * Functions:
+ * this_config() - internal routine to return section name.
+ * first_config() - goto first named [] section within the config file.
+ * next_config() - skip to the next named [] section.
+ */
+
+#include <other/config.h>
+#include <other/string.h>
+#include <other/env.h>
+
+#ifndef LBUF
+#define LBUF 1024
+#endif
+
+/*
+ * Internal program to support parsing of found section name.
+ */
+
+static char *this_config(CONFIG *cfg)
+{
+ char *p;
+
+ if(feof(cfg->cfg_fp))
+ return NULL;
+
+ if(cfg->cfg_lbuf[0] != '[')
+ return NULL;
+
+ cfg->cfg_flag = TRUE;
+ p = strtok(cfg->cfg_lbuf, "[]\n\r");
+ return p;
+}
+
+/*
+ * Automatically seek the very first [] section within a config file.
+ *
+ * Paramaters:
+ * cfg - config object pointer.
+ *
+ * Returns:
+ * Name string of first [] name in config file.
+ *
+ * Exceptions:
+ * If no [] section in config file, NULL cfg pointer, or file
+ * error, returns NULL.
+ */
+
+char *first_config(CONFIG *cfg)
+{
+ if(!cfg)
+ return NULL;
+
+ fseek(cfg->cfg_fp, 0l, SEEK_SET);
+ return next_config(cfg);
+}
+
+/*
+ * Skip to the next named [] section within a config file.
+ *
+ * Paramaters:
+ * cfg - config object pointer.
+ *
+ * Returns:
+ * Name string of next named [] section in config file.
+ *
+ * Exceptions:
+ * Returns NULL if cfg invalid or end of file reached.
+ *
+ */
+
+char *next_config(CONFIG *cfg)
+{
+ if(!cfg)
+ return NULL;
+
+ if(feof(cfg->cfg_fp))
+ return NULL;
+
+ for(;;)
+ {
+ fgets(cfg->cfg_lbuf, LBUF - 1, cfg->cfg_fp);
+ if(feof(cfg->cfg_fp))
+ return NULL;
+
+ if(cfg->cfg_lbuf[0] == '[')
+ return this_config(cfg);
+ }
+}
+
+
+
+
+
+
diff --git a/sdk/other/config.c b/sdk/other/config.c
new file mode 100644
index 0000000..e274b85
--- /dev/null
+++ b/sdk/other/config.c
@@ -0,0 +1,437 @@
+/*
+ * Routines to access and parse standard text config files.
+ * $Id: config.c 1.2 Wed, 19 Mar 1997 12:44:53 -0500 dyfet $
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and use see product license.
+ *
+ * Abstract:
+ * These routines are used to open and parse human readable '.conf'
+ * files, such as those which may be stored in the /etc directory.
+ * The .conf file is parsed as a sectioned text file, with the name
+ * for each logical section appearing in []'s. Entries within each
+ * section are typically in the format 'keyword = value', though
+ * there are exceptions for multi-line fixed size lists, in
+ * the form 'keyword = { list }', and repeated lines. Comments may
+ * also appear within .conf files.
+ *
+ * Functions:
+ * sys_config() - find and open a /etc or /etc/prior .conf file.
+ * open_config() - open any text file as a config file.
+ * read_config() - read a keyword = value pair from current section.
+ * seek_config() - seek a named [] section within the config file.
+ * get_config() - tests current input for a specified keyword.
+ * usr_config() - user specific resource config file.
+ */
+
+#include <other/config.h>
+#include <other/strcvt.h>
+#include <other/string.h>
+#include <other/env.h>
+#include <std/process.h>
+
+/*
+ * When searching for 'system' .conf files, which are normally held in
+ * /etc, also search in /etc/prior. This is used so that a human
+ * readable .conf file can momentarily be moved into '/etc/prior' and
+ * still be usable while a GUI system management program is in the middle
+ * building a new .conf file.
+ */
+
+#ifndef CFGPATH
+#define CFGPATH "/etc:/etc/prior"
+#endif
+
+/*
+ * Maximum working space for single or multi-line input records being
+ * parsed.
+ */
+
+#ifndef LBUF
+#define LBUF 1024
+#endif
+
+#ifndef SUFFIX
+#define SUFFIX ".conf"
+#endif
+
+/*
+ * Open a system .conf file, as found in the system config directories.
+ *
+ * Abstract:
+ * This function finds a .conf file in either the /etc or /etc/prior
+ * directory. /etc/prior is searched if the current .conf file is
+ * not found (in /etc), as may happen if it is in the middle of
+ * being re-built by a management application. This provides an
+ * initial function which may be used to open most .conf files.
+ *
+ * Paramaters:
+ * cfg_name - 'base' filename of system .conf file to open.
+ *
+ * Returns:
+ * pointer to active CONFIG object for specified filename.
+ *
+ * Exceptions:
+ * If the file is not found, a NULL pointer is returned.
+ */
+
+CONFIG *sys_config(const char *cfg_name)
+{
+ char cfgname[PATH_MAX + 1];
+
+ strcpy(cfgname, cfg_name);
+ strcat(cfgname, SUFFIX);
+ return open_config(search(CFGPATH, cfgname));
+}
+
+/*
+ * Open any specified filename as a .conf file.
+ *
+ * Abstract:
+ * This function opens the specified file as a 'config' file for use
+ * in config file parsing routines. Any filename may be specified
+ * and opened as a config file with this routine.
+ *
+ * Paramaters:
+ * config_name - full pathname of a .conf file to open.
+ *
+ * Returns:
+ * pointer to a newly allocated CONFIG parsing object for the
+ * specified filename.
+ *
+ * Exceptions:
+ * If the file is not found, a NULL pointer is returned.
+ */
+
+
+CONFIG *open_config(const char *config_name)
+{
+ CONFIG *new;
+ char *env;
+
+ if(NULL == (new = (CONFIG *)malloc(sizeof(CONFIG) + LBUF)))
+ return NULL;
+
+ if(NULL == (new->cfg_fp = fopen(config_name, "r")))
+ {
+ free(new);
+ return NULL;
+ }
+ new->cfg_flag = FALSE;
+ return new;
+}
+
+/*
+ * Close an open config file and destroy the CONFIG parser object.
+ */
+
+void close_config(CONFIG *cfg)
+{
+ if(!cfg)
+ return;
+
+ fclose(cfg->cfg_fp);
+ free(cfg);
+}
+
+/* Read a line of ASCII text input from an open config file.
+ *
+ * Abstract:
+ * This routine extracts a line of input from an open config file.
+ * The input line extracted and returned is a "keyword = value" line
+ * found within the current [] section. If the end of the current
+ * [] section has been reached, then no further input is returned.
+ *
+ * Lines which contain comments are automatically skipped. Comments
+ * include those lines which begin with a '#' or ';' character.
+ * Empty lines are also automatically skipped.
+ *
+ * Special {} subsections may also be used to specify language
+ * variant .conf values. When these subsection identifiers are found
+ * and the current language found in the ENV (LANG=) does not match
+ * the language for the specified {} section, the entire {} section
+ * is skipped.
+ *
+ * The input line retreived automatically has lead and trailing
+ * whitespaces removed.
+ *
+ * Paramaters:
+ * cfg - a 'config' parser object.
+ *
+ * Returns:
+ * ASCII text for 'keyword = value' item from config file.
+ *
+ * Exceptions:
+ * A NULL is returned when the current [] section has been completed,
+ * when at the end of the file, or if any error occurs while reading.
+ */
+
+char *read_config(CONFIG *cfg)
+{
+ char *p, *q;
+ int skip = 0;
+
+ if(!cfg)
+ return NULL;
+
+ if(!cfg->cfg_flag)
+ return NULL;
+
+ for(;;)
+ {
+ fgets(cfg->cfg_lbuf, LBUF - 1, cfg->cfg_fp);
+ if(feof(cfg->cfg_fp) || cfg->cfg_lbuf[0] == '[' || ferror(cfg->cfg_fp))
+ {
+ cfg->cfg_flag = FALSE;
+ return NULL;
+ }
+ p = strtrim(cfg->cfg_lbuf, __SPACES);
+
+ if(*p == '{')
+ {
+ skip = 1;
+ p = strtok(p, "{}| \t");
+ while(p)
+ {
+ if(!stricmp(p, "all"))
+ skip = 0;
+ if(!stricmp(p, language()))
+ skip = 0;
+ p = strtok(NULL, "{}| \t");
+ }
+ continue;
+ }
+
+ if(!*p || *p == '!' || *p == '#' || *p == ';' || skip)
+ continue;
+
+ return p;
+ }
+}
+
+/*
+ * Seek a named [] section within the .conf file to begin input.
+ *
+ * Abstract:
+ * The named section is found within the .conf file. Once
+ * found, all read_config() input will be returned from the
+ * specified [] section. Section names are case insensitive.
+ *
+ * Paramaters:
+ * cfg - config object pointer.
+ * seek_name - name of config [] section to find.
+ *
+ * Returns:
+ * TRUE if the section name is found in the .conf file , FALSE if
+ * not.
+ *
+ * Exceptions:
+ * If a NULL cfg or seek_name is passed, the search always fails.
+ * If a file error is found, the search always fails. The maximum
+ * size of a [] section name that is tested is 22 characters.
+ */
+
+bool seek_config(CONFIG *cfg, const char *seek_name)
+{
+ char group[25];
+ int len;
+
+ if(!cfg || !seek_name)
+ return FALSE;
+
+ cfg->cfg_flag = FALSE; /* mark as outside old [] section */
+
+ len = strlen(seek_name);
+ if (len > 22)
+ len = 22;
+
+ memset(group, 0, sizeof(group));
+
+ if(*seek_name != '[')
+ strcpy(group, "[");
+
+ strncat(group, seek_name, len);
+
+ if(*seek_name != '[' && strlen(seek_name) < 23)
+ strcat(group, "]");
+
+ fseek(cfg->cfg_fp, 0l, SEEK_SET);
+ len = strlen(group);
+ for(;;)
+ {
+ fgets(cfg->cfg_lbuf, LBUF - 1, cfg->cfg_fp);
+ if(feof(cfg->cfg_fp) || ferror(cfg->cfg_fp))
+ return FALSE;
+
+ if(!strnicmp(group, cfg->cfg_lbuf, len))
+ {
+ cfg->cfg_flag = TRUE;
+ return TRUE;
+ }
+ }
+}
+
+/*
+ * Parse and test a keyword value pair from current config input.
+ *
+ * Abstract:
+ * This routine is commonly used to search the current input line
+ * that is returned by read_config() for a specified keyword. The
+ * current input line is assumed to be in the form 'keyword = value'.
+ * lead and trailing spaces around the '=' are ignored, as is keyword
+ * case. White spaces within a keyword are also ignored.
+ *
+ * Assuming the keyword requested is found in the current input line,
+ * the 'value' string is returned. If the keyword being tested is
+ * a multi-line keyword = { list }, then all lines for the value are
+ * scanned and loaded into the config line buffer. If the special
+ * '+' entry is found in the config file, then the keyword is assumed
+ * to be a continuation of the last one found.
+ *
+ * A value is normally stripped of all lead and trailing spaces. If
+ * these need to be preserved, then the value may be put in single
+ * or double quotes.
+ *
+ * Since get_config() only looks at the current input line buffered
+ * by read_config(), a test for every possible keyword the application
+ * may need should be performed after each successful read_config()
+ * for a given [] section.
+ *
+ * Paramaters:
+ * cfg - config object pointer.
+ * keyword - keyword to test for.
+ *
+ * Returns:
+ * Value string if keyword is found in current input line, else NULL.
+ *
+ * Exceptions:
+ * If a NULL pointer or keyword is used, a NULL value is returned.
+ */
+
+char *get_config(CONFIG *cfg, const char *keyword)
+{
+ char *cbuf;
+ char *out, *p;
+ int pos = 0;
+ bool found = FALSE;
+
+ if(!cfg || !keyword)
+ return NULL;
+
+ cbuf = cfg->cfg_lbuf;
+
+ if(*cbuf == '+') /* alternate multi-line syntax */
+ {
+ if(!stricmp(cfg->cfg_test, keyword))
+ return strltrim(++cbuf, __SPACES);
+ else
+ return NULL;
+ }
+
+ while((pos < 33) && *cbuf && (*cbuf != '='))
+ {
+ if((*cbuf != ' ') && (*cbuf != '_') && (*cbuf != '\t'))
+ cfg->cfg_test[pos++] = *(cbuf++);
+ else
+ ++cbuf;
+ }
+ cfg->cfg_test[pos] = 0;
+ out = p = strltrim(++cbuf, __SPACES);
+ switch(*p)
+ {
+ case '{':
+ cbuf = p;
+ while(!found)
+ {
+ while(*(++p))
+ {
+ if(*p == '}')
+ {
+ found = TRUE;
+ *p = 0;
+ }
+ else
+ *(cbuf++) = *p;
+ }
+
+ if(!found)
+ {
+ p = cbuf;
+ fgets(p, LBUF - 1 + (int)(cfg->cfg_lbuf - p), cfg->cfg_fp);
+ if(feof(cfg->cfg_fp) || *p == '[')
+ {
+ cfg->cfg_flag = FALSE;
+ *p = 0;
+ break;
+ }
+ *(cbuf++) = '\n';
+ p = strtrim(p, __SPACES);
+ }
+ }
+ *cbuf = 0;
+ out = strltrim(++out, __SPACES);
+ break;
+ case '\'':
+ case '\"':
+ while(*(++p))
+ {
+ if(*p == *out)
+ {
+ *p = 0;
+ break;
+ }
+ }
+ out = strltrim(++out, __SPACES);
+ break;
+ }
+ if(!stricmp(cfg->cfg_test, keyword))
+ return out;
+ else
+ return NULL;
+}
+
+/*
+ * Find config file in user's home directory.
+ *
+ * Abstract:
+ * In addition to searching for a master config file in /etc, many
+ * applications may support an optional user specific 'rc' or config
+ * file in the user's own home directory, which, if found, may
+ * override global defaults. This ability is easily supported with
+ * the usr_config() service, which looks for a named .config file
+ * in the user's home.
+ *
+ * Paramaters:
+ * Filename of '.config' file to look for in a user's home directory,
+ * without the leading '.'.
+ *
+ * Returns:
+ * Config object pointer if file is found in user's home, otherwise
+ * a NULL pointer.
+ *
+ * Exceptions:
+ * A NULL filename will result in a NULL object being returned.
+ */
+
+CONFIG *usr_config(const char *name)
+{
+ char path[NAME_MAX + 1];
+
+ if(!name)
+ return NULL;
+
+ strcpy(path, homedir());
+ fncat(path, ".");
+ strcat(path, name);
+ return open_config(path);
+}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sdk/other/config.h b/sdk/other/config.h
new file mode 100644
index 0000000..4d76d1a
--- /dev/null
+++ b/sdk/other/config.h
@@ -0,0 +1,67 @@
+/*
+ * Portable human readable config text file parsing routines.
+ * $Id: config.h 1.2 Wed, 19 Mar 1997 12:44:53 -0500 dyfet $
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and use see product license.
+ *
+ * Abstract:
+ * The config routines allow locating, opening, and parsing of
+ * human readable .conf files. These .conf files are broken into
+ * seperate named [] sections, each of which may be individually
+ * located and examined, and config data. Config data is usually
+ * in the form of a 'keyword = value' statement.
+ *
+ * Data types:
+ * CONFIG - object line parse buffer for an open config file.
+ */
+
+#ifndef __OTHER_CONFIG_H__
+#define __OTHER_CONFIG_H__
+
+#ifndef __OTHER_STRING_H__
+#include <other/string.h>
+#endif
+
+#ifndef __OTHER_FILES_H__
+#include <other/files.h>
+#endif
+
+typedef struct
+{
+ bool cfg_flag;
+ FILE *cfg_fp;
+ char cfg_test[33];
+ char cfg_lbuf[ EMPTY ];
+} CONFIG;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __NAMESPACE
+#define open_config __NAMESPACE(open_config)
+#define sys_config __NAMESPACE(sys_config)
+#define usr_config __NAMESPACE(usr_config)
+#define first_config __NAMESPACE(first_config)
+#define next_config __NAMESPACE(next_config)
+#define seek_config __NAMESPACE(seek_config)
+#define read_config __NAMESPACE(read_config)
+#define close_config __NAMESPACE(close_config)
+#define get_config __NAMESPACE(get_config)
+#endif
+
+CONFIG *open_config(const char *name);
+CONFIG *sys_config(const char *name);
+CONFIG *usr_config(const char *name);
+char *first_config(CONFIG *cfg);
+char *next_config(CONFIG *cfg);
+bool seek_config(CONFIG *cfg, const char *name);
+char *read_config(CONFIG *cfg);
+void close_config(CONFIG *cfg);
+char *get_config(CONFIG *cfg, const char *option);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sdk/other/env.c b/sdk/other/env.c
new file mode 100644
index 0000000..cf3dfb0
--- /dev/null
+++ b/sdk/other/env.c
@@ -0,0 +1,36 @@
+/*
+ * Common values found in process environment space.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * See conditions of distribution and reuse see product license.
+ */
+
+#include <other/env.h>
+#include <std/string.h>
+
+char *homedir(void)
+{
+ char *env = getenv("HOME");
+
+ if(!env)
+ env = "/";
+
+ return env;
+}
+
+char *language(void)
+{
+ static char lbuf[32] = "default";
+
+ char *env = getenv("LANG");
+
+ if(env)
+ {
+ strncpy(lbuf, env, 31);
+ lbuf[31] = 0;
+ strtok(lbuf, "._");
+ }
+ return lbuf;
+}
+
+
diff --git a/sdk/other/env.h b/sdk/other/env.h
new file mode 100644
index 0000000..96b70e3
--- /dev/null
+++ b/sdk/other/env.h
@@ -0,0 +1,31 @@
+/*
+ * Portable process environment routines.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#ifndef __OTHER_ENV_H__
+#define __OTHER_ENV_H__
+
+#ifndef __STD_PROCESS_H__
+#include <std/process.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __NAMESPACE
+#define homedir __NAMESPACE(homedir)
+#define language __NAMESPACE(language)
+#endif
+
+char *homedir(void);
+char *language(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sdk/other/expand.c b/sdk/other/expand.c
new file mode 100644
index 0000000..8005957
--- /dev/null
+++ b/sdk/other/expand.c
@@ -0,0 +1,36 @@
+/*
+ * String expansion and normalization of 'plain text' line data.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <std/string.h>
+
+char *expand(const char *s)
+{
+ static char buf[320];
+
+ int pos = 0;
+
+ while(*s)
+ {
+ if(*s == '\t')
+ {
+ buf[pos++] = ' ';
+ while(pos % 8)
+ buf[pos++] = ' ';
+ }
+ else if (*s > 31)
+ buf[pos++] = *s;
+ else
+ {
+ buf[pos++] = '^';
+ buf[pos++] = *s + '@';
+ }
+ ++s;
+ }
+ buf[pos] = 0;
+ return buf;
+}
+
diff --git a/sdk/other/fatal.c b/sdk/other/fatal.c
new file mode 100644
index 0000000..fd3ef54
--- /dev/null
+++ b/sdk/other/fatal.c
@@ -0,0 +1,23 @@
+/*
+ * Print error message to stderr and exit with status code.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <other/string.h>
+#include <std/files.h>
+#include <std/process.h>
+#include <stdarg.h>
+
+void fatal(int excode, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ exit(excode);
+}
+
+
diff --git a/sdk/other/filename.c b/sdk/other/filename.c
new file mode 100644
index 0000000..2a7275e
--- /dev/null
+++ b/sdk/other/filename.c
@@ -0,0 +1,74 @@
+/*
+ * Portable file and directory name functions.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <other/files.h>
+#include <std/string.h>
+#include <std/math.h>
+
+char *dirname(char *path)
+{
+ char *p = basename(path);
+ if(p == path)
+ return ".";
+
+ *(--p) = 0;
+ return path;
+}
+
+char *basename(const char *path)
+{
+ char *p = strrchr(path, '/');
+#if defined(_MSDOS) || defined(_OS2) || defined(_WIN32)
+ char *p1 = strrchr(path, '\\');
+ p = max(p, p1);
+#endif
+
+ if(p)
+ return ++p;
+ else
+ return (char *)path;
+}
+
+char *extfname(const char *path)
+{
+ char *e = strrchr(pathfname(path), '.');
+
+ if(e)
+ return e;
+ else
+ return "";
+}
+
+bool ispath(const char *p)
+{
+ if(strchr(p, '/'))
+ return TRUE;
+#if defined(_MSDOS) || defined(_OS2) || defined(_WIN32)
+ if(strchr(p, '\\'))
+ return TRUE;
+#endif
+ return FALSE;
+}
+
+bool isroot(const char *p)
+{
+#if defined(_MSDOS) || defined(_OS2) || defined(_WIN32)
+ if(!strncmp(p, "\\\\", 2))
+ return TRUE;
+
+ if(p[1] == ':')
+ return TRUE;
+#else
+ if(*p == '/')
+ return TRUE;
+#endif
+ return FALSE;
+}
+
+
+
+
diff --git a/sdk/other/files.h b/sdk/other/files.h
new file mode 100644
index 0000000..7e9f421
--- /dev/null
+++ b/sdk/other/files.h
@@ -0,0 +1,52 @@
+/*
+ * Portable support for file manipulation and access related functions.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#ifndef __OTHER_FILES_H__
+#define __OTHER_FILES_H__
+
+#ifndef __STD_FILES_H__
+#include <std/files.h>
+#endif
+
+#define isdir(fpath) isftype(fpath, S_IFDIR)
+#define isfile(fpath) isftype(fpath, S_IFREG)
+#define islink(fpath) isftype(fpath, S_IFLNK)
+#define isfifo(fpath) isftype(fpath, S_IFIFO)
+#define pathfname(fn) basename(fn)
+#define rewind(fd) lseek(fd, (off_t)0, SEEK_SET)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __NAMESPACE
+#define isnewfile __NAMESPACE(isnewfile)
+#define isftype __NAMESPACE(isftype)
+#define ispath __NAMESPACE(ispath)
+#define isroot __NAMESPACE(isroot)
+#define fncat __NAMESPACE(fncat)
+#define search __NAMESPACE(search)
+#define basename __NAMESPACE(basename)
+#define dirname __NAMESPACE(dirname)
+#define extfname __NAMESPACE(extfname)
+#endif
+
+bool isnewfile(const char *from, const char *to);
+bool isftype(const char *fpath, int ftype);
+bool ispath(const char *fpath);
+bool isroot(const char *fpath);
+char *fncat(char *prefix, const char *suffix);
+char *search(const char *path, const char *fname);
+char *basename(const char *path);
+char *dirname(char *path);
+char *extfname(const char *path);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sdk/other/fncat.c b/sdk/other/fncat.c
new file mode 100644
index 0000000..1d8e3e7
--- /dev/null
+++ b/sdk/other/fncat.c
@@ -0,0 +1,30 @@
+/*
+ * Concatenate filenames.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse review product license.
+ */
+
+#include <std/files.h>
+#include <other/string.h>
+
+char *fncat(char *prefix, const char *suffix)
+{
+ char *t = tail(prefix);
+
+ if(!*prefix)
+ {
+ strcpy(prefix, suffix);
+ return prefix;
+ };
+
+ if(*(--t) != '/')
+ {
+ *(++t) = '/';
+ *(++t) = 0;
+ }
+
+ strcat(prefix, suffix);
+ return prefix;
+}
+
diff --git a/sdk/other/getargv.c b/sdk/other/getargv.c
new file mode 100644
index 0000000..bae4d4f
--- /dev/null
+++ b/sdk/other/getargv.c
@@ -0,0 +1,57 @@
+/*
+ * Portable routines to create argv[] argument lists for exec and spawn.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <other/string.h>
+
+int getargv(char *base[], char *cbuf)
+{
+ int arg = 0;
+ int qflag = 0;
+ int sflag = 1;
+
+ while(*cbuf)
+ {
+ switch(*cbuf)
+ {
+ case ' ':
+ case '\t':
+ if(qflag)
+ break;
+ if(!sflag)
+ {
+ *cbuf = 0;
+ sflag = 1;
+ }
+ break;
+ case '\"':
+ if(!qflag)
+ {
+ *cbuf = 0;
+ base[arg++] = cbuf + 1;
+ sflag = 0;
+ qflag = 1;
+ }
+ else
+ {
+ *cbuf = 0;
+ sflag = 1;
+ qflag = 0;
+ }
+ break;
+ default:
+ if(sflag)
+ {
+ base[arg++] = cbuf;
+ sflag = 0;
+ }
+ }
+ ++cbuf;
+ }
+ base[arg] = NULL;
+ return arg;
+}
+
diff --git a/sdk/other/hex.c b/sdk/other/hex.c
new file mode 100644
index 0000000..ae5ccec
--- /dev/null
+++ b/sdk/other/hex.c
@@ -0,0 +1,44 @@
+/*
+ * Hex digit conversion functions.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <other/strcvt.h>
+
+char hex(int digit)
+{
+ if(digit < 10)
+ return '0' + digit;
+ else
+ return '7' + digit;
+};
+
+char *hexbyte(uchar v)
+{
+ static char h[3];
+
+ h[0] = hex(v / 16);
+ h[1] = hex(v % 16);
+ h[2] = 0;
+ return h;
+};
+
+char *hexshort(ushort v)
+{
+ static char h[5];
+
+ strcpy(h, hexbyte((uchar)(v / 256)));
+ strcpy(h + 2, hexbyte((uchar)(v % 256)));
+ return h;
+};
+
+char *hexlong(ulong v)
+{
+ static char h[9];
+
+ strcpy(h, hexshort((ushort)(v / 65536)));
+ strcpy(h + 4, hexshort((ushort)(v % 65536)));
+ return h;
+};
diff --git a/sdk/other/isftype.c b/sdk/other/isftype.c
new file mode 100644
index 0000000..bee42ca
--- /dev/null
+++ b/sdk/other/isftype.c
@@ -0,0 +1,22 @@
+/*
+ * File type testing routine.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <std/files.h>
+
+bool isftype(const char *path, int ftype)
+{
+ struct stat ino;
+
+ if(stat(path, &ino))
+ return FALSE;
+
+ if((ino.st_mode & S_IFMT) == ftype)
+ return TRUE;
+
+ return FALSE;
+}
+
diff --git a/sdk/other/make.conf b/sdk/other/make.conf
new file mode 100644
index 0000000..e8b05bd
--- /dev/null
+++ b/sdk/other/make.conf
@@ -0,0 +1,2 @@
+fn_find_file MEMORY_H_MISSING $inc/memory.h
+
diff --git a/sdk/other/memalloc.c b/sdk/other/memalloc.c
new file mode 100644
index 0000000..6d31108
--- /dev/null
+++ b/sdk/other/memalloc.c
@@ -0,0 +1,35 @@
+/*
+ * Advanced memory pool allocation scheme.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse consult product license.
+ */
+
+#include <other/memory.h>
+#include <std/math.h>
+
+void *memalloc(MEMPOOL *mem, int len)
+{
+ _MEMFREE *free = mem->mem_free;
+ _MEMCELL *cell = NULL;
+
+ len = align(len, __OBJALIGN);
+
+ while(free)
+ {
+ if(free->size == len)
+ {
+ cell = free->list;
+ break;
+ }
+ free = free->next;
+ }
+
+ if(cell)
+ {
+ free->list = cell->next;
+ return cell;
+ }
+
+ return memreq(mem, len);
+}
diff --git a/sdk/other/memdup.c b/sdk/other/memdup.c
new file mode 100644
index 0000000..af1f3cf
--- /dev/null
+++ b/sdk/other/memdup.c
@@ -0,0 +1,22 @@
+/*
+ * Duplicate object into a memory pool.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <std/string.h>
+#include <other/memory.h>
+
+void *memdup(void *obj, size_t size)
+{
+ void *new = (void *)malloc(size);
+
+ if(!new)
+ return NULL;
+
+ memcpy(new, obj, size);
+ return new;
+}
+
+
diff --git a/sdk/other/memfree.c b/sdk/other/memfree.c
new file mode 100644
index 0000000..1939f14
--- /dev/null
+++ b/sdk/other/memfree.c
@@ -0,0 +1,38 @@
+/*
+ * Advanced free space deallocation for memory pools.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <other/memory.h>
+#include <std/math.h>
+
+void memfree(MEMPOOL *mem, void *obj, int len)
+{
+ _MEMFREE *free = mem->mem_free;
+ _MEMCELL *cell = (_MEMCELL *)obj;
+ len = align(len, __OBJALIGN);
+
+ while(free)
+ {
+ if(free->size == len)
+ break;
+
+ free = free->next;
+ }
+
+ if(!free)
+ {
+ free = memreq(mem, sizeof(_MEMFREE));
+ free->list = NULL;
+ free->next = mem->mem_free;
+ mem->mem_free = free;
+ }
+
+ if(free)
+ {
+ cell->next = free->list;
+ free->list = cell;
+ }
+}
diff --git a/sdk/other/memory.h b/sdk/other/memory.h
new file mode 100644
index 0000000..902edd2
--- /dev/null
+++ b/sdk/other/memory.h
@@ -0,0 +1,103 @@
+/*
+ * Portable memory manipulation and management routines.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#ifndef __OTHER_MEMORY_H__
+#define __OTHER_MEMORY_H__
+
+#ifndef __STD_TYPES_H__
+#include <std/types.h>
+#endif
+
+#ifndef MEMORY_H_MISSING
+#include <memory.h>
+#endif
+
+#ifndef __MEMALIGN
+#define __MEMALIGN sizeof(ptr_t)
+#endif
+
+#ifndef __OBJALIGN
+#define __OBJALIGN __MEMALIGN
+#endif
+
+struct _mempool;
+struct _mempage;
+struct _memfree;
+struct _memcell;
+
+typedef struct _mempool
+{
+ int mem_psize;
+ int mem_pcount;
+ int mem_pused;
+ void *(*mem_pfault)(struct _mempool *mem, int reqsize);
+ struct _memfree *mem_free;
+ struct _mempage *mem_reuse;
+ struct _mempage *mem_last;
+} MEMPOOL;
+
+typedef struct _mempage
+{
+ struct _mempage *page_next;
+ int page_used;
+ uchar page[ EMPTY ];
+} MEMPAGE;
+
+typedef struct _memfree
+{
+ struct _memfree *next;
+ struct _memcell *list;
+ int size;
+} _MEMFREE;
+
+typedef struct _memcell
+{
+ void *next;
+} _MEMCELL;
+
+#define memfault(mem, fault) mem->mem_pfault = fault;
+#define memfirst(mem) ((MEMPAGE *)((char *)(mem) - sizeof(MEMPAGE)))
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __NAMESPACE
+#define mempool __NAMESPACE(mempool)
+#define memreuse __NAMESPACE(memreuse)
+#define memrelease __NAMESPACE(memrelease)
+#define memreq __NAMESPACE(memreq)
+#define memlreq __NAMESPACE(memlreq)
+#define strreq __NAMESPACE(strreq)
+#define strlreq __NAMESPACE(strlreq)
+#define memdup __NAMESPACE(memdup)
+#define memalloc __NAMESPACE(memalloc)
+#define memfree __NAMESPACE(memfree)
+#endif
+
+MEMPOOL *mempool(int psize, int pcount);
+void memreuse(MEMPOOL *mem);
+void memrelease(MEMPOOL *mem);
+void *memreq(MEMPOOL *mem, size_t memsize);
+void *memlreq(MEMPOOL *mem, size_t memsize);
+char *strreq(MEMPOOL *mem, const char *str);
+char *strlreq(MEMPOOL *mem, const char *str);
+void *memdup(void *, size_t);
+
+/* more advanced allocation schemes */
+
+void *memalloc(MEMPOOL *mem, int memsize);
+void memfree(MEMPOOL *mem, void *obj, int memsize);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
+
diff --git a/sdk/other/mempool.c b/sdk/other/mempool.c
new file mode 100644
index 0000000..ef27638
--- /dev/null
+++ b/sdk/other/mempool.c
@@ -0,0 +1,49 @@
+/*
+ * Memory pool creation.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <other/memory.h>
+#include <std/files.h>
+#include <std/math.h>
+#include <std/process.h>
+
+static void *fault(MEMPOOL *mem, int request)
+{
+ fputs("* mempool: memory pool exhausted\n", stderr);
+ exit(EX_SOFTWARE);
+}
+
+MEMPOOL *mempool(int psize, int pcount)
+{
+ char *page;
+ MEMPAGE *first;
+ MEMPOOL *pool;
+
+ psize = align(psize, __MEMALIGN);
+ if(NULL == (page = (char *)malloc(psize)))
+ return NULL;
+
+ first = (MEMPAGE *)page;
+ pool = (MEMPOOL *)(page + sizeof(MEMPAGE));
+
+ first->page_next = NULL;
+ first->page_used = sizeof(MEMPOOL);
+
+ pool->mem_psize = psize - sizeof(MEMPAGE);
+ pool->mem_pcount = pcount;
+ pool->mem_pused = 1;
+ pool->mem_pfault = fault;
+ pool->mem_reuse = NULL;
+ pool->mem_last = first;
+ pool->mem_free = NULL;
+ return pool;
+}
+
+
+
+
+
+
diff --git a/sdk/other/memrelease.c b/sdk/other/memrelease.c
new file mode 100644
index 0000000..144bff6
--- /dev/null
+++ b/sdk/other/memrelease.c
@@ -0,0 +1,43 @@
+/*
+ * Relallocate and release memory pools.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <other/memory.h>
+
+void memrelease(MEMPOOL *mem)
+{
+ MEMPAGE *page = memfirst(mem);
+ MEMPAGE *next;
+
+ while(page)
+ {
+ next = page->page_next;
+ free(page);
+ page = next;
+ }
+}
+
+void memreuse(MEMPOOL *mem)
+{
+ MEMPAGE *page = memfirst(mem);
+ MEMPAGE *next;
+
+ page = page->page_next;
+ while(page)
+ {
+ next = page->page_next;
+ free(page);
+ page = next;
+ }
+ mem->mem_pused = 1;
+ mem->mem_free = NULL;
+ page = mem->mem_last = memfirst(mem);
+ page->page_used = 0;
+ page->page_next = NULL;
+}
+
+
+
diff --git a/sdk/other/memreq.c b/sdk/other/memreq.c
new file mode 100644
index 0000000..16f8433
--- /dev/null
+++ b/sdk/other/memreq.c
@@ -0,0 +1,59 @@
+/*
+ * Copy strings and objects into a memory pool.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <other/memory.h>
+#include <std/math.h>
+
+static void *memrequest(MEMPOOL *mem, MEMPAGE *page, size_t len)
+{
+ int psize = mem->mem_psize;
+ void *obj;
+
+ /* align objects to ptr field size */
+
+ len = align(len, __OBJALIGN);
+
+ if(len > mem->mem_psize)
+ return (*mem->mem_pfault)(mem, len);
+
+ while(page)
+ {
+ if(page->page_used + len <= psize)
+ {
+ obj = &page->page[page->page_used];
+ page->page_used += len;
+ return obj;
+ }
+ page = page->page_next;
+ }
+
+ if(mem->mem_pused >= mem->mem_pcount)
+ return (*mem->mem_pfault)(mem, len);
+
+ ++mem->mem_pused;
+ page = (MEMPAGE *)malloc(psize + sizeof(MEMPAGE));
+ if(!page)
+ return (*mem->mem_pfault)(mem, len);
+
+ mem->mem_last->page_next = page;
+ mem->mem_last = page;
+ page->page_used = len;
+ page->page_next = NULL;
+ return page->page;
+}
+
+void *memlreq(MEMPOOL *mem, size_t len)
+{
+ return memrequest(mem, mem->mem_last, len);
+}
+
+void *memreq(MEMPOOL *mem, size_t len)
+{
+ return memrequest(mem, memfirst(mem), len);
+}
+
+
diff --git a/sdk/other/picture.c b/sdk/other/picture.c
new file mode 100644
index 0000000..3ff2dba
--- /dev/null
+++ b/sdk/other/picture.c
@@ -0,0 +1,112 @@
+/*
+ * String formatting of numeric data.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <std/string.h>
+
+char *picture(char *buf, const char *pict, long value)
+{
+ char *bp = buf, *tp;
+ long shift = 0;
+ int sign = 0;
+ int zfill = 0;
+ int digit;
+ int currency = 0;
+ int digits = 0;
+
+ if(value < 0)
+ {
+ ++sign;
+ value = -value;
+ }
+
+ while(*pict)
+ {
+ switch(*pict)
+ {
+ case '$':
+ ++currency;
+ *(bp++) = ' ';
+ ++pict;
+ break;
+ case '+':
+ if(sign)
+ *(bp++) = ' ';
+ else
+ *(bp++) = '+';
+ ++pict;
+ break;
+ case '-':
+ if(sign)
+ *(bp++) = '-';
+ else
+ *(bp++) = ' ';
+ ++pict;
+ break;
+ case '9':
+ case '0':
+ shift *= 10;
+ if(!shift)
+ shift = 1;
+ default:
+ *(bp++) = *(pict++);
+ }
+ }
+ if(value >= shift * 10)
+ {
+ bp = buf;
+ while(*bp)
+ {
+ if(isdigit(*bp))
+ *bp = '#';
+ ++bp;
+ }
+ return buf;
+ }
+ bp = tp = buf;
+ while(*bp)
+ {
+ switch(*bp)
+ {
+ case ',':
+ if(*(bp - 1) == '#')
+ {
+ *bp = '#';
+ break;
+ }
+ if(!zfill)
+ *bp = ' ';
+ break;
+ case '#':
+ if(!digits)
+ if(shift > value)
+ break;
+ case '0':
+ ++zfill;
+ case '9':
+ ++digits;
+ digit = (int)(value / shift);
+ if((digit > 0) || (shift == 1))
+ ++zfill;
+ if(!zfill && !digit)
+ digit = (int)(' ' - '0');
+ *bp = (char)('0' + digit);
+ if(isdigit(*bp) && currency)
+ {
+ currency = 0;
+ *(tp - 1) = '$';
+ }
+ value %= shift;
+ shift /= 10;
+ }
+ if(*bp != '#')
+ *(tp++) = *bp;
+ ++bp;
+ }
+ *tp = 0;
+ return buf;
+}
+
diff --git a/sdk/other/search.c b/sdk/other/search.c
new file mode 100644
index 0000000..15963bf
--- /dev/null
+++ b/sdk/other/search.c
@@ -0,0 +1,46 @@
+/*
+ * File path search routines.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <other/files.h>
+#include <other/string.h>
+#include <std/process.h>
+
+#ifdef QNX
+#define PATHMARK "!"
+#endif
+
+#ifndef PATHMARK
+#define PATHMARK ":"
+#endif
+
+char *search(const char *path, const char *file)
+{
+ static char buf[PATH_MAX + 1];
+ char pbuf[PATH_MAX + 1];
+ char *p;
+
+ if(!path)
+ return NULL;
+
+ strcpy(pbuf, path);
+
+ p = strtok(pbuf, PATHMARK);
+
+ while(p)
+ {
+ if(*p)
+ fncat(strcpy(buf, p), file);
+ else
+ strcpy(buf, file);
+ if(isfile(buf))
+ return buf;
+ p = strtok(NULL, PATHMARK);
+ }
+ return NULL;
+}
+
+
diff --git a/sdk/other/strblank.c b/sdk/other/strblank.c
new file mode 100644
index 0000000..d3e8d18
--- /dev/null
+++ b/sdk/other/strblank.c
@@ -0,0 +1,24 @@
+/*
+ * Test for blank strings.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <other/string.h>
+
+char __SPACES[] = " \t\r\n";
+
+bool strblank(const char *str)
+{
+ if(!str)
+ return TRUE;
+
+ while(*str)
+ {
+ if(!strchr(__SPACES, *str))
+ return FALSE;
+ ++str;
+ }
+ return TRUE;
+}
diff --git a/sdk/other/strcopy.c b/sdk/other/strcopy.c
new file mode 100644
index 0000000..077f897
--- /dev/null
+++ b/sdk/other/strcopy.c
@@ -0,0 +1,61 @@
+/*
+ * String copying defined for supporting over-lapping strings 'insertion'.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <other/string.h>
+
+static char *revcopy(char *to, const char *from, size_t count)
+{
+ while(count--)
+ *(to--) = *(from--);
+
+ *to = *from;
+ return to;
+};
+
+char *strcopy(char *to, const char *from)
+{
+ char *s1 = to;
+ int l = from - to;
+ int l2 = len(from);
+
+ if(!to || !from)
+ return NULL;
+
+ if(l > 0 && l <= l2)
+ return revcopy(to + l2, from + l2, l2);
+
+ ++l2;
+ while(l2--)
+ *(to++) = *(from++);
+
+ return s1;
+};
+
+char *strncopy(char *to, const char *from, int l2)
+{
+ char *s1 = to;
+ int l = from - to;
+ if(len(from) < l2)
+ return strcopy(to, from);
+
+ if(!to || !from)
+ return NULL;
+
+ if(l > 0 && l <= l2)
+ {
+ to[l2] = 0;
+ --l2;
+ return revcopy(to + l2, from + l2, l2);
+ }
+
+ while(l2--)
+ *(to++) = *(from++);
+
+ *to = 0;
+ return s1;
+};
+
diff --git a/sdk/other/strcvt.h b/sdk/other/strcvt.h
new file mode 100644
index 0000000..443c820
--- /dev/null
+++ b/sdk/other/strcvt.h
@@ -0,0 +1,56 @@
+/*
+ * Portable string handling routines.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#ifndef __OTHER_STRCVT_H__
+#define __OTHER_STRCVT_H__
+
+#ifndef __STD_STRING_H__
+#include <std/string.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __NAMESPACE
+#define __SPACES __NAMESPACE(__SPACES)
+#endif
+
+extern char __SPACES[];
+
+#ifdef __NAMESPACE
+#define atob __NAMESPACE(atob)
+#define strint __NAMESPACE(strint)
+#define picture __NAMESPACE(picture)
+#define expand __NAMESPACE(expand)
+#define xdigit __NAMESPACE(xdigit)
+#define xtol __NAMESPACE(xtol)
+#define hex __NAMESPACE(hex)
+#define hexbyte __NAMESPACE(hexbyte)
+#define hexshort __NAMESPACE(hexshort)
+#define hexlong __NAMESPACE(hexlong)
+#define str2bcd __NAMESPACE(str2bcd)
+#define bcd2str __NAMESPACE(bcd2str)
+#endif
+
+bool atob(const char *str);
+char *strint(long i, int z);
+char *picture(char *buf, const char *pict, long value);
+char *expand(const char *str);
+int xdigit(char digit);
+ulong xtol(const char *digit);
+char hex(int value);
+char *hexbyte(uchar);
+char *hexshort(ushort);
+char *hexlong(ulong);
+char *str2bcd(uchar *bcd, char *str, int max);
+uchar *bcd2str(char *str, uchar *bcd, int len);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sdk/other/strdiff.c b/sdk/other/strdiff.c
new file mode 100644
index 0000000..a0297f6
--- /dev/null
+++ b/sdk/other/strdiff.c
@@ -0,0 +1,24 @@
+/*
+ * Often used to evaluate similarity of soundex codes.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <other/string.h>
+#include <std/math.h>
+
+int strdiff(const char *s1, const char *s2)
+{
+ int l1 = len(s1);
+ int l2 = len(s2);
+ int l = min(l1, l2);
+ int dif = abs(l1 - l2);
+
+ while(l--)
+ {
+ if(*(s1++) != *(s2++))
+ ++dif;
+ }
+ return dif;
+}
diff --git a/sdk/other/string.h b/sdk/other/string.h
new file mode 100644
index 0000000..5db8cd4
--- /dev/null
+++ b/sdk/other/string.h
@@ -0,0 +1,65 @@
+/*
+ * Portable string handling routines.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#ifndef __OTHER_STRINGS_H__
+#define __OTHER_STRINGS_H__
+
+#ifndef __STD_STRING_H__
+#include <std/string.h>
+#endif
+
+#ifndef __STD_TYPES_H__
+#include <std/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __NAMESPACE
+#define __SPACES __NAMESPACE(__SPACES)
+#endif
+
+extern char __SPACES[];
+
+#ifdef __NAMESPACE
+#define strblank __NAMESPACE(strblank)
+#define strtrim __NAMESPACE(strtrim)
+#define strrtrim __NAMESPACE(strrtrim)
+#define strltrim __NAMESPACE(strltrim)
+#define right __NAMESPACE(right)
+#define left __NAMESPACE(left)
+#define ccount __NAMESPACE(ccount)
+#define tail __NAMESPACE(tail)
+#define field __NAMESPACE(field)
+#define token __NAMESPACE(token)
+#define strcopy __NAMESPACE(strcopy)
+#define strncopy __NAMESPACE(strncopy)
+#define strdiff __NAMESPACE(strdiff)
+#define getargv __NAMESPACE(getargv)
+#endif
+
+bool strblank(const char *str);
+char *strtrim(char *s, const char *trim);
+char *strrtrim(char *s, const char *trim);
+char *strltrim(char *s, const char *trim);
+char *right(char *str, size_t len);
+char *left(char *str, size_t len);
+int ccount(const char *str, const char *list);
+char *tail(const char *str);
+char *field(char **ptr, const char *tok);
+char *token(char **ptr, const char *tok);
+char *strcopy(char *to, const char *from);
+char *strncopy(char *to, const char *from, int len);
+int strdiff(const char *s1, const char *s2);
+int getargv(char *base[], char *str);
+void fatal(int exitcode, const char *format, ...);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sdk/other/strint.c b/sdk/other/strint.c
new file mode 100644
index 0000000..f4291a1
--- /dev/null
+++ b/sdk/other/strint.c
@@ -0,0 +1,51 @@
+/*
+ * Convert integer to string, with optional leading zeros.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <other/strcvt.h>
+
+char *strint(long i, int z)
+{
+ static char buf[30];
+ char b1[30];
+ char *p = buf, *q = b1;
+ unsigned u;
+
+ if(!i)
+ {
+ if(z < 1)
+ z = 1;
+ while(z--)
+ *(p++) = '0';
+ *p = 0;
+ return buf;
+ }
+ if((i < 0) && !z)
+ {
+ i = -i;
+ buf[0] = '-';
+ ++p;
+ }
+ u = (unsigned)i;
+
+ while(u > 0)
+ {
+ *(q++) = (char)(u % 10) + '0';
+ u /= 10;
+ }
+ *q = 0;
+ z -= strlen(b1);
+ while(z-- > 0)
+ *(p++) = '0';
+
+ while(q > b1)
+ *(p++) = *(--q);
+ *p = 0;
+ return buf;
+}
+
+
+
diff --git a/sdk/other/strpos.c b/sdk/other/strpos.c
new file mode 100644
index 0000000..79afbf5
--- /dev/null
+++ b/sdk/other/strpos.c
@@ -0,0 +1,46 @@
+/*
+ * String pointer manipulation routines.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <other/string.h>
+
+char *tail(const char *tail)
+{
+ if(!tail)
+ return NULL;
+
+ while(*tail)
+ ++tail;
+
+ return (char *)tail;
+}
+
+char *left(char *str, size_t pos)
+{
+ if(!str)
+ return NULL;
+
+ if(pos < strlen(str))
+ str[pos] = 0;
+
+ return str;
+};
+
+char *right(char *s, size_t l)
+{
+ size_t len;
+
+ if(!s)
+ return NULL;
+
+ len = strlen(s);
+ if(len <= l)
+ return s;
+
+ return s + len - l;
+}
+
+
diff --git a/sdk/other/strreq.c b/sdk/other/strreq.c
new file mode 100644
index 0000000..fb69b95
--- /dev/null
+++ b/sdk/other/strreq.c
@@ -0,0 +1,39 @@
+/*
+ * Memory pool string copy.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <other/memory.h>
+
+char *strreq(MEMPOOL *mem, const char *str)
+{
+ char *newstr;
+
+ if(!str)
+ return NULL;
+
+ newstr = memreq(mem, strlen(str) + 1);
+ if(!newstr)
+ return NULL;
+
+ strcpy(newstr, str);
+ return newstr;
+}
+
+char *strlreq(MEMPOOL *mem, const char *str)
+{
+ char *newstr;
+
+ if(!str)
+ return NULL;
+
+ newstr = memlreq(mem, strlen(str) + 1);
+ if(!newstr)
+ return NULL;
+
+ strcpy(newstr, str);
+ return newstr;
+}
+
diff --git a/sdk/other/strtrim.c b/sdk/other/strtrim.c
new file mode 100644
index 0000000..9afcfd5
--- /dev/null
+++ b/sdk/other/strtrim.c
@@ -0,0 +1,45 @@
+/*
+ * Portable string trimming routines.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <other/string.h>
+
+char *strtrim(char *str, const char *trim)
+{
+ return strltrim(strrtrim(str, trim), trim);
+}
+
+char *strrtrim(char *str, const char *trim)
+{
+ char *end;
+
+ if(!str)
+ return NULL;
+
+ end = str + strlen(str);
+
+ while(end-- > str)
+ {
+ if(!strchr(trim, *end))
+ return str;
+ *end = 0;
+ }
+ return str;
+}
+
+char *strltrim(char *str, const char *trim)
+{
+ if(!str)
+ return NULL;
+
+ while(*str)
+ {
+ if(!strchr(trim, *str))
+ return str;
+ ++str;
+ }
+ return str;
+}
diff --git a/sdk/other/token.c b/sdk/other/token.c
new file mode 100644
index 0000000..c9846ed
--- /dev/null
+++ b/sdk/other/token.c
@@ -0,0 +1,50 @@
+/*
+ * Alternate thread-safe string token parsing.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <other/string.h>
+
+char *token(char **ptr, const char *tok)
+{
+ char *p;
+ char *brk;
+
+ if(strblank(*ptr))
+ return NULL;
+
+ p = strltrim(*ptr, tok);
+ brk = strpbrk(p, tok);
+ if(brk)
+ {
+ *brk = 0;
+ *ptr = strltrim(++brk, tok);
+ if(!(**ptr))
+ *ptr = NULL;
+ }
+ else
+ *ptr = NULL;
+ return p;
+}
+
+char *field(char **ptr, const char *tok)
+{
+ char *p = *ptr;
+ char *brk;
+
+ if(strblank(p))
+ return NULL;
+
+ brk = strpbrk(p, tok);
+ if(brk)
+ {
+ *brk = 0;
+ *ptr = ++brk;
+ }
+ else
+ *ptr = NULL;
+
+ return p;
+}
diff --git a/sdk/other/xval.c b/sdk/other/xval.c
new file mode 100644
index 0000000..c7d1276
--- /dev/null
+++ b/sdk/other/xval.c
@@ -0,0 +1,28 @@
+/*
+ * Hex digit conversions.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <other/strcvt.h>
+
+int xdigit(char c)
+{
+ if(c > '9')
+ return upper(c) - '7';
+
+ return digit(c);
+};
+
+ulong xtol(const char *s)
+{
+ ulong v = 0l;
+
+ while(isxdigit(*s))
+ {
+ v = v << 4 | xdigit(*s);
+ ++s;
+ }
+ return v;
+};
diff --git a/sdk/proc/Makefile.in b/sdk/proc/Makefile.in
new file mode 100644
index 0000000..94ae3cb
--- /dev/null
+++ b/sdk/proc/Makefile.in
@@ -0,0 +1,18 @@
+#
+# Template to build our "other" object modules(libother.a)
+# $Id: Makefile.in 1.2 Wed, 19 Mar 1997 12:44:53 -0500 dyfet $
+# Copyright (c) 1997 by Tycho Softworks.
+#
+
+OBJS = spawn.o pdetach.o priority.o
+
+.c.o:
+ $(CC) $(CFLAGS) $(OPTIMIZE) -I.. -o $@ -c $<
+ $(AR) r ../lib/libproc.a $@
+
+all: $(OBJS)
+ ranlib ../lib/libproc.a
+
+clean:
+ rm *.o
+
diff --git a/sdk/proc/bind.conf b/sdk/proc/bind.conf
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/sdk/proc/bind.conf
@@ -0,0 +1 @@
+
diff --git a/sdk/proc/make.conf b/sdk/proc/make.conf
new file mode 100644
index 0000000..2ce0aaa
--- /dev/null
+++ b/sdk/proc/make.conf
@@ -0,0 +1,5 @@
+inc=$CONFIG_HOST/include
+
+fn_find_file SYS_RESOURCE_H_MISSING $inc/sys/resource.h
+fn_find_type SETPRIORITY_F_MISSING setpriority $inc/sys/resource.h
+
diff --git a/sdk/proc/pdetach.c b/sdk/proc/pdetach.c
new file mode 100644
index 0000000..40814e4
--- /dev/null
+++ b/sdk/proc/pdetach.c
@@ -0,0 +1,78 @@
+/*
+ * Deamon-ify a user process; detach from controlling terminal and parent.
+ * $Id: daemon.c 1.2 Wed, 19 Mar 1997 12:44:53 -0500 dyfet $
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions on distribution and reuse see product license.
+ *
+ * Abstract:
+ * Daemon processes are commonly used in UNIX to build server
+ * applications. This module captures the essense of functionality
+ * required to make a process into a daemon within a single function
+ * call.
+ *
+ * Functions:
+ * daemon() - convert user process into a daemon.
+ */
+
+#include <proc/process.h>
+#include <std/signal.h>
+
+/* Daemonify a user process under UNIX.
+ *
+ * Abstract:
+ * In UNIX, a user process becomes a daemon by detaching itself from
+ * it's parent process and establishes it's own process group. A
+ * daemon may also detach itself from it's controlling terminal.
+ * This is usually accomplished through fork().
+ *
+ * Paramaters:
+ * flag - specifies daemon mode of operation:
+ * D_KEEPALL keeps all files open.
+ * D_KEEPSTDIO keeps stdio (stdin, stdout, stderr) open.
+ * D_KEEPNONIO detaches from stdio, keeps other files.
+ * D_KEEPNONE closes all open files.
+ *
+ * Returns:
+ * New pid of user process running as a daemon.
+ *
+ * Exceptions:
+ * Any failure terminates the process. No error message is possible
+ * since the process may already be detached from user I/O.
+ */
+
+pid_t pdetach(int flag)
+{
+ pid_t pid;
+ int max = OPEN_MAX;
+ int i;
+
+ signal(SIGHUP, SIG_IGN);
+
+ i = 0;
+ if(flag == D_KEEPSTDIO)
+ i = 3;
+
+ if(flag == D_KEEPNONIO)
+ max = 3;
+
+ while((i < max) && (flag != D_KEEPALL))
+ close(i++);
+
+ pid = fork();
+ if(pid < 0)
+ return pid;
+
+ if(pid > 0)
+ exit(EX_OK);
+
+ setsid();
+ setpgid(0, getpid());
+ pid = fork();
+ if(pid < 0)
+ return pid;
+
+ if(pid > 0)
+ exit(EX_OK);
+
+ return getpid();
+}
diff --git a/sdk/proc/priority.c b/sdk/proc/priority.c
new file mode 100644
index 0000000..8818567
--- /dev/null
+++ b/sdk/proc/priority.c
@@ -0,0 +1,73 @@
+/*
+ * Specify process for soft realtime scheduling treatment.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <proc/process.h>
+#include <std/time.h>
+
+#ifndef SYS_RESOURCE_H_MISSING
+#include <sys/resource.h>
+#endif
+
+#ifndef SETPRIORITY_F_MISSING
+
+int priority(int pri)
+{
+#ifdef _POSIX_PRIORITY_SCHEDULING
+ #define _P __P
+
+ #include <sched.h>
+
+ struct sched_param p;
+#endif
+ int newpri = getpriority(PRIO_PROCESS, 0) - pri - 1;
+
+ if(setpriority(PRIO_PROCESS, 0, newpri))
+ return -1;
+
+#ifdef _POSIX_MEMLOCK
+ #include <linux/mman.h>
+
+ if(mlockall(MCL_CURRENT | MCL_FUTURE))
+ return -1;
+#endif
+
+#ifdef _POSIX_PRIORITY_SCHEDULING
+ if(pri > 0)
+ {
+ p.sched_priority = sched_get_priority_min(SCHED_RR) + pri - 1;
+ if(sched_setscheduler(0, SCHED_RR, &p))
+ return -1;
+ }
+#endif
+
+ return 0;
+}
+
+#else
+
+int priority(int priority)
+{
+ return nice(- priority - 1);
+}
+#endif
+
+#ifdef _POSIX_PRIORITY_SCHEDULING
+#include <sched.h>
+
+void yield(void)
+{
+ sched_yield();
+}
+#else
+
+void yield(void)
+{
+ sleep(0);
+}
+#endif
+
+
diff --git a/sdk/proc/process.h b/sdk/proc/process.h
new file mode 100644
index 0000000..d65b765
--- /dev/null
+++ b/sdk/proc/process.h
@@ -0,0 +1,57 @@
+/*
+ * Portable process handling routines.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#ifndef __PROC_PROCESS_H__
+#define __PROC_PROCESS_H__
+
+#ifndef __STD_PROCESS_H__
+#include <std/process.h>
+#endif
+
+/* Spawn services under UNIX fork() */
+
+#define P_NOWAIT 0x00 /* Default, run concurrent */
+#define P_WAIT 0x01 /* Wait for and return exit status */
+#define P_BACKGROUND 0x02 /* Detach child from our stdio */
+#define P_SESSION 0x04 /* Use setsid() on child */
+#define P_OVERLAY 0x08 /* Really 'exec' called via spawn */
+
+/* Some common/portable spawn varients and masks */
+
+#define P_DETACH P_NOWAIT | P_SESSION | P_BACKGROUND
+#define P_NOWAITO P_NOWAIT | P_SESSION
+
+/* Daemon initialization options */
+
+#define D_KEEPSTDIO 0 /* Daemon keeps stdio connection */
+#define D_KEEPALL 1 /* Daemon keeps all open files */
+#define D_KEEPNONIO 2 /* Detach from stdio, keep others open */
+#define D_KEEPNONE 3 /* Deamon closes all files */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Common process invokation services using fork() */
+
+#ifdef __NAMESPACE
+#define spawnv __NAMESPACE(spawnv)
+#define spawnvp __NAMESPACE(spawnvp)
+#define pdetach __NAMESPACE(pdetach)
+#define priority __NAMEPSACE(priority)
+#endif
+
+int spawnv(const int P_mode, const char *path, char *const argv[]);
+int spawnvp(const int P_mode, const char *path, char *const argv[]);
+pid_t pdetach(const int D_flag); /* Make current process a daemon */
+int priority(int pri); /* set realtime priorities */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sdk/proc/spawn.c b/sdk/proc/spawn.c
new file mode 100644
index 0000000..2b6d7db
--- /dev/null
+++ b/sdk/proc/spawn.c
@@ -0,0 +1,92 @@
+/*
+ * Spawn services built on fork() for those libc's that lack spawning.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <proc/process.h>
+#include <std/files.h>
+
+static void spawn_redirect(int io, int mode)
+{
+ int fd = open("/dev/null", mode);
+
+ if(fd < 0)
+ exit(EX_OSFILE);
+
+ if(fd != io)
+ {
+ dup2(fd, io);
+ close(fd);
+ }
+}
+
+static int spawn_wait(pid_t pid, int mode)
+{
+ int waitflag = mode & P_WAIT;
+
+ /* -1 on fork failure */
+
+ if(pid == -1)
+ return -1;
+
+ if(!waitflag)
+ return pid;
+
+ waitpid(pid, &waitflag, 0);
+ return WEXITSTATUS(waitflag);
+}
+
+static void spawn_mode(int mode)
+{
+ int i;
+
+ if(mode & P_BACKGROUND)
+ {
+ spawn_redirect(0, O_RDONLY);
+ spawn_redirect(1, O_WRONLY);
+ spawn_redirect(2, O_WRONLY);
+ }
+
+ for(i = 3; i < OPEN_MAX; ++i)
+ close(i);
+
+ if(mode & P_SESSION)
+ setsid();
+}
+
+int spawnv(const int mode, const char *path, char *const argv[])
+{
+ pid_t pid = 0;
+ int status;
+
+ if(!(mode & P_OVERLAY))
+ pid = fork();
+
+ if(pid)
+ return spawn_wait(pid, mode);
+
+ spawn_mode(mode);
+ execv(path, argv);
+ exit(EX_UNAVAILABLE);
+ return -1;
+}
+
+int spawnvp(const int mode, const char *path, char *const argv[])
+{
+ pid_t pid = 0;
+ int status;
+
+ if(!(mode & P_OVERLAY))
+ pid = fork();
+
+ if(pid)
+ return spawn_wait(pid, mode);
+
+ spawn_mode(mode);
+ execvp(path, argv);
+ exit(EX_UNAVAILABLE);
+ return -1;
+}
+
diff --git a/sdk/std/Makefile.in b/sdk/std/Makefile.in
new file mode 100644
index 0000000..d8f600b
--- /dev/null
+++ b/sdk/std/Makefile.in
@@ -0,0 +1,18 @@
+#
+# Template to build standard sdk object modules(libstd.a)
+# $Id: Makefile.in 1.2 Wed, 19 Mar 1997 12:44:53 -0500 dyfet $
+# Copyright (c) 1997 by Tycho Softworks.
+#
+
+OBJS = string.o utmp.o
+
+.c.o:
+ $(CC) $(CFLAGS) $(OPTIMIZE) -I.. -o $@ -c $<
+ $(AR) r ../lib/libstd.a $@
+
+all: $(OBJS)
+ ranlib ../lib/libstd.a
+
+clean:
+ rm *.o
+
diff --git a/sdk/std/bind.conf b/sdk/std/bind.conf
new file mode 100644
index 0000000..65ee123
--- /dev/null
+++ b/sdk/std/bind.conf
@@ -0,0 +1,69 @@
+BIND_OPTS=$BIND_OPTS' cc optimize cflags arch'
+OPTIMIZE=''
+CFLAGS=''
+
+if test -z "$CONFIG_CC" ; then
+
+ echo -n "Analyzing C Compiler..."
+
+ if test -z "$CONFIG_ARCH" ; then
+ CONFIG_ARCH=`uname -m`"-"`uname`
+ fi
+
+ if fn_find_fpath -x gcc $PATH ; then
+ CONFIG_CC='gcc'
+ echo "gcc"
+ else
+ if test -z "$CONFIG_CC" ; then
+ CONFIG_CC='cc'
+ echo 'cc'
+ fi
+ fi
+fi
+
+opt_optimize() {
+ OPTIMIZE="$1"
+ CONFIG_COPT="$1"
+ return 0
+}
+
+opt_cflags() {
+ CONFIG_ENDIAN=""
+ CONFIG_CFLAGS="$1"
+ CFLAGS="$1"
+}
+
+opt_cc() {
+ CONFIG_CC="$1"
+ CONFIG_COPT="$OPTIMIZE"
+ CONFIG_CFLAGS="$CFLAGS"
+ return 0
+}
+
+opt_arch() {
+ CONFIG_ENDIAN=""
+ CONFIG_ARCH="$1"
+ if test "gcc" = $CONFIG_CC ; then
+ CONFIG_COPT="$OPTIMIZE"
+ if test -d /usr/local/lib/gcc-lib ; then
+ GCC_LIB='/usr/local/lib/gcc-lib'
+ fi
+ if test -d /usr/lib/gcc-lib ; then
+ GCC_LIB='/usr/lib/gcc-lib'
+ fi
+ if fn_find_fpath -d "$1" "$GCC_LIB"':/usr:/usr/local' ; then
+ CONFIG_CFLAGS='-b '"$1"
+ else
+ echo "config: $1: unsupported gcc architecture"
+ exit -1
+ fi
+ if -d /usr/$1/include ; then
+ CONFIG_HOST=/usr/$1
+ fi
+ if -d /usr/local/$1/include ; then
+ CONFIG_HOST=/usr/local/$1
+ fi
+ fi
+ return 0
+}
+
diff --git a/sdk/std/files.h b/sdk/std/files.h
new file mode 100644
index 0000000..84ad33a
--- /dev/null
+++ b/sdk/std/files.h
@@ -0,0 +1,47 @@
+/*
+ * Portable support for file manipulation and access related functions.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#ifndef __STD_FILES_H__
+#define __STD_FILES_H__
+
+#ifndef __STD_TYPES_H__
+#include <std/types.h>
+#endif
+
+#include <stdio.h>
+#include <sys/stat.h>
+
+#ifndef UNISTD_H_MISSING
+#include <unistd.h>
+#endif
+
+#ifndef SYS_FCNTL_H_MISSING
+#include <sys/fcntl.h>
+#else
+#ifndef FCNTL_H_MISSING
+#include <fcntl.h>
+#endif
+#endif
+
+#ifndef IO_H_MISSING
+#include <io.h>
+#endif
+
+#ifndef __STD_TYPES_H__
+#include <std/types.h>
+#endif
+
+
+#ifdef OFF_T_MISSING
+typedef long off_t;
+#endif
+
+#ifdef FD_T_MISSING
+typedef int fd_t;
+#endif
+
+#endif
diff --git a/sdk/std/help.conf b/sdk/std/help.conf
new file mode 100644
index 0000000..71dfb97
--- /dev/null
+++ b/sdk/std/help.conf
@@ -0,0 +1,4 @@
+--arch= Compiler Architecture / Cross-Compile
+--cc= Specify C Compiler to use
+--cflags= Specify Compiler Options
+--optimize= Specify Compiler Optimizations
diff --git a/sdk/std/limits.h b/sdk/std/limits.h
new file mode 100644
index 0000000..0766fe3
--- /dev/null
+++ b/sdk/std/limits.h
@@ -0,0 +1,97 @@
+/*
+ * Portable re-definition of limits header file.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#ifndef __STD_LIMITS_H__
+#define __STD_LIMITS_H__
+
+#include <limits.h>
+
+#ifndef __CONFIG_H__
+#include <config.h>
+#endif
+
+#ifndef POSIX1_LIM_H_MISSING
+#include <posix1_lim.h>
+#else
+#ifndef UNISTD_H_MISSING
+#include <unistd.h>
+#endif
+#include <std/posix1_lim.h>
+#endif
+
+#ifndef NR_OPEN
+#ifdef OPEN_MAX
+#define NR_OPEN OPEN_MAX
+#else
+#define NR_OPEN _POSIX_OPEN_MAX
+#endif
+#endif
+
+#ifndef NGROUPS_MAX
+#define NGROUPS_MAX _POSIX_NGROUPS_MAX
+#endif
+
+#ifndef CHILD_MAX
+#define CHILD_MAX _POSIX_CHILD_MAX
+#endif
+
+#ifndef ARG_MAX
+#define ARG_MAX _POSIX_ARG_MAX
+#endif
+
+#ifndef LINK_MAX
+#define LINK_MAX _POSIX_LINK_MAX
+#endif
+
+#ifndef MAX_CANON
+#define MAX_CANON _POSIX_MAX_CANON
+#endif
+
+#ifndef MAX_INPUT
+#define MAX_INPUT _POSIX_MAX_INPUT
+#endif
+
+#ifndef NAME_MAX
+#define NAME_MAX _POSIX_NAME_MAX
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX _POSIX_PATH_MAX
+#endif
+
+#ifndef PIPE_BUF
+#define PIPE_BUF _POSIX_PIPE_BUF
+#endif
+
+#ifndef SSIZE_MAX
+#define SSIZE_MAX INT_MAX
+#endif
+
+#ifndef STREAM_MAX
+#define STREAM_MAX OPEN_MAX
+#endif
+
+#ifndef TZONE_MAX
+#define TZONE_MAX _POSIX_TZONE_MAX
+#endif
+
+#ifdef MSDOS
+#if !defined(GNU) && !defined(__386__)
+#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__))
+#define MEM_SEGMENT_MAX 16
+#endif
+#if defined(M_I86SM) || defined(M_I86MM))
+#define MEM_SEGMENT_MAX 16
+#endif
+#endif
+#endif
+
+#ifndef MEM_SEGMENT_MAX
+#define MEM_SEGMENT_MAX 32
+#endif
+
+#endif
diff --git a/sdk/std/make.conf b/sdk/std/make.conf
new file mode 100644
index 0000000..bf20113
--- /dev/null
+++ b/sdk/std/make.conf
@@ -0,0 +1,102 @@
+if test "$CONFIG_CC" = gcc ; then
+
+ CONFIG_FPIC='-fpic'
+ CONFIG_EMPTY="0"
+ if test -z "$CONFIG_GCC_GFLAG" ; then
+ echo 'void f(){}' >conftest.c
+ if gcc -g -c conftest.c 2>&1 >/dev/null ; then
+ CONFIG_CFLAGS='-g '$CONFIG_CFLAGS
+ CONFIG_GCC_GFLAG='yes'
+ else
+ CONFIG_GCC_GFLAG='no'
+ fi
+ fi
+ if test -z "$CONFIG_COPT" ; then
+ case "$CONFIG_ARCH" in
+ i486* | i586* | i686*)
+ CONFIG_COPT='-O2 -m486'
+ ;;
+ *)
+ CONFIG_COPT='-O2'
+ esac
+ fi
+else
+ CONFIG_FPIC=''
+ CONFIG_EMPTY=""
+ if test -z "$CONFIG_CFLAGS" ; then
+ case "$CONFIG_ARCH" in
+ *-SCO_SV)
+ CONFIG_CFLAGS='-b elf'
+ CONFIG_COPT='-O3'
+ CONFIG_FPIC='-KPIC'
+ ;;
+ esac
+ fi
+
+ if test -z "$CONFIG_COPT" ; then
+ CONFIG_COPT='-O'
+ fi
+fi
+
+echo "#define EMPTY "$CONFIG_EMPTY >>$CONFIG
+
+echo "CC="$CONFIG_CC >>config.make
+echo "CFLAGS="$CONFIG_CFLAGS >>config.make
+echo "PICFLAG="$CONFIG_FPIC >>config.make
+echo "OPTIMIZE="$CONFIG_COPT >>config.make
+
+inc=$CONFIG_HOST/include
+typelist=`find $inc -name types.h -follow -print`
+
+echo 'CONFIG_CC="'$CONFIG_CC'"' >>config.cache
+echo 'CONFIG_COPT="'$CONFIG_COPT'"' >>config.cache
+echo 'CONFIG_ARCH="'$CONFIG_ARCH'"' >>config.cache
+echo 'CONFIG_CFLAGS="'$CONFIG_CFLAGS'"' >>config.cache
+echo 'CONFIG_PICFLAG="'$CONFIG_FPIC'"' >>config.cache
+echo 'CONFIG_GCC_GFLAG="'$CONFIG_GCC_GFLAG'"' >>config.cache
+echo 'CONFIG_HOST="'$CONFIG_HOST'"' >>config.cache
+
+fn_find_type UCHAR_T_MISSING "uchar;" $typelist
+fn_find_type USHORT_T_MISSING "ushort;" $typelist
+fn_find_type ULONG_T_MISSING "ulong;" $typelist
+fn_find_type SIZE_T_MISSING "size_t;" $typelist
+fn_find_type SSIZE_T_MISSING "ssize_t;" $typelist
+fn_find_type PID_T_MISSING "pid_t;" $typelist $inc/unistd.h
+fn_find_type OFF_T_MISSING "off_t;" $typelist $inc/stdio.h $inc/fcntl.h $inc/sys/fcntl.h $inc/io.h
+fn_find_type FD_T_MISSING "fd_t;" $typelist:$inc/stdio.h
+
+if fn_find_type GNUSTRING_F_MISSING "strcasecmp" $inc/string.h ; then
+ fn_find_type STRICMP_F_MISSING "stricmp" $inc/string.h
+fi
+
+fn_find_type STRLWR_F_MISSING "strlwr" $inc/string.h
+fn_find_type STRDUP_F_MISSING "strdup" $inc/string.h
+fn_find_type STRISTR_F_MISSING "stristr" $inc/string.h
+fn_find_type SELECT_F_MISSING "select" $inc/select.h $inc/sys/select.h $inc/sys/time.h
+fn_find_type GETUTENT_F_MISSING "getutent" $inc/utmp.h
+
+fn_find_type UT_USER_I_MISSING "ut_user" $inc/utmp.h
+
+fn_find_file POSIX1_LIM_H_MISSING $inc/posix1_lim.h
+fn_find_file PROCESS_H_MISSING $inc/process.h
+fn_find_file UNISTD_H_MISSING $inc/unistd.h
+fn_find_file POSIX2_LIM_H_MISSING $inc/posix2_lim.h
+fn_find_file SYS_SELECT_H_MISSING $inc/sys/select.h
+fn_find_file SELECT_H_MISSING $inc/select.h
+fn_find_file POLL_H_MISSING $inc/poll.h
+fn_find_file SYS_POLL_H_MISSING $inc/sys/poll.h
+
+if fn_find_file WAIT_H_MISSING $inc/wait.h ; then
+ fn_find_file SYS_WAIT_H_MISSING $inc/sys/wait.h
+fi
+fn_find_file POSIX_OPT_H_MISSING $inc/posix_opt.h
+fn_find_file CONFNAME_H_MISSING $inc/confname.h
+fn_find_file SYSCONF_H_MISSING $inc/sysconf.h
+fn_find_file ENV_H_MISSING $inc/env.h
+fn_find_file SYSEXITS_H_MISSING $inc/sysexits.h
+fn_find_file SYS_TIME_H_MISSING $inc/sys/time.h
+if fn_find_file SYS_FCNTL_H_MISSING $inc/sys/fcntl.h ; then
+ fn_find_file FCNTL_H_MISSING $inc/fcntl.h
+fi
+fn_find_file IO_H_MISSING $inc/io.h
+
diff --git a/sdk/std/math.h b/sdk/std/math.h
new file mode 100644
index 0000000..d1eb298
--- /dev/null
+++ b/sdk/std/math.h
@@ -0,0 +1,31 @@
+/*
+ * Common math functions and macros.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#ifndef __STD_MATH_H__
+#define __STD_MATH_H__
+
+#ifndef __STD_TYPES_H__
+#include <std/types.h>
+#endif
+
+#ifndef min
+#define min(a, b) ((a)<(b)?(a):(b))
+#endif
+
+#ifndef max
+#define max(a, b) ((a)>(b)?(a):(b))
+#endif
+
+#ifndef abs
+#define abs(a) ((a)<0?(-a):(a))
+#endif
+
+#ifndef align
+#define align(x, s) ((((x) + (s) - 1) / (s)) *(s))
+#endif
+
+#endif
diff --git a/sdk/std/poll.h b/sdk/std/poll.h
new file mode 100644
index 0000000..a9eb3f9
--- /dev/null
+++ b/sdk/std/poll.h
@@ -0,0 +1,21 @@
+/*
+ * Find or insert replacement "poll" routine.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and use see product license.
+ */
+
+#ifndef __STD_POLL_H__
+#define __STD_POLL_H__
+
+#ifdef POLL_H_MISSING
+#ifndef SYS_POLL_H_MISSING
+#include <sys/poll.h>
+#endif
+#else
+#include <poll.h>
+#endif
+
+#include <std/time.h>
+
+#endif
diff --git a/sdk/std/posix1_lim.h b/sdk/std/posix1_lim.h
new file mode 100644
index 0000000..5520f22
--- /dev/null
+++ b/sdk/std/posix1_lim.h
@@ -0,0 +1,92 @@
+/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+/*
+ * POSIX Standard: 2.9.2 Minimum Values Added to <limits.h>
+ */
+
+#ifndef _POSIX1_LIMITS_H
+
+#define _POSIX1_LIMITS_H 1
+
+
+/* These are the standard-mandated minimum values. */
+
+/* Maximum length of arguments to `execve', including environment. */
+#define _POSIX_ARG_MAX 4096
+
+/* Maximum simultaneous processes per real user ID. */
+#define _POSIX_CHILD_MAX 6
+
+/* Maximum link count of a file. */
+#define _POSIX_LINK_MAX 8
+
+/* Number of bytes in a terminal canonical input queue. */
+#define _POSIX_MAX_CANON 255
+
+/* Number of bytes for which space will be
+ available in a terminal input queue. */
+#define _POSIX_MAX_INPUT 255
+
+/* Number of simultaneous supplementary group IDs per process. */
+#define _POSIX_NGROUPS_MAX 0
+
+/* Number of files one process can have open at once. */
+#define _POSIX_OPEN_MAX 16
+
+/* Number of bytes in a filename. */
+#define _POSIX_NAME_MAX 14
+
+/* Number of bytes in a pathname. */
+#define _POSIX_PATH_MAX 255
+
+/* Number of bytes than can be written atomically to a pipe. */
+#define _POSIX_PIPE_BUF 512
+
+/* Largest value of a `ssize_t'. */
+#define _POSIX_SSIZE_MAX 32767
+
+/* Number of streams a process can have open at once. */
+#define _POSIX_STREAM_MAX 8
+
+/* Number of bytes in `tzname'. */
+#define _POSIX_TZNAME_MAX 3
+
+
+/* don't even think about changing it without checking tzfile.h
+ * in source code dir ./time first.
+ */
+#undef TZNAME_MAX
+#define TZNAME_MAX 50
+
+#ifndef SSIZE_MAX
+#define SSIZE_MAX INT_MAX
+#endif
+
+#ifndef STREAM_MAX
+#define STREAM_MAX OPEN_MAX
+#endif
+
+/* This value is a guaranteed minimum maximum.
+ The current maximum can be got from `sysconf'. */
+
+#ifndef NGROUPS_MAX
+#define NGROUPS_MAX _POSIX_NGROUPS_MAX
+#endif
+
+#endif /* posix1_limits.h */
diff --git a/sdk/std/process.h b/sdk/std/process.h
new file mode 100644
index 0000000..2fdf6ae
--- /dev/null
+++ b/sdk/std/process.h
@@ -0,0 +1,99 @@
+/*
+ * Portable process handling routines.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#ifndef __STD_PROCESS_H__
+#define __STD_PROCESS_H__
+
+#ifndef __STD_TYPES_H__
+#include <std/types.h>
+#endif
+
+#ifndef __STD_LIMITS_H__
+#include <std/limits.h>
+#endif
+
+#ifndef POSIX2_LIM_H_MISSING
+#include <posix2_lim.h>
+#endif
+
+#ifndef POSIX_OPT_H_MISSING
+#include <posix_opt.h>
+#endif
+
+#ifndef UNISTD_H_MISSING
+#include <unistd.h>
+#endif
+
+#ifndef _SC_OPEN_MAX
+#ifndef CONFNAME_H_MISSING
+#include <confname.h>
+#else
+#ifndef SYSCONF_H_MISSING
+#include <sysconf.h>
+#endif
+#endif
+#endif
+
+#ifndef PROCESS_H_MISSING
+#include <process.h>
+#endif
+
+#ifndef WAIT_H_MISSING
+#include <wait.h>
+#else
+#ifndef SYS_WAIT_H_MISSING
+#include <sys/wait.h>
+#endif
+#endif
+
+#ifndef ENV_H_MISSING
+#include <env.h>
+#endif
+
+#ifndef SYSEXITS_H_MISSING
+#include <sysexits.h>
+#else
+#include <std/sysexits.h>
+#endif
+
+/* We now re-evaluate system limits using runtime sysconf() values */
+
+#ifdef _SC_ARG_MAX
+#undef ARG_MAX
+#define ARG_MAX (sysconf(_SC_ARG_MAX))
+#endif
+
+#ifdef _SC_CHILD_MAX
+#undef CHILD_MAX
+#define CHILD_MAX (sysconf(_SC_CHILD_MAX))
+#endif
+
+#ifdef _SC_NGROUPS_MAX
+#undef NGROUPS_MAX
+#define NGROUPS_MAX (sysconf(_SC_NGROUPS_MAX))
+#endif
+
+#ifdef _SC_OPEN_MAX
+#undef OPEN_MAX
+#define OPEN_MAX (sysconf(_SC_OPEN_MAX))
+#endif
+
+#ifdef _SC_STREAM_MAX
+#undef STREAM_MAX
+#define STREAM_MAX (sysconf(_SC_STREAM_MAX))
+#endif
+
+#ifdef _SC_TZNAME_MAX
+#undef TZNAME_MAX
+#define TZNAME_MAX (sysconf(_SC_TZNAME_MAX))
+#endif
+
+#ifdef PID_T_MISSING
+typedef int pid_t;
+#endif
+
+#endif
diff --git a/sdk/std/select.h b/sdk/std/select.h
new file mode 100644
index 0000000..2812581
--- /dev/null
+++ b/sdk/std/select.h
@@ -0,0 +1,21 @@
+/*
+ * Find or use "replacement" select routines.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and use see license.
+ */
+
+#ifndef __STD_SELECT_H__
+#define __STD_SELECT_H__
+
+#ifdef SELECT_H_MISSING
+#ifndef SYS_SELECT_H_MISSING
+#include <sys/select.h>
+#endif
+#else
+#include <select.h>
+#endif
+
+#include <std/time.h>
+
+#endif
diff --git a/sdk/std/signal.h b/sdk/std/signal.h
new file mode 100644
index 0000000..b56b48a
--- /dev/null
+++ b/sdk/std/signal.h
@@ -0,0 +1,11 @@
+#ifndef __STD_SIGNAL_H__
+#define __STD_SIGNAL_H__
+
+#ifndef __CONFIG_H__
+#include <config.h>
+#endif
+
+#include <signal.h>
+
+#endif
+
diff --git a/sdk/std/string.c b/sdk/std/string.c
new file mode 100644
index 0000000..6f9649e
--- /dev/null
+++ b/sdk/std/string.c
@@ -0,0 +1,110 @@
+/*
+ * Define constants used by other string services and case insensitive
+ * compare and conversion functions missing in some libc distributions.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <std/string.h>
+
+#ifdef STRLWR_F_MISSING
+
+char *strlwr(char *s)
+{
+ char *old;
+
+ if(!s)
+ return NULL;
+
+ old=s;
+ while(*s = (char)tolower(*s))
+ ++s;
+
+ return old;
+}
+
+char *strupr(char *s)
+{
+ char *old;
+
+ if(!s)
+ return NULL;
+
+ old=s;
+ while(*s = (char)toupper(*s))
+ ++s;
+ return old;
+}
+
+#endif
+
+#ifdef STRDUP_F_MISSING
+
+char *strdup(str)
+char *str;
+{
+ char *new = (char *)malloc(strlen(str) + 1);
+ if(!new)
+ return NULL;
+
+ return strcpy(new, str);
+}
+
+#endif
+
+#ifdef STRICMP_F_MISSING
+
+int stricmp(const char *s1, const char *s2)
+{
+ int t;
+
+ while(*s1 && *s2)
+ {
+ if (t=tolower(*s1)-tolower(*s2))
+ return t;
+
+ ++s1;
+ ++s2;
+ }
+ return tolower(*s1)-tolower(*s2);
+}
+
+int strnicmp(const char *s1,const char *s2, size_t n)
+{
+ int t;
+
+ while (n--)
+ {
+ if (t=tolower(*s1)-tolower(*s2))
+ return t;
+
+ if (!*s1)
+ return 0;
+
+ ++s1;
+ ++s2;
+ }
+ return 0;
+}
+
+#endif
+
+#ifdef STRISTR_F_MISSING
+
+char *stristr(char *s1, const char *s2)
+{
+ int len = strlen(s2);
+ int count = strlen(s1) - len + 1;
+
+ while(count--)
+ {
+ if(!strnicmp(s1, s2, len))
+ return s1;
+ ++s1;
+ }
+ return NULL;
+}
+
+#endif
+
diff --git a/sdk/std/string.h b/sdk/std/string.h
new file mode 100644
index 0000000..bf642cf
--- /dev/null
+++ b/sdk/std/string.h
@@ -0,0 +1,75 @@
+/*
+ * Portable string handling routines.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#ifndef __STD_STRINGS_H__
+#define __STD_STRINGS_H__
+
+#ifndef __STD_TYPES_H__
+#include <std/types.h>
+#endif
+
+#include <string.h>
+#include <ctype.h>
+
+#ifndef STRCASECMP_F_MISSING
+#define stricmp(s1, s2) strcasecmp(s1, s2)
+#define strnicmp(s1, s2, n) strncasecmp(s1, s2, n)
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __NAMESPACE
+#define __SPACES __NAMESPACE(__SPACES)
+#endif
+
+extern char __SPACES[];
+
+#ifdef STRICMP_F_MISSING
+#ifdef __NAMESPACE
+#define stricmp __NAMESPACE(stricmp)
+#define strnicmp __NAMESPACE(strnicmp)
+#endif
+
+int stricmp(const char *s1, const char *s2);
+int strnicmp(const char *s1, const char *s2, size_t n);
+#endif
+
+#ifdef STRLWR_F_MISSING
+
+#ifdef __NAMESPACE
+#define strupr __NAMESPACE(strupr)
+#define strlwr __NAMESPACE(strlwr)
+#endif
+
+char *strlwr(char *s1);
+char *strupr(char *s2);
+#endif
+
+#ifdef STRDUP_F_MISSING
+
+#ifdef __NAMESPACE
+#define strdup __NAMESPACE(strdup)
+#endif
+
+char *strdup(const char *s);
+#endif
+
+#ifdef STRISTR_F_MISSING
+#ifdef __NAMESPACE
+#define stristr __NAMESPACE(stristr)
+#endif
+
+char *stristr(char *s1, const char *s2);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sdk/std/sysexits.h b/sdk/std/sysexits.h
new file mode 100644
index 0000000..208ec0e
--- /dev/null
+++ b/sdk/std/sysexits.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)sysexits.h 4.8 (Berkeley) 4/3/91
+ */
+
+#ifndef _SYSEXITS_H
+#define _SYSEXITS_H
+
+/*
+ * SYSEXITS.H -- Exit status codes for system programs.
+ *
+ * This include file attempts to categorize possible error
+ * exit statuses for system programs, notably delivermail
+ * and the Berkeley network.
+ *
+ * Error numbers begin at EX__BASE to reduce the possibility of
+ * clashing with other exit statuses that random programs may
+ * already return. The meaning of the codes is approximately
+ * as follows:
+ *
+ * EX_USAGE -- The command was used incorrectly, e.g., with
+ * the wrong number of arguments, a bad flag, a bad
+ * syntax in a parameter, or whatever.
+ * EX_DATAERR -- The input data was incorrect in some way.
+ * This should only be used for user's data & not
+ * system files.
+ * EX_NOINPUT -- An input file (not a system file) did not
+ * exist or was not readable. This could also include
+ * errors like "No message" to a mailer (if it cared
+ * to catch it).
+ * EX_NOUSER -- The user specified did not exist. This might
+ * be used for mail addresses or remote logins.
+ * EX_NOHOST -- The host specified did not exist. This is used
+ * in mail addresses or network requests.
+ * EX_UNAVAILABLE -- A service is unavailable. This can occur
+ * if a support program or file does not exist. This
+ * can also be used as a catchall message when something
+ * you wanted to do doesn't work, but you don't know
+ * why.
+ * EX_SOFTWARE -- An internal software error has been detected.
+ * This should be limited to non-operating system related
+ * errors as possible.
+ * EX_OSERR -- An operating system error has been detected.
+ * This is intended to be used for such things as "cannot
+ * fork", "cannot create pipe", or the like. It includes
+ * things like getuid returning a user that does not
+ * exist in the passwd file.
+ * EX_OSFILE -- Some system file (e.g., /etc/passwd, /etc/utmp,
+ * etc.) does not exist, cannot be opened, or has some
+ * sort of error (e.g., syntax error).
+ * EX_CANTCREAT -- A (user specified) output file cannot be
+ * created.
+ * EX_IOERR -- An error occurred while doing I/O on some file.
+ * EX_TEMPFAIL -- temporary failure, indicating something that
+ * is not really an error. In sendmail, this means
+ * that a mailer (e.g.) could not create a connection,
+ * and the request should be reattempted later.
+ * EX_PROTOCOL -- the remote system returned something that
+ * was "not possible" during a protocol exchange.
+ * EX_NOPERM -- You did not have sufficient permission to
+ * perform the operation. This is not intended for
+ * file system problems, which should use NOINPUT or
+ * CANTCREAT, but rather for higher level permissions.
+ */
+
+#define EX_OK 0 /* successful termination */
+
+#define EX__BASE 64 /* base value for error messages */
+
+#define EX_USAGE 64 /* command line usage error */
+#define EX_DATAERR 65 /* data format error */
+#define EX_NOINPUT 66 /* cannot open input */
+#define EX_NOUSER 67 /* addressee unknown */
+#define EX_NOHOST 68 /* host name unknown */
+#define EX_UNAVAILABLE 69 /* service unavailable */
+#define EX_SOFTWARE 70 /* internal software error */
+#define EX_OSERR 71 /* system error (e.g., can't fork) */
+#define EX_OSFILE 72 /* critical OS file missing */
+#define EX_CANTCREAT 73 /* can't create (user) output file */
+#define EX_IOERR 74 /* input/output error */
+#define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */
+#define EX_PROTOCOL 76 /* remote error in protocol */
+#define EX_NOPERM 77 /* permission denied */
+#define EX_CONFIG 78 /* configuration error */
+
+#define EX__MAX 78 /* maximum listed value */
+
+#endif /* !_SYSEXITS_H */
diff --git a/sdk/std/time.h b/sdk/std/time.h
new file mode 100644
index 0000000..45c42cb
--- /dev/null
+++ b/sdk/std/time.h
@@ -0,0 +1,23 @@
+/*
+ * Portable header access into time functions.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#ifndef __STD_TIME_H__
+#define __STD_TIME_H__
+
+#ifndef __CONFIG_H__
+#include <config.h>
+#endif
+
+#include <time.h>
+
+#ifndef SYS_TIME_H_MISSING
+#include <sys/time.h>
+#endif
+
+#endif
+
+
diff --git a/sdk/std/types.h b/sdk/std/types.h
new file mode 100644
index 0000000..ebd4ea7
--- /dev/null
+++ b/sdk/std/types.h
@@ -0,0 +1,54 @@
+/*
+ * Portable common datatype declarations.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#ifndef __STD_TYPES_H__
+#define __STD_TYPES_H__
+
+#ifndef __CONFIG_H__
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <stdlib.h>
+
+#ifdef UCHAR_T_MISSING
+typedef unsigned char uchar;
+#endif
+
+#ifdef USHORT_T_MISSING
+typedef unsigned short ushort;
+#endif
+
+#ifdef ULONG_T_MISSING
+typedef unsigned long ulong;
+#endif
+
+#ifdef __cplusplus
+enum
+{
+ FALSE=0,
+ TRUE
+};
+#else
+typedef enum
+{
+ FALSE=0,
+ TRUE
+} bool;
+#endif
+
+typedef void *ptr_t;
+
+#ifdef SIZE_T_MISSING
+typedef unsigned int size_t;
+#endif
+
+#ifdef SSIZE_T_MISSING
+typedef int ssize_t;
+#endif
+
+#endif
diff --git a/sdk/std/utmp.c b/sdk/std/utmp.c
new file mode 100644
index 0000000..78cbf64
--- /dev/null
+++ b/sdk/std/utmp.c
@@ -0,0 +1,49 @@
+/*
+ * Portable emulation of utmp access routines, such as for broken BSD.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and use see license.
+ */
+
+#include <std/utmp.h>
+#include <std/files.h>
+
+#ifdef GETUTENT_F_MISSING
+
+static fd_t ut = -1;
+static struct utmp utmp;
+
+void setutent(void)
+{
+ if(ut < 0)
+ ut = open(_PATH_UTMP, O_RDONLY);
+ if(ut < 0)
+ return;
+
+ lseek(ut, 0l, SEEK_SET);
+}
+
+void endutent(void)
+{
+ if(ut > -1)
+ {
+ close(ut);
+ ut = -1;
+ }
+}
+
+struct utmp *getutent(void)
+{
+ if(ut < 0)
+ setutent();
+
+ if(ut < 0)
+ return NULL;
+
+ if(read(ut, &utmp, sizeof(utmp)) < sizeof(utmp))
+ return NULL;
+
+ return &utmp;
+}
+
+#endif
diff --git a/sdk/std/utmp.h b/sdk/std/utmp.h
new file mode 100644
index 0000000..2ac67f4
--- /dev/null
+++ b/sdk/std/utmp.h
@@ -0,0 +1,31 @@
+/*
+ * utmp file access interface, local or ported.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and use see license.
+ */
+
+#ifndef __STD_UTMP_H__
+#define __STD_UTMP_H__
+
+#ifndef __STD_TYPES_H__
+#include <std/types.h>
+#endif
+
+#include <utmp.h>
+
+#ifndef _UTMP_PATH
+#define _UTMP_PATH "/etc/utmp.h"
+#endif
+
+#ifdef UT_USER_I_MISSING
+#define ut_user ut_name
+#endif
+
+#ifdef GETUTENT_F_MISSING
+void setutent(void);
+void endutent(void);
+struct utmp *getutent(void);
+#endif
+
+#endif
diff --git a/speak.lsm b/speak.lsm
new file mode 100644
index 0000000..d96b4d5
--- /dev/null
+++ b/speak.lsm
@@ -0,0 +1,23 @@
+Begin3
+Title: SPO256-AL2 Text-to-Speech Services
+Version: 1.0
+Entered-date: March 23, 1997
+Description: This package comprises a network TCP text-to-speech server
+ designed for the SPO256-AL2 text-to-speech board, as
+ described in the January '97 issue of the Linux Journal.
+ This server is now implemented as a generic rc.d startable
+ "service" with standardized (server independent) utilities,
+ and may be used to develop other network-wide text-to-speech
+ services for different hardware. This release adds new
+ functionality to both the server and vmon utilities.
+Keywords: talk, cti, tsw, tycho, lj, spo256, vocoder
+Author: dyfet@tycho.com (David Sugar)
+Maintained-by: dyfet@tycho.com (David Sugar)
+Primary-site: ftp.tycho.com /dist
+ 58 kb speak-0.3.tar.gz
+ 1 kb speak.lsm
+Alternate-site: sunsite.unc.edu: no idea where
+Original-site: http://www.tycho.com/packages/speak
+Platform: Should be portable to virtually any UNIX system.
+Copying-policy: Free, public, terms similar to BSD on redistribution.
+End
diff --git a/spktrapd/README.NOW b/spktrapd/README.NOW
new file mode 100644
index 0000000..957e196
--- /dev/null
+++ b/spktrapd/README.NOW
@@ -0,0 +1,8 @@
+Future package!
+
+The spktrapd module will be a snmptrapd that redirects snmp traps verbally to
+the speak service using device and enterprise specific rules and tables.
+This will allow verbal monitering and alerts for a variety of network
+devices.
+
+
diff --git a/spo256/Makefile.in b/spo256/Makefile.in
new file mode 100644
index 0000000..6e21ea4
--- /dev/null
+++ b/spo256/Makefile.in
@@ -0,0 +1,34 @@
+#
+# Template to build spo256-AL2 text-to-speech server.
+# $Id: Makefile.in 1.2 Mon, 24 Mar 1997 12:25:37 -0500 dyfet $
+# Copyright (c) 1997 by Tycho Softworks.
+#
+
+OBJS = speak.o spo.o getspo.o words.o chars.o getidx.o client.o \
+ number.o currency.o
+PROGS = spo256
+START = 10
+RUNLVLS = 3
+
+all: $(PROGS)
+
+install: $(PROGS)
+ install -s -g bin $(PROGS) $(SBINDIR)
+ ln -sf $(SBINDIR)/spo256 $(BINDIR)/speak
+ install -g bin speak.conf $(SYSCONFDIR)
+ ../sdk/bin/instinit speak $(START) $(RUNLVLS)
+ ../sdk/bin/instsvc services speak 800/tcp \# SPO256-AL2 Text-to-Speech service
+ ../sdk/bin/instman $(MANDIR) 1 speak
+ ../sdk/bin/instman $(MANDIR) 7 speak.conf
+ ../sdk/bin/instman $(MANDIR) 8 spo256
+
+clean:
+ -rm $(PROGS)
+ -rm $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) $(OPTIMIZE) -I../sdk -o $@ -c $<
+
+spo256: $(OBJS)
+ $(CC) $(CFLAGS) -L../sdk/lib $(LIBS) -o $@ $(OBJS) $(LIBS)
+
diff --git a/spo256/README b/spo256/README
new file mode 100644
index 0000000..29c2fae
--- /dev/null
+++ b/spo256/README
@@ -0,0 +1,24 @@
+This particular SPO256 server is able to translate common usages for numbers
+and perform word substitution. For example, the number 123.45 is pronounced
+as "one hundred twenty three point four five". Internet names and addresses
+are also pronounced correctly to a large extent. The support of different
+usages and idioms in this server is not yet as complete as the WorldVU SPO
+server, but this is being worked on.
+
+The SPO server was rewritten in release 0.3 with a character state parser
+to allow better parsing for and pacing of spoken text. The 0.3 state
+parser now recognizes embedded server command sequences as well as text
+that is to be spoken. Embedded server commands are proceeded by the
+<ESC> character, and appear in <>'s, using a format much like mark-up tags.
+For example, word "spelling" can be turned on or off with <ESC><spell> and
+<ESC></spell>. The current tags supported by the SPO256 server are found
+in the spo256 man page. More tags will be added as they appear feasable to
+create.
+
+This SPO server differs from the original WorldVU server in that it can
+also be used in a client role to pipe standard output to the server. One
+can enter "cat filename | spo256 localhost" (or "cat filename | speak
+localhost") to redirect output to the spo server running on the local
+machine, for example.
+
+
diff --git a/spo256/chars.c b/spo256/chars.c
new file mode 100644
index 0000000..e4b2a2a
--- /dev/null
+++ b/spo256/chars.c
@@ -0,0 +1,339 @@
+/*
+ * Character state parser for text-to-speech server.
+ * $Id: chars.c 1.2 Mon, 24 Mar 1997 12:25:37 -0500 dyfet $
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <other/string.h>
+#include <other/config.h>
+#include <std/files.h>
+#include <std/process.h>
+#include "speak.h"
+
+enum
+{
+ CH_IGNORE,
+ CH_PERIOD,
+ CH_QUOTE,
+ CH_ESCAPE,
+ CH_SPACE,
+ CH_ALPHA,
+ CH_NUMERIC,
+ CH_PUNCT,
+};
+
+static uchar map[256];
+static uchar word[256];
+static int cpos = 0;
+static bool init = FALSE;
+static void (*state)(uchar ch);
+static bool quote;
+
+static void s_hex(uchar ch);
+static void s_num(uchar ch);
+static void s_cmd(uchar ch);
+static void s_leadcmd(uchar ch);
+static void s_abbrev(uchar ch);
+static void s_point(uchar ch);
+static void s_word(uchar ch);
+static void s_idle(uchar ch);
+
+static void s_hex(uchar ch)
+{
+ switch(ch)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case 'a':
+ case 'A':
+ case 'b':
+ case 'B':
+ case 'c':
+ case 'C':
+ case 'd':
+ case 'D':
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'F':
+ word[cpos++] = ch;
+ break;
+ default:
+ word[cpos] = 0;
+ number(word);
+ state = s_idle;
+ s_idle(ch);
+ }
+}
+
+static void s_num(uchar ch)
+{
+ switch(map[ch])
+ {
+ case CH_NUMERIC:
+ word[cpos++] = ch;
+ break;
+ default:
+ switch(ch)
+ {
+ case 'e':
+ case '^':
+ word[cpos++] = ch;
+ number(word);
+ cpos = 0;
+ spo_word("raised");
+ spo_word("to");
+ spo_word("the");
+ spo_word("power");
+ break;
+ case ':':
+ case '/':
+ case '.':
+ word[cpos++] = ch;
+ break;
+ case '%':
+ word[cpos] = 0;
+ number(word);
+ state = s_idle;
+ spo_word("percent");
+ break;
+ case 'x':
+ case 'X':
+ if(cpos == 1)
+ {
+ cpos = 0;
+ state = s_hex;
+ break;
+ }
+ default:
+ word[cpos] = 0;
+ number(word);
+ state = s_idle;
+ s_idle(ch);
+ }
+ }
+}
+
+static void s_cmd(uchar ch)
+{
+ if(ch == '>')
+ {
+ word[cpos] = 0;
+ spo_cmd((char *)word);
+ state = s_idle;
+ }
+ else
+ word[cpos++] = ch;
+}
+
+static void s_leadcmd(uchar ch)
+{
+ if(ch == '<')
+ state = s_cmd;
+ else
+ {
+ state = s_idle;
+ s_idle(ch);
+ }
+}
+
+static void s_abbrev(uchar ch)
+{
+ switch(map[ch])
+ {
+ case CH_SPACE:
+ abbrev((char *)word);
+ state = s_idle;
+ break;
+ default:
+ spo_word((char *)word);
+ cpos = 0;
+ spo_word("dot");
+ state = s_word;
+ s_word(ch);
+ }
+}
+
+static void s_point(uchar ch)
+{
+ switch(map[ch])
+ {
+ case CH_ALPHA:
+ state = s_word;
+ case CH_PERIOD:
+ spo_word("dot");
+ break;
+ case CH_NUMERIC:
+ spo_word("point");
+ state = s_num;
+ break;
+ default:
+ state = s_idle;
+ break;
+ }
+}
+
+static void s_word(uchar ch)
+{
+ switch(map[ch])
+ {
+ case CH_PERIOD:
+ if(!cpos)
+ state = s_point;
+ else
+ state = s_abbrev;
+ word[cpos++] = '.';
+ word[cpos] = 0;
+ break;
+ case CH_PUNCT:
+ case CH_ALPHA:
+ case CH_NUMERIC:
+ if(cpos < 255)
+ word[cpos++] = ch;
+ break;
+ case CH_SPACE:
+ word[cpos] = 0;
+ spo_word((char *)word);
+ state = s_idle;
+ break;
+ default:
+ switch(ch)
+ {
+ case '\'':
+ word[cpos++] = ch;
+ break;
+ default:
+ word[cpos] = 0;
+ spo_word((char *)word);
+ spo_pause(P_WORD);
+ state = s_idle;
+ s_idle(ch);
+ }
+ }
+}
+
+static void s_idle(uchar ch)
+{
+ cpos = 0;
+ switch(map[ch])
+ {
+ case CH_NUMERIC:
+ state = s_num;
+ s_num(ch);
+ break;
+ case CH_ALPHA:
+ state = s_word;
+ s_word(ch);
+ break;
+ case CH_ESCAPE:
+ state = s_leadcmd;
+ break;
+ case CH_SPACE:
+ spo_pause(P_WORD);
+ break;
+ case CH_QUOTE:
+ if(quote)
+ {
+ spo_word("end");
+ quote = FALSE;
+ }
+ else
+ quote = TRUE;
+ spo_word("quote");
+ break;
+ default:
+ switch(ch)
+ {
+ case '$':
+ word[0] = '$';
+ cpos = 1;
+ state = s_num;
+ break;
+ case '*':
+ spo_word("times");
+ break;
+ case '/':
+ spo_word("divided");
+ spo_word("by");
+ break;
+ case '+':
+ spo_word("plus");
+ break;
+ case '-':
+ spo_word("minus");
+ break;
+ case '&':
+ spo_word("and");
+ break;
+ case '|':
+ spo_word("or");
+ break;
+ case '~':
+ spo_word("not");
+ break;
+ case ')':
+ spo_word("end");
+ case '(':
+ spo_word("parenthesis");
+ break;
+ case '=':
+ spo_word("equals");
+ break;
+ case '<':
+ spo_word("less");
+ spo_word("than");
+ break;
+ case '>':
+ spo_word("greater");
+ spo_word("than");
+ break;
+ default:
+ spo_pause(P_WORD);
+ }
+ }
+}
+
+void chars(FILE *fp)
+{
+ int i, ch;
+
+ quote = FALSE;
+ state = s_idle;
+
+ if(!init)
+ {
+ for(i = 0; i < 256; ++i)
+ map[i] = CH_IGNORE;
+
+ map[27] = CH_ESCAPE;
+
+ for(i = 33; i < 127; ++i)
+ map[i] = CH_PUNCT;
+
+ map[9] = map[13] = map[10] = map[32] = CH_SPACE;
+ for(i = 48; i < 58; ++i)
+ map[i] = CH_NUMERIC;
+
+ for(i = 0; i < 26; ++i)
+ {
+ map[i + 65] = CH_ALPHA;
+ map[i + 97] = CH_ALPHA;
+ }
+ map['.'] = CH_PERIOD;
+ map['\"'] = CH_QUOTE;
+ }
+
+ while(EOF != (ch = fgetc(fp)))
+ (*state)(ch);
+
+ (*state)(0);
+}
diff --git a/spo256/client.c b/spo256/client.c
new file mode 100644
index 0000000..b43696f
--- /dev/null
+++ b/spo256/client.c
@@ -0,0 +1,40 @@
+/*
+ * Client operating mode.
+ * $Id: client.c 1.2 Mon, 24 Mar 1997 12:25:37 -0500 dyfet $
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ *
+ * Abstract:
+ * The client mode of operation will connect to SPO256 server and
+ * redirect standard output to the server. This allows the speak
+ * (spo256) image to be used to terminate pipes.
+ */
+
+#include <std/process.h>
+#include <other/string.h>
+#include <std/files.h>
+#include <other/config.h>
+#include <net/socket.h>
+#include <net/stream.h>
+#include "speak.h"
+
+void client(char *hostname, ushort port)
+{
+ STREAM fp = opentcp(hostname, port);
+ char buf[1024];
+
+ if(!fp)
+ fatal(EX_UNAVAILABLE, "spo256: %s: unkown host\n", hostname);
+
+ gettcp(buf, sizeof(buf) - 1, fp); /* get banner line */
+ while(!feof(stdin))
+ {
+ fgets(buf, sizeof(buf) - 1, stdin);
+ if(feof(stdin))
+ break;
+
+ puttcp(buf, fp);
+ }
+ closetcp(fp);
+ exit(0);
+}
diff --git a/spo256/currency.c b/spo256/currency.c
new file mode 100644
index 0000000..b79c036
--- /dev/null
+++ b/spo256/currency.c
@@ -0,0 +1,43 @@
+/*
+ * Currency rules, for USD.
+ * $Id: currency.c 1.2 Mon, 24 Mar 1997 12:25:37 -0500 dyfet $
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <other/string.h>
+#include <other/config.h>
+#include "speak.h"
+
+void currency(char *str)
+{
+ char *cents;
+ ++str;
+
+ cents = strchr(str, '.');
+ if(cents)
+ *(cents++) = 0;
+
+ if(atol(str) != 0)
+ {
+ number(str);
+ if(atol(str) > 1)
+ spo_word("dollars");
+ else
+ spo_word("dollar");
+ }
+
+ if(cents)
+ {
+ if(atol(str) > 0)
+ spo_word("and");
+
+ number(cents);
+ if(atoi(cents) > 1)
+ spo_word("cent");
+ else
+ spo_word("cents");
+ }
+}
+
+
diff --git a/spo256/getidx.c b/spo256/getidx.c
new file mode 100644
index 0000000..70a730c
--- /dev/null
+++ b/spo256/getidx.c
@@ -0,0 +1,98 @@
+/*
+ * Build word and abbreviation index in memory from .conf.
+ * $Id: getidx.c 1.2 Mon, 24 Mar 1997 12:25:37 -0500 dyfet $
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <other/string.h>
+#include <other/config.h>
+#include <std/files.h>
+#include <std/process.h>
+#include <other/memory.h>
+#include "speak.h"
+
+MEMPOOL *mem;
+IDX **widx, **aidx;
+
+static int key(uchar *str)
+{
+ unsigned int k = 0;
+ int len = strlen((char *)str);
+
+ while(*str)
+ {
+ k = (k * 7) | (*str & 0x1f);
+ ++str;
+ }
+
+ k |= len;
+
+ return (k % KEYSIZE);
+}
+
+void getidx(CONFIG *cfg)
+{
+ int i;
+ char *p, *q;
+ IDX *new;
+
+ mem = mempool(16384, 16);
+
+ widx = (IDX **)memreq(mem, sizeof(IDX *) * KEYSIZE);
+ aidx = (IDX **)memreq(mem, sizeof(IDX *) * KEYSIZE);
+
+
+ for(i = 0; i < KEYSIZE; ++i)
+ widx[i] = aidx[i] = NULL;
+
+ seek_config(cfg, "words");
+ while(NULL != (p = read_config(cfg)))
+ {
+ q = strchr(p, '=');
+ if(!q)
+ continue;
+
+ *(q++) = 0;
+ p = strtrim(p, __SPACES);
+ q = strtrim(q, __SPACES);
+ i = key((uchar *)p);
+ new = memlreq(mem, sizeof(IDX));
+ new->word_link = widx[i];
+ widx[i] = new;
+ new->word_key = strreq(mem, p);
+ new->word_spo = strreq(mem, q);
+ }
+ seek_config(cfg, "abbrev");
+ while(NULL != (p = read_config(cfg)))
+ {
+ q = strchr(p, '=');
+ if(!q)
+ continue;
+
+ *(q++) = 0;
+ p = strtrim(p, __SPACES);
+ q = strtrim(q, __SPACES);
+ i = key((uchar *)p);
+ new = memlreq(mem, sizeof(IDX));
+ new->word_link = aidx[i];
+ aidx[i] = new;
+ new->word_key = strreq(mem, p);
+ new->word_spo = strreq(mem, q);
+ }
+}
+
+char *find(IDX **table, char *str)
+{
+ IDX *next = table[key((uchar *)str)];
+
+
+ while(next)
+ {
+ if(!stricmp(str, next->word_key))
+ return next->word_spo;
+
+ next = next->word_link;
+ }
+ return NULL;
+}
diff --git a/spo256/getspo.c b/spo256/getspo.c
new file mode 100644
index 0000000..5ff64d7
--- /dev/null
+++ b/spo256/getspo.c
@@ -0,0 +1,68 @@
+/*
+ * Parse .conf file interface spec for spo communications.
+ * $Id: getspo.c 1.2 Mon, 24 Mar 1997 12:25:37 -0500 dyfet $
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <other/string.h>
+#include <other/config.h>
+#include <std/files.h>
+#include <proc/process.h>
+#include <dev/tty.h>
+
+char *mask = NULL;
+
+int getspo(CONFIG *cfg)
+{
+ int spo = -1;
+ char *p;
+ stty_t stty;
+
+ if(!seek_config(cfg, "interface"))
+ fatal(EX_CONFIG, "spo256: [interface]: missing from speak.conf\n");
+
+ while(NULL != read_config(cfg))
+ {
+ if(NULL != (p = get_config(cfg, "bind")))
+ {
+ mask = strdup(p);
+ continue;
+ }
+
+ if(NULL != (p = get_config(cfg, "device")))
+ {
+ spo = open(p, O_RDWR);
+ if(spo < 0)
+ fatal(EX_UNAVAILABLE, "spo256: %s: cannot access\n", p);
+ stty = getstty(spo);
+ interactive(stty, FALSE);
+ setflowctrl(stty, FC_HARD);
+ continue;
+ }
+
+ if(NULL != (p = get_config(cfg, "speed")))
+ {
+ if(spo < 0)
+ fatal(EX_CONFIG, "spo256: set speed for unspecified device\n");
+ setspeed(stty, atol(p));
+ continue;
+ }
+
+ if(NULL != (p = get_config(cfg, "parity")))
+ {
+ if(spo < 0)
+ fatal(EX_CONFIG, "spo256: set format for unspecified device\n");
+ if(!stricmp(p, "even"))
+ setformat(stty, "7e1");
+ if(!stricmp(p, "odd"))
+ setformat(stty, "7o1");
+ if(!stricmp(p, "none"))
+ setformat(stty, "8n1");
+ continue;
+ }
+ }
+ putstty(spo, stty, TRUE);
+ return spo;
+}
+
diff --git a/spo256/number.c b/spo256/number.c
new file mode 100644
index 0000000..16c662a
--- /dev/null
+++ b/spo256/number.c
@@ -0,0 +1,132 @@
+/*
+ * Number base pronounciation rules and special cases.
+ * $Id: number.c 1.2 Mon, 24 Mar 1997 12:25:37 -0500 dyfet $
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ */
+
+#include <other/string.h>
+#include <other/config.h>
+#include "speak.h"
+
+static char *nteen[] = {
+ "ten", "eleven", "twelve", "thirteen", "fourteen",
+ "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"};
+
+static char *n10[] = {
+ "zero", "ten", "twenty", "thirty", "fourty",
+ "fifty", "sixty", "seventy", "eighty", "ninety"};
+
+
+static void digits(long value)
+{
+ bool hundred = FALSE;
+ char buf[2];
+
+ if(value >= 100)
+ {
+ digits(value / 100);
+ spo_word("hundred");
+ value %= 100;
+ hundred = TRUE;
+ }
+
+ if(!value && hundred)
+ return;
+
+ if(value >= 20)
+ {
+ spo_word(n10[value / 10]);
+ value %= 10;
+ if(!value)
+ return;
+ }
+
+ if(value < 10)
+ {
+ buf[0] = value + '0';
+ buf[1] = 0;
+ spo_word(buf);
+ return;
+ }
+ spo_word(nteen[value - 10]);
+}
+
+void number(char *str)
+{
+ char *p;
+ long value = atol(str);
+
+ if(lit || spell)
+ {
+ spo_word(str);
+ return;
+ }
+
+ /* Check for w.x.y.z as "w dot x dot y dot z" */
+
+ if(ccount(str, ".") > 1)
+ {
+ while(NULL != (p = strchr(str, '.')))
+ {
+ *(p++) = 0;
+ number(str);
+ str = p;
+ }
+ number(str);
+ return;
+ }
+
+ if(NULL != (p = strchr(str, '.')))
+ {
+ *(p++) = 0;
+ number(str);
+ spo_word("point");
+ spo_word(p);
+ return;
+ }
+
+ if(NULL != (p = strchr(str, ':')))
+ {
+ digits(atol(str));
+ ++p;
+ if(atol(p) < 10)
+ if(atol(p))
+ write(spo, " O ", 2);
+
+ if(atol(p))
+ digits(atol(p));
+
+ if(NULL != (p = strchr(p, ':')))
+ {
+ spo_word("and");
+ digits(atol(++p));
+ spo_word("seconds");
+ }
+ else
+ {
+ p = str;
+ if(strchr(p, 'a') || strchr(p, 'A'))
+ write(spo, "A M ", 5);
+ if(strchr(p, 'p') || strchr(p, 'P'))
+ write(spo, "P M ", 5);
+ }
+ return;
+ }
+
+ if(value >= 1000000l)
+ {
+ digits(value / 1000000l);
+ spo_word("million");
+ value %= 1000000l;
+ }
+
+ if(value >= 1000)
+ {
+ digits(value / 1000);
+ spo_word("thousand");
+ value %= 1000;
+ }
+
+ digits(value);
+}
diff --git a/spo256/speak.1 b/spo256/speak.1
new file mode 100644
index 0000000..8ceac59
--- /dev/null
+++ b/spo256/speak.1
@@ -0,0 +1,46 @@
+.TH "speak" "1" "January 1997" "Speak 0.2" "Text-to-Speech"
+.PP
+.SH NAME
+.PP
+\fBspeak\fP - send output to text-to-speech service.
+.PP
+.SH SYNOPSIS
+.PP
+\fBspeak\fP [\fIhostname\fP]
+.PP
+.SH DESCRIPTION
+.PP
+The Text-to-speech package introduces a standard TCP/IP port service for
+attaching text-to-speech resources to your network. These resources can
+be used to monitor system status, provide verbal alarms, etc. This network
+service may be accessed by telnetting to a machine running a "speak" server,
+or by using the various application utilities, such as \fBspeak\fP.
+.PP
+
+The \fBspeak\fP program will capture and redirect all standard input to the
+network speech server, such as \fBspo256\fP, running either on the
+local machine ("\fIlocalhost\fP"), or to the server running on the host
+specified as a command line argument. \fBspeak\fP is normally used to
+terminate a pipe, such as in "\fIcat filename | speak\fP". The TCP service
+port used for the connection is specified in \fI/etc/services\fP.
+
+.PP
+While most of the text-to-speech programs are separately written, the
+\fBspeak\fP program is normally an alias for the actual server itself,
+such as the \fBspo256\fP program. This was intentional, as future
+versions of speak may drive hardware directly in an alternate usage
+(such as "\fIspeak /dev/ttyxx\fP"), as well as redirecting output to a named
+host.
+
+.PP
+.SH SEE ALSO
+.PP
+.BR say (1),
+.BR down (8),
+.BR spo256 (8),
+.BR services (7)
+.PP
+.SH AUTHOR
+.PP
+David Sugar (dyfet@tycho.com)
+.PP
diff --git a/spo256/speak.8 b/spo256/speak.8
new file mode 100644
index 0000000..aaeceef
--- /dev/null
+++ b/spo256/speak.8
@@ -0,0 +1,39 @@
+.TH "spo256" "8" "1997" "Text-to-Speech services" "Tycho Softworks"
+.PP
+.SH "NAME spo256 \- SPO256-AL2 Text-to-Speech Server"
+.PP
+.SH "SYNOPSIS"
+.PP
+\fBspo256\fP
+.br
+\fBspeak\fP [hostname]
+.PP
+.SH "DESCRIPTION"
+.PP
+.SH "FILES"
+.PP
+The spo256 server configuration may be found in \fB/etc/speak.conf\fP.
+.PP
+.SH "SEE ALSO"
+.PP
+.IP
+.IP o
+\fBdown(8)\fP: Shuts down the system.
+.IP
+.IP o
+\fBsay(1)\fP: Sends output to a "speak" server.
+.IP
+.IP o
+\fBservices(5)\fP: Installed TCP/IP network services.
+.IP
+.PP
+.SH "DIAGNOSTICS"
+.PP
+\fBspo256\fP will warn and fail to load if the "speak" services entry
+is missing, if the device cannot be opened, or if the speak.conf file
+is missing.
+.PP
+.SH "AUTHOR"
+.PP
+David Sugar (dyfet@tycho.com)
+.PP
diff --git a/spo256/speak.c b/spo256/speak.c
new file mode 100644
index 0000000..7de099f
--- /dev/null
+++ b/spo256/speak.c
@@ -0,0 +1,86 @@
+/*
+ * Base (main) for spo server.
+ * $Id: speak.c 1.2 Mon, 24 Mar 1997 12:25:37 -0500 dyfet $
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ *
+ * Abstract:
+ * Establish basic operating environment for SPO256-AL2 text-to-speech
+ * server. This module verifies system configuration, parses the
+ * config files for word lists that are stored in the quick-lookup
+ * internal hash word subsitution database, binds the server to a tcp
+ * network port, and accepts client requests.
+ */
+
+#include <proc/process.h>
+#include <std/string.h>
+#include <std/files.h>
+#include <other/config.h>
+#include <net/socket.h>
+#include <net/stream.h>
+#include "speak.h"
+
+int spo; /* device id of spo */
+FILE *io;
+
+void main(int argc, char **argv)
+{
+ int port = getservice("speak");
+ CONFIG *cfg;
+ SOCKET so;
+ char buf[1024];
+
+ if(!port)
+ fatal(EX_UNAVAILABLE, "spo256: speak: service not defined in /etc/services\n");
+
+ if(argc < 1 || argc > 2)
+ fatal(EX_USAGE, "use: spo256 [hostname]\n");
+
+ if(argc > 1)
+ client(argv[1], port);
+
+ if(!stricmp(pathfname(argv[0]), "speak"))
+ client("localhost", port);
+
+ if(NULL == (cfg = sys_config("speak")))
+ fatal(EX_CONFIG, "spo256: speak.conf: config file missing\n");
+
+ /* get device configuration */
+
+ spo = getspo(cfg);
+
+ getidx(cfg);
+ close_config(cfg);
+
+ /* bind server to socket */
+
+ so = tcpsocket(mask, port, 5);
+ if(so == INVALID_SOCKET)
+ fatal(EX_UNAVAILABLE, "spo256: %d: failed to bind port\n", port);
+
+ /* now, make ourselves a daemon */
+
+ pdetach(D_KEEPNONIO);
+
+ /* Main loop of server. The server accepts one connection in
+ turn from each requesting user application. The remaining
+ application requests are kept in backlog while the current
+ application is served. This assures non-overlapping speech.
+ */
+
+ for(;;)
+ {
+ io = accepttcp(so);
+ if(!io)
+ continue;
+
+ spo_init();
+ puttcp("SPO256-AL2 Text-to-Speech Server 1.0\r\n", io);
+
+ chars(io);
+
+ spo_pause(P_END);
+ closetcp(io);
+ }
+}
+
diff --git a/spo256/speak.conf.7 b/spo256/speak.conf.7
new file mode 100644
index 0000000..ccc3e57
--- /dev/null
+++ b/spo256/speak.conf.7
@@ -0,0 +1,72 @@
+.TH "speak.conf" "7" "January 1997" "Speak 0.2" "Text-to-Speech"
+.PP
+.SH NAME
+.PP
+\fBspeak.conf\fP - configuration file for text-to-speech services.
+.PP
+.SH SYNOPSIS
+.PP
+\fBspeak.conf\fP
+.PP
+.SH DESCRIPTION
+.PP
+The \fBspeak.conf\fP file is a text edit-able configuration file used by the
+text-to-speech server and various text-to-speech utilities.
+.PP
+\fBspeak.conf\fP is divided into sections, donated with "[]"'s. These
+sections include hardware parameters for the text-to-speech server used on the
+local machine, translation tables used for phonetic dictionaries by text-to-
+speech servers, and runtime default information for specific programs. On
+machines that do not run their own text-to-speech server, \fBspeak.conf\fP
+will still be used to specify runtime defaults for utility programs that are
+present.
+.PP
+.SH FILE FORMAT
+.PP
+The file consists of sections and parameters. A section begins with the
+name of the section in square brackets and continues until the next section
+begins. Sections contain parameters of the form \'name = value`'.
+.PP
+The file is line-based text - that is, each newline-terminated line
+represents either a comment, a section name, or a parameter. Parameters
+in the .conf file normally do not appear on multiple lines, except for
+several specific exceptions (lists and tables) that are not used in this
+package.
+.PP
+Section and parameter names are not case sensitive.
+.PP
+Only the first equal sign in a parameter is significant. Whitepsaces before
+or after the = are ignored. Leading and trailing whitespaces are ignored.
+Whitepaces within a parameter name are also ignored, while whitespaces
+within a parameter value are preserved.
+.PP
+Any line beginning with a semicolon or a pound sign is treated as a comment
+and is ignored.
+.PP
+Any line containing a list, in the form 'name = { v1 v2 v3 }' may be
+continued over multiple lines if the terminating '}' is not found in the
+current line.
+.PP
+Any line beginning with a plus is considered a repeat of the "name =" portion
+of the last parameter line. This is often used to build up hostname lists
+when multiple hostnames may be specified.
+.PP
+The parameter value may either be quoted or unquoted. Quoted parameters
+values may be used to specify lead or trailing spaces which would otherwise
+be ignored. Either matching single or double quotes may be used, and the
+quotes are not kept as part of the value returned to the application.
+.PP
+Parameter values may either be strings, numeric values, or boolean flags.
+When a boolean parameter is used, the characters "T" for 'true' and "F" for
+'false' may be used. The full word, "true" and "false", may also be
+spelled out. "Y" or "Yes" and "N" or "No" may also be used for "true" or
+"false".
+.PP
+.SH SEE ALSO
+.PP
+.BR speak (1)
+.PP
+.SH AUTHOR
+.PP
+David Sugar (dyfet@tycho.com)
+.PP
diff --git a/spo256/speak.h b/spo256/speak.h
new file mode 100644
index 0000000..07b9875
--- /dev/null
+++ b/spo256/speak.h
@@ -0,0 +1,48 @@
+/*
+ * Master header for spo server.
+ * $Id$
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and use see license.
+ *
+ * Abstract:
+ * Define internal hash index system to quickly find text for
+ * substitutions. The spo-256 is driven by substitution tables
+ * which provide alternate spellings to adjust mis-pronounced
+ * speech.
+ */
+
+typedef enum
+{
+ P_END, /* Finish line off, send SPO-end mark */
+ P_LINE, /* Send nl because we have a empty line */
+ P_SENTANCE, /* Pause at end of sentance (nl) */
+ P_WORD /* Inter-word delay (spaces) */
+} PAUSE;
+
+#define KEYSIZE 791 /* Size of internal hash database keyrange */
+
+typedef struct _idx
+{
+ struct _idx *word_link; /* hash link chain */
+ char *word_key; /* initial word & hash key */
+ char *word_spo; /* substitute spelling */
+} IDX;
+
+extern int spo;
+extern IDX **widx, **aidx;
+extern char *mask;
+extern FILE *io;
+extern bool echo, spell, lit;
+
+void abbrev(char *str);
+int getspo(CONFIG *cfg);
+void getidx(CONFIG *cfg);
+char *find(IDX **table, char *str);
+void client(char *hostname, ushort port);
+
+void spo_init(void);
+void spo_cmd(char *str);
+void spo_word(char *str);
+void spo_pause(PAUSE);
+void spo_begquote(void);
+void spo_endquote(void);
diff --git a/spo256/speak.init b/spo256/speak.init
new file mode 100644
index 0000000..0c46b8a
--- /dev/null
+++ b/spo256/speak.init
@@ -0,0 +1,54 @@
+#!/bin/sh
+
+# modify FILESYSTEMS to activate and use vmon.
+FILESYSTEMS="/"
+
+mode=$1
+
+if [ $# = 0 ] ; then
+ mode='rc'
+fi
+
+if [ ! "$mode" = 'rc' ] ; then
+ # Source function library.
+ . /etc/rc.d/init.d/functions
+
+ # Source networking configuration.
+ . /etc/sysconfig/network
+
+ # Check that networking is up.
+ [ ${NETWORKING} = "no" ] && exit 0
+fi
+
+# See how we were called.
+case "$mode" in
+ rc)
+ echo "Starting SPO256-AL2 server"
+ spo256
+ if [ ! -z "$FILESYSTEMS" ] ; then
+ vmon $FILESYSTEMS
+ fi
+ ;;
+ start)
+ echo -n "Starting SPO256-AL2 speech services: "
+ daemon spo256
+ if [ ! -z "$FILESYSTEMS" ] ; then
+ daemon vmon $FILESYSTEMS
+ fi
+ echo
+ touch /var/lock/subsys/speak
+ ;;
+ stop)
+ echo -n "Shutting down SPO256-AL2 speech services: "
+ killproc spo256
+ if [ ! -z "$FILESYSTEMS" ] ; then
+ killproc vmon
+ fi
+ rm -f /var/lock/subsys/speak
+ echo ""
+ ;;
+ *)
+ echo "Usage: speak.init {start|stop}"
+ exit 1
+esac
+
diff --git a/spo256/spo.c b/spo256/spo.c
new file mode 100644
index 0000000..5c4f7ec
--- /dev/null
+++ b/spo256/spo.c
@@ -0,0 +1,161 @@
+/*
+ * SPO256 low level operations.
+ * $Id: spo.c 1.2 Mon, 24 Mar 1997 12:25:37 -0500 dyfet $
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions on distribution and reuse see product license.
+ *
+ * Abstract:
+ * Key SPO translation modules. This includes the word substution
+ * module, the numeric pronounciation system, pause control, and
+ * other low level spo services.
+ */
+
+#include <other/config.h>
+#include <other/string.h>
+#include "speak.h"
+
+/*
+ * Flags and operating mode properties that may now be effected by
+ * server commands.
+ */
+
+bool echo = FALSE; /* echo SPO output to user? */
+bool spell = FALSE; /* spell all words? */
+bool lit = FALSE; /* literally pronounce as is? */
+
+/*
+ * A new 'init' function is added to initialize operating state for
+ * each new connection. This assures that spo command sequences
+ * issued from a previous session are not left in effect.
+ */
+
+void spo_init(void)
+{
+ echo = FALSE; /* echo off by default */
+ spell = FALSE;
+ lit = FALSE;
+};
+
+/*
+ * Interpret server specific commands embedded in <ESC><cmd>
+ * sequences. The SPO has limited options to effect in this manner.
+ */
+
+void spo_cmd(char *str)
+{
+ if(!stricmp(str, "echo"))
+ {
+ echo = TRUE;
+ return;
+ }
+
+ if(!stricmp(str, "/echo"))
+ {
+ echo = FALSE;
+ return;
+ }
+
+ if(!stricmp(str, "spell"))
+ {
+ spell = TRUE;
+ return;
+ }
+
+ if(!stricmp(str, "/spell"))
+ {
+ spell = FALSE;
+ return;
+ }
+
+ if(!stricmp(str, "lit"))
+ {
+ lit = TRUE;
+ return;
+ }
+
+ if(!stricmp(str, "/lit"))
+ {
+ lit = FALSE;
+ return;
+ }
+};
+
+/*
+ * Pause spo output between words, numbers, and empty lines, so that
+ * words are properly announciated. This is typically accomplished with
+ * spaces and newline control.
+ */
+
+void spo_pause(PAUSE p)
+{
+ switch(p)
+ {
+ case P_WORD:
+ write(spo, " ", 1);
+ if(echo)
+ puttcp(" ", io);
+ break;
+ case P_SENTANCE:
+ write(spo, " \n", 2);
+ if(echo)
+ puttcp(" \n", io);
+ break;
+ case P_LINE:
+ write(spo, " \r\n", 3);
+ if(echo)
+ puttcp(" \r\n", io);
+ break;
+ case P_END:
+ write(spo, "\r\n", 2);
+ }
+}
+
+/* Announce quoted text. */
+
+void spo_begquote(void)
+{
+ spo_word("quote");
+}
+
+void spo_endquote(void)
+{
+ spo_word("end");
+ spo_begquote();
+}
+
+/*
+ * This performs low level lookup and pronounciation of words, either
+ * in the originally submitted spelling, or in the spo dictionary
+ * spelling.
+ */
+
+void spo_word(char *word)
+{
+ char *p = find(widx, word);
+ if(!p)
+ p = word;
+
+ if(lit)
+ p = word;
+
+ if(spell)
+ {
+ p = word;
+ while(*p)
+ {
+ write(spo, p, 1);
+ if(echo)
+ fputc(*p, io);
+ spo_pause(P_WORD);
+ ++p;
+ }
+ }
+ else
+ {
+ write(spo, p, strlen(p));
+ if(echo)
+ puttcp(p, io);
+ }
+ spo_pause(P_WORD);
+}
+
diff --git a/spo256/spo256.8 b/spo256/spo256.8
new file mode 100644
index 0000000..a0826ad
--- /dev/null
+++ b/spo256/spo256.8
@@ -0,0 +1,98 @@
+.TH "spo256" "8" "January 1997" "Speak 0.2" "Text-to-Speech"
+.PP
+.SH NAME
+.PP
+\fBspo256\fP - text-to-speech server for SPO256-AL2 chipset.
+.PP
+.SH SYNOPSIS
+.PP
+\fBspo256\fP
+.PP
+.SH DESCRIPTION
+.PP
+The \fBspo256\fP server provides a TCP/IP service interface for controlling
+a serial based SPO256-AL2 text-to-speech chip. The server binds to the
+"\fIspeak\fP" port defined in /etc/services and attaches to the serial
+tty device specified in the [\fIinterface\fP] section of \fBspeak.conf\fP.
+The server accepts a single TCP session from a client application at a time,
+streaming that client's text to the SPO device. The server corrects
+pronunciation of words, numbers, and common usages by performing in-stream
+text substitution before sending output to the SPO.
+.PP
+.SH INSTALLATION
+.PP
+The \fBspo256\fP server is meant to be started during system initialization
+(usually for run level 3). A \fBspeak.init\fP script is installed into
+/etc/rc.d, and this script will be linked to a numbered phase in the
+/etc/rc3.d directory. This final linkage is now part of the 'make install'
+supplied and should work for Linux, and perhaps other UNIX systems with
+similar rc.d directory and file layouts. The \fBspo256\fP service can
+normally start immediately after network services (\fIS10network\fP) have ran.
+.PP
+For BSD style systems, the speak.init script is installed as 'rc.speak'. For
+systems that have different naming schemes for the rc.d scripts, some
+additional work may be needed to correctly install speak.init. The
+\fBspo256\fP server may also be ran directly from the command line For
+testing, and the \fBspo256\fP command can simply be added to the
+\fIrc.local\fP file.
+.PP
+The make install will add an entry to \fB/etc/services\fP for the TCP speak
+port. By default, I normally use port 800. Since no effort has been made
+to register text-to-speech as a defined Internet port service, it is quite
+conceivable port 800 may at some point be defined for another service. If
+this happens, simply edit the /etc/services file as needed.
+.PP
+The [\fIinterface\fP] section of \fB/etc/speak.conf\fP will need to be
+edited before you start \fBspo256\fP for the first time. The entry for
+\fIdevice\fP should be given the correct tty serial port where your SPO
+board is attached. The speed I choose to use is 2400bps, which is the
+maximum speed the board is capable of. Valid values for parity include
+"odd", "even", and "none". Also verify board jumpers
+are set for the speed and data format specified in [\fIinterface\fP].
+.PP
+.SH "CORRECTIVE SPEECH"
+.PP
+The [\fIwords\fP] section of \fBspeak.conf\fP holds a list of text
+substitutions. These substitutions correct the inability of the SPO to
+correctly pronounce may words. Since the SPO provides no direct access
+to the low-level phonetic dictionary, these substitute spellings may
+appear odd. Sometimes, words are broken into multiple words with spaces,
+such as "online", which is sent to the SPO as "on lyne". Basically,
+through trial and error, one can build up a substitution table that works
+for the device.
+.PP
+The [\fIabbrev\fP] section simply provides the meaning behind commonly
+used abbreviations, so that they are spoken out correctly. Abbreviations
+are presumed to terminate with a '.', such as "Dr.", "Mr.", and are
+represented in a table separate from the text substitution table.
+.PP
+.SH SERVER COMMANDS
+.PP
+Server commands were introduced with the third release of the SPO256
+server. These commands are formed as "tags" which appear as part of the
+output stream sent to the server. These tags are preceeded by the <ESC>
+character, and are held in <>'s (much like HTML tags). Server commands
+that are supported by different speech servers may very widly to support
+features such as volume level, tone, inflection, etc. The limited set
+of commands supported by the SPO server are as follows:
+.PP
+The <\fIecho\fP> and <\fI/echo\fP> tags may be used to turn echo on and
+off. When echo is enabled, the output that is actually sent to the SPO
+device (including corrected spellings) is also echo'd back to the client
+that is connected to the server.
+.PP
+The <\fIspell\fP> and <\fI/spell\fP> tags may be used to turn spelling of
+words on and off. In spelling mode, each letter of each word is spoken.
+This should not be confused with <\fIlit\fP> and <\fI/lit\fP>, which are
+used to disable the word lookup function so that text as actually sent
+to the server is sent unprocessed to the SPO board.
+.PP
+.SH SEE ALSO
+.PP
+.BR speak.conf (7),
+.BR services (7)
+.PP
+.SH AUTHOR
+.PP
+David Sugar (dyfet@tycho.com)
+.PP
diff --git a/spo256/word.c b/spo256/word.c
new file mode 100644
index 0000000..2150837
--- /dev/null
+++ b/spo256/word.c
@@ -0,0 +1,38 @@
+/*
+
+ Word base pronounciation rules and special cases.
+*/
+
+#include <ctype.h>
+#include <std/types.h>
+#include <std/string.h>
+#include <std/config.h>
+#include "speak.h"
+
+void word(char *str)
+{
+ char *p;
+
+ /* Internet x@y as "x at y" */
+
+ if(NULL != (p = strchr(str, '@')))
+ {
+ *(p++) = 0;
+ word(str);
+ word("at");
+ word(p);
+ return;
+ }
+
+ /* Check for x.y.z as "x dot y dot z" */
+
+ while(NULL != (p = strchr(str, '.')))
+ {
+ *(p++) = 0;
+ spo_word(str);
+ spo_word("dot");
+ str = p;
+ }
+
+ spo_word(str);
+}
diff --git a/spo256/words.c b/spo256/words.c
new file mode 100644
index 0000000..19c8d57
--- /dev/null
+++ b/spo256/words.c
@@ -0,0 +1,34 @@
+/*
+
+ Each line of input from the client application is examined and split
+ into words, numbers, abbreviations, and special catagories for further
+ translation from free-form text to SPO spoken speech. Generally a
+ word is a collection of characters grouped by white-space markers
+ (nl, tab, and space). Special consideration is also given to quoting
+ properties. Additional rules may be applied once words have been
+ catagorized.
+*/
+
+#include <other/string.h>
+#include <other/config.h>
+#include <std/string.h>
+#include "speak.h"
+
+void abbrev(char *str)
+{
+ char *p;
+
+ if(!lit && !spell)
+ p = find(aidx, str);
+
+ if(p)
+ spo_word(p);
+ else
+ {
+ p = tail(str);
+ *(--p) = 0;
+ spo_word(str);
+ spo_pause(P_SENTANCE);
+ }
+}
+
diff --git a/utils/Makefile.in b/utils/Makefile.in
new file mode 100644
index 0000000..8ff750c
--- /dev/null
+++ b/utils/Makefile.in
@@ -0,0 +1,31 @@
+#
+# Template to build speak utilities.
+# $Id: Makefile.in 1.2 Mon, 24 Mar 1997 12:25:37 -0500 dyfet $
+# Copyright (c) 1997 by Tycho Softworks.
+#
+
+UPROGS = say
+SPROGS = down vmon
+PROGS = $(SPROGS) $(UPROGS)
+
+all: $(PROGS)
+
+install: $(PROGS)
+ install -s -g bin $(UPROGS) $(BINDIR)
+ install -s -g bin $(SPROGS) $(SBINDIR)
+ ln -sf $(SBINDIR)/vmon $(SBINDIR)/vstat
+ ../sdk/bin/instman $(MANDIR) 1 say
+ ../sdk/bin/instman $(MANDIR) 8 down vmon
+
+clean:
+ rm $(PROGS)
+
+say: say.c
+ $(CC) $(CFLAGS) $(OPTIMIZE) -I../sdk -L../sdk/lib -o $@ say.c $(LIBS)
+
+down: down.c
+ $(CC) $(CFLAGS) $(OPTIMIZE) -I../sdk -L../sdk/lib -o $@ down.c $(LIBS)
+
+vmon: vmon.c
+ $(CC) $(CFLAGS) $(OPTIMIZE) -I../sdk -L../sdk/lib -o $@ vmon.c $(LIBS)
+
diff --git a/utils/README b/utils/README
new file mode 100644
index 0000000..66d3435
--- /dev/null
+++ b/utils/README
@@ -0,0 +1,9 @@
+This section includes portable 'speak' service based utilities. These
+utilities are being ported from the original WorldVU SPO speak services. So
+far, only "say", "down", and "vmon" have been ported. Additional
+utilities to be added will include a new non-WorldVU related user session
+announcement daemon, perhaps as part of vmon. The original user session
+monitoring utility was closely tied into the WorldVU user cluster
+monitoring system.
+
+
diff --git a/utils/down.8 b/utils/down.8
new file mode 100644
index 0000000..fe0b81d
--- /dev/null
+++ b/utils/down.8
@@ -0,0 +1,44 @@
+.TH "down" "8" "January 1997" "Speak 0.2" "Text-to-Speech"
+.PP
+.SH NAME
+.PP
+\fBdown\fP - warn and then shutdown system.
+.PP
+.SH SYNOPSIS
+.PP
+\fBdown\fP [\fIseconds\fP]
+.PP
+.SH DESCRIPTION
+.PP
+The Text-to-speech package introduces a standard TCP/IP port service for
+attaching text-to-speech resources to your network. These resources can
+be used to monitor system status, provide verbal alarms, etc. This network
+service may be accessed by telnetting to a machine running a "speak" server,
+or by using the various application utilities, such as \fBdown\fP.
+.PP
+
+The \fBdown\fP program will provide a warning with a countdown that may
+be aborted. When the countdown reaches 0, your system will begin a normal
+shutdown and reboot. The warning and countdown is shown on screen and
+spoken over the text-to-speech interface. The \fBdown\fP program uses the
+[\fIdown\fP] information in \fBspeak.conf\fP for default values. Only an
+alternate countdown (in seconds) may be specified via a command line
+argument.
+
+.PP
+The [\fIdown\fP] section specifies a default timer to use, the hostname
+where the speech server is running, and the program to execute to bring
+the system down. If you are using \fBdown\fP on a machine that does not
+have it's own text-to-speech server, then you will need to create a local
+\fB/etc/speak.conf\fP file on that machine with at minimum a [\fIdown\fP]
+section with an entry for the text-to-speech host server to use.
+
+.PP
+.SH SEE ALSO
+.PP
+.BR speak.conf (7)
+.PP
+.SH AUTHOR
+.PP
+David Sugar (dyfet@tycho.com)
+.PP
diff --git a/utils/down.c b/utils/down.c
new file mode 100644
index 0000000..66d9d19
--- /dev/null
+++ b/utils/down.c
@@ -0,0 +1,129 @@
+/*
+ * A verbal system shutdown utility.
+ * $Id: down.c 1.2 Mon, 24 Mar 1997 12:25:37 -0500 dyfet $
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions of distribution and reuse see product license.
+ *
+ * Abstract:
+ * A verbal system shutdown utility. You may need to adjust the name
+ * of the shutdown program used. This gives some warning and then
+ * initiates the shutdown processing, unless cancelled in time.
+ */
+
+#include <std/signal.h>
+#include <proc/process.h>
+#include <other/string.h>
+#include <std/files.h>
+#include <other/config.h>
+#include <net/stream.h>
+
+static char host[128] = "localhost";
+static char halt[60] = "/sbin/halt";
+static char abort_msg[] = "System shutdown overriden. Resuming normal operation.\n";
+static char down_msg[] = "%s system shutdown sequence initiated. You have %d seconds to override.\n";
+static int timer = 10;
+static STREAM fp = NULL;
+
+/*
+ * If the user aborts the shutdown, then we send the cancellation message
+ * and gracefully exit the scene.
+ */
+
+static void abort_sig()
+{
+ if(fp)
+ {
+ puttcp(abort_msg, fp);
+ closetcp(fp);
+ }
+ fputs("\n", stdout);
+ exit(-1);
+}
+
+void main(int argc, char **argv)
+{
+ char *p;
+ char *reboot = halt;
+ int port = getservice("speak");
+ CONFIG *cfg = sys_config("speak");
+ char hostname[128];
+
+ if(argc < 1 || argc > 2)
+ fatal(EX_USAGE, "use: down [timer]\n");
+
+ if(!port)
+ fatal(EX_UNAVAILABLE, "down: speak: service unlisted in /etc/services\n");
+
+ if(!cfg)
+ fatal(EX_CONFIG, "down: speak.conf: config missing\n");
+
+ seek_config(cfg, "down");
+ while(read_config(cfg))
+ {
+ if(NULL != (p = get_config(cfg, "timer")))
+ {
+ timer = atoi(p);
+ continue;
+ }
+
+ if(NULL != (p = get_config(cfg, "halt")))
+ {
+ strcpy(halt, p);
+ continue;
+ }
+
+ if(NULL != (p = get_config(cfg, "host")))
+ {
+ strcpy(host, p);
+ continue;
+ }
+
+ if(NULL != (p = get_config(cfg, "server")))
+ {
+ strcpy(host, p);
+ continue;
+ }
+ }
+ close_config(cfg);
+ if(argc > 1)
+ timer = atoi(argv[1]);
+
+ fp = opentcp(host, port);
+ if(!fp)
+ fatal(EX_UNAVAILABLE, "down: %s: speak service unreachable\n", host);
+
+ printf("System shutdown initiated...use <break> to override; ");
+ fflush(stdout);
+ signal(SIGINT, abort_sig);
+ gettcp(hostname, 127, fp);
+ gethostname(hostname, 80);
+ fprintf(fp, down_msg, hostname, timer);
+ fflush(fp);
+ sleep(strlen(down_msg) / 9 + 1);
+
+ /* count down timer until 0 */
+
+ while(timer)
+ {
+ printf("%d ", timer);
+ fflush(stdout);
+ fprintf(fp, "%d\n", timer);
+ fflush(fp);
+ sleep(1);
+ --timer;
+ }
+
+ /* too late now!! */
+
+ signal(SIGINT, SIG_IGN);
+ printf("\n");
+ closetcp(fp);
+
+ /* detach return to user and execute reboot program */
+
+ pdetach(D_KEEPALL);
+ argv[0] = reboot;
+ argv[1] = NULL;
+ execvp(reboot, argv);
+}
+
diff --git a/utils/say.1 b/utils/say.1
new file mode 100644
index 0000000..1807b76
--- /dev/null
+++ b/utils/say.1
@@ -0,0 +1,35 @@
+.TH "say" "1" "January 1997" "Speak 0.2" "Text-to-Speech"
+.PP
+.SH NAME
+.PP
+\fBsay\fP - send output string to text-to-speech service.
+.PP
+.SH SYNOPSIS
+.PP
+\fBspeak\fP \fIhostname\fP "\fImessage\fP"
+.PP
+.SH DESCRIPTION
+.PP
+The Text-to-speech package introduces a standard TCP/IP port service for
+attaching text-to-speech resources to your network. These resources can
+be used to monitor system status, provide verbal alarms, etc. This network
+service may be accessed by telnetting to a machine running a "speak" server,
+or by using the various application utilities, such as \fBsay\fP.
+.PP
+
+The \fBsay\fP program will send a specified string of text to a specified
+network speech server. The intent is to use say to produce verbal output
+much like the way "echo" may be used to create screen output. \fBsay\fP
+will form a momentary connection with the speech server (such as
+\fBspo256\fP), send the message, and then disconnect. The TCP
+service port used for the connection is specified in \fI/etc/services\fP.
+
+.PP
+.SH SEE ALSO
+.PP
+.BR speak (1)
+.PP
+.SH AUTHOR
+.PP
+David Sugar (dyfet@tycho.com)
+.PP
diff --git a/utils/say.c b/utils/say.c
new file mode 100644
index 0000000..b774eaf
--- /dev/null
+++ b/utils/say.c
@@ -0,0 +1,34 @@
+/*
+ * Send text to speech server. May be used in script files.
+ * $Id: say.c 1.2 Mon, 24 Mar 1997 12:25:37 -0500 dyfet $
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions on distribution and reuse see product license.
+ */
+
+#include <std/string.h>
+#include <std/process.h>
+#include <net/stream.h>
+
+void main(int argc, char **argv)
+{
+ STREAM fp;
+ int port = getservice("speak");
+ char buf[128];
+
+ if(argc != 3)
+ fatal(EX_USAGE, "use: say host \"message\"\n");
+
+ if(!port)
+ fatal(EX_UNAVAILABLE, "say: speak: service not in /etc/services\n");
+
+ fp = opentcp(argv[1], port);
+ if(!fp)
+ fatal(EX_UNAVAILABLE, "say: %s: speak service unavailable\n", argv[1]);
+
+ gettcp(buf, 127, fp);
+ puttcp(argv[2], fp);
+ puttcp("\n", fp);
+ closetcp(fp);
+}
+
+
diff --git a/utils/vmon.8 b/utils/vmon.8
new file mode 100644
index 0000000..84a1308
--- /dev/null
+++ b/utils/vmon.8
@@ -0,0 +1,65 @@
+.TH "vmon" "8" "January 1997" "Speak 0.2" "Text-to-Speech"
+.PP
+.SH NAME
+.PP
+\fBvmon\fP - monitor system status (town crier).
+.PP
+.SH SYNOPSIS
+.PP
+\fBvmon\fP \fIfilesystems\fP
+.br
+\fBvstat\fP \fIfilesystems\fP
+.PP
+.SH DESCRIPTION
+.PP
+The Text-to-speech package introduces a standard TCP/IP port service for
+attaching text-to-speech resources to your network. These resources can
+be used to monitor system status, provide verbal alarms, etc. This network
+service may be accessed by telnetting to a machine running a "speak" server,
+or by using the various application utilities, such as \fBvmon\fP.
+.PP
+
+The \fBvmon\fP program will monitor the specified list of file systems.
+If any of these file systems exceed a maximum "quota" (such as over 90%
+capacity in blocks or i-node use), then the monitor will send verbal
+alerts every 5 minutes. This quota, and other parameters for vmon, may
+be found in the [\fIvmon\fP] section of \fBspeak.conf\fP.
+.PP
+
+The \fBvmon\fP program will also announce current system status once
+every hour. This system status includes the total used capacity of
+all file systems being monitored, how long the system has been up, and
+how many users are currently logged in (excluding root). This hourly
+announcement can be used to determine a given system is still alive.
+.PP
+
+The \fBvmon\fP program will now also monitor specified user mailboxes
+for new mail and announce when new mail arrives. The users to be
+monitored are specified in the [\fIvmon\fP] section of \fBspeak.conf\fP.
+Simply list mailbox= entries for each mailbox you wish to monitor. See
+the example speak.conf included with the distribution.
+.PP
+
+The \fBvmon\fP program can also be ran as \fBvstat\fP. When used as
+\fBvstat\fP, the program performs an immediate system check, announces,
+and then terminates. You can either use \fBvstat\fP from a crontab or
+start \fBvmon\fP from \fBspeak.init\fP. You may also start \fBvmon\fP
+from a \fBrc.local\fP file. Please check the \fBspeak.init\fP file
+to add any file systems you wish to monitor. By default, the root
+filesystem is enabled in \fBspeak.init\fP.
+.PP
+
+A mute option may also be specified in the [\fIvmon\fP] section of
+\fBspeak.conf\fP. This option mutes voice output during certain times of
+the day. This is normally specified by 24 hour clock in hours, hence 18-7
+means to mute output anytime after 18' hours (6pm) and anytime before 7'
+hours (7am).
+.PP
+.SH SEE ALSO
+.PP
+.BR speak.conf (7)
+.PP
+.SH AUTHOR
+.PP
+David Sugar (dyfet@tycho.com)
+.PP
diff --git a/utils/vmon.c b/utils/vmon.c
new file mode 100644
index 0000000..e1015b4
--- /dev/null
+++ b/utils/vmon.c
@@ -0,0 +1,442 @@
+/* Verbal monitor system status.
+ * $Id: vmon.c 1.2 Mon, 24 Mar 1997 12:25:37 -0500 dyfet $
+ * Copyright (c) 1997 by Tycho Softworks.
+ * For conditions on distribution and reuse see product license.
+ *
+ * Abstract:
+ * Monitor system status in background. This service is normally
+ * started with the speech server. It may also be ran as 'vstat'
+ * to perform immediate notification.
+ */
+
+#include <std/time.h>
+#include <other/string.h>
+#include <proc/process.h>
+#include <other/config.h>
+#include <net/stream.h>
+#include <std/utmp.h>
+
+/* For systems that use statfs! */
+
+#ifdef __linux__
+#include <sys/vfs.h>
+#define __statfs__
+#endif
+
+typedef struct _MAILBOX
+{
+ struct _MAILBOX *next;
+ time_t update;
+ ulong size;
+ char name[0];
+} MAILBOX;
+
+static int freq = 3600;
+static int timer = 3600;
+static int interval = 300;
+static int iter;
+static int orig_timer;
+static int alert = 90; /* warn on 90% full */
+static char alertmsg[] = "emergency alert emergency alert \r\n";
+static char **fs;
+static char host[128] = "localhost";
+static int mute[2] = {24, 0};
+
+static char *vmailbox(MAILBOX *mbox)
+{
+ struct stat ino;
+ static char buf[80];
+
+ if(stat(mbox->name, &ino))
+ return NULL;
+
+ if(!ino.st_size)
+ {
+ mbox->size = 0;
+ return NULL;
+ }
+
+ if(ino.st_size == mbox->size)
+ return NULL;
+
+ if(mbox->size == -1)
+ {
+ mbox->size = ino.st_size;
+ return NULL;
+ }
+
+ mbox->size = ino.st_size;
+ sprintf(buf, "User %s has new mail\n", mbox->name);
+ return buf;
+}
+
+static void vmbox(MAILBOX *box, int port)
+{
+ STREAM fp = NULL;
+ char *p;
+ time_t now;
+ struct tm *dt;
+ char buf[128];
+
+ time(&now);
+ dt = localtime(&now);
+ if(dt->tm_hour > mute[0] || dt->tm_hour < mute[1])
+ return;
+
+ while(box)
+ {
+ p = vmailbox(box);
+ if(!p)
+ {
+ box = box->next;
+ continue;
+ }
+ if(!fp)
+ {
+ fp = opentcp(host, port);
+ if(!fp)
+ return;
+
+ gettcp(buf, sizeof(buf) - 1, fp);
+ }
+ puttcp(p, fp);
+ box = box->next;
+ }
+ if(fp)
+ closetcp(fp);
+}
+
+static int vstat(int port)
+{
+ int i = 0;
+ char *f;
+ long btotal = 0;
+ long bfree = 0;
+ bool failed = FALSE;
+ STREAM fp = NULL;
+#ifdef __statfs__
+ struct statfs fnode;
+#endif
+ int blocks, inodes;
+ char buf[128];
+ int newtimer = orig_timer;
+ time_t now;
+ static prior = -1;
+ struct tm *dt;
+ int apm, hour;
+ char *apmstr[] = {" A M ", " P M "};
+ int fd;
+ struct utmp *utmp, uptime;
+ int users = 0;
+ int utcnt = 0;
+
+#ifdef __statfs__
+ while(fs[i])
+ {
+ if(!statfs(fs[i], &fnode))
+ {
+ btotal += fnode.f_blocks;
+ bfree += fnode.f_bfree;
+ blocks = 100 - (int)(fnode.f_ffree / (fnode.f_files / 100l));
+ inodes = 100 - (int)(fnode.f_bfree / (fnode.f_blocks / 100l));
+ if((blocks < alert) && (inodes < alert))
+ {
+ ++i;
+ continue;
+ }
+ }
+ else
+ {
+ inodes = 0;
+ blocks = 0;
+ failed = TRUE;
+ }
+ if(!fp)
+ {
+ fp = opentcp(host, port);
+ if(!fp)
+ {
+ newtimer = 300;
+ break;
+ }
+ gettcp(buf, 128, fp);
+ puttcp(alertmsg, fp);
+ }
+
+ if(blocks > alert)
+ fprintf(fp, "File system %s is %d percent full.\r\n", fs[i], blocks);
+
+ if(inodes > alert)
+ fprintf(fp, "File system %s i-node table is %d percent full.\r\n", fs[i], inodes);
+
+ if(failed)
+ fprintf(fp, "File system %s is dismounted or failed\r\n", fs[i]);
+
+ fflush(fp);
+ newtimer = 60;
+ ++i;
+ }
+#endif
+
+ if(fp)
+ closetcp(fp);
+
+ time(&now);
+ if(prior == (now / freq))
+ return newtimer;
+
+ if(prior == -1)
+ prior = now / freq - 1;
+ else
+ prior = now / freq;
+
+ dt = localtime(&now);
+ hour = dt->tm_hour % 12;
+ if(dt->tm_hour > mute[0] || dt->tm_hour < mute[1])
+ return newtimer;
+
+ if(!hour)
+ hour = 12;
+
+ if(dt->tm_hour > 11)
+ apm = 1;
+ else
+ apm = 0;
+
+ fp = opentcp(host, port);
+ if(!fp)
+ return newtimer;
+
+ gettcp(buf, 128, fp);
+ fprintf(fp, "It is %d:%d %s \r\n", hour, dt->tm_min, apmstr[apm]);
+ fflush(fp);
+
+ fd = open("/proc/uptime", O_RDONLY);
+ hour = -1;
+ if(fd > -1)
+ {
+ read(fd, buf, 128);
+ close(fd);
+ hour = atol(buf) / 3600;
+ }
+
+#if defined(BOOT_TIME) || defined(RUN_LVL)
+ if(hour == -1)
+ {
+ utmp = NULL;
+ memset(&uptime, 0, sizeof(uptime));
+#ifdef BOOT_TIME
+ setutent();
+ uptime.ut_type = BOOT_TIME;
+ utmp = getutid(&uptime);
+#endif
+#ifdef RUN_LVL
+ if(!utmp)
+ {
+ setutent();
+ uptime.ut_type = RUN_LVL;
+ utmp = getutid(&uptime);
+ }
+#endif
+ if(utmp)
+ hour = (now - utmp->ut_time) / 3600l;
+
+ endutent();
+ }
+#endif
+
+ if(hour > -1)
+ {
+ if(hour == 1)
+ fprintf(fp, "The system has been up 1 hour\r\n");
+ else if(hour < 48)
+ fprintf(fp, "The system has been up %d hours\r\n", hour);
+ else
+ fprintf(fp, "The system has been up %d days\r\n", hour / 24);
+ fflush(fp);
+ }
+
+ setutent();
+ while(NULL != (utmp = getutent()))
+ {
+ ++utcnt;
+
+#ifdef USER_PROCESS
+ if(utmp->ut_type != USER_PROCESS)
+ continue;
+#endif
+
+ utmp->ut_user[sizeof(utmp->ut_user)] = 0;
+ if(!strcmp(utmp->ut_user, "root"))
+ continue;
+
+ if(!utmp->ut_user[0])
+ continue;
+
+ if(!utmp->ut_line[0])
+ continue;
+
+#ifdef USER_PROCESS
+ if(kill(utmp->ut_pid, 0))
+ continue;
+#endif
+
+ ++users;
+ }
+ endutent();
+
+ if(utcnt)
+ {
+ if(!users)
+ fprintf(fp, "There are no users online\r\n");
+ else if(users == 1)
+ fprintf(fp, "There is 1 user online\r\n");
+ else
+ fprintf(fp, "There are %d users online\r\n", users);
+ fflush(fp);
+ }
+
+ if(btotal)
+ {
+ fprintf(fp, "The main system drives are at %d percent of capacity\r\n",
+ 100 - (int)(bfree / (btotal / 100)));
+ fflush(fp);
+ }
+
+ closetcp(fp);
+ return newtimer;
+}
+
+void main(int argc, char **argv)
+{
+ int port = getservice("speak");
+ char *maildir = getenv("MAILDIR");
+ MAILBOX *mbox = NULL, *newbox;
+ char *prog = basename(*argv);
+ CONFIG *cfg = sys_config("speak");
+ time_t now;
+ char *p;
+
+ if(argc < 2)
+ fatal(EX_USAGE, "use %s filesystems...\n", prog);
+
+ if(!maildir)
+ maildir = "/var/spool/mail";
+
+ fs = ++argv;
+
+ if(!port)
+ fatal(EX_UNAVAILABLE, "%s: speak: service unavailable\n", prog);
+
+ if(!cfg)
+ fatal(EX_UNAVAILABLE, "%s: speak.conf: missing\n", prog);
+
+ seek_config(cfg, "vmon");
+ while(read_config(cfg))
+ {
+ if(NULL != (p = get_config(cfg, "mailbox")))
+ {
+ p = strtok(p, __SPACES);
+ while(p)
+ {
+ newbox = (MAILBOX *)malloc(sizeof(MAILBOX) + strlen(p) + 1);
+ newbox->next = mbox;
+ time(&newbox->update);
+ newbox->size = -1l;
+ strcpy(newbox->name, p);
+ mbox = newbox;
+ p = strtok(NULL, __SPACES);
+ }
+ continue;
+ }
+
+ if(NULL != (p = get_config(cfg, "interval")))
+ {
+ interval = atoi(p) * 60;
+ continue;
+ }
+
+ if(NULL != (p = get_config(cfg, "frequency")))
+ {
+ timer = 3600 / atoi(p);
+ continue;
+ }
+
+ if(NULL != (p = get_config(cfg, "server")))
+ {
+ strcpy(host, p);
+ continue;
+ }
+
+ if(NULL != (p = get_config(cfg, "host")))
+ {
+ strcpy(host, p);
+ continue;
+ }
+
+ if(NULL != (p = get_config(cfg, "alert")))
+ {
+ alert = atoi(p);
+ continue;
+ }
+
+ if(NULL != (p = get_config(cfg, "timer")))
+ {
+ timer = atoi(p) * 60;
+ continue;
+ }
+
+ if(NULL != (p = get_config(cfg, "mute")))
+ {
+ mute[0] = atoi(p);
+ p = strchr(p, '-');
+ if(p)
+ mute[1] = atoi(strtrim(++p, __SPACES));
+ continue;
+ }
+
+ if(NULL != (p = get_config(cfg, "maildir")))
+ {
+ maildir = strdup(p);
+ continue;
+ }
+
+ }
+ close_config(cfg);
+
+ if(stricmp(prog, "vmon"))
+ {
+ vstat(port);
+ exit(0);
+ }
+
+ pdetach(D_KEEPNONE);
+
+ chdir(maildir);
+ freq = timer;
+ orig_timer = timer;
+ time(&now);
+ for(;;)
+ {
+ timer = vstat(port);
+ iter = interval;
+ for(;;)
+ {
+ vmbox(mbox, port);
+ sleep(iter);
+ time(&now);
+ iter = timer - (now % timer) - 1;
+
+ if(iter > interval)
+ iter = interval;
+
+ if(iter < 2)
+ {
+ sleep(iter + 2);
+ break;
+ }
+ }
+ }
+}
+
+