summaryrefslogtreecommitdiffstats
path: root/zarb-ml/mageia-sysadm/2011-February/002835.html
diff options
context:
space:
mode:
authorNicolas Vigier <boklm@mageia.org>2013-04-14 13:46:12 +0000
committerNicolas Vigier <boklm@mageia.org>2013-04-14 13:46:12 +0000
commit1be510f9529cb082f802408b472a77d074b394c0 (patch)
treeb175f9d5fcb107576dabc768e7bd04d4a3e491a0 /zarb-ml/mageia-sysadm/2011-February/002835.html
parentfa5098cf210b23ab4f419913e28af7b1b07dafb2 (diff)
downloadarchives-master.tar
archives-master.tar.gz
archives-master.tar.bz2
archives-master.tar.xz
archives-master.zip
Add zarb MLs html archivesHEADmaster
Diffstat (limited to 'zarb-ml/mageia-sysadm/2011-February/002835.html')
-rw-r--r--zarb-ml/mageia-sysadm/2011-February/002835.html166825
1 files changed, 166825 insertions, 0 deletions
diff --git a/zarb-ml/mageia-sysadm/2011-February/002835.html b/zarb-ml/mageia-sysadm/2011-February/002835.html
new file mode 100644
index 000000000..5ac1dabd7
--- /dev/null
+++ b/zarb-ml/mageia-sysadm/2011-February/002835.html
@@ -0,0 +1,166825 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+ <HEAD>
+ <TITLE> [Mageia-sysadm] [451] Import stage1
+ </TITLE>
+ <LINK REL="Index" HREF="index.html" >
+ <LINK REL="made" HREF="mailto:mageia-sysadm%40mageia.org?Subject=Re%3A%20%5BMageia-sysadm%5D%20%5B451%5D%20Import%20stage1&In-Reply-To=%3C20110207000158.AE50C402D8%40valstar.mageia.org%3E">
+ <META NAME="robots" CONTENT="index,nofollow">
+ <META http-equiv="Content-Type" content="text/html; charset=us-ascii">
+ <LINK REL="Previous" HREF="002827.html">
+ <LINK REL="Next" HREF="002582.html">
+ </HEAD>
+ <BODY BGCOLOR="#ffffff">
+ <H1>[Mageia-sysadm] [451] Import stage1</H1>
+ <B>root at mageia.org</B>
+ <A HREF="mailto:mageia-sysadm%40mageia.org?Subject=Re%3A%20%5BMageia-sysadm%5D%20%5B451%5D%20Import%20stage1&In-Reply-To=%3C20110207000158.AE50C402D8%40valstar.mageia.org%3E"
+ TITLE="[Mageia-sysadm] [451] Import stage1">root at mageia.org
+ </A><BR>
+ <I>Mon Feb 7 01:03:48 CET 2011</I>
+ <P><UL>
+ <LI>Previous message: <A HREF="002827.html">[Mageia-sysadm] [450] Import cleaned tools
+</A></li>
+ <LI>Next message: <A HREF="002582.html">[Mageia-sysadm] [452] Do not get mirrorlist from Mandriva
+</A></li>
+ <LI> <B>Messages sorted by:</B>
+ <a href="date.html#2835">[ date ]</a>
+ <a href="thread.html#2835">[ thread ]</a>
+ <a href="subject.html#2835">[ subject ]</a>
+ <a href="author.html#2835">[ author ]</a>
+ </LI>
+ </UL>
+ <HR>
+<!--beginarticle-->
+<PRE>Revision: 451
+Author: dmorgan
+Date: 2011-02-07 01:01:56 +0100 (Mon, 07 Feb 2011)
+Log Message:
+-----------
+Import stage1
+
+Added Paths:
+-----------
+ drakx/trunk/mdk-stage1/
+ drakx/trunk/mdk-stage1/Makefile
+ drakx/trunk/mdk-stage1/Makefile.common
+ drakx/trunk/mdk-stage1/NEWS
+ drakx/trunk/mdk-stage1/adsl.c
+ drakx/trunk/mdk-stage1/adsl.h
+ drakx/trunk/mdk-stage1/automatic.c
+ drakx/trunk/mdk-stage1/automatic.h
+ drakx/trunk/mdk-stage1/bootsplash.c
+ drakx/trunk/mdk-stage1/bootsplash.h
+ drakx/trunk/mdk-stage1/cdrom.c
+ drakx/trunk/mdk-stage1/cdrom.h
+ drakx/trunk/mdk-stage1/config-stage1.h
+ drakx/trunk/mdk-stage1/dhcp.c
+ drakx/trunk/mdk-stage1/dhcp.h
+ drakx/trunk/mdk-stage1/directory.c
+ drakx/trunk/mdk-stage1/directory.h
+ drakx/trunk/mdk-stage1/disk.c
+ drakx/trunk/mdk-stage1/disk.h
+ drakx/trunk/mdk-stage1/dns.c
+ drakx/trunk/mdk-stage1/dns.h
+ drakx/trunk/mdk-stage1/doc/
+ drakx/trunk/mdk-stage1/doc/HACKING
+ drakx/trunk/mdk-stage1/doc/README
+ drakx/trunk/mdk-stage1/doc/TECH-INFOS
+ drakx/trunk/mdk-stage1/doc/UPDATEMODULES
+ drakx/trunk/mdk-stage1/doc/WHY-DIETLIBC
+ drakx/trunk/mdk-stage1/doc/documented..frontend.h
+ drakx/trunk/mdk-stage1/frontend-common.c
+ drakx/trunk/mdk-stage1/frontend.h
+ drakx/trunk/mdk-stage1/init.c
+ drakx/trunk/mdk-stage1/ka.c
+ drakx/trunk/mdk-stage1/ka.h
+ drakx/trunk/mdk-stage1/log.c
+ drakx/trunk/mdk-stage1/log.h
+ drakx/trunk/mdk-stage1/lomount.c
+ drakx/trunk/mdk-stage1/lomount.h
+ drakx/trunk/mdk-stage1/modules.c
+ drakx/trunk/mdk-stage1/modules.h
+ drakx/trunk/mdk-stage1/mount.c
+ drakx/trunk/mdk-stage1/mount.h
+ drakx/trunk/mdk-stage1/mount_rpcgen.h
+ drakx/trunk/mdk-stage1/network.c
+ drakx/trunk/mdk-stage1/network.h
+ drakx/trunk/mdk-stage1/newt/
+ drakx/trunk/mdk-stage1/newt/Makefile
+ drakx/trunk/mdk-stage1/newt/button.c
+ drakx/trunk/mdk-stage1/newt/buttonbar.c
+ drakx/trunk/mdk-stage1/newt/checkbox.c
+ drakx/trunk/mdk-stage1/newt/checkboxtree.c
+ drakx/trunk/mdk-stage1/newt/entry.c
+ drakx/trunk/mdk-stage1/newt/form.c
+ drakx/trunk/mdk-stage1/newt/grid.c
+ drakx/trunk/mdk-stage1/newt/label.c
+ drakx/trunk/mdk-stage1/newt/listbox.c
+ drakx/trunk/mdk-stage1/newt/newt.c
+ drakx/trunk/mdk-stage1/newt/newt.h
+ drakx/trunk/mdk-stage1/newt/newt_pr.h
+ drakx/trunk/mdk-stage1/newt/scale.c
+ drakx/trunk/mdk-stage1/newt/scrollbar.c
+ drakx/trunk/mdk-stage1/newt/textbox.c
+ drakx/trunk/mdk-stage1/newt/windows.c
+ drakx/trunk/mdk-stage1/newt-frontend.c
+ drakx/trunk/mdk-stage1/nfs_mount4.h
+ drakx/trunk/mdk-stage1/nfsmount.c
+ drakx/trunk/mdk-stage1/nfsmount.h
+ drakx/trunk/mdk-stage1/params.c
+ drakx/trunk/mdk-stage1/params.h
+ drakx/trunk/mdk-stage1/partition.c
+ drakx/trunk/mdk-stage1/partition.h
+ drakx/trunk/mdk-stage1/pci-resource/
+ drakx/trunk/mdk-stage1/pci-resource/Makefile
+ drakx/trunk/mdk-stage1/pci-resource/update-pci-ids.pl
+ drakx/trunk/mdk-stage1/pcmcia/
+ drakx/trunk/mdk-stage1/pcmcia/Makefile
+ drakx/trunk/mdk-stage1/pcmcia/bulkmem.h
+ drakx/trunk/mdk-stage1/pcmcia/cirrus.h
+ drakx/trunk/mdk-stage1/pcmcia/cistpl.h
+ drakx/trunk/mdk-stage1/pcmcia/cs.h
+ drakx/trunk/mdk-stage1/pcmcia/cs_types.h
+ drakx/trunk/mdk-stage1/pcmcia/driver_ops.h
+ drakx/trunk/mdk-stage1/pcmcia/ds.h
+ drakx/trunk/mdk-stage1/pcmcia/i82365.h
+ drakx/trunk/mdk-stage1/pcmcia/lex_config.l
+ drakx/trunk/mdk-stage1/pcmcia/merge_from_pcitable
+ drakx/trunk/mdk-stage1/pcmcia/pcmcia.h
+ drakx/trunk/mdk-stage1/pcmcia/probe.c
+ drakx/trunk/mdk-stage1/pcmcia/startup.c
+ drakx/trunk/mdk-stage1/pcmcia/startup.h
+ drakx/trunk/mdk-stage1/pcmcia/tcic.h
+ drakx/trunk/mdk-stage1/pcmcia/version.h
+ drakx/trunk/mdk-stage1/pcmcia/vg468.h
+ drakx/trunk/mdk-stage1/pcmcia/yacc_config.y
+ drakx/trunk/mdk-stage1/pcmcia-resource/
+ drakx/trunk/mdk-stage1/pcmcia-resource/Makefile
+ drakx/trunk/mdk-stage1/pcmcia-resource/update-pcmcia-ids.pl
+ drakx/trunk/mdk-stage1/ppp/
+ drakx/trunk/mdk-stage1/ppp/Changes-2.3
+ drakx/trunk/mdk-stage1/ppp/FAQ
+ drakx/trunk/mdk-stage1/ppp/PLUGINS
+ drakx/trunk/mdk-stage1/ppp/README
+ drakx/trunk/mdk-stage1/ppp/README.MSCHAP80
+ drakx/trunk/mdk-stage1/ppp/README.cbcp
+ drakx/trunk/mdk-stage1/ppp/README.linux
+ drakx/trunk/mdk-stage1/ppp/README.sol2
+ drakx/trunk/mdk-stage1/ppp/README.sunos4
+ drakx/trunk/mdk-stage1/ppp/SETUP
+ drakx/trunk/mdk-stage1/ppp/chat/
+ drakx/trunk/mdk-stage1/ppp/chat/Makefile.linux
+ drakx/trunk/mdk-stage1/ppp/chat/Makefile.linux.makeopt
+ drakx/trunk/mdk-stage1/ppp/chat/Makefile.sol2
+ drakx/trunk/mdk-stage1/ppp/chat/Makefile.sunos4
+ drakx/trunk/mdk-stage1/ppp/chat/chat.8
+ drakx/trunk/mdk-stage1/ppp/chat/chat.c
+ drakx/trunk/mdk-stage1/ppp/common/
+ drakx/trunk/mdk-stage1/ppp/common/zlib.c
+ drakx/trunk/mdk-stage1/ppp/common/zlib.h
+ drakx/trunk/mdk-stage1/ppp/configure
+ drakx/trunk/mdk-stage1/ppp/contrib/
+ drakx/trunk/mdk-stage1/ppp/contrib/pppgetpass/
+ drakx/trunk/mdk-stage1/ppp/contrib/pppgetpass/Makefile.linux
+ drakx/trunk/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.8
+ drakx/trunk/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.gtk.c
+ drakx/trunk/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.sh
+ drakx/trunk/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.vt.c
+ drakx/trunk/mdk-stage1/ppp/etc.ppp/
+ drakx/trunk/mdk-stage1/ppp/etc.ppp/chap-secrets
+ drakx/trunk/mdk-stage1/ppp/etc.ppp/options
+ drakx/trunk/mdk-stage1/ppp/etc.ppp/options.options
+ drakx/trunk/mdk-stage1/ppp/etc.ppp/pap-secrets
+ drakx/trunk/mdk-stage1/ppp/include/
+ drakx/trunk/mdk-stage1/ppp/include/linux/
+ drakx/trunk/mdk-stage1/ppp/include/linux/if_ppp.h
+ drakx/trunk/mdk-stage1/ppp/include/linux/if_pppvar.h
+ drakx/trunk/mdk-stage1/ppp/include/linux/ppp-comp.h
+ drakx/trunk/mdk-stage1/ppp/include/linux/ppp_defs.h
+ drakx/trunk/mdk-stage1/ppp/include/net/
+ drakx/trunk/mdk-stage1/ppp/include/net/if_ppp.h
+ drakx/trunk/mdk-stage1/ppp/include/net/ppp-comp.h
+ drakx/trunk/mdk-stage1/ppp/include/net/ppp_defs.h
+ drakx/trunk/mdk-stage1/ppp/include/net/pppio.h
+ drakx/trunk/mdk-stage1/ppp/include/net/slcompress.h
+ drakx/trunk/mdk-stage1/ppp/include/net/vjcompress.h
+ drakx/trunk/mdk-stage1/ppp/include/pcap-int.h
+ drakx/trunk/mdk-stage1/ppp/linux/
+ drakx/trunk/mdk-stage1/ppp/linux/Makefile.top
+ drakx/trunk/mdk-stage1/ppp/modules/
+ drakx/trunk/mdk-stage1/ppp/modules/bsd-comp.c
+ drakx/trunk/mdk-stage1/ppp/modules/deflate.c
+ drakx/trunk/mdk-stage1/ppp/modules/if_ppp.c
+ drakx/trunk/mdk-stage1/ppp/modules/ppp.c
+ drakx/trunk/mdk-stage1/ppp/modules/ppp_ahdlc.c
+ drakx/trunk/mdk-stage1/ppp/modules/ppp_comp.c
+ drakx/trunk/mdk-stage1/ppp/modules/ppp_mod.h
+ drakx/trunk/mdk-stage1/ppp/modules/vjcompress.c
+ drakx/trunk/mdk-stage1/ppp/pppd/
+ drakx/trunk/mdk-stage1/ppp/pppd/Makefile
+ drakx/trunk/mdk-stage1/ppp/pppd/Makefile.linux
+ drakx/trunk/mdk-stage1/ppp/pppd/Makefile.linux.make
+ drakx/trunk/mdk-stage1/ppp/pppd/Makefile.linux.makeopt
+ drakx/trunk/mdk-stage1/ppp/pppd/Makefile.sol2
+ drakx/trunk/mdk-stage1/ppp/pppd/Makefile.sunos4
+ drakx/trunk/mdk-stage1/ppp/pppd/auth.c
+ drakx/trunk/mdk-stage1/ppp/pppd/cbcp.c
+ drakx/trunk/mdk-stage1/ppp/pppd/cbcp.h
+ drakx/trunk/mdk-stage1/ppp/pppd/ccp.c
+ drakx/trunk/mdk-stage1/ppp/pppd/ccp.h
+ drakx/trunk/mdk-stage1/ppp/pppd/chap.c
+ drakx/trunk/mdk-stage1/ppp/pppd/chap.h
+ drakx/trunk/mdk-stage1/ppp/pppd/chap_ms.c
+ drakx/trunk/mdk-stage1/ppp/pppd/chap_ms.h
+ drakx/trunk/mdk-stage1/ppp/pppd/demand.c
+ drakx/trunk/mdk-stage1/ppp/pppd/eui64.c
+ drakx/trunk/mdk-stage1/ppp/pppd/eui64.h
+ drakx/trunk/mdk-stage1/ppp/pppd/fsm.c
+ drakx/trunk/mdk-stage1/ppp/pppd/fsm.h
+ drakx/trunk/mdk-stage1/ppp/pppd/ipcp.c
+ drakx/trunk/mdk-stage1/ppp/pppd/ipcp.h
+ drakx/trunk/mdk-stage1/ppp/pppd/ipv6cp.c
+ drakx/trunk/mdk-stage1/ppp/pppd/ipv6cp.h
+ drakx/trunk/mdk-stage1/ppp/pppd/ipxcp.c
+ drakx/trunk/mdk-stage1/ppp/pppd/ipxcp.h
+ drakx/trunk/mdk-stage1/ppp/pppd/lcp.c
+ drakx/trunk/mdk-stage1/ppp/pppd/lcp.h
+ drakx/trunk/mdk-stage1/ppp/pppd/magic.c
+ drakx/trunk/mdk-stage1/ppp/pppd/magic.h
+ drakx/trunk/mdk-stage1/ppp/pppd/main.c
+ drakx/trunk/mdk-stage1/ppp/pppd/md4.c
+ drakx/trunk/mdk-stage1/ppp/pppd/md4.h
+ drakx/trunk/mdk-stage1/ppp/pppd/md5.c
+ drakx/trunk/mdk-stage1/ppp/pppd/md5.h
+ drakx/trunk/mdk-stage1/ppp/pppd/multilink.c
+ drakx/trunk/mdk-stage1/ppp/pppd/options.c
+ drakx/trunk/mdk-stage1/ppp/pppd/patchlevel.h
+ drakx/trunk/mdk-stage1/ppp/pppd/pathnames.h
+ drakx/trunk/mdk-stage1/ppp/pppd/plugins/
+ drakx/trunk/mdk-stage1/ppp/pppd/plugins/Makefile.linux
+ drakx/trunk/mdk-stage1/ppp/pppd/plugins/Makefile.sol2
+ drakx/trunk/mdk-stage1/ppp/pppd/plugins/minconn.c
+ drakx/trunk/mdk-stage1/ppp/pppd/plugins/passprompt.c
+ drakx/trunk/mdk-stage1/ppp/pppd/ppp.pam
+ drakx/trunk/mdk-stage1/ppp/pppd/pppd.8
+ drakx/trunk/mdk-stage1/ppp/pppd/pppd.h
+ drakx/trunk/mdk-stage1/ppp/pppd/pppd.h.wtmp
+ drakx/trunk/mdk-stage1/ppp/pppd/sys-linux.c
+ drakx/trunk/mdk-stage1/ppp/pppd/sys-linux.c.wtmp
+ drakx/trunk/mdk-stage1/ppp/pppd/sys-solaris.c
+ drakx/trunk/mdk-stage1/ppp/pppd/sys-sunos4.c
+ drakx/trunk/mdk-stage1/ppp/pppd/tdb.c
+ drakx/trunk/mdk-stage1/ppp/pppd/tdb.h
+ drakx/trunk/mdk-stage1/ppp/pppd/tty.c
+ drakx/trunk/mdk-stage1/ppp/pppd/upap.c
+ drakx/trunk/mdk-stage1/ppp/pppd/upap.h
+ drakx/trunk/mdk-stage1/ppp/pppd/utils.c
+ drakx/trunk/mdk-stage1/ppp/pppdump/
+ drakx/trunk/mdk-stage1/ppp/pppdump/Makefile.linux
+ drakx/trunk/mdk-stage1/ppp/pppdump/Makefile.linux.makeopt
+ drakx/trunk/mdk-stage1/ppp/pppdump/Makefile.linux.pppdump-Makefile
+ drakx/trunk/mdk-stage1/ppp/pppdump/Makefile.sol2
+ drakx/trunk/mdk-stage1/ppp/pppdump/Makefile.sunos4
+ drakx/trunk/mdk-stage1/ppp/pppdump/bsd-comp.c
+ drakx/trunk/mdk-stage1/ppp/pppdump/deflate.c
+ drakx/trunk/mdk-stage1/ppp/pppdump/ppp-comp.h
+ drakx/trunk/mdk-stage1/ppp/pppdump/pppdump.8
+ drakx/trunk/mdk-stage1/ppp/pppdump/pppdump.c
+ drakx/trunk/mdk-stage1/ppp/pppdump/zlib.c
+ drakx/trunk/mdk-stage1/ppp/pppdump/zlib.h
+ drakx/trunk/mdk-stage1/ppp/pppstats/
+ drakx/trunk/mdk-stage1/ppp/pppstats/Makefile.linux
+ drakx/trunk/mdk-stage1/ppp/pppstats/Makefile.sol2
+ drakx/trunk/mdk-stage1/ppp/pppstats/Makefile.sunos4
+ drakx/trunk/mdk-stage1/ppp/pppstats/pppstats.8
+ drakx/trunk/mdk-stage1/ppp/pppstats/pppstats.c
+ drakx/trunk/mdk-stage1/ppp/sample/
+ drakx/trunk/mdk-stage1/ppp/sample/auth-down
+ drakx/trunk/mdk-stage1/ppp/sample/auth-up
+ drakx/trunk/mdk-stage1/ppp/sample/ip-down
+ drakx/trunk/mdk-stage1/ppp/sample/ip-up
+ drakx/trunk/mdk-stage1/ppp/sample/options
+ drakx/trunk/mdk-stage1/ppp/sample/options.ttyXX
+ drakx/trunk/mdk-stage1/ppp/sample/pap-secrets
+ drakx/trunk/mdk-stage1/ppp/scripts/
+ drakx/trunk/mdk-stage1/ppp/scripts/README
+ drakx/trunk/mdk-stage1/ppp/scripts/callback
+ drakx/trunk/mdk-stage1/ppp/scripts/chat-callback
+ drakx/trunk/mdk-stage1/ppp/scripts/chatchat/
+ drakx/trunk/mdk-stage1/ppp/scripts/chatchat/README
+ drakx/trunk/mdk-stage1/ppp/scripts/chatchat/chatchat.c
+ drakx/trunk/mdk-stage1/ppp/scripts/ip-down.local.add
+ drakx/trunk/mdk-stage1/ppp/scripts/ip-up.local.add
+ drakx/trunk/mdk-stage1/ppp/scripts/options-rsh-loc
+ drakx/trunk/mdk-stage1/ppp/scripts/options-rsh-rem
+ drakx/trunk/mdk-stage1/ppp/scripts/options-ssh-loc
+ drakx/trunk/mdk-stage1/ppp/scripts/options-ssh-rem
+ drakx/trunk/mdk-stage1/ppp/scripts/ppp-off
+ drakx/trunk/mdk-stage1/ppp/scripts/ppp-on
+ drakx/trunk/mdk-stage1/ppp/scripts/ppp-on-dialer
+ drakx/trunk/mdk-stage1/ppp/scripts/ppp-on-rsh
+ drakx/trunk/mdk-stage1/ppp/scripts/ppp-on-ssh
+ drakx/trunk/mdk-stage1/ppp/scripts/redialer
+ drakx/trunk/mdk-stage1/ppp/scripts/secure-card
+ drakx/trunk/mdk-stage1/ppp/solaris/
+ drakx/trunk/mdk-stage1/ppp/solaris/Makedefs
+ drakx/trunk/mdk-stage1/ppp/solaris/Makedefs.sol2
+ drakx/trunk/mdk-stage1/ppp/solaris/Makefile.sol2
+ drakx/trunk/mdk-stage1/ppp/solaris/Makefile.sol2-64
+ drakx/trunk/mdk-stage1/ppp/solaris/Makefile.top
+ drakx/trunk/mdk-stage1/ppp/solaris/ppp.c
+ drakx/trunk/mdk-stage1/ppp/solaris/ppp.conf
+ drakx/trunk/mdk-stage1/ppp/solaris/ppp_ahdlc.c
+ drakx/trunk/mdk-stage1/ppp/solaris/ppp_ahdlc_mod.c
+ drakx/trunk/mdk-stage1/ppp/solaris/ppp_comp.c
+ drakx/trunk/mdk-stage1/ppp/solaris/ppp_comp_mod.c
+ drakx/trunk/mdk-stage1/ppp/solaris/ppp_mod.c
+ drakx/trunk/mdk-stage1/ppp/solaris/ppp_mod.h
+ drakx/trunk/mdk-stage1/ppp/sunos4/
+ drakx/trunk/mdk-stage1/ppp/sunos4/Makedefs
+ drakx/trunk/mdk-stage1/ppp/sunos4/Makefile
+ drakx/trunk/mdk-stage1/ppp/sunos4/Makefile.top
+ drakx/trunk/mdk-stage1/ppp/sunos4/if_ppp_vdcmd.c
+ drakx/trunk/mdk-stage1/ppp/sunos4/ppp.INSTALL
+ drakx/trunk/mdk-stage1/ppp/sunos4/ppp_ahdlc_vdcmd.c
+ drakx/trunk/mdk-stage1/ppp/sunos4/ppp_comp_vdcmd.c
+ drakx/trunk/mdk-stage1/ppp/sunos4/ppp_vdcmd.c
+ drakx/trunk/mdk-stage1/ppp/svr4/
+ drakx/trunk/mdk-stage1/ppp/svr4/Makedefs
+ drakx/trunk/mdk-stage1/ppp/svr4/Makedefs.sol2
+ drakx/trunk/mdk-stage1/ppp/svr4/Makefile.sol2
+ drakx/trunk/mdk-stage1/ppp/svr4/Makefile.sol2-64
+ drakx/trunk/mdk-stage1/ppp/svr4/Makefile.svr4
+ drakx/trunk/mdk-stage1/ppp/svr4/Makefile.top
+ drakx/trunk/mdk-stage1/ppp/svr4/ppp.Master
+ drakx/trunk/mdk-stage1/ppp/svr4/ppp.Node
+ drakx/trunk/mdk-stage1/ppp/svr4/ppp.System
+ drakx/trunk/mdk-stage1/ppp/svr4/ppp.conf
+ drakx/trunk/mdk-stage1/ppp/svr4/ppp_ahdl.Master
+ drakx/trunk/mdk-stage1/ppp/svr4/ppp_ahdl.System
+ drakx/trunk/mdk-stage1/ppp/svr4/ppp_ahdlc_mod.c
+ drakx/trunk/mdk-stage1/ppp/svr4/ppp_comp.Master
+ drakx/trunk/mdk-stage1/ppp/svr4/ppp_comp.System
+ drakx/trunk/mdk-stage1/ppp/svr4/ppp_comp_mod.c
+ drakx/trunk/mdk-stage1/ppp/svr4/ppp_mod.c
+ drakx/trunk/mdk-stage1/probe-modules.c
+ drakx/trunk/mdk-stage1/probing.c
+ drakx/trunk/mdk-stage1/probing.h
+ drakx/trunk/mdk-stage1/rescue-gui.c
+ drakx/trunk/mdk-stage1/rp-pppoe/
+ drakx/trunk/mdk-stage1/rp-pppoe/README
+ drakx/trunk/mdk-stage1/rp-pppoe/configs/
+ drakx/trunk/mdk-stage1/rp-pppoe/configs/firewall-masq
+ drakx/trunk/mdk-stage1/rp-pppoe/configs/firewall-standalone
+ drakx/trunk/mdk-stage1/rp-pppoe/configs/pap-secrets
+ drakx/trunk/mdk-stage1/rp-pppoe/configs/pppoe-server-options
+ drakx/trunk/mdk-stage1/rp-pppoe/configs/pppoe.conf
+ drakx/trunk/mdk-stage1/rp-pppoe/doc/
+ drakx/trunk/mdk-stage1/rp-pppoe/doc/CHANGES
+ drakx/trunk/mdk-stage1/rp-pppoe/doc/HOW-TO-CONNECT
+ drakx/trunk/mdk-stage1/rp-pppoe/doc/KERNEL-MODE-PPPOE
+ drakx/trunk/mdk-stage1/rp-pppoe/doc/LICENSE
+ drakx/trunk/mdk-stage1/rp-pppoe/doc/PROBLEMS
+ drakx/trunk/mdk-stage1/rp-pppoe/go
+ drakx/trunk/mdk-stage1/rp-pppoe/go-gui
+ drakx/trunk/mdk-stage1/rp-pppoe/gui/
+ drakx/trunk/mdk-stage1/rp-pppoe/gui/Makefile.in
+ drakx/trunk/mdk-stage1/rp-pppoe/gui/html/
+ drakx/trunk/mdk-stage1/rp-pppoe/gui/html/tkpppoe.html
+ drakx/trunk/mdk-stage1/rp-pppoe/gui/pppoe-wrapper.1
+ drakx/trunk/mdk-stage1/rp-pppoe/gui/tkpppoe.1
+ drakx/trunk/mdk-stage1/rp-pppoe/gui/tkpppoe.in
+ drakx/trunk/mdk-stage1/rp-pppoe/gui/wrapper.c
+ drakx/trunk/mdk-stage1/rp-pppoe/man/
+ drakx/trunk/mdk-stage1/rp-pppoe/man/adsl-connect.8
+ drakx/trunk/mdk-stage1/rp-pppoe/man/adsl-setup.8
+ drakx/trunk/mdk-stage1/rp-pppoe/man/adsl-start.8
+ drakx/trunk/mdk-stage1/rp-pppoe/man/adsl-status.8
+ drakx/trunk/mdk-stage1/rp-pppoe/man/adsl-stop.8
+ drakx/trunk/mdk-stage1/rp-pppoe/man/pppoe-relay.8
+ drakx/trunk/mdk-stage1/rp-pppoe/man/pppoe-server.8
+ drakx/trunk/mdk-stage1/rp-pppoe/man/pppoe-sniff.8
+ drakx/trunk/mdk-stage1/rp-pppoe/man/pppoe.8
+ drakx/trunk/mdk-stage1/rp-pppoe/man/pppoe.conf.5
+ drakx/trunk/mdk-stage1/rp-pppoe/rp-pppoe-gui.spec
+ drakx/trunk/mdk-stage1/rp-pppoe/rp-pppoe.spec
+ drakx/trunk/mdk-stage1/rp-pppoe/scripts/
+ drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-connect.in
+ drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-init-suse.in
+ drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-init-turbolinux.in
+ drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-init.in
+ drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-setup.in
+ drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-start.in
+ drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-status
+ drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-stop.in
+ drakx/trunk/mdk-stage1/rp-pppoe/src/
+ drakx/trunk/mdk-stage1/rp-pppoe/src/Makefile
+ drakx/trunk/mdk-stage1/rp-pppoe/src/Makefile.in
+ drakx/trunk/mdk-stage1/rp-pppoe/src/common.c
+ drakx/trunk/mdk-stage1/rp-pppoe/src/config.h
+ drakx/trunk/mdk-stage1/rp-pppoe/src/config.h.in
+ drakx/trunk/mdk-stage1/rp-pppoe/src/configure
+ drakx/trunk/mdk-stage1/rp-pppoe/src/configure.in
+ drakx/trunk/mdk-stage1/rp-pppoe/src/debug.c
+ drakx/trunk/mdk-stage1/rp-pppoe/src/discovery.c
+ drakx/trunk/mdk-stage1/rp-pppoe/src/if.c
+ drakx/trunk/mdk-stage1/rp-pppoe/src/install-sh
+ drakx/trunk/mdk-stage1/rp-pppoe/src/md5.c
+ drakx/trunk/mdk-stage1/rp-pppoe/src/md5.h
+ drakx/trunk/mdk-stage1/rp-pppoe/src/plugin.c
+ drakx/trunk/mdk-stage1/rp-pppoe/src/ppp.c
+ drakx/trunk/mdk-stage1/rp-pppoe/src/pppoe-server.c
+ drakx/trunk/mdk-stage1/rp-pppoe/src/pppoe-sniff.c
+ drakx/trunk/mdk-stage1/rp-pppoe/src/pppoe.c
+ drakx/trunk/mdk-stage1/rp-pppoe/src/pppoe.h
+ drakx/trunk/mdk-stage1/rp-pppoe/src/relay.c
+ drakx/trunk/mdk-stage1/rp-pppoe/src/relay.h
+ drakx/trunk/mdk-stage1/slang/
+ drakx/trunk/mdk-stage1/slang/Makefile
+ drakx/trunk/mdk-stage1/slang/_slang.h
+ drakx/trunk/mdk-stage1/slang/config.h
+ drakx/trunk/mdk-stage1/slang/jdmacros.h
+ drakx/trunk/mdk-stage1/slang/keywhash.c
+ drakx/trunk/mdk-stage1/slang/sl-feat.h
+ drakx/trunk/mdk-stage1/slang/slang.c
+ drakx/trunk/mdk-stage1/slang/slang.h
+ drakx/trunk/mdk-stage1/slang/slarith.c
+ drakx/trunk/mdk-stage1/slang/slarith.inc
+ drakx/trunk/mdk-stage1/slang/slarray.c
+ drakx/trunk/mdk-stage1/slang/slarrfun.c
+ drakx/trunk/mdk-stage1/slang/slarrfun.inc
+ drakx/trunk/mdk-stage1/slang/slarrmis.c
+ drakx/trunk/mdk-stage1/slang/slassoc.c
+ drakx/trunk/mdk-stage1/slang/slbstr.c
+ drakx/trunk/mdk-stage1/slang/slclass.c
+ drakx/trunk/mdk-stage1/slang/slcmd.c
+ drakx/trunk/mdk-stage1/slang/slcmplex.c
+ drakx/trunk/mdk-stage1/slang/slcompat.c
+ drakx/trunk/mdk-stage1/slang/slcurses.c
+ drakx/trunk/mdk-stage1/slang/slcurses.h
+ drakx/trunk/mdk-stage1/slang/sldisply.c
+ drakx/trunk/mdk-stage1/slang/slerr.c
+ drakx/trunk/mdk-stage1/slang/slerrno.c
+ drakx/trunk/mdk-stage1/slang/slgetkey.c
+ drakx/trunk/mdk-stage1/slang/slimport.c
+ drakx/trunk/mdk-stage1/slang/slinclud.h
+ drakx/trunk/mdk-stage1/slang/slintall.c
+ drakx/trunk/mdk-stage1/slang/slistruc.c
+ drakx/trunk/mdk-stage1/slang/slkeymap.c
+ drakx/trunk/mdk-stage1/slang/slkeypad.c
+ drakx/trunk/mdk-stage1/slang/sllimits.h
+ drakx/trunk/mdk-stage1/slang/slmalloc.c
+ drakx/trunk/mdk-stage1/slang/slmath.c
+ drakx/trunk/mdk-stage1/slang/slmemchr.c
+ drakx/trunk/mdk-stage1/slang/slmemcmp.c
+ drakx/trunk/mdk-stage1/slang/slmemcpy.c
+ drakx/trunk/mdk-stage1/slang/slmemset.c
+ drakx/trunk/mdk-stage1/slang/slmisc.c
+ drakx/trunk/mdk-stage1/slang/slnspace.c
+ drakx/trunk/mdk-stage1/slang/slospath.c
+ drakx/trunk/mdk-stage1/slang/slpack.c
+ drakx/trunk/mdk-stage1/slang/slparse.c
+ drakx/trunk/mdk-stage1/slang/slpath.c
+ drakx/trunk/mdk-stage1/slang/slposdir.c
+ drakx/trunk/mdk-stage1/slang/slposio.c
+ drakx/trunk/mdk-stage1/slang/slprepr.c
+ drakx/trunk/mdk-stage1/slang/slproc.c
+ drakx/trunk/mdk-stage1/slang/slregexp.c
+ drakx/trunk/mdk-stage1/slang/slrline.c
+ drakx/trunk/mdk-stage1/slang/slscanf.c
+ drakx/trunk/mdk-stage1/slang/slscroll.c
+ drakx/trunk/mdk-stage1/slang/slsearch.c
+ drakx/trunk/mdk-stage1/slang/slsignal.c
+ drakx/trunk/mdk-stage1/slang/slsmg.c
+ drakx/trunk/mdk-stage1/slang/slstd.c
+ drakx/trunk/mdk-stage1/slang/slstdio.c
+ drakx/trunk/mdk-stage1/slang/slstring.c
+ drakx/trunk/mdk-stage1/slang/slstrops.c
+ drakx/trunk/mdk-stage1/slang/slstruct.c
+ drakx/trunk/mdk-stage1/slang/sltermin.c
+ drakx/trunk/mdk-stage1/slang/sltime.c
+ drakx/trunk/mdk-stage1/slang/sltoken.c
+ drakx/trunk/mdk-stage1/slang/sltypes.c
+ drakx/trunk/mdk-stage1/slang/slutty.c
+ drakx/trunk/mdk-stage1/slang/slxstrng.c
+ drakx/trunk/mdk-stage1/stage1.c
+ drakx/trunk/mdk-stage1/stage1.h
+ drakx/trunk/mdk-stage1/stdio-frontend.c
+ drakx/trunk/mdk-stage1/sysfs/
+ drakx/trunk/mdk-stage1/sysfs/Makefile
+ drakx/trunk/mdk-stage1/sysfs/libsysfs.h
+ drakx/trunk/mdk-stage1/sysfs/sysfs.h
+ drakx/trunk/mdk-stage1/sysfs/sysfs_attr.c
+ drakx/trunk/mdk-stage1/sysfs/sysfs_utils.c
+ drakx/trunk/mdk-stage1/thirdparty.c
+ drakx/trunk/mdk-stage1/thirdparty.h
+ drakx/trunk/mdk-stage1/tools.c
+ drakx/trunk/mdk-stage1/tools.h
+ drakx/trunk/mdk-stage1/url.c
+ drakx/trunk/mdk-stage1/url.h
+ drakx/trunk/mdk-stage1/usb-resource/
+ drakx/trunk/mdk-stage1/usb-resource/Makefile
+ drakx/trunk/mdk-stage1/usb-resource/update-usb-ids.pl
+ drakx/trunk/mdk-stage1/utils.c
+ drakx/trunk/mdk-stage1/utils.h
+ drakx/trunk/mdk-stage1/wireless.c
+ drakx/trunk/mdk-stage1/wireless.h
+ drakx/trunk/mdk-stage1/zlibsupport.c
+ drakx/trunk/mdk-stage1/zlibsupport.h
+
+Added: drakx/trunk/mdk-stage1/Makefile
+===================================================================
+--- drakx/trunk/mdk-stage1/Makefile (rev 0)
++++ drakx/trunk/mdk-stage1/Makefile 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,238 @@
++ #******************************************************************************
++ #
++ # mdk-stage1 - the program that will load second-stage install
++ #
++ # $Id: Makefile 271082 2010-10-13 18:55:00Z tv $
++ #
++ # Pixel (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">pixel at mandriva.com</A>) (mostly done by Guillaume Cottenceau)
++ #
++ # Copyright 2000-2004 Mandriva
++ #
++ # This software may be freely redistributed under the terms of the GNU
++ # public license.
++ #
++ # You should have received a copy of the GNU General Public License
++ # along with this program; if not, write to the Free Software
++ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++VERSION=1.47
++PRODUCT=drakx-installer-binaries
++
++ #
++ # Portions from Erik Troan (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ewt at redhat.com</A>) Copyright 1996 Red Hat Software
++ #
++ #*****************************************************************************
++ #
++ # Currently:
++ #
++ # ix86
++ # init with dietlibc
++ # stage1 with dietlibc
++ #
++ # ppc
++ # init with dietlibc
++ # stage1 with glibc
++ #
++ # ia64
++ # init with glibc
++ # stage1 with glibc
++ #
++ # x86-64
++ # init with dietlibc
++ # stage1 with dietlibc
++ #
++ #*****************************************************************************
++
++
++top_dir = .
++
++include $(top_dir)/Makefile.common
++include $(top_dir)/../Makefile.config
++ARCHDIR=$(ARCH)
++ifeq (i386, $(ARCH))
++ARCHDIR=i586
++endif
++
++DEFS = -DDISTRIB_NAME=\&quot;$(DISTRIB_NAME)\&quot; -DDISTRIB_VERSION=\&quot;$(DISTRIB_VERSION)\&quot; -DDISTRIB_TYPE=\&quot;$(DISTRIB_TYPE)\&quot; -DDISTRIB_DESCR=\&quot;$(DISTRIB_DESCR)\&quot; $(ADDITIONAL_DEFS) -D_FILE_OFFSET_BITS=64 -DARCH=\&quot;$(ARCHDIR)\&quot; -DCONFIG_USE_ZLIB
++
++COMPILE = $(CC) $(DEFS) $(CFLAGS)
++
++INIT_DEFS =
++INITSRC = init.c
++ifneq (DIETLIBC, $(L))
++INIT_DEFS += $(GLIBC_INCLUDES)
++endif
++
++INITOBJS = $(subst .c,.o,$(INITSRC))
++
++
++ #- frontends
++NEWT_FRONTEND_SRC = newt-frontend.c
++NEWT_FRONTEND_LIBS = newt/libnewt.a slang/libslang.a
++
++STDIO_FRONTEND_SRC = stdio-frontend.c
++STDIO_FRONTEND_LIBS =
++STDIO_FRONTEND_LIBS =
++
++
++FRONTEND_OBJS = $(subst .c,.o,$($(F)_FRONTEND_SRC))
++
++FRONTEND_LINK = $(FRONTEND_OBJS) $($(F)_FRONTEND_LIBS)
++
++STAGE1_STATIC_LIBS = libmodprobe.a
++STAGE1_STATIC_USR_LIBS = libz.a libldetect.a libpci.a
++STAGE1_OWN_LIBS =
++ifeq (DIETLIBC, $(L))
++STAGE1_OWN_LIBS = $(patsubst %,/usr/lib/dietlibc/lib-$(ARCH)/%,$(STAGE1_STATIC_USR_LIBS) $(STAGE1_STATIC_LIBS))
++else
++STAGE1_OWN_LIBS = $(patsubst %,/usr/$(LIB)/%,$(STAGE1_STATIC_USR_LIBS)) $(patsubst %,/$(LIB)/%,$(STAGE1_STATIC_LIBS))
++endif
++
++
++ifeq (DIETLIBC, $(L))
++STAGE1_NETWORK_LIBS = /usr/lib/dietlibc/lib-$(ARCH)/librpc.a
++else
++STAGE1_NETWORK_LIBS = /usr/$(LIB)/libresolv.a
++endif
++
++ #- stage1 itself
++STAGE1SRC = stage1.c log.c utils.c params.c tools.c modules.c probing.c mount.c automatic.c frontend-common.c lomount.c thirdparty.c zlibsupport.c
++CDROMSRC = cdrom.c
++DISKSRC = disk.c directory.c partition.c
++NETWORKSRC = network.c nfsmount.c dhcp.c url.c dns.c adsl.c directory.c wireless.c
++KASRC = ka.c
++
++# use sort to remove duplicates
++STAGE1_ALLSRC = $(sort $(STAGE1SRC) $(CDROMSRC) $(DISKSRC) $(NETWORKSRC) $(KASRC))
++ALLSRC = $(INITSRC) $(STAGE1_ALLSRC)
++
++
++
++CDROM_DEFS = -DSPAWN_SHELL -DDISABLE_DISK -DDISABLE_NETWORK
++
++
++STAGE1OBJS-NETWORK = $(subst .c,-NETWORK.o,$(STAGE1SRC) $(NETWORKSRC))
++
++NETWORK_DEFS = -DSPAWN_SHELL -DDISABLE_CDROM -DDISABLE_DISK -DDISABLE_KA
++
++
++STAGE1OBJS-NETWORK-STANDALONE = $(subst .c,-NETWORK-STANDALONE.o,$(STAGE1SRC) $(NETWORKSRC))
++
++NETWORK_STANDALONE_DEFS = -DDISABLE_CDROM -DDISABLE_DISK -DENABLE_NETWORK_STANDALONE -DDISABLE_KA
++
++
++STAGE1OBJS-FULL = $(subst .c,-FULL.o,$(STAGE1_ALLSRC))
++
++BINS = init stage1 dhcp-client rescue-gui probe-modules
++
++DIRS += pci-resource usb-resource slang newt ppp/pppd rp-pppoe/src
++ifeq (i386, $(ARCH))
++DIRS += pcmcia pcmcia-resource sysfs
++endif
++ifeq (x86_64, $(ARCH))
++DIRS += pcmcia pcmcia-resource sysfs
++endif
++
++
++ifeq (i386,$(ARCH))
++PCMCIA_LIB = pcmcia/libpcmcia.a sysfs/libsysfs.a
++PCMCIA_DEFS = -DENABLE_PCMCIA
++endif
++ifeq (x86_64,$(ARCH))
++PCMCIA_LIB = pcmcia/libpcmcia.a sysfs/libsysfs.a
++PCMCIA_DEFS = -DENABLE_PCMCIA
++endif
++
++
++USB_DEFS_GEN = -DENABLE_USB
++USB_DEFS = -DENABLE_USB -DDISABLE_PCIADAPTERS
++
++all: dirs $(BINS)
++
++dirs:
++ @for n in . $(DIRS); do \
++ [ &quot;$$n&quot; = &quot;.&quot; ] || make -C $$n || exit 1 ;\
++ done
++
++init: $(INITOBJS) $(STAGE1_LIBC)
++ $(DIET) $(CC) $(LDFLAGS) -o $@ $^
++ $(STRIPCMD) $@
++
++stage1: $(STAGE1OBJS-FULL) $(STAGE1_OWN_LIBS) $(STAGE1_NETWORK_LIBS) $(FRONTEND_LINK) bootsplash.o $(PCMCIA_LIB) $(STAGE1_LIBC)
++ $(DIET) $(CC) $(LDFLAGS) -o $@ $^
++ $(STRIPCMD) $@
++
++dhcp-client: $(STAGE1OBJS-NETWORK-STANDALONE) $(STAGE1_OWN_LIBS) $(STAGE1_NETWORK_LIBS) $(FRONTEND_LINK) $(STAGE1_LIBC)
++ $(DIET) $(CC) $(LDFLAGS) -o $@ $^
++ $(STRIPCMD) $@
++
++
++$(INITOBJS): %.o: %.c
++ $(COMPILE) $(INIT_DEFS) -c $&lt;
++
++$(STAGE1OBJS-NETWORK): %-NETWORK.o: %.c
++ $(DIET) $(COMPILE) $(INCLUDES) $(NETWORK_DEFS) $(PCMCIA_DEFS) $(USB_DEFS_GEN) -DENABLE_ADDITIONAL_MODULES -c $&lt; -o $@
++
++$(STAGE1OBJS-NETWORK-STANDALONE): %-NETWORK-STANDALONE.o: %.c
++ $(DIET) $(COMPILE) $(INCLUDES) $(NETWORK_STANDALONE_DEFS) $(USB_DEFS_GEN) -c $&lt; -o $@
++
++$(STAGE1OBJS-FULL): %-FULL.o: %.c
++ $(DIET) $(COMPILE) $(INCLUDES) -DSPAWN_SHELL $(USB_DEFS_GEN) $(PCMCIA_DEFS) -DENABLE_BOOTSPLASH -c $&lt; -o $@
++
++.c.o:
++ $(DIET) $(COMPILE) $(INCLUDES) -DENABLE_BOOTSPLASH -c $&lt;
++
++
++clean: localclean
++ @for n in $(DIRS); do \
++ (cd $$n; make clean) \
++ done
++
++localclean:
++ rm -f *.o .depend *.rdz *.img $(BINS)
++
++
++rescue-gui: rescue-gui.o frontend-common.o params.o utils.o log.o automatic.o $(FRONTEND_LINK) $(STAGE1_LIBC)
++ $(DIET) $(CC) $(LDFLAGS) -o $@ $^
++ $(STRIPCMD) $@
++
++probe-modules: probe-modules.o probing-FULL.o modules-FULL.o params-FULL.o utils-FULL.o log-FULL.o automatic-FULL.o frontend-common-FULL.o stdio-frontend.o zlibsupport-FULL.o $(STAGE1_OWN_LIBS) $(PCMCIA_LIB) $(STAGE1_LIBC)
++ $(DIET) $(CC) $(LDFLAGS) -o $@ $^
++ $(STRIPCMD) $@
++
++dist: tar
++tar:
++ rm -rf $(PRODUCT)*.tar* $(PRODUCT)-$(VERSION)
++ @if [ -e &quot;.svn&quot; ]; then \
++ $(MAKE) dist-svn; \
++ elif [ -e &quot;../.git&quot; ]; then \
++ $(MAKE) dist-git; \
++ else \
++ echo &quot;Unknown SCM (not SVN nor GIT)&quot;;\
++ exit 1; \
++ fi;
++ $(info $(NAME)-$(VERSION).tar.bz2 is ready)
++
++dist-svn:
++ mkdir -p $(PRODUCT)-$(VERSION)
++ svn export -q -rBASE . $(PRODUCT)-$(VERSION)/mdk-stage1
++ svn export -q -rBASE ../kernel $(PRODUCT)-$(VERSION)/kernel
++ cp ../Makefile.config $(PRODUCT)-$(VERSION)/
++ tar cfj $(PRODUCT)-$(VERSION).tar.bz2 $(PRODUCT)-$(VERSION)
++ rm -rf $(PRODUCT)-$(VERSION)
++
++dist-git:
++ @cd ..; git archive --prefix=$(PRODUCT)-$(VERSION)/ HEAD mdk-stage1 kernel Makefile.config | bzip2 &gt;mdk-stage1/$(PRODUCT)-$(VERSION).tar.bz2;
++
++.depend:
++ $(CPP) $(CFLAGS) -M $(ALLSRC) &gt; .depend
++
++ifeq (.depend,$(wildcard .depend))
++include .depend
++endif
++
++
++*-NETWORK.o: %-NETWORK.o: %.o
++
++*-FULL.o: %-FULL.o: %.o
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/Makefile
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/Makefile.common
+===================================================================
+--- drakx/trunk/mdk-stage1/Makefile.common (rev 0)
++++ drakx/trunk/mdk-stage1/Makefile.common 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,68 @@
++ # -*- makefile -*-
++ #******************************************************************************
++ #
++ # Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ #
++ # Copyright 2000 Mandriva
++ #
++ # This software may be freely redistributed under the terms of the GNU
++ # public license.
++ #
++ # You should have received a copy of the GNU General Public License
++ # along with this program; if not, write to the Free Software
++ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ #
++ #*****************************************************************************
++
++ARCH := $(patsubst i%86,i386,$(shell uname -m))
++ARCH := $(patsubst sparc%,sparc,$(ARCH))
++
++# DEBUG = 1
++
++ #- default frontend is newt (honoured by main Makefile whenever possible)
++ifdef DEBUG
++F = STDIO
++else
++F = NEWT
++endif
++
++DIET = $(shell test -x /usr/bin/diet &amp;&amp; echo diet)
++
++ifeq ($(DIET), diet)
++ #- default lib is dietlibc (honoured by main Makefile whenever possible)
++L = DIETLIBC
++else
++L = GLIBC
++endif
++
++ifdef DEBUG
++OPTFLAGS = -g
++else
++OPTFLAGS = -Os
++endif
++
++#- flags used by all stuff
++CFLAGS = $(OPTFLAGS) -pipe -Wall -fomit-frame-pointer -fno-strict-aliasing
++
++ifneq (ppc, $(ARCH))
++ifneq (sparc, $(ARCH))
++CFLAGS += -Werror
++endif
++endif
++
++DIETLIBC_INCLUDES = -I/usr/lib/dietlibc/include -I.
++DIETLIBC_LIBC = /usr/lib/dietlibc/lib-$(ARCH)/libcompat.a
++GLIBC_INCLUDES = -I.
++INCLUDES = $($(L)_INCLUDES)
++
++GLIBC_LDFLAGS = -static
++LDFLAGS = $($(L)_LDFLAGS)
++
++STAGE1_LIBC = $($(L)_LIBC)
++
++ifdef DEBUG
++STRIPCMD = echo not stripping
++else
++STRIPCMD = strip -R .note -R .comment
++endif
++
+
+Added: drakx/trunk/mdk-stage1/NEWS
+===================================================================
+--- drakx/trunk/mdk-stage1/NEWS (rev 0)
++++ drakx/trunk/mdk-stage1/NEWS 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,173 @@
++1.47:
++- 2011.0 build
++
++1.46:
++- create device listed in /proc/partitions with correct major/minor (#57032)
++
++1.45:
++- do not list /dev/fd0 when no floppy is found (#58390)
++
++1.44:
++- rebuild with latest list_modules.pm (might fix #57833)
++
++1.43:
++- bump version (#57466)
++
++1.42:
++- list asix module in network/usb group
++- virtio: fix device probing: use PCI subdevices
++- fix format string bug from 1.41
++
++1.41:
++- load needed modules for known virtio devices, fixes #51804
++
++1.39:
++- set uevent helper which will load firmware and do not set firmware
++ timeout to 1 second (it will fail if firmware is not there)
++
++1.38:
++- handle hybrid ISOs (ISO images dumped to USB keys)
++
++1.37:
++- enumerate hid bus and load hid quirk modules, fixes #47167
++
++1.36:
++- load appropriate modules before trying to mount ext4/reiser4
++
++1.35:
++- allow installing from ext3/ext4/reiser4
++
++1.34:
++- adapt to new modules.dep format (prefix modules with directory path)
++- try to use arch-prefixed location for automatic disk installs
++
++1.33:
++- build fix for glibc 2.8
++- sort modules in the interface
++- try to load squashfs_lzma too
++
++1.32:
++- automatically find compressed stage2 with automatic=method:disk
++
++1.31:
++- usbkbd is dead, using usbhid instead
++
++1.30:
++- add back &quot;ide-generic&quot; support (incorrectly removed in 1.17), the
++ module that we want to avoid is &quot;ide-pci-generic&quot; (previously &quot;generic&quot;),
++ and this is handled by ldetect-lst preferred modules list
++- handle ide-cd being renamed as ide-cd_mod
++
++1.29:
++- allow to pass module options to probe-modules
++- build fixes for gcc 4.3
++
++1.28:
++- fix segfault with empty device description (can happen for USB devices)
++
++1.27.1:
++- fix build
++
++1.27:
++- do not set firmware timeout to 1 second in probe-modules helper for
++ Mandriva One (#39216)
++
++1.26:
++- load bus/firewire controllers (#31356)
++- really ask dhcp domain if not guessed
++
++1.25:
++- do not allow to choose outdated cooker mirror list (#37278)
++
++1.24:
++- load disk/ide before disk/scsi (#38451, to prevent sata deps from
++ overriding non-libata pata modules, like in stage2)
++- fix asking modules when no controller is detected
++
++1.23:
++- probe usb-storage/sbp2 only when probing USB/SCSI buses
++ (to make automatic boot faster on IDE)
++- make dhcp the first choice (instead of static) in the network type menu
++- clear tty2 after shell is killed
++- log &quot;killed shell&quot; message on tty3
++- add a space in front of top line (like help message)
++- space-pad top line with spaces to the right (like help message)
++
++1.22:
++- fix automatic IDE media detection (was broken with multiple CD drives, #36161)
++- fix bootsplash in automatic CD-Rom mode (as a result of IDE media detection fix)
++- wait only 1 second for firmware upload (not to hang boot with iwl3945, #37279)
++
++1.21:
++- load nls_cp437 and nls_iso8859_1 when loading vfat
++ (used to be in custom modules.dep)
++
++1.20:
++- probe-modules:
++ o handle the &quot;--usb&quot; option instead of &quot;usb&quot;
++ o load module passed as argument (if any), instead of probing bus
++- switch to modules from /lib/modules/`uname -r`, modules.dep containing full filename
++
++1.19:
++- rebuild with list_modules to handle atl2 ethernet driver
++
++1.18:
++- add probe-modules helper
++
++1.17:
++- use modules from disk/ide category (#33043)
++- do not explicitely try to load ide-generic, ldetect will fallback to
++ ide-generic when appropriate (#33043)
++
++1.16:
++- if you give nfs directory xxx, try to use xxx/ARCH
++- handle cdroms with and without ARCH at the root
++
++1.15:
++- ask loading modules from /modules if needed
++- read modules description from /modules/modules.description
++
++1.14:
++- fix segfault in USB detection code (when no module match, #32624)
++
++1.13:
++- use module names instead of filenames
++- convert module name to filename before loading it
++ (using modules.dep to get filename)
++- keep module in dependencies list even if it has no dependencies
++ (to keep track of its filename)
++- use '_' in module names when explicitely loading modules (cosmetics)
++
++1.12:
++- adapt to new list_modules
++
++1.11:
++- use ldetect/libmodprobe/libpci instead of custom pci/usb probe
++- rename rescue &quot;GUI&quot; as rescue &quot;menu&quot;
++
++1.10.1:
++- link init with dietlibc instead of minilibc on ix86/x86-64
++- add missing includes for wireless
++- fix build of pppoe by using dietlibc termios header
++
++1.10:
++- add ide-disk module
++- load ide-disk when detecting disks (ide is now modularized...)
++
++1.9:
++- ide is now modularized
++
++1.8:
++- build pcmcia header only on i386/x86_64 (#30668)
++- use api.mandriva.com to retrieve mirror list (#29346)
++
++1.7:
++- don't kill our init/klogd when running stage2
++ (bug introduced when switching to initramfs)
++
++1.6:
++- write DNS settings in temporary ifcfg file
++ (fixes resolv.conf post install)
++
++1.5:
++- fix infinite loop in wired interface mode
+
+Added: drakx/trunk/mdk-stage1/adsl.c
+===================================================================
+--- drakx/trunk/mdk-stage1/adsl.c (rev 0)
++++ drakx/trunk/mdk-stage1/adsl.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,183 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#include &lt;stdlib.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;string.h&gt;
++#include &lt;sys/socket.h&gt;
++#include &lt;netinet/in.h&gt;
++#include &lt;arpa/inet.h&gt;
++#include &lt;sys/ioctl.h&gt;
++#include &lt;errno.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;resolv.h&gt;
++#include &lt;signal.h&gt;
++
++#include &quot;stage1.h&quot;
++#include &quot;log.h&quot;
++#include &quot;network.h&quot;
++#include &quot;modules.h&quot;
++#include &quot;utils.h&quot;
++#include &quot;frontend.h&quot;
++#include &quot;automatic.h&quot;
++
++#include &quot;adsl.h&quot;
++
++
++static enum return_type adsl_connect(struct interface_info * intf, char * username, char * password, char * acname)
++{
++ char pppoe_call[500];
++ char * pppd_launch[] = { &quot;/sbin/pppd&quot;, &quot;pty&quot;, pppoe_call, &quot;noipdefault&quot;, &quot;noauth&quot;, &quot;default-asyncmap&quot;, &quot;defaultroute&quot;,
++ &quot;hide-password&quot;, &quot;nodetach&quot;, &quot;usepeerdns&quot;, &quot;local&quot;, &quot;mtu&quot;, &quot;1492&quot;, &quot;mru&quot;, &quot;1492&quot;, &quot;noaccomp&quot;,
++ &quot;noccp&quot;, &quot;nobsdcomp&quot;, &quot;nodeflate&quot;, &quot;nopcomp&quot;, &quot;novj&quot;, &quot;novjccomp&quot;, &quot;user&quot;, username,
++ &quot;password&quot;, password, &quot;lcp-echo-interval&quot;, &quot;20&quot;, &quot;lcp-echo-failure&quot;, &quot;3&quot;, &quot;lock&quot;, &quot;persist&quot;, NULL };
++ int fd;
++ int retries = 10;
++ char * tty_adsl = &quot;/dev/tty6&quot;;
++ enum return_type status = RETURN_ERROR;
++ pid_t ppp_pid;
++
++ snprintf(pppoe_call, sizeof(pppoe_call), &quot;/sbin/pppoe -p /var/run/pppoe.conf-adsl.pid.pppoe -I %s -T 80 -U -m 1412&quot;, intf-&gt;device);
++
++ if (!streq(acname, &quot;&quot;)) {
++ strcat(pppoe_call, &quot;-C &quot;);
++ strcat(pppoe_call, acname);
++ }
++
++ fd = open(tty_adsl, O_RDWR);
++ if (fd == -1) {
++ log_message(&quot;cannot open tty -- no pppd&quot;);
++ return RETURN_ERROR;
++ }
++ else if (access(pppd_launch[0], X_OK)) {
++ log_message(&quot;cannot open pppd - %s doesn't exist&quot;, pppd_launch[0]);
++ return RETURN_ERROR;
++ }
++
++ if (!(ppp_pid = fork())) {
++ dup2(fd, 0);
++ dup2(fd, 1);
++ dup2(fd, 2);
++
++ close(fd);
++ setsid();
++ if (ioctl(0, TIOCSCTTY, NULL))
++ log_perror(&quot;could not set new controlling tty&quot;);
++
++ printf(&quot;\t(exec of pppd)\n&quot;);
++ execv(pppd_launch[0], pppd_launch);
++ log_message(&quot;execve of %s failed: %s&quot;, pppd_launch[0], strerror(errno));
++ exit(-1);
++ }
++ close(fd);
++ while (retries &gt; 0 &amp;&amp; kill(ppp_pid, 0) == 0) {
++ FILE * f;
++ if ((f = fopen(&quot;/var/run/pppd.tdb&quot;, &quot;rb&quot;))) {
++ while (1) {
++ char buf[500];
++ char *p;
++ if (!fgets(buf, sizeof(buf), f))
++ break;
++ p = strstr(buf, &quot;IPLOCAL=&quot;);
++ if (p) {
++ struct sockaddr_in addr;
++ if (inet_aton(p + 8, &amp;addr.sin_addr))
++ intf-&gt;ip = addr.sin_addr;
++ status = RETURN_OK;
++ }
++ }
++ fclose(f);
++ if (status == RETURN_OK) {
++ log_message(&quot;PPP: connected!&quot;);
++ break;
++ }
++ }
++ retries--;
++ log_message(&quot;PPP: &lt;sleep&gt;&quot;);
++ sleep(2);
++ }
++
++ if (status != RETURN_OK) {
++ log_message(&quot;PPP: could not connect&quot;);
++ kill(ppp_pid, SIGTERM);
++ sleep(1);
++ kill(ppp_pid, SIGKILL);
++ sleep(1);
++ }
++ return status;
++}
++
++
++enum return_type perform_adsl(struct interface_info * intf)
++{
++ struct in_addr addr;
++ char * questions[] = { &quot;Username&quot;, &quot;Password&quot;, &quot;AC Name&quot;, NULL };
++ char * questions_auto[] = { &quot;adsluser&quot;, &quot;adslpass&quot;, &quot;adslacname&quot;, NULL };
++ static char ** answers = NULL;
++ enum return_type results;
++
++ inet_aton(&quot;10.0.0.10&quot;, &amp;addr);
++ memcpy(&amp;intf-&gt;ip, &amp;addr, sizeof(addr));
++
++ inet_aton(&quot;255.255.255.0&quot;, &amp;addr);
++ memcpy(&amp;intf-&gt;netmask, &amp;addr, sizeof(addr));
++
++ *((uint32_t *) &amp;intf-&gt;broadcast) = (*((uint32_t *) &amp;intf-&gt;ip) &amp;
++ *((uint32_t *) &amp;intf-&gt;netmask)) | ~(*((uint32_t *) &amp;intf-&gt;netmask));
++
++ intf-&gt;is_ptp = 0;
++
++ if (configure_net_device(intf)) {
++ stg1_error_message(&quot;Could not configure..&quot;);
++ return RETURN_ERROR;
++ }
++
++ results = ask_from_entries_auto(&quot;Please enter the username and password for your ADSL account.\n&quot;
++ &quot;Leave blank the AC Name field if you don't know what it means.\n&quot;
++ &quot;(Warning! only PPPoE protocol is supported)&quot;,
++ questions, &amp;answers, 40, questions_auto, NULL);
++ if (results != RETURN_OK)
++ return results;
++
++ intf-&gt;boot_proto = BOOTPROTO_ADSL_PPPOE;
++
++ wait_message(&quot;Waiting for ADSL connection to show up...&quot;);
++ my_insmod(&quot;ppp_generic&quot;, ANY_DRIVER_TYPE, NULL, 1);
++ my_insmod(&quot;ppp_async&quot;, ANY_DRIVER_TYPE, NULL, 1);
++ results = adsl_connect(intf, answers[0], answers[1], answers[2]);
++ remove_wait_message();
++
++ if (results != RETURN_OK) {
++ wait_message(&quot;Retrying the ADSL connection...&quot;);
++ results = adsl_connect(intf, answers[0], answers[1], answers[2]);
++ remove_wait_message();
++ } else {
++ intf-&gt;user = strdup(answers[0]);
++ intf-&gt;pass = strdup(answers[1]);
++ intf-&gt;acname = strdup(answers[2]);
++ }
++
++ if (results != RETURN_OK) {
++ stg1_error_message(&quot;I could not connect to the ADSL network.&quot;);
++ return perform_adsl(intf);
++ }
++
++ sleep(1);
++ res_init(); /* reinit the resolver, pppd modified /etc/resolv.conf */
++
++ return RETURN_OK;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/adsl.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/adsl.h
+===================================================================
+--- drakx/trunk/mdk-stage1/adsl.h (rev 0)
++++ drakx/trunk/mdk-stage1/adsl.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,34 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * View the homepage: <A HREF="http://us.mandriva.com/~gc/html/stage1.html">http://us.mandriva.com/~gc/html/stage1.html</A>
++ *
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Portions from GRUB -- GRand Unified Bootloader
++ * Copyright (C) 2000 Free Software Foundation, Inc.
++ *
++ * Itself based on etherboot-4.6.4 by Martin Renters.
++ *
++ */
++
++#ifndef _ADSL_H_
++#define _ADSL_H_
++
++#include &quot;stage1.h&quot;
++#include &quot;network.h&quot;
++
++enum return_type perform_adsl(struct interface_info * intf);
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/adsl.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/automatic.c
+===================================================================
+--- drakx/trunk/mdk-stage1/automatic.c (rev 0)
++++ drakx/trunk/mdk-stage1/automatic.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,166 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * This is supposed to replace the redhat &quot;kickstart&quot;, by name but
++ * also by design (less code pollution).
++ *
++ */
++
++
++#include &lt;unistd.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++#include &quot;tools.h&quot;
++#include &quot;utils.h&quot;
++#include &quot;stage1.h&quot;
++#include &quot;frontend.h&quot;
++#include &quot;log.h&quot;
++
++#include &quot;automatic.h&quot;
++
++
++static struct param_elem * automatic_params;
++static char * value_not_bound = &quot;&quot;;
++
++void grab_automatic_params(char * line)
++{
++ int i, p;
++ struct param_elem tmp_params[50];
++
++ i = 0; p = 0;
++ while (line[i] != '\0') {
++ char *name, *value;
++ int k;
++ int j = i;
++ while (line[i] != ':' &amp;&amp; line[i] != '\0')
++ i++;
++ name = memdup(&amp;line[j], i-j + 1);
++ name[i-j] = 0;
++
++ k = i+1;
++ i++;
++ while (line[i] != ',' &amp;&amp; line[i] != '\0')
++ i++;
++ value = memdup(&amp;line[k], i-k + 1);
++ value[i-k] = 0;
++
++ tmp_params[p].name = name;
++ tmp_params[p].value = value;
++ p++;
++ if (line[i] == '\0')
++ break;
++ i++;
++ }
++
++ tmp_params[p++].name = NULL;
++ automatic_params = memdup(tmp_params, sizeof(struct param_elem) * p);
++
++ log_message(&quot;AUTOMATIC MODE: got %d params&quot;, p-1);
++}
++
++
++char * get_auto_value(char * auto_param)
++{
++ struct param_elem * ptr = automatic_params;
++
++ struct param_elem short_aliases[] =
++ { { &quot;method&quot;, &quot;met&quot; }, { &quot;network&quot;, &quot;netw&quot; }, { &quot;interface&quot;, &quot;int&quot; }, { &quot;gateway&quot;, &quot;gat&quot; },
++ { &quot;netmask&quot;, &quot;netm&quot; }, { &quot;adsluser&quot;, &quot;adslu&quot; }, { &quot;adslpass&quot;, &quot;adslp&quot; }, { &quot;hostname&quot;, &quot;hos&quot; },
++ { &quot;domain&quot;, &quot;dom&quot; }, { &quot;server&quot;, &quot;ser&quot; }, { &quot;directory&quot;, &quot;dir&quot; }, { &quot;user&quot;, &quot;use&quot; },
++ { &quot;pass&quot;, &quot;pas&quot; }, { &quot;disk&quot;, &quot;dis&quot; }, { &quot;partition&quot;, &quot;par&quot; }, { &quot;proxy_host&quot;, &quot;proxh&quot; },
++ { &quot;proxy_port&quot;, &quot;proxp&quot; }, { NULL, NULL } };
++ struct param_elem * ptr_alias = short_aliases;
++ while (ptr_alias-&gt;name) {
++ if (streq(auto_param, ptr_alias-&gt;name))
++ break;
++ ptr_alias++;
++ }
++
++ while (ptr-&gt;name) {
++ if (streq(ptr-&gt;name, auto_param)
++ || (ptr_alias-&gt;name &amp;&amp; streq(ptr_alias-&gt;value, ptr-&gt;name)))
++ return ptr-&gt;value;
++ ptr++;
++ }
++
++ return value_not_bound;
++}
++
++
++enum return_type ask_from_list_auto(char *msg, char ** elems, char ** choice, char * auto_param, char ** elems_auto)
++{
++ if (!IS_AUTOMATIC) {
++ exit_bootsplash();
++ return ask_from_list(msg, elems, choice);
++ } else {
++ char ** sav_elems = elems;
++ char * tmp = get_auto_value(auto_param);
++ while (elems &amp;&amp; *elems) {
++ if (!strcmp(tmp, *elems_auto)) {
++ *choice = *elems;
++ log_message(&quot;AUTOMATIC: parameter %s for %s means returning %s&quot;, tmp, auto_param, *elems);
++ return RETURN_OK;
++ }
++ elems++;
++ elems_auto++;
++ }
++ unset_automatic(); /* we are in a fallback mode */
++ return ask_from_list(msg, sav_elems, choice);
++ }
++}
++
++enum return_type ask_from_list_comments_auto(char *msg, char ** elems, char ** elems_comments, char ** choice, char * auto_param, char ** elems_auto)
++{
++ if (!IS_AUTOMATIC) {
++ exit_bootsplash();
++ return ask_from_list_comments(msg, elems, elems_comments, choice);
++ } else {
++ char ** sav_elems = elems;
++ char * tmp = get_auto_value(auto_param);
++ while (elems &amp;&amp; *elems) {
++ if (!strcmp(tmp, *elems_auto)) {
++ *choice = *elems;
++ log_message(&quot;AUTOMATIC: parameter %s for %s means returning %s&quot;, tmp, auto_param, *elems);
++ return RETURN_OK;
++ }
++ elems++;
++ elems_auto++;
++ }
++ unset_automatic(); /* we are in a fallback mode */
++ return ask_from_list_comments(msg, sav_elems, elems_comments, choice);
++ }
++}
++
++
++enum return_type ask_from_entries_auto(char *msg, char ** questions, char *** answers, int entry_size, char ** questions_auto, void (*callback_func)(char ** strings))
++{
++ if (!IS_AUTOMATIC) {
++ exit_bootsplash();
++ return ask_from_entries(msg, questions, answers, entry_size, callback_func);
++ } else {
++ char * tmp_answers[50];
++ int i = 0;
++ while (questions &amp;&amp; *questions) {
++ tmp_answers[i] = get_auto_value(*questions_auto);
++ log_message(&quot;AUTOMATIC: question %s answers %s because of param %s&quot;, *questions, tmp_answers[i], *questions_auto);
++ i++;
++ questions++;
++ questions_auto++;
++
++ }
++ *answers = memdup(tmp_answers, sizeof(char *) * i);
++ return RETURN_OK;
++ }
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/automatic.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/automatic.h
+===================================================================
+--- drakx/trunk/mdk-stage1/automatic.h (rev 0)
++++ drakx/trunk/mdk-stage1/automatic.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,33 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * This is supposed to replace the redhat &quot;kickstart&quot;, by name but
++ * also by design (no code pollution).
++ *
++ */
++
++#ifndef _AUTOMATIC_H_
++#define _AUTOMATIC_H_
++
++#include &quot;stage1.h&quot;
++
++void grab_automatic_params(char * line);
++char * get_auto_value(char * auto_param);
++
++enum return_type ask_from_list_auto(char *msg, char ** elems, char ** choice, char * auto_param, char ** elems_auto);
++enum return_type ask_from_list_comments_auto(char *msg, char ** elems, char ** elems_comments, char ** choice, char * auto_param, char ** elems_auto);
++enum return_type ask_from_entries_auto(char *msg, char ** questions, char *** answers, int entry_size, char ** questions_auto, void (*callback_func)(char ** strings));
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/automatic.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/bootsplash.c
+===================================================================
+--- drakx/trunk/mdk-stage1/bootsplash.c (rev 0)
++++ drakx/trunk/mdk-stage1/bootsplash.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,70 @@
++/*
++ * Pixel (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">pixel at mandriva.com</A>)
++ *
++ * Copyright 2004 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#include &lt;stdio.h&gt;
++#include &quot;bootsplash.h&quot;
++#include &quot;frontend.h&quot;
++#include &quot;log.h&quot;
++
++static int total_size;
++static float previous;
++static FILE* splash = NULL;
++
++static void update_progression_only(int current_size)
++{
++ if (splash &amp;&amp; total_size) {
++ float ratio = (float) (current_size + 1) / total_size;
++ if (ratio &gt; previous + 0.01) {
++ fprintf(splash, &quot;show %d\n&quot;, (int) (ratio * 65534));
++ fflush(splash);
++ previous = ratio;
++ }
++ }
++}
++
++static void open_bootsplash(void)
++{
++ if (!splash) splash = fopen(&quot;/proc/splash&quot;, &quot;w&quot;);
++ if (!splash) log_message(&quot;opening /proc/splash failed&quot;);
++}
++
++void exit_bootsplash(void)
++{
++ log_message(&quot;exiting bootsplash&quot;);
++ open_bootsplash();
++ if (splash) {
++ fprintf(splash, &quot;verbose\n&quot;);
++ fflush(splash);
++ }
++}
++
++
++void init_progression(char *msg, int size)
++{
++ previous = 0; total_size = size;
++ open_bootsplash();
++ update_progression_only(0);
++ init_progression_raw(msg, size);
++}
++
++void update_progression(int current_size)
++{
++ update_progression_only(current_size);
++ update_progression_raw(current_size);
++}
++
++void end_progression(void)
++{
++ end_progression_raw();
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/bootsplash.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/bootsplash.h
+===================================================================
+--- drakx/trunk/mdk-stage1/bootsplash.h (rev 0)
++++ drakx/trunk/mdk-stage1/bootsplash.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,25 @@
++/*
++ * Pixel (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">pixel at mandriva.com</A>)
++ *
++ * Copyright 2004 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#ifndef _BOOTSPLASH_H_
++#define _BOOTSPLASH_H_
++
++#ifdef ENABLE_BOOTSPLASH
++void exit_bootsplash(void);
++void tell_bootsplash(char *cmd);
++#else
++#define exit_bootsplash()
++#endif
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/bootsplash.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/cdrom.c
+===================================================================
+--- drakx/trunk/mdk-stage1/cdrom.c (rev 0)
++++ drakx/trunk/mdk-stage1/cdrom.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,226 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Portions from Erik Troan (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ewt at redhat.com</A>)
++ *
++ * Copyright 1996 Red Hat Software
++ *
++ */
++
++#include &lt;stdlib.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;string.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;sys/mount.h&gt;
++#include &quot;stage1.h&quot;
++#include &quot;frontend.h&quot;
++#include &quot;modules.h&quot;
++#include &quot;probing.h&quot;
++#include &quot;log.h&quot;
++#include &quot;mount.h&quot;
++#include &quot;tools.h&quot;
++#include &quot;utils.h&quot;
++
++#include &quot;cdrom.h&quot;
++
++
++static int mount_that_cd_device(char * dev_name)
++{
++ char device_fullname[50];
++ int mount_result;
++
++ snprintf(device_fullname, sizeof(device_fullname), &quot;/dev/%s&quot;, dev_name);
++
++ mount_result = my_mount(device_fullname, MEDIA_LOCATION, &quot;iso9660&quot;, 0);
++
++ create_IMAGE_LOCATION(MEDIA_LOCATION);
++
++ return mount_result;
++}
++
++
++static enum return_type try_with_device(char * dev_name, char * dev_model);
++
++static enum return_type do_with_device(char * dev_name, char * dev_model)
++{
++ if (!image_has_stage2()) {
++ enum return_type results;
++ umount(MEDIA_LOCATION);
++ results = ask_yes_no(&quot;That CDROM disc does not seem to be a &quot; DISTRIB_NAME &quot; Installation CDROM.\nRetry with another disc?&quot;);
++ if (results == RETURN_OK)
++ return try_with_device(dev_name, dev_model);
++ return results;
++ }
++
++ log_message(&quot;found a &quot; DISTRIB_NAME &quot; CDROM, good news!&quot;);
++
++ may_load_compressed_image();
++
++ if (!KEEP_MOUNTED)
++ /* in rescue mode, we don't need the media anymore */
++ umount(MEDIA_LOCATION);
++
++ add_to_env(&quot;METHOD&quot;, &quot;cdrom&quot;);
++ return RETURN_OK;
++}
++
++static enum return_type try_with_device(char * dev_name, char * dev_model)
++{
++ wait_message(&quot;Trying to access a CDROM disc (drive %s)&quot;, dev_model);
++
++ if (mount_that_cd_device(dev_name) == -1) {
++ enum return_type results;
++ char msg[500];
++ unset_automatic(); /* we are in a fallback mode */
++ remove_wait_message();
++
++ snprintf(msg, sizeof(msg), &quot;I can't access a &quot; DISTRIB_NAME &quot; Installation disc in your CDROM drive (%s).\nRetry?&quot;, dev_model);
++ results = ask_yes_no(msg);
++ if (results == RETURN_OK)
++ return try_with_device(dev_name, dev_model);
++ return results;
++ }
++ remove_wait_message();
++
++ return do_with_device(dev_name, dev_model);
++}
++
++int try_automatic(char ** medias, char ** medias_models)
++{
++ static char * already_tried[50] = { NULL };
++ char ** model = medias_models;
++ char ** ptr = medias;
++ int i = 0;
++ while (ptr &amp;&amp; *ptr) {
++ char ** p;
++ for (p = already_tried; p &amp;&amp; *p; p++)
++ if (streq(*p, *ptr))
++ goto try_automatic_already_tried;
++ *p = strdup(*ptr);
++ *(p+1) = NULL;
++
++ wait_message(&quot;Trying to access &quot; DISTRIB_NAME &quot; CDROM disc (drive %s)&quot;, *model);
++ if (mount_that_cd_device(*ptr) != -1) {
++ if (image_has_stage2()) {
++ remove_wait_message();
++ return i;
++ }
++ else
++ umount(MEDIA_LOCATION);
++ }
++ remove_wait_message();
++
++ try_automatic_already_tried:
++ ptr++;
++ model++;
++ i++;
++ }
++ return -1;
++}
++
++enum return_type cdrom_prepare(void)
++{
++ char ** medias, ** ptr, ** medias_models;
++ char * choice;
++ int i, count = 0;
++ enum return_type results;
++ static int already_probed_ide_generic = 0;
++
++ my_insmod(&quot;ide_cd_mod&quot;, ANY_DRIVER_TYPE, NULL, 0);
++
++ if (IS_AUTOMATIC) {
++ get_medias(CDROM, &amp;medias, &amp;medias_models, BUS_IDE);
++ if ((i = try_automatic(medias, medias_models)) != -1)
++ return do_with_device(medias[i], medias_models[i]);
++
++ get_medias(CDROM, &amp;medias, &amp;medias_models, BUS_PCMCIA);
++ if ((i = try_automatic(medias, medias_models)) != -1)
++ return do_with_device(medias[i], medias_models[i]);
++
++ my_insmod(&quot;sr_mod&quot;, ANY_DRIVER_TYPE, NULL, 0);
++ get_medias(CDROM, &amp;medias, &amp;medias_models, BUS_SCSI);
++ if ((i = try_automatic(medias, medias_models)) != -1)
++ return do_with_device(medias[i], medias_models[i]);
++
++ get_medias(CDROM, &amp;medias, &amp;medias_models, BUS_USB);
++ if ((i = try_automatic(medias, medias_models)) != -1)
++ return do_with_device(medias[i], medias_models[i]);
++
++ /* detect hybrid isos (isos dumped to an USB stick) */
++ my_insmod(&quot;sd_mod&quot;, ANY_DRIVER_TYPE, NULL, 0);
++ get_medias(DISK, &amp;medias, &amp;medias_models, BUS_USB);
++ if ((i = try_automatic(medias, medias_models)) != -1) {
++ return do_with_device(medias[i], medias_models[i]);
++ }
++
++ unset_automatic();
++ } else
++ my_insmod(&quot;sr_mod&quot;, ANY_DRIVER_TYPE, NULL, 0);
++
++
++ get_medias(CDROM, &amp;medias, &amp;medias_models, BUS_ANY);
++ ptr = medias;
++ while (ptr &amp;&amp; *ptr) {
++ count++;
++ ptr++;
++ }
++
++ if (count == 0) {
++ if (!already_probed_ide_generic) {
++ already_probed_ide_generic = 1;
++ my_insmod(&quot;ide_generic&quot;, ANY_DRIVER_TYPE, NULL, 0);
++ return cdrom_prepare();
++ }
++ stg1_error_message(&quot;No CDROM device found.&quot;);
++ i = ask_insmod(MEDIA_ADAPTERS);
++ if (i == RETURN_BACK)
++ return RETURN_BACK;
++ return cdrom_prepare();
++ }
++
++ if (count == 1) {
++ results = try_with_device(*medias, *medias_models);
++ if (results == RETURN_OK)
++ return RETURN_OK;
++ i = ask_insmod(MEDIA_ADAPTERS);
++ if (i == RETURN_BACK)
++ return RETURN_BACK;
++ return cdrom_prepare();
++ }
++
++ results = ask_from_list_comments(&quot;Please choose the CDROM drive to use for the installation.&quot;, medias, medias_models, &amp;choice);
++ if (results == RETURN_OK) {
++ char ** model = medias_models;
++ ptr = medias;
++ while (ptr &amp;&amp; *ptr &amp;&amp; model &amp;&amp; *model) {
++ if (!strcmp(*ptr, choice))
++ break;
++ ptr++;
++ model++;
++ }
++ results = try_with_device(choice, *model);
++ } else
++ return results;
++
++ if (results == RETURN_OK)
++ return RETURN_OK;
++ if (results == RETURN_BACK)
++ return cdrom_prepare();
++
++ i = ask_insmod(MEDIA_ADAPTERS);
++ if (i == RETURN_BACK)
++ return RETURN_BACK;
++ return cdrom_prepare();
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/cdrom.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/cdrom.h
+===================================================================
+--- drakx/trunk/mdk-stage1/cdrom.h (rev 0)
++++ drakx/trunk/mdk-stage1/cdrom.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,29 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Portions from Erik Troan (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ewt at redhat.com</A>)
++ *
++ * Copyright 1996 Red Hat Software
++ *
++ */
++
++#ifndef _CDROM_H_
++#define _CDROM_H_
++
++#include &quot;stage1.h&quot;
++
++enum return_type cdrom_prepare(void);
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/cdrom.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/config-stage1.h
+===================================================================
+--- drakx/trunk/mdk-stage1/config-stage1.h (rev 0)
++++ drakx/trunk/mdk-stage1/config-stage1.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,82 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#ifndef _CONFIG_STAGE1_H_
++#define _CONFIG_STAGE1_H_
++
++#ifdef _GNU_SOURCE
++# undef _GNU_SOURCE
++#endif
++#define _GNU_SOURCE 1
++
++
++/* If we have more than that amount of memory (in Mbytes), we assume we can load the second stage as a ramdisk */
++#define MEM_LIMIT_DRAKX 68
++/* If we have more than that amount of memory (in Mbytes), we preload the second stage as a ramdisk */
++#define MEM_LIMIT_DRAKX_PRELOAD 100
++
++/* If we have more than that amount of memory (in Mbytes), we assume we can load the rescue as a ramdisk */
++#define MEM_LIMIT_RESCUE 40
++/* If we have more than that amount of memory (in Mbytes), we preload the rescue as a ramdisk */
++#define MEM_LIMIT_RESCUE_PRELOAD 100
++
++#define KA_MAX_RETRY 5
++
++#define LIVE_LOCATION_REL &quot;install/stage2/live/&quot;
++#define COMPRESSED_LOCATION_REL &quot;install/stage2/&quot;
++#define COMPRESSED_STAGE2_NAME &quot;mdkinst.sqfs&quot;
++#define COMPRESSED_RESCUE_NAME &quot;rescue.sqfs&quot;
++#define COMPRESSED_NAME(prefix) (IS_RESCUE ? prefix COMPRESSED_RESCUE_NAME : prefix COMPRESSED_STAGE2_NAME)
++#define COMPRESSED_FILE_REL(prefix) COMPRESSED_NAME(prefix COMPRESSED_LOCATION_REL)
++
++/* the remote media is mounted in MEDIA_LOCATION, and
++ - IMAGE_LOCATION is a symlink image -&gt; image/mdk/mirror/dir
++ - IMAGE_LOCATION is a symlink image -&gt; loop/i586 and iso file is loopback mounted in LOOP_LOCATION
++ */
++#define MEDIA_LOCATION_REL &quot;media&quot;
++#define MEDIA_LOCATION IMAGE_LOCATION_DIR MEDIA_LOCATION_REL
++
++#define LOOP_LOCATION_REL &quot;loop&quot;
++#define LOOP_LOCATION IMAGE_LOCATION_DIR LOOP_LOCATION_REL
++
++#define IMAGE_LOCATION_REL &quot;image&quot;
++#define IMAGE_LOCATION_DIR &quot;/tmp/&quot;
++#define IMAGE_LOCATION IMAGE_LOCATION_DIR IMAGE_LOCATION_REL
++
++#define COMPRESSED_LOCATION IMAGE_LOCATION &quot;/&quot; COMPRESSED_LOCATION_REL
++
++/* - if we use a compressed image : STAGE2_LOCATION is a the mount point
++ - if we use the live: STAGE2_LOCATION is a relative symlink to image/install/stage2/live
++*/
++#define STAGE2_LOCATION &quot;/tmp/stage2&quot;
++
++
++/* user-definable (in Makefile): DISABLE_NETWORK, DISABLE_DISK, DISABLE_CDROM, DISABLE_PCMCIA */
++
++
++/* some factorizing for disabling more features */
++
++#ifdef DISABLE_DISK
++#ifdef DISABLE_CDROM
++#define DISABLE_MEDIAS
++#endif
++#endif
++
++/* path to mirror list for net install */
++#ifndef DISABLE_NETWORK
++#define MIRRORLIST_HOST &quot;api.mandriva.com&quot;
++#define MIRRORLIST_PATH &quot;/mirrors&quot;
++#endif
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/config-stage1.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/dhcp.c
+===================================================================
+--- drakx/trunk/mdk-stage1/dhcp.c (rev 0)
++++ drakx/trunk/mdk-stage1/dhcp.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,678 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Portions from Erik Troan (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ewt at redhat.com</A>)
++ *
++ * Copyright 1996 Red Hat Software
++ *
++ */
++
++/*
++ * Portions from GRUB -- GRand Unified Bootloader
++ * Copyright (C) 2000 Free Software Foundation, Inc.
++ */
++
++
++#include &lt;stdlib.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;string.h&gt;
++#include &lt;sys/socket.h&gt;
++#include &lt;sys/ioctl.h&gt;
++#include &lt;net/if.h&gt;
++#include &lt;arpa/inet.h&gt;
++#include &lt;net/route.h&gt;
++#include &lt;errno.h&gt;
++#include &lt;net/ethernet.h&gt;
++#include &lt;netinet/ip.h&gt;
++#include &lt;netinet/udp.h&gt;
++#include &lt;sys/time.h&gt;
++#include &lt;time.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;sys/poll.h&gt;
++
++#include &quot;stage1.h&quot;
++#include &quot;log.h&quot;
++#include &quot;tools.h&quot;
++#include &quot;utils.h&quot;
++#include &quot;network.h&quot;
++#include &quot;frontend.h&quot;
++#include &quot;automatic.h&quot;
++
++#include &quot;dhcp.h&quot;
++
++
++typedef int bp_int32;
++typedef short bp_int16;
++
++#define BOOTP_OPTION_NETMASK 1
++#define BOOTP_OPTION_GATEWAY 3
++#define BOOTP_OPTION_DNS 6
++#define BOOTP_OPTION_HOSTNAME 12
++#define BOOTP_OPTION_DOMAIN 15
++#define BOOTP_OPTION_BROADCAST 28
++
++#define DHCP_OPTION_REQADDR 50
++#define DHCP_OPTION_LEASE 51
++#define DHCP_OPTION_TYPE 53
++#define DHCP_OPTION_SERVER 54
++#define DHCP_OPTION_OPTIONREQ 55
++#define DHCP_OPTION_MAXSIZE 57
++
++#define DHCP_OPTION_CLIENT_IDENTIFIER 61
++
++#define BOOTP_CLIENT_PORT 68
++#define BOOTP_SERVER_PORT 67
++
++#define BOOTP_OPCODE_REQUEST 1
++#define BOOTP_OPCODE_REPLY 2
++
++#define DHCP_TYPE_DISCOVER 1
++#define DHCP_TYPE_OFFER 2
++#define DHCP_TYPE_REQUEST 3
++#define DHCP_TYPE_ACK 5
++#define DHCP_TYPE_RELEASE 7
++
++#define BOOTP_VENDOR_LENGTH 64
++#define DHCP_VENDOR_LENGTH 340
++
++struct bootp_request {
++ char opcode;
++ char hw;
++ char hwlength;
++ char hopcount;
++ bp_int32 id;
++ bp_int16 secs;
++ bp_int16 flags;
++ bp_int32 ciaddr, yiaddr, server_ip, bootp_gw_ip;
++ char hwaddr[16];
++ char servername[64];
++ char bootfile[128];
++ char vendor[DHCP_VENDOR_LENGTH];
++} ;
++
++static const char vendor_cookie[] = { 99, 130, 83, 99, 255 };
++
++
++static unsigned int verify_checksum(void * buf2, int length2)
++{
++ unsigned int csum = 0;
++ unsigned short * sp;
++
++ for (sp = (unsigned short *) buf2; length2 &gt; 0; (length2 -= 2), sp++)
++ csum += *sp;
++
++ while (csum &gt;&gt; 16)
++ csum = (csum &amp; 0xffff) + (csum &gt;&gt; 16);
++
++ return (csum == 0xffff);
++}
++
++
++static int initial_setup_interface(char * device, int s) {
++ struct sockaddr_in * addrp;
++ struct ifreq req;
++ struct rtentry route;
++ int true = 1;
++
++ addrp = (struct sockaddr_in *) &amp;req.ifr_addr;
++
++ strcpy(req.ifr_name, device);
++ addrp-&gt;sin_family = AF_INET;
++ addrp-&gt;sin_port = 0;
++ memset(&amp;addrp-&gt;sin_addr, 0, sizeof(addrp-&gt;sin_addr));
++
++ req.ifr_flags = 0; /* take it down */
++ if (ioctl(s, SIOCSIFFLAGS, &amp;req)) {
++ log_perror(&quot;SIOCSIFFLAGS (downing)&quot;);
++ return -1;
++ }
++
++ addrp-&gt;sin_family = AF_INET;
++ addrp-&gt;sin_addr.s_addr = htonl(0);
++ if (ioctl(s, SIOCSIFADDR, &amp;req)) {
++ log_perror(&quot;SIOCSIFADDR&quot;);
++ return -1;
++ }
++
++ req.ifr_flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING;
++ if (ioctl(s, SIOCSIFFLAGS, &amp;req)) {
++ log_perror(&quot;SIOCSIFFLAGS (upping)&quot;);
++ return -1;
++ }
++
++ memset(&amp;route, 0, sizeof(route));
++ memcpy(&amp;route.rt_gateway, addrp, sizeof(*addrp));
++
++ addrp-&gt;sin_family = AF_INET;
++ addrp-&gt;sin_port = 0;
++ addrp-&gt;sin_addr.s_addr = INADDR_ANY;
++ memcpy(&amp;route.rt_dst, addrp, sizeof(*addrp));
++ memcpy(&amp;route.rt_genmask, addrp, sizeof(*addrp));
++
++ route.rt_dev = device;
++ route.rt_flags = RTF_UP;
++ route.rt_metric = 0;
++
++ if (ioctl(s, SIOCADDRT, &amp;route)) {
++ if (errno != EEXIST) {
++ close(s);
++ log_perror(&quot;SIOCADDRT&quot;);
++ return -1;
++ }
++ }
++
++ if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &amp;true, sizeof(true))) {
++ close(s);
++ log_perror(&quot;setsockopt&quot;);
++ return -1;
++ }
++
++ /* I need to sleep a bit in order for kernel to finish init of the
++ network device; this would allow to not send further multiple
++ dhcp requests when only one is needed. */
++ wait_message(&quot;Bringing up networking...&quot;);
++ sleep(2);
++ remove_wait_message();
++
++ return 0;
++}
++
++
++void set_missing_ip_info(struct interface_info * intf)
++{
++ bp_int32 ipNum = *((bp_int32 *) &amp;intf-&gt;ip);
++ bp_int32 nmNum;
++
++ if (intf-&gt;netmask.s_addr == 0)
++ inet_aton(guess_netmask(inet_ntoa(intf-&gt;ip)), &amp;intf-&gt;netmask);
++
++ nmNum = *((bp_int32 *) &amp;intf-&gt;netmask);
++
++ if (intf-&gt;broadcast.s_addr == 0)
++ *((bp_int32 *) &amp;intf-&gt;broadcast) = (ipNum &amp; nmNum) | ~(nmNum);
++
++ if (intf-&gt;network.s_addr == 0)
++ *((bp_int32 *) &amp;intf-&gt;network) = ipNum &amp; nmNum;
++}
++
++static void parse_reply(struct bootp_request * breq, struct interface_info * intf)
++{
++ unsigned char * chptr;
++ unsigned char option, length;
++
++ if (breq-&gt;bootfile &amp;&amp; strlen(breq-&gt;bootfile) &gt; 0) {
++ if (IS_NETAUTO)
++ add_to_env(&quot;KICKSTART&quot;, breq-&gt;bootfile);
++ else
++ log_message(&quot;warning: ignoring `bootfile' DHCP server parameter, since `netauto' boot parameter was not given; reboot with `linux netauto' (and anymore useful boot parameters) if you want `bootfile' to be used as a `auto_inst.cfg.pl' stage2 configuration file&quot;);
++ }
++
++ memcpy(&amp;intf-&gt;ip, &amp;breq-&gt;yiaddr, 4);
++
++ chptr = (unsigned char *) breq-&gt;vendor;
++ chptr += 4;
++ while (*chptr != 0xFF &amp;&amp; (void *) chptr &lt; (void *) breq-&gt;vendor + DHCP_VENDOR_LENGTH) {
++ char tmp_str[500];
++ option = *chptr++;
++ if (!option)
++ continue;
++ length = *chptr++;
++
++ switch (option) {
++ case BOOTP_OPTION_DNS:
++ memcpy(&amp;dns_server, chptr, sizeof(dns_server));
++ log_message(&quot;got dns %s&quot;, inet_ntoa(dns_server));
++ if (length &gt;= sizeof(dns_server)*2) {
++ memcpy(&amp;dns_server2, chptr+sizeof(dns_server), sizeof(dns_server2));
++ log_message(&quot;got dns2 %s&quot;, inet_ntoa(dns_server2));
++ }
++ break;
++
++ case BOOTP_OPTION_NETMASK:
++ memcpy(&amp;intf-&gt;netmask, chptr, sizeof(intf-&gt;netmask));
++ log_message(&quot;got netmask %s&quot;, inet_ntoa(intf-&gt;netmask));
++ break;
++
++ case BOOTP_OPTION_DOMAIN:
++ memcpy(tmp_str, chptr, length);
++ tmp_str[length] = '\0';
++ domain = strdup(tmp_str);
++ log_message(&quot;got domain %s&quot;, domain);
++ break;
++
++ case BOOTP_OPTION_BROADCAST:
++ memcpy(&amp;intf-&gt;broadcast, chptr, sizeof(intf-&gt;broadcast));
++ log_message(&quot;got broadcast %s&quot;, inet_ntoa(intf-&gt;broadcast));
++ break;
++
++ case BOOTP_OPTION_GATEWAY:
++ memcpy(&amp;gateway, chptr, sizeof(gateway));
++ log_message(&quot;got gateway %s&quot;, inet_ntoa(gateway));
++ break;
++
++ }
++
++ chptr += length;
++ }
++
++ set_missing_ip_info(intf);
++}
++
++
++static void init_vendor_codes(struct bootp_request * breq) {
++ memcpy(breq-&gt;vendor, vendor_cookie, sizeof(vendor_cookie));
++}
++
++static char gen_hwaddr[16];
++
++static int prepare_request(struct bootp_request * breq, int sock, char * device)
++{
++ struct ifreq req;
++
++ memset(breq, 0, sizeof(*breq));
++
++ breq-&gt;opcode = BOOTP_OPCODE_REQUEST;
++
++ strcpy(req.ifr_name, device);
++ if (ioctl(sock, SIOCGIFHWADDR, &amp;req)) {
++ log_perror(&quot;SIOCSIFHWADDR&quot;);
++ return -1;
++ }
++
++ breq-&gt;hw = req.ifr_hwaddr.sa_family;
++ breq-&gt;hwlength = IFHWADDRLEN;
++ memcpy(breq-&gt;hwaddr, req.ifr_hwaddr.sa_data, IFHWADDRLEN);
++ memcpy(gen_hwaddr, req.ifr_hwaddr.sa_data, IFHWADDRLEN);
++
++ breq-&gt;hopcount = 0;
++
++ init_vendor_codes(breq);
++
++ return 0;
++}
++
++static int get_vendor_code(struct bootp_request * bresp, unsigned char option, void * data)
++{
++ unsigned char * chptr;
++ unsigned int length, theOption;
++
++ chptr = (unsigned char*) bresp-&gt;vendor + 4;
++ while (*chptr != 0xFF &amp;&amp; *chptr != option) {
++ theOption = *chptr++;
++ if (!theOption)
++ continue;
++ length = *chptr++;
++ chptr += length;
++ }
++
++ if (*chptr++ == 0xff)
++ return 1;
++
++ length = *chptr++;
++ memcpy(data, chptr, length);
++
++ return 0;
++}
++
++
++static unsigned long currticks(void)
++{
++ struct timeval tv;
++ unsigned long csecs;
++ unsigned long ticks_per_csec, ticks_per_usec;
++
++ /* Note: 18.2 ticks/sec. */
++
++ gettimeofday (&amp;tv, 0);
++ csecs = tv.tv_sec / 10;
++ ticks_per_csec = csecs * 182;
++ ticks_per_usec = (((tv.tv_sec - csecs * 10) * 1000000 + tv.tv_usec) * 182 / 10000000);
++ return ticks_per_csec + ticks_per_usec;
++}
++
++
++#define BACKOFF_LIMIT 7
++#define TICKS_PER_SEC 18
++#define MAX_ARP_RETRIES 7
++
++static void rfc951_sleep(int exp)
++{
++ static long seed = 0;
++ long q;
++ unsigned long tmo;
++
++ if (exp &gt; BACKOFF_LIMIT)
++ exp = BACKOFF_LIMIT;
++
++ if (!seed)
++ /* Initialize linear congruential generator. */
++ seed = (currticks () + *(long *) &amp;gen_hwaddr + ((short *) gen_hwaddr)[2]);
++
++ /* Simplified version of the LCG given in Bruce Scheier's
++ &quot;Applied Cryptography&quot;. */
++ q = seed / 53668;
++ if ((seed = 40014 * (seed - 53668 * q) - 12211 * q) &lt; 0)
++ seed += 2147483563l;
++
++ /* Compute mask. */
++ for (tmo = 63; tmo &lt;= 60 * TICKS_PER_SEC &amp;&amp; --exp &gt; 0; tmo = 2 * tmo + 1)
++ ;
++
++ /* Sleep. */
++ log_message(&quot;&lt;sleep&gt;&quot;);
++
++ for (tmo = (tmo &amp; seed) + currticks (); currticks () &lt; tmo;);
++}
++
++
++static int handle_transaction(int s, struct bootp_request * breq, struct bootp_request * bresp,
++ struct sockaddr_in * server_addr, int dhcp_type)
++{
++ struct pollfd polls;
++ int i, j;
++ int retry = 1;
++ int sin;
++ char eth_packet[ETH_FRAME_LEN];
++ struct iphdr * ip_hdr;
++ struct udphdr * udp_hdr;
++ unsigned char type;
++ unsigned long starttime;
++ int timeout = 1;
++
++ breq-&gt;id = starttime = currticks();
++ breq-&gt;secs = 0;
++
++ sin = socket(AF_PACKET, SOCK_DGRAM, ntohs(ETH_P_IP));
++ if (sin &lt; 0) {
++ log_perror(&quot;af_packet socket&quot;);
++ return -1;
++ }
++
++ while (retry &lt;= MAX_ARP_RETRIES) {
++ i = sizeof(*breq);
++
++ if (sendto(s, breq, i, 0, (struct sockaddr *) server_addr, sizeof(*server_addr)) != i) {
++ close(s);
++ log_perror(&quot;sendto&quot;);
++ return -1;
++ }
++
++ polls.fd = sin;
++ polls.events = POLLIN;
++
++ while (poll(&amp;polls, 1, timeout*1000) == 1) {
++
++ if ((j = recv(sin, eth_packet, sizeof(eth_packet), 0)) == -1) {
++ log_perror(&quot;recv&quot;);
++ continue;
++ }
++
++ /* We need to do some basic sanity checking of the header */
++ if (j &lt; (signed)(sizeof(*ip_hdr) + sizeof(*udp_hdr)))
++ continue;
++
++ ip_hdr = (void *) eth_packet;
++ if (!verify_checksum(ip_hdr, sizeof(*ip_hdr)))
++ continue;
++
++ if (ntohs(ip_hdr-&gt;tot_len) &gt; j)
++ continue;
++
++ j = ntohs(ip_hdr-&gt;tot_len);
++
++ if (ip_hdr-&gt;protocol != IPPROTO_UDP)
++ continue;
++
++ udp_hdr = (void *) (eth_packet + sizeof(*ip_hdr));
++
++ if (ntohs(udp_hdr-&gt;source) != BOOTP_SERVER_PORT)
++ continue;
++
++ if (ntohs(udp_hdr-&gt;dest) != BOOTP_CLIENT_PORT)
++ continue;
++ /* Go on with this packet; it looks sane */
++
++ /* Originally copied sizeof (*bresp) - this is a security
++ problem due to a potential underflow of the source
++ buffer. Also, it trusted that the packet was properly
++ 0xFF terminated, which is not true in the case of the
++ DHCP server on Cisco 800 series ISDN router. */
++
++ memset (bresp, 0xFF, sizeof (*bresp));
++ memcpy (bresp, (char *) udp_hdr + sizeof (*udp_hdr), j - sizeof (*ip_hdr) - sizeof (*udp_hdr));
++
++ /* sanity checks */
++ if (bresp-&gt;id != breq-&gt;id)
++ continue;
++ if (bresp-&gt;opcode != BOOTP_OPCODE_REPLY)
++ continue;
++ if (bresp-&gt;hwlength != breq-&gt;hwlength)
++ continue;
++ if (memcmp(bresp-&gt;hwaddr, breq-&gt;hwaddr, bresp-&gt;hwlength))
++ continue;
++ if (get_vendor_code(bresp, DHCP_OPTION_TYPE, &amp;type) || type != dhcp_type)
++ continue;
++ if (memcmp(bresp-&gt;vendor, vendor_cookie, 4))
++ continue;
++ return 0;
++ }
++ rfc951_sleep(retry);
++ breq-&gt;secs = htons ((currticks () - starttime) / 20);
++ retry++;
++ timeout *= 2;
++ if (timeout &gt; 5)
++ timeout = 5;
++ }
++
++ return -1;
++}
++
++static void add_vendor_code(struct bootp_request * breq, unsigned char option, unsigned char length, void * data)
++{
++ unsigned char * chptr;
++ int theOption, theLength;
++
++ chptr = (unsigned char*) breq-&gt;vendor;
++ chptr += 4;
++ while (*chptr != 0xFF &amp;&amp; *chptr != option) {
++ theOption = *chptr++;
++ if (!theOption) continue;
++ theLength = *chptr++;
++ chptr += theLength;
++ }
++
++ *chptr++ = option;
++ *chptr++ = length;
++ memcpy(chptr, data, length);
++ chptr[length] = 0xff;
++}
++
++
++char * dhcp_hostname = NULL;
++char * dhcp_domain = NULL;
++
++enum return_type perform_dhcp(struct interface_info * intf)
++{
++ int s, i;
++ struct sockaddr_in server_addr;
++ struct sockaddr_in client_addr;
++ struct sockaddr_in broadcast_addr;
++ struct bootp_request breq, bresp;
++ unsigned char messageType;
++ unsigned int lease;
++ short aShort;
++ int num_options;
++ char requested_options[50];
++ char * client_id_str, * client_id_hwaddr;
++
++ s = socket(AF_INET, SOCK_DGRAM, 0);
++ if (s &lt; 0) {
++ log_perror(&quot;socket&quot;);
++ return RETURN_ERROR;
++ }
++
++ {
++ enum return_type results;
++ char * questions[] = { &quot;Host name&quot;, &quot;Domain name&quot;, NULL };
++ char * questions_auto[] = { &quot;hostname&quot;, &quot;domain&quot; };
++ static char ** answers = NULL;
++ char * boulet;
++
++ client_id_str = client_id_hwaddr = NULL;
++
++ results = ask_from_entries_auto(&quot;If the DHCP server needs to know you by name; please fill in this information. &quot;
++ &quot;Valid answers are for example: `mybox' for hostname and `mynetwork.com' for &quot;
++ &quot;domain name, for a machine called `mybox.mynetwork.com' on the Internet.&quot;,
++ questions, &amp;answers, 32, questions_auto, NULL);
++ if (results == RETURN_OK)
++ {
++ dhcp_hostname = answers[0];
++ if ((boulet = strchr(dhcp_hostname, '.')) != NULL)
++ boulet[0] = '\0';
++ dhcp_domain = answers[1];
++
++ if (*dhcp_hostname &amp;&amp; *dhcp_domain) {
++ /* if we have both, then create client id from them */
++ client_id_str = malloc(1 + strlen(dhcp_hostname) + 1 + strlen(dhcp_domain) + 1);
++ client_id_str[0] = '\0';
++ sprintf(client_id_str+1, &quot;%s.%s&quot;, dhcp_hostname, dhcp_domain);
++ }
++ }
++ }
++
++ if (initial_setup_interface(intf-&gt;device, s) != 0) {
++ close(s);
++ return RETURN_ERROR;
++ }
++
++ if (prepare_request(&amp;breq, s, intf-&gt;device) != 0) {
++ close(s);
++ return RETURN_ERROR;
++ }
++
++ messageType = DHCP_TYPE_DISCOVER;
++ add_vendor_code(&amp;breq, DHCP_OPTION_TYPE, 1, &amp;messageType);
++
++ /* add pieces needed to have DDNS/DHCP IP selection based on requested name */
++ if (dhcp_hostname &amp;&amp; *dhcp_hostname) { /* pick client id form based on absence or presence of domain name */
++ if (*dhcp_domain) /* alternate style &lt;hostname&gt;.&lt;domainname&gt; */
++ add_vendor_code(&amp;breq, DHCP_OPTION_CLIENT_IDENTIFIER, strlen(client_id_str+1)+1, client_id_str);
++ else { /* usual style (aka windows / dhcpcd) */
++ /* but put MAC in form required for client identifier first */
++ client_id_hwaddr = malloc(IFHWADDRLEN+2);
++ /* (from pump-0.8.22/dhcp.c)
++ * Microsoft uses a client identifier field of the 802.3 address with a
++ * pre-byte of a &quot;1&quot;. In order to re-use the DHCP address that they set
++ * for this interface, we have to mimic their identifier.
++ */
++ client_id_hwaddr[0] = 1; /* set flag for ethernet */
++ memcpy(client_id_hwaddr+1, gen_hwaddr, IFHWADDRLEN);
++ add_vendor_code(&amp;breq, DHCP_OPTION_CLIENT_IDENTIFIER, IFHWADDRLEN+1, client_id_hwaddr);
++ }
++ /* this is the one that the dhcp server really wants for DDNS updates */
++ add_vendor_code(&amp;breq, BOOTP_OPTION_HOSTNAME, strlen(dhcp_hostname), dhcp_hostname);
++ log_message(&quot;DHCP: telling server to use name = %s&quot;, dhcp_hostname);
++ }
++
++ memset(&amp;client_addr.sin_addr, 0, sizeof(&amp;client_addr.sin_addr));
++ client_addr.sin_family = AF_INET;
++ client_addr.sin_port = htons(BOOTP_CLIENT_PORT); /* bootp client */
++
++ if (bind(s, (struct sockaddr *) &amp;client_addr, sizeof(client_addr))) {
++ log_perror(&quot;bind&quot;);
++ return RETURN_ERROR;
++ }
++
++ broadcast_addr.sin_family = AF_INET;
++ broadcast_addr.sin_port = htons(BOOTP_SERVER_PORT); /* bootp server */
++ memset(&amp;broadcast_addr.sin_addr, 0xff, sizeof(broadcast_addr.sin_addr)); /* broadcast */
++
++ log_message(&quot;DHCP: sending DISCOVER&quot;);
++
++ wait_message(&quot;Sending DHCP request...&quot;);
++ i = handle_transaction(s, &amp;breq, &amp;bresp, &amp;broadcast_addr, DHCP_TYPE_OFFER);
++ remove_wait_message();
++
++ if (i != 0) {
++ stg1_error_message(&quot;No DHCP reply received.&quot;);
++ close(s);
++ return RETURN_ERROR;
++ }
++
++ server_addr.sin_family = AF_INET;
++ server_addr.sin_port = htons(BOOTP_SERVER_PORT); /* bootp server */
++ if (get_vendor_code(&amp;bresp, DHCP_OPTION_SERVER, &amp;server_addr.sin_addr)) {
++ close(s);
++ log_message(&quot;DHCPOFFER didn't include server address&quot;);
++ return RETURN_ERROR;
++ }
++
++ init_vendor_codes(&amp;breq);
++ messageType = DHCP_TYPE_REQUEST;
++ add_vendor_code(&amp;breq, DHCP_OPTION_TYPE, 1, &amp;messageType);
++ add_vendor_code(&amp;breq, DHCP_OPTION_SERVER, 4, &amp;server_addr.sin_addr);
++ add_vendor_code(&amp;breq, DHCP_OPTION_REQADDR, 4, &amp;bresp.yiaddr);
++
++ /* if used the first time, then have to use it again */
++ if (dhcp_hostname &amp;&amp; *dhcp_hostname) { /* add pieces needed to have DDNS/DHCP IP selection based on requested name */
++ if (dhcp_domain &amp;&amp; *dhcp_domain) /* alternate style */
++ add_vendor_code(&amp;breq, DHCP_OPTION_CLIENT_IDENTIFIER, strlen(client_id_str+1)+1, client_id_str);
++ else /* usual style (aka windows / dhcpcd) */
++ add_vendor_code(&amp;breq, DHCP_OPTION_CLIENT_IDENTIFIER, IFHWADDRLEN+1, client_id_hwaddr);
++ /* this is the one that the dhcp server really wants for DDNS updates */
++ add_vendor_code(&amp;breq, BOOTP_OPTION_HOSTNAME, strlen(dhcp_hostname), dhcp_hostname);
++ }
++
++ aShort = ntohs(sizeof(struct bootp_request));
++ add_vendor_code(&amp;breq, DHCP_OPTION_MAXSIZE, 2, &amp;aShort);
++
++ num_options = 0;
++ requested_options[num_options++] = BOOTP_OPTION_NETMASK;
++ requested_options[num_options++] = BOOTP_OPTION_GATEWAY;
++ requested_options[num_options++] = BOOTP_OPTION_DNS;
++ requested_options[num_options++] = BOOTP_OPTION_DOMAIN;
++ requested_options[num_options++] = BOOTP_OPTION_BROADCAST;
++ add_vendor_code(&amp;breq, DHCP_OPTION_OPTIONREQ, num_options, requested_options);
++
++ /* request a lease of 1 hour */
++ i = htonl(60 * 60);
++ add_vendor_code(&amp;breq, DHCP_OPTION_LEASE, 4, &amp;i);
++
++ log_message(&quot;DHCP: sending REQUEST&quot;);
++
++ i = handle_transaction(s, &amp;breq, &amp;bresp, &amp;broadcast_addr, DHCP_TYPE_ACK);
++
++ if (i != 0) {
++ close(s);
++ return RETURN_ERROR;
++ }
++
++ if (get_vendor_code(&amp;bresp, DHCP_OPTION_LEASE, &amp;lease)) {
++ log_message(&quot;failed to get lease time\n&quot;);
++ return RETURN_ERROR;
++ }
++ lease = ntohl(lease);
++
++ close(s);
++
++ intf-&gt;netmask.s_addr = 0;
++ intf-&gt;broadcast.s_addr = 0;
++ intf-&gt;network.s_addr = 0;
++
++ parse_reply(&amp;bresp, intf);
++
++ return RETURN_OK;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/dhcp.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/dhcp.h
+===================================================================
+--- drakx/trunk/mdk-stage1/dhcp.h (rev 0)
++++ drakx/trunk/mdk-stage1/dhcp.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,37 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * View the homepage: <A HREF="http://us.mandriva.com/~gc/html/stage1.html">http://us.mandriva.com/~gc/html/stage1.html</A>
++ *
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Portions from GRUB -- GRand Unified Bootloader
++ * Copyright (C) 2000 Free Software Foundation, Inc.
++ *
++ * Itself based on etherboot-4.6.4 by Martin Renters.
++ *
++ */
++
++#ifndef _DHCP_H_
++#define _DHCP_H_
++
++#include &quot;stage1.h&quot;
++#include &quot;network.h&quot;
++
++enum return_type perform_dhcp(struct interface_info * intf);
++
++extern char * dhcp_hostname;
++extern char * dhcp_domain;
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/dhcp.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/directory.c
+===================================================================
+--- drakx/trunk/mdk-stage1/directory.c (rev 0)
++++ drakx/trunk/mdk-stage1/directory.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,169 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ * Olivier Blin (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">oblin at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Portions from Erik Troan (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ewt at redhat.com</A>)
++ *
++ * Copyright 1996 Red Hat Software
++ *
++ */
++
++#include &lt;unistd.h&gt;
++#include &lt;sys/mount.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;string.h&gt;
++#include &lt;libgen.h&gt;
++#include &quot;stage1.h&quot;
++#include &quot;frontend.h&quot;
++#include &quot;log.h&quot;
++#include &quot;tools.h&quot;
++#include &quot;utils.h&quot;
++#include &quot;lomount.h&quot;
++
++char * extract_list_directory(char * direct)
++{
++ char ** full = list_directory(direct);
++ char tmp[20000] = &quot;&quot;;
++ int i;
++ for (i=0; i&lt;50 ; i++) {
++ if (!full || !*full)
++ break;
++ strcat(tmp, *full);
++ strcat(tmp, &quot;\n&quot;);
++ full++;
++ }
++ return strdup(tmp);
++}
++
++static void choose_iso_in_directory(char *directory, char *location_full)
++{
++ char **file;
++ char *stage2_isos[100] = { &quot;Use directory as a mirror tree&quot;, &quot;-----&quot; };
++ int stage2_iso_number = 2;
++
++ log_message(&quot;\&quot;%s\&quot; exists and is a directory, looking for iso files&quot;, directory);
++
++ for (file = list_directory(directory); *file; file++) {
++ char isofile[500];
++ char * loopdev = NULL;
++
++ if (strstr(*file, &quot;.iso&quot;) != *file + strlen(*file) - 4)
++ /* file doesn't end in .iso, skipping */
++ continue;
++
++ strcpy(isofile, directory);
++ strcat(isofile, &quot;/&quot;);
++ strcat(isofile, *file);
++
++ if (lomount(isofile, LOOP_LOCATION, &amp;loopdev, 0)) {
++ log_message(&quot;unable to mount iso file \&quot;%s\&quot;, skipping&quot;, isofile);
++ continue;
++ }
++ symlink(LOOP_LOCATION_REL &quot;/&quot; ARCH, IMAGE_LOCATION);
++
++ if (image_has_stage2()) {
++ log_message(&quot;stage2 installer found in ISO image \&quot;%s\&quot;&quot;, isofile);
++ stage2_isos[stage2_iso_number++] = strdup(*file);
++ } else {
++ log_message(&quot;ISO image \&quot;%s\&quot; doesn't contain stage2 installer&quot;, isofile);
++ }
++
++ unlink(IMAGE_LOCATION);
++ umount(LOOP_LOCATION);
++ del_loop(loopdev);
++ }
++
++ stage2_isos[stage2_iso_number] = NULL;
++
++ if (stage2_iso_number &gt; 2) {
++ enum return_type results;
++ do {
++ results = ask_from_list(&quot;Please choose the ISO image to be used to install the &quot;
++ DISTRIB_NAME &quot; Distribution.&quot;,
++ stage2_isos, file);
++ if (results == RETURN_BACK) {
++ return;
++ } else if (results == RETURN_OK) {
++ if (!strcmp(*file, stage2_isos[0])) {
++ /* use directory as a mirror tree */
++ continue;
++ } else if (!strcmp(*file, stage2_isos[1])) {
++ /* the separator has been selected */
++ results = RETURN_ERROR;
++ continue;
++ } else {
++ /* use selected ISO image */
++ strcat(location_full, &quot;/&quot;);
++ strcat(location_full, *file);
++ log_message(&quot;installer will use ISO image \&quot;%s\&quot;&quot;, location_full);
++ }
++ }
++ } while (results == RETURN_ERROR);
++ } else {
++ log_message(&quot;no ISO image found in \&quot;%s\&quot; directory&quot;, location_full);
++ }
++}
++
++
++enum return_type try_with_directory(char *directory, char *method_live, char *method_iso) {
++ char location_full[500];
++ char * loopdev = NULL;
++ struct stat statbuf;
++ enum return_type ret = RETURN_OK;
++
++ unlink(IMAGE_LOCATION);
++ strcpy(location_full, directory);
++
++ if (!stat(directory, &amp;statbuf) &amp;&amp; S_ISDIR(statbuf.st_mode)) {
++ choose_iso_in_directory(directory, location_full);
++ }
++
++ loopdev = NULL;
++ if (!stat(location_full, &amp;statbuf) &amp;&amp; !S_ISDIR(statbuf.st_mode)) {
++ log_message(&quot;%s exists and is not a directory, assuming this is an ISO image&quot;, location_full);
++ if (lomount(location_full, LOOP_LOCATION, &amp;loopdev, 0)) {
++ stg1_error_message(&quot;Could not mount file %s as an ISO image of the &quot; DISTRIB_NAME &quot; Distribution.&quot;, location_full);
++ return RETURN_ERROR;
++ }
++ symlink(LOOP_LOCATION_REL &quot;/&quot; ARCH, IMAGE_LOCATION);
++ add_to_env(&quot;ISOPATH&quot;, location_full);
++ add_to_env(&quot;METHOD&quot;, method_iso);
++ } else {
++ create_IMAGE_LOCATION(location_full);
++ add_to_env(&quot;METHOD&quot;, method_live);
++ }
++
++ if (access(IMAGE_LOCATION &quot;/&quot; COMPRESSED_LOCATION_REL, R_OK)) {
++ stg1_error_message(&quot;I can't find the &quot; DISTRIB_NAME &quot; Distribution in the specified directory. &quot;
++ &quot;(I need the subdirectory &quot; COMPRESSED_LOCATION_REL &quot;)\n&quot;
++ &quot;Here's a short extract of the files in the directory:\n&quot;
++ &quot;%s&quot;, extract_list_directory(IMAGE_LOCATION));
++ ret = RETURN_BACK;
++ } else if (may_load_compressed_image() != RETURN_OK) {
++ stg1_error_message(&quot;Could not load program into memory.&quot;);
++ ret = RETURN_ERROR;
++ }
++
++ if (ret == RETURN_OK)
++ log_message(&quot;found the &quot; DISTRIB_NAME &quot; Installation, good news!&quot;);
++
++ if (!KEEP_MOUNTED || ret != RETURN_OK) {
++ /* in rescue mode, we don't need the media anymore */
++ umount(LOOP_LOCATION);
++ del_loop(loopdev);
++ }
++
++ return ret;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/directory.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/directory.h
+===================================================================
+--- drakx/trunk/mdk-stage1/directory.h (rev 0)
++++ drakx/trunk/mdk-stage1/directory.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,29 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ * Olivier Blin (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">oblin at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Portions from Erik Troan (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ewt at redhat.com</A>)
++ *
++ * Copyright 1996 Red Hat Software
++ *
++ */
++
++#ifndef _DIRECTORY_H_
++#define _DIRECTORY_H_
++
++char * extract_list_directory(char * direct);
++enum return_type try_with_directory(char *location_full, char *method_live, char *method_iso);
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/directory.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/disk.c
+===================================================================
+--- drakx/trunk/mdk-stage1/disk.c (rev 0)
++++ drakx/trunk/mdk-stage1/disk.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,228 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Portions from Erik Troan (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ewt at redhat.com</A>)
++ *
++ * Copyright 1996 Red Hat Software
++ *
++ */
++
++#include &lt;stdlib.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;string.h&gt;
++#include &lt;sys/mount.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;string.h&gt;
++#include &lt;libgen.h&gt;
++#include &quot;stage1.h&quot;
++#include &quot;frontend.h&quot;
++#include &quot;modules.h&quot;
++#include &quot;probing.h&quot;
++#include &quot;log.h&quot;
++#include &quot;tools.h&quot;
++#include &quot;utils.h&quot;
++#include &quot;mount.h&quot;
++#include &quot;automatic.h&quot;
++#include &quot;directory.h&quot;
++#include &quot;partition.h&quot;
++
++#include &quot;disk.h&quot;
++
++static enum return_type try_automatic_with_partition(char *dev) {
++ enum return_type results;
++ int mounted;
++ wait_message(&quot;Trying to access &quot; DISTRIB_NAME &quot; disk (partition %s)&quot;, dev);
++ mounted = !try_mount(dev, MEDIA_LOCATION);
++ remove_wait_message();
++ if (mounted) {
++ create_IMAGE_LOCATION(MEDIA_LOCATION);
++ if (image_has_stage2()) {
++ results = try_with_directory(MEDIA_LOCATION, &quot;disk&quot;, &quot;disk-iso&quot;);
++ if (results == RETURN_OK) {
++ if (!KEEP_MOUNTED)
++ umount(MEDIA_LOCATION);
++ return RETURN_OK;
++ }
++ }
++ }
++ if (mounted)
++ umount(MEDIA_LOCATION);
++ return RETURN_ERROR;
++}
++
++static enum return_type try_automatic_with_disk(char *disk, char *model) {
++ char * parts[50];
++ char * parts_comments[50];
++ enum return_type results;
++ char **dev;
++ wait_message(&quot;Trying to access &quot; DISTRIB_NAME &quot; disk (drive %s)&quot;, model);
++ if (list_partitions(disk, parts, parts_comments)) {
++ stg1_error_message(&quot;Could not read partitions information.&quot;);
++ return RETURN_ERROR;
++ }
++ remove_wait_message();
++ dev = parts;
++ while (dev &amp;&amp; *dev) {
++ results = try_automatic_with_partition(*dev);
++ if (results == RETURN_OK) {
++ return RETURN_OK;
++ }
++ dev++;
++ }
++ return RETURN_ERROR;
++}
++
++static enum return_type try_automatic(char ** medias, char ** medias_models)
++{
++ char ** model = medias_models;
++ char ** ptr = medias;
++ while (ptr &amp;&amp; *ptr) {
++ enum return_type results;
++ results = try_automatic_with_disk(*ptr, *model);
++ if (results == RETURN_OK)
++ return RETURN_OK;
++ ptr++;
++ model++;
++ }
++ return RETURN_ERROR;
++}
++
++static enum return_type try_with_device(char *dev_name)
++{
++ char * questions_location[] = { &quot;Directory or ISO images directory or ISO image&quot;, NULL };
++ char * questions_location_auto[] = { &quot;directory&quot;, NULL };
++ static char ** answers_location = NULL;
++ char location_full[500];
++
++ char * parts[50];
++ char * parts_comments[50];
++ enum return_type results;
++ char * choice;
++
++ if (list_partitions(dev_name, parts, parts_comments)) {
++ stg1_error_message(&quot;Could not read partitions information.&quot;);
++ return RETURN_ERROR;
++ }
++
++ /* uglyness to allow auto starting with devfs */
++ if (!IS_AUTOMATIC || streq((choice = get_auto_value(&quot;partition&quot;)), &quot;&quot;)) {
++ if (parts[0] == NULL) {
++ stg1_error_message(&quot;No partition found.&quot;);
++ return RETURN_ERROR;
++ }
++
++ results = ask_from_list_comments_auto(&quot;Please select the partition containing the copy of the &quot;
++ DISTRIB_NAME &quot; Distribution install source.&quot;,
++ parts, parts_comments, &amp;choice, &quot;partition&quot;, parts);
++ if (results != RETURN_OK)
++ return results;
++ }
++
++ /* in testing mode, assume the partition is already mounted on MEDIA_LOCATION */
++ if (!IS_TESTING &amp;&amp; try_mount(choice, MEDIA_LOCATION)) {
++ stg1_error_message(&quot;I can't find a valid filesystem (tried: ext2, vfat, ntfs, reiserfs). &quot;
++ &quot;Make sure the partition has been cleanly unmounted.&quot;);
++ return try_with_device(dev_name);
++ }
++
++ ask_dir:
++ if (ask_from_entries_auto(&quot;Please enter the directory (or ISO image file) containing the &quot;
++ DISTRIB_NAME &quot; Distribution install source.&quot;,
++ questions_location, &amp;answers_location, 24, questions_location_auto, NULL) != RETURN_OK) {
++ umount(MEDIA_LOCATION);
++ return try_with_device(dev_name);
++ }
++
++ strcpy(location_full, MEDIA_LOCATION);
++ strcat(location_full, &quot;/&quot;);
++ strcat(location_full, answers_location[0]);
++
++ if (access(location_full, R_OK)) {
++ char * path = strdup(answers_location[0]);
++ stg1_error_message(&quot;Directory or ISO image file could not be found on partition.\n&quot;
++ &quot;Here's a short extract of the files in the directory %s:\n&quot;
++ &quot;%s&quot;, dirname(path), extract_list_directory(dirname(location_full)));
++ free(path);
++ goto ask_dir;
++ }
++
++ results = try_with_directory(location_full, &quot;disk&quot;, &quot;disk-iso&quot;);
++ if (results != RETURN_OK) {
++ goto ask_dir;
++ }
++
++ if (!KEEP_MOUNTED)
++ umount(MEDIA_LOCATION);
++
++ return RETURN_OK;
++}
++
++enum return_type disk_prepare(void)
++{
++ char ** medias, ** medias_models;
++ char * choice;
++ int i;
++ enum return_type results;
++ static int already_probed_ide_generic = 0;
++
++ int count = get_disks(&amp;medias, &amp;medias_models);
++
++ if (IS_AUTOMATIC) {
++ results = try_automatic(medias, medias_models);
++ if (results != RETURN_ERROR)
++ return results;
++ unset_automatic();
++ }
++
++ if (count == 0) {
++ if (!already_probed_ide_generic) {
++ already_probed_ide_generic = 1;
++ my_insmod(&quot;ide_generic&quot;, ANY_DRIVER_TYPE, NULL, 0);
++ return disk_prepare();
++ }
++ stg1_error_message(&quot;No DISK drive found.&quot;);
++ i = ask_insmod(MEDIA_ADAPTERS);
++ if (i == RETURN_BACK)
++ return RETURN_BACK;
++ return disk_prepare();
++ }
++
++ if (count == 1) {
++ results = try_with_device(*medias);
++ if (results != RETURN_ERROR)
++ return results;
++ i = ask_insmod(MEDIA_ADAPTERS);
++ if (i == RETURN_BACK)
++ return RETURN_BACK;
++ return disk_prepare();
++ }
++
++ results = ask_from_list_comments_auto(&quot;Please select the disk containing the copy of the &quot;
++ DISTRIB_NAME &quot; Distribution install source.&quot;,
++ medias, medias_models, &amp;choice, &quot;disk&quot;, medias);
++
++ if (results != RETURN_OK)
++ return results;
++
++ results = try_with_device(choice);
++ if (results != RETURN_ERROR)
++ return results;
++ i = ask_insmod(MEDIA_ADAPTERS);
++ if (i == RETURN_BACK)
++ return RETURN_BACK;
++ return disk_prepare();
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/disk.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/disk.h
+===================================================================
+--- drakx/trunk/mdk-stage1/disk.h (rev 0)
++++ drakx/trunk/mdk-stage1/disk.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,27 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Portions from Erik Troan (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ewt at redhat.com</A>)
++ *
++ * Copyright 1996 Red Hat Software
++ *
++ */
++
++#ifndef _DISK_H_
++#define _DISK_H_
++
++enum return_type disk_prepare(void);
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/disk.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/dns.c
+===================================================================
+--- drakx/trunk/mdk-stage1/dns.c (rev 0)
++++ drakx/trunk/mdk-stage1/dns.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,224 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Portions from Erik Troan (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ewt at redhat.com</A>)
++ *
++ * Copyright 1996 Red Hat Software
++ *
++ */
++
++#include &lt;stdlib.h&gt;
++
++// dietlibc can do hostname lookup, whereas glibc can't when linked statically :-(
++
++#if defined(__dietlibc__)
++
++#include &lt;unistd.h&gt;
++#include &lt;string.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;netdb.h&gt;
++#include &lt;sys/socket.h&gt;
++#include &lt;resolv.h&gt;
++
++#include &quot;network.h&quot;
++#include &quot;log.h&quot;
++
++#include &quot;dns.h&quot;
++
++int mygethostbyname(char * name, struct in_addr * addr)
++{
++ struct hostent * h;
++
++ /* prevent from timeouts */
++ if (_res.nscount == 0)
++ return -1;
++
++ h = gethostbyname(name);
++
++ if (!h &amp;&amp; domain) {
++ // gethostbyname from dietlibc doesn't support domain handling
++ char fully_qualified[500];
++ sprintf(fully_qualified, &quot;%s.%s&quot;, name, domain);
++ h = gethostbyname(fully_qualified);
++ }
++
++ if (h &amp;&amp; h-&gt;h_addr_list &amp;&amp; (h-&gt;h_addr_list)[0]) {
++ memcpy(addr, (h-&gt;h_addr_list)[0], sizeof(*addr));
++ log_message(&quot;is-at: %s&quot;, inet_ntoa(*addr));
++ return 0;
++ }
++
++ log_message(&quot;unknown host %s&quot;, name);
++ return -1;
++}
++
++char * mygethostbyaddr(char * ipnum)
++{
++ struct in_addr in;
++ struct hostent * host;
++
++ /* prevent from timeouts */
++ if (_res.nscount == 0)
++ return NULL;
++
++ if (!inet_aton(ipnum, &amp;in))
++ return NULL;
++ host = gethostbyaddr(&amp;(in.s_addr), sizeof(in.s_addr) /* INADDRSZ */, AF_INET);
++ if (host &amp;&amp; host-&gt;h_name)
++ return host-&gt;h_name;
++ return NULL;
++}
++
++#elif defined(__GLIBC__)
++
++#include &lt;alloca.h&gt;
++#include &lt;sys/socket.h&gt;
++#include &lt;netinet/in.h&gt;
++#include &lt;resolv.h&gt;
++#include &lt;arpa/nameser.h&gt;
++#include &lt;arpa/inet.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++
++#include &quot;log.h&quot;
++
++#include &quot;dns.h&quot;
++
++/* This is dumb, but glibc doesn't like to do hostname lookups w/o libc.so */
++
++union dns_response {
++ HEADER hdr;
++ u_char buf[PACKETSZ];
++} ;
++
++static int do_query(char * query, int queryType, char ** domainName, struct in_addr * ipNum)
++{
++ int len, ancount, type;
++ u_char * data, * end;
++ char name[MAXDNAME];
++ union dns_response response;
++
++#ifdef __sparc__
++ /* from jj: */
++ /* We have to wait till ethernet negotiation is done */
++ _res.retry = 3;
++#else
++ _res.retry = 2;
++#endif
++
++
++ len = res_search(query, C_IN, queryType, (void *) &amp;response, sizeof(response));
++ if (len &lt;= 0)
++ return -1;
++
++ if (ntohs(response.hdr.rcode) != NOERROR)
++ return -1;
++
++ ancount = ntohs(response.hdr.ancount);
++ if (ancount &lt; 1)
++ return -1;
++
++ data = response.buf + sizeof(HEADER);
++ end = response.buf + len;
++
++ /* skip the question */
++ data += dn_skipname(data, end) + QFIXEDSZ;
++
++ /* parse the answer(s) */
++ while (--ancount &gt;= 0 &amp;&amp; data &lt; end) {
++
++ /* skip the domain name portion of the RR record */
++ data += dn_skipname(data, end);
++
++ /* get RR information */
++ GETSHORT(type, data);
++ data += INT16SZ; /* skipp class */
++ data += INT32SZ; /* skipp TTL */
++ GETSHORT(len, data);
++
++ if (type == T_PTR) {
++ /* we got a pointer */
++ len = dn_expand(response.buf, end, data, name, sizeof(name));
++ if (len &lt;= 0) return -1;
++ if (queryType == T_PTR &amp;&amp; domainName) {
++ /* we wanted a pointer */
++ *domainName = malloc(strlen(name) + 1);
++ strcpy(*domainName, name);
++ return 0;
++ }
++ } else if (type == T_A) {
++ /* we got an address */
++ if (queryType == T_A &amp;&amp; ipNum) {
++ /* we wanted an address */
++ memcpy(ipNum, data, sizeof(*ipNum));
++ return 0;
++ }
++ }
++
++ /* move ahead to next RR */
++ data += len;
++ }
++
++ return -1;
++}
++
++char * mygethostbyaddr(char * ipnum) {
++ int rc;
++ char * result;
++ char * strbuf;
++ char * chptr;
++ char * splits[4];
++ int i;
++
++ _res.retry = 1;
++
++ strbuf = alloca(strlen(ipnum) + 1);
++ strcpy(strbuf, ipnum);
++
++ ipnum = alloca(strlen(strbuf) + 20);
++
++ for (i = 0; i &lt; 4; i++) {
++ chptr = strbuf;
++ while (*chptr &amp;&amp; *chptr != '.')
++ chptr++;
++ *chptr = '\0';
++
++ if (chptr - strbuf &gt; 3) return NULL;
++ splits[i] = strbuf;
++ strbuf = chptr + 1;
++ }
++
++ sprintf(ipnum, &quot;%s.%s.%s.%s.in-addr.arpa&quot;, splits[3], splits[2], splits[1], splits[0]);
++
++ rc = do_query(ipnum, T_PTR, &amp;result, NULL);
++
++ if (rc)
++ return NULL;
++ else
++ return result;
++}
++
++int mygethostbyname(char * name, struct in_addr * addr) {
++ int rc = do_query(name, T_A, NULL, addr);
++ if (!rc)
++ log_message(&quot;is-at %s&quot;, inet_ntoa(*addr));
++ return rc;
++}
++
++#else
++
++#error &quot;Unsupported C library&quot;
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/dns.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/dns.h
+===================================================================
+--- drakx/trunk/mdk-stage1/dns.h (rev 0)
++++ drakx/trunk/mdk-stage1/dns.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,30 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Portions from Erik Troan (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ewt at redhat.com</A>)
++ *
++ * Copyright 1996 Red Hat Software
++ *
++ */
++
++#ifndef H_DNS
++#define H_DNS
++
++#include &lt;netinet/in.h&gt;
++
++int mygethostbyname(char * name, struct in_addr * addr);
++char * mygethostbyaddr(char * ipnum);
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/dns.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/doc/HACKING
+===================================================================
+--- drakx/trunk/mdk-stage1/doc/HACKING (rev 0)
++++ drakx/trunk/mdk-stage1/doc/HACKING 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,31 @@
++If you have to boot pretty often, you'll appreciate to speed the things up
++a little.
++
++Here's what we use: the GRUB feature to boot from the network using the
++DHCP protocol and the TFTP protocol.
++
++Here's the &quot;menu.lst&quot; to do that:
++
++-=-=--
++
++timeout 0
++
++title linux
++dhcp
++tftpserver 192.168.1.17
++kernel (nd)/tftpboot/gc/vmlinuz ramdisk=32000 vga=788
++initrd (nd)/tftpboot/gc/network.rdz
++
++-=-=--
++
++
++The option &quot;tftpserver&quot; is used to override the tftpserver address given
++as an answer by the DHCP server. That way, you'll not need to bother your
++system administrator to modify his dhcp server configuration.
++
++The directory /tftpboot seems to be the only one defaultly accepted by the
++server, and its subdirs.
++
++
++Of course, your GRUB needs to be compiled with the specific code for your
++network card; use ./configure --help in the GRUB build dir for more infos.
+
+Added: drakx/trunk/mdk-stage1/doc/README
+===================================================================
+--- drakx/trunk/mdk-stage1/doc/README (rev 0)
++++ drakx/trunk/mdk-stage1/doc/README 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,185 @@
++-------------------------------------------------------
++* Stage1 of the Mandriva Linux installation program *
++-------------------------------------------------------
++
++
++[ Author ]
++
++ Guillaume Cottenceau (gc at mandriva.com)
++
++
++[ Copyright ]
++
++ Copyright 2000, 2001, 2002 Mandriva
++
++ Partially inspired by Redhat stuff (install from 5.x and 7.x) copyright
++ Red Hat Software, and Debian stuff (boot-floppies) copyright by their
++ respective holders.
++
++
++[ Licence ]
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++
++
++ *** WARNING! ***
++
++ This General Public License does not permit incorporating any part
++ of this program as a library into proprietary programs.
++
++
++[ Online ]
++
++ <A HREF="http://people.mandriva.com/~gc/html/stage1.html">http://people.mandriva.com/~gc/html/stage1.html</A>
++
++
++[ Purpose ]
++
++ This code will take the control of the computer after that Linux
++ kernel booted properly, and will try to run the main installer
++ (also known as &quot;stage 2&quot;) from a series of different media
++ including harddrive, cdrom, and network.
++
++ Use the source, Luke.
++
++
++
++
++ -=-=-- Okay, now, more details --=-=-
++
++
++ [ Installing Mandriva Linux ]
++
++Per default, just insert your Mandriva Linux Installation CD into your
++CDROM tray, be sure your system BIOS is configured to boot on your CDROM,
++and that's all.
++
++If you have multiple CDROM drives and the installer can't autodetect in
++which CDROM drive is the disc, it may ask you to choose the correct drive,
++between your CDROM drives.
++
++Also, if you want to install from an SCSI CDROM, the installer should
++detect your SCSI adapter; if it fails you may have to select the right
++driver and/or supply additional parameters.
++
++
++ [ Position of the problem ]
++
++The need for alternate installation methods come with more specific
++hardware configuration and/or need for frequent updates of the Installer
++software.
++
++All of these methods will require to use a special boot disk. The method
++is to download it and then to copy it &quot;physically&quot; to a floppy with the
++command:
++
++# dd if=&lt;boot-disk&gt; of=/dev/fd0
++
++Our boot disks are called &quot;cdrom.img&quot;, &quot;network.img&quot;, etc.
++
++
++ [ Installation from CDROM ]
++
++The first situation you may encounter is an old BIOS which does not permit
++you to boot from your CDROM drive.
++
++In that case, you'll need to use the &quot;cdrom.img&quot; image file. The steps are
++the same as with CDROM boot, and everything should be automatic.
++
++
++ [ Installation from DISK ]
++
++If you like trying occasionnally our development version, the Cooker, one
++of the easiest way is to grab a local copy of the Distribution on one of
++your local hard drives, and to install from that location.
++
++At present time, you can install from IDE or SCSI drives, from Linux
++(ext2), Windows (vfat) or Reiserfs partition.
++
++In that case, you'll need to use the &quot;hd.img&quot; image file. The dialogs will
++ask you to choose the DISK drive to use to install from, then the
++partition on which you copied the Distribution, then the location
++(directory) in which you copied the Distribution.
++
++
++ [ Installation from NETWORK ]
++
++For convenience, you can also install from a NFS volume, from a FTP
++server, or from a HTTP server. NFS installs are maybe the fastest
++and most convenient possible, so if you need to do frequent and/or
++multiple installs, you may like this option.
++
++In that case, you'll need to use the &quot;network.img&quot; image file. If you have
++PCI network card(s), you'll probably have to only setup your network
++options. If not, you'll have to choose the appropriate driver(s) and/or
++optional parameters. Supported network configurations include static IP
++allocation and DHCP automatic configuration.
++
++
++ [ Installation from PCMCIA ]
++
++If you want to perform an installation on your laptop that is not based on
++local IDE CDROM or DISK, nor on built-in network card, but on PCMCIA
++extension (probably a network adapter or CDROM drive), you'll need the
++&quot;pcmcia.img&quot; image file.
++
++PCMCIA services should automatically start and be transparent to you.
++Then, you'll follow the instructions according to your preferred
++installation method.
++
++
++ [ Monitoring a stage1 session ]
++
++Linux supports virtual consoles. You can switch between them by issueing
++Ctrl+Alt+Fx key, in which 'x' is the number of the console. Here's console
++occupancy during stage1.
++
++(#1) The user-interface of the stage1 is on the first console. In case of
++newt interaction, it's provided with a neat blue and black color scheme,
++and nice widgets. In case of stdio interaction (cdrom and disk installs),
++it's more basic but still usable :-).
++
++(#2) A shell is provided on second console in some cases (you need to
++compile it with -DSPAWN_SHELL and you need to provide a valid shell in the
++initrd) and of course it's not in, in image files of Mandriva Linux
++releases because it's too much diskspace.
++
++(#3) The log is printed out on the third console. This is the location
++where you can find most valuable information, prefixed by a '*'. See
++&quot;log.h&quot; for calls that print things out to the log.
++
++(#4) The kernel messages are printed on the fourth console. There is a
++process forked very early in the init (the program before the stage1)
++which monitors /proc/kmsg for new kernel messages. Also, syslog stuff (the
++logs commited by the programs) should appear on the /dev/log Unix socket,
++this is also printed on this console.
++
++(#5) Former place for the stderr of insmod calls. It's not used anymore.
++
++(#6) Place where a trivial interactive communication with the stage1 is
++set up if the parameter -DSPAWN_INTERACTIVE is compiled in. Basically, you
++can set switches such as &quot;expert&quot; and &quot;rescue&quot; on the fly with this
++feature. It's implemented with a fork and a Unix pipe.
++
++
++ [ Rescueing a system ]
++
++Since Mandriva Linux 7.1, we provide a rescue system through each of the
++previously described methods. You don't need a special &quot;rescue.img&quot; file.
++Just hit &quot;F1&quot; at boot time, type in &quot;rescue&quot;, and follow the first steps
++of the installation according to the method you chose (choose
++disks/partitions for disk method, network parameters for network method,
++etc). Then, you'll end up with a workable system, very useful to rescue a
++damaged system, or do other basic actions.
+
+Added: drakx/trunk/mdk-stage1/doc/TECH-INFOS
+===================================================================
+--- drakx/trunk/mdk-stage1/doc/TECH-INFOS (rev 0)
++++ drakx/trunk/mdk-stage1/doc/TECH-INFOS 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,106 @@
++
++| (*) Automatic install
++\----------------------
++
++This feature is used to replace redhat kickstart. It uses the kernel
++parameter &quot;automatic&quot; with keywords separated with commas and colons, on
++the following genres:
++
++ automatic=method:nfs,network:static,ip:192.168.1.24,server:192.168.1.7,directory:/stable/i586
++
++ automatic=method:ftp,network:dhcp,server:ftp.ciril.fr,directory:/pub/linux/mandriva-devel/cooker
++
++ automatic=method:ftp,network:dhcp,server:companyserver,directory:/mdkinst,user:XXX,pass:XXX
++
++ automatic=method:ftp,interface:eth1,network:dhcp,...
++
++ automatic=method:ftp,network:adsl,adsluser:XXX,adslpass:XXX,...
++
++ automatic=method:cdrom
++
++ automatic=method:disk,disk:hdb,partition:hdb7,directory:/cooker
++
++
++The keywords correspond to each &quot;virtual&quot; question answered automatically,
++either from a list or from a free field.
++
++
++Keywords are:
++
++
++`method' &lt;- (nfs,ftp,http,cdrom,disk)
++
++if nfs/ftp/http:
++
++ `network' &lt;- (static,dhcp,adsl)
++
++ if multiple interfaces detected:
++
++ `interface' &lt;- (list-of-detected-interfaces)
++ if &quot;auto&quot;:
++ use the first interface with a link beat
++ if &quot;wired&quot;:
++ use the first wired interface with a link beat
++ or the first wired interface if none has a link beat
++
++ fi
++
++ if static:
++
++ `ip', `dns', `gateway', `netmask' (free fields)
++
++ elsif adsl:
++
++ `adsluser', `adslpass' (free field)
++
++ fi
++
++ if resolving fails:
++
++ `hostname', `domain' (free fields)
++
++ fi
++
++ `server', `directory' (free fields)
++
++ if ftp:
++
++ `user', `pass' (free fields)
++
++ fi
++
++fi
++
++if disk:
++
++ `disk' &lt;- (list-of-detected-disks)
++
++ `partition' &lt;- (list-of-detected-partitions)
++
++ `directory' (free fields)
++
++fi
++
++
++
++You may use shorter versions of keywords (it helps reducing size of
++commandline), please find each keyword short-alias counterpart in file
++../automatic.c under the identifier named &quot;short_aliases&quot;.
++
++This gives for example for:
++
++ automatic=method:nfs,network:static,ip:192.168.1.24,server:192.168.1.7,directory:/stable/i586
++==&gt;
++ automatic=met:nfs,net:static,ip:192.168.1.24,ser:192.168.1.7,dir:/stable/i586
++
++
++
++You may specify a stage2 auto-install file, different from the
++default `auto_inst.cfg.pl' in install/, by filling the
++`bootfile' parameter of your DHCP server response.
++
++Note that if the name ends with `-IP' or `-IP.pl', IP will be
++replaced by the IP address given to the host, normalized to
++hexadecimal (that is, `192.168.100.57' would give 'C0A86439').
++
++
+
+Added: drakx/trunk/mdk-stage1/doc/UPDATEMODULES
+===================================================================
+--- drakx/trunk/mdk-stage1/doc/UPDATEMODULES (rev 0)
++++ drakx/trunk/mdk-stage1/doc/UPDATEMODULES 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,96 @@
++This is the documentation for the &quot;Update Modules&quot; (Update Drivers)
++feature.
++
++This feature aims to propose new modules or replacement modules for the
++install and afterwards. This is useful when there is a firmware update for a
++given driver, an additional driver needed for something, etc.
++
++
++You must use a floppy disk with e2fs filesystem (NOT vfat/windows
++formatted). Use &quot;mke2fs /dev/fd0&quot; on your own box to format a floppy with
++e2fs filesystem.
++
++This disk may contain a number of kernel modules; some of them
++may replace existing modules, some of them may be added.
++
++Create a directory per kernel version, named from the version, for example
++2.6.27-desktop586-0.rc8.2mnb. In this directory put the modules and a special
++file, named &quot;to_load&quot;. This file will contain a series of module names, with
++optional module options; the program will try to load all these modules one
++after another, using file on the floppy if present, else using file within
++standard module repository. It can contain comments, these are strictly defined
++by the presence of a hash (#) character on column 0 of any line.
++
++This disk may also contain some update or new modules for installed kernels.
++Those modules must be placed in directory &lt;kernel-version&gt;. They must be
++gzipped if the installed kernel modules are gzipped.
++
++You may need to specify the &quot;category&quot; so that new modules are used correctly.
++For example, a scsi module should be put in category disk/scsi so that it is
++put in scsi_hostadapter and initrd.
++
++
++Here's a typical scenario:
++
++
++1. Boot the floppy (or cdrom) with the option &quot;updatemodules&quot;
++
++ (you may do that by pressing F1 then entering &quot;linux updatemodules&quot;)
++
++
++2. At the very beginning of the User Interface, you are asked to insert
++ the Update Modules disk. Insert the Update Modules disk and press
++ Enter.
++
++--=----=----=----=----=----=----=----=----=--
++Our example disk contains:
++
++[<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">root at obiwan</A> mnt]# ll floppy/*
++2.6.27-desktop586-0.rc8.2mnb/:
++total 541
++drwxrwxr-x 3 a a 1024 2009-03-09 12:09 kernel/
++-rw-rw-r-- 1 a a 547480 2009-03-09 12:04 msdos.ko
++-rw-rw-r-- 1 a a 54748 2009-03-09 12:04 ppa.ko
++-rw-rw-r-- 1 a a 79 2009-03-09 12:08 to_load
++[<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">root at obiwan</A> mnt]# cat floppy/*/to_load
++# Update Drivers description file
++3c59x
++# fat is a dep for msdos
++fat
++# updated msdos (handling of 9+4 filenames)
++msdos
++ppa
++# ISA network card needing options
++ne io=0x300 irq=7
++# New module [list_modules: disk/scsi]
++a320raid
++[<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">root at obiwan</A> mnt]# (cd floppy/2.6.27-desktop586-0.rc8.2mnb ; find -type f)
++./msdos.ko
++./ppa.ko
++./to_load
++./kernel/fs/msdos/msdos.ko.gz
++./kernel/drivers/scsi/ppa.ko.gz
++./kernel/drivers/usb/host/uhci-hcd.ko.gz
++./kernel/drivers/usb/input/wacom.ko.gz
++[<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">root at obiwan</A> mnt]#
++--=----=----=----=----=----=----=----=----=--
++
++
++3. The program reads the special file &quot;to_load&quot; and processes the files.
++
++ a- 3c59x loaded from the marfile on the boot floppy
++ b- fat loaded from the marfile on the boot floppy
++ c- msdos loaded from the update modules floppy
++ d- ppa loaded from the update modules floppy
++ e- ne loaded from the marfile on the boot floppy
++
++
++
++!!! Beware !!!, the dependencies are not handled automatically in
++the case of load from the update modules floppy, that's why on
++our example we need to load &quot;fat&quot; from the standard modules
++before &quot;msdos&quot; from the update floppy.
++
++
++4. When system is installed, update floppy is asked again so that update
++modules for the installed kernels can be copied. Then depmod is called.
+
+Added: drakx/trunk/mdk-stage1/doc/WHY-DIETLIBC
+===================================================================
+--- drakx/trunk/mdk-stage1/doc/WHY-DIETLIBC (rev 0)
++++ drakx/trunk/mdk-stage1/doc/WHY-DIETLIBC 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,50 @@
++(the dietlibc is a replacement for the glibc, which aim is to produce
++smaller statically linked binaries)
++
++
++The use for dietlibc in the stage1 was clear because currently used
++install process on x86 is from a 1.44 Mbytes floppy. On this floppy we
++need to fit the kernel, modules (scsi and network access), and the code to
++do the basic things to load the stage2. The only part on which we could
++progress was the code.
++
++As always, figures demonstrate evidences. Here are the size of the
++binaries used for the cdrom, disk, network and full floppy installs, using
++newt as the UI library:
++
++ - with glibc
++
++-rwxr-xr-x 1 gc gc 569448 May 15 15:29 stage1-cdrom
++-rwxr-xr-x 1 gc gc 572264 May 15 15:29 stage1-disk
++-rwxr-xr-x 1 gc gc 624712 May 15 15:30 stage1-network
++-rwxr-xr-x 1 gc gc 720360 May 15 15:29 stage1-full
++
++ - with dietlibc
++
++-rwxr-xr-x 1 gc gc 169332 May 15 14:26 stage1-cdrom
++-rwxr-xr-x 1 gc gc 172180 May 15 14:26 stage1-disk
++-rwxr-xr-x 1 gc gc 198612 May 15 14:26 stage1-network
++-rwxr-xr-x 1 gc gc 251764 May 15 14:26 stage1-full
++
++
++The `stage1-full' binary has code for many things, most notably: data
++decrunching (bzlib), archive extraction (in-house format), module loading
++(insmod from busybox), PCI detection, ide and scsi handling,
++cdrom/disk/loopback mounting, DHCP client negociation (redhat+grub), NFS
++mounting (util-linux), FTP and HTTP transmission (redhat), pcmcia
++initializing (pcmcia-cs), UI interaction (slang/newt); with use of the
++dietlibc, the binary is only 250 kbytes!
++
++
++Due to the modular coding, it is also possible to choose to not use
++slang/newt as the UI, but a stdio-only UI. In that case, the binaries get
++even smaller:
++
++-rwxr-xr-x 1 gc gc 104500 May 15 15:46 stage1-cdrom*
++-rwxr-xr-x 1 gc gc 107348 May 15 15:46 stage1-disk*
++-rwxr-xr-x 1 gc gc 133972 May 15 15:47 stage1-network*
++-rwxr-xr-x 1 gc gc 187348 May 15 15:46 stage1-full*
++
++
++
++gc [Tue May 15 15:58:34 2001]
+\ No newline at end of file
+
+Added: drakx/trunk/mdk-stage1/doc/documented..frontend.h
+===================================================================
+--- drakx/trunk/mdk-stage1/doc/documented..frontend.h (rev 0)
++++ drakx/trunk/mdk-stage1/doc/documented..frontend.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,69 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Using high-level UI.
++ *
++ * These functions are frontend-independant: your program won't know each
++ * `frontend' (e.g. each way to grab user input) will be used.
++ *
++ * Then you may link your binary against any `frontend' that implement all
++ * these functions (and possibly necessary libraries).
++ */
++
++
++#ifndef _FRONTEND_H_
++#define _FRONTEND_H_
++
++/* this must be called before anything else */
++void init_frontend(void);
++
++/* this must be called before exit of program */
++void finish_frontend(void);
++
++
++void info_message(char *msg, ...) __attribute__ ((format (printf, 1, 2))); /* (blocks program) */
++
++void error_message(char *msg, ...) __attribute__ ((format (printf, 1, 2))); /* (blocks program) */
++
++/* (doesn't block program)
++ * (this is not necessarily stackable, e.g. only one wait_message at a time) */
++void wait_message(char *msg, ...) __attribute__ ((format (printf, 1, 2)));
++
++/* call this to finish the wait on wait_message */
++void remove_wait_message(void);
++
++/* monitor progression of something (downloading a file, etc)
++ * if size of progression is unknown, use `0' */
++void init_progression(char *msg, int size);
++void update_progression(int current_size);
++void end_progression(void);
++
++enum frontend_return { RETURN_OK, RETURN_BACK, RETURN_ERROR };
++
++/* Yes == RETURN_OK No == RETURN_ERROR Back == RETURN_BACK */
++enum frontend_return ask_yes_no(char *msg);
++
++/* [elems] NULL terminated array of char*
++ * [choice] address of a (unitialized) char* */
++enum frontend_return ask_from_list(char *msg, char ** elems, char ** choice);
++
++enum frontend_return ask_from_list_comments(char *msg, char ** elems, char ** elems_comments, char ** choice);
++
++/* [questions] NULL terminated array of char*
++ * [answers] address of a (unitialized) char**, will contain a non-NULL terminated array of char*
++ * [callback_func] function called at most when the answers change; it can examine the array of char* and assign some new char* */
++enum frontend_return ask_from_entries(char *msg, char ** questions, char *** answers, int entry_size, void (*callback_func)(char ** strings));
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/doc/documented..frontend.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/frontend-common.c
+===================================================================
+--- drakx/trunk/mdk-stage1/frontend-common.c (rev 0)
++++ drakx/trunk/mdk-stage1/frontend-common.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,64 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#include &lt;stdlib.h&gt;
++#include &lt;stdarg.h&gt;
++#include &lt;string.h&gt;
++
++#include &lt;probing.h&gt;
++
++#include &quot;frontend.h&quot;
++
++
++void info_message(char *msg, ...)
++{
++ va_list args;
++ va_start(args, msg);
++ vinfo_message(msg, args);
++ va_end(args);
++}
++
++void wait_message(char *msg, ...)
++{
++ va_list args;
++ va_start(args, msg);
++ vwait_message(msg, args);
++ va_end(args);
++}
++
++void error_message(char *msg, ...)
++{
++ va_list args;
++ va_start(args, msg);
++ verror_message(msg, args);
++ va_end(args);
++}
++
++enum return_type ask_from_list_comments(char *msg, char ** elems, char ** elems_comments, char ** choice)
++{
++ int answer = 0;
++ enum return_type results;
++
++ results = ask_from_list_index(msg, elems, elems_comments, &amp;answer);
++
++ if (results == RETURN_OK)
++ *choice = strdup(elems[answer]);
++
++ return results;
++}
++
++enum return_type ask_from_list(char *msg, char ** elems, char ** choice)
++{
++ return ask_from_list_comments(msg, elems, NULL, choice);
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/frontend-common.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/frontend.h
+===================================================================
+--- drakx/trunk/mdk-stage1/frontend.h (rev 0)
++++ drakx/trunk/mdk-stage1/frontend.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,68 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * For doc please read doc/documented..frontend.h
++ */
++
++#ifndef _FRONTEND_H_
++#define _FRONTEND_H_
++
++#include &lt;stdarg.h&gt;
++
++/* 'unused' atttribute, gcc specific and just to turn down some warnings. */
++#if defined __GNUC__
++#define UNUSED __attribute__((unused))
++#else
++#define UNUSED
++#endif
++
++enum return_type { RETURN_OK, RETURN_BACK, RETURN_ERROR };
++
++void init_frontend(char * welcome_msg);
++void finish_frontend(void);
++
++void error_message(char *msg, ...) __attribute__ ((format (printf, 1, 2))); /* blocking */
++void info_message(char *msg, ...) __attribute__ ((format (printf, 1, 2))); /* blocking */
++void wait_message(char *msg, ...) __attribute__ ((format (printf, 1, 2))); /* non-blocking */
++void remove_wait_message(void);
++
++void init_progression_raw(char *msg, int size);
++void update_progression_raw(int current_size);
++void end_progression_raw(void);
++
++#ifdef ENABLE_BOOTSPLASH
++void init_progression(char *msg, int size);
++void update_progression(int current_size);
++void end_progression(void);
++#else
++#define init_progression init_progression_raw
++#define update_progression update_progression_raw
++#define end_progression end_progression_raw
++#endif
++
++enum return_type ask_yes_no(char *msg);
++enum return_type ask_from_list_index(char *msg, char ** elems, char ** elems_comments, int *answer);
++enum return_type ask_from_list(char *msg, char ** elems, char ** choice);
++enum return_type ask_from_list_comments(char *msg, char ** elems, char ** elems_comments, char ** choice);
++enum return_type ask_from_entries(char *msg, char ** questions, char *** answers, int entry_size, void (*callback_func)(char ** strings));
++
++void suspend_to_console(void);
++void resume_from_suspend(void);
++
++void verror_message(char *msg, va_list ap);
++void vinfo_message(char *msg, va_list ap);
++void vwait_message(char *msg, va_list ap);
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/frontend.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/init.c
+===================================================================
+--- drakx/trunk/mdk-stage1/init.c (rev 0)
++++ drakx/trunk/mdk-stage1/init.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,546 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Portions from Erik Troan (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ewt at redhat.com</A>)
++ *
++ * Copyright 1996 Red Hat Software
++ *
++ */
++
++#include &lt;stdlib.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;string.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/socket.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;sys/mount.h&gt;
++#include &lt;linux/un.h&gt;
++#include &lt;errno.h&gt;
++#include &lt;signal.h&gt;
++#include &lt;sys/resource.h&gt;
++#include &lt;sys/wait.h&gt;
++#include &lt;linux/unistd.h&gt;
++#include &lt;sys/select.h&gt;
++#include &lt;sys/ioctl.h&gt;
++
++#include &lt;sys/syscall.h&gt;
++#define syslog(...) syscall(__NR_syslog, __VA_ARGS__)
++#define reboot(...) syscall(__NR_reboot, __VA_ARGS__)
++
++#include &quot;config-stage1.h&quot;
++#include &lt;linux/cdrom.h&gt;
++
++#if defined(__powerpc__)
++#define TIOCSCTTY 0x540E
++#endif
++
++
++#define BINARY &quot;/sbin/stage1&quot;
++#define BINARY_STAGE2 &quot;/usr/bin/runinstall2&quot;
++
++
++char * env[] = {
++ &quot;PATH=/usr/bin:/bin:/sbin:/usr/sbin:/mnt/sbin:/mnt/usr/sbin:/mnt/bin:/mnt/usr/bin&quot;,
++ &quot;LD_LIBRARY_PATH=/lib:/usr/lib:/mnt/lib:/mnt/usr/lib:/usr/X11R6/lib:/mnt/usr/X11R6/lib&quot;
++#if defined(__x86_64__) || defined(__ppc64__)
++ &quot;:/lib64:/usr/lib64:/usr/X11R6/lib64:/mnt/lib64:/mnt/usr/lib64:/mnt/usr/X11R6/lib64&quot;
++#endif
++ ,
++ &quot;HOME=/&quot;,
++ &quot;TERM=linux&quot;,
++ &quot;TERMINFO=/etc/terminfo&quot;,
++ NULL
++};
++
++
++/*
++ * this needs to handle the following cases:
++ *
++ * 1) run from a CD root filesystem
++ * 2) run from a read only nfs rooted filesystem
++ * 3) run from a floppy
++ * 4) run from a floppy that's been loaded into a ramdisk
++ *
++ */
++
++int testing = 0;
++int klog_pid;
++
++
++void fatal_error(char *msg)
++{
++ printf(&quot;FATAL ERROR IN INIT: %s\n\nI can't recover from this, please reboot manually and send bugreport.\n&quot;, msg);
++ select(0, NULL, NULL, NULL, NULL);
++}
++
++void print_error(char *msg)
++{
++ printf(&quot;E: %s\n&quot;, msg);
++}
++
++void print_warning(char *msg)
++{
++ printf(&quot;W: %s\n&quot;, msg);
++}
++
++void print_int_init(int fd, int i)
++{
++ char buf[10];
++ char * chptr = buf + 9;
++ int j = 0;
++
++ if (i &lt; 0)
++ {
++ write(1, &quot;-&quot;, 1);
++ i = -1 * i;
++ }
++
++ while (i)
++ {
++ *chptr-- = '0' + (i % 10);
++ j++;
++ i = i / 10;
++ }
++
++ write(fd, chptr + 1, j);
++}
++
++void print_str_init(int fd, char * string)
++{
++ write(fd, string, strlen(string));
++}
++
++/* fork to:
++ * (1) watch /proc/kmsg and copy the stuff to /dev/tty4
++ * (2) listens to /dev/log and copy also this stuff (log from programs)
++ */
++void doklog()
++{
++ fd_set readset, unixs;
++ int in, out, i;
++ int log;
++ socklen_t s;
++ int sock = -1;
++ struct sockaddr_un sockaddr;
++ char buf[1024];
++ int readfd;
++
++ /* open kernel message logger */
++ in = open(&quot;/proc/kmsg&quot;, O_RDONLY,0);
++ if (in &lt; 0) {
++ print_error(&quot;could not open /proc/kmsg&quot;);
++ return;
++ }
++
++ mkdir(&quot;/tmp&quot;, 0755);
++ if ((log = open(&quot;/tmp/syslog&quot;, O_WRONLY | O_CREAT | O_APPEND, 0644)) &lt; 0) {
++ print_error(&quot;error opening /tmp/syslog&quot;);
++ sleep(5);
++ return;
++ }
++
++ if ((klog_pid = fork())) {
++ close(in);
++ close(log);
++ return;
++ } else {
++ close(0);
++ close(1);
++ close(2);
++ }
++
++ out = open(&quot;/dev/tty4&quot;, O_WRONLY, 0);
++ if (out &lt; 0)
++ print_warning(&quot;couldn't open tty for syslog -- still using /tmp/syslog\n&quot;);
++
++ /* now open the syslog socket */
++// ############# LINUX 2.4 /dev/log IS BUGGED! --&gt; apparently the syslogs can't reach me, and it's full up after a while
++// sockaddr.sun_family = AF_UNIX;
++// strncpy(sockaddr.sun_path, &quot;/dev/log&quot;, UNIX_PATH_MAX);
++// sock = socket(AF_UNIX, SOCK_STREAM, 0);
++// if (sock &lt; 0) {
++// printf(&quot;error creating socket: %d\n&quot;, errno);
++// sleep(5);
++// }
++//
++// print_str_init(log, &quot;] got socket\n&quot;);
++// if (bind(sock, (struct sockaddr *) &amp;sockaddr, sizeof(sockaddr.sun_family) + strlen(sockaddr.sun_path))) {
++// print_str_init(log, &quot;] bind error: &quot;);
++// print_int_init(log, errno);
++// print_str_init(log, &quot;\n&quot;);
++// sleep(// }
++//
++// print_str_init(log, &quot;] bound socket\n&quot;);
++// chmod(&quot;/dev/log&quot;, 0666);
++// if (listen(sock, 5)) {
++// print_str_init(log, &quot;] listen error: &quot;);
++// print_int_init(log, errno);
++// print_str_init(log, &quot;\n&quot;);
++// sleep(5);
++// }
++
++ /* disable on-console syslog output */
++ syslog(8, NULL, 1);
++
++ print_str_init(log, &quot;] kernel/system logger ok\n&quot;);
++ FD_ZERO(&amp;unixs);
++ while (1) {
++ memcpy(&amp;readset, &amp;unixs, sizeof(unixs));
++
++ if (sock &gt;= 0)
++ FD_SET(sock, &amp;readset);
++ FD_SET(in, &amp;readset);
++
++ i = select(20, &amp;readset, NULL, NULL, NULL);
++ if (i &lt;= 0)
++ continue;
++
++ /* has /proc/kmsg things to tell us? */
++ if (FD_ISSET(in, &amp;readset)) {
++ i = read(in, buf, sizeof(buf));
++ if (i &gt; 0) {
++ if (out &gt;= 0)
++ write(out, buf, i);
++ write(log, buf, i);
++ }
++ }
++
++ /* the socket has moved, new stuff to do */
++ if (sock &gt;= 0 &amp;&amp; FD_ISSET(sock, &amp;readset)) {
++ s = sizeof(sockaddr);
++ readfd = accept(sock, (struct sockaddr *) &amp;sockaddr, &amp;s);
++ if (readfd &lt; 0) {
++ char * msg_error = &quot;] error in accept\n&quot;;
++ if (out &gt;= 0)
++ write(out, msg_error, strlen(msg_error));
++ write(log, msg_error, strlen(msg_error));
++ close(sock);
++ sock = -1;
++ }
++ else
++ FD_SET(readfd, &amp;unixs);
++ }
++ }
++}
++
++
++#define LOOP_CLR_FD 0x4C01
++
++void del_loops(void)
++{
++ char loopdev[] = &quot;/dev/loop0&quot;;
++ char chloopdev[] = &quot;/dev/chloop0&quot;;
++ int i;
++ for (i=0; i&lt;8; i++) {
++ int fd;
++ loopdev[9] = '0' + i;
++ fd = open(loopdev, O_RDONLY, 0);
++ if (fd &gt; 0) {
++ if (!ioctl(fd, LOOP_CLR_FD, 0))
++ printf(&quot;\t%s\n&quot;, loopdev);
++ close(fd);
++ }
++ chloopdev[11] = '0' + i;
++ fd = open(chloopdev, O_RDONLY, 0);
++ if (fd &gt; 0) {
++ if (!ioctl(fd, LOOP_CLR_FD, 0))
++ printf(&quot;\t%s\n&quot;, chloopdev);
++ close(fd);
++ }
++ }
++}
++
++struct filesystem
++{
++ char * dev;
++ char * name;
++ char * fs;
++ int mounted;
++};
++
++char* strcat(register char* s,register const char* t)
++{
++ char *dest=s;
++ s+=strlen(s);
++ for (;;) {
++ if (!(*s = *t)) break; ++s; ++t;
++ }
++ return dest;
++}
++
++/* attempt to unmount all filesystems in /proc/mounts */
++void unmount_filesystems(void)
++{
++ int fd, size;
++ char buf[65535]; /* this should be big enough */
++ char *p;
++ struct filesystem fs[500];
++ int numfs = 0;
++ int i, nb;
++ int disallow_eject = 0;
++
++ printf(&quot;unmounting filesystems...\n&quot;);
++
++ fd = open(&quot;/proc/mounts&quot;, O_RDONLY, 0);
++ if (fd &lt; 1) {
++ print_error(&quot;failed to open /proc/mounts&quot;);
++ sleep(2);
++ return;
++ }
++
++ size = read(fd, buf, sizeof(buf) - 1);
++ buf[size] = '\0';
++
++ close(fd);
++
++ p = buf;
++ while (*p) {
++ fs[numfs].mounted = 1;
++ fs[numfs].dev = p;
++ while (*p != ' ') p++;
++ *p++ = '\0';
++ fs[numfs].name = p;
++ while (*p != ' ') p++;
++ *p++ = '\0';
++ fs[numfs].fs = p;
++ while (*p != ' ') p++;
++ *p++ = '\0';
++ while (*p != '\n') p++;
++ p++;
++ if (!strcmp(fs[numfs].fs, &quot;nfs&quot;))
++ disallow_eject = 1;
++ if (strcmp(fs[numfs].name, &quot;/&quot;)
++ &amp;&amp; !strstr(fs[numfs].dev, &quot;ram&quot;)
++ &amp;&amp; strcmp(fs[numfs].name, &quot;/dev&quot;)
++ &amp;&amp; strcmp(fs[numfs].name, &quot;/sys&quot;)
++ &amp;&amp; strncmp(fs[numfs].name, &quot;/proc&quot;, 5))
++ numfs++;
++ }
++
++ /* Pixel's ultra-optimized sorting algorithm:
++ multiple passes trying to umount everything until nothing moves
++ anymore (a.k.a holy shotgun method) */
++ do {
++ nb = 0;
++ for (i = 0; i &lt; numfs; i++) {
++ /*printf(&quot;trying with %s\n&quot;, fs[i].name);*/
++ del_loops();
++ if (fs[i].mounted &amp;&amp; umount(fs[i].name) == 0) {
++ printf(&quot;\t%s\n&quot;, fs[i].name);
++ fs[i].mounted = 0;
++ nb++;
++ }
++ }
++ } while (nb);
++
++ for (i = nb = 0; i &lt; numfs; i++)
++ if (fs[i].mounted) {
++ printf(&quot;\tumount failed: %s\n&quot;, fs[i].name);
++ if (strcmp(fs[i].fs, &quot;ext3&quot;) == 0) nb++; /* don't count not-ext3 umount failed */
++ }
++
++
++ if (nb) {
++ printf(&quot;failed to umount some filesystems\n&quot;);
++ select(0, NULL, NULL, NULL, NULL);
++ }
++}
++
++#define BMAGIC_HARD 0x89ABCDEF
++#define BMAGIC_SOFT 0
++#define BMAGIC_REBOOT 0x01234567
++#define BMAGIC_HALT 0xCDEF0123
++#define BMAGIC_POWEROFF 0x4321FEDC
++int reboot_magic = BMAGIC_REBOOT;
++
++int in_reboot(void)
++{
++ int fd;
++ if ((fd = open(&quot;/var/run/rebootctl&quot;, O_RDONLY, 0)) &gt; 0) {
++ char buf[100];
++ int i = read(fd, buf, sizeof(buf));
++ close(fd);
++ if (strstr(buf, &quot;halt&quot;))
++ reboot_magic = BMAGIC_POWEROFF;
++ return i &gt; 0;
++ }
++ return 0;
++}
++
++int exit_value_proceed = 66;
++int exit_value_restart = 0x35;
++
++int main(int argc, char **argv)
++{
++ pid_t installpid, childpid;
++ int wait_status;
++ int fd;
++ int counter = 0;
++ int abnormal_termination = 0;
++
++ if (argc &gt; 1 &amp;&amp; argv[1][0] &gt;= '0' &amp;&amp; argv[1][0] &lt;= '9') {
++ printf(&quot;This is no normal init, sorry.\n&quot;
++ &quot;Call `reboot' or `halt' directly.\n&quot;);
++ return 0;
++ }
++
++ if (!testing) {
++ /* turn off screen blanking */
++ printf(&quot;\033[9;0]&quot;);
++ printf(&quot;\033[8]&quot;);
++ }
++ else
++ printf(&quot;*** TESTING MODE *** (pid is %d)\n&quot;, getpid());
++
++
++ if (!testing) {
++ mkdir(&quot;/proc&quot;, 0755);
++ if (mount(&quot;/proc&quot;, &quot;/proc&quot;, &quot;proc&quot;, 0, NULL))
++ fatal_error(&quot;Unable to mount proc filesystem&quot;);
++ mkdir(&quot;/sys&quot;, 0755);
++ if (mount(&quot;none&quot;, &quot;/sys&quot;, &quot;sysfs&quot;, 0, NULL))
++ fatal_error(&quot;Unable to mount sysfs filesystem&quot;);
++ }
++
++
++ /* ignore Control-C and keyboard stop signals */
++ signal(SIGINT, SIG_IGN);
++ signal(SIGTSTP, SIG_IGN);
++
++ if (!testing) {
++ fd = open(&quot;/dev/console&quot;, O_RDWR, 0);
++ if (fd &lt; 0)
++ fatal_error(&quot;failed to open /dev/console&quot;);
++
++ dup2(fd, 0);
++ dup2(fd, 1);
++ dup2(fd, 2);
++ close(fd);
++ }
++
++
++ /* I set me up as session leader (probably not necessary?) */
++ setsid();
++// if (ioctl(0, TIOCSCTTY, NULL))
++// print_error(&quot;could not set new controlling tty&quot;);
++
++ if (!testing) {
++ char my_hostname[] = &quot;localhost&quot;;
++ sethostname(my_hostname, sizeof(my_hostname));
++ /* the default domainname (as of 2.0.35) is &quot;(none)&quot;, which confuses
++ glibc */
++ setdomainname(&quot;&quot;, 0);
++ }
++
++ if (!testing)
++ doklog();
++
++ /* Go into normal init mode - keep going, and then do a orderly shutdown
++ when:
++
++ 1) install exits
++ 2) we receive a SIGHUP
++ */
++
++ do {
++ if (counter == 1) {
++ printf(&quot;proceeding, please wait...\n&quot;);
++ }
++
++ if (!(installpid = fork())) {
++ /* child */
++ char * child_argv[2];
++ child_argv[0] = counter == 0 ? BINARY : BINARY_STAGE2;
++ child_argv[1] = NULL;
++
++ execve(child_argv[0], child_argv, env);
++ printf(&quot;error in exec of %s :-( [%d]\n&quot;, child_argv[0], errno);
++ return 0;
++ }
++
++ do {
++ childpid = wait4(-1, &amp;wait_status, 0, NULL);
++ } while (childpid != installpid);
++
++ counter++;
++ } while (WIFEXITED(wait_status) &amp;&amp; WEXITSTATUS(wait_status) == exit_value_restart);
++
++ /* allow Ctrl Alt Del to reboot */
++ reboot(0xfee1dead, 672274793, BMAGIC_HARD);
++
++ if (in_reboot()) {
++ // any exitcode is valid if we're in_reboot
++ } else if (WIFEXITED(wait_status) &amp;&amp; WEXITSTATUS(wait_status) == exit_value_proceed) {
++ kill(klog_pid, 9);
++ printf(&quot;proceeding, please wait...\n&quot;);
++
++ {
++ char * child_argv[2] = { &quot;/sbin/init&quot;, NULL };
++ execve(child_argv[0], child_argv, env);
++ }
++ fatal_error(&quot;failed to exec /sbin/init&quot;);
++ } else if (!WIFEXITED(wait_status) || WEXITSTATUS(wait_status) != 0) {
++ printf(&quot;exited abnormally :-( &quot;);
++ if (WIFSIGNALED(wait_status))
++ printf(&quot;-- received signal %d&quot;, WTERMSIG(wait_status));
++ printf(&quot;\n&quot;);
++ abnormal_termination = 1;
++ }
++
++ if (!abnormal_termination) {
++ int i;
++ for (i=0; i&lt;50; i++)
++ printf(&quot;\n&quot;); /* cleanup startkde messages */
++ }
++
++ if (testing)
++ return 0;
++
++ sync(); sync();
++ sleep(2);
++
++ printf(&quot;sending termination signals...&quot;);
++ kill(-1, 15);
++ sleep(2);
++ printf(&quot;done\n&quot;);
++
++ printf(&quot;sending kill signals...&quot;);
++ kill(-1, 9);
++ sleep(2);
++ printf(&quot;done\n&quot;);
++
++ unmount_filesystems();
++
++ sync(); sync();
++
++ if (!abnormal_termination) {
++ if (reboot_magic == BMAGIC_REBOOT) {
++#ifdef DEBUG
++ printf(&quot;automatic reboot in 10 seconds\n&quot;);
++ sleep(10);
++#endif
++ reboot(0xfee1dead, 672274793, reboot_magic);
++ } else {
++ printf(&quot;you may safely poweroff your computer now\n&quot;);
++ }
++ } else {
++ printf(&quot;you may safely reboot or halt your system\n&quot;);
++ }
++
++ select(0, NULL, NULL, NULL, NULL);
++ return 0;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/init.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ka.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ka.c (rev 0)
++++ drakx/trunk/mdk-stage1/ka.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,198 @@
++/*
++ * Copyright 2005 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#include &quot;ka.h&quot;
++#include &lt;sys/mount.h&gt;
++#include &quot;mount.h&quot;
++#include &lt;sys/wait.h&gt;
++#include &lt;dirent.h&gt;
++#include &lt;errno.h&gt;
++#include &lt;sys/socket.h&gt;
++#include &lt;netinet/in.h&gt;
++#include &lt;arpa/inet.h&gt;
++#include &lt;unistd.h&gt;
++
++#include &quot;config-stage1.h&quot;
++#include &quot;frontend.h&quot;
++#include &quot;log.h&quot;
++#include &quot;tools.h&quot;
++
++struct in_addr next_server = { 0 };
++
++#if 0
++static void save_stuff_for_rescue(void)
++{
++ copy_file(&quot;/etc/resolv.conf&quot;, STAGE2_LOCATION &quot;/etc/resolv.conf&quot;, NULL);
++}
++#endif
++
++static void my_pause(void) {
++ unsigned char t;
++ fflush(stdout);
++ read(0, &amp;t, 1);
++}
++
++static enum return_type ka_wait_for_stage2(int count)
++{
++ char * ramdisk = &quot;/dev/ram3&quot;; /* warning, verify that this file exists in the initrd*/
++ char * ka_launch[] = { &quot;/ka/ka-d-client&quot;, &quot;-w&quot;,&quot;-s&quot;,&quot;getstage2&quot;,&quot;-e&quot;,&quot;(cd /tmp/stage2; tar -x -f - )&quot;, NULL }; /* The command line for ka_launch */
++ char * mkfs_launch[] = { &quot;/sbin/mke2fs&quot;, &quot;-m&quot;, &quot;0&quot;, ramdisk, NULL}; /* The mkfs command for formating the ramdisk */
++
++ log_message(&quot;KA: Preparing to receive stage 2....&quot;);
++ wait_message(&quot;Preparing to receive stage 2&quot;);
++
++ int pida, wait_status;
++
++ if (!(pida = fork())) { /* Forking current process for running mkfs */
++ //close(1);
++ close(2);
++ execv(mkfs_launch[0], mkfs_launch); /* Formating the ramdisk */
++ printf(&quot;KA: Can't execute %s\n&lt;press Enter&gt;\n&quot;, mkfs_launch[0]);
++ my_pause();
++ return KAERR_CANTFORK;
++ }
++ while (wait4(-1, &amp;wait_status, 0, NULL) != pida) {}; /* Waiting the end of mkfs */
++ remove_wait_message();
++
++ wait_message(&quot;Mounting /dev/ram3 at %s&quot;, STAGE2_LOCATION);
++ if (my_mount(ramdisk, STAGE2_LOCATION, &quot;ext2&quot;, 1)) {/* Trying to mount the ramdisk */
++ return RETURN_ERROR;
++ }
++ remove_wait_message();
++
++ log_message(&quot;KA: Waiting for stage 2....&quot;);
++ wait_message(&quot;Waiting for rescue from KA server (Try %d/%d)&quot;, count, KA_MAX_RETRY);
++ pid_t pid; /* Process ID of the child process */
++ pid_t wpid; /* Process ID from wait() */
++ int status; /* Exit status from wait() */
++
++ pid = fork();
++ if ( pid == -1 ) {
++ fprintf(stderr, &quot;%s: Failed to fork()\n&quot;, strerror(errno));
++ exit(13);
++ } else if ( pid == 0 ) {
++ // close(2);
++ execv(ka_launch[0], ka_launch);
++ } else {
++ // wpid = wait(&amp;status); /* Child's exit status */
++ wpid = wait4(-1, &amp;status, 0, NULL);
++ if ( wpid == -1 ) {
++ fprintf(stderr,&quot;%s: wait()\n&quot;, strerror(errno));
++ return RETURN_ERROR;
++ } else if ( wpid != pid )
++ abort();
++ else {
++ if ( WIFEXITED(status) ) {
++ printf(&quot;Exited: $? = %d\n&quot;, WEXITSTATUS(status));
++ } else if ( WIFSIGNALED(status) ) {
++ printf(&quot;Signal: %d%s\n&quot;, WTERMSIG(status), WCOREDUMP(status) ? &quot; with core file.&quot; : &quot;&quot;);
++ }
++ }
++ }
++
++ remove_wait_message();
++ return RETURN_OK;
++ // if (!(pid = fork())) { /* Froking current process for running ka-deploy (client side) */
++ // close(1); /* Closing stdout */
++ // close(2); /* Closing stderr */
++ // execve(ka_launch[0], ka_launch,grab_env()); /* Running ka-deploy (client side) */
++ // printf(&quot;KA: Can't execute %s\n&lt;press Enter&gt;\n&quot;, ka_launch[0]);
++ // log_message(&quot;KA: Can't execute %s\n&lt;press Enter&gt;\n&quot;, ka_launch[0]);
++ // my_pause();
++ // return KAERR_CANTFORK;
++ //}
++
++ //while (wait4(-1, &amp;wait_status, 0, NULL) != pid) {}; /* Waiting the end of duplication */
++ // log_message(&quot;kalaunch ret %d\n&quot;, WIFEXITED(wait_status));
++ // remove_wait_message();
++ //sleep(100000);
++ // return RETURN_OK;
++}
++
++enum return_type perform_ka(void) {
++ enum return_type results;
++ int server_failure = 1; /* Number of time we've failed to find a ka server */
++ FILE *f = fopen (&quot;/ka/tftpserver&quot;,&quot;w&quot;);
++
++ if (f != NULL) {
++ /* Writing the NEXT_SERVER value of the DHCP Request in the /ka/tftpserver file */
++ fprintf(f,&quot;%s\n&quot;,inet_ntoa(next_server));
++ fclose(f);
++ }
++
++ log_message(&quot;KA: Trying to retrieve stage2 from server&quot;);
++ log_message(&quot;KA: ka_wait_for_stage2&quot;);
++ do {
++ /* We are trying to get a valid stage 2 (rescue) */
++ results=ka_wait_for_stage2(server_failure);
++ if (results != RETURN_OK) {
++ return results;
++ } else {
++ /* Trying to open STAGE2_LOCATION/ka directory */
++ char dir[255] = STAGE2_LOCATION;
++ strcat(dir,&quot;/ka&quot;);
++ DIR *dp = opendir(dir);
++
++ /* Does the STAGE2_LOCATION/ka directory exists ? = Does the rescue with ka well downloaded ?*/
++ if (!dp) {
++ log_message(&quot;KA: Server not found !&quot;);
++ /* Be sure that the STAGE2_LOCATION isn't mounted after receiving a wrong rescue */
++ if (umount (STAGE2_LOCATION)) {
++ log_perror(&quot;KA: Unable to umount STAGE2&quot;);
++ }
++ int cpt;
++
++ if (server_failure++ == KA_MAX_RETRY){
++ /* if the KA server can't be reach KA_MAX_RETRY times */
++ char * reboot_launch[] = { &quot;/sbin/reboot&quot;, NULL};
++ for (cpt=5; cpt&gt;0; cpt--) {
++ wait_message(&quot;!!! Can't reach a valid KA server !!! (Rebooting in %d sec)&quot;,cpt);
++ sleep (1);
++ }
++ /* Rebooting the computer to avoid infinite loop on ka mode */
++ execv(reboot_launch[0], reboot_launch);
++ }
++
++ for (cpt=5; cpt&gt;0; cpt--) {
++ wait_message(&quot;KA server not found ! (Try %d/%d in %d sec)&quot;,server_failure,KA_MAX_RETRY,cpt);
++ log_message(&quot;Ka not found %d/%d&quot;, server_failure,KA_MAX_RETRY);
++ sleep (1);
++ }
++ remove_wait_message();
++ /* We should try another time*/
++ results=RETURN_BACK;
++ continue;
++ }
++
++ if (dp) {
++ log_message(&quot;KA: Stage 2 downloaded successfully&quot;);
++ closedir(dp); /* Closing the /ka directory */
++ server_failure=1; /* Resetting server_failure */
++ results = RETURN_OK;
++ }
++ }
++
++ log_message(&quot;KA: Preparing chroot&quot;);
++ return RETURN_OK;
++
++ // if (IS_RESCUE) { /* if we are in rescue mode */
++ // save_stuff_for_rescue(); /* Saving resolve.conf */
++ // if (umount (STAGE2_LOCATION)) { /* Unmounting STAGE2 elseif kernel can't mount it ! */
++ // log_perror(&quot;KA: Unable to umount STAGE2&quot;);
++ // return RETURN_ERROR;
++ // }
++ // }
++ } while (results == RETURN_BACK);
++
++ // method_name = strdup(&quot;ka&quot;);
++ return RETURN_OK;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ka.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ka.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ka.h (rev 0)
++++ drakx/trunk/mdk-stage1/ka.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,20 @@
++/*
++ * Copyright 2005 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#ifndef _KA_H_
++#define _KA_H_
++
++#define KAERR_CANTFORK -20
++
++enum return_type perform_ka(void);
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/ka.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/log.c
+===================================================================
+--- drakx/trunk/mdk-stage1/log.c (rev 0)
++++ drakx/trunk/mdk-stage1/log.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,94 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Portions from Erik Troan (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ewt at redhat.com</A>)
++ *
++ * Copyright 1996 Red Hat Software
++ *
++ */
++
++#include &lt;stdlib.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;stdarg.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;string.h&gt;
++#include &lt;time.h&gt;
++#include &lt;errno.h&gt;
++#include &quot;stage1.h&quot;
++
++#include &quot;log.h&quot;
++
++static FILE * logtty = NULL;
++static FILE * logfile = NULL;
++
++
++void vlog_message(const char * s, va_list args)
++{
++ va_list args_copy;
++ va_copy(args_copy, args);
++
++ if (logfile) {
++ fprintf(logfile, &quot;* &quot;);
++ vfprintf(logfile, s, args);
++ fprintf(logfile, &quot;\n&quot;);
++ fflush(logfile);
++ }
++ if (logtty) {
++ fprintf(logtty, &quot;* &quot;);
++ vfprintf(logtty, s, args_copy);
++ fprintf(logtty, &quot;\n&quot;);
++ fflush(logtty);
++ }
++
++ va_end(args_copy);
++}
++
++
++void log_message(const char * s, ...)
++{
++ va_list args;
++ va_start(args, s);
++ vlog_message(s, args);
++ va_end(args);
++
++ return;
++}
++
++void log_perror(const char *msg)
++{
++ log_message(&quot;%s: %s&quot;, msg, strerror(errno));
++}
++
++
++void open_log(void)
++{
++ if (!IS_TESTING) {
++ logtty = fopen(&quot;/dev/tty3&quot;, &quot;w&quot;);
++ logfile = fopen(&quot;/tmp/stage1.log&quot;, &quot;w&quot;);
++ }
++ else
++ logfile = fopen(&quot;debug.log&quot;, &quot;w&quot;);
++}
++
++void close_log(void)
++{
++ if (logfile) {
++ log_message(&quot;stage1: disconnecting life support systems&quot;);
++ fclose(logfile);
++ if (logtty)
++ fclose(logtty);
++ }
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/log.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/log.h
+===================================================================
+--- drakx/trunk/mdk-stage1/log.h (rev 0)
++++ drakx/trunk/mdk-stage1/log.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,34 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Portions from Erik Troan (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ewt at redhat.com</A>)
++ *
++ * Copyright 1996 Red Hat Software
++ *
++ */
++
++
++#ifndef _LOG_H_
++#define _LOG_H_
++
++#include &lt;stdarg.h&gt;
++
++void log_message(const char * s, ...) __attribute__ ((format (printf, 1, 2)));
++void vlog_message(const char * s, va_list args);
++void log_perror(const char *msg);
++void open_log(void);
++void close_log(void);
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/log.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/lomount.c
+===================================================================
+--- drakx/trunk/mdk-stage1/lomount.c (rev 0)
++++ drakx/trunk/mdk-stage1/lomount.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,196 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/* This code comes from util-linux-2.10n (mount/lomount.c)
++ * (this is a simplified version of this code)
++ */
++
++#include &lt;sys/types.h&gt;
++#include &lt;sys/mount.h&gt;
++#include &lt;sys/ioctl.h&gt;
++#include &lt;sys/mount.h&gt;
++#include &lt;errno.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;string.h&gt;
++#include &lt;unistd.h&gt;
++
++#include &quot;stage1.h&quot;
++#include &quot;frontend.h&quot;
++#include &quot;log.h&quot;
++#include &quot;mount.h&quot;
++#include &quot;modules.h&quot;
++
++#include &quot;lomount.h&quot;
++
++
++#define LO_NAME_SIZE 64
++#define LO_KEY_SIZE 32
++
++struct loop_info
++{
++ int lo_number; /* ioctl r/o */
++ dev_t lo_device; /* ioctl r/o */
++ unsigned long lo_inode; /* ioctl r/o */
++ dev_t lo_rdevice; /* ioctl r/o */
++ int lo_offset;
++ int lo_encrypt_type;
++ int lo_encrypt_key_size; /* ioctl w/o */
++ int lo_flags; /* ioctl r/o */
++ char lo_name[LO_NAME_SIZE];
++ unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
++ unsigned long lo_init[2];
++ char reserved[4];
++};
++
++#define LOOP_SET_FD 0x4C00
++#define LOOP_CLR_FD 0x4C01
++#define LOOP_SET_STATUS 0x4C02
++#define LOOP_GET_STATUS 0x4C03
++
++int
++set_loop (const char *device, const char *file)
++{
++ struct loop_info loopinfo;
++ int fd, ffd, mode;
++
++ mode = O_RDONLY;
++
++ if ((ffd = open (file, mode)) &lt; 0)
++ return 1;
++
++ if ((fd = open (device, mode)) &lt; 0) {
++ close(ffd);
++ return 1;
++ }
++
++ memset(&amp;loopinfo, 0, sizeof (loopinfo));
++ strncpy(loopinfo.lo_name, file, LO_NAME_SIZE);
++ loopinfo.lo_name[LO_NAME_SIZE - 1] = 0;
++ loopinfo.lo_offset = 0;
++
++#ifdef MCL_FUTURE
++ /*
++ * Oh-oh, sensitive data coming up. Better lock into memory to prevent
++ * passwd etc being swapped out and left somewhere on disk.
++ */
++
++ if(mlockall(MCL_CURRENT|MCL_FUTURE)) {
++ log_message(&quot;CRITICAL Couldn't lock into memory! %s (memlock)&quot;, strerror(errno));
++ return 1;
++ }
++#endif
++
++ if (ioctl(fd, LOOP_SET_FD, ffd) &lt; 0) {
++ close(fd);
++ close(ffd);
++ return 1;
++ }
++
++ if (ioctl(fd, LOOP_SET_STATUS, &amp;loopinfo) &lt; 0) {
++ (void) ioctl (fd, LOOP_CLR_FD, 0);
++ close(fd);
++ close(ffd);
++ return 1;
++ }
++
++ close(fd);
++ close(ffd);
++ return 0;
++}
++
++
++char* find_free_loop()
++{
++ struct loop_info loopinfo;
++ int i;
++ for (i=0; i&lt;256; i++) {
++ int fd;
++ char ldev[100];
++ sprintf(ldev, &quot;/dev/loop%d&quot;, i);
++ ensure_dev_exists(ldev);
++ fd = open(ldev, O_RDONLY);
++ if (!ioctl(fd, LOOP_GET_STATUS, &amp;loopinfo)) {
++ close(fd);
++ continue;
++ }
++ if (errno == ENXIO) {
++ log_message(&quot;%s is available&quot;, ldev);
++ close(fd);
++ return strdup(ldev);
++ } else {
++ log_perror(&quot;LOOP_GET_STATUS(unexpected error)&quot;);
++ close(fd);
++ continue;
++ }
++ }
++ return NULL;
++}
++
++void
++del_loop(char * loopdev)
++{
++ int fd;
++
++ if (!loopdev)
++ return;
++
++ if ((fd = open (loopdev, O_RDONLY)) &lt; 0)
++ return;
++
++ if (ioctl (fd, LOOP_CLR_FD, 0) &lt; 0)
++ return;
++
++ close (fd);
++}
++
++int
++lomount(char *loopfile, char *where, char **dev, int compressed)
++{
++
++ long int flag;
++ char * loopdev;
++
++ flag = MS_MGC_VAL;
++ flag |= MS_RDONLY;
++
++ my_insmod(&quot;loop&quot;, ANY_DRIVER_TYPE, &quot;max_loop=256&quot;, 1);
++ if (compressed) {
++ my_insmod(&quot;sqlzma&quot;, ANY_DRIVER_TYPE, NULL, 1);
++ my_insmod(&quot;squashfs_lzma&quot;, ANY_DRIVER_TYPE, NULL, 1);
++ my_insmod(&quot;squashfs&quot;, ANY_DRIVER_TYPE, NULL, 1);
++ }
++
++ if (!(loopdev = find_free_loop())) {
++ log_message(&quot;could not find a free loop&quot;);
++ return 1;
++ }
++ if (dev)
++ *dev = loopdev;
++
++ if (set_loop(loopdev, loopfile)) {
++ log_message(&quot;set_loop failed on %s (%s)&quot;, loopdev, strerror(errno));
++ return 1;
++ }
++
++ if (my_mount(loopdev, where, compressed ? &quot;squashfs&quot; : &quot;iso9660&quot;, 0)) {
++ del_loop(loopdev);
++ return 1;
++ }
++
++ log_message(&quot;lomount succeeded for %s on %s&quot;, loopfile, where);
++ return 0;
++}
++
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/lomount.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/lomount.h
+===================================================================
+--- drakx/trunk/mdk-stage1/lomount.h (rev 0)
++++ drakx/trunk/mdk-stage1/lomount.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,21 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#ifndef LOMOUNT_H
++#define LOMOUNT_H
++
++int lomount(char *loopfile, char *where, char **loopdev, int compressed);
++void del_loop(char *loopdev);
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/lomount.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/modules.c
+===================================================================
+--- drakx/trunk/mdk-stage1/modules.c (rev 0)
++++ drakx/trunk/mdk-stage1/modules.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,490 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * (1) calculate dependencies
++ * (2) unarchive relevant modules
++ * (3) insmod them
++ */
++
++#include &quot;stage1.h&quot;
++
++#include &lt;stdlib.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;sys/mount.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;libgen.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;string.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;errno.h&gt;
++#include &lt;sys/utsname.h&gt;
++#include &quot;log.h&quot;
++#include &quot;utils.h&quot;
++#include &quot;frontend.h&quot;
++#include &quot;mount.h&quot;
++#include &quot;zlibsupport.h&quot;
++
++#include &quot;modules.h&quot;
++
++#define UEVENT_HELPER_FILE &quot;/sys/kernel/uevent_helper&quot;
++#define UEVENT_HELPER_VALUE &quot;/sbin/hotplug&quot;
++
++static char modules_directory[100];
++static struct module_deps_elem * modules_deps = NULL;
++static struct module_descr_elem * modules_descr = NULL;
++
++extern long init_module(void *, unsigned long, const char *);
++
++
++static const char *moderror(int err)
++{
++ switch (err) {
++ case ENOEXEC:
++ return &quot;Invalid module format&quot;;
++ case ENOENT:
++ return &quot;Unknown symbol in module&quot;;
++ case ESRCH:
++ return &quot;Module has wrong symbol version&quot;;
++ case EINVAL:
++ return &quot;Invalid parameters&quot;;
++ default:
++ return strerror(err);
++ }
++}
++
++int insmod_local_file(char * path, char * options)
++{
++ void *file;
++ unsigned long len;
++ int rc;
++
++ if (IS_TESTING)
++ return 0;
++
++ file = grab_file(path, &amp;len);
++
++ if (!file) {
++ log_perror(asprintf_(&quot;\terror reading %s&quot;, path));
++ return -1;
++ }
++
++ rc = init_module(file, len, options ? options : &quot;&quot;);
++ if (rc)
++ log_message(&quot;\terror: %s&quot;, moderror(errno));
++ return rc;
++}
++
++static char *kernel_module_extension(void)
++{
++ return &quot;.ko.gz&quot;;
++}
++
++
++static char *filename2modname(char * filename) {
++ char *modname, *p;
++
++ modname = strdup(basename(filename));
++ if (strstr(modname, kernel_module_extension())) {
++ modname[strlen(modname)-strlen(kernel_module_extension())] = '\0'; /* remove trailing .ko.gz */
++ }
++
++ p = modname;
++ while (p &amp;&amp; *p) {
++ if (*p == '-')
++ *p = '_';
++ p++;
++ }
++
++ return modname;
++}
++
++static void find_modules_directory(void)
++{
++ struct utsname kernel_uname;
++ char * prefix = &quot;/lib/modules&quot;;
++ char * release;
++ if (uname(&amp;kernel_uname)) {
++ fatal_error(&quot;uname failed&quot;);
++ }
++ release = kernel_uname.release;
++ sprintf(modules_directory , &quot;%s/%s&quot;, prefix, release);
++}
++
++static int load_modules_dependencies(void)
++{
++ char * deps_file = asprintf_(&quot;%s/%s&quot;, modules_directory, &quot;modules.dep&quot;);
++ char * buf, * ptr, * start, * end;
++ struct stat s;
++ int line, i;
++
++ log_message(&quot;loading modules dependencies&quot;);
++ buf = cat_file(deps_file, &amp;s);
++ if (!buf)
++ return -1;
++ line = line_counts(buf);
++ modules_deps = malloc(sizeof(*modules_deps) * (line+1));
++
++ start = buf;
++ line = 0;
++ while (start &lt; (buf+s.st_size) &amp;&amp; *start) {
++ char * tmp_deps[50];
++
++ end = strchr(start, '\n');
++ *end = '\0';
++
++ ptr = strchr(start, ':');
++ if (!ptr) {
++ start = end + 1;
++ continue;
++ }
++ *ptr = '\0';
++ ptr++;
++
++ while (*ptr &amp;&amp; (*ptr == ' ')) ptr++;
++
++ /* sort of a good line */
++ modules_deps[line].filename = start[0] == '/' ? strdup(start) : asprintf_(&quot;%s/%s&quot;, modules_directory, start);
++ modules_deps[line].modname = filename2modname(start);
++
++ start = ptr;
++ i = 0;
++ while (start &amp;&amp; *start &amp;&amp; i &lt; sizeof(tmp_deps)/sizeof(char *)) {
++ ptr = strchr(start, ' ');
++ if (ptr) *ptr = '\0';
++ tmp_deps[i++] = filename2modname(start);
++ if (ptr)
++ start = ptr + 1;
++ else
++ start = NULL;
++ while (start &amp;&amp; *start &amp;&amp; *start == ' ')
++ start++;
++ }
++ if(i &gt;= sizeof(tmp_deps)/sizeof(char *)-1) {
++ log_message(&quot;warning, more than %zu dependencies for module %s&quot;,
++ sizeof(tmp_deps)/sizeof(char *)-1,
++ modules_deps[line].modname);
++ i = sizeof(tmp_deps)/sizeof(char *)-1;
++ }
++ tmp_deps[i++] = NULL;
++
++ modules_deps[line].deps = memdup(tmp_deps, sizeof(char *) * i);
++
++ line++;
++ start = end + 1;
++ }
++ modules_deps[line].modname = NULL;
++
++ free(buf);
++
++ return 0;
++}
++
++
++static int load_modules_descriptions(void)
++{
++ char * descr_file = asprintf_(&quot;%s/%s&quot;, modules_directory, &quot;modules.description&quot;);
++ char * buf, * ptr, * start, * end;
++ struct stat s;
++ int line;
++
++ log_message(&quot;loading modules descriptions&quot;);
++
++ buf = cat_file(descr_file, &amp;s);
++ if (!buf)
++ return -1;
++ line = line_counts(buf);
++ modules_descr = malloc(sizeof(*modules_descr) * (line+1));
++
++ start = buf;
++ line = 0;
++ while (start &lt; (buf+s.st_size) &amp;&amp; *start) {
++ end = strchr(start, '\n');
++ *end = '\0';
++
++ ptr = strchr(start, '\t');
++ if (!ptr) {
++ start = end + 1;
++ continue;
++ }
++ *ptr = '\0';
++ ptr++;
++
++ modules_descr[line].modname = filename2modname(start);
++ modules_descr[line].description = strndup(ptr, 50);
++
++ line++;
++ start = end + 1;
++ }
++ modules_descr[line].modname = NULL;
++
++ free(buf);
++
++ return 0;
++}
++
++void init_firmware_loader(void)
++{
++ int fd = open(UEVENT_HELPER_FILE, O_WRONLY|O_TRUNC, 0666);
++ if (!fd) {
++ log_message(&quot;warning, unable to set firmware loader&quot;);
++ return;
++ }
++ write(fd, UEVENT_HELPER_VALUE, strlen(UEVENT_HELPER_VALUE));
++ close(fd);
++}
++
++void init_modules_insmoding(void)
++{
++ find_modules_directory();
++ if (load_modules_dependencies()) {
++ fatal_error(&quot;warning, error initing modules stuff, modules loading disabled&quot;);
++ }
++ if (load_modules_descriptions()) {
++ log_message(&quot;warning, error initing modules stuff&quot;);
++ }
++}
++
++
++static void add_modules_conf(char * str)
++{
++ static char data[5000] = &quot;&quot;;
++ char * target = &quot;/tmp/modules.conf&quot;;
++ int fd;
++
++ if (strlen(data) + strlen(str) &gt;= sizeof(data))
++ return;
++
++ strcat(data, str);
++ strcat(data, &quot;\n&quot;);
++
++ fd = open(target, O_CREAT|O_WRONLY|O_TRUNC, 00660);
++
++ if (fd == -1) {
++ log_perror(str);
++ return;
++ }
++
++ if (write(fd, data, strlen(data) + 1) != (ssize_t) (strlen(data) + 1))
++ log_perror(str);
++
++ close(fd);
++}
++
++
++int module_already_present(const char * name)
++{
++ FILE * f;
++ int answ = 0;
++
++ if ((f = fopen(&quot;/proc/modules&quot;, &quot;rb&quot;))) {
++ while (1) {
++ char buf[500];
++ if (!fgets(buf, sizeof(buf), f)) break;
++ if (!strncmp(name, buf, strlen(name)) &amp;&amp; buf[strlen(name)] == ' ')
++ answ = 1;
++ }
++ fclose(f);
++ }
++ return answ;
++}
++
++
++#ifndef ENABLE_NETWORK_STANDALONE
++static enum insmod_return insmod_with_deps(const char * mod_name, char * options, int allow_modules_floppy)
++{
++ struct module_deps_elem * dep;
++ const char * filename;
++
++ dep = modules_deps;
++ while (dep &amp;&amp; dep-&gt;modname &amp;&amp; strcmp(dep-&gt;modname, mod_name)) dep++;
++
++ if (dep &amp;&amp; dep-&gt;modname &amp;&amp; dep-&gt;deps) {
++ char ** one_dep;
++ one_dep = dep-&gt;deps;
++ while (*one_dep) {
++ /* here, we can fail but we don't care, if the error is
++ * important, the desired module will fail also */
++ insmod_with_deps(*one_dep, NULL, allow_modules_floppy);
++ one_dep++;
++ }
++ }
++
++ if (dep &amp;&amp; dep-&gt;filename) {
++ filename = dep-&gt;filename;
++ } else {
++ log_message(&quot;warning: unable to get module filename for %s&quot;, mod_name);
++ filename = mod_name;
++ }
++
++ if (module_already_present(mod_name))
++ return INSMOD_OK;
++
++ log_message(&quot;needs %s&quot;, filename);
++ {
++ return insmod_local_file((char *) filename, options);
++ }
++}
++#endif
++
++
++#ifndef DISABLE_NETWORK
++enum insmod_return my_insmod(const char * mod_name, enum driver_type type, char * options, int allow_modules_floppy)
++#else
++enum insmod_return my_insmod(const char * mod_name, enum driver_type type __attribute__ ((unused)), char * options, int allow_modules_floppy)
++#endif
++{
++ int i;
++#ifndef DISABLE_NETWORK
++ char ** net_devices = NULL; /* fucking compiler */
++#endif
++
++ if (module_already_present(mod_name))
++ return INSMOD_OK;
++
++ log_message(&quot;have to insmod %s&quot;, mod_name);
++
++#ifndef DISABLE_NETWORK
++ if (type == NETWORK_DEVICES)
++ net_devices = get_net_devices();
++#endif
++
++#ifdef ENABLE_NETWORK_STANDALONE
++ {
++ char *cmd = options ? asprintf_(&quot;/sbin/modprobe %s %s&quot;, mod_name, options) :
++ asprintf_(&quot;/sbin/modprobe %s&quot;, mod_name);
++ log_message(&quot;running %s&quot;, cmd);
++ i = system(cmd);
++ }
++#else
++ i = insmod_with_deps(mod_name, options, allow_modules_floppy);
++#endif
++ if (i == 0) {
++ log_message(&quot;\tsucceeded %s&quot;, mod_name);
++#ifndef DISABLE_NETWORK
++ if (type == NETWORK_DEVICES) {
++ char ** new_net_devices = get_net_devices();
++ while (new_net_devices &amp;&amp; *new_net_devices) {
++ char alias[500];
++ char ** ptr = net_devices;
++ while (ptr &amp;&amp; *ptr) {
++ if (!strcmp(*new_net_devices, *ptr))
++ goto already_present;
++ ptr++;
++ }
++ sprintf(alias, &quot;alias %s %s&quot;, *new_net_devices, mod_name);
++ add_modules_conf(alias);
++ log_message(&quot;NET: %s&quot;, alias);
++ net_discovered_interface(*new_net_devices);
++
++ already_present:
++ new_net_devices++;
++ }
++ }
++#endif
++ } else
++ log_message(&quot;warning, insmod failed (%s %s) (%d)&quot;, mod_name, options, i);
++
++ return i;
++
++}
++
++static enum return_type insmod_with_options(char * mod, enum driver_type type)
++{
++ char * questions[] = { &quot;Options&quot;, NULL };
++ static char ** answers = NULL;
++ enum return_type results;
++ char options[500] = &quot;options &quot;;
++
++ results = ask_from_entries(&quot;Please enter the parameters to give to the kernel:&quot;, questions, &amp;answers, 24, NULL);
++ if (results != RETURN_OK)
++ return results;
++
++ strcat(options, mod);
++ strcat(options, &quot; &quot;);
++ strcat(options, answers[0]); // because my_insmod will eventually modify the string
++
++ if (my_insmod(mod, type, answers[0], 1) != INSMOD_OK) {
++ stg1_error_message(&quot;Insmod failed.&quot;);
++ return RETURN_ERROR;
++ }
++
++ add_modules_conf(options);
++
++ return RETURN_OK;
++}
++
++static int strsortfunc(const void *a, const void *b)
++{
++ return strcmp(* (char * const *) a, * (char * const *) b);
++}
++
++enum return_type ask_insmod(enum driver_type type)
++{
++ enum return_type results;
++ char * choice;
++ char ** dlist = list_directory(modules_directory);
++ char ** modules = alloca(sizeof(char *) * (string_array_length(dlist) + 1));
++ char ** descrs = alloca(sizeof(char *) * (string_array_length(dlist) + 1));
++ char ** p_dlist = dlist;
++ char ** p_modules = modules;
++ char ** p_descrs = descrs;
++
++ qsort(dlist, string_array_length(dlist), sizeof(char *), strsortfunc);
++
++ unset_automatic(); /* we are in a fallback mode */
++
++ while (p_dlist &amp;&amp; *p_dlist) {
++ struct module_descr_elem * descr;
++ if (!strstr(*p_dlist, kernel_module_extension())) {
++ p_dlist++;
++ continue;
++ }
++ *p_modules = *p_dlist;
++ *p_descrs = NULL;
++ (*p_modules)[strlen(*p_modules)-strlen(kernel_module_extension())] = '\0'; /* remove trailing .ko.gz */
++
++ descr = modules_descr;
++ while (descr &amp;&amp; descr-&gt;modname &amp;&amp; strcmp(descr-&gt;modname, *p_modules)) descr++;
++ if (descr)
++ *p_descrs = descr-&gt;description;
++
++ p_dlist++;
++ p_modules++;
++ p_descrs++;
++ }
++ *p_modules = NULL;
++ *p_descrs = NULL;
++
++ if (modules &amp;&amp; *modules) {
++ char * mytype;
++ char msg[200];
++ if (type == MEDIA_ADAPTERS)
++ mytype = &quot;MEDIA&quot;;
++ else if (type == NETWORK_DEVICES)
++ mytype = &quot;NET&quot;;
++ else
++ return RETURN_ERROR;
++
++ snprintf(msg, sizeof(msg), &quot;Which driver should I try to gain %s access?&quot;, mytype);
++ results = ask_from_list_comments(msg, modules, descrs, &amp;choice);
++ if (results == RETURN_OK)
++ return insmod_with_options(choice, type);
++ else
++ return results;
++ } else {
++ return RETURN_BACK;
++ }
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/modules.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/modules.h
+===================================================================
+--- drakx/trunk/mdk-stage1/modules.h (rev 0)
++++ drakx/trunk/mdk-stage1/modules.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,43 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#ifndef _MODULES_H_
++#define _MODULES_H_
++
++#include &quot;stage1.h&quot;
++#include &quot;probing.h&quot;
++
++enum insmod_return { INSMOD_OK, INSMOD_FAILED, INSMOD_FAILED_FILE_NOT_FOUND };
++
++void init_modules_insmoding(void);
++void init_firmware_loader(void);
++int insmod_local_file(char * path, char * options);
++enum insmod_return my_insmod(const char * mod_name, enum driver_type type, char * options, int allow_modules_floppy);
++enum return_type ask_insmod(enum driver_type);
++int module_already_present(const char * name);
++
++struct module_deps_elem {
++ char * modname;
++ char * filename;
++ char ** deps;
++};
++
++struct module_descr_elem {
++ char * modname;
++ char * description;
++};
++
++extern int disable_modules;
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/modules.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/mount.c
+===================================================================
+--- drakx/trunk/mdk-stage1/mount.c (rev 0)
++++ drakx/trunk/mdk-stage1/mount.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,246 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Portions from Erik Troan (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ewt at redhat.com</A>)
++ *
++ * Copyright 1996 Red Hat Software
++ *
++ */
++
++#include &lt;stdlib.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;string.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;sys/mount.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;sys/types.h&gt;
++#include &quot;log.h&quot;
++#include &quot;utils.h&quot;
++#include &quot;modules.h&quot;
++
++#include &quot;mount.h&quot;
++
++
++
++/* WARNING: this won't work if the argument is not /dev/ based */
++int ensure_dev_exists(const char * dev)
++{
++ int major, minor;
++ int type = S_IFBLK; /* my default type is block. don't forget to change for chars */
++ const char * name;
++ struct stat buf;
++ char * ptr;
++
++ name = &amp;dev[5]; /* we really need that dev be passed as /dev/something.. */
++
++ if (!stat(dev, &amp;buf))
++ return 0; /* if the file already exists, we assume it's correct */
++
++ if (ptr_begins_static_str(name, &quot;sd&quot;)) {
++ /* SCSI disks */
++ major = 8;
++ minor = (name[2] - 'a') &lt;&lt; 4;
++ if (name[3] &amp;&amp; name[4]) {
++ minor += 10 + (name[4] - '0');
++ if (name[3] &gt; 1 || name[4] &gt; 5) {
++ log_message(&quot;I don't know how to create device %s, please post bugreport to me!&quot;, dev);
++ return -1;
++ }
++ } else if (name[3])
++ minor += (name[3] - '0');
++ } else if (ptr_begins_static_str(name, &quot;hd&quot;)) {
++ /* IDE disks/cd's */
++ if (name[2] == 'a')
++ major = 3, minor = 0;
++ else if (name[2] == 'b')
++ major = 3, minor = 64;
++ else if (name[2] == 'c')
++ major = 22, minor = 0;
++ else if (name[2] == 'd')
++ major = 22, minor = 64;
++ else if (name[2] == 'e')
++ major = 33, minor = 0;
++ else if (name[2] == 'f')
++ major = 33, minor = 64;
++ else if (name[2] == 'g')
++ major = 34, minor = 0;
++ else if (name[2] == 'h')
++ major = 34, minor = 64;
++ else if (name[2] == 'i')
++ major = 56, minor = 0;
++ else if (name[2] == 'j')
++ major = 56, minor = 64;
++ else if (name[2] == 'k')
++ major = 57, minor = 0;
++ else if (name[2] == 'l')
++ major = 57, minor = 64;
++ else if (name[2] == 'm')
++ major = 88, minor = 0;
++ else if (name[2] == 'n')
++ major = 88, minor = 64;
++ else if (name[2] == 'o')
++ major = 89, minor = 0;
++ else if (name[2] == 'p')
++ major = 89, minor = 64;
++ else if (name[2] == 'q')
++ major = 90, minor = 0;
++ else if (name[2] == 'r')
++ major = 90, minor = 64;
++ else if (name[2] == 's')
++ major = 91, minor = 0;
++ else if (name[2] == 't')
++ major = 91, minor = 64;
++ else
++ return -1;
++
++ if (name[3] &amp;&amp; name[4])
++ minor += 10 + (name[4] - '0');
++ else if (name[3])
++ minor += (name[3] - '0');
++ } else if (ptr_begins_static_str(name , &quot;sr&quot;)) {
++ /* SCSI cd's */
++ major = 11;
++ minor = name[2] - '0';
++ } else if (ptr_begins_static_str(name, &quot;ida/&quot;) ||
++ ptr_begins_static_str(name, &quot;cciss/&quot;)) {
++ /* Compaq Smart Array &quot;ida/c0d0{p1}&quot; */
++ ptr = strchr(name, '/');
++ mkdir(&quot;/dev/ida&quot;, 0755);
++ mkdir(&quot;/dev/cciss&quot;, 0755);
++ major = ptr_begins_static_str(name, &quot;ida/&quot;) ? 72 : 104 + charstar_to_int(ptr+2);
++ ptr = strchr(ptr, 'd');
++ minor = 16 * charstar_to_int(ptr+1);
++ ptr = strchr(ptr, 'p');
++ minor += charstar_to_int(ptr+1);
++ } else if (ptr_begins_static_str(name, &quot;rd/&quot;)) {
++ /* DAC960 &quot;rd/cXdXXpX&quot; */
++ mkdir(&quot;/dev/rd&quot;, 0755);
++ major = 48 + charstar_to_int(name+4);
++ ptr = strchr(name+4, 'd');
++ minor = 8 * charstar_to_int(ptr+1);
++ ptr = strchr(ptr, 'p');
++ minor += charstar_to_int(ptr+1);
++ } else if (ptr_begins_static_str(name, &quot;loop&quot;)) {
++ major = 7;
++ minor = name[4] - '0';
++ } else if (ptr_begins_static_str(name, &quot;chloop&quot;)) {
++ major = 100;
++ minor = name[6] - '0';
++ } else {
++ log_message(&quot;I don't know how to create device %s, please post bugreport to me!&quot;, dev);
++ return -1;
++ }
++
++ if (mknod(dev, type | 0600, makedev(major, minor))) {
++ log_perror(dev);
++ return -1;
++ }
++
++ return 0;
++}
++
++
++/* mounts, creating the device if needed+possible */
++int my_mount(char *dev, char *location, char *fs, int force_rw)
++{
++ unsigned long flags = MS_MGC_VAL | (force_rw ? 0 : MS_RDONLY);
++ char * opts = NULL;
++ struct stat buf;
++ int rc;
++
++ if (strcmp(fs, &quot;nfs&quot;)) {
++ rc = ensure_dev_exists(dev);
++ if (rc != 0) {
++ log_message(&quot;could not create required device file&quot;);
++ return -1;
++ }
++ }
++
++ log_message(&quot;mounting %s on %s as type %s&quot;, dev, location, fs);
++
++ if (stat(location, &amp;buf)) {
++ if (mkdir(location, 0755)) {
++ log_perror(&quot;could not create location dir&quot;);
++ return -1;
++ }
++ } else if (!S_ISDIR(buf.st_mode)) {
++ log_message(&quot;not a dir %s, will unlink and mkdir&quot;, location);
++ if (unlink(location)) {
++ log_perror(&quot;could not unlink&quot;);
++ return -1;
++ }
++ if (mkdir(location, 0755)) {
++ log_perror(&quot;could not create location dir&quot;);
++ return -1;
++ }
++ }
++
++ if (!strcmp(fs, &quot;supermount&quot;)) {
++ my_insmod(&quot;supermount&quot;, ANY_DRIVER_TYPE, NULL, 1);
++ my_insmod(&quot;isofs&quot;, ANY_DRIVER_TYPE, NULL, 1);
++ opts = alloca(500);
++ sprintf(opts, &quot;dev=%s,fs=iso9660,tray_lock=always&quot;, dev);
++ dev = &quot;none&quot;;
++ }
++
++#ifndef DISABLE_MEDIAS
++ if (!strcmp(fs, &quot;vfat&quot;)) {
++ my_insmod(&quot;nls_cp437&quot;, ANY_DRIVER_TYPE, NULL, 1);
++ my_insmod(&quot;nls_iso8859_1&quot;, ANY_DRIVER_TYPE, NULL, 1);
++ my_insmod(&quot;vfat&quot;, ANY_DRIVER_TYPE, NULL, 1);
++ opts = &quot;check=relaxed&quot;;
++ }
++
++ if (!strcmp(fs, &quot;ntfs&quot;)) {
++ my_insmod(&quot;ntfs&quot;, ANY_DRIVER_TYPE, NULL, 1);
++ }
++
++ if (!strcmp(fs, &quot;reiserfs&quot;))
++ my_insmod(&quot;reiserfs&quot;, ANY_DRIVER_TYPE, NULL, 1);
++
++ if (!strcmp(fs, &quot;reiser4&quot;))
++ my_insmod(&quot;reiser4&quot;, ANY_DRIVER_TYPE, NULL, 1);
++
++ if (!strcmp(fs, &quot;jfs&quot;))
++ my_insmod(&quot;jfs&quot;, ANY_DRIVER_TYPE, NULL, 1);
++
++ if (!strcmp(fs, &quot;xfs&quot;))
++ my_insmod(&quot;xfs&quot;, ANY_DRIVER_TYPE, NULL, 1);
++
++ if (!strcmp(fs, &quot;ext4&quot;))
++ my_insmod(&quot;ext4&quot;, ANY_DRIVER_TYPE, NULL, 1);
++
++#endif
++ if (!strcmp(fs, &quot;iso9660&quot;))
++ my_insmod(&quot;isofs&quot;, ANY_DRIVER_TYPE, NULL, 1);
++
++#ifndef DISABLE_NETWORK
++ if (!strcmp(fs, &quot;nfs&quot;)) {
++ my_insmod(&quot;nfs&quot;, ANY_DRIVER_TYPE, NULL, 1);
++ log_message(&quot;preparing nfsmount for %s&quot;, dev);
++ rc = nfsmount_prepare(dev, &amp;opts);
++ if (rc != 0)
++ return rc;
++ }
++#endif
++
++ rc = mount(dev, location, fs, flags, opts);
++ if (rc != 0) {
++ log_perror(&quot;mount failed&quot;);
++ rmdir(location);
++ }
++
++ return rc;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/mount.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/mount.h
+===================================================================
+--- drakx/trunk/mdk-stage1/mount.h (rev 0)
++++ drakx/trunk/mdk-stage1/mount.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,32 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Portions from Erik Troan (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ewt at redhat.com</A>)
++ *
++ * Copyright 1996 Red Hat Software
++ *
++ */
++
++#ifndef _MOUNT_H_
++#define _MOUNT_H_
++
++#ifndef DISABLE_NETWORK
++#include &quot;nfsmount.h&quot;
++#endif
++
++int my_mount(char *dev, char *location, char *fs, int force_rw);
++int ensure_dev_exists(const char * dev);
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/mount.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/mount_rpcgen.h
+===================================================================
+--- drakx/trunk/mdk-stage1/mount_rpcgen.h (rev 0)
++++ drakx/trunk/mdk-stage1/mount_rpcgen.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,208 @@
++/*
++ * Please do not edit this file.
++ * It was generated using rpcgen.
++ */
++
++#ifndef _MOUNT_H_RPCGEN
++#define _MOUNT_H_RPCGEN
++
++#include &lt;rpc/rpc.h&gt;
++
++#define MNTPATHLEN 1024
++#define MNTNAMLEN 255
++#define FHSIZE 32
++
++typedef char fhandle[FHSIZE];
++#ifdef __cplusplus
++extern &quot;C&quot; bool_t xdr_fhandle(XDR *, fhandle);
++#elif __STDC__
++extern bool_t xdr_fhandle(XDR *, fhandle);
++#else /* Old Style C */
++bool_t xdr_fhandle();
++#endif /* Old Style C */
++
++
++struct fhstatus {
++ u_int fhs_status;
++ union {
++ fhandle fhs_fhandle;
++ } fhstatus_u;
++};
++typedef struct fhstatus fhstatus;
++#ifdef __cplusplus
++extern &quot;C&quot; bool_t xdr_fhstatus(XDR *, fhstatus*);
++#elif __STDC__
++extern bool_t xdr_fhstatus(XDR *, fhstatus*);
++#else /* Old Style C */
++bool_t xdr_fhstatus();
++#endif /* Old Style C */
++
++
++typedef char *dirpath;
++#ifdef __cplusplus
++extern &quot;C&quot; bool_t xdr_dirpath(XDR *, dirpath*);
++#elif __STDC__
++extern bool_t xdr_dirpath(XDR *, dirpath*);
++#else /* Old Style C */
++bool_t xdr_dirpath();
++#endif /* Old Style C */
++
++
++typedef char *name;
++#ifdef __cplusplus
++extern &quot;C&quot; bool_t xdr_name(XDR *, name*);
++#elif __STDC__
++extern bool_t xdr_name(XDR *, name*);
++#else /* Old Style C */
++bool_t xdr_name();
++#endif /* Old Style C */
++
++
++typedef struct mountbody *mountlist;
++#ifdef __cplusplus
++extern &quot;C&quot; bool_t xdr_mountlist(XDR *, mountlist*);
++#elif __STDC__
++extern bool_t xdr_mountlist(XDR *, mountlist*);
++#else /* Old Style C */
++bool_t xdr_mountlist();
++#endif /* Old Style C */
++
++
++struct mountbody {
++ name ml_hostname;
++ dirpath ml_directory;
++ mountlist ml_next;
++};
++typedef struct mountbody mountbody;
++#ifdef __cplusplus
++extern &quot;C&quot; bool_t xdr_mountbody(XDR *, mountbody*);
++#elif __STDC__
++extern bool_t xdr_mountbody(XDR *, mountbody*);
++#else /* Old Style C */
++bool_t xdr_mountbody();
++#endif /* Old Style C */
++
++
++typedef struct groupnode *groups;
++#ifdef __cplusplus
++extern &quot;C&quot; bool_t xdr_groups(XDR *, groups*);
++#elif __STDC__
++extern bool_t xdr_groups(XDR *, groups*);
++#else /* Old Style C */
++bool_t xdr_groups();
++#endif /* Old Style C */
++
++
++struct groupnode {
++ name gr_name;
++ groups gr_next;
++};
++typedef struct groupnode groupnode;
++#ifdef __cplusplus
++extern &quot;C&quot; bool_t xdr_groupnode(XDR *, groupnode*);
++#elif __STDC__
++extern bool_t xdr_groupnode(XDR *, groupnode*);
++#else /* Old Style C */
++bool_t xdr_groupnode();
++#endif /* Old Style C */
++
++
++typedef struct exportnode *exports;
++#ifdef __cplusplus
++extern &quot;C&quot; bool_t xdr_exports(XDR *, exports*);
++#elif __STDC__
++extern bool_t xdr_exports(XDR *, exports*);
++#else /* Old Style C */
++bool_t xdr_exports();
++#endif /* Old Style C */
++
++
++struct exportnode {
++ dirpath ex_dir;
++ groups ex_groups;
++ exports ex_next;
++};
++typedef struct exportnode exportnode;
++#ifdef __cplusplus
++extern &quot;C&quot; bool_t xdr_exportnode(XDR *, exportnode*);
++#elif __STDC__
++extern bool_t xdr_exportnode(XDR *, exportnode*);
++#else /* Old Style C */
++bool_t xdr_exportnode();
++#endif /* Old Style C */
++
++
++#define MOUNTPROG ((u_long)100005)
++#define MOUNTVERS ((u_long)1)
++
++#ifdef __cplusplus
++#define MOUNTPROC_NULL ((u_long)0)
++extern &quot;C&quot; void * mountproc_null_1(void *, CLIENT *);
++extern &quot;C&quot; void * mountproc_null_1_svc(void *, struct svc_req *);
++#define MOUNTPROC_MNT ((u_long)1)
++extern &quot;C&quot; fhstatus * mountproc_mnt_1(dirpath *, CLIENT *);
++extern &quot;C&quot; fhstatus * mountproc_mnt_1_svc(dirpath *, struct svc_req *);
++#define MOUNTPROC_DUMP ((u_long)2)
++extern &quot;C&quot; mountlist * mountproc_dump_1(void *, CLIENT *);
++extern &quot;C&quot; mountlist * mountproc_dump_1_svc(void *, struct svc_req *);
++#define MOUNTPROC_UMNT ((u_long)3)
++extern &quot;C&quot; void * mountproc_umnt_1(dirpath *, CLIENT *);
++extern &quot;C&quot; void * mountproc_umnt_1_svc(dirpath *, struct svc_req *);
++#define MOUNTPROC_UMNTALL ((u_long)4)
++extern &quot;C&quot; void * mountproc_umntall_1(void *, CLIENT *);
++extern &quot;C&quot; void * mountproc_umntall_1_svc(void *, struct svc_req *);
++#define MOUNTPROC_EXPORT ((u_long)5)
++extern &quot;C&quot; exports * mountproc_export_1(void *, CLIENT *);
++extern &quot;C&quot; exports * mountproc_export_1_svc(void *, struct svc_req *);
++#define MOUNTPROC_EXPORTALL ((u_long)6)
++extern &quot;C&quot; exports * mountproc_exportall_1(void *, CLIENT *);
++extern &quot;C&quot; exports * mountproc_exportall_1_svc(void *, struct svc_req *);
++
++#elif __STDC__
++#define MOUNTPROC_NULL ((u_long)0)
++extern void * mountproc_null_1(void *, CLIENT *);
++extern void * mountproc_null_1_svc(void *, struct svc_req *);
++#define MOUNTPROC_MNT ((u_long)1)
++extern fhstatus * mountproc_mnt_1(dirpath *, CLIENT *);
++extern fhstatus * mountproc_mnt_1_svc(dirpath *, struct svc_req *);
++#define MOUNTPROC_DUMP ((u_long)2)
++extern mountlist * mountproc_dump_1(void *, CLIENT *);
++extern mountlist * mountproc_dump_1_svc(void *, struct svc_req *);
++#define MOUNTPROC_UMNT ((u_long)3)
++extern void * mountproc_umnt_1(dirpath *, CLIENT *);
++extern void * mountproc_umnt_1_svc(dirpath *, struct svc_req *);
++#define MOUNTPROC_UMNTALL ((u_long)4)
++extern void * mountproc_umntall_1(void *, CLIENT *);
++extern void * mountproc_umntall_1_svc(void *, struct svc_req *);
++#define MOUNTPROC_EXPORT ((u_long)5)
++extern exports * mountproc_export_1(void *, CLIENT *);
++extern exports * mountproc_export_1_svc(void *, struct svc_req *);
++#define MOUNTPROC_EXPORTALL ((u_long)6)
++extern exports * mountproc_exportall_1(void *, CLIENT *);
++extern exports * mountproc_exportall_1_svc(void *, struct svc_req *);
++
++#else /* Old Style C */
++#define MOUNTPROC_NULL ((u_long)0)
++extern void * mountproc_null_1();
++extern void * mountproc_null_1_svc();
++#define MOUNTPROC_MNT ((u_long)1)
++extern fhstatus * mountproc_mnt_1();
++extern fhstatus * mountproc_mnt_1_svc();
++#define MOUNTPROC_DUMP ((u_long)2)
++extern mountlist * mountproc_dump_1();
++extern mountlist * mountproc_dump_1_svc();
++#define MOUNTPROC_UMNT ((u_long)3)
++extern void * mountproc_umnt_1();
++extern void * mountproc_umnt_1_svc();
++#define MOUNTPROC_UMNTALL ((u_long)4)
++extern void * mountproc_umntall_1();
++extern void * mountproc_umntall_1_svc();
++#define MOUNTPROC_EXPORT ((u_long)5)
++extern exports * mountproc_export_1();
++extern exports * mountproc_export_1_svc();
++#define MOUNTPROC_EXPORTALL ((u_long)6)
++extern exports * mountproc_exportall_1();
++extern exports * mountproc_exportall_1_svc();
++#endif /* Old Style C */
++
++#endif /* !_MOUNT_H_RPCGEN */
+
+
+Property changes on: drakx/trunk/mdk-stage1/mount_rpcgen.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/network.c
+===================================================================
+--- drakx/trunk/mdk-stage1/network.c (rev 0)
++++ drakx/trunk/mdk-stage1/network.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1209 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Portions from Erik Troan (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ewt at redhat.com</A>)
++ *
++ * Copyright 1996 Red Hat Software
++ *
++ */
++
++#include &quot;stage1.h&quot;
++
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;sys/socket.h&gt;
++#include &lt;net/if.h&gt;
++#include &lt;arpa/inet.h&gt;
++#include &lt;net/route.h&gt;
++#include &lt;sys/ioctl.h&gt;
++#include &lt;sys/mount.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;netdb.h&gt;
++#include &lt;resolv.h&gt;
++#include &lt;sys/utsname.h&gt;
++
++#include &quot;frontend.h&quot;
++#include &quot;modules.h&quot;
++#include &quot;probing.h&quot;
++#include &quot;log.h&quot;
++#include &quot;tools.h&quot;
++#include &quot;utils.h&quot;
++#include &quot;mount.h&quot;
++#include &quot;automatic.h&quot;
++#include &quot;dhcp.h&quot;
++#include &quot;adsl.h&quot;
++#include &quot;url.h&quot;
++#include &quot;dns.h&quot;
++
++#include &quot;network.h&quot;
++#include &quot;directory.h&quot;
++#include &quot;wireless.h&quot;
++
++#ifndef DISABLE_KA
++#include &quot;ka.h&quot;
++#endif
++
++static void error_message_net(void) /* reduce code size */
++{
++ stg1_error_message(&quot;Could not configure network.&quot;);
++}
++
++
++int configure_net_device(struct interface_info * intf)
++{
++ struct ifreq req;
++ struct rtentry route;
++ int s;
++ struct sockaddr_in addr;
++ struct in_addr ia;
++ char ip[20], nm[20], nw[20], bc[20];
++
++ addr.sin_family = AF_INET;
++ addr.sin_port = 0;
++
++ memcpy(&amp;ia, &amp;intf-&gt;ip, sizeof(intf-&gt;ip));
++ strcpy(ip, inet_ntoa(ia));
++
++ memcpy(&amp;ia, &amp;intf-&gt;netmask, sizeof(intf-&gt;netmask));
++ strcpy(nm, inet_ntoa(ia));
++
++ memcpy(&amp;ia, &amp;intf-&gt;broadcast, sizeof(intf-&gt;broadcast));
++ strcpy(bc, inet_ntoa(ia));
++
++ memcpy(&amp;ia, &amp;intf-&gt;network, sizeof(intf-&gt;network));
++ strcpy(nw, inet_ntoa(ia));
++
++ log_message(&quot;configuring device %s ip: %s nm: %s nw: %s bc: %s&quot;, intf-&gt;device, ip, nm, nw, bc);
++
++ if (IS_TESTING)
++ return 0;
++
++ s = socket(AF_INET, SOCK_DGRAM, 0);
++ if (s &lt; 0) {
++ log_perror(&quot;socket&quot;);
++ error_message_net();
++ return 1;
++ }
++
++ strcpy(req.ifr_name, intf-&gt;device);
++
++ if (intf-&gt;is_up == 1) {
++ log_message(&quot;interface already up, downing before reconfigure&quot;);
++
++ req.ifr_flags = 0;
++ if (ioctl(s, SIOCSIFFLAGS, &amp;req)) {
++ close(s);
++ log_perror(&quot;SIOCSIFFLAGS (downing)&quot;);
++ error_message_net();
++ return 1;
++ }
++ }
++
++ /* sets IP address */
++ addr.sin_port = 0;
++ memcpy(&amp;addr.sin_addr, &amp;intf-&gt;ip, sizeof(intf-&gt;ip));
++ memcpy(&amp;req.ifr_addr, &amp;addr, sizeof(addr));
++ if (ioctl(s, SIOCSIFADDR, &amp;req)) {
++ close(s);
++ log_perror(&quot;SIOCSIFADDR&quot;);
++ error_message_net();
++ return 1;
++ }
++
++ /* sets broadcast */
++ memcpy(&amp;addr.sin_addr, &amp;intf-&gt;broadcast, sizeof(intf-&gt;broadcast));
++ memcpy(&amp;req.ifr_broadaddr, &amp;addr, sizeof(addr));
++ if (ioctl(s, SIOCSIFBRDADDR, &amp;req)) {
++ close(s);
++ log_perror(&quot;SIOCSIFBRDADDR&quot;);
++ error_message_net();
++ return 1;
++ }
++
++ /* sets netmask */
++ memcpy(&amp;addr.sin_addr, &amp;intf-&gt;netmask, sizeof(intf-&gt;netmask));
++ memcpy(&amp;req.ifr_netmask, &amp;addr, sizeof(addr));
++ if (ioctl(s, SIOCSIFNETMASK, &amp;req)) {
++ close(s);
++ log_perror(&quot;SIOCSIFNETMASK&quot;);
++ error_message_net();
++ return 1;
++ }
++
++ if (intf-&gt;is_ptp)
++ req.ifr_flags = IFF_UP | IFF_RUNNING | IFF_POINTOPOINT | IFF_NOARP;
++ else
++ req.ifr_flags = IFF_UP | IFF_RUNNING | IFF_BROADCAST;
++
++ /* brings up networking! */
++ if (ioctl(s, SIOCSIFFLAGS, &amp;req)) {
++ close(s);
++ log_perror(&quot;SIOCSIFFLAGS (upping)&quot;);
++ error_message_net();
++ return 1;
++ }
++
++ memset(&amp;route, 0, sizeof(route));
++ route.rt_dev = intf-&gt;device;
++ route.rt_flags = RTF_UP;
++
++ memcpy(&amp;addr.sin_addr, &amp;intf-&gt;network, sizeof(intf-&gt;network));
++ memcpy(&amp;route.rt_dst, &amp;addr, sizeof(addr));
++
++ memcpy(&amp;addr.sin_addr, &amp;intf-&gt;netmask, sizeof(intf-&gt;netmask));
++ memcpy(&amp;route.rt_genmask, &amp;addr, sizeof(addr));
++
++ /* adds route */
++ if (ioctl(s, SIOCADDRT, &amp;route)) {
++ close(s);
++ log_perror(&quot;SIOCADDRT&quot;);
++ error_message_net();
++ return 1;
++ }
++
++ close(s);
++
++ intf-&gt;is_up = 1;
++
++ if (intf-&gt;boot_proto != BOOTPROTO_DHCP &amp;&amp; !streq(intf-&gt;device, &quot;lo&quot;)) {
++ /* I need to sleep a bit in order for kernel to finish
++ init of the network device; if not, first sendto() for
++ gethostbyaddr will get an EINVAL. */
++ wait_message(&quot;Bringing up networking...&quot;);
++ sleep(2);
++ remove_wait_message();
++ }
++
++ return 0;
++}
++
++/* host network informations */
++char * hostname = NULL;
++char * domain = NULL;
++struct in_addr gateway = { 0 };
++struct in_addr dns_server = { 0 };
++struct in_addr dns_server2 = { 0 };
++
++static int add_default_route(void)
++{
++ int s;
++ struct rtentry route;
++ struct sockaddr_in addr;
++
++ if (IS_TESTING)
++ return 0;
++
++ if (gateway.s_addr == 0) {
++ log_message(&quot;no gateway provided, can't add default route&quot;);
++ return 0;
++ }
++
++ s = socket(AF_INET, SOCK_DGRAM, 0);
++ if (s &lt; 0) {
++ close(s);
++ log_perror(&quot;socket&quot;);
++ error_message_net();
++ return 1;
++ }
++
++ memset(&amp;route, 0, sizeof(route));
++
++ addr.sin_family = AF_INET;
++ addr.sin_port = 0;
++ addr.sin_addr = gateway;
++ memcpy(&amp;route.rt_gateway, &amp;addr, sizeof(addr));
++
++ addr.sin_addr.s_addr = INADDR_ANY;
++ memcpy(&amp;route.rt_dst, &amp;addr, sizeof(addr));
++ memcpy(&amp;route.rt_genmask, &amp;addr, sizeof(addr));
++
++ route.rt_flags = RTF_UP | RTF_GATEWAY;
++ route.rt_metric = 0;
++
++ if (ioctl(s, SIOCADDRT, &amp;route)) {
++ close(s);
++ log_perror(&quot;SIOCADDRT&quot;);
++ error_message_net();
++ return 1;
++ }
++
++ close(s);
++
++ return 0;
++}
++
++
++static int write_resolvconf(void)
++{
++ char * filename = &quot;/etc/resolv.conf&quot;;
++ FILE * f;
++
++ if (dns_server.s_addr == 0) {
++ log_message(&quot;resolvconf needs a dns server&quot;);
++ return -1;
++ }
++
++ f = fopen(filename, &quot;w&quot;);
++ if (!f) {
++ log_perror(filename);
++ return -1;
++ }
++
++ if (domain)
++ fprintf(f, &quot;search %s\n&quot;, domain); /* we can live without the domain search (user will have to enter fully-qualified names) */
++ fprintf(f, &quot;nameserver %s\n&quot;, inet_ntoa(dns_server));
++ if (dns_server2.s_addr != 0)
++ fprintf(f, &quot;nameserver %s\n&quot;, inet_ntoa(dns_server2));
++
++ fclose(f);
++ res_init(); /* reinit the resolver so DNS changes take affect */
++
++ return 0;
++}
++
++
++static int save_netinfo(struct interface_info * intf)
++{
++ char * file_network = &quot;/tmp/network&quot;;
++ char file_intf[500];
++ FILE * f;
++
++ f = fopen(file_network, &quot;w&quot;);
++ if (!f) {
++ log_perror(file_network);
++ return -1;
++ }
++
++ fprintf(f, &quot;NETWORKING=yes\n&quot;);
++ fprintf(f, &quot;FORWARD_IPV4=false\n&quot;);
++
++ if (hostname &amp;&amp; !intf-&gt;boot_proto == BOOTPROTO_DHCP)
++ fprintf(f, &quot;HOSTNAME=%s\n&quot;, hostname);
++ if (gateway.s_addr != 0)
++ fprintf(f, &quot;GATEWAY=%s\n&quot;, inet_ntoa(gateway));
++
++ fclose(f);
++
++
++ strcpy(file_intf, &quot;/tmp/ifcfg-&quot;);
++ strcat(file_intf, intf-&gt;device);
++
++ f = fopen(file_intf, &quot;w&quot;);
++ if (!f) {
++ log_perror(file_intf);
++ return -1;
++ }
++
++ fprintf(f, &quot;DEVICE=%s\n&quot;, intf-&gt;device);
++
++ if (intf-&gt;boot_proto == BOOTPROTO_DHCP) {
++ fprintf(f, &quot;BOOTPROTO=dhcp\n&quot;);
++ if (dhcp_hostname &amp;&amp; !streq(dhcp_hostname, &quot;&quot;))
++ fprintf(f, &quot;DHCP_HOSTNAME=%s\n&quot;, dhcp_hostname);
++ } else if (intf-&gt;boot_proto == BOOTPROTO_STATIC) {
++ fprintf(f, &quot;BOOTPROTO=static\n&quot;);
++ fprintf(f, &quot;IPADDR=%s\n&quot;, inet_ntoa(intf-&gt;ip));
++ fprintf(f, &quot;NETMASK=%s\n&quot;, inet_ntoa(intf-&gt;netmask));
++ fprintf(f, &quot;NETWORK=%s\n&quot;, inet_ntoa(intf-&gt;network));
++ fprintf(f, &quot;BROADCAST=%s\n&quot;, inet_ntoa(intf-&gt;broadcast));
++ if (domain)
++ fprintf(f, &quot;DOMAIN=%s\n&quot;, domain);
++ if (dns_server.s_addr != 0)
++ fprintf(f, &quot;DNS1=%s\n&quot;, inet_ntoa(dns_server));
++ if (dns_server2.s_addr != 0)
++ fprintf(f, &quot;DNS2=%s\n&quot;, inet_ntoa(dns_server2));
++ } else if (intf-&gt;boot_proto == BOOTPROTO_ADSL_PPPOE) {
++ fprintf(f, &quot;BOOTPROTO=adsl_pppoe\n&quot;);
++ fprintf(f, &quot;USER=%s\n&quot;, intf-&gt;user);
++ fprintf(f, &quot;PASS=%s\n&quot;, intf-&gt;pass);
++ fprintf(f, &quot;ACNAME=%s\n&quot;, intf-&gt;acname);
++ }
++
++ fclose(f);
++
++ return 0;
++}
++
++
++char * guess_netmask(char * ip_addr)
++{
++ struct in_addr addr;
++ unsigned long int tmp;
++
++ if (streq(ip_addr, &quot;&quot;) || !inet_aton(ip_addr, &amp;addr))
++ return &quot;&quot;;
++
++ log_message(&quot;guessing netmask&quot;);
++
++ tmp = ntohl(addr.s_addr);
++
++ if (((tmp &amp; 0xFF000000) &gt;&gt; 24) &lt;= 127)
++ return &quot;255.0.0.0&quot;;
++ else if (((tmp &amp; 0xFF000000) &gt;&gt; 24) &lt;= 191)
++ return &quot;255.255.0.0&quot;;
++ else
++ return &quot;255.255.255.0&quot;;
++}
++
++
++char * guess_domain_from_hostname(char *hostname)
++{
++ char *domain = strchr(strdup(hostname), '.');
++ if (!domain || domain[1] == '\0') {
++ log_message(&quot;unable to guess domain from hostname: %s&quot;, hostname);
++ return NULL;
++ }
++ return domain + 1; /* skip '.' */
++}
++
++
++static void static_ip_callback(char ** strings)
++{
++ struct in_addr addr;
++
++ static int done = 0;
++ if (done)
++ return;
++ if (streq(strings[0], &quot;&quot;) || !inet_aton(strings[0], &amp;addr))
++ return;
++ done = 1;
++
++ if (!strcmp(strings[1], &quot;&quot;)) {
++ char * ptr;
++ strings[1] = strdup(strings[0]);
++ ptr = strrchr(strings[1], '.');
++ if (ptr)
++ *(ptr+1) = '\0';
++ }
++
++ if (!strcmp(strings[2], &quot;&quot;))
++ strings[2] = strdup(strings[1]);
++
++ if (!strcmp(strings[3], &quot;&quot;))
++ strings[3] = strdup(guess_netmask(strings[0]));
++}
++
++
++static enum return_type setup_network_interface(struct interface_info * intf)
++{
++ enum return_type results;
++ char * bootprotos[] = { &quot;DHCP&quot;, &quot;Static&quot;, &quot;ADSL&quot;, NULL };
++ char * bootprotos_auto[] = { &quot;dhcp&quot;, &quot;static&quot;, &quot;adsl&quot; };
++ char * choice;
++
++ results = ask_from_list_auto(&quot;Please select your network connection type.&quot;, bootprotos, &amp;choice, &quot;network&quot;, bootprotos_auto);
++ if (results != RETURN_OK)
++ return results;
++
++ if (!strcmp(choice, &quot;Static&quot;)) {
++ char * questions[] = { &quot;IP of this machine&quot;, &quot;IP of DNS&quot;, &quot;IP of default gateway&quot;, &quot;Netmask&quot;, NULL };
++ char * questions_auto[] = { &quot;ip&quot;, &quot;dns&quot;, &quot;gateway&quot;, &quot;netmask&quot; };
++ static char ** answers = NULL;
++ struct in_addr addr;
++
++ results = ask_from_entries_auto(&quot;Please enter the network information. (leave netmask blank for Internet standard)&quot;,
++ questions, &amp;answers, 16, questions_auto, static_ip_callback);
++ if (results != RETURN_OK)
++ return setup_network_interface(intf);
++
++ if (streq(answers[0], &quot;&quot;) || !inet_aton(answers[0], &amp;addr)) {
++ stg1_error_message(&quot;Invalid IP address.&quot;);
++ return setup_network_interface(intf);
++ }
++ memcpy(&amp;intf-&gt;ip, &amp;addr, sizeof(addr));
++
++ if (!inet_aton(answers[1], &amp;dns_server)) {
++ log_message(&quot;invalid DNS&quot;);
++ dns_server.s_addr = 0; /* keep an understandable state */
++ }
++
++ if (streq(answers[0], answers[1])) {
++ log_message(&quot;IP and DNS are the same, guess you don't want a DNS, disabling it&quot;);
++ dns_server.s_addr = 0; /* keep an understandable state */
++ }
++
++ if (!inet_aton(answers[2], &amp;gateway)) {
++ log_message(&quot;invalid gateway&quot;);
++ gateway.s_addr = 0; /* keep an understandable state */
++ }
++
++ if ((streq(answers[3], &quot;&quot;) &amp;&amp; inet_aton(guess_netmask(answers[0]), &amp;addr))
++ || inet_aton(answers[3], &amp;addr))
++ memcpy(&amp;intf-&gt;netmask, &amp;addr, sizeof(addr));
++ else {
++ stg1_error_message(&quot;Invalid netmask.&quot;);
++ return setup_network_interface(intf);
++ }
++
++ *((uint32_t *) &amp;intf-&gt;broadcast) = (*((uint32_t *) &amp;intf-&gt;ip) &amp;
++ *((uint32_t *) &amp;intf-&gt;netmask)) | ~(*((uint32_t *) &amp;intf-&gt;netmask));
++
++ inet_aton(&quot;255.255.255.255&quot;, &amp;addr);
++ if (!memcmp(&amp;addr, &amp;intf-&gt;netmask, sizeof(addr))) {
++ log_message(&quot;netmask is 255.255.255.255 -&gt; point to point device&quot;);
++ intf-&gt;network = gateway;
++ intf-&gt;is_ptp = 1;
++ } else {
++ *((uint32_t *) &amp;intf-&gt;network) = *((uint32_t *) &amp;intf-&gt;ip) &amp; *((uint32_t *) &amp;intf-&gt;netmask);
++ intf-&gt;is_ptp = 0;
++ }
++ intf-&gt;boot_proto = BOOTPROTO_STATIC;
++
++ if (configure_net_device(intf))
++ return RETURN_ERROR;
++
++ } else if (streq(choice, &quot;DHCP&quot;)) {
++ results = perform_dhcp(intf);
++
++ if (results == RETURN_BACK)
++ return setup_network_interface(intf);
++ if (results == RETURN_ERROR)
++ return results;
++ intf-&gt;boot_proto = BOOTPROTO_DHCP;
++
++ if (configure_net_device(intf))
++ return RETURN_ERROR;
++
++ } else if (streq(choice, &quot;ADSL&quot;)) {
++ results = perform_adsl(intf);
++
++ if (results == RETURN_BACK)
++ return setup_network_interface(intf);
++ if (results == RETURN_ERROR)
++ return results;
++ } else
++ return RETURN_ERROR;
++
++ return add_default_route();
++}
++
++
++static enum return_type configure_network(struct interface_info * intf)
++{
++ char * dnshostname;
++
++ if (hostname &amp;&amp; domain)
++ return RETURN_OK;
++
++ dnshostname = mygethostbyaddr(inet_ntoa(intf-&gt;ip));
++
++ if (dnshostname) {
++ if (intf-&gt;boot_proto == BOOTPROTO_STATIC)
++ hostname = strdup(dnshostname);
++ domain = guess_domain_from_hostname(dnshostname);
++ if (domain) {
++ log_message(&quot;got hostname and domain from dns entry, %s and %s&quot;, dnshostname, domain);
++ return RETURN_OK;
++ }
++ } else
++ log_message(&quot;reverse name lookup on self failed&quot;);
++
++ if (domain)
++ return RETURN_OK;
++
++ dnshostname = NULL;
++ if (dns_server.s_addr != 0) {
++ wait_message(&quot;Trying to resolve dns...&quot;);
++ dnshostname = mygethostbyaddr(inet_ntoa(dns_server));
++ remove_wait_message();
++ if (dnshostname) {
++ log_message(&quot;got DNS fullname, %s&quot;, dnshostname);
++ domain = guess_domain_from_hostname(dnshostname);
++ } else
++ log_message(&quot;reverse name lookup on DNS failed&quot;);
++ } else
++ log_message(&quot;no DNS, unable to guess domain&quot;);
++
++ if (domain) {
++ log_message(&quot;got domain from DNS fullname, %s&quot;, domain);
++ } else {
++ enum return_type results;
++ char * questions[] = { &quot;Host name&quot;, &quot;Domain name&quot;, NULL };
++ char * questions_auto[] = { &quot;hostname&quot;, &quot;domain&quot; };
++ static char ** answers = NULL;
++ char * boulet;
++
++ if (dhcp_hostname || dhcp_domain) {
++ answers = (char **) malloc(sizeof(questions));
++ answers[0] = strdup(dhcp_hostname);
++ answers[1] = strdup(dhcp_domain);
++ }
++
++ if (!dhcp_hostname || !dhcp_domain) {
++ results = ask_from_entries_auto(&quot;I could not guess hostname and domain name; please fill in this information. &quot;
++ &quot;Valid answers are for example: `mybox' for hostname and `mynetwork.com' for &quot;
++ &quot;domain name, for a machine called `mybox.mynetwork.com' on the Internet.&quot;,
++ questions, &amp;answers, 32, questions_auto, NULL);
++ if (results != RETURN_OK)
++ return results;
++ }
++
++ hostname = answers[0];
++ if ((boulet = strchr(hostname, '.')) != NULL)
++ boulet[0] = '\0';
++ domain = answers[1];
++ }
++
++ log_message(&quot;using hostname %s&quot;, hostname);
++ log_message(&quot;using domain %s&quot;, domain);
++
++ return RETURN_OK;
++}
++
++
++static enum return_type bringup_networking(struct interface_info * intf)
++{
++ static struct interface_info loopback;
++ enum return_type results;
++
++ my_insmod(&quot;af_packet&quot;, ANY_DRIVER_TYPE, NULL, 1);
++
++ do {
++ results = configure_wireless(intf-&gt;device);
++ } while (results == RETURN_ERROR);
++
++ if (results == RETURN_BACK)
++ return RETURN_BACK;
++
++ do {
++ results = setup_network_interface(intf);
++ if (results != RETURN_OK)
++ return results;
++ write_resolvconf();
++ results = configure_network(intf);
++ } while (results == RETURN_ERROR);
++
++ if (results == RETURN_BACK)
++ return bringup_networking(intf);
++
++ write_resolvconf(); /* maybe we have now domain to write also */
++
++ if (loopback.is_up == 0) {
++ int rc;
++ strcpy(loopback.device, &quot;lo&quot;);
++ loopback.is_ptp = 0;
++ loopback.is_up = 0;
++ loopback.ip.s_addr = htonl(0x7f000001);
++ loopback.netmask.s_addr = htonl(0xff000000);
++ loopback.broadcast.s_addr = htonl(0x7fffffff);
++ loopback.network.s_addr = htonl(0x7f000000);
++ rc = configure_net_device(&amp;loopback);
++ if (rc)
++ return RETURN_ERROR;
++ }
++
++ return RETURN_OK;
++}
++
++
++static char * auto_select_up_intf(int detection_mode)
++{
++#define SIOCETHTOOL 0x8946
++#define ETHTOOL_GLINK 0x0000000a /* Get link status (ethtool_value) */
++
++ struct ethtool_value {
++ uint32_t cmd;
++ uint32_t data;
++ };
++
++ char ** interfaces, ** ptr;
++ interfaces = get_net_devices();
++
++ int s;
++ s = socket(AF_INET, SOCK_DGRAM, 0);
++ if (s &lt; 0) {
++ return NULL;
++ }
++
++ ptr = interfaces;
++ while (ptr &amp;&amp; *ptr) {
++ if (detection_mode != AUTO_DETECTION_WIRED || !wireless_is_aware(s, *interfaces)) {
++ struct ifreq ifr;
++ struct ethtool_value edata;
++ strncpy(ifr.ifr_name, *ptr, IFNAMSIZ);
++ edata.cmd = ETHTOOL_GLINK;
++ ifr.ifr_data = (caddr_t)&amp;edata;
++ if (ioctl(s, SIOCETHTOOL, &amp;ifr) == 0 &amp;&amp; edata.data) {
++ close(s);
++ log_message(&quot;NETWORK: choosing interface %s (link beat detected)&quot;, *ptr);
++ return *ptr;
++ }
++ }
++ ptr++;
++ }
++
++ log_message(&quot;NETWORK: no interface has a link beat&quot;);
++
++ if (detection_mode == AUTO_DETECTION_WIRED) {
++ ptr = interfaces;
++ while (ptr &amp;&amp; *ptr) {
++ if (!wireless_is_aware(s, *interfaces)) {
++ close(s);
++ log_message(&quot;NETWORK: choosing interface %s (wired interface)&quot;, *ptr);
++ return *ptr;
++ }
++ ptr++;
++ }
++ log_message(&quot;NETWORK: no interface is wired&quot;);
++ }
++
++ close(s);
++
++ return NULL;
++}
++
++
++static char * interface_select(void)
++{
++ char ** interfaces, ** ptr;
++ char * descriptions[50];
++ char * choice;
++ int i, count = 0;
++ enum return_type results;
++
++ interfaces = get_net_devices();
++
++ ptr = interfaces;
++ while (ptr &amp;&amp; *ptr) {
++ count++;
++ ptr++;
++ }
++
++ if (count == 0) {
++ stg1_error_message(&quot;No NET device found.\n&quot;
++ &quot;Hint: if you're using a Laptop, note that PCMCIA Network adapters are now supported either with `pcmcia.img' or `network.img', please try both these bootdisks.&quot;);
++ i = ask_insmod(NETWORK_DEVICES);
++ if (i == RETURN_BACK)
++ return NULL;
++ return interface_select();
++ }
++
++ if (count == 1)
++ return *interfaces;
++
++ /* this can't be done in ask_from_list_comments_auto because &quot;auto&quot; and &quot;wired&quot; are not in the interfaces list */
++ if (IS_AUTOMATIC) {
++ enum auto_detection_type auto_detect = AUTO_DETECTION_NONE;
++ if (streq(get_auto_value(&quot;interface&quot;), &quot;auto&quot;))
++ auto_detect = AUTO_DETECTION_ALL;
++ else if (streq(get_auto_value(&quot;interface&quot;), &quot;wired&quot;))
++ auto_detect = AUTO_DETECTION_WIRED;
++ if (auto_detect != AUTO_DETECTION_NONE) {
++ choice = auto_select_up_intf(auto_detect);
++ if (choice)
++ return choice;
++ }
++ }
++
++ i = 0;
++ while (interfaces[i]) {
++ descriptions[i] = get_net_intf_description(interfaces[i]);
++ i++;
++ }
++
++ results = ask_from_list_comments_auto(&quot;Please choose the NET device to use for the installation.&quot;,
++ interfaces, descriptions, &amp;choice, &quot;interface&quot;, interfaces);
++
++ if (results != RETURN_OK)
++ return NULL;
++
++ return choice;
++}
++
++static enum return_type get_http_proxy(char **http_proxy_host, char **http_proxy_port)
++{
++ char *questions[] = { &quot;HTTP proxy host&quot;, &quot;HTTP proxy port&quot;, NULL };
++ char *questions_auto[] = { &quot;proxy_host&quot;, &quot;proxy_port&quot;, NULL };
++ static char ** answers = NULL;
++ enum return_type results;
++
++ results = ask_from_entries_auto(&quot;Please enter HTTP proxy host and port if you need it, else leave them blank or cancel.&quot;,
++ questions, &amp;answers, 40, questions_auto, NULL);
++ if (results == RETURN_OK) {
++ *http_proxy_host = answers[0];
++ *http_proxy_port = answers[1];
++ } else {
++ *http_proxy_host = NULL;
++ *http_proxy_port = NULL;
++ }
++
++ return results;
++}
++
++
++static int url_split(const char *url, const char *protocol, char **host, char **path)
++{
++ char *protocol_sep, *host_sep;
++
++ protocol_sep = strstr(url, &quot;://&quot;);
++ if (!protocol_sep) {
++ log_message(&quot;NETWORK: no protocol in \&quot;%s\&quot;&quot;, url);
++ return -1;
++ }
++
++ if (strncmp(protocol, url, protocol_sep - url))
++ return -1;
++
++ url = protocol_sep + 3;
++ host_sep = strchr(url, '/');
++ if (!host_sep || host_sep == url) {
++ log_message(&quot;NETWORK: no hostname in \&quot;%s\&quot;&quot;, url);
++ return -1;
++ }
++
++ *host = strndup(url, host_sep - url);
++ *path = strdup(host_sep);
++
++ return 0;
++}
++
++#define MIRRORLIST_MAX_ITEMS 500
++typedef char *mirrorlist_t[2][MIRRORLIST_MAX_ITEMS+1];
++
++static enum return_type get_mirrorlist(mirrorlist_t mirrorlist, int start, char *version, const char *protocol, char *http_proxy_host, char *http_proxy_port) {
++ int fd, size, line_pos = 0;
++ char path[1024];
++ char line[1024];
++ char type[100] = DISTRIB_TYPE;
++ int mirror_idx = start;
++
++ int use_http_proxy = http_proxy_host &amp;&amp; http_proxy_port &amp;&amp; !streq(http_proxy_host, &quot;&quot;) &amp;&amp; !streq(http_proxy_port, &quot;&quot;);
++ lowercase(type);
++ snprintf(path, sizeof(path), &quot;%s/%s.%s.%s.list&quot;, MIRRORLIST_PATH, type, version, ARCH);
++
++ fd = http_download_file(MIRRORLIST_HOST, path, &amp;size, use_http_proxy ? &quot;http&quot; : NULL, http_proxy_host, http_proxy_port);
++ if (fd &lt; 0) {
++ log_message(&quot;HTTP: unable to get mirrors list from %s (%s)&quot;, MIRRORLIST_HOST, path);
++ return RETURN_ERROR;
++ }
++
++ while (read(fd, line + line_pos, 1) &gt; 0) {
++ if (line[line_pos] == '\n') {
++ char *url;
++ line[line_pos] = '\0';
++ line_pos = 0;
++
++ /* skip medium if it does not look like a distrib path */
++ if (!strstr(line, &quot;,type=distrib,&quot;))
++ continue;
++
++ url = strstr(line, &quot;,url=&quot;);
++ if (!url)
++ continue;
++ url += 5;
++
++ if (url_split(url, protocol, &amp;mirrorlist[0][mirror_idx], &amp;mirrorlist[1][mirror_idx]) &lt; 0)
++ continue;
++
++ mirror_idx++;
++ } else {
++ line_pos++;
++ }
++
++ if (mirror_idx &gt;= MIRRORLIST_MAX_ITEMS)
++ break;
++ }
++ close(fd);
++
++ mirrorlist[0][mirror_idx] = NULL;
++ mirrorlist[1][mirror_idx] = NULL;
++
++ return RETURN_OK;
++}
++
++static int choose_mirror_from_host_list(mirrorlist_t mirrorlist, char **selected_host, char **filepath)
++{
++ enum return_type results;
++ int mirror_idx = 0;
++
++ do {
++ results = ask_from_list_index(&quot;Please select a mirror from the list below.&quot;,
++ mirrorlist[0], NULL, &amp;mirror_idx);
++
++ if (results == RETURN_BACK) {
++ return RETURN_ERROR;
++ } else if (results == RETURN_OK) {
++ if (mirror_idx == 0) {
++ /* enter the mirror manually */
++ return RETURN_OK;
++ }
++ *selected_host = strdup(mirrorlist[0][mirror_idx]);
++ *filepath = strdup(mirrorlist[1][mirror_idx]);
++ return RETURN_OK;
++ }
++ } while (results == RETURN_ERROR);
++
++ return RETURN_ERROR;
++}
++
++
++static int choose_mirror_from_list(char *http_proxy_host, char *http_proxy_port, const char *protocol, char **selected_host, char **filepath)
++{
++ enum return_type results;
++ char *versions[] = { &quot;Specify the mirror manually&quot;, DISTRIB_VERSION, NULL };
++ char *version = DISTRIB_VERSION;
++
++ do {
++ results = ask_from_list(&quot;Please select a medium from the list below.&quot;, versions, &amp;version);
++
++ if (results == RETURN_BACK) {
++ return RETURN_BACK;
++ } else if (results == RETURN_OK) {
++ if (!strcmp(version, versions[0])) {
++ /* enter the mirror manually */
++ return RETURN_OK;
++ } else {
++ /* a medium has been selected */
++ mirrorlist_t mirrorlist;
++ mirrorlist[0][0] = &quot;Specify the mirror manually&quot;;
++ mirrorlist[1][0] = NULL;
++
++ results = get_mirrorlist(mirrorlist, 1, version, protocol, http_proxy_host, http_proxy_port);
++ if (results == RETURN_ERROR)
++ return RETURN_ERROR;
++
++ results = choose_mirror_from_host_list(mirrorlist, selected_host, filepath);
++ }
++ }
++ } while (results == RETURN_ERROR);
++
++ return results;
++}
++
++
++/* -=-=-- */
++
++
++enum return_type intf_select_and_up()
++{
++ static struct interface_info intf[20];
++ static int num_interfaces = 0;
++ struct interface_info * sel_intf = NULL;
++ int i;
++ enum return_type results;
++ char * iface = interface_select();
++
++ if (iface == NULL)
++ return RETURN_BACK;
++
++ for (i = 0; i &lt; num_interfaces ; i++)
++ if (!strcmp(intf[i].device, iface))
++ sel_intf = &amp;(intf[i]);
++
++ if (sel_intf == NULL) {
++ sel_intf = &amp;(intf[num_interfaces]);
++ strcpy(sel_intf-&gt;device, iface);
++ sel_intf-&gt;is_up = 0;
++ num_interfaces++;
++ }
++
++ results = bringup_networking(sel_intf);
++
++ if (results == RETURN_OK)
++ save_netinfo(sel_intf);
++
++ return results;
++}
++
++
++
++enum return_type nfs_prepare(void)
++{
++ char * questions[] = { &quot;NFS server name&quot;, DISTRIB_NAME &quot; directory&quot;, NULL };
++ char * questions_auto[] = { &quot;server&quot;, &quot;directory&quot;, NULL };
++ static char ** answers = NULL;
++ char * nfsmount_location;
++ enum return_type results = intf_select_and_up(NULL, NULL);
++
++ if (results != RETURN_OK)
++ return results;
++
++ do {
++ results = ask_from_entries_auto(&quot;Please enter the name or IP address of your NFS server, &quot;
++ &quot;and the directory containing the &quot; DISTRIB_NAME &quot; Distribution.&quot;,
++ questions, &amp;answers, 40, questions_auto, NULL);
++ if (results != RETURN_OK || streq(answers[0], &quot;&quot;)) {
++ unset_automatic(); /* we are in a fallback mode */
++ return nfs_prepare();
++ }
++
++ nfsmount_location = malloc(strlen(answers[0]) + strlen(answers[1]) + 2);
++ strcpy(nfsmount_location, answers[0]);
++ strcat(nfsmount_location, &quot;:&quot;);
++ strcat(nfsmount_location, answers[1]);
++
++ if (my_mount(nfsmount_location, MEDIA_LOCATION, &quot;nfs&quot;, 0) == -1) {
++ stg1_error_message(&quot;I can't mount the directory from the NFS server.&quot;);
++ results = RETURN_BACK;
++ continue;
++ }
++ free(nfsmount_location); nfsmount_location = NULL;
++
++ results = try_with_directory(MEDIA_LOCATION, &quot;nfs&quot;, &quot;nfs-iso&quot;);
++ if (results != RETURN_OK)
++ umount(MEDIA_LOCATION);
++ if (results == RETURN_ERROR)
++ return RETURN_ERROR;
++ }
++ while (results == RETURN_BACK);
++
++ return RETURN_OK;
++}
++
++
++enum return_type ftp_prepare(void)
++{
++ char * questions[] = { &quot;FTP server&quot;, DISTRIB_NAME &quot; directory&quot;, &quot;Login&quot;, &quot;Password&quot;, NULL };
++ char * questions_auto[] = { &quot;server&quot;, &quot;directory&quot;, &quot;user&quot;, &quot;pass&quot;, NULL };
++ static char ** answers = NULL;
++ enum return_type results;
++ struct utsname kernel_uname;
++ char *http_proxy_host, *http_proxy_port;
++ int use_http_proxy;
++
++ if (!ramdisk_possible()) {
++ stg1_error_message(&quot;FTP install needs more than %d Mbytes of memory (detected %d Mbytes). You may want to try an NFS install.&quot;,
++ MEM_LIMIT_DRAKX, total_memory());
++ return RETURN_ERROR;
++ }
++
++ results = intf_select_and_up();
++
++ if (results != RETURN_OK)
++ return results;
++
++ get_http_proxy(&amp;http_proxy_host, &amp;http_proxy_port);
++ use_http_proxy = http_proxy_host &amp;&amp; http_proxy_port &amp;&amp; !streq(http_proxy_host, &quot;&quot;) &amp;&amp; !streq(http_proxy_port, &quot;&quot;);
++
++ uname(&amp;kernel_uname);
++
++ do {
++ char location_full[500];
++ int ftp_serv_response = -1;
++ int fd, size;
++ char ftp_hostname[500];
++
++ if (!IS_AUTOMATIC) {
++ if (answers == NULL)
++ answers = (char **) malloc(sizeof(questions));
++
++ results = choose_mirror_from_list(http_proxy_host, http_proxy_port, &quot;ftp&quot;, &amp;answers[0], &amp;answers[1]);
++
++ if (results == RETURN_BACK)
++ return ftp_prepare();
++
++ if (use_http_proxy) {
++ results = ask_yes_no(&quot;Do you want to use this HTTP proxy for FTP connections too ?&quot;);
++
++ if (results == RETURN_BACK)
++ return ftp_prepare();
++
++ use_http_proxy = results == RETURN_OK;
++ }
++ }
++
++ results = ask_from_entries_auto(&quot;Please enter the name or IP address of the FTP server, &quot;
++ &quot;the directory containing the &quot; DISTRIB_NAME &quot; Distribution, &quot;
++ &quot;and the login/pass if necessary (leave login blank for anonymous). &quot;,
++ questions, &amp;answers, 40, questions_auto, NULL);
++ if (results != RETURN_OK || streq(answers[0], &quot;&quot;)) {
++ unset_automatic(); /* we are in a fallback mode */
++ return ftp_prepare();
++ }
++
++ strcpy(location_full, answers[1][0] == '/' ? &quot;&quot; : &quot;/&quot;);
++ strcat(location_full, answers[1]);
++
++ if (use_http_proxy) {
++ log_message(&quot;FTP: don't connect to %s directly, will use proxy&quot;, answers[0]);
++ } else {
++ log_message(&quot;FTP: trying to connect to %s&quot;, answers[0]);
++ ftp_serv_response = ftp_open_connection(answers[0], answers[2], answers[3], &quot;&quot;);
++ if (ftp_serv_response &lt; 0) {
++ log_message(&quot;FTP: error connect %d&quot;, ftp_serv_response);
++ if (ftp_serv_response == FTPERR_BAD_HOSTNAME)
++ stg1_error_message(&quot;Error: bad hostname.&quot;);
++ else if (ftp_serv_response == FTPERR_FAILED_CONNECT)
++ stg1_error_message(&quot;Error: failed to connect to remote host.&quot;);
++ else
++ stg1_error_message(&quot;Error: couldn't connect.&quot;);
++ results = RETURN_BACK;
++ continue;
++ }
++ }
++
++ strcat(location_full, COMPRESSED_FILE_REL(&quot;/&quot;));
++
++ log_message(&quot;FTP: trying to retrieve %s&quot;, location_full);
++
++ if (use_http_proxy) {
++ if (strcmp(answers[2], &quot;&quot;)) {
++ strcpy(ftp_hostname, answers[2]); /* user name */
++ strcat(ftp_hostname, &quot;:&quot;);
++ strcat(ftp_hostname, answers[3]); /* password */
++ strcat(ftp_hostname, &quot;@&quot;);
++ } else {
++ strcpy(ftp_hostname, &quot;&quot;);
++ }
++ strcat(ftp_hostname, answers[0]);
++ fd = http_download_file(ftp_hostname, location_full, &amp;size, &quot;ftp&quot;, http_proxy_host, http_proxy_port);
++ } else {
++ fd = ftp_start_download(ftp_serv_response, location_full, &amp;size);
++ }
++
++ if (fd &lt; 0) {
++ char *msg = str_ftp_error(fd);
++ log_message(&quot;FTP: error get %d for remote file %s&quot;, fd, location_full);
++ stg1_error_message(&quot;Error: %s.&quot;, msg ? msg : &quot;couldn't retrieve Installation program&quot;);
++ results = RETURN_BACK;
++ continue;
++ }
++
++ log_message(&quot;FTP: size of download %d bytes&quot;, size);
++
++ results = load_compressed_fd(fd, size);
++ if (results == RETURN_OK) {
++ if (!use_http_proxy)
++ ftp_end_data_command(ftp_serv_response);
++ } else {
++ unset_automatic(); /* we are in a fallback mode */
++ return results;
++ }
++
++ if (use_http_proxy) {
++ add_to_env(&quot;METHOD&quot;, &quot;http&quot;);
++ sprintf(location_full, &quot;<A HREF="ftp://%s%s">ftp://%s%s</A>&quot;, ftp_hostname, answers[1]);
++ add_to_env(&quot;URLPREFIX&quot;, location_full);
++ add_to_env(&quot;PROXY&quot;, http_proxy_host);
++ add_to_env(&quot;PROXYPORT&quot;, http_proxy_port);
++ } else {
++ add_to_env(&quot;METHOD&quot;, &quot;ftp&quot;);
++ add_to_env(&quot;HOST&quot;, answers[0]);
++ add_to_env(&quot;PREFIX&quot;, answers[1]);
++ if (!streq(answers[2], &quot;&quot;)) {
++ add_to_env(&quot;LOGIN&quot;, answers[2]);
++ add_to_env(&quot;PASSWORD&quot;, answers[3]);
++ }
++ }
++ }
++ while (results == RETURN_BACK);
++
++ return RETURN_OK;
++}
++
++enum return_type http_prepare(void)
++{
++ char * questions[] = { &quot;HTTP server&quot;, DISTRIB_NAME &quot; directory&quot;, NULL };
++ char * questions_auto[] = { &quot;server&quot;, &quot;directory&quot;, NULL };
++ static char ** answers = NULL;
++ enum return_type results;
++ char *http_proxy_host, *http_proxy_port;
++
++ if (!ramdisk_possible()) {
++ stg1_error_message(&quot;HTTP install needs more than %d Mbytes of memory (detected %d Mbytes). You may want to try an NFS install.&quot;,
++ MEM_LIMIT_DRAKX, total_memory());
++ return RETURN_ERROR;
++ }
++
++ results = intf_select_and_up();
++
++ if (results != RETURN_OK)
++ return results;
++
++ get_http_proxy(&amp;http_proxy_host, &amp;http_proxy_port);
++
++ do {
++ char location_full[500];
++ int fd, size;
++ int use_http_proxy;
++
++ if (!IS_AUTOMATIC) {
++ if (answers == NULL)
++ answers = (char **) malloc(sizeof(questions));
++
++ results = choose_mirror_from_list(http_proxy_host, http_proxy_port, &quot;http&quot;, &amp;answers[0], &amp;answers[1]);
++
++ if (results == RETURN_BACK)
++ return ftp_prepare();
++ }
++
++ results = ask_from_entries_auto(&quot;Please enter the name or IP address of the HTTP server, &quot;
++ &quot;and the directory containing the &quot; DISTRIB_NAME &quot; Distribution.&quot;,
++ questions, &amp;answers, 40, questions_auto, NULL);
++ if (results != RETURN_OK || streq(answers[0], &quot;&quot;)) {
++ unset_automatic(); /* we are in a fallback mode */
++ return http_prepare();
++ }
++
++ strcpy(location_full, answers[1][0] == '/' ? &quot;&quot; : &quot;/&quot;);
++ strcat(location_full, answers[1]);
++ strcat(location_full, COMPRESSED_FILE_REL(&quot;/&quot;));
++
++ log_message(&quot;HTTP: trying to retrieve %s from %s&quot;, location_full, answers[0]);
++
++ use_http_proxy = http_proxy_host &amp;&amp; http_proxy_port &amp;&amp; !streq(http_proxy_host, &quot;&quot;) &amp;&amp; !streq(http_proxy_port, &quot;&quot;);
++
++ fd = http_download_file(answers[0], location_full, &amp;size, use_http_proxy ? &quot;http&quot; : NULL, http_proxy_host, http_proxy_port);
++ if (fd &lt; 0) {
++ log_message(&quot;HTTP: error %d&quot;, fd);
++ if (fd == FTPERR_FAILED_CONNECT)
++ stg1_error_message(&quot;Error: couldn't connect to server.&quot;);
++ else
++ stg1_error_message(&quot;Error: couldn't get file (%s).&quot;, location_full);
++ results = RETURN_BACK;
++ continue;
++ }
++
++ log_message(&quot;HTTP: size of download %d bytes&quot;, size);
++
++ if (load_compressed_fd(fd, size) != RETURN_OK) {
++ unset_automatic(); /* we are in a fallback mode */
++ return RETURN_ERROR;
++ }
++
++ add_to_env(&quot;METHOD&quot;, &quot;http&quot;);
++ sprintf(location_full, &quot;<A HREF="http://%s%s%s">http://%s%s%s</A>&quot;, answers[0], answers[1][0] == '/' ? &quot;&quot; : &quot;/&quot;, answers[1]);
++ add_to_env(&quot;URLPREFIX&quot;, location_full);
++ if (!streq(http_proxy_host, &quot;&quot;))
++ add_to_env(&quot;PROXY&quot;, http_proxy_host);
++ if (!streq(http_proxy_port, &quot;&quot;))
++ add_to_env(&quot;PROXYPORT&quot;, http_proxy_port);
++ }
++ while (results == RETURN_BACK);
++
++ return RETURN_OK;
++
++}
++
++#ifndef DISABLE_KA
++enum return_type ka_prepare(void)
++{
++ enum return_type results;
++
++ if (!ramdisk_possible()) {
++ stg1_error_message(&quot;KA install needs more than %d Mbytes of memory (detected %d Mbytes).&quot;,
++ MEM_LIMIT_DRAKX, total_memory());
++ return RETURN_ERROR;
++ }
++
++ results = intf_select_and_up();
++
++ if (results != RETURN_OK)
++ return results;
++
++ return perform_ka();
++}
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/network.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/network.h
+===================================================================
+--- drakx/trunk/mdk-stage1/network.h (rev 0)
++++ drakx/trunk/mdk-stage1/network.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,66 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Portions from Erik Troan (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ewt at redhat.com</A>)
++ *
++ * Copyright 1996 Red Hat Software
++ *
++ */
++
++#ifndef _NETWORK_H_
++#define _NETWORK_H_
++
++#include &lt;netinet/in.h&gt;
++#include &lt;netinet/ip.h&gt;
++#include &lt;arpa/inet.h&gt;
++
++enum return_type intf_select_and_up();
++
++enum return_type nfs_prepare(void);
++enum return_type ftp_prepare(void);
++enum return_type http_prepare(void);
++#ifndef DISABLE_KA
++enum return_type ka_prepare(void);
++#endif
++
++
++enum boot_proto_type { BOOTPROTO_STATIC, BOOTPROTO_DHCP, BOOTPROTO_ADSL_PPPOE };
++enum auto_detection_type { AUTO_DETECTION_NONE, AUTO_DETECTION_ALL, AUTO_DETECTION_WIRED };
++
++/* all of these in_addr things are in network byte order! */
++struct interface_info {
++ char device[10];
++ int is_ptp, is_up;
++ struct in_addr ip, netmask, broadcast, network;
++ enum boot_proto_type boot_proto;
++ char *user, *pass, *acname; /* for ADSL connection */
++};
++
++
++/* these are to be used only by dhcp.c */
++
++char * guess_netmask(char * ip_addr);
++
++int configure_net_device(struct interface_info * intf);
++
++extern char * hostname;
++extern char * domain;
++extern struct in_addr gateway;
++extern struct in_addr dns_server;
++extern struct in_addr dns_server2;
++
++
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/network.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/newt/Makefile
+===================================================================
+--- drakx/trunk/mdk-stage1/newt/Makefile (rev 0)
++++ drakx/trunk/mdk-stage1/newt/Makefile 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,42 @@
++ #******************************************************************************
++ #
++ # Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ #
++ # Copyright 2000 Mandriva
++ #
++ # This software may be freely redistributed under the terms of the GNU
++ # public license.
++ #
++ # You should have received a copy of the GNU General Public License
++ # along with this program; if not, write to the Free Software
++ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ #
++ #*****************************************************************************
++
++top_dir = ..
++
++include $(top_dir)/Makefile.common
++
++
++LIBNAME = libnewt
++
++OBJS = newt.o button.o form.o checkbox.o entry.o label.o listbox.o scrollbar.o textbox.o scale.o grid.o windows.o buttonbar.o checkboxtree.o
++
++DEFS = -DVERSION=\&quot;0.50.19\&quot;
++
++INCS = -I../slang
++
++
++TARGETS = $(LIBNAME).a
++
++all: $(TARGETS)
++
++clean:
++ rm -f *.o *.a
++
++$(LIBNAME).a: $(OBJS)
++ ar -cru $@ $^
++ ranlib $@
++
++$(OBJS): %.o: %.c
++ $(DIET) gcc $(CFLAGS) $(DEFS) $(INCS) $(INCLUDES) -c $&lt; -o $@
+
+
+Property changes on: drakx/trunk/mdk-stage1/newt/Makefile
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/newt/button.c
+===================================================================
+--- drakx/trunk/mdk-stage1/newt/button.c (rev 0)
++++ drakx/trunk/mdk-stage1/newt/button.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,192 @@
++#include &lt;slang.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++
++#include &quot;newt.h&quot;
++#include &quot;newt_pr.h&quot;
++
++struct button {
++ char * text;
++ int compact;
++};
++
++static void buttonDrawIt(newtComponent co, int active, int pushed);
++static void buttonDrawText(newtComponent co, int active, int pushed);
++
++static void buttonDraw(newtComponent c);
++static void buttonDestroy(newtComponent co);
++static struct eventResult buttonEvent(newtComponent c,
++ struct event ev);
++static void buttonPlace(newtComponent co, int newLeft, int newTop);
++
++static struct componentOps buttonOps = {
++ buttonDraw,
++ buttonEvent,
++ buttonDestroy,
++ buttonPlace,
++ newtDefaultMappedHandler,
++} ;
++
++static newtComponent createButton(int left, int row, const char * text, int compact) {
++ newtComponent co;
++ struct button * bu;
++
++ co = malloc(sizeof(*co));
++ bu = malloc(sizeof(struct button));
++ co-&gt;data = bu;
++
++ bu-&gt;text = strdup(text);
++ bu-&gt;compact = compact;
++ co-&gt;ops = &amp;buttonOps;
++
++ if (bu-&gt;compact) {
++ co-&gt;height = 1;
++ co-&gt;width = strlen(text) + 3;
++ } else {
++ co-&gt;height = 4;
++ co-&gt;width = strlen(text) + 5;
++ }
++
++ co-&gt;top = row;
++ co-&gt;left = left;
++ co-&gt;takesFocus = 1;
++ co-&gt;isMapped = 0;
++
++ newtGotorc(co-&gt;top, co-&gt;left);
++
++ return co;
++}
++
++newtComponent newtCompactButton(int left, int row, const char * text) {
++ return createButton(left, row, text, 1);
++}
++
++newtComponent newtButton(int left, int row, const char * text) {
++ return createButton(left, row, text, 0);
++}
++
++static void buttonDestroy(newtComponent co) {
++ struct button * bu = co-&gt;data;
++
++ free(bu-&gt;text);
++ free(bu);
++ free(co);
++}
++
++static void buttonPlace(newtComponent co, int newLeft, int newTop) {
++ co-&gt;top = newTop;
++ co-&gt;left = newLeft;
++
++ newtGotorc(co-&gt;top, co-&gt;left);
++}
++
++static void buttonDraw(newtComponent co) {
++ buttonDrawIt(co, 0, 0);
++}
++
++static void buttonDrawIt(newtComponent co, int active, int pushed) {
++ struct button * bu = co-&gt;data;
++
++ if (!co-&gt;isMapped) return;
++
++ SLsmg_set_color(NEWT_COLORSET_BUTTON);
++
++ if (bu-&gt;compact) {
++ if (active)
++ SLsmg_set_color(NEWT_COLORSET_COMPACTBUTTON);
++ else
++ SLsmg_set_color(NEWT_COLORSET_BUTTON);
++ newtGotorc(co-&gt;top+ pushed, co-&gt;left + 1 + pushed);
++ SLsmg_write_char('&lt;');
++ SLsmg_write_string(bu-&gt;text);
++ SLsmg_write_char('&gt;');
++ } else {
++ if (pushed) {
++ SLsmg_set_color(NEWT_COLORSET_BUTTON);
++ newtDrawBox(co-&gt;left + 1, co-&gt;top + 1, co-&gt;width - 1, 3, 0);
++
++ SLsmg_set_color(NEWT_COLORSET_WINDOW);
++ newtClearBox(co-&gt;left, co-&gt;top, co-&gt;width, 1);
++ newtClearBox(co-&gt;left, co-&gt;top, 1, co-&gt;height);
++ } else {
++ newtDrawBox(co-&gt;left, co-&gt;top, co-&gt;width - 1, 3, 1);
++ }
++
++ buttonDrawText(co, active, pushed);
++ }
++}
++
++static void buttonDrawText(newtComponent co, int active, int pushed) {
++ struct button * bu = co-&gt;data;
++
++ if (pushed) pushed = 1;
++
++ if (active)
++ SLsmg_set_color(NEWT_COLORSET_ACTBUTTON);
++ else
++ SLsmg_set_color(NEWT_COLORSET_BUTTON);
++
++ newtGotorc(co-&gt;top + 1 + pushed, co-&gt;left + 1 + pushed);
++ SLsmg_write_char(' ');
++ SLsmg_write_string(bu-&gt;text);
++ SLsmg_write_char(' ');
++}
++
++static struct eventResult buttonEvent(newtComponent co,
++ struct event ev) {
++ struct eventResult er;
++ struct button * bu = co-&gt;data;
++ er.result = ER_IGNORED;
++ er.u.focus = NULL;
++
++ if (ev.when == EV_NORMAL) {
++ switch (ev.event) {
++ case EV_FOCUS:
++ buttonDrawIt(co, 1, 0);
++ er.result = ER_SWALLOWED;
++ break;
++
++ case EV_UNFOCUS:
++ buttonDrawIt(co, 0, 0);
++ er.result = ER_SWALLOWED;
++ break;
++
++ case EV_KEYPRESS:
++ if (ev.u.key == ' ' || ev.u.key == '\r') {
++ if (!bu-&gt;compact) {
++ /* look pushed */
++ buttonDrawIt(co, 1, 1);
++ newtRefresh();
++ newtDelay(150000);
++ buttonDrawIt(co, 1, 0);
++ newtRefresh();
++ newtDelay(150000);
++ }
++
++ er.result = ER_EXITFORM;
++ } else
++ er.result = ER_IGNORED;
++ break;
++ case EV_MOUSE:
++ if (ev.u.mouse.type == MOUSE_BUTTON_DOWN &amp;&amp;
++ co-&gt;top &lt;= ev.u.mouse.y &amp;&amp;
++ co-&gt;top + co-&gt;height - !bu-&gt;compact &gt; ev.u.mouse.y &amp;&amp;
++ co-&gt;left &lt;= ev.u.mouse.x &amp;&amp;
++ co-&gt;left + co-&gt;width - !bu-&gt;compact &gt; ev.u.mouse.x) {
++ if (!bu-&gt;compact) {
++ buttonDrawIt(co, 1, 1);
++ newtRefresh();
++ newtDelay(150000);
++ buttonDrawIt(co, 1, 0);
++ newtRefresh();
++ newtDelay(150000);
++ }
++ er.result = ER_EXITFORM;
++ }
++ break;
++ }
++ } else
++ er.result = ER_IGNORED;
++
++ return er;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/newt/button.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/newt/buttonbar.c
+===================================================================
+--- drakx/trunk/mdk-stage1/newt/buttonbar.c (rev 0)
++++ drakx/trunk/mdk-stage1/newt/buttonbar.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,46 @@
++#include &lt;stdarg.h&gt;
++
++#include &quot;newt.h&quot;
++
++/* if they try and pack more then 50 buttons, screw 'em */
++newtGrid newtButtonBarv(char * button1, newtComponent * b1comp, va_list args) {
++ newtGrid grid;
++ struct buttonInfo {
++ char * name;
++ newtComponent * compPtr;
++ } buttons[50];
++ int num;
++ int i;
++
++ buttons[0].name = button1, buttons[0].compPtr = b1comp, num = 1;
++ while (1) {
++ buttons[num].name = va_arg(args, char *);
++ if (!buttons[num].name) break;
++ buttons[num].compPtr = va_arg(args, newtComponent *);
++ num++;
++ }
++
++ grid = newtCreateGrid(num, 1);
++
++ for (i = 0; i &lt; num; i++) {
++ *buttons[i].compPtr = newtButton(-1, -1, buttons[i].name);
++ newtGridSetField(grid, i, 0, NEWT_GRID_COMPONENT,
++ *buttons[i].compPtr,
++ num ? 1 : 0, 0, 0, 0, 0, 0);
++ }
++
++ return grid;
++}
++
++newtGrid newtButtonBar(char * button1, newtComponent * b1comp, ...) {
++ va_list args;
++ newtGrid grid;
++
++ va_start(args, b1comp);
++
++ grid = newtButtonBarv(button1, b1comp, args);
++
++ va_end(args);
++
++ return grid;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/newt/buttonbar.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/newt/checkbox.c
+===================================================================
+--- drakx/trunk/mdk-stage1/newt/checkbox.c (rev 0)
++++ drakx/trunk/mdk-stage1/newt/checkbox.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,292 @@
++#include &lt;slang.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++
++#include &quot;newt.h&quot;
++#include &quot;newt_pr.h&quot;
++
++enum type { CHECK, RADIO };
++
++struct checkbox {
++ char * text;
++ char * seq;
++ char * result;
++ newtComponent prevButton, lastButton;
++ enum type type;
++ char value;
++ int active, inactive;
++ const void * data;
++ int flags;
++ int hasFocus;
++};
++
++static void makeActive(newtComponent co);
++
++static void cbDraw(newtComponent c);
++static void cbDestroy(newtComponent co);
++struct eventResult cbEvent(newtComponent co, struct event ev);
++
++static struct componentOps cbOps = {
++ cbDraw,
++ cbEvent,
++ cbDestroy,
++ newtDefaultPlaceHandler,
++ newtDefaultMappedHandler,
++} ;
++
++newtComponent newtRadiobutton(int left, int top, const char * text, int isDefault,
++ newtComponent prevButton) {
++ newtComponent co;
++ newtComponent curr;
++ struct checkbox * rb;
++ char initialValue;
++
++ if (isDefault)
++ initialValue = '*';
++ else
++ initialValue = ' ';
++
++ co = newtCheckbox(left, top, text, initialValue, &quot; *&quot;, NULL);
++ rb = co-&gt;data;
++ rb-&gt;type = RADIO;
++
++ rb-&gt;prevButton = prevButton;
++
++ for (curr = co; curr; curr = rb-&gt;prevButton) {
++ rb = curr-&gt;data;
++ rb-&gt;lastButton = co;
++ }
++
++ return co;
++}
++
++newtComponent newtRadioGetCurrent(newtComponent setMember) {
++ struct checkbox * rb = setMember-&gt;data;
++
++ setMember = rb-&gt;lastButton;
++ rb = setMember-&gt;data;
++
++ while (rb &amp;&amp; rb-&gt;value != '*') {
++ setMember = rb-&gt;prevButton;
++ if (!setMember)
++ return NULL;
++ rb = setMember-&gt;data;
++ }
++
++ return setMember;
++}
++
++char newtCheckboxGetValue(newtComponent co) {
++ struct checkbox * cb = co-&gt;data;
++
++ return cb-&gt;value;
++}
++
++void newtCheckboxSetValue(newtComponent co, char value) {
++ struct checkbox * cb = co-&gt;data;
++
++ *cb-&gt;result = value;
++ cbDraw(co);
++}
++
++newtComponent newtCheckbox(int left, int top, const char * text, char defValue,
++ const char * seq, char * result) {
++ newtComponent co;
++ struct checkbox * cb;
++
++ if (!seq) seq = &quot; *&quot;;
++
++ co = malloc(sizeof(*co));
++ cb = malloc(sizeof(struct checkbox));
++ co-&gt;data = cb;
++ cb-&gt;flags = 0;
++ if (result)
++ cb-&gt;result = result;
++ else
++ cb-&gt;result = &amp;cb-&gt;value;
++
++ cb-&gt;text = strdup(text);
++ cb-&gt;seq = strdup(seq);
++ cb-&gt;type = CHECK;
++ cb-&gt;hasFocus = 0;
++ cb-&gt;inactive = COLORSET_CHECKBOX;
++ cb-&gt;active = COLORSET_ACTCHECKBOX;
++ defValue ? (*cb-&gt;result = defValue) : (*cb-&gt;result = cb-&gt;seq[0]);
++
++ co-&gt;ops = &amp;cbOps;
++
++ co-&gt;callback = NULL;
++ co-&gt;height = 1;
++ co-&gt;width = strlen(text) + 4;
++ co-&gt;top = top;
++ co-&gt;left = left;
++ co-&gt;takesFocus = 1;
++
++ return co;
++}
++
++void newtCheckboxSetFlags(newtComponent co, int flags, enum newtFlagsSense sense) {
++ struct checkbox * cb = co-&gt;data;
++ int row, col;
++
++ cb-&gt;flags = newtSetFlags(cb-&gt;flags, flags, sense);
++
++ if (!(cb-&gt;flags &amp; NEWT_FLAG_DISABLED))
++ co-&gt;takesFocus = 1;
++ else
++ co-&gt;takesFocus = 0;
++
++ newtGetrc(&amp;row, &amp;col);
++ cbDraw(co);
++ newtGotorc(row, col);
++}
++
++static void cbDraw(newtComponent c) {
++ struct checkbox * cb = c-&gt;data;
++
++ if (c-&gt;top == -1 || !c-&gt;isMapped) return;
++
++ if (cb-&gt;flags &amp; NEWT_FLAG_DISABLED) {
++ cb-&gt;inactive = NEWT_COLORSET_DISENTRY;
++ cb-&gt;active = NEWT_COLORSET_DISENTRY;
++ } else {
++ cb-&gt;inactive = COLORSET_CHECKBOX;
++ cb-&gt;active = COLORSET_ACTCHECKBOX;
++ }
++
++ SLsmg_set_color(cb-&gt;inactive);
++
++ newtGotorc(c-&gt;top, c-&gt;left);
++
++ switch (cb-&gt;type) {
++ case RADIO:
++ SLsmg_write_string(&quot;( ) &quot;);
++ break;
++
++ case CHECK:
++ SLsmg_write_string(&quot;[ ] &quot;);
++ break;
++
++ default:
++ break;
++ }
++
++ SLsmg_write_string(cb-&gt;text);
++
++ if (cb-&gt;hasFocus)
++ SLsmg_set_color(cb-&gt;active);
++
++ newtGotorc(c-&gt;top, c-&gt;left + 1);
++ SLsmg_write_char(*cb-&gt;result);
++}
++
++static void cbDestroy(newtComponent co) {
++ struct checkbox * cb = co-&gt;data;
++
++ free(cb-&gt;text);
++ free(cb-&gt;seq);
++ free(cb);
++ free(co);
++}
++
++struct eventResult cbEvent(newtComponent co, struct event ev) {
++ struct checkbox * cb = co-&gt;data;
++ struct eventResult er;
++ const char * cur;
++ er.result = ER_IGNORED;
++ er.u.focus = NULL;
++
++ if (ev.when == EV_NORMAL) {
++ switch (ev.event) {
++ case EV_FOCUS:
++ cb-&gt;hasFocus = 1;
++ cbDraw(co);
++ er.result = ER_SWALLOWED;
++ break;
++
++ case EV_UNFOCUS:
++ cb-&gt;hasFocus = 0;
++ cbDraw(co);
++ er.result = ER_SWALLOWED;
++ break;
++
++ case EV_KEYPRESS:
++ if (ev.u.key == ' ') {
++ if (cb-&gt;type == RADIO) {
++ makeActive(co);
++ } else if (cb-&gt;type == CHECK) {
++ cur = strchr(cb-&gt;seq, *cb-&gt;result);
++ if (!cur)
++ *cb-&gt;result = *cb-&gt;seq;
++ else {
++ cur++;
++ if (! *cur)
++ *cb-&gt;result = *cb-&gt;seq;
++ else
++ *cb-&gt;result = *cur;
++ }
++ cbDraw(co);
++ er.result = ER_SWALLOWED;
++
++ if (co-&gt;callback)
++ co-&gt;callback(co, co-&gt;callbackData);
++ } else {
++ er.result = ER_IGNORED;
++ }
++ } else if(ev.u.key == NEWT_KEY_ENTER) {
++ er.result = ER_IGNORED;
++ } else {
++ er.result = ER_IGNORED;
++ }
++ break;
++ case EV_MOUSE:
++ if (ev.u.mouse.type == MOUSE_BUTTON_DOWN) {
++ if (cb-&gt;type == RADIO) {
++ makeActive(co);
++ } else if (cb-&gt;type == CHECK) {
++ cur = strchr(cb-&gt;seq, *cb-&gt;result);
++ if (!cur)
++ *cb-&gt;result = *cb-&gt;seq;
++ else {
++ cur++;
++ if (! *cur)
++ *cb-&gt;result = *cb-&gt;seq;
++ else
++ *cb-&gt;result = *cur;
++ }
++ cbDraw(co);
++ er.result = ER_SWALLOWED;
++
++ if (co-&gt;callback)
++ co-&gt;callback(co, co-&gt;callbackData);
++ }
++ }
++ }
++ } else
++ er.result = ER_IGNORED;
++
++ return er;
++}
++
++static void makeActive(newtComponent co) {
++ struct checkbox * cb = co-&gt;data;
++ struct checkbox * rb;
++ newtComponent curr;
++
++ /* find the one that's turned off */
++ curr = cb-&gt;lastButton;
++ rb = curr-&gt;data;
++ while (curr &amp;&amp; rb-&gt;value == rb-&gt;seq[0]) {
++ curr = rb-&gt;prevButton;
++ if (curr) rb = curr-&gt;data;
++ }
++ if (curr) {
++ rb-&gt;value = rb-&gt;seq[0];
++ cbDraw(curr);
++ }
++ cb-&gt;value = cb-&gt;seq[1];
++ cbDraw(co);
++
++ if (co-&gt;callback)
++ co-&gt;callback(co, co-&gt;callbackData);
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/newt/checkbox.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/newt/checkboxtree.c
+===================================================================
+--- drakx/trunk/mdk-stage1/newt/checkboxtree.c (rev 0)
++++ drakx/trunk/mdk-stage1/newt/checkboxtree.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,714 @@
++#include &lt;slang.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++
++#include &quot;newt.h&quot;
++#include &quot;newt_pr.h&quot;
++
++struct items {
++ char * text;
++ const void *data;
++ unsigned char selected;
++ struct items *next;
++ struct items *prev;
++ struct items *branch;
++ int flags;
++ int depth;
++};
++
++struct CheckboxTree {
++ newtComponent sb;
++ int curWidth; /* size of text w/o scrollbar or border*/
++ int curHeight; /* size of text w/o border */
++ struct items * itemlist;
++ struct items ** flatList, ** currItem, ** firstItem;
++ int flatCount;
++ int flags;
++ int pad;
++ char * seq;
++ char * result;
++};
++
++static void ctDraw(newtComponent c);
++static void ctDestroy(newtComponent co);
++static void ctPlace(newtComponent co, int newLeft, int newTop);
++struct eventResult ctEvent(newtComponent co, struct event ev);
++static void ctMapped(newtComponent co, int isMapped);
++static struct items * findItem(struct items * items, const void * data);
++static void buildFlatList(newtComponent co);
++static void doBuildFlatList(struct CheckboxTree * ct, struct items * item);
++enum countWhat { COUNT_EXPOSED=0, COUNT_SELECTED=1 };
++static int countItems(struct items * item, enum countWhat justExposed);
++
++static struct componentOps ctOps = {
++ ctDraw,
++ ctEvent,
++ ctDestroy,
++ ctPlace,
++ ctMapped,
++} ;
++
++static int countItems(struct items * item, enum countWhat what) {
++ int count = 0;
++
++ while (item) {
++ if ((!item-&gt;branch &amp;&amp; item-&gt;selected == what) || (what == COUNT_EXPOSED))
++ count++;
++ if (item-&gt;branch || (what == COUNT_EXPOSED &amp;&amp; item-&gt;selected))
++ count += countItems(item-&gt;branch, what);
++ item = item-&gt;next;
++ }
++
++ return count;
++}
++
++static void doBuildFlatList(struct CheckboxTree * ct, struct items * item) {
++ while (item) {
++ ct-&gt;flatList[ct-&gt;flatCount++] = item;
++ if (item-&gt;branch &amp;&amp; item-&gt;selected) doBuildFlatList(ct, item-&gt;branch);
++ item = item-&gt;next;
++ }
++}
++
++static void buildFlatList(newtComponent co) {
++ struct CheckboxTree * ct = co-&gt;data;
++
++ if (ct-&gt;flatList) free(ct-&gt;flatList);
++ ct-&gt;flatCount = countItems(ct-&gt;itemlist, COUNT_EXPOSED);
++
++ ct-&gt;flatList = malloc(sizeof(*ct-&gt;flatList) * (ct-&gt;flatCount+1));
++ ct-&gt;flatCount = 0;
++ doBuildFlatList(ct, ct-&gt;itemlist);
++ ct-&gt;flatList[ct-&gt;flatCount] = NULL;
++}
++
++int newtCheckboxTreeAddItem(newtComponent co,
++ const char * text, const void * data,
++ int flags, int index, ...) {
++ va_list argList;
++ int numIndexes;
++ int * indexes;
++ int i;
++
++ va_start(argList, index);
++ numIndexes = 0;
++ i = index;
++ while (i != NEWT_ARG_LAST) {
++ numIndexes++;
++ i = va_arg(argList, int);
++ }
++
++ va_end(argList);
++
++ indexes = alloca(sizeof(*indexes) * (numIndexes + 1));
++ va_start(argList, index);
++ numIndexes = 0;
++ i = index;
++ va_start(argList, index);
++ while (i != NEWT_ARG_LAST) {
++ indexes[numIndexes++] = i;
++ i = va_arg(argList, int);
++ }
++ va_end(argList);
++
++ indexes[numIndexes++] = NEWT_ARG_LAST;
++
++ return newtCheckboxTreeAddArray(co, text, data, flags, indexes);
++}
++
++static int doFindItemPath(struct items * items, void * data, int * path,
++ int * len) {
++ int where = 0;
++
++ while (items) {
++ if (items-&gt;data == data) {
++ if (path) path[items-&gt;depth] = where;
++ if (len) *len = items-&gt;depth + 1;
++ return 1;
++ }
++
++ if (items-&gt;branch &amp;&amp; doFindItemPath(items-&gt;branch, data, path, len)) {
++ if (path) path[items-&gt;depth] = where;
++ return 1;
++ }
++
++ items = items-&gt;next;
++ where++;
++ }
++
++ return 0;
++}
++
++int * newtCheckboxTreeFindItem(newtComponent co, void * data) {
++ int len;
++ int * path;
++ struct CheckboxTree * ct = co-&gt;data;
++
++ if (!doFindItemPath(ct-&gt;itemlist, data, NULL, &amp;len)) return NULL;
++
++ path = malloc(sizeof(*path) * (len + 1));
++ doFindItemPath(ct-&gt;itemlist, data, path, NULL);
++ path[len] = NEWT_ARG_LAST;
++
++ return path;
++}
++
++int newtCheckboxTreeAddArray(newtComponent co,
++ const char * text, const void * data,
++ int flags, int * indexes) {
++ struct items * curList, * newNode, * item = NULL;
++ struct items ** listPtr = NULL;
++ int i, index, numIndexes;
++ struct CheckboxTree * ct = co-&gt;data;
++
++ numIndexes = 0;
++ while (indexes[numIndexes] != NEWT_ARG_LAST) numIndexes++;
++
++ if (!ct-&gt;itemlist) {
++ if (numIndexes &gt; 1) return -1;
++
++ ct-&gt;itemlist = malloc(sizeof(*ct-&gt;itemlist));
++ item = ct-&gt;itemlist;
++ item-&gt;prev = NULL;
++ item-&gt;next = NULL;
++ } else {
++ curList = ct-&gt;itemlist;
++ listPtr = &amp;ct-&gt;itemlist;
++
++ i = 0;
++ index = indexes[i];
++ while (i &lt; numIndexes) {
++ item = curList;
++
++ if (index == NEWT_ARG_APPEND) {
++ item = NULL;
++ } else {
++ while (index &amp;&amp; item)
++ item = item-&gt;next, index--;
++ }
++
++ i++;
++ if (i &lt; numIndexes) {
++ curList = item-&gt;branch;
++ listPtr = &amp;item-&gt;branch;
++ if (!curList &amp;&amp; (i + 1 != numIndexes)) return -1;
++
++ index = indexes[i];
++ }
++ }
++
++ if (!curList) { /* create a new branch */
++ item = malloc(sizeof(*curList-&gt;prev));
++ item-&gt;next = item-&gt;prev = NULL;
++ *listPtr = item;
++ } else if (!item) { /* append to end */
++ item = curList;
++ while (item-&gt;next) item = item-&gt;next;
++ item-&gt;next = malloc(sizeof(*curList-&gt;prev));
++ item-&gt;next-&gt;prev = item;
++ item = item-&gt;next;
++ item-&gt;next = NULL;
++ } else {
++ newNode = malloc(sizeof(*newNode));
++ newNode-&gt;prev = item-&gt;prev;
++ newNode-&gt;next = item;
++
++ if (item-&gt;prev) item-&gt;prev-&gt;next = newNode;
++ item-&gt;prev = newNode;
++ item = newNode;
++ if (!item-&gt;prev) *listPtr = item;
++ }
++ }
++
++ item-&gt;text = strdup(text);
++ item-&gt;data = data;
++ if (flags &amp; NEWT_FLAG_SELECTED) {
++ item-&gt;selected = 1;
++ } else {
++ item-&gt;selected = 0;
++ }
++ item-&gt;flags = flags;
++ item-&gt;branch = NULL;
++ item-&gt;depth = numIndexes - 1;
++
++ i = 4 + (3 * item-&gt;depth);
++
++ if ((strlen(text) + i + ct-&gt;pad) &gt; (size_t)co-&gt;width) {
++ co-&gt;width = strlen(text) + i + ct-&gt;pad;
++ }
++
++ return 0;
++}
++
++static struct items * findItem(struct items * items, const void * data) {
++ struct items * i;
++
++ while (items) {
++ if (items-&gt;data == data) return items;
++ if (items-&gt;branch) {
++ i = findItem(items-&gt;branch, data);
++ if (i) return i;
++ }
++
++ items = items-&gt;next;
++ }
++
++ return NULL;
++}
++
++static void listSelected(struct items * items, int * num, const void ** list, int seqindex) {
++ while (items) {
++ if ((seqindex ? items-&gt;selected==seqindex : items-&gt;selected) &amp;&amp; !items-&gt;branch)
++ list[(*num)++] = (void *) items-&gt;data;
++ if (items-&gt;branch)
++ listSelected(items-&gt;branch, num, list, seqindex);
++ items = items-&gt;next;
++ }
++}
++
++const void ** newtCheckboxTreeGetSelection(newtComponent co, int *numitems)
++{
++ return newtCheckboxTreeGetMultiSelection(co, numitems, 0);
++}
++
++const void ** newtCheckboxTreeGetMultiSelection(newtComponent co, int *numitems, char seqnum)
++{
++ struct CheckboxTree * ct;
++ const void **retval;
++ int seqindex=0;
++
++ if(!co || !numitems) return NULL;
++
++ ct = co-&gt;data;
++
++ if (seqnum) {
++ while( ct-&gt;seq[seqindex] &amp;&amp; ( ct-&gt;seq[seqindex] != seqnum )) seqindex++;
++ } else {
++ seqindex = 0;
++ }
++
++ *numitems = countItems(ct-&gt;itemlist, (seqindex ? seqindex : COUNT_SELECTED));
++ if (!*numitems) return NULL;
++
++ retval = malloc(*numitems * sizeof(void *));
++ *numitems = 0;
++ listSelected(ct-&gt;itemlist, numitems, retval, seqindex);
++
++ return retval;
++}
++
++newtComponent newtCheckboxTree(int left, int top, int height, int flags) {
++ return newtCheckboxTreeMulti(left, top, height, NULL, flags);
++}
++
++newtComponent newtCheckboxTreeMulti(int left, int top, int height, char *seq, int flags) {
++ newtComponent co;
++ struct CheckboxTree * ct;
++
++ co = malloc(sizeof(*co));
++ ct = malloc(sizeof(struct CheckboxTree));
++ co-&gt;callback = NULL;
++ co-&gt;data = ct;
++ co-&gt;ops = &amp;ctOps;
++ co-&gt;takesFocus = 1;
++ co-&gt;height = height;
++ co-&gt;width = 0;
++ co-&gt;isMapped = 0;
++ ct-&gt;itemlist = NULL;
++ ct-&gt;firstItem = NULL;
++ ct-&gt;currItem = NULL;
++ ct-&gt;flatList = NULL;
++ if (seq)
++ ct-&gt;seq = strdup(seq);
++ else
++ ct-&gt;seq = strdup(&quot; *&quot;);
++ if (flags &amp; NEWT_FLAG_SCROLL) {
++ ct-&gt;sb = newtVerticalScrollbar(left, top, height,
++ COLORSET_LISTBOX, COLORSET_ACTLISTBOX);
++ ct-&gt;pad = 2;
++ } else {
++ ct-&gt;sb = NULL;
++ ct-&gt;pad = 0;
++ }
++
++ return co;
++}
++
++static void ctMapped(newtComponent co, int isMapped) {
++ struct CheckboxTree * ct = co-&gt;data;
++
++ co-&gt;isMapped = isMapped;
++ if (ct-&gt;sb)
++ ct-&gt;sb-&gt;ops-&gt;mapped(ct-&gt;sb, isMapped);
++}
++
++static void ctPlace(newtComponent co, int newLeft, int newTop) {
++ struct CheckboxTree * ct = co-&gt;data;
++
++ co-&gt;top = newTop;
++ co-&gt;left = newLeft;
++
++ if (ct-&gt;sb)
++ ct-&gt;sb-&gt;ops-&gt;place(ct-&gt;sb, co-&gt;left + co-&gt;width - 1, co-&gt;top);
++}
++
++int ctSetItem(newtComponent co, struct items *item, enum newtFlagsSense sense)
++{
++ struct CheckboxTree * ct = co-&gt;data;
++ struct items * currItem;
++ struct items * firstItem;
++
++ if (!item)
++ return 1;
++
++ switch(sense) {
++ case NEWT_FLAGS_RESET:
++ item-&gt;selected = 0;
++ break;
++ case NEWT_FLAGS_SET:
++ item-&gt;selected = 1;
++ break;
++ case NEWT_FLAGS_TOGGLE:
++ if (item-&gt;branch)
++ item-&gt;selected = !item-&gt;selected;
++ else {
++ item-&gt;selected++;
++ if (item-&gt;selected==strlen(ct-&gt;seq))
++ item-&gt;selected = 0;
++ }
++ break;
++ }
++
++ if (item-&gt;branch) {
++ currItem = *ct-&gt;currItem;
++ firstItem = *ct-&gt;firstItem;
++
++ buildFlatList(co);
++
++ ct-&gt;currItem = ct-&gt;flatList;
++ while (*ct-&gt;currItem != currItem) ct-&gt;currItem++;
++
++ ct-&gt;firstItem = ct-&gt;flatList;
++ if (ct-&gt;flatCount &gt; co-&gt;height) {
++ struct items ** last = ct-&gt;flatList + ct-&gt;flatCount - co-&gt;height;
++ while (*ct-&gt;firstItem != firstItem &amp;&amp; ct-&gt;firstItem != last)
++ ct-&gt;firstItem++;
++ }
++ }
++
++ return 0;
++}
++
++static void ctSetItems(struct items *item, int selected)
++{
++ for (; item; item = item-&gt;next) {
++ if (!item-&gt;branch)
++ item-&gt;selected = selected;
++ else
++ ctSetItems(item-&gt;branch, selected);
++ }
++}
++
++static void ctDraw(newtComponent co) {
++ struct CheckboxTree * ct = co-&gt;data;
++ struct items ** item;
++ int i, j;
++ char * spaces = NULL;
++ int currRow = -1;
++
++ if (!co-&gt;isMapped) return ;
++
++ if (!ct-&gt;firstItem) {
++ buildFlatList(co);
++ ct-&gt;firstItem = ct-&gt;currItem = ct-&gt;flatList;
++ }
++
++ item = ct-&gt;firstItem;
++
++ i = 0;
++ while (*item &amp;&amp; i &lt; co-&gt;height) {
++ newtGotorc(co-&gt;top + i, co-&gt;left);
++ if (*item == *ct-&gt;currItem) {
++ SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX);
++ currRow = co-&gt;top + i;
++ } else
++ SLsmg_set_color(NEWT_COLORSET_LISTBOX);
++
++ for (j = 0; j &lt; (*item)-&gt;depth; j++)
++ SLsmg_write_string(&quot; &quot;);
++
++ if ((*item)-&gt;branch) {
++ if ((*item)-&gt;selected)
++ SLsmg_write_string(&quot;&lt;-&gt; &quot;);
++ else
++ SLsmg_write_string(&quot;&lt;+&gt; &quot;);
++ } else {
++ char tmp[5];
++ snprintf(tmp,5,&quot;[%c] &quot;,ct-&gt;seq[(*item)-&gt;selected]);
++ SLsmg_write_string(tmp);
++ }
++
++ SLsmg_write_nstring((*item)-&gt;text, co-&gt;width - 4 -
++ (3 * (*item)-&gt;depth));
++ item++;
++ i++;
++ }
++
++ /* There could be empty lines left (i.e. if the user closes an expanded
++ list which is the last thing in the tree, and whose elements are
++ displayed at the bottom of the screen */
++ if (i &lt; co-&gt;height) {
++ spaces = alloca(co-&gt;width);
++ memset(spaces, ' ', co-&gt;width);
++ SLsmg_set_color(NEWT_COLORSET_LISTBOX);
++ }
++ while (i &lt; co-&gt;height) {
++ newtGotorc(co-&gt;top + i, co-&gt;left);
++ SLsmg_write_nstring(spaces, co-&gt;width);
++ i++;
++ }
++
++ if(ct-&gt;sb) {
++ newtScrollbarSet(ct-&gt;sb, ct-&gt;currItem - ct-&gt;flatList,
++ ct-&gt;flatCount - 1);
++ ct-&gt;sb-&gt;ops-&gt;draw(ct-&gt;sb);
++ }
++
++ newtGotorc(currRow, co-&gt;left + 1);
++}
++
++static void ctDestroy(newtComponent co) {
++ struct CheckboxTree * ct = co-&gt;data;
++ struct items * item, * nextitem;
++
++ nextitem = item = ct-&gt;itemlist;
++
++ while (item != NULL) {
++ nextitem = item-&gt;next;
++ free(item-&gt;text);
++ free(item);
++ item = nextitem;
++ }
++
++ free(ct-&gt;seq);
++ free(ct);
++ free(co);
++}
++
++struct eventResult ctEvent(newtComponent co, struct event ev) {
++ struct CheckboxTree * ct = co-&gt;data;
++ struct eventResult er;
++ struct items ** listEnd, ** lastItem;
++ int key, selnum = 1;
++
++ er.result = ER_IGNORED;
++
++ if(ev.when == EV_EARLY || ev.when == EV_LATE) {
++ return er;
++ }
++
++ switch(ev.event) {
++ case EV_KEYPRESS:
++ key = ev.u.key;
++ if (key == (char) key &amp;&amp; key != ' ') {
++ for (selnum = 0; ct-&gt;seq[selnum]; selnum++)
++ if (key == ct-&gt;seq[selnum])
++ break;
++ if (!ct-&gt;seq[selnum])
++ switch (key) {
++ case '-': selnum = 0; break;
++ case '+':
++ case '*': selnum = 1; break;
++ }
++ if (ct-&gt;seq[selnum])
++ key = '*';
++ }
++ switch(key) {
++ case ' ':
++ case NEWT_KEY_ENTER:
++ ctSetItem(co, *ct-&gt;currItem, NEWT_FLAGS_TOGGLE);
++ er.result = ER_SWALLOWED;
++ if (!(*ct-&gt;currItem)-&gt;branch || (*ct-&gt;currItem)-&gt;selected)
++ key = NEWT_KEY_DOWN;
++ else
++ key = '*';
++ break;
++ case '*':
++ if ((*ct-&gt;currItem)-&gt;branch) {
++ ctSetItems((*ct-&gt;currItem)-&gt;branch, selnum);
++ if (!(*ct-&gt;currItem)-&gt;selected)
++ key = NEWT_KEY_DOWN;
++ } else {
++ (*ct-&gt;currItem)-&gt;selected = selnum;
++ key = NEWT_KEY_DOWN;
++ }
++ er.result = ER_SWALLOWED;
++ break;
++ }
++ switch (key) {
++ case '*':
++ ctDraw(co);
++ if(co-&gt;callback) co-&gt;callback(co, co-&gt;callbackData);
++ return er;
++ case NEWT_KEY_HOME:
++ ct-&gt;currItem = ct-&gt;flatList;
++ ct-&gt;firstItem = ct-&gt;flatList;
++ ctDraw(co);
++ if(co-&gt;callback) co-&gt;callback(co, co-&gt;callbackData);
++ er.result = ER_SWALLOWED;
++ return er;
++ case NEWT_KEY_END:
++ ct-&gt;currItem = ct-&gt;flatList + ct-&gt;flatCount - 1;
++ if (ct-&gt;flatCount &lt;= co-&gt;height)
++ ct-&gt;firstItem = ct-&gt;flatList;
++ else
++ ct-&gt;firstItem = ct-&gt;flatList + ct-&gt;flatCount - co-&gt;height;
++ ctDraw(co);
++ if(co-&gt;callback) co-&gt;callback(co, co-&gt;callbackData);
++ er.result = ER_SWALLOWED;
++ return er;
++ case NEWT_KEY_DOWN:
++ if (ev.u.key != NEWT_KEY_DOWN) {
++ if(co-&gt;callback) co-&gt;callback(co, co-&gt;callbackData);
++ if (strlen(ct-&gt;seq) != 2) {
++ ctDraw(co);
++ return er;
++ }
++ }
++ if ((ct-&gt;currItem - ct-&gt;flatList + 1) &lt; ct-&gt;flatCount) {
++ ct-&gt;currItem++;
++
++ if (ct-&gt;currItem - ct-&gt;firstItem &gt;= co-&gt;height)
++ ct-&gt;firstItem++;
++
++ ctDraw(co);
++ } else if (ev.u.key != NEWT_KEY_DOWN)
++ ctDraw(co);
++ if(co-&gt;callback) co-&gt;callback(co, co-&gt;callbackData);
++ er.result = ER_SWALLOWED;
++ return er;
++ case NEWT_KEY_UP:
++ if (ct-&gt;currItem != ct-&gt;flatList) {
++ ct-&gt;currItem--;
++
++ if (ct-&gt;currItem &lt; ct-&gt;firstItem)
++ ct-&gt;firstItem = ct-&gt;currItem;
++
++ ctDraw(co);
++ }
++ er.result = ER_SWALLOWED;
++ if(co-&gt;callback) co-&gt;callback(co, co-&gt;callbackData);
++ return er;
++ case NEWT_KEY_PGUP:
++ if (ct-&gt;firstItem - co-&gt;height &lt; ct-&gt;flatList) {
++ ct-&gt;firstItem = ct-&gt;currItem = ct-&gt;flatList;
++ } else {
++ ct-&gt;currItem -= co-&gt;height;
++ ct-&gt;firstItem -= co-&gt;height;
++ }
++
++ ctDraw(co);
++ if(co-&gt;callback) co-&gt;callback(co, co-&gt;callbackData);
++ er.result = ER_SWALLOWED;
++ return er;
++ case NEWT_KEY_PGDN:
++ listEnd = ct-&gt;flatList + ct-&gt;flatCount - 1;
++ lastItem = ct-&gt;firstItem + co-&gt;height - 1;
++
++ if (lastItem + co-&gt;height &gt; listEnd) {
++ ct-&gt;firstItem = listEnd - co-&gt;height + 1;
++ ct-&gt;currItem = listEnd;
++ } else {
++ ct-&gt;currItem += co-&gt;height;
++ ct-&gt;firstItem += co-&gt;height;
++ }
++
++ ctDraw(co);
++ if(co-&gt;callback) co-&gt;callback(co, co-&gt;callbackData);
++ er.result = ER_SWALLOWED;
++ return er;
++ }
++ break;
++
++ case EV_FOCUS:
++ ctDraw(co);
++ er.result = ER_SWALLOWED;
++ break;
++
++ case EV_UNFOCUS:
++ ctDraw(co);
++ er.result = ER_SWALLOWED;
++ break;
++ default:
++ break;
++ }
++
++ return er;
++}
++
++const void * newtCheckboxTreeGetCurrent(newtComponent co) {
++ struct CheckboxTree * ct = co-&gt;data;
++
++ if (!ct-&gt;currItem) return NULL;
++ return (*ct-&gt;currItem)-&gt;data;
++}
++
++void newtCheckboxTreeSetEntry(newtComponent co, const void * data, const char * text)
++{
++ struct CheckboxTree * ct;
++ struct items * item;
++ int i;
++
++ if (!co) return;
++ ct = co-&gt;data;
++ item = findItem(ct-&gt;itemlist, data);
++ if (!item) return;
++
++ free(item-&gt;text);
++ item-&gt;text = strdup(text);
++
++ i = 4 + (3 * item-&gt;depth);
++
++ if ((strlen(text) + i + ct-&gt;pad) &gt; (size_t)co-&gt;width) {
++ co-&gt;width = strlen(text) + i + ct-&gt;pad;
++ }
++
++ ctDraw(co);
++}
++
++char newtCheckboxTreeGetEntryValue(newtComponent co, const void * data)
++{
++ struct CheckboxTree * ct;
++ struct items * item;
++
++ if (!co) return -1;
++ ct = co-&gt;data;
++ item = findItem(ct-&gt;itemlist, data);
++ if (!item) return -1;
++ if (item-&gt;branch)
++ return item-&gt;selected ? NEWT_CHECKBOXTREE_EXPANDED : NEWT_CHECKBOXTREE_COLLAPSED;
++ else
++ return ct-&gt;seq[item-&gt;selected];
++}
++
++void newtCheckboxTreeSetEntryValue(newtComponent co, const void * data, char value)
++{
++ struct CheckboxTree * ct;
++ struct items * item;
++ int i;
++
++ if (!co) return;
++ ct = co-&gt;data;
++ item = findItem(ct-&gt;itemlist, data);
++ if (!item || item-&gt;branch) return;
++
++ for(i = 0; ct-&gt;seq[i]; i++)
++ if (value == ct-&gt;seq[i])
++ break;
++
++ if (!ct-&gt;seq[i]) return;
++ item-&gt;selected = i;
++
++ ctDraw(co);
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/newt/checkboxtree.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/newt/entry.c
+===================================================================
+--- drakx/trunk/mdk-stage1/newt/entry.c (rev 0)
++++ drakx/trunk/mdk-stage1/newt/entry.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,378 @@
++#include &lt;ctype.h&gt;
++#include &lt;slang.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++
++#include &quot;newt.h&quot;
++#include &quot;newt_pr.h&quot;
++
++struct entry {
++ int flags;
++ char * buf;
++ char ** resultPtr;
++ int bufAlloced;
++ int bufUsed; /* amount of the buffer that's been used */
++ int cursorPosition; /* cursor *in the string* on on screen */
++ int firstChar; /* first character position being shown */
++ newtEntryFilter filter;
++ void * filterData;
++};
++
++static void entryDraw(newtComponent co);
++static void entryDestroy(newtComponent co);
++static struct eventResult entryEvent(newtComponent co,
++ struct event ev);
++
++static struct eventResult entryHandleKey(newtComponent co, int key);
++
++static struct componentOps entryOps = {
++ entryDraw,
++ entryEvent,
++ entryDestroy,
++ newtDefaultPlaceHandler,
++ newtDefaultMappedHandler,
++} ;
++
++void newtEntrySet(newtComponent co, const char * value, int cursorAtEnd) {
++ struct entry * en = co-&gt;data;
++
++ if ((strlen(value) + 1) &gt; (unsigned int)en-&gt;bufAlloced) {
++ free(en-&gt;buf);
++ en-&gt;bufAlloced = strlen(value) + 1;
++ en-&gt;buf = malloc(en-&gt;bufAlloced);
++ if (en-&gt;resultPtr) *en-&gt;resultPtr = en-&gt;buf;
++ }
++ memset(en-&gt;buf, 0, en-&gt;bufAlloced); /* clear the buffer */
++ strcpy(en-&gt;buf, value);
++ en-&gt;bufUsed = strlen(value);
++ en-&gt;firstChar = 0;
++ if (cursorAtEnd)
++ en-&gt;cursorPosition = en-&gt;bufUsed;
++ else
++ en-&gt;cursorPosition = 0;
++
++ entryDraw(co);
++} ;
++
++newtComponent newtEntry(int left, int top, const char * initialValue, int width,
++ char ** resultPtr, int flags) {
++ newtComponent co;
++ struct entry * en;
++
++ co = malloc(sizeof(*co));
++ en = malloc(sizeof(struct entry));
++ co-&gt;data = en;
++
++ co-&gt;top = top;
++ co-&gt;left = left;
++ co-&gt;height = 1;
++ co-&gt;width = width;
++ co-&gt;isMapped = 0;
++ co-&gt;callback = NULL;
++
++ co-&gt;ops = &amp;entryOps;
++
++ en-&gt;flags = flags;
++ en-&gt;cursorPosition = 0;
++ en-&gt;firstChar = 0;
++ en-&gt;bufUsed = 0;
++ en-&gt;bufAlloced = width + 1;
++ en-&gt;filter = NULL;
++
++ if (!(en-&gt;flags &amp; NEWT_FLAG_DISABLED))
++ co-&gt;takesFocus = 1;
++ else
++ co-&gt;takesFocus = 0;
++
++ if (initialValue &amp;&amp; strlen(initialValue) &gt; (unsigned int)width) {
++ en-&gt;bufAlloced = strlen(initialValue) + 1;
++ }
++ en-&gt;buf = malloc(en-&gt;bufAlloced);
++ en-&gt;resultPtr = resultPtr;
++ if (en-&gt;resultPtr) *en-&gt;resultPtr = en-&gt;buf;
++
++ memset(en-&gt;buf, 0, en-&gt;bufAlloced);
++ if (initialValue) {
++ strcpy(en-&gt;buf, initialValue);
++ en-&gt;bufUsed = strlen(initialValue);
++ en-&gt;cursorPosition = en-&gt;bufUsed;
++ } else {
++ *en-&gt;buf = '\0';
++ en-&gt;bufUsed = 0;
++ en-&gt;cursorPosition = 0;
++ }
++
++ return co;
++}
++
++static void entryDraw(newtComponent co) {
++ struct entry * en = co-&gt;data;
++ int i;
++ char * chptr;
++ int len;
++
++ if (!co-&gt;isMapped) return;
++
++ if (en-&gt;flags &amp; NEWT_FLAG_DISABLED)
++ SLsmg_set_color(NEWT_COLORSET_DISENTRY);
++ else
++ SLsmg_set_color(NEWT_COLORSET_ENTRY);
++
++ if (en-&gt;flags &amp; NEWT_FLAG_HIDDEN) {
++ newtGotorc(co-&gt;top, co-&gt;left);
++ for (i = 0; i &lt; co-&gt;width; i++)
++ SLsmg_write_char('_');
++ newtGotorc(co-&gt;top, co-&gt;left);
++
++ return;
++ }
++
++ newtGotorc(co-&gt;top, co-&gt;left);
++
++ if (en-&gt;cursorPosition &lt; en-&gt;firstChar) {
++ /* scroll to the left */
++ en-&gt;firstChar = en-&gt;cursorPosition;
++ } else if ((en-&gt;firstChar + co-&gt;width) &lt;= en-&gt;cursorPosition) {
++ /* scroll to the right */
++ en-&gt;firstChar = en-&gt;cursorPosition - co-&gt;width + 1;
++ }
++
++ chptr = en-&gt;buf + en-&gt;firstChar;
++
++ if (en-&gt;flags &amp; NEWT_FLAG_PASSWORD) {
++ char *tmpptr, *p;
++
++ tmpptr = alloca(strlen(chptr+2));
++ strcpy(tmpptr, chptr);
++ for (p = tmpptr; *p; p++)
++ *p = '*';
++ chptr = tmpptr;
++ }
++
++ len = strlen(chptr);
++
++ if (len &lt;= co-&gt;width) {
++ i = len;
++ SLsmg_write_string(chptr);
++ while (i &lt; co-&gt;width) {
++ SLsmg_write_char('_');
++ i++;
++ }
++ } else {
++ SLsmg_write_nstring(chptr, co-&gt;width);
++ }
++
++ if (en-&gt;flags &amp; NEWT_FLAG_HIDDEN)
++ newtGotorc(co-&gt;top, co-&gt;left);
++ else
++ newtGotorc(co-&gt;top, co-&gt;left + (en-&gt;cursorPosition - en-&gt;firstChar));
++}
++
++void newtEntrySetFlags(newtComponent co, int flags, enum newtFlagsSense sense) {
++ struct entry * en = co-&gt;data;
++ int row, col;
++
++ en-&gt;flags = newtSetFlags(en-&gt;flags, flags, sense);
++
++ if (!(en-&gt;flags &amp; NEWT_FLAG_DISABLED))
++ co-&gt;takesFocus = 1;
++ else
++ co-&gt;takesFocus = 0;
++
++ newtGetrc(&amp;row, &amp;col);
++ entryDraw(co);
++ newtGotorc(row, col);
++}
++
++static void entryDestroy(newtComponent co) {
++ struct entry * en = co-&gt;data;
++
++ free(en-&gt;buf);
++ free(en);
++ free(co);
++}
++
++static struct eventResult entryEvent(newtComponent co,
++ struct event ev) {
++ struct entry * en = co-&gt;data;
++ struct eventResult er;
++ int ch;
++ er.result = ER_IGNORED;
++ er.u.focus = NULL;
++
++ if (ev.when == EV_NORMAL) {
++ switch (ev.event) {
++ case EV_FOCUS:
++ newtCursorOn();
++ if (en-&gt;flags &amp; NEWT_FLAG_HIDDEN)
++ newtGotorc(co-&gt;top, co-&gt;left);
++ else
++ newtGotorc(co-&gt;top, co-&gt;left +
++ (en-&gt;cursorPosition - en-&gt;firstChar));
++ er.result = ER_SWALLOWED;
++ break;
++
++ case EV_UNFOCUS:
++ newtCursorOff();
++ newtGotorc(0, 0);
++ er.result = ER_SWALLOWED;
++ if (co-&gt;callback)
++ co-&gt;callback(co, co-&gt;callbackData);
++ break;
++
++ case EV_KEYPRESS:
++ ch = ev.u.key;
++ if (en-&gt;filter)
++ ch = en-&gt;filter(co, en-&gt;filterData, ch, en-&gt;cursorPosition);
++ if (ch) er = entryHandleKey(co, ch);
++ break;
++
++ case EV_MOUSE:
++ if ((ev.u.mouse.type == MOUSE_BUTTON_DOWN) &amp;&amp;
++ (en-&gt;flags ^ NEWT_FLAG_HIDDEN)) {
++ if (strlen(en-&gt;buf) &gt;= (size_t) (ev.u.mouse.x - co-&gt;left)) {
++ en-&gt;cursorPosition = ev.u.mouse.x - co-&gt;left;
++ newtGotorc(co-&gt;top,
++ co-&gt;left +(en-&gt;cursorPosition - en-&gt;firstChar));
++ } else {
++ en-&gt;cursorPosition = strlen(en-&gt;buf);
++ newtGotorc(co-&gt;top,
++ co-&gt;left +(en-&gt;cursorPosition - en-&gt;firstChar));
++ }
++ }
++ break;
++ }
++ } else
++ er.result = ER_IGNORED;
++
++ return er;
++}
++
++static struct eventResult entryHandleKey(newtComponent co, int key) {
++ struct entry * en = co-&gt;data;
++ struct eventResult er;
++ char * chptr, * insPoint;
++
++ er.result = ER_SWALLOWED;
++ switch (key) {
++ case '\r': /* Return */
++ if (en-&gt;flags &amp; NEWT_FLAG_RETURNEXIT) {
++ er.result = ER_EXITFORM;
++ } else {
++ er.result = ER_NEXTCOMP;
++ }
++ break;
++
++ case '\001': /* ^A */
++ case NEWT_KEY_HOME:
++ en-&gt;cursorPosition = 0;
++ break;
++
++ case '\005': /* ^E */
++ case NEWT_KEY_END:
++ en-&gt;cursorPosition = en-&gt;bufUsed;
++ break;
++
++ case '\013': /* ^K */
++ en-&gt;bufUsed = en-&gt;cursorPosition;
++ memset(en-&gt;buf + en-&gt;bufUsed, 0, en-&gt;bufAlloced - en-&gt;bufUsed);
++ break;
++
++ case '\002': /* ^B */
++ case NEWT_KEY_LEFT:
++ if (en-&gt;cursorPosition)
++ en-&gt;cursorPosition--;
++ break;
++
++ case '\004':
++ case NEWT_KEY_DELETE:
++ chptr = en-&gt;buf + en-&gt;cursorPosition;
++ if (*chptr) {
++ chptr++;
++ while (*chptr) {
++ *(chptr - 1) = *chptr;
++ chptr++;
++ }
++ *(chptr - 1) = '\0';
++ en-&gt;bufUsed--;
++ }
++ break;
++
++ case NEWT_KEY_BKSPC:
++ if (en-&gt;cursorPosition) {
++ /* if this isn't true, there's nothing to erase */
++ chptr = en-&gt;buf + en-&gt;cursorPosition;
++ en-&gt;bufUsed--;
++ en-&gt;cursorPosition--;
++ while (*chptr) {
++ *(chptr - 1) = *chptr;
++ chptr++;
++ }
++ *(chptr - 1) = '\0';
++ }
++ break;
++
++ case '\006': /* ^B */
++ case NEWT_KEY_RIGHT:
++ if (en-&gt;cursorPosition &lt; en-&gt;bufUsed)
++ en-&gt;cursorPosition++;
++ break;
++
++ default:
++ if ((key &gt;= 0x20 &amp;&amp; key &lt;= 0x7e) || (key &gt;= 0xa0 &amp;&amp; key &lt;= 0xff)) {
++ if (!(en-&gt;flags &amp; NEWT_FLAG_SCROLL) &amp;&amp; en-&gt;bufUsed &gt;= co-&gt;width) {
++ SLtt_beep();
++ break;
++ }
++
++ if ((en-&gt;bufUsed + 1) == en-&gt;bufAlloced) {
++ en-&gt;bufAlloced += 20;
++ en-&gt;buf = realloc(en-&gt;buf, en-&gt;bufAlloced);
++ if (en-&gt;resultPtr) *en-&gt;resultPtr = en-&gt;buf;
++ memset(en-&gt;buf + en-&gt;bufUsed + 1, 0, 20);
++ }
++
++ if (en-&gt;cursorPosition == en-&gt;bufUsed) {
++ en-&gt;bufUsed++;
++ } else {
++ /* insert the new character */
++
++ /* chptr is the last character in the string */
++ chptr = (en-&gt;buf + en-&gt;bufUsed) - 1;
++ if ((en-&gt;bufUsed + 1) == en-&gt;bufAlloced) {
++ /* this string fills the buffer, so clip it */
++ chptr--;
++ } else
++ en-&gt;bufUsed++;
++
++ insPoint = en-&gt;buf + en-&gt;cursorPosition;
++
++ while (chptr &gt;= insPoint) {
++ *(chptr + 1) = *chptr;
++ chptr--;
++ }
++
++ }
++
++ en-&gt;buf[en-&gt;cursorPosition++] = key;
++ } else {
++ er.result = ER_IGNORED;
++ }
++ }
++
++ entryDraw(co);
++
++ return er;
++}
++
++char * newtEntryGetValue(newtComponent co) {
++ struct entry * en = co-&gt;data;
++
++ return en-&gt;buf;
++}
++
++void newtEntrySetFilter(newtComponent co, newtEntryFilter filter, void * data) {
++ struct entry * en = co-&gt;data;
++ en-&gt;filter = filter;
++ en-&gt;filterData = data;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/newt/entry.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/newt/form.c
+===================================================================
+--- drakx/trunk/mdk-stage1/newt/form.c (rev 0)
++++ drakx/trunk/mdk-stage1/newt/form.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,713 @@
++#include &lt;unistd.h&gt;
++#include &lt;slang.h&gt;
++#include &lt;stdarg.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++#include &lt;sys/time.h&gt;
++#include &lt;sys/types.h&gt;
++
++#include &quot;newt.h&quot;
++#include &quot;newt_pr.h&quot;
++
++
++/****************************************************************************
++ These forms handle vertical scrolling of components with a height of 1
++
++ Horizontal scrolling won't work, and scrolling large widgets will fail
++ miserably. It shouldn't be too hard to fix either of those if anyone
++ cares to. I only use scrolling for listboxes and text boxes though so
++ I didn't bother.
++*****************************************************************************/
++
++struct element {
++ int top, left; /* Actual, not virtual. These are translated */
++ newtComponent co; /* into actual through vertOffset */
++};
++
++struct fdInfo {
++ int fd;
++ int flags;
++};
++
++struct form {
++ int numCompsAlloced;
++ struct element * elements;
++ int numComps;
++ int currComp;
++ int fixedHeight;
++ int flags;
++ int vertOffset;
++ newtComponent vertBar, exitComp;
++ const char * help;
++ int numRows;
++ int * hotKeys;
++ int numHotKeys;
++ int background;
++ int beenSet;
++ int numFds;
++ struct fdInfo * fds;
++ int maxFd;
++ int timer; /* in milliseconds */
++ struct timeval lastTimeout;
++ void * helpTag;
++ newtCallback helpCb;
++};
++
++static void gotoComponent(struct form * form, int newComp);
++static struct eventResult formEvent(newtComponent co, struct event ev);
++static struct eventResult sendEvent(newtComponent comp, struct event ev);
++static void formPlace(newtComponent co, int left, int top);
++
++/* Global, ick */
++static newtCallback helpCallback;
++
++/* this isn't static as grid.c tests against it to find forms */
++struct componentOps formOps = {
++ newtDrawForm,
++ formEvent,
++ newtFormDestroy,
++ formPlace,
++ newtDefaultMappedHandler,
++} ;
++
++static inline int componentFits(newtComponent co, int compNum) {
++ struct form * form = co-&gt;data;
++ struct element * el = form-&gt;elements + compNum;
++
++ if ((co-&gt;top + form-&gt;vertOffset) &gt; el-&gt;top) return 0;
++ if ((co-&gt;top + form-&gt;vertOffset + co-&gt;height) &lt;
++ (el-&gt;top + el-&gt;co-&gt;height)) return 0;
++
++ return 1;
++}
++
++newtComponent newtForm(newtComponent vertBar, void * help, int flags) {
++ newtComponent co;
++ struct form * form;
++
++ co = malloc(sizeof(*co));
++ form = malloc(sizeof(*form));
++ co-&gt;data = form;
++ co-&gt;width = 0;
++ co-&gt;height = 0;
++ co-&gt;top = -1;
++ co-&gt;left = -1;
++ co-&gt;isMapped = 0;
++
++ co-&gt;takesFocus = 0; /* we may have 0 components */
++ co-&gt;ops = &amp;formOps;
++
++ form-&gt;help = help;
++ form-&gt;flags = flags;
++ form-&gt;numCompsAlloced = 5;
++ form-&gt;numComps = 0;
++ form-&gt;currComp = -1;
++ form-&gt;vertOffset = 0;
++ form-&gt;fixedHeight = 0;
++ form-&gt;numRows = 0;
++ form-&gt;numFds = 0;
++ form-&gt;maxFd = 0;
++ form-&gt;fds = NULL;
++ form-&gt;beenSet = 0;
++ form-&gt;elements = malloc(sizeof(*(form-&gt;elements)) * form-&gt;numCompsAlloced);
++
++ form-&gt;background = COLORSET_WINDOW;
++ form-&gt;hotKeys = malloc(sizeof(int));
++ form-&gt;numHotKeys = 0;
++ form-&gt;timer = 0;
++ form-&gt;lastTimeout.tv_sec = form-&gt;lastTimeout.tv_usec = 0;
++ if (!(form-&gt;flags &amp; NEWT_FLAG_NOF12)) {
++ newtFormAddHotKey(co, NEWT_KEY_F12);
++ }
++
++ if (vertBar)
++ form-&gt;vertBar = vertBar;
++ else
++ form-&gt;vertBar = NULL;
++
++ form-&gt;helpTag = help;
++ form-&gt;helpCb = helpCallback;
++
++ return co;
++}
++
++newtComponent newtFormGetCurrent(newtComponent co) {
++ struct form * form = co-&gt;data;
++
++ return form-&gt;elements[form-&gt;currComp].co;
++}
++
++void newtFormSetCurrent(newtComponent co, newtComponent subco) {
++ struct form * form = co-&gt;data;
++ int i, new;
++
++ for (i = 0; i &lt; form-&gt;numComps; i++) {
++ if (form-&gt;elements[i].co == subco) break;
++ }
++
++ if (form-&gt;elements[i].co != subco) return;
++ new = i;
++
++ if (co-&gt;isMapped &amp;&amp; !componentFits(co, new)) {
++ gotoComponent(form, -1);
++ form-&gt;vertOffset = form-&gt;elements[new].top - co-&gt;top - 1;
++ if (form-&gt;vertOffset &gt; (form-&gt;numRows - co-&gt;height))
++ form-&gt;vertOffset = form-&gt;numRows - co-&gt;height;
++ }
++
++ gotoComponent(form, new);
++}
++
++void newtFormSetTimer(newtComponent co, int millisecs) {
++ struct form * form = co-&gt;data;
++
++ form-&gt;timer = millisecs;
++ form-&gt;lastTimeout.tv_usec = 0;
++ form-&gt;lastTimeout.tv_sec = 0;
++}
++
++void newtFormSetHeight(newtComponent co, int height) {
++ struct form * form = co-&gt;data;
++
++ form-&gt;fixedHeight = 1;
++ co-&gt;height = height;
++}
++
++void newtFormSetWidth(newtComponent co, int width) {
++ co-&gt;width = width;
++}
++
++void newtFormAddComponent(newtComponent co, newtComponent newco) {
++ struct form * form = co-&gt;data;
++
++ co-&gt;takesFocus = 1;
++
++ if (form-&gt;numCompsAlloced == form-&gt;numComps) {
++ form-&gt;numCompsAlloced += 5;
++ form-&gt;elements = realloc(form-&gt;elements,
++ sizeof(*(form-&gt;elements)) * form-&gt;numCompsAlloced);
++ }
++
++ /* we grab real values for these a bit later */
++ form-&gt;elements[form-&gt;numComps].left = -2;
++ form-&gt;elements[form-&gt;numComps].top = -2;
++ form-&gt;elements[form-&gt;numComps].co = newco;
++
++ if (newco-&gt;takesFocus &amp;&amp; form-&gt;currComp == -1)
++ form-&gt;currComp = form-&gt;numComps;
++
++ form-&gt;numComps++;
++}
++
++void newtFormAddComponents(newtComponent co, ...) {
++ va_list ap;
++ newtComponent subco;
++
++ va_start(ap, co);
++
++ while ((subco = va_arg(ap, newtComponent)))
++ newtFormAddComponent(co, subco);
++
++ va_end(ap);
++}
++
++static void formPlace(newtComponent co, int left, int top) {
++ struct form * form = co-&gt;data;
++ int vertDelta, horizDelta;
++ struct element * el;
++ int i;
++
++ newtFormSetSize(co);
++
++ vertDelta = top - co-&gt;top;
++ horizDelta = left - co-&gt;left;
++ co-&gt;top = top;
++ co-&gt;left = left;
++
++ for (i = 0, el = form-&gt;elements; i &lt; form-&gt;numComps; i++, el++) {
++ el-&gt;co-&gt;top += vertDelta;
++ el-&gt;top += vertDelta;
++ el-&gt;co-&gt;left += horizDelta;
++ el-&gt;left += horizDelta;
++ }
++}
++
++void newtDrawForm(newtComponent co) {
++ struct form * form = co-&gt;data;
++ struct element * el;
++ int i;
++
++ newtFormSetSize(co);
++
++ SLsmg_set_color(form-&gt;background);
++ newtClearBox(co-&gt;left, co-&gt;top, co-&gt;width, co-&gt;height);
++ for (i = 0, el = form-&gt;elements; i &lt; form-&gt;numComps; i++, el++) {
++ /* the scrollbar *always* fits somewhere */
++ if (el-&gt;co == form-&gt;vertBar) {
++ el-&gt;co-&gt;ops-&gt;mapped(el-&gt;co, 1);
++ el-&gt;co-&gt;ops-&gt;draw(el-&gt;co);
++ } else {
++ /* only draw it if it'll fit on the screen vertically */
++ if (componentFits(co, i)) {
++ el-&gt;co-&gt;top = el-&gt;top - form-&gt;vertOffset;
++ el-&gt;co-&gt;ops-&gt;mapped(el-&gt;co, 1);
++ el-&gt;co-&gt;ops-&gt;draw(el-&gt;co);
++ } else {
++ el-&gt;co-&gt;ops-&gt;mapped(el-&gt;co, 0);
++ }
++ }
++ }
++
++ if (form-&gt;vertBar)
++ newtScrollbarSet(form-&gt;vertBar, form-&gt;vertOffset,
++ form-&gt;numRows - co-&gt;height);
++}
++
++static struct eventResult formEvent(newtComponent co, struct event ev) {
++ struct form * form = co-&gt;data;
++ newtComponent subco = form-&gt;elements[form-&gt;currComp].co;
++ int new, wrap = 0;
++ struct eventResult er;
++ int dir = 0, page = 0;
++ int i, num, found;
++ struct element * el;
++
++ er.result = ER_IGNORED;
++ if (!form-&gt;numComps) return er;
++
++ subco = form-&gt;elements[form-&gt;currComp].co;
++
++ switch (ev.when) {
++ case EV_EARLY:
++ if (ev.event == EV_KEYPRESS) {
++ if (ev.u.key == NEWT_KEY_TAB) {
++ er.result = ER_SWALLOWED;
++ dir = 1;
++ wrap = 1;
++ } else if (ev.u.key == NEWT_KEY_UNTAB) {
++ er.result = ER_SWALLOWED;
++ dir = -1;
++ wrap = 1;
++ }
++ }
++
++ if (form-&gt;numComps) {
++ i = form-&gt;currComp;
++ num = 0;
++ while (er.result == ER_IGNORED &amp;&amp; num != form-&gt;numComps ) {
++ er = form-&gt;elements[i].co-&gt;ops-&gt;event(form-&gt;elements[i].co, ev);
++
++ num++;
++ i++;
++ if (i == form-&gt;numComps) i = 0;
++ }
++ }
++
++ break;
++
++ case EV_NORMAL:
++ if (ev.event == EV_MOUSE) {
++ found = 0;
++ for (i = 0, el = form-&gt;elements; i &lt; form-&gt;numComps; i++, el++) {
++ if ((el-&gt;co-&gt;top &lt;= ev.u.mouse.y) &amp;&amp;
++ (el-&gt;co-&gt;top + el-&gt;co-&gt;height &gt; ev.u.mouse.y) &amp;&amp;
++ (el-&gt;co-&gt;left &lt;= ev.u.mouse.x) &amp;&amp;
++ (el-&gt;co-&gt;left + el-&gt;co-&gt;width &gt; ev.u.mouse.x)) {
++ found = 1;
++ if (el-&gt;co-&gt;takesFocus) {
++ gotoComponent(form, i);
++ subco = form-&gt;elements[form-&gt;currComp].co;
++ }
++ }
++ /* If we did not find a co to send this event to, we
++ should just swallow the event here. */
++ }
++ if (!found) {
++ er.result = ER_SWALLOWED;
++
++ return er;
++ }
++ }
++ er = subco-&gt;ops-&gt;event(subco, ev);
++ switch (er.result) {
++ case ER_NEXTCOMP:
++ er.result = ER_SWALLOWED;
++ dir = 1;
++ break;
++
++ case ER_EXITFORM:
++ form-&gt;exitComp = subco;
++ break;
++
++ default:
++ break;
++ }
++ break;
++
++ case EV_LATE:
++ er = subco-&gt;ops-&gt;event(subco, ev);
++
++ if (er.result == ER_IGNORED) {
++ switch (ev.u.key) {
++ case NEWT_KEY_UP:
++ case NEWT_KEY_LEFT:
++ case NEWT_KEY_BKSPC:
++ er.result = ER_SWALLOWED;
++ dir = -1;
++ break;
++
++ case NEWT_KEY_DOWN:
++ case NEWT_KEY_RIGHT:
++ er.result = ER_SWALLOWED;
++ dir = 1;
++ break;
++
++ case NEWT_KEY_PGUP:
++ er.result = ER_SWALLOWED;
++ dir = -1;
++ page = 1;
++ break;
++
++ case NEWT_KEY_PGDN:
++ er.result = ER_SWALLOWED;
++ dir = 1;
++ page = 1;
++ break;
++ }
++ }
++ }
++
++ if (dir) {
++ new = form-&gt;currComp;
++
++ if (page) {
++ new += dir * co-&gt;height;
++ if (new &lt; 0)
++ new = 0;
++ else if (new &gt;= form-&gt;numComps)
++ new = (form-&gt;numComps - 1);
++
++ while (!form-&gt;elements[new].co-&gt;takesFocus)
++ new = new - dir;
++ } else {
++ do {
++ new += dir;
++
++ if (wrap) {
++ if (new &lt; 0)
++ new = form-&gt;numComps - 1;
++ else if (new &gt;= form-&gt;numComps)
++ new = 0;
++ } else if (new &lt; 0 || new &gt;= form-&gt;numComps)
++ return er;
++ } while (!form-&gt;elements[new].co-&gt;takesFocus);
++ }
++
++ /* make sure this component is visible */
++ if (!componentFits(co, new)) {
++ gotoComponent(form, -1);
++
++ if (dir &lt; 0) {
++ /* make the new component the first one */
++ form-&gt;vertOffset = form-&gt;elements[new].top - co-&gt;top;
++ } else {
++ /* make the new component the last one */
++ form-&gt;vertOffset = (form-&gt;elements[new].top +
++ form-&gt;elements[new].co-&gt;height) -
++ (co-&gt;top + co-&gt;height);
++ }
++
++ if (form-&gt;vertOffset &lt; 0) form-&gt;vertOffset = 0;
++ if (form-&gt;vertOffset &gt; (form-&gt;numRows - co-&gt;height))
++ form-&gt;vertOffset = form-&gt;numRows - co-&gt;height;
++
++ newtDrawForm(co);
++ }
++
++ gotoComponent(form, new);
++ er.result = ER_SWALLOWED;
++ }
++
++ return er;
++}
++
++/* this also destroys all of the components on the form */
++void newtFormDestroy(newtComponent co) {
++ newtComponent subco;
++ struct form * form = co-&gt;data;
++ int i;
++
++ /* first, destroy all of the components */
++ for (i = 0; i &lt; form-&gt;numComps; i++) {
++ subco = form-&gt;elements[i].co;
++ if (subco-&gt;ops-&gt;destroy) {
++ subco-&gt;ops-&gt;destroy(subco);
++ } else {
++ if (subco-&gt;data) free(subco-&gt;data);
++ free(subco);
++ }
++ }
++
++ if (form-&gt;hotKeys) free(form-&gt;hotKeys);
++
++ free(form-&gt;elements);
++ free(form);
++ free(co);
++}
++
++newtComponent newtRunForm(newtComponent co) {
++ struct newtExitStruct es;
++
++ newtFormRun(co, &amp;es);
++ if (es.reason == NEWT_EXIT_HOTKEY) {
++ if (es.u.key == NEWT_KEY_F12) {
++ es.reason = NEWT_EXIT_COMPONENT;
++ es.u.co = co;
++ } else {
++ return NULL;
++ }
++ }
++
++ return es.u.co;
++}
++
++void newtFormAddHotKey(newtComponent co, int key) {
++ struct form * form = co-&gt;data;
++
++ form-&gt;numHotKeys++;
++ form-&gt;hotKeys = realloc(form-&gt;hotKeys, sizeof(int) * form-&gt;numHotKeys);
++ form-&gt;hotKeys[form-&gt;numHotKeys - 1] = key;
++}
++
++void newtFormSetSize(newtComponent co) {
++ struct form * form = co-&gt;data;
++ int delta, i;
++ struct element * el;
++
++ if (form-&gt;beenSet) return;
++
++ form-&gt;beenSet = 1;
++
++ if (!form-&gt;numComps) return;
++
++ co-&gt;width = 0;
++ if (!form-&gt;fixedHeight) co-&gt;height = 0;
++
++ co-&gt;top = form-&gt;elements[0].co-&gt;top;
++ co-&gt;left = form-&gt;elements[0].co-&gt;left;
++ for (i = 0, el = form-&gt;elements; i &lt; form-&gt;numComps; i++, el++) {
++ if (el-&gt;co-&gt;ops == &amp;formOps)
++ newtFormSetSize(el-&gt;co);
++
++ el-&gt;left = el-&gt;co-&gt;left;
++ el-&gt;top = el-&gt;co-&gt;top;
++
++ if (co-&gt;left &gt; el-&gt;co-&gt;left) {
++ delta = co-&gt;left - el-&gt;co-&gt;left;
++ co-&gt;left -= delta;
++ co-&gt;width += delta;
++ }
++
++ if (co-&gt;top &gt; el-&gt;co-&gt;top) {
++ delta = co-&gt;top - el-&gt;co-&gt;top;
++ co-&gt;top -= delta;
++ if (!form-&gt;fixedHeight)
++ co-&gt;height += delta;
++ }
++
++ if ((co-&gt;left + co-&gt;width) &lt; (el-&gt;co-&gt;left + el-&gt;co-&gt;width))
++ co-&gt;width = (el-&gt;co-&gt;left + el-&gt;co-&gt;width) - co-&gt;left;
++
++ if (!form-&gt;fixedHeight) {
++ if ((co-&gt;top + co-&gt;height) &lt; (el-&gt;co-&gt;top + el-&gt;co-&gt;height))
++ co-&gt;height = (el-&gt;co-&gt;top + el-&gt;co-&gt;height) - co-&gt;top;
++ }
++
++ if ((el-&gt;co-&gt;top + el-&gt;co-&gt;height - co-&gt;top) &gt; form-&gt;numRows) {
++ form-&gt;numRows = el-&gt;co-&gt;top + el-&gt;co-&gt;height - co-&gt;top;
++ }
++ }
++}
++
++void newtFormRun(newtComponent co, struct newtExitStruct * es) {
++ struct form * form = co-&gt;data;
++ struct event ev;
++ struct eventResult er;
++ int key, i, max;
++ int done = 0;
++ fd_set readSet, writeSet;
++ struct timeval nextTimeout, now, timeout;
++
++ newtFormSetSize(co);
++ /* draw all of the components */
++ newtDrawForm(co);
++
++ if (form-&gt;currComp == -1) {
++ gotoComponent(form, 0);
++ } else
++ gotoComponent(form, form-&gt;currComp);
++
++ while (!done) {
++ newtRefresh();
++
++ FD_ZERO(&amp;readSet);
++ FD_ZERO(&amp;writeSet);
++ FD_SET(0, &amp;readSet);
++ max = form-&gt;maxFd;
++
++ for (i = 0; i &lt; form-&gt;numFds; i++) {
++ if (form-&gt;fds[i].flags &amp; NEWT_FD_READ)
++ FD_SET(form-&gt;fds[i].fd, &amp;readSet);
++ if (form-&gt;fds[i].flags &amp; NEWT_FD_WRITE)
++ FD_SET(form-&gt;fds[i].fd, &amp;writeSet);
++ }
++
++ if (form-&gt;timer) {
++ /* Calculate when we next need to return with a timeout. Do
++ this inside the loop in case a callback resets the timer. */
++ if (!form-&gt;lastTimeout.tv_sec &amp;&amp; !form-&gt;lastTimeout.tv_usec)
++ gettimeofday(&amp;form-&gt;lastTimeout, NULL);
++
++ nextTimeout.tv_sec = form-&gt;lastTimeout.tv_sec +
++ (form-&gt;timer / 1000);
++ nextTimeout.tv_usec = form-&gt;lastTimeout.tv_usec +
++ (form-&gt;timer % 1000) * 1000;
++
++ gettimeofday(&amp;now, 0);
++
++ if (now.tv_sec &gt; nextTimeout.tv_sec) {
++ timeout.tv_sec = timeout.tv_usec = 0;
++ } else if (now.tv_sec == nextTimeout.tv_sec) {
++ timeout.tv_sec = 0;
++ if (now.tv_usec &gt; nextTimeout.tv_usec)
++ timeout.tv_usec = 0;
++ else
++ timeout.tv_usec = nextTimeout.tv_usec - now.tv_usec;
++ } else if (now.tv_sec &lt; nextTimeout.tv_sec) {
++ timeout.tv_sec = nextTimeout.tv_sec - now.tv_sec;
++ if (now.tv_usec &gt; nextTimeout.tv_usec)
++ timeout.tv_sec--,
++ timeout.tv_usec = nextTimeout.tv_usec + 1000000 -
++ now.tv_usec;
++ else
++ timeout.tv_usec = nextTimeout.tv_usec - now.tv_usec;
++ }
++ } else {
++ timeout.tv_sec = timeout.tv_usec = 0;
++ }
++
++ i = select(max + 1, &amp;readSet, &amp;writeSet, NULL,
++ form-&gt;timer ? &amp;timeout : NULL);
++ if (i &lt; 0) continue; /* ?? What should we do here? */
++
++ if (i == 0) {
++ done = 1;
++ es-&gt;reason = NEWT_EXIT_TIMER;
++ gettimeofday(&amp;form-&gt;lastTimeout, NULL);
++ } else
++ {
++ if (FD_ISSET(0, &amp;readSet)) {
++
++ key = newtGetKey();
++
++ if (key == NEWT_KEY_RESIZE) {
++ /* newtResizeScreen(1); */
++ continue;
++ }
++
++ for (i = 0; i &lt; form-&gt;numHotKeys; i++) {
++ if (form-&gt;hotKeys[i] == key) {
++ es-&gt;reason = NEWT_EXIT_HOTKEY;
++ es-&gt;u.key = key;
++ done = 1;
++ break;
++ }
++ }
++
++ if (key == NEWT_KEY_F1 &amp;&amp; form-&gt;helpTag &amp;&amp; form-&gt;helpCb)
++ form-&gt;helpCb(co, form-&gt;helpTag);
++
++ if (!done) {
++ ev.event = EV_KEYPRESS;
++ ev.u.key = key;
++
++ er = sendEvent(co, ev);
++
++ if (er.result == ER_EXITFORM) {
++ done = 1;
++ es-&gt;reason = NEWT_EXIT_COMPONENT;
++ es-&gt;u.co = form-&gt;exitComp;
++ }
++ }
++ } else {
++ es-&gt;reason = NEWT_EXIT_FDREADY;
++ done = 1;
++ }
++ }
++ }
++ newtRefresh();
++}
++
++static struct eventResult sendEvent(newtComponent co, struct event ev) {
++ struct eventResult er;
++
++ ev.when = EV_EARLY;
++ er = co-&gt;ops-&gt;event(co, ev);
++
++ if (er.result == ER_IGNORED) {
++ ev.when = EV_NORMAL;
++ er = co-&gt;ops-&gt;event(co, ev);
++ }
++
++ if (er.result == ER_IGNORED) {
++ ev.when = EV_LATE;
++ er = co-&gt;ops-&gt;event(co, ev);
++ }
++
++ return er;
++}
++
++static void gotoComponent(struct form * form, int newComp) {
++ struct event ev;
++
++ if (form-&gt;currComp != -1) {
++ ev.event = EV_UNFOCUS;
++ sendEvent(form-&gt;elements[form-&gt;currComp].co, ev);
++ }
++
++ form-&gt;currComp = newComp;
++
++ if (form-&gt;currComp != -1) {
++ ev.event = EV_FOCUS;
++ ev.when = EV_NORMAL;
++ sendEvent(form-&gt;elements[form-&gt;currComp].co, ev);
++ }
++}
++
++void newtComponentAddCallback(newtComponent co, newtCallback f, void * data) {
++ co-&gt;callback = f;
++ co-&gt;callbackData = data;
++}
++
++void newtComponentTakesFocus(newtComponent co, int val) {
++ co-&gt;takesFocus = val;
++}
++
++void newtFormSetBackground(newtComponent co, int color) {
++ struct form * form = co-&gt;data;
++
++ form-&gt;background = color;
++}
++
++void newtFormWatchFd(newtComponent co, int fd, int fdFlags) {
++ struct form * form = co-&gt;data;
++
++ form-&gt;fds = realloc(form-&gt;fds, (form-&gt;numFds + 1) * sizeof(*form-&gt;fds));
++ form-&gt;fds[form-&gt;numFds].fd = fd;
++ form-&gt;fds[form-&gt;numFds++].flags = fdFlags;
++ if (form-&gt;maxFd &lt; fd) form-&gt;maxFd = fd;
++}
++
++void newtSetHelpCallback(newtCallback cb) {
++ helpCallback = cb;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/newt/form.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/newt/grid.c
+===================================================================
+--- drakx/trunk/mdk-stage1/newt/grid.c (rev 0)
++++ drakx/trunk/mdk-stage1/newt/grid.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,389 @@
++#include &lt;alloca.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++
++#include &quot;newt.h&quot;
++#include &quot;newt_pr.h&quot;
++
++struct gridField {
++ enum newtGridElement type;
++ union {
++ newtGrid grid;
++ newtComponent co;
++ } u;
++ int padLeft, padTop, padRight, padBottom;
++ int anchor;
++ int flags;
++};
++
++struct grid_s {
++ int rows, cols;
++ int width, height; /* totals, -1 means unknown */
++ struct gridField ** fields;
++};
++
++/* this is a bit of a hack */
++extern struct componentOps formOps[];
++
++newtGrid newtCreateGrid(int cols, int rows) {
++ newtGrid grid;
++
++ grid = malloc(sizeof(*grid));
++ grid-&gt;rows = rows;
++ grid-&gt;cols = cols;
++
++ grid-&gt;fields = malloc(sizeof(*grid-&gt;fields) * cols);
++ while (cols--) {
++ grid-&gt;fields[cols] = malloc(sizeof(**(grid-&gt;fields)) * rows);
++ memset(grid-&gt;fields[cols], 0, sizeof(**(grid-&gt;fields)) * rows);
++ }
++
++ grid-&gt;width = grid-&gt;height = -1;
++
++ return grid;
++}
++
++void newtGridSetField(newtGrid grid, int col, int row,
++ enum newtGridElement type, void * val, int padLeft,
++ int padTop, int padRight, int padBottom, int anchor,
++ int flags) {
++ struct gridField * field = &amp;grid-&gt;fields[col][row];
++
++ if (field-&gt;type == NEWT_GRID_SUBGRID)
++ newtGridFree(field-&gt;u.grid, 1);
++
++ field-&gt;type = type;
++ field-&gt;u.co = (void *) val;
++
++ field-&gt;padLeft = padLeft;
++ field-&gt;padRight = padRight;
++ field-&gt;padTop = padTop;
++ field-&gt;padBottom = padBottom;
++ field-&gt;anchor = anchor;
++ field-&gt;flags = flags;
++
++ grid-&gt;width = grid-&gt;height = -1;
++}
++
++static void distSpace(int extra, int items, int * list) {
++ int all, some, i;
++
++ all = extra / items;
++ some = extra % items;
++ for (i = 0; i &lt; items; i++) {
++ list[i] += all;
++ if (some) {
++ list[i]++;
++ some--;
++ }
++ }
++}
++
++static void shuffleGrid(newtGrid grid, int left, int top, int set) {
++ struct gridField * field;
++ int row, col;
++ int i, j;
++ int minWidth, minHeight;
++ int * widths, * heights;
++ int thisLeft, thisTop;
++ int x, y, remx, remy;
++
++ widths = alloca(sizeof(*widths) * grid-&gt;cols);
++ memset(widths, 0, sizeof(*widths) * grid-&gt;cols);
++ heights = alloca(sizeof(*heights) * grid-&gt;rows);
++ memset(heights, 0, sizeof(*heights) * grid-&gt;rows);
++
++ minWidth = 0;
++ for (row = 0; row &lt; grid-&gt;rows; row++) {
++ i = 0;
++ for (col = 0; col &lt; grid-&gt;cols; col++) {
++ field = &amp;grid-&gt;fields[col][row];
++ if (field-&gt;type == NEWT_GRID_SUBGRID) {
++ /* we'll have to redo this later */
++ if (field-&gt;u.grid-&gt;width == -1)
++ shuffleGrid(field-&gt;u.grid, left, top, 0);
++ j = field-&gt;u.grid-&gt;width;
++ } else if (field-&gt;type == NEWT_GRID_COMPONENT) {
++ if (field-&gt;u.co-&gt;ops == formOps)
++ newtFormSetSize(field-&gt;u.co);
++ j = field-&gt;u.co-&gt;width;
++ } else
++ j = 0;
++
++ j += field-&gt;padLeft + field-&gt;padRight;
++
++ if (j &gt; widths[col]) widths[col] = j;
++ i += widths[col];
++ }
++
++ if (i &gt; minWidth) minWidth = i;
++ }
++
++ minHeight = 0;
++ for (col = 0; col &lt; grid-&gt;cols; col++) {
++ i = 0;
++ for (row = 0; row &lt; grid-&gt;rows; row++) {
++ field = &amp;grid-&gt;fields[col][row];
++ if (field-&gt;type == NEWT_GRID_SUBGRID) {
++ /* we'll have to redo this later */
++ if (field-&gt;u.grid-&gt;height == -1)
++ shuffleGrid(field-&gt;u.grid, 0, 0, 0);
++ j = field-&gt;u.grid-&gt;height;
++ } else if (field-&gt;type == NEWT_GRID_COMPONENT){
++ j = field-&gt;u.co-&gt;height;
++ } else
++ j = 0;
++
++ j += field-&gt;padTop + field-&gt;padBottom;
++
++ if (j &gt; heights[row]) heights[row] = j;
++ i += heights[row];
++ }
++
++ if (i &gt; minHeight) minHeight = i;
++ }
++
++ /* this catches the -1 case */
++ if (grid-&gt;width &lt; minWidth) grid-&gt;width = minWidth; /* ack! */
++ if (grid-&gt;height &lt; minHeight) grid-&gt;height = minHeight; /* ditto! */
++
++ if (!set) return;
++
++ distSpace(grid-&gt;width - minWidth, grid-&gt;cols, widths);
++ distSpace(grid-&gt;height - minHeight, grid-&gt;rows, heights);
++
++ thisTop = top;
++ for (row = 0; row &lt; grid-&gt;rows; row++) {
++ i = 0;
++ thisLeft = left;
++ for (col = 0; col &lt; grid-&gt;cols; col++) {
++ field = &amp;grid-&gt;fields[col][row];
++
++ if (field-&gt;type == NEWT_GRID_EMPTY) continue;
++
++ x = thisLeft + field-&gt;padLeft;
++ remx = widths[col] - field-&gt;padLeft - field-&gt;padRight;
++ y = thisTop + field-&gt;padTop;
++ remy = heights[row] - field-&gt;padTop - field-&gt;padBottom;
++
++ if (field-&gt;type == NEWT_GRID_SUBGRID) {
++ remx -= field-&gt;u.grid-&gt;width;
++ remy -= field-&gt;u.grid-&gt;height;
++ } else if (field-&gt;type == NEWT_GRID_COMPONENT) {
++ remx -= field-&gt;u.co-&gt;width;
++ remy -= field-&gt;u.co-&gt;height;
++ }
++
++ if (!(field-&gt;flags &amp; NEWT_GRID_FLAG_GROWX)) {
++ if (field-&gt;anchor &amp; NEWT_ANCHOR_RIGHT)
++ x += remx;
++ else if (!(field-&gt;anchor &amp; NEWT_ANCHOR_LEFT))
++ x += (remx / 2);
++ }
++
++ if (!(field-&gt;flags &amp; NEWT_GRID_FLAG_GROWY)) {
++ if (field-&gt;anchor &amp; NEWT_ANCHOR_BOTTOM)
++ y += remx;
++ else if (!(field-&gt;anchor &amp; NEWT_ANCHOR_TOP))
++ y += (remy / 2);
++ }
++
++ if (field-&gt;type == NEWT_GRID_SUBGRID) {
++ if (field-&gt;flags &amp; NEWT_GRID_FLAG_GROWX)
++ field-&gt;u.grid-&gt;width = widths[col] - field-&gt;padLeft
++ - field-&gt;padRight;
++ if (field-&gt;flags &amp; NEWT_GRID_FLAG_GROWY)
++ field-&gt;u.grid-&gt;height = heights[col] - field-&gt;padTop
++ - field-&gt;padBottom;
++
++ shuffleGrid(field-&gt;u.grid, x, y, 1);
++ } else if (field-&gt;type == NEWT_GRID_COMPONENT) {
++ field-&gt;u.co-&gt;ops-&gt;place(field-&gt;u.co, x, y);
++ }
++
++ thisLeft += widths[col];
++ }
++
++ thisTop += heights[row];
++ }
++}
++
++void newtGridPlace(newtGrid grid, int left, int top) {
++ shuffleGrid(grid, left, top, 1);
++}
++
++void newtGridFree(newtGrid grid, int recurse) {
++ int row, col;
++
++ for (col = 0; col &lt; grid-&gt;cols; col++) {
++ if (recurse) {
++ for (row = 0; row &lt; grid-&gt;rows; row++) {
++ if (grid-&gt;fields[col][row].type == NEWT_GRID_SUBGRID)
++ newtGridFree(grid-&gt;fields[col][row].u.grid, 1);
++ }
++ }
++
++ free(grid-&gt;fields[col]);
++ }
++
++ free(grid-&gt;fields);
++ free(grid);
++}
++
++void newtGridGetSize(newtGrid grid, int * width, int * height) {
++ if (grid-&gt;width == -1 || grid-&gt;height == -1) {
++ grid-&gt;width = grid-&gt;height = -1;
++ shuffleGrid(grid, 0, 0, 1);
++ }
++
++ *width = grid-&gt;width;
++ *height = grid-&gt;height;
++}
++
++void newtGridWrappedWindow(newtGrid grid, char * title) {
++ int width, height, offset = 0;
++
++ newtGridGetSize(grid, &amp;width, &amp;height);
++ if ((size_t)width &lt; strlen(title) + 2) {
++ offset = ((strlen(title) + 2) - width) / 2;
++ width = strlen(title) + 2;
++ }
++ newtCenteredWindow(width + 2, height + 2, title);
++ newtGridPlace(grid, 1 + offset, 1);
++}
++
++void newtGridWrappedWindowAt(newtGrid grid, char * title, int left, int top) {
++ int width, height;
++
++ newtGridGetSize(grid, &amp;width, &amp;height);
++ newtOpenWindow(left, top, width + 2, height + 2, title);
++ newtGridPlace(grid, 1, 1);
++}
++
++void newtGridAddComponentsToForm(newtGrid grid, newtComponent form,
++ int recurse) {
++ int row, col;
++
++ for (col = 0; col &lt; grid-&gt;cols; col++) {
++ for (row = 0; row &lt; grid-&gt;rows; row++) {
++ if (grid-&gt;fields[col][row].type == NEWT_GRID_SUBGRID &amp;&amp; recurse)
++ newtGridAddComponentsToForm(grid-&gt;fields[col][row].u.grid,
++ form, 1);
++ else if (grid-&gt;fields[col][row].type == NEWT_GRID_COMPONENT)
++ newtFormAddComponent(form, grid-&gt;fields[col][row].u.co);
++ }
++ }
++}
++
++/* this handles up to 50 items */
++static newtGrid stackem(int isVert, enum newtGridElement type1, void * what1,
++ va_list args, int close) {
++ struct item {
++ enum newtGridElement type;
++ void * what;
++ } items[50];
++ int i, num;
++ newtGrid grid;
++
++ items[0].type = type1, items[0].what = what1, num = 1;
++ while (1) {
++ items[num].type = va_arg(args, enum newtGridElement);
++ if (items[num].type == NEWT_GRID_EMPTY) break;
++
++ items[num].what = va_arg(args, void *);
++ num++;
++ }
++
++ grid = newtCreateGrid(isVert ? 1 : num, isVert ? num : 1);
++
++ for (i = 0; i &lt; num; i++) {
++ newtGridSetField(grid, isVert ? 0 : i, isVert ? i : 0,
++ items[i].type, items[i].what,
++ close ? 0 : (i ? (isVert ? 0 : 1) : 0),
++ close ? 0 : (i ? (isVert ? 1 : 0) : 0), 0, 0, 0, 0);
++ }
++
++ return grid;
++}
++
++newtGrid newtGridHCloseStacked(enum newtGridElement type1, void * what1, ...) {
++ va_list args;
++ newtGrid grid;
++
++ va_start(args, what1);
++
++ grid = stackem(0, type1, what1, args, 1);
++
++ va_start(args, what1);
++
++ return grid;
++}
++
++newtGrid newtGridVCloseStacked(enum newtGridElement type1, void * what1, ...) {
++ va_list args;
++ newtGrid grid;
++
++ va_start(args, what1);
++
++ grid = stackem(1, type1, what1, args, 1);
++
++ va_start(args, what1);
++
++ return grid;
++}
++
++newtGrid newtGridVStacked(enum newtGridElement type1, void * what1, ...) {
++ va_list args;
++ newtGrid grid;
++
++ va_start(args, what1);
++
++ grid = stackem(1, type1, what1, args, 0);
++
++ va_start(args, what1);
++
++ return grid;
++}
++
++newtGrid newtGridHStacked(enum newtGridElement type1, void * what1, ...) {
++ va_list args;
++ newtGrid grid;
++
++ va_start(args, what1);
++
++ grid = stackem(0, type1, what1, args, 0);
++
++ va_start(args, what1);
++
++ return grid;
++}
++
++newtGrid newtGridBasicWindow(newtComponent text, newtGrid middle,
++ newtGrid buttons) {
++ newtGrid grid;
++
++ grid = newtCreateGrid(1, 3);
++ newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text,
++ 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
++ newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, middle,
++ 0, 1, 0, 0, 0, 0);
++ newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttons,
++ 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
++
++ return grid;
++}
++
++newtGrid newtGridSimpleWindow(newtComponent text, newtComponent middle,
++ newtGrid buttons) {
++ newtGrid grid;
++
++ grid = newtCreateGrid(1, 3);
++ newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text,
++ 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
++ newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, middle,
++ 0, 1, 0, 0, 0, 0);
++ newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttons,
++ 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
++
++ return grid;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/newt/grid.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/newt/label.c
+===================================================================
+--- drakx/trunk/mdk-stage1/newt/label.c (rev 0)
++++ drakx/trunk/mdk-stage1/newt/label.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,81 @@
++#include &lt;slang.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++
++#include &quot;newt.h&quot;
++#include &quot;newt_pr.h&quot;
++
++struct label {
++ char * text;
++ int length;
++};
++
++static void labelDraw(newtComponent co);
++static void labelDestroy(newtComponent co);
++
++static struct componentOps labelOps = {
++ labelDraw,
++ newtDefaultEventHandler,
++ labelDestroy,
++ newtDefaultPlaceHandler,
++ newtDefaultMappedHandler,
++} ;
++
++newtComponent newtLabel(int left, int top, const char * text) {
++ newtComponent co;
++ struct label * la;
++
++ co = malloc(sizeof(*co));
++ la = malloc(sizeof(struct label));
++ co-&gt;data = la;
++
++ co-&gt;ops = &amp;labelOps;
++
++ co-&gt;height = 1;
++ co-&gt;width = strlen(text);
++ co-&gt;top = top;
++ co-&gt;left = left;
++ co-&gt;takesFocus = 0;
++
++ la-&gt;length = strlen(text);
++ la-&gt;text = strdup(text);
++
++ return co;
++}
++
++void newtLabelSetText(newtComponent co, const char * text) {
++ int newLength;
++ struct label * la = co-&gt;data;
++
++ newLength = strlen(text);
++ if (newLength &lt;= la-&gt;length) {
++ memset(la-&gt;text, ' ', la-&gt;length);
++ memcpy(la-&gt;text, text, newLength);
++ } else {
++ free(la-&gt;text);
++ la-&gt;text = strdup(text);
++ la-&gt;length = newLength;
++ co-&gt;width = newLength;
++ }
++
++ labelDraw(co);
++}
++
++static void labelDraw(newtComponent co) {
++ struct label * la = co-&gt;data;
++
++ if (co-&gt;isMapped == -1) return;
++
++ SLsmg_set_color(COLORSET_LABEL);
++
++ newtGotorc(co-&gt;top, co-&gt;left);
++ SLsmg_write_string(la-&gt;text);
++}
++
++static void labelDestroy(newtComponent co) {
++ struct label * la = co-&gt;data;
++
++ free(la-&gt;text);
++ free(la);
++ free(co);
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/newt/label.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/newt/listbox.c
+===================================================================
+--- drakx/trunk/mdk-stage1/newt/listbox.c (rev 0)
++++ drakx/trunk/mdk-stage1/newt/listbox.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,752 @@
++/* This goofed-up box whacked into shape by Elliot Lee &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">sopwith at cuc.edu</A>&gt;
++ (from the original listbox by Erik Troan &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ewt at redhat.com</A>&gt;)
++ and contributed to newt for use under the LGPL license.
++ Copyright (C) 1996, 1997 Elliot Lee */
++
++#include &lt;slang.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++#include &lt;ctype.h&gt;
++
++#include &quot;newt.h&quot;
++#include &quot;newt_pr.h&quot;
++
++
++/* Linked list of items in the listbox */
++struct items {
++ char * text;
++ const void *data;
++ unsigned char isSelected;
++ struct items *next;
++};
++
++/* Holds all the relevant information for this listbox */
++struct listbox {
++ newtComponent sb; /* Scrollbar on right side of listbox */
++ int curWidth; /* size of text w/o scrollbar or border*/
++ int curHeight; /* size of text w/o border */
++ int sbAdjust;
++ int bdxAdjust, bdyAdjust;
++ int numItems, numSelected;
++ int userHasSetWidth;
++ int currItem, startShowItem; /* startShowItem is the first item displayed
++ on the screen */
++ int isActive; /* If we handle key events all the time, it seems
++ to do things even when they are supposed to be for
++ another button/whatever */
++ struct items *boxItems;
++ int grow;
++ int flags; /* flags for this listbox, right now just
++ NEWT_FLAG_RETURNEXIT */
++};
++
++static void listboxDraw(newtComponent co);
++static void listboxDestroy(newtComponent co);
++static struct eventResult listboxEvent(newtComponent co, struct event ev);
++static void newtListboxRealSetCurrent(newtComponent co);
++static void listboxPlace(newtComponent co, int newLeft, int newTop);
++static inline void updateWidth(newtComponent co, struct listbox * li,
++ int maxField);
++static void listboxMapped(newtComponent co, int isMapped);
++
++static struct componentOps listboxOps = {
++ listboxDraw,
++ listboxEvent,
++ listboxDestroy,
++ listboxPlace,
++ listboxMapped,
++};
++
++static void listboxMapped(newtComponent co, int isMapped) {
++ struct listbox * li = co-&gt;data;
++
++ co-&gt;isMapped = isMapped;
++ if (li-&gt;sb)
++ li-&gt;sb-&gt;ops-&gt;mapped(li-&gt;sb, isMapped);
++}
++
++static void listboxPlace(newtComponent co, int newLeft, int newTop) {
++ struct listbox * li = co-&gt;data;
++
++ co-&gt;top = newTop;
++ co-&gt;left = newLeft;
++
++ if (li-&gt;sb)
++ li-&gt;sb-&gt;ops-&gt;place(li-&gt;sb, co-&gt;left + co-&gt;width - li-&gt;bdxAdjust - 1,
++ co-&gt;top);
++}
++
++newtComponent newtListbox(int left, int top, int height, int flags) {
++ newtComponent co, sb;
++ struct listbox * li;
++
++ if (!(co = malloc(sizeof(*co))))
++ return NULL;
++
++ if (!(li = malloc(sizeof(struct listbox)))) {
++ free(co);
++ return NULL;
++ }
++
++ li-&gt;boxItems = NULL;
++ li-&gt;numItems = 0;
++ li-&gt;currItem = 0;
++ li-&gt;numSelected = 0;
++ li-&gt;isActive = 0;
++ li-&gt;userHasSetWidth = 0;
++ li-&gt;startShowItem = 0;
++ li-&gt;sbAdjust = 0;
++ li-&gt;bdxAdjust = 0;
++ li-&gt;bdyAdjust = 0;
++ li-&gt;flags = flags &amp; (NEWT_FLAG_RETURNEXIT | NEWT_FLAG_BORDER |
++ NEWT_FLAG_MULTIPLE);
++
++ if (li-&gt;flags &amp; NEWT_FLAG_BORDER) {
++ li-&gt;bdxAdjust = 2;
++ li-&gt;bdyAdjust = 1;
++ }
++
++ co-&gt;height = height;
++ li-&gt;curHeight = co-&gt;height - (2 * li-&gt;bdyAdjust);
++
++ if (height) {
++ li-&gt;grow = 0;
++ if (flags &amp; NEWT_FLAG_SCROLL) {
++ sb = newtVerticalScrollbar(left, top + li-&gt;bdyAdjust,
++ li-&gt;curHeight,
++ COLORSET_LISTBOX, COLORSET_ACTLISTBOX);
++ li-&gt;sbAdjust = 3;
++ } else {
++ sb = NULL;
++ }
++ } else {
++ li-&gt;grow = 1;
++ sb = NULL;
++ }
++
++ li-&gt;sb = sb;
++ co-&gt;data = li;
++ co-&gt;isMapped = 0;
++ co-&gt;left = left;
++ co-&gt;top = top;
++ co-&gt;ops = &amp;listboxOps;
++ co-&gt;takesFocus = 1;
++ co-&gt;callback = NULL;
++
++ updateWidth(co, li, 5);
++
++ return co;
++}
++
++static inline void updateWidth(newtComponent co, struct listbox * li,
++ int maxField) {
++ li-&gt;curWidth = maxField;
++ co-&gt;width = li-&gt;curWidth + li-&gt;sbAdjust + 2 * li-&gt;bdxAdjust;
++
++ if (li-&gt;sb)
++ li-&gt;sb-&gt;left = co-&gt;left + co-&gt;width - li-&gt;bdxAdjust - 1;
++}
++
++void newtListboxSetCurrentByKey(newtComponent co, void * key) {
++ struct listbox * li = co-&gt;data;
++ struct items * item;
++ int i;
++
++ item = li-&gt;boxItems, i = 0;
++ while (item &amp;&amp; item-&gt;data != key)
++ item = item-&gt;next, i++;
++
++ if (item)
++ newtListboxSetCurrent(co, i);
++}
++
++void newtListboxSetCurrent(newtComponent co, int num)
++{
++ struct listbox * li = co-&gt;data;
++
++ if (num &gt;= li-&gt;numItems)
++ li-&gt;currItem = li-&gt;numItems - 1;
++ else if (num &lt; 0)
++ li-&gt;currItem = 0;
++ else
++ li-&gt;currItem = num;
++
++ if (li-&gt;currItem &lt; li-&gt;startShowItem)
++ li-&gt;startShowItem = li-&gt;currItem;
++ else if (li-&gt;currItem - li-&gt;startShowItem &gt; li-&gt;curHeight - 1)
++ li-&gt;startShowItem = li-&gt;currItem - li-&gt;curHeight + 1;
++ if (li-&gt;startShowItem + li-&gt;curHeight &gt; li-&gt;numItems)
++ li-&gt;startShowItem = li-&gt;numItems - li-&gt;curHeight;
++ if(li-&gt;startShowItem &lt; 0)
++ li-&gt;startShowItem = 0;
++
++ newtListboxRealSetCurrent(co);
++}
++
++static void newtListboxRealSetCurrent(newtComponent co)
++{
++ struct listbox * li = co-&gt;data;
++
++ if(li-&gt;sb)
++ newtScrollbarSet(li-&gt;sb, li-&gt;currItem + 1, li-&gt;numItems);
++ listboxDraw(co);
++ if(co-&gt;callback) co-&gt;callback(co, co-&gt;callbackData);
++}
++
++void newtListboxSetWidth(newtComponent co, int width) {
++ struct listbox * li = co-&gt;data;
++
++ co-&gt;width = width;
++ li-&gt;curWidth = co-&gt;width - li-&gt;sbAdjust - 2 * li-&gt;bdxAdjust;
++ li-&gt;userHasSetWidth = 1;
++ if (li-&gt;sb) li-&gt;sb-&gt;left = co-&gt;width + co-&gt;left - 1;
++ listboxDraw(co);
++}
++
++void * newtListboxGetCurrent(newtComponent co) {
++ struct listbox * li = co-&gt;data;
++ int i;
++ struct items *item;
++
++ for(i = 0, item = li-&gt;boxItems; item != NULL &amp;&amp; i &lt; li-&gt;currItem;
++ i++, item = item-&gt;next);
++
++ if (item)
++ return (void *)item-&gt;data;
++ else
++ return NULL;
++}
++
++void newtListboxSelectItem(newtComponent co, const void * key,
++ enum newtFlagsSense sense)
++{
++ struct listbox * li = co-&gt;data;
++ int i;
++ struct items * item;
++
++ item = li-&gt;boxItems, i = 0;
++ while (item &amp;&amp; item-&gt;data != key)
++ item = item-&gt;next, i++;
++
++ if (!item) return;
++
++ if (item-&gt;isSelected)
++ li-&gt;numSelected--;
++
++ switch(sense) {
++ case NEWT_FLAGS_RESET:
++ item-&gt;isSelected = 0; break;
++ case NEWT_FLAGS_SET:
++ item-&gt;isSelected = 1; break;
++ case NEWT_FLAGS_TOGGLE:
++ item-&gt;isSelected = !item-&gt;isSelected;
++ }
++
++ if (item-&gt;isSelected)
++ li-&gt;numSelected++;
++
++ listboxDraw(co);
++}
++
++void newtListboxClearSelection(newtComponent co)
++{
++ struct items *item;
++ struct listbox * li = co-&gt;data;
++
++ for(item = li-&gt;boxItems; item != NULL;
++ item = item-&gt;next)
++ item-&gt;isSelected = 0;
++ li-&gt;numSelected = 0;
++ listboxDraw(co);
++}
++
++/* Free the returned array after use, but NOT the values in the array */
++void ** newtListboxGetSelection(newtComponent co, int *numitems)
++{
++ struct listbox * li;
++ int i;
++ void **retval;
++ struct items *item;
++
++ if(!co || !numitems) return NULL;
++
++ li = co-&gt;data;
++ if(!li || !li-&gt;numSelected) return NULL;
++
++ retval = malloc(li-&gt;numSelected * sizeof(void *));
++ for(i = 0, item = li-&gt;boxItems; item != NULL;
++ item = item-&gt;next)
++ if(item-&gt;isSelected)
++ retval[i++] = (void *)item-&gt;data;
++ *numitems = li-&gt;numSelected;
++ return retval;
++}
++
++void newtListboxSetEntry(newtComponent co, int num, const char * text) {
++ struct listbox * li = co-&gt;data;
++ int i;
++ struct items *item;
++
++ for(i = 0, item = li-&gt;boxItems; item != NULL &amp;&amp; i &lt; num;
++ i++, item = item-&gt;next);
++
++ if(!item)
++ return;
++ else {
++ free(item-&gt;text);
++ item-&gt;text = strdup(text);
++ }
++ if (li-&gt;userHasSetWidth == 0 &amp;&amp; strlen(text) &gt; (size_t)li-&gt;curWidth) {
++ updateWidth(co, li, strlen(text));
++ }
++
++ if (num &gt;= li-&gt;startShowItem &amp;&amp; num &lt;= li-&gt;startShowItem + co-&gt;height)
++ listboxDraw(co);
++}
++
++void newtListboxSetData(newtComponent co, int num, void * data) {
++ struct listbox * li = co-&gt;data;
++ int i;
++ struct items *item;
++
++ for(i = 0, item = li-&gt;boxItems; item != NULL &amp;&amp; i &lt; num;
++ i++, item = item-&gt;next);
++
++ item-&gt;data = data;
++}
++
++int newtListboxAppendEntry(newtComponent co, const char * text,
++ const void * data) {
++ struct listbox * li = co-&gt;data;
++ struct items *item;
++
++ if(li-&gt;boxItems) {
++ for (item = li-&gt;boxItems; item-&gt;next != NULL; item = item-&gt;next);
++
++ item = item-&gt;next = malloc(sizeof(struct items));
++ } else {
++ item = li-&gt;boxItems = malloc(sizeof(struct items));
++ }
++
++ if (!li-&gt;userHasSetWidth &amp;&amp; text &amp;&amp; (strlen(text) &gt; (size_t)li-&gt;curWidth))
++ updateWidth(co, li, strlen(text));
++
++ item-&gt;text = strdup(text); item-&gt;data = data; item-&gt;next = NULL;
++ item-&gt;isSelected = 0;
++
++ if (li-&gt;grow)
++ co-&gt;height++, li-&gt;curHeight++;
++ li-&gt;numItems++;
++
++ return 0;
++}
++
++int newtListboxInsertEntry(newtComponent co, const char * text,
++ const void * data, void * key) {
++ struct listbox * li = co-&gt;data;
++ struct items *item, *t;
++
++ if (li-&gt;boxItems) {
++ if (key) {
++ item = li-&gt;boxItems;
++ while (item &amp;&amp; item-&gt;data != key) item = item-&gt;next;
++
++ if (!item) return 1;
++
++ t = item-&gt;next;
++ item = item-&gt;next = malloc(sizeof(struct items));
++ item-&gt;next = t;
++ } else {
++ t = li-&gt;boxItems;
++ item = li-&gt;boxItems = malloc(sizeof(struct items));
++ item-&gt;next = t;
++ }
++ } else if (key) {
++ return 1;
++ } else {
++ item = li-&gt;boxItems = malloc(sizeof(struct items));
++ item-&gt;next = NULL;
++ }
++
++ if (!li-&gt;userHasSetWidth &amp;&amp; text &amp;&amp; (strlen(text) &gt; (size_t)li-&gt;curWidth))
++ updateWidth(co, li, strlen(text));
++
++ item-&gt;text = strdup(text?text:&quot;(null)&quot;); item-&gt;data = data;
++ item-&gt;isSelected = 0;
++
++ if (li-&gt;sb)
++ li-&gt;sb-&gt;left = co-&gt;left + co-&gt;width - li-&gt;bdxAdjust - 1;
++ li-&gt;numItems++;
++
++ listboxDraw(co);
++
++ return 0;
++}
++
++int newtListboxDeleteEntry(newtComponent co, void * key) {
++ struct listbox * li = co-&gt;data;
++ int widest = 0, t;
++ struct items *item, *item2 = NULL;
++ int num;
++
++ if (li-&gt;boxItems == NULL || li-&gt;numItems &lt;= 0)
++ return 0;
++
++ num = 0;
++
++ item2 = NULL, item = li-&gt;boxItems;
++ while (item &amp;&amp; item-&gt;data != key) {
++ item2 = item;
++ item = item-&gt;next;
++ num++;
++ }
++
++ if (!item)
++ return -1;
++
++ if (item2)
++ item2-&gt;next = item-&gt;next;
++ else
++ li-&gt;boxItems = item-&gt;next;
++
++ free(item-&gt;text);
++ free(item);
++ li-&gt;numItems--;
++
++ if (!li-&gt;userHasSetWidth) {
++ widest = 0;
++ for (item = li-&gt;boxItems; item != NULL; item = item-&gt;next)
++ if ((t = strlen(item-&gt;text)) &gt; widest) widest = t;
++ }
++
++ if (li-&gt;currItem &gt;= num)
++ li-&gt;currItem--;
++
++ if (!li-&gt;userHasSetWidth) {
++ updateWidth(co, li, widest);
++ }
++
++ listboxDraw(co);
++
++ return 0;
++}
++
++void newtListboxClear(newtComponent co)
++{
++ struct listbox * li;
++ struct items *anitem, *nextitem;
++ if(co == NULL || (li = co-&gt;data) == NULL)
++ return;
++ for(anitem = li-&gt;boxItems; anitem != NULL; anitem = nextitem) {
++ nextitem = anitem-&gt;next;
++ free(anitem-&gt;text);
++ free(anitem);
++ }
++ li-&gt;numItems = li-&gt;numSelected = li-&gt;currItem = li-&gt;startShowItem = 0;
++ li-&gt;boxItems = NULL;
++ if (!li-&gt;userHasSetWidth)
++ updateWidth(co, li, 5);
++}
++
++/* If you don't want to get back the text, pass in NULL for the ptr-ptr. Same
++ goes for the data. */
++void newtListboxGetEntry(newtComponent co, int num, char **text, void **data) {
++ struct listbox * li = co-&gt;data;
++ int i;
++ struct items *item;
++
++ if (!li-&gt;boxItems || num &gt;= li-&gt;numItems) {
++ if(text)
++ *text = NULL;
++ if(data)
++ *data = NULL;
++ return;
++ }
++
++ i = 0;
++ item = li-&gt;boxItems;
++ while (item &amp;&amp; i &lt; num) {
++ i++, item = item-&gt;next;
++ }
++
++ if (item) {
++ if (text)
++ *text = item-&gt;text;
++ if (data)
++ *data = (void *)item-&gt;data;
++ }
++}
++
++static void listboxDraw(newtComponent co)
++{
++ struct listbox * li = co-&gt;data;
++ struct items *item;
++ int i, j;
++
++ if (!co-&gt;isMapped) return ;
++
++ if(li-&gt;flags &amp; NEWT_FLAG_BORDER) {
++ if(li-&gt;isActive)
++ SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX);
++ else
++ SLsmg_set_color(NEWT_COLORSET_LISTBOX);
++
++ newtDrawBox(co-&gt;left, co-&gt;top, co-&gt;width, co-&gt;height, 0);
++ }
++
++ if(li-&gt;sb)
++ li-&gt;sb-&gt;ops-&gt;draw(li-&gt;sb);
++
++ SLsmg_set_color(NEWT_COLORSET_LISTBOX);
++
++ for(i = 0, item = li-&gt;boxItems; item != NULL &amp;&amp; i &lt; li-&gt;startShowItem;
++ i++, item = item-&gt;next);
++
++ j = i;
++
++ for (i = 0; item != NULL &amp;&amp; i &lt; li-&gt;curHeight; i++, item = item-&gt;next) {
++ if (!item-&gt;text) continue;
++
++ newtGotorc(co-&gt;top + i + li-&gt;bdyAdjust, co-&gt;left + li-&gt;bdxAdjust);
++ if(j + i == li-&gt;currItem) {
++ if(item-&gt;isSelected)
++ SLsmg_set_color(NEWT_COLORSET_ACTSELLISTBOX);
++ else
++ SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX);
++ } else if(item-&gt;isSelected)
++ SLsmg_set_color(NEWT_COLORSET_SELLISTBOX);
++ else
++ SLsmg_set_color(NEWT_COLORSET_LISTBOX);
++
++ SLsmg_write_nstring(item-&gt;text, li-&gt;curWidth);
++
++ }
++ newtGotorc(co-&gt;top + (li-&gt;currItem - li-&gt;startShowItem), co-&gt;left);
++}
++
++static struct eventResult listboxEvent(newtComponent co, struct event ev) {
++ struct eventResult er;
++ struct listbox * li = co-&gt;data;
++ struct items *item;
++ int i;
++
++ er.result = ER_IGNORED;
++
++ if(ev.when == EV_EARLY || ev.when == EV_LATE) {
++ return er;
++ }
++
++ switch(ev.event) {
++ case EV_KEYPRESS:
++ if (!li-&gt;isActive) break;
++
++ switch(ev.u.key) {
++ case ' ':
++ if(!(li-&gt;flags &amp; NEWT_FLAG_MULTIPLE)) break;
++ newtListboxSelectItem(co, li-&gt;boxItems[li-&gt;currItem].data,
++ NEWT_FLAGS_TOGGLE);
++ er.result = ER_SWALLOWED;
++ /* We don't break here, because it is cool to be able to
++ hold space to select a bunch of items in a list at once */
++
++ case NEWT_KEY_DOWN:
++ if(li-&gt;numItems &lt;= 0) break;
++ if(li-&gt;currItem &lt; li-&gt;numItems - 1) {
++ li-&gt;currItem++;
++ if(li-&gt;currItem &gt; (li-&gt;startShowItem + li-&gt;curHeight - 1)) {
++ li-&gt;startShowItem = li-&gt;currItem - li-&gt;curHeight + 1;
++ if(li-&gt;startShowItem + li-&gt;curHeight &gt; li-&gt;numItems)
++ li-&gt;startShowItem = li-&gt;numItems - li-&gt;curHeight;
++ }
++ if(li-&gt;sb)
++ newtScrollbarSet(li-&gt;sb, li-&gt;currItem + 1, li-&gt;numItems);
++ listboxDraw(co);
++ }
++ if(co-&gt;callback) co-&gt;callback(co, co-&gt;callbackData);
++ er.result = ER_SWALLOWED;
++ break;
++
++ case NEWT_KEY_ENTER:
++ if(li-&gt;numItems &lt;= 0) break;
++ if(li-&gt;flags &amp; NEWT_FLAG_RETURNEXIT)
++ er.result = ER_EXITFORM;
++ break;
++
++ case NEWT_KEY_UP:
++ if(li-&gt;numItems &lt;= 0) break;
++ if(li-&gt;currItem &gt; 0) {
++ li-&gt;currItem--;
++ if(li-&gt;currItem &lt; li-&gt;startShowItem)
++ li-&gt;startShowItem = li-&gt;currItem;
++ if(li-&gt;sb)
++ newtScrollbarSet(li-&gt;sb, li-&gt;currItem + 1, li-&gt;numItems);
++ listboxDraw(co);
++ }
++ if(co-&gt;callback) co-&gt;callback(co, co-&gt;callbackData);
++ er.result = ER_SWALLOWED;
++ break;
++
++ case NEWT_KEY_PGUP:
++ if(li-&gt;numItems &lt;= 0) break;
++ li-&gt;startShowItem -= li-&gt;curHeight - 1;
++ if(li-&gt;startShowItem &lt; 0)
++ li-&gt;startShowItem = 0;
++ li-&gt;currItem -= li-&gt;curHeight - 1;
++ if(li-&gt;currItem &lt; 0)
++ li-&gt;currItem = 0;
++ newtListboxRealSetCurrent(co);
++ er.result = ER_SWALLOWED;
++ break;
++
++ case NEWT_KEY_PGDN:
++ if(li-&gt;numItems &lt;= 0) break;
++ li-&gt;startShowItem += li-&gt;curHeight;
++ if(li-&gt;startShowItem &gt; (li-&gt;numItems - li-&gt;curHeight)) {
++ li-&gt;startShowItem = li-&gt;numItems - li-&gt;curHeight;
++ }
++ li-&gt;currItem += li-&gt;curHeight;
++ if(li-&gt;currItem &gt;= li-&gt;numItems) {
++ li-&gt;currItem = li-&gt;numItems - 1;
++ }
++ newtListboxRealSetCurrent(co);
++ er.result = ER_SWALLOWED;
++ break;
++
++ case NEWT_KEY_HOME:
++ if(li-&gt;numItems &lt;= 0) break;
++ newtListboxSetCurrent(co, 0);
++ er.result = ER_SWALLOWED;
++ break;
++
++ case NEWT_KEY_END:
++ if(li-&gt;numItems &lt;= 0) break;
++ li-&gt;startShowItem = li-&gt;numItems - li-&gt;curHeight;
++ if(li-&gt;startShowItem &lt; 0)
++ li-&gt;startShowItem = 0;
++ li-&gt;currItem = li-&gt;numItems - 1;
++ newtListboxRealSetCurrent(co);
++ er.result = ER_SWALLOWED;
++ break;
++ default:
++ if (li-&gt;numItems &lt;= 0) break;
++ if (ev.u.key &lt; NEWT_KEY_EXTRA_BASE &amp;&amp; isalpha(ev.u.key)) {
++ for(i = 0, item = li-&gt;boxItems; item != NULL &amp;&amp;
++ i &lt; li-&gt;currItem; i++, item = item-&gt;next);
++
++ if (item &amp;&amp; item-&gt;text &amp;&amp; (toupper(*item-&gt;text) == toupper(ev.u.key))) {
++ item = item-&gt;next;
++ i++;
++ } else {
++ item = li-&gt;boxItems;
++ i = 0;
++ }
++ while (item &amp;&amp; item-&gt;text &amp;&amp;
++ toupper(*item-&gt;text) != toupper(ev.u.key)) {
++ item = item-&gt;next;
++ i++;
++ }
++ if (item) {
++ li-&gt;currItem = i;
++ if(li-&gt;currItem &lt; li-&gt;startShowItem ||
++ li-&gt;currItem &gt; li-&gt;startShowItem)
++ li-&gt;startShowItem =
++ li-&gt;currItem &gt; li-&gt;numItems - li-&gt;curHeight ?
++ li-&gt;startShowItem = li-&gt;numItems - li-&gt;curHeight :
++ li-&gt;currItem;
++ if(li-&gt;sb)
++ newtScrollbarSet(li-&gt;sb, li-&gt;currItem + 1, li-&gt;numItems);
++ newtListboxRealSetCurrent(co);
++ er.result = ER_SWALLOWED;
++ }
++ }
++ }
++ break;
++
++ case EV_FOCUS:
++ li-&gt;isActive = 1;
++ listboxDraw(co);
++ er.result = ER_SWALLOWED;
++ break;
++
++ case EV_UNFOCUS:
++ li-&gt;isActive = 0;
++ listboxDraw(co);
++ er.result = ER_SWALLOWED;
++ break;
++
++ case EV_MOUSE:
++ /* if this mouse click was within the listbox, make the current
++ item the item clicked on. */
++ /* Up scroll arrow */
++ if (li-&gt;sb &amp;&amp;
++ ev.u.mouse.x == co-&gt;left + co-&gt;width - li-&gt;bdxAdjust - 1 &amp;&amp;
++ ev.u.mouse.y == co-&gt;top + li-&gt;bdyAdjust) {
++ if(li-&gt;numItems &lt;= 0) break;
++ if(li-&gt;currItem &gt; 0) {
++ li-&gt;currItem--;
++ if(li-&gt;currItem &lt; li-&gt;startShowItem)
++ li-&gt;startShowItem = li-&gt;currItem;
++ if(li-&gt;sb)
++ newtScrollbarSet(li-&gt;sb, li-&gt;currItem + 1, li-&gt;numItems);
++ listboxDraw(co);
++ }
++ if(co-&gt;callback) co-&gt;callback(co, co-&gt;callbackData);
++ er.result = ER_SWALLOWED;
++ break;
++ }
++ /* Down scroll arrow */
++ if (li-&gt;sb &amp;&amp;
++ ev.u.mouse.x == co-&gt;left + co-&gt;width - li-&gt;bdxAdjust - 1 &amp;&amp;
++ ev.u.mouse.y == co-&gt;top + co-&gt;height - li-&gt;bdyAdjust - 1) {
++ if(li-&gt;numItems &lt;= 0) break;
++ if(li-&gt;currItem &lt; li-&gt;numItems - 1) {
++ li-&gt;currItem++;
++ if(li-&gt;currItem &gt; (li-&gt;startShowItem + li-&gt;curHeight - 1)) {
++ li-&gt;startShowItem = li-&gt;currItem - li-&gt;curHeight + 1;
++ if(li-&gt;startShowItem + li-&gt;curHeight &gt; li-&gt;numItems)
++ li-&gt;startShowItem = li-&gt;numItems - li-&gt;curHeight;
++ }
++ if(li-&gt;sb)
++ newtScrollbarSet(li-&gt;sb, li-&gt;currItem + 1, li-&gt;numItems);
++ listboxDraw(co);
++ }
++ if(co-&gt;callback) co-&gt;callback(co, co-&gt;callbackData);
++ er.result = ER_SWALLOWED;
++ break;
++ }
++ if ((ev.u.mouse.y &gt;= co-&gt;top + li-&gt;bdyAdjust) &amp;&amp;
++ (ev.u.mouse.y &lt;= co-&gt;top + co-&gt;height - (li-&gt;bdyAdjust * 2)) &amp;&amp;
++ (ev.u.mouse.x &gt;= co-&gt;left + li-&gt;bdxAdjust) &amp;&amp;
++ (ev.u.mouse.x &lt;= co-&gt;left + co-&gt;width + (li-&gt;bdxAdjust * 2))) {
++ li-&gt;currItem = li-&gt;startShowItem +
++ (ev.u.mouse.y - li-&gt;bdyAdjust - co-&gt;top);
++ newtListboxRealSetCurrent(co);
++ listboxDraw(co);
++ if(co-&gt;callback) co-&gt;callback(co, co-&gt;callbackData);
++ er.result = ER_SWALLOWED;
++ break;
++ }
++ }
++
++ return er;
++}
++
++static void listboxDestroy(newtComponent co) {
++ struct listbox * li = co-&gt;data;
++ struct items * item, * nextitem;
++
++ nextitem = item = li-&gt;boxItems;
++
++ while (item != NULL) {
++ nextitem = item-&gt;next;
++ free(item-&gt;text);
++ free(item);
++ item = nextitem;
++ }
++
++ if (li-&gt;sb) li-&gt;sb-&gt;ops-&gt;destroy(li-&gt;sb);
++
++ free(li);
++ free(co);
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/newt/listbox.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/newt/newt.c
+===================================================================
+--- drakx/trunk/mdk-stage1/newt/newt.c (rev 0)
++++ drakx/trunk/mdk-stage1/newt/newt.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,672 @@
++#include &lt;slang.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++#include &lt;sys/signal.h&gt;
++#include &lt;sys/time.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;termios.h&gt;
++#include &lt;unistd.h&gt;
++
++#include &quot;newt.h&quot;
++#include &quot;newt_pr.h&quot;
++
++struct Window {
++ int height, width, top, left;
++ short * buffer;
++ char * title;
++};
++
++struct keymap {
++ char * str;
++ int code;
++ char * tc;
++};
++
++static struct Window windowStack[20];
++static struct Window * currentWindow = NULL;
++
++static char * helplineStack[20];
++static char ** currentHelpline = NULL;
++
++static int cursorRow, cursorCol;
++static int needResize;
++static int cursorOn = 1;
++
++static const char * defaultHelpLine =
++&quot; &lt;Tab&gt;/&lt;Alt-Tab&gt; between elements | &lt;Space&gt; selects | &lt;F12&gt; next screen&quot;
++;
++
++const struct newtColors newtDefaultColorPalette = {
++ &quot;cyan&quot;, &quot;black&quot;, /* root fg, bg */
++ &quot;black&quot;, &quot;blue&quot;, /* border fg, bg */
++ &quot;white&quot;, &quot;blue&quot;, /* window fg, bg */
++ &quot;white&quot;, &quot;black&quot;, /* shadow fg, bg */
++ &quot;white&quot;, &quot;blue&quot;, /* title fg, bg */
++ &quot;black&quot;, &quot;cyan&quot;, /* button fg, bg */
++ &quot;yellow&quot;, &quot;cyan&quot;, /* active button fg, bg */
++ &quot;yellow&quot;, &quot;blue&quot;, /* checkbox fg, bg */
++ &quot;blue&quot;, &quot;brown&quot;, /* active checkbox fg, bg */
++ &quot;yellow&quot;, &quot;blue&quot;, /* entry box fg, bg */
++ &quot;white&quot;, &quot;blue&quot;, /* label fg, bg */
++ &quot;black&quot;, &quot;cyan&quot;, /* listbox fg, bg */
++ &quot;yellow&quot;, &quot;cyan&quot;, /* active listbox fg, bg */
++ &quot;white&quot;, &quot;blue&quot;, /* textbox fg, bg */
++ &quot;cyan&quot;, &quot;black&quot;, /* active textbox fg, bg */
++ &quot;white&quot;, &quot;blue&quot;, /* help line */
++ &quot;yellow&quot;, &quot;blue&quot;, /* root text */
++ &quot;blue&quot;, /* scale full */
++ &quot;red&quot;, /* scale empty */
++ &quot;blue&quot;, &quot;cyan&quot;, /* disabled entry fg, bg */
++ &quot;white&quot;, &quot;blue&quot;, /* compact button fg, bg */
++ &quot;yellow&quot;, &quot;red&quot;, /* active &amp; sel listbox */
++ &quot;black&quot;, &quot;brown&quot; /* selected listbox */
++};
++
++static const struct keymap keymap[] = {
++ { &quot;\033OA&quot;, NEWT_KEY_UP, &quot;kh&quot; },
++ { &quot;\033[A&quot;, NEWT_KEY_UP, &quot;ku&quot; },
++ { &quot;\033OB&quot;, NEWT_KEY_DOWN, &quot;kd&quot; },
++ { &quot;\033[B&quot;, NEWT_KEY_DOWN, &quot;kd&quot; },
++ { &quot;\033[C&quot;, NEWT_KEY_RIGHT, &quot;kr&quot; },
++ { &quot;\033OC&quot;, NEWT_KEY_RIGHT, &quot;kr&quot; },
++ { &quot;\033[D&quot;, NEWT_KEY_LEFT, &quot;kl&quot; },
++ { &quot;\033OD&quot;, NEWT_KEY_LEFT, &quot;kl&quot; },
++ { &quot;\033[H&quot;, NEWT_KEY_HOME, &quot;kh&quot; },
++ { &quot;\033[1~&quot;, NEWT_KEY_HOME, &quot;kh&quot; },
++ { &quot;\033Ow&quot;, NEWT_KEY_END, &quot;kH&quot; },
++ { &quot;\033[4~&quot;, NEWT_KEY_END, &quot;kH&quot; },
++
++ { &quot;\033[3~&quot;, NEWT_KEY_DELETE, &quot;kl&quot; },
++ { &quot;\033[2~&quot;, NEWT_KEY_INSERT, NULL },
++
++ { &quot;\033\t&quot;, NEWT_KEY_UNTAB, NULL },
++
++ { &quot;\033[5~&quot;, NEWT_KEY_PGUP, NULL },
++ { &quot;\033[6~&quot;, NEWT_KEY_PGDN, NULL },
++ { &quot;\033V&quot;, NEWT_KEY_PGUP, &quot;kH&quot; },
++ { &quot;\033v&quot;, NEWT_KEY_PGUP, &quot;kH&quot; },
++
++ { &quot;\033[[A&quot;, NEWT_KEY_F1, NULL },
++ { &quot;\033[[B&quot;, NEWT_KEY_F2, NULL },
++ { &quot;\033[[C&quot;, NEWT_KEY_F3, NULL },
++ { &quot;\033[[D&quot;, NEWT_KEY_F4, NULL },
++ { &quot;\033[[E&quot;, NEWT_KEY_F5, NULL },
++
++ { &quot;\033OP&quot;, NEWT_KEY_F1, NULL },
++ { &quot;\033OQ&quot;, NEWT_KEY_F2, NULL },
++ { &quot;\033OR&quot;, NEWT_KEY_F3, NULL },
++ { &quot;\033OS&quot;, NEWT_KEY_F4, NULL },
++
++ { &quot;\033[11~&quot;, NEWT_KEY_F1, NULL },
++ { &quot;\033[12~&quot;, NEWT_KEY_F2, NULL },
++ { &quot;\033[13~&quot;, NEWT_KEY_F3, NULL },
++ { &quot;\033[14~&quot;, NEWT_KEY_F4, NULL },
++ { &quot;\033[15~&quot;, NEWT_KEY_F5, NULL },
++ { &quot;\033[17~&quot;, NEWT_KEY_F6, NULL },
++ { &quot;\033[18~&quot;, NEWT_KEY_F7, NULL },
++ { &quot;\033[19~&quot;, NEWT_KEY_F8, NULL },
++ { &quot;\033[20~&quot;, NEWT_KEY_F9, NULL },
++ { &quot;\033[21~&quot;, NEWT_KEY_F10, NULL },
++ { &quot;\033[23~&quot;, NEWT_KEY_F11, NULL },
++ { &quot;\033[24~&quot;, NEWT_KEY_F12, NULL },
++
++ { NULL, 0, NULL }, /* LEAVE this one */
++};
++static char keyPrefix = '\033';
++
++static const char * version = &quot;Newt windowing library version &quot; VERSION
++ &quot; - (C) 1996-2000 Red Hat Software. &quot;
++ &quot;Redistributable under the term of the Library &quot;
++ &quot;GNU Public License. &quot;
++ &quot;Written by Erik Troan\n&quot;;
++
++static newtSuspendCallback suspendCallback = NULL;
++static void * suspendCallbackData = NULL;
++
++void newtSetSuspendCallback(newtSuspendCallback cb, void * data) {
++ suspendCallback = cb;
++ suspendCallbackData = data;
++}
++
++static void handleSigwinch(int signum __attribute__ ((unused))) {
++ needResize = 1;
++}
++
++static int getkeyInterruptHook(void) {
++ return -1;
++}
++
++void newtFlushInput(void) {
++ while (SLang_input_pending(0)) {
++ SLang_getkey();
++ }
++}
++
++void newtRefresh(void) {
++ SLsmg_refresh();
++}
++
++void newtSuspend(void) {
++ SLtt_set_cursor_visibility (1);
++ SLsmg_suspend_smg();
++ SLang_reset_tty();
++ SLtt_set_cursor_visibility (cursorOn);
++}
++
++void newtResume(void) {
++ SLsmg_resume_smg ();
++ SLsmg_refresh();
++ SLang_init_tty(0, 0, 0);
++}
++
++void newtCls(void) {
++ SLsmg_set_color(NEWT_COLORSET_ROOT);
++ SLsmg_gotorc(0, 0);
++ SLsmg_erase_eos();
++
++ newtRefresh();
++}
++
++#if defined(THIS_DOESNT_WORK)
++void newtResizeScreen(int redraw) {
++ newtPushHelpLine(&quot;&quot;);
++
++ SLtt_get_screen_size();
++ SLang_init_tty(0, 0, 0);
++
++ SLsmg_touch_lines (0, SLtt_Screen_Rows - 1);
++
++ /* I don't know why I need this */
++ SLsmg_refresh();
++
++ newtPopHelpLine();
++
++ if (redraw)
++ SLsmg_refresh();
++}
++#endif
++
++int newtInit(void) {
++ char * MonoValue, * MonoEnv = &quot;NEWT_MONO&quot;;
++
++ /* use the version variable just to be sure it gets included */
++ (void) strlen(version);
++
++ SLtt_get_terminfo();
++ SLtt_get_screen_size();
++
++ MonoValue = getenv(MonoEnv);
++ if ( MonoValue == NULL ) {
++ SLtt_Use_Ansi_Colors = 1;
++ } else {
++ SLtt_Use_Ansi_Colors = 0;
++ }
++
++ SLsmg_init_smg();
++ SLang_init_tty(0, 0, 0);
++
++ newtSetColors(newtDefaultColorPalette);
++ newtCursorOff();
++ /*initKeymap();*/
++
++ /*memset(&amp;sa, 0, sizeof(sa));
++ sa.sa_handler = handleSigwinch;
++ sigaction(SIGWINCH, &amp;sa, NULL);*/
++
++ SLsignal_intr(SIGWINCH, handleSigwinch);
++ SLang_getkey_intr_hook = getkeyInterruptHook;
++
++
++
++ return 0;
++}
++
++int newtFinished(void) {
++ SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
++ newtCursorOn();
++ SLsmg_refresh();
++ SLsmg_reset_smg();
++ SLang_reset_tty();
++
++ return 0;
++}
++
++void newtSetColors(struct newtColors colors) {
++ SLtt_set_color(NEWT_COLORSET_ROOT, &quot;&quot;, colors.rootFg, colors.rootBg);
++ SLtt_set_color(NEWT_COLORSET_BORDER, &quot;&quot;, colors.borderFg, colors.borderBg);
++ SLtt_set_color(NEWT_COLORSET_WINDOW, &quot;&quot;, colors.windowFg, colors.windowBg);
++ SLtt_set_color(NEWT_COLORSET_SHADOW, &quot;&quot;, colors.shadowFg, colors.shadowBg);
++ SLtt_set_color(NEWT_COLORSET_TITLE, &quot;&quot;, colors.titleFg, colors.titleBg);
++ SLtt_set_color(NEWT_COLORSET_BUTTON, &quot;&quot;, colors.buttonFg, colors.buttonBg);
++ SLtt_set_color(NEWT_COLORSET_ACTBUTTON, &quot;&quot;, colors.actButtonFg,
++ colors.actButtonBg);
++ SLtt_set_color(NEWT_COLORSET_CHECKBOX, &quot;&quot;, colors.checkboxFg,
++ colors.checkboxBg);
++ SLtt_set_color(NEWT_COLORSET_ACTCHECKBOX, &quot;&quot;, colors.actCheckboxFg,
++ colors.actCheckboxBg);
++ SLtt_set_color(NEWT_COLORSET_ENTRY, &quot;&quot;, colors.entryFg, colors.entryBg);
++ SLtt_set_color(NEWT_COLORSET_LABEL, &quot;&quot;, colors.labelFg, colors.labelBg);
++ SLtt_set_color(NEWT_COLORSET_LISTBOX, &quot;&quot;, colors.listboxFg,
++ colors.listboxBg);
++ SLtt_set_color(NEWT_COLORSET_ACTLISTBOX, &quot;&quot;, colors.actListboxFg,
++ colors.actListboxBg);
++ SLtt_set_color(NEWT_COLORSET_TEXTBOX, &quot;&quot;, colors.textboxFg,
++ colors.textboxBg);
++ SLtt_set_color(NEWT_COLORSET_ACTTEXTBOX, &quot;&quot;, colors.actTextboxFg,
++ colors.actTextboxBg);
++ SLtt_set_color(NEWT_COLORSET_HELPLINE, &quot;&quot;, colors.helpLineFg,
++ colors.helpLineBg);
++ SLtt_set_color(NEWT_COLORSET_ROOTTEXT, &quot;&quot;, colors.rootTextFg,
++ colors.rootTextBg);
++
++ SLtt_set_color(NEWT_COLORSET_EMPTYSCALE, &quot;&quot;, &quot;black&quot;,
++ colors.emptyScale);
++ SLtt_set_color(NEWT_COLORSET_FULLSCALE, &quot;&quot;, &quot;black&quot;,
++ colors.fullScale);
++ SLtt_set_color(NEWT_COLORSET_DISENTRY, &quot;&quot;, colors.disabledEntryFg,
++ colors.disabledEntryBg);
++
++ SLtt_set_color(NEWT_COLORSET_COMPACTBUTTON, &quot;&quot;, colors.compactButtonFg,
++ colors.compactButtonBg);
++
++ SLtt_set_color(NEWT_COLORSET_ACTSELLISTBOX, &quot;&quot;, colors.actSelListboxFg,
++ colors.actSelListboxBg);
++ SLtt_set_color(NEWT_COLORSET_SELLISTBOX, &quot;&quot;, colors.selListboxFg,
++ colors.selListboxBg);
++}
++
++int newtGetKey(void) {
++ int key;
++ char buf[10], * chptr = buf;
++ const struct keymap * curr;
++
++ do {
++ key = SLang_getkey();
++ if (key == 0xFFFF) {
++ if (needResize)
++ return NEWT_KEY_RESIZE;
++
++ /* ignore other signals */
++ continue;
++ }
++
++ if (key == NEWT_KEY_SUSPEND &amp;&amp; suspendCallback)
++ suspendCallback(suspendCallbackData);
++ } while (key == NEWT_KEY_SUSPEND);
++
++ switch (key) {
++ case 'v' | 0x80:
++ case 'V' | 0x80:
++ return NEWT_KEY_PGUP;
++
++ case 22:
++ return NEWT_KEY_PGDN;
++
++ return NEWT_KEY_BKSPC;
++ case 0x7f:
++ return NEWT_KEY_BKSPC;
++
++ case 0x08:
++ return NEWT_KEY_BKSPC;
++
++ default:
++ if (key != keyPrefix) return key;
++ }
++
++ memset(buf, 0, sizeof(buf));
++
++ *chptr++ = key;
++ while (SLang_input_pending(5)) {
++ key = SLang_getkey();
++ if (key == keyPrefix) {
++ /* he hit unknown keys too many times -- start over */
++ memset(buf, 0, sizeof(buf));
++ chptr = buf;
++ }
++
++ *chptr++ = key;
++
++ /* this search should use bsearch(), but when we only look through
++ a list of 20 (or so) keymappings, it's probably faster just to
++ do a inline linear search */
++
++ for (curr = keymap; curr-&gt;code; curr++) {
++ if (curr-&gt;str) {
++ if (!strcmp(curr-&gt;str, buf))
++ return curr-&gt;code;
++ }
++ }
++ }
++
++ for (curr = keymap; curr-&gt;code; curr++) {
++ if (curr-&gt;str) {
++ if (!strcmp(curr-&gt;str, buf))
++ return curr-&gt;code;
++ }
++ }
++
++ /* Looks like we were a bit overzealous in reading characters. Return
++ just the first character, and put everything else back in the buffer
++ for later */
++
++ chptr--;
++ while (chptr &gt; buf)
++ SLang_ungetkey(*chptr--);
++
++ return *chptr;
++}
++
++void newtWaitForKey(void) {
++ newtRefresh();
++
++ SLang_getkey();
++ newtClearKeyBuffer();
++}
++
++void newtClearKeyBuffer(void) {
++ while (SLang_input_pending(1)) {
++ SLang_getkey();
++ }
++}
++
++int newtOpenWindow(int left, int top, int width, int height,
++ const char * title) {
++ int j, row, col;
++ int n;
++ int i;
++
++ newtFlushInput();
++
++ if (!currentWindow) {
++ currentWindow = windowStack;
++ } else {
++ currentWindow++;
++ }
++
++ currentWindow-&gt;left = left;
++ currentWindow-&gt;top = top;
++ currentWindow-&gt;width = width;
++ currentWindow-&gt;height = height;
++ currentWindow-&gt;title = title ? strdup(title) : NULL;
++
++ currentWindow-&gt;buffer = malloc(sizeof(short) * (width + 3) * (height + 3));
++
++ row = top - 1;
++ col = left - 1;
++ n = 0;
++ for (j = 0; j &lt; height + 3; j++, row++) {
++ SLsmg_gotorc(row, col);
++ SLsmg_read_raw((SLsmg_Char_Type *)currentWindow-&gt;buffer + n,
++ currentWindow-&gt;width + 3);
++ n += currentWindow-&gt;width + 3;
++ }
++
++ SLsmg_set_color(NEWT_COLORSET_BORDER);
++ SLsmg_draw_box(top - 1, left - 1, height + 2, width + 2);
++
++ if (currentWindow-&gt;title) {
++ i = strlen(currentWindow-&gt;title) + 4;
++ i = ((width - i) / 2) + left;
++ SLsmg_gotorc(top - 1, i);
++ SLsmg_set_char_set(1);
++ SLsmg_write_char(SLSMG_RTEE_CHAR);
++ SLsmg_set_char_set(0);
++ SLsmg_write_char(' ');
++ SLsmg_set_color(NEWT_COLORSET_TITLE);
++ SLsmg_write_string((char *)currentWindow-&gt;title);
++ SLsmg_set_color(NEWT_COLORSET_BORDER);
++ SLsmg_write_char(' ');
++ SLsmg_set_char_set(1);
++ SLsmg_write_char(SLSMG_LTEE_CHAR);
++ SLsmg_set_char_set(0);
++ }
++
++ SLsmg_set_color(NEWT_COLORSET_WINDOW);
++ SLsmg_fill_region(top, left, height, width, ' ');
++
++ SLsmg_set_color(NEWT_COLORSET_SHADOW);
++ SLsmg_fill_region(top + height + 1, left, 1, width + 2, ' ');
++ SLsmg_fill_region(top, left + width + 1, height + 1, 1, ' ');
++
++ for (i = top; i &lt; (top + height + 1); i++) {
++ SLsmg_gotorc(i, left + width + 1);
++ SLsmg_write_string(&quot; &quot;);
++ }
++
++ return 0;
++}
++
++int newtCenteredWindow(int width, int height, const char * title) {
++ int top, left;
++
++ top = (SLtt_Screen_Rows - height) / 2;
++
++ /* I don't know why, but this seems to look better */
++ if ((SLtt_Screen_Rows % 2) &amp;&amp; (top % 2)) top--;
++
++ left = (SLtt_Screen_Cols - width) / 2;
++
++ newtOpenWindow(left, top, width, height, title);
++
++ return 0;
++}
++
++void newtPopWindow(void) {
++ int j, row, col;
++ int n = 0;
++
++ row = col = 0;
++
++ row = currentWindow-&gt;top - 1;
++ col = currentWindow-&gt;left - 1;
++ for (j = 0; j &lt; currentWindow-&gt;height + 3; j++, row++) {
++ SLsmg_gotorc(row, col);
++ SLsmg_write_raw((SLsmg_Char_Type *)currentWindow-&gt;buffer + n,
++ currentWindow-&gt;width + 3);
++ n += currentWindow-&gt;width + 3;
++ }
++
++ free(currentWindow-&gt;buffer);
++ free(currentWindow-&gt;title);
++
++ if (currentWindow == windowStack)
++ currentWindow = NULL;
++ else
++ currentWindow--;
++
++ SLsmg_set_char_set(0);
++
++ newtRefresh();
++}
++
++void newtGetWindowPos(int * x, int * y) {
++ if (currentWindow) {
++ *x = currentWindow-&gt;left;
++ *y = currentWindow-&gt;top;
++ } else
++ *x = *y = 0;
++}
++
++void newtGetrc(int * row, int * col) {
++ *row = cursorRow;
++ *col = cursorCol;
++}
++
++void newtGotorc(int newRow, int newCol) {
++ if (currentWindow) {
++ newRow += currentWindow-&gt;top;
++ newCol += currentWindow-&gt;left;
++ }
++
++ cursorRow = newRow;
++ cursorCol = newCol;
++ SLsmg_gotorc(cursorRow, cursorCol);
++}
++
++void newtDrawBox(int left, int top, int width, int height, int shadow) {
++ if (currentWindow) {
++ top += currentWindow-&gt;top;
++ left += currentWindow-&gt;left;
++ }
++
++ SLsmg_draw_box(top, left, height, width);
++
++ if (shadow) {
++ SLsmg_set_color(NEWT_COLORSET_SHADOW);
++ SLsmg_fill_region(top + height, left + 1, 1, width - 1, ' ');
++ SLsmg_fill_region(top + 1, left + width, height, 1, ' ');
++ }
++}
++
++void newtClearBox(int left, int top, int width, int height) {
++ if (currentWindow) {
++ top += currentWindow-&gt;top;
++ left += currentWindow-&gt;left;
++ }
++
++ SLsmg_fill_region(top, left, height, width, ' ');
++}
++
++#if 0
++/* This doesn't seem to work quite right. I don't know why not, but when
++ I rsh from an rxvt into a box and run this code, the machine returns
++ console key's (\033[B) rather then xterm ones (\033OB). */
++static void initKeymap(void) {
++ struct keymap * curr;
++
++ for (curr = keymap; curr-&gt;code; curr++) {
++ if (!curr-&gt;str)
++ curr-&gt;str = SLtt_tgetstr(curr-&gt;tc);
++ }
++
++ /* Newt's keymap handling is a bit broken. It assumes that any extended
++ keystrokes begin with ESC. If you're using a homebrek terminal you
++ will probably need to fix this, or just yell at me and I'll be so
++ ashamed of myself for doing it this way I'll fix it */
++
++ keyPrefix = 0x1b; /* ESC */
++}
++#endif
++
++void newtDelay(int usecs) {
++ fd_set set;
++ struct timeval tv;
++
++ FD_ZERO(&amp;set);
++
++ tv.tv_sec = usecs / 1000000;
++ tv.tv_usec = usecs % 1000000;
++
++ select(0, &amp;set, &amp;set, &amp;set, &amp;tv);
++}
++
++struct eventResult newtDefaultEventHandler(newtComponent c __attribute__ ((unused)),
++ struct event ev __attribute__ ((unused))) {
++ struct eventResult er;
++
++ er.result = ER_IGNORED;
++ return er;
++}
++
++void newtRedrawHelpLine(void) {
++ char * buf;
++
++ SLsmg_set_color(NEWT_COLORSET_HELPLINE);
++
++ buf = alloca(SLtt_Screen_Cols + 1);
++ memset(buf, ' ', SLtt_Screen_Cols);
++ buf[SLtt_Screen_Cols] = '\0';
++
++ if (currentHelpline)
++ memcpy(buf, *currentHelpline, strlen(*currentHelpline));
++
++ SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
++ SLsmg_write_string(buf);
++}
++
++void newtPushHelpLine(const char * text) {
++ if (!text)
++ text = defaultHelpLine;
++
++ if (currentHelpline)
++ (*(++currentHelpline)) = strdup(text);
++ else {
++ currentHelpline = helplineStack;
++ *currentHelpline = strdup(text);
++ }
++
++ newtRedrawHelpLine();
++}
++
++void newtPopHelpLine(void) {
++ if (!currentHelpline) return;
++
++ free(*currentHelpline);
++ if (currentHelpline == helplineStack)
++ currentHelpline = NULL;
++ else
++ currentHelpline--;
++
++ newtRedrawHelpLine();
++}
++
++void newtDrawRootText(int col, int row, const char * text) {
++ SLsmg_set_color(NEWT_COLORSET_ROOTTEXT);
++
++ if (col &lt; 0) {
++ col = SLtt_Screen_Cols + col;
++ }
++
++ if (row &lt; 0) {
++ row = SLtt_Screen_Rows + row;
++ }
++
++ SLsmg_gotorc(row, col);
++ SLsmg_write_string((char *)text);
++}
++
++int newtSetFlags(int oldFlags, int newFlags, enum newtFlagsSense sense) {
++ switch (sense) {
++ case NEWT_FLAGS_SET:
++ return oldFlags | newFlags;
++
++ case NEWT_FLAGS_RESET:
++ return oldFlags &amp; (~newFlags);
++
++ case NEWT_FLAGS_TOGGLE:
++ return oldFlags ^ newFlags;
++
++ default:
++ return oldFlags;
++ }
++}
++
++void newtBell(void)
++{
++ SLtt_beep();
++}
++
++void newtGetScreenSize(int * cols, int * rows) {
++ if (rows) *rows = SLtt_Screen_Rows;
++ if (cols) *cols = SLtt_Screen_Cols;
++}
++
++void newtDefaultPlaceHandler(newtComponent c, int newLeft, int newTop) {
++ c-&gt;left = newLeft;
++ c-&gt;top = newTop;
++}
++
++void newtDefaultMappedHandler(newtComponent c, int isMapped) {
++ c-&gt;isMapped = isMapped;
++}
++
++void newtCursorOff(void) {
++ cursorOn = 0;
++ SLtt_set_cursor_visibility (cursorOn);
++}
++
++void newtCursorOn(void) {
++ cursorOn = 1;
++ SLtt_set_cursor_visibility (cursorOn);
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/newt/newt.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/newt/newt.h
+===================================================================
+--- drakx/trunk/mdk-stage1/newt/newt.h (rev 0)
++++ drakx/trunk/mdk-stage1/newt/newt.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,362 @@
++#ifndef H_NEWT
++#define H_NEWT
++
++#ifdef __cplusplus
++extern &quot;C&quot; {
++#endif
++
++#include &lt;stdarg.h&gt;
++
++#define NEWT_COLORSET_ROOT 2
++#define NEWT_COLORSET_BORDER 3
++#define NEWT_COLORSET_WINDOW 4
++#define NEWT_COLORSET_SHADOW 5
++#define NEWT_COLORSET_TITLE 6
++#define NEWT_COLORSET_BUTTON 7
++#define NEWT_COLORSET_ACTBUTTON 8
++#define NEWT_COLORSET_CHECKBOX 9
++#define NEWT_COLORSET_ACTCHECKBOX 10
++#define NEWT_COLORSET_ENTRY 11
++#define NEWT_COLORSET_LABEL 12
++#define NEWT_COLORSET_LISTBOX 13
++#define NEWT_COLORSET_ACTLISTBOX 14
++#define NEWT_COLORSET_TEXTBOX 15
++#define NEWT_COLORSET_ACTTEXTBOX 16
++#define NEWT_COLORSET_HELPLINE 17
++#define NEWT_COLORSET_ROOTTEXT 18
++#define NEWT_COLORSET_EMPTYSCALE 19
++#define NEWT_COLORSET_FULLSCALE 20
++#define NEWT_COLORSET_DISENTRY 21
++#define NEWT_COLORSET_COMPACTBUTTON 22
++#define NEWT_COLORSET_ACTSELLISTBOX 23
++#define NEWT_COLORSET_SELLISTBOX 24
++
++#define NEWT_ARG_LAST -100000
++#define NEWT_ARG_APPEND -1
++
++struct newtColors {
++ char * rootFg, * rootBg;
++ char * borderFg, * borderBg;
++ char * windowFg, * windowBg;
++ char * shadowFg, * shadowBg;
++ char * titleFg, * titleBg;
++ char * buttonFg, * buttonBg;
++ char * actButtonFg, * actButtonBg;
++ char * checkboxFg, * checkboxBg;
++ char * actCheckboxFg, * actCheckboxBg;
++ char * entryFg, * entryBg;
++ char * labelFg, * labelBg;
++ char * listboxFg, * listboxBg;
++ char * actListboxFg, * actListboxBg;
++ char * textboxFg, * textboxBg;
++ char * actTextboxFg, * actTextboxBg;
++ char * helpLineFg, * helpLineBg;
++ char * rootTextFg, * rootTextBg;
++ char * emptyScale, * fullScale;
++ char * disabledEntryFg, * disabledEntryBg;
++ char * compactButtonFg, * compactButtonBg;
++ char * actSelListboxFg, * actSelListboxBg;
++ char * selListboxFg, * selListboxBg;
++};
++
++enum newtFlagsSense { NEWT_FLAGS_SET, NEWT_FLAGS_RESET, NEWT_FLAGS_TOGGLE };
++
++#define NEWT_FLAG_RETURNEXIT (1 &lt;&lt; 0)
++#define NEWT_FLAG_HIDDEN (1 &lt;&lt; 1)
++#define NEWT_FLAG_SCROLL (1 &lt;&lt; 2)
++#define NEWT_FLAG_DISABLED (1 &lt;&lt; 3)
++/* OBSOLETE #define NEWT_FLAG_NOSCROLL (1 &lt;&lt; 4) for listboxes */
++#define NEWT_FLAG_BORDER (1 &lt;&lt; 5)
++#define NEWT_FLAG_WRAP (1 &lt;&lt; 6)
++#define NEWT_FLAG_NOF12 (1 &lt;&lt; 7)
++#define NEWT_FLAG_MULTIPLE (1 &lt;&lt; 8)
++#define NEWT_FLAG_SELECTED (1 &lt;&lt; 9)
++#define NEWT_FLAG_CHECKBOX (1 &lt;&lt; 10)
++#define NEWT_FLAG_PASSWORD (1 &lt;&lt; 11) /* draw '*' of chars in entrybox */
++#define NEWT_FD_READ (1 &lt;&lt; 0)
++#define NEWT_FD_WRITE (1 &lt;&lt; 1)
++
++#define NEWT_CHECKBOXTREE_COLLAPSED '\0'
++#define NEWT_CHECKBOXTREE_EXPANDED '\1'
++#define NEWT_CHECKBOXTREE_UNSELECTED ' '
++#define NEWT_CHECKBOXTREE_SELECTED '*'
++
++/* Backwards compatibility */
++#define NEWT_LISTBOX_RETURNEXIT NEWT_FLAG_RETURNEXIT
++#define NEWT_ENTRY_SCROLL NEWT_FLAG_SCROLL
++#define NEWT_ENTRY_HIDDEN NEWT_FLAG_HIDDEN
++#define NEWT_ENTRY_RETURNEXIT NEWT_FLAG_RETURNEXIT
++#define NEWT_ENTRY_DISABLED NEWT_FLAG_DISABLED
++
++#define NEWT_TEXTBOX_WRAP NEWT_FLAG_WRAP
++#define NEWT_TEXTBOX_SCROLL NEWT_FLAG_SCROLL
++#define NEWT_FORM_NOF12 NEWT_FLAG_NOF12
++
++#define newtListboxAddEntry newtListboxAppendEntry
++
++
++typedef struct newtComponent_struct * newtComponent;
++
++extern const struct newtColors newtDefaultColorPalette;
++
++typedef void (*newtCallback)(newtComponent, void *);
++typedef void (*newtSuspendCallback)(void * data);
++
++int newtInit(void);
++int newtFinished(void);
++void newtCls(void);
++void newtResizeScreen(int redraw);
++void newtWaitForKey(void);
++void newtClearKeyBuffer(void);
++void newtDelay(int usecs);
++/* top, left are *not* counting the border */
++int newtOpenWindow(int left, int top, int width, int height,
++ const char * title);
++int newtCenteredWindow(int width, int height, const char * title);
++void newtPopWindow(void);
++void newtSetColors(struct newtColors colors);
++void newtRefresh(void);
++void newtSuspend(void);
++void newtSetSuspendCallback(newtSuspendCallback cb, void * data);
++void newtSetHelpCallback(newtCallback cb);
++void newtResume(void);
++void newtPushHelpLine(const char * text);
++void newtRedrawHelpLine(void);
++void newtPopHelpLine(void);
++void newtDrawRootText(int col, int row, const char * text);
++void newtBell(void);
++void newtCursorOff(void);
++void newtCursorOn(void);
++
++/* Components */
++
++newtComponent newtCompactButton(int left, int top, const char * text);
++newtComponent newtButton(int left, int top, const char * text);
++newtComponent newtCheckbox(int left, int top, const char * text, char defValue,
++ const char * seq, char * result);
++char newtCheckboxGetValue(newtComponent co);
++void newtCheckboxSetValue(newtComponent co, char value);
++void newtCheckboxSetFlags(newtComponent co, int flags, enum newtFlagsSense sense);
++
++
++newtComponent newtRadiobutton(int left, int top, const char * text, int isDefault,
++ newtComponent prevButton);
++newtComponent newtRadioGetCurrent(newtComponent setMember);
++newtComponent newtListitem(int left, int top, const char * text, int isDefault,
++ newtComponent prevItem, const void * data, int flags);
++void newtListitemSet(newtComponent co, const char * text);
++void * newtListitemGetData(newtComponent co);
++void newtGetScreenSize(int * cols, int * rows);
++
++newtComponent newtLabel(int left, int top, const char * text);
++void newtLabelSetText(newtComponent co, const char * text);
++newtComponent newtVerticalScrollbar(int left, int top, int height,
++ int normalColorset, int thumbColorset);
++void newtScrollbarSet(newtComponent co, int where, int total);
++
++newtComponent newtListbox(int left, int top, int height, int flags);
++void * newtListboxGetCurrent(newtComponent co);
++void newtListboxSetCurrent(newtComponent co, int num);
++void newtListboxSetCurrentByKey(newtComponent co, void * key);
++void newtListboxSetEntry(newtComponent co, int num, const char * text);
++void newtListboxSetWidth(newtComponent co, int width);
++void newtListboxSetData(newtComponent co, int num, void * data);
++int newtListboxAppendEntry(newtComponent co, const char * text,
++ const void * data);
++/* Send the key to insert after, or NULL to insert at the top */
++int newtListboxInsertEntry(newtComponent co, const char * text, const void * data, void * key);
++int newtListboxDeleteEntry(newtComponent co, void * data);
++void newtListboxClear(newtComponent co); /* removes all entries from listbox */
++void newtListboxGetEntry(newtComponent co, int num, char **text, void **data);
++/* Returns an array of data pointers from items, last element is NULL */
++void **newtListboxGetSelection(newtComponent co, int *numitems);
++void newtListboxClearSelection(newtComponent co);
++void newtListboxSelectItem(newtComponent co, const void * key,
++ enum newtFlagsSense sense);
++
++newtComponent newtCheckboxTree(int left, int top, int height, int flags);
++newtComponent newtCheckboxTreeMulti(int left, int top, int height, char *seq, int flags);
++const void ** newtCheckboxTreeGetSelection(newtComponent co, int *numitems);
++const void * newtCheckboxTreeGetCurrent(newtComponent co);
++const void ** newtCheckboxTreeGetMultiSelection(newtComponent co, int *numitems, char seqnum);
++/* last item is NEWT_ARG_LAST for all of these */
++int newtCheckboxTreeAddItem(newtComponent co,
++ const char * text, const void * data,
++ int flags, int index, ...);
++int newtCheckboxTreeAddArray(newtComponent co,
++ const char * text, const void * data,
++ int flags, int * indexes);
++int * newtCheckboxTreeFindItem(newtComponent co, void * data);
++void newtCheckboxTreeSetEntry(newtComponent co, const void * data,
++ const char * text);
++char newtCheckboxTreeGetEntryValue(newtComponent co, const void * data);
++void newtCheckboxTreeSetEntryValue(newtComponent co, const void * data,
++ char value);
++
++newtComponent newtTextboxReflowed(int left, int top, char * text, int width,
++ int flexDown, int flexUp, int flags);
++newtComponent newtTextbox(int left, int top, int width, int height, int flags);
++void newtTextboxSetText(newtComponent co, const char * text);
++void newtTextboxSetHeight(newtComponent co, int height);
++int newtTextboxGetNumLines(newtComponent co);
++char * newtReflowText(char * text, int width, int flexDown, int flexUp,
++ int * actualWidth, int * actualHeight);
++
++struct newtExitStruct {
++ enum { NEWT_EXIT_HOTKEY, NEWT_EXIT_COMPONENT, NEWT_EXIT_FDREADY,
++ NEWT_EXIT_TIMER } reason;
++ union {
++ int key;
++ newtComponent co;
++ } u;
++} ;
++
++newtComponent newtForm(newtComponent vertBar, void * helpTag, int flags);
++void newtFormSetTimer(newtComponent form, int millisecs);
++void newtFormWatchFd(newtComponent form, int fd, int fdFlags);
++void newtFormSetSize(newtComponent co);
++newtComponent newtFormGetCurrent(newtComponent co);
++void newtFormSetBackground(newtComponent co, int color);
++void newtFormSetCurrent(newtComponent co, newtComponent subco);
++void newtFormAddComponent(newtComponent form, newtComponent co);
++void newtFormAddComponents(newtComponent form, ...);
++void newtFormSetHeight(newtComponent co, int height);
++void newtFormSetWidth(newtComponent co, int width);
++newtComponent newtRunForm(newtComponent form); /* obsolete */
++void newtFormRun(newtComponent co, struct newtExitStruct * es);
++void newtDrawForm(newtComponent form);
++void newtFormAddHotKey(newtComponent co, int key);
++
++typedef int (*newtEntryFilter)(newtComponent entry, void * data, int ch,
++ int cursor);
++newtComponent newtEntry(int left, int top, const char * initialValue, int width,
++ char ** resultPtr, int flags);
++void newtEntrySet(newtComponent co, const char * value, int cursorAtEnd);
++void newtEntrySetFilter(newtComponent co, newtEntryFilter filter, void * data);
++char * newtEntryGetValue(newtComponent co);
++void newtEntrySetFlags(newtComponent co, int flags, enum newtFlagsSense sense);
++
++newtComponent newtScale(int left, int top, int width, int fullValue);
++void newtScaleSet(newtComponent co, unsigned int amount);
++
++void newtComponentAddCallback(newtComponent co, newtCallback f, void * data);
++void newtComponentTakesFocus(newtComponent co, int val);
++
++/* this also destroys all of the components (including other forms) on the
++ form */
++void newtFormDestroy(newtComponent form);
++
++/* Key codes */
++
++#define NEWT_KEY_TAB '\t'
++#define NEWT_KEY_ENTER '\r'
++#define NEWT_KEY_SUSPEND '\032' /* ctrl - z*/
++#define NEWT_KEY_RETURN NEWT_KEY_ENTER
++
++#define NEWT_KEY_EXTRA_BASE 0x8000
++#define NEWT_KEY_UP NEWT_KEY_EXTRA_BASE + 1
++#define NEWT_KEY_DOWN NEWT_KEY_EXTRA_BASE + 2
++#define NEWT_KEY_LEFT NEWT_KEY_EXTRA_BASE + 4
++#define NEWT_KEY_RIGHT NEWT_KEY_EXTRA_BASE + 5
++#define NEWT_KEY_BKSPC NEWT_KEY_EXTRA_BASE + 6
++#define NEWT_KEY_DELETE NEWT_KEY_EXTRA_BASE + 7
++#define NEWT_KEY_HOME NEWT_KEY_EXTRA_BASE + 8
++#define NEWT_KEY_END NEWT_KEY_EXTRA_BASE + 9
++#define NEWT_KEY_UNTAB NEWT_KEY_EXTRA_BASE + 10
++#define NEWT_KEY_PGUP NEWT_KEY_EXTRA_BASE + 11
++#define NEWT_KEY_PGDN NEWT_KEY_EXTRA_BASE + 12
++#define NEWT_KEY_INSERT NEWT_KEY_EXTRA_BASE + 13
++
++#define NEWT_KEY_F1 NEWT_KEY_EXTRA_BASE + 101
++#define NEWT_KEY_F2 NEWT_KEY_EXTRA_BASE + 102
++#define NEWT_KEY_F3 NEWT_KEY_EXTRA_BASE + 103
++#define NEWT_KEY_F4 NEWT_KEY_EXTRA_BASE + 104
++#define NEWT_KEY_F5 NEWT_KEY_EXTRA_BASE + 105
++#define NEWT_KEY_F6 NEWT_KEY_EXTRA_BASE + 106
++#define NEWT_KEY_F7 NEWT_KEY_EXTRA_BASE + 107
++#define NEWT_KEY_F8 NEWT_KEY_EXTRA_BASE + 108
++#define NEWT_KEY_F9 NEWT_KEY_EXTRA_BASE + 109
++#define NEWT_KEY_F10 NEWT_KEY_EXTRA_BASE + 110
++#define NEWT_KEY_F11 NEWT_KEY_EXTRA_BASE + 111
++#define NEWT_KEY_F12 NEWT_KEY_EXTRA_BASE + 112
++
++/* not really a key, but newtGetKey returns it */
++#define NEWT_KEY_RESIZE NEWT_KEY_EXTRA_BASE + 113
++
++#define NEWT_ANCHOR_LEFT (1 &lt;&lt; 0)
++#define NEWT_ANCHOR_RIGHT (1 &lt;&lt; 1)
++#define NEWT_ANCHOR_TOP (1 &lt;&lt; 2)
++#define NEWT_ANCHOR_BOTTOM (1 &lt;&lt; 3)
++
++#define NEWT_GRID_FLAG_GROWX (1 &lt;&lt; 0)
++#define NEWT_GRID_FLAG_GROWY (1 &lt;&lt; 1)
++
++typedef struct grid_s * newtGrid;
++enum newtGridElement { NEWT_GRID_EMPTY = 0,
++ NEWT_GRID_COMPONENT, NEWT_GRID_SUBGRID };
++
++newtGrid newtCreateGrid(int cols, int rows);
++/* TYPE, what, TYPE, what, ..., NULL */
++newtGrid newtGridVStacked(enum newtGridElement type, void * what, ...);
++newtGrid newtGridVCloseStacked(enum newtGridElement type, void * what, ...);
++newtGrid newtGridHStacked(enum newtGridElement type1, void * what1, ...);
++newtGrid newtGridHCloseStacked(enum newtGridElement type1, void * what1, ...);
++newtGrid newtGridBasicWindow(newtComponent text, newtGrid middle,
++ newtGrid buttons);
++newtGrid newtGridSimpleWindow(newtComponent text, newtComponent middle,
++ newtGrid buttons);
++void newtGridSetField(newtGrid grid, int col, int row,
++ enum newtGridElement type, void * val, int padLeft,
++ int padTop, int padRight, int padBottom, int anchor,
++ int flags);
++void newtGridPlace(newtGrid grid, int left, int top);
++#define newtGridDestroy newtGridFree
++void newtGridFree(newtGrid grid, int recurse);
++void newtGridGetSize(newtGrid grid, int * width, int * height);
++void newtGridWrappedWindow(newtGrid grid, char * title);
++void newtGridWrappedWindowAt(newtGrid grid, char * title, int left, int top);
++void newtGridAddComponentsToForm(newtGrid grid, newtComponent form,
++ int recurse);
++
++/* convienve */
++newtGrid newtButtonBarv(char * button1, newtComponent * b1comp, va_list args);
++newtGrid newtButtonBar(char * button1, newtComponent * b1comp, ...);
++
++/* automatically centered and shrink wrapped */
++void newtWinMessage(char * title, char * buttonText, char * text, ...);
++void newtWinMessagev(char * title, char * buttonText, char * text,
++ va_list argv);
++
++/* having separate calls for these two seems silly, but having two separate
++ variable length-arg lists seems like a bad idea as well */
++
++/* Returns 0 if F12 was pressed, 1 for button1, 2 for button2 */
++int newtWinChoice(char * title, char * button1, char * button2,
++ char * text, ...);
++/* Returns 0 if F12 was pressed, 1 for button1, 2 for button2,
++ 3 for button3 */
++int newtWinTernary(char * title, char * button1, char * button2,
++ char * button3, char * message, ...);
++
++/* Returns the button number pressed, 0 on F12 */
++int newtWinMenu(char * title, char * text, int suggestedWidth, int flexDown,
++ int flexUp, int maxListHeight, char ** items, int * listItem,
++ char * button1, ...);
++
++struct newtWinEntry {
++ char * text;
++ char ** value; /* may be initialized to set default */
++ int flags;
++};
++
++/* Returns the button number pressed, 0 on F12. The final values are
++ dynamically allocated, and need to be freed. */
++int newtWinEntries(char * title, char * text, int suggestedWidth, int flexDown,
++ int flexUp, int dataWidth,
++ struct newtWinEntry * items, char * button1, ...);
++
++#ifdef __cplusplus
++} /* End of extern &quot;C&quot; { */
++#endif
++
++#endif /* H_NEWT */
+
+
+Property changes on: drakx/trunk/mdk-stage1/newt/newt.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/newt/newt_pr.h
+===================================================================
+--- drakx/trunk/mdk-stage1/newt/newt_pr.h (rev 0)
++++ drakx/trunk/mdk-stage1/newt/newt_pr.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,82 @@
++#ifndef H_NEWT_PR
++#define H_NEWT_PR
++
++#define COLORSET_ROOT NEWT_COLORSET_ROOT
++#define COLORSET_BORDER NEWT_COLORSET_BORDER
++#define COLORSET_WINDOW NEWT_COLORSET_WINDOW
++#define COLORSET_SHADOW NEWT_COLORSET_SHADOW
++#define COLORSET_TITLE NEWT_COLORSET_TITLE
++#define COLORSET_BUTTON NEWT_COLORSET_BUTTON
++#define COLORSET_ACTBUTTON NEWT_COLORSET_ACTBUTTON
++#define COLORSET_CHECKBOX NEWT_COLORSET_CHECKBOX
++#define COLORSET_ACTCHECKBOX NEWT_COLORSET_ACTCHECKBOX
++#define COLORSET_ENTRY NEWT_COLORSET_ENTRY
++#define COLORSET_LABEL NEWT_COLORSET_LABEL
++#define COLORSET_LISTBOX NEWT_COLORSET_LISTBOX
++#define COLORSET_ACTLISTBOX NEWT_COLORSET_ACTLISTBOX
++#define COLORSET_TEXTBOX NEWT_COLORSET_TEXTBOX
++#define COLORSET_ACTTEXTBOX NEWT_COLORSET_ACTTEXTBOX
++
++int newtSetFlags(int oldFlags, int newFlags, enum newtFlagsSense sense);
++
++void newtGotorc(int row, int col);
++void newtGetrc(int * row, int * col);
++void newtGetWindowPos(int * x, int * y);
++void newtDrawBox(int left, int top, int width, int height, int shadow);
++void newtClearBox(int left, int top, int width, int height);
++
++int newtGetKey(void);
++
++struct newtComponent_struct {
++ /* common data */
++ int height, width;
++ int top, left;
++ int takesFocus;
++ int isMapped;
++
++ struct componentOps * ops;
++
++ newtCallback callback;
++ void * callbackData;
++
++ void * data;
++} ;
++
++enum eventResultTypes { ER_IGNORED, ER_SWALLOWED, ER_EXITFORM, ER_SETFOCUS,
++ ER_NEXTCOMP };
++struct eventResult {
++ enum eventResultTypes result;
++ union {
++ newtComponent focus;
++ } u;
++};
++
++enum eventTypes { EV_FOCUS, EV_UNFOCUS, EV_KEYPRESS, EV_MOUSE };
++enum eventSequence { EV_EARLY, EV_NORMAL, EV_LATE };
++
++struct event {
++ enum eventTypes event;
++ enum eventSequence when;
++ union {
++ int key;
++ struct {
++ enum { MOUSE_MOTION, MOUSE_BUTTON_DOWN, MOUSE_BUTTON_UP } type;
++ int x, y;
++ } mouse;
++ } u;
++} ;
++
++struct componentOps {
++ void (* draw)(newtComponent c);
++ struct eventResult (* event)(newtComponent c, struct event ev);
++ void (* destroy)(newtComponent c);
++ void (* place)(newtComponent c, int newLeft, int newTop);
++ void (* mapped)(newtComponent c, int isMapped);
++} ;
++
++void newtDefaultPlaceHandler(newtComponent c, int newLeft, int newTop);
++void newtDefaultMappedHandler(newtComponent c, int isMapped);
++struct eventResult newtDefaultEventHandler(newtComponent c,
++ struct event ev);
++
++#endif /* H_NEWT_PR */
+
+
+Property changes on: drakx/trunk/mdk-stage1/newt/newt_pr.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/newt/scale.c
+===================================================================
+--- drakx/trunk/mdk-stage1/newt/scale.c (rev 0)
++++ drakx/trunk/mdk-stage1/newt/scale.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,72 @@
++#include &lt;slang.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++
++#include &quot;newt.h&quot;
++#include &quot;newt_pr.h&quot;
++
++struct scale {
++ int fullValue;
++ int charsSet;
++};
++
++static void scaleDraw(newtComponent co);
++
++static struct componentOps scaleOps = {
++ scaleDraw,
++ newtDefaultEventHandler,
++ NULL,
++ newtDefaultPlaceHandler,
++ newtDefaultMappedHandler,
++} ;
++
++newtComponent newtScale(int left, int top, int width, int fullValue) {
++ newtComponent co;
++ struct scale * sc;
++
++ co = malloc(sizeof(*co));
++ sc = malloc(sizeof(struct scale));
++ co-&gt;data = sc;
++
++ co-&gt;ops = &amp;scaleOps;
++
++ co-&gt;height = 1;
++ co-&gt;width = width;
++ co-&gt;top = top;
++ co-&gt;left = left;
++ co-&gt;takesFocus = 0;
++
++ sc-&gt;fullValue = fullValue;
++ sc-&gt;charsSet = 0;
++
++ return co;
++}
++
++void newtScaleSet(newtComponent co, unsigned int amount) {
++ struct scale * sc = co-&gt;data;
++ int newCharsSet;
++
++ newCharsSet = (amount * co-&gt;width) / sc-&gt;fullValue;
++
++ if (newCharsSet != sc-&gt;charsSet) {
++ sc-&gt;charsSet = newCharsSet;
++ scaleDraw(co);
++ }
++}
++
++static void scaleDraw(newtComponent co) {
++ struct scale * sc = co-&gt;data;
++ int i;
++
++ if (co-&gt;top == -1) return;
++
++ newtGotorc(co-&gt;top, co-&gt;left);
++
++ SLsmg_set_color(NEWT_COLORSET_FULLSCALE);
++ for (i = 0; i &lt; sc-&gt;charsSet; i++)
++ SLsmg_write_string(&quot; &quot;);
++
++ SLsmg_set_color(NEWT_COLORSET_EMPTYSCALE);
++ for (i = 0; i &lt; (co-&gt;width - sc-&gt;charsSet); i++)
++ SLsmg_write_string(&quot; &quot;);
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/newt/scale.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/newt/scrollbar.c
+===================================================================
+--- drakx/trunk/mdk-stage1/newt/scrollbar.c (rev 0)
++++ drakx/trunk/mdk-stage1/newt/scrollbar.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,124 @@
++#include &lt;slang.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++
++#include &quot;newt.h&quot;
++#include &quot;newt_pr.h&quot;
++
++struct scrollbar {
++ int curr;
++ int cs, csThumb;
++ int arrows;
++} ;
++
++static void sbDraw(newtComponent co);
++static void sbDestroy(newtComponent co);
++static void sbDrawThumb(newtComponent co, int isOn);
++
++static struct componentOps sbOps = {
++ sbDraw,
++ newtDefaultEventHandler,
++ sbDestroy,
++ newtDefaultPlaceHandler,
++ newtDefaultMappedHandler,
++} ;
++
++void newtScrollbarSet(newtComponent co, int where, int total) {
++ struct scrollbar * sb = co-&gt;data;
++ int new;
++
++ if (sb-&gt;arrows)
++ new = (where * (co-&gt;height - 3)) / (total ? total : 1) + 1;
++ else
++ new = (where * (co-&gt;height - 1)) / (total ? total : 1);
++ if (new != sb-&gt;curr) {
++ sbDrawThumb(co, 0);
++ sb-&gt;curr = new;
++ sbDrawThumb(co, 1);
++ }
++}
++
++newtComponent newtVerticalScrollbar(int left, int top, int height,
++ int normalColorset, int thumbColorset) {
++ newtComponent co;
++ struct scrollbar * sb;
++
++ co = malloc(sizeof(*co));
++ sb = malloc(sizeof(*sb));
++ co-&gt;data = sb;
++
++ if (!strcmp(getenv(&quot;TERM&quot;), &quot;linux&quot;) &amp;&amp; height &gt;= 2) {
++ sb-&gt;arrows = 1;
++ sb-&gt;curr = 1;
++ } else {
++ sb-&gt;arrows = 0;
++ sb-&gt;curr = 0;
++ }
++ sb-&gt;cs = normalColorset;
++ sb-&gt;csThumb = thumbColorset;
++
++ co-&gt;ops = &amp;sbOps;
++ co-&gt;isMapped = 0;
++ co-&gt;left = left;
++ co-&gt;top = top;
++ co-&gt;height = height;
++ co-&gt;width = 1;
++ co-&gt;takesFocus = 0;
++
++ return co;
++}
++
++static void sbDraw(newtComponent co) {
++ struct scrollbar * sb = co-&gt;data;
++ int i;
++
++ if (!co-&gt;isMapped) return;
++
++ SLsmg_set_color(sb-&gt;cs);
++
++ SLsmg_set_char_set(1);
++ if (sb-&gt;arrows) {
++ newtGotorc(co-&gt;top, co-&gt;left);
++ SLsmg_write_char('\x2d');
++ for (i = 1; i &lt; co-&gt;height - 1; i++) {
++ newtGotorc(i + co-&gt;top, co-&gt;left);
++ SLsmg_write_char('\x61');
++ }
++ newtGotorc(co-&gt;top + co-&gt;height - 1, co-&gt;left);
++ SLsmg_write_char('\x2e');
++ } else {
++ for (i = 0; i &lt; co-&gt;height; i++) {
++ newtGotorc(i + co-&gt;top, co-&gt;left);
++ SLsmg_write_char('\x61');
++ }
++ }
++
++ SLsmg_set_char_set(0);
++
++ sbDrawThumb(co, 1);
++}
++
++static void sbDrawThumb(newtComponent co, int isOn) {
++ struct scrollbar * sb = co-&gt;data;
++ char ch = isOn ? '#' : '\x61';
++
++ if (!co-&gt;isMapped) return;
++
++ newtGotorc(sb-&gt;curr + co-&gt;top, co-&gt;left);
++ SLsmg_set_char_set(1);
++
++ /*if (isOn)
++ SLsmg_set_color(sb-&gt;csThumb);
++ else*/
++ SLsmg_set_color(sb-&gt;cs);
++
++ SLsmg_write_char(ch);
++ SLsmg_set_char_set(0);
++}
++
++static void sbDestroy(newtComponent co) {
++ struct scrollbar * sb = co-&gt;data;
++
++ free(sb);
++ free(co);
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/newt/scrollbar.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/newt/textbox.c
+===================================================================
+--- drakx/trunk/mdk-stage1/newt/textbox.c (rev 0)
++++ drakx/trunk/mdk-stage1/newt/textbox.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,409 @@
++#include &lt;ctype.h&gt;
++#include &lt;slang.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++
++#include &quot;newt.h&quot;
++#include &quot;newt_pr.h&quot;
++
++struct textbox {
++ char ** lines;
++ int numLines;
++ int linesAlloced;
++ int doWrap;
++ newtComponent sb;
++ int topLine;
++ int textWidth;
++};
++
++static char * expandTabs(const char * text);
++static void textboxDraw(newtComponent co);
++static void addLine(newtComponent co, const char * s, int len);
++static void doReflow(const char * text, char ** resultPtr, int width,
++ int * badness, int * heightPtr);
++static struct eventResult textboxEvent(newtComponent c,
++ struct event ev);
++static void textboxDestroy(newtComponent co);
++static void textboxPlace(newtComponent co, int newLeft, int newTop);
++static void textboxMapped(newtComponent co, int isMapped);
++
++static struct componentOps textboxOps = {
++ textboxDraw,
++ textboxEvent,
++ textboxDestroy,
++ textboxPlace,
++ textboxMapped,
++} ;
++
++static void textboxMapped(newtComponent co, int isMapped) {
++ struct textbox * tb = co-&gt;data;
++
++ co-&gt;isMapped = isMapped;
++ if (tb-&gt;sb)
++ tb-&gt;sb-&gt;ops-&gt;mapped(tb-&gt;sb, isMapped);
++}
++
++static void textboxPlace(newtComponent co, int newLeft, int newTop) {
++ struct textbox * tb = co-&gt;data;
++
++ co-&gt;top = newTop;
++ co-&gt;left = newLeft;
++
++ if (tb-&gt;sb)
++ tb-&gt;sb-&gt;ops-&gt;place(tb-&gt;sb, co-&gt;left + co-&gt;width - 1, co-&gt;top);
++}
++
++void newtTextboxSetHeight(newtComponent co, int height) {
++ co-&gt;height = height;
++}
++
++int newtTextboxGetNumLines(newtComponent co) {
++ struct textbox * tb = co-&gt;data;
++
++ return (tb-&gt;numLines);
++}
++
++newtComponent newtTextboxReflowed(int left, int top, char * text, int width,
++ int flexDown, int flexUp, int flags __attribute__ ((unused))) {
++ newtComponent co;
++ char * reflowedText;
++ int actWidth, actHeight;
++
++ reflowedText = newtReflowText(text, width, flexDown, flexUp,
++ &amp;actWidth, &amp;actHeight);
++
++ co = newtTextbox(left, top, actWidth, actHeight, NEWT_FLAG_WRAP);
++ newtTextboxSetText(co, reflowedText);
++ free(reflowedText);
++
++ return co;
++}
++
++newtComponent newtTextbox(int left, int top, int width, int height, int flags) {
++ newtComponent co;
++ struct textbox * tb;
++
++ co = malloc(sizeof(*co));
++ tb = malloc(sizeof(*tb));
++ co-&gt;data = tb;
++
++ co-&gt;ops = &amp;textboxOps;
++
++ co-&gt;height = height;
++ co-&gt;top = top;
++ co-&gt;left = left;
++ co-&gt;takesFocus = 0;
++ co-&gt;width = width;
++
++ tb-&gt;doWrap = flags &amp; NEWT_FLAG_WRAP;
++ tb-&gt;numLines = 0;
++ tb-&gt;linesAlloced = 0;
++ tb-&gt;lines = NULL;
++ tb-&gt;topLine = 0;
++ tb-&gt;textWidth = width;
++
++ if (flags &amp; NEWT_FLAG_SCROLL) {
++ co-&gt;width += 2;
++ tb-&gt;sb = newtVerticalScrollbar(co-&gt;left + co-&gt;width - 1, co-&gt;top,
++ co-&gt;height, COLORSET_TEXTBOX, COLORSET_TEXTBOX);
++ } else {
++ tb-&gt;sb = NULL;
++ }
++
++ return co;
++}
++
++static char * expandTabs(const char * text) {
++ int bufAlloced = strlen(text) + 40;
++ char * buf, * dest;
++ const char * src;
++ int bufUsed = 0;
++ int linePos = 0;
++ int i;
++
++ buf = malloc(bufAlloced + 1);
++ for (src = text, dest = buf; *src; src++) {
++ if ((bufUsed + 10) &gt; bufAlloced) {
++ bufAlloced += strlen(text) / 2;
++ buf = realloc(buf, bufAlloced + 1);
++ dest = buf + bufUsed;
++ }
++ if (*src == '\t') {
++ i = 8 - (linePos &amp; 8);
++ memset(dest, ' ', i);
++ dest += i, bufUsed += i, linePos += i;
++ } else {
++ if (*src == '\n')
++ linePos = 0;
++ else
++ linePos++;
++
++ *dest++ = *src;
++ bufUsed++;
++ }
++ }
++
++ *dest = '\0';
++ return buf;
++}
++
++#define iseuckanji(c) (0xa1 &lt;= (unsigned char)(c&amp;0xff) &amp;&amp; (unsigned char)(c&amp;0xff) &lt;= 0xfe)
++
++static void doReflow(const char * text, char ** resultPtr, int width,
++ int * badness, int * heightPtr) {
++ char * result = NULL;
++ const char * chptr, * end;
++ int i;
++ int howbad = 0;
++ int height = 0;
++ int kanji = 0;
++
++ if (resultPtr) {
++ /* XXX I think this will work */
++ result = malloc(strlen(text) + (strlen(text) / width) + 50);
++ *result = '\0';
++ }
++
++ while (*text) {
++ kanji = 0;
++ end = strchr(text, '\n');
++ if (!end)
++ end = text + strlen(text);
++
++ while (*text &amp;&amp; text &lt; end) {
++ if (end - text &lt; width) {
++ if (result) {
++ strncat(result, text, end - text);
++ strcat(result, &quot;\n&quot;);
++ height++;
++ }
++
++ if (end - text &lt; (width / 2))
++ howbad += ((width / 2) - (end - text)) / 2;
++ text = end;
++ if (*text) text++;
++ } else {
++ chptr = text;
++ kanji = 0;
++ for ( i = 0; i &lt; width - 1; i++ ) {
++ if ( !iseuckanji(*chptr)) {
++ kanji = 0;
++ } else if ( kanji == 1 ) {
++ kanji = 2;
++ } else {
++ kanji = 1;
++ }
++ chptr++;
++ }
++ if (kanji == 0) {
++ while (chptr &gt; text &amp;&amp; !isspace(*chptr)) chptr--;
++ while (chptr &gt; text &amp;&amp; isspace(*chptr)) chptr--;
++ chptr++;
++ }
++
++ if (chptr-text == 1 &amp;&amp; !isspace(*chptr))
++ chptr = text + width - 1;
++
++ if (chptr &gt; text)
++ howbad += width - (chptr - text) + 1;
++ if (result) {
++ if (kanji == 1) {
++ strncat(result, text, chptr - text + 1);
++ chptr++;
++ kanji = 0;
++ } else {
++ strncat(result, text, chptr - text);
++ }
++ strcat(result, &quot;\n&quot;);
++ height++;
++ }
++
++ if (isspace(*chptr))
++ text = chptr + 1;
++ else
++ text = chptr;
++ while (isspace(*text)) text++;
++ }
++ }
++ }
++
++// if (result) printf(&quot;result: %s\n&quot;, result);
++
++ if (badness) *badness = howbad;
++ if (resultPtr) *resultPtr = result;
++ if (heightPtr) *heightPtr = height;
++}
++
++char * newtReflowText(char * text, int width, int flexDown, int flexUp,
++ int * actualWidth, int * actualHeight) {
++ int min, max;
++ int i;
++ char * result;
++ int minbad, minbadwidth, howbad;
++ char * expandedText;
++
++ expandedText = expandTabs(text);
++
++ if (flexDown || flexUp) {
++ min = width - flexDown;
++ max = width + flexUp;
++
++ minbad = -1;
++ minbadwidth = width;
++
++ for (i = min; i &lt;= max; i++) {
++ doReflow(expandedText, NULL, i, &amp;howbad, NULL);
++
++ if (minbad == -1 || howbad &lt; minbad) {
++ minbad = howbad;
++ minbadwidth = i;
++ }
++ }
++
++ width = minbadwidth;
++ }
++
++ doReflow(expandedText, &amp;result, width, NULL, actualHeight);
++ free(expandedText);
++ if (actualWidth) *actualWidth = width;
++ return result;
++}
++
++void newtTextboxSetText(newtComponent co, const char * text) {
++ const char * start, * end;
++ struct textbox * tb = co-&gt;data;
++ char * reflowed, * expanded;
++ int badness, height;
++
++ if (tb-&gt;lines) {
++ free(tb-&gt;lines);
++ tb-&gt;linesAlloced = tb-&gt;numLines = 0;
++ }
++
++ expanded = expandTabs(text);
++
++ if (tb-&gt;doWrap) {
++ doReflow(expanded, &amp;reflowed, tb-&gt;textWidth, &amp;badness, &amp;height);
++ free(expanded);
++ expanded = reflowed;
++ }
++
++ for (start = expanded; *start; start++)
++ if (*start == '\n') tb-&gt;linesAlloced++;
++
++ /* This ++ leaves room for an ending line w/o a \n */
++ tb-&gt;linesAlloced++;
++ tb-&gt;lines = malloc(sizeof(char *) * tb-&gt;linesAlloced);
++
++ start = expanded;
++ while ((end = strchr(start, '\n'))) {
++ addLine(co, start, end - start);
++ start = end + 1;
++ }
++
++ if (*start)
++ addLine(co, start, strlen(start));
++
++ free(expanded);
++}
++
++/* This assumes the buffer is allocated properly! */
++static void addLine(newtComponent co, const char * s, int len) {
++ struct textbox * tb = co-&gt;data;
++
++ if (len &gt; tb-&gt;textWidth) len = tb-&gt;textWidth;
++
++ tb-&gt;lines[tb-&gt;numLines] = malloc(tb-&gt;textWidth + 1);
++ memset(tb-&gt;lines[tb-&gt;numLines], ' ', tb-&gt;textWidth);
++ memcpy(tb-&gt;lines[tb-&gt;numLines], s, len);
++ tb-&gt;lines[tb-&gt;numLines++][tb-&gt;textWidth] = '\0';
++}
++
++static void textboxDraw(newtComponent c) {
++ int i;
++ struct textbox * tb = c-&gt;data;
++ int size;
++
++ if (tb-&gt;sb) {
++ size = tb-&gt;numLines - c-&gt;height;
++ newtScrollbarSet(tb-&gt;sb, tb-&gt;topLine, size ? size : 0);
++ tb-&gt;sb-&gt;ops-&gt;draw(tb-&gt;sb);
++ }
++
++ SLsmg_set_color(NEWT_COLORSET_TEXTBOX);
++
++ for (i = 0; (i + tb-&gt;topLine) &lt; tb-&gt;numLines &amp;&amp; i &lt; c-&gt;height; i++) {
++ newtGotorc(c-&gt;top + i, c-&gt;left);
++ SLsmg_write_string(tb-&gt;lines[i + tb-&gt;topLine]);
++ }
++}
++
++static struct eventResult textboxEvent(newtComponent co,
++ struct event ev) {
++ struct textbox * tb = co-&gt;data;
++ struct eventResult er;
++
++ er.result = ER_IGNORED;
++
++ if (ev.when == EV_EARLY &amp;&amp; ev.event == EV_KEYPRESS &amp;&amp; tb-&gt;sb) {
++ switch (ev.u.key) {
++ case NEWT_KEY_UP:
++ if (tb-&gt;topLine) tb-&gt;topLine--;
++ textboxDraw(co);
++ er.result = ER_SWALLOWED;
++ break;
++
++ case NEWT_KEY_DOWN:
++ if (tb-&gt;topLine &lt; (tb-&gt;numLines - co-&gt;height)) tb-&gt;topLine++;
++ textboxDraw(co);
++ er.result = ER_SWALLOWED;
++ break;
++
++ case NEWT_KEY_PGDN:
++ tb-&gt;topLine += co-&gt;height;
++ if (tb-&gt;topLine &gt; (tb-&gt;numLines - co-&gt;height)) {
++ tb-&gt;topLine = tb-&gt;numLines - co-&gt;height;
++ if (tb-&gt;topLine &lt; 0) tb-&gt;topLine = 0;
++ }
++ textboxDraw(co);
++ er.result = ER_SWALLOWED;
++ break;
++
++ case NEWT_KEY_PGUP:
++ tb-&gt;topLine -= co-&gt;height;
++ if (tb-&gt;topLine &lt; 0) tb-&gt;topLine = 0;
++ textboxDraw(co);
++ er.result = ER_SWALLOWED;
++ break;
++ }
++ }
++ if (ev.when == EV_EARLY &amp;&amp; ev.event == EV_MOUSE &amp;&amp; tb-&gt;sb) {
++ /* Top scroll arrow */
++ if (ev.u.mouse.x == co-&gt;width &amp;&amp; ev.u.mouse.y == co-&gt;top) {
++ if (tb-&gt;topLine) tb-&gt;topLine--;
++ textboxDraw(co);
++
++ er.result = ER_SWALLOWED;
++ }
++ /* Bottom scroll arrow */
++ if (ev.u.mouse.x == co-&gt;width &amp;&amp;
++ ev.u.mouse.y == co-&gt;top + co-&gt;height - 1) {
++ if (tb-&gt;topLine &lt; (tb-&gt;numLines - co-&gt;height)) tb-&gt;topLine++;
++ textboxDraw(co);
++
++ er.result = ER_SWALLOWED;
++ }
++ }
++ return er;
++}
++
++static void textboxDestroy(newtComponent co) {
++ int i;
++ struct textbox * tb = co-&gt;data;
++
++ for (i = 0; i &lt; tb-&gt;numLines; i++)
++ free(tb-&gt;lines[i]);
++ free(tb-&gt;lines);
++ free(tb);
++ free(co);
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/newt/textbox.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/newt/windows.c
+===================================================================
+--- drakx/trunk/mdk-stage1/newt/windows.c (rev 0)
++++ drakx/trunk/mdk-stage1/newt/windows.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,275 @@
++#include &lt;errno.h&gt;
++#include &lt;stdarg.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++
++#include &quot;errno.h&quot;
++#include &quot;newt.h&quot;
++
++static void * newtvwindow(char * title, char * button1, char * button2,
++ char * button3, char * message, va_list args) {
++ newtComponent b1, b2 = NULL, b3 = NULL, t, f, answer;
++ char * buf = NULL;
++ int size = 0;
++ int i = 0;
++ int scroll = 0;
++ int width, height;
++ char * flowedText;
++ newtGrid grid, buttonGrid;
++
++ do {
++ size += 1000;
++ if (buf) free(buf);
++ buf = malloc(size);
++ i = vsnprintf(buf, size, message, args);
++ } while (i &gt;= size || i == -1);
++
++ flowedText = newtReflowText(buf, 50, 5, 5, &amp;width, &amp;height);
++ if (height &gt; 6) {
++ free(flowedText);
++ flowedText = newtReflowText(buf, 60, 5, 5, &amp;width, &amp;height);
++ }
++ free(buf);
++
++ if (height &gt; 12) {
++ height = 12;
++ scroll = NEWT_FLAG_SCROLL;
++ }
++ t = newtTextbox(-1, -1, width, height, NEWT_TEXTBOX_WRAP | scroll);
++ newtTextboxSetText(t, flowedText);
++ free(flowedText);
++
++ if (button3) {
++ buttonGrid = newtButtonBar(button1, &amp;b1, button2, &amp;b2,
++ button3, &amp;b3, NULL);
++ } else if (button2) {
++ buttonGrid = newtButtonBar(button1, &amp;b1, button2, &amp;b2, NULL);
++ } else {
++ buttonGrid = newtButtonBar(button1, &amp;b1, NULL);
++ }
++
++ newtGridSetField(buttonGrid, 0, 0, NEWT_GRID_COMPONENT, b1,
++ 0, 0, button2 ? 1 : 0, 0, 0, 0);
++
++ grid = newtCreateGrid(1, 2);
++ newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, t, 0, 0, 0, 0, 0, 0);
++ newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, buttonGrid,
++ 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
++ newtGridWrappedWindow(grid, title);
++
++ f = newtForm(NULL, NULL, 0);
++ newtFormAddComponents(f, t, b1, NULL);
++
++ if (button2)
++ newtFormAddComponent(f, b2);
++ if (button3)
++ newtFormAddComponent(f, b3);
++
++ answer = newtRunForm(f);
++ newtGridFree(grid, 1);
++
++ newtFormDestroy(f);
++ newtPopWindow();
++
++ if (answer == f)
++ return NULL;
++ else if (answer == b1)
++ return button1;
++ else if (answer == b2)
++ return button2;
++
++ return button3;
++}
++
++int newtWinChoice(char * title, char * button1, char * button2,
++ char * message, ...) {
++ va_list args;
++ void * rc;
++
++ va_start(args, message);
++ rc = newtvwindow(title, button1, button2, NULL, message, args);
++ va_end(args);
++
++ if (rc == button1)
++ return 1;
++ else if (rc == button2)
++ return 2;
++
++ return 0;
++}
++
++void newtWinMessage(char * title, char * buttonText, char * text, ...) {
++ va_list args;
++
++ va_start(args, text);
++ newtvwindow(title, buttonText, NULL, NULL, text, args);
++ va_end(args);
++}
++
++void newtWinMessagev(char * title, char * buttonText, char * text,
++ va_list argv) {
++ newtvwindow(title, buttonText, NULL, NULL, text, argv);
++}
++
++int newtWinTernary(char * title, char * button1, char * button2,
++ char * button3, char * message, ...) {
++ va_list args;
++ void * rc;
++
++ va_start(args, message);
++ rc = newtvwindow(title, button1, button2, button3, message, args);
++ va_end(args);
++
++ if (rc == button1)
++ return 1;
++ else if (rc == button2)
++ return 2;
++ else if (rc == button3)
++ return 3;
++
++ return 0;
++}
++
++/* only supports up to 50 buttons -- shucks! */
++int newtWinMenu(char * title, char * text, int suggestedWidth, int flexDown,
++ int flexUp, int maxListHeight, char ** items, int * listItem,
++ char * button1, ...) {
++ newtComponent textbox, listbox, result, form;
++ va_list args;
++ newtComponent buttons[50];
++ newtGrid grid, buttonBar;
++ int numButtons;
++ int i, rc;
++ int needScroll;
++ char * buttonName;
++
++ textbox = newtTextboxReflowed(-1, -1, text, suggestedWidth, flexDown,
++ flexUp, 0);
++
++ for (i = 0; items[i]; i++) ;
++ if (i &lt; maxListHeight) maxListHeight = i;
++ needScroll = i &gt; maxListHeight;
++
++ listbox = newtListbox(-1, -1, maxListHeight,
++ (needScroll ? NEWT_FLAG_SCROLL : 0) | NEWT_FLAG_RETURNEXIT);
++ for (i = 0; items[i]; i++) {
++ newtListboxAddEntry(listbox, items[i], (void *) (long)i);
++ }
++
++ newtListboxSetCurrent(listbox, *listItem);
++
++ buttonName = button1, numButtons = 0;
++ va_start(args, button1);
++ while (buttonName) {
++ buttons[numButtons] = newtButton(-1, -1, buttonName);
++ numButtons++;
++ buttonName = va_arg(args, char *);
++ }
++
++ va_end(args);
++
++ buttonBar = newtCreateGrid(numButtons, 1);
++ for (i = 0; i &lt; numButtons; i++) {
++ newtGridSetField(buttonBar, i, 0, NEWT_GRID_COMPONENT,
++ buttons[i],
++ i ? 1 : 0, 0, 0, 0, 0, 0);
++ }
++
++ grid = newtGridSimpleWindow(textbox, listbox, buttonBar);
++ newtGridWrappedWindow(grid, title);
++
++ form = newtForm(NULL, 0, 0);
++ newtGridAddComponentsToForm(grid, form, 1);
++ newtGridFree(grid, 1);
++
++ result = newtRunForm(form);
++
++ *listItem = ((long) newtListboxGetCurrent(listbox));
++
++ for (rc = 0; result != buttons[rc] &amp;&amp; rc &lt; numButtons; rc++);
++ if (rc == numButtons)
++ rc = 0; /* F12 or return-on-exit (which are the same for us) */
++ else
++ rc++;
++
++ newtFormDestroy(form);
++ newtPopWindow();
++
++ return rc;
++}
++
++/* only supports up to 50 buttons and entries -- shucks! */
++int newtWinEntries(char * title, char * text, int suggestedWidth, int flexDown,
++ int flexUp, int dataWidth,
++ struct newtWinEntry * items, char * button1, ...) {
++ newtComponent buttons[50], result, form, textw;
++ newtGrid grid, buttonBar, subgrid;
++ int numItems;
++ int rc, i;
++ int numButtons;
++ char * buttonName;
++ va_list args;
++
++ textw = newtTextboxReflowed(-1, -1, text, suggestedWidth, flexDown,
++ flexUp, 0);
++
++ for (numItems = 0; items[numItems].text; numItems++);
++
++ buttonName = button1, numButtons = 0;
++ va_start(args, button1);
++ while (buttonName) {
++ buttons[numButtons] = newtButton(-1, -1, buttonName);
++ numButtons++;
++ buttonName = va_arg(args, char *);
++ }
++
++ va_end(args);
++
++ buttonBar = newtCreateGrid(numButtons, 1);
++ for (i = 0; i &lt; numButtons; i++) {
++ newtGridSetField(buttonBar, i, 0, NEWT_GRID_COMPONENT,
++ buttons[i],
++ i ? 1 : 0, 0, 0, 0, 0, 0);
++ }
++
++ subgrid = newtCreateGrid(2, numItems);
++ for (i = 0; i &lt; numItems; i++) {
++ newtGridSetField(subgrid, 0, i, NEWT_GRID_COMPONENT,
++ newtLabel(-1, -1, items[i].text),
++ 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
++ newtGridSetField(subgrid, 1, i, NEWT_GRID_COMPONENT,
++ newtEntry(-1, -1, items[i].value ?
++ *items[i].value : NULL, dataWidth,
++ items[i].value, items[i].flags),
++ 1, 0, 0, 0, 0, 0);
++ }
++
++ grid = newtCreateGrid(1, 3);
++ form = newtForm(NULL, 0, 0);
++ newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, textw,
++ 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
++ newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, subgrid,
++ 0, 1, 0, 0, 0, 0);
++ newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttonBar,
++ 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
++ newtGridAddComponentsToForm(grid, form, 1);
++ newtGridWrappedWindow(grid, title);
++ newtGridFree(grid, 1);
++
++ result = newtRunForm(form);
++
++ for (rc = 0; rc &lt; numItems; rc++)
++ *items[rc].value = strdup(*items[rc].value);
++
++ for (rc = 0; result != buttons[rc] &amp;&amp; rc &lt; numButtons; rc++);
++ if (rc == numButtons)
++ rc = 0; /* F12 */
++ else
++ rc++;
++
++ newtFormDestroy(form);
++ newtPopWindow();
++
++ return rc;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/newt/windows.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/newt-frontend.c
+===================================================================
+--- drakx/trunk/mdk-stage1/newt-frontend.c (rev 0)
++++ drakx/trunk/mdk-stage1/newt-frontend.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,389 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Portions from Erik Troan (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ewt at redhat.com</A>)
++ *
++ * Copyright 1996 Red Hat Software
++ *
++ */
++
++
++/*
++ * Each different frontend must implement all functions defined in frontend.h
++ */
++
++#define _GNU_SOURCE
++
++#include &lt;stdlib.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;string.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;stdarg.h&gt;
++#include &lt;sys/time.h&gt;
++#include &quot;newt/newt.h&quot;
++
++#include &lt;probing.h&gt;
++
++#include &quot;frontend.h&quot;
++
++void init_frontend(char * welcome_msg)
++{
++ int i;
++ for (i=0; i&lt;38; i++) printf(&quot;\n&quot;);
++ newtInit();
++ newtCls();
++
++ if (welcome_msg[0]) {
++ char *msg;
++ int cols, rows;
++ newtGetScreenSize(&amp;cols, &amp;rows);
++ asprintf(&amp;msg, &quot; %-*s&quot;, cols - 1, welcome_msg);
++ newtDrawRootText(0, 0, msg);
++ free(msg);
++ newtPushHelpLine(&quot; &lt;Alt-F1&gt; for here, &lt;Alt-F3&gt; to see the logs, &lt;Alt-F4&gt; for kernel msg&quot;);
++ }
++ newtRefresh();
++}
++
++
++void finish_frontend(void)
++{
++ newtFinished();
++}
++
++
++void verror_message(char *msg, va_list ap)
++{
++ newtWinMessagev(&quot;Error&quot;, &quot;Ok&quot;, msg, ap);
++}
++
++void vinfo_message(char *msg, va_list ap)
++{
++ newtWinMessagev(&quot;Notice&quot;, &quot;Ok&quot;, msg, ap);
++}
++
++
++void vwait_message(char *msg, va_list ap)
++{
++ int width, height;
++ char * title = &quot;Please wait...&quot;;
++ newtComponent c, f;
++ newtGrid grid;
++ char * buf = NULL;
++ char * flowed;
++ int size = 0;
++ int i = 0;
++
++ do {
++ size += 1000;
++ if (buf) free(buf);
++ buf = malloc(size);
++ i = vsnprintf(buf, size, msg, ap);
++ } while (i &gt;= size || i == -1);
++
++ flowed = newtReflowText(buf, 60, 5, 5, &amp;width, &amp;height);
++
++ c = newtTextbox(-1, -1, width, height, NEWT_TEXTBOX_WRAP);
++ newtTextboxSetText(c, flowed);
++
++ grid = newtCreateGrid(1, 1);
++ newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, c, 0, 0, 0, 0, 0, 0);
++ newtGridWrappedWindow(grid, title);
++
++ free(flowed);
++ free(buf);
++
++ f = newtForm(NULL, NULL, 0);
++ newtFormAddComponent(f, c);
++
++ newtDrawForm(f);
++ newtRefresh();
++ newtFormDestroy(f);
++}
++
++void remove_wait_message(void)
++{
++ newtPopWindow();
++}
++
++
++static newtComponent form = NULL, scale = NULL;
++static int size_progress;
++static int actually_drawn;
++static char * msg_progress;
++
++void init_progression_raw(char *msg, int size)
++{
++ size_progress = size;
++ if (size) {
++ actually_drawn = 0;
++ newtCenteredWindow(70, 5, &quot;Please wait...&quot;);
++ form = newtForm(NULL, NULL, 0);
++ newtFormAddComponent(form, newtLabel(1, 1, msg));
++ scale = newtScale(1, 3, 68, size);
++ newtFormAddComponent(form, scale);
++ newtDrawForm(form);
++ newtRefresh();
++ }
++ else {
++ wait_message(msg);
++ msg_progress = msg;
++ }
++}
++
++void update_progression_raw(int current_size)
++{
++ if (size_progress) {
++ if (current_size &lt;= size_progress)
++ newtScaleSet(scale, current_size);
++ newtRefresh();
++ }
++ else {
++ struct timeval t;
++ int time;
++ static int last_time = -1;
++ gettimeofday(&amp;t, NULL);
++ time = t.tv_sec*3 + t.tv_usec/300000;
++ if (time != last_time) {
++ char msg_prog_final[500];
++ sprintf(msg_prog_final, &quot;%s (%d bytes read) &quot;, msg_progress, current_size);
++ remove_wait_message();
++ wait_message(msg_prog_final);
++ }
++ last_time = time;
++ }
++}
++
++void end_progression_raw(void)
++{
++ if (size_progress) {
++ newtPopWindow();
++ newtFormDestroy(form);
++ }
++ else
++ remove_wait_message();
++}
++
++
++enum return_type ask_from_list_index(char *msg, char ** elems, char ** elems_comments, int * answer)
++{
++ char * items[50000];
++ int rc;
++
++ if (elems_comments) {
++ int i;
++
++ i = 0;
++ while (elems &amp;&amp; *elems) {
++ int j = (*elems_comments) ? strlen(*elems_comments) : 0;
++ items[i] = malloc(sizeof(char) * (strlen(*elems) + j + 4));
++ strcpy(items[i], *elems);
++ if (*elems_comments) {
++ strcat(items[i], &quot; (&quot;);
++ strcat(items[i], *elems_comments);
++ strcat(items[i], &quot;)&quot;);
++ }
++ elems_comments++;
++ i++;
++ elems++;
++ }
++ items[i] = NULL;
++ }
++
++ rc = newtWinMenu(&quot;Please choose...&quot;, msg, 52, 5, 5, 7, elems_comments ? items : elems, answer, &quot;Ok&quot;, &quot;Cancel&quot;, NULL);
++
++ if (rc == 2)
++ return RETURN_BACK;
++
++ return RETURN_OK;
++}
++
++enum return_type ask_yes_no(char *msg)
++{
++ int rc;
++
++ rc = newtWinTernary(&quot;Please answer...&quot;, &quot;Yes&quot;, &quot;No&quot;, &quot;Back&quot;, msg);
++
++ if (rc == 1)
++ return RETURN_OK;
++ else if (rc == 3)
++ return RETURN_BACK;
++ else return RETURN_ERROR;
++}
++
++
++static void (*callback_real_function)(char ** strings) = NULL;
++
++static void default_callback(newtComponent co __attribute__ ((unused)), void * data)
++{
++ newtComponent * entries = data;
++ char * strings[50], ** ptr;
++
++ if (!callback_real_function)
++ return;
++
++ ptr = strings;
++ while (entries &amp;&amp; *entries) {
++ *ptr = newtEntryGetValue(*entries);
++ entries++;
++ ptr++;
++ }
++
++ callback_real_function(strings);
++
++ ptr = strings;
++ entries = data;
++ while (entries &amp;&amp; *entries) {
++ newtEntrySet(*entries, strdup(*ptr), 1);
++ entries++;
++ ptr++;
++ }
++}
++
++/* only supports up to 50 buttons and entries -- shucks! */
++static int mynewtWinEntries(char * title, char * text, int suggestedWidth, int flexDown,
++ int flexUp, int dataWidth, void (*callback_func)(char ** strings),
++ struct newtWinEntry * items, char * button1, ...) {
++ newtComponent buttons[50], result, form, textw;
++ newtGrid grid, buttonBar, subgrid;
++ int numItems;
++ int rc, i;
++ int numButtons;
++ char * buttonName;
++ newtComponent entries[50];
++
++ va_list args;
++
++ textw = newtTextboxReflowed(-1, -1, text, suggestedWidth, flexDown,
++ flexUp, 0);
++
++ for (numItems = 0; items[numItems].text; numItems++);
++
++ buttonName = button1, numButtons = 0;
++ va_start(args, button1);
++ while (buttonName) {
++ buttons[numButtons] = newtButton(-1, -1, buttonName);
++ numButtons++;
++ buttonName = va_arg(args, char *);
++ }
++
++ va_end(args);
++
++ buttonBar = newtCreateGrid(numButtons, 1);
++ for (i = 0; i &lt; numButtons; i++) {
++ newtGridSetField(buttonBar, i, 0, NEWT_GRID_COMPONENT,
++ buttons[i],
++ i ? 1 : 0, 0, 0, 0, 0, 0);
++ }
++
++ if (callback_func) {
++ callback_real_function = callback_func;
++ entries[numItems] = NULL;
++ }
++ else
++ callback_real_function = NULL;
++
++ subgrid = newtCreateGrid(2, numItems);
++ for (i = 0; i &lt; numItems; i++) {
++ newtComponent entr = newtEntry(-1, -1, items[i].value ?
++ *items[i].value : NULL, dataWidth,
++ items[i].value, items[i].flags);
++
++ newtGridSetField(subgrid, 0, i, NEWT_GRID_COMPONENT,
++ newtLabel(-1, -1, items[i].text),
++ 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
++ newtGridSetField(subgrid, 1, i, NEWT_GRID_COMPONENT,
++ entr,
++ 1, 0, 0, 0, 0, 0);
++ if (callback_func) {
++ entries[i] = entr;
++ newtComponentAddCallback(entr, default_callback, entries);
++ }
++ }
++
++
++ grid = newtCreateGrid(1, 3);
++ form = newtForm(NULL, 0, 0);
++ newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, textw,
++ 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
++ newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, subgrid,
++ 0, 1, 0, 0, 0, 0);
++ newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttonBar,
++ 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
++ newtGridAddComponentsToForm(grid, form, 1);
++ newtGridWrappedWindow(grid, title);
++ newtGridFree(grid, 1);
++
++ result = newtRunForm(form);
++
++ for (rc = 0; rc &lt; numItems; rc++)
++ *items[rc].value = strdup(*items[rc].value);
++
++ for (rc = 0; result != buttons[rc] &amp;&amp; rc &lt; numButtons; rc++);
++ if (rc == numButtons)
++ rc = 0; /* F12 */
++ else
++ rc++;
++
++ newtFormDestroy(form);
++ newtPopWindow();
++
++ return rc;
++}
++
++
++enum return_type ask_from_entries(char *msg, char ** questions, char *** answers, int entry_size, void (*callback_func)(char ** strings))
++{
++ struct newtWinEntry entries[50];
++ int j, i = 0;
++ int rc;
++ char ** already_answers = NULL;
++
++ while (questions &amp;&amp; *questions) {
++ entries[i].text = *questions;
++ entries[i].flags = NEWT_FLAG_SCROLL | (!strcmp(*questions, &quot;Password&quot;) ? NEWT_FLAG_PASSWORD : 0);
++ i++;
++ questions++;
++ }
++ entries[i].text = NULL;
++ entries[i].value = NULL;
++
++ if (*answers == NULL)
++ *answers = (char **) malloc(sizeof(char *) * i);
++ else
++ already_answers = *answers;
++
++ for (j = 0 ; j &lt; i ; j++) {
++ entries[j].value = &amp;((*answers)[j]);
++ if (already_answers &amp;&amp; *already_answers) {
++ *(entries[j].value) = *already_answers;
++ already_answers++;
++ } else
++ *(entries[j].value) = NULL;
++ }
++
++ rc = mynewtWinEntries(&quot;Please fill in entries...&quot;, msg, 52, 5, 5, entry_size, callback_func, entries, &quot;Ok&quot;, &quot;Cancel&quot;, NULL);
++
++ if (rc == 3)
++ return RETURN_BACK;
++ if (rc != 1)
++ return RETURN_ERROR;
++
++ return RETURN_OK;
++}
++
++
++void suspend_to_console(void) { newtSuspend(); }
++void resume_from_suspend(void) { newtResume(); }
+
+
+Property changes on: drakx/trunk/mdk-stage1/newt-frontend.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/nfs_mount4.h
+===================================================================
+--- drakx/trunk/mdk-stage1/nfs_mount4.h (rev 0)
++++ drakx/trunk/mdk-stage1/nfs_mount4.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,54 @@
++/*
++ * We want to be able to compile mount on old kernels in such a way
++ * that the binary will work well on more recent kernels.
++ * Thus, if necessary we teach nfsmount.c the structure of new fields
++ * that will come later.
++ *
++ * Moreover, the new kernel includes conflict with glibc includes
++ * so it is easiest to ignore the kernel altogether (at compile time).
++ */
++
++#define NFS_MOUNT_VERSION 4
++
++struct nfs2_fh {
++ char data[32];
++};
++struct nfs3_fh {
++ unsigned short size;
++ unsigned char data[64];
++};
++
++struct nfs_mount_data {
++ int version; /* 1 */
++ int fd; /* 1 */
++ struct nfs2_fh old_root; /* 1 */
++ int flags; /* 1 */
++ int rsize; /* 1 */
++ int wsize; /* 1 */
++ int timeo; /* 1 */
++ int retrans; /* 1 */
++ int acregmin; /* 1 */
++ int acregmax; /* 1 */
++ int acdirmin; /* 1 */
++ int acdirmax; /* 1 */
++ struct sockaddr_in addr; /* 1 */
++ char hostname[256]; /* 1 */
++ int namlen; /* 2 */
++ unsigned int bsize; /* 3 */
++ struct nfs3_fh root; /* 4 */
++};
++
++/* bits in the flags field */
++
++#define NFS_MOUNT_SOFT 0x0001 /* 1 */
++#define NFS_MOUNT_INTR 0x0002 /* 1 */
++#define NFS_MOUNT_SECURE 0x0004 /* 1 */
++#define NFS_MOUNT_POSIX 0x0008 /* 1 */
++#define NFS_MOUNT_NOCTO 0x0010 /* 1 */
++#define NFS_MOUNT_NOAC 0x0020 /* 1 */
++#define NFS_MOUNT_TCP 0x0040 /* 2 */
++#define NFS_MOUNT_VER3 0x0080 /* 3 */
++#define NFS_MOUNT_KERBEROS 0x0100 /* 3 */
++#define NFS_MOUNT_NONLM 0x0200 /* 3 */
++#define NFS_MOUNT_BROKEN_SUID 0x0400 /* 4 */
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/nfs_mount4.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/nfsmount.c
+===================================================================
+--- drakx/trunk/mdk-stage1/nfsmount.c (rev 0)
++++ drakx/trunk/mdk-stage1/nfsmount.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,740 @@
++ /*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2003 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * basing on nfsmount.c from util-linux-2.11z:
++ * - use our logging facilities
++ * - use our host resolving stuff
++ * - remove unneeded code
++ */
++
++/*
++ * nfsmount.c -- Linux NFS mount
++ * Copyright (C) 1993 Rick Sladkey &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">jrs at world.std.com</A>&gt;
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * Wed Feb 8 12:51:48 1995, <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">biro at yggdrasil.com</A> (Ross Biro): allow all port
++ * numbers to be specified on the command line.
++ *
++ * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">swen at uni-paderborn.de</A>&gt;:
++ * Omit the call to connect() for Linux version 1.3.11 or later.
++ *
++ * Wed Oct 1 23:55:28 1997: Dick Streefland &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dick_streefland at tasking.com</A>&gt;
++ * Implemented the &quot;bg&quot;, &quot;fg&quot; and &quot;retry&quot; mount options for NFS.
++ *
++ * 1999-02-22 Arkadiusz Mi&#347;kiewicz &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">misiek at pld.ORG.PL</A>&gt;
++ * - added Native Language Support
++ *
++ * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
++ * plus NFSv3 stuff.
++ *
++ * 2003-04-14 David Black &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">david.black at xilinx.com</A>&gt;
++ * - added support for multiple hostname NFS mounts
++ */
++
++/*
++ * nfsmount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
++ */
++
++#define HAVE_rpcsvc_nfs_prot_h
++#define HAVE_inet_aton
++
++#include &lt;unistd.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;string.h&gt;
++#include &lt;errno.h&gt;
++#include &lt;netdb.h&gt;
++#include &lt;time.h&gt;
++#include &lt;rpc/rpc.h&gt;
++#include &lt;rpc/pmap_prot.h&gt;
++#include &lt;rpc/pmap_clnt.h&gt;
++#include &lt;sys/socket.h&gt;
++#include &lt;sys/time.h&gt;
++#include &lt;sys/utsname.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;netinet/in.h&gt;
++#include &lt;arpa/inet.h&gt;
++#include &lt;values.h&gt;
++
++#include &quot;nfsmount.h&quot;
++
++#ifdef HAVE_rpcsvc_nfs_prot_h
++#include &lt;rpcsvc/nfs_prot.h&gt;
++#else
++#include &lt;linux/nfs.h&gt;
++#define nfsstat nfs_stat
++#endif
++
++#include &quot;nfs_mount4.h&quot;
++
++#include &quot;log.h&quot;
++#include &quot;dns.h&quot;
++
++#ifndef NFS_PORT
++#define NFS_PORT 2049
++#endif
++#ifndef NFS_FHSIZE
++#define NFS_FHSIZE 32
++#endif
++
++static char *nfs_strerror(int stat);
++
++#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r))
++
++#define MAX_NFSPROT ((nfs_mount_version &gt;= 4) ? 3 : 2)
++
++bool_t
++xdr_fhandle3 (XDR *xdrs, fhandle3 *objp)
++{
++ if (!xdr_bytes (xdrs, (char **)&amp;objp-&gt;fhandle3_val, (u_int *) &amp;objp-&gt;fhandle3_len, FHSIZE3))
++ return FALSE;
++ return TRUE;
++}
++
++bool_t
++xdr_mountstat3 (XDR *xdrs, mountstat3 *objp)
++{
++ if (!xdr_enum (xdrs, (enum_t *) objp))
++ return FALSE;
++ return TRUE;
++}
++
++bool_t
++xdr_mountres3_ok (XDR *xdrs, mountres3_ok *objp)
++{
++ if (!xdr_fhandle3 (xdrs, &amp;objp-&gt;fhandle))
++ return FALSE;
++ if (!xdr_array (xdrs, (char **)&amp;objp-&gt;auth_flavours.auth_flavours_val, (u_int *) &amp;objp-&gt;auth_flavours.auth_flavours_len, ~0,
++ sizeof (int), (xdrproc_t) xdr_int))
++ return FALSE;
++ return TRUE;
++}
++
++bool_t
++xdr_mountres3 (XDR *xdrs, mountres3 *objp)
++{
++ if (!xdr_mountstat3 (xdrs, &amp;objp-&gt;fhs_status))
++ return FALSE;
++ switch (objp-&gt;fhs_status) {
++ case MNT_OK:
++ if (!xdr_mountres3_ok (xdrs, &amp;objp-&gt;mountres3_u.mountinfo))
++ return FALSE;
++ break;
++ default:
++ break;
++ }
++ return TRUE;
++}
++
++bool_t
++xdr_dirpath (XDR *xdrs, dirpath *objp)
++{
++ if (!xdr_string (xdrs, objp, MNTPATHLEN))
++ return FALSE;
++ return TRUE;
++}
++
++bool_t
++xdr_fhandle (XDR *xdrs, fhandle objp)
++{
++ if (!xdr_opaque (xdrs, objp, FHSIZE))
++ return FALSE;
++ return TRUE;
++}
++
++bool_t
++xdr_fhstatus (XDR *xdrs, fhstatus *objp)
++{
++ if (!xdr_u_int (xdrs, &amp;objp-&gt;fhs_status))
++ return FALSE;
++ switch (objp-&gt;fhs_status) {
++ case 0:
++ if (!xdr_fhandle (xdrs, objp-&gt;fhstatus_u.fhs_fhandle))
++ return FALSE;
++ break;
++ default:
++ break;
++ }
++ return TRUE;
++}
++
++
++static int
++linux_version_code(void) {
++ struct utsname my_utsname;
++ int p, q, r;
++
++ if (uname(&amp;my_utsname) == 0) {
++ p = atoi(strtok(my_utsname.release, &quot;.&quot;));
++ q = atoi(strtok(NULL, &quot;.&quot;));
++ r = atoi(strtok(NULL, &quot;.&quot;));
++ return MAKE_VERSION(p,q,r);
++ }
++ return 0;
++}
++
++/*
++ * Unfortunately, the kernel prints annoying console messages
++ * in case of an unexpected nfs mount version (instead of
++ * just returning some error). Therefore we'll have to try
++ * and figure out what version the kernel expects.
++ *
++ * Variables:
++ * NFS_MOUNT_VERSION: these nfsmount sources at compile time
++ * nfs_mount_version: version this source and running kernel can handle
++ */
++static int
++find_kernel_nfs_mount_version(void) {
++ static int kernel_version = -1;
++ int nfs_mount_version = NFS_MOUNT_VERSION;
++
++ if (kernel_version == -1)
++ kernel_version = linux_version_code();
++
++ if (kernel_version) {
++ if (kernel_version &lt; MAKE_VERSION(2,1,32))
++ nfs_mount_version = 1;
++ else if (kernel_version &lt; MAKE_VERSION(2,2,18))
++ nfs_mount_version = 3;
++ else if (kernel_version &lt; MAKE_VERSION(2,3,0))
++ nfs_mount_version = 4; /* since 2.2.18pre9 */
++ else if (kernel_version &lt; MAKE_VERSION(2,3,99))
++ nfs_mount_version = 3;
++ else
++ nfs_mount_version = 4; /* since 2.3.99pre4 */
++ }
++ if (nfs_mount_version &gt; NFS_MOUNT_VERSION)
++ nfs_mount_version = NFS_MOUNT_VERSION;
++ log_message(&quot;nfsmount: kernel_nfs_mount_version: %d&quot;, nfs_mount_version);
++ return nfs_mount_version;
++}
++
++static struct pmap *
++get_mountport(struct sockaddr_in *server_addr,
++ long unsigned prog,
++ long unsigned version,
++ long unsigned proto,
++ long unsigned port,
++ int nfs_mount_version)
++{
++ struct pmaplist *pmap;
++ static struct pmap p = {0, 0, 0, 0};
++
++ if (version &gt; MAX_NFSPROT)
++ version = MAX_NFSPROT;
++ if (!prog)
++ prog = MOUNTPROG;
++ p.pm_prog = prog;
++ p.pm_vers = version;
++ p.pm_prot = proto;
++ p.pm_port = port;
++
++ server_addr-&gt;sin_port = PMAPPORT;
++ pmap = pmap_getmaps(server_addr);
++
++ while (pmap) {
++ if (pmap-&gt;pml_map.pm_prog != prog)
++ goto next;
++ if (!version &amp;&amp; p.pm_vers &gt; pmap-&gt;pml_map.pm_vers)
++ goto next;
++ if (version &gt; 2 &amp;&amp; pmap-&gt;pml_map.pm_vers != version)
++ goto next;
++ if (version &amp;&amp; version &lt;= 2 &amp;&amp; pmap-&gt;pml_map.pm_vers &gt; 2)
++ goto next;
++ if (pmap-&gt;pml_map.pm_vers &gt; MAX_NFSPROT ||
++ (proto &amp;&amp; p.pm_prot &amp;&amp; pmap-&gt;pml_map.pm_prot != proto) ||
++ (port &amp;&amp; pmap-&gt;pml_map.pm_port != port))
++ goto next;
++ memcpy(&amp;p, &amp;pmap-&gt;pml_map, sizeof(p));
++ next:
++ pmap = pmap-&gt;pml_next;
++ }
++ if (!p.pm_vers)
++ p.pm_vers = MOUNTVERS;
++ if (!p.pm_prot)
++ p.pm_prot = IPPROTO_TCP;
++ return &amp;p;
++}
++
++
++
++int nfsmount_prepare(const char *spec, char **mount_opts)
++{
++ char hostdir[1024];
++ CLIENT *mclient;
++ char *hostname, *dirname, *mounthost = NULL;
++ struct timeval total_timeout;
++ enum clnt_stat clnt_stat;
++ static struct nfs_mount_data data;
++ int nfs_mount_version;
++ int val;
++ struct sockaddr_in server_addr;
++ struct sockaddr_in mount_server_addr;
++ struct pmap *pm_mnt;
++ int msock, fsock;
++ struct timeval retry_timeout;
++ union {
++ struct fhstatus nfsv2;
++ struct mountres3 nfsv3;
++ } status;
++ char *s;
++ int port, mountport, proto, soft, intr;
++ int posix, nocto, noac, broken_suid, nolock;
++ int retry, tcp;
++ int mountprog, mountvers, nfsprog, nfsvers;
++ int retval;
++ time_t t;
++ time_t prevt;
++ time_t timeout;
++
++ nfs_mount_version = find_kernel_nfs_mount_version();
++
++ retval = -1;
++ msock = fsock = -1;
++ mclient = NULL;
++ if (strlen(spec) &gt;= sizeof(hostdir)) {
++ log_message(&quot;nfsmount: excessively long host:dir argument&quot;);
++ goto fail;
++ }
++ strcpy(hostdir, spec);
++ if ((s = strchr(hostdir, ':'))) {
++ hostname = hostdir;
++ dirname = s + 1;
++ *s = '\0';
++ } else {
++ log_message(&quot;nfsmount: directory to mount not in host:dir format&quot;);
++ goto fail;
++ }
++
++ server_addr.sin_family = AF_INET;
++#ifdef HAVE_inet_aton
++ if (!inet_aton(hostname, &amp;server_addr.sin_addr))
++#endif
++ {
++ if (mygethostbyname(hostname, &amp;server_addr.sin_addr)) {
++ log_message(&quot;nfsmount: can't get address for %s&quot;, hostname);
++ goto fail;
++ }
++ }
++
++ memcpy (&amp;mount_server_addr, &amp;server_addr, sizeof (mount_server_addr));
++
++
++
++ /* Set default options.
++ * rsize/wsize are set to 8192 to enable nfs install on
++ * old i586 machines
++ * timeo is filled in after we know whether it'll be TCP or UDP. */
++ memset(&amp;data, 0, sizeof(data));
++ data.rsize = 8192;
++ data.wsize = 8192;
++ data.retrans = 30;
++ data.acregmin = 3;
++ data.acregmax = 60;
++ data.acdirmin = 30;
++ data.acdirmax = 60;
++#if NFS_MOUNT_VERSION &gt;= 2
++ data.namlen = NAME_MAX;
++#endif
++
++ soft = 1;
++ intr = 0;
++ posix = 0;
++ nocto = 0;
++ nolock = 1;
++ broken_suid = 0;
++ noac = 0;
++ retry = 10000; /* 10000 minutes ~ 1 week */
++ tcp = 0;
++
++ mountprog = MOUNTPROG;
++ mountvers = 0;
++ port = 0;
++ mountport = 0;
++ nfsprog = NFS_PROGRAM;
++ nfsvers = 0;
++
++
++
++retry_mount:
++ proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
++
++ data.flags = (soft ? NFS_MOUNT_SOFT : 0)
++ | (intr ? NFS_MOUNT_INTR : 0)
++ | (posix ? NFS_MOUNT_POSIX : 0)
++ | (nocto ? NFS_MOUNT_NOCTO : 0)
++ | (noac ? NFS_MOUNT_NOAC : 0);
++#if NFS_MOUNT_VERSION &gt;= 2
++ if (nfs_mount_version &gt;= 2)
++ data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
++#endif
++#if NFS_MOUNT_VERSION &gt;= 3
++ if (nfs_mount_version &gt;= 3)
++ data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
++#endif
++#if NFS_MOUNT_VERSION &gt;= 4
++ if (nfs_mount_version &gt;= 4)
++ data.flags |= (broken_suid ? NFS_MOUNT_BROKEN_SUID : 0);
++#endif
++ if (nfsvers &gt; MAX_NFSPROT) {
++ log_message(&quot;NFSv%d not supported!&quot;, nfsvers);
++ return 0;
++ }
++ if (mountvers &gt; MAX_NFSPROT) {
++ log_message(&quot;NFSv%d not supported!&quot;, nfsvers);
++ return 0;
++ }
++ if (nfsvers &amp;&amp; !mountvers)
++ mountvers = (nfsvers &lt; 3) ? 1 : nfsvers;
++ if (nfsvers &amp;&amp; nfsvers &lt; mountvers)
++ mountvers = nfsvers;
++
++ /* Adjust options if none specified */
++ if (!data.timeo)
++ data.timeo = tcp ? 70 : 7;
++
++#ifdef NFS_MOUNT_DEBUG
++ log_message(&quot;rsize = %d, wsize = %d, timeo = %d, retrans = %d&quot;,
++ data.rsize, data.wsize, data.timeo, data.retrans);
++ log_message(&quot;acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)&quot;,
++ data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
++ log_message(&quot;port = %d, retry = %d, flags = %.8x&quot;,
++ port, retry, data.flags);
++ log_message(&quot;mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d&quot;,
++ mountprog, mountvers, nfsprog, nfsvers);
++ log_message(&quot;soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d&quot;,
++ (data.flags &amp; NFS_MOUNT_SOFT) != 0,
++ (data.flags &amp; NFS_MOUNT_INTR) != 0,
++ (data.flags &amp; NFS_MOUNT_POSIX) != 0,
++ (data.flags &amp; NFS_MOUNT_NOCTO) != 0,
++ (data.flags &amp; NFS_MOUNT_NOAC) != 0);
++#if NFS_MOUNT_VERSION &gt;= 2
++ log_message(&quot;tcp = %d&quot;,
++ (data.flags &amp; NFS_MOUNT_TCP) != 0);
++#endif
++#endif
++
++ data.version = nfs_mount_version;
++ *mount_opts = (char *) &amp;data;
++
++
++ /* create mount deamon client */
++ /* See if the nfs host = mount host. */
++ if (mounthost) {
++ if (mounthost[0] &gt;= '0' &amp;&amp; mounthost[0] &lt;= '9') {
++ mount_server_addr.sin_family = AF_INET;
++ mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
++ } else {
++ if (mygethostbyname(mounthost, &amp;mount_server_addr.sin_addr)) {
++ log_message(&quot;nfsmount: can't get address for %s&quot;, mounthost);
++ goto fail;
++ }
++ }
++ }
++
++ /*
++ * The following loop implements the mount retries. On the first
++ * call, &quot;running_bg&quot; is 0. When the mount times out, and the
++ * &quot;bg&quot; option is set, the exit status EX_BG will be returned.
++ * For a backgrounded mount, there will be a second call by the
++ * child process with &quot;running_bg&quot; set to 1.
++ *
++ * The case where the mount point is not present and the &quot;bg&quot;
++ * option is set, is treated as a timeout. This is done to
++ * support nested mounts.
++ *
++ * The &quot;retry&quot; count specified by the user is the number of
++ * minutes to retry before giving up.
++ *
++ * Only the first error message will be displayed.
++ */
++ retry_timeout.tv_sec = 3;
++ retry_timeout.tv_usec = 0;
++ total_timeout.tv_sec = 20;
++ total_timeout.tv_usec = 0;
++ timeout = time(NULL) + 60 * retry;
++ prevt = 0;
++ t = 30;
++ val = 1;
++
++
++ /* be careful not to use too many CPU cycles */
++ if (t - prevt &lt; 30)
++ sleep(30);
++
++ pm_mnt = get_mountport(&amp;mount_server_addr,
++ mountprog,
++ mountvers,
++ proto,
++ mountport,
++ nfs_mount_version);
++
++ /* contact the mount daemon via TCP */
++ mount_server_addr.sin_port = htons(pm_mnt-&gt;pm_port);
++ msock = RPC_ANYSOCK;
++
++ switch (pm_mnt-&gt;pm_prot) {
++ case IPPROTO_UDP:
++ mclient = clntudp_create(&amp;mount_server_addr,
++ pm_mnt-&gt;pm_prog,
++ pm_mnt-&gt;pm_vers,
++ retry_timeout,
++ &amp;msock);
++ if (mclient)
++ break;
++ mount_server_addr.sin_port =
++ htons(pm_mnt-&gt;pm_port);
++ msock = RPC_ANYSOCK;
++ case IPPROTO_TCP:
++ mclient = clnttcp_create(&amp;mount_server_addr,
++ pm_mnt-&gt;pm_prog,
++ pm_mnt-&gt;pm_vers,
++ &amp;msock, 0, 0);
++ break;
++ default:
++ mclient = 0;
++ }
++
++ if (mclient) {
++ /* try to mount hostname:dirname */
++ mclient-&gt;cl_auth = authunix_create_default();
++
++ /* make pointers in xdr_mountres3 NULL so
++ * that xdr_array allocates memory for us
++ */
++ memset(&amp;status, 0, sizeof(status));
++
++ log_message(&quot;nfsmount: doing client call in nfs version: %ld&quot;, pm_mnt-&gt;pm_vers);
++ if (pm_mnt-&gt;pm_vers == 3)
++ clnt_stat = clnt_call(mclient,
++ MOUNTPROC3_MNT,
++ (xdrproc_t) xdr_dirpath,
++ (caddr_t) &amp;dirname,
++ (xdrproc_t) xdr_mountres3,
++ (caddr_t) &amp;status,
++ total_timeout);
++ else
++ clnt_stat = clnt_call(mclient,
++ MOUNTPROC_MNT,
++ (xdrproc_t) xdr_dirpath,
++ (caddr_t) &amp;dirname,
++ (xdrproc_t) xdr_fhstatus,
++ (caddr_t) &amp;status,
++ total_timeout);
++
++ if (clnt_stat == RPC_SUCCESS)
++ goto succeeded;
++
++ if (prevt == 0)
++ log_message(&quot;could not call server: probably protocol or version error&quot;);
++ auth_destroy(mclient-&gt;cl_auth);
++ clnt_destroy(mclient);
++ mclient = 0;
++ close(msock);
++ } else {
++ log_message(&quot;could not create rpc client: host probably not found or NFS server is down&quot;);
++ }
++ prevt = t;
++
++ goto fail;
++
++ succeeded:
++ nfsvers = (pm_mnt-&gt;pm_vers &lt; 2) ? 2 : pm_mnt-&gt;pm_vers;
++
++ if (nfsvers == 2) {
++ if (status.nfsv2.fhs_status != 0) {
++ log_message(&quot;nfsmount: %s:%s failed, reason given by server: %s&quot;,
++ hostname, dirname, nfs_strerror(status.nfsv2.fhs_status));
++ goto fail;
++ }
++ memcpy(data.root.data,
++ (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
++ NFS_FHSIZE);
++#if NFS_MOUNT_VERSION &gt;= 4
++ data.root.size = NFS_FHSIZE;
++ memcpy(data.old_root.data,
++ (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
++ NFS_FHSIZE);
++#endif
++ } else {
++#if NFS_MOUNT_VERSION &gt;= 4
++ fhandle3 *fhandle;
++ if (status.nfsv3.fhs_status != 0) {
++ log_message(&quot;nfsmount: %s:%s failed, reason given by server: %s&quot;,
++ hostname, dirname, nfs_strerror(status.nfsv3.fhs_status));
++ goto fail;
++ }
++ fhandle = &amp;status.nfsv3.mountres3_u.mountinfo.fhandle;
++ memset(data.old_root.data, 0, NFS_FHSIZE);
++ memset(&amp;data.root, 0, sizeof(data.root));
++ data.root.size = fhandle-&gt;fhandle3_len;
++ memcpy(data.root.data,
++ (char *) fhandle-&gt;fhandle3_val,
++ fhandle-&gt;fhandle3_len);
++
++ data.flags |= NFS_MOUNT_VER3;
++#endif
++ }
++
++ /* create nfs socket for kernel */
++
++ if (tcp) {
++ if (nfs_mount_version &lt; 3) {
++ log_message(&quot;NFS over TCP is not supported.&quot;);
++ goto fail;
++ }
++ fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
++ } else
++ fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
++ if (fsock &lt; 0) {
++ log_perror(&quot;nfs socket&quot;);
++ goto fail;
++ }
++ if (bindresvport(fsock, 0) &lt; 0) {
++ log_perror(&quot;nfs bindresvport&quot;);
++ goto fail;
++ }
++ if (port == 0) {
++ server_addr.sin_port = PMAPPORT;
++ port = pmap_getport(&amp;server_addr, nfsprog, nfsvers,
++ tcp ? IPPROTO_TCP : IPPROTO_UDP);
++#if 1
++ /* Here we check to see if user is mounting with the
++ * tcp option. If so, and if the portmap returns a
++ * '0' for port (service unavailable), we then notify
++ * the user, and retry with udp.
++ */
++ if (port == 0 &amp;&amp; tcp == 1) {
++ log_message(&quot;NFS server reported TCP not available, retrying with UDP...&quot;);
++ tcp = 0;
++ goto retry_mount;
++ }
++#endif
++
++ if (port == 0)
++ port = NFS_PORT;
++#ifdef NFS_MOUNT_DEBUG
++ else
++ log_message(&quot;used portmapper to find NFS port&quot;);
++#endif
++ }
++#ifdef NFS_MOUNT_DEBUG
++ log_message(&quot;using port %d for nfs deamon&quot;, port);
++#endif
++ server_addr.sin_port = htons(port);
++ /*
++ * connect() the socket for kernels 1.3.10 and below only,
++ * to avoid problems with multihomed hosts.
++ * --Swen
++ */
++ if (linux_version_code() &lt;= 66314
++ &amp;&amp; connect(fsock, (struct sockaddr *) &amp;server_addr,
++ sizeof (server_addr)) &lt; 0) {
++ log_perror(&quot;nfs connect&quot;);
++ goto fail;
++ }
++
++ /* prepare data structure for kernel */
++
++ data.fd = fsock;
++ memcpy((char *) &amp;data.addr, (char *) &amp;server_addr, sizeof(data.addr));
++ strncpy(data.hostname, hostname, sizeof(data.hostname));
++
++ /* clean up */
++
++ auth_destroy(mclient-&gt;cl_auth);
++ clnt_destroy(mclient);
++ close(msock);
++ return 0;
++
++ /* abort */
++
++ fail:
++ if (msock != -1) {
++ if (mclient) {
++ auth_destroy(mclient-&gt;cl_auth);
++ clnt_destroy(mclient);
++ }
++ close(msock);
++ }
++ if (fsock != -1)
++ close(fsock);
++ return retval;
++}
++
++/*
++ * We need to translate between nfs status return values and
++ * the local errno values which may not be the same.
++ *
++ * Andreas Schwab &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">schwab at LS5.informatik.uni-dortmund.de</A>&gt;: change errno:
++ * &quot;after #include &lt;errno.h&gt; the symbol errno is reserved for any use,
++ * it cannot even be used as a struct tag or field name&quot;.
++ */
++
++#ifndef EDQUOT
++#define EDQUOT ENOSPC
++#endif
++
++static struct {
++ enum nfsstat stat;
++ int errnum;
++} nfs_errtbl[] = {
++ { NFS_OK, 0 },
++ { NFSERR_PERM, EPERM },
++ { NFSERR_NOENT, ENOENT },
++ { NFSERR_IO, EIO },
++ { NFSERR_NXIO, ENXIO },
++ { NFSERR_ACCES, EACCES },
++ { NFSERR_EXIST, EEXIST },
++ { NFSERR_NODEV, ENODEV },
++ { NFSERR_NOTDIR, ENOTDIR },
++ { NFSERR_ISDIR, EISDIR },
++#ifdef NFSERR_INVAL
++ { NFSERR_INVAL, EINVAL }, /* that Sun forgot */
++#endif
++ { NFSERR_FBIG, EFBIG },
++ { NFSERR_NOSPC, ENOSPC },
++ { NFSERR_ROFS, EROFS },
++ { NFSERR_NAMETOOLONG, ENAMETOOLONG },
++ { NFSERR_NOTEMPTY, ENOTEMPTY },
++ { NFSERR_DQUOT, EDQUOT },
++ { NFSERR_STALE, ESTALE },
++#ifdef EWFLUSH
++ { NFSERR_WFLUSH, EWFLUSH },
++#endif
++ /* Throw in some NFSv3 values for even more fun (HP returns these) */
++ { 71, EREMOTE },
++
++ { -1, EIO }
++};
++
++static char *nfs_strerror(int stat)
++{
++ int i;
++ static char buf[256];
++
++ for (i = 0; nfs_errtbl[i].stat != (unsigned)-1; i++) {
++ if (nfs_errtbl[i].stat == (unsigned)stat)
++ return strerror(nfs_errtbl[i].errnum);
++ }
++ sprintf(buf, &quot;unknown nfs status return value: %d&quot;, stat);
++ return buf;
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/nfsmount.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/nfsmount.h
+===================================================================
+--- drakx/trunk/mdk-stage1/nfsmount.h (rev 0)
++++ drakx/trunk/mdk-stage1/nfsmount.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,331 @@
++/*
++ * Please do not edit this file.
++ * It was generated using rpcgen.
++ */
++
++#ifndef _NFSMOUNT_H_RPCGEN
++#define _NFSMOUNT_H_RPCGEN
++
++#include &lt;rpc/rpc.h&gt;
++
++int nfsmount_prepare(const char *spec, char **mount_opts);
++
++
++#ifdef __cplusplus
++extern &quot;C&quot; {
++#endif
++
++/*
++ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
++ * unrestricted use provided that this legend is included on all tape
++ * media and as a part of the software program in whole or part. Users
++ * may copy or modify Sun RPC without charge, but are not authorized
++ * to license or distribute it to anyone else except as part of a product or
++ * program developed by the user or with the express written consent of
++ * Sun Microsystems, Inc.
++ *
++ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
++ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
++ *
++ * Sun RPC is provided with no support and without any obligation on the
++ * part of Sun Microsystems, Inc. to assist in its use, correction,
++ * modification or enhancement.
++ *
++ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
++ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
++ * OR ANY PART THEREOF.
++ *
++ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
++ * or profits or other special, indirect and consequential damages, even if
++ * Sun has been advised of the possibility of such damages.
++ *
++ * Sun Microsystems, Inc.
++ * 2550 Garcia Avenue
++ * Mountain View, California 94043
++ */
++/*
++ * Copyright (c) 1985, 1990 by Sun Microsystems, Inc.
++ */
++
++/* from @(#)mount.x 1.3 91/03/11 TIRPC 1.0 */
++#ifndef _rpcsvc_mount_h
++#define _rpcsvc_mount_h
++#include &lt;asm/types.h&gt;
++#define MNTPATHLEN 1024
++#define MNTNAMLEN 255
++#define FHSIZE 32
++#define FHSIZE3 64
++
++typedef char fhandle[FHSIZE];
++
++typedef struct {
++ u_int fhandle3_len;
++ char *fhandle3_val;
++} fhandle3;
++
++enum mountstat3 {
++ MNT_OK = 0,
++ MNT3ERR_PERM = 1,
++ MNT3ERR_NOENT = 2,
++ MNT3ERR_IO = 5,
++ MNT3ERR_ACCES = 13,
++ MNT3ERR_NOTDIR = 20,
++ MNT3ERR_INVAL = 22,
++ MNT3ERR_NAMETOOLONG = 63,
++ MNT3ERR_NOTSUPP = 10004,
++ MNT3ERR_SERVERFAULT = 10006,
++};
++typedef enum mountstat3 mountstat3;
++
++struct fhstatus {
++ u_int fhs_status;
++ union {
++ fhandle fhs_fhandle;
++ } fhstatus_u;
++};
++typedef struct fhstatus fhstatus;
++
++struct mountres3_ok {
++ fhandle3 fhandle;
++ struct {
++ u_int auth_flavours_len;
++ int *auth_flavours_val;
++ } auth_flavours;
++};
++typedef struct mountres3_ok mountres3_ok;
++
++struct mountres3 {
++ mountstat3 fhs_status;
++ union {
++ mountres3_ok mountinfo;
++ } mountres3_u;
++};
++typedef struct mountres3 mountres3;
++
++typedef char *dirpath;
++
++typedef char *name;
++
++typedef struct mountbody *mountlist;
++
++struct mountbody {
++ name ml_hostname;
++ dirpath ml_directory;
++ mountlist ml_next;
++};
++typedef struct mountbody mountbody;
++
++typedef struct groupnode *groups;
++
++struct groupnode {
++ name gr_name;
++ groups gr_next;
++};
++typedef struct groupnode groupnode;
++
++typedef struct exportnode *exports;
++
++struct exportnode {
++ dirpath ex_dir;
++ groups ex_groups;
++ exports ex_next;
++};
++typedef struct exportnode exportnode;
++
++struct ppathcnf {
++ int pc_link_max;
++ short pc_max_canon;
++ short pc_max_input;
++ short pc_name_max;
++ short pc_path_max;
++ short pc_pipe_buf;
++ u_char pc_vdisable;
++ char pc_xxx;
++ short pc_mask[2];
++};
++typedef struct ppathcnf ppathcnf;
++#endif /*!_rpcsvc_mount_h*/
++
++#define MOUNTPROG 100005
++#define MOUNTVERS 1
++
++#if defined(__STDC__) || defined(__cplusplus)
++#define MOUNTPROC_NULL 0
++extern void * mountproc_null_1(void *, CLIENT *);
++extern void * mountproc_null_1_svc(void *, struct svc_req *);
++#define MOUNTPROC_MNT 1
++extern fhstatus * mountproc_mnt_1(dirpath *, CLIENT *);
++extern fhstatus * mountproc_mnt_1_svc(dirpath *, struct svc_req *);
++#define MOUNTPROC_DUMP 2
++extern mountlist * mountproc_dump_1(void *, CLIENT *);
++extern mountlist * mountproc_dump_1_svc(void *, struct svc_req *);
++#define MOUNTPROC_UMNT 3
++extern void * mountproc_umnt_1(dirpath *, CLIENT *);
++extern void * mountproc_umnt_1_svc(dirpath *, struct svc_req *);
++#define MOUNTPROC_UMNTALL 4
++extern void * mountproc_umntall_1(void *, CLIENT *);
++extern void * mountproc_umntall_1_svc(void *, struct svc_req *);
++#define MOUNTPROC_EXPORT 5
++extern exports * mountproc_export_1(void *, CLIENT *);
++extern exports * mountproc_export_1_svc(void *, struct svc_req *);
++#define MOUNTPROC_EXPORTALL 6
++extern exports * mountproc_exportall_1(void *, CLIENT *);
++extern exports * mountproc_exportall_1_svc(void *, struct svc_req *);
++extern int mountprog_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
++
++#else /* K&amp;R C */
++#define MOUNTPROC_NULL 0
++extern void * mountproc_null_1();
++extern void * mountproc_null_1_svc();
++#define MOUNTPROC_MNT 1
++extern fhstatus * mountproc_mnt_1();
++extern fhstatus * mountproc_mnt_1_svc();
++#define MOUNTPROC_DUMP 2
++extern mountlist * mountproc_dump_1();
++extern mountlist * mountproc_dump_1_svc();
++#define MOUNTPROC_UMNT 3
++extern void * mountproc_umnt_1();
++extern void * mountproc_umnt_1_svc();
++#define MOUNTPROC_UMNTALL 4
++extern void * mountproc_umntall_1();
++extern void * mountproc_umntall_1_svc();
++#define MOUNTPROC_EXPORT 5
++extern exports * mountproc_export_1();
++extern exports * mountproc_export_1_svc();
++#define MOUNTPROC_EXPORTALL 6
++extern exports * mountproc_exportall_1();
++extern exports * mountproc_exportall_1_svc();
++extern int mountprog_1_freeresult ();
++#endif /* K&amp;R C */
++#define MOUNTVERS_POSIX 2
++
++#if defined(__STDC__) || defined(__cplusplus)
++extern void * mountproc_null_2(void *, CLIENT *);
++extern void * mountproc_null_2_svc(void *, struct svc_req *);
++extern fhstatus * mountproc_mnt_2(dirpath *, CLIENT *);
++extern fhstatus * mountproc_mnt_2_svc(dirpath *, struct svc_req *);
++extern mountlist * mountproc_dump_2(void *, CLIENT *);
++extern mountlist * mountproc_dump_2_svc(void *, struct svc_req *);
++extern void * mountproc_umnt_2(dirpath *, CLIENT *);
++extern void * mountproc_umnt_2_svc(dirpath *, struct svc_req *);
++extern void * mountproc_umntall_2(void *, CLIENT *);
++extern void * mountproc_umntall_2_svc(void *, struct svc_req *);
++extern exports * mountproc_export_2(void *, CLIENT *);
++extern exports * mountproc_export_2_svc(void *, struct svc_req *);
++extern exports * mountproc_exportall_2(void *, CLIENT *);
++extern exports * mountproc_exportall_2_svc(void *, struct svc_req *);
++#define MOUNTPROC_PATHCONF 7
++extern ppathcnf * mountproc_pathconf_2(dirpath *, CLIENT *);
++extern ppathcnf * mountproc_pathconf_2_svc(dirpath *, struct svc_req *);
++extern int mountprog_2_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
++
++#else /* K&amp;R C */
++extern void * mountproc_null_2();
++extern void * mountproc_null_2_svc();
++extern fhstatus * mountproc_mnt_2();
++extern fhstatus * mountproc_mnt_2_svc();
++extern mountlist * mountproc_dump_2();
++extern mountlist * mountproc_dump_2_svc();
++extern void * mountproc_umnt_2();
++extern void * mountproc_umnt_2_svc();
++extern void * mountproc_umntall_2();
++extern void * mountproc_umntall_2_svc();
++extern exports * mountproc_export_2();
++extern exports * mountproc_export_2_svc();
++extern exports * mountproc_exportall_2();
++extern exports * mountproc_exportall_2_svc();
++#define MOUNTPROC_PATHCONF 7
++extern ppathcnf * mountproc_pathconf_2();
++extern ppathcnf * mountproc_pathconf_2_svc();
++extern int mountprog_2_freeresult ();
++#endif /* K&amp;R C */
++#define MOUNT_V3 3
++
++#if defined(__STDC__) || defined(__cplusplus)
++#define MOUNTPROC3_NULL 0
++extern void * mountproc3_null_3(void *, CLIENT *);
++extern void * mountproc3_null_3_svc(void *, struct svc_req *);
++#define MOUNTPROC3_MNT 1
++extern mountres3 * mountproc3_mnt_3(dirpath *, CLIENT *);
++extern mountres3 * mountproc3_mnt_3_svc(dirpath *, struct svc_req *);
++#define MOUNTPROC3_DUMP 2
++extern mountlist * mountproc3_dump_3(void *, CLIENT *);
++extern mountlist * mountproc3_dump_3_svc(void *, struct svc_req *);
++#define MOUNTPROC3_UMNT 3
++extern void * mountproc3_umnt_3(dirpath *, CLIENT *);
++extern void * mountproc3_umnt_3_svc(dirpath *, struct svc_req *);
++#define MOUNTPROC3_UMNTALL 4
++extern void * mountproc3_umntall_3(void *, CLIENT *);
++extern void * mountproc3_umntall_3_svc(void *, struct svc_req *);
++#define MOUNTPROC3_EXPORT 5
++extern exports * mountproc3_export_3(void *, CLIENT *);
++extern exports * mountproc3_export_3_svc(void *, struct svc_req *);
++extern int mountprog_3_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
++
++#else /* K&amp;R C */
++#define MOUNTPROC3_NULL 0
++extern void * mountproc3_null_3();
++extern void * mountproc3_null_3_svc();
++#define MOUNTPROC3_MNT 1
++extern mountres3 * mountproc3_mnt_3();
++extern mountres3 * mountproc3_mnt_3_svc();
++#define MOUNTPROC3_DUMP 2
++extern mountlist * mountproc3_dump_3();
++extern mountlist * mountproc3_dump_3_svc();
++#define MOUNTPROC3_UMNT 3
++extern void * mountproc3_umnt_3();
++extern void * mountproc3_umnt_3_svc();
++#define MOUNTPROC3_UMNTALL 4
++extern void * mountproc3_umntall_3();
++extern void * mountproc3_umntall_3_svc();
++#define MOUNTPROC3_EXPORT 5
++extern exports * mountproc3_export_3();
++extern exports * mountproc3_export_3_svc();
++extern int mountprog_3_freeresult ();
++#endif /* K&amp;R C */
++
++/* the xdr functions */
++
++#if defined(__STDC__) || defined(__cplusplus)
++extern bool_t xdr_fhandle (XDR *, fhandle);
++extern bool_t xdr_fhandle3 (XDR *, fhandle3*);
++extern bool_t xdr_mountstat3 (XDR *, mountstat3*);
++extern bool_t xdr_fhstatus (XDR *, fhstatus*);
++extern bool_t xdr_mountres3_ok (XDR *, mountres3_ok*);
++extern bool_t xdr_mountres3 (XDR *, mountres3*);
++extern bool_t xdr_dirpath (XDR *, dirpath*);
++extern bool_t xdr_name (XDR *, name*);
++extern bool_t xdr_mountlist (XDR *, mountlist*);
++extern bool_t xdr_mountbody (XDR *, mountbody*);
++extern bool_t xdr_groups (XDR *, groups*);
++extern bool_t xdr_groupnode (XDR *, groupnode*);
++extern bool_t xdr_exports (XDR *, exports*);
++extern bool_t xdr_exportnode (XDR *, exportnode*);
++extern bool_t xdr_ppathcnf (XDR *, ppathcnf*);
++
++#else /* K&amp;R C */
++extern bool_t xdr_fhandle ();
++extern bool_t xdr_fhandle3 ();
++extern bool_t xdr_mountstat3 ();
++extern bool_t xdr_fhstatus ();
++extern bool_t xdr_mountres3_ok ();
++extern bool_t xdr_mountres3 ();
++extern bool_t xdr_dirpath ();
++extern bool_t xdr_name ();
++extern bool_t xdr_mountlist ();
++extern bool_t xdr_mountbody ();
++extern bool_t xdr_groups ();
++extern bool_t xdr_groupnode ();
++extern bool_t xdr_exports ();
++extern bool_t xdr_exportnode ();
++extern bool_t xdr_ppathcnf ();
++
++#endif /* K&amp;R C */
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* !_NFSMOUNT_H_RPCGEN */
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/nfsmount.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/params.c
+===================================================================
+--- drakx/trunk/mdk-stage1/params.c (rev 0)
++++ drakx/trunk/mdk-stage1/params.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,177 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;fcntl.h&gt;
++#include &quot;params.h&quot;
++#include &quot;utils.h&quot;
++#include &quot;automatic.h&quot;
++#include &quot;log.h&quot;
++#include &quot;bootsplash.h&quot;
++
++static struct param_elem params[50];
++static int param_number = 0;
++
++void process_cmdline(void)
++{
++ char buf[512];
++ int size, i;
++ int fd = -1;
++
++ if (IS_TESTING) {
++ log_message(&quot;TESTING: opening cmdline... &quot;);
++
++ if ((fd = open(&quot;cmdline&quot;, O_RDONLY)) == -1)
++ log_message(&quot;TESTING: could not open cmdline&quot;);
++ }
++
++ if (fd == -1) {
++ log_message(&quot;opening /proc/cmdline... &quot;);
++
++ if ((fd = open(&quot;/proc/cmdline&quot;, O_RDONLY)) == -1)
++ fatal_error(&quot;could not open /proc/cmdline&quot;);
++ }
++
++ size = read(fd, buf, sizeof(buf));
++ buf[size-1] = '\0'; // -1 to eat the \n
++ close(fd);
++
++ log_message(&quot;\t%s&quot;, buf);
++
++ i = 0;
++ while (buf[i] != '\0') {
++ char *name, *value = NULL;
++ int j = i;
++ while (buf[i] != ' ' &amp;&amp; buf[i] != '=' &amp;&amp; buf[i] != '\0')
++ i++;
++ if (i == j) {
++ i++;
++ continue;
++ }
++ name = memdup(&amp;buf[j], i-j + 1);
++ name[i-j] = '\0';
++
++ if (buf[i] == '=') {
++ int k = i+1;
++ i++;
++ while (buf[i] != ' ' &amp;&amp; buf[i] != '\0')
++ i++;
++ value = memdup(&amp;buf[k], i-k + 1);
++ value[i-k] = '\0';
++ }
++
++ params[param_number].name = name;
++ params[param_number].value = value;
++ param_number++;
++ if (!strcmp(name, &quot;changedisk&quot;)) set_param(MODE_CHANGEDISK);
++ if (!strcmp(name, &quot;updatemodules&quot;) ||
++ !strcmp(name, &quot;thirdparty&quot;)) set_param(MODE_THIRDPARTY);
++ if (!strcmp(name, &quot;rescue&quot;) ||
++ !strcmp(name, &quot;kamethod&quot;)) set_param(MODE_RESCUE);
++ if (!strcmp(name, &quot;rescue&quot;)) set_param(MODE_RESCUE);
++ if (!strcmp(name, &quot;keepmounted&quot;)) set_param(MODE_KEEP_MOUNTED);
++ if (!strcmp(name, &quot;noauto&quot;)) set_param(MODE_NOAUTO);
++ if (!strcmp(name, &quot;netauto&quot;)) set_param(MODE_NETAUTO);
++ if (!strcmp(name, &quot;debugstage1&quot;)) set_param(MODE_DEBUGSTAGE1);
++ if (!strcmp(name, &quot;automatic&quot;)) {
++ set_param(MODE_AUTOMATIC);
++ grab_automatic_params(value);
++ }
++ if (buf[i] == '\0')
++ break;
++ i++;
++ }
++
++ if (IS_AUTOMATIC &amp;&amp; strcmp(get_auto_value(&quot;thirdparty&quot;), &quot;&quot;)) {
++ set_param(MODE_THIRDPARTY);
++ }
++
++ log_message(&quot;\tgot %d args&quot;, param_number);
++}
++
++
++int stage1_mode = 0;
++
++int get_param(int i)
++{
++#ifdef SPAWN_INTERACTIVE
++ static int fd = 0;
++ char buf[5000];
++ char * ptr;
++ int nb;
++
++ if (fd &lt;= 0) {
++ fd = open(interactive_fifo, O_RDONLY);
++ if (fd == -1)
++ return (stage1_mode &amp; i);
++ fcntl(fd, F_SETFL, O_NONBLOCK);
++ }
++
++ if (fd &gt; 0) {
++ if ((nb = read(fd, buf, sizeof(buf))) &gt; 0) {
++ buf[nb] = '\0';
++ ptr = buf;
++ while ((ptr = strstr(ptr, &quot;+ &quot;))) {
++ if (!strncmp(ptr+2, &quot;rescue&quot;, 6)) set_param(MODE_RESCUE);
++ ptr++;
++ }
++ ptr = buf;
++ while ((ptr = strstr(ptr, &quot;- &quot;))) {
++ if (!strncmp(ptr+2, &quot;rescue&quot;, 6)) unset_param(MODE_RESCUE);
++ ptr++;
++ }
++ }
++ }
++#endif
++
++ return (stage1_mode &amp; i);
++}
++
++char * get_param_valued(char *param_name)
++{
++ int i;
++ for (i = 0; i &lt; param_number ; i++)
++ if (!strcmp(params[i].name, param_name))
++ return params[i].value;
++
++ return NULL;
++}
++
++void set_param_valued(char *param_name, char *param_value)
++{
++ params[param_number].name = param_name;
++ params[param_number].value = param_value;
++ param_number++;
++}
++
++void set_param(int i)
++{
++ stage1_mode |= i;
++}
++
++void unset_param(int i)
++{
++ stage1_mode &amp;= ~i;
++}
++
++void unset_automatic(void)
++{
++ log_message(&quot;unsetting automatic&quot;);
++ unset_param(MODE_AUTOMATIC);
++ exit_bootsplash();
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/params.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/params.h
+===================================================================
+--- drakx/trunk/mdk-stage1/params.h (rev 0)
++++ drakx/trunk/mdk-stage1/params.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,31 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#ifndef _PARAMS_H_
++#define _PARAMS_H_
++
++void process_cmdline(void);
++int get_param(int i);
++char * get_param_valued(char *param_name);
++void set_param(int i);
++void unset_param(int i);
++void unset_automatic(void);
++
++struct param_elem
++{
++ char * name;
++ char * value;
++};
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/params.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/partition.c
+===================================================================
+--- drakx/trunk/mdk-stage1/partition.c (rev 0)
++++ drakx/trunk/mdk-stage1/partition.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,170 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Portions from Erik Troan (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ewt at redhat.com</A>)
++ *
++ * Copyright 1996 Red Hat Software
++ *
++ */
++
++#include &lt;stdlib.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;string.h&gt;
++#include &lt;sys/mount.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;string.h&gt;
++#include &lt;libgen.h&gt;
++#include &quot;stage1.h&quot;
++#include &quot;frontend.h&quot;
++#include &quot;modules.h&quot;
++#include &quot;probing.h&quot;
++#include &quot;log.h&quot;
++#include &quot;mount.h&quot;
++#include &quot;automatic.h&quot;
++
++#include &quot;disk.h&quot;
++#include &quot;partition.h&quot;
++
++struct partition_detection_anchor {
++ off_t offset;
++ const char * anchor;
++};
++
++static int seek_and_compare(int fd, struct partition_detection_anchor anch)
++{
++ char buf[500];
++ size_t count;
++ if (lseek(fd, anch.offset, SEEK_SET) == (off_t)-1) {
++ log_perror(&quot;seek failed&quot;);
++ return -1;
++ }
++ count = read(fd, buf, strlen(anch.anchor));
++ if (count != strlen(anch.anchor)) {
++ log_perror(&quot;read failed&quot;);
++ return -1;
++ }
++ buf[count] = '\0';
++ if (strcmp(anch.anchor, buf))
++ return 1;
++ return 0;
++}
++
++static const char * detect_partition_type(char * dev)
++{
++ struct partition_detection_info {
++ const char * name;
++ struct partition_detection_anchor anchor0;
++ struct partition_detection_anchor anchor1;
++ struct partition_detection_anchor anchor2;
++ };
++ struct partition_detection_info partitions_signatures[] = {
++ { &quot;Linux Swap&quot;, { 4086, &quot;SWAP-SPACE&quot; }, { 0, NULL }, { 0, NULL } },
++ { &quot;Linux Swap&quot;, { 4086, &quot;SWAPSPACE2&quot; }, { 0, NULL }, { 0, NULL } },
++ { &quot;Ext2&quot;, { 0x438, &quot;\x53\xEF&quot; }, { 0, NULL }, { 0, NULL } },
++ { &quot;ReiserFS&quot;, { 0x10034, &quot;ReIsErFs&quot; }, { 0, NULL }, { 0, NULL } },
++ { &quot;ReiserFS&quot;, { 0x10034, &quot;ReIsEr2Fs&quot; }, { 0, NULL }, { 0, NULL } },
++ { &quot;XFS&quot;, { 0, &quot;XFSB&quot; }, { 0x200, &quot;XAGF&quot; }, { 0x400, &quot;XAGI&quot; } },
++ { &quot;JFS&quot;, { 0x8000, &quot;JFS1&quot; }, { 0, NULL }, { 0, NULL } },
++ { &quot;NTFS&quot;, { 0x1FE, &quot;\x55\xAA&quot; }, { 0x3, &quot;NTFS&quot; }, { 0, NULL } },
++ { &quot;FAT32&quot;, { 0x1FE, &quot;\x55\xAA&quot; }, { 0x52, &quot;FAT32&quot; }, { 0, NULL } },
++ { &quot;FAT&quot;, { 0x1FE, &quot;\x55\xAA&quot; }, { 0x36, &quot;FAT&quot; }, { 0, NULL } },
++ { &quot;Linux LVM&quot;, { 0, &quot;HM\1\0&quot; }, { 0, NULL }, { 0, NULL } }
++ };
++ int partitions_signatures_nb = sizeof(partitions_signatures) / sizeof(struct partition_detection_info);
++ int i;
++ int fd;
++ const char *part_type = NULL;
++
++ char device_fullname[50];
++ strcpy(device_fullname, &quot;/dev/&quot;);
++ strcat(device_fullname, dev);
++
++ if (ensure_dev_exists(device_fullname))
++ return NULL;
++ log_message(&quot;guessing type of %s&quot;, device_fullname);
++
++ if ((fd = open(device_fullname, O_RDONLY, 0)) &lt; 0) {
++ log_perror(&quot;open&quot;);
++ return NULL;
++ }
++
++ for (i=0; i&lt;partitions_signatures_nb; i++) {
++ int results = seek_and_compare(fd, partitions_signatures[i].anchor0);
++ if (results == -1)
++ goto detect_partition_type_end;
++ if (results == 1)
++ continue;
++ if (!partitions_signatures[i].anchor1.anchor)
++ goto detect_partition_found_it;
++
++ results = seek_and_compare(fd, partitions_signatures[i].anchor1);
++ if (results == -1)
++ goto detect_partition_type_end;
++ if (results == 1)
++ continue;
++ if (!partitions_signatures[i].anchor2.anchor)
++ goto detect_partition_found_it;
++
++ results = seek_and_compare(fd, partitions_signatures[i].anchor2);
++ if (results == -1)
++ goto detect_partition_type_end;
++ if (results == 1)
++ continue;
++
++ detect_partition_found_it:
++ part_type = partitions_signatures[i].name;
++ break;
++ }
++
++ detect_partition_type_end:
++ close(fd);
++ return part_type;
++}
++
++int list_partitions(char * dev_name, char ** parts, char ** comments)
++{
++ int major, minor, blocks;
++ char name[100];
++ FILE * f;
++ int i = 0;
++ char buf[512];
++
++ if (!(f = fopen(&quot;/proc/partitions&quot;, &quot;rb&quot;)) || !fgets(buf, sizeof(buf), f) || !fgets(buf, sizeof(buf), f)) {
++ log_perror(dev_name);
++ return 1;
++ }
++
++ while (fgets(buf, sizeof(buf), f)) {
++ memset(name, 0, sizeof(name));
++ sscanf(buf, &quot; %d %d %d %s&quot;, &amp;major, &amp;minor, &amp;blocks, name);
++ if ((strstr(name, dev_name) == name) &amp;&amp; (blocks &gt; 1) &amp;&amp; (name[strlen(dev_name)] != '\0')) {
++ const char * partition_type = detect_partition_type(name);
++ parts[i] = strdup(name);
++ comments[i] = (char *) malloc(sizeof(char) * 100);
++ sprintf(comments[i], &quot;size: %d Mbytes&quot;, blocks &gt;&gt; 10);
++ if (partition_type) {
++ strcat(comments[i], &quot;, type: &quot;);
++ strcat(comments[i], partition_type);
++ }
++ i++;
++ }
++ }
++ parts[i] = NULL;
++ fclose(f);
++
++ return 0;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/partition.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/partition.h
+===================================================================
+--- drakx/trunk/mdk-stage1/partition.h (rev 0)
++++ drakx/trunk/mdk-stage1/partition.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,28 @@
++/*
++ * Olivier Blin (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">oblin at mandriva.com</A>)
++ *
++ * Copyright 2005 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Portions from Erik Troan (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ewt at redhat.com</A>)
++ *
++ * Copyright 1996 Red Hat Software
++ *
++ */
++
++#ifndef _PARTITION_H_
++#define _PARTITION_H_
++
++int list_partitions(char * dev_name, char ** parts, char ** comments);
++
++#endif
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/partition.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/pci-resource/Makefile
+===================================================================
+--- drakx/trunk/mdk-stage1/pci-resource/Makefile (rev 0)
++++ drakx/trunk/mdk-stage1/pci-resource/Makefile 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,25 @@
++ #******************************************************************************
++ #
++ # $Id: Makefile 253685 2009-03-06 14:27:29Z tv $
++ #
++ # Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ #
++ # Copyright 2000 Mandriva
++ #
++ # This software may be freely redistributed under the terms of the GNU
++ # public license.
++ #
++ # You should have received a copy of the GNU General Public License
++ # along with this program; if not, write to the Free Software
++ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ #
++ #*****************************************************************************
++
++
++all: pci-ids.h
++
++pci-ids.h: /usr/share/ldetect-lst/pcitable.gz update-pci-ids.pl
++ perl update-pci-ids.pl &gt; $@ || { rm -f $@; exit 1; }
++
++clean:
++ rm -f pci-ids.h
+
+
+Property changes on: drakx/trunk/mdk-stage1/pci-resource/Makefile
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/pci-resource/update-pci-ids.pl
+===================================================================
+--- drakx/trunk/mdk-stage1/pci-resource/update-pci-ids.pl (rev 0)
++++ drakx/trunk/mdk-stage1/pci-resource/update-pci-ids.pl 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,27 @@
++#!/usr/bin/perl
++
++use lib '../kernel';
++use strict;
++use MDK::Common;
++
++
++my %t = (
++ network =&gt; 'network/main|gigabit|tokenring|wireless|pcmcia',
++ medias_ide =&gt; 'disk/ide',
++ medias_other =&gt; 'disk/scsi|hardware_raid|sata bus/firewire',
++);
++
++foreach my $type (keys %t) {
++ my @modules = chomp_(`perl ../../kernel/modules.pl pci_modules4stage1 &quot;$t{$type}&quot;`)
++ or die &quot;unable to get PCI modules&quot;;
++
++ print &quot;#ifndef DISABLE_&quot;.uc($type).&quot;
++char* ${type}_pci_modules[] = {
++&quot;;
++ printf qq|\t&quot;%s&quot;,\n|, $_ foreach @modules;
++ print &quot;};
++unsigned int ${type}_pci_modules_len = sizeof(${type}_pci_modules) / sizeof(char *);
++#endif
++
++&quot;;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/pci-resource/update-pci-ids.pl
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: drakx/trunk/mdk-stage1/pcmcia/Makefile
+===================================================================
+--- drakx/trunk/mdk-stage1/pcmcia/Makefile (rev 0)
++++ drakx/trunk/mdk-stage1/pcmcia/Makefile 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,52 @@
++ #******************************************************************************
++ #
++ # Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ #
++ # Copyright 2001 Mandriva
++ #
++ # This software may be freely redistributed under the terms of the GNU
++ # public license.
++ #
++ # You should have received a copy of the GNU General Public License
++ # along with this program; if not, write to the Free Software
++ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ #
++ #*****************************************************************************
++
++# startup.c is based on pcmcia-socket-startup from pcmciautils-013
++
++top_dir = ..
++
++include $(top_dir)/Makefile.common
++
++TARGET = libpcmcia.a
++YFLAGS := -d
++
++all: $(TARGET) pcmcia_probe.o
++
++clean:
++ rm -f *.o $(TARGET) lex_config.c yacc_config.c yacc_config.h
++
++FLAGS = -D__linux__ -Wall -Werror -Wno-deprecated-declarations -Os -fomit-frame-pointer -pipe -c -I.. -D_BSD_SOURCE
++# (blino) make sure yynewerror and yyerrlab are uselessly used
++FLAGS += -Dlint
++LFLAGS += --nounput
++
++
++OBJS = probe.o startup.o yacc_config.o lex_config.o
++
++
++%.c %.h : %.y
++ $(YACC) $(YFLAGS) $&lt;
++ mv y.tab.c $*.c
++ mv y.tab.h $*.h
++
++$(TARGET): $(OBJS) yacc_config.h
++ ar -cru $@ $^
++ ranlib $@
++
++$(OBJS): %.o: %.c
++ $(DIET) gcc $(FLAGS) $(INCLUDES) -c $&lt; -o $@
++
++pcmcia_probe.o: probe.c
++ $(DIET) gcc -fPIC $(FLAGS) $(INCLUDES) -c $&lt; -o $@
+
+
+Property changes on: drakx/trunk/mdk-stage1/pcmcia/Makefile
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/pcmcia/bulkmem.h
+===================================================================
+--- drakx/trunk/mdk-stage1/pcmcia/bulkmem.h (rev 0)
++++ drakx/trunk/mdk-stage1/pcmcia/bulkmem.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,195 @@
++/*
++ * Definitions for bulk memory services
++ *
++ * bulkmem.h 1.13 2001/08/24 12:16:12
++ *
++ * The contents of this file are subject to the Mozilla Public License
++ * Version 1.1 (the &quot;License&quot;); you may not use this file except in
++ * compliance with the License. You may obtain a copy of the License
++ * at <A HREF="http://www.mozilla.org/MPL/">http://www.mozilla.org/MPL/</A>
++ *
++ * Software distributed under the License is distributed on an &quot;AS IS&quot;
++ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
++ * the License for the specific language governing rights and
++ * limitations under the License.
++ *
++ * The initial developer of the original code is David A. Hinds
++ * &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dahinds at users.sourceforge.net</A>&gt;. Portions created by David A. Hinds
++ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
++ *
++ * Alternatively, the contents of this file may be used under the
++ * terms of the GNU General Public License version 2 (the &quot;GPL&quot;), in
++ * which case the provisions of the GPL are applicable instead of the
++ * above. If you wish to allow the use of your version of this file
++ * only under the terms of the GPL and not to allow others to use
++ * your version of this file under the MPL, indicate your decision by
++ * deleting the provisions above and replace them with the notice and
++ * other provisions required by the GPL. If you do not delete the
++ * provisions above, a recipient may use your version of this file
++ * under either the MPL or the GPL.
++ * bulkmem.h 1.3 1995/05/27 04:49:49
++ */
++
++#ifndef _LINUX_BULKMEM_H
++#define _LINUX_BULKMEM_H
++
++/* For GetFirstRegion and GetNextRegion */
++typedef struct region_info_t {
++ u_int Attributes;
++ u_int CardOffset;
++ u_int RegionSize;
++ u_int AccessSpeed;
++ u_int BlockSize;
++ u_int PartMultiple;
++ u_char JedecMfr, JedecInfo;
++ memory_handle_t next;
++} region_info_t;
++
++#define REGION_TYPE 0x0001
++#define REGION_TYPE_CM 0x0000
++#define REGION_TYPE_AM 0x0001
++#define REGION_PREFETCH 0x0008
++#define REGION_CACHEABLE 0x0010
++#define REGION_BAR_MASK 0xe000
++#define REGION_BAR_SHIFT 13
++
++/* For OpenMemory */
++typedef struct open_mem_t {
++ u_int Attributes;
++ u_int Offset;
++} open_mem_t;
++
++/* Attributes for OpenMemory */
++#define MEMORY_TYPE 0x0001
++#define MEMORY_TYPE_CM 0x0000
++#define MEMORY_TYPE_AM 0x0001
++#define MEMORY_EXCLUSIVE 0x0002
++#define MEMORY_PREFETCH 0x0008
++#define MEMORY_CACHEABLE 0x0010
++#define MEMORY_BAR_MASK 0xe000
++#define MEMORY_BAR_SHIFT 13
++
++typedef struct eraseq_entry_t {
++ memory_handle_t Handle;
++ u_char State;
++ u_int Size;
++ u_int Offset;
++ void *Optional;
++} eraseq_entry_t;
++
++typedef struct eraseq_hdr_t {
++ int QueueEntryCnt;
++ eraseq_entry_t *QueueEntryArray;
++} eraseq_hdr_t;
++
++#define ERASE_QUEUED 0x00
++#define ERASE_IN_PROGRESS(n) (((n) &gt; 0) &amp;&amp; ((n) &lt; 0x80))
++#define ERASE_IDLE 0xff
++#define ERASE_PASSED 0xe0
++#define ERASE_FAILED 0xe1
++
++#define ERASE_MISSING 0x80
++#define ERASE_MEDIA_WRPROT 0x84
++#define ERASE_NOT_ERASABLE 0x85
++#define ERASE_BAD_OFFSET 0xc1
++#define ERASE_BAD_TECH 0xc2
++#define ERASE_BAD_SOCKET 0xc3
++#define ERASE_BAD_VCC 0xc4
++#define ERASE_BAD_VPP 0xc5
++#define ERASE_BAD_SIZE 0xc6
++
++/* For CopyMemory */
++typedef struct copy_op_t {
++ u_int Attributes;
++ u_int SourceOffset;
++ u_int DestOffset;
++ u_int Count;
++} copy_op_t;
++
++/* For ReadMemory and WriteMemory */
++typedef struct mem_op_t {
++ u_int Attributes;
++ u_int Offset;
++ u_int Count;
++} mem_op_t;
++
++#define MEM_OP_BUFFER 0x01
++#define MEM_OP_BUFFER_USER 0x00
++#define MEM_OP_BUFFER_KERNEL 0x01
++#define MEM_OP_DISABLE_ERASE 0x02
++#define MEM_OP_VERIFY 0x04
++
++/* For RegisterMTD */
++typedef struct mtd_reg_t {
++ u_int Attributes;
++ u_int Offset;
++ u_long MediaID;
++} mtd_reg_t;
++
++/*
++ * Definitions for MTD requests
++ */
++
++typedef struct mtd_request_t {
++ u_int SrcCardOffset;
++ u_int DestCardOffset;
++ u_int TransferLength;
++ u_int Function;
++ u_long MediaID;
++ u_int Status;
++ u_int Timeout;
++} mtd_request_t;
++
++/* Fields in MTD Function */
++#define MTD_REQ_ACTION 0x003
++#define MTD_REQ_ERASE 0x000
++#define MTD_REQ_READ 0x001
++#define MTD_REQ_WRITE 0x002
++#define MTD_REQ_COPY 0x003
++#define MTD_REQ_NOERASE 0x004
++#define MTD_REQ_VERIFY 0x008
++#define MTD_REQ_READY 0x010
++#define MTD_REQ_TIMEOUT 0x020
++#define MTD_REQ_LAST 0x040
++#define MTD_REQ_FIRST 0x080
++#define MTD_REQ_KERNEL 0x100
++
++/* Status codes */
++#define MTD_WAITREQ 0x00
++#define MTD_WAITTIMER 0x01
++#define MTD_WAITRDY 0x02
++#define MTD_WAITPOWER 0x03
++
++/*
++ * Definitions for MTD helper functions
++ */
++
++/* For MTDModifyWindow */
++typedef struct mtd_mod_win_t {
++ u_int Attributes;
++ u_int AccessSpeed;
++ u_int CardOffset;
++} mtd_mod_win_t;
++
++/* For MTDSetVpp */
++typedef struct mtd_vpp_req_t {
++ u_char Vpp1, Vpp2;
++} mtd_vpp_req_t;
++
++/* For MTDRDYMask */
++typedef struct mtd_rdy_req_t {
++ u_int Mask;
++} mtd_rdy_req_t;
++
++enum mtd_helper {
++ MTDRequestWindow, MTDModifyWindow, MTDReleaseWindow,
++ MTDSetVpp, MTDRDYMask
++};
++
++#ifdef IN_CARD_SERVICES
++extern int MTDHelperEntry(int func, void *a1, void *a2);
++#else
++extern int MTDHelperEntry(int func, ...);
++#endif
++
++#endif /* _LINUX_BULKMEM_H */
+
+
+Property changes on: drakx/trunk/mdk-stage1/pcmcia/bulkmem.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/pcmcia/cirrus.h
+===================================================================
+--- drakx/trunk/mdk-stage1/pcmcia/cirrus.h (rev 0)
++++ drakx/trunk/mdk-stage1/pcmcia/cirrus.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,157 @@
++/*
++ * cirrus.h 1.10 2001/08/24 12:15:33
++ *
++ * The contents of this file are subject to the Mozilla Public License
++ * Version 1.1 (the &quot;License&quot;); you may not use this file except in
++ * compliance with the License. You may obtain a copy of the License
++ * at <A HREF="http://www.mozilla.org/MPL/">http://www.mozilla.org/MPL/</A>
++ *
++ * Software distributed under the License is distributed on an &quot;AS IS&quot;
++ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
++ * the License for the specific language governing rights and
++ * limitations under the License.
++ *
++ * The initial developer of the original code is David A. Hinds
++ * &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dahinds at users.sourceforge.net</A>&gt;. Portions created by David A. Hinds
++ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
++ *
++ * Alternatively, the contents of this file may be used under the
++ * terms of the GNU General Public License version 2 (the &quot;GPL&quot;), in
++ * which case the provisions of the GPL are applicable instead of the
++ * above. If you wish to allow the use of your version of this file
++ * only under the terms of the GPL and not to allow others to use
++ * your version of this file under the MPL, indicate your decision by
++ * deleting the provisions above and replace them with the notice and
++ * other provisions required by the GPL. If you do not delete the
++ * provisions above, a recipient may use your version of this file
++ * under either the MPL or the GPL.
++ */
++
++#ifndef _LINUX_CIRRUS_H
++#define _LINUX_CIRRUS_H
++
++#ifndef PCI_VENDOR_ID_CIRRUS
++#define PCI_VENDOR_ID_CIRRUS 0x1013
++#endif
++#ifndef PCI_DEVICE_ID_CIRRUS_6729
++#define PCI_DEVICE_ID_CIRRUS_6729 0x1100
++#endif
++#ifndef PCI_DEVICE_ID_CIRRUS_6832
++#define PCI_DEVICE_ID_CIRRUS_6832 0x1110
++#endif
++
++#define PD67_MISC_CTL_1 0x16 /* Misc control 1 */
++#define PD67_FIFO_CTL 0x17 /* FIFO control */
++#define PD67_MISC_CTL_2 0x1E /* Misc control 2 */
++#define PD67_CHIP_INFO 0x1f /* Chip information */
++#define PD67_ATA_CTL 0x026 /* 6730: ATA control */
++#define PD67_EXT_INDEX 0x2e /* Extension index */
++#define PD67_EXT_DATA 0x2f /* Extension data */
++
++/* PD6722 extension registers -- indexed in PD67_EXT_INDEX */
++#define PD67_DATA_MASK0 0x01 /* Data mask 0 */
++#define PD67_DATA_MASK1 0x02 /* Data mask 1 */
++#define PD67_DMA_CTL 0x03 /* DMA control */
++
++/* PD6730 extension registers -- indexed in PD67_EXT_INDEX */
++#define PD67_EXT_CTL_1 0x03 /* Extension control 1 */
++#define PD67_MEM_PAGE(n) ((n)+5) /* PCI window bits 31:24 */
++#define PD67_EXTERN_DATA 0x0a
++#define PD67_MISC_CTL_3 0x25
++#define PD67_SMB_PWR_CTL 0x26
++
++/* I/O window address offset */
++#define PD67_IO_OFF(w) (0x36+((w)&lt;&lt;1))
++
++/* Timing register sets */
++#define PD67_TIME_SETUP(n) (0x3a + 3*(n))
++#define PD67_TIME_CMD(n) (0x3b + 3*(n))
++#define PD67_TIME_RECOV(n) (0x3c + 3*(n))
++
++/* Flags for PD67_MISC_CTL_1 */
++#define PD67_MC1_5V_DET 0x01 /* 5v detect */
++#define PD67_MC1_MEDIA_ENA 0x01 /* 6730: Multimedia enable */
++#define PD67_MC1_VCC_3V 0x02 /* 3.3v Vcc */
++#define PD67_MC1_PULSE_MGMT 0x04
++#define PD67_MC1_PULSE_IRQ 0x08
++#define PD67_MC1_SPKR_ENA 0x10
++#define PD67_MC1_INPACK_ENA 0x80
++
++/* Flags for PD67_FIFO_CTL */
++#define PD67_FIFO_EMPTY 0x80
++
++/* Flags for PD67_MISC_CTL_2 */
++#define PD67_MC2_FREQ_BYPASS 0x01
++#define PD67_MC2_DYNAMIC_MODE 0x02
++#define PD67_MC2_SUSPEND 0x04
++#define PD67_MC2_5V_CORE 0x08
++#define PD67_MC2_LED_ENA 0x10 /* IRQ 12 is LED enable */
++#define PD67_MC2_FAST_PCI 0x10 /* 6729: PCI bus &gt; 25 MHz */
++#define PD67_MC2_3STATE_BIT7 0x20 /* Floppy change bit */
++#define PD67_MC2_DMA_MODE 0x40
++#define PD67_MC2_IRQ15_RI 0x80 /* IRQ 15 is ring enable */
++
++/* Flags for PD67_CHIP_INFO */
++#define PD67_INFO_SLOTS 0x20 /* 0 = 1 slot, 1 = 2 slots */
++#define PD67_INFO_CHIP_ID 0xc0
++#define PD67_INFO_REV 0x1c
++
++/* Fields in PD67_TIME_* registers */
++#define PD67_TIME_SCALE 0xc0
++#define PD67_TIME_SCALE_1 0x00
++#define PD67_TIME_SCALE_16 0x40
++#define PD67_TIME_SCALE_256 0x80
++#define PD67_TIME_SCALE_4096 0xc0
++#define PD67_TIME_MULT 0x3f
++
++/* Fields in PD67_DMA_CTL */
++#define PD67_DMA_MODE 0xc0
++#define PD67_DMA_OFF 0x00
++#define PD67_DMA_DREQ_INPACK 0x40
++#define PD67_DMA_DREQ_WP 0x80
++#define PD67_DMA_DREQ_BVD2 0xc0
++#define PD67_DMA_PULLUP 0x20 /* Disable socket pullups? */
++
++/* Fields in PD67_EXT_CTL_1 */
++#define PD67_EC1_VCC_PWR_LOCK 0x01
++#define PD67_EC1_AUTO_PWR_CLEAR 0x02
++#define PD67_EC1_LED_ENA 0x04
++#define PD67_EC1_INV_CARD_IRQ 0x08
++#define PD67_EC1_INV_MGMT_IRQ 0x10
++#define PD67_EC1_PULLUP_CTL 0x20
++
++/* Fields in PD67_MISC_CTL_3 */
++#define PD67_MC3_IRQ_MASK 0x03
++#define PD67_MC3_IRQ_PCPCI 0x00
++#define PD67_MC3_IRQ_EXTERN 0x01
++#define PD67_MC3_IRQ_PCIWAY 0x02
++#define PD67_MC3_IRQ_PCI 0x03
++#define PD67_MC3_PWR_MASK 0x0c
++#define PD67_MC3_PWR_SERIAL 0x00
++#define PD67_MC3_PWR_TI2202 0x08
++#define PD67_MC3_PWR_SMB 0x0c
++
++/* Register definitions for Cirrus PD6832 PCI-to-CardBus bridge */
++
++/* PD6832 extension registers -- indexed in PD67_EXT_INDEX */
++#define PD68_EXT_CTL_2 0x0b
++#define PD68_PCI_SPACE 0x22
++#define PD68_PCCARD_SPACE 0x23
++#define PD68_WINDOW_TYPE 0x24
++#define PD68_EXT_CSC 0x2e
++#define PD68_MISC_CTL_4 0x2f
++#define PD68_MISC_CTL_5 0x30
++#define PD68_MISC_CTL_6 0x31
++
++/* Extra flags in PD67_MISC_CTL_3 */
++#define PD68_MC3_HW_SUSP 0x10
++#define PD68_MC3_MM_EXPAND 0x40
++#define PD68_MC3_MM_ARM 0x80
++
++/* Bridge Control Register */
++#define PD6832_BCR_MGMT_IRQ_ENA 0x0800
++
++/* Socket Number Register */
++#define PD6832_SOCKET_NUMBER 0x004c /* 8 bit */
++
++#endif /* _LINUX_CIRRUS_H */
+
+
+Property changes on: drakx/trunk/mdk-stage1/pcmcia/cirrus.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/pcmcia/cistpl.h
+===================================================================
+--- drakx/trunk/mdk-stage1/pcmcia/cistpl.h (rev 0)
++++ drakx/trunk/mdk-stage1/pcmcia/cistpl.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,604 @@
++/*
++ * cistpl.h 1.35 2001/08/24 12:16:12
++ *
++ * The contents of this file are subject to the Mozilla Public License
++ * Version 1.1 (the &quot;License&quot;); you may not use this file except in
++ * compliance with the License. You may obtain a copy of the License
++ * at <A HREF="http://www.mozilla.org/MPL/">http://www.mozilla.org/MPL/</A>
++ *
++ * Software distributed under the License is distributed on an &quot;AS IS&quot;
++ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
++ * the License for the specific language governing rights and
++ * limitations under the License.
++ *
++ * The initial developer of the original code is David A. Hinds
++ * &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dahinds at users.sourceforge.net</A>&gt;. Portions created by David A. Hinds
++ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
++ *
++ * Alternatively, the contents of this file may be used under the
++ * terms of the GNU General Public License version 2 (the &quot;GPL&quot;), in
++ * which case the provisions of the GPL are applicable instead of the
++ * above. If you wish to allow the use of your version of this file
++ * only under the terms of the GPL and not to allow others to use
++ * your version of this file under the MPL, indicate your decision by
++ * deleting the provisions above and replace them with the notice and
++ * other provisions required by the GPL. If you do not delete the
++ * provisions above, a recipient may use your version of this file
++ * under either the MPL or the GPL.
++ */
++
++#ifndef _LINUX_CISTPL_H
++#define _LINUX_CISTPL_H
++
++#define CISTPL_NULL 0x00
++#define CISTPL_DEVICE 0x01
++#define CISTPL_LONGLINK_CB 0x02
++#define CISTPL_INDIRECT 0x03
++#define CISTPL_CONFIG_CB 0x04
++#define CISTPL_CFTABLE_ENTRY_CB 0x05
++#define CISTPL_LONGLINK_MFC 0x06
++#define CISTPL_BAR 0x07
++#define CISTPL_PWR_MGMNT 0x08
++#define CISTPL_EXTDEVICE 0x09
++#define CISTPL_CHECKSUM 0x10
++#define CISTPL_LONGLINK_A 0x11
++#define CISTPL_LONGLINK_C 0x12
++#define CISTPL_LINKTARGET 0x13
++#define CISTPL_NO_LINK 0x14
++#define CISTPL_VERS_1 0x15
++#define CISTPL_ALTSTR 0x16
++#define CISTPL_DEVICE_A 0x17
++#define CISTPL_JEDEC_C 0x18
++#define CISTPL_JEDEC_A 0x19
++#define CISTPL_CONFIG 0x1a
++#define CISTPL_CFTABLE_ENTRY 0x1b
++#define CISTPL_DEVICE_OC 0x1c
++#define CISTPL_DEVICE_OA 0x1d
++#define CISTPL_DEVICE_GEO 0x1e
++#define CISTPL_DEVICE_GEO_A 0x1f
++#define CISTPL_MANFID 0x20
++#define CISTPL_FUNCID 0x21
++#define CISTPL_FUNCE 0x22
++#define CISTPL_SWIL 0x23
++#define CISTPL_END 0xff
++/* Layer 2 tuples */
++#define CISTPL_VERS_2 0x40
++#define CISTPL_FORMAT 0x41
++#define CISTPL_GEOMETRY 0x42
++#define CISTPL_BYTEORDER 0x43
++#define CISTPL_DATE 0x44
++#define CISTPL_BATTERY 0x45
++#define CISTPL_FORMAT_A 0x47
++/* Layer 3 tuples */
++#define CISTPL_ORG 0x46
++#define CISTPL_SPCL 0x90
++
++typedef struct cistpl_longlink_t {
++ u_int addr;
++} cistpl_longlink_t;
++
++typedef struct cistpl_checksum_t {
++ u_short addr;
++ u_short len;
++ u_char sum;
++} cistpl_checksum_t;
++
++#define CISTPL_MAX_FUNCTIONS 8
++#define CISTPL_MFC_ATTR 0x00
++#define CISTPL_MFC_COMMON 0x01
++
++typedef struct cistpl_longlink_mfc_t {
++ u_char nfn;
++ struct {
++ u_char space;
++ u_int addr;
++ } fn[CISTPL_MAX_FUNCTIONS];
++} cistpl_longlink_mfc_t;
++
++#define CISTPL_MAX_ALTSTR_STRINGS 4
++
++typedef struct cistpl_altstr_t {
++ u_char ns;
++ u_char ofs[CISTPL_MAX_ALTSTR_STRINGS];
++ char str[254];
++} cistpl_altstr_t;
++
++#define CISTPL_DTYPE_NULL 0x00
++#define CISTPL_DTYPE_ROM 0x01
++#define CISTPL_DTYPE_OTPROM 0x02
++#define CISTPL_DTYPE_EPROM 0x03
++#define CISTPL_DTYPE_EEPROM 0x04
++#define CISTPL_DTYPE_FLASH 0x05
++#define CISTPL_DTYPE_SRAM 0x06
++#define CISTPL_DTYPE_DRAM 0x07
++#define CISTPL_DTYPE_FUNCSPEC 0x0d
++#define CISTPL_DTYPE_EXTEND 0x0e
++
++#define CISTPL_MAX_DEVICES 4
++
++typedef struct cistpl_device_t {
++ u_char ndev;
++ struct {
++ u_char type;
++ u_char wp;
++ u_int speed;
++ u_int size;
++ } dev[CISTPL_MAX_DEVICES];
++} cistpl_device_t;
++
++#define CISTPL_DEVICE_MWAIT 0x01
++#define CISTPL_DEVICE_3VCC 0x02
++
++typedef struct cistpl_device_o_t {
++ u_char flags;
++ cistpl_device_t device;
++} cistpl_device_o_t;
++
++#define CISTPL_VERS_1_MAX_PROD_STRINGS 4
++
++typedef struct cistpl_vers_1_t {
++ u_char major;
++ u_char minor;
++ u_char ns;
++ u_char ofs[CISTPL_VERS_1_MAX_PROD_STRINGS];
++ char str[254];
++} cistpl_vers_1_t;
++
++typedef struct cistpl_jedec_t {
++ u_char nid;
++ struct {
++ u_char mfr;
++ u_char info;
++ } id[CISTPL_MAX_DEVICES];
++} cistpl_jedec_t;
++
++typedef struct cistpl_manfid_t {
++ u_short manf;
++ u_short card;
++} cistpl_manfid_t;
++
++#define CISTPL_FUNCID_MULTI 0x00
++#define CISTPL_FUNCID_MEMORY 0x01
++#define CISTPL_FUNCID_SERIAL 0x02
++#define CISTPL_FUNCID_PARALLEL 0x03
++#define CISTPL_FUNCID_FIXED 0x04
++#define CISTPL_FUNCID_VIDEO 0x05
++#define CISTPL_FUNCID_NETWORK 0x06
++#define CISTPL_FUNCID_AIMS 0x07
++#define CISTPL_FUNCID_SCSI 0x08
++
++#define CISTPL_SYSINIT_POST 0x01
++#define CISTPL_SYSINIT_ROM 0x02
++
++typedef struct cistpl_funcid_t {
++ u_char func;
++ u_char sysinit;
++} cistpl_funcid_t;
++
++typedef struct cistpl_funce_t {
++ u_char type;
++ u_char data[0];
++} cistpl_funce_t;
++
++/*======================================================================
++
++ Modem Function Extension Tuples
++
++======================================================================*/
++
++#define CISTPL_FUNCE_SERIAL_IF 0x00
++#define CISTPL_FUNCE_SERIAL_CAP 0x01
++#define CISTPL_FUNCE_SERIAL_SERV_DATA 0x02
++#define CISTPL_FUNCE_SERIAL_SERV_FAX 0x03
++#define CISTPL_FUNCE_SERIAL_SERV_VOICE 0x04
++#define CISTPL_FUNCE_SERIAL_CAP_DATA 0x05
++#define CISTPL_FUNCE_SERIAL_CAP_FAX 0x06
++#define CISTPL_FUNCE_SERIAL_CAP_VOICE 0x07
++#define CISTPL_FUNCE_SERIAL_IF_DATA 0x08
++#define CISTPL_FUNCE_SERIAL_IF_FAX 0x09
++#define CISTPL_FUNCE_SERIAL_IF_VOICE 0x0a
++
++/* UART identification */
++#define CISTPL_SERIAL_UART_8250 0x00
++#define CISTPL_SERIAL_UART_16450 0x01
++#define CISTPL_SERIAL_UART_16550 0x02
++#define CISTPL_SERIAL_UART_8251 0x03
++#define CISTPL_SERIAL_UART_8530 0x04
++#define CISTPL_SERIAL_UART_85230 0x05
++
++/* UART capabilities */
++#define CISTPL_SERIAL_UART_SPACE 0x01
++#define CISTPL_SERIAL_UART_MARK 0x02
++#define CISTPL_SERIAL_UART_ODD 0x04
++#define CISTPL_SERIAL_UART_EVEN 0x08
++#define CISTPL_SERIAL_UART_5BIT 0x01
++#define CISTPL_SERIAL_UART_6BIT 0x02
++#define CISTPL_SERIAL_UART_7BIT 0x04
++#define CISTPL_SERIAL_UART_8BIT 0x08
++#define CISTPL_SERIAL_UART_1STOP 0x10
++#define CISTPL_SERIAL_UART_MSTOP 0x20
++#define CISTPL_SERIAL_UART_2STOP 0x40
++
++typedef struct cistpl_serial_t {
++ u_char uart_type;
++ u_char uart_cap_0;
++ u_char uart_cap_1;
++} cistpl_serial_t;
++
++typedef struct cistpl_modem_cap_t {
++ u_char flow;
++ u_char cmd_buf;
++ u_char rcv_buf_0, rcv_buf_1, rcv_buf_2;
++ u_char xmit_buf_0, xmit_buf_1, xmit_buf_2;
++} cistpl_modem_cap_t;
++
++#define CISTPL_SERIAL_MOD_103 0x01
++#define CISTPL_SERIAL_MOD_V21 0x02
++#define CISTPL_SERIAL_MOD_V23 0x04
++#define CISTPL_SERIAL_MOD_V22 0x08
++#define CISTPL_SERIAL_MOD_212A 0x10
++#define CISTPL_SERIAL_MOD_V22BIS 0x20
++#define CISTPL_SERIAL_MOD_V26 0x40
++#define CISTPL_SERIAL_MOD_V26BIS 0x80
++#define CISTPL_SERIAL_MOD_V27BIS 0x01
++#define CISTPL_SERIAL_MOD_V29 0x02
++#define CISTPL_SERIAL_MOD_V32 0x04
++#define CISTPL_SERIAL_MOD_V32BIS 0x08
++#define CISTPL_SERIAL_MOD_V34 0x10
++
++#define CISTPL_SERIAL_ERR_MNP2_4 0x01
++#define CISTPL_SERIAL_ERR_V42_LAPM 0x02
++
++#define CISTPL_SERIAL_CMPR_V42BIS 0x01
++#define CISTPL_SERIAL_CMPR_MNP5 0x02
++
++#define CISTPL_SERIAL_CMD_AT1 0x01
++#define CISTPL_SERIAL_CMD_AT2 0x02
++#define CISTPL_SERIAL_CMD_AT3 0x04
++#define CISTPL_SERIAL_CMD_MNP_AT 0x08
++#define CISTPL_SERIAL_CMD_V25BIS 0x10
++#define CISTPL_SERIAL_CMD_V25A 0x20
++#define CISTPL_SERIAL_CMD_DMCL 0x40
++
++typedef struct cistpl_data_serv_t {
++ u_char max_data_0;
++ u_char max_data_1;
++ u_char modulation_0;
++ u_char modulation_1;
++ u_char error_control;
++ u_char compression;
++ u_char cmd_protocol;
++ u_char escape;
++ u_char encrypt;
++ u_char misc_features;
++ u_char ccitt_code[0];
++} cistpl_data_serv_t;
++
++typedef struct cistpl_fax_serv_t {
++ u_char max_data_0;
++ u_char max_data_1;
++ u_char modulation;
++ u_char encrypt;
++ u_char features_0;
++ u_char features_1;
++ u_char ccitt_code[0];
++} cistpl_fax_serv_t;
++
++typedef struct cistpl_voice_serv_t {
++ u_char max_data_0;
++ u_char max_data_1;
++} cistpl_voice_serv_t;
++
++/*======================================================================
++
++ LAN Function Extension Tuples
++
++======================================================================*/
++
++#define CISTPL_FUNCE_LAN_TECH 0x01
++#define CISTPL_FUNCE_LAN_SPEED 0x02
++#define CISTPL_FUNCE_LAN_MEDIA 0x03
++#define CISTPL_FUNCE_LAN_NODE_ID 0x04
++#define CISTPL_FUNCE_LAN_CONNECTOR 0x05
++
++/* LAN technologies */
++#define CISTPL_LAN_TECH_ARCNET 0x01
++#define CISTPL_LAN_TECH_ETHERNET 0x02
++#define CISTPL_LAN_TECH_TOKENRING 0x03
++#define CISTPL_LAN_TECH_LOCALTALK 0x04
++#define CISTPL_LAN_TECH_FDDI 0x05
++#define CISTPL_LAN_TECH_ATM 0x06
++#define CISTPL_LAN_TECH_WIRELESS 0x07
++
++typedef struct cistpl_lan_tech_t {
++ u_char tech;
++} cistpl_lan_tech_t;
++
++typedef struct cistpl_lan_speed_t {
++ u_int speed;
++} cistpl_lan_speed_t;
++
++/* LAN media definitions */
++#define CISTPL_LAN_MEDIA_UTP 0x01
++#define CISTPL_LAN_MEDIA_STP 0x02
++#define CISTPL_LAN_MEDIA_THIN_COAX 0x03
++#define CISTPL_LAN_MEDIA_THICK_COAX 0x04
++#define CISTPL_LAN_MEDIA_FIBER 0x05
++#define CISTPL_LAN_MEDIA_900MHZ 0x06
++#define CISTPL_LAN_MEDIA_2GHZ 0x07
++#define CISTPL_LAN_MEDIA_5GHZ 0x08
++#define CISTPL_LAN_MEDIA_DIFF_IR 0x09
++#define CISTPL_LAN_MEDIA_PTP_IR 0x0a
++
++typedef struct cistpl_lan_media_t {
++ u_char media;
++} cistpl_lan_media_t;
++
++typedef struct cistpl_lan_node_id_t {
++ u_char nb;
++ u_char id[16];
++} cistpl_lan_node_id_t;
++
++typedef struct cistpl_lan_connector_t {
++ u_char code;
++} cistpl_lan_connector_t;
++
++/*======================================================================
++
++ IDE Function Extension Tuples
++
++======================================================================*/
++
++#define CISTPL_IDE_INTERFACE 0x01
++
++typedef struct cistpl_ide_interface_t {
++ u_char interface;
++} cistpl_ide_interface_t;
++
++/* First feature byte */
++#define CISTPL_IDE_SILICON 0x04
++#define CISTPL_IDE_UNIQUE 0x08
++#define CISTPL_IDE_DUAL 0x10
++
++/* Second feature byte */
++#define CISTPL_IDE_HAS_SLEEP 0x01
++#define CISTPL_IDE_HAS_STANDBY 0x02
++#define CISTPL_IDE_HAS_IDLE 0x04
++#define CISTPL_IDE_LOW_POWER 0x08
++#define CISTPL_IDE_REG_INHIBIT 0x10
++#define CISTPL_IDE_HAS_INDEX 0x20
++#define CISTPL_IDE_IOIS16 0x40
++
++typedef struct cistpl_ide_feature_t {
++ u_char feature1;
++ u_char feature2;
++} cistpl_ide_feature_t;
++
++#define CISTPL_FUNCE_IDE_IFACE 0x01
++#define CISTPL_FUNCE_IDE_MASTER 0x02
++#define CISTPL_FUNCE_IDE_SLAVE 0x03
++
++/*======================================================================
++
++ Configuration Table Entries
++
++======================================================================*/
++
++#define CISTPL_BAR_SPACE 0x07
++#define CISTPL_BAR_SPACE_IO 0x10
++#define CISTPL_BAR_PREFETCH 0x20
++#define CISTPL_BAR_CACHEABLE 0x40
++#define CISTPL_BAR_1MEG_MAP 0x80
++
++typedef struct cistpl_bar_t {
++ u_char attr;
++ u_int size;
++} cistpl_bar_t;
++
++typedef struct cistpl_config_t {
++ u_char last_idx;
++ u_int base;
++ u_int rmask[4];
++ u_char subtuples;
++} cistpl_config_t;
++
++/* These are bits in the 'present' field, and indices in 'param' */
++#define CISTPL_POWER_VNOM 0
++#define CISTPL_POWER_VMIN 1
++#define CISTPL_POWER_VMAX 2
++#define CISTPL_POWER_ISTATIC 3
++#define CISTPL_POWER_IAVG 4
++#define CISTPL_POWER_IPEAK 5
++#define CISTPL_POWER_IDOWN 6
++
++#define CISTPL_POWER_HIGHZ_OK 0x01
++#define CISTPL_POWER_HIGHZ_REQ 0x02
++
++typedef struct cistpl_power_t {
++ u_char present;
++ u_char flags;
++ u_int param[7];
++} cistpl_power_t;
++
++typedef struct cistpl_timing_t {
++ u_int wait, waitscale;
++ u_int ready, rdyscale;
++ u_int reserved, rsvscale;
++} cistpl_timing_t;
++
++#define CISTPL_IO_LINES_MASK 0x1f
++#define CISTPL_IO_8BIT 0x20
++#define CISTPL_IO_16BIT 0x40
++#define CISTPL_IO_RANGE 0x80
++
++#define CISTPL_IO_MAX_WIN 16
++
++typedef struct cistpl_io_t {
++ u_char flags;
++ u_char nwin;
++ struct {
++ u_int base;
++ u_int len;
++ } win[CISTPL_IO_MAX_WIN];
++} cistpl_io_t;
++
++typedef struct cistpl_irq_t {
++ u_int IRQInfo1;
++ u_int IRQInfo2;
++} cistpl_irq_t;
++
++#define CISTPL_MEM_MAX_WIN 8
++
++typedef struct cistpl_mem_t {
++ u_char flags;
++ u_char nwin;
++ struct {
++ u_int len;
++ u_int card_addr;
++ u_int host_addr;
++ } win[CISTPL_MEM_MAX_WIN];
++} cistpl_mem_t;
++
++#define CISTPL_CFTABLE_DEFAULT 0x0001
++#define CISTPL_CFTABLE_BVDS 0x0002
++#define CISTPL_CFTABLE_WP 0x0004
++#define CISTPL_CFTABLE_RDYBSY 0x0008
++#define CISTPL_CFTABLE_MWAIT 0x0010
++#define CISTPL_CFTABLE_AUDIO 0x0800
++#define CISTPL_CFTABLE_READONLY 0x1000
++#define CISTPL_CFTABLE_PWRDOWN 0x2000
++
++typedef struct cistpl_cftable_entry_t {
++ u_char index;
++ u_short flags;
++ u_char interface;
++ cistpl_power_t vcc, vpp1, vpp2;
++ cistpl_timing_t timing;
++ cistpl_io_t io;
++ cistpl_irq_t irq;
++ cistpl_mem_t mem;
++ u_char subtuples;
++} cistpl_cftable_entry_t;
++
++#define CISTPL_CFTABLE_MASTER 0x000100
++#define CISTPL_CFTABLE_INVALIDATE 0x000200
++#define CISTPL_CFTABLE_VGA_PALETTE 0x000400
++#define CISTPL_CFTABLE_PARITY 0x000800
++#define CISTPL_CFTABLE_WAIT 0x001000
++#define CISTPL_CFTABLE_SERR 0x002000
++#define CISTPL_CFTABLE_FAST_BACK 0x004000
++#define CISTPL_CFTABLE_BINARY_AUDIO 0x010000
++#define CISTPL_CFTABLE_PWM_AUDIO 0x020000
++
++typedef struct cistpl_cftable_entry_cb_t {
++ u_char index;
++ u_int flags;
++ cistpl_power_t vcc, vpp1, vpp2;
++ u_char io;
++ cistpl_irq_t irq;
++ u_char mem;
++ u_char subtuples;
++} cistpl_cftable_entry_cb_t;
++
++typedef struct cistpl_device_geo_t {
++ u_char ngeo;
++ struct {
++ u_char buswidth;
++ u_int erase_block;
++ u_int read_block;
++ u_int write_block;
++ u_int partition;
++ u_int interleave;
++ } geo[CISTPL_MAX_DEVICES];
++} cistpl_device_geo_t;
++
++typedef struct cistpl_vers_2_t {
++ u_char vers;
++ u_char comply;
++ u_short dindex;
++ u_char vspec8, vspec9;
++ u_char nhdr;
++ u_char vendor, info;
++ char str[244];
++} cistpl_vers_2_t;
++
++typedef struct cistpl_org_t {
++ u_char data_org;
++ char desc[30];
++} cistpl_org_t;
++
++#define CISTPL_ORG_FS 0x00
++#define CISTPL_ORG_APPSPEC 0x01
++#define CISTPL_ORG_XIP 0x02
++
++typedef struct cistpl_format_t {
++ u_char type;
++ u_char edc;
++ u_int offset;
++ u_int length;
++} cistpl_format_t;
++
++#define CISTPL_FORMAT_DISK 0x00
++#define CISTPL_FORMAT_MEM 0x01
++
++#define CISTPL_EDC_NONE 0x00
++#define CISTPL_EDC_CKSUM 0x01
++#define CISTPL_EDC_CRC 0x02
++#define CISTPL_EDC_PCC 0x03
++
++typedef union cisparse_t {
++ cistpl_device_t device;
++ cistpl_checksum_t checksum;
++ cistpl_longlink_t longlink;
++ cistpl_longlink_mfc_t longlink_mfc;
++ cistpl_vers_1_t version_1;
++ cistpl_altstr_t altstr;
++ cistpl_jedec_t jedec;
++ cistpl_manfid_t manfid;
++ cistpl_funcid_t funcid;
++ cistpl_funce_t funce;
++ cistpl_bar_t bar;
++ cistpl_config_t config;
++ cistpl_cftable_entry_t cftable_entry;
++ cistpl_cftable_entry_cb_t cftable_entry_cb;
++ cistpl_device_geo_t device_geo;
++ cistpl_vers_2_t vers_2;
++ cistpl_org_t org;
++ cistpl_format_t format;
++} cisparse_t;
++
++typedef struct tuple_t {
++ u_int Attributes;
++ cisdata_t DesiredTuple;
++ u_int Flags; /* internal use */
++ u_int LinkOffset; /* internal use */
++ u_int CISOffset; /* internal use */
++ cisdata_t TupleCode;
++ cisdata_t TupleLink;
++ cisdata_t TupleOffset;
++ cisdata_t TupleDataMax;
++ cisdata_t TupleDataLen;
++ cisdata_t *TupleData;
++} tuple_t;
++
++/* Special cisdata_t value */
++#define RETURN_FIRST_TUPLE 0xff
++
++/* Attributes for tuple calls */
++#define TUPLE_RETURN_LINK 0x01
++#define TUPLE_RETURN_COMMON 0x02
++
++/* For ValidateCIS */
++typedef struct cisinfo_t {
++ u_int Chains;
++} cisinfo_t;
++
++#define CISTPL_MAX_CIS_SIZE 0x200
++
++/* For ReplaceCIS */
++typedef struct cisdump_t {
++ u_int Length;
++ cisdata_t Data[CISTPL_MAX_CIS_SIZE];
++} cisdump_t;
++
++#endif /* LINUX_CISTPL_H */
+
+
+Property changes on: drakx/trunk/mdk-stage1/pcmcia/cistpl.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/pcmcia/cs.h
+===================================================================
+--- drakx/trunk/mdk-stage1/pcmcia/cs.h (rev 0)
++++ drakx/trunk/mdk-stage1/pcmcia/cs.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,433 @@
++/*
++ * cs.h 1.73 2001/08/24 12:16:12
++ *
++ * The contents of this file are subject to the Mozilla Public License
++ * Version 1.1 (the &quot;License&quot;); you may not use this file except in
++ * compliance with the License. You may obtain a copy of the License
++ * at <A HREF="http://www.mozilla.org/MPL/">http://www.mozilla.org/MPL/</A>
++ *
++ * Software distributed under the License is distributed on an &quot;AS IS&quot;
++ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
++ * the License for the specific language governing rights and
++ * limitations under the License.
++ *
++ * The initial developer of the original code is David A. Hinds
++ * &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dahinds at users.sourceforge.net</A>&gt;. Portions created by David A. Hinds
++ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
++ *
++ * Alternatively, the contents of this file may be used under the
++ * terms of the GNU General Public License version 2 (the &quot;GPL&quot;), in
++ * which case the provisions of the GPL are applicable instead of the
++ * above. If you wish to allow the use of your version of this file
++ * only under the terms of the GPL and not to allow others to use
++ * your version of this file under the MPL, indicate your decision by
++ * deleting the provisions above and replace them with the notice and
++ * other provisions required by the GPL. If you do not delete the
++ * provisions above, a recipient may use your version of this file
++ * under either the MPL or the GPL.
++ */
++
++#ifndef _LINUX_CS_H
++#define _LINUX_CS_H
++
++/* For AccessConfigurationRegister */
++typedef struct conf_reg_t {
++ u_char Function;
++ u_int Action;
++ off_t Offset;
++ u_int Value;
++} conf_reg_t;
++
++/* Actions */
++#define CS_READ 1
++#define CS_WRITE 2
++
++/* for AdjustResourceInfo */
++typedef struct adjust_t {
++ u_int Action;
++ u_int Resource;
++ u_int Attributes;
++ union {
++ struct memory {
++ unsigned long Base;
++ unsigned long Size;
++ } memory;
++ struct io {
++ ioaddr_t BasePort;
++ ioaddr_t NumPorts;
++ u_int IOAddrLines;
++ } io;
++ struct irq {
++ u_int IRQ;
++ } irq;
++ } resource;
++} adjust_t;
++
++/* Action field */
++#define REMOVE_MANAGED_RESOURCE 1
++#define ADD_MANAGED_RESOURCE 2
++#define GET_FIRST_MANAGED_RESOURCE 3
++#define GET_NEXT_MANAGED_RESOURCE 4
++/* Resource field */
++#define RES_MEMORY_RANGE 1
++#define RES_IO_RANGE 2
++#define RES_IRQ 3
++/* Attribute field */
++#define RES_IRQ_TYPE 0x03
++#define RES_IRQ_TYPE_EXCLUSIVE 0
++#define RES_IRQ_TYPE_TIME 1
++#define RES_IRQ_TYPE_DYNAMIC 2
++#define RES_IRQ_CSC 0x04
++#define RES_SHARED 0x08
++#define RES_RESERVED 0x10
++#define RES_ALLOCATED 0x20
++#define RES_REMOVED 0x40
++
++typedef struct servinfo_t {
++ char Signature[2];
++ u_int Count;
++ u_int Revision;
++ u_int CSLevel;
++ char *VendorString;
++} servinfo_t;
++
++typedef struct event_callback_args_t {
++ client_handle_t client_handle;
++ void *info;
++ void *mtdrequest;
++ void *buffer;
++ void *misc;
++ void *client_data;
++ struct bus_operations *bus;
++} event_callback_args_t;
++
++/* for GetConfigurationInfo */
++typedef struct config_info_t {
++ u_char Function;
++ u_int Attributes;
++ u_int Vcc, Vpp1, Vpp2;
++ u_int IntType;
++ u_int ConfigBase;
++ u_char Status, Pin, Copy, Option, ExtStatus;
++ u_int Present;
++ u_int CardValues;
++ u_int AssignedIRQ;
++ u_int IRQAttributes;
++ ioaddr_t BasePort1;
++ ioaddr_t NumPorts1;
++ u_int Attributes1;
++ ioaddr_t BasePort2;
++ ioaddr_t NumPorts2;
++ u_int Attributes2;
++ u_int IOAddrLines;
++} config_info_t;
++
++/* For CardValues field */
++#define CV_OPTION_VALUE 0x01
++#define CV_STATUS_VALUE 0x02
++#define CV_PIN_REPLACEMENT 0x04
++#define CV_COPY_VALUE 0x08
++#define CV_EXT_STATUS 0x10
++
++/* For GetFirst/NextClient */
++typedef struct client_req_t {
++ socket_t Socket;
++ u_int Attributes;
++} client_req_t;
++
++#define CLIENT_THIS_SOCKET 0x01
++
++/* For RegisterClient */
++typedef struct client_reg_t {
++ dev_info_t *dev_info;
++ u_int Attributes;
++ u_int EventMask;
++ int (*event_handler)(event_t event, int priority,
++ event_callback_args_t *);
++ event_callback_args_t event_callback_args;
++ u_int Version;
++} client_reg_t;
++
++/* ModifyConfiguration */
++typedef struct modconf_t {
++ u_int Attributes;
++ u_int Vcc, Vpp1, Vpp2;
++} modconf_t;
++
++/* Attributes for ModifyConfiguration */
++#define CONF_IRQ_CHANGE_VALID 0x100
++#define CONF_VCC_CHANGE_VALID 0x200
++#define CONF_VPP1_CHANGE_VALID 0x400
++#define CONF_VPP2_CHANGE_VALID 0x800
++
++/* For RequestConfiguration */
++typedef struct config_req_t {
++ u_int Attributes;
++ u_int Vcc, Vpp1, Vpp2;
++ u_int IntType;
++ u_int ConfigBase;
++ u_char Status, Pin, Copy, ExtStatus;
++ u_char ConfigIndex;
++ u_int Present;
++} config_req_t;
++
++/* Attributes for RequestConfiguration */
++#define CONF_ENABLE_IRQ 0x01
++#define CONF_ENABLE_DMA 0x02
++#define CONF_ENABLE_SPKR 0x04
++#define CONF_VALID_CLIENT 0x100
++
++/* IntType field */
++#define INT_MEMORY 0x01
++#define INT_MEMORY_AND_IO 0x02
++#define INT_CARDBUS 0x04
++#define INT_ZOOMED_VIDEO 0x08
++
++/* For RequestIO and ReleaseIO */
++typedef struct io_req_t {
++ ioaddr_t BasePort1;
++ ioaddr_t NumPorts1;
++ u_int Attributes1;
++ ioaddr_t BasePort2;
++ ioaddr_t NumPorts2;
++ u_int Attributes2;
++ u_int IOAddrLines;
++} io_req_t;
++
++/* Attributes for RequestIO and ReleaseIO */
++#define IO_SHARED 0x01
++#define IO_FIRST_SHARED 0x02
++#define IO_FORCE_ALIAS_ACCESS 0x04
++#define IO_DATA_PATH_WIDTH 0x18
++#define IO_DATA_PATH_WIDTH_8 0x00
++#define IO_DATA_PATH_WIDTH_16 0x08
++#define IO_DATA_PATH_WIDTH_AUTO 0x10
++
++/* For RequestIRQ and ReleaseIRQ */
++typedef struct irq_req_t {
++ u_int Attributes;
++ u_int AssignedIRQ;
++ u_int IRQInfo1, IRQInfo2;
++ void *Handler;
++ void *Instance;
++} irq_req_t;
++
++/* Attributes for RequestIRQ and ReleaseIRQ */
++#define IRQ_TYPE 0x03
++#define IRQ_TYPE_EXCLUSIVE 0x00
++#define IRQ_TYPE_TIME 0x01
++#define IRQ_TYPE_DYNAMIC_SHARING 0x02
++#define IRQ_FORCED_PULSE 0x04
++#define IRQ_FIRST_SHARED 0x08
++#define IRQ_HANDLE_PRESENT 0x10
++#define IRQ_PULSE_ALLOCATED 0x100
++
++/* Bits in IRQInfo1 field */
++#define IRQ_MASK 0x0f
++#define IRQ_NMI_ID 0x01
++#define IRQ_IOCK_ID 0x02
++#define IRQ_BERR_ID 0x04
++#define IRQ_VEND_ID 0x08
++#define IRQ_INFO2_VALID 0x10
++#define IRQ_LEVEL_ID 0x20
++#define IRQ_PULSE_ID 0x40
++#define IRQ_SHARE_ID 0x80
++
++typedef struct eventmask_t {
++ u_int Attributes;
++ u_int EventMask;
++} eventmask_t;
++
++#define CONF_EVENT_MASK_VALID 0x01
++
++/* Configuration registers present */
++#define PRESENT_OPTION 0x001
++#define PRESENT_STATUS 0x002
++#define PRESENT_PIN_REPLACE 0x004
++#define PRESENT_COPY 0x008
++#define PRESENT_EXT_STATUS 0x010
++#define PRESENT_IOBASE_0 0x020
++#define PRESENT_IOBASE_1 0x040
++#define PRESENT_IOBASE_2 0x080
++#define PRESENT_IOBASE_3 0x100
++#define PRESENT_IOSIZE 0x200
++
++/* For GetMemPage, MapMemPage */
++typedef struct memreq_t {
++ u_int CardOffset;
++ page_t Page;
++} memreq_t;
++
++/* For ModifyWindow */
++typedef struct modwin_t {
++ u_int Attributes;
++ u_int AccessSpeed;
++} modwin_t;
++
++/* For RequestWindow */
++typedef struct win_req_t {
++ u_int Attributes;
++ unsigned long Base;
++ u_int Size;
++ u_int AccessSpeed;
++} win_req_t;
++
++/* Attributes for RequestWindow */
++#define WIN_ADDR_SPACE 0x0001
++#define WIN_ADDR_SPACE_MEM 0x0000
++#define WIN_ADDR_SPACE_IO 0x0001
++#define WIN_MEMORY_TYPE 0x0002
++#define WIN_MEMORY_TYPE_CM 0x0000
++#define WIN_MEMORY_TYPE_AM 0x0002
++#define WIN_ENABLE 0x0004
++#define WIN_DATA_WIDTH 0x0018
++#define WIN_DATA_WIDTH_8 0x0000
++#define WIN_DATA_WIDTH_16 0x0008
++#define WIN_DATA_WIDTH_32 0x0010
++#define WIN_PAGED 0x0020
++#define WIN_SHARED 0x0040
++#define WIN_FIRST_SHARED 0x0080
++#define WIN_USE_WAIT 0x0100
++#define WIN_STRICT_ALIGN 0x0200
++#define WIN_MAP_BELOW_1MB 0x0400
++#define WIN_PREFETCH 0x0800
++#define WIN_CACHEABLE 0x1000
++#define WIN_BAR_MASK 0xe000
++#define WIN_BAR_SHIFT 13
++
++/* Attributes for RegisterClient */
++#define INFO_MASTER_CLIENT 0x01
++#define INFO_IO_CLIENT 0x02
++#define INFO_MTD_CLIENT 0x04
++#define INFO_MEM_CLIENT 0x08
++#define MAX_NUM_CLIENTS 3
++
++#define INFO_CARD_SHARE 0x10
++#define INFO_CARD_EXCL 0x20
++
++typedef struct cs_status_t {
++ u_char Function;
++ event_t CardState;
++ event_t SocketState;
++} cs_status_t;
++
++typedef struct error_info_t {
++ int func;
++ int retcode;
++} error_info_t;
++
++/* Special stuff for binding drivers to sockets */
++typedef struct bind_req_t {
++ socket_t Socket;
++ u_char Function;
++ dev_info_t *dev_info;
++} bind_req_t;
++
++/* Flag to bind to all functions */
++#define BIND_FN_ALL 0xff
++
++typedef struct mtd_bind_t {
++ socket_t Socket;
++ u_int Attributes;
++ u_int CardOffset;
++ dev_info_t *dev_info;
++} mtd_bind_t;
++
++/* Events */
++#define CS_EVENT_PRI_LOW 0
++#define CS_EVENT_PRI_HIGH 1
++
++#define CS_EVENT_WRITE_PROTECT 0x000001
++#define CS_EVENT_CARD_LOCK 0x000002
++#define CS_EVENT_CARD_INSERTION 0x000004
++#define CS_EVENT_CARD_REMOVAL 0x000008
++#define CS_EVENT_BATTERY_DEAD 0x000010
++#define CS_EVENT_BATTERY_LOW 0x000020
++#define CS_EVENT_READY_CHANGE 0x000040
++#define CS_EVENT_CARD_DETECT 0x000080
++#define CS_EVENT_RESET_REQUEST 0x000100
++#define CS_EVENT_RESET_PHYSICAL 0x000200
++#define CS_EVENT_CARD_RESET 0x000400
++#define CS_EVENT_REGISTRATION_COMPLETE 0x000800
++#define CS_EVENT_RESET_COMPLETE 0x001000
++#define CS_EVENT_PM_SUSPEND 0x002000
++#define CS_EVENT_PM_RESUME 0x004000
++#define CS_EVENT_INSERTION_REQUEST 0x008000
++#define CS_EVENT_EJECTION_REQUEST 0x010000
++#define CS_EVENT_MTD_REQUEST 0x020000
++#define CS_EVENT_ERASE_COMPLETE 0x040000
++#define CS_EVENT_REQUEST_ATTENTION 0x080000
++#define CS_EVENT_CB_DETECT 0x100000
++#define CS_EVENT_3VCARD 0x200000
++#define CS_EVENT_XVCARD 0x400000
++
++/* Return codes */
++#define CS_SUCCESS 0x00
++#define CS_BAD_ADAPTER 0x01
++#define CS_BAD_ATTRIBUTE 0x02
++#define CS_BAD_BASE 0x03
++#define CS_BAD_EDC 0x04
++#define CS_BAD_IRQ 0x06
++#define CS_BAD_OFFSET 0x07
++#define CS_BAD_PAGE 0x08
++#define CS_READ_FAILURE 0x09
++#define CS_BAD_SIZE 0x0a
++#define CS_BAD_SOCKET 0x0b
++#define CS_BAD_TYPE 0x0d
++#define CS_BAD_VCC 0x0e
++#define CS_BAD_VPP 0x0f
++#define CS_BAD_WINDOW 0x11
++#define CS_WRITE_FAILURE 0x12
++#define CS_NO_CARD 0x14
++#define CS_UNSUPPORTED_FUNCTION 0x15
++#define CS_UNSUPPORTED_MODE 0x16
++#define CS_BAD_SPEED 0x17
++#define CS_BUSY 0x18
++#define CS_GENERAL_FAILURE 0x19
++#define CS_WRITE_PROTECTED 0x1a
++#define CS_BAD_ARG_LENGTH 0x1b
++#define CS_BAD_ARGS 0x1c
++#define CS_CONFIGURATION_LOCKED 0x1d
++#define CS_IN_USE 0x1e
++#define CS_NO_MORE_ITEMS 0x1f
++#define CS_OUT_OF_RESOURCE 0x20
++#define CS_BAD_HANDLE 0x21
++
++#define CS_BAD_TUPLE 0x40
++
++#ifdef __KERNEL__
++
++/*
++ * The main Card Services entry point
++ */
++
++enum service {
++ AccessConfigurationRegister, AddSocketServices,
++ AdjustResourceInfo, CheckEraseQueue, CloseMemory, CopyMemory,
++ DeregisterClient, DeregisterEraseQueue, GetCardServicesInfo,
++ GetClientInfo, GetConfigurationInfo, GetEventMask,
++ GetFirstClient, GetFirstPartion, GetFirstRegion, GetFirstTuple,
++ GetNextClient, GetNextPartition, GetNextRegion, GetNextTuple,
++ GetStatus, GetTupleData, MapLogSocket, MapLogWindow, MapMemPage,
++ MapPhySocket, MapPhyWindow, ModifyConfiguration, ModifyWindow,
++ OpenMemory, ParseTuple, ReadMemory, RegisterClient,
++ RegisterEraseQueue, RegisterMTD, RegisterTimer,
++ ReleaseConfiguration, ReleaseExclusive, ReleaseIO, ReleaseIRQ,
++ ReleaseSocketMask, ReleaseWindow, ReplaceSocketServices,
++ RequestConfiguration, RequestExclusive, RequestIO, RequestIRQ,
++ RequestSocketMask, RequestWindow, ResetCard, ReturnSSEntry,
++ SetEventMask, SetRegion, ValidateCIS, VendorSpecific,
++ WriteMemory, BindDevice, BindMTD, ReportError,
++ SuspendCard, ResumeCard, EjectCard, InsertCard, ReplaceCIS,
++ GetFirstWindow, GetNextWindow, GetMemPage
++};
++
++#ifdef IN_CARD_SERVICES
++extern int CardServices(int func, void *a1, void *a2, void *a3);
++#else
++extern int CardServices(int func, ...);
++#endif
++
++#endif /* __KERNEL__ */
++
++#endif /* _LINUX_CS_H */
+
+
+Property changes on: drakx/trunk/mdk-stage1/pcmcia/cs.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/pcmcia/cs_types.h
+===================================================================
+--- drakx/trunk/mdk-stage1/pcmcia/cs_types.h (rev 0)
++++ drakx/trunk/mdk-stage1/pcmcia/cs_types.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,70 @@
++/*
++ * cs_types.h 1.19 2001/08/24 12:16:12
++ *
++ * The contents of this file are subject to the Mozilla Public License
++ * Version 1.1 (the &quot;License&quot;); you may not use this file except in
++ * compliance with the License. You may obtain a copy of the License
++ * at <A HREF="http://www.mozilla.org/MPL/">http://www.mozilla.org/MPL/</A>
++ *
++ * Software distributed under the License is distributed on an &quot;AS IS&quot;
++ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
++ * the License for the specific language governing rights and
++ * limitations under the License.
++ *
++ * The initial developer of the original code is David A. Hinds
++ * &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dahinds at users.sourceforge.net</A>&gt;. Portions created by David A. Hinds
++ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
++ *
++ * Alternatively, the contents of this file may be used under the
++ * terms of the GNU General Public License version 2 (the &quot;GPL&quot;), in
++ * which case the provisions of the GPL are applicable instead of the
++ * above. If you wish to allow the use of your version of this file
++ * only under the terms of the GPL and not to allow others to use
++ * your version of this file under the MPL, indicate your decision by
++ * deleting the provisions above and replace them with the notice and
++ * other provisions required by the GPL. If you do not delete the
++ * provisions above, a recipient may use your version of this file
++ * under either the MPL or the GPL.
++ */
++
++#ifndef _LINUX_CS_TYPES_H
++#define _LINUX_CS_TYPES_H
++
++#ifdef __linux__
++#ifdef __KERNEL__
++#include &lt;linux/types.h&gt;
++#else
++#include &lt;sys/types.h&gt;
++#endif
++#endif
++
++#ifdef __arm__
++typedef u_int ioaddr_t;
++#else
++typedef u_short ioaddr_t;
++#endif
++
++typedef u_short socket_t;
++typedef u_int event_t;
++typedef u_char cisdata_t;
++typedef u_short page_t;
++
++struct client_t;
++typedef struct client_t *client_handle_t;
++
++struct window_t;
++typedef struct window_t *window_handle_t;
++
++struct region_t;
++typedef struct region_t *memory_handle_t;
++
++struct eraseq_t;
++typedef struct eraseq_t *eraseq_handle_t;
++
++#ifndef DEV_NAME_LEN
++#define DEV_NAME_LEN 32
++#endif
++
++typedef char dev_info_t[DEV_NAME_LEN];
++
++#endif /* _LINUX_CS_TYPES_H */
+
+
+Property changes on: drakx/trunk/mdk-stage1/pcmcia/cs_types.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/pcmcia/driver_ops.h
+===================================================================
+--- drakx/trunk/mdk-stage1/pcmcia/driver_ops.h (rev 0)
++++ drakx/trunk/mdk-stage1/pcmcia/driver_ops.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,73 @@
++/*
++ * driver_ops.h 1.16 2001/08/24 12:16:13
++ *
++ * The contents of this file are subject to the Mozilla Public License
++ * Version 1.1 (the &quot;License&quot;); you may not use this file except in
++ * compliance with the License. You may obtain a copy of the License
++ * at <A HREF="http://www.mozilla.org/MPL/">http://www.mozilla.org/MPL/</A>
++ *
++ * Software distributed under the License is distributed on an &quot;AS IS&quot;
++ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
++ * the License for the specific language governing rights and
++ * limitations under the License.
++ *
++ * The initial developer of the original code is David A. Hinds
++ * &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dahinds at users.sourceforge.net</A>&gt;. Portions created by David A. Hinds
++ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
++ *
++ * Alternatively, the contents of this file may be used under the
++ * terms of the GNU General Public License version 2 (the &quot;GPL&quot;), in
++ * which case the provisions of the GPL are applicable instead of the
++ * above. If you wish to allow the use of your version of this file
++ * only under the terms of the GPL and not to allow others to use
++ * your version of this file under the MPL, indicate your decision by
++ * deleting the provisions above and replace them with the notice and
++ * other provisions required by the GPL. If you do not delete the
++ * provisions above, a recipient may use your version of this file
++ * under either the MPL or the GPL.
++ */
++
++#ifndef _LINUX_DRIVER_OPS_H
++#define _LINUX_DRIVER_OPS_H
++
++#ifndef DEV_NAME_LEN
++#define DEV_NAME_LEN 32
++#endif
++
++#ifdef __KERNEL__
++
++typedef struct dev_node_t {
++ char dev_name[DEV_NAME_LEN];
++ u_short major, minor;
++ struct dev_node_t *next;
++} dev_node_t;
++
++typedef struct dev_locator_t {
++ enum { LOC_ISA, LOC_PCI } bus;
++ union {
++ struct {
++ u_short io_base_1, io_base_2;
++ u_long mem_base;
++ u_char irq, dma;
++ } isa;
++ struct {
++ u_char bus;
++ u_char devfn;
++ } pci;
++ } b;
++} dev_locator_t;
++
++typedef struct driver_operations {
++ char *name;
++ dev_node_t *(*attach) (dev_locator_t *loc);
++ void (*suspend) (dev_node_t *dev);
++ void (*resume) (dev_node_t *dev);
++ void (*detach) (dev_node_t *dev);
++} driver_operations;
++
++int register_driver(struct driver_operations *ops);
++void unregister_driver(struct driver_operations *ops);
++
++#endif /* __KERNEL__ */
++
++#endif /* _LINUX_DRIVER_OPS_H */
+
+
+Property changes on: drakx/trunk/mdk-stage1/pcmcia/driver_ops.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/pcmcia/ds.h
+===================================================================
+--- drakx/trunk/mdk-stage1/pcmcia/ds.h (rev 0)
++++ drakx/trunk/mdk-stage1/pcmcia/ds.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,148 @@
++/*
++ * ds.h 1.57 2001/08/24 12:16:13
++ *
++ * The contents of this file are subject to the Mozilla Public License
++ * Version 1.1 (the &quot;License&quot;); you may not use this file except in
++ * compliance with the License. You may obtain a copy of the License
++ * at <A HREF="http://www.mozilla.org/MPL/">http://www.mozilla.org/MPL/</A>
++ *
++ * Software distributed under the License is distributed on an &quot;AS IS&quot;
++ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
++ * the License for the specific language governing rights and
++ * limitations under the License.
++ *
++ * The initial developer of the original code is David A. Hinds
++ * &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dahinds at users.sourceforge.net</A>&gt;. Portions created by David A. Hinds
++ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
++ *
++ * Alternatively, the contents of this file may be used under the
++ * terms of the GNU General Public License version 2 (the &quot;GPL&quot;), in
++ * which case the provisions of the GPL are applicable instead of the
++ * above. If you wish to allow the use of your version of this file
++ * only under the terms of the GPL and not to allow others to use
++ * your version of this file under the MPL, indicate your decision by
++ * deleting the provisions above and replace them with the notice and
++ * other provisions required by the GPL. If you do not delete the
++ * provisions above, a recipient may use your version of this file
++ * under either the MPL or the GPL.
++ */
++
++#ifndef _LINUX_DS_H
++#define _LINUX_DS_H
++
++#include &lt;pcmcia_/driver_ops.h&gt;
++#include &lt;pcmcia_/bulkmem.h&gt;
++
++typedef struct tuple_parse_t {
++ tuple_t tuple;
++ cisdata_t data[255];
++ cisparse_t parse;
++} tuple_parse_t;
++
++typedef struct win_info_t {
++ window_handle_t handle;
++ win_req_t window;
++ memreq_t map;
++} win_info_t;
++
++typedef struct bind_info_t {
++ dev_info_t dev_info;
++ u_char function;
++ struct dev_link_t *instance;
++ char name[DEV_NAME_LEN];
++ u_short major, minor;
++ void *next;
++} bind_info_t;
++
++typedef struct mtd_info_t {
++ dev_info_t dev_info;
++ u_int Attributes;
++ u_int CardOffset;
++} mtd_info_t;
++
++typedef union ds_ioctl_arg_t {
++ servinfo_t servinfo;
++ adjust_t adjust;
++ config_info_t config;
++ tuple_t tuple;
++ tuple_parse_t tuple_parse;
++ client_req_t client_req;
++ cs_status_t status;
++ conf_reg_t conf_reg;
++ cisinfo_t cisinfo;
++ region_info_t region;
++ bind_info_t bind_info;
++ mtd_info_t mtd_info;
++ win_info_t win_info;
++ cisdump_t cisdump;
++} ds_ioctl_arg_t;
++
++#define DS_GET_CARD_SERVICES_INFO _IOR ('d', 1, servinfo_t)
++#define DS_ADJUST_RESOURCE_INFO _IOWR('d', 2, adjust_t)
++#define DS_GET_CONFIGURATION_INFO _IOWR('d', 3, config_info_t)
++#define DS_GET_FIRST_TUPLE _IOWR('d', 4, tuple_t)
++#define DS_GET_NEXT_TUPLE _IOWR('d', 5, tuple_t)
++#define DS_GET_TUPLE_DATA _IOWR('d', 6, tuple_parse_t)
++#define DS_PARSE_TUPLE _IOWR('d', 7, tuple_parse_t)
++#define DS_RESET_CARD _IO ('d', 8)
++#define DS_GET_STATUS _IOWR('d', 9, cs_status_t)
++#define DS_ACCESS_CONFIGURATION_REGISTER _IOWR('d', 10, conf_reg_t)
++#define DS_VALIDATE_CIS _IOR ('d', 11, cisinfo_t)
++#define DS_SUSPEND_CARD _IO ('d', 12)
++#define DS_RESUME_CARD _IO ('d', 13)
++#define DS_EJECT_CARD _IO ('d', 14)
++#define DS_INSERT_CARD _IO ('d', 15)
++#define DS_GET_FIRST_REGION _IOWR('d', 16, region_info_t)
++#define DS_GET_NEXT_REGION _IOWR('d', 17, region_info_t)
++#define DS_REPLACE_CIS _IOWR('d', 18, cisdump_t)
++#define DS_GET_FIRST_WINDOW _IOR ('d', 19, win_info_t)
++#define DS_GET_NEXT_WINDOW _IOWR('d', 20, win_info_t)
++#define DS_GET_MEM_PAGE _IOWR('d', 21, win_info_t)
++
++#define DS_BIND_REQUEST _IOWR('d', 60, bind_info_t)
++#define DS_GET_DEVICE_INFO _IOWR('d', 61, bind_info_t)
++#define DS_GET_NEXT_DEVICE _IOWR('d', 62, bind_info_t)
++#define DS_UNBIND_REQUEST _IOW ('d', 63, bind_info_t)
++#define DS_BIND_MTD _IOWR('d', 64, mtd_info_t)
++
++#ifdef __KERNEL__
++
++typedef struct dev_link_t {
++ dev_node_t *dev;
++ u_int state, open;
++ wait_queue_head_t pending;
++ struct timer_list release;
++ client_handle_t handle;
++ io_req_t io;
++ irq_req_t irq;
++ config_req_t conf;
++ window_handle_t win;
++ void *priv;
++ struct dev_link_t *next;
++} dev_link_t;
++
++/* Flags for device state */
++#define DEV_PRESENT 0x01
++#define DEV_CONFIG 0x02
++#define DEV_STALE_CONFIG 0x04 /* release on close */
++#define DEV_STALE_LINK 0x08 /* detach on release */
++#define DEV_CONFIG_PENDING 0x10
++#define DEV_RELEASE_PENDING 0x20
++#define DEV_SUSPEND 0x40
++#define DEV_BUSY 0x80
++
++#define DEV_OK(l) \
++ ((l) &amp;&amp; ((l-&gt;state &amp; ~DEV_BUSY) == (DEV_CONFIG|DEV_PRESENT)))
++
++int register_pccard_driver(dev_info_t *dev_info,
++ dev_link_t *(*attach)(void),
++ void (*detach)(dev_link_t *));
++
++int unregister_pccard_driver(dev_info_t *dev_info);
++
++#define register_pcmcia_driver register_pccard_driver
++#define unregister_pcmcia_driver unregister_pccard_driver
++
++#endif /* __KERNEL__ */
++
++#endif /* _LINUX_DS_H */
+
+
+Property changes on: drakx/trunk/mdk-stage1/pcmcia/ds.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/pcmcia/i82365.h
+===================================================================
+--- drakx/trunk/mdk-stage1/pcmcia/i82365.h (rev 0)
++++ drakx/trunk/mdk-stage1/pcmcia/i82365.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,135 @@
++/*
++ * i82365.h 1.21 2001/08/24 12:15:33
++ *
++ * The contents of this file are subject to the Mozilla Public License
++ * Version 1.1 (the &quot;License&quot;); you may not use this file except in
++ * compliance with the License. You may obtain a copy of the License
++ * at <A HREF="http://www.mozilla.org/MPL/">http://www.mozilla.org/MPL/</A>
++ *
++ * Software distributed under the License is distributed on an &quot;AS IS&quot;
++ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
++ * the License for the specific language governing rights and
++ * limitations under the License.
++ *
++ * The initial developer of the original code is David A. Hinds
++ * &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dahinds at users.sourceforge.net</A>&gt;. Portions created by David A. Hinds
++ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
++ *
++ * Alternatively, the contents of this file may be used under the
++ * terms of the GNU General Public License version 2 (the &quot;GPL&quot;), in
++ * which case the provisions of the GPL are applicable instead of the
++ * above. If you wish to allow the use of your version of this file
++ * only under the terms of the GPL and not to allow others to use
++ * your version of this file under the MPL, indicate your decision by
++ * deleting the provisions above and replace them with the notice and
++ * other provisions required by the GPL. If you do not delete the
++ * provisions above, a recipient may use your version of this file
++ * under either the MPL or the GPL.
++ */
++
++#ifndef _LINUX_I82365_H
++#define _LINUX_I82365_H
++
++/* register definitions for the Intel 82365SL PCMCIA controller */
++
++/* Offsets for PCIC registers */
++#define I365_IDENT 0x00 /* Identification and revision */
++#define I365_STATUS 0x01 /* Interface status */
++#define I365_POWER 0x02 /* Power and RESETDRV control */
++#define I365_INTCTL 0x03 /* Interrupt and general control */
++#define I365_CSC 0x04 /* Card status change */
++#define I365_CSCINT 0x05 /* Card status change interrupt control */
++#define I365_ADDRWIN 0x06 /* Address window enable */
++#define I365_IOCTL 0x07 /* I/O control */
++#define I365_GENCTL 0x16 /* Card detect and general control */
++#define I365_GBLCTL 0x1E /* Global control register */
++
++/* Offsets for I/O and memory window registers */
++#define I365_IO(map) (0x08+((map)&lt;&lt;2))
++#define I365_MEM(map) (0x10+((map)&lt;&lt;3))
++#define I365_W_START 0
++#define I365_W_STOP 2
++#define I365_W_OFF 4
++
++/* Flags for I365_STATUS */
++#define I365_CS_BVD1 0x01
++#define I365_CS_STSCHG 0x01
++#define I365_CS_BVD2 0x02
++#define I365_CS_SPKR 0x02
++#define I365_CS_DETECT 0x0C
++#define I365_CS_WRPROT 0x10
++#define I365_CS_READY 0x20 /* Inverted */
++#define I365_CS_POWERON 0x40
++#define I365_CS_GPI 0x80
++
++/* Flags for I365_POWER */
++#define I365_PWR_OFF 0x00 /* Turn off the socket */
++#define I365_PWR_OUT 0x80 /* Output enable */
++#define I365_PWR_NORESET 0x40 /* Disable RESETDRV on resume */
++#define I365_PWR_AUTO 0x20 /* Auto pwr switch enable */
++#define I365_VCC_MASK 0x18 /* Mask for turning off Vcc */
++/* There are different layouts for B-step and DF-step chips: the B
++ step has independent Vpp1/Vpp2 control, and the DF step has only
++ Vpp1 control, plus 3V control */
++#define I365_VCC_5V 0x10 /* Vcc = 5.0v */
++#define I365_VCC_3V 0x18 /* Vcc = 3.3v */
++#define I365_VPP2_MASK 0x0c /* Mask for turning off Vpp2 */
++#define I365_VPP2_5V 0x04 /* Vpp2 = 5.0v */
++#define I365_VPP2_12V 0x08 /* Vpp2 = 12.0v */
++#define I365_VPP1_MASK 0x03 /* Mask for turning off Vpp1 */
++#define I365_VPP1_5V 0x01 /* Vpp2 = 5.0v */
++#define I365_VPP1_12V 0x02 /* Vpp2 = 12.0v */
++
++/* Flags for I365_INTCTL */
++#define I365_RING_ENA 0x80
++#define I365_PC_RESET 0x40
++#define I365_PC_IOCARD 0x20
++#define I365_INTR_ENA 0x10
++#define I365_IRQ_MASK 0x0F
++
++/* Flags for I365_CSC and I365_CSCINT*/
++#define I365_CSC_BVD1 0x01
++#define I365_CSC_STSCHG 0x01
++#define I365_CSC_BVD2 0x02
++#define I365_CSC_READY 0x04
++#define I365_CSC_DETECT 0x08
++#define I365_CSC_ANY 0x0F
++#define I365_CSC_GPI 0x10
++
++/* Flags for I365_ADDRWIN */
++#define I365_ENA_IO(map) (0x40 &lt;&lt; (map))
++#define I365_ENA_MEM(map) (0x01 &lt;&lt; (map))
++
++/* Flags for I365_IOCTL */
++#define I365_IOCTL_MASK(map) (0x0F &lt;&lt; (map&lt;&lt;2))
++#define I365_IOCTL_WAIT(map) (0x08 &lt;&lt; (map&lt;&lt;2))
++#define I365_IOCTL_0WS(map) (0x04 &lt;&lt; (map&lt;&lt;2))
++#define I365_IOCTL_IOCS16(map) (0x02 &lt;&lt; (map&lt;&lt;2))
++#define I365_IOCTL_16BIT(map) (0x01 &lt;&lt; (map&lt;&lt;2))
++
++/* Flags for I365_GENCTL */
++#define I365_CTL_16DELAY 0x01
++#define I365_CTL_RESET 0x02
++#define I365_CTL_GPI_ENA 0x04
++#define I365_CTL_GPI_CTL 0x08
++#define I365_CTL_RESUME 0x10
++#define I365_CTL_SW_IRQ 0x20
++
++/* Flags for I365_GBLCTL */
++#define I365_GBL_PWRDOWN 0x01
++#define I365_GBL_CSC_LEV 0x02
++#define I365_GBL_WRBACK 0x04
++#define I365_GBL_IRQ_0_LEV 0x08
++#define I365_GBL_IRQ_1_LEV 0x10
++
++/* Flags for memory window registers */
++#define I365_MEM_16BIT 0x8000 /* In memory start high byte */
++#define I365_MEM_0WS 0x4000
++#define I365_MEM_WS1 0x8000 /* In memory stop high byte */
++#define I365_MEM_WS0 0x4000
++#define I365_MEM_WRPROT 0x8000 /* In offset high byte */
++#define I365_MEM_REG 0x4000
++
++#define I365_REG(slot, reg) (((slot) &lt;&lt; 6) + reg)
++
++#endif /* _LINUX_I82365_H */
+
+
+Property changes on: drakx/trunk/mdk-stage1/pcmcia/i82365.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/pcmcia/lex_config.l
+===================================================================
+--- drakx/trunk/mdk-stage1/pcmcia/lex_config.l (rev 0)
++++ drakx/trunk/mdk-stage1/pcmcia/lex_config.l 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,224 @@
++/* Special state for handling include files */
++%x src
++
++%{
++/*
++ * Startup tool for non statically mapped PCMCIA sockets
++ *
++ * (C) 2005 Dominik Brodowski &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">linux at brodo.de</A>&gt;
++ *
++ * The initial developer of the original code is David A. Hinds
++ * &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dahinds at users.sourceforge.net</A>&gt;. Portions created by David A. Hinds
++ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
++ *
++ * License: GPL v2
++ */
++
++#undef src
++
++#include &lt;stdio.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;string.h&gt;
++#include &lt;syslog.h&gt;
++
++#ifdef HAS_WORDEXP
++#include &lt;wordexp.h&gt;
++#else
++#include &lt;glob.h&gt;
++#endif
++
++#define src 1
++
++#include &quot;yacc_config.h&quot;
++
++#define YY_NO_INPUT 1 /* mdk-stage1 */
++#define YY_NO_UNPUT 1 /* mdk-stage1 */
++extern int yyparse(void); /* mdk-stage1 */
++
++/* For assembling nice error messages */
++char *current_file;
++int current_lineno;
++
++static int lex_number(char *s);
++static int lex_string(char *s);
++static void do_source(char *fn);
++static int do_eof(void);
++
++%}
++
++int [0-9]+
++hex 0x[0-9a-fA-F]+
++str \&quot;([^&quot;]|\\.)*\&quot;
++
++%%
++
++source[ \t]+ BEGIN(src); return SOURCE;
++&lt;src&gt;[^\n]+ do_source(yytext); BEGIN(INITIAL);
++&lt;&lt;EOF&gt;&gt; if (do_eof()) yyterminate();
++
++\n current_lineno++;
++[ \t]* /* skip */ ;
++[ ]*[#;].* /* skip */ ;
++
++exclude return EXCLUDE;
++include return INCLUDE;
++irq return IRQ_NO;
++port return PORT;
++memory return MEMORY;
++module /* skip */ ;
++
++{int} return lex_number(yytext);
++
++{hex} return lex_number(yytext);
++
++{str} return lex_string(yytext);
++
++. return yytext[0];
++
++%%
++
++#ifndef yywrap
++int yywrap() { return 1; }
++#endif
++
++/*======================================================================
++
++ Stuff to parse basic data types
++
++======================================================================*/
++
++static int lex_number(char *s)
++{
++ yylval.num = strtoul(s, NULL, 0);
++ return NUMBER;
++}
++
++static int lex_string(char *s)
++{
++ int n = strlen(s);
++ yylval.str = malloc(n-1);
++ strncpy(yylval.str, s+1, n-2);
++ yylval.str[n-2] = '\0';
++ return STRING;
++}
++
++/*======================================================================
++
++ Code to support nesting of configuration files
++
++======================================================================*/
++
++#define MAX_SOURCE_DEPTH 4
++struct source_stack {
++ YY_BUFFER_STATE buffer;
++ char *filename;
++ int lineno, fileno;
++ FILE *file;
++#ifdef HAS_WORDEXP
++ wordexp_t word;
++#else
++ glob_t glob;
++#endif
++} source_stack[MAX_SOURCE_DEPTH];
++static int source_stack_ptr = 0;
++static int parse_env = 0;
++
++static int get_glob(void)
++{
++ struct source_stack *s = &amp;source_stack[source_stack_ptr];
++#ifdef HAS_WORDEXP
++ while (s-&gt;fileno &lt; s-&gt;word.we_wordc) {
++ char *fn = s-&gt;word.we_wordv[s-&gt;fileno];
++#else
++ while (s-&gt;fileno &lt; s-&gt;glob.gl_pathc) {
++ char *fn = s-&gt;glob.gl_pathv[s-&gt;fileno];
++#endif
++ s-&gt;file = fopen(fn, &quot;r&quot;);
++ if (s-&gt;file == NULL) {
++ if (strpbrk(fn, &quot;?*[&quot;) == NULL)
++ syslog(LOG_ERR, &quot;could not open '%s': %m&quot;, fn);
++ s-&gt;fileno++;
++ } else {
++ current_lineno = 1;
++ current_file = strdup(fn);
++ yy_switch_to_buffer(yy_create_buffer(s-&gt;file, YY_BUF_SIZE));
++ source_stack_ptr++;
++ s-&gt;fileno++;
++ return 0;
++ }
++ }
++ return -1;
++}
++
++static void do_source(char *fn)
++{
++ struct source_stack *s = &amp;source_stack[source_stack_ptr];
++
++ if (source_stack_ptr &gt;= MAX_SOURCE_DEPTH) {
++ syslog(LOG_ERR, &quot;source depth limit exceeded&quot;);
++ return;
++ }
++#ifdef HAS_WORDEXP
++ wordexp(fn, &amp;s-&gt;word, 0);
++#else
++ glob(fn, GLOB_NOCHECK, NULL, &amp;s-&gt;glob);
++#endif
++ s-&gt;fileno = 0;
++ s-&gt;buffer = YY_CURRENT_BUFFER;
++ s-&gt;lineno = current_lineno;
++ s-&gt;filename = current_file;
++ get_glob();
++}
++
++static int do_eof(void)
++{
++ struct source_stack *s = &amp;source_stack[--source_stack_ptr];
++ if (source_stack_ptr &lt; 0) {
++ if (parse_env == 0) {
++ char *t = getenv(&quot;PCMCIA_OPTS&quot;);
++ if (t == NULL) return -1;
++ parse_env = 1;
++ source_stack_ptr = 0;
++ current_file = &quot;PCMCIA_OPTS&quot;;
++ current_lineno = 1;
++ yy_scan_string(t);
++ return 0;
++ } else
++ return -1;
++ }
++ fclose(s-&gt;file);
++ free(current_file);
++ yy_delete_buffer(YY_CURRENT_BUFFER);
++ if (get_glob() != 0) {
++ yy_switch_to_buffer(s-&gt;buffer);
++ current_lineno = s-&gt;lineno;
++ current_file = s-&gt;filename;
++ }
++ return 0;
++}
++
++/*======================================================================
++
++ The main entry point... returns -1 if the file can't be accessed.
++
++======================================================================*/
++
++int parse_configfile(char *fn)
++{
++ FILE *f;
++
++ f = fopen(fn, &quot;r&quot;);
++ if (!f) {
++ syslog(LOG_ERR, &quot;could not open '%s': %m&quot;, fn);
++ return -1;
++ }
++ current_lineno = 1;
++ current_file = fn;
++ source_stack_ptr = 0;
++ yyrestart(f);
++ yyparse();
++ fclose(f);
++ return 0;
++}
++
+
+Added: drakx/trunk/mdk-stage1/pcmcia/merge_from_pcitable
+===================================================================
+--- drakx/trunk/mdk-stage1/pcmcia/merge_from_pcitable (rev 0)
++++ drakx/trunk/mdk-stage1/pcmcia/merge_from_pcitable 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,47 @@
++#!/usr/bin/perl
++
++# This program will show on stdout yenta_socket stuff from pcitable
++# which is not in probe.c
++
++use MDK::Common;
++
++my %probes;
++foreach (cat_('probe.c')) {
++ if (/^pci_id_t pci_id\[\] = {/ ... /^};/) {
++ /^\s*{\s*0x([\da-f]+),\s*0x([\da-f]+),\s*&quot;([^&quot;]*)&quot;,\s*&quot;([^&quot;]*)&quot;\s*}/
++ and $probes{&quot;$1$2&quot;} = { vendor =&gt; $1, device =&gt; $2, driver =&gt; $3, name =&gt; $4 };
++ }
++}
++
++require '/usr/bin/merge2pcitable.pl';
++my $drivers = read_pcitable(&quot;/usr/share/ldetect-lst/pcitable&quot;);
++
++my %pcitable = map_each {
++ $::a =~ /^(....)(....)/ or die;
++ &quot;$1$2&quot; =&gt; { vendor =&gt; $1, device =&gt; $2, driver =&gt; $::b-&gt;[0], name =&gt; $::b-&gt;[1] };
++} %$drivers;
++
++my @yenta_socket_ids = grep { $pcitable{$_}{driver} eq 'yenta_socket' } keys %pcitable;
++
++if (my @missing_in_probe_c = difference2(\@yenta_socket_ids, [ keys %probes ])) {
++ print &quot;Missing in `probe.c':\n&quot;,
++ map {
++ my $p = $pcitable{$_};
++ qq( { 0x$p-&gt;{vendor}, 0x$p-&gt;{device}, &quot;yenta_socket&quot;, &quot;$p-&gt;{name}&quot; },\n);
++ } sort @missing_in_probe_c;
++}
++
++my @res;
++foreach my $id (keys %probes) {
++ my $p = $probes{$id};
++ my $r = $pcitable{$id};
++ if (!$r || $r-&gt;{driver} ne 'yenta_socket') {
++ push @res, qq(0x$p-&gt;{vendor}\t0x$p-&gt;{device}\t&quot;yenta_socket&quot;\t&quot;) . ($r ? $r-&gt;{name} : '(COMPLETELY MISSING)') . qq(&quot;\n);
++ }
++ if ($r &amp;&amp; $r-&gt;{driver} ne 'unknown' &amp;&amp; $r-&gt;{driver} ne $p-&gt;{driver}) {
++ warn &quot;WARNING: $id: pcitable:$r-&gt;{driver} vs probe.c:$p-&gt;{driver}\n&quot;;
++ }
++}
++if (@res) {
++ print &quot;\n&quot;, &quot;Missing in pcitable:\n&quot;, sort @res;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/pcmcia/merge_from_pcitable
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: drakx/trunk/mdk-stage1/pcmcia/pcmcia.h
+===================================================================
+--- drakx/trunk/mdk-stage1/pcmcia/pcmcia.h (rev 0)
++++ drakx/trunk/mdk-stage1/pcmcia/pcmcia.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,21 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#ifndef _PCMCIA_CARDMGR_INTERFACE_H_
++#define _PCMCIA_CARDMGR_INTERFACE_H_
++
++char * pcmcia_probe(void);
++void pcmcia_socket_startup(int socket_no);
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/pcmcia/pcmcia.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/pcmcia/probe.c
+===================================================================
+--- drakx/trunk/mdk-stage1/pcmcia/probe.c (rev 0)
++++ drakx/trunk/mdk-stage1/pcmcia/probe.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,524 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000-2001 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ * Code comes from /<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">anonymous at projects.sourceforge.net</A>:/pub/pcmcia-cs/pcmcia-cs-3.1.29.tar.bz2
++ */
++
++/*======================================================================
++
++ PCMCIA controller probe
++
++ probe.c 1.55 2001/08/24 12:19:20
++
++ The contents of this file are subject to the Mozilla Public
++ License Version 1.1 (the &quot;License&quot;); you may not use this file
++ except in compliance with the License. You may obtain a copy of
++ the License at <A HREF="http://www.mozilla.org/MPL/">http://www.mozilla.org/MPL/</A>
++
++ Software distributed under the License is distributed on an &quot;AS
++ IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
++ implied. See the License for the specific language governing
++ rights and limitations under the License.
++
++ The initial developer of the original code is David A. Hinds
++ &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dahinds at users.sourceforge.net</A>&gt;. Portions created by David A. Hinds
++ are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
++
++ Alternatively, the contents of this file may be used under the
++ terms of the GNU General Public License version 2 (the &quot;GPL&quot;), in
++ which case the provisions of the GPL are applicable instead of the
++ above. If you wish to allow the use of your version of this file
++ only under the terms of the GPL and not to allow others to use
++ your version of this file under the MPL, indicate your decision
++ by deleting the provisions above and replace them with the notice
++ and other provisions required by the GPL. If you do not delete
++ the provisions above, a recipient may use your version of this
++ file under either the MPL or the GPL.
++
++======================================================================*/
++
++#include &lt;sys/types.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;string.h&gt;
++#include &lt;errno.h&gt;
++#include &lt;fcntl.h&gt;
++
++//mdk-stage1// #include &lt;pcmcia/config.h&gt;
++#include &quot;log.h&quot;
++#include &quot;pcmcia.h&quot;
++
++/*====================================================================*/
++
++//mdk-stage1// #ifdef CONFIG_PCI
++
++typedef struct {
++ u_short vendor, device;
++ char *modname;
++ char *name;
++} pci_id_t;
++
++pci_id_t pci_id[] = {
++ { 0x1013, 0x1100, &quot;i82365&quot;, &quot;Cirrus Logic CL 6729&quot; },
++ { 0x1013, 0x1110, &quot;yenta_socket&quot;, &quot;Cirrus Logic PD 6832&quot; },
++ { 0x10b3, 0xb106, &quot;yenta_socket&quot;, &quot;SMC 34C90&quot; },
++ { 0x1180, 0x0465, &quot;yenta_socket&quot;, &quot;Ricoh RL5C465&quot; },
++ { 0x1180, 0x0466, &quot;yenta_socket&quot;, &quot;Ricoh RL5C466&quot; },
++ { 0x1180, 0x0475, &quot;yenta_socket&quot;, &quot;Ricoh RL5C475&quot; },
++ { 0x1180, 0x0476, &quot;yenta_socket&quot;, &quot;Ricoh RL5C476&quot; },
++ { 0x1180, 0x0477, &quot;yenta_socket&quot;, &quot;Ricoh RL5C477&quot; },
++ { 0x1180, 0x0478, &quot;yenta_socket&quot;, &quot;Ricoh RL5C478&quot; },
++ { 0x104c, 0xac12, &quot;yenta_socket&quot;, &quot;Texas Instruments PCI1130&quot; },
++ { 0x104c, 0xac13, &quot;yenta_socket&quot;, &quot;Texas Instruments PCI1031&quot; },
++ { 0x104c, 0xac15, &quot;yenta_socket&quot;, &quot;Texas Instruments PCI1131&quot; },
++ { 0x104c, 0xac1a, &quot;yenta_socket&quot;, &quot;Texas Instruments PCI1210&quot; },
++ { 0x104c, 0xac1e, &quot;yenta_socket&quot;, &quot;Texas Instruments PCI1211&quot; },
++ { 0x104c, 0xac17, &quot;yenta_socket&quot;, &quot;Texas Instruments PCI1220&quot; },
++ { 0x104c, 0xac19, &quot;yenta_socket&quot;, &quot;Texas Instruments PCI1221&quot; },
++ { 0x104c, 0xac1c, &quot;yenta_socket&quot;, &quot;Texas Instruments PCI1225&quot; },
++ { 0x104c, 0xac16, &quot;yenta_socket&quot;, &quot;Texas Instruments PCI1250&quot; },
++ { 0x104c, 0xac1d, &quot;yenta_socket&quot;, &quot;Texas Instruments PCI1251A&quot; },
++ { 0x104c, 0xac1f, &quot;yenta_socket&quot;, &quot;Texas Instruments PCI1251B&quot; },
++ { 0x104c, 0xac50, &quot;yenta_socket&quot;, &quot;Texas Instruments PCI1410&quot; },
++ { 0x104c, 0xac51, &quot;yenta_socket&quot;, &quot;Texas Instruments PCI1420&quot; },
++ { 0x104c, 0xac1b, &quot;yenta_socket&quot;, &quot;Texas Instruments PCI1450&quot; },
++ { 0x104c, 0xac52, &quot;yenta_socket&quot;, &quot;Texas Instruments PCI1451&quot; },
++ { 0x104c, 0xac56, &quot;yenta_socket&quot;, &quot;Texas Instruments PCI1510&quot; },
++ { 0x104c, 0xac55, &quot;yenta_socket&quot;, &quot;Texas Instruments PCI1520&quot; },
++ { 0x104c, 0xac54, &quot;yenta_socket&quot;, &quot;Texas Instruments PCI1620&quot; },
++ { 0x104c, 0xac41, &quot;yenta_socket&quot;, &quot;Texas Instruments PCI4410&quot; },
++ { 0x104c, 0xac40, &quot;yenta_socket&quot;, &quot;Texas Instruments PCI4450&quot; },
++ { 0x104c, 0xac42, &quot;yenta_socket&quot;, &quot;Texas Instruments PCI4451&quot; },
++ { 0x104c, 0xac44, &quot;yenta_socket&quot;, &quot;Texas Instruments PCI4510&quot; },
++ { 0x104c, 0xac46, &quot;yenta_socket&quot;, &quot;Texas Instruments PCI4520&quot; },
++ { 0x104c, 0xac49, &quot;yenta_socket&quot;, &quot;Texas Instruments PCI7410&quot; },
++ { 0x104c, 0xac47, &quot;yenta_socket&quot;, &quot;Texas Instruments PCI7510&quot; },
++ { 0x104c, 0xac48, &quot;yenta_socket&quot;, &quot;Texas Instruments PCI7610&quot; },
++ { 0x104c, 0xac8e, &quot;yenta_socket&quot;, &quot;Texas Instruments PCI7420&quot; },
++ { 0x1217, 0x6729, &quot;i82365&quot;, &quot;O2 Micro 6729&quot; },
++ { 0x1217, 0x673a, &quot;i82365&quot;, &quot;O2 Micro 6730&quot; },
++ { 0x1217, 0x6832, &quot;yenta_socket&quot;, &quot;O2 Micro 6832/6833&quot; },
++ { 0x1217, 0x6836, &quot;yenta_socket&quot;, &quot;O2 Micro 6836/6860&quot; },
++ { 0x1217, 0x6872, &quot;yenta_socket&quot;, &quot;O2 Micro 6812&quot; },
++ { 0x1217, 0x6925, &quot;yenta_socket&quot;, &quot;O2 Micro 6922&quot; },
++ { 0x1217, 0x6933, &quot;yenta_socket&quot;, &quot;O2 Micro 6933&quot; },
++ { 0x1217, 0x6972, &quot;yenta_socket&quot;, &quot;O2 Micro 6912&quot; },
++ { 0x1217, 0x7114, &quot;yenta_socket&quot;, &quot;O2 Micro 711M1&quot; },
++ { 0x1179, 0x0603, &quot;i82365&quot;, &quot;Toshiba ToPIC95-A&quot; },
++ { 0x1179, 0x060a, &quot;yenta_socket&quot;, &quot;Toshiba ToPIC95-B&quot; },
++ { 0x1179, 0x060f, &quot;yenta_socket&quot;, &quot;Toshiba ToPIC97&quot; },
++ { 0x1179, 0x0617, &quot;yenta_socket&quot;, &quot;Toshiba ToPIC100&quot; },
++ { 0x119b, 0x1221, &quot;i82365&quot;, &quot;Omega Micro 82C092G&quot; },
++ { 0x8086, 0x1221, &quot;i82092&quot;, &quot;Intel 82092AA_0&quot; },
++ { 0x8086, 0x1222, &quot;i82092&quot;, &quot;Intel 82092AA_1&quot; },
++ { 0x1524, 0x1211, &quot;yenta_socket&quot;, &quot;ENE 1211&quot; },
++ { 0x1524, 0x1225, &quot;yenta_socket&quot;, &quot;ENE 1225&quot; },
++ { 0x1524, 0x1410, &quot;yenta_socket&quot;, &quot;ENE 1410&quot; },
++ { 0x1524, 0x1411, &quot;yenta_socket&quot;, &quot;ENE Technology CB1411&quot; },
++ { 0x1524, 0x1420, &quot;yenta_socket&quot;, &quot;ENE 1420&quot; },
++};
++#define PCI_COUNT (sizeof(pci_id)/sizeof(pci_id_t))
++
++char * driver = NULL;
++
++static int pci_probe(void)
++{
++ char s[256], *name = NULL;
++ u_int device, vendor, i;
++ FILE *f;
++
++//mdk-stage1// if (!module)
++ log_message(&quot;PCMCIA: probing PCI bus..&quot;);
++
++ if ((f = fopen(&quot;/proc/bus/pci/devices&quot;, &quot;r&quot;)) != NULL) {
++ while (fgets(s, 256, f) != NULL) {
++ u_int n = strtoul(s+5, NULL, 16);
++ vendor = (n &gt;&gt; 16); device = (n &amp; 0xffff);
++ for (i = 0; i &lt; PCI_COUNT; i++)
++ if ((vendor == pci_id[i].vendor) &amp;&amp;
++ (device == pci_id[i].device)) break;
++ if (i &lt; PCI_COUNT) {
++ name = pci_id[i].name;
++ driver = pci_id[i].modname;
++ }
++ }
++ }
++//mdk-stage1// else if ((f = fopen(&quot;/proc/pci&quot;, &quot;r&quot;)) != NULL) {
++//mdk-stage1// while (fgets(s, 256, f) != NULL) {
++//mdk-stage1// t = strstr(s, &quot;Device id=&quot;);
++//mdk-stage1// if (t) {
++//mdk-stage1// device = strtoul(t+10, NULL, 16);
++//mdk-stage1// t = strstr(s, &quot;Vendor id=&quot;);
++//mdk-stage1// vendor = strtoul(t+10, NULL, 16);
++//mdk-stage1// for (i = 0; i &lt; PCI_COUNT; i++)
++//mdk-stage1// if ((vendor == pci_id[i].vendor) &amp;&amp;
++//mdk-stage1// (device == pci_id[i].device)) break;
++//mdk-stage1// } else
++//mdk-stage1// for (i = 0; i &lt; PCI_COUNT; i++)
++//mdk-stage1// if (strstr(s, pci_id[i].tag) != NULL) break;
++//mdk-stage1// if (i != PCI_COUNT) {
++//mdk-stage1// name = pci_id[i].name;
++//mdk-stage1// break;
++//mdk-stage1// } else {
++//mdk-stage1// t = strstr(s, &quot;CardBus bridge&quot;);
++//mdk-stage1// if (t != NULL) {
++//mdk-stage1// name = t + 16;
++//mdk-stage1// t = strchr(s, '(');
++//mdk-stage1// t[-1] = '\0';
++//mdk-stage1// break;
++//mdk-stage1// }
++//mdk-stage1// }
++//mdk-stage1// }
++//mdk-stage1// }
++ fclose(f);
++
++ if (name) {
++//mdk-stage1// if (module)
++//mdk-stage1// printf(&quot;i82365\n&quot;);
++//mdk-stage1// else
++ log_message(&quot;\t%s found, 2 sockets (driver %s).&quot;, name, driver);
++ return 0;
++ } else {
++//mdk-stage1// if (!module)
++ log_message(&quot;\tnot found.&quot;);
++ return -ENODEV;
++ }
++}
++//mdk-stage1// #endif
++
++/*====================================================================*/
++
++//mdk-stage1// #ifdef CONFIG_ISA
++//mdk-stage1//
++//mdk-stage1// #ifdef __GLIBC__
++#include &lt;sys/io.h&gt;
++//mdk-stage1// #else
++//mdk-stage1// #include &lt;asm/io.h&gt;
++//mdk-stage1// #endif
++typedef u_short ioaddr_t;
++
++#include &quot;i82365.h&quot;
++#include &quot;cirrus.h&quot;
++#include &quot;vg468.h&quot;
++
++static ioaddr_t i365_base = 0x03e0;
++
++static u_char i365_get(u_short sock, u_short reg)
++{
++ u_char val = I365_REG(sock, reg);
++ outb(val, i365_base); val = inb(i365_base+1);
++ return val;
++}
++
++static void i365_set(u_short sock, u_short reg, u_char data)
++{
++ u_char val = I365_REG(sock, reg);
++ outb(val, i365_base); outb(data, i365_base+1);
++}
++
++static void i365_bset(u_short sock, u_short reg, u_char mask)
++{
++ u_char d = i365_get(sock, reg);
++ d |= mask;
++ i365_set(sock, reg, d);
++}
++
++static void i365_bclr(u_short sock, u_short reg, u_char mask)
++{
++ u_char d = i365_get(sock, reg);
++ d &amp;= ~mask;
++ i365_set(sock, reg, d);
++}
++
++int i365_probe(void)
++{
++ int val, sock, done;
++ char *name = &quot;i82365sl&quot;;
++
++//mdk-stage1// if (!module)
++ log_message(&quot;PCMCIA: probing for Intel PCIC (ISA)..&quot;);
++//mdk-stage1// if (verbose) printf(&quot;\n&quot;);
++
++ sock = done = 0;
++ if (ioperm(i365_base, 4, 1)) {
++ log_perror(&quot;PCMCIA: ioperm&quot;);
++ return -1;
++ }
++ ioperm(0x80, 1, 1);
++ for (; sock &lt; 2; sock++) {
++ val = i365_get(sock, I365_IDENT);
++//mdk-stage1// if (verbose)
++//mdk-stage1// printf(&quot; ident(%d)=%#2.2x&quot;, sock, val);
++ switch (val) {
++ case 0x82:
++ name = &quot;i82365sl A step&quot;;
++ break;
++ case 0x83:
++ name = &quot;i82365sl B step&quot;;
++ break;
++ case 0x84:
++ name = &quot;VLSI 82C146&quot;;
++ break;
++ case 0x88: case 0x89: case 0x8a:
++ name = &quot;IBM Clone&quot;;
++ break;
++ case 0x8b: case 0x8c:
++ break;
++ default:
++ done = 1;
++ }
++ if (done) break;
++ }
++
++//mdk-stage1// if (verbose) printf(&quot;\n &quot;);
++ if (sock == 0) {
++//mdk-stage1// if (!module)
++ log_message(&quot;\tnot found.&quot;);
++ return -ENODEV;
++ }
++
++ if ((sock == 2) &amp;&amp; (strcmp(name, &quot;VLSI 82C146&quot;) == 0))
++ name = &quot;i82365sl DF&quot;;
++
++ /* Check for Vadem chips */
++ outb(0x0e, i365_base);
++ outb(0x37, i365_base);
++ i365_bset(0, VG468_MISC, VG468_MISC_VADEMREV);
++ val = i365_get(0, I365_IDENT);
++ if (val &amp; I365_IDENT_VADEM) {
++ if ((val &amp; 7) &lt; 4)
++ name = &quot;Vadem VG-468&quot;;
++ else
++ name = &quot;Vadem VG-469&quot;;
++ i365_bclr(0, VG468_MISC, VG468_MISC_VADEMREV);
++ }
++
++ /* Check for Cirrus CL-PD67xx chips */
++ i365_set(0, PD67_CHIP_INFO, 0);
++ val = i365_get(0, PD67_CHIP_INFO);
++ if ((val &amp; PD67_INFO_CHIP_ID) == PD67_INFO_CHIP_ID) {
++ val = i365_get(0, PD67_CHIP_INFO);
++ if ((val &amp; PD67_INFO_CHIP_ID) == 0) {
++ if (val &amp; PD67_INFO_SLOTS)
++ name = &quot;Cirrus CL-PD672x&quot;;
++ else {
++ name = &quot;Cirrus CL-PD6710&quot;;
++ sock = 1;
++ }
++ i365_set(0, PD67_EXT_INDEX, 0xe5);
++ if (i365_get(0, PD67_EXT_INDEX) != 0xe5)
++ name = &quot;VIA VT83C469&quot;;
++ }
++ }
++
++//mdk-stage1// if (module)
++//mdk-stage1// printf(&quot;i82365\n&quot;);
++//mdk-stage1// else
++ printf(&quot;\t%s found, %d sockets.\n&quot;, name, sock);
++ return 0;
++
++} /* i365_probe */
++
++//mdk-stage1//#endif /* CONFIG_ISA */
++
++/*====================================================================*/
++
++//mdk-stage1//#ifdef CONFIG_ISA
++
++#include &quot;tcic.h&quot;
++
++//mdk-stage1//static ioaddr_t tcic_base = TCIC_BASE;
++
++static u_char tcic_getb(ioaddr_t base, u_char reg)
++{
++ u_char val = inb(base+reg);
++ return val;
++}
++
++static void tcic_setb(ioaddr_t base, u_char reg, u_char data)
++{
++ outb(data, base+reg);
++}
++
++static u_short tcic_getw(ioaddr_t base, u_char reg)
++{
++ u_short val = inw(base+reg);
++ return val;
++}
++
++static void tcic_setw(ioaddr_t base, u_char reg, u_short data)
++{
++ outw(data, base+reg);
++}
++
++static u_short tcic_aux_getw(ioaddr_t base, u_short reg)
++{
++ u_char mode = (tcic_getb(base, TCIC_MODE) &amp; TCIC_MODE_PGMMASK) | reg;
++ tcic_setb(base, TCIC_MODE, mode);
++ return tcic_getw(base, TCIC_AUX);
++}
++
++static void tcic_aux_setw(ioaddr_t base, u_short reg, u_short data)
++{
++ u_char mode = (tcic_getb(base, TCIC_MODE) &amp; TCIC_MODE_PGMMASK) | reg;
++ tcic_setb(base, TCIC_MODE, mode);
++ tcic_setw(base, TCIC_AUX, data);
++}
++
++static int get_tcic_id(ioaddr_t base)
++{
++ u_short id;
++ tcic_aux_setw(base, TCIC_AUX_TEST, TCIC_TEST_DIAG);
++ id = tcic_aux_getw(base, TCIC_AUX_ILOCK);
++ id = (id &amp; TCIC_ILOCKTEST_ID_MASK) &gt;&gt; TCIC_ILOCKTEST_ID_SH;
++ tcic_aux_setw(base, TCIC_AUX_TEST, 0);
++ return id;
++}
++
++int tcic_probe_at(ioaddr_t base)
++{
++ int i;
++ u_short old;
++
++ /* Anything there?? */
++ for (i = 0; i &lt; 0x10; i += 2)
++ if (tcic_getw(base, i) == 0xffff)
++ return -1;
++
++//mdk-stage1// if (!module)
++ log_message(&quot;\tat %#3.3x: &quot;, base); fflush(stdout);
++
++ /* Try to reset the chip */
++ tcic_setw(base, TCIC_SCTRL, TCIC_SCTRL_RESET);
++ tcic_setw(base, TCIC_SCTRL, 0);
++
++ /* Can we set the addr register? */
++ old = tcic_getw(base, TCIC_ADDR);
++ tcic_setw(base, TCIC_ADDR, 0);
++ if (tcic_getw(base, TCIC_ADDR) != 0) {
++ tcic_setw(base, TCIC_ADDR, old);
++ return -2;
++ }
++
++ tcic_setw(base, TCIC_ADDR, 0xc3a5);
++ if (tcic_getw(base, TCIC_ADDR) != 0xc3a5)
++ return -3;
++
++ return 2;
++}
++
++int tcic_probe(void)
++{
++ int sock, id;
++
++//mdk-stage1// if (!module)
++ log_message(&quot;PCMCIA: probing for Databook TCIC-2 (ISA)..&quot;); fflush(stdout);
++
++ if (ioperm(TCIC_BASE, 16, 1)) {
++ log_perror(&quot;PCMCIA: ioperm&quot;);
++ return -1;
++ }
++ ioperm(0x80, 1, 1);
++ sock = tcic_probe_at(TCIC_BASE);
++
++ if (sock &lt;= 0) {
++//mdk-stage1// if (!module)
++ log_message(&quot;\tnot found.&quot;);
++ return -ENODEV;
++ }
++
++//mdk-stage1// if (module)
++//mdk-stage1// printf(&quot;tcic\n&quot;);
++//mdk-stage1// else {
++ id = get_tcic_id(TCIC_BASE);
++ switch (id) {
++ case TCIC_ID_DB86082:
++ log_message(&quot;DB86082&quot;); break;
++ case TCIC_ID_DB86082A:
++ log_message(&quot;DB86082A&quot;); break;
++ case TCIC_ID_DB86084:
++ log_message(&quot;DB86084&quot;); break;
++ case TCIC_ID_DB86084A:
++ log_message(&quot;DB86084A&quot;); break;
++ case TCIC_ID_DB86072:
++ log_message(&quot;DB86072&quot;); break;
++ case TCIC_ID_DB86184:
++ log_message(&quot;DB86184&quot;); break;
++ case TCIC_ID_DB86082B:
++ log_message(&quot;DB86082B&quot;); break;
++ default:
++ log_message(&quot;Unknown TCIC-2 ID 0x%02x&quot;, id);
++ }
++ log_message(&quot; found at %#6x, %d sockets.&quot;, TCIC_BASE, sock);
++//mdk-stage1// }
++ return 0;
++
++} /* tcic_probe */
++
++//mdk-stage1// #endif /* CONFIG_ISA */
++
++//mdk-stage1// /*====================================================================*/
++//mdk-stage1//
++//mdk-stage1// int main(int argc, char *argv[])
++//mdk-stage1// {
++//mdk-stage1// int optch, errflg;
++//mdk-stage1// extern char *optarg;
++//mdk-stage1// int verbose = 0, module = 0;
++//mdk-stage1//
++//mdk-stage1// errflg = 0;
++//mdk-stage1// while ((optch = getopt(argc, argv, &quot;t:vxm&quot;)) != -1) {
++//mdk-stage1// switch (optch) {
++//mdk-stage1// #ifdef CONFIG_ISA
++//mdk-stage1// case 't':
++//mdk-stage1// tcic_base = strtoul(optarg, NULL, 0); break;
++//mdk-stage1// #endif
++//mdk-stage1// case 'v':
++//mdk-stage1// verbose = 1; break;
++//mdk-stage1// case 'm':
++//mdk-stage1// module = 1; break;
++//mdk-stage1// default:
++//mdk-stage1// errflg = 1; break;
++//mdk-stage1// }
++//mdk-stage1// }
++//mdk-stage1// if (errflg || (optind &lt; argc)) {
++//mdk-stage1// fprintf(stderr, &quot;usage: %s [-t tcic_base] [-v] [-m]\n&quot;, argv[0]);
++//mdk-stage1// exit(EXIT_FAILURE);
++//mdk-stage1// }
++//mdk-stage1//
++//mdk-stage1// #ifdef CONFIG_PCI
++//mdk-stage1// if (pci_probe(verbose, module) == 0)
++//mdk-stage1// exit(EXIT_SUCCESS);
++//mdk-stage1// #endif
++//mdk-stage1// #ifdef CONFIG_ISA
++//mdk-stage1// if (i365_probe(verbose, module) == 0)
++//mdk-stage1// exit(EXIT_SUCCESS);
++//mdk-stage1// else if (tcic_probe(verbose, module, tcic_base) == 0)
++//mdk-stage1// exit(EXIT_SUCCESS);
++//mdk-stage1// #endif
++//mdk-stage1// exit(EXIT_FAILURE);
++//mdk-stage1// return 0;
++//mdk-stage1// }
++
++
++char * pcmcia_probe(void)
++{
++ if (!pci_probe())
++ return driver;
++ else if (!i365_probe())
++ return &quot;i82365&quot;;
++ else if (!tcic_probe())
++ return &quot;tcic&quot;;
++ else
++ return NULL;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/pcmcia/probe.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/pcmcia/startup.c
+===================================================================
+--- drakx/trunk/mdk-stage1/pcmcia/startup.c (rev 0)
++++ drakx/trunk/mdk-stage1/pcmcia/startup.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,271 @@
++/*
++ * Startup tool for non statically mapped PCMCIA sockets
++ *
++ * (C) 2005 Dominik Brodowski &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">linux at brodo.de</A>&gt;
++ *
++ * The initial developer of the original code is David A. Hinds
++ * &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dahinds at users.sourceforge.net</A>&gt;. Portions created by David A. Hinds
++ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
++ *
++ * License: GPL v2
++ */
++
++#include &lt;stdio.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++#include &lt;errno.h&gt;
++#include &lt;syslog.h&gt;
++#include &lt;unistd.h&gt;
++
++#include &lt;sysfs/libsysfs.h&gt;
++
++#include &quot;startup.h&quot;
++
++/* uncomment for debug output */
++#ifdef DEBUG
++#define dprintf printf
++#else
++#define dprintf(...) do { } while(0);
++#endif
++
++/* Linked list of resource adjustments */
++struct adjust_list_t *root_adjust = NULL;
++
++/* path for config file, device scripts */
++static char *configpath = &quot;/etc/pcmcia&quot;;
++
++enum {
++ RESOURCE_MEM,
++ RESOURCE_IO,
++ MAX_RESOURCE_FILES
++};
++
++
++static const char *resource_files[MAX_RESOURCE_FILES] = {
++ [RESOURCE_MEM] = &quot;available_resources_mem&quot;,
++ [RESOURCE_IO] = &quot;available_resources_io&quot;,
++};
++
++#define PATH_TO_SOCKET &quot;/sys/class/pcmcia_socket/&quot;
++
++
++static int add_available_resource(unsigned int socket_no, unsigned int type,
++ unsigned int action,
++ unsigned long start, unsigned long end)
++{
++ char file[SYSFS_PATH_MAX];
++ char content[SYSFS_PATH_MAX];
++ struct sysfs_attribute *attr;
++ int ret;
++ size_t len;
++
++ if (type &gt;= MAX_RESOURCE_FILES)
++ return -EINVAL;
++
++ if (end &lt;= start)
++ return -EINVAL;
++
++ dprintf(&quot;%d %d %d 0x%lx 0x%lx\n&quot;, socket_no, type, action, start, end);
++
++ snprintf(file, SYSFS_PATH_MAX, PATH_TO_SOCKET &quot;pcmcia_socket%u/%s&quot;,
++ socket_no, resource_files[type]);
++
++ switch(action) {
++ case ADD_MANAGED_RESOURCE:
++ len = snprintf(content, SYSFS_PATH_MAX,
++ &quot;0x%08lx - 0x%08lx&quot;, start, end);
++ break;
++
++ case REMOVE_MANAGED_RESOURCE:
++ len = snprintf(content, SYSFS_PATH_MAX,
++ &quot;- 0x%08lx - 0x%08lx&quot;, start, end);
++ break;
++
++ default:
++ return -EINVAL;
++ }
++
++ dprintf(&quot;content is %s\n&quot;, content);
++
++ dprintf(&quot;file is %s\n&quot;, file);
++
++ attr = sysfs_open_attribute(file);
++ if (!attr)
++ return -ENODEV;
++
++ dprintf(&quot;open, len %d\n&quot;, len);
++
++ ret = sysfs_write_attribute(attr, content, len);
++
++ dprintf(&quot;ret is %d\n&quot;, ret);
++
++ sysfs_close_attribute(attr);
++
++ return (ret);
++}
++
++static int setup_done(unsigned int socket_no)
++{
++ int ret;
++ char file[SYSFS_PATH_MAX];
++ struct sysfs_attribute *attr;
++
++ snprintf(file, SYSFS_PATH_MAX, PATH_TO_SOCKET
++ &quot;pcmcia_socket%u/available_resources_setup_done&quot;,
++ socket_no);
++
++ attr = sysfs_open_attribute(file);
++ if (!attr)
++ return -ENODEV;
++
++ ret = sysfs_write_attribute(attr, &quot;42&quot;, 2);
++
++ sysfs_close_attribute(attr);
++
++ return (ret);
++}
++
++
++static int disallow_irq(unsigned int socket_no, unsigned int irq)
++{
++ char file[SYSFS_PATH_MAX];
++ char content[SYSFS_PATH_MAX];
++ struct sysfs_attribute *attr;
++ unsigned int mask = 0xfff;
++ unsigned int new_mask;
++ int ret;
++ size_t len;
++
++ if (irq &gt;= 32)
++ return -EINVAL;
++
++ len = snprintf(file, SYSFS_PATH_MAX, PATH_TO_SOCKET
++ &quot;pcmcia_socket%u/card_irq_mask&quot;,
++ socket_no);
++ dprintf(&quot;file is %s\n&quot;, file);
++
++ attr = sysfs_open_attribute(file);
++ if (!attr)
++ return -ENODEV;
++
++ dprintf(&quot;open, len %d\n&quot;, len);
++
++ ret = sysfs_read_attribute(attr);
++ if (ret) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ if (!attr-&gt;value || (attr-&gt;len &lt; 6)) {
++ ret = -EIO;
++ goto out;
++ }
++
++ ret = sscanf(attr-&gt;value, &quot;0x%x\n&quot;, &amp;mask);
++
++ new_mask = 1 &lt;&lt; irq;
++
++ mask &amp;= ~new_mask;
++
++ len = snprintf(content, SYSFS_PATH_MAX, &quot;0x%04x&quot;, mask);
++
++ dprintf(&quot;content is %s\n&quot;, content);
++
++ ret = sysfs_write_attribute(attr, content, len);
++
++ out:
++ sysfs_close_attribute(attr);
++
++ return (ret);
++}
++
++
++static void load_config(void)
++{
++ if (chdir(configpath) != 0) {
++ syslog(LOG_ERR, &quot;chdir to %s failed: %m&quot;, configpath);
++ exit(EXIT_FAILURE);
++ }
++ parse_configfile(&quot;config.opts&quot;);
++ return;
++}
++
++
++static void adjust_resources(unsigned int socket_no)
++{
++ adjust_list_t *al;
++
++ for (al = root_adjust; al; al = al-&gt;next) {
++ switch (al-&gt;adj.Resource) {
++ case RES_MEMORY_RANGE:
++ add_available_resource(socket_no, RESOURCE_MEM,
++ al-&gt;adj.Action,
++ al-&gt;adj.resource.memory.Base,
++ al-&gt;adj.resource.memory.Base +
++ al-&gt;adj.resource.memory.Size - 1);
++ break;
++ case RES_IO_RANGE:
++ add_available_resource(socket_no, RESOURCE_IO,
++ al-&gt;adj.Action,
++ al-&gt;adj.resource.io.BasePort,
++ al-&gt;adj.resource.io.BasePort +
++ al-&gt;adj.resource.io.NumPorts - 1);
++ break;
++ case RES_IRQ:
++ if(al-&gt;adj.Action == REMOVE_MANAGED_RESOURCE)
++ disallow_irq(socket_no, al-&gt;adj.resource.irq.IRQ);
++ break;
++ }
++ }
++}
++
++/* mdk-stage1
++int main(int argc, char *argv[])
++{
++ char *socket_no;
++ unsigned long socket, i;
++ unsigned int all_sockets = 0;
++
++
++ if ((socket_no = getenv(&quot;SOCKET_NO&quot;))) {
++ socket = strtoul(socket_no, NULL, 0);
++ } else if (argc == 2) {
++ socket = strtoul(argv[1], NULL, 0);
++ } else if (argc == 1) {
++ socket = 0;
++ all_sockets = 1;
++ } else {
++ return -EINVAL;
++ }
++
++ load_config();
++
++ for (i = 0; i &lt; MAX_SOCKS; i++) {
++ if ((socket != i) &amp;&amp; (!all_sockets))
++ continue;
++
++ adjust_resources(i);
++ setup_done(i);
++ }
++
++ return 0;
++}
++*/
++
++void pcmcia_socket_startup(int socket_no) {
++ unsigned long i;
++ unsigned int all_sockets = 0;
++
++ if (socket_no == -1)
++ all_sockets = 1;
++
++ load_config();
++
++ for (i = 0; i &lt; MAX_SOCKS; i++) {
++ if ((socket_no != i) &amp;&amp; (!all_sockets))
++ continue;
++
++ adjust_resources(i);
++ setup_done(i);
++ }
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/pcmcia/startup.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/pcmcia/startup.h
+===================================================================
+--- drakx/trunk/mdk-stage1/pcmcia/startup.h (rev 0)
++++ drakx/trunk/mdk-stage1/pcmcia/startup.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,54 @@
++/*
++ * Startup tool for non statically mapped PCMCIA sockets
++ *
++ * The initial developer of the original code is David A. Hinds
++ * &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dahinds at users.sourceforge.net</A>&gt;. Portions created by David A. Hinds
++ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
++ *
++ * License: GPL v2
++ *
++ */
++
++#define MAX_SOCKS 8
++#define MAX_BINDINGS 4
++#define MAX_MODULES 4
++
++/* for AdjustResourceInfo */
++typedef struct adjust_t {
++ unsigned int Action;
++ unsigned int Resource;
++ unsigned int Attributes;
++ union {
++ struct memory {
++ unsigned long Base;
++ unsigned long Size;
++ } memory;
++ struct io {
++ unsigned long BasePort;
++ unsigned long NumPorts;
++ unsigned int IOAddrLines;
++ } io;
++ struct irq {
++ unsigned int IRQ;
++ } irq;
++ } resource;
++} adjust_t;
++
++
++typedef struct adjust_list_t {
++ adjust_t adj;
++ struct adjust_list_t *next;
++} adjust_list_t;
++
++
++extern adjust_list_t *root_adjust;
++
++int parse_configfile(char *fn);
++
++
++#define RES_MEMORY_RANGE 1
++#define RES_IO_RANGE 2
++#define RES_IRQ 3
++#define RES_RESERVED 0x10
++#define REMOVE_MANAGED_RESOURCE 1
++#define ADD_MANAGED_RESOURCE 2
+
+
+Property changes on: drakx/trunk/mdk-stage1/pcmcia/startup.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/pcmcia/tcic.h
+===================================================================
+--- drakx/trunk/mdk-stage1/pcmcia/tcic.h (rev 0)
++++ drakx/trunk/mdk-stage1/pcmcia/tcic.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,266 @@
++/*
++ * tcic.h 1.15 2001/08/24 12:15:34
++ *
++ * The contents of this file are subject to the Mozilla Public License
++ * Version 1.1 (the &quot;License&quot;); you may not use this file except in
++ * compliance with the License. You may obtain a copy of the License
++ * at <A HREF="http://www.mozilla.org/MPL/">http://www.mozilla.org/MPL/</A>
++ *
++ * Software distributed under the License is distributed on an &quot;AS IS&quot;
++ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
++ * the License for the specific language governing rights and
++ * limitations under the License.
++ *
++ * The initial developer of the original code is David A. Hinds
++ * &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dahinds at users.sourceforge.net</A>&gt;. Portions created by David A. Hinds
++ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
++ *
++ * Alternatively, the contents of this file may be used under the
++ * terms of the GNU General Public License version 2 (the &quot;GPL&quot;), in
++ * which case the provisions of the GPL are applicable instead of the
++ * above. If you wish to allow the use of your version of this file
++ * only under the terms of the GPL and not to allow others to use
++ * your version of this file under the MPL, indicate your decision by
++ * deleting the provisions above and replace them with the notice and
++ * other provisions required by the GPL. If you do not delete the
++ * provisions above, a recipient may use your version of this file
++ * under either the MPL or the GPL.
++ */
++
++#ifndef _LINUX_TCIC_H
++#define _LINUX_TCIC_H
++
++#define TCIC_BASE 0x240
++
++/* offsets of registers from TCIC_BASE */
++#define TCIC_DATA 0x00
++#define TCIC_ADDR 0x02
++#define TCIC_SCTRL 0x06
++#define TCIC_SSTAT 0x07
++#define TCIC_MODE 0x08
++#define TCIC_PWR 0x09
++#define TCIC_EDC 0x0A
++#define TCIC_ICSR 0x0C
++#define TCIC_IENA 0x0D
++#define TCIC_AUX 0x0E
++
++#define TCIC_SS_SHFT 12
++#define TCIC_SS_MASK 0x7000
++
++/* Flags for TCIC_ADDR */
++#define TCIC_ADR2_REG 0x8000
++#define TCIC_ADR2_INDREG 0x0800
++
++#define TCIC_ADDR_REG 0x80000000
++#define TCIC_ADDR_SS_SHFT (TCIC_SS_SHFT+16)
++#define TCIC_ADDR_SS_MASK (TCIC_SS_MASK&lt;&lt;16)
++#define TCIC_ADDR_INDREG 0x08000000
++#define TCIC_ADDR_IO 0x04000000
++#define TCIC_ADDR_MASK 0x03ffffff
++
++/* Flags for TCIC_SCTRL */
++#define TCIC_SCTRL_ENA 0x01
++#define TCIC_SCTRL_INCMODE 0x18
++#define TCIC_SCTRL_INCMODE_HOLD 0x00
++#define TCIC_SCTRL_INCMODE_WORD 0x08
++#define TCIC_SCTRL_INCMODE_REG 0x10
++#define TCIC_SCTRL_INCMODE_AUTO 0x18
++#define TCIC_SCTRL_EDCSUM 0x20
++#define TCIC_SCTRL_RESET 0x80
++
++/* Flags for TCIC_SSTAT */
++#define TCIC_SSTAT_6US 0x01
++#define TCIC_SSTAT_10US 0x02
++#define TCIC_SSTAT_PROGTIME 0x04
++#define TCIC_SSTAT_LBAT1 0x08
++#define TCIC_SSTAT_LBAT2 0x10
++#define TCIC_SSTAT_RDY 0x20 /* Inverted */
++#define TCIC_SSTAT_WP 0x40
++#define TCIC_SSTAT_CD 0x80 /* Card detect */
++
++/* Flags for TCIC_MODE */
++#define TCIC_MODE_PGMMASK 0x1f
++#define TCIC_MODE_NORMAL 0x00
++#define TCIC_MODE_PGMWR 0x01
++#define TCIC_MODE_PGMRD 0x02
++#define TCIC_MODE_PGMCE 0x04
++#define TCIC_MODE_PGMDBW 0x08
++#define TCIC_MODE_PGMWORD 0x10
++#define TCIC_MODE_AUXSEL_MASK 0xe0
++
++/* Registers accessed through TCIC_AUX, by setting TCIC_MODE */
++#define TCIC_AUX_TCTL (0&lt;&lt;5)
++#define TCIC_AUX_PCTL (1&lt;&lt;5)
++#define TCIC_AUX_WCTL (2&lt;&lt;5)
++#define TCIC_AUX_EXTERN (3&lt;&lt;5)
++#define TCIC_AUX_PDATA (4&lt;&lt;5)
++#define TCIC_AUX_SYSCFG (5&lt;&lt;5)
++#define TCIC_AUX_ILOCK (6&lt;&lt;5)
++#define TCIC_AUX_TEST (7&lt;&lt;5)
++
++/* Flags for TCIC_PWR */
++#define TCIC_PWR_VCC(sock) (0x01&lt;&lt;(sock))
++#define TCIC_PWR_VCC_MASK 0x03
++#define TCIC_PWR_VPP(sock) (0x08&lt;&lt;(sock))
++#define TCIC_PWR_VPP_MASK 0x18
++#define TCIC_PWR_CLIMENA 0x40
++#define TCIC_PWR_CLIMSTAT 0x80
++
++/* Flags for TCIC_ICSR */
++#define TCIC_ICSR_CLEAR 0x01
++#define TCIC_ICSR_SET 0x02
++#define TCIC_ICSR_JAM (TCIC_ICSR_CLEAR|TCIC_ICSR_SET)
++#define TCIC_ICSR_STOPCPU 0x04
++#define TCIC_ICSR_ILOCK 0x08
++#define TCIC_ICSR_PROGTIME 0x10
++#define TCIC_ICSR_ERR 0x20
++#define TCIC_ICSR_CDCHG 0x40
++#define TCIC_ICSR_IOCHK 0x80
++
++/* Flags for TCIC_IENA */
++#define TCIC_IENA_CFG_MASK 0x03
++#define TCIC_IENA_CFG_OFF 0x00 /* disabled */
++#define TCIC_IENA_CFG_OD 0x01 /* active low, open drain */
++#define TCIC_IENA_CFG_LOW 0x02 /* active low, totem pole */
++#define TCIC_IENA_CFG_HIGH 0x03 /* active high, totem pole */
++#define TCIC_IENA_ILOCK 0x08
++#define TCIC_IENA_PROGTIME 0x10
++#define TCIC_IENA_ERR 0x20 /* overcurrent or iochk */
++#define TCIC_IENA_CDCHG 0x40
++
++/* Flags for TCIC_AUX_WCTL */
++#define TCIC_WAIT_COUNT_MASK 0x001f
++#define TCIC_WAIT_ASYNC 0x0020
++#define TCIC_WAIT_SENSE 0x0040
++#define TCIC_WAIT_SRC 0x0080
++#define TCIC_WCTL_WR 0x0100
++#define TCIC_WCTL_RD 0x0200
++#define TCIC_WCTL_CE 0x0400
++#define TCIC_WCTL_LLBAT1 0x0800
++#define TCIC_WCTL_LLBAT2 0x1000
++#define TCIC_WCTL_LRDY 0x2000
++#define TCIC_WCTL_LWP 0x4000
++#define TCIC_WCTL_LCD 0x8000
++
++/* Flags for TCIC_AUX_SYSCFG */
++#define TCIC_SYSCFG_IRQ_MASK 0x000f
++#define TCIC_SYSCFG_MCSFULL 0x0010
++#define TCIC_SYSCFG_IO1723 0x0020
++#define TCIC_SYSCFG_MCSXB 0x0040
++#define TCIC_SYSCFG_ICSXB 0x0080
++#define TCIC_SYSCFG_NOPDN 0x0100
++#define TCIC_SYSCFG_MPSEL_SHFT 9
++#define TCIC_SYSCFG_MPSEL_MASK 0x0e00
++#define TCIC_SYSCFG_MPSENSE 0x2000
++#define TCIC_SYSCFG_AUTOBUSY 0x4000
++#define TCIC_SYSCFG_ACC 0x8000
++
++#define TCIC_ILOCK_OUT 0x01
++#define TCIC_ILOCK_SENSE 0x02
++#define TCIC_ILOCK_CRESET 0x04
++#define TCIC_ILOCK_CRESENA 0x08
++#define TCIC_ILOCK_CWAIT 0x10
++#define TCIC_ILOCK_CWAITSNS 0x20
++#define TCIC_ILOCK_HOLD_MASK 0xc0
++#define TCIC_ILOCK_HOLD_CCLK 0xc0
++
++#define TCIC_ILOCKTEST_ID_SH 8
++#define TCIC_ILOCKTEST_ID_MASK 0x7f00
++#define TCIC_ILOCKTEST_MCIC_1 0x8000
++
++#define TCIC_ID_DB86082 0x02
++#define TCIC_ID_DB86082A 0x03
++#define TCIC_ID_DB86084 0x04
++#define TCIC_ID_DB86084A 0x08
++#define TCIC_ID_DB86072 0x15
++#define TCIC_ID_DB86184 0x14
++#define TCIC_ID_DB86082B 0x17
++
++#define TCIC_TEST_DIAG 0x8000
++
++/*
++ * Indirectly addressed registers
++ */
++
++#define TCIC_SCF1(sock) ((sock)&lt;&lt;3)
++#define TCIC_SCF2(sock) (((sock)&lt;&lt;3)+2)
++
++/* Flags for SCF1 */
++#define TCIC_SCF1_IRQ_MASK 0x000f
++#define TCIC_SCF1_IRQ_OFF 0x0000
++#define TCIC_SCF1_IRQOC 0x0010
++#define TCIC_SCF1_PCVT 0x0020
++#define TCIC_SCF1_IRDY 0x0040
++#define TCIC_SCF1_ATA 0x0080
++#define TCIC_SCF1_DMA_SHIFT 8
++#define TCIC_SCF1_DMA_MASK 0x0700
++#define TCIC_SCF1_DMA_OFF 0
++#define TCIC_SCF1_DREQ2 2
++#define TCIC_SCF1_IOSTS 0x0800
++#define TCIC_SCF1_SPKR 0x1000
++#define TCIC_SCF1_FINPACK 0x2000
++#define TCIC_SCF1_DELWR 0x4000
++#define TCIC_SCF1_HD7IDE 0x8000
++
++/* Flags for SCF2 */
++#define TCIC_SCF2_RI 0x0001
++#define TCIC_SCF2_IDBR 0x0002
++#define TCIC_SCF2_MDBR 0x0004
++#define TCIC_SCF2_MLBAT1 0x0008
++#define TCIC_SCF2_MLBAT2 0x0010
++#define TCIC_SCF2_MRDY 0x0020
++#define TCIC_SCF2_MWP 0x0040
++#define TCIC_SCF2_MCD 0x0080
++#define TCIC_SCF2_MALL 0x00f8
++
++/* Indirect addresses for memory window registers */
++#define TCIC_MWIN(sock,map) (0x100+(((map)+((sock)&lt;&lt;2))&lt;&lt;3))
++#define TCIC_MBASE_X 2
++#define TCIC_MMAP_X 4
++#define TCIC_MCTL_X 6
++
++#define TCIC_MBASE_4K_BIT 0x4000
++#define TCIC_MBASE_HA_SHFT 12
++#define TCIC_MBASE_HA_MASK 0x0fff
++
++#define TCIC_MMAP_REG 0x8000
++#define TCIC_MMAP_CA_SHFT 12
++#define TCIC_MMAP_CA_MASK 0x3fff
++
++#define TCIC_MCTL_WSCNT_MASK 0x001f
++#define TCIC_MCTL_WCLK 0x0020
++#define TCIC_MCTL_WCLK_CCLK 0x0000
++#define TCIC_MCTL_WCLK_BCLK 0x0020
++#define TCIC_MCTL_QUIET 0x0040
++#define TCIC_MCTL_WP 0x0080
++#define TCIC_MCTL_ACC 0x0100
++#define TCIC_MCTL_KE 0x0200
++#define TCIC_MCTL_EDC 0x0400
++#define TCIC_MCTL_B8 0x0800
++#define TCIC_MCTL_SS_SHFT TCIC_SS_SHFT
++#define TCIC_MCTL_SS_MASK TCIC_SS_MASK
++#define TCIC_MCTL_ENA 0x8000
++
++/* Indirect addresses for I/O window registers */
++#define TCIC_IWIN(sock,map) (0x200+(((map)+((sock)&lt;&lt;1))&lt;&lt;2))
++#define TCIC_IBASE_X 0
++#define TCIC_ICTL_X 2
++
++#define TCIC_ICTL_WSCNT_MASK TCIC_MCTL_WSCNT_MASK
++#define TCIC_ICTL_QUIET TCIC_MCTL_QUIET
++#define TCIC_ICTL_1K 0x0080
++#define TCIC_ICTL_PASS16 0x0100
++#define TCIC_ICTL_ACC TCIC_MCTL_ACC
++#define TCIC_ICTL_TINY 0x0200
++#define TCIC_ICTL_B16 0x0400
++#define TCIC_ICTL_B8 TCIC_MCTL_B8
++#define TCIC_ICTL_BW_MASK (TCIC_ICTL_B16|TCIC_ICTL_B8)
++#define TCIC_ICTL_BW_DYN 0
++#define TCIC_ICTL_BW_8 TCIC_ICTL_B8
++#define TCIC_ICTL_BW_16 TCIC_ICTL_B16
++#define TCIC_ICTL_BW_ATA (TCIC_ICTL_B16|TCIC_ICTL_B8)
++#define TCIC_ICTL_SS_SHFT TCIC_SS_SHFT
++#define TCIC_ICTL_SS_MASK TCIC_SS_MASK
++#define TCIC_ICTL_ENA TCIC_MCTL_ENA
++
++#endif /* _LINUX_TCIC_H */
+
+
+Property changes on: drakx/trunk/mdk-stage1/pcmcia/tcic.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/pcmcia/version.h
+===================================================================
+--- drakx/trunk/mdk-stage1/pcmcia/version.h (rev 0)
++++ drakx/trunk/mdk-stage1/pcmcia/version.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,4 @@
++/* version.h 1.101 2001/08/09 12:29:14 (David Hinds) */
++
++#define CS_RELEASE &quot;3.1.29&quot;
++#define CS_RELEASE_CODE 0x311d
+
+
+Property changes on: drakx/trunk/mdk-stage1/pcmcia/version.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/pcmcia/vg468.h
+===================================================================
+--- drakx/trunk/mdk-stage1/pcmcia/vg468.h (rev 0)
++++ drakx/trunk/mdk-stage1/pcmcia/vg468.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,106 @@
++/*
++ * vg468.h 1.14 2001/08/24 12:15:34
++ *
++ * The contents of this file are subject to the Mozilla Public License
++ * Version 1.1 (the &quot;License&quot;); you may not use this file except in
++ * compliance with the License. You may obtain a copy of the License
++ * at <A HREF="http://www.mozilla.org/MPL/">http://www.mozilla.org/MPL/</A>
++ *
++ * Software distributed under the License is distributed on an &quot;AS IS&quot;
++ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
++ * the License for the specific language governing rights and
++ * limitations under the License.
++ *
++ * The initial developer of the original code is David A. Hinds
++ * &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dahinds at users.sourceforge.net</A>&gt;. Portions created by David A. Hinds
++ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
++ *
++ * Alternatively, the contents of this file may be used under the
++ * terms of the GNU General Public License version 2 (the &quot;GPL&quot;), in
++ * which case the provisions of the GPL are applicable instead of the
++ * above. If you wish to allow the use of your version of this file
++ * only under the terms of the GPL and not to allow others to use
++ * your version of this file under the MPL, indicate your decision by
++ * deleting the provisions above and replace them with the notice and
++ * other provisions required by the GPL. If you do not delete the
++ * provisions above, a recipient may use your version of this file
++ * under either the MPL or the GPL.
++ */
++
++#ifndef _LINUX_VG468_H
++#define _LINUX_VG468_H
++
++/* Special bit in I365_IDENT used for Vadem chip detection */
++#define I365_IDENT_VADEM 0x08
++
++/* Special definitions in I365_POWER */
++#define VG468_VPP2_MASK 0x0c
++#define VG468_VPP2_5V 0x04
++#define VG468_VPP2_12V 0x08
++
++/* Unique Vadem registers */
++#define VG469_VSENSE 0x1f /* Card voltage sense */
++#define VG469_VSELECT 0x2f /* Card voltage select */
++#define VG468_CTL 0x38 /* Control register */
++#define VG468_TIMER 0x39 /* Timer control */
++#define VG468_MISC 0x3a /* Miscellaneous */
++#define VG468_GPIO_CFG 0x3b /* GPIO configuration */
++#define VG469_EXT_MODE 0x3c /* Extended mode register */
++#define VG468_SELECT 0x3d /* Programmable chip select */
++#define VG468_SELECT_CFG 0x3e /* Chip select configuration */
++#define VG468_ATA 0x3f /* ATA control */
++
++/* Flags for VG469_VSENSE */
++#define VG469_VSENSE_A_VS1 0x01
++#define VG469_VSENSE_A_VS2 0x02
++#define VG469_VSENSE_B_VS1 0x04
++#define VG469_VSENSE_B_VS2 0x08
++
++/* Flags for VG469_VSELECT */
++#define VG469_VSEL_VCC 0x03
++#define VG469_VSEL_5V 0x00
++#define VG469_VSEL_3V 0x03
++#define VG469_VSEL_MAX 0x0c
++#define VG469_VSEL_EXT_STAT 0x10
++#define VG469_VSEL_EXT_BUS 0x20
++#define VG469_VSEL_MIXED 0x40
++#define VG469_VSEL_ISA 0x80
++
++/* Flags for VG468_CTL */
++#define VG468_CTL_SLOW 0x01 /* 600ns memory timing */
++#define VG468_CTL_ASYNC 0x02 /* Asynchronous bus clocking */
++#define VG468_CTL_TSSI 0x08 /* Tri-state some outputs */
++#define VG468_CTL_DELAY 0x10 /* Card detect debounce */
++#define VG468_CTL_INPACK 0x20 /* Obey INPACK signal? */
++#define VG468_CTL_POLARITY 0x40 /* VCCEN polarity */
++#define VG468_CTL_COMPAT 0x80 /* Compatibility stuff */
++
++#define VG469_CTL_WS_COMPAT 0x04 /* Wait state compatibility */
++#define VG469_CTL_STRETCH 0x10 /* LED stretch */
++
++/* Flags for VG468_TIMER */
++#define VG468_TIMER_ZEROPWR 0x10 /* Zero power control */
++#define VG468_TIMER_SIGEN 0x20 /* Power up */
++#define VG468_TIMER_STATUS 0x40 /* Activity timer status */
++#define VG468_TIMER_RES 0x80 /* Timer resolution */
++#define VG468_TIMER_MASK 0x0f /* Activity timer timeout */
++
++/* Flags for VG468_MISC */
++#define VG468_MISC_GPIO 0x04 /* General-purpose IO */
++#define VG468_MISC_DMAWSB 0x08 /* DMA wait state control */
++#define VG469_MISC_LEDENA 0x10 /* LED enable */
++#define VG468_MISC_VADEMREV 0x40 /* Vadem revision control */
++#define VG468_MISC_UNLOCK 0x80 /* Unique register lock */
++
++/* Flags for VG469_EXT_MODE_A */
++#define VG469_MODE_VPPST 0x03 /* Vpp steering control */
++#define VG469_MODE_INT_SENSE 0x04 /* Internal voltage sense */
++#define VG469_MODE_CABLE 0x08
++#define VG469_MODE_COMPAT 0x10 /* i82365sl B or DF step */
++#define VG469_MODE_TEST 0x20
++#define VG469_MODE_RIO 0x40 /* Steer RIO to INTR? */
++
++/* Flags for VG469_EXT_MODE_B */
++#define VG469_MODE_B_3V 0x01 /* 3.3v for socket B */
++
++#endif /* _LINUX_VG468_H */
+
+
+Property changes on: drakx/trunk/mdk-stage1/pcmcia/vg468.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/pcmcia/yacc_config.y
+===================================================================
+--- drakx/trunk/mdk-stage1/pcmcia/yacc_config.y (rev 0)
++++ drakx/trunk/mdk-stage1/pcmcia/yacc_config.y 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,133 @@
++%{
++/*
++ * Startup tool for non statically mapped PCMCIA sockets - config file parsing
++ *
++ * (C) 2005 Dominik Brodowski &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">linux at brodo.de</A>&gt;
++ *
++ * The initial developer of the original code is David A. Hinds
++ * &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dahinds at users.sourceforge.net</A>&gt;. Portions created by David A. Hinds
++ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
++ *
++ * License: GPL v2
++ */
++
++#include &lt;stdlib.h&gt;
++#include &lt;stdarg.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;string.h&gt;
++#include &lt;syslog.h&gt;
++#include &lt;sys/types.h&gt;
++
++#include &quot;startup.h&quot;
++
++/* If bison: generate nicer error messages */
++#define YYERROR_VERBOSE 1
++
++/* from lex_config, for nice error messages */
++extern char *current_file;
++extern int current_lineno;
++
++extern int yylex(void); /* mdk-stage1 */
++
++void yyerror(char *msg, ...);
++
++%}
++
++%token DEVICE CARD ANONYMOUS TUPLE MANFID VERSION FUNCTION PCI
++%token BIND CIS TO NEEDS_MTD MODULE OPTS CLASS
++%token REGION JEDEC DTYPE DEFAULT MTD
++%token INCLUDE EXCLUDE RESERVE IRQ_NO PORT MEMORY
++%token STRING NUMBER SOURCE
++
++%union {
++ char *str;
++ u_long num;
++ struct adjust_list_t *adjust;
++}
++
++%type &lt;str&gt; STRING
++%type &lt;num&gt; NUMBER
++%type &lt;adjust&gt; adjust resource
++%%
++list: /* nothing */
++ | list adjust
++ {
++ adjust_list_t **tail = &amp;root_adjust;
++ while (*tail != NULL) tail = &amp;(*tail)-&gt;next;
++ *tail = $2;
++ }
++ ;
++
++adjust: INCLUDE resource
++ {
++ $2-&gt;adj.Action = ADD_MANAGED_RESOURCE;
++ $$ = $2;
++ }
++ | EXCLUDE resource
++ {
++ $2-&gt;adj.Action = REMOVE_MANAGED_RESOURCE;
++ $$ = $2;
++ }
++ | RESERVE resource
++ {
++ $2-&gt;adj.Action = ADD_MANAGED_RESOURCE;
++ $2-&gt;adj.Attributes |= RES_RESERVED;
++ $$ = $2;
++ }
++ | adjust ',' resource
++ {
++ $3-&gt;adj.Action = $1-&gt;adj.Action;
++ $3-&gt;adj.Attributes = $1-&gt;adj.Attributes;
++ $3-&gt;next = $1;
++ $$ = $3;
++ }
++ ;
++
++resource: IRQ_NO NUMBER
++ {
++ $$ = calloc(sizeof(adjust_list_t), 1);
++ $$-&gt;adj.Resource = RES_IRQ;
++ $$-&gt;adj.resource.irq.IRQ = $2;
++ }
++ | PORT NUMBER '-' NUMBER
++ {
++ if (($4 &lt; $2) || ($4 &gt; 0xffff)) {
++ yyerror(&quot;invalid port range 0x%x-0x%x&quot;, $2, $4);
++ YYERROR;
++ }
++ $$ = calloc(sizeof(adjust_list_t), 1);
++ $$-&gt;adj.Resource = RES_IO_RANGE;
++ $$-&gt;adj.resource.io.BasePort = $2;
++ $$-&gt;adj.resource.io.NumPorts = $4 - $2 + 1;
++ }
++ | MEMORY NUMBER '-' NUMBER
++ {
++ if ($4 &lt; $2) {
++ yyerror(&quot;invalid address range 0x%x-0x%x&quot;, $2, $4);
++ YYERROR;
++ }
++ $$ = calloc(sizeof(adjust_list_t), 1);
++ $$-&gt;adj.Resource = RES_MEMORY_RANGE;
++ $$-&gt;adj.resource.memory.Base = $2;
++ $$-&gt;adj.resource.memory.Size = $4 - $2 + 1;
++ }
++ ;
++
++%%
++void yyerror(char *msg, ...)
++{
++ va_list ap;
++ char str[256];
++
++ va_start(ap, msg);
++ sprintf(str, &quot;error in file '%s' line %d: &quot;,
++ current_file, current_lineno);
++ vsprintf(str+strlen(str), msg, ap);
++#if YYDEBUG
++ fprintf(stderr, &quot;%s\n&quot;, str);
++#else
++ syslog(LOG_ERR, &quot;%s&quot;, str);
++#endif
++ va_end(ap);
++}
++
+
+Added: drakx/trunk/mdk-stage1/pcmcia-resource/Makefile
+===================================================================
+--- drakx/trunk/mdk-stage1/pcmcia-resource/Makefile (rev 0)
++++ drakx/trunk/mdk-stage1/pcmcia-resource/Makefile 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,24 @@
++ #******************************************************************************
++ #
++ # Olivier Blin (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">blino at mandriva.com</A>)
++ #
++ # Copyright 2006 Mandriva
++ #
++ # This software may be freely redistributed under the terms of the GNU
++ # public license.
++ #
++ # You should have received a copy of the GNU General Public License
++ # along with this program; if not, write to the Free Software
++ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ #
++ #*****************************************************************************
++
++TARGET=pcmcia-ids.h
++
++all: $(TARGET)
++
++$(TARGET):
++ perl update-pcmcia-ids.pl &gt; $@ || { rm -f $@; exit 1; }
++
++clean:
++ rm -f $(TARGET)
+
+
+Property changes on: drakx/trunk/mdk-stage1/pcmcia-resource/Makefile
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/pcmcia-resource/update-pcmcia-ids.pl
+===================================================================
+--- drakx/trunk/mdk-stage1/pcmcia-resource/update-pcmcia-ids.pl (rev 0)
++++ drakx/trunk/mdk-stage1/pcmcia-resource/update-pcmcia-ids.pl 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,42 @@
++#!/usr/bin/perl
++
++use lib '../kernel';
++use strict;
++use MDK::Common;
++
++my @aliases;
++my ($main) = `ls -t /lib/modules/*/modules.alias`;
++foreach (cat_(chomp_($main))) {
++ push @aliases, [ $1, $2 ] if /^alias\s+(pcmcia:\S+)\s+(\S+)$/; #- modalias, module
++}
+<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">+ at aliases</A> or die &quot;unable to get PCMCIA aliases&quot;;
++
++print '
++struct pcmcia_alias {
++ const char *modalias;
++ const char *module;
++};
++
++';
++
++my %t = (
++ network =&gt; 'network/pcmcia',
++ medias =&gt; 'disk/pcmcia',
++);
++
++foreach my $type (keys %t) {
++ my @modules = chomp_(`perl ../../kernel/modules.pl pci_modules4stage1 &quot;$t{$type}&quot;`)
++ or die &quot;unable to get PCMCIA modules&quot;;
++
++ print &quot;#ifndef DISABLE_&quot;.uc($type).&quot;
++struct pcmcia_alias ${type}_pcmcia_ids[] = {
++&quot;;
++ print qq|\t{ &quot;$_-&gt;[0]&quot;, &quot;$_-&gt;[1]&quot; },\n| foreach grep { member($_-&gt;[1], @modules) } @aliases;
++ print &quot;};
++unsigned int ${type}_pcmcia_num_ids = sizeof(${type}_pcmcia_ids) / sizeof(struct pcmcia_alias);
++
++#endif
++
++&quot;;
++
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/pcmcia-resource/update-pcmcia-ids.pl
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: drakx/trunk/mdk-stage1/ppp/Changes-2.3
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/Changes-2.3 (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/Changes-2.3 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,441 @@
++What was new in ppp-2.3.11.
++***************************
++
++* Support for Solaris 8 has been added, including support for
++ replumbing and IPV6.
++
++* The Solaris `snoop' utility should now work on ppp interfaces.
++
++* New hooks have been added - pap_logout_hook, ip_up_hook, and
++ ip_down_hook.
++
++* A new `passprompt' plugin is included, thanks to Alan Curry, which
++ makes it possible for pppd to call an external program to get the
++ PAP password to send to the peer.
++
++* The error messages for the situation where authentication is
++ required because the system has a default route have been improved.
++
++* There is a new connect_delay option which specifies how long pppd
++ should pause after the connect script finishes. Previously this
++ delay was fixed at 1 second. (This delay terminates as soon as pppd
++ sees a valid PPP frame from the peer.)
++
++* The `hide-password' option is now the default, and there is a new
++ `show-password' option to enable the printing of password strings in
++ the debug output.
++
++* A fairly complete list of the names of PPP protocols has been added
++ so that when pppd rejects a frame because its protocol is not
++ supported, it can print the name of the unsupported protocol.
++
++* Synchronous serial lines are supported under Linux 2.3.x.
++
++* The bug where pppd would not recognize a modem hangup under Linux
++ 2.3.x kernels has been fixed.
++
++
++What was new in ppp-2.3.10.
++***************************
++
++* Pppd now supports `plugins', which are pieces of code (packaged as
++ shared libraries) which can be loaded into pppd at runtime and which
++ can affect its behaviour. The intention is that plugins provide a
++ way for people to customize the behaviour of pppd for their own
++ needs without needing to change the base pppd source. I have added
++ some hooks into pppd (places where pppd will call a function
++ pointer, if non-zero, to replace some of pppd's code) and I will be
++ receptive to suggestions about places to add more hooks. Plugins
++ are supported under Linux and Solaris at present.
++
++* We have a new maintainer for the Solaris port, Adi Masputra of Sun
++ Microsystems, and he has updated the Solaris port so that it should
++ work on 64-bit machines under Solaris 7 and later.
++
++* Pppd now has an `allow-ip' option, which takes an argument which is
++ an IP address (or subnet) which peers are permitted to use without
++ authenticating themselves. The argument takes the same form as each
++ element of the allowed IP address list in the secrets files. The
++ allow-ip option is privileged and may be specified multiple times.
++ Using the allow-ip option should be cleaner than putting a line like
++ `&quot;&quot; * &quot;&quot; address' in /etc/ppp/pap-secrets.
++
++* Chat can now substitute environment variables into the script. This
++ is enabled by the -E flag. (Thanks to Andreas Arens for the patch.)
++
++* If the PAP username and password from the peer contains unprintable
++ characters, they will be translated to a printable form before
++ looking in the pap-secrets file. Characters &gt;= 0x80 are translated
++ to a M- form, and characters from 0 to 0x1f (and 0x7f as well) are
++ translated to a ^X form. If this change causes you grief, let me
++ know what would be a better translation. It appears that some peers
++ send nulls or other control characters in their usernames and
++ passwords.
++
++* Pppd has new `ktune' and `noktune' options, which enable/disable
++ it to change kernel settings as appropriate. This is only
++ implemented under Linux, and requires the /proc filesystem to be
++ mounted. Under Linux, with the ktune option, pppd will enable IP
++ forwarding in the kernel if the proxyarp option is used, and will
++ enable the dynamic IP address kernel option in demand mode if the
++ local IP address changes.
++
++* Pppd no longer requires a remote address to be specified for demand
++ dialling. If none is specified, it will use a default value of
++ 10.112.112.112+unit_number. (It will not propose this default to
++ the peer.)
++
++* The default holdoff is now 0 if no connect script is given.
++
++* The IPV6 code from Tommi Komulainen, which I unfortunately only
++ partially merged in to ppp-2.3.9, has been fixed and updated.
++
++* The linux compilation glitches should be fixed now.
++
++
++What was new in ppp-2.3.9.
++**************************
++
++* Support for the new generic PPP layer under development for the
++ Linux kernel.
++
++* You can now place extra options to apply to specific users at the
++ end of the line with their password in the pap-secrets or
++ chap-secrets file, separated from the IP address(es) with a &quot;--&quot;
++ separator. These options are parsed after the peer is authenticated
++ but before network protocol (IPCP, IPXCP) or CCP negotiation
++ commences.
++
++* Pppd will apply the holdoff period if the link was terminated by the
++ peer. It doesn't apply it if the link was terminated because the
++ local pppd thought it was idle.
++
++* Synchronous support for Solaris has been added, thanks to John
++ Morrison, and for FreeBSD, thanks to Paul Fulghum.
++
++* IPV6 support has been merged in, from Tommi Komulainen. At the
++ moment it only supports Linux and it is not tested by me.
++
++* The `nodefaultip' option can be used in demand mode to say that pppd
++ should not suggest its local IP address to the peer.
++
++* The `init' option has been added; this causes pppd to run a script
++ to initialize the serial device (e.g. by sending an init string to
++ the modem). Unlike the connect option, this can be used in a
++ dial-in situation. (Thanks to Tobias Ringstrom.)
++
++* There is a new `logfile' option to send log messages to a file as
++ well as syslog.
++
++* There is a new, privileged `linkname' option which sets a logical
++ name for the link. Pppd will create a /var/run/ppp-&lt;linkname&gt;.pid
++ file containing its process ID.
++
++* There is a new `maxfail' option which specifies how many consecutive
++ failed connection attempts are permitted before pppd will exit. The
++ default value is 10, and 0 means infinity. :-)
++
++* Sundry bugs fixed.
++
++
++What was new in ppp-2.3.8.
++**************************
++
++* The exit status of pppd will now indicate whether the link was
++ successfully established, or if not, what error was encountered.
++
++* Pppd has two new options: fdlog &lt;n&gt; will send log messages to file
++ descriptor &lt;n&gt; instead of standard output, and nofdlog will stop log
++ messages from being sent to any file descriptor (they will still be
++ sent to syslog). Pppd now will not send log messages to a file
++ descriptor if the serial port is open on that file descriptor.
++
++* Pppd sets an environment variable called PPPLOGNAME for scripts that
++ it runs, indicating the login name of the user who invoked pppd.
++
++* Pppd sets environment variables CONNECT_TIME, BYTES_SENT and
++ BYTES_RCVD for the ip-down and auth-down scripts indicating the
++ statistics for the connection just terminated. (CONNECT_TIME is in
++ seconds.)
++
++* If the user has the serial device open on standard input and
++ specifies a symbolic link to the serial device on the command line,
++ pppd will detect this and behave correctly (i.e. not detach from its
++ controlling terminal). Furthermore, if the serial port is open for
++ reading and writing on standard input, pppd will assume that it is
++ locked by its invoker and not lock it itself.
++
++* Chat now has a feature where if a string to be sent begins with an
++ at sign (@), the rest of the string is taken as the name of a file
++ (regular file or named pipe), and the actual string to send is taken
++ from that file.
++
++* Support for FreeBSD-2.2.8 and 3.0 has been added, thanks to Paul
++ Fulghum.
++
++* The Tru64 (aka Digital Unix aka OSF/1) port has been updated.
++
++* The system panics on Solaris SMP systems related to PPP connections
++ being established and terminated should no longer occur.
++
++* Fixed quite a few bugs.
++
++
++What was new in ppp-2.3.7.
++**************************
++
++* Pppd can now automatically allocate itself a pseudo-tty to use as
++ the serial device. This has made three new options possible:
++
++ - `pty script' will run `script' with its standard input and output
++ connected to the master side of the pty. For example:
++ pppd pty 'ssh -t server.my.net pppd'
++ is a basic command for setting up a PPP link (tunnel) over ssh.
++ (In practice you may need to specify other options such as IP
++ addresses, etc.)
++
++ - `notty' tells pppd to communicate over its standard input and
++ output, which do not have to be a terminal device.
++
++ - `record filename' tells pppd to record all of the characters sent
++ and received over the serial device to a file called `filename'.
++ The data is recorded in a tagged format with timestamps, which can
++ be printed in a readable form with the pppdump program, which is
++ included in this distribution.
++
++* Pppd now logs the connect time and number of bytes sent and received
++ (at the level of the serial device) when the connection is
++ terminated.
++
++* If you use the updetach or nodetach option, pppd will print its
++ messages to standard output as well as logging them with syslog
++ (provided of course pppd isn't using its standard input or output as
++ its serial device).
++
++* There is a new `privgroup groupname' option (a privileged option).
++ If the user running pppd is in group `groupname', s/he can use
++ privileged options without restriction.
++
++* There is a new `receive-all' option, which causes pppd to accept all
++ control characters, even the ones that the peer should be escaping
++ (i.e. the receive asyncmap is 0). This is useful with some buggy
++ peers.
++
++* The default asyncmap is now 0.
++
++* There is a new `sync' option, currently only implemented under
++ Linux, which allows pppd to run on synchronous HDLC devices.
++
++* If a value for the device name or for the connect, disconnect,
++ welcome or pty option is given in a privileged option file
++ (i.e. /etc/ppp/options or a file loaded with the `call' option), it
++ cannot be overridden by a non-privileged user.
++
++* Many bugs have been fixed, notably:
++ - signals are not blocked unnecessarily, as they were in 2.3.6.
++ - the usepeerdns option should work now.
++ - the SPEED environment variable for scripts is set correctly.
++ - the /etc/ppp/auth-down script is not run until auth-up completes.
++ - the device is opened as root if it is the device on standard
++ input.
++ - pppd doesn't die with the ioctl(PPPIOCSASYNCMAP) error under linux
++ if a hangup occurs at the wrong time.
++
++* Some error messages have been changed to be clearer (I hope :-)
++
++
++What was new in ppp-2.3.6.
++**************************
++
++* Pppd now opens the tty device as the user (rather than as root) if
++ the device name was given by the user, i.e. on the command line or
++ in the ~/.ppprc file. If the device name was given in
++ /etc/ppp/options or in a file loaded with the `call' option, the
++ device is opened as root.
++
++* The default behaviour of pppd is now to let a peer which has not
++ authenticated itself (e.g. your ISP) use any IP address to which the
++ system does not already have a route. (This is currently only
++ supported under Linux, Solaris and Digital Unix; on the other
++ systems, the peer must now authenticate itself unless the noauth
++ option is used.)
++
++* Added new option `usepeerdns', thanks to Nick Walker
++ &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">nickwalker at email.com</A>&gt;. If the peer supplies DNS addresses, these
++ will be written to /etc/ppp/resolv.conf. The ip-up script can then
++ be used to add these addresses to /etc/resolv.conf if desired (see
++ the ip-up.local.add and ip-down.local.add files in the scripts
++ directory).
++
++* The Solaris ppp driver should now work correctly on SMP systems.
++
++* Minor corrections so that the code can compile under Solaris 7,
++ and under Linux with glibc-2.1.
++
++* The Linux kernel driver has been restructured for improved
++ performance.
++
++* Pppd now won't start the ip-down script until the ip-up script has
++ finished.
++
++
++What was new in ppp-2.3.5.
++**************************
++
++* Minor corrections to the Digital UNIX and NetBSD ports.
++
++* A workaround to avoid tickling a bug in the `se' serial port driver
++on Sun PCI Ultra machines running Solaris.
++
++* Fixed a bug in the negotiation of the Microsoft WINS server address
++option.
++
++* Fixed a bug in the Linux port where it would fail for kernel
++versions above 2.1.99.
++
++
++What was new in ppp-2.3.4.
++**************************
++
++* The NeXT port has been updated, thanks to Steve Perkins.
++
++* ppp-2.3.4 compiles and works under Solaris 2.6, using either gcc or
++cc.
++
++* With the Solaris, SVR4 and SunOS ports, you can control the choice
++of C compiler, C compiler options, and installation directories by
++editing the svr4/Makedefs or sunos4/Makedefs file.
++
++* Until now, we have been using the number 24 to identify Deflate
++compression in the CCP negotiations, which was the number in the draft
++RFC describing Deflate. The number actually assigned to Deflate is
++26. The code has been changed to use 26, but to allow the use of 24
++for now for backwards compatibility. (This can be disabled with the
++`nodeflatedraft' option to pppd.)
++
++* Fixed some bugs in the linux driver and deflate compressor which
++were causing compression problems, including corrupting long
++incompressible packets sometimes.
++
++* Fixes to the PAM and shadow password support in pppd, from Al
++Longyear and others.
++
++* Pppd now sets some environment variables for scripts it invokes
++(ip-up/down, auth-ip/down), giving information about the connection.
++The variables it sets are PEERNAME, IPLOCAL, IPREMOTE, UID, DEVICE,
++SPEED, and IFNAME.
++
++* Pppd now has an `updetach' option, which will cause it to detach
++from its controlling terminal once the link has come up (i.e. once it
++is available for IP traffic).
++
++
++What was new in ppp-2.3.3.
++**************************
++
++* Fixed compilation problems under SunOS.
++
++* Fixed a bug introduced into chat in 2.3.2, and compilation problems
++introduced into the MS-CHAP implementation in 2.3.2.
++
++* The linux kernel driver has been updated for recent 2.1-series
++kernel changes, and it now will ask kerneld to load compression
++modules when required, if the kernel is configured to support kerneld.
++
++* Pppd should now compile correctly under linux on systems with glibc.
++
++
++What was new in ppp-2.3.2.
++**************************
++
++* In 2.3.1, I made a change which was intended to make pppd able to
++detect loss of CD during or immediately after the connection script
++runs. Unfortunately, this had the side-effect that the connection
++script wouldn't work at all on some systems. This change has been
++reversed.
++
++* Fix compilation problems in the Linux kernel driver.
++
++
++What was new in ppp-2.3.1.
++**************************
++
++* Enhancements to chat, thanks to Francis Demierre. Chat can now
++accept comments in the chat script file, and has new SAY, HANGUP,
++CLR_ABORT and CLR_REPORT keywords.
++
++* Fixed a bug which causes 2.3.0 to crash Solaris systems.
++
++* Bug-fixes and restructuring of the Linux kernel driver.
++
++* The holdoff behaviour of pppd has been changed slightly: now, if
++the link comes up for IP (or other network protocol) traffic, we
++consider that the link has been successfully established, and don't
++enforce the holdoff period after the link goes down.
++
++* Pppd should now correctly wait for CD (carrier detect) from the
++modem, even when the serial port initially had CLOCAL set, and it
++should also detect loss of CD during or immediately after the
++connection script runs.
++
++* Under linux, pppd will work with older 2.2.0* version kernel
++drivers, although demand-dialling is not supported with them.
++
++* Minor bugfixes for pppd.
++
++
++What was new in ppp-2.3.
++************************
++
++* Demand-dialling. Pppd now has a mode where it will establish the
++network interface immediately when it starts, but not actually bring
++the link up until it sees some data to be sent. Look for the demand
++option description in the pppd man page. Demand-dialling is not
++supported under Ultrix or NeXTStep.
++
++* Idle timeout. Pppd will optionally terminate the link if no data
++packets are sent or received within a certain time interval.
++
++* Pppd now runs the /etc/ppp/auth-up script, if it exists, when the
++peer successfully authenticates itself, and /etc/ppp/auth-down when
++the connection is subsequently terminated. This can be useful for
++accounting purposes.
++
++* A new packet compression scheme, Deflate, has been implemented.
++This uses the same compression method as `gzip'. This method is free
++of patent or copyright restrictions, and it achieves better
++compression than BSD-Compress. It does consume more CPU cycles for
++compression than BSD-Compress, but this shouldn't be a problem for
++links running at 100kbit/s or less.
++
++* There is no code in this distribution which is covered by Brad
++Clements' restrictive copyright notice. The STREAMS modules for SunOS
++and OSF/1 have been rewritten, based on the Solaris 2 modules, which
++were written from scratch without any Clements code.
++
++* Pppstats has been reworked to clean up the output format somewhat.
++It also has a new -d option which displays data rate in kbyte/s for
++those columns which would normally display bytes.
++
++* Pppd options beginning with - or + have been renamed, e.g. -ip
++became noip, +chap became require-chap, etc. The old options are
++still accepted for compatibility but may be removed in future.
++
++* Pppd now has some options (such as the new `noauth' option) which
++can only be specified if it is being run by root, or in an
++&quot;privileged&quot; options file: /etc/ppp/options or an options file in the
++/etc/ppp/peers directory. There is a new &quot;call&quot; option to read
++options from a file in /etc/ppp/peers, making it possible for non-root
++users to make unauthenticated connections, but only to certain trusted
++peers. My intention is to make the `auth' option the default in a
++future release.
++
++* Several minor new features have been added to pppd, including the
++maxconnect and welcome options. Pppd will now terminate the
++connection when there are no network control protocols running. The
++allowed IP address(es) field in the secrets files can now specify
++subnets (with a notation like 123.45.67.89/24) and addresses which are
++not acceptable (put a ! on the front).
++
++* Numerous bugs have been fixed (no doubt some have been introduced :-)
++Thanks to those who reported bugs in ppp-2.2.
+
+Added: drakx/trunk/mdk-stage1/ppp/FAQ
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/FAQ (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/FAQ 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,634 @@
++This is a list of Frequently Asked Questions about using ppp-2.x and
++their answers.
++
++
++------------------------------------------------------------------------
++
++Q: Can you give me an example of how I might set up my machine to dial
++out to an ISP?
++
++A: Here's an example for dialling out to an ISP via a modem on
++/dev/tty02. The modem uses hardware (CTS/RTS) flow control, and the
++serial port is run at 38400 baud. The ISP assigns our IP address.
++
++To configure pppd for this connection, create a file under
++/etc/ppp/peers called (say) my-isp containing the following:
++
++tty02 crtscts 38400
++connect 'chat -v -f /etc/ppp/chat/my-isp'
++defaultroute
++
++The ppp connection is then initiated using the following command:
++
++pppd call my-isp
++
++Of course, if the directory containing pppd is not in your path, you
++will need to give the full pathname for pppd, for example,
++/usr/sbin/pppd.
++
++When you run this, pppd will use the chat program to dial the ISP and
++invoke its ppp service. Chat will read the file specified with -f,
++namely /etc/ppp/chat/my-isp, to find a list of strings to expect to
++receive, and strings to send. This file would contain something like
++this:
++
++ABORT &quot;NO CARRIER&quot;
++ABORT &quot;NO DIALTONE&quot;
++ABORT &quot;ERROR&quot;
++ABORT &quot;NO ANSWER&quot;
++ABORT &quot;BUSY&quot;
++ABORT &quot;Username/Password Incorrect&quot;
++&quot;&quot; &quot;at&quot;
++OK &quot;at&amp;d2&amp;c1&quot;
++OK &quot;atdt2479381&quot;
++&quot;name:&quot; &quot;^Uusername&quot;
++&quot;word:&quot; &quot;\qpassword&quot;
++&quot;annex&quot; &quot;\q^Uppp&quot;
++&quot;Switching to PPP-ppp-Switching to PPP&quot;
++
++You will need to change the details here. The first string on each
++line is a string to expect to receive; the second is the string to
++send. You can add or delete lines according to the dialog required to
++access your ISP's system. This example is for a modem with a standard
++AT command set, dialling out to an Annex terminal server. The \q
++toggles &quot;quiet&quot; mode; when quiet mode is on, the strings to be sent
++are replaced by ?????? in the log. You may need to go through the
++dialog manually using kermit or tip first to determine what should go
++in the script.
++
++To terminate the link, run the following script, called (say)
++kill-ppp:
++
++#!/bin/sh
++unit=ppp${1-0}
++piddir=/var/run
++if [ -f $piddir/$unit.pid ]; then
++ kill -1 `cat $piddir/$unit.pid`
++fi
++
++On some systems (SunOS, Solaris, Ultrix), you will need to change
++/var/run to /etc/ppp.
++
++
++------------------------------------------------------------------------
++
++Q: Can you give me an example of how I could set up my office machine
++so I can dial in to it from home?
++
++A: Let's assume that the office machine is called &quot;office&quot; and is on a
++local ethernet subnet. Call the home machine &quot;home&quot; and give it an IP
++address on the same subnet as &quot;office&quot;. We'll require both machines
++to authenticate themselves to each other.
++
++Set up the files on &quot;office&quot; as follows:
++
++/etc/ppp/options contains:
++
++auth # require the peer to authenticate itself
++lock
++# other options can go here if desired
++
++/etc/ppp/chap-secrets contains:
++
++home office &quot;beware the frub-jub&quot; home
++office home &quot;bird, my son!%&amp;*&quot; -
++
++Set up a modem on a serial port so that users can dial in to the
++modem and get a login prompt.
++
++On &quot;home&quot;, set up the files as follows:
++
++/etc/ppp/options contains the same as on &quot;office&quot;.
++
++/etc/ppp/chap-secrets contains:
++
++home office &quot;beware the frub-jub&quot; -
++office home &quot;bird, my son!%&amp;*&quot; office
++
++Create a file called /etc/ppp/peers/office containing the following:
++
++tty02 crtscts 38400
++connect 'chat -v -f /etc/ppp/chat/office'
++defaultroute
++
++(You may need to change some of the details here.)
++
++Create the /etc/ppp/chat/office file containing the following:
++
++ABORT &quot;NO CARRIER&quot;
++ABORT &quot;NO DIALTONE&quot;
++ABORT &quot;ERROR&quot;
++ABORT &quot;NO ANSWER&quot;
++ABORT &quot;BUSY&quot;
++ABORT &quot;ogin incorrect&quot;
++&quot;&quot; &quot;at&quot;
++OK &quot;at&amp;d2&amp;c1&quot;
++OK &quot;atdt2479381&quot;
++&quot;name:&quot; &quot;^Uusername&quot;
++&quot;word:&quot; &quot;\qpassword&quot;
++&quot;$&quot; &quot;\q^U/usr/sbin/pppd proxyarp&quot;
++&quot;~&quot;
++
++You will need to change the details. Note that the &quot;$&quot; in the
++second-last line is expecting the shell prompt after a successful
++login - you may need to change it to &quot;%&quot; or something else.
++
++You then initiate the connection (from home) with the command:
++
++pppd call office
++
++------------------------------------------------------------------------
++
++Q: When I try to establish a connection, the modem successfully dials
++the remote system, but then hangs up a few seconds later. How do I
++find out what's going wrong?
++
++A: There are a number of possible problems here. The first thing to
++do is to ensure that pppd's messages are visible. Pppd uses the
++syslog facility to log messages which help to identify specific
++problems. Messages from pppd have facility &quot;daemon&quot; and levels
++ranging from &quot;debug&quot; to &quot;error&quot;.
++
++Usually it is useful to see messages of level &quot;notice&quot; or higher on
++the console. To see these, find the line in /etc/syslog.conf which
++has /dev/console on the right-hand side, and add &quot;daemon.notice&quot; in
++the list on the left. The line will end up looking something like
++this:
++
++*.err;kern.debug;auth.notice;mail.crit;daemon.notice /dev/console
++
++Note that the whitespace is tabs, *not* spaces.
++
++If you are having problems, it may be useful to see messages of level
++&quot;info&quot; as well, in which case you would change &quot;daemon.notice&quot; to
++&quot;daemon.info&quot;.
++
++In addition, it is useful to collect pppd's debugging output in a
++file - the debug option to pppd causes it to log the contents of all
++control packets sent and received in human-readable form. To do this,
++add a line like this to /etc/syslog.conf:
++
++daemon,local2.debug /etc/ppp/log
++
++and create an empty /etc/ppp/log file.
++
++When you change syslog.conf, you will need to send a HUP signal to
++syslogd to causes it to re-read syslog.conf. You can do this with a
++command like this (as root):
++
++ kill -HUP `cat /etc/syslogd.pid`
++
++(On some systems, you need to use /var/run/syslog.pid instead of
++/etc/syslogd.pid.)
++
++After setting up syslog like this, you can use the -v flag to chat and
++the `debug' option to pppd to get more information. Try initiating
++the connection again; when it fails, inspect /etc/ppp/log to see what
++happened and where the connection failed.
++
++
++------------------------------------------------------------------------
++
++Q: When I try to establish a connection, I get an error message saying
++&quot;Serial link is not 8-bit clean&quot;. Why?
++
++A: The most common cause is that your connection script hasn't
++successfully dialled out to the remote system and invoked ppp service
++there. Instead, pppd is talking to something (a shell or login
++process on the remote machine, or maybe just the modem) which is only
++outputting 7-bit characters.
++
++This can also arise with a modem which uses an AT command set if the
++dial command is issued before pppd is invoked, rather than within a
++connect script started by pppd. If the serial port is set to 7
++bits/character plus parity when the last AT command is issued, the
++modem serial port will be set to the same setting.
++
++Note that pppd *always* sets the local serial port to 8 bits per
++character, with no parity and 1 stop bit. So you shouldn't need to
++issue an stty command before invoking pppd.
++
++
++------------------------------------------------------------------------
++
++Q: When I try to establish a connection, I get an error message saying
++&quot;Serial line is looped back&quot;. Why?
++
++A: Probably your connection script hasn't successfully dialled out to
++the remote system and invoked ppp service there. Instead, pppd is
++talking to something which is just echoing back the characters it
++receives. The -v option to chat can help you find out what's going
++on. It can be useful to include &quot;~&quot; as the last expect string to
++chat, so chat won't return until it's seen the start of the first PPP
++frame from the remote system.
++
++Another possibility is that your phone connection has dropped for some
++obscure reason and the modem is echoing the characters it receives
++from your system.
++
++
++------------------------------------------------------------------------
++
++Q: I installed pppd successfully, but when I try to run it, I get a
++message saying something like &quot;peer authentication required but no
++authentication files accessible&quot;.
++
++A: When pppd is used on a machine which already has a connection to
++the Internet (or to be more precise, one which has a default route in
++its routing table), it will require all peers to authenticate
++themselves. The reason for this is that if you don't require
++authentication, you have a security hole, because the peer can
++basically choose any IP address it wants, even the IP address of some
++trusted host (for example, a host mentioned in some .rhosts file).
++
++On machines which don't have a default route, pppd does not require
++the peer to authenticate itself. The reason is that such machines
++would mostly be using pppd to dial out to an ISP which will refuse to
++authenticate itself. In that case the peer can use any IP address as
++long as the system does not already have a route to that address.
++For example, if you have a local ethernet network, the peer can't use
++an address on that network. (In fact it could if it authenticated
++itself and it was permitted to use that address by the pap-secrets or
++chap-secrets file.)
++
++There are 3 ways around the problem:
++
++1. If possible, arrange for the peer to authenticate itself, and
++create the necessary secrets files (/etc/ppp/pap-secrets and/or
++/etc/ppp/chap-secrets).
++
++2. If the peer refuses to authenticate itself, and will always be
++using the same IP address, or one of a small set of IP addresses, you
++can create an entry in the /etc/ppp/pap-secrets file like this:
++
++ &quot;&quot; * &quot;&quot; his-ip.his-domain his-other-ip.other-domain
++
++(that is, using the empty string for the client name and password
++fields). Of couse, you replace the 4th and following fields in the
++example above with the IP address(es) that the peer may use. You can
++use either hostnames or numeric IP addresses.
++
++3. You can add the `noauth' option to the /etc/ppp/options file.
++Pppd will then not ask the peer to authenticate itself. If you do
++this, I *strongly* recommend that you remove the set-uid bit from the
++permissions on the pppd executable, with a command like this:
++
++ chmod u-s /usr/sbin/pppd
++
++Then, an intruder could only use pppd maliciously if they had already
++become root, in which case they couldn't do any more damage using pppd
++than they could anyway.
++
++
++------------------------------------------------------------------------
++
++Q: What do I need to put in the secrets files?
++
++A: Three things:
++ - secrets (i.e. passwords) to use for authenticating this host to
++ other hosts (i.e., for proving our identity to others);
++ - secrets which other hosts can use for authenticating themselves
++ to us (i.e., so that they can prove their identity to us); and
++ - information about which IP addresses other hosts may use, once
++ they have authenticated themselves.
++
++There are two authentication files: /etc/ppp/pap-secrets, which
++contains secrets for use with PAP (the Password Authentication
++Protocol), and /etc/ppp/chap-secrets, which contains secrets for use
++with CHAP (the Challenge Handshake Authentication Protocol). Both
++files have the same simple format, which is as follows:
++
++- The file contains a series of entries, each of which contains a
++secret for authenticating one machine to another.
++
++- Each entry is contained on a single logical line. A logical line
++may be continued across several lines by placing a backslash (\) at
++the end of each line except the last.
++
++- Each entry has 3 or more fields, separated by whitespace (spaces
++and/or tabs). These fields are, in order:
++ * The name of the machine that is authenticating itself
++ (the &quot;client&quot;).
++ * The name of the machine that is authenticating the client
++ (the &quot;server&quot;).
++ * The secret to be used for authenticating that client to that
++ server. If this field begins with the at-sign `@', the rest
++ of the field is taken as the name of a file containing the
++ actual secret.
++ * The 4th and any following fields list the IP address(es)
++ that the client may use.
++
++- The file may contain comments, which begin with a `#' and continue
++to the end of the line.
++
++- Double quotes `&quot;' should be used around a field if it contains
++characters with special significance, such as space, tab, `#', etc.
++
++- The backslash `\' may be used before characters with special
++significance (space, tab, `#', `\', etc.) to remove that significance.
++
++Some important points to note:
++
++* A machine can be *both* a &quot;client&quot; and a &quot;server&quot; for the purposes
++of authentication - this happens when both peers require the other to
++authenticate itself. So A would authenticate itself to B, and B would
++also authenticate itself to A (possibly using a different
++authentication protocol).
++
++* If both the &quot;client&quot; and the &quot;server&quot; are running ppp-2.x, they need
++to have a similar entry in the appropriate secrets file; the first two
++fields are *not* swapped on the client, compared to the server. So
++the client might have an entry like this:
++
++ ay bee &quot;our little secret&quot; -
++
++and the corresponding entry on the server could look like this:
++
++ ay bee &quot;our little secret&quot; 123.45.67.89
++
++
++------------------------------------------------------------------------
++
++Q: Explain about PAP and CHAP?
++
++PAP stands for the Password Authentication Protocol. With this
++protocol, the &quot;client&quot; (the machine that needs to authenticate itself)
++sends its name and a password, in clear text, to the &quot;server&quot;. The
++server returns a message indicating whether the name and password are
++valid.
++
++CHAP stands for the Challenge Handshake Authentication Protocol. It
++is designed to address some of the deficiencies and vulnerabilities of
++PAP. Like PAP, it is based on the client and server having a shared
++secret, but the secret is never passed in clear text over the link.
++Instead, the server sends a &quot;challenge&quot; - an arbitrary string of
++bytes, and the client must prove it knows the shared secret by
++generating a hash value from the challenge combined with the shared
++secret, and sending the hash value back to the server. The server
++also generates the hash value and compares it with the value received
++from the client.
++
++At a practical level, CHAP can be slightly easier to configure than
++PAP because the server sends its name with the challenge. Thus, when
++finding the appropriate secret in the secrets file, the client knows
++the server's name. In contrast, with PAP, the client has to find its
++password (i.e. the shared secret) before it has received anything from
++the server. Thus, it may be necessary to use the `remotename' option
++to pppd when using PAP authentication so that it can select the
++appropriate secret from /etc/ppp/pap-secrets.
++
++Microsoft also has a variant of CHAP which uses a different hashing
++arrangement from normal CHAP. There is a client-side implementation
++of Microsoft's CHAP in ppp-2.3; see README.MSCHAP80.
++
++
++------------------------------------------------------------------------
++
++Q: When the modem hangs up, without the remote system having
++terminated the connection properly, pppd does not notice the hangup,
++but just keeps running. How do I get pppd to notice the hangup and
++exit?
++
++A: Pppd detects modem hangup by looking for an end-of-file indication
++from the serial driver, which should be generated when the CD (carrier
++detect) signal on the serial port is deasserted. For this to work:
++
++- The modem has to be set to assert CD when the connection is made and
++deassert it when the phone line hangs up. Usually the AT&amp;C1 modem
++command sets this mode.
++
++- The cable from the modem to the serial port must connect the CD
++signal (on pin 8).
++
++- Some serial drivers have a &quot;software carrier detect&quot; mode, which
++must be *disabled*. The method of doing this varies between systems.
++Under SunOS, use the ttysoftcar command. Under NetBSD, edit /etc/ttys
++to remove the &quot;softcar&quot; flag from the line for the serial port, and
++run ttyflags.
++
++
++------------------------------------------------------------------------
++
++Q: Why should I use PPP compression (BSD-Compress or Deflate) when my
++modem already does V.42 compression? Won't it slow the CPU down a
++lot?
++
++A: Using PPP compression is preferable, especially when using modems
++over phone lines, for the following reasons:
++
++- The V.42 compression in the modem isn't very strong - it's an LZW
++technique (same as BSD-Compress) with a 10, 11 or 12 bit code size.
++With BSD-Compress you can use a code size of up to 15 bits and get
++much better compression, or you can use Deflate and get even better
++compression ratios.
++
++- I have found that enabling V.42 compression in my 14.4k modem
++increases the round-trip time for a character to be sent, echoed and
++returned by around 40ms, from 160ms to 200ms (with error correction
++enabled). This is enough to make it feel less responsive on rlogin or
++telnet sessions. Using PPP compression adds less than 5ms (small
++enough that I couldn't measure it reliably). I admit my modem is a
++cheapie and other modems may well perform better.
++
++- While compression and decompression do require some CPU time, they
++reduce the amount of time spent in the serial driver to transmit a
++given amount of data. Many machines require an interrupt for each
++character sent or received, and the interrupt handler can take a
++significant amount of CPU time. So the increase in CPU load isn't as
++great as you might think. My measurements indicate that a system with
++a 33MHz 486 CPU should be able to do Deflate compression for serial
++link speeds of up to 100kb/s or more. It depends somewhat on the type
++of data, of course; for example, when compressing a string of nulls
++with Deflate, it's hard to get a high output data rate from the
++compressor, simply because it compresses strings of nulls so well that
++it has to eat a very large amount of input data to get each byte of
++output.
++
++
++------------------------------------------------------------------------
++
++Q: I get messages saying &quot;Unsupported protocol (...) received&quot;. What do
++these mean?
++
++A: If you only get one or two when pppd starts negotiating with the
++peer, they mean that the peer wanted to negotiate some PPP protocol
++that pppd doesn't understand. This doesn't represent a problem, it
++simply means that there is some functionality that the peer supports
++that pppd doesn't, so that functionality can't be used.
++
++If you get them sporadically while the link is operating, or if the
++protocol numbers (in parentheses) don't correspond to any valid PPP
++protocol that the peer might be using, then the problem is probably
++that characters are getting corrupted on the receive side, or that
++extra characters are being inserted into the receive stream somehow.
++If this is happening, most packets that get corrupted should get
++discarded by the FCS (Frame Check Sequence, a 16-bit CRC) check, but a
++small number may get through.
++
++One possibility may be that you are receiving broadcast messages on
++the remote system which are being sent over your serial link. Another
++possibility is that your modem is set for XON/XOFF (software) flow
++control and is inserting ^Q and ^S characters into the receive data
++stream.
++
++
++------------------------------------------------------------------------
++
++Q: I get messages saying &quot;Protocol-Reject for unsupported protocol ...&quot;.
++What do these mean?
++
++A: This is the other side of the previous question. If characters are
++getting corrupted on the way to the peer, or if your system is
++inserting extra bogus characters into the transmit data stream, the
++peer may send protocol-reject messages to you, resulting in the above
++message (since your pppd doesn't recognize the protocol number
++either.)
++
++
++------------------------------------------------------------------------
++
++Q: I get a message saying something like &quot;ioctl(TIOCSETD): Operation
++not permitted&quot;. How do I fix this?
++
++A: This is because pppd is not running as root. If you have not
++installed pppd setuid-root, you will have to be root to run it. If
++you have installed pppd setuid-root and you still get this message, it
++is probably because your shell is using some other copy of pppd than
++the installed one - for example, if you are in the pppd directory
++where you've just built pppd and your $PATH has . before /usr/sbin (or
++wherever pppd gets installed).
++
++
++------------------------------------------------------------------------
++
++Q: Has your package been ported to HP/UX or IRIX or AIX?
++
++A: No. I don't have access to systems running HP/UX or AIX. No-one
++has volunteered to port it to HP/UX. I had someone who did a port for
++AIX 4.x, but who is no longer able to maintain it. And apparently AIX
++3.x is quite different, so it would need a separate port.
++
++IRIX includes a good PPP implementation in the standard distribution,
++as far as I know.
++
++
++------------------------------------------------------------------------
++
++Q: Under SunOS 4, when I try to modload the ppp modules, I get the
++message &quot;can't open /dev/vd: No such device&quot;.
++
++A: First check in /dev that there is an entry like this:
++
++crw-r--r-- 1 root 57, 0 Oct 2 1991 vd
++
++If not, make one (mknod /dev/vd c 57 0). If the problem still exists,
++probably your kernel has been configured without the vd driver
++included. The vd driver is needed for loadable module support.
++
++First, identify the config file that was used. When you boot your
++machine, or if you run /etc/dmesg, you'll see a line that looks
++something like this:
++
++SunOS Release 4.1.3_U1 (CAP_XBOX) #7: Thu Mar 21 15:31:56 EST 1996
++ ^^^^^^^^
++ this is the config file name
++
++The config file will be in the /sys/`arch -k`/conf directory (arch -k
++should return sun4m for a SparcStation 10, sun3x for a Sun 3/80,
++etc.). Look in there for a line saying &quot;options VDDRV&quot;. If that line
++isn't present (or is commented out), add it (or uncomment it).
++
++You then need to rebuild the kernel as described in the SunOS
++manuals. Basically you need to run config and make like this:
++
++ /usr/etc/config CAP_XBOX
++ cd ../CAP_XBOX
++ make
++
++(replacing the string CAP_XBOX by the name of the config file for your
++kernel, of course).
++
++Then copy the new kernel to /:
++
++ mv /vmunix /vmunix.working
++ cp vmunix /
++
++and reboot. Modload should then work.
++
++
++------------------------------------------------------------------------
++
++Q: I'm running Linux (or NetBSD or FreeBSD), and my system comes with
++PPP already. Should I consider installing this package? Why?
++
++A: The PPP that is already installed in your system is (or is derived
++from) some version of this PPP package. You can find out what version
++of this package is already installed with the command &quot;pppd --help&quot;.
++If this is older than the latest version, you may wish to install the
++latest version so that you can take advantage of the new features or
++bug fixes.
++
++
++------------------------------------------------------------------------
++
++Q: I'm running pppd in demand mode, and I find that pppd often dials
++out unnecessarily when I try to make a connection within my local
++machine or with a machine on my local LAN. What can I do about this?
++
++A: Very often the cause of this is that a program is trying to contact
++a nameserver to resolve a hostname, and the nameserver (specified in
++/etc/resolv.conf, usually) is on the far side of the ppp link. You
++can try executing a command such as `ping myhost' (where myhost is the
++name of the local machine, or some other machine on a local LAN), to
++see whether that starts the ppp link. If it does, check the setup of
++your /etc/hosts file to make sure you have the local machine and any
++hosts on your local LAN listed, and /etc/resolv.conf and/or
++/etc/nsswitch.conf files to make sure you resolve hostnames from
++/etc/hosts if possible before trying to contact a nameserver.
++
++
++------------------------------------------------------------------------
++
++Q: Since I installed ppp-2.3.6, dialin users to my server have been
++getting this message when they run pppd:
++
++peer authentication required but no suitable secret(s) found for
++authenticating any peer to us (ispserver)
++
++A: In 2.3.6, the default is to let an unauthenticated peer only use IP
++addresses to which the machine doesn't already have a route. So on a
++machine with a default route, everyone has to authenticate. If you
++really don't want that, you can put `noauth' in the /etc/ppp/options
++file. Note that there is then no check on who is using which IP
++address. IMHO, this is undesirably insecure, but I guess it may be
++tolerable as long as you don't use any .rhosts files or anything like
++that. I recommend that you require dialin users to authenticate, even
++if just with PAP using their login password (using the `login' option
++to pppd). If you do use `noauth', you should at least have a pppusers
++group and set the permissions on pppd to allow only user and group to
++execute it.
++
++------------------------------------------------------------------------
++
++Q: When running pppd as a dial-in server, I often get the message
++&quot;LCP: timeout sending Config-Requests&quot; from pppd. It seems to be
++random, but dial-out always works fine. What is wrong?
++
++A: Most modern modems auto-detects the speed of the serial line
++between the modem and the computer. This auto-detection occurs when
++the computer sends characters to the modem, when the modem is in
++command mode. It does not occur when the modem is in data mode.
++Thus, if you send commands to the modem at 2400 bps, and then change
++the serial port speed to 115200 bps, the modem will not detect this
++change until something is transmitted from the computer to the modem.
++When running pppd in dial-in mode (i.e. without a connect script),
++pppd sets the speed of the serial port, but does not transmit
++anything. If the modem was already running at the specified speed,
++everything is fine, but if not, you will just receive garbage from the
++modem. To cure this, use an init script such as the following:
++
++ pppd ttyS0 115200 modem crtscts init &quot;chat '' AT OK&quot;
++
++To reset the modem and enable auto-answer, use:
++
++ pppd ttyS0 115200 modem crtscts init &quot;chat '' ATZ OK ATS0=1 OK&quot;
+
+Added: drakx/trunk/mdk-stage1/ppp/PLUGINS
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/PLUGINS (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/PLUGINS 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,131 @@
++Starting with version 2.3.10, pppd includes support for `plugins' -
++pieces of code which can be loaded into pppd at runtime and which can
++affect its behaviour in various ways. The idea of plugins is to
++provide a way for people to customize the behaviour of pppd without
++having to either apply local patches to each version or get their
++patches accepted into the standard distribution. My aim is that
++plugins will be able to be used with successive versions of pppd
++without needing to recompile the plugins.
++
++A plugin is a standard shared library object, typically with a name
++ending in .so. They are loaded using the standard dlopen() library
++call, so plugins are only supported on systems which support shared
++libraries and the dlopen call. At present pppd is compiled with
++plugin support only under Linux and Solaris.
++
++Plugins are loaded into pppd using the `plugin' option, which takes
++one argument, the name of a shared object file. The plugin option is
++a privileged option. I suggest that you give the full path name of
++the shared object file; if you don't, it may be possible for
++unscrupulous users to substitute another shared object file for the
++one you mean to load, e.g. by setting the LD_LIBRARY_PATH variable.
++
++Plugins are usually written in C and compiled and linked to a shared
++object file in the appropriate manner for your platform. Using gcc
++under Linux, a plugin called `xyz' could be compiled and linked with
++the following commands:
++
++ gcc -c -O xyz.c
++ gcc -shared -o xyz.so xyz.o
++
++There are some example plugins in the pppd/plugins directory in the
++ppp distribution. Currently there is one example, minconn.c, which
++implements a `minconnect' option, which specifies a minimum connect
++time before the idle timeout applies.
++
++Plugins can access global variables within pppd, so it is useful for
++them to #include &quot;pppd.h&quot; from the pppd source directory.
++
++Every plugin must contain a global procedure called `plugin_init'.
++This procedure will get called (with no arguments) immediately after
++the plugin is loaded.
++
++Plugins can affect the behaviour of pppd in at least three ways:
++
++1. They can add extra options which pppd will then recognize. This is
++ done by calling the add_options() procedure with a pointer to an
++ array of option_t structures. The last entry in the array must
++ have its name field set to NULL.
++
++2. Pppd contains `hook' variables which are procedure pointers. If a
++ given hook is not NULL, pppd will call the procedure it points to
++ at the appropriate point in its processing. The plugin can set any
++ of these hooks to point to its own procedures. See below for a
++ description of the hooks which are currently implemented.
++
++3. Plugin code can call any global procedures and access any global
++ variables in pppd.
++
++Here is a list of the currently implemented hooks in pppd.
++
++
++int (*idle_time_hook)(struct ppp_idle *idlep);
++
++The idle_time_hook is called when the link first comes up (i.e. when
++the first network protocol comes up) and at intervals thereafter. On
++the first call, the idlep parameter is NULL, and the return value is
++the number of seconds before pppd should check the link activity, or 0
++if there is to be no idle timeout.
++
++On subsequent calls, idlep points to a structure giving the number of
++seconds since the last packets were sent and received. If the return
++value is &gt; 0, pppd will wait that many seconds before checking again.
++If it is &lt;= 0, that indicates that the link should be terminated due
++to lack of activity.
++
++
++int (*holdoff_hook)(void);
++
++The holdoff_hook is called when an attempt to bring up the link fails,
++or the link is terminated, and the persist or demand option was used.
++It returns the number of seconds that pppd should wait before trying
++to reestablish the link (0 means immediately).
++
++
++int (*pap_check_hook)(void);
++int (*pap_passwd_hook)(char *user, char *passwd);
++int (*pap_auth_hook)(char *user, int userlen,
++ char *passwd, int passlen,
++ char **msgp, int *msglenp,
++ struct wordlist **paddrs,
++ struct wordlist **popts);
++
++These hooks are designed to allow a plugin to replace the normal PAP
++password processing in pppd with something different (e.g. contacting
++an external server).
++
++The pap_check_hook is called to check whether there is any possibility
++that the peer could authenticate itself to us. If it returns 1, pppd
++will ask the peer to authenticate itself. If it returns 0, pppd will
++not ask the peer to authenticate itself (but if authentication is
++required, pppd may exit, or terminate the link before network protocol
++negotiation). If it returns -1, pppd will look in the pap-secrets
++file as it would normally.
++
++The pap_passwd_hook is called to determine what username and password
++pppd should use in authenticating itself to the peer with PAP. The
++user string will already be initialized, by the `user' option, the
++`name' option, or from the hostname, but can be changed if necessary.
++MAXNAMELEN bytes of space are available at *user, and MAXSECRETLEN
++bytes of space at *passwd. If this hook returns 0, pppd will use the
++values at *user and *passwd; if it returns -1, pppd will look in the
++pap-secrets file, or use the value from the +ua or password option, as
++it would normally.
++
++The pap_auth_hook is called to determine whether the username and
++password supplied by the peer are valid. user and passwd point to
++null-terminated strings containing the username and password supplied
++by the peer, with non-printable characters converted to a printable
++form. The pap_auth_hook function should set msg to a string to be
++returned to the peer and return 1 if the username/password was valid
++and 0 if not. If the hook returns -1, pppd will look in the
++pap-secrets file as usual.
++
++If the username/password was valid, the hook can set *paddrs to point
++to a wordlist containing the IP address(es) which the peer is
++permitted to use, formatted as in the pap-secrets file. It can also
++set *popts to a wordlist containing any extra options for this user
++which pppd should apply at this point.
++
++
++## $Id: PLUGINS 195720 2001-06-11 11:44:34Z gc $ ##
+
+Added: drakx/trunk/mdk-stage1/ppp/README
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/README (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/README 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,168 @@
++This is the README file for ppp-2.4, a package which implements the
++Point-to-Point Protocol (PPP) to provide Internet connections over
++serial lines.
++
++
++Introduction.
++*************
++
++The Point-to-Point Protocol (PPP) provides a standard way to establish
++a network connection over a serial link. At present, this package
++supports IP and the protocols layered above IP, such as TCP and UDP.
++The Linux and Solaris ports of this package have optional support for
++IPV6; the Linux port of this package also has support for IPX.
++
++This software consists of two parts:
++
++- Kernel code, which establishes a network interface and passes
++packets between the serial port, the kernel networking code and the
++PPP daemon (pppd). This code is implemented using STREAMS modules on
++SunOS 4.x and Solaris, and as a line discipline under Linux and FreeBSD.
++
++- The PPP daemon (pppd), which negotiates with the peer to establish
++the link and sets up the ppp network interface. Pppd includes support
++for authentication, so you can control which other systems may make a
++PPP connection and what IP addresses they may use.
++
++The primary platforms supported by this package are Linux and Solaris.
++Code for SunOS 4.x is included here but is largely untested. I have
++code for NeXTStep, FreeBSD, SVR4, Tru64 (Digital Unix), AIX and Ultrix
++but no active maintainers for these platforms. Code for all of these
++except AIX is included in the ppp-2.3.11 release.
++
++
++Installation.
++*************
++
++The file SETUP contains general information about setting up your
++system for using PPP. There is also a README file for each supported
++system, which contains more specific details for installing PPP on
++that system. The supported systems, and the corresponding README
++files, are:
++
++ Linux README.linux
++ Solaris 2 README.sol2
++ SunOS 4.x README.sunos4
++
++In each case you start by running the ./configure script. This works
++out which operating system you are using and creates symbolic links to
++the appropriate makefiles. You then run `make' to compile the
++user-level code, and (as root) `make install' to install the
++user-level programs pppd, chat and pppstats.
++
++N.B. Since 2.3.0, leaving the permitted IP addresses column of the
++pap-secrets or chap-secrets file empty means that no addresses are
++permitted. You need to put a &quot;*&quot; in that column to allow the peer to
++use any IP address. (This only applies where the peer is
++authenticating itself to you, of course.)
++
++
++What's new in ppp-2.4.1.
++************************
++
++* Pppd can now print out the set of options that are in effect. The
++ new `dump' option causes pppd to print out the option values after
++ option parsing is complete. The `dryrun' option causes pppd to
++ print the options and then exit.
++
++* The option parsing code has been fixed so that options in the
++ per-tty options file are parsed correctly, and don't override values
++ from the command line in most cases.
++
++* The plugin option now looks in /usr/lib/pppd/&lt;pppd-version&gt; (for
++ example, /usr/lib/pppd/2.4.1b1) for shared objects for plugins if
++ there is no slash in the plugin name.
++
++* When loading a plugin, pppd will now check the version of pppd for
++ which the plugin was compiled, and refuse to load it if it is
++ different to pppd's version string. To enable this, the plugin
++ source needs to #include &quot;pppd.h&quot; and have a line saying:
++ char pppd_version[] = VERSION;
++
++* There is a bug in zlib, discovered by James Carlson, which can cause
++ kernel memory corruption if Deflate is used with the lowest setting,
++ 8. As a workaround pppd will now insist on using at least 9.
++
++* Pppd should compile on Solaris and SunOS again.
++
++* Pppd should now set the MTU correctly on demand-dialled interfaces.
++
++
++What was new in ppp-2.4.0.
++**************************
++
++* Multilink: this package now allows you to combine multiple serial
++ links into one logical link or `bundle', for increased bandwidth and
++ reduced latency. This is currently only supported under the
++ Linux-2.3.99pre5 or later kernels.
++
++* All the pppd processes running on a system now write information
++ into a common database. I used the `tdb' code from samba for this.
++
++* New hooks have been added.
++
++For a list of the changes made during the 2.3 series releases of this
++package, see the Changes-2.3 file.
++
++
++Compression methods.
++********************
++
++This package supports two packet compression methods: Deflate and
++BSD-Compress. Other compression methods which are in common use
++include Predictor, LZS, and MPPC. These methods are not supported for
++two reasons - they are patent-encumbered, and they cause some packets
++to expand slightly, which pppd doesn't currently allow for.
++BSD-Compress is also patent-encumbered (its inclusion in this package
++can be considered a historical anomaly :-) but it doesn't ever expand
++packets. Neither does Deflate, which uses the same algorithm as gzip.
++
++
++Patents.
++********
++
++The BSD-Compress algorithm used for packet compression is the same as
++that used in the Unix &quot;compress&quot; command. It is apparently covered by
++U.S. patents 4,814,746 (owned by IBM) and 4,558,302 (owned by Unisys),
++and corresponding patents in various other countries (but not
++Australia). If this is of concern, you can build the package without
++including BSD-Compress. To do this, edit net/ppp-comp.h to change the
++definition of DO_BSD_COMPRESS to 0. The bsd-comp.c files are then no
++longer needed, so the references to bsd-comp.o may optionally be
++removed from the Makefiles.
++
++
++Contacts.
++*********
++
++The comp.protocols.ppp newsgroup is a useful place to get help if you
++have trouble getting your ppp connections to work. Please do not send
++me questions of the form &quot;please help me get connected to my ISP&quot; -
++I'm sorry, but I simply do not have the time to answer all the
++questions like this that I get.
++
++If you find bugs in this package, please report them to the maintainer
++for the port for the operating system you are using:
++
++Linux Paul Mackerras &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">paulus at linuxcare.com</A>&gt;
++Solaris 2 James Carlson &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">james.d.carlson at east.sun.com</A>&gt;
++SunOS 4.x Adi Masputra &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">adi.masputra at sun.com</A>&gt;
++
++
++Copyrights:
++***********
++
++All of the code can be freely used and redistributed. The individual
++source files each have their own copyright and permission notice; some
++have a BSD-style notice and some are under the GPL.
++
++
++Distribution:
++*************
++
++The primary site for releases of this software is:
++
++ <A HREF="ftp://linuxcare.com.au/pub/ppp/">ftp://linuxcare.com.au/pub/ppp/</A>
++
++
++($Id: README 195720 2001-06-11 11:44:34Z gc $)
+
+Added: drakx/trunk/mdk-stage1/ppp/README.MSCHAP80
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/README.MSCHAP80 (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/README.MSCHAP80 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,284 @@
++PPP Client Support for Microsoft's CHAP-80
++==========================================
++
++Eric Rosenquist <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">rosenqui at strataware.com</A>
++(updated by Paul Mackerras)
++(updated by Al Longyear)
++(updated by Farrell Woods)
++
++INTRODUCTION
++
++Microsoft has introduced an extension to the Challenge/Handshake
++Authentication Protocol (CHAP) which avoids storing cleartext
++passwords on a server. (Unfortunately, this is not as secure as it
++sounds, because the encrypted password stored on a server can be used
++by a bogus client to gain access to the server just as easily as if
++the password were stored in cleartext.) The details of the Microsoft
++extensions can be found in the document:
++
++ &lt;<A HREF="ftp://ftp.microsoft.com/developr/rfc/chapexts.txt">ftp://ftp.microsoft.com/developr/rfc/chapexts.txt</A>&gt;
++
++In short, MS-CHAP is identified as &lt;auth chap 80&gt; since the hex value
++of 80 is used to designate Microsoft's scheme. Standard PPP CHAP uses
++a value of 5. If you enable PPP debugging with the &quot;debug&quot; option and
++see something like the following in your logs, the remote server is
++requesting MS-CHAP:
++
++ rcvd [LCP ConfReq id=0x2 &lt;asyncmap 0x0&gt; &lt;auth chap 80&gt; &lt;magic 0x46a3&gt;]
++ ^^^^^^^^^^^^
++
++The standard pppd implementation will indicate its lack of support for
++MS-CHAP by NAKing it:
++
++ sent [LCP ConfNak id=0x2 &lt;auth chap 05&gt;]
++
++Windows NT Server systems are often configured to &quot;Accept only
++Microsoft Authentication&quot; (this is intended to enhance security). Up
++until now, that meant that you couldn't use this version of PPPD to
++connect to such a system. I've managed to get a client-only
++implementation of MS-CHAP working; it will authenticate itself to
++another system using MS-CHAP, but if you're using PPPD as a dial-in
++server, you won't be able to use MS-CHAP to authenticate the clients.
++This would not be a lot of extra work given that the framework is in
++place, but I didn't need it myself so I didn't implement it.
++
++
++BUILDING THE PPPD
++
++MS-CHAP uses a combination of MD4 hashing and DES encryption for
++authentication. You may need to get Eric Young's libdes library in
++order to use my MS-CHAP extensions. A lot of UNIX systems already
++have DES encryption available via the crypt(3), encrypt(3) and
++setkey(3) interfaces. Some may (such as that on Digital UNIX)
++provide only the encryption mechanism and will not perform
++decryption. This is okay. We only need to encrypt to perform
++MS-CHAP authentication.
++
++If you have encrypt/setkey available, then hopefully you need only
++define these two things in your Makefile: -DUSE_CRYPT and -DCHAPMS.
++Skip the paragraphs below about obtaining and building libdes. Do
++the &quot;make clean&quot; and &quot;make&quot; as described below. Linux users
++should not need to modify their Makefiles. Instead,
++just do &quot;make CHAPMS=1 USE_CRYPT=1&quot;.
++
++If you don't have encrypt and setkey, you will need Eric Young's
++libdes library. You can find it in:
++
++<A HREF="ftp://ftp.funet.fi/pub/crypt/mirrors/ftp.psy.uq.oz.au/DES/libdes-3.06.tar.gz">ftp://ftp.funet.fi/pub/crypt/mirrors/ftp.psy.uq.oz.au/DES/libdes-3.06.tar.gz</A>
++
++Australian residents can get libdes from Eric Young's site:
++
++<A HREF="ftp://ftp.psy.uq.oz.au/pub/Crypto/DES/libdes-3.06.tar.gz">ftp://ftp.psy.uq.oz.au/pub/Crypto/DES/libdes-3.06.tar.gz</A>
++
++It is also available on many other sites (ask Archie).
++
++I used libdes-3.06, but hopefully anything newer than that will work
++also. Get the library, build and test it on your system, and install
++it somewhere (typically /usr/local/lib and /usr/local/include).
++
++
++
++You should now be ready to (re)compile the PPPD. Go to the pppd
++subdirectory and make sure the Makefile contains &quot;-DCHAPMS&quot; in the
++CFLAGS or COMPILE_FLAGS macro, and that the LIBS macro (or LDADD for
++BSD systems) contains &quot;-ldes&quot;. Depending on your system and where the
++DES library was installed, you may also need to alter the include and
++library paths used by your compiler.
++
++Do a &quot;make clean&quot; and then a &quot;make&quot; to rebuild pppd. Assuming all
++goes well, install the new pppd and move on to the CONFIGURATION
++section.
++
++
++CONFIGURATION
++
++If you've never used PPPD with CHAP before, read the man page (type
++&quot;man pppd&quot;) and read the description in there. Basically, you need to
++edit the &quot;chap-secrets&quot; file typically named /etc/ppp/chap-secrets.
++This should contain the following two lines for each system with which
++you use CHAP (with no leading blanks):
++
++ RemoteHost Account Secret
++ Account RemoteHost Secret
++
++Note that you need both lines and that item 1 and 2 are swapped in the
++second line. I'm not sure why you need it twice, but it works and I didn't
++have time to look into it further. The &quot;RemoteHost&quot; is a somewhat
++arbitrary name for the remote Windows NT system you're dialing. It doesn't
++have to match the NT system's name, but it *does* have to match what you
++use with the &quot;remotename&quot; parameter. The &quot;Account&quot; is the Windows NT
++account name you have been told to use when dialing, and the &quot;Secret&quot; is
++the password for that account. For example, if your service provider calls
++their machine &quot;DialupNT&quot; and tells you your account and password are
++&quot;customer47&quot; and &quot;foobar&quot;, add the following to your chap-secrets file:
++
++ DialupNT customer47 foobar
++ customer47 DialupNT foobar
++
++The only other thing you need to do for MS-CHAP (compared to normal CHAP)
++is to always use the &quot;remotename&quot; option, either on the command line or in
++your &quot;options&quot; file (see the pppd man page for details). In the case of
++the above example, you would need to use the following command line:
++
++ pppd name customer47 remotename DialupNT &lt;other options&gt;
++
++or add:
++
++ name customer47
++ remotename DialupNT
++
++to your PPPD &quot;options&quot; file.
++
++The &quot;remotename&quot; option is required for MS-CHAP since Microsoft PPP servers
++don't send their system name in the CHAP challenge packet.
++
++
++E=691 (AUTHENTICATION_FAILURE) ERRORS WHEN YOU HAVE THE VALID SECRET (PASSWORD)
++
++If your RAS server is not the domain controller and is not a 'stand-alone'
++server then it must make a query to the domain controller for your domain.
++
++You need to specify the domain name with the user name when you attempt to
++use this type of a configuration. The domain name is specified with the
++local name in the chap-secrets file and with the option for the 'name'
++parameter.
++
++For example, the previous example would become:
++
++ DialupNT domain\\customer47 foobar
++ domain\\customer47 DialupNT foobar
++
++and
++
++ pppd name 'domain\\customer47' remotename DialupNT &lt;other options&gt;
++
++or add:
++
++ name domain\\customer47
++ remotename DialupNT
++
++when the Windows NT domain name is simply called 'domain'.
++
++
++TROUBLESHOOTING
++
++Assuming that everything else has been configured correctly for PPP and
++CHAP, the MS-CHAP-specific problems you're likely to encounter are mostly
++related to your Windows NT account and its settings. A Microsoft server
++returns error codes in its CHAP response. The following are extracted from
++Microsoft's &quot;chapexts.txt&quot; file referenced above:
++
++ 646 ERROR_RESTRICTED_LOGON_HOURS
++ 647 ERROR_ACCT_DISABLED
++ 648 ERROR_PASSWD_EXPIRED
++ 649 ERROR_NO_DIALIN_PERMISSION
++ 691 ERROR_AUTHENTICATION_FAILURE
++ 709 ERROR_CHANGING_PASSWORD
++
++You'll see these in your pppd log as a line similar to:
++
++ Remote message: E=649 R=0
++
++The &quot;E=&quot; is the error number from the table above, and the &quot;R=&quot; flag
++indicates whether the error is transient and the client should retry. If
++you consistently get error 691, then either you're using the wrong account
++name/password, or the DES library or MD4 hashing (in md4.c) aren't working
++properly. Verify your account name and password (use a Windows NT or
++Windows 95 system to dial-in if you have one available). If that checks
++out, test the DES library with the &quot;destest&quot; program included with the DES
++library. If DES checks out, the md4.c routines are probably failing
++(system byte ordering may be a problem) or my code is screwing up. I've
++only got access to a Linux system, so you're on your own for anything else.
++
++Another thing that might cause problems is that some RAS servers won't
++respond at all to LCP config requests without seeing the word &quot;CLIENT&quot;
++from the other end. If you see pppd sending out LCP config requests
++without getting any reply, try putting something in your chat script
++to send the word CLIENT after the modem has connected.
++
++If everything compiles cleanly, but fails at authentication time, then
++it might be a case of the MD4 or DES code screwing up. The following
++small program can be used to test the MS-CHAP code to see if it
++produces a known response:
++
++-----------------
++#include &lt;stdio.h&gt;
++
++#include &quot;pppd.h&quot;
++#include &quot;chap.h&quot;
++#include &quot;chap_ms.h&quot;
++
++int main(argc, argv)
++ int argc;
++ char *argv[];
++{
++ u_char challenge[8];
++ int challengeInt[sizeof(challenge)];
++ chap_state cstate;
++ int i;
++
++ if (argc != 3) {
++ fprintf(stderr, &quot;Usage: %s &lt;16-hexchar challenge&gt; &lt;password&gt;\n&quot;,
++ argv[0]); exit(1);
++ }
++
++ sscanf(argv[1], &quot;%2x%2x%2x%2x%2x%2x%2x%2x&quot;,
++ challengeInt + 0, challengeInt + 1, challengeInt + 2,
++ challengeInt + 3, challengeInt + 4, challengeInt + 5,
++ challengeInt + 6, challengeInt + 7);
++
++ for (i = 0; i &lt; sizeof(challenge); i++)
++ challenge[i] = (u_char)challengeInt[i];
++
++ ChapMS(&amp;cstate, challenge, sizeof(challenge), argv[2], strlen(argv[2]));
++ printf(&quot;Response length is %d, response is:&quot;, cstate.resp_length);
++
++ for (i = 0; i &lt; cstate.resp_length; i++) {
++ if (i % 8 == 0)
++ putchar('\n');
++ printf(&quot;%02X &quot;, (unsigned int)cstate.response[i]);
++ }
++
++ putchar('\n');
++
++ exit(0);
++}
++-------------
++
++This needs to link against chap_ms.o, md4.o, and the DES library. When
++you run it with the command line:
++
++ $ testchap 00000000000000000000000000000000 hello
++
++it should output the following:
++
++ Response length is 49, response is:
++ 00 00 00 00 00 00 00 00
++ 00 00 00 00 00 00 00 00
++ 00 00 00 00 00 00 00 00
++ F4 D9 9D AF 82 64 DC 3C
++ 53 F9 BC 92 14 B5 5D 9E
++ 78 C4 21 48 9D B7 A8 B4
++ 01
++
++if not, then either the DES library is not working, the MD4 code isn't
++working, or there are some problems with the port of the code in
++chap_ms.c.
++
++
++STILL TO DO
++
++A site using only MS-CHAP to authenticate has no need to store cleartext
++passwords in the &quot;chap-secrets&quot; file. A utility that spits out the ASCII
++hex MD4 hash of a given password would be nice, and would allow that hash
++to be used in chap-secrets in place of the password. The code to do this
++could quite easily be lifted from chap_ms.c (you have to convert the
++password to Unicode before hashing it). The chap_ms.c file would also have
++to be changed to recognize a password hash (16 binary bytes == 32 ASCII hex
++characters) and skip the hashing stage.
++
++A server implementation would allow MS-CHAP to be used with Windows NT and
++Windows 95 clients for enhanced security. Some new command-line options
++would be required, as would code to generate the Challenge packet and
++verify the response. Most of the helper functions are in place, so this
++shouldn't be too hard for someone to add.
+
+Added: drakx/trunk/mdk-stage1/ppp/README.cbcp
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/README.cbcp (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/README.cbcp 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,97 @@
++ Microsoft Call Back Configuration Protocol.
++ by Pedro Roque Marques
++ (updated by Paul Mackerras)
++
++The CBCP is a method by which the Microsoft Windows NT Server may
++implement additional security. It is possible to configure the server
++in such a manner so as to require that the client systems which
++connect with it are required that following a valid authentication to
++leave a method by which the number may be returned call.
++
++It is a requirement of servers so configured that the protocol be
++exchanged.
++
++So, this set of patches may be applied to the pppd process to enable
++the cbcp client *only* portion of the specification. It is primarily
++meant to permit connection with Windows NT Servers.
++
++The ietf-working specification may be obtained from ftp.microsoft.com
++in the developr/rfc directory.
++
++The ietf task group has decided to recommend that the LCP sequence be
++extended to permit the callback operation. For this reason, these
++patches are not 'part' of pppd but are an adjunct to the code.
++
++To enable CBCP support, all that is required is to change the
++appropriate Makefile in the pppd subdirectory to add &quot;-DCBCP_SUPPORT&quot;
++to the CFLAGS definition and add cbcp.o to the list of object files,
++and then recompile pppd. The patch below does this for Makefile.bsd
++and Makefile.linux.
++
++
++--------------------------------cut here-------------------------------
++diff -r -c ppp-2.3.orig/pppd/Makefile.bsd ppp-2.3/pppd/Makefile.bsd
++*** ppp-2.3.orig/pppd/Makefile.bsd Tue Oct 8 13:33:33 1996
++--- ppp-2.3/pppd/Makefile.bsd Fri Apr 11 23:59:15 1997
++***************
++*** 4,14 ****
++ # -D_BITYPES is for FreeBSD, which doesn't define anything to
++ # tell us that u_int32_t gets defined if &lt;sys/types.h&gt; is included.
++ # Remove for older *BSD systems for which this isn't true.
++! CFLAGS+= -g -I.. -DHAVE_PATHS_H -D_BITYPES
++
++ PROG= pppd
++ SRCS= main.c magic.c fsm.c lcp.c ipcp.c upap.c chap.c md5.c ccp.c \
++! demand.c auth.c options.c sys-bsd.c
++ MAN= pppd.cat8
++ MAN8= pppd.8
++ BINMODE=4555
++--- 4,14 ----
++ # -D_BITYPES is for FreeBSD, which doesn't define anything to
++ # tell us that u_int32_t gets defined if &lt;sys/types.h&gt; is included.
++ # Remove for older *BSD systems for which this isn't true.
++! CFLAGS+= -I.. -DHAVE_PATHS_H -D_BITYPES -DCBCP_SUPPORT
++
++ PROG= pppd
++ SRCS= main.c magic.c fsm.c lcp.c ipcp.c upap.c chap.c md5.c ccp.c \
++! demand.c auth.c options.c sys-bsd.c cbcp.c
++ MAN= pppd.cat8
++ MAN8= pppd.8
++ BINMODE=4555
++diff -r -c ppp-2.3.orig/pppd/Makefile.linux ppp-2.3/pppd/Makefile.linux
++*** ppp-2.3.orig/pppd/Makefile.linux Tue Oct 8 15:42:41 1996
++--- ppp-2.3/pppd/Makefile.linux Sat Apr 12 00:02:28 1997
++***************
++*** 14,20 ****
++ ipxcp.h cbcp.h
++ MANPAGES = pppd.8
++ PPPDOBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap.o md5.o ccp.o \
++! auth.o options.o demand.o sys-linux.o ipxcp.o
++
++ all: pppd
++
++--- 14,20 ----
++ ipxcp.h cbcp.h
++ MANPAGES = pppd.8
++ PPPDOBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap.o md5.o ccp.o \
++! auth.o options.o demand.o sys-linux.o ipxcp.o cbcp.o
++
++ all: pppd
++
++***************
++*** 36,42 ****
++ #INCLUDE_DIRS= -I/usr/include -I..
++ INCLUDE_DIRS=
++
++! COMPILE_FLAGS= -D_linux_=1 -DHAVE_PATHS_H -DIPX_CHANGE
++
++ CFLAGS= $(COPTS) $(COMPILE_FLAGS) $(INCLUDE_DIRS)
++
++--- 36,42 ----
++ #INCLUDE_DIRS= -I/usr/include -I..
++ INCLUDE_DIRS=
++
++! COMPILE_FLAGS= -D_linux_=1 -DHAVE_PATHS_H -DIPX_CHANGE -DCBCP_SUPPORT
++
++ CFLAGS= $(COPTS) $(COMPILE_FLAGS) $(INCLUDE_DIRS)
++
+
+Added: drakx/trunk/mdk-stage1/ppp/README.linux
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/README.linux (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/README.linux 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,297 @@
++ PPP for Linux
++ -------------
++
++ Paul Mackerras
++ 8 March 2001
++
++ for ppp-2.4.1
++
++1. Introduction
++---------------
++
++The Linux PPP implementation includes both kernel and user-level
++parts. This package contains the user-level part, which consists of
++the PPP daemon (pppd) and associated utilities. In the past this
++package has contained updated kernel drivers. This is no longer
++necessary, as the current 2.2 and 2.4 kernel sources contain
++up-to-date drivers.
++
++The Linux PPP implementation is capable of being used both for
++initiating PPP connections (as a `client') or for handling incoming
++PPP connections (as a `server'). Note that this is an operational
++distinction, based on how the connection is created, rather than a
++distinction that is made in the PPP protocols themselves.
++
++Mostly this package is used for PPP connections over modems connected
++via asynchronous serial ports, so this guide concentrates on this
++situation.
++
++The PPP protocol consists of two parts. One is a scheme for framing
++and encoding packets, the other is a series of protocols called LCP,
++IPCP, PAP and CHAP, for negotiating link options and for
++authentication. This package similarly consists of two parts: a
++kernel module which handles PPP's low-level framing protocol, and a
++user-level program called pppd which implements PPP's negotiation
++protocols.
++
++The kernel module assembles/disassembles PPP frames, handles error
++detection, and forwards packets between the serial port and either the
++kernel network code or the user-level program pppd. IP packets go
++directly to the kernel network code. So once pppd has negotiated the
++link, it in practice lies completely dormant until you want to take
++the link down, when it negotiates a graceful disconnect.
++
++
++2. Installation
++---------------
++
++2.1 Kernel driver
++
++Assuming you are running a recent 2.2 or 2.4 (or later) series kernel,
++the kernel source code will contain an up-to-date kernel PPP driver.
++If the PPP driver was included in your kernel configuration when your
++kernel was built, then you only need to install the user-level
++programs. Otherwise you will need to get the source tree for your
++kernel version, configure it with PPP included, and recompile. Most
++Linux distribution vendors ship kernels with PPP included in the
++configuration.
++
++The PPP driver can be either compiled into the kernel or compiled as a
++kernel module. If it is compiled into the kernel, the PPP driver is
++included in the kernel image which is loaded at boot time. If it is
++compiled as a module, the PPP driver is present in one or more files
++under /lib/modules and is loaded into the kernel when needed.
++
++The 2.2 series kernels contain an older version of the kernel PPP
++driver, one which doesn't support multilink. If you want multilink,
++you need to run the latest 2.4 series kernel. The kernel PPP driver
++was completely rewritten for the 2.4 series kernels to support
++multilink and to allow it to operate over diverse kinds of
++communication medium (the 2.2 driver only operates over serial ports
++and devices which look like serial ports, such as pseudo-ttys).
++
++Under the 2.2 kernels, if PPP is compiled as a module, the PPP driver
++modules should be present in the /lib/modules/`uname -r`/net directory
++(where `uname -r` represents the kernel version number). The PPP
++driver module itself is called ppp.o, and there will usually be
++compression modules there, ppp_deflate.o and bsd_comp.o, as well as
++slhc.o, which handles TCP/IP header compression. If the PPP driver is
++compiled into the kernel, the compression code will still be compiled
++as modules, for kernels before 2.2.17pre12. For 2.2.17pre12 and later,
++if the PPP driver is compiled in, the compression code will also.
++
++Under the 2.4 kernels, there are two PPP modules, ppp_generic.o and
++ppp_async.o, plus the compression modules (ppp_deflate.o, bsd_comp.o
++and slhc.o). If the PPP generic driver is compiled into the kernel,
++the other four can then be present either as modules or compiled into
++the kernel. There is a sixth module, ppp_synctty.o, which is used for
++synchronous tty devices such as high-speed WAN adaptors.
++
++
++2.2 User-level programs
++
++If you obtained this package in .rpm or .deb format, you simply follow
++the usual procedure for installing the package.
++
++If you are using the .tar.gz form of this package, then cd into the
++ppp-2.4.1b1 directory you obtained by unpacking the archive and issue
++the following commands:
++
++$ ./configure
++$ make
++# make install
++
++The `make install' has to be done as root. This makes and installs
++four programs and their man pages: pppd, chat, pppstats and pppdump.
++If the /etc/ppp configuration directory doesn't exist, the `make
++install' step will create it and install some default configuration
++files.
++
++
++2.3 System setup for 2.4 kernels
++
++Under the 2.4 series kernels, pppd needs to be able to open /dev/ppp,
++character device (108,0). If you are using devfs (the device
++filesystem), the /dev/ppp node will automagically appear when the
++ppp_generic module is loaded, or at startup if ppp_generic is compiled
++in.
++
++If you have ppp_generic as a module, and you are using devfsd (the
++devfs daemon), you will need to add a line like this to your
++/etc/devfsd.conf:
++
++LOOKUP ppp MODLOAD
++
++Otherwise you will need to create a /dev/ppp device node with the
++commands:
++
++# mknod /dev/ppp c 108 0
++# chmod 600 /dev/ppp
++
++If you use module autoloading and have PPP as a module, you will need
++to add the following to your /etc/modules.conf or /etc/conf.modules:
++
++alias /dev/ppp ppp_generic
++alias char-major-108 ppp_generic
++alias tty-ldisc-3 ppp_async
++alias tty-ldisc-14 ppp_synctty
++alias ppp-compress-21 bsd_comp
++alias ppp-compress-24 ppp_deflate
++alias ppp-compress-26 ppp_deflate
++
++
++2.4 System setup under 2.2 series kernels
++
++Under the 2.2 series kernels, you should add the following to your
++/etc/modules.conf or /etc/conf.modules:
++
++alias tty-ldisc-3 ppp
++alias ppp-compress-21 bsd_comp
++alias ppp-compress-24 ppp_deflate
++alias ppp-compress-26 ppp_deflate
++
++
++3. Getting help with problems
++-----------------------------
++
++If you have problems with your PPP setup, or you just want to ask some
++questions, or better yet if you can help others with their PPP
++questions, then you should join the linux-ppp mailing list. Send an
++email to <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">majordomo at vger.kernel.org</A> with a line in the body saying
++
++subscribe linux-ppp
++
++To leave the mailing list, send an email to <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">majordomo at vger.kernel.org</A>
++with a line in the body saying
++
++unsubscribe linux-ppp
++
++To send a message to the list, email it to <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">linux-ppp at vger.kernel.org.</A>
++You don't have to be subscribed to send messages to the list.
++
++You can also email me (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">paulus at linuxcare.com.au</A>) but I am overloaded
++with email and I can't respond to most messages I get in a timely
++fashion.
++
++There are also several relevant news groups, such as comp.protocols.ppp,
++comp.os.linux.networking, or comp.os.linux.setup.
++
++
++4. Configuring your dial-out PPP connections
++--------------------------------------------
++
++Some Linux distribution makers include tools in their distributions
++for setting up PPP connections. For example, for Red Hat Linux and
++derivatives, you should probably use linuxconf or netcfg to set up
++your PPP connections.
++
++The two main windowing environments for Linux, KDE and Gnome, both
++come with GUI utilities for configuring and controlling PPP dial-out
++connections. They are convenient and relatively easy to configure.
++
++A third alternative is to use a PPP front-end package such as wvdial
++or ezppp. These also will handle most of the details of talking to
++the modem and setting up the PPP connection for you.
++
++Assuming that you don't want to use any of these tools, you want to
++set up the configuration manually yourself, then read on. This
++document gives a brief description and example. More details can be
++found by reading the pppd and chat man pages and the PPP-HOWTO.
++
++We assume that you have a modem that uses the Hayes-compatible AT
++command set connected to an async serial port (e.g. /dev/ttyS0) and
++that you are dialling out to an ISP.
++
++The trickiest and most variable part of setting up a dial-out PPP
++connection is the part which involves getting the modem to dial and
++then invoking PPP service at the far end. Generally, once both ends
++are talking PPP the rest is relatively straightforward.
++
++Now in fact pppd doesn't know anything about how to get modems to dial
++or what you have to say to the system at the far end to get it to talk
++PPP. That's handled by an external program such as chat, specified
++with the connect option to pppd. Chat takes a series of strings to
++expect from the modem interleaved with a series of strings to send to
++the modem. See the chat man page for more information. Here is a
++simple example for connecting to an ISP, assuming that the ISP's
++system starts talking PPP as soon as it answers the phone:
++
++pppd connect 'chat -v &quot;&quot; AT OK ATDT5551212 ~' \
++ /dev/ttyS0 57600 crtscts debug defaultroute
++
++Going through pppd's options in order:
++ connect 'chat ...' This gives a command to run to contact the
++ PPP server. Here the supplied 'chat' program is used to dial a
++ remote computer. The whole command is enclosed in single quotes
++ because pppd expects a one-word argument for the 'connect' option.
++ The options to 'chat' itself are:
++
++ -v verbose mode; log what we do to syslog
++ &quot;&quot; don't wait for any prompt, but instead...
++ AT send the string &quot;AT&quot;
++ OK expect the response &quot;OK&quot;, then
++ ATDT5551212 dial the modem, then
++ ~ wait for a ~ character, indicating the start
++ of a PPP frame from the server
++
++ /dev/ttyS0 specifies which serial port the modem is connected to
++ 57600 specifies the baud rate to use
++ crtscts use hardware flow control using the RTS &amp; CTS signals
++ debug log the PPP negotiation with syslog
++ defaultroute add default network route via the PPP link
++
++Pppd will write error messages and debugging logs to the syslogd
++daemon using the facility name &quot;daemon&quot;. These messages may already
++be logged to the console or to a file like /var/log/messages; consult
++your /etc/syslog.conf file to see. If you want to make all pppd
++messages go to a file such as /var/log/ppp-debug, add the line
++
++daemon.* /var/log/ppp-debug
++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++ This is one or more tabs. Do not use spaces.
++
++to syslog.conf; make sure to put one or more TAB characters (not
++spaces!) between the two fields. Then you need to create an empty
++/var/log/ppp-debug file with a command such as
++
++ touch /var/log/ppp-debug
++
++and then restart syslogd, usually by sending it a SIGHUP signal with a
++command like this:
++
++ killall -HUP syslogd
++
++
++4.1 Is the link up?
++
++The main way to tell if your PPP link is up and operational is the
++ifconfig (&quot;interface configuration&quot;) command. Type
++
++ /sbin/ifconfig
++
++at a shell prompt. It should print a list of interfaces including one
++like this example:
++
++ppp0 Link encap Point-to-Point Protocol
++ inet addr 192.76.32.3 P-t-P 129.67.1.165 Mask 255.255.255.0
++ UP POINTOPOINT RUNNING MTU 1500 Metric 1
++ RX packets 33 errors 0 dropped 0 overrun 0
++ TX packets 42 errors 0 dropped 0 overrun 0
++
++Assuming that ifconfig shows the ppp network interface, you can test
++the link using the ping command like this:
++
++ /sbin/ping -c 3 129.67.1.165
++
++where the address you give is the address shown as the P-t-P address
++in the ifconfig output. If the link is operating correctly, you
++should see output like this:
++
++ PING 129.67.1.165 (129.67.1.165): 56 data bytes
++ 64 bytes from 129.67.1.165: icmp_seq=0 ttl=255 time=268 ms
++ 64 bytes from 129.67.1.165: icmp_seq=1 ttl=255 time=247 ms
++ 64 bytes from 129.67.1.165: icmp_seq=2 ttl=255 time=266 ms
++ --- 129.67.1.165 ping statistics ---
++ 3 packets transmitted, 3 packets received, 0% packet loss
++ round-trip min/avg/max = 247/260/268 ms
++
+
+Added: drakx/trunk/mdk-stage1/ppp/README.sol2
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/README.sol2 (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/README.sol2 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,220 @@
++This file describes the installation process for ppp-2.3 on systems
++running Solaris 2. The Solaris 2 and SVR4 ports share a lot of code
++but are not identical. The STREAMS kernel modules and driver for
++Solaris 2 are in the svr4 directory (and use some code from the
++modules directory).
++
++NOTE: Although the kernel driver and modules have been designed to
++operate correctly on SMP systems, they have not been extensively
++tested on SMP machines. Some users of SMP Solaris x86 systems have
++reported system problems apparently linked to the use of previous
++versions of this software. I believe these problems have been fixed.
++
++
++Installation.
++*************
++
++1. Run the configure script and make the user-level programs and the
++kernel modules.
++
++ ./configure
++ make
++
++If you wish to use gcc (or another compiler) instead of Sun's cc, edit
++the svr4/Makedefs file and uncomment the definition of CC. You can
++also change the options passed to the C compiler by editing the COPTS
++definition.
++
++2. Install the programs and kernel modules: as root, do
++
++ make install
++
++This installs pppd, chat and pppstats in /usr/local/bin and the kernel
++modules in /kernel/drv and /kernel/strmod, and creates the /etc/ppp
++directory and populates it with default configuration files. You can
++change the installation directories by editing svr4/Makedefs.
++
++If your system normally has only one network interface, the default
++Solaris 2 system startup scripts will disable IP forwarding in the IP
++kernel module. This will prevent the remote machine from using the
++local machine as a gateway to access other hosts. The solution is to
++create an /etc/ppp/ip-up script containing something like this:
++
++ #!/bin/sh
++ /usr/sbin/ndd -set /dev/ip ip_forwarding 1
++
++See the man page for ip(7p) for details.
++
++Dynamic STREAMS Re-Plumbing Support.
++************************************
++
++Solaris 8 includes dynamic re-plumbing support. With this, modules
++below ip can be inserted, or removed, without having the ip stream be
++unplumbed, and re-plumbed again. All states in ip for an interface
++will therefore now be preserved. Users can install (or upgrade)
++modules like firewall, bandwidth manager, cache manager, tunneling,
++etc., without shutting the machine down.
++
++To support this, ppp driver now uses /dev/udp instead of /dev/ip for
++the ip stream. The interface stream (where ip module pushed on top of
++ppp) is then I_PLINK'ed below the ip stream. /dev/udp is used because
++STREAMS will not let a driver be PLINK'ed under itself, and /dev/ip is
++typically the driver at the bottom of the tunneling interfaces
++stream. The mux ids of the ip streams are then added using
++SIOCSxIFMUXID ioctl.
++
++Users will be able to see the modules on the interface stream by, for
++example:
++
++ pikapon% ifconfig ppp modlist
++ 0 ip
++ 1 ppp
++
++Or arbitrarily if bandwidth manager and firewall modules are installed:
++
++ pikapon% ifconfig hme0 modlist
++ 0 arp
++ 1 ip
++ 2 ipqos
++ 3 firewall
++ 4 hme
++
++Snoop Support.
++**************
++
++This version includes support for /usr/sbin/snoop. Tests has been done
++on both Solaris 7 and 8. Only IPv4 and IPv6 packets will be sent up to
++stream(s) marked as promiscuous, e.g, snoop et al.
++
++Users will be able to see the packets on the ppp interface by, for example:
++
++ snoop -d ppp0
++
++See the man page for snoop(1M) for details.
++
++IPv6 Support.
++*************
++
++This is for Solaris 8 and later.
++
++This version has been tested under Solaris 8 running IPv6. As of now,
++interoperability testing has only been done between Solaris machines
++in terms of the IPV6 NCP. An additional command line option for the
++pppd daemon has been added: ipv6cp-use-persistent.
++
++By default, compilation for IPv6 support is not enabled. Uncomment
++the necessary lines in pppd/Makefile.sol2 to enable it. Once done, the
++quickest way to get IPv6 running is to add the following somewhere in
++the command line option:
++
++ +ipv6 ipv6cp-use-persistent
++
++The persistent id for the link-local address was added to conform to
++RFC 2472; such that if there's an EUI-48 available, use that to make
++up the EUI-64. As of now, the Solaris implementation extracts the
++EUI-48 id from the Ethernet's MAC address (the ethernet interface
++needs to be up). Future works might support other ways of obtaining a
++unique yet persistent id, such as EEPROM serial numbers, etc.
++
++There need not be any up/down scripts for ipv6, e.g. /etc/ppp/ipv6-up
++or /etc/ppp/ipv6-down, to trigger IPv6 neighbor discovery for auto
++configuration and routing. The in.ndpd daemon will perform all of the
++necessary jobs in the background. /etc/inet/ndpd.conf can be further
++customized to enable the machine as an IPv6 router. See the man page
++for in.ndpd(1M) and ndpd.conf(4) for details.
++
++Below is a sample output of &quot;ifconfig -a&quot; with persistent link-local
++address. Note the UNNUMBERED flag is set because hme0 and ppp0 both
++have identical link-local IPv6 addresses:
++
++lo0: flags=1000849&lt;UP,LOOPBACK,RUNNING,MULTICAST,IPv4&gt; mtu 8232 index 1
++ inet 127.0.0.1 netmask ff000000
++hme0: flags=1000843&lt;UP,BROADCAST,RUNNING,MULTICAST,IPv4&gt; mtu 1500 index 2
++ inet 129.146.86.248 netmask ffffff00 broadcast 129.146.86.255
++ ether 8:0:20:8d:38:c1
++lo0: flags=2000849&lt;UP,LOOPBACK,RUNNING,MULTICAST,IPv6&gt; mtu 8252 index 1
++ inet6 ::1/128
++hme0: flags=2000841&lt;UP,RUNNING,MULTICAST,IPv6&gt; mtu 1500 index 2
++ ether 8:0:20:8d:38:c1
++ inet6 fe80::a00:20ff:fe8d:38c1/10
++hme0:1: flags=2080841&lt;UP,RUNNING,MULTICAST,ADDRCONF,IPv6&gt; mtu 1500 index 2
++ inet6 fec0::56:a00:20ff:fe8d:38c1/64
++hme0:2: flags=2080841&lt;UP,RUNNING,MULTICAST,ADDRCONF,IPv6&gt; mtu 1500 index 2
++ inet6 2000::56:a00:20ff:fe8d:38c1/64
++hme0:3: flags=2080841&lt;UP,RUNNING,MULTICAST,ADDRCONF,IPv6&gt; mtu 1500 index 2
++ inet6 2::56:a00:20ff:fe8d:38c1/64
++ppp0: flags=10008d1&lt;UP,POINTOPOINT,RUNNING,NOARP,MULTICAST,IPv4&gt; mtu 1500 index 12
++ inet 172.16.1.1 --&gt; 172.16.1.2 netmask ffffff00
++ppp0: flags=2202851&lt;UP,POINTOPOINT,RUNNING,MULTICAST,UNNUMBERED,NONUD,IPv6&gt; mtu 1500 index 12
++ inet6 fe80::a00:20ff:fe8d:38c1/10 --&gt; fe80::a00:20ff:fe7a:24fb
++
++Note also that a plumbed ipv6 interface stream will exist throughout
++the entire PPP session in the case where the peer rejects IPV6CP,
++which further causes the interface state to stay down. Unplumbing will
++happen when the daemon exits. This is done by design and is not a bug.
++
++64-bit Support.
++***************
++
++This version has been tested under Solaris 7 (and Solaris 8 ) in both
++32- and 64-bits environments (Ultra class machines). Installing the
++package by executing &quot;make install&quot; will result in additional files
++residing in /kernel/drv/sparcv9 and /kernel/strmod/sparcv9
++subdirectories.
++
++64-bit modules and driver have been compiled and tested using Sun's cc.
++
++Synchronous Serial Support.
++***************************
++
++This version has working but limited support for the on-board
++synchronous HDLC interfaces. It has been tested with the /dev/se_hdlc
++and /dev/zsh drivers. Synchronous mode was tested with a Cisco
++router.
++
++There ppp daemon does not directly support controlling the serial
++interface. It relies on the /usr/sbin/syncinit command to initialize
++HDLC mode and clocking.
++
++Some bugs remain: large sized frames are not sent/received properly,
++and may be related to the IP mtu. This may be due to bugs in pppd
++itself, bugs in Solaris or the serial drivers. The /dev/zsh driver
++seems more larger and can send/receive larger frames than the
++/dev/se_hdlc driver. There is a confirmed bug with NRZ/NRZI mode in
++the /dev/se_hdlc driver, and Solaris patch 104596-11 is needed to
++correct it. (However this patch seems to introduce other serial
++problems. If you don't apply the patch, the workaround is to change
++the nrzi mode to yes or no, whichever works)
++
++How to start pppd with synchronous support:
++
++#!/bin/sh
++
++local=1.1.1.1 # your ip address here
++baud=38400 # needed, but ignored by serial driver
++
++# Change to the correct serial driver/port
++#dev=/dev/zsh0
++dev=/dev/se_hdlc0
++
++# Change the driver, nrzi mode, speed and clocking to match your setup
++# This configuration is for external clocking from the DCE
++connect=&quot;syncinit se_hdlc0 nrzi=no speed=64000 txc=rxc rxc=rxc&quot;
++
++/usr/sbin/pppd $dev sync $baud novj noauth $local: connect &quot;$connect&quot;
++
++
++Sample Cisco router config excerpt:
++
++!
++! Cisco router setup as DCE with RS-232 DCE cable
++!
++!
++interface Serial0
++ ip address 1.1.1.2 255.255.255.0
++ encapsulation ppp
++ clockrate 64000
++ no nrzi-encoding
++ no shutdown
++!
++
+
+Added: drakx/trunk/mdk-stage1/ppp/README.sunos4
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/README.sunos4 (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/README.sunos4 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,62 @@
++This file describes the installation process for ppp-2.3 on systems
++running SunOS 4.1.x (or the equivalent).
++
++The STREAMS modules in the sunos4 directory provide kernel support for
++PPP on SunOS 4.1.x systems. They have been tested under SunOS 4.1.3
++on a SparcStation 1+. They should work under earlier SunOS 4.1.x
++systems, but no guarantees are given.
++
++These modules are designed to be loaded into the running kernel using
++the `modload' command.
++
++
++Installation.
++*************
++
++1. Run the configure script and make the user-level programs and the
++kernel modules.
++
++ ./configure
++ make
++
++If you wish to compile using gcc instead of cc, edit the
++sunos4/Makedefs file and uncomment the line saying &quot;CC = gcc&quot;. You
++can also change the C compiler options by editing the COPTS
++definition.
++
++2. Install the pppd, pppstats and chat programs and the loadable
++module object files (you need to be root to do this):
++
++ make install
++
++By default, the programs and the loadable module object files go into
++/usr/local/etc. Doing `make install' also copies a script called
++ppp.INSTALL into /dev, and makes ppp.LOAD, ppp.UNLOAD, ppp.MKDEV and
++ppp.RMDEV links to it. You can change the installation directories by
++editing sunos4/Makedefs.
++
++3. Load the ppp modules (you need to be root for this too):
++
++ /dev/ppp.LOAD
++
++You will want to do this in your /etc/rc.local file once you have
++everything installed. I suggest you put something like the following
++in /etc/rc.local (or /etc/loadable, if you have one):
++
++ if [ -f /dev/ppp.AUTOLOAD ]; then
++ /dev/ppp.LOAD
++ fi
++
++and then create a /dev/ppp.AUTOLOAD file with the command
++
++ touch /dev/ppp.AUTOLOAD
++
++It is not advisable to unload the &quot;if_ppp&quot; module, because it creates
++network interface units, and SunOS does not provide any way to destroy
++network interfaces once created. If you do unload it, the system will
++probably crash at some later stage.
++
++If you have previously had ppp-2.2 installed, you may have statements
++in your /etc/rc.local to load the ppp module. You will need to remove
++those. Having done this, you will need to reboot to remove the old
++ppp module and load the new modules.
+
+Added: drakx/trunk/mdk-stage1/ppp/SETUP
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/SETUP (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/SETUP 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,111 @@
++ Configuring a PPP link.
++
++After you have compiled and installed this package, there are some
++configuration files which will generally need to be set up. The
++pppd(8) man page is the best reference for the full details; this file
++outlines the configuration process for the most common case, where
++this package is being used to enable a machine to dial an ISP and
++connect to the internet. The FAQ and README.linux files also provide
++useful information about setting up PPP.
++
++Dialling an ISP.
++****************
++
++Usually, an ISP will assign an IP address to your machine, and will
++refuse to authenticate itself to you. Some ISPs require a username
++and password to be entered before PPP service commences, while others
++use PPP authentication (using either the PAP or CHAP protocols).
++
++The recommended way to set up to dial an ISP is for the system
++administrator to create a file under /etc/ppp/peers, named for the ISP
++that you will be dialling. For example, suppose the file is called
++/etc/ppp/peers/isp. This file would contain something like this:
++
++cua0 # modem is connected to /dev/cua0
++38400 # run the serial port at 38400 baud
++crtscts # use hardware flow control
++noauth # don't require the ISP to authenticate itself
++defaultroute # use the ISP as our default route
++connect '/usr/sbin/chat -v -f /etc/ppp/chat-isp'
++
++If there are any other pppd options that should apply when calling
++this ISP, they can also be placed in this file.
++
++The /etc/ppp/chat-isp file named in the last line contains the script
++for chat(8) to use to dial the ISP and go through any username/
++password authentication required before PPP service starts. Here is
++an example (for dialling an Annex terminal server):
++
++ABORT &quot;NO CARRIER&quot;
++ABORT &quot;NO DIALTONE&quot;
++ABORT &quot;ERROR&quot;
++ABORT &quot;NO ANSWER&quot;
++ABORT &quot;BUSY&quot;
++ABORT &quot;Username/Password Incorrect&quot;
++&quot;&quot; &quot;at&quot;
++OK &quot;at&amp;d2&amp;c1&quot;
++OK &quot;atdt2479381&quot;
++&quot;name:&quot; &quot;^Uusername&quot;
++&quot;word:&quot; &quot;\qpassword&quot;
++&quot;annex&quot; &quot;ppp&quot;
++&quot;Switching to PPP-ppp-Switching to PPP&quot;
++
++See the chat(8) man page for details of the script. If you are not
++sure how the initial dialog with your ISP will go, you could use
++a terminal emulator such as kermit or minicom to go through the
++process manually.
++
++If your ISP requires PAP or CHAP authentication, you will have to
++create a line in /etc/ppp/pap-secrets or /etc/ppp/chap-secrets like
++this:
++
++myhostname * &quot;password&quot;
++
++(Replace myhostname with the hostname of your machine.)
++
++At this point, you can initiate the link with the command:
++
++/usr/sbin/pppd call isp
++
++(N.B.: pppd might be installed in a different directory on some
++systems).
++
++This will return to the shell prompt immediately, as pppd will detach
++itself from its controlling terminal. (If you don't want it to do
++this, use the &quot;nodetach&quot; option.)
++
++Pppd will log messages describing the progress of the connection and
++any errors using the syslog facility (see the syslogd(8) and
++syslog.conf(5) man pages). Pppd issues messages using syslog facility
++daemon (or local2 if it has been compiled with debugging enabled);
++chat uses facility local2. It is often useful to see messages of
++priority notice or higher on the console. To see these, find the line
++in /etc/syslog.conf which has /dev/console on the right-hand side, and
++add `daemon.notice' on the left. This line should end up something
++like this:
++
++*.err;kern.debug;daemon,local2,auth.notice;mail.crit /dev/console
++
++If you want to see more messages from pppd, request messages of
++priority info or higher for facility daemon, like this:
++
++*.err;kern.debug;daemon.info;local2,auth.notice;mail.crit /dev/console
++
++It is also useful to add a line like this:
++
++daemon,local2.debug /etc/ppp/ppp-log
++
++If you do this, you will need to create an empty /etc/ppp/ppp-log
++file.
++
++After modifying syslog.conf, you will then need to send a HUP signal
++to syslogd (or reboot).
++
++When you wish terminate the PPP link, you should send a TERM or INTR
++signal to pppd. Pppd writes its process ID to a file called
++ppp&lt;n&gt;.pid in /var/run (or /etc/ppp on older systems such as SunOS or
++Ultrix). Here &lt;n&gt; is the PPP interface unit number, which will be 0
++unless you have more than one PPP link running simultaneously. Thus
++you can terminate the link with a command like
++
++ kill `cat /var/run/ppp0.pid`
+
+Added: drakx/trunk/mdk-stage1/ppp/chat/Makefile.linux
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/chat/Makefile.linux (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/chat/Makefile.linux 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,27 @@
++# $Id: Makefile.linux 195720 2001-06-11 11:44:34Z gc $
++
++CDEF1= -DTERMIOS # Use the termios structure
++CDEF2= -DSIGTYPE=void # Standard definition
++CDEF3= -UNO_SLEEP # Use the usleep function
++CDEF4= -DFNDELAY=O_NDELAY # Old name value
++CDEFS= $(CDEF1) $(CDEF2) $(CDEF3) $(CDEF4)
++
++CFLAGS= $(RPM_OPT_FLAGS) $(CDEFS)
++
++INSTALL= install
++
++all: chat
++
++chat: chat.o
++ $(CC) -o chat chat.o
++
++chat.o: chat.c
++ $(CC) -c $(CFLAGS) -o chat.o chat.c
++
++install: chat
++ mkdir -p $(BINDIR)
++ $(INSTALL) -s -c chat $(BINDIR)
++ $(INSTALL) -c -m 644 chat.8 $(MANDIR)/man8
++
++clean:
++ rm -f chat.o chat *~
+
+Added: drakx/trunk/mdk-stage1/ppp/chat/Makefile.linux.makeopt
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/chat/Makefile.linux.makeopt (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/chat/Makefile.linux.makeopt 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,27 @@
++# $Id: Makefile.linux.makeopt 195720 2001-06-11 11:44:34Z gc $
++
++CDEF1= -DTERMIOS # Use the termios structure
++CDEF2= -DSIGTYPE=void # Standard definition
++CDEF3= -UNO_SLEEP # Use the usleep function
++CDEF4= -DFNDELAY=O_NDELAY # Old name value
++CDEFS= $(CDEF1) $(CDEF2) $(CDEF3) $(CDEF4)
++
++CFLAGS= -O2 -g -pipe $(CDEFS)
++
++INSTALL= install
++
++all: chat
++
++chat: chat.o
++ $(CC) -o chat chat.o
++
++chat.o: chat.c
++ $(CC) -c $(CFLAGS) -o chat.o chat.c
++
++install: chat
++ mkdir -p $(BINDIR)
++ $(INSTALL) -s -c chat $(BINDIR)
++ $(INSTALL) -c -m 644 chat.8 $(MANDIR)/man8
++
++clean:
++ rm -f chat.o chat *~
+
+Added: drakx/trunk/mdk-stage1/ppp/chat/Makefile.sol2
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/chat/Makefile.sol2 (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/chat/Makefile.sol2 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,19 @@
++#
++# Makefile for chat on Solaris 2
++#
++
++include ../solaris/Makedefs
++
++CFLAGS = $(COPTS) -DNO_USLEEP -DSOL2
++
++all: chat
++
++chat: chat.o
++ $(CC) -o chat chat.o
++
++install: chat
++ $(INSTALL) -f $(BINDIR) chat
++ $(INSTALL) -m 444 -f $(MANDIR)/man8 chat.8
++
++clean:
++ rm -f *~ *.o chat
+
+Added: drakx/trunk/mdk-stage1/ppp/chat/Makefile.sunos4
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/chat/Makefile.sunos4 (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/chat/Makefile.sunos4 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,19 @@
++#
++# Makefile for chat on suns
++#
++
++include ../sunos4/Makedefs
++
++CFLAGS = -DSUNOS $(COPTS)
++
++all: chat
++
++chat: chat.o
++ $(CC) -o chat chat.o
++
++install: chat
++ $(INSTALL) -c chat $(BINDIR)/chat
++ $(INSTALL) -c -m 444 chat.8 $(MANDIR)/man8/chat.8
++
++clean:
++ rm -f *~ *.o chat
+
+Added: drakx/trunk/mdk-stage1/ppp/chat/chat.8
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/chat/chat.8 (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/chat/chat.8 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,515 @@
++.\&quot; -*- nroff -*-
++.\&quot; manual page [] for chat 1.8
++.\&quot; $Id: chat.8 195720 2001-06-11 11:44:34Z gc $
++.\&quot; SH section heading
++.\&quot; SS subsection heading
++.\&quot; LP paragraph
++.\&quot; IP indented paragraph
++.\&quot; TP hanging label
++.TH CHAT 8 &quot;22 May 1999&quot; &quot;Chat Version 1.22&quot;
++.SH NAME
++chat \- Automated conversational script with a modem
++.SH SYNOPSIS
++.B chat
++[
++.I options
++]
++.I script
++.SH DESCRIPTION
++.LP
++The \fIchat\fR program defines a conversational exchange between the
++computer and the modem. Its primary purpose is to establish the
++connection between the Point-to-Point Protocol Daemon (\fIpppd\fR) and
++the remote's \fIpppd\fR process.
++.SH OPTIONS
++.TP
++.B -f \fI&lt;chat file&gt;
++Read the chat script from the chat \fIfile\fR. The use of this option
++is mutually exclusive with the chat script parameters. The user must
++have read access to the file. Multiple lines are permitted in the
++file. Space or horizontal tab characters should be used to separate
++the strings.
++.TP
++.B -t \fI&lt;timeout&gt;
++Set the timeout for the expected string to be received. If the string
++is not received within the time limit then the reply string is not
++sent. An alternate reply may be sent or the script will fail if there
++is no alternate reply string. A failed script will cause the
++\fIchat\fR program to terminate with a non-zero error code.
++.TP
++.B -r \fI&lt;report file&gt;
++Set the file for output of the report strings. If you use the keyword
++\fIREPORT\fR, the resulting strings are written to this file. If this
++option is not used and you still use \fIREPORT\fR keywords, the
++\fIstderr\fR file is used for the report strings.
++.TP
++.B -e
++Start with the echo option turned on. Echoing may also be turned on
++or off at specific points in the chat script by using the \fIECHO\fR
++keyword. When echoing is enabled, all output from the modem is echoed
++to \fIstderr\fR.
++.TP
++.B -E
++Enables environment variable substituion within chat scripts using the
++standard \fI$xxx\fR syntax.
++.TP
++.B -v
++Request that the \fIchat\fR script be executed in a verbose mode. The
++\fIchat\fR program will then log the execution state of the chat
++script as well as all text received from the modem and the output
++strings sent to the modem. The default is to log through the SYSLOG;
++the logging method may be altered with the -S and -s flags.
++.TP
++.B -V
++Request that the \fIchat\fR script be executed in a stderr verbose
++mode. The \fIchat\fR program will then log all text received from the
++modem and the output strings sent to the modem to the stderr device. This
++device is usually the local console at the station running the chat or
++pppd program.
++.TP
++.B -s
++Use stderr. All log messages from '-v' and all error messages will be
++sent to stderr.
++.TP
++.B -S
++Do not use the SYSLOG. By default, error messages are sent to the
++SYSLOG. The use of -S will prevent both log messages from '-v' and
++error messages from being sent to the SYSLOG.
++.TP
++.B -T \fI&lt;phone number&gt;
++Pass in an arbitary string, usually a phone number, that will be
++substituted for the \\T substitution metacharacter in a send string.
++.TP
++.B -U \fI&lt;phone number 2&gt;
++Pass in a second string, usually a phone number, that will be
++substituted for the \\U substitution metacharacter in a send string.
++This is useful when dialing an ISDN terminal adapter that requires two
++numbers.
++.TP
++.B script
++If the script is not specified in a file with the \fI-f\fR option then
++the script is included as parameters to the \fIchat\fR program.
++.SH CHAT SCRIPT
++.LP
++The \fIchat\fR script defines the communications.
++.LP
++A script consists of one or more &quot;expect-send&quot; pairs of strings,
++separated by spaces, with an optional &quot;subexpect-subsend&quot; string pair,
++separated by a dash as in the following example:
++.IP
++ogin:-BREAK-ogin: ppp ssword: hello2u2
++.LP
++This line indicates that the \fIchat\fR program should expect the string
++&quot;ogin:&quot;. If it fails to receive a login prompt within the time interval
++allotted, it is to send a break sequence to the remote and then expect the
++string &quot;ogin:&quot;. If the first &quot;ogin:&quot; is received then the break sequence is
++not generated.
++.LP
++Once it received the login prompt the \fIchat\fR program will send the
++string ppp and then expect the prompt &quot;ssword:&quot;. When it receives the
++prompt for the password, it will send the password hello2u2.
++.LP
++A carriage return is normally sent following the reply string. It is not
++expected in the &quot;expect&quot; string unless it is specifically requested by using
++the \\r character sequence.
++.LP
++The expect sequence should contain only what is needed to identify the
++string. Since it is normally stored on a disk file, it should not contain
++variable information. It is generally not acceptable to look for time
++strings, network identification strings, or other variable pieces of data as
++an expect string.
++.LP
++To help correct for characters which may be corrupted during the initial
++sequence, look for the string &quot;ogin:&quot; rather than &quot;login:&quot;. It is possible
++that the leading &quot;l&quot; character may be received in error and you may never
++find the string even though it was sent by the system. For this reason,
++scripts look for &quot;ogin:&quot; rather than &quot;login:&quot; and &quot;ssword:&quot; rather than
++&quot;password:&quot;.
++.LP
++A very simple script might look like this:
++.IP
++ogin: ppp ssword: hello2u2
++.LP
++In other words, expect ....ogin:, send ppp, expect ...ssword:, send hello2u2.
++.LP
++In actual practice, simple scripts are rare. At the vary least, you
++should include sub-expect sequences should the original string not be
++received. For example, consider the following script:
++.IP
++ogin:--ogin: ppp ssword: hello2u2
++.LP
++This would be a better script than the simple one used earlier. This would look
++for the same login: prompt, however, if one was not received, a single
++return sequence is sent and then it will look for login: again. Should line
++noise obscure the first login prompt then sending the empty line will
++usually generate a login prompt again.
++.SH COMMENTS
++Comments can be embedded in the chat script. A comment is a line which
++starts with the \fB#\fR (hash) character in column 1. Such comment
++lines are just ignored by the chat program. If a '#' character is to
++be expected as the first character of the expect sequence, you should
++quote the expect string.
++If you want to wait for a prompt that starts with a # (hash)
++character, you would have to write something like this:
++.IP
++# Now wait for the prompt and send logout string
++.br
++\'# ' logout
++.LP
++
++.SH SENDING DATA FROM A FILE
++If the string to send starts with an at sign (@), the rest of the
++string is taken to be the name of a file to read to get the string to
++send. If the last character of the data read is a newline, it is
++removed. The file can be a named pipe (or fifo) instead of a regular
++file. This provides a way for \fBchat\fR to communicate with another
++program, for example, a program to prompt the user and receive a
++password typed in.
++.LP
++
++.SH ABORT STRINGS
++Many modems will report the status of the call as a string. These
++strings may be \fBCONNECTED\fR or \fBNO CARRIER\fR or \fBBUSY\fR. It
++is often desirable to terminate the script should the modem fail to
++connect to the remote. The difficulty is that a script would not know
++exactly which modem string it may receive. On one attempt, it may
++receive \fBBUSY\fR while the next time it may receive \fBNO CARRIER\fR.
++.LP
++These &quot;abort&quot; strings may be specified in the script using the \fIABORT\fR
++sequence. It is written in the script as in the following example:
++.IP
++ABORT BUSY ABORT 'NO CARRIER' '' ATZ OK ATDT5551212 CONNECT
++.LP
++This sequence will expect nothing; and then send the string ATZ. The
++expected response to this is the string \fIOK\fR. When it receives \fIOK\fR,
++the string ATDT5551212 to dial the telephone. The expected string is
++\fICONNECT\fR. If the string \fICONNECT\fR is received the remainder of the
++script is executed. However, should the modem find a busy telephone, it will
++send the string \fIBUSY\fR. This will cause the string to match the abort
++character sequence. The script will then fail because it found a match to
++the abort string. If it received the string \fINO CARRIER\fR, it will abort
++for the same reason. Either string may be received. Either string will
++terminate the \fIchat\fR script.
++.SH CLR_ABORT STRINGS
++This sequence allows for clearing previously set \fBABORT\fR strings.
++\fBABORT\fR strings are kept in an array of a pre-determined size (at
++compilation time); \fBCLR_ABORT\fR will reclaim the space for cleared
++entries so that new strings can use that space.
++.SH SAY STRINGS
++The \fBSAY\fR directive allows the script to send strings to the user
++at the terminal via standard error. If \fBchat\fR is being run by
++pppd, and pppd is running as a daemon (detached from its controlling
++terminal), standard error will normally be redirected to the file
++/etc/ppp/connect-errors.
++.LP
++\fBSAY\fR strings must be enclosed in single or double quotes. If
++carriage return and line feed are needed in the string to be output,
++you must explicitely add them to your string.
++.LP
++The SAY strings could be used to give progress messages in sections of
++the script where you want to have 'ECHO OFF' but still let the user
++know what is happening. An example is:
++.IP
++ABORT BUSY
++.br
++ECHO OFF
++.br
++SAY &quot;Dialling your ISP...\\n&quot;
++.br
++\'' ATDT5551212
++.br
++TIMEOUT 120
++.br
++SAY &quot;Waiting up to 2 minutes for connection ... &quot;
++.br
++CONNECT ''
++.br
++SAY &quot;Connected, now logging in ...\n&quot;
++.br
++ogin: account
++.br
++ssword: pass
++.br
++$ \c
++SAY &quot;Logged in OK ...\n&quot;
++\fIetc ...\fR
++.LP
++This sequence will only present the SAY strings to the user and all
++the details of the script will remain hidden. For example, if the
++above script works, the user will see:
++.IP
++Dialling your ISP...
++.br
++Waiting up to 2 minutes for connection ... Connected, now logging in ...
++.br
++Logged in OK ...
++.LP
++
++.SH REPORT STRINGS
++A \fBreport\fR string is similar to the ABORT string. The difference
++is that the strings, and all characters to the next control character
++such as a carriage return, are written to the report file.
++.LP
++The report strings may be used to isolate the transmission rate of the
++modem's connect string and return the value to the chat user. The
++analysis of the report string logic occurs in conjunction with the
++other string processing such as looking for the expect string. The use
++of the same string for a report and abort sequence is probably not
++very useful, however, it is possible.
++.LP
++The report strings to no change the completion code of the program.
++.LP
++These &quot;report&quot; strings may be specified in the script using the \fIREPORT\fR
++sequence. It is written in the script as in the following example:
++.IP
++REPORT CONNECT ABORT BUSY '' ATDT5551212 CONNECT '' ogin: account
++.LP
++This sequence will expect nothing; and then send the string
++ATDT5551212 to dial the telephone. The expected string is
++\fICONNECT\fR. If the string \fICONNECT\fR is received the remainder
++of the script is executed. In addition the program will write to the
++expect-file the string &quot;CONNECT&quot; plus any characters which follow it
++such as the connection rate.
++.SH CLR_REPORT STRINGS
++This sequence allows for clearing previously set \fBREPORT\fR strings.
++\fBREPORT\fR strings are kept in an array of a pre-determined size (at
++compilation time); \fBCLR_REPORT\fR will reclaim the space for cleared
++entries so that new strings can use that space.
++.SH ECHO
++The echo options controls whether the output from the modem is echoed
++to \fIstderr\fR. This option may be set with the \fI-e\fR option, but
++it can also be controlled by the \fIECHO\fR keyword. The &quot;expect-send&quot;
++pair \fIECHO\fR \fION\fR enables echoing, and \fIECHO\fR \fIOFF\fR
++disables it. With this keyword you can select which parts of the
++conversation should be visible. For instance, with the following
++script:
++.IP
++ABORT 'BUSY'
++.br
++ABORT 'NO CARRIER'
++.br
++'' ATZ
++.br
++OK\\r\\n ATD1234567
++.br
++\\r\\n \\c
++.br
++ECHO ON
++.br
++CONNECT \\c
++.br
++ogin: account
++.LP
++all output resulting from modem configuration and dialing is not visible,
++but starting with the \fICONNECT\fR (or \fIBUSY\fR) message, everything
++will be echoed.
++.SH HANGUP
++The HANGUP options control whether a modem hangup should be considered
++as an error or not. This option is useful in scripts for dialling
++systems which will hang up and call your system back. The HANGUP
++options can be \fBON\fR or \fBOFF\fR.
++.br
++When HANGUP is set OFF and the modem hangs up (e.g., after the first
++stage of logging in to a callback system), \fBchat\fR will continue
++running the script (e.g., waiting for the incoming call and second
++stage login prompt). As soon as the incoming call is connected, you
++should use the \fBHANGUP ON\fR directive to reinstall normal hang up
++signal behavior. Here is an (simple) example script:
++.IP
++ABORT 'BUSY'
++.br
++'' ATZ
++.br
++OK\\r\\n ATD1234567
++.br
++\\r\\n \\c
++.br
++CONNECT \\c
++.br
++\'Callback login:' call_back_ID
++.br
++HANGUP OFF
++.br
++ABORT &quot;Bad Login&quot;
++.br
++\'Callback Password:' Call_back_password
++.br
++TIMEOUT 120
++.br
++CONNECT \\c
++.br
++HANGUP ON
++.br
++ABORT &quot;NO CARRIER&quot;
++.br
++ogin:--BREAK--ogin: real_account
++.br
++\fIetc ...\fR
++.LP
++.SH TIMEOUT
++The initial timeout value is 45 seconds. This may be changed using the \fB-t\fR
++parameter.
++.LP
++To change the timeout value for the next expect string, the following
++example may be used:
++.IP
++ATZ OK ATDT5551212 CONNECT TIMEOUT 10 ogin:--ogin: TIMEOUT 5 assword: hello2u2
++.LP
++This will change the timeout to 10 seconds when it expects the login:
++prompt. The timeout is then changed to 5 seconds when it looks for the
++password prompt.
++.LP
++The timeout, once changed, remains in effect until it is changed again.
++.SH SENDING EOT
++The special reply string of \fIEOT\fR indicates that the chat program
++should send an EOT character to the remote. This is normally the
++End-of-file character sequence. A return character is not sent
++following the EOT.
++.PR
++The EOT sequence may be embedded into the send string using the
++sequence \fI^D\fR.
++.SH GENERATING BREAK
++The special reply string of \fIBREAK\fR will cause a break condition
++to be sent. The break is a special signal on the transmitter. The
++normal processing on the receiver is to change the transmission rate.
++It may be used to cycle through the available transmission rates on
++the remote until you are able to receive a valid login prompt.
++.PR
++The break sequence may be embedded into the send string using the
++\fI\\K\fR sequence.
++.SH ESCAPE SEQUENCES
++The expect and reply strings may contain escape sequences. All of the
++sequences are legal in the reply string. Many are legal in the expect.
++Those which are not valid in the expect sequence are so indicated.
++.TP
++.B ''
++Expects or sends a null string. If you send a null string then it will still
++send the return character. This sequence may either be a pair of apostrophe
++or quote characters.
++.TP
++.B \\\\b
++represents a backspace character.
++.TP
++.B \\\\c
++Suppresses the newline at the end of the reply string. This is the only
++method to send a string without a trailing return character. It must
++be at the end of the send string. For example,
++the sequence hello\\c will simply send the characters h, e, l, l, o.
++.I (not valid in expect.)
++.TP
++.B \\\\d
++Delay for one second. The program uses sleep(1) which will delay to a
++maximum of one second.
++.I (not valid in expect.)
++.TP
++.B \\\\K
++Insert a BREAK
++.I (not valid in expect.)
++.TP
++.B \\\\n
++Send a newline or linefeed character.
++.TP
++.B \\\\N
++Send a null character. The same sequence may be represented by \\0.
++.I (not valid in expect.)
++.TP
++.B \\\\p
++Pause for a fraction of a second. The delay is 1/10th of a second.
++.I (not valid in expect.)
++.TP
++.B \\\\q
++Suppress writing the string to the SYSLOG file. The string ?????? is
++written to the log in its place.
++.I (not valid in expect.)
++.TP
++.B \\\\r
++Send or expect a carriage return.
++.TP
++.B \\\\s
++Represents a space character in the string. This may be used when it
++is not desirable to quote the strings which contains spaces. The
++sequence 'HI TIM' and HI\\sTIM are the same.
++.TP
++.B \\\\t
++Send or expect a tab character.
++.TP
++.B \\\\T
++Send the phone number string as specified with the \fI-T\fR option
++.I (not valid in expect.)
++.TP
++.B \\\\U
++Send the phone number 2 string as specified with the \fI-U\fR option
++.I (not valid in expect.)
++.TP
++.B \\\\\\\\
++Send or expect a backslash character.
++.TP
++.B \\\\ddd
++Collapse the octal digits (ddd) into a single ASCII character and send that
++character.
++.I (some characters are not valid in expect.)
++.TP
++.B \^^C
++Substitute the sequence with the control character represented by C.
++For example, the character DC1 (17) is shown as \^^Q.
++.I (some characters are not valid in expect.)
++.SH ENVIRONMENT VARIABLES
++Environment variables are available within chat scripts, if the \fI-E\fR
++option was specified in the command line. The metacharacter \fI$\fR is used
++to introduce the name of the environment variable to substitute. If the
++substition fails, because the requested environment variable is not set,
++\fInothing\fR is replaced for the variable.
++.SH TERMINATION CODES
++The \fIchat\fR program will terminate with the following completion
++codes.
++.TP
++.B 0
++The normal termination of the program. This indicates that the script
++was executed without error to the normal conclusion.
++.TP
++.B 1
++One or more of the parameters are invalid or an expect string was too
++large for the internal buffers. This indicates that the program as not
++properly executed.
++.TP
++.B 2
++An error occurred during the execution of the program. This may be due
++to a read or write operation failing for some reason or chat receiving
++a signal such as SIGINT.
++.TP
++.B 3
++A timeout event occurred when there was an \fIexpect\fR string without
++having a &quot;-subsend&quot; string. This may mean that you did not program the
++script correctly for the condition or that some unexpected event has
++occurred and the expected string could not be found.
++.TP
++.B 4
++The first string marked as an \fIABORT\fR condition occurred.
++.TP
++.B 5
++The second string marked as an \fIABORT\fR condition occurred.
++.TP
++.B 6
++The third string marked as an \fIABORT\fR condition occurred.
++.TP
++.B 7
++The fourth string marked as an \fIABORT\fR condition occurred.
++.TP
++.B ...
++The other termination codes are also strings marked as an \fIABORT\fR
++condition.
++.LP
++Using the termination code, it is possible to determine which event
++terminated the script. It is possible to decide if the string &quot;BUSY&quot;
++was received from the modem as opposed to &quot;NO DIAL TONE&quot;. While the
++first event may be retried, the second will probably have little
++chance of succeeding during a retry.
++.SH SEE ALSO
++Additional information about \fIchat\fR scripts may be found with UUCP
++documentation. The \fIchat\fR script was taken from the ideas proposed
++by the scripts used by the \fIuucico\fR program.
++.LP
++uucico(1), uucp(1)
++.SH COPYRIGHT
++The \fIchat\fR program is in public domain. This is not the GNU public
++license. If it breaks then you get to keep both pieces.
+
+Added: drakx/trunk/mdk-stage1/ppp/chat/chat.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/chat/chat.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/chat/chat.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1756 @@
++/*
++ * Chat -- a program for automatic session establishment (i.e. dial
++ * the phone and log in).
++ *
++ * Standard termination codes:
++ * 0 - successful completion of the script
++ * 1 - invalid argument, expect string too large, etc.
++ * 2 - error on an I/O operation or fatal error condition.
++ * 3 - timeout waiting for a simple string.
++ * 4 - the first string declared as &quot;ABORT&quot;
++ * 5 - the second string declared as &quot;ABORT&quot;
++ * 6 - ... and so on for successive ABORT strings.
++ *
++ * This software is in the public domain.
++ *
++ * -----------------
++ * 22-May-99 added environment substitutuion, enabled with -E switch.
++ * Andreas Arens &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">andras at cityweb.de</A>&gt;.
++ *
++ * 12-May-99 added a feature to read data to be sent from a file,
++ * if the send string starts with @. Idea from gpk &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gpk at onramp.net</A>&gt;.
++ *
++ * added -T and -U option and \T and \U substitution to pass a phone
++ * number into chat script. Two are needed for some ISDN TA applications.
++ * Keith Dart &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">kdart at cisco.com</A>&gt;
++ *
++ *
++ * Added SAY keyword to send output to stderr.
++ * This allows to turn ECHO OFF and to output specific, user selected,
++ * text to give progress messages. This best works when stderr
++ * exists (i.e.: pppd in nodetach mode).
++ *
++ * Added HANGUP directives to allow for us to be called
++ * back. When HANGUP is set to NO, chat will not hangup at HUP signal.
++ * We rely on timeouts in that case.
++ *
++ * Added CLR_ABORT to clear previously set ABORT string. This has been
++ * dictated by the HANGUP above as &quot;NO CARRIER&quot; (for example) must be
++ * an ABORT condition until we know the other host is going to close
++ * the connection for call back. As soon as we have completed the
++ * first stage of the call back sequence, &quot;NO CARRIER&quot; is a valid, non
++ * fatal string. As soon as we got called back (probably get &quot;CONNECT&quot;),
++ * we should re-arm the ABORT &quot;NO CARRIER&quot;. Hence the CLR_ABORT command.
++ * Note that CLR_ABORT packs the abort_strings[] array so that we do not
++ * have unused entries not being reclaimed.
++ *
++ * In the same vein as above, added CLR_REPORT keyword.
++ *
++ * Allow for comments. Line starting with '#' are comments and are
++ * ignored. If a '#' is to be expected as the first character, the
++ * expect string must be quoted.
++ *
++ *
++ * Francis Demierre &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">Francis at SwissMail.Com</A>&gt;
++ * Thu May 15 17:15:40 MET DST 1997
++ *
++ *
++ * Added -r &quot;report file&quot; switch &amp; REPORT keyword.
++ * Robert Geer &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">bgeer at xmission.com</A>&gt;
++ *
++ * Added -s &quot;use stderr&quot; and -S &quot;don't use syslog&quot; switches.
++ * June 18, 1997
++ * Karl O. Pinc &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">kop at meme.com</A>&gt;
++ *
++ *
++ * Added -e &quot;echo&quot; switch &amp; ECHO keyword
++ * Dick Streefland &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dicks at tasking.nl</A>&gt;
++ *
++ *
++ * Considerable updates and modifications by
++ * Al Longyear &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">longyear at pobox.com</A>&gt;
++ * Paul Mackerras &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">paulus at cs.anu.edu.au</A>&gt;
++ *
++ *
++ * The original author is:
++ *
++ * Karl Fox &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">karl at MorningStar.Com</A>&gt;
++ * Morning Star Technologies, Inc.
++ * 1760 Zollinger Road
++ * Columbus, OH 43221
++ * (614)451-1883
++ *
++ */
++
++#ifndef __STDC__
++#define const
++#endif
++
++#ifndef lint
++static const char rcsid[] = &quot;$Id: chat.c 195720 2001-06-11 11:44:34Z gc $&quot;;
++#endif
++
++#include &lt;stdio.h&gt;
++#include &lt;ctype.h&gt;
++#include &lt;time.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;signal.h&gt;
++#include &lt;errno.h&gt;
++#include &lt;string.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;syslog.h&gt;
++
++#ifndef TERMIO
++#undef TERMIOS
++#define TERMIOS
++#endif
++
++#ifdef TERMIO
++#include &lt;termio.h&gt;
++#endif
++#ifdef TERMIOS
++#include &lt;termios.h&gt;
++#endif
++
++#define STR_LEN 1024
++
++#ifndef SIGTYPE
++#define SIGTYPE void
++#endif
++
++#undef __P
++#undef __V
++
++#ifdef __STDC__
++#include &lt;stdarg.h&gt;
++#define __V(x) x
++#define __P(x) x
++#else
++#include &lt;varargs.h&gt;
++#define __V(x) (va_alist) va_dcl
++#define __P(x) ()
++#define const
++#endif
++
++#ifndef O_NONBLOCK
++#define O_NONBLOCK O_NDELAY
++#endif
++
++#ifdef SUNOS
++extern int sys_nerr;
++extern char *sys_errlist[];
++#define memmove(to, from, n) bcopy(from, to, n)
++#define strerror(n) ((unsigned)(n) &lt; sys_nerr? sys_errlist[(n)] :\
++ &quot;unknown error&quot;)
++#endif
++
++/*************** Micro getopt() *********************************************/
++#define OPTION(c,v) (_O&amp;2&amp;&amp;**v?*(*v)++:!c||_O&amp;4?0:(!(_O&amp;1)&amp;&amp; \
++ (--c,++v),_O=4,c&amp;&amp;**v=='-'&amp;&amp;v[0][1]?*++*v=='-'\
++ &amp;&amp;!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0))
++#define OPTARG(c,v) (_O&amp;2?**v||(++v,--c)?(_O=1,--c,*v++): \
++ (_O=4,(char*)0):(char*)0)
++#define OPTONLYARG(c,v) (_O&amp;2&amp;&amp;**v?(_O=1,--c,*v++):(char*)0)
++#define ARG(c,v) (c?(--c,*v++):(char*)0)
++
++static int _O = 0; /* Internal state */
++/*************** Micro getopt() *********************************************/
++
++char *program_name;
++
++#define MAX_ABORTS 50
++#define MAX_REPORTS 50
++#define DEFAULT_CHAT_TIMEOUT 45
++
++int echo = 0;
++int verbose = 0;
++int to_log = 1;
++int to_stderr = 0;
++int Verbose = 0;
++int quiet = 0;
++int report = 0;
++int use_env = 0;
++int exit_code = 0;
++FILE* report_fp = (FILE *) 0;
++char *report_file = (char *) 0;
++char *chat_file = (char *) 0;
++char *phone_num = (char *) 0;
++char *phone_num2 = (char *) 0;
++int timeout = DEFAULT_CHAT_TIMEOUT;
++
++int have_tty_parameters = 0;
++
++#ifdef TERMIO
++#define term_parms struct termio
++#define get_term_param(param) ioctl(0, TCGETA, param)
++#define set_term_param(param) ioctl(0, TCSETA, param)
++struct termio saved_tty_parameters;
++#endif
++
++#ifdef TERMIOS
++#define term_parms struct termios
++#define get_term_param(param) tcgetattr(0, param)
++#define set_term_param(param) tcsetattr(0, TCSANOW, param)
++struct termios saved_tty_parameters;
++#endif
++
++char *abort_string[MAX_ABORTS], *fail_reason = (char *)0,
++ fail_buffer[50];
++int n_aborts = 0, abort_next = 0, timeout_next = 0, echo_next = 0;
++int clear_abort_next = 0;
++
++char *report_string[MAX_REPORTS] ;
++char report_buffer[50] ;
++int n_reports = 0, report_next = 0, report_gathering = 0 ;
++int clear_report_next = 0;
++
++int say_next = 0, hup_next = 0;
++
++void *dup_mem __P((void *b, size_t c));
++void *copy_of __P((char *s));
++void usage __P((void));
++void logf __P((const char *fmt, ...));
++void fatal __P((int code, const char *fmt, ...));
++SIGTYPE sigalrm __P((int signo));
++SIGTYPE sigint __P((int signo));
++SIGTYPE sigterm __P((int signo));
++SIGTYPE sighup __P((int signo));
++void unalarm __P((void));
++void init __P((void));
++void set_tty_parameters __P((void));
++void echo_stderr __P((int));
++void break_sequence __P((void));
++void terminate __P((int status));
++void do_file __P((char *chat_file));
++int get_string __P((register char *string));
++int put_string __P((register char *s));
++int write_char __P((int c));
++int put_char __P((int c));
++int get_char __P((void));
++void chat_send __P((register char *s));
++char *character __P((int c));
++void chat_expect __P((register char *s));
++char *clean __P((register char *s, int sending));
++void break_sequence __P((void));
++void terminate __P((int status));
++void pack_array __P((char **array, int end));
++char *expect_strtok __P((char *, char *));
++int vfmtmsg __P((char *, int, const char *, va_list)); /* vsprintf++ */
++
++int main __P((int, char *[]));
++
++void *dup_mem(b, c)
++void *b;
++size_t c;
++{
++ void *ans = malloc (c);
++ if (!ans)
++ fatal(2, &quot;memory error!&quot;);
++
++ memcpy (ans, b, c);
++ return ans;
++}
++
++void *copy_of (s)
++char *s;
++{
++ return dup_mem (s, strlen (s) + 1);
++}
++
++/*
++ * chat [ -v ] [ -E ] [ -T number ] [ -U number ] [ -t timeout ] [ -f chat-file ] \
++ * [ -r report-file ] \
++ * [...[[expect[-say[-expect...]] say expect[-say[-expect]] ...]]]
++ *
++ * Perform a UUCP-dialer-like chat script on stdin and stdout.
++ */
++int
++main(argc, argv)
++ int argc;
++ char **argv;
++{
++ int option;
++ char *arg;
++
++ program_name = *argv;
++ tzset();
++
++ while ((option = OPTION(argc, argv)) != 0) {
++ switch (option) {
++ case 'e':
++ ++echo;
++ break;
++
++ case 'E':
++ ++use_env;
++ break;
++
++ case 'v':
++ ++verbose;
++ break;
++
++ case 'V':
++ ++Verbose;
++ break;
++
++ case 's':
++ ++to_stderr;
++ break;
++
++ case 'S':
++ to_log = 0;
++ break;
++
++ case 'f':
++ if ((arg = OPTARG(argc, argv)) != NULL)
++ chat_file = copy_of(arg);
++ else
++ usage();
++ break;
++
++ case 't':
++ if ((arg = OPTARG(argc, argv)) != NULL)
++ timeout = atoi(arg);
++ else
++ usage();
++ break;
++
++ case 'r':
++ arg = OPTARG (argc, argv);
++ if (arg) {
++ if (report_fp != NULL)
++ fclose (report_fp);
++ report_file = copy_of (arg);
++ report_fp = fopen (report_file, &quot;a&quot;);
++ if (report_fp != NULL) {
++ if (verbose)
++ fprintf (report_fp, &quot;Opening \&quot;%s\&quot;...\n&quot;,
++ report_file);
++ report = 1;
++ }
++ }
++ break;
++
++ case 'T':
++ if ((arg = OPTARG(argc, argv)) != NULL)
++ phone_num = copy_of(arg);
++ else
++ usage();
++ break;
++
++ case 'U':
++ if ((arg = OPTARG(argc, argv)) != NULL)
++ phone_num2 = copy_of(arg);
++ else
++ usage();
++ break;
++
++ default:
++ usage();
++ break;
++ }
++ }
++/*
++ * Default the report file to the stderr location
++ */
++ if (report_fp == NULL)
++ report_fp = stderr;
++
++ if (to_log) {
++#ifdef ultrix
++ openlog(&quot;chat&quot;, LOG_PID);
++#else
++ openlog(&quot;chat&quot;, LOG_PID | LOG_NDELAY, LOG_LOCAL2);
++
++ if (verbose)
++ setlogmask(LOG_UPTO(LOG_INFO));
++ else
++ setlogmask(LOG_UPTO(LOG_WARNING));
++#endif
++ }
++
++ init();
++
++ if (chat_file != NULL) {
++ arg = ARG(argc, argv);
++ if (arg != NULL)
++ usage();
++ else
++ do_file (chat_file);
++ } else {
++ while ((arg = ARG(argc, argv)) != NULL) {
++ chat_expect(arg);
++
++ if ((arg = ARG(argc, argv)) != NULL)
++ chat_send(arg);
++ }
++ }
++
++ terminate(0);
++ return 0;
++}
++
++/*
++ * Process a chat script when read from a file.
++ */
++
++void do_file (chat_file)
++char *chat_file;
++{
++ int linect, sendflg;
++ char *sp, *arg, quote;
++ char buf [STR_LEN];
++ FILE *cfp;
++
++ cfp = fopen (chat_file, &quot;r&quot;);
++ if (cfp == NULL)
++ fatal(1, &quot;%s -- open failed: %m&quot;, chat_file);
++
++ linect = 0;
++ sendflg = 0;
++
++ while (fgets(buf, STR_LEN, cfp) != NULL) {
++ sp = strchr (buf, '\n');
++ if (sp)
++ *sp = '\0';
++
++ linect++;
++ sp = buf;
++
++ /* lines starting with '#' are comments. If a real '#'
++ is to be expected, it should be quoted .... */
++ if ( *sp == '#' )
++ continue;
++
++ while (*sp != '\0') {
++ if (*sp == ' ' || *sp == '\t') {
++ ++sp;
++ continue;
++ }
++
++ if (*sp == '&quot;' || *sp == '\'') {
++ quote = *sp++;
++ arg = sp;
++ while (*sp != quote) {
++ if (*sp == '\0')
++ fatal(1, &quot;unterminated quote (line %d)&quot;, linect);
++
++ if (*sp++ == '\\') {
++ if (*sp != '\0')
++ ++sp;
++ }
++ }
++ }
++ else {
++ arg = sp;
++ while (*sp != '\0' &amp;&amp; *sp != ' ' &amp;&amp; *sp != '\t')
++ ++sp;
++ }
++
++ if (*sp != '\0')
++ *sp++ = '\0';
++
++ if (sendflg)
++ chat_send (arg);
++ else
++ chat_expect (arg);
++ sendflg = !sendflg;
++ }
++ }
++ fclose (cfp);
++}
++
++/*
++ * We got an error parsing the command line.
++ */
++void usage()
++{
++ fprintf(stderr, &quot;\
++Usage: %s [-e] [-E] [-v] [-V] [-t timeout] [-r report-file]\n\
++ [-T phone-number] [-U phone-number2] {-f chat-file | chat-script}\n&quot;, program_name);
++ exit(1);
++}
++
++char line[1024];
++
++/*
++ * Send a message to syslog and/or stderr.
++ */
++void logf __V((const char *fmt, ...))
++{
++ va_list args;
++
++#ifdef __STDC__
++ va_start(args, fmt);
++#else
++ char *fmt;
++ va_start(args);
++ fmt = va_arg(args, char *);
++#endif
++
++ vfmtmsg(line, sizeof(line), fmt, args);
++ if (to_log)
++ syslog(LOG_INFO, &quot;%s&quot;, line);
++ if (to_stderr)
++ fprintf(stderr, &quot;%s\n&quot;, line);
++}
++
++/*
++ * Print an error message and terminate.
++ */
++
++void fatal __V((int code, const char *fmt, ...))
++{
++ va_list args;
++
++#ifdef __STDC__
++ va_start(args, fmt);
++#else
++ int code;
++ char *fmt;
++ va_start(args);
++ code = va_arg(args, int);
++ fmt = va_arg(args, char *);
++#endif
++
++ vfmtmsg(line, sizeof(line), fmt, args);
++ if (to_log)
++ syslog(LOG_ERR, &quot;%s&quot;, line);
++ if (to_stderr)
++ fprintf(stderr, &quot;%s\n&quot;, line);
++ terminate(code);
++}
++
++int alarmed = 0;
++
++SIGTYPE sigalrm(signo)
++int signo;
++{
++ int flags;
++
++ alarm(1);
++ alarmed = 1; /* Reset alarm to avoid race window */
++ signal(SIGALRM, sigalrm); /* that can cause hanging in read() */
++
++ if ((flags = fcntl(0, F_GETFL, 0)) == -1)
++ fatal(2, &quot;Can't get file mode flags on stdin: %m&quot;);
++
++ if (fcntl(0, F_SETFL, flags | O_NONBLOCK) == -1)
++ fatal(2, &quot;Can't set file mode flags on stdin: %m&quot;);
++
++ if (verbose)
++ logf(&quot;alarm&quot;);
++}
++
++void unalarm()
++{
++ int flags;
++
++ if ((flags = fcntl(0, F_GETFL, 0)) == -1)
++ fatal(2, &quot;Can't get file mode flags on stdin: %m&quot;);
++
++ if (fcntl(0, F_SETFL, flags &amp; ~O_NONBLOCK) == -1)
++ fatal(2, &quot;Can't set file mode flags on stdin: %m&quot;);
++}
++
++SIGTYPE sigint(signo)
++int signo;
++{
++ fatal(2, &quot;SIGINT&quot;);
++}
++
++SIGTYPE sigterm(signo)
++int signo;
++{
++ fatal(2, &quot;SIGTERM&quot;);
++}
++
++SIGTYPE sighup(signo)
++int signo;
++{
++ fatal(2, &quot;SIGHUP&quot;);
++}
++
++void init()
++{
++ signal(SIGINT, sigint);
++ signal(SIGTERM, sigterm);
++ signal(SIGHUP, sighup);
++
++ set_tty_parameters();
++ signal(SIGALRM, sigalrm);
++ alarm(0);
++ alarmed = 0;
++}
++
++void set_tty_parameters()
++{
++#if defined(get_term_param)
++ term_parms t;
++
++ if (get_term_param (&amp;t) &lt; 0)
++ fatal(2, &quot;Can't get terminal parameters: %m&quot;);
++
++ saved_tty_parameters = t;
++ have_tty_parameters = 1;
++
++ t.c_iflag |= IGNBRK | ISTRIP | IGNPAR;
++ t.c_oflag = 0;
++ t.c_lflag = 0;
++ t.c_cc[VERASE] =
++ t.c_cc[VKILL] = 0;
++ t.c_cc[VMIN] = 1;
++ t.c_cc[VTIME] = 0;
++
++ if (set_term_param (&amp;t) &lt; 0)
++ fatal(2, &quot;Can't set terminal parameters: %m&quot;);
++#endif
++}
++
++void break_sequence()
++{
++#ifdef TERMIOS
++ tcsendbreak (0, 0);
++#endif
++}
++
++void terminate(status)
++int status;
++{
++ static int terminating = 0;
++
++ if (terminating)
++ exit(status);
++ terminating = 1;
++ echo_stderr(-1);
++/*
++ * Allow the last of the report string to be gathered before we terminate.
++ */
++ if (report_gathering) {
++ int c, rep_len;
++
++ rep_len = strlen(report_buffer);
++ while (rep_len + 1 &lt;= sizeof(report_buffer)) {
++ alarm(1);
++ c = get_char();
++ alarm(0);
++ if (c &lt; 0 || iscntrl(c))
++ break;
++ report_buffer[rep_len] = c;
++ ++rep_len;
++ }
++ report_buffer[rep_len] = 0;
++ fprintf (report_fp, &quot;chat: %s\n&quot;, report_buffer);
++ }
++ if (report_file != (char *) 0 &amp;&amp; report_fp != (FILE *) NULL) {
++ if (verbose)
++ fprintf (report_fp, &quot;Closing \&quot;%s\&quot;.\n&quot;, report_file);
++ fclose (report_fp);
++ report_fp = (FILE *) NULL;
++ }
++
++#if defined(get_term_param)
++ if (have_tty_parameters) {
++ if (set_term_param (&amp;saved_tty_parameters) &lt; 0)
++ fatal(2, &quot;Can't restore terminal parameters: %m&quot;);
++ }
++#endif
++
++ exit(status);
++}
++
++/*
++ * 'Clean up' this string.
++ */
++char *clean(s, sending)
++register char *s;
++int sending; /* set to 1 when sending (putting) this string. */
++{
++ char temp[STR_LEN], env_str[STR_LEN], cur_chr;
++ register char *s1, *phchar;
++ int add_return = sending;
++#define isoctal(chr) (((chr) &gt;= '0') &amp;&amp; ((chr) &lt;= '7'))
++#define isalnumx(chr) ((((chr) &gt;= '0') &amp;&amp; ((chr) &lt;= '9')) \
++ || (((chr) &gt;= 'a') &amp;&amp; ((chr) &lt;= 'z')) \
++ || (((chr) &gt;= 'A') &amp;&amp; ((chr) &lt;= 'Z')) \
++ || (chr) == '_')
++
++ s1 = temp;
++ while (*s) {
++ cur_chr = *s++;
++ if (cur_chr == '^') {
++ cur_chr = *s++;
++ if (cur_chr == '\0') {
++ *s1++ = '^';
++ break;
++ }
++ cur_chr &amp;= 0x1F;
++ if (cur_chr != 0) {
++ *s1++ = cur_chr;
++ }
++ continue;
++ }
++
++ if (use_env &amp;&amp; cur_chr == '$') { /* ARI */
++ phchar = env_str;
++ while (isalnumx(*s))
++ *phchar++ = *s++;
++ *phchar = '\0';
++ phchar = getenv(env_str);
++ if (phchar)
++ while (*phchar)
++ *s1++ = *phchar++;
++ continue;
++ }
++
++ if (cur_chr != '\\') {
++ *s1++ = cur_chr;
++ continue;
++ }
++
++ cur_chr = *s++;
++ if (cur_chr == '\0') {
++ if (sending) {
++ *s1++ = '\\';
++ *s1++ = '\\';
++ }
++ break;
++ }
++
++ switch (cur_chr) {
++ case 'b':
++ *s1++ = '\b';
++ break;
++
++ case 'c':
++ if (sending &amp;&amp; *s == '\0')
++ add_return = 0;
++ else
++ *s1++ = cur_chr;
++ break;
++
++ case '\\':
++ case 'K':
++ case 'p':
++ case 'd':
++ if (sending)
++ *s1++ = '\\';
++ *s1++ = cur_chr;
++ break;
++
++ case 'T':
++ if (sending &amp;&amp; phone_num) {
++ for (phchar = phone_num; *phchar != '\0'; phchar++)
++ *s1++ = *phchar;
++ }
++ else {
++ *s1++ = '\\';
++ *s1++ = 'T';
++ }
++ break;
++
++ case 'U':
++ if (sending &amp;&amp; phone_num2) {
++ for (phchar = phone_num2; *phchar != '\0'; phchar++)
++ *s1++ = *phchar;
++ }
++ else {
++ *s1++ = '\\';
++ *s1++ = 'U';
++ }
++ break;
++
++ case 'q':
++ quiet = 1;
++ break;
++
++ case 'r':
++ *s1++ = '\r';
++ break;
++
++ case 'n':
++ *s1++ = '\n';
++ break;
++
++ case 's':
++ *s1++ = ' ';
++ break;
++
++ case 't':
++ *s1++ = '\t';
++ break;
++
++ case 'N':
++ if (sending) {
++ *s1++ = '\\';
++ *s1++ = '\0';
++ }
++ else
++ *s1++ = 'N';
++ break;
++
++ case '$': /* ARI */
++ if (use_env) {
++ *s1++ = cur_chr;
++ break;
++ }
++ /* FALL THROUGH */
++
++ default:
++ if (isoctal (cur_chr)) {
++ cur_chr &amp;= 0x07;
++ if (isoctal (*s)) {
++ cur_chr &lt;&lt;= 3;
++ cur_chr |= *s++ - '0';
++ if (isoctal (*s)) {
++ cur_chr &lt;&lt;= 3;
++ cur_chr |= *s++ - '0';
++ }
++ }
++
++ if (cur_chr != 0 || sending) {
++ if (sending &amp;&amp; (cur_chr == '\\' || cur_chr == 0))
++ *s1++ = '\\';
++ *s1++ = cur_chr;
++ }
++ break;
++ }
++
++ if (sending)
++ *s1++ = '\\';
++ *s1++ = cur_chr;
++ break;
++ }
++ }
++
++ if (add_return)
++ *s1++ = '\r';
++
++ *s1++ = '\0'; /* guarantee closure */
++ *s1++ = '\0'; /* terminate the string */
++ return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */
++}
++
++/*
++ * A modified version of 'strtok'. This version skips \ sequences.
++ */
++
++char *expect_strtok (s, term)
++ char *s, *term;
++{
++ static char *str = &quot;&quot;;
++ int escape_flag = 0;
++ char *result;
++
++/*
++ * If a string was specified then do initial processing.
++ */
++ if (s)
++ str = s;
++
++/*
++ * If this is the escape flag then reset it and ignore the character.
++ */
++ if (*str)
++ result = str;
++ else
++ result = (char *) 0;
++
++ while (*str) {
++ if (escape_flag) {
++ escape_flag = 0;
++ ++str;
++ continue;
++ }
++
++ if (*str == '\\') {
++ ++str;
++ escape_flag = 1;
++ continue;
++ }
++
++/*
++ * If this is not in the termination string, continue.
++ */
++ if (strchr (term, *str) == (char *) 0) {
++ ++str;
++ continue;
++ }
++
++/*
++ * This is the terminator. Mark the end of the string and stop.
++ */
++ *str++ = '\0';
++ break;
++ }
++ return (result);
++}
++
++/*
++ * Process the expect string
++ */
++
++void chat_expect (s)
++char *s;
++{
++ char *expect;
++ char *reply;
++
++ if (strcmp(s, &quot;HANGUP&quot;) == 0) {
++ ++hup_next;
++ return;
++ }
++
++ if (strcmp(s, &quot;ABORT&quot;) == 0) {
++ ++abort_next;
++ return;
++ }
++
++ if (strcmp(s, &quot;CLR_ABORT&quot;) == 0) {
++ ++clear_abort_next;
++ return;
++ }
++
++ if (strcmp(s, &quot;REPORT&quot;) == 0) {
++ ++report_next;
++ return;
++ }
++
++ if (strcmp(s, &quot;CLR_REPORT&quot;) == 0) {
++ ++clear_report_next;
++ return;
++ }
++
++ if (strcmp(s, &quot;TIMEOUT&quot;) == 0) {
++ ++timeout_next;
++ return;
++ }
++
++ if (strcmp(s, &quot;ECHO&quot;) == 0) {
++ ++echo_next;
++ return;
++ }
++
++ if (strcmp(s, &quot;SAY&quot;) == 0) {
++ ++say_next;
++ return;
++ }
++
++/*
++ * Fetch the expect and reply string.
++ */
++ for (;;) {
++ expect = expect_strtok (s, &quot;-&quot;);
++ s = (char *) 0;
++
++ if (expect == (char *) 0)
++ return;
++
++ reply = expect_strtok (s, &quot;-&quot;);
++
++/*
++ * Handle the expect string. If successful then exit.
++ */
++ if (get_string (expect))
++ return;
++
++/*
++ * If there is a sub-reply string then send it. Otherwise any condition
++ * is terminal.
++ */
++ if (reply == (char *) 0 || exit_code != 3)
++ break;
++
++ chat_send (reply);
++ }
++
++/*
++ * The expectation did not occur. This is terminal.
++ */
++ if (fail_reason)
++ logf(&quot;Failed (%s)&quot;, fail_reason);
++ else
++ logf(&quot;Failed&quot;);
++ terminate(exit_code);
++}
++
++/*
++ * Translate the input character to the appropriate string for printing
++ * the data.
++ */
++
++char *character(c)
++int c;
++{
++ static char string[10];
++ char *meta;
++
++ meta = (c &amp; 0x80) ? &quot;M-&quot; : &quot;&quot;;
++ c &amp;= 0x7F;
++
++ if (c &lt; 32)
++ sprintf(string, &quot;%s^%c&quot;, meta, (int)c + '@');
++ else if (c == 127)
++ sprintf(string, &quot;%s^?&quot;, meta);
++ else
++ sprintf(string, &quot;%s%c&quot;, meta, c);
++
++ return (string);
++}
++
++/*
++ * process the reply string
++ */
++void chat_send (s)
++register char *s;
++{
++ char file_data[STR_LEN];
++
++ if (say_next) {
++ say_next = 0;
++ s = clean(s, 1);
++ write(2, s, strlen(s));
++ free(s);
++ return;
++ }
++
++ if (hup_next) {
++ hup_next = 0;
++ if (strcmp(s, &quot;OFF&quot;) == 0)
++ signal(SIGHUP, SIG_IGN);
++ else
++ signal(SIGHUP, sighup);
++ return;
++ }
++
++ if (echo_next) {
++ echo_next = 0;
++ echo = (strcmp(s, &quot;ON&quot;) == 0);
++ return;
++ }
++
++ if (abort_next) {
++ char *s1;
++
++ abort_next = 0;
++
++ if (n_aborts &gt;= MAX_ABORTS)
++ fatal(2, &quot;Too many ABORT strings&quot;);
++
++ s1 = clean(s, 0);
++
++ if (strlen(s1) &gt; strlen(s)
++ || strlen(s1) + 1 &gt; sizeof(fail_buffer))
++ fatal(1, &quot;Illegal or too-long ABORT string ('%v')&quot;, s);
++
++ abort_string[n_aborts++] = s1;
++
++ if (verbose)
++ logf(&quot;abort on (%v)&quot;, s);
++ return;
++ }
++
++ if (clear_abort_next) {
++ char *s1;
++ int i;
++ int old_max;
++ int pack = 0;
++
++ clear_abort_next = 0;
++
++ s1 = clean(s, 0);
++
++ if (strlen(s1) &gt; strlen(s)
++ || strlen(s1) + 1 &gt; sizeof(fail_buffer))
++ fatal(1, &quot;Illegal or too-long CLR_ABORT string ('%v')&quot;, s);
++
++ old_max = n_aborts;
++ for (i=0; i &lt; n_aborts; i++) {
++ if ( strcmp(s1,abort_string[i]) == 0 ) {
++ free(abort_string[i]);
++ abort_string[i] = NULL;
++ pack++;
++ n_aborts--;
++ if (verbose)
++ logf(&quot;clear abort on (%v)&quot;, s);
++ }
++ }
++ free(s1);
++ if (pack)
++ pack_array(abort_string,old_max);
++ return;
++ }
++
++ if (report_next) {
++ char *s1;
++
++ report_next = 0;
++ if (n_reports &gt;= MAX_REPORTS)
++ fatal(2, &quot;Too many REPORT strings&quot;);
++
++ s1 = clean(s, 0);
++
++ if (strlen(s1) &gt; strlen(s) || strlen(s1) &gt; sizeof fail_buffer - 1)
++ fatal(1, &quot;Illegal or too-long REPORT string ('%v')&quot;, s);
++
++ report_string[n_reports++] = s1;
++
++ if (verbose)
++ logf(&quot;report (%v)&quot;, s);
++ return;
++ }
++
++ if (clear_report_next) {
++ char *s1;
++ int i;
++ int old_max;
++ int pack = 0;
++
++ clear_report_next = 0;
++
++ s1 = clean(s, 0);
++
++ if (strlen(s1) &gt; strlen(s) || strlen(s1) &gt; sizeof fail_buffer - 1)
++ fatal(1, &quot;Illegal or too-long REPORT string ('%v')&quot;, s);
++
++ old_max = n_reports;
++ for (i=0; i &lt; n_reports; i++) {
++ if ( strcmp(s1,report_string[i]) == 0 ) {
++ free(report_string[i]);
++ report_string[i] = NULL;
++ pack++;
++ n_reports--;
++ if (verbose)
++ logf(&quot;clear report (%v)&quot;, s);
++ }
++ }
++ free(s1);
++ if (pack)
++ pack_array(report_string,old_max);
++
++ return;
++ }
++
++ if (timeout_next) {
++ timeout_next = 0;
++ timeout = atoi(s);
++
++ if (timeout &lt;= 0)
++ timeout = DEFAULT_CHAT_TIMEOUT;
++
++ if (verbose)
++ logf(&quot;timeout set to %d seconds&quot;, timeout);
++
++ return;
++ }
++
++ /*
++ * The syntax @filename means read the string to send from the
++ * file `filename'.
++ */
++ if (s[0] == '@') {
++ /* skip the @ and any following white-space */
++ char *fn = s;
++ while (*++fn == ' ' || *fn == '\t')
++ ;
++
++ if (*fn != 0) {
++ FILE *f;
++ int n = 0;
++
++ /* open the file and read until STR_LEN-1 bytes or end-of-file */
++ f = fopen(fn, &quot;r&quot;);
++ if (f == NULL)
++ fatal(1, &quot;%s -- open failed: %m&quot;, fn);
++ while (n &lt; STR_LEN - 1) {
++ int nr = fread(&amp;file_data[n], 1, STR_LEN - 1 - n, f);
++ if (nr &lt; 0)
++ fatal(1, &quot;%s -- read error&quot;, fn);
++ if (nr == 0)
++ break;
++ n += nr;
++ }
++ fclose(f);
++
++ /* use the string we got as the string to send,
++ but trim off the final newline if any. */
++ if (n &gt; 0 &amp;&amp; file_data[n-1] == '\n')
++ --n;
++ file_data[n] = 0;
++ s = file_data;
++ }
++ }
++
++ if (strcmp(s, &quot;EOT&quot;) == 0)
++ s = &quot;^D\\c&quot;;
++ else if (strcmp(s, &quot;BREAK&quot;) == 0)
++ s = &quot;\\K\\c&quot;;
++
++ if (!put_string(s))
++ fatal(1, &quot;Failed&quot;);
++}
++
++int get_char()
++{
++ int status;
++ char c;
++
++ status = read(0, &amp;c, 1);
++
++ switch (status) {
++ case 1:
++ return ((int)c &amp; 0x7F);
++
++ default:
++ logf(&quot;warning: read() on stdin returned %d&quot;, status);
++
++ case -1:
++ if ((status = fcntl(0, F_GETFL, 0)) == -1)
++ fatal(2, &quot;Can't get file mode flags on stdin: %m&quot;);
++
++ if (fcntl(0, F_SETFL, status &amp; ~O_NONBLOCK) == -1)
++ fatal(2, &quot;Can't set file mode flags on stdin: %m&quot;);
++
++ return (-1);
++ }
++}
++
++int put_char(c)
++int c;
++{
++ int status;
++ char ch = c;
++
++ usleep(10000); /* inter-character typing delay (?) */
++
++ status = write(1, &amp;ch, 1);
++
++ switch (status) {
++ case 1:
++ return (0);
++
++ default:
++ logf(&quot;warning: write() on stdout returned %d&quot;, status);
++
++ case -1:
++ if ((status = fcntl(0, F_GETFL, 0)) == -1)
++ fatal(2, &quot;Can't get file mode flags on stdin, %m&quot;);
++
++ if (fcntl(0, F_SETFL, status &amp; ~O_NONBLOCK) == -1)
++ fatal(2, &quot;Can't set file mode flags on stdin: %m&quot;);
++
++ return (-1);
++ }
++}
++
++int write_char (c)
++int c;
++{
++ if (alarmed || put_char(c) &lt; 0) {
++ alarm(0);
++ alarmed = 0;
++
++ if (verbose) {
++ if (errno == EINTR || errno == EWOULDBLOCK)
++ logf(&quot; -- write timed out&quot;);
++ else
++ logf(&quot; -- write failed: %m&quot;);
++ }
++ return (0);
++ }
++ return (1);
++}
++
++int put_string (s)
++register char *s;
++{
++ quiet = 0;
++ s = clean(s, 1);
++
++ if (verbose) {
++ if (quiet)
++ logf(&quot;send (??????)&quot;);
++ else
++ logf(&quot;send (%v)&quot;, s);
++ }
++
++ alarm(timeout); alarmed = 0;
++
++ while (*s) {
++ register char c = *s++;
++
++ if (c != '\\') {
++ if (!write_char (c))
++ return 0;
++ continue;
++ }
++
++ c = *s++;
++ switch (c) {
++ case 'd':
++ sleep(1);
++ break;
++
++ case 'K':
++ break_sequence();
++ break;
++
++ case 'p':
++ usleep(10000); /* 1/100th of a second (arg is microseconds) */
++ break;
++
++ default:
++ if (!write_char (c))
++ return 0;
++ break;
++ }
++ }
++
++ alarm(0);
++ alarmed = 0;
++ return (1);
++}
++
++/*
++ * Echo a character to stderr.
++ * When called with -1, a '\n' character is generated when
++ * the cursor is not at the beginning of a line.
++ */
++void echo_stderr(n)
++int n;
++{
++ static int need_lf;
++ char *s;
++
++ switch (n) {
++ case '\r': /* ignore '\r' */
++ break;
++ case -1:
++ if (need_lf == 0)
++ break;
++ /* fall through */
++ case '\n':
++ write(2, &quot;\n&quot;, 1);
++ need_lf = 0;
++ break;
++ default:
++ s = character(n);
++ write(2, s, strlen(s));
++ need_lf = 1;
++ break;
++ }
++}
++
++/*
++ * 'Wait for' this string to appear on this file descriptor.
++ */
++int get_string(string)
++register char *string;
++{
++ char temp[STR_LEN];
++ int c, printed = 0, len, minlen;
++ register char *s = temp, *end = s + STR_LEN;
++ char *logged = temp;
++
++ fail_reason = (char *)0;
++ string = clean(string, 0);
++ len = strlen(string);
++ minlen = (len &gt; sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1;
++
++ if (verbose)
++ logf(&quot;expect (%v)&quot;, string);
++
++ if (len &gt; STR_LEN) {
++ logf(&quot;expect string is too long&quot;);
++ exit_code = 1;
++ return 0;
++ }
++
++ if (len == 0) {
++ if (verbose)
++ logf(&quot;got it&quot;);
++ return (1);
++ }
++
++ alarm(timeout);
++ alarmed = 0;
++
++ while ( ! alarmed &amp;&amp; (c = get_char()) &gt;= 0) {
++ int n, abort_len, report_len;
++
++ if (echo)
++ echo_stderr(c);
++ if (verbose &amp;&amp; c == '\n') {
++ if (s == logged)
++ logf(&quot;&quot;); /* blank line */
++ else
++ logf(&quot;%0.*v&quot;, s - logged, logged);
++ logged = s + 1;
++ }
++
++ *s++ = c;
++
++ if (verbose &amp;&amp; s &gt;= logged + 80) {
++ logf(&quot;%0.*v&quot;, s - logged, logged);
++ logged = s;
++ }
++
++ if (Verbose) {
++ if (c == '\n')
++ fputc( '\n', stderr );
++ else if (c != '\r')
++ fprintf( stderr, &quot;%s&quot;, character(c) );
++ }
++
++ if (!report_gathering) {
++ for (n = 0; n &lt; n_reports; ++n) {
++ if ((report_string[n] != (char*) NULL) &amp;&amp;
++ s - temp &gt;= (report_len = strlen(report_string[n])) &amp;&amp;
++ strncmp(s - report_len, report_string[n], report_len) == 0) {
++ time_t time_now = time ((time_t*) NULL);
++ struct tm* tm_now = localtime (&amp;time_now);
++
++ strftime (report_buffer, 20, &quot;%b %d %H:%M:%S &quot;, tm_now);
++ strcat (report_buffer, report_string[n]);
++
++ report_string[n] = (char *) NULL;
++ report_gathering = 1;
++ break;
++ }
++ }
++ }
++ else {
++ if (!iscntrl (c)) {
++ int rep_len = strlen (report_buffer);
++ report_buffer[rep_len] = c;
++ report_buffer[rep_len + 1] = '\0';
++ }
++ else {
++ report_gathering = 0;
++ fprintf (report_fp, &quot;chat: %s\n&quot;, report_buffer);
++ }
++ }
++
++ if (s - temp &gt;= len &amp;&amp;
++ c == string[len - 1] &amp;&amp;
++ strncmp(s - len, string, len) == 0) {
++ if (verbose) {
++ if (s &gt; logged)
++ logf(&quot;%0.*v&quot;, s - logged, logged);
++ logf(&quot; -- got it\n&quot;);
++ }
++
++ alarm(0);
++ alarmed = 0;
++ return (1);
++ }
++
++ for (n = 0; n &lt; n_aborts; ++n) {
++ if (s - temp &gt;= (abort_len = strlen(abort_string[n])) &amp;&amp;
++ strncmp(s - abort_len, abort_string[n], abort_len) == 0) {
++ if (verbose) {
++ if (s &gt; logged)
++ logf(&quot;%0.*v&quot;, s - logged, logged);
++ logf(&quot; -- failed&quot;);
++ }
++
++ alarm(0);
++ alarmed = 0;
++ exit_code = n + 4;
++ strcpy(fail_reason = fail_buffer, abort_string[n]);
++ return (0);
++ }
++ }
++
++ if (s &gt;= end) {
++ if (logged &lt; s - minlen) {
++ if (verbose)
++ logf(&quot;%0.*v&quot;, s - logged, logged);
++ logged = s;
++ }
++ s -= minlen;
++ memmove(temp, s, minlen);
++ logged = temp + (logged - s);
++ s = temp + minlen;
++ }
++
++ if (alarmed &amp;&amp; verbose)
++ logf(&quot;warning: alarm synchronization problem&quot;);
++ }
++
++ alarm(0);
++
++ if (verbose &amp;&amp; printed) {
++ if (alarmed)
++ logf(&quot; -- read timed out&quot;);
++ else
++ logf(&quot; -- read failed: %m&quot;);
++ }
++
++ exit_code = 3;
++ alarmed = 0;
++ return (0);
++}
++
++/*
++ * Gross kludge to handle Solaris versions &gt;= 2.6 having usleep.
++ */
++#ifdef SOL2
++#include &lt;sys/param.h&gt;
++#if MAXUID &gt; 65536 /* then this is Solaris 2.6 or later */
++#undef NO_USLEEP
++#endif
++#endif /* SOL2 */
++
++#ifdef NO_USLEEP
++#include &lt;sys/types.h&gt;
++#include &lt;sys/time.h&gt;
++
++/*
++ usleep -- support routine for 4.2BSD system call emulations
++ last edit: 29-Oct-1984 D A Gwyn
++ */
++
++extern int select();
++
++int
++usleep( usec ) /* returns 0 if ok, else -1 */
++ long usec; /* delay in microseconds */
++{
++ static struct { /* `timeval' */
++ long tv_sec; /* seconds */
++ long tv_usec; /* microsecs */
++ } delay; /* _select() timeout */
++
++ delay.tv_sec = usec / 1000000L;
++ delay.tv_usec = usec % 1000000L;
++
++ return select(0, (long *)0, (long *)0, (long *)0, &amp;delay);
++}
++#endif
++
++void
++pack_array (array, end)
++ char **array; /* The address of the array of string pointers */
++ int end; /* The index of the next free entry before CLR_ */
++{
++ int i, j;
++
++ for (i = 0; i &lt; end; i++) {
++ if (array[i] == NULL) {
++ for (j = i+1; j &lt; end; ++j)
++ if (array[j] != NULL)
++ array[i++] = array[j];
++ for (; i &lt; end; ++i)
++ array[i] = NULL;
++ break;
++ }
++ }
++}
++
++/*
++ * vfmtmsg - format a message into a buffer. Like vsprintf except we
++ * also specify the length of the output buffer, and we handle the
++ * %m (error message) format.
++ * Doesn't do floating-point formats.
++ * Returns the number of chars put into buf.
++ */
++#define OUTCHAR(c) (buflen &gt; 0? (--buflen, *buf++ = (c)): 0)
++
++int
++vfmtmsg(buf, buflen, fmt, args)
++ char *buf;
++ int buflen;
++ const char *fmt;
++ va_list args;
++{
++ int c, i, n;
++ int width, prec, fillch;
++ int base, len, neg, quoted;
++ unsigned long val = 0;
++ char *str, *buf0;
++ const char *f;
++ unsigned char *p;
++ char num[32];
++ static char hexchars[] = &quot;0123456789abcdef&quot;;
++
++ buf0 = buf;
++ --buflen;
++ while (buflen &gt; 0) {
++ for (f = fmt; *f != '%' &amp;&amp; *f != 0; ++f)
++ ;
++ if (f &gt; fmt) {
++ len = f - fmt;
++ if (len &gt; buflen)
++ len = buflen;
++ memcpy(buf, fmt, len);
++ buf += len;
++ buflen -= len;
++ fmt = f;
++ }
++ if (*fmt == 0)
++ break;
++ c = *++fmt;
++ width = prec = 0;
++ fillch = ' ';
++ if (c == '0') {
++ fillch = '0';
++ c = *++fmt;
++ }
++ if (c == '*') {
++ width = va_arg(args, int);
++ c = *++fmt;
++ } else {
++ while (isdigit(c)) {
++ width = width * 10 + c - '0';
++ c = *++fmt;
++ }
++ }
++ if (c == '.') {
++ c = *++fmt;
++ if (c == '*') {
++ prec = va_arg(args, int);
++ c = *++fmt;
++ } else {
++ while (isdigit(c)) {
++ prec = prec * 10 + c - '0';
++ c = *++fmt;
++ }
++ }
++ }
++ str = 0;
++ base = 0;
++ neg = 0;
++ ++fmt;
++ switch (c) {
++ case 'd':
++ i = va_arg(args, int);
++ if (i &lt; 0) {
++ neg = 1;
++ val = -i;
++ } else
++ val = i;
++ base = 10;
++ break;
++ case 'o':
++ val = va_arg(args, unsigned int);
++ base = 8;
++ break;
++ case 'x':
++ val = va_arg(args, unsigned int);
++ base = 16;
++ break;
++ case 'p':
++ val = (unsigned long) va_arg(args, void *);
++ base = 16;
++ neg = 2;
++ break;
++ case 's':
++ str = va_arg(args, char *);
++ break;
++ case 'c':
++ num[0] = va_arg(args, int);
++ num[1] = 0;
++ str = num;
++ break;
++ case 'm':
++ str = strerror(errno);
++ break;
++ case 'v': /* &quot;visible&quot; string */
++ case 'q': /* quoted string */
++ quoted = c == 'q';
++ p = va_arg(args, unsigned char *);
++ if (fillch == '0' &amp;&amp; prec &gt; 0) {
++ n = prec;
++ } else {
++ n = strlen((char *)p);
++ if (prec &gt; 0 &amp;&amp; prec &lt; n)
++ n = prec;
++ }
++ while (n &gt; 0 &amp;&amp; buflen &gt; 0) {
++ c = *p++;
++ --n;
++ if (!quoted &amp;&amp; c &gt;= 0x80) {
++ OUTCHAR('M');
++ OUTCHAR('-');
++ c -= 0x80;
++ }
++ if (quoted &amp;&amp; (c == '&quot;' || c == '\\'))
++ OUTCHAR('\\');
++ if (c &lt; 0x20 || (0x7f &lt;= c &amp;&amp; c &lt; 0xa0)) {
++ if (quoted) {
++ OUTCHAR('\\');
++ switch (c) {
++ case '\t': OUTCHAR('t'); break;
++ case '\n': OUTCHAR('n'); break;
++ case '\b': OUTCHAR('b'); break;
++ case '\f': OUTCHAR('f'); break;
++ default:
++ OUTCHAR('x');
++ OUTCHAR(hexchars[c &gt;&gt; 4]);
++ OUTCHAR(hexchars[c &amp; 0xf]);
++ }
++ } else {
++ if (c == '\t')
++ OUTCHAR(c);
++ else {
++ OUTCHAR('^');
++ OUTCHAR(c ^ 0x40);
++ }
++ }
++ } else
++ OUTCHAR(c);
++ }
++ continue;
++ default:
++ *buf++ = '%';
++ if (c != '%')
++ --fmt; /* so %z outputs %z etc. */
++ --buflen;
++ continue;
++ }
++ if (base != 0) {
++ str = num + sizeof(num);
++ *--str = 0;
++ while (str &gt; num + neg) {
++ *--str = hexchars[val % base];
++ val = val / base;
++ if (--prec &lt;= 0 &amp;&amp; val == 0)
++ break;
++ }
++ switch (neg) {
++ case 1:
++ *--str = '-';
++ break;
++ case 2:
++ *--str = 'x';
++ *--str = '0';
++ break;
++ }
++ len = num + sizeof(num) - 1 - str;
++ } else {
++ len = strlen(str);
++ if (prec &gt; 0 &amp;&amp; len &gt; prec)
++ len = prec;
++ }
++ if (width &gt; 0) {
++ if (width &gt; buflen)
++ width = buflen;
++ if ((n = width - len) &gt; 0) {
++ buflen -= n;
++ for (; n &gt; 0; --n)
++ *buf++ = fillch;
++ }
++ }
++ if (len &gt; buflen)
++ len = buflen;
++ memcpy(buf, str, len);
++ buf += len;
++ buflen -= len;
++ }
++ *buf = 0;
++ return buf - buf0;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/chat/chat.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/common/zlib.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/common/zlib.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/common/zlib.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,5376 @@
++/*
++ * This file is derived from various .h and .c files from the zlib-1.0.4
++ * distribution by Jean-loup Gailly and Mark Adler, with some additions
++ * by Paul Mackerras to aid in implementing Deflate compression and
++ * decompression for PPP packets. See zlib.h for conditions of
++ * distribution and use.
++ *
++ * Changes that have been made include:
++ * - added Z_PACKET_FLUSH (see zlib.h for details)
++ * - added inflateIncomp and deflateOutputPending
++ * - allow strm-&gt;next_out to be NULL, meaning discard the output
++ *
++ * $Id: zlib.c 195720 2001-06-11 11:44:34Z gc $
++ */
++
++/*
++ * ==FILEVERSION 971210==
++ *
++ * This marker is used by the Linux installation script to determine
++ * whether an up-to-date version of this file is already installed.
++ */
++
++#define NO_DUMMY_DECL
++#define NO_ZCFUNCS
++#define MY_ZCALLOC
++
++#if defined(__FreeBSD__) &amp;&amp; (defined(KERNEL) || defined(_KERNEL))
++#define inflate inflate_ppp /* FreeBSD already has an inflate :-( */
++#endif
++
++
++/* +++ zutil.h */
++/* zutil.h -- internal interface and configuration of the compression library
++ * Copyright (C) 1995-1996 Jean-loup Gailly.
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* WARNING: this file should *not* be used by applications. It is
++ part of the implementation of the compression library and is
++ subject to change. Applications should only use zlib.h.
++ */
++
++/* From: zutil.h,v 1.16 1996/07/24 13:41:13 me Exp $ */
++
++#ifndef _Z_UTIL_H
++#define _Z_UTIL_H
++
++#include &quot;zlib.h&quot;
++
++#if defined(KERNEL) || defined(_KERNEL)
++/* Assume this is a *BSD or SVR4 kernel */
++#include &lt;sys/types.h&gt;
++#include &lt;sys/time.h&gt;
++#include &lt;sys/systm.h&gt;
++#undef u
++# define HAVE_MEMCPY
++# define memcpy(d, s, n) bcopy((s), (d), (n))
++# define memset(d, v, n) bzero((d), (n))
++# define memcmp bcmp
++
++#else
++#if defined(__KERNEL__)
++/* Assume this is a Linux kernel */
++#include &lt;linux/string.h&gt;
++#define HAVE_MEMCPY
++
++#else /* not kernel */
++
++#if defined(MSDOS)||defined(VMS)||defined(CRAY)||defined(WIN32)||defined(RISCOS)
++# include &lt;stddef.h&gt;
++# include &lt;errno.h&gt;
++#else
++ extern int errno;
++#endif
++#ifdef STDC
++# include &lt;string.h&gt;
++# include &lt;stdlib.h&gt;
++#endif
++#endif /* __KERNEL__ */
++#endif /* _KERNEL || KERNEL */
++
++#ifndef local
++# define local static
++#endif
++/* compile with -Dlocal if your debugger can't find static symbols */
++
++typedef unsigned char uch;
++typedef uch FAR uchf;
++typedef unsigned short ush;
++typedef ush FAR ushf;
++typedef unsigned long ulg;
++
++extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */
++/* (size given to avoid silly warnings with Visual C++) */
++
++#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
++
++#define ERR_RETURN(strm,err) \
++ return (strm-&gt;msg = (char*)ERR_MSG(err), (err))
++/* To be used only when the state is known to be valid */
++
++ /* common constants */
++
++#ifndef DEF_WBITS
++# define DEF_WBITS MAX_WBITS
++#endif
++/* default windowBits for decompression. MAX_WBITS is for compression only */
++
++#if MAX_MEM_LEVEL &gt;= 8
++# define DEF_MEM_LEVEL 8
++#else
++# define DEF_MEM_LEVEL MAX_MEM_LEVEL
++#endif
++/* default memLevel */
++
++#define STORED_BLOCK 0
++#define STATIC_TREES 1
++#define DYN_TREES 2
++/* The three kinds of block type */
++
++#define MIN_MATCH 3
++#define MAX_MATCH 258
++/* The minimum and maximum match lengths */
++
++#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
++
++ /* target dependencies */
++
++#ifdef MSDOS
++# define OS_CODE 0x00
++# ifdef __TURBOC__
++# include &lt;alloc.h&gt;
++# else /* MSC or DJGPP */
++# include &lt;malloc.h&gt;
++# endif
++#endif
++
++#ifdef OS2
++# define OS_CODE 0x06
++#endif
++
++#ifdef WIN32 /* Window 95 &amp; Windows NT */
++# define OS_CODE 0x0b
++#endif
++
++#if defined(VAXC) || defined(VMS)
++# define OS_CODE 0x02
++# define FOPEN(name, mode) \
++ fopen((name), (mode), &quot;mbc=60&quot;, &quot;ctx=stm&quot;, &quot;rfm=fix&quot;, &quot;mrs=512&quot;)
++#endif
++
++#ifdef AMIGA
++# define OS_CODE 0x01
++#endif
++
++#if defined(ATARI) || defined(atarist)
++# define OS_CODE 0x05
++#endif
++
++#ifdef MACOS
++# define OS_CODE 0x07
++#endif
++
++#ifdef __50SERIES /* Prime/PRIMOS */
++# define OS_CODE 0x0F
++#endif
++
++#ifdef TOPS20
++# define OS_CODE 0x0a
++#endif
++
++#if defined(_BEOS_) || defined(RISCOS)
++# define fdopen(fd,mode) NULL /* No fdopen() */
++#endif
++
++ /* Common defaults */
++
++#ifndef OS_CODE
++# define OS_CODE 0x03 /* assume Unix */
++#endif
++
++#ifndef FOPEN
++# define FOPEN(name, mode) fopen((name), (mode))
++#endif
++
++ /* functions */
++
++#ifdef HAVE_STRERROR
++ extern char *strerror OF((int));
++# define zstrerror(errnum) strerror(errnum)
++#else
++# define zstrerror(errnum) &quot;&quot;
++#endif
++
++#if defined(pyr)
++# define NO_MEMCPY
++#endif
++#if (defined(M_I86SM) || defined(M_I86MM)) &amp;&amp; !defined(_MSC_VER)
++ /* Use our own functions for small and medium model with MSC &lt;= 5.0.
++ * You may have to use the same strategy for Borland C (untested).
++ */
++# define NO_MEMCPY
++#endif
++#if defined(STDC) &amp;&amp; !defined(HAVE_MEMCPY) &amp;&amp; !defined(NO_MEMCPY)
++# define HAVE_MEMCPY
++#endif
++#ifdef HAVE_MEMCPY
++# ifdef SMALL_MEDIUM /* MSDOS small or medium model */
++# define zmemcpy _fmemcpy
++# define zmemcmp _fmemcmp
++# define zmemzero(dest, len) _fmemset(dest, 0, len)
++# else
++# define zmemcpy memcpy
++# define zmemcmp memcmp
++# define zmemzero(dest, len) memset(dest, 0, len)
++# endif
++#else
++ extern void zmemcpy OF((Bytef* dest, Bytef* source, uInt len));
++ extern int zmemcmp OF((Bytef* s1, Bytef* s2, uInt len));
++ extern void zmemzero OF((Bytef* dest, uInt len));
++#endif
++
++/* Diagnostic functions */
++#ifdef DEBUG_ZLIB
++# include &lt;stdio.h&gt;
++# ifndef verbose
++# define verbose 0
++# endif
++ extern void z_error OF((char *m));
++# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
++# define Trace(x) fprintf x
++# define Tracev(x) {if (verbose) fprintf x ;}
++# define Tracevv(x) {if (verbose&gt;1) fprintf x ;}
++# define Tracec(c,x) {if (verbose &amp;&amp; (c)) fprintf x ;}
++# define Tracecv(c,x) {if (verbose&gt;1 &amp;&amp; (c)) fprintf x ;}
++#else
++# define Assert(cond,msg)
++# define Trace(x)
++# define Tracev(x)
++# define Tracevv(x)
++# define Tracec(c,x)
++# define Tracecv(c,x)
++#endif
++
++
++typedef uLong (*check_func) OF((uLong check, const Bytef *buf, uInt len));
++
++voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
++void zcfree OF((voidpf opaque, voidpf ptr));
++
++#define ZALLOC(strm, items, size) \
++ (*((strm)-&gt;zalloc))((strm)-&gt;opaque, (items), (size))
++#define ZFREE(strm, addr) (*((strm)-&gt;zfree))((strm)-&gt;opaque, (voidpf)(addr))
++#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
++
++#endif /* _Z_UTIL_H */
++/* --- zutil.h */
++
++/* +++ deflate.h */
++/* deflate.h -- internal compression state
++ * Copyright (C) 1995-1996 Jean-loup Gailly
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* WARNING: this file should *not* be used by applications. It is
++ part of the implementation of the compression library and is
++ subject to change. Applications should only use zlib.h.
++ */
++
++/* From: deflate.h,v 1.10 1996/07/02 12:41:00 me Exp $ */
++
++#ifndef _DEFLATE_H
++#define _DEFLATE_H
++
++/* #include &quot;zutil.h&quot; */
++
++/* ===========================================================================
++ * Internal compression state.
++ */
++
++#define LENGTH_CODES 29
++/* number of length codes, not counting the special END_BLOCK code */
++
++#define LITERALS 256
++/* number of literal bytes 0..255 */
++
++#define L_CODES (LITERALS+1+LENGTH_CODES)
++/* number of Literal or Length codes, including the END_BLOCK code */
++
++#define D_CODES 30
++/* number of distance codes */
++
++#define BL_CODES 19
++/* number of codes used to transfer the bit lengths */
++
++#define HEAP_SIZE (2*L_CODES+1)
++/* maximum heap size */
++
++#define MAX_BITS 15
++/* All codes must not exceed MAX_BITS bits */
++
++#define INIT_STATE 42
++#define BUSY_STATE 113
++#define FINISH_STATE 666
++/* Stream status */
++
++
++/* Data structure describing a single value and its code string. */
++typedef struct ct_data_s {
++ union {
++ ush freq; /* frequency count */
++ ush code; /* bit string */
++ } fc;
++ union {
++ ush dad; /* father node in Huffman tree */
++ ush len; /* length of bit string */
++ } dl;
++} FAR ct_data;
++
++#define Freq fc.freq
++#define Code fc.code
++#define Dad dl.dad
++#define Len dl.len
++
++typedef struct static_tree_desc_s static_tree_desc;
++
++typedef struct tree_desc_s {
++ ct_data *dyn_tree; /* the dynamic tree */
++ int max_code; /* largest code with non zero frequency */
++ static_tree_desc *stat_desc; /* the corresponding static tree */
++} FAR tree_desc;
++
++typedef ush Pos;
++typedef Pos FAR Posf;
++typedef unsigned IPos;
++
++/* A Pos is an index in the character window. We use short instead of int to
++ * save space in the various tables. IPos is used only for parameter passing.
++ */
++
++typedef struct deflate_state {
++ z_streamp strm; /* pointer back to this zlib stream */
++ int status; /* as the name implies */
++ Bytef *pending_buf; /* output still pending */
++ ulg pending_buf_size; /* size of pending_buf */
++ Bytef *pending_out; /* next pending byte to output to the stream */
++ int pending; /* nb of bytes in the pending buffer */
++ int noheader; /* suppress zlib header and adler32 */
++ Byte data_type; /* UNKNOWN, BINARY or ASCII */
++ Byte method; /* STORED (for zip only) or DEFLATED */
++ int last_flush; /* value of flush param for previous deflate call */
++
++ /* used by deflate.c: */
++
++ uInt w_size; /* LZ77 window size (32K by default) */
++ uInt w_bits; /* log2(w_size) (8..16) */
++ uInt w_mask; /* w_size - 1 */
++
++ Bytef *window;
++ /* Sliding window. Input bytes are read into the second half of the window,
++ * and move to the first half later to keep a dictionary of at least wSize
++ * bytes. With this organization, matches are limited to a distance of
++ * wSize-MAX_MATCH bytes, but this ensures that IO is always
++ * performed with a length multiple of the block size. Also, it limits
++ * the window size to 64K, which is quite useful on MSDOS.
++ * To do: use the user input buffer as sliding window.
++ */
++
++ ulg window_size;
++ /* Actual size of window: 2*wSize, except when the user input buffer
++ * is directly used as sliding window.
++ */
++
++ Posf *prev;
++ /* Link to older string with same hash index. To limit the size of this
++ * array to 64K, this link is maintained only for the last 32K strings.
++ * An index in this array is thus a window index modulo 32K.
++ */
++
++ Posf *head; /* Heads of the hash chains or NIL. */
++
++ uInt ins_h; /* hash index of string to be inserted */
++ uInt hash_size; /* number of elements in hash table */
++ uInt hash_bits; /* log2(hash_size) */
++ uInt hash_mask; /* hash_size-1 */
++
++ uInt hash_shift;
++ /* Number of bits by which ins_h must be shifted at each input
++ * step. It must be such that after MIN_MATCH steps, the oldest
++ * byte no longer takes part in the hash key, that is:
++ * hash_shift * MIN_MATCH &gt;= hash_bits
++ */
++
++ long block_start;
++ /* Window position at the beginning of the current output block. Gets
++ * negative when the window is moved backwards.
++ */
++
++ uInt match_length; /* length of best match */
++ IPos prev_match; /* previous match */
++ int match_available; /* set if previous match exists */
++ uInt strstart; /* start of string to insert */
++ uInt match_start; /* start of matching string */
++ uInt lookahead; /* number of valid bytes ahead in window */
++
++ uInt prev_length;
++ /* Length of the best match at previous step. Matches not greater than this
++ * are discarded. This is used in the lazy match evaluation.
++ */
++
++ uInt max_chain_length;
++ /* To speed up deflation, hash chains are never searched beyond this
++ * length. A higher limit improves compression ratio but degrades the
++ * speed.
++ */
++
++ uInt max_lazy_match;
++ /* Attempt to find a better match only when the current match is strictly
++ * smaller than this value. This mechanism is used only for compression
++ * levels &gt;= 4.
++ */
++# define max_insert_length max_lazy_match
++ /* Insert new strings in the hash table only if the match length is not
++ * greater than this length. This saves time but degrades compression.
++ * max_insert_length is used only for compression levels &lt;= 3.
++ */
++
++ int level; /* compression level (1..9) */
++ int strategy; /* favor or force Huffman coding*/
++
++ uInt good_match;
++ /* Use a faster search when the previous match is longer than this */
++
++ int nice_match; /* Stop searching when current match exceeds this */
++
++ /* used by trees.c: */
++ /* Didn't use ct_data typedef below to supress compiler warning */
++ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
++ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
++ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
++
++ struct tree_desc_s l_desc; /* desc. for literal tree */
++ struct tree_desc_s d_desc; /* desc. for distance tree */
++ struct tree_desc_s bl_desc; /* desc. for bit length tree */
++
++ ush bl_count[MAX_BITS+1];
++ /* number of codes at each bit length for an optimal tree */
++
++ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
++ int heap_len; /* number of elements in the heap */
++ int heap_max; /* element of largest frequency */
++ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
++ * The same heap array is used to build all trees.
++ */
++
++ uch depth[2*L_CODES+1];
++ /* Depth of each subtree used as tie breaker for trees of equal frequency
++ */
++
++ uchf *l_buf; /* buffer for literals or lengths */
++
++ uInt lit_bufsize;
++ /* Size of match buffer for literals/lengths. There are 4 reasons for
++ * limiting lit_bufsize to 64K:
++ * - frequencies can be kept in 16 bit counters
++ * - if compression is not successful for the first block, all input
++ * data is still in the window so we can still emit a stored block even
++ * when input comes from standard input. (This can also be done for
++ * all blocks if lit_bufsize is not greater than 32K.)
++ * - if compression is not successful for a file smaller than 64K, we can
++ * even emit a stored file instead of a stored block (saving 5 bytes).
++ * This is applicable only for zip (not gzip or zlib).
++ * - creating new Huffman trees less frequently may not provide fast
++ * adaptation to changes in the input data statistics. (Take for
++ * example a binary file with poorly compressible code followed by
++ * a highly compressible string table.) Smaller buffer sizes give
++ * fast adaptation but have of course the overhead of transmitting
++ * trees more frequently.
++ * - I can't count above 4
++ */
++
++ uInt last_lit; /* running index in l_buf */
++
++ ushf *d_buf;
++ /* Buffer for distances. To simplify the code, d_buf and l_buf have
++ * the same number of elements. To use different lengths, an extra flag
++ * array would be necessary.
++ */
++
++ ulg opt_len; /* bit length of current block with optimal trees */
++ ulg static_len; /* bit length of current block with static trees */
++ ulg compressed_len; /* total bit length of compressed file */
++ uInt matches; /* number of string matches in current block */
++ int last_eob_len; /* bit length of EOB code for last block */
++
++#ifdef DEBUG_ZLIB
++ ulg bits_sent; /* bit length of the compressed data */
++#endif
++
++ ush bi_buf;
++ /* Output buffer. bits are inserted starting at the bottom (least
++ * significant bits).
++ */
++ int bi_valid;
++ /* Number of valid bits in bi_buf. All bits above the last valid bit
++ * are always zero.
++ */
++
++} FAR deflate_state;
++
++/* Output a byte on the stream.
++ * IN assertion: there is enough room in pending_buf.
++ */
++#define put_byte(s, c) {s-&gt;pending_buf[s-&gt;pending++] = (c);}
++
++
++#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
++/* Minimum amount of lookahead, except at the end of the input file.
++ * See deflate.c for comments about the MIN_MATCH+1.
++ */
++
++#define MAX_DIST(s) ((s)-&gt;w_size-MIN_LOOKAHEAD)
++/* In order to simplify the code, particularly on 16 bit machines, match
++ * distances are limited to MAX_DIST instead of WSIZE.
++ */
++
++ /* in trees.c */
++void _tr_init OF((deflate_state *s));
++int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
++ulg _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len,
++ int eof));
++void _tr_align OF((deflate_state *s));
++void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
++ int eof));
++void _tr_stored_type_only OF((deflate_state *));
++
++#endif
++/* --- deflate.h */
++
++/* +++ deflate.c */
++/* deflate.c -- compress data using the deflation algorithm
++ * Copyright (C) 1995-1996 Jean-loup Gailly.
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/*
++ * ALGORITHM
++ *
++ * The &quot;deflation&quot; process depends on being able to identify portions
++ * of the input text which are identical to earlier input (within a
++ * sliding window trailing behind the input currently being processed).
++ *
++ * The most straightforward technique turns out to be the fastest for
++ * most input files: try all possible matches and select the longest.
++ * The key feature of this algorithm is that insertions into the string
++ * dictionary are very simple and thus fast, and deletions are avoided
++ * completely. Insertions are performed at each input character, whereas
++ * string matches are performed only when the previous match ends. So it
++ * is preferable to spend more time in matches to allow very fast string
++ * insertions and avoid deletions. The matching algorithm for small
++ * strings is inspired from that of Rabin &amp; Karp. A brute force approach
++ * is used to find longer strings when a small match has been found.
++ * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
++ * (by Leonid Broukhis).
++ * A previous version of this file used a more sophisticated algorithm
++ * (by Fiala and Greene) which is guaranteed to run in linear amortized
++ * time, but has a larger average cost, uses more memory and is patented.
++ * However the F&amp;G algorithm may be faster for some highly redundant
++ * files if the parameter max_chain_length (described below) is too large.
++ *
++ * ACKNOWLEDGEMENTS
++ *
++ * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
++ * I found it in 'freeze' written by Leonid Broukhis.
++ * Thanks to many people for bug reports and testing.
++ *
++ * REFERENCES
++ *
++ * Deutsch, L.P.,&quot;DEFLATE Compressed Data Format Specification&quot;.
++ * Available in <A HREF="ftp://ds.internic.net/rfc/rfc1951.txt">ftp://ds.internic.net/rfc/rfc1951.txt</A>
++ *
++ * A description of the Rabin and Karp algorithm is given in the book
++ * &quot;Algorithms&quot; by R. Sedgewick, Addison-Wesley, p252.
++ *
++ * Fiala,E.R., and Greene,D.H.
++ * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
++ *
++ */
++
++/* From: deflate.c,v 1.15 1996/07/24 13:40:58 me Exp $ */
++
++/* #include &quot;deflate.h&quot; */
++
++char deflate_copyright[] = &quot; deflate 1.0.4 Copyright 1995-1996 Jean-loup Gailly &quot;;
++/*
++ If you use the zlib library in a product, an acknowledgment is welcome
++ in the documentation of your product. If for some reason you cannot
++ include such an acknowledgment, I would appreciate that you keep this
++ copyright string in the executable of your product.
++ */
++
++/* ===========================================================================
++ * Function prototypes.
++ */
++typedef enum {
++ need_more, /* block not completed, need more input or more output */
++ block_done, /* block flush performed */
++ finish_started, /* finish started, need only more output at next deflate */
++ finish_done /* finish done, accept no more input or output */
++} block_state;
++
++typedef block_state (*compress_func) OF((deflate_state *s, int flush));
++/* Compression function. Returns the block state after the call. */
++
++local void fill_window OF((deflate_state *s));
++local block_state deflate_stored OF((deflate_state *s, int flush));
++local block_state deflate_fast OF((deflate_state *s, int flush));
++local block_state deflate_slow OF((deflate_state *s, int flush));
++local void lm_init OF((deflate_state *s));
++local void putShortMSB OF((deflate_state *s, uInt b));
++local void flush_pending OF((z_streamp strm));
++local int read_buf OF((z_streamp strm, charf *buf, unsigned size));
++#ifdef ASMV
++ void match_init OF((void)); /* asm code initialization */
++ uInt longest_match OF((deflate_state *s, IPos cur_match));
++#else
++local uInt longest_match OF((deflate_state *s, IPos cur_match));
++#endif
++
++#ifdef DEBUG_ZLIB
++local void check_match OF((deflate_state *s, IPos start, IPos match,
++ int length));
++#endif
++
++/* ===========================================================================
++ * Local data
++ */
++
++#define NIL 0
++/* Tail of hash chains */
++
++#ifndef TOO_FAR
++# define TOO_FAR 4096
++#endif
++/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
++
++#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
++/* Minimum amount of lookahead, except at the end of the input file.
++ * See deflate.c for comments about the MIN_MATCH+1.
++ */
++
++/* Values for max_lazy_match, good_match and max_chain_length, depending on
++ * the desired pack level (0..9). The values given below have been tuned to
++ * exclude worst case performance for pathological files. Better values may be
++ * found for specific files.
++ */
++typedef struct config_s {
++ ush good_length; /* reduce lazy search above this match length */
++ ush max_lazy; /* do not perform lazy search above this match length */
++ ush nice_length; /* quit search above this match length */
++ ush max_chain;
++ compress_func func;
++} config;
++
++local config configuration_table[10] = {
++/* good lazy nice chain */
++/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
++/* 1 */ {4, 4, 8, 4, deflate_fast}, /* maximum speed, no lazy matches */
++/* 2 */ {4, 5, 16, 8, deflate_fast},
++/* 3 */ {4, 6, 32, 32, deflate_fast},
++
++/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */
++/* 5 */ {8, 16, 32, 32, deflate_slow},
++/* 6 */ {8, 16, 128, 128, deflate_slow},
++/* 7 */ {8, 32, 128, 256, deflate_slow},
++/* 8 */ {32, 128, 258, 1024, deflate_slow},
++/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */
++
++/* Note: the deflate() code requires max_lazy &gt;= MIN_MATCH and max_chain &gt;= 4
++ * For deflate_fast() (levels &lt;= 3) good is ignored and lazy has a different
++ * meaning.
++ */
++
++#define EQUAL 0
++/* result of memcmp for equal strings */
++
++#ifndef NO_DUMMY_DECL
++struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
++#endif
++
++/* ===========================================================================
++ * Update a hash value with the given input byte
++ * IN assertion: all calls to to UPDATE_HASH are made with consecutive
++ * input characters, so that a running hash key can be computed from the
++ * previous key instead of complete recalculation each time.
++ */
++#define UPDATE_HASH(s,h,c) (h = (((h)&lt;&lt;s-&gt;hash_shift) ^ (c)) &amp; s-&gt;hash_mask)
++
++
++/* ===========================================================================
++ * Insert string str in the dictionary and set match_head to the previous head
++ * of the hash chain (the most recent string with same hash key). Return
++ * the previous length of the hash chain.
++ * IN assertion: all calls to to INSERT_STRING are made with consecutive
++ * input characters and the first MIN_MATCH bytes of str are valid
++ * (except for the last MIN_MATCH-1 bytes of the input file).
++ */
++#define INSERT_STRING(s, str, match_head) \
++ (UPDATE_HASH(s, s-&gt;ins_h, s-&gt;window[(str) + (MIN_MATCH-1)]), \
++ s-&gt;prev[(str) &amp; s-&gt;w_mask] = match_head = s-&gt;head[s-&gt;ins_h], \
++ s-&gt;head[s-&gt;ins_h] = (Pos)(str))
++
++/* ===========================================================================
++ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
++ * prev[] will be initialized on the fly.
++ */
++#define CLEAR_HASH(s) \
++ s-&gt;head[s-&gt;hash_size-1] = NIL; \
++ zmemzero((charf *)s-&gt;head, (unsigned)(s-&gt;hash_size-1)*sizeof(*s-&gt;head));
++
++/* ========================================================================= */
++int deflateInit_(strm, level, version, stream_size)
++ z_streamp strm;
++ int level;
++ const char *version;
++ int stream_size;
++{
++ return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
++ Z_DEFAULT_STRATEGY, version, stream_size);
++ /* To do: ignore strm-&gt;next_in if we use it as window */
++}
++
++/* ========================================================================= */
++int deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
++ version, stream_size)
++ z_streamp strm;
++ int level;
++ int method;
++ int windowBits;
++ int memLevel;
++ int strategy;
++ const char *version;
++ int stream_size;
++{
++ deflate_state *s;
++ int noheader = 0;
++ static char* my_version = ZLIB_VERSION;
++
++ ushf *overlay;
++ /* We overlay pending_buf and d_buf+l_buf. This works since the average
++ * output size for (length,distance) codes is &lt;= 24 bits.
++ */
++
++ if (version == Z_NULL || version[0] != my_version[0] ||
++ stream_size != sizeof(z_stream)) {
++ return Z_VERSION_ERROR;
++ }
++ if (strm == Z_NULL) return Z_STREAM_ERROR;
++
++ strm-&gt;msg = Z_NULL;
++#ifndef NO_ZCFUNCS
++ if (strm-&gt;zalloc == Z_NULL) {
++ strm-&gt;zalloc = zcalloc;
++ strm-&gt;opaque = (voidpf)0;
++ }
++ if (strm-&gt;zfree == Z_NULL) strm-&gt;zfree = zcfree;
++#endif
++
++ if (level == Z_DEFAULT_COMPRESSION) level = 6;
++
++ if (windowBits &lt; 0) { /* undocumented feature: suppress zlib header */
++ noheader = 1;
++ windowBits = -windowBits;
++ }
++ if (memLevel &lt; 1 || memLevel &gt; MAX_MEM_LEVEL || method != Z_DEFLATED ||
++ windowBits &lt; 8 || windowBits &gt; 15 || level &lt; 0 || level &gt; 9 ||
++ strategy &lt; 0 || strategy &gt; Z_HUFFMAN_ONLY) {
++ return Z_STREAM_ERROR;
++ }
++ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
++ if (s == Z_NULL) return Z_MEM_ERROR;
++ strm-&gt;state = (struct internal_state FAR *)s;
++ s-&gt;strm = strm;
++
++ s-&gt;noheader = noheader;
++ s-&gt;w_bits = windowBits;
++ s-&gt;w_size = 1 &lt;&lt; s-&gt;w_bits;
++ s-&gt;w_mask = s-&gt;w_size - 1;
++
++ s-&gt;hash_bits = memLevel + 7;
++ s-&gt;hash_size = 1 &lt;&lt; s-&gt;hash_bits;
++ s-&gt;hash_mask = s-&gt;hash_size - 1;
++ s-&gt;hash_shift = ((s-&gt;hash_bits+MIN_MATCH-1)/MIN_MATCH);
++
++ s-&gt;window = (Bytef *) ZALLOC(strm, s-&gt;w_size, 2*sizeof(Byte));
++ s-&gt;prev = (Posf *) ZALLOC(strm, s-&gt;w_size, sizeof(Pos));
++ s-&gt;head = (Posf *) ZALLOC(strm, s-&gt;hash_size, sizeof(Pos));
++
++ s-&gt;lit_bufsize = 1 &lt;&lt; (memLevel + 6); /* 16K elements by default */
++
++ overlay = (ushf *) ZALLOC(strm, s-&gt;lit_bufsize, sizeof(ush)+2);
++ s-&gt;pending_buf = (uchf *) overlay;
++ s-&gt;pending_buf_size = (ulg)s-&gt;lit_bufsize * (sizeof(ush)+2L);
++
++ if (s-&gt;window == Z_NULL || s-&gt;prev == Z_NULL || s-&gt;head == Z_NULL ||
++ s-&gt;pending_buf == Z_NULL) {
++ strm-&gt;msg = (char*)ERR_MSG(Z_MEM_ERROR);
++ deflateEnd (strm);
++ return Z_MEM_ERROR;
++ }
++ s-&gt;d_buf = overlay + s-&gt;lit_bufsize/sizeof(ush);
++ s-&gt;l_buf = s-&gt;pending_buf + (1+sizeof(ush))*s-&gt;lit_bufsize;
++
++ s-&gt;level = level;
++ s-&gt;strategy = strategy;
++ s-&gt;method = (Byte)method;
++
++ return deflateReset(strm);
++}
++
++/* ========================================================================= */
++int deflateSetDictionary (strm, dictionary, dictLength)
++ z_streamp strm;
++ const Bytef *dictionary;
++ uInt dictLength;
++{
++ deflate_state *s;
++ uInt length = dictLength;
++ uInt n;
++ IPos hash_head = 0;
++
++ if (strm == Z_NULL || strm-&gt;state == Z_NULL || dictionary == Z_NULL)
++ return Z_STREAM_ERROR;
++
++ s = (deflate_state *) strm-&gt;state;
++ if (s-&gt;status != INIT_STATE) return Z_STREAM_ERROR;
++
++ strm-&gt;adler = adler32(strm-&gt;adler, dictionary, dictLength);
++
++ if (length &lt; MIN_MATCH) return Z_OK;
++ if (length &gt; MAX_DIST(s)) {
++ length = MAX_DIST(s);
++#ifndef USE_DICT_HEAD
++ dictionary += dictLength - length; /* use the tail of the dictionary */
++#endif
++ }
++ zmemcpy((charf *)s-&gt;window, dictionary, length);
++ s-&gt;strstart = length;
++ s-&gt;block_start = (long)length;
++
++ /* Insert all strings in the hash table (except for the last two bytes).
++ * s-&gt;lookahead stays null, so s-&gt;ins_h will be recomputed at the next
++ * call of fill_window.
++ */
++ s-&gt;ins_h = s-&gt;window[0];
++ UPDATE_HASH(s, s-&gt;ins_h, s-&gt;window[1]);
++ for (n = 0; n &lt;= length - MIN_MATCH; n++) {
++ INSERT_STRING(s, n, hash_head);
++ }
++ if (hash_head) hash_head = 0; /* to make compiler happy */
++ return Z_OK;
++}
++
++/* ========================================================================= */
++int deflateReset (strm)
++ z_streamp strm;
++{
++ deflate_state *s;
++
++ if (strm == Z_NULL || strm-&gt;state == Z_NULL ||
++ strm-&gt;zalloc == Z_NULL || strm-&gt;zfree == Z_NULL) return Z_STREAM_ERROR;
++
++ strm-&gt;total_in = strm-&gt;total_out = 0;
++ strm-&gt;msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
++ strm-&gt;data_type = Z_UNKNOWN;
++
++ s = (deflate_state *)strm-&gt;state;
++ s-&gt;pending = 0;
++ s-&gt;pending_out = s-&gt;pending_buf;
++
++ if (s-&gt;noheader &lt; 0) {
++ s-&gt;noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */
++ }
++ s-&gt;status = s-&gt;noheader ? BUSY_STATE : INIT_STATE;
++ strm-&gt;adler = 1;
++ s-&gt;last_flush = Z_NO_FLUSH;
++
++ _tr_init(s);
++ lm_init(s);
++
++ return Z_OK;
++}
++
++/* ========================================================================= */
++int deflateParams(strm, level, strategy)
++ z_streamp strm;
++ int level;
++ int strategy;
++{
++ deflate_state *s;
++ compress_func func;
++ int err = Z_OK;
++
++ if (strm == Z_NULL || strm-&gt;state == Z_NULL) return Z_STREAM_ERROR;
++ s = (deflate_state *) strm-&gt;state;
++
++ if (level == Z_DEFAULT_COMPRESSION) {
++ level = 6;
++ }
++ if (level &lt; 0 || level &gt; 9 || strategy &lt; 0 || strategy &gt; Z_HUFFMAN_ONLY) {
++ return Z_STREAM_ERROR;
++ }
++ func = configuration_table[s-&gt;level].func;
++
++ if (func != configuration_table[level].func &amp;&amp; strm-&gt;total_in != 0) {
++ /* Flush the last buffer: */
++ err = deflate(strm, Z_PARTIAL_FLUSH);
++ }
++ if (s-&gt;level != level) {
++ s-&gt;level = level;
++ s-&gt;max_lazy_match = configuration_table[level].max_lazy;
++ s-&gt;good_match = configuration_table[level].good_length;
++ s-&gt;nice_match = configuration_table[level].nice_length;
++ s-&gt;max_chain_length = configuration_table[level].max_chain;
++ }
++ s-&gt;strategy = strategy;
++ return err;
++}
++
++/* =========================================================================
++ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
++ * IN assertion: the stream state is correct and there is enough room in
++ * pending_buf.
++ */
++local void putShortMSB (s, b)
++ deflate_state *s;
++ uInt b;
++{
++ put_byte(s, (Byte)(b &gt;&gt; 8));
++ put_byte(s, (Byte)(b &amp; 0xff));
++}
++
++/* =========================================================================
++ * Flush as much pending output as possible. All deflate() output goes
++ * through this function so some applications may wish to modify it
++ * to avoid allocating a large strm-&gt;next_out buffer and copying into it.
++ * (See also read_buf()).
++ */
++local void flush_pending(strm)
++ z_streamp strm;
++{
++ deflate_state *s = (deflate_state *) strm-&gt;state;
++ unsigned len = s-&gt;pending;
++
++ if (len &gt; strm-&gt;avail_out) len = strm-&gt;avail_out;
++ if (len == 0) return;
++
++ if (strm-&gt;next_out != Z_NULL) {
++ zmemcpy(strm-&gt;next_out, s-&gt;pending_out, len);
++ strm-&gt;next_out += len;
++ }
++ s-&gt;pending_out += len;
++ strm-&gt;total_out += len;
++ strm-&gt;avail_out -= len;
++ s-&gt;pending -= len;
++ if (s-&gt;pending == 0) {
++ s-&gt;pending_out = s-&gt;pending_buf;
++ }
++}
++
++/* ========================================================================= */
++int deflate (strm, flush)
++ z_streamp strm;
++ int flush;
++{
++ int old_flush; /* value of flush param for previous deflate call */
++ deflate_state *s;
++
++ if (strm == Z_NULL || strm-&gt;state == Z_NULL ||
++ flush &gt; Z_FINISH || flush &lt; 0) {
++ return Z_STREAM_ERROR;
++ }
++ s = (deflate_state *) strm-&gt;state;
++
++ if ((strm-&gt;next_in == Z_NULL &amp;&amp; strm-&gt;avail_in != 0) ||
++ (s-&gt;status == FINISH_STATE &amp;&amp; flush != Z_FINISH)) {
++ ERR_RETURN(strm, Z_STREAM_ERROR);
++ }
++ if (strm-&gt;avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
++
++ s-&gt;strm = strm; /* just in case */
++ old_flush = s-&gt;last_flush;
++ s-&gt;last_flush = flush;
++
++ /* Write the zlib header */
++ if (s-&gt;status == INIT_STATE) {
++
++ uInt header = (Z_DEFLATED + ((s-&gt;w_bits-8)&lt;&lt;4)) &lt;&lt; 8;
++ uInt level_flags = (s-&gt;level-1) &gt;&gt; 1;
++
++ if (level_flags &gt; 3) level_flags = 3;
++ header |= (level_flags &lt;&lt; 6);
++ if (s-&gt;strstart != 0) header |= PRESET_DICT;
++ header += 31 - (header % 31);
++
++ s-&gt;status = BUSY_STATE;
++ putShortMSB(s, header);
++
++ /* Save the adler32 of the preset dictionary: */
++ if (s-&gt;strstart != 0) {
++ putShortMSB(s, (uInt)(strm-&gt;adler &gt;&gt; 16));
++ putShortMSB(s, (uInt)(strm-&gt;adler &amp; 0xffff));
++ }
++ strm-&gt;adler = 1L;
++ }
++
++ /* Flush as much pending output as possible */
++ if (s-&gt;pending != 0) {
++ flush_pending(strm);
++ if (strm-&gt;avail_out == 0) {
++ /* Since avail_out is 0, deflate will be called again with
++ * more output space, but possibly with both pending and
++ * avail_in equal to zero. There won't be anything to do,
++ * but this is not an error situation so make sure we
++ * return OK instead of BUF_ERROR at next call of deflate:
++ */
++ s-&gt;last_flush = -1;
++ return Z_OK;
++ }
++
++ /* Make sure there is something to do and avoid duplicate consecutive
++ * flushes. For repeated and useless calls with Z_FINISH, we keep
++ * returning Z_STREAM_END instead of Z_BUFF_ERROR.
++ */
++ } else if (strm-&gt;avail_in == 0 &amp;&amp; flush &lt;= old_flush &amp;&amp;
++ flush != Z_FINISH) {
++ ERR_RETURN(strm, Z_BUF_ERROR);
++ }
++
++ /* User must not provide more input after the first FINISH: */
++ if (s-&gt;status == FINISH_STATE &amp;&amp; strm-&gt;avail_in != 0) {
++ ERR_RETURN(strm, Z_BUF_ERROR);
++ }
++
++ /* Start a new block or continue the current one.
++ */
++ if (strm-&gt;avail_in != 0 || s-&gt;lookahead != 0 ||
++ (flush != Z_NO_FLUSH &amp;&amp; s-&gt;status != FINISH_STATE)) {
++ block_state bstate;
++
++ bstate = (*(configuration_table[s-&gt;level].func))(s, flush);
++
++ if (bstate == finish_started || bstate == finish_done) {
++ s-&gt;status = FINISH_STATE;
++ }
++ if (bstate == need_more || bstate == finish_started) {
++ if (strm-&gt;avail_out == 0) {
++ s-&gt;last_flush = -1; /* avoid BUF_ERROR next call, see above */
++ }
++ return Z_OK;
++ /* If flush != Z_NO_FLUSH &amp;&amp; avail_out == 0, the next call
++ * of deflate should use the same flush parameter to make sure
++ * that the flush is complete. So we don't have to output an
++ * empty block here, this will be done at next call. This also
++ * ensures that for a very small output buffer, we emit at most
++ * one empty block.
++ */
++ }
++ if (bstate == block_done) {
++ if (flush == Z_PARTIAL_FLUSH) {
++ _tr_align(s);
++ } else if (flush == Z_PACKET_FLUSH) {
++ /* Output just the 3-bit `stored' block type value,
++ but not a zero length. */
++ _tr_stored_type_only(s);
++ } else { /* FULL_FLUSH or SYNC_FLUSH */
++ _tr_stored_block(s, (char*)0, 0L, 0);
++ /* For a full flush, this empty block will be recognized
++ * as a special marker by inflate_sync().
++ */
++ if (flush == Z_FULL_FLUSH) {
++ CLEAR_HASH(s); /* forget history */
++ }
++ }
++ flush_pending(strm);
++ if (strm-&gt;avail_out == 0) {
++ s-&gt;last_flush = -1; /* avoid BUF_ERROR at next call, see above */
++ return Z_OK;
++ }
++ }
++ }
++ Assert(strm-&gt;avail_out &gt; 0, &quot;bug2&quot;);
++
++ if (flush != Z_FINISH) return Z_OK;
++ if (s-&gt;noheader) return Z_STREAM_END;
++
++ /* Write the zlib trailer (adler32) */
++ putShortMSB(s, (uInt)(strm-&gt;adler &gt;&gt; 16));
++ putShortMSB(s, (uInt)(strm-&gt;adler &amp; 0xffff));
++ flush_pending(strm);
++ /* If avail_out is zero, the application will call deflate again
++ * to flush the rest.
++ */
++ s-&gt;noheader = -1; /* write the trailer only once! */
++ return s-&gt;pending != 0 ? Z_OK : Z_STREAM_END;
++}
++
++/* ========================================================================= */
++int deflateEnd (strm)
++ z_streamp strm;
++{
++ int status;
++ deflate_state *s;
++
++ if (strm == Z_NULL || strm-&gt;state == Z_NULL) return Z_STREAM_ERROR;
++ s = (deflate_state *) strm-&gt;state;
++
++ status = s-&gt;status;
++ if (status != INIT_STATE &amp;&amp; status != BUSY_STATE &amp;&amp;
++ status != FINISH_STATE) {
++ return Z_STREAM_ERROR;
++ }
++
++ /* Deallocate in reverse order of allocations: */
++ TRY_FREE(strm, s-&gt;pending_buf);
++ TRY_FREE(strm, s-&gt;head);
++ TRY_FREE(strm, s-&gt;prev);
++ TRY_FREE(strm, s-&gt;window);
++
++ ZFREE(strm, s);
++ strm-&gt;state = Z_NULL;
++
++ return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
++}
++
++/* =========================================================================
++ * Copy the source state to the destination state.
++ */
++int deflateCopy (dest, source)
++ z_streamp dest;
++ z_streamp source;
++{
++ deflate_state *ds;
++ deflate_state *ss;
++ ushf *overlay;
++
++ if (source == Z_NULL || dest == Z_NULL || source-&gt;state == Z_NULL)
++ return Z_STREAM_ERROR;
++ ss = (deflate_state *) source-&gt;state;
++
++ zmemcpy(dest, source, sizeof(*dest));
++
++ ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
++ if (ds == Z_NULL) return Z_MEM_ERROR;
++ dest-&gt;state = (struct internal_state FAR *) ds;
++ zmemcpy(ds, ss, sizeof(*ds));
++ ds-&gt;strm = dest;
++
++ ds-&gt;window = (Bytef *) ZALLOC(dest, ds-&gt;w_size, 2*sizeof(Byte));
++ ds-&gt;prev = (Posf *) ZALLOC(dest, ds-&gt;w_size, sizeof(Pos));
++ ds-&gt;head = (Posf *) ZALLOC(dest, ds-&gt;hash_size, sizeof(Pos));
++ overlay = (ushf *) ZALLOC(dest, ds-&gt;lit_bufsize, sizeof(ush)+2);
++ ds-&gt;pending_buf = (uchf *) overlay;
++
++ if (ds-&gt;window == Z_NULL || ds-&gt;prev == Z_NULL || ds-&gt;head == Z_NULL ||
++ ds-&gt;pending_buf == Z_NULL) {
++ deflateEnd (dest);
++ return Z_MEM_ERROR;
++ }
++ /* ??? following zmemcpy doesn't work for 16-bit MSDOS */
++ zmemcpy(ds-&gt;window, ss-&gt;window, ds-&gt;w_size * 2 * sizeof(Byte));
++ zmemcpy(ds-&gt;prev, ss-&gt;prev, ds-&gt;w_size * sizeof(Pos));
++ zmemcpy(ds-&gt;head, ss-&gt;head, ds-&gt;hash_size * sizeof(Pos));
++ zmemcpy(ds-&gt;pending_buf, ss-&gt;pending_buf, (uInt)ds-&gt;pending_buf_size);
++
++ ds-&gt;pending_out = ds-&gt;pending_buf + (ss-&gt;pending_out - ss-&gt;pending_buf);
++ ds-&gt;d_buf = overlay + ds-&gt;lit_bufsize/sizeof(ush);
++ ds-&gt;l_buf = ds-&gt;pending_buf + (1+sizeof(ush))*ds-&gt;lit_bufsize;
++
++ ds-&gt;l_desc.dyn_tree = ds-&gt;dyn_ltree;
++ ds-&gt;d_desc.dyn_tree = ds-&gt;dyn_dtree;
++ ds-&gt;bl_desc.dyn_tree = ds-&gt;bl_tree;
++
++ return Z_OK;
++}
++
++/* ===========================================================================
++ * Return the number of bytes of output which are immediately available
++ * for output from the decompressor.
++ */
++int deflateOutputPending (strm)
++ z_streamp strm;
++{
++ if (strm == Z_NULL || strm-&gt;state == Z_NULL) return 0;
++
++ return ((deflate_state *)(strm-&gt;state))-&gt;pending;
++}
++
++/* ===========================================================================
++ * Read a new buffer from the current input stream, update the adler32
++ * and total number of bytes read. All deflate() input goes through
++ * this function so some applications may wish to modify it to avoid
++ * allocating a large strm-&gt;next_in buffer and copying from it.
++ * (See also flush_pending()).
++ */
++local int read_buf(strm, buf, size)
++ z_streamp strm;
++ charf *buf;
++ unsigned size;
++{
++ unsigned len = strm-&gt;avail_in;
++
++ if (len &gt; size) len = size;
++ if (len == 0) return 0;
++
++ strm-&gt;avail_in -= len;
++
++ if (!((deflate_state *)(strm-&gt;state))-&gt;noheader) {
++ strm-&gt;adler = adler32(strm-&gt;adler, strm-&gt;next_in, len);
++ }
++ zmemcpy(buf, strm-&gt;next_in, len);
++ strm-&gt;next_in += len;
++ strm-&gt;total_in += len;
++
++ return (int)len;
++}
++
++/* ===========================================================================
++ * Initialize the &quot;longest match&quot; routines for a new zlib stream
++ */
++local void lm_init (s)
++ deflate_state *s;
++{
++ s-&gt;window_size = (ulg)2L*s-&gt;w_size;
++
++ CLEAR_HASH(s);
++
++ /* Set the default configuration parameters:
++ */
++ s-&gt;max_lazy_match = configuration_table[s-&gt;level].max_lazy;
++ s-&gt;good_match = configuration_table[s-&gt;level].good_length;
++ s-&gt;nice_match = configuration_table[s-&gt;level].nice_length;
++ s-&gt;max_chain_length = configuration_table[s-&gt;level].max_chain;
++
++ s-&gt;strstart = 0;
++ s-&gt;block_start = 0L;
++ s-&gt;lookahead = 0;
++ s-&gt;match_length = s-&gt;prev_length = MIN_MATCH-1;
++ s-&gt;match_available = 0;
++ s-&gt;ins_h = 0;
++#ifdef ASMV
++ match_init(); /* initialize the asm code */
++#endif
++}
++
++/* ===========================================================================
++ * Set match_start to the longest match starting at the given string and
++ * return its length. Matches shorter or equal to prev_length are discarded,
++ * in which case the result is equal to prev_length and match_start is
++ * garbage.
++ * IN assertions: cur_match is the head of the hash chain for the current
++ * string (strstart) and its distance is &lt;= MAX_DIST, and prev_length &gt;= 1
++ * OUT assertion: the match length is not greater than s-&gt;lookahead.
++ */
++#ifndef ASMV
++/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
++ * match.S. The code will be functionally equivalent.
++ */
++local uInt longest_match(s, cur_match)
++ deflate_state *s;
++ IPos cur_match; /* current match */
++{
++ unsigned chain_length = s-&gt;max_chain_length;/* max hash chain length */
++ register Bytef *scan = s-&gt;window + s-&gt;strstart; /* current string */
++ register Bytef *match; /* matched string */
++ register int len; /* length of current match */
++ int best_len = s-&gt;prev_length; /* best match length so far */
++ int nice_match = s-&gt;nice_match; /* stop if match long enough */
++ IPos limit = s-&gt;strstart &gt; (IPos)MAX_DIST(s) ?
++ s-&gt;strstart - (IPos)MAX_DIST(s) : NIL;
++ /* Stop when cur_match becomes &lt;= limit. To simplify the code,
++ * we prevent matches with the string of window index 0.
++ */
++ Posf *prev = s-&gt;prev;
++ uInt wmask = s-&gt;w_mask;
++
++#ifdef UNALIGNED_OK
++ /* Compare two bytes at a time. Note: this is not always beneficial.
++ * Try with and without -DUNALIGNED_OK to check.
++ */
++ register Bytef *strend = s-&gt;window + s-&gt;strstart + MAX_MATCH - 1;
++ register ush scan_start = *(ushf*)scan;
++ register ush scan_end = *(ushf*)(scan+best_len-1);
++#else
++ register Bytef *strend = s-&gt;window + s-&gt;strstart + MAX_MATCH;
++ register Byte scan_end1 = scan[best_len-1];
++ register Byte scan_end = scan[best_len];
++#endif
++
++ /* The code is optimized for HASH_BITS &gt;= 8 and MAX_MATCH-2 multiple of 16.
++ * It is easy to get rid of this optimization if necessary.
++ */
++ Assert(s-&gt;hash_bits &gt;= 8 &amp;&amp; MAX_MATCH == 258, &quot;Code too clever&quot;);
++
++ /* Do not waste too much time if we already have a good match: */
++ if (s-&gt;prev_length &gt;= s-&gt;good_match) {
++ chain_length &gt;&gt;= 2;
++ }
++ /* Do not look for matches beyond the end of the input. This is necessary
++ * to make deflate deterministic.
++ */
++ if ((uInt)nice_match &gt; s-&gt;lookahead) nice_match = s-&gt;lookahead;
++
++ Assert((ulg)s-&gt;strstart &lt;= s-&gt;window_size-MIN_LOOKAHEAD, &quot;need lookahead&quot;);
++
++ do {
++ Assert(cur_match &lt; s-&gt;strstart, &quot;no future&quot;);
++ match = s-&gt;window + cur_match;
++
++ /* Skip to next match if the match length cannot increase
++ * or if the match length is less than 2:
++ */
++#if (defined(UNALIGNED_OK) &amp;&amp; MAX_MATCH == 258)
++ /* This code assumes sizeof(unsigned short) == 2. Do not use
++ * UNALIGNED_OK if your compiler uses a different size.
++ */
++ if (*(ushf*)(match+best_len-1) != scan_end ||
++ *(ushf*)match != scan_start) continue;
++
++ /* It is not necessary to compare scan[2] and match[2] since they are
++ * always equal when the other bytes match, given that the hash keys
++ * are equal and that HASH_BITS &gt;= 8. Compare 2 bytes at a time at
++ * strstart+3, +5, ... up to strstart+257. We check for insufficient
++ * lookahead only every 4th comparison; the 128th check will be made
++ * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
++ * necessary to put more guard bytes at the end of the window, or
++ * to check more often for insufficient lookahead.
++ */
++ Assert(scan[2] == match[2], &quot;scan[2]?&quot;);
++ scan++, match++;
++ do {
++ } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &amp;&amp;
++ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &amp;&amp;
++ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &amp;&amp;
++ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &amp;&amp;
++ scan &lt; strend);
++ /* The funny &quot;do {}&quot; generates better code on most compilers */
++
++ /* Here, scan &lt;= window+strstart+257 */
++ Assert(scan &lt;= s-&gt;window+(unsigned)(s-&gt;window_size-1), &quot;wild scan&quot;);
++ if (*scan == *match) scan++;
++
++ len = (MAX_MATCH - 1) - (int)(strend-scan);
++ scan = strend - (MAX_MATCH-1);
++
++#else /* UNALIGNED_OK */
++
++ if (match[best_len] != scan_end ||
++ match[best_len-1] != scan_end1 ||
++ *match != *scan ||
++ *++match != scan[1]) continue;
++
++ /* The check at best_len-1 can be removed because it will be made
++ * again later. (This heuristic is not always a win.)
++ * It is not necessary to compare scan[2] and match[2] since they
++ * are always equal when the other bytes match, given that
++ * the hash keys are equal and that HASH_BITS &gt;= 8.
++ */
++ scan += 2, match++;
++ Assert(*scan == *match, &quot;match[2]?&quot;);
++
++ /* We check for insufficient lookahead only every 8th comparison;
++ * the 256th check will be made at strstart+258.
++ */
++ do {
++ } while (*++scan == *++match &amp;&amp; *++scan == *++match &amp;&amp;
++ *++scan == *++match &amp;&amp; *++scan == *++match &amp;&amp;
++ *++scan == *++match &amp;&amp; *++scan == *++match &amp;&amp;
++ *++scan == *++match &amp;&amp; *++scan == *++match &amp;&amp;
++ scan &lt; strend);
++
++ Assert(scan &lt;= s-&gt;window+(unsigned)(s-&gt;window_size-1), &quot;wild scan&quot;);
++
++ len = MAX_MATCH - (int)(strend - scan);
++ scan = strend - MAX_MATCH;
++
++#endif /* UNALIGNED_OK */
++
++ if (len &gt; best_len) {
++ s-&gt;match_start = cur_match;
++ best_len = len;
++ if (len &gt;= nice_match) break;
++#ifdef UNALIGNED_OK
++ scan_end = *(ushf*)(scan+best_len-1);
++#else
++ scan_end1 = scan[best_len-1];
++ scan_end = scan[best_len];
++#endif
++ }
++ } while ((cur_match = prev[cur_match &amp; wmask]) &gt; limit
++ &amp;&amp; --chain_length != 0);
++
++ if ((uInt)best_len &lt;= s-&gt;lookahead) return best_len;
++ return s-&gt;lookahead;
++}
++#endif /* ASMV */
++
++#ifdef DEBUG_ZLIB
++/* ===========================================================================
++ * Check that the match at match_start is indeed a match.
++ */
++local void check_match(s, start, match, length)
++ deflate_state *s;
++ IPos start, match;
++ int length;
++{
++ /* check that the match is indeed a match */
++ if (zmemcmp((charf *)s-&gt;window + match,
++ (charf *)s-&gt;window + start, length) != EQUAL) {
++ fprintf(stderr, &quot; start %u, match %u, length %d\n&quot;,
++ start, match, length);
++ do {
++ fprintf(stderr, &quot;%c%c&quot;, s-&gt;window[match++], s-&gt;window[start++]);
++ } while (--length != 0);
++ z_error(&quot;invalid match&quot;);
++ }
++ if (z_verbose &gt; 1) {
++ fprintf(stderr,&quot;\\[%d,%d]&quot;, start-match, length);
++ do { putc(s-&gt;window[start++], stderr); } while (--length != 0);
++ }
++}
++#else
++# define check_match(s, start, match, length)
++#endif
++
++/* ===========================================================================
++ * Fill the window when the lookahead becomes insufficient.
++ * Updates strstart and lookahead.
++ *
++ * IN assertion: lookahead &lt; MIN_LOOKAHEAD
++ * OUT assertions: strstart &lt;= window_size-MIN_LOOKAHEAD
++ * At least one byte has been read, or avail_in == 0; reads are
++ * performed for at least two bytes (required for the zip translate_eol
++ * option -- not supported here).
++ */
++local void fill_window(s)
++ deflate_state *s;
++{
++ register unsigned n, m;
++ register Posf *p;
++ unsigned more; /* Amount of free space at the end of the window. */
++ uInt wsize = s-&gt;w_size;
++
++ do {
++ more = (unsigned)(s-&gt;window_size -(ulg)s-&gt;lookahead -(ulg)s-&gt;strstart);
++
++ /* Deal with !@#$% 64K limit: */
++ if (more == 0 &amp;&amp; s-&gt;strstart == 0 &amp;&amp; s-&gt;lookahead == 0) {
++ more = wsize;
++
++ } else if (more == (unsigned)(-1)) {
++ /* Very unlikely, but possible on 16 bit machine if strstart == 0
++ * and lookahead == 1 (input done one byte at time)
++ */
++ more--;
++
++ /* If the window is almost full and there is insufficient lookahead,
++ * move the upper half to the lower one to make room in the upper half.
++ */
++ } else if (s-&gt;strstart &gt;= wsize+MAX_DIST(s)) {
++
++ zmemcpy((charf *)s-&gt;window, (charf *)s-&gt;window+wsize,
++ (unsigned)wsize);
++ s-&gt;match_start -= wsize;
++ s-&gt;strstart -= wsize; /* we now have strstart &gt;= MAX_DIST */
++ s-&gt;block_start -= (long) wsize;
++
++ /* Slide the hash table (could be avoided with 32 bit values
++ at the expense of memory usage). We slide even when level == 0
++ to keep the hash table consistent if we switch back to level &gt; 0
++ later. (Using level 0 permanently is not an optimal usage of
++ zlib, so we don't care about this pathological case.)
++ */
++ n = s-&gt;hash_size;
++ p = &amp;s-&gt;head[n];
++ do {
++ m = *--p;
++ *p = (Pos)(m &gt;= wsize ? m-wsize : NIL);
++ } while (--n);
++
++ n = wsize;
++ p = &amp;s-&gt;prev[n];
++ do {
++ m = *--p;
++ *p = (Pos)(m &gt;= wsize ? m-wsize : NIL);
++ /* If n is not on any hash chain, prev[n] is garbage but
++ * its value will never be used.
++ */
++ } while (--n);
++ more += wsize;
++ }
++ if (s-&gt;strm-&gt;avail_in == 0) return;
++
++ /* If there was no sliding:
++ * strstart &lt;= WSIZE+MAX_DIST-1 &amp;&amp; lookahead &lt;= MIN_LOOKAHEAD - 1 &amp;&amp;
++ * more == window_size - lookahead - strstart
++ * =&gt; more &gt;= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
++ * =&gt; more &gt;= window_size - 2*WSIZE + 2
++ * In the BIG_MEM or MMAP case (not yet supported),
++ * window_size == input_size + MIN_LOOKAHEAD &amp;&amp;
++ * strstart + s-&gt;lookahead &lt;= input_size =&gt; more &gt;= MIN_LOOKAHEAD.
++ * Otherwise, window_size == 2*WSIZE so more &gt;= 2.
++ * If there was sliding, more &gt;= WSIZE. So in all cases, more &gt;= 2.
++ */
++ Assert(more &gt;= 2, &quot;more &lt; 2&quot;);
++
++ n = read_buf(s-&gt;strm, (charf *)s-&gt;window + s-&gt;strstart + s-&gt;lookahead,
++ more);
++ s-&gt;lookahead += n;
++
++ /* Initialize the hash value now that we have some input: */
++ if (s-&gt;lookahead &gt;= MIN_MATCH) {
++ s-&gt;ins_h = s-&gt;window[s-&gt;strstart];
++ UPDATE_HASH(s, s-&gt;ins_h, s-&gt;window[s-&gt;strstart+1]);
++#if MIN_MATCH != 3
++ Call UPDATE_HASH() MIN_MATCH-3 more times
++#endif
++ }
++ /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
++ * but this is not important since only literal bytes will be emitted.
++ */
++
++ } while (s-&gt;lookahead &lt; MIN_LOOKAHEAD &amp;&amp; s-&gt;strm-&gt;avail_in != 0);
++}
++
++/* ===========================================================================
++ * Flush the current block, with given end-of-file flag.
++ * IN assertion: strstart is set to the end of the current match.
++ */
++#define FLUSH_BLOCK_ONLY(s, eof) { \
++ _tr_flush_block(s, (s-&gt;block_start &gt;= 0L ? \
++ (charf *)&amp;s-&gt;window[(unsigned)s-&gt;block_start] : \
++ (charf *)Z_NULL), \
++ (ulg)((long)s-&gt;strstart - s-&gt;block_start), \
++ (eof)); \
++ s-&gt;block_start = s-&gt;strstart; \
++ flush_pending(s-&gt;strm); \
++ Tracev((stderr,&quot;[FLUSH]&quot;)); \
++}
++
++/* Same but force premature exit if necessary. */
++#define FLUSH_BLOCK(s, eof) { \
++ FLUSH_BLOCK_ONLY(s, eof); \
++ if (s-&gt;strm-&gt;avail_out == 0) return (eof) ? finish_started : need_more; \
++}
++
++/* ===========================================================================
++ * Copy without compression as much as possible from the input stream, return
++ * the current block state.
++ * This function does not insert new strings in the dictionary since
++ * uncompressible data is probably not useful. This function is used
++ * only for the level=0 compression option.
++ * NOTE: this function should be optimized to avoid extra copying from
++ * window to pending_buf.
++ */
++local block_state deflate_stored(s, flush)
++ deflate_state *s;
++ int flush;
++{
++ /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
++ * to pending_buf_size, and each stored block has a 5 byte header:
++ */
++ ulg max_block_size = 0xffff;
++ ulg max_start;
++
++ if (max_block_size &gt; s-&gt;pending_buf_size - 5) {
++ max_block_size = s-&gt;pending_buf_size - 5;
++ }
++
++ /* Copy as much as possible from input to output: */
++ for (;;) {
++ /* Fill the window as much as possible: */
++ if (s-&gt;lookahead &lt;= 1) {
++
++ Assert(s-&gt;strstart &lt; s-&gt;w_size+MAX_DIST(s) ||
++ s-&gt;block_start &gt;= (long)s-&gt;w_size, &quot;slide too late&quot;);
++
++ fill_window(s);
++ if (s-&gt;lookahead == 0 &amp;&amp; flush == Z_NO_FLUSH) return need_more;
++
++ if (s-&gt;lookahead == 0) break; /* flush the current block */
++ }
++ Assert(s-&gt;block_start &gt;= 0L, &quot;block gone&quot;);
++
++ s-&gt;strstart += s-&gt;lookahead;
++ s-&gt;lookahead = 0;
++
++ /* Emit a stored block if pending_buf will be full: */
++ max_start = s-&gt;block_start + max_block_size;
++ if (s-&gt;strstart == 0 || (ulg)s-&gt;strstart &gt;= max_start) {
++ /* strstart == 0 is possible when wraparound on 16-bit machine */
++ s-&gt;lookahead = (uInt)(s-&gt;strstart - max_start);
++ s-&gt;strstart = (uInt)max_start;
++ FLUSH_BLOCK(s, 0);
++ }
++ /* Flush if we may have to slide, otherwise block_start may become
++ * negative and the data will be gone:
++ */
++ if (s-&gt;strstart - (uInt)s-&gt;block_start &gt;= MAX_DIST(s)) {
++ FLUSH_BLOCK(s, 0);
++ }
++ }
++ FLUSH_BLOCK(s, flush == Z_FINISH);
++ return flush == Z_FINISH ? finish_done : block_done;
++}
++
++/* ===========================================================================
++ * Compress as much as possible from the input stream, return the current
++ * block state.
++ * This function does not perform lazy evaluation of matches and inserts
++ * new strings in the dictionary only for unmatched strings or for short
++ * matches. It is used only for the fast compression options.
++ */
++local block_state deflate_fast(s, flush)
++ deflate_state *s;
++ int flush;
++{
++ IPos hash_head = NIL; /* head of the hash chain */
++ int bflush; /* set if current block must be flushed */
++
++ for (;;) {
++ /* Make sure that we always have enough lookahead, except
++ * at the end of the input file. We need MAX_MATCH bytes
++ * for the next match, plus MIN_MATCH bytes to insert the
++ * string following the next match.
++ */
++ if (s-&gt;lookahead &lt; MIN_LOOKAHEAD) {
++ fill_window(s);
++ if (s-&gt;lookahead &lt; MIN_LOOKAHEAD &amp;&amp; flush == Z_NO_FLUSH) {
++ return need_more;
++ }
++ if (s-&gt;lookahead == 0) break; /* flush the current block */
++ }
++
++ /* Insert the string window[strstart .. strstart+2] in the
++ * dictionary, and set hash_head to the head of the hash chain:
++ */
++ if (s-&gt;lookahead &gt;= MIN_MATCH) {
++ INSERT_STRING(s, s-&gt;strstart, hash_head);
++ }
++
++ /* Find the longest match, discarding those &lt;= prev_length.
++ * At this point we have always match_length &lt; MIN_MATCH
++ */
++ if (hash_head != NIL &amp;&amp; s-&gt;strstart - hash_head &lt;= MAX_DIST(s)) {
++ /* To simplify the code, we prevent matches with the string
++ * of window index 0 (in particular we have to avoid a match
++ * of the string with itself at the start of the input file).
++ */
++ if (s-&gt;strategy != Z_HUFFMAN_ONLY) {
++ s-&gt;match_length = longest_match (s, hash_head);
++ }
++ /* longest_match() sets match_start */
++ }
++ if (s-&gt;match_length &gt;= MIN_MATCH) {
++ check_match(s, s-&gt;strstart, s-&gt;match_start, s-&gt;match_length);
++
++ bflush = _tr_tally(s, s-&gt;strstart - s-&gt;match_start,
++ s-&gt;match_length - MIN_MATCH);
++
++ s-&gt;lookahead -= s-&gt;match_length;
++
++ /* Insert new strings in the hash table only if the match length
++ * is not too large. This saves time but degrades compression.
++ */
++ if (s-&gt;match_length &lt;= s-&gt;max_insert_length &amp;&amp;
++ s-&gt;lookahead &gt;= MIN_MATCH) {
++ s-&gt;match_length--; /* string at strstart already in hash table */
++ do {
++ s-&gt;strstart++;
++ INSERT_STRING(s, s-&gt;strstart, hash_head);
++ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
++ * always MIN_MATCH bytes ahead.
++ */
++ } while (--s-&gt;match_length != 0);
++ s-&gt;strstart++;
++ } else {
++ s-&gt;strstart += s-&gt;match_length;
++ s-&gt;match_length = 0;
++ s-&gt;ins_h = s-&gt;window[s-&gt;strstart];
++ UPDATE_HASH(s, s-&gt;ins_h, s-&gt;window[s-&gt;strstart+1]);
++#if MIN_MATCH != 3
++ Call UPDATE_HASH() MIN_MATCH-3 more times
++#endif
++ /* If lookahead &lt; MIN_MATCH, ins_h is garbage, but it does not
++ * matter since it will be recomputed at next deflate call.
++ */
++ }
++ } else {
++ /* No match, output a literal byte */
++ Tracevv((stderr,&quot;%c&quot;, s-&gt;window[s-&gt;strstart]));
++ bflush = _tr_tally (s, 0, s-&gt;window[s-&gt;strstart]);
++ s-&gt;lookahead--;
++ s-&gt;strstart++;
++ }
++ if (bflush) FLUSH_BLOCK(s, 0);
++ }
++ FLUSH_BLOCK(s, flush == Z_FINISH);
++ return flush == Z_FINISH ? finish_done : block_done;
++}
++
++/* ===========================================================================
++ * Same as above, but achieves better compression. We use a lazy
++ * evaluation for matches: a match is finally adopted only if there is
++ * no better match at the next window position.
++ */
++local block_state deflate_slow(s, flush)
++ deflate_state *s;
++ int flush;
++{
++ IPos hash_head = NIL; /* head of hash chain */
++ int bflush; /* set if current block must be flushed */
++
++ /* Process the input block. */
++ for (;;) {
++ /* Make sure that we always have enough lookahead, except
++ * at the end of the input file. We need MAX_MATCH bytes
++ * for the next match, plus MIN_MATCH bytes to insert the
++ * string following the next match.
++ */
++ if (s-&gt;lookahead &lt; MIN_LOOKAHEAD) {
++ fill_window(s);
++ if (s-&gt;lookahead &lt; MIN_LOOKAHEAD &amp;&amp; flush == Z_NO_FLUSH) {
++ return need_more;
++ }
++ if (s-&gt;lookahead == 0) break; /* flush the current block */
++ }
++
++ /* Insert the string window[strstart .. strstart+2] in the
++ * dictionary, and set hash_head to the head of the hash chain:
++ */
++ if (s-&gt;lookahead &gt;= MIN_MATCH) {
++ INSERT_STRING(s, s-&gt;strstart, hash_head);
++ }
++
++ /* Find the longest match, discarding those &lt;= prev_length.
++ */
++ s-&gt;prev_length = s-&gt;match_length, s-&gt;prev_match = s-&gt;match_start;
++ s-&gt;match_length = MIN_MATCH-1;
++
++ if (hash_head != NIL &amp;&amp; s-&gt;prev_length &lt; s-&gt;max_lazy_match &amp;&amp;
++ s-&gt;strstart - hash_head &lt;= MAX_DIST(s)) {
++ /* To simplify the code, we prevent matches with the string
++ * of window index 0 (in particular we have to avoid a match
++ * of the string with itself at the start of the input file).
++ */
++ if (s-&gt;strategy != Z_HUFFMAN_ONLY) {
++ s-&gt;match_length = longest_match (s, hash_head);
++ }
++ /* longest_match() sets match_start */
++
++ if (s-&gt;match_length &lt;= 5 &amp;&amp; (s-&gt;strategy == Z_FILTERED ||
++ (s-&gt;match_length == MIN_MATCH &amp;&amp;
++ s-&gt;strstart - s-&gt;match_start &gt; TOO_FAR))) {
++
++ /* If prev_match is also MIN_MATCH, match_start is garbage
++ * but we will ignore the current match anyway.
++ */
++ s-&gt;match_length = MIN_MATCH-1;
++ }
++ }
++ /* If there was a match at the previous step and the current
++ * match is not better, output the previous match:
++ */
++ if (s-&gt;prev_length &gt;= MIN_MATCH &amp;&amp; s-&gt;match_length &lt;= s-&gt;prev_length) {
++ uInt max_insert = s-&gt;strstart + s-&gt;lookahead - MIN_MATCH;
++ /* Do not insert strings in hash table beyond this. */
++
++ check_match(s, s-&gt;strstart-1, s-&gt;prev_match, s-&gt;prev_length);
++
++ bflush = _tr_tally(s, s-&gt;strstart -1 - s-&gt;prev_match,
++ s-&gt;prev_length - MIN_MATCH);
++
++ /* Insert in hash table all strings up to the end of the match.
++ * strstart-1 and strstart are already inserted. If there is not
++ * enough lookahead, the last two strings are not inserted in
++ * the hash table.
++ */
++ s-&gt;lookahead -= s-&gt;prev_length-1;
++ s-&gt;prev_length -= 2;
++ do {
++ if (++s-&gt;strstart &lt;= max_insert) {
++ INSERT_STRING(s, s-&gt;strstart, hash_head);
++ }
++ } while (--s-&gt;prev_length != 0);
++ s-&gt;match_available = 0;
++ s-&gt;match_length = MIN_MATCH-1;
++ s-&gt;strstart++;
++
++ if (bflush) FLUSH_BLOCK(s, 0);
++
++ } else if (s-&gt;match_available) {
++ /* If there was no match at the previous position, output a
++ * single literal. If there was a match but the current match
++ * is longer, truncate the previous match to a single literal.
++ */
++ Tracevv((stderr,&quot;%c&quot;, s-&gt;window[s-&gt;strstart-1]));
++ if (_tr_tally (s, 0, s-&gt;window[s-&gt;strstart-1])) {
++ FLUSH_BLOCK_ONLY(s, 0);
++ }
++ s-&gt;strstart++;
++ s-&gt;lookahead--;
++ if (s-&gt;strm-&gt;avail_out == 0) return need_more;
++ } else {
++ /* There is no previous match to compare with, wait for
++ * the next step to decide.
++ */
++ s-&gt;match_available = 1;
++ s-&gt;strstart++;
++ s-&gt;lookahead--;
++ }
++ }
++ Assert (flush != Z_NO_FLUSH, &quot;no flush?&quot;);
++ if (s-&gt;match_available) {
++ Tracevv((stderr,&quot;%c&quot;, s-&gt;window[s-&gt;strstart-1]));
++ _tr_tally (s, 0, s-&gt;window[s-&gt;strstart-1]);
++ s-&gt;match_available = 0;
++ }
++ FLUSH_BLOCK(s, flush == Z_FINISH);
++ return flush == Z_FINISH ? finish_done : block_done;
++}
++/* --- deflate.c */
++
++/* +++ trees.c */
++/* trees.c -- output deflated data using Huffman coding
++ * Copyright (C) 1995-1996 Jean-loup Gailly
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/*
++ * ALGORITHM
++ *
++ * The &quot;deflation&quot; process uses several Huffman trees. The more
++ * common source values are represented by shorter bit sequences.
++ *
++ * Each code tree is stored in a compressed form which is itself
++ * a Huffman encoding of the lengths of all the code strings (in
++ * ascending order by source values). The actual code strings are
++ * reconstructed from the lengths in the inflate process, as described
++ * in the deflate specification.
++ *
++ * REFERENCES
++ *
++ * Deutsch, L.P.,&quot;'Deflate' Compressed Data Format Specification&quot;.
++ * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
++ *
++ * Storer, James A.
++ * Data Compression: Methods and Theory, pp. 49-50.
++ * Computer Science Press, 1988. ISBN 0-7167-8156-5.
++ *
++ * Sedgewick, R.
++ * Algorithms, p290.
++ * Addison-Wesley, 1983. ISBN 0-201-06672-6.
++ */
++
++/* From: trees.c,v 1.11 1996/07/24 13:41:06 me Exp $ */
++
++/* #include &quot;deflate.h&quot; */
++
++#ifdef DEBUG_ZLIB
++# include &lt;ctype.h&gt;
++#endif
++
++/* ===========================================================================
++ * Constants
++ */
++
++#define MAX_BL_BITS 7
++/* Bit length codes must not exceed MAX_BL_BITS bits */
++
++#define END_BLOCK 256
++/* end of block literal code */
++
++#define REP_3_6 16
++/* repeat previous bit length 3-6 times (2 bits of repeat count) */
++
++#define REPZ_3_10 17
++/* repeat a zero length 3-10 times (3 bits of repeat count) */
++
++#define REPZ_11_138 18
++/* repeat a zero length 11-138 times (7 bits of repeat count) */
++
++local int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
++ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
++
++local int extra_dbits[D_CODES] /* extra bits for each distance code */
++ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
++
++local int extra_blbits[BL_CODES]/* extra bits for each bit length code */
++ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
++
++local uch bl_order[BL_CODES]
++ = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
++/* The lengths of the bit length codes are sent in order of decreasing
++ * probability, to avoid transmitting the lengths for unused bit length codes.
++ */
++
++#define Buf_size (8 * 2*sizeof(char))
++/* Number of bits used within bi_buf. (bi_buf might be implemented on
++ * more than 16 bits on some systems.)
++ */
++
++/* ===========================================================================
++ * Local data. These are initialized only once.
++ */
++
++local ct_data static_ltree[L_CODES+2];
++/* The static literal tree. Since the bit lengths are imposed, there is no
++ * need for the L_CODES extra codes used during heap construction. However
++ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
++ * below).
++ */
++
++local ct_data static_dtree[D_CODES];
++/* The static distance tree. (Actually a trivial tree since all codes use
++ * 5 bits.)
++ */
++
++local uch dist_code[512];
++/* distance codes. The first 256 values correspond to the distances
++ * 3 .. 258, the last 256 values correspond to the top 8 bits of
++ * the 15 bit distances.
++ */
++
++local uch length_code[MAX_MATCH-MIN_MATCH+1];
++/* length code for each normalized match length (0 == MIN_MATCH) */
++
++local int base_length[LENGTH_CODES];
++/* First normalized length for each code (0 = MIN_MATCH) */
++
++local int base_dist[D_CODES];
++/* First normalized distance for each code (0 = distance of 1) */
++
++struct static_tree_desc_s {
++ ct_data *static_tree; /* static tree or NULL */
++ intf *extra_bits; /* extra bits for each code or NULL */
++ int extra_base; /* base index for extra_bits */
++ int elems; /* max number of elements in the tree */
++ int max_length; /* max bit length for the codes */
++};
++
++local static_tree_desc static_l_desc =
++{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
++
++local static_tree_desc static_d_desc =
++{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS};
++
++local static_tree_desc static_bl_desc =
++{(ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS};
++
++/* ===========================================================================
++ * Local (static) routines in this file.
++ */
++
++local void tr_static_init OF((void));
++local void init_block OF((deflate_state *s));
++local void pqdownheap OF((deflate_state *s, ct_data *tree, int k));
++local void gen_bitlen OF((deflate_state *s, tree_desc *desc));
++local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count));
++local void build_tree OF((deflate_state *s, tree_desc *desc));
++local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code));
++local void send_tree OF((deflate_state *s, ct_data *tree, int max_code));
++local int build_bl_tree OF((deflate_state *s));
++local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
++ int blcodes));
++local void compress_block OF((deflate_state *s, ct_data *ltree,
++ ct_data *dtree));
++local void set_data_type OF((deflate_state *s));
++local unsigned bi_reverse OF((unsigned value, int length));
++local void bi_windup OF((deflate_state *s));
++local void bi_flush OF((deflate_state *s));
++local void copy_block OF((deflate_state *s, charf *buf, unsigned len,
++ int header));
++
++#ifndef DEBUG_ZLIB
++# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
++ /* Send a code of the given tree. c and tree must not have side effects */
++
++#else /* DEBUG_ZLIB */
++# define send_code(s, c, tree) \
++ { if (verbose&gt;2) fprintf(stderr,&quot;\ncd %3d &quot;,(c)); \
++ send_bits(s, tree[c].Code, tree[c].Len); }
++#endif
++
++#define d_code(dist) \
++ ((dist) &lt; 256 ? dist_code[dist] : dist_code[256+((dist)&gt;&gt;7)])
++/* Mapping from a distance to a distance code. dist is the distance - 1 and
++ * must not have side effects. dist_code[256] and dist_code[257] are never
++ * used.
++ */
++
++/* ===========================================================================
++ * Output a short LSB first on the stream.
++ * IN assertion: there is enough room in pendingBuf.
++ */
++#define put_short(s, w) { \
++ put_byte(s, (uch)((w) &amp; 0xff)); \
++ put_byte(s, (uch)((ush)(w) &gt;&gt; 8)); \
++}
++
++/* ===========================================================================
++ * Send a value on a given number of bits.
++ * IN assertion: length &lt;= 16 and value fits in length bits.
++ */
++#ifdef DEBUG_ZLIB
++local void send_bits OF((deflate_state *s, int value, int length));
++
++local void send_bits(s, value, length)
++ deflate_state *s;
++ int value; /* value to send */
++ int length; /* number of bits */
++{
++ Tracevv((stderr,&quot; l %2d v %4x &quot;, length, value));
++ Assert(length &gt; 0 &amp;&amp; length &lt;= 15, &quot;invalid length&quot;);
++ s-&gt;bits_sent += (ulg)length;
++
++ /* If not enough room in bi_buf, use (valid) bits from bi_buf and
++ * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
++ * unused bits in value.
++ */
++ if (s-&gt;bi_valid &gt; (int)Buf_size - length) {
++ s-&gt;bi_buf |= (value &lt;&lt; s-&gt;bi_valid);
++ put_short(s, s-&gt;bi_buf);
++ s-&gt;bi_buf = (ush)value &gt;&gt; (Buf_size - s-&gt;bi_valid);
++ s-&gt;bi_valid += length - Buf_size;
++ } else {
++ s-&gt;bi_buf |= value &lt;&lt; s-&gt;bi_valid;
++ s-&gt;bi_valid += length;
++ }
++}
++#else /* !DEBUG_ZLIB */
++
++#define send_bits(s, value, length) \
++{ int len = length;\
++ if (s-&gt;bi_valid &gt; (int)Buf_size - len) {\
++ int val = value;\
++ s-&gt;bi_buf |= (val &lt;&lt; s-&gt;bi_valid);\
++ put_short(s, s-&gt;bi_buf);\
++ s-&gt;bi_buf = (ush)val &gt;&gt; (Buf_size - s-&gt;bi_valid);\
++ s-&gt;bi_valid += len - Buf_size;\
++ } else {\
++ s-&gt;bi_buf |= (value) &lt;&lt; s-&gt;bi_valid;\
++ s-&gt;bi_valid += len;\
++ }\
++}
++#endif /* DEBUG_ZLIB */
++
++
++#define MAX(a,b) (a &gt;= b ? a : b)
++/* the arguments must not have side effects */
++
++/* ===========================================================================
++ * Initialize the various 'constant' tables. In a multi-threaded environment,
++ * this function may be called by two threads concurrently, but this is
++ * harmless since both invocations do exactly the same thing.
++ */
++local void tr_static_init()
++{
++ static int static_init_done = 0;
++ int n; /* iterates over tree elements */
++ int bits; /* bit counter */
++ int length; /* length value */
++ int code; /* code value */
++ int dist; /* distance index */
++ ush bl_count[MAX_BITS+1];
++ /* number of codes at each bit length for an optimal tree */
++
++ if (static_init_done) return;
++
++ /* Initialize the mapping length (0..255) -&gt; length code (0..28) */
++ length = 0;
++ for (code = 0; code &lt; LENGTH_CODES-1; code++) {
++ base_length[code] = length;
++ for (n = 0; n &lt; (1&lt;&lt;extra_lbits[code]); n++) {
++ length_code[length++] = (uch)code;
++ }
++ }
++ Assert (length == 256, &quot;tr_static_init: length != 256&quot;);
++ /* Note that the length 255 (match length 258) can be represented
++ * in two different ways: code 284 + 5 bits or code 285, so we
++ * overwrite length_code[255] to use the best encoding:
++ */
++ length_code[length-1] = (uch)code;
++
++ /* Initialize the mapping dist (0..32K) -&gt; dist code (0..29) */
++ dist = 0;
++ for (code = 0 ; code &lt; 16; code++) {
++ base_dist[code] = dist;
++ for (n = 0; n &lt; (1&lt;&lt;extra_dbits[code]); n++) {
++ dist_code[dist++] = (uch)code;
++ }
++ }
++ Assert (dist == 256, &quot;tr_static_init: dist != 256&quot;);
++ dist &gt;&gt;= 7; /* from now on, all distances are divided by 128 */
++ for ( ; code &lt; D_CODES; code++) {
++ base_dist[code] = dist &lt;&lt; 7;
++ for (n = 0; n &lt; (1&lt;&lt;(extra_dbits[code]-7)); n++) {
++ dist_code[256 + dist++] = (uch)code;
++ }
++ }
++ Assert (dist == 256, &quot;tr_static_init: 256+dist != 512&quot;);
++
++ /* Construct the codes of the static literal tree */
++ for (bits = 0; bits &lt;= MAX_BITS; bits++) bl_count[bits] = 0;
++ n = 0;
++ while (n &lt;= 143) static_ltree[n++].Len = 8, bl_count[8]++;
++ while (n &lt;= 255) static_ltree[n++].Len = 9, bl_count[9]++;
++ while (n &lt;= 279) static_ltree[n++].Len = 7, bl_count[7]++;
++ while (n &lt;= 287) static_ltree[n++].Len = 8, bl_count[8]++;
++ /* Codes 286 and 287 do not exist, but we must include them in the
++ * tree construction to get a canonical Huffman tree (longest code
++ * all ones)
++ */
++ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
++
++ /* The static distance tree is trivial: */
++ for (n = 0; n &lt; D_CODES; n++) {
++ static_dtree[n].Len = 5;
++ static_dtree[n].Code = bi_reverse((unsigned)n, 5);
++ }
++ static_init_done = 1;
++}
++
++/* ===========================================================================
++ * Initialize the tree data structures for a new zlib stream.
++ */
++void _tr_init(s)
++ deflate_state *s;
++{
++ tr_static_init();
++
++ s-&gt;compressed_len = 0L;
++
++ s-&gt;l_desc.dyn_tree = s-&gt;dyn_ltree;
++ s-&gt;l_desc.stat_desc = &amp;static_l_desc;
++
++ s-&gt;d_desc.dyn_tree = s-&gt;dyn_dtree;
++ s-&gt;d_desc.stat_desc = &amp;static_d_desc;
++
++ s-&gt;bl_desc.dyn_tree = s-&gt;bl_tree;
++ s-&gt;bl_desc.stat_desc = &amp;static_bl_desc;
++
++ s-&gt;bi_buf = 0;
++ s-&gt;bi_valid = 0;
++ s-&gt;last_eob_len = 8; /* enough lookahead for inflate */
++#ifdef DEBUG_ZLIB
++ s-&gt;bits_sent = 0L;
++#endif
++
++ /* Initialize the first block of the first file: */
++ init_block(s);
++}
++
++/* ===========================================================================
++ * Initialize a new block.
++ */
++local void init_block(s)
++ deflate_state *s;
++{
++ int n; /* iterates over tree elements */
++
++ /* Initialize the trees. */
++ for (n = 0; n &lt; L_CODES; n++) s-&gt;dyn_ltree[n].Freq = 0;
++ for (n = 0; n &lt; D_CODES; n++) s-&gt;dyn_dtree[n].Freq = 0;
++ for (n = 0; n &lt; BL_CODES; n++) s-&gt;bl_tree[n].Freq = 0;
++
++ s-&gt;dyn_ltree[END_BLOCK].Freq = 1;
++ s-&gt;opt_len = s-&gt;static_len = 0L;
++ s-&gt;last_lit = s-&gt;matches = 0;
++}
++
++#define SMALLEST 1
++/* Index within the heap array of least frequent node in the Huffman tree */
++
++
++/* ===========================================================================
++ * Remove the smallest element from the heap and recreate the heap with
++ * one less element. Updates heap and heap_len.
++ */
++#define pqremove(s, tree, top) \
++{\
++ top = s-&gt;heap[SMALLEST]; \
++ s-&gt;heap[SMALLEST] = s-&gt;heap[s-&gt;heap_len--]; \
++ pqdownheap(s, tree, SMALLEST); \
++}
++
++/* ===========================================================================
++ * Compares to subtrees, using the tree depth as tie breaker when
++ * the subtrees have equal frequency. This minimizes the worst case length.
++ */
++#define smaller(tree, n, m, depth) \
++ (tree[n].Freq &lt; tree[m].Freq || \
++ (tree[n].Freq == tree[m].Freq &amp;&amp; depth[n] &lt;= depth[m]))
++
++/* ===========================================================================
++ * Restore the heap property by moving down the tree starting at node k,
++ * exchanging a node with the smallest of its two sons if necessary, stopping
++ * when the heap property is re-established (each father smaller than its
++ * two sons).
++ */
++local void pqdownheap(s, tree, k)
++ deflate_state *s;
++ ct_data *tree; /* the tree to restore */
++ int k; /* node to move down */
++{
++ int v = s-&gt;heap[k];
++ int j = k &lt;&lt; 1; /* left son of k */
++ while (j &lt;= s-&gt;heap_len) {
++ /* Set j to the smallest of the two sons: */
++ if (j &lt; s-&gt;heap_len &amp;&amp;
++ smaller(tree, s-&gt;heap[j+1], s-&gt;heap[j], s-&gt;depth)) {
++ j++;
++ }
++ /* Exit if v is smaller than both sons */
++ if (smaller(tree, v, s-&gt;heap[j], s-&gt;depth)) break;
++
++ /* Exchange v with the smallest son */
++ s-&gt;heap[k] = s-&gt;heap[j]; k = j;
++
++ /* And continue down the tree, setting j to the left son of k */
++ j &lt;&lt;= 1;
++ }
++ s-&gt;heap[k] = v;
++}
++
++/* ===========================================================================
++ * Compute the optimal bit lengths for a tree and update the total bit length
++ * for the current block.
++ * IN assertion: the fields freq and dad are set, heap[heap_max] and
++ * above are the tree nodes sorted by increasing frequency.
++ * OUT assertions: the field len is set to the optimal bit length, the
++ * array bl_count contains the frequencies for each bit length.
++ * The length opt_len is updated; static_len is also updated if stree is
++ * not null.
++ */
++local void gen_bitlen(s, desc)
++ deflate_state *s;
++ tree_desc *desc; /* the tree descriptor */
++{
++ ct_data *tree = desc-&gt;dyn_tree;
++ int max_code = desc-&gt;max_code;
++ ct_data *stree = desc-&gt;stat_desc-&gt;static_tree;
++ intf *extra = desc-&gt;stat_desc-&gt;extra_bits;
++ int base = desc-&gt;stat_desc-&gt;extra_base;
++ int max_length = desc-&gt;stat_desc-&gt;max_length;
++ int h; /* heap index */
++ int n, m; /* iterate over the tree elements */
++ int bits; /* bit length */
++ int xbits; /* extra bits */
++ ush f; /* frequency */
++ int overflow = 0; /* number of elements with bit length too large */
++
++ for (bits = 0; bits &lt;= MAX_BITS; bits++) s-&gt;bl_count[bits] = 0;
++
++ /* In a first pass, compute the optimal bit lengths (which may
++ * overflow in the case of the bit length tree).
++ */
++ tree[s-&gt;heap[s-&gt;heap_max]].Len = 0; /* root of the heap */
++
++ for (h = s-&gt;heap_max+1; h &lt; HEAP_SIZE; h++) {
++ n = s-&gt;heap[h];
++ bits = tree[tree[n].Dad].Len + 1;
++ if (bits &gt; max_length) bits = max_length, overflow++;
++ tree[n].Len = (ush)bits;
++ /* We overwrite tree[n].Dad which is no longer needed */
++
++ if (n &gt; max_code) continue; /* not a leaf node */
++
++ s-&gt;bl_count[bits]++;
++ xbits = 0;
++ if (n &gt;= base) xbits = extra[n-base];
++ f = tree[n].Freq;
++ s-&gt;opt_len += (ulg)f * (bits + xbits);
++ if (stree) s-&gt;static_len += (ulg)f * (stree[n].Len + xbits);
++ }
++ if (overflow == 0) return;
++
++ Trace((stderr,&quot;\nbit length overflow\n&quot;));
++ /* This happens for example on obj2 and pic of the Calgary corpus */
++
++ /* Find the first bit length which could increase: */
++ do {
++ bits = max_length-1;
++ while (s-&gt;bl_count[bits] == 0) bits--;
++ s-&gt;bl_count[bits]--; /* move one leaf down the tree */
++ s-&gt;bl_count[bits+1] += 2; /* move one overflow item as its brother */
++ s-&gt;bl_count[max_length]--;
++ /* The brother of the overflow item also moves one step up,
++ * but this does not affect bl_count[max_length]
++ */
++ overflow -= 2;
++ } while (overflow &gt; 0);
++
++ /* Now recompute all bit lengths, scanning in increasing frequency.
++ * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
++ * lengths instead of fixing only the wrong ones. This idea is taken
++ * from 'ar' written by Haruhiko Okumura.)
++ */
++ for (bits = max_length; bits != 0; bits--) {
++ n = s-&gt;bl_count[bits];
++ while (n != 0) {
++ m = s-&gt;heap[--h];
++ if (m &gt; max_code) continue;
++ if (tree[m].Len != (unsigned) bits) {
++ Trace((stderr,&quot;code %d bits %d-&gt;%d\n&quot;, m, tree[m].Len, bits));
++ s-&gt;opt_len += ((long)bits - (long)tree[m].Len)
++ *(long)tree[m].Freq;
++ tree[m].Len = (ush)bits;
++ }
++ n--;
++ }
++ }
++}
++
++/* ===========================================================================
++ * Generate the codes for a given tree and bit counts (which need not be
++ * optimal).
++ * IN assertion: the array bl_count contains the bit length statistics for
++ * the given tree and the field len is set for all tree elements.
++ * OUT assertion: the field code is set for all tree elements of non
++ * zero code length.
++ */
++local void gen_codes (tree, max_code, bl_count)
++ ct_data *tree; /* the tree to decorate */
++ int max_code; /* largest code with non zero frequency */
++ ushf *bl_count; /* number of codes at each bit length */
++{
++ ush next_code[MAX_BITS+1]; /* next code value for each bit length */
++ ush code = 0; /* running code value */
++ int bits; /* bit index */
++ int n; /* code index */
++
++ /* The distribution counts are first used to generate the code values
++ * without bit reversal.
++ */
++ for (bits = 1; bits &lt;= MAX_BITS; bits++) {
++ next_code[bits] = code = (code + bl_count[bits-1]) &lt;&lt; 1;
++ }
++ /* Check that the bit counts in bl_count are consistent. The last code
++ * must be all ones.
++ */
++ Assert (code + bl_count[MAX_BITS]-1 == (1&lt;&lt;MAX_BITS)-1,
++ &quot;inconsistent bit counts&quot;);
++ Tracev((stderr,&quot;\ngen_codes: max_code %d &quot;, max_code));
++
++ for (n = 0; n &lt;= max_code; n++) {
++ int len = tree[n].Len;
++ if (len == 0) continue;
++ /* Now reverse the bits */
++ tree[n].Code = bi_reverse(next_code[len]++, len);
++
++ Tracecv(tree != static_ltree, (stderr,&quot;\nn %3d %c l %2d c %4x (%x) &quot;,
++ n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
++ }
++}
++
++/* ===========================================================================
++ * Construct one Huffman tree and assigns the code bit strings and lengths.
++ * Update the total bit length for the current block.
++ * IN assertion: the field freq is set for all tree elements.
++ * OUT assertions: the fields len and code are set to the optimal bit length
++ * and corresponding code. The length opt_len is updated; static_len is
++ * also updated if stree is not null. The field max_code is set.
++ */
++local void build_tree(s, desc)
++ deflate_state *s;
++ tree_desc *desc; /* the tree descriptor */
++{
++ ct_data *tree = desc-&gt;dyn_tree;
++ ct_data *stree = desc-&gt;stat_desc-&gt;static_tree;
++ int elems = desc-&gt;stat_desc-&gt;elems;
++ int n, m; /* iterate over heap elements */
++ int max_code = -1; /* largest code with non zero frequency */
++ int node; /* new node being created */
++
++ /* Construct the initial heap, with least frequent element in
++ * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
++ * heap[0] is not used.
++ */
++ s-&gt;heap_len = 0, s-&gt;heap_max = HEAP_SIZE;
++
++ for (n = 0; n &lt; elems; n++) {
++ if (tree[n].Freq != 0) {
++ s-&gt;heap[++(s-&gt;heap_len)] = max_code = n;
++ s-&gt;depth[n] = 0;
++ } else {
++ tree[n].Len = 0;
++ }
++ }
++
++ /* The pkzip format requires that at least one distance code exists,
++ * and that at least one bit should be sent even if there is only one
++ * possible code. So to avoid special checks later on we force at least
++ * two codes of non zero frequency.
++ */
++ while (s-&gt;heap_len &lt; 2) {
++ node = s-&gt;heap[++(s-&gt;heap_len)] = (max_code &lt; 2 ? ++max_code : 0);
++ tree[node].Freq = 1;
++ s-&gt;depth[node] = 0;
++ s-&gt;opt_len--; if (stree) s-&gt;static_len -= stree[node].Len;
++ /* node is 0 or 1 so it does not have extra bits */
++ }
++ desc-&gt;max_code = max_code;
++
++ /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
++ * establish sub-heaps of increasing lengths:
++ */
++ for (n = s-&gt;heap_len/2; n &gt;= 1; n--) pqdownheap(s, tree, n);
++
++ /* Construct the Huffman tree by repeatedly combining the least two
++ * frequent nodes.
++ */
++ node = elems; /* next internal node of the tree */
++ do {
++ pqremove(s, tree, n); /* n = node of least frequency */
++ m = s-&gt;heap[SMALLEST]; /* m = node of next least frequency */
++
++ s-&gt;heap[--(s-&gt;heap_max)] = n; /* keep the nodes sorted by frequency */
++ s-&gt;heap[--(s-&gt;heap_max)] = m;
++
++ /* Create a new node father of n and m */
++ tree[node].Freq = tree[n].Freq + tree[m].Freq;
++ s-&gt;depth[node] = (uch) (MAX(s-&gt;depth[n], s-&gt;depth[m]) + 1);
++ tree[n].Dad = tree[m].Dad = (ush)node;
++#ifdef DUMP_BL_TREE
++ if (tree == s-&gt;bl_tree) {
++ fprintf(stderr,&quot;\nnode %d(%d), sons %d(%d) %d(%d)&quot;,
++ node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
++ }
++#endif
++ /* and insert the new node in the heap */
++ s-&gt;heap[SMALLEST] = node++;
++ pqdownheap(s, tree, SMALLEST);
++
++ } while (s-&gt;heap_len &gt;= 2);
++
++ s-&gt;heap[--(s-&gt;heap_max)] = s-&gt;heap[SMALLEST];
++
++ /* At this point, the fields freq and dad are set. We can now
++ * generate the bit lengths.
++ */
++ gen_bitlen(s, (tree_desc *)desc);
++
++ /* The field len is now set, we can generate the bit codes */
++ gen_codes ((ct_data *)tree, max_code, s-&gt;bl_count);
++}
++
++/* ===========================================================================
++ * Scan a literal or distance tree to determine the frequencies of the codes
++ * in the bit length tree.
++ */
++local void scan_tree (s, tree, max_code)
++ deflate_state *s;
++ ct_data *tree; /* the tree to be scanned */
++ int max_code; /* and its largest code of non zero frequency */
++{
++ int n; /* iterates over all tree elements */
++ int prevlen = -1; /* last emitted length */
++ int curlen; /* length of current code */
++ int nextlen = tree[0].Len; /* length of next code */
++ int count = 0; /* repeat count of the current code */
++ int max_count = 7; /* max repeat count */
++ int min_count = 4; /* min repeat count */
++
++ if (nextlen == 0) max_count = 138, min_count = 3;
++ tree[max_code+1].Len = (ush)0xffff; /* guard */
++
++ for (n = 0; n &lt;= max_code; n++) {
++ curlen = nextlen; nextlen = tree[n+1].Len;
++ if (++count &lt; max_count &amp;&amp; curlen == nextlen) {
++ continue;
++ } else if (count &lt; min_count) {
++ s-&gt;bl_tree[curlen].Freq += count;
++ } else if (curlen != 0) {
++ if (curlen != prevlen) s-&gt;bl_tree[curlen].Freq++;
++ s-&gt;bl_tree[REP_3_6].Freq++;
++ } else if (count &lt;= 10) {
++ s-&gt;bl_tree[REPZ_3_10].Freq++;
++ } else {
++ s-&gt;bl_tree[REPZ_11_138].Freq++;
++ }
++ count = 0; prevlen = curlen;
++ if (nextlen == 0) {
++ max_count = 138, min_count = 3;
++ } else if (curlen == nextlen) {
++ max_count = 6, min_count = 3;
++ } else {
++ max_count = 7, min_count = 4;
++ }
++ }
++}
++
++/* ===========================================================================
++ * Send a literal or distance tree in compressed form, using the codes in
++ * bl_tree.
++ */
++local void send_tree (s, tree, max_code)
++ deflate_state *s;
++ ct_data *tree; /* the tree to be scanned */
++ int max_code; /* and its largest code of non zero frequency */
++{
++ int n; /* iterates over all tree elements */
++ int prevlen = -1; /* last emitted length */
++ int curlen; /* length of current code */
++ int nextlen = tree[0].Len; /* length of next code */
++ int count = 0; /* repeat count of the current code */
++ int max_count = 7; /* max repeat count */
++ int min_count = 4; /* min repeat count */
++
++ /* tree[max_code+1].Len = -1; */ /* guard already set */
++ if (nextlen == 0) max_count = 138, min_count = 3;
++
++ for (n = 0; n &lt;= max_code; n++) {
++ curlen = nextlen; nextlen = tree[n+1].Len;
++ if (++count &lt; max_count &amp;&amp; curlen == nextlen) {
++ continue;
++ } else if (count &lt; min_count) {
++ do { send_code(s, curlen, s-&gt;bl_tree); } while (--count != 0);
++
++ } else if (curlen != 0) {
++ if (curlen != prevlen) {
++ send_code(s, curlen, s-&gt;bl_tree); count--;
++ }
++ Assert(count &gt;= 3 &amp;&amp; count &lt;= 6, &quot; 3_6?&quot;);
++ send_code(s, REP_3_6, s-&gt;bl_tree); send_bits(s, count-3, 2);
++
++ } else if (count &lt;= 10) {
++ send_code(s, REPZ_3_10, s-&gt;bl_tree); send_bits(s, count-3, 3);
++
++ } else {
++ send_code(s, REPZ_11_138, s-&gt;bl_tree); send_bits(s, count-11, 7);
++ }
++ count = 0; prevlen = curlen;
++ if (nextlen == 0) {
++ max_count = 138, min_count = 3;
++ } else if (curlen == nextlen) {
++ max_count = 6, min_count = 3;
++ } else {
++ max_count = 7, min_count = 4;
++ }
++ }
++}
++
++/* ===========================================================================
++ * Construct the Huffman tree for the bit lengths and return the index in
++ * bl_order of the last bit length code to send.
++ */
++local int build_bl_tree(s)
++ deflate_state *s;
++{
++ int max_blindex; /* index of last bit length code of non zero freq */
++
++ /* Determine the bit length frequencies for literal and distance trees */
++ scan_tree(s, (ct_data *)s-&gt;dyn_ltree, s-&gt;l_desc.max_code);
++ scan_tree(s, (ct_data *)s-&gt;dyn_dtree, s-&gt;d_desc.max_code);
++
++ /* Build the bit length tree: */
++ build_tree(s, (tree_desc *)(&amp;(s-&gt;bl_desc)));
++ /* opt_len now includes the length of the tree representations, except
++ * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
++ */
++
++ /* Determine the number of bit length codes to send. The pkzip format
++ * requires that at least 4 bit length codes be sent. (appnote.txt says
++ * 3 but the actual value used is 4.)
++ */
++ for (max_blindex = BL_CODES-1; max_blindex &gt;= 3; max_blindex--) {
++ if (s-&gt;bl_tree[bl_order[max_blindex]].Len != 0) break;
++ }
++ /* Update opt_len to include the bit length tree and counts */
++ s-&gt;opt_len += 3*(max_blindex+1) + 5+5+4;
++ Tracev((stderr, &quot;\ndyn trees: dyn %ld, stat %ld&quot;,
++ s-&gt;opt_len, s-&gt;static_len));
++
++ return max_blindex;
++}
++
++/* ===========================================================================
++ * Send the header for a block using dynamic Huffman trees: the counts, the
++ * lengths of the bit length codes, the literal tree and the distance tree.
++ * IN assertion: lcodes &gt;= 257, dcodes &gt;= 1, blcodes &gt;= 4.
++ */
++local void send_all_trees(s, lcodes, dcodes, blcodes)
++ deflate_state *s;
++ int lcodes, dcodes, blcodes; /* number of codes for each tree */
++{
++ int rank; /* index in bl_order */
++
++ Assert (lcodes &gt;= 257 &amp;&amp; dcodes &gt;= 1 &amp;&amp; blcodes &gt;= 4, &quot;not enough codes&quot;);
++ Assert (lcodes &lt;= L_CODES &amp;&amp; dcodes &lt;= D_CODES &amp;&amp; blcodes &lt;= BL_CODES,
++ &quot;too many codes&quot;);
++ Tracev((stderr, &quot;\nbl counts: &quot;));
++ send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
++ send_bits(s, dcodes-1, 5);
++ send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */
++ for (rank = 0; rank &lt; blcodes; rank++) {
++ Tracev((stderr, &quot;\nbl code %2d &quot;, bl_order[rank]));
++ send_bits(s, s-&gt;bl_tree[bl_order[rank]].Len, 3);
++ }
++ Tracev((stderr, &quot;\nbl tree: sent %ld&quot;, s-&gt;bits_sent));
++
++ send_tree(s, (ct_data *)s-&gt;dyn_ltree, lcodes-1); /* literal tree */
++ Tracev((stderr, &quot;\nlit tree: sent %ld&quot;, s-&gt;bits_sent));
++
++ send_tree(s, (ct_data *)s-&gt;dyn_dtree, dcodes-1); /* distance tree */
++ Tracev((stderr, &quot;\ndist tree: sent %ld&quot;, s-&gt;bits_sent));
++}
++
++/* ===========================================================================
++ * Send a stored block
++ */
++void _tr_stored_block(s, buf, stored_len, eof)
++ deflate_state *s;
++ charf *buf; /* input block */
++ ulg stored_len; /* length of input block */
++ int eof; /* true if this is the last block for a file */
++{
++ send_bits(s, (STORED_BLOCK&lt;&lt;1)+eof, 3); /* send block type */
++ s-&gt;compressed_len = (s-&gt;compressed_len + 3 + 7) &amp; (ulg)~7L;
++ s-&gt;compressed_len += (stored_len + 4) &lt;&lt; 3;
++
++ copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
++}
++
++/* Send just the `stored block' type code without any length bytes or data.
++ */
++void _tr_stored_type_only(s)
++ deflate_state *s;
++{
++ send_bits(s, (STORED_BLOCK &lt;&lt; 1), 3);
++ bi_windup(s);
++ s-&gt;compressed_len = (s-&gt;compressed_len + 3) &amp; ~7L;
++}
++
++
++/* ===========================================================================
++ * Send one empty static block to give enough lookahead for inflate.
++ * This takes 10 bits, of which 7 may remain in the bit buffer.
++ * The current inflate code requires 9 bits of lookahead. If the
++ * last two codes for the previous block (real code plus EOB) were coded
++ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
++ * the last real code. In this case we send two empty static blocks instead
++ * of one. (There are no problems if the previous block is stored or fixed.)
++ * To simplify the code, we assume the worst case of last real code encoded
++ * on one bit only.
++ */
++void _tr_align(s)
++ deflate_state *s;
++{
++ send_bits(s, STATIC_TREES&lt;&lt;1, 3);
++ send_code(s, END_BLOCK, static_ltree);
++ s-&gt;compressed_len += 10L; /* 3 for block type, 7 for EOB */
++ bi_flush(s);
++ /* Of the 10 bits for the empty block, we have already sent
++ * (10 - bi_valid) bits. The lookahead for the last real code (before
++ * the EOB of the previous block) was thus at least one plus the length
++ * of the EOB plus what we have just sent of the empty static block.
++ */
++ if (1 + s-&gt;last_eob_len + 10 - s-&gt;bi_valid &lt; 9) {
++ send_bits(s, STATIC_TREES&lt;&lt;1, 3);
++ send_code(s, END_BLOCK, static_ltree);
++ s-&gt;compressed_len += 10L;
++ bi_flush(s);
++ }
++ s-&gt;last_eob_len = 7;
++}
++
++/* ===========================================================================
++ * Determine the best encoding for the current block: dynamic trees, static
++ * trees or store, and output the encoded block to the zip file. This function
++ * returns the total compressed length for the file so far.
++ */
++ulg _tr_flush_block(s, buf, stored_len, eof)
++ deflate_state *s;
++ charf *buf; /* input block, or NULL if too old */
++ ulg stored_len; /* length of input block */
++ int eof; /* true if this is the last block for a file */
++{
++ ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
++ int max_blindex = 0; /* index of last bit length code of non zero freq */
++
++ /* Build the Huffman trees unless a stored block is forced */
++ if (s-&gt;level &gt; 0) {
++
++ /* Check if the file is ascii or binary */
++ if (s-&gt;data_type == Z_UNKNOWN) set_data_type(s);
++
++ /* Construct the literal and distance trees */
++ build_tree(s, (tree_desc *)(&amp;(s-&gt;l_desc)));
++ Tracev((stderr, &quot;\nlit data: dyn %ld, stat %ld&quot;, s-&gt;opt_len,
++ s-&gt;static_len));
++
++ build_tree(s, (tree_desc *)(&amp;(s-&gt;d_desc)));
++ Tracev((stderr, &quot;\ndist data: dyn %ld, stat %ld&quot;, s-&gt;opt_len,
++ s-&gt;static_len));
++ /* At this point, opt_len and static_len are the total bit lengths of
++ * the compressed block data, excluding the tree representations.
++ */
++
++ /* Build the bit length tree for the above two trees, and get the index
++ * in bl_order of the last bit length code to send.
++ */
++ max_blindex = build_bl_tree(s);
++
++ /* Determine the best encoding. Compute first the block length in bytes*/
++ opt_lenb = (s-&gt;opt_len+3+7)&gt;&gt;3;
++ static_lenb = (s-&gt;static_len+3+7)&gt;&gt;3;
++
++ Tracev((stderr, &quot;\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u &quot;,
++ opt_lenb, s-&gt;opt_len, static_lenb, s-&gt;static_len, stored_len,
++ s-&gt;last_lit));
++
++ if (static_lenb &lt;= opt_lenb) opt_lenb = static_lenb;
++
++ } else {
++ Assert(buf != (char*)0, &quot;lost buf&quot;);
++ opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
++ }
++
++ /* If compression failed and this is the first and last block,
++ * and if the .zip file can be seeked (to rewrite the local header),
++ * the whole file is transformed into a stored file:
++ */
++#ifdef STORED_FILE_OK
++# ifdef FORCE_STORED_FILE
++ if (eof &amp;&amp; s-&gt;compressed_len == 0L) { /* force stored file */
++# else
++ if (stored_len &lt;= opt_lenb &amp;&amp; eof &amp;&amp; s-&gt;compressed_len==0L &amp;&amp; seekable()) {
++# endif
++ /* Since LIT_BUFSIZE &lt;= 2*WSIZE, the input data must be there: */
++ if (buf == (charf*)0) error (&quot;block vanished&quot;);
++
++ copy_block(s, buf, (unsigned)stored_len, 0); /* without header */
++ s-&gt;compressed_len = stored_len &lt;&lt; 3;
++ s-&gt;method = STORED;
++ } else
++#endif /* STORED_FILE_OK */
++
++#ifdef FORCE_STORED
++ if (buf != (char*)0) { /* force stored block */
++#else
++ if (stored_len+4 &lt;= opt_lenb &amp;&amp; buf != (char*)0) {
++ /* 4: two words for the lengths */
++#endif
++ /* The test buf != NULL is only necessary if LIT_BUFSIZE &gt; WSIZE.
++ * Otherwise we can't have processed more than WSIZE input bytes since
++ * the last block flush, because compression would have been
++ * successful. If LIT_BUFSIZE &lt;= WSIZE, it is never too late to
++ * transform a block into a stored block.
++ */
++ _tr_stored_block(s, buf, stored_len, eof);
++
++#ifdef FORCE_STATIC
++ } else if (static_lenb &gt;= 0) { /* force static trees */
++#else
++ } else if (static_lenb == opt_lenb) {
++#endif
++ send_bits(s, (STATIC_TREES&lt;&lt;1)+eof, 3);
++ compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
++ s-&gt;compressed_len += 3 + s-&gt;static_len;
++ } else {
++ send_bits(s, (DYN_TREES&lt;&lt;1)+eof, 3);
++ send_all_trees(s, s-&gt;l_desc.max_code+1, s-&gt;d_desc.max_code+1,
++ max_blindex+1);
++ compress_block(s, (ct_data *)s-&gt;dyn_ltree, (ct_data *)s-&gt;dyn_dtree);
++ s-&gt;compressed_len += 3 + s-&gt;opt_len;
++ }
++ Assert (s-&gt;compressed_len == s-&gt;bits_sent, &quot;bad compressed size&quot;);
++ init_block(s);
++
++ if (eof) {
++ bi_windup(s);
++ s-&gt;compressed_len += 7; /* align on byte boundary */
++ }
++ Tracev((stderr,&quot;\ncomprlen %lu(%lu) &quot;, s-&gt;compressed_len&gt;&gt;3,
++ s-&gt;compressed_len-7*eof));
++
++ return s-&gt;compressed_len &gt;&gt; 3;
++}
++
++/* ===========================================================================
++ * Save the match info and tally the frequency counts. Return true if
++ * the current block must be flushed.
++ */
++int _tr_tally (s, dist, lc)
++ deflate_state *s;
++ unsigned dist; /* distance of matched string */
++ unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
++{
++ s-&gt;d_buf[s-&gt;last_lit] = (ush)dist;
++ s-&gt;l_buf[s-&gt;last_lit++] = (uch)lc;
++ if (dist == 0) {
++ /* lc is the unmatched char */
++ s-&gt;dyn_ltree[lc].Freq++;
++ } else {
++ s-&gt;matches++;
++ /* Here, lc is the match length - MIN_MATCH */
++ dist--; /* dist = match distance - 1 */
++ Assert((ush)dist &lt; (ush)MAX_DIST(s) &amp;&amp;
++ (ush)lc &lt;= (ush)(MAX_MATCH-MIN_MATCH) &amp;&amp;
++ (ush)d_code(dist) &lt; (ush)D_CODES, &quot;_tr_tally: bad match&quot;);
++
++ s-&gt;dyn_ltree[length_code[lc]+LITERALS+1].Freq++;
++ s-&gt;dyn_dtree[d_code(dist)].Freq++;
++ }
++
++ /* Try to guess if it is profitable to stop the current block here */
++ if (s-&gt;level &gt; 2 &amp;&amp; (s-&gt;last_lit &amp; 0xfff) == 0) {
++ /* Compute an upper bound for the compressed length */
++ ulg out_length = (ulg)s-&gt;last_lit*8L;
++ ulg in_length = (ulg)((long)s-&gt;strstart - s-&gt;block_start);
++ int dcode;
++ for (dcode = 0; dcode &lt; D_CODES; dcode++) {
++ out_length += (ulg)s-&gt;dyn_dtree[dcode].Freq *
++ (5L+extra_dbits[dcode]);
++ }
++ out_length &gt;&gt;= 3;
++ Tracev((stderr,&quot;\nlast_lit %u, in %ld, out ~%ld(%ld%%) &quot;,
++ s-&gt;last_lit, in_length, out_length,
++ 100L - out_length*100L/in_length));
++ if (s-&gt;matches &lt; s-&gt;last_lit/2 &amp;&amp; out_length &lt; in_length/2) return 1;
++ }
++ return (s-&gt;last_lit == s-&gt;lit_bufsize-1);
++ /* We avoid equality with lit_bufsize because of wraparound at 64K
++ * on 16 bit machines and because stored blocks are restricted to
++ * 64K-1 bytes.
++ */
++}
++
++/* ===========================================================================
++ * Send the block data compressed using the given Huffman trees
++ */
++local void compress_block(s, ltree, dtree)
++ deflate_state *s;
++ ct_data *ltree; /* literal tree */
++ ct_data *dtree; /* distance tree */
++{
++ unsigned dist; /* distance of matched string */
++ int lc; /* match length or unmatched char (if dist == 0) */
++ unsigned lx = 0; /* running index in l_buf */
++ unsigned code; /* the code to send */
++ int extra; /* number of extra bits to send */
++
++ if (s-&gt;last_lit != 0) do {
++ dist = s-&gt;d_buf[lx];
++ lc = s-&gt;l_buf[lx++];
++ if (dist == 0) {
++ send_code(s, lc, ltree); /* send a literal byte */
++ Tracecv(isgraph(lc), (stderr,&quot; '%c' &quot;, lc));
++ } else {
++ /* Here, lc is the match length - MIN_MATCH */
++ code = length_code[lc];
++ send_code(s, code+LITERALS+1, ltree); /* send the length code */
++ extra = extra_lbits[code];
++ if (extra != 0) {
++ lc -= base_length[code];
++ send_bits(s, lc, extra); /* send the extra length bits */
++ }
++ dist--; /* dist is now the match distance - 1 */
++ code = d_code(dist);
++ Assert (code &lt; D_CODES, &quot;bad d_code&quot;);
++
++ send_code(s, code, dtree); /* send the distance code */
++ extra = extra_dbits[code];
++ if (extra != 0) {
++ dist -= base_dist[code];
++ send_bits(s, dist, extra); /* send the extra distance bits */
++ }
++ } /* literal or match pair ? */
++
++ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
++ Assert(s-&gt;pending &lt; s-&gt;lit_bufsize + 2*lx, &quot;pendingBuf overflow&quot;);
++
++ } while (lx &lt; s-&gt;last_lit);
++
++ send_code(s, END_BLOCK, ltree);
++ s-&gt;last_eob_len = ltree[END_BLOCK].Len;
++}
++
++/* ===========================================================================
++ * Set the data type to ASCII or BINARY, using a crude approximation:
++ * binary if more than 20% of the bytes are &lt;= 6 or &gt;= 128, ascii otherwise.
++ * IN assertion: the fields freq of dyn_ltree are set and the total of all
++ * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
++ */
++local void set_data_type(s)
++ deflate_state *s;
++{
++ int n = 0;
++ unsigned ascii_freq = 0;
++ unsigned bin_freq = 0;
++ while (n &lt; 7) bin_freq += s-&gt;dyn_ltree[n++].Freq;
++ while (n &lt; 128) ascii_freq += s-&gt;dyn_ltree[n++].Freq;
++ while (n &lt; LITERALS) bin_freq += s-&gt;dyn_ltree[n++].Freq;
++ s-&gt;data_type = (Byte)(bin_freq &gt; (ascii_freq &gt;&gt; 2) ? Z_BINARY : Z_ASCII);
++}
++
++/* ===========================================================================
++ * Reverse the first len bits of a code, using straightforward code (a faster
++ * method would use a table)
++ * IN assertion: 1 &lt;= len &lt;= 15
++ */
++local unsigned bi_reverse(code, len)
++ unsigned code; /* the value to invert */
++ int len; /* its bit length */
++{
++ register unsigned res = 0;
++ do {
++ res |= code &amp; 1;
++ code &gt;&gt;= 1, res &lt;&lt;= 1;
++ } while (--len &gt; 0);
++ return res &gt;&gt; 1;
++}
++
++/* ===========================================================================
++ * Flush the bit buffer, keeping at most 7 bits in it.
++ */
++local void bi_flush(s)
++ deflate_state *s;
++{
++ if (s-&gt;bi_valid == 16) {
++ put_short(s, s-&gt;bi_buf);
++ s-&gt;bi_buf = 0;
++ s-&gt;bi_valid = 0;
++ } else if (s-&gt;bi_valid &gt;= 8) {
++ put_byte(s, (Byte)s-&gt;bi_buf);
++ s-&gt;bi_buf &gt;&gt;= 8;
++ s-&gt;bi_valid -= 8;
++ }
++}
++
++/* ===========================================================================
++ * Flush the bit buffer and align the output on a byte boundary
++ */
++local void bi_windup(s)
++ deflate_state *s;
++{
++ if (s-&gt;bi_valid &gt; 8) {
++ put_short(s, s-&gt;bi_buf);
++ } else if (s-&gt;bi_valid &gt; 0) {
++ put_byte(s, (Byte)s-&gt;bi_buf);
++ }
++ s-&gt;bi_buf = 0;
++ s-&gt;bi_valid = 0;
++#ifdef DEBUG_ZLIB
++ s-&gt;bits_sent = (s-&gt;bits_sent+7) &amp; ~7;
++#endif
++}
++
++/* ===========================================================================
++ * Copy a stored block, storing first the length and its
++ * one's complement if requested.
++ */
++local void copy_block(s, buf, len, header)
++ deflate_state *s;
++ charf *buf; /* the input data */
++ unsigned len; /* its length */
++ int header; /* true if block header must be written */
++{
++ bi_windup(s); /* align on byte boundary */
++ s-&gt;last_eob_len = 8; /* enough lookahead for inflate */
++
++ if (header) {
++ put_short(s, (ush)len);
++ put_short(s, (ush)~len);
++#ifdef DEBUG_ZLIB
++ s-&gt;bits_sent += 2*16;
++#endif
++ }
++#ifdef DEBUG_ZLIB
++ s-&gt;bits_sent += (ulg)len&lt;&lt;3;
++#endif
++ /* bundle up the put_byte(s, *buf++) calls */
++ zmemcpy(&amp;s-&gt;pending_buf[s-&gt;pending], buf, len);
++ s-&gt;pending += len;
++}
++/* --- trees.c */
++
++/* +++ inflate.c */
++/* inflate.c -- zlib interface to inflate modules
++ * Copyright (C) 1995-1996 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* #include &quot;zutil.h&quot; */
++
++/* +++ infblock.h */
++/* infblock.h -- header to use infblock.c
++ * Copyright (C) 1995-1996 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* WARNING: this file should *not* be used by applications. It is
++ part of the implementation of the compression library and is
++ subject to change. Applications should only use zlib.h.
++ */
++
++struct inflate_blocks_state;
++typedef struct inflate_blocks_state FAR inflate_blocks_statef;
++
++extern inflate_blocks_statef * inflate_blocks_new OF((
++ z_streamp z,
++ check_func c, /* check function */
++ uInt w)); /* window size */
++
++extern int inflate_blocks OF((
++ inflate_blocks_statef *,
++ z_streamp ,
++ int)); /* initial return code */
++
++extern void inflate_blocks_reset OF((
++ inflate_blocks_statef *,
++ z_streamp ,
++ uLongf *)); /* check value on output */
++
++extern int inflate_blocks_free OF((
++ inflate_blocks_statef *,
++ z_streamp ,
++ uLongf *)); /* check value on output */
++
++extern void inflate_set_dictionary OF((
++ inflate_blocks_statef *s,
++ const Bytef *d, /* dictionary */
++ uInt n)); /* dictionary length */
++
++extern int inflate_addhistory OF((
++ inflate_blocks_statef *,
++ z_streamp));
++
++extern int inflate_packet_flush OF((
++ inflate_blocks_statef *));
++/* --- infblock.h */
++
++#ifndef NO_DUMMY_DECL
++struct inflate_blocks_state {int dummy;}; /* for buggy compilers */
++#endif
++
++/* inflate private state */
++struct internal_state {
++
++ /* mode */
++ enum {
++ METHOD, /* waiting for method byte */
++ FLAG, /* waiting for flag byte */
++ DICT4, /* four dictionary check bytes to go */
++ DICT3, /* three dictionary check bytes to go */
++ DICT2, /* two dictionary check bytes to go */
++ DICT1, /* one dictionary check byte to go */
++ DICT0, /* waiting for inflateSetDictionary */
++ BLOCKS, /* decompressing blocks */
++ CHECK4, /* four check bytes to go */
++ CHECK3, /* three check bytes to go */
++ CHECK2, /* two check bytes to go */
++ CHECK1, /* one check byte to go */
++ DONE, /* finished check, done */
++ BAD} /* got an error--stay here */
++ mode; /* current inflate mode */
++
++ /* mode dependent information */
++ union {
++ uInt method; /* if FLAGS, method byte */
++ struct {
++ uLong was; /* computed check value */
++ uLong need; /* stream check value */
++ } check; /* if CHECK, check values to compare */
++ uInt marker; /* if BAD, inflateSync's marker bytes count */
++ } sub; /* submode */
++
++ /* mode independent information */
++ int nowrap; /* flag for no wrapper */
++ uInt wbits; /* log2(window size) (8..15, defaults to 15) */
++ inflate_blocks_statef
++ *blocks; /* current inflate_blocks state */
++
++};
++
++
++int inflateReset(z)
++z_streamp z;
++{
++ uLong c;
++
++ if (z == Z_NULL || z-&gt;state == Z_NULL)
++ return Z_STREAM_ERROR;
++ z-&gt;total_in = z-&gt;total_out = 0;
++ z-&gt;msg = Z_NULL;
++ z-&gt;state-&gt;mode = z-&gt;state-&gt;nowrap ? BLOCKS : METHOD;
++ inflate_blocks_reset(z-&gt;state-&gt;blocks, z, &amp;c);
++ Trace((stderr, &quot;inflate: reset\n&quot;));
++ return Z_OK;
++}
++
++
++int inflateEnd(z)
++z_streamp z;
++{
++ uLong c;
++
++ if (z == Z_NULL || z-&gt;state == Z_NULL || z-&gt;zfree == Z_NULL)
++ return Z_STREAM_ERROR;
++ if (z-&gt;state-&gt;blocks != Z_NULL)
++ inflate_blocks_free(z-&gt;state-&gt;blocks, z, &amp;c);
++ ZFREE(z, z-&gt;state);
++ z-&gt;state = Z_NULL;
++ Trace((stderr, &quot;inflate: end\n&quot;));
++ return Z_OK;
++}
++
++
++int inflateInit2_(z, w, version, stream_size)
++z_streamp z;
++int w;
++const char *version;
++int stream_size;
++{
++ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
++ stream_size != sizeof(z_stream))
++ return Z_VERSION_ERROR;
++
++ /* initialize state */
++ if (z == Z_NULL)
++ return Z_STREAM_ERROR;
++ z-&gt;msg = Z_NULL;
++#ifndef NO_ZCFUNCS
++ if (z-&gt;zalloc == Z_NULL)
++ {
++ z-&gt;zalloc = zcalloc;
++ z-&gt;opaque = (voidpf)0;
++ }
++ if (z-&gt;zfree == Z_NULL) z-&gt;zfree = zcfree;
++#endif
++ if ((z-&gt;state = (struct internal_state FAR *)
++ ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
++ return Z_MEM_ERROR;
++ z-&gt;state-&gt;blocks = Z_NULL;
++
++ /* handle undocumented nowrap option (no zlib header or check) */
++ z-&gt;state-&gt;nowrap = 0;
++ if (w &lt; 0)
++ {
++ w = - w;
++ z-&gt;state-&gt;nowrap = 1;
++ }
++
++ /* set window size */
++ if (w &lt; 8 || w &gt; 15)
++ {
++ inflateEnd(z);
++ return Z_STREAM_ERROR;
++ }
++ z-&gt;state-&gt;wbits = (uInt)w;
++
++ /* create inflate_blocks state */
++ if ((z-&gt;state-&gt;blocks =
++ inflate_blocks_new(z, z-&gt;state-&gt;nowrap ? Z_NULL : adler32, (uInt)1 &lt;&lt; w))
++ == Z_NULL)
++ {
++ inflateEnd(z);
++ return Z_MEM_ERROR;
++ }
++ Trace((stderr, &quot;inflate: allocated\n&quot;));
++
++ /* reset state */
++ inflateReset(z);
++ return Z_OK;
++}
++
++
++int inflateInit_(z, version, stream_size)
++z_streamp z;
++const char *version;
++int stream_size;
++{
++ return inflateInit2_(z, DEF_WBITS, version, stream_size);
++}
++
++
++#define NEEDBYTE {if(z-&gt;avail_in==0)goto empty;r=Z_OK;}
++#define NEXTBYTE (z-&gt;avail_in--,z-&gt;total_in++,*z-&gt;next_in++)
++
++int inflate(z, f)
++z_streamp z;
++int f;
++{
++ int r;
++ uInt b;
++
++ if (z == Z_NULL || z-&gt;state == Z_NULL || z-&gt;next_in == Z_NULL || f &lt; 0)
++ return Z_STREAM_ERROR;
++ r = Z_BUF_ERROR;
++ while (1) switch (z-&gt;state-&gt;mode)
++ {
++ case METHOD:
++ NEEDBYTE
++ if (((z-&gt;state-&gt;sub.method = NEXTBYTE) &amp; 0xf) != Z_DEFLATED)
++ {
++ z-&gt;state-&gt;mode = BAD;
++ z-&gt;msg = (char*)&quot;unknown compression method&quot;;
++ z-&gt;state-&gt;sub.marker = 5; /* can't try inflateSync */
++ break;
++ }
++ if ((z-&gt;state-&gt;sub.method &gt;&gt; 4) + 8 &gt; z-&gt;state-&gt;wbits)
++ {
++ z-&gt;state-&gt;mode = BAD;
++ z-&gt;msg = (char*)&quot;invalid window size&quot;;
++ z-&gt;state-&gt;sub.marker = 5; /* can't try inflateSync */
++ break;
++ }
++ z-&gt;state-&gt;mode = FLAG;
++ case FLAG:
++ NEEDBYTE
++ b = NEXTBYTE;
++ if (((z-&gt;state-&gt;sub.method &lt;&lt; 8) + b) % 31)
++ {
++ z-&gt;state-&gt;mode = BAD;
++ z-&gt;msg = (char*)&quot;incorrect header check&quot;;
++ z-&gt;state-&gt;sub.marker = 5; /* can't try inflateSync */
++ break;
++ }
++ Trace((stderr, &quot;inflate: zlib header ok\n&quot;));
++ if (!(b &amp; PRESET_DICT))
++ {
++ z-&gt;state-&gt;mode = BLOCKS;
++ break;
++ }
++ z-&gt;state-&gt;mode = DICT4;
++ case DICT4:
++ NEEDBYTE
++ z-&gt;state-&gt;sub.check.need = (uLong)NEXTBYTE &lt;&lt; 24;
++ z-&gt;state-&gt;mode = DICT3;
++ case DICT3:
++ NEEDBYTE
++ z-&gt;state-&gt;sub.check.need += (uLong)NEXTBYTE &lt;&lt; 16;
++ z-&gt;state-&gt;mode = DICT2;
++ case DICT2:
++ NEEDBYTE
++ z-&gt;state-&gt;sub.check.need += (uLong)NEXTBYTE &lt;&lt; 8;
++ z-&gt;state-&gt;mode = DICT1;
++ case DICT1:
++ NEEDBYTE
++ z-&gt;state-&gt;sub.check.need += (uLong)NEXTBYTE;
++ z-&gt;adler = z-&gt;state-&gt;sub.check.need;
++ z-&gt;state-&gt;mode = DICT0;
++ return Z_NEED_DICT;
++ case DICT0:
++ z-&gt;state-&gt;mode = BAD;
++ z-&gt;msg = (char*)&quot;need dictionary&quot;;
++ z-&gt;state-&gt;sub.marker = 0; /* can try inflateSync */
++ return Z_STREAM_ERROR;
++ case BLOCKS:
++ r = inflate_blocks(z-&gt;state-&gt;blocks, z, r);
++ if (f == Z_PACKET_FLUSH &amp;&amp; z-&gt;avail_in == 0 &amp;&amp; z-&gt;avail_out != 0)
++ r = inflate_packet_flush(z-&gt;state-&gt;blocks);
++ if (r == Z_DATA_ERROR)
++ {
++ z-&gt;state-&gt;mode = BAD;
++ z-&gt;state-&gt;sub.marker = 0; /* can try inflateSync */
++ break;
++ }
++ if (r != Z_STREAM_END)
++ return r;
++ r = Z_OK;
++ inflate_blocks_reset(z-&gt;state-&gt;blocks, z, &amp;z-&gt;state-&gt;sub.check.was);
++ if (z-&gt;state-&gt;nowrap)
++ {
++ z-&gt;state-&gt;mode = DONE;
++ break;
++ }
++ z-&gt;state-&gt;mode = CHECK4;
++ case CHECK4:
++ NEEDBYTE
++ z-&gt;state-&gt;sub.check.need = (uLong)NEXTBYTE &lt;&lt; 24;
++ z-&gt;state-&gt;mode = CHECK3;
++ case CHECK3:
++ NEEDBYTE
++ z-&gt;state-&gt;sub.check.need += (uLong)NEXTBYTE &lt;&lt; 16;
++ z-&gt;state-&gt;mode = CHECK2;
++ case CHECK2:
++ NEEDBYTE
++ z-&gt;state-&gt;sub.check.need += (uLong)NEXTBYTE &lt;&lt; 8;
++ z-&gt;state-&gt;mode = CHECK1;
++ case CHECK1:
++ NEEDBYTE
++ z-&gt;state-&gt;sub.check.need += (uLong)NEXTBYTE;
++
++ if (z-&gt;state-&gt;sub.check.was != z-&gt;state-&gt;sub.check.need)
++ {
++ z-&gt;state-&gt;mode = BAD;
++ z-&gt;msg = (char*)&quot;incorrect data check&quot;;
++ z-&gt;state-&gt;sub.marker = 5; /* can't try inflateSync */
++ break;
++ }
++ Trace((stderr, &quot;inflate: zlib check ok\n&quot;));
++ z-&gt;state-&gt;mode = DONE;
++ case DONE:
++ return Z_STREAM_END;
++ case BAD:
++ return Z_DATA_ERROR;
++ default:
++ return Z_STREAM_ERROR;
++ }
++
++ empty:
++ if (f != Z_PACKET_FLUSH)
++ return r;
++ z-&gt;state-&gt;mode = BAD;
++ z-&gt;msg = (char *)&quot;need more for packet flush&quot;;
++ z-&gt;state-&gt;sub.marker = 0; /* can try inflateSync */
++ return Z_DATA_ERROR;
++}
++
++
++int inflateSetDictionary(z, dictionary, dictLength)
++z_streamp z;
++const Bytef *dictionary;
++uInt dictLength;
++{
++ uInt length = dictLength;
++
++ if (z == Z_NULL || z-&gt;state == Z_NULL || z-&gt;state-&gt;mode != DICT0)
++ return Z_STREAM_ERROR;
++
++ if (adler32(1L, dictionary, dictLength) != z-&gt;adler) return Z_DATA_ERROR;
++ z-&gt;adler = 1L;
++
++ if (length &gt;= ((uInt)1&lt;&lt;z-&gt;state-&gt;wbits))
++ {
++ length = (1&lt;&lt;z-&gt;state-&gt;wbits)-1;
++ dictionary += dictLength - length;
++ }
++ inflate_set_dictionary(z-&gt;state-&gt;blocks, dictionary, length);
++ z-&gt;state-&gt;mode = BLOCKS;
++ return Z_OK;
++}
++
++/*
++ * This subroutine adds the data at next_in/avail_in to the output history
++ * without performing any output. The output buffer must be &quot;caught up&quot;;
++ * i.e. no pending output (hence s-&gt;read equals s-&gt;write), and the state must
++ * be BLOCKS (i.e. we should be willing to see the start of a series of
++ * BLOCKS). On exit, the output will also be caught up, and the checksum
++ * will have been updated if need be.
++ */
++
++int inflateIncomp(z)
++z_stream *z;
++{
++ if (z-&gt;state-&gt;mode != BLOCKS)
++ return Z_DATA_ERROR;
++ return inflate_addhistory(z-&gt;state-&gt;blocks, z);
++}
++
++
++int inflateSync(z)
++z_streamp z;
++{
++ uInt n; /* number of bytes to look at */
++ Bytef *p; /* pointer to bytes */
++ uInt m; /* number of marker bytes found in a row */
++ uLong r, w; /* temporaries to save total_in and total_out */
++
++ /* set up */
++ if (z == Z_NULL || z-&gt;state == Z_NULL)
++ return Z_STREAM_ERROR;
++ if (z-&gt;state-&gt;mode != BAD)
++ {
++ z-&gt;state-&gt;mode = BAD;
++ z-&gt;state-&gt;sub.marker = 0;
++ }
++ if ((n = z-&gt;avail_in) == 0)
++ return Z_BUF_ERROR;
++ p = z-&gt;next_in;
++ m = z-&gt;state-&gt;sub.marker;
++
++ /* search */
++ while (n &amp;&amp; m &lt; 4)
++ {
++ if (*p == (Byte)(m &lt; 2 ? 0 : 0xff))
++ m++;
++ else if (*p)
++ m = 0;
++ else
++ m = 4 - m;
++ p++, n--;
++ }
++
++ /* restore */
++ z-&gt;total_in += p - z-&gt;next_in;
++ z-&gt;next_in = p;
++ z-&gt;avail_in = n;
++ z-&gt;state-&gt;sub.marker = m;
++
++ /* return no joy or set up to restart on a new block */
++ if (m != 4)
++ return Z_DATA_ERROR;
++ r = z-&gt;total_in; w = z-&gt;total_out;
++ inflateReset(z);
++ z-&gt;total_in = r; z-&gt;total_out = w;
++ z-&gt;state-&gt;mode = BLOCKS;
++ return Z_OK;
++}
++
++#undef NEEDBYTE
++#undef NEXTBYTE
++/* --- inflate.c */
++
++/* +++ infblock.c */
++/* infblock.c -- interpret and process block types to last block
++ * Copyright (C) 1995-1996 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* #include &quot;zutil.h&quot; */
++/* #include &quot;infblock.h&quot; */
++
++/* +++ inftrees.h */
++/* inftrees.h -- header to use inftrees.c
++ * Copyright (C) 1995-1996 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* WARNING: this file should *not* be used by applications. It is
++ part of the implementation of the compression library and is
++ subject to change. Applications should only use zlib.h.
++ */
++
++/* Huffman code lookup table entry--this entry is four bytes for machines
++ that have 16-bit pointers (e.g. PC's in the small or medium model). */
++
++typedef struct inflate_huft_s FAR inflate_huft;
++
++struct inflate_huft_s {
++ union {
++ struct {
++ Byte Exop; /* number of extra bits or operation */
++ Byte Bits; /* number of bits in this code or subcode */
++ } what;
++ Bytef *pad; /* pad structure to a power of 2 (4 bytes for */
++ } word; /* 16-bit, 8 bytes for 32-bit machines) */
++ union {
++ uInt Base; /* literal, length base, or distance base */
++ inflate_huft *Next; /* pointer to next level of table */
++ } more;
++};
++
++#ifdef DEBUG_ZLIB
++ extern uInt inflate_hufts;
++#endif
++
++extern int inflate_trees_bits OF((
++ uIntf *, /* 19 code lengths */
++ uIntf *, /* bits tree desired/actual depth */
++ inflate_huft * FAR *, /* bits tree result */
++ z_streamp )); /* for zalloc, zfree functions */
++
++extern int inflate_trees_dynamic OF((
++ uInt, /* number of literal/length codes */
++ uInt, /* number of distance codes */
++ uIntf *, /* that many (total) code lengths */
++ uIntf *, /* literal desired/actual bit depth */
++ uIntf *, /* distance desired/actual bit depth */
++ inflate_huft * FAR *, /* literal/length tree result */
++ inflate_huft * FAR *, /* distance tree result */
++ z_streamp )); /* for zalloc, zfree functions */
++
++extern int inflate_trees_fixed OF((
++ uIntf *, /* literal desired/actual bit depth */
++ uIntf *, /* distance desired/actual bit depth */
++ inflate_huft * FAR *, /* literal/length tree result */
++ inflate_huft * FAR *)); /* distance tree result */
++
++extern int inflate_trees_free OF((
++ inflate_huft *, /* tables to free */
++ z_streamp )); /* for zfree function */
++
++/* --- inftrees.h */
++
++/* +++ infcodes.h */
++/* infcodes.h -- header to use infcodes.c
++ * Copyright (C) 1995-1996 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* WARNING: this file should *not* be used by applications. It is
++ part of the implementation of the compression library and is
++ subject to change. Applications should only use zlib.h.
++ */
++
++struct inflate_codes_state;
++typedef struct inflate_codes_state FAR inflate_codes_statef;
++
++extern inflate_codes_statef *inflate_codes_new OF((
++ uInt, uInt,
++ inflate_huft *, inflate_huft *,
++ z_streamp ));
++
++extern int inflate_codes OF((
++ inflate_blocks_statef *,
++ z_streamp ,
++ int));
++
++extern void inflate_codes_free OF((
++ inflate_codes_statef *,
++ z_streamp ));
++
++/* --- infcodes.h */
++
++/* +++ infutil.h */
++/* infutil.h -- types and macros common to blocks and codes
++ * Copyright (C) 1995-1996 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* WARNING: this file should *not* be used by applications. It is
++ part of the implementation of the compression library and is
++ subject to change. Applications should only use zlib.h.
++ */
++
++#ifndef _INFUTIL_H
++#define _INFUTIL_H
++
++typedef enum {
++ TYPE, /* get type bits (3, including end bit) */
++ LENS, /* get lengths for stored */
++ STORED, /* processing stored block */
++ TABLE, /* get table lengths */
++ BTREE, /* get bit lengths tree for a dynamic block */
++ DTREE, /* get length, distance trees for a dynamic block */
++ CODES, /* processing fixed or dynamic block */
++ DRY, /* output remaining window bytes */
++ DONEB, /* finished last block, done */
++ BADB} /* got a data error--stuck here */
++inflate_block_mode;
++
++/* inflate blocks semi-private state */
++struct inflate_blocks_state {
++
++ /* mode */
++ inflate_block_mode mode; /* current inflate_block mode */
++
++ /* mode dependent information */
++ union {
++ uInt left; /* if STORED, bytes left to copy */
++ struct {
++ uInt table; /* table lengths (14 bits) */
++ uInt index; /* index into blens (or border) */
++ uIntf *blens; /* bit lengths of codes */
++ uInt bb; /* bit length tree depth */
++ inflate_huft *tb; /* bit length decoding tree */
++ } trees; /* if DTREE, decoding info for trees */
++ struct {
++ inflate_huft *tl;
++ inflate_huft *td; /* trees to free */
++ inflate_codes_statef
++ *codes;
++ } decode; /* if CODES, current state */
++ } sub; /* submode */
++ uInt last; /* true if this block is the last block */
++
++ /* mode independent information */
++ uInt bitk; /* bits in bit buffer */
++ uLong bitb; /* bit buffer */
++ Bytef *window; /* sliding window */
++ Bytef *end; /* one byte after sliding window */
++ Bytef *read; /* window read pointer */
++ Bytef *write; /* window write pointer */
++ check_func checkfn; /* check function */
++ uLong check; /* check on output */
++
++};
++
++
++/* defines for inflate input/output */
++/* update pointers and return */
++#define UPDBITS {s-&gt;bitb=b;s-&gt;bitk=k;}
++#define UPDIN {z-&gt;avail_in=n;z-&gt;total_in+=p-z-&gt;next_in;z-&gt;next_in=p;}
++#define UPDOUT {s-&gt;write=q;}
++#define UPDATE {UPDBITS UPDIN UPDOUT}
++#define LEAVE {UPDATE return inflate_flush(s,z,r);}
++/* get bytes and bits */
++#define LOADIN {p=z-&gt;next_in;n=z-&gt;avail_in;b=s-&gt;bitb;k=s-&gt;bitk;}
++#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
++#define NEXTBYTE (n--,*p++)
++#define NEEDBITS(j) {while(k&lt;(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)&lt;&lt;k;k+=8;}}
++#define DUMPBITS(j) {b&gt;&gt;=(j);k-=(j);}
++/* output bytes */
++#define WAVAIL (uInt)(q&lt;s-&gt;read?s-&gt;read-q-1:s-&gt;end-q)
++#define LOADOUT {q=s-&gt;write;m=(uInt)WAVAIL;}
++#define WWRAP {if(q==s-&gt;end&amp;&amp;s-&gt;read!=s-&gt;window){q=s-&gt;window;m=(uInt)WAVAIL;}}
++#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
++#define NEEDOUT {if(m==0){WWRAP if(m==0){FLUSH WWRAP if(m==0) LEAVE}}r=Z_OK;}
++#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
++/* load local pointers */
++#define LOAD {LOADIN LOADOUT}
++
++/* masks for lower bits (size given to avoid silly warnings with Visual C++) */
++extern uInt inflate_mask[17];
++
++/* copy as much as possible from the sliding window to the output area */
++extern int inflate_flush OF((
++ inflate_blocks_statef *,
++ z_streamp ,
++ int));
++
++#ifndef NO_DUMMY_DECL
++struct internal_state {int dummy;}; /* for buggy compilers */
++#endif
++
++#endif
++/* --- infutil.h */
++
++#ifndef NO_DUMMY_DECL
++struct inflate_codes_state {int dummy;}; /* for buggy compilers */
++#endif
++
++/* Table for deflate from PKZIP's appnote.txt. */
++local const uInt border[] = { /* Order of the bit length code lengths */
++ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
++
++/*
++ Notes beyond the 1.93a appnote.txt:
++
++ 1. Distance pointers never point before the beginning of the output
++ stream.
++ 2. Distance pointers can point back across blocks, up to 32k away.
++ 3. There is an implied maximum of 7 bits for the bit length table and
++ 15 bits for the actual data.
++ 4. If only one code exists, then it is encoded using one bit. (Zero
++ would be more efficient, but perhaps a little confusing.) If two
++ codes exist, they are coded using one bit each (0 and 1).
++ 5. There is no way of sending zero distance codes--a dummy must be
++ sent if there are none. (History: a pre 2.0 version of PKZIP would
++ store blocks with no distance codes, but this was discovered to be
++ too harsh a criterion.) Valid only for 1.93a. 2.04c does allow
++ zero distance codes, which is sent as one code of zero bits in
++ length.
++ 6. There are up to 286 literal/length codes. Code 256 represents the
++ end-of-block. Note however that the static length tree defines
++ 288 codes just to fill out the Huffman codes. Codes 286 and 287
++ cannot be used though, since there is no length base or extra bits
++ defined for them. Similarily, there are up to 30 distance codes.
++ However, static trees define 32 codes (all 5 bits) to fill out the
++ Huffman codes, but the last two had better not show up in the data.
++ 7. Unzip can check dynamic Huffman blocks for complete code sets.
++ The exception is that a single code would not be complete (see #4).
++ 8. The five bits following the block type is really the number of
++ literal codes sent minus 257.
++ 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
++ (1+6+6). Therefore, to output three times the length, you output
++ three codes (1+1+1), whereas to output four times the same length,
++ you only need two codes (1+3). Hmm.
++ 10. In the tree reconstruction algorithm, Code = Code + Increment
++ only if BitLength(i) is not zero. (Pretty obvious.)
++ 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19)
++ 12. Note: length code 284 can represent 227-258, but length code 285
++ really is 258. The last length deserves its own, short code
++ since it gets used a lot in very redundant files. The length
++ 258 is special since 258 - 3 (the min match length) is 255.
++ 13. The literal/length and distance code bit lengths are read as a
++ single stream of lengths. It is possible (and advantageous) for
++ a repeat code (16, 17, or 18) to go across the boundary between
++ the two sets of lengths.
++ */
++
++
++void inflate_blocks_reset(s, z, c)
++inflate_blocks_statef *s;
++z_streamp z;
++uLongf *c;
++{
++ if (s-&gt;checkfn != Z_NULL)
++ *c = s-&gt;check;
++ if (s-&gt;mode == BTREE || s-&gt;mode == DTREE)
++ ZFREE(z, s-&gt;sub.trees.blens);
++ if (s-&gt;mode == CODES)
++ {
++ inflate_codes_free(s-&gt;sub.decode.codes, z);
++ inflate_trees_free(s-&gt;sub.decode.td, z);
++ inflate_trees_free(s-&gt;sub.decode.tl, z);
++ }
++ s-&gt;mode = TYPE;
++ s-&gt;bitk = 0;
++ s-&gt;bitb = 0;
++ s-&gt;read = s-&gt;write = s-&gt;window;
++ if (s-&gt;checkfn != Z_NULL)
++ z-&gt;adler = s-&gt;check = (*s-&gt;checkfn)(0L, Z_NULL, 0);
++ Trace((stderr, &quot;inflate: blocks reset\n&quot;));
++}
++
++
++inflate_blocks_statef *inflate_blocks_new(z, c, w)
++z_streamp z;
++check_func c;
++uInt w;
++{
++ inflate_blocks_statef *s;
++
++ if ((s = (inflate_blocks_statef *)ZALLOC
++ (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
++ return s;
++ if ((s-&gt;window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
++ {
++ ZFREE(z, s);
++ return Z_NULL;
++ }
++ s-&gt;end = s-&gt;window + w;
++ s-&gt;checkfn = c;
++ s-&gt;mode = TYPE;
++ Trace((stderr, &quot;inflate: blocks allocated\n&quot;));
++ inflate_blocks_reset(s, z, &amp;s-&gt;check);
++ return s;
++}
++
++
++#ifdef DEBUG_ZLIB
++ extern uInt inflate_hufts;
++#endif
++int inflate_blocks(s, z, r)
++inflate_blocks_statef *s;
++z_streamp z;
++int r;
++{
++ uInt t; /* temporary storage */
++ uLong b; /* bit buffer */
++ uInt k; /* bits in bit buffer */
++ Bytef *p; /* input data pointer */
++ uInt n; /* bytes available there */
++ Bytef *q; /* output window write pointer */
++ uInt m; /* bytes to end of window or read pointer */
++
++ /* copy input/output information to locals (UPDATE macro restores) */
++ LOAD
++
++ /* process input based on current state */
++ while (1) switch (s-&gt;mode)
++ {
++ case TYPE:
++ NEEDBITS(3)
++ t = (uInt)b &amp; 7;
++ s-&gt;last = t &amp; 1;
++ switch (t &gt;&gt; 1)
++ {
++ case 0: /* stored */
++ Trace((stderr, &quot;inflate: stored block%s\n&quot;,
++ s-&gt;last ? &quot; (last)&quot; : &quot;&quot;));
++ DUMPBITS(3)
++ t = k &amp; 7; /* go to byte boundary */
++ DUMPBITS(t)
++ s-&gt;mode = LENS; /* get length of stored block */
++ break;
++ case 1: /* fixed */
++ Trace((stderr, &quot;inflate: fixed codes block%s\n&quot;,
++ s-&gt;last ? &quot; (last)&quot; : &quot;&quot;));
++ {
++ uInt bl, bd;
++ inflate_huft *tl, *td;
++
++ inflate_trees_fixed(&amp;bl, &amp;bd, &amp;tl, &amp;td);
++ s-&gt;sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
++ if (s-&gt;sub.decode.codes == Z_NULL)
++ {
++ r = Z_MEM_ERROR;
++ LEAVE
++ }
++ s-&gt;sub.decode.tl = Z_NULL; /* don't try to free these */
++ s-&gt;sub.decode.td = Z_NULL;
++ }
++ DUMPBITS(3)
++ s-&gt;mode = CODES;
++ break;
++ case 2: /* dynamic */
++ Trace((stderr, &quot;inflate: dynamic codes block%s\n&quot;,
++ s-&gt;last ? &quot; (last)&quot; : &quot;&quot;));
++ DUMPBITS(3)
++ s-&gt;mode = TABLE;
++ break;
++ case 3: /* illegal */
++ DUMPBITS(3)
++ s-&gt;mode = BADB;
++ z-&gt;msg = (char*)&quot;invalid block type&quot;;
++ r = Z_DATA_ERROR;
++ LEAVE
++ }
++ break;
++ case LENS:
++ NEEDBITS(32)
++ if ((((~b) &gt;&gt; 16) &amp; 0xffff) != (b &amp; 0xffff))
++ {
++ s-&gt;mode = BADB;
++ z-&gt;msg = (char*)&quot;invalid stored block lengths&quot;;
++ r = Z_DATA_ERROR;
++ LEAVE
++ }
++ s-&gt;sub.left = (uInt)b &amp; 0xffff;
++ b = k = 0; /* dump bits */
++ Tracev((stderr, &quot;inflate: stored length %u\n&quot;, s-&gt;sub.left));
++ s-&gt;mode = s-&gt;sub.left ? STORED : (s-&gt;last ? DRY : TYPE);
++ break;
++ case STORED:
++ if (n == 0)
++ LEAVE
++ NEEDOUT
++ t = s-&gt;sub.left;
++ if (t &gt; n) t = n;
++ if (t &gt; m) t = m;
++ zmemcpy(q, p, t);
++ p += t; n -= t;
++ q += t; m -= t;
++ if ((s-&gt;sub.left -= t) != 0)
++ break;
++ Tracev((stderr, &quot;inflate: stored end, %lu total out\n&quot;,
++ z-&gt;total_out + (q &gt;= s-&gt;read ? q - s-&gt;read :
++ (s-&gt;end - s-&gt;read) + (q - s-&gt;window))));
++ s-&gt;mode = s-&gt;last ? DRY : TYPE;
++ break;
++ case TABLE:
++ NEEDBITS(14)
++ s-&gt;sub.trees.table = t = (uInt)b &amp; 0x3fff;
++#ifndef PKZIP_BUG_WORKAROUND
++ if ((t &amp; 0x1f) &gt; 29 || ((t &gt;&gt; 5) &amp; 0x1f) &gt; 29)
++ {
++ s-&gt;mode = BADB;
++ z-&gt;msg = (char*)&quot;too many length or distance symbols&quot;;
++ r = Z_DATA_ERROR;
++ LEAVE
++ }
++#endif
++ t = 258 + (t &amp; 0x1f) + ((t &gt;&gt; 5) &amp; 0x1f);
++ if (t &lt; 19)
++ t = 19;
++ if ((s-&gt;sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
++ {
++ r = Z_MEM_ERROR;
++ LEAVE
++ }
++ DUMPBITS(14)
++ s-&gt;sub.trees.index = 0;
++ Tracev((stderr, &quot;inflate: table sizes ok\n&quot;));
++ s-&gt;mode = BTREE;
++ case BTREE:
++ while (s-&gt;sub.trees.index &lt; 4 + (s-&gt;sub.trees.table &gt;&gt; 10))
++ {
++ NEEDBITS(3)
++ s-&gt;sub.trees.blens[border[s-&gt;sub.trees.index++]] = (uInt)b &amp; 7;
++ DUMPBITS(3)
++ }
++ while (s-&gt;sub.trees.index &lt; 19)
++ s-&gt;sub.trees.blens[border[s-&gt;sub.trees.index++]] = 0;
++ s-&gt;sub.trees.bb = 7;
++ t = inflate_trees_bits(s-&gt;sub.trees.blens, &amp;s-&gt;sub.trees.bb,
++ &amp;s-&gt;sub.trees.tb, z);
++ if (t != Z_OK)
++ {
++ ZFREE(z, s-&gt;sub.trees.blens);
++ r = t;
++ if (r == Z_DATA_ERROR)
++ s-&gt;mode = BADB;
++ LEAVE
++ }
++ s-&gt;sub.trees.index = 0;
++ Tracev((stderr, &quot;inflate: bits tree ok\n&quot;));
++ s-&gt;mode = DTREE;
++ case DTREE:
++ while (t = s-&gt;sub.trees.table,
++ s-&gt;sub.trees.index &lt; 258 + (t &amp; 0x1f) + ((t &gt;&gt; 5) &amp; 0x1f))
++ {
++ inflate_huft *h;
++ uInt i, j, c;
++
++ t = s-&gt;sub.trees.bb;
++ NEEDBITS(t)
++ h = s-&gt;sub.trees.tb + ((uInt)b &amp; inflate_mask[t]);
++ t = h-&gt;word.what.Bits;
++ c = h-&gt;more.Base;
++ if (c &lt; 16)
++ {
++ DUMPBITS(t)
++ s-&gt;sub.trees.blens[s-&gt;sub.trees.index++] = c;
++ }
++ else /* c == 16..18 */
++ {
++ i = c == 18 ? 7 : c - 14;
++ j = c == 18 ? 11 : 3;
++ NEEDBITS(t + i)
++ DUMPBITS(t)
++ j += (uInt)b &amp; inflate_mask[i];
++ DUMPBITS(i)
++ i = s-&gt;sub.trees.index;
++ t = s-&gt;sub.trees.table;
++ if (i + j &gt; 258 + (t &amp; 0x1f) + ((t &gt;&gt; 5) &amp; 0x1f) ||
++ (c == 16 &amp;&amp; i &lt; 1))
++ {
++ inflate_trees_free(s-&gt;sub.trees.tb, z);
++ ZFREE(z, s-&gt;sub.trees.blens);
++ s-&gt;mode = BADB;
++ z-&gt;msg = (char*)&quot;invalid bit length repeat&quot;;
++ r = Z_DATA_ERROR;
++ LEAVE
++ }
++ c = c == 16 ? s-&gt;sub.trees.blens[i - 1] : 0;
++ do {
++ s-&gt;sub.trees.blens[i++] = c;
++ } while (--j);
++ s-&gt;sub.trees.index = i;
++ }
++ }
++ inflate_trees_free(s-&gt;sub.trees.tb, z);
++ s-&gt;sub.trees.tb = Z_NULL;
++ {
++ uInt bl, bd;
++ inflate_huft *tl, *td;
++ inflate_codes_statef *c;
++
++ bl = 9; /* must be &lt;= 9 for lookahead assumptions */
++ bd = 6; /* must be &lt;= 9 for lookahead assumptions */
++ t = s-&gt;sub.trees.table;
++#ifdef DEBUG_ZLIB
++ inflate_hufts = 0;
++#endif
++ t = inflate_trees_dynamic(257 + (t &amp; 0x1f), 1 + ((t &gt;&gt; 5) &amp; 0x1f),
++ s-&gt;sub.trees.blens, &amp;bl, &amp;bd, &amp;tl, &amp;td, z);
++ ZFREE(z, s-&gt;sub.trees.blens);
++ if (t != Z_OK)
++ {
++ if (t == (uInt)Z_DATA_ERROR)
++ s-&gt;mode = BADB;
++ r = t;
++ LEAVE
++ }
++ Tracev((stderr, &quot;inflate: trees ok, %d * %d bytes used\n&quot;,
++ inflate_hufts, sizeof(inflate_huft)));
++ if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
++ {
++ inflate_trees_free(td, z);
++ inflate_trees_free(tl, z);
++ r = Z_MEM_ERROR;
++ LEAVE
++ }
++ s-&gt;sub.decode.codes = c;
++ s-&gt;sub.decode.tl = tl;
++ s-&gt;sub.decode.td = td;
++ }
++ s-&gt;mode = CODES;
++ case CODES:
++ UPDATE
++ if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
++ return inflate_flush(s, z, r);
++ r = Z_OK;
++ inflate_codes_free(s-&gt;sub.decode.codes, z);
++ inflate_trees_free(s-&gt;sub.decode.td, z);
++ inflate_trees_free(s-&gt;sub.decode.tl, z);
++ LOAD
++ Tracev((stderr, &quot;inflate: codes end, %lu total out\n&quot;,
++ z-&gt;total_out + (q &gt;= s-&gt;read ? q - s-&gt;read :
++ (s-&gt;end - s-&gt;read) + (q - s-&gt;window))));
++ if (!s-&gt;last)
++ {
++ s-&gt;mode = TYPE;
++ break;
++ }
++ if (k &gt; 7) /* return unused byte, if any */
++ {
++ Assert(k &lt; 16, &quot;inflate_codes grabbed too many bytes&quot;)
++ k -= 8;
++ n++;
++ p--; /* can always return one */
++ }
++ s-&gt;mode = DRY;
++ case DRY:
++ FLUSH
++ if (s-&gt;read != s-&gt;write)
++ LEAVE
++ s-&gt;mode = DONEB;
++ case DONEB:
++ r = Z_STREAM_END;
++ LEAVE
++ case BADB:
++ r = Z_DATA_ERROR;
++ LEAVE
++ default:
++ r = Z_STREAM_ERROR;
++ LEAVE
++ }
++}
++
++
++int inflate_blocks_free(s, z, c)
++inflate_blocks_statef *s;
++z_streamp z;
++uLongf *c;
++{
++ inflate_blocks_reset(s, z, c);
++ ZFREE(z, s-&gt;window);
++ ZFREE(z, s);
++ Trace((stderr, &quot;inflate: blocks freed\n&quot;));
++ return Z_OK;
++}
++
++
++void inflate_set_dictionary(s, d, n)
++inflate_blocks_statef *s;
++const Bytef *d;
++uInt n;
++{
++ zmemcpy((charf *)s-&gt;window, d, n);
++ s-&gt;read = s-&gt;write = s-&gt;window + n;
++}
++
++/*
++ * This subroutine adds the data at next_in/avail_in to the output history
++ * without performing any output. The output buffer must be &quot;caught up&quot;;
++ * i.e. no pending output (hence s-&gt;read equals s-&gt;write), and the state must
++ * be BLOCKS (i.e. we should be willing to see the start of a series of
++ * BLOCKS). On exit, the output will also be caught up, and the checksum
++ * will have been updated if need be.
++ */
++int inflate_addhistory(s, z)
++inflate_blocks_statef *s;
++z_stream *z;
++{
++ uLong b; /* bit buffer */ /* NOT USED HERE */
++ uInt k; /* bits in bit buffer */ /* NOT USED HERE */
++ uInt t; /* temporary storage */
++ Bytef *p; /* input data pointer */
++ uInt n; /* bytes available there */
++ Bytef *q; /* output window write pointer */
++ uInt m; /* bytes to end of window or read pointer */
++
++ if (s-&gt;read != s-&gt;write)
++ return Z_STREAM_ERROR;
++ if (s-&gt;mode != TYPE)
++ return Z_DATA_ERROR;
++
++ /* we're ready to rock */
++ LOAD
++ /* while there is input ready, copy to output buffer, moving
++ * pointers as needed.
++ */
++ while (n) {
++ t = n; /* how many to do */
++ /* is there room until end of buffer? */
++ if (t &gt; m) t = m;
++ /* update check information */
++ if (s-&gt;checkfn != Z_NULL)
++ s-&gt;check = (*s-&gt;checkfn)(s-&gt;check, q, t);
++ zmemcpy(q, p, t);
++ q += t;
++ p += t;
++ n -= t;
++ z-&gt;total_out += t;
++ s-&gt;read = q; /* drag read pointer forward */
++/* WWRAP */ /* expand WWRAP macro by hand to handle s-&gt;read */
++ if (q == s-&gt;end) {
++ s-&gt;read = q = s-&gt;window;
++ m = WAVAIL;
++ }
++ }
++ UPDATE
++ return Z_OK;
++}
++
++
++/*
++ * At the end of a Deflate-compressed PPP packet, we expect to have seen
++ * a `stored' block type value but not the (zero) length bytes.
++ */
++int inflate_packet_flush(s)
++ inflate_blocks_statef *s;
++{
++ if (s-&gt;mode != LENS)
++ return Z_DATA_ERROR;
++ s-&gt;mode = TYPE;
++ return Z_OK;
++}
++/* --- infblock.c */
++
++/* +++ inftrees.c */
++/* inftrees.c -- generate Huffman trees for efficient decoding
++ * Copyright (C) 1995-1996 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* #include &quot;zutil.h&quot; */
++/* #include &quot;inftrees.h&quot; */
++
++char inflate_copyright[] = &quot; inflate 1.0.4 Copyright 1995-1996 Mark Adler &quot;;
++/*
++ If you use the zlib library in a product, an acknowledgment is welcome
++ in the documentation of your product. If for some reason you cannot
++ include such an acknowledgment, I would appreciate that you keep this
++ copyright string in the executable of your product.
++ */
++
++#ifndef NO_DUMMY_DECL
++struct internal_state {int dummy;}; /* for buggy compilers */
++#endif
++
++/* simplify the use of the inflate_huft type with some defines */
++#define base more.Base
++#define next more.Next
++#define exop word.what.Exop
++#define bits word.what.Bits
++
++
++local int huft_build OF((
++ uIntf *, /* code lengths in bits */
++ uInt, /* number of codes */
++ uInt, /* number of &quot;simple&quot; codes */
++ const uIntf *, /* list of base values for non-simple codes */
++ const uIntf *, /* list of extra bits for non-simple codes */
++ inflate_huft * FAR*,/* result: starting table */
++ uIntf *, /* maximum lookup bits (returns actual) */
++ z_streamp )); /* for zalloc function */
++
++local voidpf falloc OF((
++ voidpf, /* opaque pointer (not used) */
++ uInt, /* number of items */
++ uInt)); /* size of item */
++
++/* Tables for deflate from PKZIP's appnote.txt. */
++local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */
++ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
++ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
++ /* see note #13 above about 258 */
++local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */
++ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
++ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */
++local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */
++ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
++ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
++ 8193, 12289, 16385, 24577};
++local const uInt cpdext[30] = { /* Extra bits for distance codes */
++ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
++ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
++ 12, 12, 13, 13};
++
++/*
++ Huffman code decoding is performed using a multi-level table lookup.
++ The fastest way to decode is to simply build a lookup table whose
++ size is determined by the longest code. However, the time it takes
++ to build this table can also be a factor if the data being decoded
++ is not very long. The most common codes are necessarily the
++ shortest codes, so those codes dominate the decoding time, and hence
++ the speed. The idea is you can have a shorter table that decodes the
++ shorter, more probable codes, and then point to subsidiary tables for
++ the longer codes. The time it costs to decode the longer codes is
++ then traded against the time it takes to make longer tables.
++
++ This results of this trade are in the variables lbits and dbits
++ below. lbits is the number of bits the first level table for literal/
++ length codes can decode in one step, and dbits is the same thing for
++ the distance codes. Subsequent tables are also less than or equal to
++ those sizes. These values may be adjusted either when all of the
++ codes are shorter than that, in which case the longest code length in
++ bits is used, or when the shortest code is *longer* than the requested
++ table size, in which case the length of the shortest code in bits is
++ used.
++
++ There are two different values for the two tables, since they code a
++ different number of possibilities each. The literal/length table
++ codes 286 possible values, or in a flat code, a little over eight
++ bits. The distance table codes 30 possible values, or a little less
++ than five bits, flat. The optimum values for speed end up being
++ about one bit more than those, so lbits is 8+1 and dbits is 5+1.
++ The optimum values may differ though from machine to machine, and
++ possibly even between compilers. Your mileage may vary.
++ */
++
++
++/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
++#define BMAX 15 /* maximum bit length of any code */
++#define N_MAX 288 /* maximum number of codes in any set */
++
++#ifdef DEBUG_ZLIB
++ uInt inflate_hufts;
++#endif
++
++local int huft_build(b, n, s, d, e, t, m, zs)
++uIntf *b; /* code lengths in bits (all assumed &lt;= BMAX) */
++uInt n; /* number of codes (assumed &lt;= N_MAX) */
++uInt s; /* number of simple-valued codes (0..s-1) */
++const uIntf *d; /* list of base values for non-simple codes */
++const uIntf *e; /* list of extra bits for non-simple codes */
++inflate_huft * FAR *t; /* result: starting table */
++uIntf *m; /* maximum lookup bits, returns actual */
++z_streamp zs; /* for zalloc function */
++/* Given a list of code lengths and a maximum table size, make a set of
++ tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR
++ if the given code set is incomplete (the tables are still built in this
++ case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
++ lengths), or Z_MEM_ERROR if not enough memory. */
++{
++
++ uInt a; /* counter for codes of length k */
++ uInt c[BMAX+1]; /* bit length count table */
++ uInt f; /* i repeats in table every f entries */
++ int g; /* maximum code length */
++ int h; /* table level */
++ register uInt i; /* counter, current code */
++ register uInt j; /* counter */
++ register int k; /* number of bits in current code */
++ int l; /* bits per table (returned in m) */
++ register uIntf *p; /* pointer into c[], b[], or v[] */
++ inflate_huft *q; /* points to current table */
++ struct inflate_huft_s r; /* table entry for structure assignment */
++ inflate_huft *u[BMAX]; /* table stack */
++ uInt v[N_MAX]; /* values in order of bit length */
++ register int w; /* bits before this table == (l * h) */
++ uInt x[BMAX+1]; /* bit offsets, then code stack */
++ uIntf *xp; /* pointer into x */
++ int y; /* number of dummy codes added */
++ uInt z; /* number of entries in current table */
++
++
++ /* Generate counts for each bit length */
++ p = c;
++#define C0 *p++ = 0;
++#define C2 C0 C0 C0 C0
++#define C4 C2 C2 C2 C2
++ C4 /* clear c[]--assume BMAX+1 is 16 */
++ p = b; i = n;
++ do {
++ c[*p++]++; /* assume all entries &lt;= BMAX */
++ } while (--i);
++ if (c[0] == n) /* null input--all zero length codes */
++ {
++ *t = (inflate_huft *)Z_NULL;
++ *m = 0;
++ return Z_OK;
++ }
++
++
++ /* Find minimum and maximum length, bound *m by those */
++ l = *m;
++ for (j = 1; j &lt;= BMAX; j++)
++ if (c[j])
++ break;
++ k = j; /* minimum code length */
++ if ((uInt)l &lt; j)
++ l = j;
++ for (i = BMAX; i; i--)
++ if (c[i])
++ break;
++ g = i; /* maximum code length */
++ if ((uInt)l &gt; i)
++ l = i;
++ *m = l;
++
++
++ /* Adjust last length count to fill out codes, if needed */
++ for (y = 1 &lt;&lt; j; j &lt; i; j++, y &lt;&lt;= 1)
++ if ((y -= c[j]) &lt; 0)
++ return Z_DATA_ERROR;
++ if ((y -= c[i]) &lt; 0)
++ return Z_DATA_ERROR;
++ c[i] += y;
++
++
++ /* Generate starting offsets into the value table for each length */
++ x[1] = j = 0;
++ p = c + 1; xp = x + 2;
++ while (--i) { /* note that i == g from above */
++ *xp++ = (j += *p++);
++ }
++
++
++ /* Make a table of values in order of bit lengths */
++ p = b; i = 0;
++ do {
++ if ((j = *p++) != 0)
++ v[x[j]++] = i;
++ } while (++i &lt; n);
++ n = x[g]; /* set n to length of v */
++
++
++ /* Generate the Huffman codes and for each, make the table entries */
++ x[0] = i = 0; /* first Huffman code is zero */
++ p = v; /* grab values in bit order */
++ h = -1; /* no tables yet--level -1 */
++ w = -l; /* bits decoded == (l * h) */
++ u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */
++ q = (inflate_huft *)Z_NULL; /* ditto */
++ z = 0; /* ditto */
++
++ /* go through the bit lengths (k already is bits in shortest code) */
++ for (; k &lt;= g; k++)
++ {
++ a = c[k];
++ while (a--)
++ {
++ /* here i is the Huffman code of length k bits for value *p */
++ /* make tables up to required level */
++ while (k &gt; w + l)
++ {
++ h++;
++ w += l; /* previous table always l bits */
++
++ /* compute minimum size table less than or equal to l bits */
++ z = g - w;
++ z = z &gt; (uInt)l ? l : z; /* table size upper limit */
++ if ((f = 1 &lt;&lt; (j = k - w)) &gt; a + 1) /* try a k-w bit table */
++ { /* too few codes for k-w bit table */
++ f -= a + 1; /* deduct codes from patterns left */
++ xp = c + k;
++ if (j &lt; z)
++ while (++j &lt; z) /* try smaller tables up to z bits */
++ {
++ if ((f &lt;&lt;= 1) &lt;= *++xp)
++ break; /* enough codes to use up j bits */
++ f -= *xp; /* else deduct codes from patterns */
++ }
++ }
++ z = 1 &lt;&lt; j; /* table entries for j-bit table */
++
++ /* allocate and link in new table */
++ if ((q = (inflate_huft *)ZALLOC
++ (zs,z + 1,sizeof(inflate_huft))) == Z_NULL)
++ {
++ if (h)
++ inflate_trees_free(u[0], zs);
++ return Z_MEM_ERROR; /* not enough memory */
++ }
++#ifdef DEBUG_ZLIB
++ inflate_hufts += z + 1;
++#endif
++ *t = q + 1; /* link to list for huft_free() */
++ *(t = &amp;(q-&gt;next)) = Z_NULL;
++ u[h] = ++q; /* table starts after link */
++
++ /* connect to last table, if there is one */
++ if (h)
++ {
++ x[h] = i; /* save pattern for backing up */
++ r.bits = (Byte)l; /* bits to dump before this table */
++ r.exop = (Byte)j; /* bits in this table */
++ r.next = q; /* pointer to this table */
++ j = i &gt;&gt; (w - l); /* (get around Turbo C bug) */
++ u[h-1][j] = r; /* connect to last table */
++ }
++ }
++
++ /* set up table entry in r */
++ r.bits = (Byte)(k - w);
++ if (p &gt;= v + n)
++ r.exop = 128 + 64; /* out of values--invalid code */
++ else if (*p &lt; s)
++ {
++ r.exop = (Byte)(*p &lt; 256 ? 0 : 32 + 64); /* 256 is end-of-block */
++ r.base = *p++; /* simple code is just the value */
++ }
++ else
++ {
++ r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */
++ r.base = d[*p++ - s];
++ }
++
++ /* fill code-like entries with r */
++ f = 1 &lt;&lt; (k - w);
++ for (j = i &gt;&gt; w; j &lt; z; j += f)
++ q[j] = r;
++
++ /* backwards increment the k-bit code i */
++ for (j = 1 &lt;&lt; (k - 1); i &amp; j; j &gt;&gt;= 1)
++ i ^= j;
++ i ^= j;
++
++ /* backup over finished tables */
++ while ((i &amp; ((1 &lt;&lt; w) - 1)) != x[h])
++ {
++ h--; /* don't need to update q */
++ w -= l;
++ }
++ }
++ }
++
++
++ /* Return Z_BUF_ERROR if we were given an incomplete table */
++ return y != 0 &amp;&amp; g != 1 ? Z_BUF_ERROR : Z_OK;
++}
++
++
++int inflate_trees_bits(c, bb, tb, z)
++uIntf *c; /* 19 code lengths */
++uIntf *bb; /* bits tree desired/actual depth */
++inflate_huft * FAR *tb; /* bits tree result */
++z_streamp z; /* for zfree function */
++{
++ int r;
++
++ r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z);
++ if (r == Z_DATA_ERROR)
++ z-&gt;msg = (char*)&quot;oversubscribed dynamic bit lengths tree&quot;;
++ else if (r == Z_BUF_ERROR || *bb == 0)
++ {
++ inflate_trees_free(*tb, z);
++ z-&gt;msg = (char*)&quot;incomplete dynamic bit lengths tree&quot;;
++ r = Z_DATA_ERROR;
++ }
++ return r;
++}
++
++
++int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z)
++uInt nl; /* number of literal/length codes */
++uInt nd; /* number of distance codes */
++uIntf *c; /* that many (total) code lengths */
++uIntf *bl; /* literal desired/actual bit depth */
++uIntf *bd; /* distance desired/actual bit depth */
++inflate_huft * FAR *tl; /* literal/length tree result */
++inflate_huft * FAR *td; /* distance tree result */
++z_streamp z; /* for zfree function */
++{
++ int r;
++
++ /* build literal/length tree */
++ r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z);
++ if (r != Z_OK || *bl == 0)
++ {
++ if (r == Z_DATA_ERROR)
++ z-&gt;msg = (char*)&quot;oversubscribed literal/length tree&quot;;
++ else if (r != Z_MEM_ERROR)
++ {
++ inflate_trees_free(*tl, z);
++ z-&gt;msg = (char*)&quot;incomplete literal/length tree&quot;;
++ r = Z_DATA_ERROR;
++ }
++ return r;
++ }
++
++ /* build distance tree */
++ r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z);
++ if (r != Z_OK || (*bd == 0 &amp;&amp; nl &gt; 257))
++ {
++ if (r == Z_DATA_ERROR)
++ z-&gt;msg = (char*)&quot;oversubscribed distance tree&quot;;
++ else if (r == Z_BUF_ERROR) {
++#ifdef PKZIP_BUG_WORKAROUND
++ r = Z_OK;
++ }
++#else
++ inflate_trees_free(*td, z);
++ z-&gt;msg = (char*)&quot;incomplete distance tree&quot;;
++ r = Z_DATA_ERROR;
++ }
++ else if (r != Z_MEM_ERROR)
++ {
++ z-&gt;msg = (char*)&quot;empty distance tree with lengths&quot;;
++ r = Z_DATA_ERROR;
++ }
++ inflate_trees_free(*tl, z);
++ return r;
++#endif
++ }
++
++ /* done */
++ return Z_OK;
++}
++
++
++/* build fixed tables only once--keep them here */
++local int fixed_built = 0;
++#define FIXEDH 530 /* number of hufts used by fixed tables */
++local inflate_huft fixed_mem[FIXEDH];
++local uInt fixed_bl;
++local uInt fixed_bd;
++local inflate_huft *fixed_tl;
++local inflate_huft *fixed_td;
++
++
++local voidpf falloc(q, n, s)
++voidpf q; /* opaque pointer */
++uInt n; /* number of items */
++uInt s; /* size of item */
++{
++ Assert(s == sizeof(inflate_huft) &amp;&amp; n &lt;= *(intf *)q,
++ &quot;inflate_trees falloc overflow&quot;);
++ *(intf *)q -= n+s-s; /* s-s to avoid warning */
++ return (voidpf)(fixed_mem + *(intf *)q);
++}
++
++
++int inflate_trees_fixed(bl, bd, tl, td)
++uIntf *bl; /* literal desired/actual bit depth */
++uIntf *bd; /* distance desired/actual bit depth */
++inflate_huft * FAR *tl; /* literal/length tree result */
++inflate_huft * FAR *td; /* distance tree result */
++{
++ /* build fixed tables if not already (multiple overlapped executions ok) */
++ if (!fixed_built)
++ {
++ int k; /* temporary variable */
++ unsigned c[288]; /* length list for huft_build */
++ z_stream z; /* for falloc function */
++ int f = FIXEDH; /* number of hufts left in fixed_mem */
++
++ /* set up fake z_stream for memory routines */
++ z.zalloc = falloc;
++ z.zfree = Z_NULL;
++ z.opaque = (voidpf)&amp;f;
++
++ /* literal table */
++ for (k = 0; k &lt; 144; k++)
++ c[k] = 8;
++ for (; k &lt; 256; k++)
++ c[k] = 9;
++ for (; k &lt; 280; k++)
++ c[k] = 7;
++ for (; k &lt; 288; k++)
++ c[k] = 8;
++ fixed_bl = 7;
++ huft_build(c, 288, 257, cplens, cplext, &amp;fixed_tl, &amp;fixed_bl, &amp;z);
++
++ /* distance table */
++ for (k = 0; k &lt; 30; k++)
++ c[k] = 5;
++ fixed_bd = 5;
++ huft_build(c, 30, 0, cpdist, cpdext, &amp;fixed_td, &amp;fixed_bd, &amp;z);
++
++ /* done */
++ Assert(f == 0, &quot;invalid build of fixed tables&quot;);
++ fixed_built = 1;
++ }
++ *bl = fixed_bl;
++ *bd = fixed_bd;
++ *tl = fixed_tl;
++ *td = fixed_td;
++ return Z_OK;
++}
++
++
++int inflate_trees_free(t, z)
++inflate_huft *t; /* table to free */
++z_streamp z; /* for zfree function */
++/* Free the malloc'ed tables built by huft_build(), which makes a linked
++ list of the tables it made, with the links in a dummy first entry of
++ each table. */
++{
++ register inflate_huft *p, *q, *r;
++
++ /* Reverse linked list */
++ p = Z_NULL;
++ q = t;
++ while (q != Z_NULL)
++ {
++ r = (q - 1)-&gt;next;
++ (q - 1)-&gt;next = p;
++ p = q;
++ q = r;
++ }
++ /* Go through linked list, freeing from the malloced (t[-1]) address. */
++ while (p != Z_NULL)
++ {
++ q = (--p)-&gt;next;
++ ZFREE(z,p);
++ p = q;
++ }
++ return Z_OK;
++}
++/* --- inftrees.c */
++
++/* +++ infcodes.c */
++/* infcodes.c -- process literals and length/distance pairs
++ * Copyright (C) 1995-1996 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* #include &quot;zutil.h&quot; */
++/* #include &quot;inftrees.h&quot; */
++/* #include &quot;infblock.h&quot; */
++/* #include &quot;infcodes.h&quot; */
++/* #include &quot;infutil.h&quot; */
++
++/* +++ inffast.h */
++/* inffast.h -- header to use inffast.c
++ * Copyright (C) 1995-1996 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* WARNING: this file should *not* be used by applications. It is
++ part of the implementation of the compression library and is
++ subject to change. Applications should only use zlib.h.
++ */
++
++extern int inflate_fast OF((
++ uInt,
++ uInt,
++ inflate_huft *,
++ inflate_huft *,
++ inflate_blocks_statef *,
++ z_streamp ));
++/* --- inffast.h */
++
++/* simplify the use of the inflate_huft type with some defines */
++#define base more.Base
++#define next more.Next
++#define exop word.what.Exop
++#define bits word.what.Bits
++
++/* inflate codes private state */
++struct inflate_codes_state {
++
++ /* mode */
++ enum { /* waiting for &quot;i:&quot;=input, &quot;o:&quot;=output, &quot;x:&quot;=nothing */
++ START, /* x: set up for LEN */
++ LEN, /* i: get length/literal/eob next */
++ LENEXT, /* i: getting length extra (have base) */
++ DIST, /* i: get distance next */
++ DISTEXT, /* i: getting distance extra */
++ COPY, /* o: copying bytes in window, waiting for space */
++ LIT, /* o: got literal, waiting for output space */
++ WASH, /* o: got eob, possibly still output waiting */
++ END, /* x: got eob and all data flushed */
++ BADCODE} /* x: got error */
++ mode; /* current inflate_codes mode */
++
++ /* mode dependent information */
++ uInt len;
++ union {
++ struct {
++ inflate_huft *tree; /* pointer into tree */
++ uInt need; /* bits needed */
++ } code; /* if LEN or DIST, where in tree */
++ uInt lit; /* if LIT, literal */
++ struct {
++ uInt get; /* bits to get for extra */
++ uInt dist; /* distance back to copy from */
++ } copy; /* if EXT or COPY, where and how much */
++ } sub; /* submode */
++
++ /* mode independent information */
++ Byte lbits; /* ltree bits decoded per branch */
++ Byte dbits; /* dtree bits decoder per branch */
++ inflate_huft *ltree; /* literal/length/eob tree */
++ inflate_huft *dtree; /* distance tree */
++
++};
++
++
++inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
++uInt bl, bd;
++inflate_huft *tl;
++inflate_huft *td; /* need separate declaration for Borland C++ */
++z_streamp z;
++{
++ inflate_codes_statef *c;
++
++ if ((c = (inflate_codes_statef *)
++ ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
++ {
++ c-&gt;mode = START;
++ c-&gt;lbits = (Byte)bl;
++ c-&gt;dbits = (Byte)bd;
++ c-&gt;ltree = tl;
++ c-&gt;dtree = td;
++ Tracev((stderr, &quot;inflate: codes new\n&quot;));
++ }
++ return c;
++}
++
++
++int inflate_codes(s, z, r)
++inflate_blocks_statef *s;
++z_streamp z;
++int r;
++{
++ uInt j; /* temporary storage */
++ inflate_huft *t; /* temporary pointer */
++ uInt e; /* extra bits or operation */
++ uLong b; /* bit buffer */
++ uInt k; /* bits in bit buffer */
++ Bytef *p; /* input data pointer */
++ uInt n; /* bytes available there */
++ Bytef *q; /* output window write pointer */
++ uInt m; /* bytes to end of window or read pointer */
++ Bytef *f; /* pointer to copy strings from */
++ inflate_codes_statef *c = s-&gt;sub.decode.codes; /* codes state */
++
++ /* copy input/output information to locals (UPDATE macro restores) */
++ LOAD
++
++ /* process input and output based on current state */
++ while (1) switch (c-&gt;mode)
++ { /* waiting for &quot;i:&quot;=input, &quot;o:&quot;=output, &quot;x:&quot;=nothing */
++ case START: /* x: set up for LEN */
++#ifndef SLOW
++ if (m &gt;= 258 &amp;&amp; n &gt;= 10)
++ {
++ UPDATE
++ r = inflate_fast(c-&gt;lbits, c-&gt;dbits, c-&gt;ltree, c-&gt;dtree, s, z);
++ LOAD
++ if (r != Z_OK)
++ {
++ c-&gt;mode = r == Z_STREAM_END ? WASH : BADCODE;
++ break;
++ }
++ }
++#endif /* !SLOW */
++ c-&gt;sub.code.need = c-&gt;lbits;
++ c-&gt;sub.code.tree = c-&gt;ltree;
++ c-&gt;mode = LEN;
++ case LEN: /* i: get length/literal/eob next */
++ j = c-&gt;sub.code.need;
++ NEEDBITS(j)
++ t = c-&gt;sub.code.tree + ((uInt)b &amp; inflate_mask[j]);
++ DUMPBITS(t-&gt;bits)
++ e = (uInt)(t-&gt;exop);
++ if (e == 0) /* literal */
++ {
++ c-&gt;sub.lit = t-&gt;base;
++ Tracevv((stderr, t-&gt;base &gt;= 0x20 &amp;&amp; t-&gt;base &lt; 0x7f ?
++ &quot;inflate: literal '%c'\n&quot; :
++ &quot;inflate: literal 0x%02x\n&quot;, t-&gt;base));
++ c-&gt;mode = LIT;
++ break;
++ }
++ if (e &amp; 16) /* length */
++ {
++ c-&gt;sub.copy.get = e &amp; 15;
++ c-&gt;len = t-&gt;base;
++ c-&gt;mode = LENEXT;
++ break;
++ }
++ if ((e &amp; 64) == 0) /* next table */
++ {
++ c-&gt;sub.code.need = e;
++ c-&gt;sub.code.tree = t-&gt;next;
++ break;
++ }
++ if (e &amp; 32) /* end of block */
++ {
++ Tracevv((stderr, &quot;inflate: end of block\n&quot;));
++ c-&gt;mode = WASH;
++ break;
++ }
++ c-&gt;mode = BADCODE; /* invalid code */
++ z-&gt;msg = (char*)&quot;invalid literal/length code&quot;;
++ r = Z_DATA_ERROR;
++ LEAVE
++ case LENEXT: /* i: getting length extra (have base) */
++ j = c-&gt;sub.copy.get;
++ NEEDBITS(j)
++ c-&gt;len += (uInt)b &amp; inflate_mask[j];
++ DUMPBITS(j)
++ c-&gt;sub.code.need = c-&gt;dbits;
++ c-&gt;sub.code.tree = c-&gt;dtree;
++ Tracevv((stderr, &quot;inflate: length %u\n&quot;, c-&gt;len));
++ c-&gt;mode = DIST;
++ case DIST: /* i: get distance next */
++ j = c-&gt;sub.code.need;
++ NEEDBITS(j)
++ t = c-&gt;sub.code.tree + ((uInt)b &amp; inflate_mask[j]);
++ DUMPBITS(t-&gt;bits)
++ e = (uInt)(t-&gt;exop);
++ if (e &amp; 16) /* distance */
++ {
++ c-&gt;sub.copy.get = e &amp; 15;
++ c-&gt;sub.copy.dist = t-&gt;base;
++ c-&gt;mode = DISTEXT;
++ break;
++ }
++ if ((e &amp; 64) == 0) /* next table */
++ {
++ c-&gt;sub.code.need = e;
++ c-&gt;sub.code.tree = t-&gt;next;
++ break;
++ }
++ c-&gt;mode = BADCODE; /* invalid code */
++ z-&gt;msg = (char*)&quot;invalid distance code&quot;;
++ r = Z_DATA_ERROR;
++ LEAVE
++ case DISTEXT: /* i: getting distance extra */
++ j = c-&gt;sub.copy.get;
++ NEEDBITS(j)
++ c-&gt;sub.copy.dist += (uInt)b &amp; inflate_mask[j];
++ DUMPBITS(j)
++ Tracevv((stderr, &quot;inflate: distance %u\n&quot;, c-&gt;sub.copy.dist));
++ c-&gt;mode = COPY;
++ case COPY: /* o: copying bytes in window, waiting for space */
++#ifndef __TURBOC__ /* Turbo C bug for following expression */
++ f = (uInt)(q - s-&gt;window) &lt; c-&gt;sub.copy.dist ?
++ s-&gt;end - (c-&gt;sub.copy.dist - (q - s-&gt;window)) :
++ q - c-&gt;sub.copy.dist;
++#else
++ f = q - c-&gt;sub.copy.dist;
++ if ((uInt)(q - s-&gt;window) &lt; c-&gt;sub.copy.dist)
++ f = s-&gt;end - (c-&gt;sub.copy.dist - (uInt)(q - s-&gt;window));
++#endif
++ while (c-&gt;len)
++ {
++ NEEDOUT
++ OUTBYTE(*f++)
++ if (f == s-&gt;end)
++ f = s-&gt;window;
++ c-&gt;len--;
++ }
++ c-&gt;mode = START;
++ break;
++ case LIT: /* o: got literal, waiting for output space */
++ NEEDOUT
++ OUTBYTE(c-&gt;sub.lit)
++ c-&gt;mode = START;
++ break;
++ case WASH: /* o: got eob, possibly more output */
++ FLUSH
++ if (s-&gt;read != s-&gt;write)
++ LEAVE
++ c-&gt;mode = END;
++ case END:
++ r = Z_STREAM_END;
++ LEAVE
++ case BADCODE: /* x: got error */
++ r = Z_DATA_ERROR;
++ LEAVE
++ default:
++ r = Z_STREAM_ERROR;
++ LEAVE
++ }
++}
++
++
++void inflate_codes_free(c, z)
++inflate_codes_statef *c;
++z_streamp z;
++{
++ ZFREE(z, c);
++ Tracev((stderr, &quot;inflate: codes free\n&quot;));
++}
++/* --- infcodes.c */
++
++/* +++ infutil.c */
++/* inflate_util.c -- data and routines common to blocks and codes
++ * Copyright (C) 1995-1996 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* #include &quot;zutil.h&quot; */
++/* #include &quot;infblock.h&quot; */
++/* #include &quot;inftrees.h&quot; */
++/* #include &quot;infcodes.h&quot; */
++/* #include &quot;infutil.h&quot; */
++
++#ifndef NO_DUMMY_DECL
++struct inflate_codes_state {int dummy;}; /* for buggy compilers */
++#endif
++
++/* And'ing with mask[n] masks the lower n bits */
++uInt inflate_mask[17] = {
++ 0x0000,
++ 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
++ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
++};
++
++
++/* copy as much as possible from the sliding window to the output area */
++int inflate_flush(s, z, r)
++inflate_blocks_statef *s;
++z_streamp z;
++int r;
++{
++ uInt n;
++ Bytef *p;
++ Bytef *q;
++
++ /* local copies of source and destination pointers */
++ p = z-&gt;next_out;
++ q = s-&gt;read;
++
++ /* compute number of bytes to copy as far as end of window */
++ n = (uInt)((q &lt;= s-&gt;write ? s-&gt;write : s-&gt;end) - q);
++ if (n &gt; z-&gt;avail_out) n = z-&gt;avail_out;
++ if (n &amp;&amp; r == Z_BUF_ERROR) r = Z_OK;
++
++ /* update counters */
++ z-&gt;avail_out -= n;
++ z-&gt;total_out += n;
++
++ /* update check information */
++ if (s-&gt;checkfn != Z_NULL)
++ z-&gt;adler = s-&gt;check = (*s-&gt;checkfn)(s-&gt;check, q, n);
++
++ /* copy as far as end of window */
++ if (p != Z_NULL) {
++ zmemcpy(p, q, n);
++ p += n;
++ }
++ q += n;
++
++ /* see if more to copy at beginning of window */
++ if (q == s-&gt;end)
++ {
++ /* wrap pointers */
++ q = s-&gt;window;
++ if (s-&gt;write == s-&gt;end)
++ s-&gt;write = s-&gt;window;
++
++ /* compute bytes to copy */
++ n = (uInt)(s-&gt;write - q);
++ if (n &gt; z-&gt;avail_out) n = z-&gt;avail_out;
++ if (n &amp;&amp; r == Z_BUF_ERROR) r = Z_OK;
++
++ /* update counters */
++ z-&gt;avail_out -= n;
++ z-&gt;total_out += n;
++
++ /* update check information */
++ if (s-&gt;checkfn != Z_NULL)
++ z-&gt;adler = s-&gt;check = (*s-&gt;checkfn)(s-&gt;check, q, n);
++
++ /* copy */
++ if (p != Z_NULL) {
++ zmemcpy(p, q, n);
++ p += n;
++ }
++ q += n;
++ }
++
++ /* update pointers */
++ z-&gt;next_out = p;
++ s-&gt;read = q;
++
++ /* done */
++ return r;
++}
++/* --- infutil.c */
++
++/* +++ inffast.c */
++/* inffast.c -- process literals and length/distance pairs fast
++ * Copyright (C) 1995-1996 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* #include &quot;zutil.h&quot; */
++/* #include &quot;inftrees.h&quot; */
++/* #include &quot;infblock.h&quot; */
++/* #include &quot;infcodes.h&quot; */
++/* #include &quot;infutil.h&quot; */
++/* #include &quot;inffast.h&quot; */
++
++#ifndef NO_DUMMY_DECL
++struct inflate_codes_state {int dummy;}; /* for buggy compilers */
++#endif
++
++/* simplify the use of the inflate_huft type with some defines */
++#define base more.Base
++#define next more.Next
++#define exop word.what.Exop
++#define bits word.what.Bits
++
++/* macros for bit input with no checking and for returning unused bytes */
++#define GRABBITS(j) {while(k&lt;(j)){b|=((uLong)NEXTBYTE)&lt;&lt;k;k+=8;}}
++#define UNGRAB {n+=(c=k&gt;&gt;3);p-=c;k&amp;=7;}
++
++/* Called with number of bytes left to write in window at least 258
++ (the maximum string length) and number of input bytes available
++ at least ten. The ten bytes are six bytes for the longest length/
++ distance pair plus four bytes for overloading the bit buffer. */
++
++int inflate_fast(bl, bd, tl, td, s, z)
++uInt bl, bd;
++inflate_huft *tl;
++inflate_huft *td; /* need separate declaration for Borland C++ */
++inflate_blocks_statef *s;
++z_streamp z;
++{
++ inflate_huft *t; /* temporary pointer */
++ uInt e; /* extra bits or operation */
++ uLong b; /* bit buffer */
++ uInt k; /* bits in bit buffer */
++ Bytef *p; /* input data pointer */
++ uInt n; /* bytes available there */
++ Bytef *q; /* output window write pointer */
++ uInt m; /* bytes to end of window or read pointer */
++ uInt ml; /* mask for literal/length tree */
++ uInt md; /* mask for distance tree */
++ uInt c; /* bytes to copy */
++ uInt d; /* distance back to copy from */
++ Bytef *r; /* copy source pointer */
++
++ /* load input, output, bit values */
++ LOAD
++
++ /* initialize masks */
++ ml = inflate_mask[bl];
++ md = inflate_mask[bd];
++
++ /* do until not enough input or output space for fast loop */
++ do { /* assume called with m &gt;= 258 &amp;&amp; n &gt;= 10 */
++ /* get literal/length code */
++ GRABBITS(20) /* max bits for literal/length code */
++ if ((e = (t = tl + ((uInt)b &amp; ml))-&gt;exop) == 0)
++ {
++ DUMPBITS(t-&gt;bits)
++ Tracevv((stderr, t-&gt;base &gt;= 0x20 &amp;&amp; t-&gt;base &lt; 0x7f ?
++ &quot;inflate: * literal '%c'\n&quot; :
++ &quot;inflate: * literal 0x%02x\n&quot;, t-&gt;base));
++ *q++ = (Byte)t-&gt;base;
++ m--;
++ continue;
++ }
++ do {
++ DUMPBITS(t-&gt;bits)
++ if (e &amp; 16)
++ {
++ /* get extra bits for length */
++ e &amp;= 15;
++ c = t-&gt;base + ((uInt)b &amp; inflate_mask[e]);
++ DUMPBITS(e)
++ Tracevv((stderr, &quot;inflate: * length %u\n&quot;, c));
++
++ /* decode distance base of block to copy */
++ GRABBITS(15); /* max bits for distance code */
++ e = (t = td + ((uInt)b &amp; md))-&gt;exop;
++ do {
++ DUMPBITS(t-&gt;bits)
++ if (e &amp; 16)
++ {
++ /* get extra bits to add to distance base */
++ e &amp;= 15;
++ GRABBITS(e) /* get extra bits (up to 13) */
++ d = t-&gt;base + ((uInt)b &amp; inflate_mask[e]);
++ DUMPBITS(e)
++ Tracevv((stderr, &quot;inflate: * distance %u\n&quot;, d));
++
++ /* do the copy */
++ m -= c;
++ if ((uInt)(q - s-&gt;window) &gt;= d) /* offset before dest */
++ { /* just copy */
++ r = q - d;
++ *q++ = *r++; c--; /* minimum count is three, */
++ *q++ = *r++; c--; /* so unroll loop a little */
++ }
++ else /* else offset after destination */
++ {
++ e = d - (uInt)(q - s-&gt;window); /* bytes from offset to end */
++ r = s-&gt;end - e; /* pointer to offset */
++ if (c &gt; e) /* if source crosses, */
++ {
++ c -= e; /* copy to end of window */
++ do {
++ *q++ = *r++;
++ } while (--e);
++ r = s-&gt;window; /* copy rest from start of window */
++ }
++ }
++ do { /* copy all or what's left */
++ *q++ = *r++;
++ } while (--c);
++ break;
++ }
++ else if ((e &amp; 64) == 0)
++ e = (t = t-&gt;next + ((uInt)b &amp; inflate_mask[e]))-&gt;exop;
++ else
++ {
++ z-&gt;msg = (char*)&quot;invalid distance code&quot;;
++ UNGRAB
++ UPDATE
++ return Z_DATA_ERROR;
++ }
++ } while (1);
++ break;
++ }
++ if ((e &amp; 64) == 0)
++ {
++ if ((e = (t = t-&gt;next + ((uInt)b &amp; inflate_mask[e]))-&gt;exop) == 0)
++ {
++ DUMPBITS(t-&gt;bits)
++ Tracevv((stderr, t-&gt;base &gt;= 0x20 &amp;&amp; t-&gt;base &lt; 0x7f ?
++ &quot;inflate: * literal '%c'\n&quot; :
++ &quot;inflate: * literal 0x%02x\n&quot;, t-&gt;base));
++ *q++ = (Byte)t-&gt;base;
++ m--;
++ break;
++ }
++ }
++ else if (e &amp; 32)
++ {
++ Tracevv((stderr, &quot;inflate: * end of block\n&quot;));
++ UNGRAB
++ UPDATE
++ return Z_STREAM_END;
++ }
++ else
++ {
++ z-&gt;msg = (char*)&quot;invalid literal/length code&quot;;
++ UNGRAB
++ UPDATE
++ return Z_DATA_ERROR;
++ }
++ } while (1);
++ } while (m &gt;= 258 &amp;&amp; n &gt;= 10);
++
++ /* not enough input or output--restore pointers and return */
++ UNGRAB
++ UPDATE
++ return Z_OK;
++}
++/* --- inffast.c */
++
++/* +++ zutil.c */
++/* zutil.c -- target dependent utility functions for the compression library
++ * Copyright (C) 1995-1996 Jean-loup Gailly.
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* From: zutil.c,v 1.17 1996/07/24 13:41:12 me Exp $ */
++
++#ifdef DEBUG_ZLIB
++#include &lt;stdio.h&gt;
++#endif
++
++/* #include &quot;zutil.h&quot; */
++
++#ifndef NO_DUMMY_DECL
++struct internal_state {int dummy;}; /* for buggy compilers */
++#endif
++
++#ifndef STDC
++extern void exit OF((int));
++#endif
++
++const char *z_errmsg[10] = {
++&quot;need dictionary&quot;, /* Z_NEED_DICT 2 */
++&quot;stream end&quot;, /* Z_STREAM_END 1 */
++&quot;&quot;, /* Z_OK 0 */
++&quot;file error&quot;, /* Z_ERRNO (-1) */
++&quot;stream error&quot;, /* Z_STREAM_ERROR (-2) */
++&quot;data error&quot;, /* Z_DATA_ERROR (-3) */
++&quot;insufficient memory&quot;, /* Z_MEM_ERROR (-4) */
++&quot;buffer error&quot;, /* Z_BUF_ERROR (-5) */
++&quot;incompatible version&quot;,/* Z_VERSION_ERROR (-6) */
++&quot;&quot;};
++
++
++const char *zlibVersion()
++{
++ return ZLIB_VERSION;
++}
++
++#ifdef DEBUG_ZLIB
++void z_error (m)
++ char *m;
++{
++ fprintf(stderr, &quot;%s\n&quot;, m);
++ exit(1);
++}
++#endif
++
++#ifndef HAVE_MEMCPY
++
++void zmemcpy(dest, source, len)
++ Bytef* dest;
++ Bytef* source;
++ uInt len;
++{
++ if (len == 0) return;
++ do {
++ *dest++ = *source++; /* ??? to be unrolled */
++ } while (--len != 0);
++}
++
++int zmemcmp(s1, s2, len)
++ Bytef* s1;
++ Bytef* s2;
++ uInt len;
++{
++ uInt j;
++
++ for (j = 0; j &lt; len; j++) {
++ if (s1[j] != s2[j]) return 2*(s1[j] &gt; s2[j])-1;
++ }
++ return 0;
++}
++
++void zmemzero(dest, len)
++ Bytef* dest;
++ uInt len;
++{
++ if (len == 0) return;
++ do {
++ *dest++ = 0; /* ??? to be unrolled */
++ } while (--len != 0);
++}
++#endif
++
++#ifdef __TURBOC__
++#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) &amp;&amp; !defined(__32BIT__)
++/* Small and medium model in Turbo C are for now limited to near allocation
++ * with reduced MAX_WBITS and MAX_MEM_LEVEL
++ */
++# define MY_ZCALLOC
++
++/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
++ * and farmalloc(64K) returns a pointer with an offset of 8, so we
++ * must fix the pointer. Warning: the pointer must be put back to its
++ * original form in order to free it, use zcfree().
++ */
++
++#define MAX_PTR 10
++/* 10*64K = 640K */
++
++local int next_ptr = 0;
++
++typedef struct ptr_table_s {
++ voidpf org_ptr;
++ voidpf new_ptr;
++} ptr_table;
++
++local ptr_table table[MAX_PTR];
++/* This table is used to remember the original form of pointers
++ * to large buffers (64K). Such pointers are normalized with a zero offset.
++ * Since MSDOS is not a preemptive multitasking OS, this table is not
++ * protected from concurrent access. This hack doesn't work anyway on
++ * a protected system like OS/2. Use Microsoft C instead.
++ */
++
++voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
++{
++ voidpf buf = opaque; /* just to make some compilers happy */
++ ulg bsize = (ulg)items*size;
++
++ /* If we allocate less than 65520 bytes, we assume that farmalloc
++ * will return a usable pointer which doesn't have to be normalized.
++ */
++ if (bsize &lt; 65520L) {
++ buf = farmalloc(bsize);
++ if (*(ush*)&amp;buf != 0) return buf;
++ } else {
++ buf = farmalloc(bsize + 16L);
++ }
++ if (buf == NULL || next_ptr &gt;= MAX_PTR) return NULL;
++ table[next_ptr].org_ptr = buf;
++
++ /* Normalize the pointer to seg:0 */
++ *((ush*)&amp;buf+1) += ((ush)((uch*)buf-0) + 15) &gt;&gt; 4;
++ *(ush*)&amp;buf = 0;
++ table[next_ptr++].new_ptr = buf;
++ return buf;
++}
++
++void zcfree (voidpf opaque, voidpf ptr)
++{
++ int n;
++ if (*(ush*)&amp;ptr != 0) { /* object &lt; 64K */
++ farfree(ptr);
++ return;
++ }
++ /* Find the original pointer */
++ for (n = 0; n &lt; next_ptr; n++) {
++ if (ptr != table[n].new_ptr) continue;
++
++ farfree(table[n].org_ptr);
++ while (++n &lt; next_ptr) {
++ table[n-1] = table[n];
++ }
++ next_ptr--;
++ return;
++ }
++ ptr = opaque; /* just to make some compilers happy */
++ Assert(0, &quot;zcfree: ptr not found&quot;);
++}
++#endif
++#endif /* __TURBOC__ */
++
++
++#if defined(M_I86) &amp;&amp; !defined(__32BIT__)
++/* Microsoft C in 16-bit mode */
++
++# define MY_ZCALLOC
++
++#if (!defined(_MSC_VER) || (_MSC_VER &lt; 600))
++# define _halloc halloc
++# define _hfree hfree
++#endif
++
++voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
++{
++ if (opaque) opaque = 0; /* to make compiler happy */
++ return _halloc((long)items, size);
++}
++
++void zcfree (voidpf opaque, voidpf ptr)
++{
++ if (opaque) opaque = 0; /* to make compiler happy */
++ _hfree(ptr);
++}
++
++#endif /* MSC */
++
++
++#ifndef MY_ZCALLOC /* Any system without a special alloc function */
++
++#ifndef STDC
++extern voidp calloc OF((uInt items, uInt size));
++extern void free OF((voidpf ptr));
++#endif
++
++voidpf zcalloc (opaque, items, size)
++ voidpf opaque;
++ unsigned items;
++ unsigned size;
++{
++ if (opaque) items += size - size; /* make compiler happy */
++ return (voidpf)calloc(items, size);
++}
++
++void zcfree (opaque, ptr)
++ voidpf opaque;
++ voidpf ptr;
++{
++ free(ptr);
++ if (opaque) return; /* make compiler happy */
++}
++
++#endif /* MY_ZCALLOC */
++/* --- zutil.c */
++
++/* +++ adler32.c */
++/* adler32.c -- compute the Adler-32 checksum of a data stream
++ * Copyright (C) 1995-1996 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* From: adler32.c,v 1.10 1996/05/22 11:52:18 me Exp $ */
++
++/* #include &quot;zlib.h&quot; */
++
++#define BASE 65521L /* largest prime smaller than 65536 */
++#define NMAX 5552
++/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) &lt;= 2^32-1 */
++
++#define DO1(buf,i) {s1 += buf[i]; s2 += s1;}
++#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
++#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
++#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
++#define DO16(buf) DO8(buf,0); DO8(buf,8);
++
++/* ========================================================================= */
++uLong adler32(adler, buf, len)
++ uLong adler;
++ const Bytef *buf;
++ uInt len;
++{
++ unsigned long s1 = adler &amp; 0xffff;
++ unsigned long s2 = (adler &gt;&gt; 16) &amp; 0xffff;
++ int k;
++
++ if (buf == Z_NULL) return 1L;
++
++ while (len &gt; 0) {
++ k = len &lt; NMAX ? len : NMAX;
++ len -= k;
++ while (k &gt;= 16) {
++ DO16(buf);
++ buf += 16;
++ k -= 16;
++ }
++ if (k != 0) do {
++ s1 += *buf++;
++ s2 += s1;
++ } while (--k);
++ s1 %= BASE;
++ s2 %= BASE;
++ }
++ return (s2 &lt;&lt; 16) | s1;
++}
++/* --- adler32.c */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/common/zlib.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/common/zlib.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/common/zlib.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/common/zlib.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1010 @@
++/* $Id: zlib.h 195720 2001-06-11 11:44:34Z gc $ */
++
++/*
++ * This file is derived from zlib.h and zconf.h from the zlib-1.0.4
++ * distribution by Jean-loup Gailly and Mark Adler, with some additions
++ * by Paul Mackerras to aid in implementing Deflate compression and
++ * decompression for PPP packets.
++ */
++
++/*
++ * ==FILEVERSION 971127==
++ *
++ * This marker is used by the Linux installation script to determine
++ * whether an up-to-date version of this file is already installed.
++ */
++
++
++/* +++ zlib.h */
++/* zlib.h -- interface of the 'zlib' general purpose compression library
++ version 1.0.4, Jul 24th, 1996.
++
++ Copyright (C) 1995-1996 Jean-loup Gailly and Mark Adler
++
++ This software is provided 'as-is', without any express or implied
++ warranty. In no event will the authors be held liable for any damages
++ arising from the use of this software.
++
++ Permission is granted to anyone to use this software for any purpose,
++ including commercial applications, and to alter it and redistribute it
++ freely, subject to the following restrictions:
++
++ 1. The origin of this software must not be misrepresented; you must not
++ claim that you wrote the original software. If you use this software
++ in a product, an acknowledgment in the product documentation would be
++ appreciated but is not required.
++ 2. Altered source versions must be plainly marked as such, and must not be
++ misrepresented as being the original software.
++ 3. This notice may not be removed or altered from any source distribution.
++
++ Jean-loup Gailly Mark Adler
++ <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gzip at prep.ai.mit.edu</A> <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">madler at alumni.caltech.edu</A>
++
++
++ The data format used by the zlib library is described by RFCs (Request for
++ Comments) 1950 to 1952 in the files <A HREF="ftp://ds.internic.net/rfc/rfc1950.txt">ftp://ds.internic.net/rfc/rfc1950.txt</A>
++ (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
++*/
++
++#ifndef _ZLIB_H
++#define _ZLIB_H
++
++#ifdef __cplusplus
++extern &quot;C&quot; {
++#endif
++
++
++/* +++ zconf.h */
++/* zconf.h -- configuration of the zlib compression library
++ * Copyright (C) 1995-1996 Jean-loup Gailly.
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* From: zconf.h,v 1.20 1996/07/02 15:09:28 me Exp $ */
++
++#ifndef _ZCONF_H
++#define _ZCONF_H
++
++/*
++ * If you *really* need a unique prefix for all types and library functions,
++ * compile with -DZ_PREFIX. The &quot;standard&quot; zlib should be compiled without it.
++ */
++#ifdef Z_PREFIX
++# define deflateInit_ z_deflateInit_
++# define deflate z_deflate
++# define deflateEnd z_deflateEnd
++# define inflateInit_ z_inflateInit_
++# define inflate z_inflate
++# define inflateEnd z_inflateEnd
++# define deflateInit2_ z_deflateInit2_
++# define deflateSetDictionary z_deflateSetDictionary
++# define deflateCopy z_deflateCopy
++# define deflateReset z_deflateReset
++# define deflateParams z_deflateParams
++# define inflateInit2_ z_inflateInit2_
++# define inflateSetDictionary z_inflateSetDictionary
++# define inflateSync z_inflateSync
++# define inflateReset z_inflateReset
++# define compress z_compress
++# define uncompress z_uncompress
++# define adler32 z_adler32
++# define crc32 z_crc32
++# define get_crc_table z_get_crc_table
++
++# define Byte z_Byte
++# define uInt z_uInt
++# define uLong z_uLong
++# define Bytef z_Bytef
++# define charf z_charf
++# define intf z_intf
++# define uIntf z_uIntf
++# define uLongf z_uLongf
++# define voidpf z_voidpf
++# define voidp z_voidp
++#endif
++
++#if (defined(_WIN32) || defined(__WIN32__)) &amp;&amp; !defined(WIN32)
++# define WIN32
++#endif
++#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386)
++# ifndef __32BIT__
++# define __32BIT__
++# endif
++#endif
++#if defined(__MSDOS__) &amp;&amp; !defined(MSDOS)
++# define MSDOS
++#endif
++
++/*
++ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
++ * than 64k bytes at a time (needed on systems with 16-bit int).
++ */
++#if defined(MSDOS) &amp;&amp; !defined(__32BIT__)
++# define MAXSEG_64K
++#endif
++#ifdef MSDOS
++# define UNALIGNED_OK
++#endif
++
++#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32)) &amp;&amp; !defined(STDC)
++# define STDC
++#endif
++#if (defined(__STDC__) || defined(__cplusplus)) &amp;&amp; !defined(STDC)
++# define STDC
++#endif
++
++#ifndef STDC
++# ifndef const /* cannot use !defined(STDC) &amp;&amp; !defined(const) on Mac */
++# define const
++# endif
++#endif
++
++/* Some Mac compilers merge all .h files incorrectly: */
++#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__)
++# define NO_DUMMY_DECL
++#endif
++
++/* Maximum value for memLevel in deflateInit2 */
++#ifndef MAX_MEM_LEVEL
++# ifdef MAXSEG_64K
++# define MAX_MEM_LEVEL 8
++# else
++# define MAX_MEM_LEVEL 9
++# endif
++#endif
++
++/* Maximum value for windowBits in deflateInit2 and inflateInit2 */
++#ifndef MAX_WBITS
++# define MAX_WBITS 15 /* 32K LZ77 window */
++#endif
++
++/* The memory requirements for deflate are (in bytes):
++ 1 &lt;&lt; (windowBits+2) + 1 &lt;&lt; (memLevel+9)
++ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
++ plus a few kilobytes for small objects. For example, if you want to reduce
++ the default memory requirements from 256K to 128K, compile with
++ make CFLAGS=&quot;-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7&quot;
++ Of course this will generally degrade compression (there's no free lunch).
++
++ The memory requirements for inflate are (in bytes) 1 &lt;&lt; windowBits
++ that is, 32K for windowBits=15 (default value) plus a few kilobytes
++ for small objects.
++*/
++
++ /* Type declarations */
++
++#ifndef OF /* function prototypes */
++# ifdef STDC
++# define OF(args) args
++# else
++# define OF(args) ()
++# endif
++#endif
++
++/* The following definitions for FAR are needed only for MSDOS mixed
++ * model programming (small or medium model with some far allocations).
++ * This was tested only with MSC; for other MSDOS compilers you may have
++ * to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
++ * just define FAR to be empty.
++ */
++#if (defined(M_I86SM) || defined(M_I86MM)) &amp;&amp; !defined(__32BIT__)
++ /* MSC small or medium model */
++# define SMALL_MEDIUM
++# ifdef _MSC_VER
++# define FAR __far
++# else
++# define FAR far
++# endif
++#endif
++#if defined(__BORLANDC__) &amp;&amp; (defined(__SMALL__) || defined(__MEDIUM__))
++# ifndef __32BIT__
++# define SMALL_MEDIUM
++# define FAR __far
++# endif
++#endif
++#ifndef FAR
++# define FAR
++#endif
++
++typedef unsigned char Byte; /* 8 bits */
++typedef unsigned int uInt; /* 16 bits or more */
++typedef unsigned long uLong; /* 32 bits or more */
++
++#if defined(__BORLANDC__) &amp;&amp; defined(SMALL_MEDIUM)
++ /* Borland C/C++ ignores FAR inside typedef */
++# define Bytef Byte FAR
++#else
++ typedef Byte FAR Bytef;
++#endif
++typedef char FAR charf;
++typedef int FAR intf;
++typedef uInt FAR uIntf;
++typedef uLong FAR uLongf;
++
++#ifdef STDC
++ typedef void FAR *voidpf;
++ typedef void *voidp;
++#else
++ typedef Byte FAR *voidpf;
++ typedef Byte *voidp;
++#endif
++
++
++/* Compile with -DZLIB_DLL for Windows DLL support */
++#if (defined(_WINDOWS) || defined(WINDOWS)) &amp;&amp; defined(ZLIB_DLL)
++# include &lt;windows.h&gt;
++# define EXPORT WINAPI
++#else
++# define EXPORT
++#endif
++
++#endif /* _ZCONF_H */
++/* --- zconf.h */
++
++#define ZLIB_VERSION &quot;1.0.4P&quot;
++
++/*
++ The 'zlib' compression library provides in-memory compression and
++ decompression functions, including integrity checks of the uncompressed
++ data. This version of the library supports only one compression method
++ (deflation) but other algorithms may be added later and will have the same
++ stream interface.
++
++ For compression the application must provide the output buffer and
++ may optionally provide the input buffer for optimization. For decompression,
++ the application must provide the input buffer and may optionally provide
++ the output buffer for optimization.
++
++ Compression can be done in a single step if the buffers are large
++ enough (for example if an input file is mmap'ed), or can be done by
++ repeated calls of the compression function. In the latter case, the
++ application must provide more input and/or consume the output
++ (providing more output space) before each call.
++
++ The library does not install any signal handler. It is recommended to
++ add at least a handler for SIGSEGV when decompressing; the library checks
++ the consistency of the input data whenever possible but may go nuts
++ for some forms of corrupted input.
++*/
++
++typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
++typedef void (*free_func) OF((voidpf opaque, voidpf address));
++
++struct internal_state;
++
++typedef struct z_stream_s {
++ Bytef *next_in; /* next input byte */
++ uInt avail_in; /* number of bytes available at next_in */
++ uLong total_in; /* total nb of input bytes read so far */
++
++ Bytef *next_out; /* next output byte should be put there */
++ uInt avail_out; /* remaining free space at next_out */
++ uLong total_out; /* total nb of bytes output so far */
++
++ char *msg; /* last error message, NULL if no error */
++ struct internal_state FAR *state; /* not visible by applications */
++
++ alloc_func zalloc; /* used to allocate the internal state */
++ free_func zfree; /* used to free the internal state */
++ voidpf opaque; /* private data object passed to zalloc and zfree */
++
++ int data_type; /* best guess about the data type: ascii or binary */
++ uLong adler; /* adler32 value of the uncompressed data */
++ uLong reserved; /* reserved for future use */
++} z_stream;
++
++typedef z_stream FAR *z_streamp;
++
++/*
++ The application must update next_in and avail_in when avail_in has
++ dropped to zero. It must update next_out and avail_out when avail_out
++ has dropped to zero. The application must initialize zalloc, zfree and
++ opaque before calling the init function. All other fields are set by the
++ compression library and must not be updated by the application.
++
++ The opaque value provided by the application will be passed as the first
++ parameter for calls of zalloc and zfree. This can be useful for custom
++ memory management. The compression library attaches no meaning to the
++ opaque value.
++
++ zalloc must return Z_NULL if there is not enough memory for the object.
++ On 16-bit systems, the functions zalloc and zfree must be able to allocate
++ exactly 65536 bytes, but will not be required to allocate more than this
++ if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
++ pointers returned by zalloc for objects of exactly 65536 bytes *must*
++ have their offset normalized to zero. The default allocation function
++ provided by this library ensures this (see zutil.c). To reduce memory
++ requirements and avoid any allocation of 64K objects, at the expense of
++ compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
++
++ The fields total_in and total_out can be used for statistics or
++ progress reports. After compression, total_in holds the total size of
++ the uncompressed data and may be saved for use in the decompressor
++ (particularly if the decompressor wants to decompress everything in
++ a single step).
++*/
++
++ /* constants */
++
++#define Z_NO_FLUSH 0
++#define Z_PARTIAL_FLUSH 1
++#define Z_PACKET_FLUSH 2
++#define Z_SYNC_FLUSH 3
++#define Z_FULL_FLUSH 4
++#define Z_FINISH 5
++/* Allowed flush values; see deflate() below for details */
++
++#define Z_OK 0
++#define Z_STREAM_END 1
++#define Z_NEED_DICT 2
++#define Z_ERRNO (-1)
++#define Z_STREAM_ERROR (-2)
++#define Z_DATA_ERROR (-3)
++#define Z_MEM_ERROR (-4)
++#define Z_BUF_ERROR (-5)
++#define Z_VERSION_ERROR (-6)
++/* Return codes for the compression/decompression functions. Negative
++ * values are errors, positive values are used for special but normal events.
++ */
++
++#define Z_NO_COMPRESSION 0
++#define Z_BEST_SPEED 1
++#define Z_BEST_COMPRESSION 9
++#define Z_DEFAULT_COMPRESSION (-1)
++/* compression levels */
++
++#define Z_FILTERED 1
++#define Z_HUFFMAN_ONLY 2
++#define Z_DEFAULT_STRATEGY 0
++/* compression strategy; see deflateInit2() below for details */
++
++#define Z_BINARY 0
++#define Z_ASCII 1
++#define Z_UNKNOWN 2
++/* Possible values of the data_type field */
++
++#define Z_DEFLATED 8
++/* The deflate compression method (the only one supported in this version) */
++
++#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
++
++#define zlib_version zlibVersion()
++/* for compatibility with versions &lt; 1.0.2 */
++
++ /* basic functions */
++
++extern const char * EXPORT zlibVersion OF((void));
++/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
++ If the first character differs, the library code actually used is
++ not compatible with the zlib.h header file used by the application.
++ This check is automatically made by deflateInit and inflateInit.
++ */
++
++/*
++extern int EXPORT deflateInit OF((z_streamp strm, int level));
++
++ Initializes the internal stream state for compression. The fields
++ zalloc, zfree and opaque must be initialized before by the caller.
++ If zalloc and zfree are set to Z_NULL, deflateInit updates them to
++ use default allocation functions.
++
++ The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
++ 1 gives best speed, 9 gives best compression, 0 gives no compression at
++ all (the input data is simply copied a block at a time).
++ Z_DEFAULT_COMPRESSION requests a default compromise between speed and
++ compression (currently equivalent to level 6).
++
++ deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
++ enough memory, Z_STREAM_ERROR if level is not a valid compression level,
++ Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
++ with the version assumed by the caller (ZLIB_VERSION).
++ msg is set to null if there is no error message. deflateInit does not
++ perform any compression: this will be done by deflate().
++*/
++
++
++extern int EXPORT deflate OF((z_streamp strm, int flush));
++/*
++ Performs one or both of the following actions:
++
++ - Compress more input starting at next_in and update next_in and avail_in
++ accordingly. If not all input can be processed (because there is not
++ enough room in the output buffer), next_in and avail_in are updated and
++ processing will resume at this point for the next call of deflate().
++
++ - Provide more output starting at next_out and update next_out and avail_out
++ accordingly. This action is forced if the parameter flush is non zero.
++ Forcing flush frequently degrades the compression ratio, so this parameter
++ should be set only when necessary (in interactive applications).
++ Some output may be provided even if flush is not set.
++
++ Before the call of deflate(), the application should ensure that at least
++ one of the actions is possible, by providing more input and/or consuming
++ more output, and updating avail_in or avail_out accordingly; avail_out
++ should never be zero before the call. The application can consume the
++ compressed output when it wants, for example when the output buffer is full
++ (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
++ and with zero avail_out, it must be called again after making room in the
++ output buffer because there might be more output pending.
++
++ If the parameter flush is set to Z_PARTIAL_FLUSH, the current compression
++ block is terminated and flushed to the output buffer so that the
++ decompressor can get all input data available so far. For method 9, a future
++ variant on method 8, the current block will be flushed but not terminated.
++ Z_SYNC_FLUSH has the same effect as partial flush except that the compressed
++ output is byte aligned (the compressor can clear its internal bit buffer)
++ and the current block is always terminated; this can be useful if the
++ compressor has to be restarted from scratch after an interruption (in which
++ case the internal state of the compressor may be lost).
++ If flush is set to Z_FULL_FLUSH, the compression block is terminated, a
++ special marker is output and the compression dictionary is discarded; this
++ is useful to allow the decompressor to synchronize if one compressed block
++ has been damaged (see inflateSync below). Flushing degrades compression and
++ so should be used only when necessary. Using Z_FULL_FLUSH too often can
++ seriously degrade the compression. If deflate returns with avail_out == 0,
++ this function must be called again with the same value of the flush
++ parameter and more output space (updated avail_out), until the flush is
++ complete (deflate returns with non-zero avail_out).
++
++ If the parameter flush is set to Z_PACKET_FLUSH, the compression
++ block is terminated, and a zero-length stored block is output,
++ omitting the length bytes (the effect of this is that the 3-bit type
++ code 000 for a stored block is output, and the output is then
++ byte-aligned). This is designed for use at the end of a PPP packet.
++
++ If the parameter flush is set to Z_FINISH, pending input is processed,
++ pending output is flushed and deflate returns with Z_STREAM_END if there
++ was enough output space; if deflate returns with Z_OK, this function must be
++ called again with Z_FINISH and more output space (updated avail_out) but no
++ more input data, until it returns with Z_STREAM_END or an error. After
++ deflate has returned Z_STREAM_END, the only possible operations on the
++ stream are deflateReset or deflateEnd.
++
++ Z_FINISH can be used immediately after deflateInit if all the compression
++ is to be done in a single step. In this case, avail_out must be at least
++ 0.1% larger than avail_in plus 12 bytes. If deflate does not return
++ Z_STREAM_END, then it must be called again as described above.
++
++ deflate() may update data_type if it can make a good guess about
++ the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
++ binary. This field is only for information purposes and does not affect
++ the compression algorithm in any manner.
++
++ deflate() returns Z_OK if some progress has been made (more input
++ processed or more output produced), Z_STREAM_END if all input has been
++ consumed and all output has been produced (only when flush is set to
++ Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
++ if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible.
++*/
++
++
++extern int EXPORT deflateEnd OF((z_streamp strm));
++/*
++ All dynamically allocated data structures for this stream are freed.
++ This function discards any unprocessed input and does not flush any
++ pending output.
++
++ deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
++ stream state was inconsistent, Z_DATA_ERROR if the stream was freed
++ prematurely (some input or output was discarded). In the error case,
++ msg may be set but then points to a static string (which must not be
++ deallocated).
++*/
++
++
++/*
++extern int EXPORT inflateInit OF((z_streamp strm));
++
++ Initializes the internal stream state for decompression. The fields
++ zalloc, zfree and opaque must be initialized before by the caller. If
++ zalloc and zfree are set to Z_NULL, inflateInit updates them to use default
++ allocation functions.
++
++ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
++ enough memory, Z_VERSION_ERROR if the zlib library version is incompatible
++ with the version assumed by the caller. msg is set to null if there is no
++ error message. inflateInit does not perform any decompression: this will be
++ done by inflate().
++*/
++
++
++extern int EXPORT inflate OF((z_streamp strm, int flush));
++/*
++ Performs one or both of the following actions:
++
++ - Decompress more input starting at next_in and update next_in and avail_in
++ accordingly. If not all input can be processed (because there is not
++ enough room in the output buffer), next_in is updated and processing
++ will resume at this point for the next call of inflate().
++
++ - Provide more output starting at next_out and update next_out and avail_out
++ accordingly. inflate() provides as much output as possible, until there
++ is no more input data or no more space in the output buffer (see below
++ about the flush parameter).
++
++ Before the call of inflate(), the application should ensure that at least
++ one of the actions is possible, by providing more input and/or consuming
++ more output, and updating the next_* and avail_* values accordingly.
++ The application can consume the uncompressed output when it wants, for
++ example when the output buffer is full (avail_out == 0), or after each
++ call of inflate(). If inflate returns Z_OK and with zero avail_out, it
++ must be called again after making room in the output buffer because there
++ might be more output pending.
++
++ If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH,
++ inflate flushes as much output as possible to the output buffer. The
++ flushing behavior of inflate is not specified for values of the flush
++ parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the
++ current implementation actually flushes as much output as possible
++ anyway. For Z_PACKET_FLUSH, inflate checks that once all the input data
++ has been consumed, it is expecting to see the length field of a stored
++ block; if not, it returns Z_DATA_ERROR.
++
++ inflate() should normally be called until it returns Z_STREAM_END or an
++ error. However if all decompression is to be performed in a single step
++ (a single call of inflate), the parameter flush should be set to
++ Z_FINISH. In this case all pending input is processed and all pending
++ output is flushed; avail_out must be large enough to hold all the
++ uncompressed data. (The size of the uncompressed data may have been saved
++ by the compressor for this purpose.) The next operation on this stream must
++ be inflateEnd to deallocate the decompression state. The use of Z_FINISH
++ is never required, but can be used to inform inflate that a faster routine
++ may be used for the single inflate() call.
++
++ inflate() returns Z_OK if some progress has been made (more input
++ processed or more output produced), Z_STREAM_END if the end of the
++ compressed data has been reached and all uncompressed output has been
++ produced, Z_NEED_DICT if a preset dictionary is needed at this point (see
++ inflateSetDictionary below), Z_DATA_ERROR if the input data was corrupted,
++ Z_STREAM_ERROR if the stream structure was inconsistent (for example if
++ next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
++ Z_BUF_ERROR if no progress is possible or if there was not enough room in
++ the output buffer when Z_FINISH is used. In the Z_DATA_ERROR case, the
++ application may then call inflateSync to look for a good compression block.
++ In the Z_NEED_DICT case, strm-&gt;adler is set to the Adler32 value of the
++ dictionary chosen by the compressor.
++*/
++
++
++extern int EXPORT inflateEnd OF((z_streamp strm));
++/*
++ All dynamically allocated data structures for this stream are freed.
++ This function discards any unprocessed input and does not flush any
++ pending output.
++
++ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
++ was inconsistent. In the error case, msg may be set but then points to a
++ static string (which must not be deallocated).
++*/
++
++ /* Advanced functions */
++
++/*
++ The following functions are needed only in some special applications.
++*/
++
++/*
++extern int EXPORT deflateInit2 OF((z_streamp strm,
++ int level,
++ int method,
++ int windowBits,
++ int memLevel,
++ int strategy));
++
++ This is another version of deflateInit with more compression options. The
++ fields next_in, zalloc, zfree and opaque must be initialized before by
++ the caller.
++
++ The method parameter is the compression method. It must be Z_DEFLATED in
++ this version of the library. (Method 9 will allow a 64K history buffer and
++ partial block flushes.)
++
++ The windowBits parameter is the base two logarithm of the window size
++ (the size of the history buffer). It should be in the range 8..15 for this
++ version of the library (the value 16 will be allowed for method 9). Larger
++ values of this parameter result in better compression at the expense of
++ memory usage. The default value is 15 if deflateInit is used instead.
++
++ The memLevel parameter specifies how much memory should be allocated
++ for the internal compression state. memLevel=1 uses minimum memory but
++ is slow and reduces compression ratio; memLevel=9 uses maximum memory
++ for optimal speed. The default value is 8. See zconf.h for total memory
++ usage as a function of windowBits and memLevel.
++
++ The strategy parameter is used to tune the compression algorithm. Use the
++ value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
++ filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
++ string match). Filtered data consists mostly of small values with a
++ somewhat random distribution. In this case, the compression algorithm is
++ tuned to compress them better. The effect of Z_FILTERED is to force more
++ Huffman coding and less string matching; it is somewhat intermediate
++ between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
++ the compression ratio but not the correctness of the compressed output even
++ if it is not set appropriately.
++
++ If next_in is not null, the library will use this buffer to hold also
++ some history information; the buffer must either hold the entire input
++ data, or have at least 1&lt;&lt;(windowBits+1) bytes and be writable. If next_in
++ is null, the library will allocate its own history buffer (and leave next_in
++ null). next_out need not be provided here but must be provided by the
++ application for the next call of deflate().
++
++ If the history buffer is provided by the application, next_in must
++ must never be changed by the application since the compressor maintains
++ information inside this buffer from call to call; the application
++ must provide more input only by increasing avail_in. next_in is always
++ reset by the library in this case.
++
++ deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
++ not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
++ an invalid method). msg is set to null if there is no error message.
++ deflateInit2 does not perform any compression: this will be done by
++ deflate().
++*/
++
++extern int EXPORT deflateSetDictionary OF((z_streamp strm,
++ const Bytef *dictionary,
++ uInt dictLength));
++/*
++ Initializes the compression dictionary (history buffer) from the given
++ byte sequence without producing any compressed output. This function must
++ be called immediately after deflateInit or deflateInit2, before any call
++ of deflate. The compressor and decompressor must use exactly the same
++ dictionary (see inflateSetDictionary).
++ The dictionary should consist of strings (byte sequences) that are likely
++ to be encountered later in the data to be compressed, with the most commonly
++ used strings preferably put towards the end of the dictionary. Using a
++ dictionary is most useful when the data to be compressed is short and
++ can be predicted with good accuracy; the data can then be compressed better
++ than with the default empty dictionary. In this version of the library,
++ only the last 32K bytes of the dictionary are used.
++ Upon return of this function, strm-&gt;adler is set to the Adler32 value
++ of the dictionary; the decompressor may later use this value to determine
++ which dictionary has been used by the compressor. (The Adler32 value
++ applies to the whole dictionary even if only a subset of the dictionary is
++ actually used by the compressor.)
++
++ deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
++ parameter is invalid (such as NULL dictionary) or the stream state
++ is inconsistent (for example if deflate has already been called for this
++ stream). deflateSetDictionary does not perform any compression: this will
++ be done by deflate().
++*/
++
++extern int EXPORT deflateCopy OF((z_streamp dest,
++ z_streamp source));
++/*
++ Sets the destination stream as a complete copy of the source stream. If
++ the source stream is using an application-supplied history buffer, a new
++ buffer is allocated for the destination stream. The compressed output
++ buffer is always application-supplied. It's the responsibility of the
++ application to provide the correct values of next_out and avail_out for the
++ next call of deflate.
++
++ This function can be useful when several compression strategies will be
++ tried, for example when there are several ways of pre-processing the input
++ data with a filter. The streams that will be discarded should then be freed
++ by calling deflateEnd. Note that deflateCopy duplicates the internal
++ compression state which can be quite large, so this strategy is slow and
++ can consume lots of memory.
++
++ deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
++ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
++ (such as zalloc being NULL). msg is left unchanged in both source and
++ destination.
++*/
++
++extern int EXPORT deflateReset OF((z_streamp strm));
++/*
++ This function is equivalent to deflateEnd followed by deflateInit,
++ but does not free and reallocate all the internal compression state.
++ The stream will keep the same compression level and any other attributes
++ that may have been set by deflateInit2.
++
++ deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
++ stream state was inconsistent (such as zalloc or state being NULL).
++*/
++
++extern int EXPORT deflateParams OF((z_streamp strm, int level, int strategy));
++/*
++ Dynamically update the compression level and compression strategy.
++ This can be used to switch between compression and straight copy of
++ the input data, or to switch to a different kind of input data requiring
++ a different strategy. If the compression level is changed, the input
++ available so far is compressed with the old level (and may be flushed);
++ the new level will take effect only at the next call of deflate().
++
++ Before the call of deflateParams, the stream state must be set as for
++ a call of deflate(), since the currently available input may have to
++ be compressed and flushed. In particular, strm-&gt;avail_out must be non-zero.
++
++ deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
++ stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
++ if strm-&gt;avail_out was zero.
++*/
++
++extern int EXPORT deflateOutputPending OF((z_streamp strm));
++/*
++ Returns the number of bytes of output which are immediately
++ available from the compressor (i.e. without any further input
++ or flush).
++*/
++
++/*
++extern int EXPORT inflateInit2 OF((z_streamp strm,
++ int windowBits));
++
++ This is another version of inflateInit with more compression options. The
++ fields next_out, zalloc, zfree and opaque must be initialized before by
++ the caller.
++
++ The windowBits parameter is the base two logarithm of the maximum window
++ size (the size of the history buffer). It should be in the range 8..15 for
++ this version of the library (the value 16 will be allowed soon). The
++ default value is 15 if inflateInit is used instead. If a compressed stream
++ with a larger window size is given as input, inflate() will return with
++ the error code Z_DATA_ERROR instead of trying to allocate a larger window.
++
++ If next_out is not null, the library will use this buffer for the history
++ buffer; the buffer must either be large enough to hold the entire output
++ data, or have at least 1&lt;&lt;windowBits bytes. If next_out is null, the
++ library will allocate its own buffer (and leave next_out null). next_in
++ need not be provided here but must be provided by the application for the
++ next call of inflate().
++
++ If the history buffer is provided by the application, next_out must
++ never be changed by the application since the decompressor maintains
++ history information inside this buffer from call to call; the application
++ can only reset next_out to the beginning of the history buffer when
++ avail_out is zero and all output has been consumed.
++
++ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
++ not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
++ windowBits &lt; 8). msg is set to null if there is no error message.
++ inflateInit2 does not perform any decompression: this will be done by
++ inflate().
++*/
++
++extern int EXPORT inflateSetDictionary OF((z_streamp strm,
++ const Bytef *dictionary,
++ uInt dictLength));
++/*
++ Initializes the decompression dictionary (history buffer) from the given
++ uncompressed byte sequence. This function must be called immediately after
++ a call of inflate if this call returned Z_NEED_DICT. The dictionary chosen
++ by the compressor can be determined from the Adler32 value returned by this
++ call of inflate. The compressor and decompressor must use exactly the same
++ dictionary (see deflateSetDictionary).
++
++ inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
++ parameter is invalid (such as NULL dictionary) or the stream state is
++ inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
++ expected one (incorrect Adler32 value). inflateSetDictionary does not
++ perform any decompression: this will be done by subsequent calls of
++ inflate().
++*/
++
++extern int EXPORT inflateSync OF((z_streamp strm));
++/*
++ Skips invalid compressed data until the special marker (see deflate()
++ above) can be found, or until all available input is skipped. No output
++ is provided.
++
++ inflateSync returns Z_OK if the special marker has been found, Z_BUF_ERROR
++ if no more input was provided, Z_DATA_ERROR if no marker has been found,
++ or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
++ case, the application may save the current current value of total_in which
++ indicates where valid compressed data was found. In the error case, the
++ application may repeatedly call inflateSync, providing more input each time,
++ until success or end of the input data.
++*/
++
++extern int EXPORT inflateReset OF((z_streamp strm));
++/*
++ This function is equivalent to inflateEnd followed by inflateInit,
++ but does not free and reallocate all the internal decompression state.
++ The stream will keep attributes that may have been set by inflateInit2.
++
++ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
++ stream state was inconsistent (such as zalloc or state being NULL).
++*/
++
++extern int inflateIncomp OF((z_stream *strm));
++/*
++ This function adds the data at next_in (avail_in bytes) to the output
++ history without performing any output. There must be no pending output,
++ and the decompressor must be expecting to see the start of a block.
++ Calling this function is equivalent to decompressing a stored block
++ containing the data at next_in (except that the data is not output).
++*/
++
++ /* utility functions */
++
++/*
++ The following utility functions are implemented on top of the
++ basic stream-oriented functions. To simplify the interface, some
++ default options are assumed (compression level, window size,
++ standard memory allocation functions). The source code of these
++ utility functions can easily be modified if you need special options.
++*/
++
++extern int EXPORT compress OF((Bytef *dest, uLongf *destLen,
++ const Bytef *source, uLong sourceLen));
++/*
++ Compresses the source buffer into the destination buffer. sourceLen is
++ the byte length of the source buffer. Upon entry, destLen is the total
++ size of the destination buffer, which must be at least 0.1% larger than
++ sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the
++ compressed buffer.
++ This function can be used to compress a whole file at once if the
++ input file is mmap'ed.
++ compress returns Z_OK if success, Z_MEM_ERROR if there was not
++ enough memory, Z_BUF_ERROR if there was not enough room in the output
++ buffer.
++*/
++
++extern int EXPORT uncompress OF((Bytef *dest, uLongf *destLen,
++ const Bytef *source, uLong sourceLen));
++/*
++ Decompresses the source buffer into the destination buffer. sourceLen is
++ the byte length of the source buffer. Upon entry, destLen is the total
++ size of the destination buffer, which must be large enough to hold the
++ entire uncompressed data. (The size of the uncompressed data must have
++ been saved previously by the compressor and transmitted to the decompressor
++ by some mechanism outside the scope of this compression library.)
++ Upon exit, destLen is the actual size of the compressed buffer.
++ This function can be used to decompress a whole file at once if the
++ input file is mmap'ed.
++
++ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
++ enough memory, Z_BUF_ERROR if there was not enough room in the output
++ buffer, or Z_DATA_ERROR if the input data was corrupted.
++*/
++
++
++typedef voidp gzFile;
++
++extern gzFile EXPORT gzopen OF((const char *path, const char *mode));
++/*
++ Opens a gzip (.gz) file for reading or writing. The mode parameter
++ is as in fopen (&quot;rb&quot; or &quot;wb&quot;) but can also include a compression level
++ (&quot;wb9&quot;). gzopen can be used to read a file which is not in gzip format;
++ in this case gzread will directly read from the file without decompression.
++ gzopen returns NULL if the file could not be opened or if there was
++ insufficient memory to allocate the (de)compression state; errno
++ can be checked to distinguish the two cases (if errno is zero, the
++ zlib error is Z_MEM_ERROR).
++*/
++
++extern gzFile EXPORT gzdopen OF((int fd, const char *mode));
++/*
++ gzdopen() associates a gzFile with the file descriptor fd. File
++ descriptors are obtained from calls like open, dup, creat, pipe or
++ fileno (in the file has been previously opened with fopen).
++ The mode parameter is as in gzopen.
++ The next call of gzclose on the returned gzFile will also close the
++ file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
++ descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
++ gzdopen returns NULL if there was insufficient memory to allocate
++ the (de)compression state.
++*/
++
++extern int EXPORT gzread OF((gzFile file, voidp buf, unsigned len));
++/*
++ Reads the given number of uncompressed bytes from the compressed file.
++ If the input file was not in gzip format, gzread copies the given number
++ of bytes into the buffer.
++ gzread returns the number of uncompressed bytes actually read (0 for
++ end of file, -1 for error). */
++
++extern int EXPORT gzwrite OF((gzFile file, const voidp buf, unsigned len));
++/*
++ Writes the given number of uncompressed bytes into the compressed file.
++ gzwrite returns the number of uncompressed bytes actually written
++ (0 in case of error).
++*/
++
++extern int EXPORT gzflush OF((gzFile file, int flush));
++/*
++ Flushes all pending output into the compressed file. The parameter
++ flush is as in the deflate() function. The return value is the zlib
++ error number (see function gzerror below). gzflush returns Z_OK if
++ the flush parameter is Z_FINISH and all output could be flushed.
++ gzflush should be called only when strictly necessary because it can
++ degrade compression.
++*/
++
++extern int EXPORT gzclose OF((gzFile file));
++/*
++ Flushes all pending output if necessary, closes the compressed file
++ and deallocates all the (de)compression state. The return value is the zlib
++ error number (see function gzerror below).
++*/
++
++extern const char * EXPORT gzerror OF((gzFile file, int *errnum));
++/*
++ Returns the error message for the last error which occurred on the
++ given compressed file. errnum is set to zlib error number. If an
++ error occurred in the file system and not in the compression library,
++ errnum is set to Z_ERRNO and the application may consult errno
++ to get the exact error code.
++*/
++
++ /* checksum functions */
++
++/*
++ These functions are not related to compression but are exported
++ anyway because they might be useful in applications using the
++ compression library.
++*/
++
++extern uLong EXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
++
++/*
++ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
++ return the updated checksum. If buf is NULL, this function returns
++ the required initial value for the checksum.
++ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
++ much faster. Usage example:
++
++ uLong adler = adler32(0L, Z_NULL, 0);
++
++ while (read_buffer(buffer, length) != EOF) {
++ adler = adler32(adler, buffer, length);
++ }
++ if (adler != original_adler) error();
++*/
++
++extern uLong EXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len));
++/*
++ Update a running crc with the bytes buf[0..len-1] and return the updated
++ crc. If buf is NULL, this function returns the required initial value
++ for the crc. Pre- and post-conditioning (one's complement) is performed
++ within this function so it shouldn't be done by the application.
++ Usage example:
++
++ uLong crc = crc32(0L, Z_NULL, 0);
++
++ while (read_buffer(buffer, length) != EOF) {
++ crc = crc32(crc, buffer, length);
++ }
++ if (crc != original_crc) error();
++*/
++
++
++ /* various hacks, don't look :) */
++
++/* deflateInit and inflateInit are macros to allow checking the zlib version
++ * and the compiler's view of z_stream:
++ */
++extern int EXPORT deflateInit_ OF((z_streamp strm, int level,
++ const char *version, int stream_size));
++extern int EXPORT inflateInit_ OF((z_streamp strm,
++ const char *version, int stream_size));
++extern int EXPORT deflateInit2_ OF((z_streamp strm, int level, int method,
++ int windowBits, int memLevel, int strategy,
++ const char *version, int stream_size));
++extern int EXPORT inflateInit2_ OF((z_streamp strm, int windowBits,
++ const char *version, int stream_size));
++#define deflateInit(strm, level) \
++ deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
++#define inflateInit(strm) \
++ inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
++#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
++ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
++ (strategy), ZLIB_VERSION, sizeof(z_stream))
++#define inflateInit2(strm, windowBits) \
++ inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
++
++#if !defined(_Z_UTIL_H) &amp;&amp; !defined(NO_DUMMY_DECL)
++ struct internal_state {int dummy;}; /* hack for buggy compilers */
++#endif
++
++uLongf *get_crc_table OF((void)); /* can be used by asm versions of crc32() */
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _ZLIB_H */
++/* --- zlib.h */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/common/zlib.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/configure
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/configure (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/configure 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,141 @@
++#!/bin/sh
++# $Id: configure 195720 2001-06-11 11:44:34Z gc $
++
++# if [ -d /NextApps ]; then
++# system=&quot;NeXTStep&quot;
++# else
++ system=`uname -s`
++ release=`uname -r`
++ machine=`uname -p`
++ arch=`uname -m`
++# fi
++state=&quot;unknown&quot;
++
++case $system in
++ Linux)
++ makext=&quot;linux&quot;;
++ ksrc=&quot;linux&quot;;
++ state=&quot;known&quot;;;
++ SunOS)
++ case $release in
++# [0-3]*) state=&quot;ancient&quot;;;
++# 4*) state=&quot;known&quot;; ksrc=&quot;sunos4&quot;; makext=&quot;sunos4&quot;;;
++ 5.[1-6]*) state=&quot;known&quot;; ksrc=&quot;solaris&quot;; makext=&quot;sol2&quot;;;
++ 5.[7-9]*) state=&quot;known&quot;; ksrc=&quot;solaris&quot;; makext=&quot;sol2&quot;;
++ case $arch in
++ sun4u) lp64='y';;
++ *) ;;
++ esac;;
++ esac;;
++ NetBSD|FreeBSD|ULTRIX|OSF1|NeXTStep|SINIX-?|UNIX_SV|UNIX_System_V)
++ state=&quot;notincluded&quot;;;
++# NetBSD)
++# makext=&quot;bsd&quot;;
++# case $release in
++# 0.*) state=&quot;ancient&quot;;;
++# 1.0*) state=&quot;ancient&quot;;;
++# 1.1*) state=&quot;known&quot;; ksrc=&quot;netbsd-1.1&quot;;;
++# 1.2*) state=&quot;known&quot;; ksrc=&quot;netbsd-1.2&quot;; makext=&quot;netbsd-1.2&quot;;;
++# 1.[3-9]*|[2-9]*)
++# state=&quot;late&quot;; ksrc=&quot;netbsd-1.2&quot;;;
++# esac;;
++# ULTRIX)
++# makext=&quot;ultrix&quot;;
++# case $release in
++# [0-3]*) state=&quot;ancient&quot;;;
++# 4.[01]*) state=&quot;early&quot;; ksrc=&quot;ultrix&quot;;;
++# 4.[234]) state=&quot;known&quot;; ksrc=&quot;ultrix&quot;;;
++# esac;;
++# OSF1)
++# makext=&quot;osf&quot;;
++# case $release in
++# V1.*) state=&quot;neolithic&quot;; ksrc=&quot;osf1&quot;;;
++# V[23].*) state=&quot;neolithic&quot;; ksrc=&quot;osf1&quot;;;
++# V4.*) state=&quot;known&quot;; ksrc=&quot;osf1&quot;;;
++# V[5-9]*) state=&quot;late&quot;; ksrc=&quot;osf1&quot;;;
++# esac;;
++# FreeBSD)
++# makext=&quot;bsd&quot;;
++# case $release in
++# 1.*) state=&quot;known&quot;; ksrc=&quot;freebsd-old&quot;;;
++# 2.[01]*) state=&quot;known&quot;; ksrc=&quot;freebsd-2.0&quot;;;
++# 2.2.[2-7]*) state=&quot;late&quot;; ksrc=&quot;freebsd-2.0&quot;;;
++# 2.2.8*) state=&quot;known&quot;; ksrc=&quot;freebsd-2.2.8&quot;;;
++# 3.[0-1]*) state=&quot;known&quot;; ksrc=&quot;freebsd-3.0&quot;;;
++# esac;;
++# NeXTStep)
++# makext=&quot;NeXT&quot;;
++# ksrc=&quot;NeXT&quot;;
++# state=&quot;known&quot;;;
++# SINIX-?)
++# case $release in
++# 5.4[01]) state=known; ksrc=svr4; makext=svr4;;
++# 5.4[2-9]) state=late; ksrc=svr4; makext=svr4;;
++# esac;;
++# # Intel SVR4 systems come with a bug in the uname program. Unless
++# # your provider fixed the bug, or you get a fix for it, uname -S will
++# # overwrite the system name with the node name!
++# UNIX_SV|UNIX_System_V|`uname -n`)
++# case $release in
++# 4.0) state=known; ksrc=svr4; makext=svr4;;
++# 4.2) state=late; ksrc=svr4; makext=svr4;;
++# esac;;
++esac
++
++if [ -d &quot;$ksrc&quot; ]; then :; else
++ state=&quot;notincluded&quot;
++ unset ksrc
++fi
++
++case $state in
++ neolithic)
++ echo &quot;This is a newer release on an outdated OS ($system).&quot;
++ echo &quot; This software may or may not work on this OS.&quot;
++ echo &quot; You may want to download an older version of PPP for this OS.&quot;;;
++ ancient)
++ echo &quot;This is an old release of a supported OS ($system).&quot;
++ echo &quot;This software cannot be used as-is on this system,&quot;
++ echo &quot;but you may be able to port it. Good luck!&quot;
++ exit;;
++ early)
++ echo &quot;This is an old release of a supported OS ($system).&quot;
++ echo &quot;This software should install and run on this system,&quot;
++ echo &quot;but it hasn't been tested.&quot;;;
++ late)
++ echo &quot;This is a newer release of $system than is supported by&quot;
++ echo &quot;this software. It may or may not work.&quot;;;
++ unknown)
++ echo &quot;This software has not been ported to this system. Sorry.&quot;;;
++ notincluded)
++ echo &quot;Support for this system has not been included&quot;
++ echo &quot;in this distribution. Sorry.&quot;;;
++esac
++
++orig_makext=$makext
++
++if [ -d &quot;$ksrc&quot; ]; then
++ echo &quot;Creating links to Makefiles.&quot;
++ rm -f Makefile
++ ln -s $ksrc/Makefile.top Makefile
++ echo &quot; Makefile -&gt; $ksrc/Makefile.top&quot;
++ if [ &quot;$ksrc&quot; = solaris ]; then
++ # Point to 64-bit Makefile extension
++ if [ &quot;$lp64&quot; = y ]; then
++ makext=$makext-64
++ fi
++ rm -f $ksrc/Makefile
++ ln -s Makefile.$makext $ksrc/Makefile
++ echo &quot; $ksrc/Makefile -&gt; Makefile.$makext&quot;
++ # Restore extension
++ if [ &quot;$lp64&quot; = y ]; then
++ makext=$orig_makext
++ fi
++ fi
++ for dir in pppd pppstats chat pppdump; do
++ rm -f $dir/Makefile
++ if [ -f $dir/Makefile.$makext ]; then
++ ln -s Makefile.$makext $dir/Makefile
++ echo &quot; $dir/Makefile -&gt; Makefile.$makext&quot;
++ fi
++ done
++fi
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/configure
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: drakx/trunk/mdk-stage1/ppp/contrib/pppgetpass/Makefile.linux
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/contrib/pppgetpass/Makefile.linux (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/contrib/pppgetpass/Makefile.linux 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,16 @@
++all: pppgetpass.vt pppgetpass.gtk
++
++pppgetpass.vt: pppgetpass.vt.o
++
++pppgetpass.gtk: pppgetpass.gtk.o
++ $(CC) $(LDFLAGS) pppgetpass.gtk.o `gtk-config --libs` -o pppgetpass.gtk
++pppgetpass.gtk.o: pppgetpass.gtk.c
++ $(CC) $(CFLAGS) -c pppgetpass.gtk.c `gtk-config --cflags`
++
++install: all
++ install -m 755 pppgetpass.sh /usr/bin/pppgetpass
++ install -m 4755 -o root -g root pppgetpass.vt /usr/bin/
++ install -m 755 -o root -g root pppgetpass.gtk /usr/X11/bin/
++
++clean:
++ rm -f *.o pppgetpass.gtk pppgetpass.vt core
+
+Added: drakx/trunk/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.8
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.8 (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.8 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,18 @@
++.TH PPPGETPASS 8 &quot;26 Sep 1999&quot;
++.SH NAME
++pppgetpass \- prompt for PAP password
++.SH SYNOPSIS
++.B pppgetpass
++.I client server fd
++.SH DESCRIPTION
++.B pppgetpass
++the outer half of a plugin for PAP password prompting in pppd.
++If the peer requires PAP, and the
++.B passprompt.so
++plugin is loaded into pppd, it will run
++.B /usr/sbin/pppgetpass
++(or another program specified by the
++.B promptprog
++option) to prompt the user for the password.
++.SH SEE ALSO
++pppd(8)
+
+Added: drakx/trunk/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.gtk.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.gtk.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.gtk.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,92 @@
++#include &lt;glib.h&gt;
++#include &lt;gdk/gdk.h&gt;
++#include &lt;gtk/gtkwindow.h&gt;
++#include &lt;gtk/gtkmain.h&gt;
++#include &lt;gtk/gtkbutton.h&gt;
++#include &lt;gtk/gtkvbox.h&gt;
++#include &lt;gtk/gtklabel.h&gt;
++#include &lt;gtk/gtkentry.h&gt;
++#include &lt;gtk/gtksignal.h&gt;
++
++#include &lt;stdio.h&gt;
++#include &lt;string.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;syslog.h&gt;
++
++int outfd;
++int err;
++
++static void okpressed(void *widget, void *clientdata)
++{
++ GtkWidget *answer=clientdata;
++ gchar *pass;
++ int passlen;
++ ssize_t wrote;
++ (void)widget;
++
++ pass=gtk_entry_get_text(GTK_ENTRY(answer));
++
++ passlen=strlen(pass);
++ if(!passlen)
++ return;
++
++ if((wrote=write(outfd, pass, passlen))!=passlen) {
++ if(wrote&lt;0)
++ syslog(LOG_ERR, &quot;write error on outpipe: %m&quot;);
++ else
++ syslog(LOG_ERR, &quot;short write on outpipe&quot;);
++ err=1;
++ }
++ gtk_main_quit();
++}
++
++int main(int argc, char **argv)
++{
++ GtkWidget *mainwindow, *vbox, *question, *answer, *ok;
++ char buf[1024];
++ gtk_init(&amp;argc, &amp;argv);
++
++ openlog(argv[0], LOG_PID, LOG_DAEMON);
++ if(argc!=4) {
++ syslog(LOG_WARNING, &quot;Usage error&quot;);
++ return 1;
++ }
++ outfd=atoi(argv[3]);
++ mainwindow=gtk_window_new(GTK_WINDOW_TOPLEVEL);
++ gtk_window_set_title(GTK_WINDOW(mainwindow), &quot;pppgetpass&quot;);
++ gtk_signal_connect(GTK_OBJECT(mainwindow), &quot;destroy&quot;,
++ GTK_SIGNAL_FUNC(gtk_main_quit), 0);
++
++ vbox=gtk_vbox_new(FALSE, 5);
++ gtk_container_add(GTK_CONTAINER(mainwindow), vbox);
++ gtk_widget_show(vbox);
++
++ if(argv[1][0] &amp;&amp; argv[2][0])
++ snprintf(buf, sizeof buf, &quot;Password for PPP client %s on server %s: &quot;, argv[1], argv[2]);
++ else if(argv[1][0] &amp;&amp; !argv[2][0])
++ snprintf(buf, sizeof buf, &quot;Password for PPP client %s: &quot;, argv[1]);
++ else if(!argv[1][0] &amp;&amp; argv[2][0])
++ snprintf(buf, sizeof buf, &quot;Password for PPP on server %s: &quot;, argv[2]);
++ else
++ snprintf(buf, sizeof buf, &quot;Enter PPP password: &quot;);
++ question=gtk_label_new(buf);
++ gtk_box_pack_start(GTK_BOX(vbox), question, FALSE, TRUE, 0);
++ gtk_widget_show(question);
++
++ answer=gtk_entry_new();
++ gtk_entry_set_visibility(GTK_ENTRY(answer), 0);
++ gtk_box_pack_start(GTK_BOX(vbox), answer, FALSE, TRUE, 0);
++ gtk_widget_show(answer);
++
++ ok=gtk_button_new_with_label(&quot;OK&quot;);
++ gtk_box_pack_start(GTK_BOX(vbox), ok, FALSE, TRUE, 0);
++ gtk_signal_connect(GTK_OBJECT(ok), &quot;clicked&quot;,
++ GTK_SIGNAL_FUNC(okpressed), answer);
++ gtk_widget_show(ok);
++
++ gtk_widget_show(mainwindow);
++ gtk_main();
++
++ return err;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.gtk.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.sh
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.sh (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.sh 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,7 @@
++#!/bin/sh
++
++if [ -z &quot;$DISPLAY&quot; ]; then
++ exec pppgetpass.vt &quot;$@&quot;
++else
++ exec pppgetpass.gtk &quot;$@&quot;
++fi
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.sh
+___________________________________________________________________
+Added: svn:executable
+ + *
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.vt.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.vt.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.vt.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,218 @@
++#include &lt;stdio.h&gt;
++#include &lt;string.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;errno.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;sys/ioctl.h&gt;
++#include &lt;syslog.h&gt;
++#include &lt;termios.h&gt;
++#include &lt;sys/vt.h&gt;
++
++static int console_owner(uid_t, int);
++
++int main(int argc, char **argv)
++{
++ int console;
++ uid_t uid;
++ struct vt_stat origstate;
++ int openvtnum;
++ char openvtname[256];
++ int openvt;
++ gid_t gid;
++ int chowned;
++ FILE *fp;
++ struct termios t;
++ char pass[256], *nl;
++ int outfd, passlen;
++ ssize_t wrote;
++ console=open(&quot;/dev/console&quot;, O_RDWR);
++
++ uid=getuid();
++ gid=getgid();
++ seteuid(uid);
++
++ openlog(argv[0], LOG_PID, LOG_DAEMON);
++
++ if(argc!=4) {
++ syslog(LOG_WARNING, &quot;Usage error&quot;);
++ return 1;
++ }
++
++ if(console&lt;0) {
++ syslog(LOG_ERR, &quot;open(/dev/console): %m&quot;);
++ return 1;
++ }
++
++ if(ioctl(console, VT_GETSTATE, &amp;origstate)&lt;0) {
++ syslog(LOG_ERR, &quot;VT_GETSTATE: %m&quot;);
++ return 1;
++ }
++
++ if(uid) {
++ if(!console_owner(uid, origstate.v_active)) {
++ int i;
++ for(i=0;i&lt;64;++i) {
++ if(i!=origstate.v_active &amp;&amp; console_owner(uid, i))
++ break;
++ }
++ if(i==64) {
++ syslog(LOG_WARNING, &quot;run by uid %lu not at console&quot;, (unsigned long)uid);
++ return 1;
++ }
++ }
++ }
++
++ if(ioctl(console, VT_OPENQRY, &amp;openvtnum)&lt;0) {
++ syslog(LOG_ERR, &quot;VT_OPENQRY: %m&quot;);
++ return 1;
++ }
++ if(openvtnum==-1) {
++ syslog(LOG_ERR, &quot;No free VTs&quot;);
++ return 1;
++ }
++
++ snprintf(openvtname, sizeof openvtname, &quot;/dev/tty%d&quot;, openvtnum);
++ seteuid(0);
++ openvt=open(openvtname, O_RDWR);
++ if(openvt&lt;0) {
++ seteuid(uid);
++ syslog(LOG_ERR, &quot;open(%s): %m&quot;, openvtname);
++ return 1;
++ }
++
++ chowned=fchown(openvt, uid, gid);
++ if(chowned&lt;0) {
++ seteuid(uid);
++ syslog(LOG_ERR, &quot;fchown(%s): %m&quot;, openvtname);
++ return 1;
++ }
++
++ close(console);
++
++ if(ioctl(openvt, VT_ACTIVATE, openvtnum)&lt;0) {
++ seteuid(uid);
++ syslog(LOG_ERR, &quot;VT_ACTIVATE(%d): %m&quot;, openvtnum);
++ return 1;
++ }
++
++ while(ioctl(openvt, VT_WAITACTIVE, openvtnum)&lt;0) {
++ if(errno!=EINTR) {
++ ioctl(openvt, VT_ACTIVATE, origstate.v_active);
++ seteuid(uid);
++ syslog(LOG_ERR, &quot;VT_WAITACTIVE(%d): %m&quot;, openvtnum);
++ return 1;
++ }
++ }
++
++ seteuid(uid);
++ fp=fdopen(openvt, &quot;r+&quot;);
++ if(!fp) {
++ seteuid(0);
++ ioctl(openvt, VT_ACTIVATE, origstate.v_active);
++ seteuid(uid);
++ syslog(LOG_ERR, &quot;fdopen(%s): %m&quot;, openvtname);
++ return 1;
++ }
++
++ if(tcgetattr(openvt, &amp;t)&lt;0) {
++ seteuid(0);
++ ioctl(openvt, VT_ACTIVATE, origstate.v_active);
++ seteuid(uid);
++ syslog(LOG_ERR, &quot;tcgetattr(%s): %m&quot;, openvtname);
++ return 1;
++ }
++ t.c_lflag &amp;= ~ECHO;
++ if(tcsetattr(openvt, TCSANOW, &amp;t)&lt;0) {
++ seteuid(0);
++ ioctl(openvt, VT_ACTIVATE, origstate.v_active);
++ seteuid(uid);
++ syslog(LOG_ERR, &quot;tcsetattr(%s): %m&quot;, openvtname);
++ return 1;
++ }
++
++ if(fprintf(fp, &quot;\033[2J\033[H&quot;)&lt;0) {
++ seteuid(0);
++ ioctl(openvt, VT_ACTIVATE, origstate.v_active);
++ seteuid(uid);
++ syslog(LOG_ERR, &quot;write error on %s: %m&quot;, openvtname);
++ return 1;
++ }
++ if(argv[1][0] &amp;&amp; argv[2][0]) {
++ if(fprintf(fp, &quot;Password for PPP client %s on server %s: &quot;, argv[1], argv[2])&lt;0) {
++ seteuid(0);
++ ioctl(openvt, VT_ACTIVATE, origstate.v_active);
++ seteuid(uid);
++ syslog(LOG_ERR, &quot;write error on %s: %m&quot;, openvtname);
++ return 1;
++ }
++ } else if(argv[1][0] &amp;&amp; !argv[2][0]) {
++ if(fprintf(fp, &quot;Password for PPP client %s: &quot;, argv[1])&lt;0) {
++ syslog(LOG_ERR, &quot;write error on %s: %m&quot;, openvtname);
++ seteuid(0);
++ ioctl(openvt, VT_ACTIVATE, origstate.v_active);
++ seteuid(uid);
++ return 1;
++ }
++ } else if(!argv[1][0] &amp;&amp; argv[2][0]) {
++ if(fprintf(fp, &quot;Password for PPP on server %s: &quot;, argv[2])&lt;0) {
++ seteuid(0);
++ ioctl(openvt, VT_ACTIVATE, origstate.v_active);
++ seteuid(uid);
++ syslog(LOG_ERR, &quot;write error on %s: %m&quot;, openvtname);
++ return 1;
++ }
++ } else {
++ if(fprintf(fp, &quot;Enter PPP password: &quot;)&lt;0) {
++ seteuid(0);
++ ioctl(openvt, VT_ACTIVATE, origstate.v_active);
++ seteuid(uid);
++ syslog(LOG_ERR, &quot;write error on %s: %m&quot;, openvtname);
++ return 1;
++ }
++ }
++
++ if(!fgets(pass, sizeof pass, fp)) {
++ seteuid(0);
++ ioctl(openvt, VT_ACTIVATE, origstate.v_active);
++ seteuid(uid);
++ if(ferror(fp)) {
++ syslog(LOG_ERR, &quot;read error on %s: %m&quot;, openvtname);
++ }
++ return 1;
++ }
++ if((nl=strchr(pass, '\n')))
++ *nl=0;
++ passlen=strlen(pass);
++
++ outfd=atoi(argv[3]);
++ if((wrote=write(outfd, pass, passlen))!=passlen) {
++ seteuid(0);
++ ioctl(openvt, VT_ACTIVATE, origstate.v_active);
++ seteuid(uid);
++ if(wrote&lt;0)
++ syslog(LOG_ERR, &quot;write error on outpipe: %m&quot;);
++ else
++ syslog(LOG_ERR, &quot;short write on outpipe&quot;);
++ return 1;
++ }
++
++ seteuid(0);
++ ioctl(openvt, VT_ACTIVATE, origstate.v_active);
++ seteuid(uid);
++ return 0;
++}
++
++static int console_owner(uid_t uid, int cons)
++{
++ char name[256];
++ struct stat st;
++ snprintf(name, sizeof name, &quot;/dev/tty%d&quot;, cons);
++ if(stat(name, &amp;st)&lt;0) {
++ if(errno!=ENOENT)
++ syslog(LOG_ERR, &quot;stat(%s): %m&quot;, name);
++ return 0;
++ }
++ return uid==st.st_uid;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.vt.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/etc.ppp/chap-secrets
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/etc.ppp/chap-secrets (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/etc.ppp/chap-secrets 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,2 @@
++# Secrets for authentication using CHAP
++# client server secret IP addresses
+
+Added: drakx/trunk/mdk-stage1/ppp/etc.ppp/options
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/etc.ppp/options (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/etc.ppp/options 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,5 @@
++lock
++noauth
++noipdefault
++usepeerdns
++
+
+Added: drakx/trunk/mdk-stage1/ppp/etc.ppp/options.options
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/etc.ppp/options.options (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/etc.ppp/options.options 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1 @@
++lock
+
+Added: drakx/trunk/mdk-stage1/ppp/etc.ppp/pap-secrets
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/etc.ppp/pap-secrets (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/etc.ppp/pap-secrets 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,2 @@
++# Secrets for authentication using PAP
++# client server secret IP addresses
+
+Added: drakx/trunk/mdk-stage1/ppp/include/linux/if_ppp.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/include/linux/if_ppp.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/include/linux/if_ppp.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,155 @@
++/* $Id: if_ppp.h 195720 2001-06-11 11:44:34Z gc $ */
++
++/*
++ * if_ppp.h - Point-to-Point Protocol definitions.
++ *
++ * Copyright (c) 1989 Carnegie Mellon University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by Carnegie Mellon University. The name of the
++ * University may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ */
++
++/*
++ * ==FILEVERSION 20000724==
++ *
++ * NOTE TO MAINTAINERS:
++ * If you modify this file at all, please set the above date.
++ * if_ppp.h is shipped with a PPP distribution as well as with the kernel;
++ * if everyone increases the FILEVERSION number above, then scripts
++ * can do the right thing when deciding whether to install a new if_ppp.h
++ * file. Don't change the format of that line otherwise, so the
++ * installation script can recognize it.
++ */
++
++#ifndef _IF_PPP_H_
++#define _IF_PPP_H_
++
++/*
++ * Packet sizes
++ */
++
++#define PPP_MTU 1500 /* Default MTU (size of Info field) */
++#define PPP_MAXMRU 65000 /* Largest MRU we allow */
++#define PROTO_IPX 0x002b /* protocol numbers */
++#define PROTO_DNA_RT 0x0027 /* DNA Routing */
++
++
++/*
++ * Bit definitions for flags.
++ */
++
++#define SC_COMP_PROT 0x00000001 /* protocol compression (output) */
++#define SC_COMP_AC 0x00000002 /* header compression (output) */
++#define SC_COMP_TCP 0x00000004 /* TCP (VJ) compression (output) */
++#define SC_NO_TCP_CCID 0x00000008 /* disable VJ connection-id comp. */
++#define SC_REJ_COMP_AC 0x00000010 /* reject adrs/ctrl comp. on input */
++#define SC_REJ_COMP_TCP 0x00000020 /* reject TCP (VJ) comp. on input */
++#define SC_CCP_OPEN 0x00000040 /* Look at CCP packets */
++#define SC_CCP_UP 0x00000080 /* May send/recv compressed packets */
++#define SC_ENABLE_IP 0x00000100 /* IP packets may be exchanged */
++#define SC_LOOP_TRAFFIC 0x00000200 /* send traffic to pppd */
++#define SC_MULTILINK 0x00000400 /* do multilink encapsulation */
++#define SC_MP_SHORTSEQ 0x00000800 /* use short MP sequence numbers */
++#define SC_COMP_RUN 0x00001000 /* compressor has been inited */
++#define SC_DECOMP_RUN 0x00002000 /* decompressor has been inited */
++#define SC_MP_XSHORTSEQ 0x00004000 /* transmit short MP seq numbers */
++#define SC_DEBUG 0x00010000 /* enable debug messages */
++#define SC_LOG_INPKT 0x00020000 /* log contents of good pkts recvd */
++#define SC_LOG_OUTPKT 0x00040000 /* log contents of pkts sent */
++#define SC_LOG_RAWIN 0x00080000 /* log all chars received */
++#define SC_LOG_FLUSH 0x00100000 /* log all chars flushed */
++#define SC_SYNC 0x00200000 /* synchronous serial mode */
++#define SC_MASK 0x0f200fff /* bits that user can change */
++
++/* state bits */
++#define SC_XMIT_BUSY 0x10000000 /* (used by isdn_ppp?) */
++#define SC_RCV_ODDP 0x08000000 /* have rcvd char with odd parity */
++#define SC_RCV_EVNP 0x04000000 /* have rcvd char with even parity */
++#define SC_RCV_B7_1 0x02000000 /* have rcvd char with bit 7 = 1 */
++#define SC_RCV_B7_0 0x01000000 /* have rcvd char with bit 7 = 0 */
++#define SC_DC_FERROR 0x00800000 /* fatal decomp error detected */
++#define SC_DC_ERROR 0x00400000 /* non-fatal decomp error detected */
++
++/*
++ * Ioctl definitions.
++ */
++
++struct npioctl {
++ int protocol; /* PPP protocol, e.g. PPP_IP */
++ enum NPmode mode;
++};
++
++/* Structure describing a CCP configuration option, for PPPIOCSCOMPRESS */
++struct ppp_option_data {
++ __u8 *ptr;
++ __u32 length;
++ int transmit;
++};
++
++struct ifpppstatsreq {
++ struct ifreq b;
++ struct ppp_stats stats; /* statistic information */
++};
++
++struct ifpppcstatsreq {
++ struct ifreq b;
++ struct ppp_comp_stats stats;
++};
++
++#define ifr__name b.ifr_ifrn.ifrn_name
++#define stats_ptr b.ifr_ifru.ifru_data
++
++/*
++ * Ioctl definitions.
++ */
++
++#define PPPIOCGFLAGS _IOR('t', 90, int) /* get configuration flags */
++#define PPPIOCSFLAGS _IOW('t', 89, int) /* set configuration flags */
++#define PPPIOCGASYNCMAP _IOR('t', 88, int) /* get async map */
++#define PPPIOCSASYNCMAP _IOW('t', 87, int) /* set async map */
++#define PPPIOCGUNIT _IOR('t', 86, int) /* get ppp unit number */
++#define PPPIOCGRASYNCMAP _IOR('t', 85, int) /* get receive async map */
++#define PPPIOCSRASYNCMAP _IOW('t', 84, int) /* set receive async map */
++#define PPPIOCGMRU _IOR('t', 83, int) /* get max receive unit */
++#define PPPIOCSMRU _IOW('t', 82, int) /* set max receive unit */
++#define PPPIOCSMAXCID _IOW('t', 81, int) /* set VJ max slot ID */
++#define PPPIOCGXASYNCMAP _IOR('t', 80, ext_accm) /* get extended ACCM */
++#define PPPIOCSXASYNCMAP _IOW('t', 79, ext_accm) /* set extended ACCM */
++#define PPPIOCXFERUNIT _IO('t', 78) /* transfer PPP unit */
++#define PPPIOCSCOMPRESS _IOW('t', 77, struct ppp_option_data)
++#define PPPIOCGNPMODE _IOWR('t', 76, struct npioctl) /* get NP mode */
++#define PPPIOCSNPMODE _IOW('t', 75, struct npioctl) /* set NP mode */
++#define PPPIOCSPASS _IOW('t', 71, struct sock_fprog) /* set pass filter */
++#define PPPIOCSACTIVE _IOW('t', 70, struct sock_fprog) /* set active filt */
++#define PPPIOCGDEBUG _IOR('t', 65, int) /* Read debug level */
++#define PPPIOCSDEBUG _IOW('t', 64, int) /* Set debug level */
++#define PPPIOCGIDLE _IOR('t', 63, struct ppp_idle) /* get idle time */
++#define PPPIOCNEWUNIT _IOWR('t', 62, int) /* create new ppp unit */
++#define PPPIOCATTACH _IOW('t', 61, int) /* attach to ppp unit */
++#define PPPIOCDETACH _IOW('t', 60, int) /* detach from ppp unit/chan */
++#define PPPIOCSMRRU _IOW('t', 59, int) /* set multilink MRU */
++#define PPPIOCCONNECT _IOW('t', 58, int) /* connect channel to unit */
++#define PPPIOCDISCONN _IO('t', 57) /* disconnect channel */
++#define PPPIOCATTCHAN _IOW('t', 56, int) /* attach to ppp channel */
++#define PPPIOCGCHAN _IOR('t', 55, int) /* get ppp channel number */
++
++#define SIOCGPPPSTATS (SIOCDEVPRIVATE + 0)
++#define SIOCGPPPVER (SIOCDEVPRIVATE + 1) /* NEVER change this!! */
++#define SIOCGPPPCSTATS (SIOCDEVPRIVATE + 2)
++
++#if !defined(ifr_mtu)
++#define ifr_mtu ifr_ifru.ifru_metric
++#endif
++
++#endif /* _IF_PPP_H_ */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/include/linux/if_ppp.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/include/linux/if_pppvar.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/include/linux/if_pppvar.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/include/linux/if_pppvar.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,138 @@
++/* From: if_pppvar.h,v 1.2 1995/06/12 11:36:51 paulus Exp */
++/*
++ * if_pppvar.h - private structures and declarations for PPP.
++ *
++ * Copyright (c) 1994 The Australian National University.
++ * All rights reserved.
++ *
++ * Permission to use, copy, modify, and distribute this software and its
++ * documentation is hereby granted, provided that the above copyright
++ * notice appears in all copies. This software is provided without any
++ * warranty, express or implied. The Australian National University
++ * makes no representations about the suitability of this software for
++ * any purpose.
++ *
++ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
++ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
++ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
++ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
++ * OF SUCH DAMAGE.
++ *
++ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
++ * ON AN &quot;AS IS&quot; BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
++ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
++ * OR MODIFICATIONS.
++ *
++ * Copyright (c) 1989 Carnegie Mellon University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by Carnegie Mellon University. The name of the
++ * University may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ */
++
++/*
++ * ==FILEVERSION 990911==
++ *
++ * NOTE TO MAINTAINERS:
++ * If you modify this file at all, please set the above date.
++ * if_pppvar.h is shipped with a PPP distribution as well as with the kernel;
++ * if everyone increases the FILEVERSION number above, then scripts
++ * can do the right thing when deciding whether to install a new if_pppvar.h
++ * file. Don't change the format of that line otherwise, so the
++ * installation script can recognize it.
++ */
++
++/*
++ * Supported network protocols. These values are used for
++ * indexing sc_npmode.
++ */
++
++#define NP_IP 0 /* Internet Protocol */
++#define NP_IPX 1 /* IPX protocol */
++#define NP_AT 2 /* Appletalk protocol */
++#define NP_IPV6 3 /* Internet Protocol */
++#define NUM_NP 4 /* Number of NPs. */
++
++#define OBUFSIZE 256 /* # chars of output buffering */
++
++/*
++ * Structure describing each ppp unit.
++ */
++
++struct ppp {
++ int magic; /* magic value for structure */
++ struct ppp *next; /* unit with next index */
++ unsigned long inuse; /* are we allocated? */
++ int line; /* network interface unit # */
++ __u32 flags; /* miscellaneous control flags */
++ int mtu; /* maximum xmit frame size */
++ int mru; /* maximum receive frame size */
++ struct slcompress *slcomp; /* for TCP header compression */
++ struct sk_buff_head xmt_q; /* frames to send from pppd */
++ struct sk_buff_head rcv_q; /* frames for pppd to read */
++ unsigned long xmit_busy; /* bit 0 set when xmitter busy */
++
++ /* Information specific to using ppp on async serial lines. */
++ struct tty_struct *tty; /* ptr to TTY structure */
++ struct tty_struct *backup_tty; /* TTY to use if tty gets closed */
++ __u8 escape; /* 0x20 if prev char was PPP_ESC */
++ __u8 toss; /* toss this frame */
++ volatile __u8 tty_pushing; /* internal state flag */
++ volatile __u8 woke_up; /* internal state flag */
++ __u32 xmit_async_map[8]; /* 1 bit means that given control
++ character is quoted on output*/
++ __u32 recv_async_map; /* 1 bit means that given control
++ character is ignored on input*/
++ __u32 bytes_sent; /* Bytes sent on frame */
++ __u32 bytes_rcvd; /* Bytes recvd on frame */
++
++ /* Async transmission information */
++ struct sk_buff *tpkt; /* frame currently being sent */
++ int tpkt_pos; /* how much of it we've done */
++ __u16 tfcs; /* FCS so far for it */
++ unsigned char *optr; /* where we're up to in sending */
++ unsigned char *olim; /* points past last valid char */
++
++ /* Async reception information */
++ struct sk_buff *rpkt; /* frame currently being rcvd */
++ __u16 rfcs; /* FCS so far of rpkt */
++
++ /* Queues for select() functionality */
++ struct wait_queue *read_wait; /* queue for reading processes */
++
++ /* info for detecting idle channels */
++ unsigned long last_xmit; /* time of last transmission */
++ unsigned long last_recv; /* time last packet received */
++
++ /* Statistic information */
++ struct pppstat stats; /* statistic information */
++
++ /* PPP compression protocol information */
++ struct compressor *sc_xcomp; /* transmit compressor */
++ void *sc_xc_state; /* transmit compressor state */
++ struct compressor *sc_rcomp; /* receive decompressor */
++ void *sc_rc_state; /* receive decompressor state */
++
++ enum NPmode sc_npmode[NUM_NP]; /* what to do with each NP */
++ int sc_xfer; /* PID of reserved PPP table */
++ char name[8]; /* space for unit name */
++ struct device dev; /* net device structure */
++ struct enet_statistics estats; /* more detailed stats */
++
++ /* tty output buffer */
++ unsigned char obuf[OBUFSIZE]; /* buffer for characters to send */
++};
++
++#define PPP_MAGIC 0x5002
++#define PPP_VERSION &quot;2.3.11&quot;
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/include/linux/if_pppvar.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/include/linux/ppp-comp.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/include/linux/ppp-comp.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/include/linux/ppp-comp.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,203 @@
++/*
++ * ppp-comp.h - Definitions for doing PPP packet compression.
++ *
++ * Copyright (c) 1994 The Australian National University.
++ * All rights reserved.
++ *
++ * Permission to use, copy, modify, and distribute this software and its
++ * documentation is hereby granted, provided that the above copyright
++ * notice appears in all copies. This software is provided without any
++ * warranty, express or implied. The Australian National University
++ * makes no representations about the suitability of this software for
++ * any purpose.
++ *
++ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
++ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
++ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
++ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
++ * OF SUCH DAMAGE.
++ *
++ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
++ * ON AN &quot;AS IS&quot; BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
++ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
++ * OR MODIFICATIONS.
++ *
++ * $Id: ppp-comp.h 195720 2001-06-11 11:44:34Z gc $
++ */
++
++/*
++ * ==FILEVERSION 980319==
++ *
++ * NOTE TO MAINTAINERS:
++ * If you modify this file at all, please set the above date.
++ * ppp-comp.h is shipped with a PPP distribution as well as with the kernel;
++ * if everyone increases the FILEVERSION number above, then scripts
++ * can do the right thing when deciding whether to install a new ppp-comp.h
++ * file. Don't change the format of that line otherwise, so the
++ * installation script can recognize it.
++ */
++
++#ifndef _NET_PPP_COMP_H
++#define _NET_PPP_COMP_H
++
++/*
++ * The following symbols control whether we include code for
++ * various compression methods.
++ */
++
++#ifndef DO_BSD_COMPRESS
++#define DO_BSD_COMPRESS 1 /* by default, include BSD-Compress */
++#endif
++#ifndef DO_DEFLATE
++#define DO_DEFLATE 1 /* by default, include Deflate */
++#endif
++#define DO_PREDICTOR_1 0
++#define DO_PREDICTOR_2 0
++
++/*
++ * Structure giving methods for compression/decompression.
++ */
++
++struct compressor {
++ int compress_proto; /* CCP compression protocol number */
++
++ /* Allocate space for a compressor (transmit side) */
++ void *(*comp_alloc) (unsigned char *options, int opt_len);
++
++ /* Free space used by a compressor */
++ void (*comp_free) (void *state);
++
++ /* Initialize a compressor */
++ int (*comp_init) (void *state, unsigned char *options,
++ int opt_len, int unit, int opthdr, int debug);
++
++ /* Reset a compressor */
++ void (*comp_reset) (void *state);
++
++ /* Compress a packet */
++ int (*compress) (void *state, unsigned char *rptr,
++ unsigned char *obuf, int isize, int osize);
++
++ /* Return compression statistics */
++ void (*comp_stat) (void *state, struct compstat *stats);
++
++ /* Allocate space for a decompressor (receive side) */
++ void *(*decomp_alloc) (unsigned char *options, int opt_len);
++
++ /* Free space used by a decompressor */
++ void (*decomp_free) (void *state);
++
++ /* Initialize a decompressor */
++ int (*decomp_init) (void *state, unsigned char *options,
++ int opt_len, int unit, int opthdr, int mru,
++ int debug);
++
++ /* Reset a decompressor */
++ void (*decomp_reset) (void *state);
++
++ /* Decompress a packet. */
++ int (*decompress) (void *state, unsigned char *ibuf, int isize,
++ unsigned char *obuf, int osize);
++
++ /* Update state for an incompressible packet received */
++ void (*incomp) (void *state, unsigned char *ibuf, int icnt);
++
++ /* Return decompression statistics */
++ void (*decomp_stat) (void *state, struct compstat *stats);
++};
++
++/*
++ * The return value from decompress routine is the length of the
++ * decompressed packet if successful, otherwise DECOMP_ERROR
++ * or DECOMP_FATALERROR if an error occurred.
++ *
++ * We need to make this distinction so that we can disable certain
++ * useful functionality, namely sending a CCP reset-request as a result
++ * of an error detected after decompression. This is to avoid infringing
++ * a patent held by Motorola.
++ * Don't you just lurve software patents.
++ */
++
++#define DECOMP_ERROR -1 /* error detected before decomp. */
++#define DECOMP_FATALERROR -2 /* error detected after decomp. */
++
++/*
++ * CCP codes.
++ */
++
++#define CCP_CONFREQ 1
++#define CCP_CONFACK 2
++#define CCP_TERMREQ 5
++#define CCP_TERMACK 6
++#define CCP_RESETREQ 14
++#define CCP_RESETACK 15
++
++/*
++ * Max # bytes for a CCP option
++ */
++
++#define CCP_MAX_OPTION_LENGTH 32
++
++/*
++ * Parts of a CCP packet.
++ */
++
++#define CCP_CODE(dp) ((dp)[0])
++#define CCP_ID(dp) ((dp)[1])
++#define CCP_LENGTH(dp) (((dp)[2] &lt;&lt; 8) + (dp)[3])
++#define CCP_HDRLEN 4
++
++#define CCP_OPT_CODE(dp) ((dp)[0])
++#define CCP_OPT_LENGTH(dp) ((dp)[1])
++#define CCP_OPT_MINLEN 2
++
++/*
++ * Definitions for BSD-Compress.
++ */
++
++#define CI_BSD_COMPRESS 21 /* config. option for BSD-Compress */
++#define CILEN_BSD_COMPRESS 3 /* length of config. option */
++
++/* Macros for handling the 3rd byte of the BSD-Compress config option. */
++#define BSD_NBITS(x) ((x) &amp; 0x1F) /* number of bits requested */
++#define BSD_VERSION(x) ((x) &gt;&gt; 5) /* version of option format */
++#define BSD_CURRENT_VERSION 1 /* current version number */
++#define BSD_MAKE_OPT(v, n) (((v) &lt;&lt; 5) | (n))
++
++#define BSD_MIN_BITS 9 /* smallest code size supported */
++#define BSD_MAX_BITS 15 /* largest code size supported */
++
++/*
++ * Definitions for Deflate.
++ */
++
++#define CI_DEFLATE 26 /* config option for Deflate */
++#define CI_DEFLATE_DRAFT 24 /* value used in original draft RFC */
++#define CILEN_DEFLATE 4 /* length of its config option */
++
++#define DEFLATE_MIN_SIZE 8
++#define DEFLATE_MAX_SIZE 15
++#define DEFLATE_METHOD_VAL 8
++#define DEFLATE_SIZE(x) (((x) &gt;&gt; 4) + DEFLATE_MIN_SIZE)
++#define DEFLATE_METHOD(x) ((x) &amp; 0x0F)
++#define DEFLATE_MAKE_OPT(w) ((((w) - DEFLATE_MIN_SIZE) &lt;&lt; 4) \
++ + DEFLATE_METHOD_VAL)
++#define DEFLATE_CHK_SEQUENCE 0
++
++/*
++ * Definitions for other, as yet unsupported, compression methods.
++ */
++
++#define CI_PREDICTOR_1 1 /* config option for Predictor-1 */
++#define CILEN_PREDICTOR_1 2 /* length of its config option */
++#define CI_PREDICTOR_2 2 /* config option for Predictor-2 */
++#define CILEN_PREDICTOR_2 2 /* length of its config option */
++
++#ifdef __KERNEL__
++extern int ppp_register_compressor(struct compressor *);
++extern void ppp_unregister_compressor(struct compressor *);
++#endif /* __KERNEL__ */
++
++#endif /* _NET_PPP_COMP_H */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/include/linux/ppp-comp.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/include/linux/ppp_defs.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/include/linux/ppp_defs.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/include/linux/ppp_defs.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,185 @@
++/* $Id: ppp_defs.h 195720 2001-06-11 11:44:34Z gc $ */
++
++/*
++ * ppp_defs.h - PPP definitions.
++ *
++ * Copyright (c) 1994 The Australian National University.
++ * All rights reserved.
++ *
++ * Permission to use, copy, modify, and distribute this software and its
++ * documentation is hereby granted, provided that the above copyright
++ * notice appears in all copies. This software is provided without any
++ * warranty, express or implied. The Australian National University
++ * makes no representations about the suitability of this software for
++ * any purpose.
++ *
++ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
++ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
++ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
++ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
++ * OF SUCH DAMAGE.
++ *
++ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
++ * ON AN &quot;AS IS&quot; BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
++ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
++ * OR MODIFICATIONS.
++ */
++
++/*
++ * ==FILEVERSION 20000114==
++ *
++ * NOTE TO MAINTAINERS:
++ * If you modify this file at all, please set the above date.
++ * ppp_defs.h is shipped with a PPP distribution as well as with the kernel;
++ * if everyone increases the FILEVERSION number above, then scripts
++ * can do the right thing when deciding whether to install a new ppp_defs.h
++ * file. Don't change the format of that line otherwise, so the
++ * installation script can recognize it.
++ */
++
++#ifndef _PPP_DEFS_H_
++#define _PPP_DEFS_H_
++
++/*
++ * The basic PPP frame.
++ */
++#define PPP_HDRLEN 4 /* octets for standard ppp header */
++#define PPP_FCSLEN 2 /* octets for FCS */
++#define PPP_MRU 1500 /* default MRU = max length of info field */
++
++#define PPP_ADDRESS(p) (((__u8 *)(p))[0])
++#define PPP_CONTROL(p) (((__u8 *)(p))[1])
++#define PPP_PROTOCOL(p) ((((__u8 *)(p))[2] &lt;&lt; 8) + ((__u8 *)(p))[3])
++
++/*
++ * Significant octet values.
++ */
++#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */
++#define PPP_UI 0x03 /* Unnumbered Information */
++#define PPP_FLAG 0x7e /* Flag Sequence */
++#define PPP_ESCAPE 0x7d /* Asynchronous Control Escape */
++#define PPP_TRANS 0x20 /* Asynchronous transparency modifier */
++
++/*
++ * Protocol field values.
++ */
++#define PPP_IP 0x21 /* Internet Protocol */
++#define PPP_AT 0x29 /* AppleTalk Protocol */
++#define PPP_IPX 0x2b /* IPX protocol */
++#define PPP_VJC_COMP 0x2d /* VJ compressed TCP */
++#define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */
++#define PPP_MP 0x3d /* Multilink protocol */
++#define PPP_IPV6 0x57 /* Internet Protocol Version 6 */
++#define PPP_COMPFRAG 0xfb /* fragment compressed below bundle */
++#define PPP_COMP 0xfd /* compressed packet */
++#define PPP_IPCP 0x8021 /* IP Control Protocol */
++#define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */
++#define PPP_IPXCP 0x802b /* IPX Control Protocol */
++#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */
++#define PPP_CCPFRAG 0x80fb /* CCP at link level (below MP bundle) */
++#define PPP_CCP 0x80fd /* Compression Control Protocol */
++#define PPP_LCP 0xc021 /* Link Control Protocol */
++#define PPP_PAP 0xc023 /* Password Authentication Protocol */
++#define PPP_LQR 0xc025 /* Link Quality Report protocol */
++#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */
++#define PPP_CBCP 0xc029 /* Callback Control Protocol */
++
++/*
++ * Values for FCS calculations.
++ */
++
++#define PPP_INITFCS 0xffff /* Initial FCS value */
++#define PPP_GOODFCS 0xf0b8 /* Good final FCS value */
++#define PPP_FCS(fcs, c) (((fcs) &gt;&gt; 8) ^ fcstab[((fcs) ^ (c)) &amp; 0xff])
++
++/*
++ * Extended asyncmap - allows any character to be escaped.
++ */
++
++typedef __u32 ext_accm[8];
++
++/*
++ * What to do with network protocol (NP) packets.
++ */
++enum NPmode {
++ NPMODE_PASS, /* pass the packet through */
++ NPMODE_DROP, /* silently drop the packet */
++ NPMODE_ERROR, /* return an error */
++ NPMODE_QUEUE /* save it up for later. */
++};
++
++/*
++ * Statistics for LQRP and pppstats
++ */
++struct pppstat {
++ __u32 ppp_discards; /* # frames discarded */
++
++ __u32 ppp_ibytes; /* bytes received */
++ __u32 ppp_ioctects; /* bytes received not in error */
++ __u32 ppp_ipackets; /* packets received */
++ __u32 ppp_ierrors; /* receive errors */
++ __u32 ppp_ilqrs; /* # LQR frames received */
++
++ __u32 ppp_obytes; /* raw bytes sent */
++ __u32 ppp_ooctects; /* frame bytes sent */
++ __u32 ppp_opackets; /* packets sent */
++ __u32 ppp_oerrors; /* transmit errors */
++ __u32 ppp_olqrs; /* # LQR frames sent */
++};
++
++struct vjstat {
++ __u32 vjs_packets; /* outbound packets */
++ __u32 vjs_compressed; /* outbound compressed packets */
++ __u32 vjs_searches; /* searches for connection state */
++ __u32 vjs_misses; /* times couldn't find conn. state */
++ __u32 vjs_uncompressedin; /* inbound uncompressed packets */
++ __u32 vjs_compressedin; /* inbound compressed packets */
++ __u32 vjs_errorin; /* inbound unknown type packets */
++ __u32 vjs_tossed; /* inbound packets tossed because of error */
++};
++
++struct compstat {
++ __u32 unc_bytes; /* total uncompressed bytes */
++ __u32 unc_packets; /* total uncompressed packets */
++ __u32 comp_bytes; /* compressed bytes */
++ __u32 comp_packets; /* compressed packets */
++ __u32 inc_bytes; /* incompressible bytes */
++ __u32 inc_packets; /* incompressible packets */
++
++ /* the compression ratio is defined as in_count / bytes_out */
++ __u32 in_count; /* Bytes received */
++ __u32 bytes_out; /* Bytes transmitted */
++
++ double ratio; /* not computed in kernel. */
++};
++
++struct ppp_stats {
++ struct pppstat p; /* basic PPP statistics */
++ struct vjstat vj; /* VJ header compression statistics */
++};
++
++struct ppp_comp_stats {
++ struct compstat c; /* packet compression statistics */
++ struct compstat d; /* packet decompression statistics */
++};
++
++/*
++ * The following structure records the time in seconds since
++ * the last NP packet was sent or received.
++ */
++struct ppp_idle {
++ time_t xmit_idle; /* time since last NP packet sent */
++ time_t recv_idle; /* time since last NP packet received */
++};
++
++#ifndef __P
++#ifdef __STDC__
++#define __P(x) x
++#else
++#define __P(x) ()
++#endif
++#endif
++
++#endif /* _PPP_DEFS_H_ */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/include/linux/ppp_defs.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/include/net/if_ppp.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/include/net/if_ppp.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/include/net/if_ppp.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,133 @@
++/* $Id: if_ppp.h 195720 2001-06-11 11:44:34Z gc $ */
++
++/*
++ * if_ppp.h - Point-to-Point Protocol definitions.
++ *
++ * Copyright (c) 1989 Carnegie Mellon University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by Carnegie Mellon University. The name of the
++ * University may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ */
++
++#ifndef _IF_PPP_H_
++#define _IF_PPP_H_
++
++/*
++ * Bit definitions for flags.
++ */
++#define SC_COMP_PROT 0x00000001 /* protocol compression (output) */
++#define SC_COMP_AC 0x00000002 /* header compression (output) */
++#define SC_COMP_TCP 0x00000004 /* TCP (VJ) compression (output) */
++#define SC_NO_TCP_CCID 0x00000008 /* disable VJ connection-id comp. */
++#define SC_REJ_COMP_AC 0x00000010 /* reject adrs/ctrl comp. on input */
++#define SC_REJ_COMP_TCP 0x00000020 /* reject TCP (VJ) comp. on input */
++#define SC_CCP_OPEN 0x00000040 /* Look at CCP packets */
++#define SC_CCP_UP 0x00000080 /* May send/recv compressed packets */
++#define SC_DEBUG 0x00010000 /* enable debug messages */
++#define SC_LOG_INPKT 0x00020000 /* log contents of good pkts recvd */
++#define SC_LOG_OUTPKT 0x00040000 /* log contents of pkts sent */
++#define SC_LOG_RAWIN 0x00080000 /* log all chars received */
++#define SC_LOG_FLUSH 0x00100000 /* log all chars flushed */
++#define SC_RCV_B7_0 0x01000000 /* have rcvd char with bit 7 = 0 */
++#define SC_RCV_B7_1 0x02000000 /* have rcvd char with bit 7 = 1 */
++#define SC_RCV_EVNP 0x04000000 /* have rcvd char with even parity */
++#define SC_RCV_ODDP 0x08000000 /* have rcvd char with odd parity */
++#define SC_SYNC 0x00200000 /* use synchronous HDLC framing */
++#define SC_MASK 0x0fff00ff /* bits that user can change */
++
++/*
++ * State bits in sc_flags, not changeable by user.
++ */
++#define SC_TIMEOUT 0x00000400 /* timeout is currently pending */
++#define SC_VJ_RESET 0x00000800 /* need to reset VJ decomp */
++#define SC_COMP_RUN 0x00001000 /* compressor has been inited */
++#define SC_DECOMP_RUN 0x00002000 /* decompressor has been inited */
++#define SC_DC_ERROR 0x00004000 /* non-fatal decomp error detected */
++#define SC_DC_FERROR 0x00008000 /* fatal decomp error detected */
++#define SC_TBUSY 0x10000000 /* xmitter doesn't need a packet yet */
++#define SC_PKTLOST 0x20000000 /* have lost or dropped a packet */
++#define SC_FLUSH 0x40000000 /* flush input until next PPP_FLAG */
++#define SC_ESCAPED 0x80000000 /* saw a PPP_ESCAPE */
++
++/*
++ * Ioctl definitions.
++ */
++
++struct npioctl {
++ int protocol; /* PPP procotol, e.g. PPP_IP */
++ enum NPmode mode;
++};
++
++/* Structure describing a CCP configuration option, for PPPIOCSCOMPRESS */
++struct ppp_option_data {
++ u_char *ptr;
++ u_int length;
++ int transmit;
++};
++
++struct ifpppstatsreq {
++ char ifr_name[IFNAMSIZ];
++ struct ppp_stats stats;
++};
++
++struct ifpppcstatsreq {
++ char ifr_name[IFNAMSIZ];
++ struct ppp_comp_stats stats;
++};
++
++/*
++ * Ioctl definitions.
++ */
++
++#define PPPIOCGFLAGS _IOR('t', 90, int) /* get configuration flags */
++#define PPPIOCSFLAGS _IOW('t', 89, int) /* set configuration flags */
++#define PPPIOCGASYNCMAP _IOR('t', 88, int) /* get async map */
++#define PPPIOCSASYNCMAP _IOW('t', 87, int) /* set async map */
++#define PPPIOCGUNIT _IOR('t', 86, int) /* get ppp unit number */
++#define PPPIOCGRASYNCMAP _IOR('t', 85, int) /* get receive async map */
++#define PPPIOCSRASYNCMAP _IOW('t', 84, int) /* set receive async map */
++#define PPPIOCGMRU _IOR('t', 83, int) /* get max receive unit */
++#define PPPIOCSMRU _IOW('t', 82, int) /* set max receive unit */
++#define PPPIOCSMAXCID _IOW('t', 81, int) /* set VJ max slot ID */
++#define PPPIOCGXASYNCMAP _IOR('t', 80, ext_accm) /* get extended ACCM */
++#define PPPIOCSXASYNCMAP _IOW('t', 79, ext_accm) /* set extended ACCM */
++#define PPPIOCXFERUNIT _IO('t', 78) /* transfer PPP unit */
++#define PPPIOCSCOMPRESS _IOW('t', 77, struct ppp_option_data)
++#define PPPIOCGNPMODE _IOWR('t', 76, struct npioctl) /* get NP mode */
++#define PPPIOCSNPMODE _IOW('t', 75, struct npioctl) /* set NP mode */
++#define PPPIOCGIDLE _IOR('t', 74, struct ppp_idle) /* get idle time */
++#ifdef PPP_FILTER
++#define PPPIOCSPASS _IOW('t', 71, struct bpf_program) /* set pass filter */
++#define PPPIOCSACTIVE _IOW('t', 70, struct bpf_program) /* set active filt */
++#endif /* PPP_FILTER */
++
++/* PPPIOC[GS]MTU are alternatives to SIOC[GS]IFMTU, used under Ultrix */
++#define PPPIOCGMTU _IOR('t', 73, int) /* get interface MTU */
++#define PPPIOCSMTU _IOW('t', 72, int) /* set interface MTU */
++
++/*
++ * These two are interface ioctls so that pppstats can do them on
++ * a socket without having to open the serial device.
++ */
++#define SIOCGPPPSTATS _IOWR('i', 123, struct ifpppstatsreq)
++#define SIOCGPPPCSTATS _IOWR('i', 122, struct ifpppcstatsreq)
++
++#if !defined(ifr_mtu)
++#define ifr_mtu ifr_ifru.ifru_metric
++#endif
++
++#if (defined(_KERNEL) || defined(KERNEL)) &amp;&amp; !defined(NeXT)
++void pppattach __P((void));
++void pppintr __P((void));
++#endif
++#endif /* _IF_PPP_H_ */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/include/net/if_ppp.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/include/net/ppp-comp.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/include/net/ppp-comp.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/include/net/ppp-comp.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,165 @@
++/*
++ * ppp-comp.h - Definitions for doing PPP packet compression.
++ *
++ * Copyright (c) 1994 The Australian National University.
++ * All rights reserved.
++ *
++ * Permission to use, copy, modify, and distribute this software and its
++ * documentation is hereby granted, provided that the above copyright
++ * notice appears in all copies. This software is provided without any
++ * warranty, express or implied. The Australian National University
++ * makes no representations about the suitability of this software for
++ * any purpose.
++ *
++ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
++ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
++ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
++ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
++ * OF SUCH DAMAGE.
++ *
++ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
++ * ON AN &quot;AS IS&quot; BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
++ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
++ * OR MODIFICATIONS.
++ *
++ * $Id: ppp-comp.h 195720 2001-06-11 11:44:34Z gc $
++ */
++
++#ifndef _NET_PPP_COMP_H
++#define _NET_PPP_COMP_H
++
++/*
++ * The following symbols control whether we include code for
++ * various compression methods.
++ */
++#ifndef DO_BSD_COMPRESS
++#define DO_BSD_COMPRESS 1 /* by default, include BSD-Compress */
++#endif
++#ifndef DO_DEFLATE
++#define DO_DEFLATE 1 /* by default, include Deflate */
++#endif
++#define DO_PREDICTOR_1 0
++#define DO_PREDICTOR_2 0
++
++/*
++ * Structure giving methods for compression/decompression.
++ */
++#ifdef PACKETPTR
++struct compressor {
++ int compress_proto; /* CCP compression protocol number */
++
++ /* Allocate space for a compressor (transmit side) */
++ void *(*comp_alloc) __P((u_char *options, int opt_len));
++ /* Free space used by a compressor */
++ void (*comp_free) __P((void *state));
++ /* Initialize a compressor */
++ int (*comp_init) __P((void *state, u_char *options, int opt_len,
++ int unit, int hdrlen, int debug));
++ /* Reset a compressor */
++ void (*comp_reset) __P((void *state));
++ /* Compress a packet */
++ int (*compress) __P((void *state, PACKETPTR *mret,
++ PACKETPTR mp, int orig_len, int max_len));
++ /* Return compression statistics */
++ void (*comp_stat) __P((void *state, struct compstat *stats));
++
++ /* Allocate space for a decompressor (receive side) */
++ void *(*decomp_alloc) __P((u_char *options, int opt_len));
++ /* Free space used by a decompressor */
++ void (*decomp_free) __P((void *state));
++ /* Initialize a decompressor */
++ int (*decomp_init) __P((void *state, u_char *options, int opt_len,
++ int unit, int hdrlen, int mru, int debug));
++ /* Reset a decompressor */
++ void (*decomp_reset) __P((void *state));
++ /* Decompress a packet. */
++ int (*decompress) __P((void *state, PACKETPTR mp,
++ PACKETPTR *dmpp));
++ /* Update state for an incompressible packet received */
++ void (*incomp) __P((void *state, PACKETPTR mp));
++ /* Return decompression statistics */
++ void (*decomp_stat) __P((void *state, struct compstat *stats));
++};
++#endif /* PACKETPTR */
++
++/*
++ * Return values for decompress routine.
++ * We need to make these distinctions so that we can disable certain
++ * useful functionality, namely sending a CCP reset-request as a result
++ * of an error detected after decompression. This is to avoid infringing
++ * a patent held by Motorola.
++ * Don't you just lurve software patents.
++ */
++#define DECOMP_OK 0 /* everything went OK */
++#define DECOMP_ERROR 1 /* error detected before decomp. */
++#define DECOMP_FATALERROR 2 /* error detected after decomp. */
++
++/*
++ * CCP codes.
++ */
++#define CCP_CONFREQ 1
++#define CCP_CONFACK 2
++#define CCP_TERMREQ 5
++#define CCP_TERMACK 6
++#define CCP_RESETREQ 14
++#define CCP_RESETACK 15
++
++/*
++ * Max # bytes for a CCP option
++ */
++#define CCP_MAX_OPTION_LENGTH 32
++
++/*
++ * Parts of a CCP packet.
++ */
++#define CCP_CODE(dp) ((dp)[0])
++#define CCP_ID(dp) ((dp)[1])
++#define CCP_LENGTH(dp) (((dp)[2] &lt;&lt; 8) + (dp)[3])
++#define CCP_HDRLEN 4
++
++#define CCP_OPT_CODE(dp) ((dp)[0])
++#define CCP_OPT_LENGTH(dp) ((dp)[1])
++#define CCP_OPT_MINLEN 2
++
++/*
++ * Definitions for BSD-Compress.
++ */
++#define CI_BSD_COMPRESS 21 /* config. option for BSD-Compress */
++#define CILEN_BSD_COMPRESS 3 /* length of config. option */
++
++/* Macros for handling the 3rd byte of the BSD-Compress config option. */
++#define BSD_NBITS(x) ((x) &amp; 0x1F) /* number of bits requested */
++#define BSD_VERSION(x) ((x) &gt;&gt; 5) /* version of option format */
++#define BSD_CURRENT_VERSION 1 /* current version number */
++#define BSD_MAKE_OPT(v, n) (((v) &lt;&lt; 5) | (n))
++
++#define BSD_MIN_BITS 9 /* smallest code size supported */
++#define BSD_MAX_BITS 15 /* largest code size supported */
++
++/*
++ * Definitions for Deflate.
++ */
++#define CI_DEFLATE 26 /* config option for Deflate */
++#define CI_DEFLATE_DRAFT 24 /* value used in original draft RFC */
++#define CILEN_DEFLATE 4 /* length of its config option */
++
++#define DEFLATE_MIN_SIZE 8
++#define DEFLATE_MAX_SIZE 15
++#define DEFLATE_METHOD_VAL 8
++#define DEFLATE_SIZE(x) (((x) &gt;&gt; 4) + DEFLATE_MIN_SIZE)
++#define DEFLATE_METHOD(x) ((x) &amp; 0x0F)
++#define DEFLATE_MAKE_OPT(w) ((((w) - DEFLATE_MIN_SIZE) &lt;&lt; 4) \
++ + DEFLATE_METHOD_VAL)
++#define DEFLATE_CHK_SEQUENCE 0
++
++/*
++ * Definitions for other, as yet unsupported, compression methods.
++ */
++#define CI_PREDICTOR_1 1 /* config option for Predictor-1 */
++#define CILEN_PREDICTOR_1 2 /* length of its config option */
++#define CI_PREDICTOR_2 2 /* config option for Predictor-2 */
++#define CILEN_PREDICTOR_2 2 /* length of its config option */
++
++#endif /* _NET_PPP_COMP_H */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/include/net/ppp-comp.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/include/net/ppp_defs.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/include/net/ppp_defs.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/include/net/ppp_defs.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,184 @@
++/* $Id: ppp_defs.h 203043 2003-06-04 18:31:57Z gbeauchesne $ */
++
++/*
++ * ppp_defs.h - PPP definitions.
++ *
++ * Copyright (c) 1994 The Australian National University.
++ * All rights reserved.
++ *
++ * Permission to use, copy, modify, and distribute this software and its
++ * documentation is hereby granted, provided that the above copyright
++ * notice appears in all copies. This software is provided without any
++ * warranty, express or implied. The Australian National University
++ * makes no representations about the suitability of this software for
++ * any purpose.
++ *
++ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
++ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
++ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
++ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
++ * OF SUCH DAMAGE.
++ *
++ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
++ * ON AN &quot;AS IS&quot; BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
++ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
++ * OR MODIFICATIONS.
++ */
++
++#ifndef _PPP_DEFS_H_
++#define _PPP_DEFS_H_
++
++/*
++ * The basic PPP frame.
++ */
++#define PPP_HDRLEN 4 /* octets for standard ppp header */
++#define PPP_FCSLEN 2 /* octets for FCS */
++
++/*
++ * Packet sizes
++ *
++ * Note - lcp shouldn't be allowed to negotiate stuff outside these
++ * limits. See lcp.h in the pppd directory.
++ * (XXX - these constants should simply be shared by lcp.c instead
++ * of living in lcp.h)
++ */
++#define PPP_MTU 1500 /* Default MTU (size of Info field) */
++#define PPP_MAXMTU 65535 - (PPP_HDRLEN + PPP_FCSLEN)
++#define PPP_MINMTU 64
++#define PPP_MRU 1500 /* default MRU = max length of info field */
++#define PPP_MAXMRU 65000 /* Largest MRU we allow */
++#define PPP_MINMRU 128
++
++#define PPP_ADDRESS(p) (((u_char *)(p))[0])
++#define PPP_CONTROL(p) (((u_char *)(p))[1])
++#define PPP_PROTOCOL(p) ((((u_char *)(p))[2] &lt;&lt; 8) + ((u_char *)(p))[3])
++
++/*
++ * Significant octet values.
++ */
++#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */
++#define PPP_UI 0x03 /* Unnumbered Information */
++#define PPP_FLAG 0x7e /* Flag Sequence */
++#define PPP_ESCAPE 0x7d /* Asynchronous Control Escape */
++#define PPP_TRANS 0x20 /* Asynchronous transparency modifier */
++
++/*
++ * Protocol field values.
++ */
++#define PPP_IP 0x21 /* Internet Protocol */
++#define PPP_AT 0x29 /* AppleTalk Protocol */
++#define PPP_IPX 0x2b /* IPX protocol */
++#define PPP_VJC_COMP 0x2d /* VJ compressed TCP */
++#define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */
++#define PPP_IPV6 0x57 /* Internet Protocol Version 6 */
++#define PPP_COMP 0xfd /* compressed packet */
++#define PPP_IPCP 0x8021 /* IP Control Protocol */
++#define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */
++#define PPP_IPXCP 0x802b /* IPX Control Protocol */
++#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */
++#define PPP_CCP 0x80fd /* Compression Control Protocol */
++#define PPP_LCP 0xc021 /* Link Control Protocol */
++#define PPP_PAP 0xc023 /* Password Authentication Protocol */
++#define PPP_LQR 0xc025 /* Link Quality Report protocol */
++#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */
++#define PPP_CBCP 0xc029 /* Callback Control Protocol */
++
++/*
++ * Values for FCS calculations.
++ */
++#define PPP_INITFCS 0xffff /* Initial FCS value */
++#define PPP_GOODFCS 0xf0b8 /* Good final FCS value */
++#define PPP_FCS(fcs, c) (((fcs) &gt;&gt; 8) ^ fcstab[((fcs) ^ (c)) &amp; 0xff])
++
++/*
++ * A 32-bit unsigned integral type.
++ */
++
++#if !defined(__BIT_TYPES_DEFINED__) &amp;&amp; !defined(_BITYPES) \
++ &amp;&amp; !defined(__FreeBSD__) &amp;&amp; (NS_TARGET &lt; 40) &amp;&amp; !defined(__dietlibc__)
++#ifdef UINT32_T
++typedef UINT32_T u_int32_t;
++#else
++typedef unsigned int u_int32_t;
++typedef unsigned short u_int16_t;
++#endif
++#endif
++
++/*
++ * Extended asyncmap - allows any character to be escaped.
++ */
++typedef u_int32_t ext_accm[8];
++
++/*
++ * What to do with network protocol (NP) packets.
++ */
++enum NPmode {
++ NPMODE_PASS, /* pass the packet through */
++ NPMODE_DROP, /* silently drop the packet */
++ NPMODE_ERROR, /* return an error */
++ NPMODE_QUEUE /* save it up for later. */
++};
++
++/*
++ * Statistics.
++ */
++struct pppstat {
++ unsigned int ppp_ibytes; /* bytes received */
++ unsigned int ppp_ipackets; /* packets received */
++ unsigned int ppp_ierrors; /* receive errors */
++ unsigned int ppp_obytes; /* bytes sent */
++ unsigned int ppp_opackets; /* packets sent */
++ unsigned int ppp_oerrors; /* transmit errors */
++};
++
++struct vjstat {
++ unsigned int vjs_packets; /* outbound packets */
++ unsigned int vjs_compressed; /* outbound compressed packets */
++ unsigned int vjs_searches; /* searches for connection state */
++ unsigned int vjs_misses; /* times couldn't find conn. state */
++ unsigned int vjs_uncompressedin; /* inbound uncompressed packets */
++ unsigned int vjs_compressedin; /* inbound compressed packets */
++ unsigned int vjs_errorin; /* inbound unknown type packets */
++ unsigned int vjs_tossed; /* inbound packets tossed because of error */
++};
++
++struct ppp_stats {
++ struct pppstat p; /* basic PPP statistics */
++ struct vjstat vj; /* VJ header compression statistics */
++};
++
++struct compstat {
++ unsigned int unc_bytes; /* total uncompressed bytes */
++ unsigned int unc_packets; /* total uncompressed packets */
++ unsigned int comp_bytes; /* compressed bytes */
++ unsigned int comp_packets; /* compressed packets */
++ unsigned int inc_bytes; /* incompressible bytes */
++ unsigned int inc_packets; /* incompressible packets */
++ unsigned int ratio; /* recent compression ratio &lt;&lt; 8 */
++};
++
++struct ppp_comp_stats {
++ struct compstat c; /* packet compression statistics */
++ struct compstat d; /* packet decompression statistics */
++};
++
++/*
++ * The following structure records the time in seconds since
++ * the last NP packet was sent or received.
++ */
++struct ppp_idle {
++ time_t xmit_idle; /* time since last NP packet sent */
++ time_t recv_idle; /* time since last NP packet received */
++};
++
++#ifndef __P
++#ifdef __STDC__
++#define __P(x) x
++#else
++#define __P(x) ()
++#endif
++#endif
++
++#endif /* _PPP_DEFS_H_ */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/include/net/ppp_defs.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/include/net/pppio.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/include/net/pppio.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/include/net/pppio.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,99 @@
++/*
++ * pppio.h - ioctl and other misc. definitions for STREAMS modules.
++ *
++ * Copyright (c) 1994 The Australian National University.
++ * All rights reserved.
++ *
++ * Permission to use, copy, modify, and distribute this software and its
++ * documentation is hereby granted, provided that the above copyright
++ * notice appears in all copies. This software is provided without any
++ * warranty, express or implied. The Australian National University
++ * makes no representations about the suitability of this software for
++ * any purpose.
++ *
++ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
++ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
++ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
++ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
++ * OF SUCH DAMAGE.
++ *
++ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
++ * ON AN &quot;AS IS&quot; BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
++ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
++ * OR MODIFICATIONS.
++ *
++ * $Id: pppio.h 195720 2001-06-11 11:44:34Z gc $
++ */
++
++#define _PPPIO(n) (('p' &lt;&lt; 8) + (n))
++
++#define PPPIO_NEWPPA _PPPIO(130) /* allocate a new PPP unit */
++#define PPPIO_GETSTAT _PPPIO(131) /* get PPP statistics */
++#define PPPIO_GETCSTAT _PPPIO(132) /* get PPP compression stats */
++#define PPPIO_MTU _PPPIO(133) /* set max transmission unit */
++#define PPPIO_MRU _PPPIO(134) /* set max receive unit */
++#define PPPIO_CFLAGS _PPPIO(135) /* set/clear/get compression flags */
++#define PPPIO_XCOMP _PPPIO(136) /* alloc transmit compressor */
++#define PPPIO_RCOMP _PPPIO(137) /* alloc receive decompressor */
++#define PPPIO_XACCM _PPPIO(138) /* set transmit asyncmap */
++#define PPPIO_RACCM _PPPIO(139) /* set receive asyncmap */
++#define PPPIO_VJINIT _PPPIO(140) /* initialize VJ comp/decomp */
++#define PPPIO_ATTACH _PPPIO(141) /* attach to a ppa (without putmsg) */
++#define PPPIO_LASTMOD _PPPIO(142) /* mark last ppp module */
++#define PPPIO_GCLEAN _PPPIO(143) /* get 8-bit-clean flags */
++#define PPPIO_DEBUG _PPPIO(144) /* request debug information */
++#define PPPIO_BIND _PPPIO(145) /* bind to SAP */
++#define PPPIO_NPMODE _PPPIO(146) /* set mode for handling data pkts */
++#define PPPIO_GIDLE _PPPIO(147) /* get time since last data pkt */
++#define PPPIO_PASSFILT _PPPIO(148) /* set filter for packets to pass */
++#define PPPIO_ACTIVEFILT _PPPIO(149) /* set filter for &quot;link active&quot; pkts */
++
++/*
++ * Values for PPPIO_CFLAGS
++ */
++#define COMP_AC 0x1 /* compress address/control */
++#define DECOMP_AC 0x2 /* decompress address/control */
++#define COMP_PROT 0x4 /* compress PPP protocol */
++#define DECOMP_PROT 0x8 /* decompress PPP protocol */
++
++#define COMP_VJC 0x10 /* compress TCP/IP headers */
++#define COMP_VJCCID 0x20 /* compress connection ID as well */
++#define DECOMP_VJC 0x40 /* decompress TCP/IP headers */
++#define DECOMP_VJCCID 0x80 /* accept compressed connection ID */
++
++#define CCP_ISOPEN 0x100 /* look at CCP packets */
++#define CCP_ISUP 0x200 /* do packet comp/decomp */
++#define CCP_ERROR 0x400 /* (status) error in packet decomp */
++#define CCP_FATALERROR 0x800 /* (status) fatal error ditto */
++#define CCP_COMP_RUN 0x1000 /* (status) seen CCP ack sent */
++#define CCP_DECOMP_RUN 0x2000 /* (status) seen CCP ack rcvd */
++
++/*
++ * Values for 8-bit-clean flags.
++ */
++#define RCV_B7_0 1 /* have rcvd char with bit 7 = 0 */
++#define RCV_B7_1 2 /* have rcvd char with bit 7 = 1 */
++#define RCV_EVNP 4 /* have rcvd char with even parity */
++#define RCV_ODDP 8 /* have rcvd char with odd parity */
++
++/*
++ * Values for the first byte of M_CTL messages passed between
++ * PPP modules.
++ */
++#define PPPCTL_OERROR 0xe0 /* output error [up] */
++#define PPPCTL_IERROR 0xe1 /* input error (e.g. FCS) [up] */
++#define PPPCTL_MTU 0xe2 /* set MTU [down] */
++#define PPPCTL_MRU 0xe3 /* set MRU [down] */
++#define PPPCTL_UNIT 0xe4 /* note PPP unit number [down] */
++
++/*
++ * Values for the integer argument to PPPIO_DEBUG.
++ */
++#define PPPDBG_DUMP 0x10000 /* print out debug info now */
++#define PPPDBG_LOG 0x100 /* log various things */
++#define PPPDBG_DRIVER 0 /* identifies ppp driver as target */
++#define PPPDBG_IF 1 /* identifies ppp network i/f target */
++#define PPPDBG_COMP 2 /* identifies ppp compression target */
++#define PPPDBG_AHDLC 3 /* identifies ppp async hdlc target */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/include/net/pppio.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/include/net/slcompress.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/include/net/slcompress.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/include/net/slcompress.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,148 @@
++/*
++ * Definitions for tcp compression routines.
++ *
++ * $Id: slcompress.h 195720 2001-06-11 11:44:34Z gc $
++ *
++ * Copyright (c) 1989 Regents of the University of California.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by the University of California, Berkeley. The name of the
++ * University may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * Van Jacobson (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">van at helios.ee.lbl.gov</A>), Dec 31, 1989:
++ * - Initial distribution.
++ */
++
++#ifndef _SLCOMPRESS_H_
++#define _SLCOMPRESS_H_
++
++#define MAX_STATES 16 /* must be &gt; 2 and &lt; 256 */
++#define MAX_HDR MLEN /* XXX 4bsd-ism: should really be 128 */
++
++/*
++ * Compressed packet format:
++ *
++ * The first octet contains the packet type (top 3 bits), TCP
++ * 'push' bit, and flags that indicate which of the 4 TCP sequence
++ * numbers have changed (bottom 5 bits). The next octet is a
++ * conversation number that associates a saved IP/TCP header with
++ * the compressed packet. The next two octets are the TCP checksum
++ * from the original datagram. The next 0 to 15 octets are
++ * sequence number changes, one change per bit set in the header
++ * (there may be no changes and there are two special cases where
++ * the receiver implicitly knows what changed -- see below).
++ *
++ * There are 5 numbers which can change (they are always inserted
++ * in the following order): TCP urgent pointer, window,
++ * acknowlegement, sequence number and IP ID. (The urgent pointer
++ * is different from the others in that its value is sent, not the
++ * change in value.) Since typical use of SLIP links is biased
++ * toward small packets (see comments on MTU/MSS below), changes
++ * use a variable length coding with one octet for numbers in the
++ * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the
++ * range 256 - 65535 or 0. (If the change in sequence number or
++ * ack is more than 65535, an uncompressed packet is sent.)
++ */
++
++/*
++ * Packet types (must not conflict with IP protocol version)
++ *
++ * The top nibble of the first octet is the packet type. There are
++ * three possible types: IP (not proto TCP or tcp with one of the
++ * control flags set); uncompressed TCP (a normal IP/TCP packet but
++ * with the 8-bit protocol field replaced by an 8-bit connection id --
++ * this type of packet syncs the sender &amp; receiver); and compressed
++ * TCP (described above).
++ *
++ * LSB of 4-bit field is TCP &quot;PUSH&quot; bit (a worthless anachronism) and
++ * is logically part of the 4-bit &quot;changes&quot; field that follows. Top
++ * three bits are actual packet type. For backward compatibility
++ * and in the interest of conserving bits, numbers are chosen so the
++ * IP protocol version number (4) which normally appears in this nibble
++ * means &quot;IP packet&quot;.
++ */
++
++/* packet types */
++#define TYPE_IP 0x40
++#define TYPE_UNCOMPRESSED_TCP 0x70
++#define TYPE_COMPRESSED_TCP 0x80
++#define TYPE_ERROR 0x00
++
++/* Bits in first octet of compressed packet */
++#define NEW_C 0x40 /* flag bits for what changed in a packet */
++#define NEW_I 0x20
++#define NEW_S 0x08
++#define NEW_A 0x04
++#define NEW_W 0x02
++#define NEW_U 0x01
++
++/* reserved, special-case values of above */
++#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */
++#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */
++#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U)
++
++#define TCP_PUSH_BIT 0x10
++
++
++/*
++ * &quot;state&quot; data for each active tcp conversation on the wire. This is
++ * basically a copy of the entire IP/TCP header from the last packet
++ * we saw from the conversation together with a small identifier
++ * the transmit &amp; receive ends of the line use to locate saved header.
++ */
++struct cstate {
++ struct cstate *cs_next; /* next most recently used cstate (xmit only) */
++ u_short cs_hlen; /* size of hdr (receive only) */
++ u_char cs_id; /* connection # associated with this state */
++ u_char cs_filler;
++ union {
++ char csu_hdr[MAX_HDR];
++ struct ip csu_ip; /* ip/tcp hdr from most recent packet */
++ } slcs_u;
++};
++#define cs_ip slcs_u.csu_ip
++#define cs_hdr slcs_u.csu_hdr
++
++/*
++ * all the state data for one serial line (we need one of these
++ * per line).
++ */
++struct slcompress {
++ struct cstate *last_cs; /* most recently used tstate */
++ u_char last_recv; /* last rcvd conn. id */
++ u_char last_xmit; /* last sent conn. id */
++ u_short flags;
++#ifndef SL_NO_STATS
++ int sls_packets; /* outbound packets */
++ int sls_compressed; /* outbound compressed packets */
++ int sls_searches; /* searches for connection state */
++ int sls_misses; /* times couldn't find conn. state */
++ int sls_uncompressedin; /* inbound uncompressed packets */
++ int sls_compressedin; /* inbound compressed packets */
++ int sls_errorin; /* inbound unknown type packets */
++ int sls_tossed; /* inbound packets tossed because of error */
++#endif
++ struct cstate tstate[MAX_STATES]; /* xmit connection states */
++ struct cstate rstate[MAX_STATES]; /* receive connection states */
++};
++/* flag values */
++#define SLF_TOSS 1 /* tossing rcvd frames because of input err */
++
++void sl_compress_init __P((struct slcompress *));
++void sl_compress_setup __P((struct slcompress *, int));
++u_int sl_compress_tcp __P((struct mbuf *,
++ struct ip *, struct slcompress *, int));
++int sl_uncompress_tcp __P((u_char **, int, u_int, struct slcompress *));
++int sl_uncompress_tcp_core __P((u_char *, int, int, u_int,
++ struct slcompress *, u_char **, u_int *));
++
++#endif /* _SLCOMPRESS_H_ */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/include/net/slcompress.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/include/net/vjcompress.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/include/net/vjcompress.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/include/net/vjcompress.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,144 @@
++/*
++ * Definitions for tcp compression routines.
++ *
++ * $Id: vjcompress.h 195720 2001-06-11 11:44:34Z gc $
++ *
++ * Copyright (c) 1989 Regents of the University of California.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by the University of California, Berkeley. The name of the
++ * University may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * Van Jacobson (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">van at helios.ee.lbl.gov</A>), Dec 31, 1989:
++ * - Initial distribution.
++ */
++
++#ifndef _VJCOMPRESS_H_
++#define _VJCOMPRESS_H_
++
++#define MAX_STATES 16 /* must be &gt; 2 and &lt; 256 */
++#define MAX_HDR 128
++
++/*
++ * Compressed packet format:
++ *
++ * The first octet contains the packet type (top 3 bits), TCP
++ * 'push' bit, and flags that indicate which of the 4 TCP sequence
++ * numbers have changed (bottom 5 bits). The next octet is a
++ * conversation number that associates a saved IP/TCP header with
++ * the compressed packet. The next two octets are the TCP checksum
++ * from the original datagram. The next 0 to 15 octets are
++ * sequence number changes, one change per bit set in the header
++ * (there may be no changes and there are two special cases where
++ * the receiver implicitly knows what changed -- see below).
++ *
++ * There are 5 numbers which can change (they are always inserted
++ * in the following order): TCP urgent pointer, window,
++ * acknowlegement, sequence number and IP ID. (The urgent pointer
++ * is different from the others in that its value is sent, not the
++ * change in value.) Since typical use of SLIP links is biased
++ * toward small packets (see comments on MTU/MSS below), changes
++ * use a variable length coding with one octet for numbers in the
++ * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the
++ * range 256 - 65535 or 0. (If the change in sequence number or
++ * ack is more than 65535, an uncompressed packet is sent.)
++ */
++
++/*
++ * Packet types (must not conflict with IP protocol version)
++ *
++ * The top nibble of the first octet is the packet type. There are
++ * three possible types: IP (not proto TCP or tcp with one of the
++ * control flags set); uncompressed TCP (a normal IP/TCP packet but
++ * with the 8-bit protocol field replaced by an 8-bit connection id --
++ * this type of packet syncs the sender &amp; receiver); and compressed
++ * TCP (described above).
++ *
++ * LSB of 4-bit field is TCP &quot;PUSH&quot; bit (a worthless anachronism) and
++ * is logically part of the 4-bit &quot;changes&quot; field that follows. Top
++ * three bits are actual packet type. For backward compatibility
++ * and in the interest of conserving bits, numbers are chosen so the
++ * IP protocol version number (4) which normally appears in this nibble
++ * means &quot;IP packet&quot;.
++ */
++
++/* packet types */
++#define TYPE_IP 0x40
++#define TYPE_UNCOMPRESSED_TCP 0x70
++#define TYPE_COMPRESSED_TCP 0x80
++#define TYPE_ERROR 0x00
++
++/* Bits in first octet of compressed packet */
++#define NEW_C 0x40 /* flag bits for what changed in a packet */
++#define NEW_I 0x20
++#define NEW_S 0x08
++#define NEW_A 0x04
++#define NEW_W 0x02
++#define NEW_U 0x01
++
++/* reserved, special-case values of above */
++#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */
++#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */
++#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U)
++
++#define TCP_PUSH_BIT 0x10
++
++
++/*
++ * &quot;state&quot; data for each active tcp conversation on the wire. This is
++ * basically a copy of the entire IP/TCP header from the last packet
++ * we saw from the conversation together with a small identifier
++ * the transmit &amp; receive ends of the line use to locate saved header.
++ */
++struct cstate {
++ struct cstate *cs_next; /* next most recently used state (xmit only) */
++ u_short cs_hlen; /* size of hdr (receive only) */
++ u_char cs_id; /* connection # associated with this state */
++ u_char cs_filler;
++ union {
++ char csu_hdr[MAX_HDR];
++ struct ip csu_ip; /* ip/tcp hdr from most recent packet */
++ } vjcs_u;
++};
++#define cs_ip vjcs_u.csu_ip
++#define cs_hdr vjcs_u.csu_hdr
++
++/*
++ * all the state data for one serial line (we need one of these per line).
++ */
++struct vjcompress {
++ struct cstate *last_cs; /* most recently used tstate */
++ u_char last_recv; /* last rcvd conn. id */
++ u_char last_xmit; /* last sent conn. id */
++ u_short flags;
++#ifndef VJ_NO_STATS
++ struct vjstat stats;
++#endif
++ struct cstate tstate[MAX_STATES]; /* xmit connection states */
++ struct cstate rstate[MAX_STATES]; /* receive connection states */
++};
++
++/* flag values */
++#define VJF_TOSS 1 /* tossing rcvd frames because of input err */
++
++extern void vj_compress_init __P((struct vjcompress *comp, int max_state));
++extern u_int vj_compress_tcp __P((struct ip *ip, u_int mlen,
++ struct vjcompress *comp, int compress_cid_flag,
++ u_char **vjhdrp));
++extern void vj_uncompress_err __P((struct vjcompress *comp));
++extern int vj_uncompress_uncomp __P((u_char *buf, int buflen,
++ struct vjcompress *comp));
++extern int vj_uncompress_tcp __P((u_char *buf, int buflen, int total_len,
++ struct vjcompress *comp, u_char **hdrp,
++ u_int *hlenp));
++
++#endif /* _VJCOMPRESS_H_ */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/include/net/vjcompress.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/include/pcap-int.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/include/pcap-int.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/include/pcap-int.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,117 @@
++/*
++ * Copyright (c) 1994, 1995, 1996
++ * The 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 Computer Systems
++ * Engineering Group at Lawrence Berkeley Laboratory.
++ * 4. Neither the name of the University nor of the Laboratory 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.
++ *
++ * @(#) $Header$ (LBL)
++ */
++
++#ifndef pcap_int_h
++#define pcap_int_h
++
++#include &lt;pcap.h&gt;
++
++/*
++ * Savefile
++ */
++struct pcap_sf {
++ FILE *rfile;
++ int swapped;
++ int version_major;
++ int version_minor;
++ u_char *base;
++};
++
++struct pcap_md {
++ struct pcap_stat stat;
++ /*XXX*/
++ int use_bpf;
++ u_long TotPkts; /* can't oflow for 79 hrs on ether */
++ u_long TotAccepted; /* count accepted by filter */
++ u_long TotDrops; /* count of dropped packets */
++ long TotMissed; /* missed by i/f during this run */
++ long OrigMissed; /* missed by i/f before this run */
++#ifdef linux
++ int pad;
++ int skip;
++ char *device;
++#endif
++};
++
++struct pcap {
++ int fd;
++ int snapshot;
++ int linktype;
++ int tzoff; /* timezone offset */
++ int offset; /* offset for proper alignment */
++
++ struct pcap_sf sf;
++ struct pcap_md md;
++
++ /*
++ * Read buffer.
++ */
++ int bufsize;
++ u_char *buffer;
++ u_char *bp;
++ int cc;
++
++ /*
++ * Place holder for pcap_next().
++ */
++ u_char *pkt;
++
++
++ /*
++ * Placeholder for filter code if bpf not in kernel.
++ */
++ struct bpf_program fcode;
++
++ char errbuf[PCAP_ERRBUF_SIZE];
++};
++
++int yylex(void);
++
++#ifndef min
++#define min(a, b) ((a) &gt; (b) ? (b) : (a))
++#endif
++
++/* XXX should these be in pcap.h? */
++int pcap_offline_read(pcap_t *, int, pcap_handler, u_char *);
++int pcap_read(pcap_t *, int cnt, pcap_handler, u_char *);
++
++/* Ultrix pads to make everything line up on a nice boundary */
++#if defined(ultrix) || defined(__alpha)
++#define PCAP_FDDIPAD 3
++#endif
++
++/* XXX */
++extern int pcap_fddipad;
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/include/pcap-int.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/linux/Makefile.top
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/linux/Makefile.top (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/linux/Makefile.top 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,55 @@
++# PPP top-level Makefile for Linux.
++
++
++BINDIR = $(DESTDIR)/usr/sbin
++MANDIR = $(DESTDIR)/usr/man
++ETCDIR = $(DESTDIR)/etc/ppp
++
++# uid 0 = root
++INSTALL= install
++
++all:
++ cd chat; $(MAKE) $(MFLAGS) all
++ cd pppd; $(MAKE) $(MFLAGS) all
++ cd pppstats; $(MAKE) $(MFLAGS) all
++ cd pppdump; $(MAKE) $(MFLAGS) all
++
++install: $(BINDIR) $(MANDIR)/man8 install-progs install-etcppp
++
++install-progs:
++ cd chat; $(MAKE) BINDIR=$(BINDIR) MANDIR=$(MANDIR) $(MFLAGS) install
++ cd pppd; $(MAKE) BINDIR=$(BINDIR) MANDIR=$(MANDIR) $(MFLAGS) install
++ cd pppstats; $(MAKE) BINDIR=$(BINDIR) MANDIR=$(MANDIR) $(MFLAGS) install
++ cd pppdump; $(MAKE) BINDIR=$(BINDIR) MANDIR=$(MANDIR) $(MFLAGS) install
++
++install-etcppp: $(ETCDIR) $(ETCDIR)/options $(ETCDIR)/pap-secrets \
++ $(ETCDIR)/chap-secrets
++
++$(ETCDIR)/options:
++ $(INSTALL) -c -m 644 etc.ppp/options $@
++$(ETCDIR)/pap-secrets:
++ $(INSTALL) -c -m 600 etc.ppp/pap-secrets $@
++$(ETCDIR)/chap-secrets:
++ $(INSTALL) -c -m 600 etc.ppp/chap-secrets $@
++
++$(BINDIR):
++ $(INSTALL) -d -m 755 $@
++$(MANDIR)/man8:
++ $(INSTALL) -d -m 755 $@
++$(ETCDIR):
++ $(INSTALL) -d -m 755 $@
++
++clean:
++ rm -f `find . -name '*.[oas]' -print`
++ rm -f `find . -name 'core' -print`
++ rm -f `find . -name '*~' -print`
++ cd chat; $(MAKE) clean
++ cd pppd; $(MAKE) clean
++ cd pppstats; $(MAKE) clean
++ cd pppdump; $(MAKE) clean
++
++dist-clean: clean
++ rm -f Makefile `find . -name Makefile -print`
++
++#kernel:
++# cd linux; ./kinstall.sh
+
+Added: drakx/trunk/mdk-stage1/ppp/modules/bsd-comp.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/modules/bsd-comp.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/modules/bsd-comp.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1116 @@
++/* Because this code is derived from the 4.3BSD compress source:
++ *
++ *
++ * Copyright (c) 1985, 1986 The Regents of the University of California.
++ * All rights reserved.
++ *
++ * This code is derived from software contributed to Berkeley by
++ * James A. Woods, derived from original work by Spencer Thomas
++ * and Joseph Orost.
++ *
++ * 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.
++ */
++
++/*
++ * This version is for use with STREAMS under SunOS 4.x,
++ * Digital UNIX, AIX 4.x, and SVR4 systems including Solaris 2.
++ *
++ * $Id: bsd-comp.c 195720 2001-06-11 11:44:34Z gc $
++ */
++
++#ifdef AIX4
++#include &lt;net/net_globals.h&gt;
++#endif
++#include &lt;sys/param.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/stream.h&gt;
++#include &lt;net/ppp_defs.h&gt;
++#include &quot;ppp_mod.h&quot;
++
++#ifdef SVR4
++#include &lt;sys/byteorder.h&gt;
++#ifndef _BIG_ENDIAN
++#define BSD_LITTLE_ENDIAN
++#endif
++#endif
++
++#ifdef __osf__
++#undef FIRST
++#undef LAST
++#define BSD_LITTLE_ENDIAN
++#endif
++
++#define PACKETPTR mblk_t *
++#include &lt;net/ppp-comp.h&gt;
++
++#if DO_BSD_COMPRESS
++
++/*
++ * PPP &quot;BSD compress&quot; compression
++ * The differences between this compression and the classic BSD LZW
++ * source are obvious from the requirement that the classic code worked
++ * with files while this handles arbitrarily long streams that
++ * are broken into packets. They are:
++ *
++ * When the code size expands, a block of junk is not emitted by
++ * the compressor and not expected by the decompressor.
++ *
++ * New codes are not necessarily assigned every time an old
++ * code is output by the compressor. This is because a packet
++ * end forces a code to be emitted, but does not imply that a
++ * new sequence has been seen.
++ *
++ * The compression ratio is checked at the first end of a packet
++ * after the appropriate gap. Besides simplifying and speeding
++ * things up, this makes it more likely that the transmitter
++ * and receiver will agree when the dictionary is cleared when
++ * compression is not going well.
++ */
++
++/*
++ * A dictionary for doing BSD compress.
++ */
++struct bsd_db {
++ int totlen; /* length of this structure */
++ u_int hsize; /* size of the hash table */
++ u_char hshift; /* used in hash function */
++ u_char n_bits; /* current bits/code */
++ u_char maxbits;
++ u_char debug;
++ u_char unit;
++ u_short seqno; /* sequence number of next packet */
++ u_int hdrlen; /* header length to preallocate */
++ u_int mru;
++ u_int maxmaxcode; /* largest valid code */
++ u_int max_ent; /* largest code in use */
++ u_int in_count; /* uncompressed bytes, aged */
++ u_int bytes_out; /* compressed bytes, aged */
++ u_int ratio; /* recent compression ratio */
++ u_int checkpoint; /* when to next check the ratio */
++ u_int clear_count; /* times dictionary cleared */
++ u_int incomp_count; /* incompressible packets */
++ u_int incomp_bytes; /* incompressible bytes */
++ u_int uncomp_count; /* uncompressed packets */
++ u_int uncomp_bytes; /* uncompressed bytes */
++ u_int comp_count; /* compressed packets */
++ u_int comp_bytes; /* compressed bytes */
++ u_short *lens; /* array of lengths of codes */
++ struct bsd_dict {
++ union { /* hash value */
++ u_int32_t fcode;
++ struct {
++#ifdef BSD_LITTLE_ENDIAN
++ u_short prefix; /* preceding code */
++ u_char suffix; /* last character of new code */
++ u_char pad;
++#else
++ u_char pad;
++ u_char suffix; /* last character of new code */
++ u_short prefix; /* preceding code */
++#endif
++ } hs;
++ } f;
++ u_short codem1; /* output of hash table -1 */
++ u_short cptr; /* map code to hash table entry */
++ } dict[1];
++};
++
++#define BSD_OVHD 2 /* BSD compress overhead/packet */
++#define BSD_INIT_BITS BSD_MIN_BITS
++
++static void *bsd_comp_alloc __P((u_char *options, int opt_len));
++static void *bsd_decomp_alloc __P((u_char *options, int opt_len));
++static void bsd_free __P((void *state));
++static int bsd_comp_init __P((void *state, u_char *options, int opt_len,
++ int unit, int hdrlen, int debug));
++static int bsd_decomp_init __P((void *state, u_char *options, int opt_len,
++ int unit, int hdrlen, int mru, int debug));
++static int bsd_compress __P((void *state, mblk_t **mret,
++ mblk_t *mp, int slen, int maxolen));
++static void bsd_incomp __P((void *state, mblk_t *dmsg));
++static int bsd_decompress __P((void *state, mblk_t *cmp, mblk_t **dmpp));
++static void bsd_reset __P((void *state));
++static void bsd_comp_stats __P((void *state, struct compstat *stats));
++
++/*
++ * Procedures exported to ppp_comp.c.
++ */
++struct compressor ppp_bsd_compress = {
++ CI_BSD_COMPRESS, /* compress_proto */
++ bsd_comp_alloc, /* comp_alloc */
++ bsd_free, /* comp_free */
++ bsd_comp_init, /* comp_init */
++ bsd_reset, /* comp_reset */
++ bsd_compress, /* compress */
++ bsd_comp_stats, /* comp_stat */
++ bsd_decomp_alloc, /* decomp_alloc */
++ bsd_free, /* decomp_free */
++ bsd_decomp_init, /* decomp_init */
++ bsd_reset, /* decomp_reset */
++ bsd_decompress, /* decompress */
++ bsd_incomp, /* incomp */
++ bsd_comp_stats, /* decomp_stat */
++};
++
++/*
++ * the next two codes should not be changed lightly, as they must not
++ * lie within the contiguous general code space.
++ */
++#define CLEAR 256 /* table clear output code */
++#define FIRST 257 /* first free entry */
++#define LAST 255
++
++#define MAXCODE(b) ((1 &lt;&lt; (b)) - 1)
++#define BADCODEM1 MAXCODE(BSD_MAX_BITS)
++
++#define BSD_HASH(prefix,suffix,hshift) ((((u_int32_t)(suffix)) &lt;&lt; (hshift)) \
++ ^ (u_int32_t)(prefix))
++#define BSD_KEY(prefix,suffix) ((((u_int32_t)(suffix)) &lt;&lt; 16) \
++ + (u_int32_t)(prefix))
++
++#define CHECK_GAP 10000 /* Ratio check interval */
++
++#define RATIO_SCALE_LOG 8
++#define RATIO_SCALE (1&lt;&lt;RATIO_SCALE_LOG)
++#define RATIO_MAX (0x7fffffff&gt;&gt;RATIO_SCALE_LOG)
++
++#define DECOMP_CHUNK 256
++
++/*
++ * clear the dictionary
++ */
++static void
++bsd_clear(db)
++ struct bsd_db *db;
++{
++ db-&gt;clear_count++;
++ db-&gt;max_ent = FIRST-1;
++ db-&gt;n_bits = BSD_INIT_BITS;
++ db-&gt;ratio = 0;
++ db-&gt;bytes_out = 0;
++ db-&gt;in_count = 0;
++ db-&gt;checkpoint = CHECK_GAP;
++}
++
++/*
++ * If the dictionary is full, then see if it is time to reset it.
++ *
++ * Compute the compression ratio using fixed-point arithmetic
++ * with 8 fractional bits.
++ *
++ * Since we have an infinite stream instead of a single file,
++ * watch only the local compression ratio.
++ *
++ * Since both peers must reset the dictionary at the same time even in
++ * the absence of CLEAR codes (while packets are incompressible), they
++ * must compute the same ratio.
++ */
++static int /* 1=output CLEAR */
++bsd_check(db)
++ struct bsd_db *db;
++{
++ u_int new_ratio;
++
++ if (db-&gt;in_count &gt;= db-&gt;checkpoint) {
++ /* age the ratio by limiting the size of the counts */
++ if (db-&gt;in_count &gt;= RATIO_MAX
++ || db-&gt;bytes_out &gt;= RATIO_MAX) {
++ db-&gt;in_count -= db-&gt;in_count/4;
++ db-&gt;bytes_out -= db-&gt;bytes_out/4;
++ }
++
++ db-&gt;checkpoint = db-&gt;in_count + CHECK_GAP;
++
++ if (db-&gt;max_ent &gt;= db-&gt;maxmaxcode) {
++ /* Reset the dictionary only if the ratio is worse,
++ * or if it looks as if it has been poisoned
++ * by incompressible data.
++ *
++ * This does not overflow, because
++ * db-&gt;in_count &lt;= RATIO_MAX.
++ */
++ new_ratio = db-&gt;in_count &lt;&lt; RATIO_SCALE_LOG;
++ if (db-&gt;bytes_out != 0)
++ new_ratio /= db-&gt;bytes_out;
++
++ if (new_ratio &lt; db-&gt;ratio || new_ratio &lt; 1 * RATIO_SCALE) {
++ bsd_clear(db);
++ return 1;
++ }
++ db-&gt;ratio = new_ratio;
++ }
++ }
++ return 0;
++}
++
++/*
++ * Return statistics.
++ */
++static void
++bsd_comp_stats(state, stats)
++ void *state;
++ struct compstat *stats;
++{
++ struct bsd_db *db = (struct bsd_db *) state;
++ u_int out;
++
++ stats-&gt;unc_bytes = db-&gt;uncomp_bytes;
++ stats-&gt;unc_packets = db-&gt;uncomp_count;
++ stats-&gt;comp_bytes = db-&gt;comp_bytes;
++ stats-&gt;comp_packets = db-&gt;comp_count;
++ stats-&gt;inc_bytes = db-&gt;incomp_bytes;
++ stats-&gt;inc_packets = db-&gt;incomp_count;
++ stats-&gt;ratio = db-&gt;in_count;
++ out = db-&gt;bytes_out;
++ if (stats-&gt;ratio &lt;= 0x7fffff)
++ stats-&gt;ratio &lt;&lt;= 8;
++ else
++ out &gt;&gt;= 8;
++ if (out != 0)
++ stats-&gt;ratio /= out;
++}
++
++/*
++ * Reset state, as on a CCP ResetReq.
++ */
++static void
++bsd_reset(state)
++ void *state;
++{
++ struct bsd_db *db = (struct bsd_db *) state;
++
++ db-&gt;seqno = 0;
++ bsd_clear(db);
++ db-&gt;clear_count = 0;
++}
++
++/*
++ * Allocate space for a (de) compressor.
++ */
++static void *
++bsd_alloc(options, opt_len, decomp)
++ u_char *options;
++ int opt_len, decomp;
++{
++ int bits;
++ u_int newlen, hsize, hshift, maxmaxcode;
++ struct bsd_db *db;
++
++ if (opt_len != 3 || options[0] != CI_BSD_COMPRESS || options[1] != 3
++ || BSD_VERSION(options[2]) != BSD_CURRENT_VERSION)
++ return NULL;
++
++ bits = BSD_NBITS(options[2]);
++ switch (bits) {
++ case 9: /* needs 82152 for both directions */
++ case 10: /* needs 84144 */
++ case 11: /* needs 88240 */
++ case 12: /* needs 96432 */
++ hsize = 5003;
++ hshift = 4;
++ break;
++ case 13: /* needs 176784 */
++ hsize = 9001;
++ hshift = 5;
++ break;
++ case 14: /* needs 353744 */
++ hsize = 18013;
++ hshift = 6;
++ break;
++ case 15: /* needs 691440 */
++ hsize = 35023;
++ hshift = 7;
++ break;
++ case 16: /* needs 1366160--far too much, */
++ /* hsize = 69001; */ /* and 69001 is too big for cptr */
++ /* hshift = 8; */ /* in struct bsd_db */
++ /* break; */
++ default:
++ return NULL;
++ }
++
++ maxmaxcode = MAXCODE(bits);
++ newlen = sizeof(*db) + (hsize-1) * (sizeof(db-&gt;dict[0]));
++#ifdef __osf__
++ db = (struct bsd_db *) ALLOC_SLEEP(newlen);
++#else
++ db = (struct bsd_db *) ALLOC_NOSLEEP(newlen);
++#endif
++ if (!db)
++ return NULL;
++ bzero(db, sizeof(*db) - sizeof(db-&gt;dict));
++
++ if (!decomp) {
++ db-&gt;lens = NULL;
++ } else {
++#ifdef __osf__
++ db-&gt;lens = (u_short *) ALLOC_SLEEP((maxmaxcode+1) * sizeof(db-&gt;lens[0]));
++#else
++ db-&gt;lens = (u_short *) ALLOC_NOSLEEP((maxmaxcode+1) * sizeof(db-&gt;lens[0]));
++#endif
++ if (!db-&gt;lens) {
++ FREE(db, newlen);
++ return NULL;
++ }
++ }
++
++ db-&gt;totlen = newlen;
++ db-&gt;hsize = hsize;
++ db-&gt;hshift = hshift;
++ db-&gt;maxmaxcode = maxmaxcode;
++ db-&gt;maxbits = bits;
++
++ return (void *) db;
++}
++
++static void
++bsd_free(state)
++ void *state;
++{
++ struct bsd_db *db = (struct bsd_db *) state;
++
++ if (db-&gt;lens)
++ FREE(db-&gt;lens, (db-&gt;maxmaxcode+1) * sizeof(db-&gt;lens[0]));
++ FREE(db, db-&gt;totlen);
++}
++
++static void *
++bsd_comp_alloc(options, opt_len)
++ u_char *options;
++ int opt_len;
++{
++ return bsd_alloc(options, opt_len, 0);
++}
++
++static void *
++bsd_decomp_alloc(options, opt_len)
++ u_char *options;
++ int opt_len;
++{
++ return bsd_alloc(options, opt_len, 1);
++}
++
++/*
++ * Initialize the database.
++ */
++static int
++bsd_init(db, options, opt_len, unit, hdrlen, mru, debug, decomp)
++ struct bsd_db *db;
++ u_char *options;
++ int opt_len, unit, hdrlen, mru, debug, decomp;
++{
++ int i;
++
++ if (opt_len &lt; CILEN_BSD_COMPRESS
++ || options[0] != CI_BSD_COMPRESS || options[1] != CILEN_BSD_COMPRESS
++ || BSD_VERSION(options[2]) != BSD_CURRENT_VERSION
++ || BSD_NBITS(options[2]) != db-&gt;maxbits
++ || decomp &amp;&amp; db-&gt;lens == NULL)
++ return 0;
++
++ if (decomp) {
++ i = LAST+1;
++ while (i != 0)
++ db-&gt;lens[--i] = 1;
++ }
++ i = db-&gt;hsize;
++ while (i != 0) {
++ db-&gt;dict[--i].codem1 = BADCODEM1;
++ db-&gt;dict[i].cptr = 0;
++ }
++
++ db-&gt;unit = unit;
++ db-&gt;hdrlen = hdrlen;
++ db-&gt;mru = mru;
++ if (debug)
++ db-&gt;debug = 1;
++
++ bsd_reset(db);
++
++ return 1;
++}
++
++static int
++bsd_comp_init(state, options, opt_len, unit, hdrlen, debug)
++ void *state;
++ u_char *options;
++ int opt_len, unit, hdrlen, debug;
++{
++ return bsd_init((struct bsd_db *) state, options, opt_len,
++ unit, hdrlen, 0, debug, 0);
++}
++
++static int
++bsd_decomp_init(state, options, opt_len, unit, hdrlen, mru, debug)
++ void *state;
++ u_char *options;
++ int opt_len, unit, hdrlen, mru, debug;
++{
++ return bsd_init((struct bsd_db *) state, options, opt_len,
++ unit, hdrlen, mru, debug, 1);
++}
++
++
++/*
++ * compress a packet
++ * One change from the BSD compress command is that when the
++ * code size expands, we do not output a bunch of padding.
++ *
++ * N.B. at present, we ignore the hdrlen specified in the comp_init call.
++ */
++static int /* new slen */
++bsd_compress(state, mretp, mp, slen, maxolen)
++ void *state;
++ mblk_t **mretp; /* return compressed mbuf chain here */
++ mblk_t *mp; /* from here */
++ int slen; /* uncompressed length */
++ int maxolen; /* max compressed length */
++{
++ struct bsd_db *db = (struct bsd_db *) state;
++ int hshift = db-&gt;hshift;
++ u_int max_ent = db-&gt;max_ent;
++ u_int n_bits = db-&gt;n_bits;
++ u_int bitno = 32;
++ u_int32_t accm = 0, fcode;
++ struct bsd_dict *dictp;
++ u_char c;
++ int hval, disp, ent, ilen;
++ mblk_t *np, *mret;
++ u_char *rptr, *wptr;
++ u_char *cp_end;
++ int olen;
++ mblk_t *m, **mnp;
++
++#define PUTBYTE(v) { \
++ if (wptr) { \
++ *wptr++ = (v); \
++ if (wptr &gt;= cp_end) { \
++ m-&gt;b_wptr = wptr; \
++ m = m-&gt;b_cont; \
++ if (m) { \
++ wptr = m-&gt;b_wptr; \
++ cp_end = m-&gt;b_datap-&gt;db_lim; \
++ } else \
++ wptr = NULL; \
++ } \
++ } \
++ ++olen; \
++}
++
++#define OUTPUT(ent) { \
++ bitno -= n_bits; \
++ accm |= ((ent) &lt;&lt; bitno); \
++ do { \
++ PUTBYTE(accm &gt;&gt; 24); \
++ accm &lt;&lt;= 8; \
++ bitno += 8; \
++ } while (bitno &lt;= 24); \
++}
++
++ /*
++ * First get the protocol and check that we're
++ * interested in this packet.
++ */
++ *mretp = NULL;
++ rptr = mp-&gt;b_rptr;
++ if (rptr + PPP_HDRLEN &gt; mp-&gt;b_wptr) {
++ if (!pullupmsg(mp, PPP_HDRLEN))
++ return 0;
++ rptr = mp-&gt;b_rptr;
++ }
++ ent = PPP_PROTOCOL(rptr); /* get the protocol */
++ if (ent &lt; 0x21 || ent &gt; 0xf9)
++ return 0;
++
++ /* Don't generate compressed packets which are larger than
++ the uncompressed packet. */
++ if (maxolen &gt; slen)
++ maxolen = slen;
++
++ /* Allocate enough message blocks to give maxolen total space. */
++ mnp = &amp;mret;
++ for (olen = maxolen; olen &gt; 0; ) {
++ m = allocb((olen &lt; 4096? olen: 4096), BPRI_MED);
++ *mnp = m;
++ if (m == NULL) {
++ if (mret != NULL) {
++ freemsg(mret);
++ mnp = &amp;mret;
++ }
++ break;
++ }
++ mnp = &amp;m-&gt;b_cont;
++ olen -= m-&gt;b_datap-&gt;db_lim - m-&gt;b_wptr;
++ }
++ *mnp = NULL;
++
++ if ((m = mret) != NULL) {
++ wptr = m-&gt;b_wptr;
++ cp_end = m-&gt;b_datap-&gt;db_lim;
++ } else
++ wptr = cp_end = NULL;
++ olen = 0;
++
++ /*
++ * Copy the PPP header over, changing the protocol,
++ * and install the 2-byte sequence number.
++ */
++ if (wptr) {
++ wptr[0] = PPP_ADDRESS(rptr);
++ wptr[1] = PPP_CONTROL(rptr);
++ wptr[2] = 0; /* change the protocol */
++ wptr[3] = PPP_COMP;
++ wptr[4] = db-&gt;seqno &gt;&gt; 8;
++ wptr[5] = db-&gt;seqno;
++ wptr += PPP_HDRLEN + BSD_OVHD;
++ }
++ ++db-&gt;seqno;
++ rptr += PPP_HDRLEN;
++
++ slen = mp-&gt;b_wptr - rptr;
++ ilen = slen + 1;
++ np = mp-&gt;b_cont;
++ for (;;) {
++ if (slen &lt;= 0) {
++ if (!np)
++ break;
++ rptr = np-&gt;b_rptr;
++ slen = np-&gt;b_wptr - rptr;
++ np = np-&gt;b_cont;
++ if (!slen)
++ continue; /* handle 0-length buffers */
++ ilen += slen;
++ }
++
++ slen--;
++ c = *rptr++;
++ fcode = BSD_KEY(ent, c);
++ hval = BSD_HASH(ent, c, hshift);
++ dictp = &amp;db-&gt;dict[hval];
++
++ /* Validate and then check the entry. */
++ if (dictp-&gt;codem1 &gt;= max_ent)
++ goto nomatch;
++ if (dictp-&gt;f.fcode == fcode) {
++ ent = dictp-&gt;codem1+1;
++ continue; /* found (prefix,suffix) */
++ }
++
++ /* continue probing until a match or invalid entry */
++ disp = (hval == 0) ? 1 : hval;
++ do {
++ hval += disp;
++ if (hval &gt;= db-&gt;hsize)
++ hval -= db-&gt;hsize;
++ dictp = &amp;db-&gt;dict[hval];
++ if (dictp-&gt;codem1 &gt;= max_ent)
++ goto nomatch;
++ } while (dictp-&gt;f.fcode != fcode);
++ ent = dictp-&gt;codem1 + 1; /* finally found (prefix,suffix) */
++ continue;
++
++ nomatch:
++ OUTPUT(ent); /* output the prefix */
++
++ /* code -&gt; hashtable */
++ if (max_ent &lt; db-&gt;maxmaxcode) {
++ struct bsd_dict *dictp2;
++ /* expand code size if needed */
++ if (max_ent &gt;= MAXCODE(n_bits))
++ db-&gt;n_bits = ++n_bits;
++
++ /* Invalidate old hash table entry using
++ * this code, and then take it over.
++ */
++ dictp2 = &amp;db-&gt;dict[max_ent+1];
++ if (db-&gt;dict[dictp2-&gt;cptr].codem1 == max_ent)
++ db-&gt;dict[dictp2-&gt;cptr].codem1 = BADCODEM1;
++ dictp2-&gt;cptr = hval;
++ dictp-&gt;codem1 = max_ent;
++ dictp-&gt;f.fcode = fcode;
++
++ db-&gt;max_ent = ++max_ent;
++ }
++ ent = c;
++ }
++
++ OUTPUT(ent); /* output the last code */
++ db-&gt;bytes_out += olen;
++ db-&gt;in_count += ilen;
++ if (bitno &lt; 32)
++ ++db-&gt;bytes_out; /* count complete bytes */
++
++ if (bsd_check(db))
++ OUTPUT(CLEAR); /* do not count the CLEAR */
++
++ /*
++ * Pad dribble bits of last code with ones.
++ * Do not emit a completely useless byte of ones.
++ */
++ if (bitno != 32)
++ PUTBYTE((accm | (0xff &lt;&lt; (bitno-8))) &gt;&gt; 24);
++
++ /*
++ * Increase code size if we would have without the packet
++ * boundary and as the decompressor will.
++ */
++ if (max_ent &gt;= MAXCODE(n_bits) &amp;&amp; max_ent &lt; db-&gt;maxmaxcode)
++ db-&gt;n_bits++;
++
++ db-&gt;uncomp_bytes += ilen;
++ ++db-&gt;uncomp_count;
++ if (olen + PPP_HDRLEN + BSD_OVHD &gt; maxolen &amp;&amp; mret != NULL) {
++ /* throw away the compressed stuff if it is longer than uncompressed */
++ freemsg(mret);
++ mret = NULL;
++ ++db-&gt;incomp_count;
++ db-&gt;incomp_bytes += ilen;
++ } else if (wptr != NULL) {
++ m-&gt;b_wptr = wptr;
++ if (m-&gt;b_cont) {
++ freemsg(m-&gt;b_cont);
++ m-&gt;b_cont = NULL;
++ }
++ ++db-&gt;comp_count;
++ db-&gt;comp_bytes += olen + BSD_OVHD;
++ }
++
++ *mretp = mret;
++ return olen + PPP_HDRLEN + BSD_OVHD;
++#undef OUTPUT
++#undef PUTBYTE
++}
++
++
++/*
++ * Update the &quot;BSD Compress&quot; dictionary on the receiver for
++ * incompressible data by pretending to compress the incoming data.
++ */
++static void
++bsd_incomp(state, dmsg)
++ void *state;
++ mblk_t *dmsg;
++{
++ struct bsd_db *db = (struct bsd_db *) state;
++ u_int hshift = db-&gt;hshift;
++ u_int max_ent = db-&gt;max_ent;
++ u_int n_bits = db-&gt;n_bits;
++ struct bsd_dict *dictp;
++ u_int32_t fcode;
++ u_char c;
++ long hval, disp;
++ int slen, ilen;
++ u_int bitno = 7;
++ u_char *rptr;
++ u_int ent;
++
++ rptr = dmsg-&gt;b_rptr;
++ if (rptr + PPP_HDRLEN &gt; dmsg-&gt;b_wptr) {
++ if (!pullupmsg(dmsg, PPP_HDRLEN))
++ return;
++ rptr = dmsg-&gt;b_rptr;
++ }
++ ent = PPP_PROTOCOL(rptr); /* get the protocol */
++ if (ent &lt; 0x21 || ent &gt; 0xf9)
++ return;
++
++ db-&gt;seqno++;
++ ilen = 1; /* count the protocol as 1 byte */
++ rptr += PPP_HDRLEN;
++ for (;;) {
++ slen = dmsg-&gt;b_wptr - rptr;
++ if (slen &lt;= 0) {
++ dmsg = dmsg-&gt;b_cont;
++ if (!dmsg)
++ break;
++ rptr = dmsg-&gt;b_rptr;
++ continue; /* skip zero-length buffers */
++ }
++ ilen += slen;
++
++ do {
++ c = *rptr++;
++ fcode = BSD_KEY(ent, c);
++ hval = BSD_HASH(ent, c, hshift);
++ dictp = &amp;db-&gt;dict[hval];
++
++ /* validate and then check the entry */
++ if (dictp-&gt;codem1 &gt;= max_ent)
++ goto nomatch;
++ if (dictp-&gt;f.fcode == fcode) {
++ ent = dictp-&gt;codem1+1;
++ continue; /* found (prefix,suffix) */
++ }
++
++ /* continue probing until a match or invalid entry */
++ disp = (hval == 0) ? 1 : hval;
++ do {
++ hval += disp;
++ if (hval &gt;= db-&gt;hsize)
++ hval -= db-&gt;hsize;
++ dictp = &amp;db-&gt;dict[hval];
++ if (dictp-&gt;codem1 &gt;= max_ent)
++ goto nomatch;
++ } while (dictp-&gt;f.fcode != fcode);
++ ent = dictp-&gt;codem1+1;
++ continue; /* finally found (prefix,suffix) */
++
++ nomatch: /* output (count) the prefix */
++ bitno += n_bits;
++
++ /* code -&gt; hashtable */
++ if (max_ent &lt; db-&gt;maxmaxcode) {
++ struct bsd_dict *dictp2;
++ /* expand code size if needed */
++ if (max_ent &gt;= MAXCODE(n_bits))
++ db-&gt;n_bits = ++n_bits;
++
++ /* Invalidate previous hash table entry
++ * assigned this code, and then take it over.
++ */
++ dictp2 = &amp;db-&gt;dict[max_ent+1];
++ if (db-&gt;dict[dictp2-&gt;cptr].codem1 == max_ent)
++ db-&gt;dict[dictp2-&gt;cptr].codem1 = BADCODEM1;
++ dictp2-&gt;cptr = hval;
++ dictp-&gt;codem1 = max_ent;
++ dictp-&gt;f.fcode = fcode;
++
++ db-&gt;max_ent = ++max_ent;
++ db-&gt;lens[max_ent] = db-&gt;lens[ent]+1;
++ }
++ ent = c;
++ } while (--slen != 0);
++ }
++ bitno += n_bits; /* output (count) the last code */
++ db-&gt;bytes_out += bitno/8;
++ db-&gt;in_count += ilen;
++ (void)bsd_check(db);
++
++ ++db-&gt;incomp_count;
++ db-&gt;incomp_bytes += ilen;
++ ++db-&gt;uncomp_count;
++ db-&gt;uncomp_bytes += ilen;
++
++ /* Increase code size if we would have without the packet
++ * boundary and as the decompressor will.
++ */
++ if (max_ent &gt;= MAXCODE(n_bits) &amp;&amp; max_ent &lt; db-&gt;maxmaxcode)
++ db-&gt;n_bits++;
++}
++
++
++/*
++ * Decompress &quot;BSD Compress&quot;
++ *
++ * Because of patent problems, we return DECOMP_ERROR for errors
++ * found by inspecting the input data and for system problems, but
++ * DECOMP_FATALERROR for any errors which could possibly be said to
++ * be being detected &quot;after&quot; decompression. For DECOMP_ERROR,
++ * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
++ * infringing a patent of Motorola's if we do, so we take CCP down
++ * instead.
++ *
++ * Given that the frame has the correct sequence number and a good FCS,
++ * errors such as invalid codes in the input most likely indicate a
++ * bug, so we return DECOMP_FATALERROR for them in order to turn off
++ * compression, even though they are detected by inspecting the input.
++ */
++static int
++bsd_decompress(state, cmsg, dmpp)
++ void *state;
++ mblk_t *cmsg, **dmpp;
++{
++ struct bsd_db *db = (struct bsd_db *) state;
++ u_int max_ent = db-&gt;max_ent;
++ u_int32_t accm = 0;
++ u_int bitno = 32; /* 1st valid bit in accm */
++ u_int n_bits = db-&gt;n_bits;
++ u_int tgtbitno = 32-n_bits; /* bitno when we have a code */
++ struct bsd_dict *dictp;
++ int explen, i, seq, len;
++ u_int incode, oldcode, finchar;
++ u_char *p, *rptr, *wptr;
++ mblk_t *dmsg, *mret;
++ int adrs, ctrl, ilen;
++ int dlen, space, codelen, extra;
++
++ /*
++ * Get at least the BSD Compress header in the first buffer
++ */
++ rptr = cmsg-&gt;b_rptr;
++ if (rptr + PPP_HDRLEN + BSD_OVHD &gt;= cmsg-&gt;b_wptr) {
++ if (!pullupmsg(cmsg, PPP_HDRLEN + BSD_OVHD + 1)) {
++ if (db-&gt;debug)
++ printf(&quot;bsd_decomp%d: failed to pullup\n&quot;, db-&gt;unit);
++ return DECOMP_ERROR;
++ }
++ rptr = cmsg-&gt;b_rptr;
++ }
++
++ /*
++ * Save the address/control from the PPP header
++ * and then get the sequence number.
++ */
++ adrs = PPP_ADDRESS(rptr);
++ ctrl = PPP_CONTROL(rptr);
++ rptr += PPP_HDRLEN;
++ seq = (rptr[0] &lt;&lt; 8) + rptr[1];
++ rptr += BSD_OVHD;
++ ilen = len = cmsg-&gt;b_wptr - rptr;
++
++ /*
++ * Check the sequence number and give up if it is not what we expect.
++ */
++ if (seq != db-&gt;seqno++) {
++ if (db-&gt;debug)
++ printf(&quot;bsd_decomp%d: bad sequence # %d, expected %d\n&quot;,
++ db-&gt;unit, seq, db-&gt;seqno - 1);
++ return DECOMP_ERROR;
++ }
++
++ /*
++ * Allocate one message block to start with.
++ */
++ if ((dmsg = allocb(DECOMP_CHUNK + db-&gt;hdrlen, BPRI_MED)) == NULL)
++ return DECOMP_ERROR;
++ mret = dmsg;
++ dmsg-&gt;b_wptr += db-&gt;hdrlen;
++ dmsg-&gt;b_rptr = wptr = dmsg-&gt;b_wptr;
++
++ /* Fill in the ppp header, but not the last byte of the protocol
++ (that comes from the decompressed data). */
++ wptr[0] = adrs;
++ wptr[1] = ctrl;
++ wptr[2] = 0;
++ wptr += PPP_HDRLEN - 1;
++ space = dmsg-&gt;b_datap-&gt;db_lim - wptr;
++
++ oldcode = CLEAR;
++ explen = 0;
++ for (;;) {
++ if (len == 0) {
++ cmsg = cmsg-&gt;b_cont;
++ if (!cmsg) /* quit at end of message */
++ break;
++ rptr = cmsg-&gt;b_rptr;
++ len = cmsg-&gt;b_wptr - rptr;
++ ilen += len;
++ continue; /* handle 0-length buffers */
++ }
++
++ /*
++ * Accumulate bytes until we have a complete code.
++ * Then get the next code, relying on the 32-bit,
++ * unsigned accm to mask the result.
++ */
++ bitno -= 8;
++ accm |= *rptr++ &lt;&lt; bitno;
++ --len;
++ if (tgtbitno &lt; bitno)
++ continue;
++ incode = accm &gt;&gt; tgtbitno;
++ accm &lt;&lt;= n_bits;
++ bitno += n_bits;
++
++ if (incode == CLEAR) {
++ /*
++ * The dictionary must only be cleared at
++ * the end of a packet. But there could be an
++ * empty message block at the end.
++ */
++ if (len &gt; 0 || cmsg-&gt;b_cont != 0) {
++ if (cmsg-&gt;b_cont)
++ len += msgdsize(cmsg-&gt;b_cont);
++ if (len &gt; 0) {
++ freemsg(dmsg);
++ if (db-&gt;debug)
++ printf(&quot;bsd_decomp%d: bad CLEAR\n&quot;, db-&gt;unit);
++ return DECOMP_FATALERROR;
++ }
++ }
++ bsd_clear(db);
++ explen = ilen = 0;
++ break;
++ }
++
++ if (incode &gt; max_ent + 2 || incode &gt; db-&gt;maxmaxcode
++ || incode &gt; max_ent &amp;&amp; oldcode == CLEAR) {
++ freemsg(dmsg);
++ if (db-&gt;debug) {
++ printf(&quot;bsd_decomp%d: bad code 0x%x oldcode=0x%x &quot;,
++ db-&gt;unit, incode, oldcode);
++ printf(&quot;max_ent=0x%x dlen=%d seqno=%d\n&quot;,
++ max_ent, dlen, db-&gt;seqno);
++ }
++ return DECOMP_FATALERROR; /* probably a bug */
++ }
++
++ /* Special case for KwKwK string. */
++ if (incode &gt; max_ent) {
++ finchar = oldcode;
++ extra = 1;
++ } else {
++ finchar = incode;
++ extra = 0;
++ }
++
++ codelen = db-&gt;lens[finchar];
++ explen += codelen + extra;
++ if (explen &gt; db-&gt;mru + 1) {
++ freemsg(dmsg);
++ if (db-&gt;debug)
++ printf(&quot;bsd_decomp%d: ran out of mru\n&quot;, db-&gt;unit);
++ return DECOMP_FATALERROR;
++ }
++
++ /*
++ * Decode this code and install it in the decompressed buffer.
++ */
++ space -= codelen + extra;
++ if (space &lt; 0) {
++ /* Allocate another message block. */
++ dmsg-&gt;b_wptr = wptr;
++ dlen = codelen + extra;
++ if (dlen &lt; DECOMP_CHUNK)
++ dlen = DECOMP_CHUNK;
++ if ((dmsg-&gt;b_cont = allocb(dlen, BPRI_MED)) == NULL) {
++ freemsg(dmsg);
++ return DECOMP_ERROR;
++ }
++ dmsg = dmsg-&gt;b_cont;
++ wptr = dmsg-&gt;b_wptr;
++ space = dmsg-&gt;b_datap-&gt;db_lim - wptr - codelen - extra;
++ }
++ p = (wptr += codelen);
++ while (finchar &gt; LAST) {
++ dictp = &amp;db-&gt;dict[db-&gt;dict[finchar].cptr];
++#ifdef DEBUG
++ --codelen;
++ if (codelen &lt;= 0) {
++ freemsg(dmsg);
++ printf(&quot;bsd_decomp%d: fell off end of chain &quot;, db-&gt;unit);
++ printf(&quot;0x%x at 0x%x by 0x%x, max_ent=0x%x\n&quot;,
++ incode, finchar, db-&gt;dict[finchar].cptr, max_ent);
++ return DECOMP_FATALERROR;
++ }
++ if (dictp-&gt;codem1 != finchar-1) {
++ freemsg(dmsg);
++ printf(&quot;bsd_decomp%d: bad code chain 0x%x finchar=0x%x &quot;,
++ db-&gt;unit, incode, finchar);
++ printf(&quot;oldcode=0x%x cptr=0x%x codem1=0x%x\n&quot;, oldcode,
++ db-&gt;dict[finchar].cptr, dictp-&gt;codem1);
++ return DECOMP_FATALERROR;
++ }
++#endif
++ *--p = dictp-&gt;f.hs.suffix;
++ finchar = dictp-&gt;f.hs.prefix;
++ }
++ *--p = finchar;
++
++#ifdef DEBUG
++ if (--codelen != 0)
++ printf(&quot;bsd_decomp%d: short by %d after code 0x%x, max_ent=0x%x\n&quot;,
++ db-&gt;unit, codelen, incode, max_ent);
++#endif
++
++ if (extra) /* the KwKwK case again */
++ *wptr++ = finchar;
++
++ /*
++ * If not first code in a packet, and
++ * if not out of code space, then allocate a new code.
++ *
++ * Keep the hash table correct so it can be used
++ * with uncompressed packets.
++ */
++ if (oldcode != CLEAR &amp;&amp; max_ent &lt; db-&gt;maxmaxcode) {
++ struct bsd_dict *dictp2;
++ u_int32_t fcode;
++ int hval, disp;
++
++ fcode = BSD_KEY(oldcode,finchar);
++ hval = BSD_HASH(oldcode,finchar,db-&gt;hshift);
++ dictp = &amp;db-&gt;dict[hval];
++
++ /* look for a free hash table entry */
++ if (dictp-&gt;codem1 &lt; max_ent) {
++ disp = (hval == 0) ? 1 : hval;
++ do {
++ hval += disp;
++ if (hval &gt;= db-&gt;hsize)
++ hval -= db-&gt;hsize;
++ dictp = &amp;db-&gt;dict[hval];
++ } while (dictp-&gt;codem1 &lt; max_ent);
++ }
++
++ /*
++ * Invalidate previous hash table entry
++ * assigned this code, and then take it over
++ */
++ dictp2 = &amp;db-&gt;dict[max_ent+1];
++ if (db-&gt;dict[dictp2-&gt;cptr].codem1 == max_ent) {
++ db-&gt;dict[dictp2-&gt;cptr].codem1 = BADCODEM1;
++ }
++ dictp2-&gt;cptr = hval;
++ dictp-&gt;codem1 = max_ent;
++ dictp-&gt;f.fcode = fcode;
++
++ db-&gt;max_ent = ++max_ent;
++ db-&gt;lens[max_ent] = db-&gt;lens[oldcode]+1;
++
++ /* Expand code size if needed. */
++ if (max_ent &gt;= MAXCODE(n_bits) &amp;&amp; max_ent &lt; db-&gt;maxmaxcode) {
++ db-&gt;n_bits = ++n_bits;
++ tgtbitno = 32-n_bits;
++ }
++ }
++ oldcode = incode;
++ }
++ dmsg-&gt;b_wptr = wptr;
++
++ /*
++ * Keep the checkpoint right so that incompressible packets
++ * clear the dictionary at the right times.
++ */
++ db-&gt;bytes_out += ilen;
++ db-&gt;in_count += explen;
++ if (bsd_check(db) &amp;&amp; db-&gt;debug) {
++ printf(&quot;bsd_decomp%d: peer should have cleared dictionary\n&quot;,
++ db-&gt;unit);
++ }
++
++ ++db-&gt;comp_count;
++ db-&gt;comp_bytes += ilen + BSD_OVHD;
++ ++db-&gt;uncomp_count;
++ db-&gt;uncomp_bytes += explen;
++
++ *dmpp = mret;
++ return DECOMP_OK;
++}
++#endif /* DO_BSD_COMPRESS */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/modules/bsd-comp.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/modules/deflate.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/modules/deflate.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/modules/deflate.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,760 @@
++/*
++ * ppp_deflate.c - interface the zlib procedures for Deflate compression
++ * and decompression (as used by gzip) to the PPP code.
++ * This version is for use with STREAMS under SunOS 4.x, Solaris 2,
++ * SVR4, OSF/1 and AIX 4.x.
++ *
++ * Copyright (c) 1994 The Australian National University.
++ * All rights reserved.
++ *
++ * Permission to use, copy, modify, and distribute this software and its
++ * documentation is hereby granted, provided that the above copyright
++ * notice appears in all copies. This software is provided without any
++ * warranty, express or implied. The Australian National University
++ * makes no representations about the suitability of this software for
++ * any purpose.
++ *
++ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
++ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
++ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
++ * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
++ * OF SUCH DAMAGE.
++ *
++ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
++ * ON AN &quot;AS IS&quot; BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
++ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
++ * OR MODIFICATIONS.
++ *
++ * $Id: deflate.c 195720 2001-06-11 11:44:34Z gc $
++ */
++
++#ifdef AIX4
++#include &lt;net/net_globals.h&gt;
++#endif
++#include &lt;sys/param.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/stream.h&gt;
++#include &lt;net/ppp_defs.h&gt;
++#include &quot;ppp_mod.h&quot;
++
++#define PACKETPTR mblk_t *
++#include &lt;net/ppp-comp.h&gt;
++
++#ifdef __osf__
++#include &quot;zlib.h&quot;
++#else
++#include &quot;../common/zlib.h&quot;
++#endif
++
++#if DO_DEFLATE
++
++#define DEFLATE_DEBUG 1
++
++/*
++ * State for a Deflate (de)compressor.
++ */
++struct deflate_state {
++ int seqno;
++ int w_size;
++ int unit;
++ int hdrlen;
++ int mru;
++ int debug;
++ z_stream strm;
++ struct compstat stats;
++};
++
++#define DEFLATE_OVHD 2 /* Deflate overhead/packet */
++
++static void *z_alloc __P((void *, u_int items, u_int size));
++static void *z_alloc_init __P((void *, u_int items, u_int size));
++static void z_free __P((void *, void *ptr));
++static void *z_comp_alloc __P((u_char *options, int opt_len));
++static void *z_decomp_alloc __P((u_char *options, int opt_len));
++static void z_comp_free __P((void *state));
++static void z_decomp_free __P((void *state));
++static int z_comp_init __P((void *state, u_char *options, int opt_len,
++ int unit, int hdrlen, int debug));
++static int z_decomp_init __P((void *state, u_char *options, int opt_len,
++ int unit, int hdrlen, int mru, int debug));
++static int z_compress __P((void *state, mblk_t **mret,
++ mblk_t *mp, int slen, int maxolen));
++static void z_incomp __P((void *state, mblk_t *dmsg));
++static int z_decompress __P((void *state, mblk_t *cmp,
++ mblk_t **dmpp));
++static void z_comp_reset __P((void *state));
++static void z_decomp_reset __P((void *state));
++static void z_comp_stats __P((void *state, struct compstat *stats));
++
++/*
++ * Procedures exported to ppp_comp.c.
++ */
++struct compressor ppp_deflate = {
++ CI_DEFLATE, /* compress_proto */
++ z_comp_alloc, /* comp_alloc */
++ z_comp_free, /* comp_free */
++ z_comp_init, /* comp_init */
++ z_comp_reset, /* comp_reset */
++ z_compress, /* compress */
++ z_comp_stats, /* comp_stat */
++ z_decomp_alloc, /* decomp_alloc */
++ z_decomp_free, /* decomp_free */
++ z_decomp_init, /* decomp_init */
++ z_decomp_reset, /* decomp_reset */
++ z_decompress, /* decompress */
++ z_incomp, /* incomp */
++ z_comp_stats, /* decomp_stat */
++};
++
++struct compressor ppp_deflate_draft = {
++ CI_DEFLATE_DRAFT, /* compress_proto */
++ z_comp_alloc, /* comp_alloc */
++ z_comp_free, /* comp_free */
++ z_comp_init, /* comp_init */
++ z_comp_reset, /* comp_reset */
++ z_compress, /* compress */
++ z_comp_stats, /* comp_stat */
++ z_decomp_alloc, /* decomp_alloc */
++ z_decomp_free, /* decomp_free */
++ z_decomp_init, /* decomp_init */
++ z_decomp_reset, /* decomp_reset */
++ z_decompress, /* decompress */
++ z_incomp, /* incomp */
++ z_comp_stats, /* decomp_stat */
++};
++
++#define DECOMP_CHUNK 512
++
++/*
++ * Space allocation and freeing routines for use by zlib routines.
++ */
++struct zchunk {
++ u_int size;
++ u_int guard;
++};
++
++#define GUARD_MAGIC 0x77a6011a
++
++static void *
++z_alloc_init(notused, items, size)
++ void *notused;
++ u_int items, size;
++{
++ struct zchunk *z;
++
++ size = items * size + sizeof(struct zchunk);
++#ifdef __osf__
++ z = (struct zchunk *) ALLOC_SLEEP(size);
++#else
++ z = (struct zchunk *) ALLOC_NOSLEEP(size);
++#endif
++ z-&gt;size = size;
++ z-&gt;guard = GUARD_MAGIC;
++ return (void *) (z + 1);
++}
++
++static void *
++z_alloc(notused, items, size)
++ void *notused;
++ u_int items, size;
++{
++ struct zchunk *z;
++
++ size = items * size + sizeof(struct zchunk);
++ z = (struct zchunk *) ALLOC_NOSLEEP(size);
++ z-&gt;size = size;
++ z-&gt;guard = GUARD_MAGIC;
++ return (void *) (z + 1);
++}
++
++static void
++z_free(notused, ptr)
++ void *notused;
++ void *ptr;
++{
++ struct zchunk *z = ((struct zchunk *) ptr) - 1;
++
++ if (z-&gt;guard != GUARD_MAGIC) {
++ printf(&quot;ppp: z_free of corrupted chunk at %x (%x, %x)\n&quot;,
++ z, z-&gt;size, z-&gt;guard);
++ return;
++ }
++ FREE(z, z-&gt;size);
++}
++
++/*
++ * Allocate space for a compressor.
++ */
++static void *
++z_comp_alloc(options, opt_len)
++ u_char *options;
++ int opt_len;
++{
++ struct deflate_state *state;
++ int w_size;
++
++ if (opt_len != CILEN_DEFLATE
++ || (options[0] != CI_DEFLATE &amp;&amp; options[0] != CI_DEFLATE_DRAFT)
++ || options[1] != CILEN_DEFLATE
++ || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
++ || options[3] != DEFLATE_CHK_SEQUENCE)
++ return NULL;
++ w_size = DEFLATE_SIZE(options[2]);
++ /*
++ * N.B. the 9 below should be DEFLATE_MIN_SIZE (8), but using
++ * 8 will cause kernel crashes because of a bug in zlib.
++ */
++ if (w_size &lt; 9 || w_size &gt; DEFLATE_MAX_SIZE)
++ return NULL;
++
++
++#ifdef __osf__
++ state = (struct deflate_state *) ALLOC_SLEEP(sizeof(*state));
++#else
++ state = (struct deflate_state *) ALLOC_NOSLEEP(sizeof(*state));
++#endif
++
++ if (state == NULL)
++ return NULL;
++
++ state-&gt;strm.next_in = NULL;
++ state-&gt;strm.zalloc = (alloc_func) z_alloc_init;
++ state-&gt;strm.zfree = (free_func) z_free;
++ if (deflateInit2(&amp;state-&gt;strm, Z_DEFAULT_COMPRESSION, DEFLATE_METHOD_VAL,
++ -w_size, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
++ FREE(state, sizeof(*state));
++ return NULL;
++ }
++
++ state-&gt;strm.zalloc = (alloc_func) z_alloc;
++ state-&gt;w_size = w_size;
++ bzero(&amp;state-&gt;stats, sizeof(state-&gt;stats));
++ return (void *) state;
++}
++
++static void
++z_comp_free(arg)
++ void *arg;
++{
++ struct deflate_state *state = (struct deflate_state *) arg;
++
++ deflateEnd(&amp;state-&gt;strm);
++ FREE(state, sizeof(*state));
++}
++
++static int
++z_comp_init(arg, options, opt_len, unit, hdrlen, debug)
++ void *arg;
++ u_char *options;
++ int opt_len, unit, hdrlen, debug;
++{
++ struct deflate_state *state = (struct deflate_state *) arg;
++
++ if (opt_len &lt; CILEN_DEFLATE
++ || (options[0] != CI_DEFLATE &amp;&amp; options[0] != CI_DEFLATE_DRAFT)
++ || options[1] != CILEN_DEFLATE
++ || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
++ || DEFLATE_SIZE(options[2]) != state-&gt;w_size
++ || options[3] != DEFLATE_CHK_SEQUENCE)
++ return 0;
++
++ state-&gt;seqno = 0;
++ state-&gt;unit = unit;
++ state-&gt;hdrlen = hdrlen;
++ state-&gt;debug = debug;
++
++ deflateReset(&amp;state-&gt;strm);
++
++ return 1;
++}
++
++static void
++z_comp_reset(arg)
++ void *arg;
++{
++ struct deflate_state *state = (struct deflate_state *) arg;
++
++ state-&gt;seqno = 0;
++ deflateReset(&amp;state-&gt;strm);
++}
++
++static int
++z_compress(arg, mret, mp, orig_len, maxolen)
++ void *arg;
++ mblk_t **mret; /* compressed packet (out) */
++ mblk_t *mp; /* uncompressed packet (in) */
++ int orig_len, maxolen;
++{
++ struct deflate_state *state = (struct deflate_state *) arg;
++ u_char *rptr, *wptr;
++ int proto, olen, wspace, r, flush;
++ mblk_t *m;
++
++ /*
++ * Check that the protocol is in the range we handle.
++ */
++ *mret = NULL;
++ rptr = mp-&gt;b_rptr;
++ if (rptr + PPP_HDRLEN &gt; mp-&gt;b_wptr) {
++ if (!pullupmsg(mp, PPP_HDRLEN))
++ return 0;
++ rptr = mp-&gt;b_rptr;
++ }
++ proto = PPP_PROTOCOL(rptr);
++ if (proto &gt; 0x3fff || proto == 0xfd || proto == 0xfb)
++ return orig_len;
++
++ /* Allocate one mblk initially. */
++ if (maxolen &gt; orig_len)
++ maxolen = orig_len;
++ if (maxolen &lt;= PPP_HDRLEN + 2) {
++ wspace = 0;
++ m = NULL;
++ } else {
++ wspace = maxolen + state-&gt;hdrlen;
++ if (wspace &gt; 4096)
++ wspace = 4096;
++ m = allocb(wspace, BPRI_MED);
++ }
++ if (m != NULL) {
++ *mret = m;
++ if (state-&gt;hdrlen + PPP_HDRLEN + 2 &lt; wspace) {
++ m-&gt;b_rptr += state-&gt;hdrlen;
++ m-&gt;b_wptr = m-&gt;b_rptr;
++ wspace -= state-&gt;hdrlen;
++ }
++ wptr = m-&gt;b_wptr;
++
++ /*
++ * Copy over the PPP header and store the 2-byte sequence number.
++ */
++ wptr[0] = PPP_ADDRESS(rptr);
++ wptr[1] = PPP_CONTROL(rptr);
++ wptr[2] = PPP_COMP &gt;&gt; 8;
++ wptr[3] = PPP_COMP;
++ wptr += PPP_HDRLEN;
++ wptr[0] = state-&gt;seqno &gt;&gt; 8;
++ wptr[1] = state-&gt;seqno;
++ wptr += 2;
++ state-&gt;strm.next_out = wptr;
++ state-&gt;strm.avail_out = wspace - (PPP_HDRLEN + 2);
++ } else {
++ state-&gt;strm.next_out = NULL;
++ state-&gt;strm.avail_out = 1000000;
++ }
++ ++state-&gt;seqno;
++
++ rptr += (proto &gt; 0xff)? 2: 3; /* skip 1st proto byte if 0 */
++ state-&gt;strm.next_in = rptr;
++ state-&gt;strm.avail_in = mp-&gt;b_wptr - rptr;
++ mp = mp-&gt;b_cont;
++ flush = (mp == NULL)? Z_PACKET_FLUSH: Z_NO_FLUSH;
++ olen = 0;
++ for (;;) {
++ r = deflate(&amp;state-&gt;strm, flush);
++ if (r != Z_OK) {
++ printf(&quot;z_compress: deflate returned %d (%s)\n&quot;,
++ r, (state-&gt;strm.msg? state-&gt;strm.msg: &quot;&quot;));
++ break;
++ }
++ if (flush != Z_NO_FLUSH &amp;&amp; state-&gt;strm.avail_out != 0)
++ break; /* all done */
++ if (state-&gt;strm.avail_in == 0 &amp;&amp; mp != NULL) {
++ state-&gt;strm.next_in = mp-&gt;b_rptr;
++ state-&gt;strm.avail_in = mp-&gt;b_wptr - mp-&gt;b_rptr;
++ mp = mp-&gt;b_cont;
++ if (mp == NULL)
++ flush = Z_PACKET_FLUSH;
++ }
++ if (state-&gt;strm.avail_out == 0) {
++ if (m != NULL) {
++ m-&gt;b_wptr += wspace;
++ olen += wspace;
++ wspace = maxolen - olen;
++ if (wspace &lt;= 0) {
++ wspace = 0;
++ m-&gt;b_cont = NULL;
++ } else {
++ if (wspace &lt; 32)
++ wspace = 32;
++ else if (wspace &gt; 4096)
++ wspace = 4096;
++ m-&gt;b_cont = allocb(wspace, BPRI_MED);
++ }
++ m = m-&gt;b_cont;
++ if (m != NULL) {
++ state-&gt;strm.next_out = m-&gt;b_wptr;
++ state-&gt;strm.avail_out = wspace;
++ }
++ }
++ if (m == NULL) {
++ state-&gt;strm.next_out = NULL;
++ state-&gt;strm.avail_out = 1000000;
++ }
++ }
++ }
++ if (m != NULL) {
++ m-&gt;b_wptr += wspace - state-&gt;strm.avail_out;
++ olen += wspace - state-&gt;strm.avail_out;
++ }
++
++ /*
++ * See if we managed to reduce the size of the packet.
++ */
++ if (olen &lt; orig_len &amp;&amp; m != NULL) {
++ state-&gt;stats.comp_bytes += olen;
++ state-&gt;stats.comp_packets++;
++ } else {
++ if (*mret != NULL) {
++ freemsg(*mret);
++ *mret = NULL;
++ }
++ state-&gt;stats.inc_bytes += orig_len;
++ state-&gt;stats.inc_packets++;
++ olen = orig_len;
++ }
++ state-&gt;stats.unc_bytes += orig_len;
++ state-&gt;stats.unc_packets++;
++
++ return olen;
++}
++
++static void
++z_comp_stats(arg, stats)
++ void *arg;
++ struct compstat *stats;
++{
++ struct deflate_state *state = (struct deflate_state *) arg;
++ u_int out;
++
++ *stats = state-&gt;stats;
++ stats-&gt;ratio = stats-&gt;unc_bytes;
++ out = stats-&gt;comp_bytes + stats-&gt;unc_bytes;
++ if (stats-&gt;ratio &lt;= 0x7ffffff)
++ stats-&gt;ratio &lt;&lt;= 8;
++ else
++ out &gt;&gt;= 8;
++ if (out != 0)
++ stats-&gt;ratio /= out;
++}
++
++/*
++ * Allocate space for a decompressor.
++ */
++static void *
++z_decomp_alloc(options, opt_len)
++ u_char *options;
++ int opt_len;
++{
++ struct deflate_state *state;
++ int w_size;
++
++ if (opt_len != CILEN_DEFLATE
++ || (options[0] != CI_DEFLATE &amp;&amp; options[0] != CI_DEFLATE_DRAFT)
++ || options[1] != CILEN_DEFLATE
++ || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
++ || options[3] != DEFLATE_CHK_SEQUENCE)
++ return NULL;
++ w_size = DEFLATE_SIZE(options[2]);
++ /*
++ * N.B. the 9 below should be DEFLATE_MIN_SIZE (8), but using
++ * 8 will cause kernel crashes because of a bug in zlib.
++ */
++ if (w_size &lt; 9 || w_size &gt; DEFLATE_MAX_SIZE)
++ return NULL;
++
++#ifdef __osf__
++ state = (struct deflate_state *) ALLOC_SLEEP(sizeof(*state));
++#else
++ state = (struct deflate_state *) ALLOC_NOSLEEP(sizeof(*state));
++#endif
++ if (state == NULL)
++ return NULL;
++
++ state-&gt;strm.next_out = NULL;
++ state-&gt;strm.zalloc = (alloc_func) z_alloc_init;
++ state-&gt;strm.zfree = (free_func) z_free;
++ if (inflateInit2(&amp;state-&gt;strm, -w_size) != Z_OK) {
++ FREE(state, sizeof(*state));
++ return NULL;
++ }
++
++ state-&gt;strm.zalloc = (alloc_func) z_alloc;
++ state-&gt;w_size = w_size;
++ bzero(&amp;state-&gt;stats, sizeof(state-&gt;stats));
++ return (void *) state;
++}
++
++static void
++z_decomp_free(arg)
++ void *arg;
++{
++ struct deflate_state *state = (struct deflate_state *) arg;
++
++ inflateEnd(&amp;state-&gt;strm);
++ FREE(state, sizeof(*state));
++}
++
++static int
++z_decomp_init(arg, options, opt_len, unit, hdrlen, mru, debug)
++ void *arg;
++ u_char *options;
++ int opt_len, unit, hdrlen, mru, debug;
++{
++ struct deflate_state *state = (struct deflate_state *) arg;
++
++ if (opt_len &lt; CILEN_DEFLATE
++ || (options[0] != CI_DEFLATE &amp;&amp; options[0] != CI_DEFLATE_DRAFT)
++ || options[1] != CILEN_DEFLATE
++ || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
++ || DEFLATE_SIZE(options[2]) != state-&gt;w_size
++ || options[3] != DEFLATE_CHK_SEQUENCE)
++ return 0;
++
++ state-&gt;seqno = 0;
++ state-&gt;unit = unit;
++ state-&gt;hdrlen = hdrlen;
++ state-&gt;debug = debug;
++ state-&gt;mru = mru;
++
++ inflateReset(&amp;state-&gt;strm);
++
++ return 1;
++}
++
++static void
++z_decomp_reset(arg)
++ void *arg;
++{
++ struct deflate_state *state = (struct deflate_state *) arg;
++
++ state-&gt;seqno = 0;
++ inflateReset(&amp;state-&gt;strm);
++}
++
++/*
++ * Decompress a Deflate-compressed packet.
++ *
++ * Because of patent problems, we return DECOMP_ERROR for errors
++ * found by inspecting the input data and for system problems, but
++ * DECOMP_FATALERROR for any errors which could possibly be said to
++ * be being detected &quot;after&quot; decompression. For DECOMP_ERROR,
++ * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
++ * infringing a patent of Motorola's if we do, so we take CCP down
++ * instead.
++ *
++ * Given that the frame has the correct sequence number and a good FCS,
++ * errors such as invalid codes in the input most likely indicate a
++ * bug, so we return DECOMP_FATALERROR for them in order to turn off
++ * compression, even though they are detected by inspecting the input.
++ */
++static int
++z_decompress(arg, mi, mop)
++ void *arg;
++ mblk_t *mi, **mop;
++{
++ struct deflate_state *state = (struct deflate_state *) arg;
++ mblk_t *mo, *mo_head;
++ u_char *rptr, *wptr;
++ int rlen, olen, ospace;
++ int seq, i, flush, r, decode_proto;
++ u_char hdr[PPP_HDRLEN + DEFLATE_OVHD];
++
++ *mop = NULL;
++ rptr = mi-&gt;b_rptr;
++ for (i = 0; i &lt; PPP_HDRLEN + DEFLATE_OVHD; ++i) {
++ while (rptr &gt;= mi-&gt;b_wptr) {
++ mi = mi-&gt;b_cont;
++ if (mi == NULL)
++ return DECOMP_ERROR;
++ rptr = mi-&gt;b_rptr;
++ }
++ hdr[i] = *rptr++;
++ }
++
++ /* Check the sequence number. */
++ seq = (hdr[PPP_HDRLEN] &lt;&lt; 8) + hdr[PPP_HDRLEN+1];
++ if (seq != state-&gt;seqno) {
++#if !DEFLATE_DEBUG
++ if (state-&gt;debug)
++#endif
++ printf(&quot;z_decompress%d: bad seq # %d, expected %d\n&quot;,
++ state-&gt;unit, seq, state-&gt;seqno);
++ return DECOMP_ERROR;
++ }
++ ++state-&gt;seqno;
++
++ /* Allocate an output message block. */
++ mo = allocb(DECOMP_CHUNK + state-&gt;hdrlen, BPRI_MED);
++ if (mo == NULL)
++ return DECOMP_ERROR;
++ mo_head = mo;
++ mo-&gt;b_cont = NULL;
++ mo-&gt;b_rptr += state-&gt;hdrlen;
++ mo-&gt;b_wptr = wptr = mo-&gt;b_rptr;
++ ospace = DECOMP_CHUNK;
++ olen = 0;
++
++ /*
++ * Fill in the first part of the PPP header. The protocol field
++ * comes from the decompressed data.
++ */
++ wptr[0] = PPP_ADDRESS(hdr);
++ wptr[1] = PPP_CONTROL(hdr);
++ wptr[2] = 0;
++
++ /*
++ * Set up to call inflate. We set avail_out to 1 initially so we can
++ * look at the first byte of the output and decide whether we have
++ * a 1-byte or 2-byte protocol field.
++ */
++ state-&gt;strm.next_in = rptr;
++ state-&gt;strm.avail_in = mi-&gt;b_wptr - rptr;
++ mi = mi-&gt;b_cont;
++ flush = (mi == NULL)? Z_PACKET_FLUSH: Z_NO_FLUSH;
++ rlen = state-&gt;strm.avail_in + PPP_HDRLEN + DEFLATE_OVHD;
++ state-&gt;strm.next_out = wptr + 3;
++ state-&gt;strm.avail_out = 1;
++ decode_proto = 1;
++
++ /*
++ * Call inflate, supplying more input or output as needed.
++ */
++ for (;;) {
++ r = inflate(&amp;state-&gt;strm, flush);
++ if (r != Z_OK) {
++#if !DEFLATE_DEBUG
++ if (state-&gt;debug)
++#endif
++ printf(&quot;z_decompress%d: inflate returned %d (%s)\n&quot;,
++ state-&gt;unit, r, (state-&gt;strm.msg? state-&gt;strm.msg: &quot;&quot;));
++ freemsg(mo_head);
++ return DECOMP_FATALERROR;
++ }
++ if (flush != Z_NO_FLUSH &amp;&amp; state-&gt;strm.avail_out != 0)
++ break; /* all done */
++ if (state-&gt;strm.avail_in == 0 &amp;&amp; mi != NULL) {
++ state-&gt;strm.next_in = mi-&gt;b_rptr;
++ state-&gt;strm.avail_in = mi-&gt;b_wptr - mi-&gt;b_rptr;
++ rlen += state-&gt;strm.avail_in;
++ mi = mi-&gt;b_cont;
++ if (mi == NULL)
++ flush = Z_PACKET_FLUSH;
++ }
++ if (state-&gt;strm.avail_out == 0) {
++ if (decode_proto) {
++ state-&gt;strm.avail_out = ospace - PPP_HDRLEN;
++ if ((wptr[3] &amp; 1) == 0) {
++ /* 2-byte protocol field */
++ wptr[2] = wptr[3];
++ --state-&gt;strm.next_out;
++ ++state-&gt;strm.avail_out;
++ }
++ decode_proto = 0;
++ } else {
++ mo-&gt;b_wptr += ospace;
++ olen += ospace;
++ mo-&gt;b_cont = allocb(DECOMP_CHUNK, BPRI_MED);
++ mo = mo-&gt;b_cont;
++ if (mo == NULL) {
++ freemsg(mo_head);
++ return DECOMP_ERROR;
++ }
++ state-&gt;strm.next_out = mo-&gt;b_rptr;
++ state-&gt;strm.avail_out = ospace = DECOMP_CHUNK;
++ }
++ }
++ }
++ if (decode_proto) {
++ freemsg(mo_head);
++ return DECOMP_ERROR;
++ }
++ mo-&gt;b_wptr += ospace - state-&gt;strm.avail_out;
++ olen += ospace - state-&gt;strm.avail_out;
++
++#if DEFLATE_DEBUG
++ if (olen &gt; state-&gt;mru + PPP_HDRLEN)
++ printf(&quot;ppp_deflate%d: exceeded mru (%d &gt; %d)\n&quot;,
++ state-&gt;unit, olen, state-&gt;mru + PPP_HDRLEN);
++#endif
++
++ state-&gt;stats.unc_bytes += olen;
++ state-&gt;stats.unc_packets++;
++ state-&gt;stats.comp_bytes += rlen;
++ state-&gt;stats.comp_packets++;
++
++ *mop = mo_head;
++ return DECOMP_OK;
++}
++
++/*
++ * Incompressible data has arrived - add it to the history.
++ */
++static void
++z_incomp(arg, mi)
++ void *arg;
++ mblk_t *mi;
++{
++ struct deflate_state *state = (struct deflate_state *) arg;
++ u_char *rptr;
++ int rlen, proto, r;
++
++ /*
++ * Check that the protocol is one we handle.
++ */
++ rptr = mi-&gt;b_rptr;
++ if (rptr + PPP_HDRLEN &gt; mi-&gt;b_wptr) {
++ if (!pullupmsg(mi, PPP_HDRLEN))
++ return;
++ rptr = mi-&gt;b_rptr;
++ }
++ proto = PPP_PROTOCOL(rptr);
++ if (proto &gt; 0x3fff || proto == 0xfd || proto == 0xfb)
++ return;
++
++ ++state-&gt;seqno;
++
++ /*
++ * Iterate through the message blocks, adding the characters in them
++ * to the decompressor's history. For the first block, we start
++ * at the either the 1st or 2nd byte of the protocol field,
++ * depending on whether the protocol value is compressible.
++ */
++ rlen = mi-&gt;b_wptr - mi-&gt;b_rptr;
++ state-&gt;strm.next_in = rptr + 3;
++ state-&gt;strm.avail_in = rlen - 3;
++ if (proto &gt; 0xff) {
++ --state-&gt;strm.next_in;
++ ++state-&gt;strm.avail_in;
++ }
++ for (;;) {
++ r = inflateIncomp(&amp;state-&gt;strm);
++ if (r != Z_OK) {
++ /* gak! */
++#if !DEFLATE_DEBUG
++ if (state-&gt;debug)
++#endif
++ printf(&quot;z_incomp%d: inflateIncomp returned %d (%s)\n&quot;,
++ state-&gt;unit, r, (state-&gt;strm.msg? state-&gt;strm.msg: &quot;&quot;));
++ return;
++ }
++ mi = mi-&gt;b_cont;
++ if (mi == NULL)
++ break;
++ state-&gt;strm.next_in = mi-&gt;b_rptr;
++ state-&gt;strm.avail_in = mi-&gt;b_wptr - mi-&gt;b_rptr;
++ rlen += state-&gt;strm.avail_in;
++ }
++
++ /*
++ * Update stats.
++ */
++ state-&gt;stats.inc_bytes += rlen;
++ state-&gt;stats.inc_packets++;
++ state-&gt;stats.unc_bytes += rlen;
++ state-&gt;stats.unc_packets++;
++}
++
++#endif /* DO_DEFLATE */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/modules/deflate.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/modules/if_ppp.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/modules/if_ppp.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/modules/if_ppp.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,865 @@
++/*
++ * if_ppp.c - a network interface connected to a STREAMS module.
++ *
++ * Copyright (c) 1994 The Australian National University.
++ * All rights reserved.
++ *
++ * Permission to use, copy, modify, and distribute this software and its
++ * documentation is hereby granted, provided that the above copyright
++ * notice appears in all copies. This software is provided without any
++ * warranty, express or implied. The Australian National University
++ * makes no representations about the suitability of this software for
++ * any purpose.
++ *
++ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
++ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
++ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
++ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
++ * OF SUCH DAMAGE.
++ *
++ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
++ * ON AN &quot;AS IS&quot; BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
++ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
++ * OR MODIFICATIONS.
++ *
++ * $Id: if_ppp.c 195720 2001-06-11 11:44:34Z gc $
++ */
++
++/*
++ * This file is used under SunOS 4 and Digital UNIX.
++ *
++ * This file provides the glue between PPP and IP.
++ */
++
++#define INET 1
++
++#include &lt;sys/types.h&gt;
++#include &lt;sys/param.h&gt;
++#include &lt;sys/errno.h&gt;
++#include &lt;sys/mbuf.h&gt;
++#include &lt;sys/socket.h&gt;
++#include &lt;net/if.h&gt;
++#include &lt;net/netisr.h&gt;
++#include &lt;net/ppp_defs.h&gt;
++#include &lt;net/pppio.h&gt;
++#include &lt;netinet/in.h&gt;
++#include &lt;netinet/in_var.h&gt;
++#ifdef __osf__
++#include &lt;sys/ioctl.h&gt;
++#include &lt;net/if_types.h&gt;
++#else
++#include &lt;sys/sockio.h&gt;
++#endif
++#include &quot;ppp_mod.h&quot;
++
++#include &lt;sys/stream.h&gt;
++
++#ifdef SNIT_SUPPORT
++#include &lt;sys/time.h&gt;
++#include &lt;net/nit_if.h&gt;
++#include &lt;netinet/if_ether.h&gt;
++#endif
++
++#ifdef __osf__
++#define SIOCSIFMTU SIOCSIPMTU
++#define SIOCGIFMTU SIOCRIPMTU
++#define IFA_ADDR(ifa) (*(ifa)-&gt;ifa_addr)
++#else
++#define IFA_ADDR(ifa) ((ifa)-&gt;ifa_addr)
++#endif
++
++#define ifr_mtu ifr_metric
++
++static int if_ppp_open __P((queue_t *, int, int, int));
++static int if_ppp_close __P((queue_t *, int));
++static int if_ppp_wput __P((queue_t *, mblk_t *));
++static int if_ppp_rput __P((queue_t *, mblk_t *));
++
++#define PPP_IF_ID 0x8021
++static struct module_info minfo = {
++ PPP_IF_ID, &quot;if_ppp&quot;, 0, INFPSZ, 4096, 128
++};
++
++static struct qinit rinit = {
++ if_ppp_rput, NULL, if_ppp_open, if_ppp_close, NULL, &amp;minfo, NULL
++};
++
++static struct qinit winit = {
++ if_ppp_wput, NULL, NULL, NULL, NULL, &amp;minfo, NULL
++};
++
++struct streamtab if_pppinfo = {
++ &amp;rinit, &amp;winit, NULL, NULL
++};
++
++typedef struct if_ppp_state {
++ int unit;
++ queue_t *q;
++ int flags;
++} if_ppp_t;
++
++/* Values for flags */
++#define DBGLOG 1
++
++static int if_ppp_count; /* Number of currently-active streams */
++
++static int ppp_nalloc; /* Number of elements of ifs and states */
++static struct ifnet **ifs; /* Array of pointers to interface structs */
++static if_ppp_t **states; /* Array of pointers to state structs */
++
++static int if_ppp_output __P((struct ifnet *, struct mbuf *,
++ struct sockaddr *));
++static int if_ppp_ioctl __P((struct ifnet *, u_int, caddr_t));
++static struct mbuf *make_mbufs __P((mblk_t *, int));
++static mblk_t *make_message __P((struct mbuf *, int));
++
++#ifdef SNIT_SUPPORT
++/* Fake ether header for SNIT */
++static struct ether_header snit_ehdr = {{0}, {0}, ETHERTYPE_IP};
++#endif
++
++#ifndef __osf__
++static void ppp_if_detach __P((struct ifnet *));
++
++/*
++ * Detach all the interfaces before unloading.
++ * Not sure this works.
++ */
++int
++if_ppp_unload()
++{
++ int i;
++
++ if (if_ppp_count &gt; 0)
++ return EBUSY;
++ for (i = 0; i &lt; ppp_nalloc; ++i)
++ if (ifs[i] != 0)
++ ppp_if_detach(ifs[i]);
++ if (ifs) {
++ FREE(ifs, ppp_nalloc * sizeof (struct ifnet *));
++ FREE(states, ppp_nalloc * sizeof (struct if_ppp_t *));
++ }
++ ppp_nalloc = 0;
++ return 0;
++}
++#endif /* __osf__ */
++
++/*
++ * STREAMS module entry points.
++ */
++static int
++if_ppp_open(q, dev, flag, sflag)
++ queue_t *q;
++ int dev;
++ int flag, sflag;
++{
++ if_ppp_t *sp;
++
++ if (q-&gt;q_ptr == 0) {
++ sp = (if_ppp_t *) ALLOC_SLEEP(sizeof (if_ppp_t));
++ if (sp == 0)
++ return OPENFAIL;
++ bzero(sp, sizeof (if_ppp_t));
++ q-&gt;q_ptr = (caddr_t) sp;
++ WR(q)-&gt;q_ptr = (caddr_t) sp;
++ sp-&gt;unit = -1; /* no interface unit attached at present */
++ sp-&gt;q = WR(q);
++ sp-&gt;flags = 0;
++ ++if_ppp_count;
++ }
++ return 0;
++}
++
++static int
++if_ppp_close(q, flag)
++ queue_t *q;
++ int flag;
++{
++ if_ppp_t *sp;
++ struct ifnet *ifp;
++
++ sp = (if_ppp_t *) q-&gt;q_ptr;
++ if (sp != 0) {
++ if (sp-&gt;flags &amp; DBGLOG)
++ printf(&quot;if_ppp closed, q=%x sp=%x\n&quot;, q, sp);
++ if (sp-&gt;unit &gt;= 0) {
++ if (sp-&gt;unit &lt; ppp_nalloc) {
++ states[sp-&gt;unit] = 0;
++ ifp = ifs[sp-&gt;unit];
++ if (ifp != 0)
++ ifp-&gt;if_flags &amp;= ~(IFF_UP | IFF_RUNNING);
++#ifdef DEBUG
++ } else {
++ printf(&quot;if_ppp: unit %d nonexistent!\n&quot;, sp-&gt;unit);
++#endif
++ }
++ }
++ FREE(sp, sizeof (if_ppp_t));
++ --if_ppp_count;
++ }
++ return 0;
++}
++
++static int
++if_ppp_wput(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ if_ppp_t *sp;
++ struct iocblk *iop;
++ int error, unit;
++ struct ifnet *ifp;
++
++ sp = (if_ppp_t *) q-&gt;q_ptr;
++ switch (mp-&gt;b_datap-&gt;db_type) {
++ case M_DATA:
++ /*
++ * Now why would we be getting data coming in here??
++ */
++ if (sp-&gt;flags &amp; DBGLOG)
++ printf(&quot;if_ppp: got M_DATA len=%d\n&quot;, msgdsize(mp));
++ freemsg(mp);
++ break;
++
++ case M_IOCTL:
++ iop = (struct iocblk *) mp-&gt;b_rptr;
++ error = EINVAL;
++
++ if (sp-&gt;flags &amp; DBGLOG)
++ printf(&quot;if_ppp: got ioctl cmd=%x count=%d\n&quot;,
++ iop-&gt;ioc_cmd, iop-&gt;ioc_count);
++
++ switch (iop-&gt;ioc_cmd) {
++ case PPPIO_NEWPPA: /* well almost */
++ if (iop-&gt;ioc_count != sizeof(int) || sp-&gt;unit &gt;= 0)
++ break;
++ if ((error = NOTSUSER()) != 0)
++ break;
++ unit = *(int *)mp-&gt;b_cont-&gt;b_rptr;
++
++ /* Check that this unit isn't already in use */
++ if (unit &lt; ppp_nalloc &amp;&amp; states[unit] != 0) {
++ error = EADDRINUSE;
++ break;
++ }
++
++ /* Extend ifs and states arrays if necessary. */
++ error = ENOSR;
++ if (unit &gt;= ppp_nalloc) {
++ int newn;
++ struct ifnet **newifs;
++ if_ppp_t **newstates;
++
++ newn = unit + 4;
++ if (sp-&gt;flags &amp; DBGLOG)
++ printf(&quot;if_ppp: extending ifs to %d\n&quot;, newn);
++ newifs = (struct ifnet **)
++ ALLOC_NOSLEEP(newn * sizeof (struct ifnet *));
++ if (newifs == 0)
++ break;
++ bzero(newifs, newn * sizeof (struct ifnet *));
++ newstates = (if_ppp_t **)
++ ALLOC_NOSLEEP(newn * sizeof (struct if_ppp_t *));
++ if (newstates == 0) {
++ FREE(newifs, newn * sizeof (struct ifnet *));
++ break;
++ }
++ bzero(newstates, newn * sizeof (struct if_ppp_t *));
++ bcopy(ifs, newifs, ppp_nalloc * sizeof(struct ifnet *));
++ bcopy(states, newstates, ppp_nalloc * sizeof(if_ppp_t *));
++ if (ifs) {
++ FREE(ifs, ppp_nalloc * sizeof(struct ifnet *));
++ FREE(states, ppp_nalloc * sizeof(if_ppp_t *));
++ }
++ ifs = newifs;
++ states = newstates;
++ ppp_nalloc = newn;
++ }
++
++ /* Allocate a new ifnet struct if necessary. */
++ ifp = ifs[unit];
++ if (ifp == 0) {
++ ifp = (struct ifnet *) ALLOC_NOSLEEP(sizeof (struct ifnet));
++ if (ifp == 0)
++ break;
++ bzero(ifp, sizeof (struct ifnet));
++ ifs[unit] = ifp;
++ ifp-&gt;if_name = &quot;ppp&quot;;
++ ifp-&gt;if_unit = unit;
++ ifp-&gt;if_mtu = PPP_MTU;
++ ifp-&gt;if_flags = IFF_POINTOPOINT | IFF_RUNNING;
++#ifndef __osf__
++#ifdef IFF_MULTICAST
++ ifp-&gt;if_flags |= IFF_MULTICAST;
++#endif
++#endif /* __osf__ */
++ ifp-&gt;if_output = if_ppp_output;
++#ifdef __osf__
++ ifp-&gt;if_version = &quot;Point-to-Point Protocol, version 2.3.11&quot;;
++ ifp-&gt;if_mediamtu = PPP_MTU;
++ ifp-&gt;if_type = IFT_PPP;
++ ifp-&gt;if_hdrlen = PPP_HDRLEN;
++ ifp-&gt;if_addrlen = 0;
++ ifp-&gt;if_flags |= IFF_NOARP | IFF_SIMPLEX | IFF_NOTRAILERS;
++#ifdef IFF_VAR_MTU
++ ifp-&gt;if_flags |= IFF_VAR_MTU;
++#endif
++#ifdef NETMASTERCPU
++ ifp-&gt;if_affinity = NETMASTERCPU;
++#endif
++#endif
++ ifp-&gt;if_ioctl = if_ppp_ioctl;
++ ifp-&gt;if_snd.ifq_maxlen = IFQ_MAXLEN;
++ if_attach(ifp);
++ if (sp-&gt;flags &amp; DBGLOG)
++ printf(&quot;if_ppp: created unit %d\n&quot;, unit);
++ } else {
++ ifp-&gt;if_mtu = PPP_MTU;
++ ifp-&gt;if_flags |= IFF_RUNNING;
++ }
++
++ states[unit] = sp;
++ sp-&gt;unit = unit;
++
++ error = 0;
++ iop-&gt;ioc_count = 0;
++ if (sp-&gt;flags &amp; DBGLOG)
++ printf(&quot;if_ppp: attached unit %d, sp=%x q=%x\n&quot;, unit,
++ sp, sp-&gt;q);
++ break;
++
++ case PPPIO_DEBUG:
++ error = -1;
++ if (iop-&gt;ioc_count == sizeof(int)) {
++ if (*(int *)mp-&gt;b_cont-&gt;b_rptr == PPPDBG_LOG + PPPDBG_IF) {
++ printf(&quot;if_ppp: debug log enabled, q=%x sp=%x\n&quot;, q, sp);
++ sp-&gt;flags |= DBGLOG;
++ error = 0;
++ iop-&gt;ioc_count = 0;
++ }
++ }
++ break;
++
++ default:
++ error = -1;
++ break;
++ }
++
++ if (sp-&gt;flags &amp; DBGLOG)
++ printf(&quot;if_ppp: ioctl result %d\n&quot;, error);
++ if (error &lt; 0)
++ putnext(q, mp);
++ else if (error == 0) {
++ mp-&gt;b_datap-&gt;db_type = M_IOCACK;
++ qreply(q, mp);
++ } else {
++ mp-&gt;b_datap-&gt;db_type = M_IOCNAK;
++ iop-&gt;ioc_count = 0;
++ iop-&gt;ioc_error = error;
++ qreply(q, mp);
++ }
++ break;
++
++ default:
++ putnext(q, mp);
++ }
++ return 0;
++}
++
++static int
++if_ppp_rput(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ if_ppp_t *sp;
++ int proto, s;
++ struct mbuf *mb;
++ struct ifqueue *inq;
++ struct ifnet *ifp;
++ int len;
++
++ sp = (if_ppp_t *) q-&gt;q_ptr;
++ switch (mp-&gt;b_datap-&gt;db_type) {
++ case M_DATA:
++ /*
++ * Convert the message into an mbuf chain
++ * and inject it into the network code.
++ */
++ if (sp-&gt;flags &amp; DBGLOG)
++ printf(&quot;if_ppp: rput pkt len %d data %x %x %x %x %x %x %x %x\n&quot;,
++ msgdsize(mp), mp-&gt;b_rptr[0], mp-&gt;b_rptr[1], mp-&gt;b_rptr[2],
++ mp-&gt;b_rptr[3], mp-&gt;b_rptr[4], mp-&gt;b_rptr[5], mp-&gt;b_rptr[6],
++ mp-&gt;b_rptr[7]);
++
++ if (sp-&gt;unit &lt; 0) {
++ freemsg(mp);
++ break;
++ }
++ if (sp-&gt;unit &gt;= ppp_nalloc || (ifp = ifs[sp-&gt;unit]) == 0) {
++#ifdef DEBUG
++ printf(&quot;if_ppp: no unit %d!\n&quot;, sp-&gt;unit);
++#endif
++ freemsg(mp);
++ break;
++ }
++
++ if ((ifp-&gt;if_flags &amp; IFF_UP) == 0) {
++ freemsg(mp);
++ break;
++ }
++ ++ifp-&gt;if_ipackets;
++
++ proto = PPP_PROTOCOL(mp-&gt;b_rptr);
++ adjmsg(mp, PPP_HDRLEN);
++ len = msgdsize(mp);
++ mb = make_mbufs(mp, sizeof(struct ifnet *));
++ freemsg(mp);
++ if (mb == NULL) {
++ if (sp-&gt;flags &amp; DBGLOG)
++ printf(&quot;if_ppp%d: make_mbufs failed\n&quot;, ifp-&gt;if_unit);
++ ++ifp-&gt;if_ierrors;
++ break;
++ }
++
++#ifdef SNIT_SUPPORT
++ if (proto == PPP_IP &amp;&amp; (ifp-&gt;if_flags &amp; IFF_PROMISC)) {
++ struct nit_if nif;
++
++ nif.nif_header = (caddr_t) &amp;snit_ehdr;
++ nif.nif_hdrlen = sizeof(snit_ehdr);
++ nif.nif_bodylen = len;
++ nif.nif_promisc = 0;
++ snit_intr(ifp, mb, &amp;nif);
++ }
++#endif
++
++/*
++ * For Digital UNIX, there's space set aside in the header mbuf
++ * for the interface info.
++ *
++ * For Sun it's smuggled around via a pointer at the front of the mbuf.
++ */
++#ifdef __osf__
++ mb-&gt;m_pkthdr.rcvif = ifp;
++ mb-&gt;m_pkthdr.len = len;
++#else
++ mb-&gt;m_off -= sizeof(struct ifnet *);
++ mb-&gt;m_len += sizeof(struct ifnet *);
++ *mtod(mb, struct ifnet **) = ifp;
++#endif
++
++ inq = 0;
++ switch (proto) {
++ case PPP_IP:
++ inq = &amp;ipintrq;
++ schednetisr(NETISR_IP);
++ }
++
++ if (inq != 0) {
++ s = splhigh();
++ if (IF_QFULL(inq)) {
++ IF_DROP(inq);
++ ++ifp-&gt;if_ierrors;
++ if (sp-&gt;flags &amp; DBGLOG)
++ printf(&quot;if_ppp: inq full, proto=%x\n&quot;, proto);
++ m_freem(mb);
++ } else {
++ IF_ENQUEUE(inq, mb);
++ }
++ splx(s);
++ } else {
++ if (sp-&gt;flags &amp; DBGLOG)
++ printf(&quot;if_ppp%d: proto=%x?\n&quot;, ifp-&gt;if_unit, proto);
++ ++ifp-&gt;if_ierrors;
++ m_freem(mb);
++ }
++ break;
++
++ default:
++ putnext(q, mp);
++ }
++ return 0;
++}
++
++/*
++ * Network code wants to output a packet.
++ * Turn it into a STREAMS message and send it down.
++ */
++static int
++if_ppp_output(ifp, m0, dst)
++ struct ifnet *ifp;
++ struct mbuf *m0;
++ struct sockaddr *dst;
++{
++ mblk_t *mp;
++ int proto, s;
++ if_ppp_t *sp;
++ u_char *p;
++
++ if ((ifp-&gt;if_flags &amp; IFF_UP) == 0) {
++ m_freem(m0);
++ return ENETDOWN;
++ }
++
++ if ((unsigned)ifp-&gt;if_unit &gt;= ppp_nalloc) {
++#ifdef DEBUG
++ printf(&quot;if_ppp_output: unit %d?\n&quot;, ifp-&gt;if_unit);
++#endif
++ m_freem(m0);
++ return EINVAL;
++ }
++ sp = states[ifp-&gt;if_unit];
++ if (sp == 0) {
++#ifdef DEBUG
++ printf(&quot;if_ppp_output: no queue?\n&quot;);
++#endif
++ m_freem(m0);
++ return ENETDOWN;
++ }
++
++ if (sp-&gt;flags &amp; DBGLOG) {
++ p = mtod(m0, u_char *);
++ printf(&quot;if_ppp_output%d: af=%d data=%x %x %x %x %x %x %x %x q=%x\n&quot;,
++ ifp-&gt;if_unit, dst-&gt;sa_family, p[0], p[1], p[2], p[3], p[4],
++ p[5], p[6], p[7], sp-&gt;q);
++ }
++
++ switch (dst-&gt;sa_family) {
++ case AF_INET:
++ proto = PPP_IP;
++#ifdef SNIT_SUPPORT
++ if (ifp-&gt;if_flags &amp; IFF_PROMISC) {
++ struct nit_if nif;
++ struct mbuf *m;
++ int len;
++
++ for (len = 0, m = m0; m != NULL; m = m-&gt;m_next)
++ len += m-&gt;m_len;
++ nif.nif_header = (caddr_t) &amp;snit_ehdr;
++ nif.nif_hdrlen = sizeof(snit_ehdr);
++ nif.nif_bodylen = len;
++ nif.nif_promisc = 0;
++ snit_intr(ifp, m0, &amp;nif);
++ }
++#endif
++ break;
++
++ default:
++ m_freem(m0);
++ return EAFNOSUPPORT;
++ }
++
++ ++ifp-&gt;if_opackets;
++ mp = make_message(m0, PPP_HDRLEN);
++ m_freem(m0);
++ if (mp == 0) {
++ ++ifp-&gt;if_oerrors;
++ return ENOBUFS;
++ }
++ mp-&gt;b_rptr -= PPP_HDRLEN;
++ mp-&gt;b_rptr[0] = PPP_ALLSTATIONS;
++ mp-&gt;b_rptr[1] = PPP_UI;
++ mp-&gt;b_rptr[2] = proto &gt;&gt; 8;
++ mp-&gt;b_rptr[3] = proto;
++
++ s = splstr();
++ if (sp-&gt;flags &amp; DBGLOG)
++ printf(&quot;if_ppp: putnext(%x, %x), r=%x w=%x p=%x\n&quot;,
++ sp-&gt;q, mp, mp-&gt;b_rptr, mp-&gt;b_wptr, proto);
++ putnext(sp-&gt;q, mp);
++ splx(s);
++
++ return 0;
++}
++
++/*
++ * Socket ioctl routine for ppp interfaces.
++ */
++static int
++if_ppp_ioctl(ifp, cmd, data)
++ struct ifnet *ifp;
++ u_int cmd;
++ caddr_t data;
++{
++ int s, error;
++ struct ifreq *ifr = (struct ifreq *) data;
++ struct ifaddr *ifa = (struct ifaddr *) data;
++ u_short mtu;
++
++ error = 0;
++ s = splimp();
++ switch (cmd) {
++ case SIOCSIFFLAGS:
++ if ((ifp-&gt;if_flags &amp; IFF_RUNNING) == 0)
++ ifp-&gt;if_flags &amp;= ~IFF_UP;
++ break;
++
++ case SIOCSIFADDR:
++ if (IFA_ADDR(ifa).sa_family != AF_INET)
++ error = EAFNOSUPPORT;
++ break;
++
++ case SIOCSIFDSTADDR:
++ if (IFA_ADDR(ifa).sa_family != AF_INET)
++ error = EAFNOSUPPORT;
++ break;
++
++ case SIOCSIFMTU:
++ if ((error = NOTSUSER()) != 0)
++ break;
++#ifdef __osf__
++ /* this hack is necessary because ifioctl checks ifr_data
++ * in 4.0 and 5.0, but ifr_data and ifr_metric overlay each
++ * other in the definition of struct ifreq so pppd can't set both.
++ */
++ bcopy(ifr-&gt;ifr_data, &amp;mtu, sizeof (u_short));
++ ifr-&gt;ifr_mtu = mtu;
++#endif
++
++ if (ifr-&gt;ifr_mtu &lt; PPP_MINMTU || ifr-&gt;ifr_mtu &gt; PPP_MAXMTU) {
++ error = EINVAL;
++ break;
++ }
++ ifp-&gt;if_mtu = ifr-&gt;ifr_mtu;
++ break;
++
++ case SIOCGIFMTU:
++ ifr-&gt;ifr_mtu = ifp-&gt;if_mtu;
++ break;
++
++ case SIOCADDMULTI:
++ case SIOCDELMULTI:
++ switch(ifr-&gt;ifr_addr.sa_family) {
++ case AF_INET:
++ break;
++ default:
++ error = EAFNOSUPPORT;
++ break;
++ }
++ break;
++
++ default:
++ error = EINVAL;
++ }
++ splx(s);
++ return (error);
++}
++
++/*
++ * Turn a STREAMS message into an mbuf chain.
++ */
++static struct mbuf *
++make_mbufs(mp, off)
++ mblk_t *mp;
++ int off;
++{
++ struct mbuf *head, **prevp, *m;
++ int len, space, n;
++ unsigned char *cp, *dp;
++
++ len = msgdsize(mp);
++ if (len == 0)
++ return 0;
++ prevp = &amp;head;
++ space = 0;
++ cp = mp-&gt;b_rptr;
++#ifdef __osf__
++ MGETHDR(m, M_DONTWAIT, MT_DATA);
++ m-&gt;m_len = 0;
++ space = MHLEN;
++ *prevp = m;
++ prevp = &amp;m-&gt;m_next;
++ dp = mtod(m, unsigned char *);
++ len -= space;
++ off = 0;
++#endif
++ for (;;) {
++ while (cp &gt;= mp-&gt;b_wptr) {
++ mp = mp-&gt;b_cont;
++ if (mp == 0) {
++ *prevp = 0;
++ return head;
++ }
++ cp = mp-&gt;b_rptr;
++ }
++ n = mp-&gt;b_wptr - cp;
++ if (space == 0) {
++ MGET(m, M_DONTWAIT, MT_DATA);
++ *prevp = m;
++ if (m == 0) {
++ if (head != 0)
++ m_freem(head);
++ return 0;
++ }
++ if (len + off &gt; 2 * MLEN) {
++#ifdef __osf__
++ MCLGET(m, M_DONTWAIT);
++#else
++ MCLGET(m);
++#endif
++ }
++#ifdef __osf__
++ space = ((m-&gt;m_flags &amp; M_EXT) ? MCLBYTES : MLEN);
++#else
++ space = (m-&gt;m_off &gt; MMAXOFF? MCLBYTES: MLEN) - off;
++ m-&gt;m_off += off;
++#endif
++ m-&gt;m_len = 0;
++ len -= space;
++ dp = mtod(m, unsigned char *);
++ off = 0;
++ prevp = &amp;m-&gt;m_next;
++ }
++ if (n &gt; space)
++ n = space;
++ bcopy(cp, dp, n);
++ cp += n;
++ dp += n;
++ space -= n;
++ m-&gt;m_len += n;
++ }
++}
++
++/*
++ * Turn an mbuf chain into a STREAMS message.
++ */
++#define ALLOCB_MAX 4096
++
++static mblk_t *
++make_message(m, off)
++ struct mbuf *m;
++ int off;
++{
++ mblk_t *head, **prevp, *mp;
++ int len, space, n, nb;
++ unsigned char *cp, *dp;
++ struct mbuf *nm;
++
++ len = 0;
++ for (nm = m; nm != 0; nm = nm-&gt;m_next)
++ len += nm-&gt;m_len;
++ prevp = &amp;head;
++ space = 0;
++ cp = mtod(m, unsigned char *);
++ nb = m-&gt;m_len;
++ for (;;) {
++ while (nb &lt;= 0) {
++ m = m-&gt;m_next;
++ if (m == 0) {
++ *prevp = 0;
++ return head;
++ }
++ cp = mtod(m, unsigned char *);
++ nb = m-&gt;m_len;
++ }
++ if (space == 0) {
++ space = len + off;
++ if (space &gt; ALLOCB_MAX)
++ space = ALLOCB_MAX;
++ mp = allocb(space, BPRI_LO);
++ *prevp = mp;
++ if (mp == 0) {
++ if (head != 0)
++ freemsg(head);
++ return 0;
++ }
++ dp = mp-&gt;b_rptr += off;
++ space -= off;
++ len -= space;
++ off = 0;
++ prevp = &amp;mp-&gt;b_cont;
++ }
++ n = nb &lt; space? nb: space;
++ bcopy(cp, dp, n);
++ cp += n;
++ dp += n;
++ nb -= n;
++ space -= n;
++ mp-&gt;b_wptr = dp;
++ }
++}
++
++/*
++ * Digital UNIX doesn't allow for removing ifnet structures
++ * from the list. But then we're not using this as a loadable
++ * module anyway, so that's OK.
++ *
++ * Under SunOS, this should allow the module to be unloaded.
++ * Unfortunately, it doesn't seem to detach all the references,
++ * so your system may well crash after you unload this module :-(
++ */
++#ifndef __osf__
++
++/*
++ * Remove an interface from the system.
++ * This routine contains magic.
++ */
++#include &lt;net/route.h&gt;
++#include &lt;netinet/in_pcb.h&gt;
++#include &lt;netinet/ip_var.h&gt;
++#include &lt;netinet/tcp.h&gt;
++#include &lt;netinet/tcp_timer.h&gt;
++#include &lt;netinet/tcp_var.h&gt;
++#include &lt;netinet/udp.h&gt;
++#include &lt;netinet/udp_var.h&gt;
++
++static void
++ppp_if_detach(ifp)
++ struct ifnet *ifp;
++{
++ int s;
++ struct inpcb *pcb;
++ struct ifaddr *ifa;
++ struct in_ifaddr **inap;
++ struct ifnet **ifpp;
++
++ s = splhigh();
++
++ /*
++ * Clear the interface from any routes currently cached in
++ * TCP or UDP protocol control blocks.
++ */
++ for (pcb = tcb.inp_next; pcb != &amp;tcb; pcb = pcb-&gt;inp_next)
++ if (pcb-&gt;inp_route.ro_rt &amp;&amp; pcb-&gt;inp_route.ro_rt-&gt;rt_ifp == ifp)
++ in_losing(pcb);
++ for (pcb = udb.inp_next; pcb != &amp;udb; pcb = pcb-&gt;inp_next)
++ if (pcb-&gt;inp_route.ro_rt &amp;&amp; pcb-&gt;inp_route.ro_rt-&gt;rt_ifp == ifp)
++ in_losing(pcb);
++
++ /*
++ * Delete routes through all addresses of the interface.
++ */
++ for (ifa = ifp-&gt;if_addrlist; ifa != 0; ifa = ifa-&gt;ifa_next) {
++ rtinit(ifa, ifa, SIOCDELRT, RTF_HOST);
++ rtinit(ifa, ifa, SIOCDELRT, 0);
++ }
++
++ /*
++ * Unlink the interface's address(es) from the in_ifaddr list.
++ */
++ for (inap = &amp;in_ifaddr; *inap != 0; ) {
++ if ((*inap)-&gt;ia_ifa.ifa_ifp == ifp)
++ *inap = (*inap)-&gt;ia_next;
++ else
++ inap = &amp;(*inap)-&gt;ia_next;
++ }
++
++ /*
++ * Delete the interface from the ifnet list.
++ */
++ for (ifpp = &amp;ifnet; (*ifpp) != 0; ) {
++ if (*ifpp == ifp)
++ break;
++ ifpp = &amp;(*ifpp)-&gt;if_next;
++ }
++ if (*ifpp == 0)
++ printf(&quot;couldn't find interface ppp%d in ifnet list\n&quot;, ifp-&gt;if_unit);
++ else
++ *ifpp = ifp-&gt;if_next;
++
++ splx(s);
++}
++
++#endif /* __osf__ */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/modules/if_ppp.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/modules/ppp.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/modules/ppp.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/modules/ppp.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,2486 @@
++/*
++ * ppp.c - STREAMS multiplexing pseudo-device driver for PPP.
++ *
++ * Copyright (c) 1994 The Australian National University.
++ * All rights reserved.
++ *
++ * Permission to use, copy, modify, and distribute this software and its
++ * documentation is hereby granted, provided that the above copyright
++ * notice appears in all copies. This software is provided without any
++ * warranty, express or implied. The Australian National University
++ * makes no representations about the suitability of this software for
++ * any purpose.
++ *
++ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
++ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
++ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
++ * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
++ * OF SUCH DAMAGE.
++ *
++ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
++ * ON AN &quot;AS IS&quot; BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
++ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
++ * OR MODIFICATIONS.
++ *
++ * $Id: ppp.c 195720 2001-06-11 11:44:34Z gc $
++ */
++
++/*
++ * This file is used under Solaris 2, SVR4, SunOS 4, and Digital UNIX.
++ */
++
++#include &lt;sys/types.h&gt;
++#include &lt;sys/param.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;sys/stream.h&gt;
++#include &lt;sys/stropts.h&gt;
++#include &lt;sys/errno.h&gt;
++#ifdef __osf__
++#include &lt;sys/ioctl.h&gt;
++#include &lt;sys/cmn_err.h&gt;
++#define queclass(mp) ((mp)-&gt;b_band &amp; QPCTL)
++#else
++#include &lt;sys/ioccom.h&gt;
++#endif
++#include &lt;sys/time.h&gt;
++#ifdef SVR4
++#include &lt;sys/cmn_err.h&gt;
++#include &lt;sys/conf.h&gt;
++#include &lt;sys/dlpi.h&gt;
++#include &lt;sys/ddi.h&gt;
++#ifdef SOL2
++#include &lt;sys/ksynch.h&gt;
++#include &lt;sys/kstat.h&gt;
++#include &lt;sys/sunddi.h&gt;
++#include &lt;sys/ethernet.h&gt;
++#else
++#include &lt;sys/socket.h&gt;
++#include &lt;sys/sockio.h&gt;
++#include &lt;net/if.h&gt;
++#include &lt;netinet/in.h&gt;
++#endif /* SOL2 */
++#else /* not SVR4 */
++#include &lt;sys/user.h&gt;
++#endif /* SVR4 */
++#include &lt;net/ppp_defs.h&gt;
++#include &lt;net/pppio.h&gt;
++#include &quot;ppp_mod.h&quot;
++
++/*
++ * Modifications marked with #ifdef PRIOQ are for priority queueing of
++ * interactive traffic, and are due to Marko Zec &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">zec at japa.tel.fer.hr</A>&gt;.
++ */
++#ifdef PRIOQ
++#endif /* PRIOQ */
++
++#include &lt;netinet/in.h&gt; /* leave this outside of PRIOQ for htons */
++
++#ifdef __STDC__
++#define __P(x) x
++#else
++#define __P(x) ()
++#endif
++
++/*
++ * The IP module may use this SAP value for IP packets.
++ */
++#ifndef ETHERTYPE_IP
++#define ETHERTYPE_IP 0x800
++#endif
++
++#if !defined(ETHERTYPE_IPV6)
++#define ETHERTYPE_IPV6 0x86dd
++#endif /* !defined(ETHERTYPE_IPV6) */
++
++#if !defined(ETHERTYPE_ALLSAP) &amp;&amp; defined(SOL2)
++#define ETHERTYPE_ALLSAP 0
++#endif /* !defined(ETHERTYPE_ALLSAP) &amp;&amp; defined(SOL2) */
++
++#if !defined(PPP_ALLSAP) &amp;&amp; defined(SOL2)
++#define PPP_ALLSAP PPP_ALLSTATIONS
++#endif /* !defined(PPP_ALLSAP) &amp;&amp; defined(SOL2) */
++
++extern time_t time;
++
++#ifdef SOL2
++/*
++ * We use this reader-writer lock to ensure that the lower streams
++ * stay connected to the upper streams while the lower-side put and
++ * service procedures are running. Essentially it is an existence
++ * lock for the upper stream associated with each lower stream.
++ */
++krwlock_t ppp_lower_lock;
++#define LOCK_LOWER_W rw_enter(&amp;ppp_lower_lock, RW_WRITER)
++#define LOCK_LOWER_R rw_enter(&amp;ppp_lower_lock, RW_READER)
++#define TRYLOCK_LOWER_R rw_tryenter(&amp;ppp_lower_lock, RW_READER)
++#define UNLOCK_LOWER rw_exit(&amp;ppp_lower_lock)
++
++#define MT_ENTER(x) mutex_enter(x)
++#define MT_EXIT(x) mutex_exit(x)
++
++/*
++ * Notes on multithreaded implementation for Solaris 2:
++ *
++ * We use an inner perimeter around each queue pair and an outer
++ * perimeter around the whole driver. The inner perimeter is
++ * entered exclusively for all entry points (open, close, put,
++ * service). The outer perimeter is entered exclusively for open
++ * and close and shared for put and service. This is all done for
++ * us by the streams framework.
++ *
++ * I used to think that the perimeters were entered for the lower
++ * streams' put and service routines as well as for the upper streams'.
++ * Because of problems experienced by people, and after reading the
++ * documentation more closely, I now don't think that is true. So we
++ * now use ppp_lower_lock to give us an existence guarantee on the
++ * upper stream controlling each lower stream.
++ *
++ * Shared entry to the outer perimeter protects the existence of all
++ * the upper streams and their upperstr_t structures, and guarantees
++ * that the following fields of any upperstr_t won't change:
++ * nextmn, next, nextppa. It guarantees that the lowerq field of an
++ * upperstr_t won't go from non-zero to zero, that the global `ppas'
++ * won't change and that the no lower stream will get unlinked.
++ *
++ * Shared (reader) access to ppa_lower_lock guarantees that no lower
++ * stream will be unlinked and that the lowerq field of all upperstr_t
++ * structures won't change.
++ */
++
++#else /* SOL2 */
++#define LOCK_LOWER_W 0
++#define LOCK_LOWER_R 0
++#define TRYLOCK_LOWER_R 1
++#define UNLOCK_LOWER 0
++#define MT_ENTER(x) 0
++#define MT_EXIT(x) 0
++
++#endif /* SOL2 */
++
++/*
++ * Private information; one per upper stream.
++ */
++typedef struct upperstr {
++ minor_t mn; /* minor device number */
++ struct upperstr *nextmn; /* next minor device */
++ queue_t *q; /* read q associated with this upper stream */
++ int flags; /* flag bits, see below */
++ int state; /* current DLPI state */
++ int sap; /* service access point */
++ int req_sap; /* which SAP the DLPI client requested */
++ struct upperstr *ppa; /* control stream for our ppa */
++ struct upperstr *next; /* next stream for this ppa */
++ uint ioc_id; /* last ioctl ID for this stream */
++ enum NPmode npmode; /* what to do with packets on this SAP */
++ unsigned char rblocked; /* flow control has blocked upper read strm */
++ /* N.B. rblocked is only changed by control stream's put/srv procs */
++ /*
++ * There is exactly one control stream for each PPA.
++ * The following fields are only used for control streams.
++ */
++ int ppa_id;
++ queue_t *lowerq; /* write queue attached below this PPA */
++ struct upperstr *nextppa; /* next control stream */
++ int mru;
++ int mtu;
++ struct pppstat stats; /* statistics */
++ time_t last_sent; /* time last NP packet sent */
++ time_t last_recv; /* time last NP packet rcvd */
++#ifdef SOL2
++ kmutex_t stats_lock; /* lock for stats updates */
++ kstat_t *kstats; /* stats for netstat */
++#endif /* SOL2 */
++#ifdef LACHTCP
++ int ifflags;
++ char ifname[IFNAMSIZ];
++ struct ifstats ifstats;
++#endif /* LACHTCP */
++} upperstr_t;
++
++/* Values for flags */
++#define US_PRIV 1 /* stream was opened by superuser */
++#define US_CONTROL 2 /* stream is a control stream */
++#define US_BLOCKED 4 /* flow ctrl has blocked lower write stream */
++#define US_LASTMOD 8 /* no PPP modules below us */
++#define US_DBGLOG 0x10 /* log various occurrences */
++#define US_RBLOCKED 0x20 /* flow ctrl has blocked upper read stream */
++
++#if defined(SOL2)
++#if DL_CURRENT_VERSION &gt;= 2
++#define US_PROMISC 0x40 /* stream is promiscuous */
++#endif /* DL_CURRENT_VERSION &gt;= 2 */
++#define US_RAWDATA 0x80 /* raw M_DATA, no DLPI header */
++#endif /* defined(SOL2) */
++
++#ifdef PRIOQ
++static u_char max_band=0;
++static u_char def_band=0;
++
++#define IPPORT_DEFAULT 65535
++
++/*
++ * Port priority table
++ * Highest priority ports are listed first, lowest are listed last.
++ * ICMP &amp; packets using unlisted ports will be treated as &quot;default&quot;.
++ * If IPPORT_DEFAULT is not listed here, &quot;default&quot; packets will be
++ * assigned lowest priority.
++ * Each line should be terminated with &quot;0&quot;.
++ * Line containing only &quot;0&quot; marks the end of the list.
++ */
++
++static u_short prioq_table[]= {
++ 113, 53, 0,
++ 22, 23, 513, 517, 518, 0,
++ 514, 21, 79, 111, 0,
++ 25, 109, 110, 0,
++ IPPORT_DEFAULT, 0,
++ 20, 70, 80, 8001, 8008, 8080, 0, /* 8001,8008,8080 - common proxy ports */
++0 };
++
++#endif /* PRIOQ */
++
++
++static upperstr_t *minor_devs = NULL;
++static upperstr_t *ppas = NULL;
++
++#ifdef SVR4
++static int pppopen __P((queue_t *, dev_t *, int, int, cred_t *));
++static int pppclose __P((queue_t *, int, cred_t *));
++#else
++static int pppopen __P((queue_t *, int, int, int));
++static int pppclose __P((queue_t *, int));
++#endif /* SVR4 */
++static int pppurput __P((queue_t *, mblk_t *));
++static int pppuwput __P((queue_t *, mblk_t *));
++static int pppursrv __P((queue_t *));
++static int pppuwsrv __P((queue_t *));
++static int ppplrput __P((queue_t *, mblk_t *));
++static int ppplwput __P((queue_t *, mblk_t *));
++static int ppplrsrv __P((queue_t *));
++static int ppplwsrv __P((queue_t *));
++#ifndef NO_DLPI
++static void dlpi_request __P((queue_t *, mblk_t *, upperstr_t *));
++static void dlpi_error __P((queue_t *, upperstr_t *, int, int, int));
++static void dlpi_ok __P((queue_t *, int));
++#endif
++static int send_data __P((mblk_t *, upperstr_t *));
++static void new_ppa __P((queue_t *, mblk_t *));
++static void attach_ppa __P((queue_t *, mblk_t *));
++static void detach_ppa __P((queue_t *, mblk_t *));
++static void detach_lower __P((queue_t *, mblk_t *));
++static void debug_dump __P((queue_t *, mblk_t *));
++static upperstr_t *find_dest __P((upperstr_t *, int));
++#if defined(SOL2)
++static upperstr_t *find_promisc __P((upperstr_t *, int));
++static mblk_t *prepend_ether __P((upperstr_t *, mblk_t *, int));
++static mblk_t *prepend_udind __P((upperstr_t *, mblk_t *, int));
++static void promisc_sendup __P((upperstr_t *, mblk_t *, int, int));
++#endif /* defined(SOL2) */
++static int putctl2 __P((queue_t *, int, int, int));
++static int putctl4 __P((queue_t *, int, int, int));
++static int pass_packet __P((upperstr_t *ppa, mblk_t *mp, int outbound));
++#ifdef FILTER_PACKETS
++static int ip_hard_filter __P((upperstr_t *ppa, mblk_t *mp, int outbound));
++#endif /* FILTER_PACKETS */
++
++#define PPP_ID 0xb1a6
++static struct module_info ppp_info = {
++#ifdef PRIOQ
++ PPP_ID, &quot;ppp&quot;, 0, 512, 512, 384
++#else
++ PPP_ID, &quot;ppp&quot;, 0, 512, 512, 128
++#endif /* PRIOQ */
++};
++
++static struct qinit pppurint = {
++ pppurput, pppursrv, pppopen, pppclose, NULL, &amp;ppp_info, NULL
++};
++
++static struct qinit pppuwint = {
++ pppuwput, pppuwsrv, NULL, NULL, NULL, &amp;ppp_info, NULL
++};
++
++static struct qinit ppplrint = {
++ ppplrput, ppplrsrv, NULL, NULL, NULL, &amp;ppp_info, NULL
++};
++
++static struct qinit ppplwint = {
++ ppplwput, ppplwsrv, NULL, NULL, NULL, &amp;ppp_info, NULL
++};
++
++#ifdef LACHTCP
++extern struct ifstats *ifstats;
++int pppdevflag = 0;
++#endif
++
++struct streamtab pppinfo = {
++ &amp;pppurint, &amp;pppuwint,
++ &amp;ppplrint, &amp;ppplwint
++};
++
++int ppp_count;
++
++/*
++ * How we maintain statistics.
++ */
++#ifdef SOL2
++#define INCR_IPACKETS(ppa) \
++ if (ppa-&gt;kstats != 0) { \
++ KSTAT_NAMED_PTR(ppa-&gt;kstats)[0].value.ul++; \
++ }
++#define INCR_IERRORS(ppa) \
++ if (ppa-&gt;kstats != 0) { \
++ KSTAT_NAMED_PTR(ppa-&gt;kstats)[1].value.ul++; \
++ }
++#define INCR_OPACKETS(ppa) \
++ if (ppa-&gt;kstats != 0) { \
++ KSTAT_NAMED_PTR(ppa-&gt;kstats)[2].value.ul++; \
++ }
++#define INCR_OERRORS(ppa) \
++ if (ppa-&gt;kstats != 0) { \
++ KSTAT_NAMED_PTR(ppa-&gt;kstats)[3].value.ul++; \
++ }
++#endif
++
++#ifdef LACHTCP
++#define INCR_IPACKETS(ppa) ppa-&gt;ifstats.ifs_ipackets++;
++#define INCR_IERRORS(ppa) ppa-&gt;ifstats.ifs_ierrors++;
++#define INCR_OPACKETS(ppa) ppa-&gt;ifstats.ifs_opackets++;
++#define INCR_OERRORS(ppa) ppa-&gt;ifstats.ifs_oerrors++;
++#endif
++
++/*
++ * STREAMS driver entry points.
++ */
++static int
++#ifdef SVR4
++pppopen(q, devp, oflag, sflag, credp)
++ queue_t *q;
++ dev_t *devp;
++ int oflag, sflag;
++ cred_t *credp;
++#else
++pppopen(q, dev, oflag, sflag)
++ queue_t *q;
++ int dev; /* really dev_t */
++ int oflag, sflag;
++#endif
++{
++ upperstr_t *up;
++ upperstr_t **prevp;
++ minor_t mn;
++#ifdef PRIOQ
++ u_short *ptr;
++ u_char new_band;
++#endif /* PRIOQ */
++
++ if (q-&gt;q_ptr)
++ DRV_OPEN_OK(dev); /* device is already open */
++
++#ifdef PRIOQ
++ /* Calculate max_bband &amp; def_band from definitions in prioq.h
++ This colud be done at some more approtiate time (less often)
++ but this way it works well so I'll just leave it here */
++
++ max_band = 1;
++ def_band = 0;
++ ptr = prioq_table;
++ while (*ptr) {
++ new_band = 1;
++ while (*ptr)
++ if (*ptr++ == IPPORT_DEFAULT) {
++ new_band = 0;
++ def_band = max_band;
++ }
++ max_band += new_band;
++ ptr++;
++ }
++ if (def_band)
++ def_band = max_band - def_band;
++ --max_band;
++#endif /* PRIOQ */
++
++ if (sflag == CLONEOPEN) {
++ mn = 0;
++ for (prevp = &amp;minor_devs; (up = *prevp) != 0; prevp = &amp;up-&gt;nextmn) {
++ if (up-&gt;mn != mn)
++ break;
++ ++mn;
++ }
++ } else {
++#ifdef SVR4
++ mn = getminor(*devp);
++#else
++ mn = minor(dev);
++#endif
++ for (prevp = &amp;minor_devs; (up = *prevp) != 0; prevp = &amp;up-&gt;nextmn) {
++ if (up-&gt;mn &gt;= mn)
++ break;
++ }
++ if (up-&gt;mn == mn) {
++ /* this can't happen */
++ q-&gt;q_ptr = WR(q)-&gt;q_ptr = (caddr_t) up;
++ DRV_OPEN_OK(dev);
++ }
++ }
++
++ /*
++ * Construct a new minor node.
++ */
++ up = (upperstr_t *) ALLOC_SLEEP(sizeof(upperstr_t));
++ bzero((caddr_t) up, sizeof(upperstr_t));
++ if (up == 0) {
++ DPRINT(&quot;pppopen: out of kernel memory\n&quot;);
++ OPEN_ERROR(ENXIO);
++ }
++ up-&gt;nextmn = *prevp;
++ *prevp = up;
++ up-&gt;mn = mn;
++#ifdef SVR4
++ *devp = makedevice(getmajor(*devp), mn);
++#endif
++ up-&gt;q = q;
++ if (NOTSUSER() == 0)
++ up-&gt;flags |= US_PRIV;
++#ifndef NO_DLPI
++ up-&gt;state = DL_UNATTACHED;
++#endif
++#ifdef LACHTCP
++ up-&gt;ifflags = IFF_UP | IFF_POINTOPOINT;
++#endif
++ up-&gt;sap = -1;
++ up-&gt;last_sent = up-&gt;last_recv = time;
++ up-&gt;npmode = NPMODE_DROP;
++ q-&gt;q_ptr = (caddr_t) up;
++ WR(q)-&gt;q_ptr = (caddr_t) up;
++ noenable(WR(q));
++#ifdef SOL2
++ mutex_init(&amp;up-&gt;stats_lock, NULL, MUTEX_DRIVER, NULL);
++#endif
++ ++ppp_count;
++
++ qprocson(q);
++ DRV_OPEN_OK(makedev(major(dev), mn));
++}
++
++static int
++#ifdef SVR4
++pppclose(q, flag, credp)
++ queue_t *q;
++ int flag;
++ cred_t *credp;
++#else
++pppclose(q, flag)
++ queue_t *q;
++ int flag;
++#endif
++{
++ upperstr_t *up, **upp;
++ upperstr_t *as, *asnext;
++ upperstr_t **prevp;
++
++ qprocsoff(q);
++
++ up = (upperstr_t *) q-&gt;q_ptr;
++ if (up == 0) {
++ DPRINT(&quot;pppclose: q_ptr = 0\n&quot;);
++ return 0;
++ }
++ if (up-&gt;flags &amp; US_DBGLOG)
++ DPRINT2(&quot;ppp/%d: close, flags=%x\n&quot;, up-&gt;mn, up-&gt;flags);
++ if (up-&gt;flags &amp; US_CONTROL) {
++#ifdef LACHTCP
++ struct ifstats *ifp, *pifp;
++#endif
++ if (up-&gt;lowerq != 0) {
++ /* Gack! the lower stream should have be unlinked earlier! */
++ DPRINT1(&quot;ppp%d: lower stream still connected on close?\n&quot;,
++ up-&gt;mn);
++ LOCK_LOWER_W;
++ up-&gt;lowerq-&gt;q_ptr = 0;
++ RD(up-&gt;lowerq)-&gt;q_ptr = 0;
++ up-&gt;lowerq = 0;
++ UNLOCK_LOWER;
++ }
++
++ /*
++ * This stream represents a PPA:
++ * For all streams attached to the PPA, clear their
++ * references to this PPA.
++ * Then remove this PPA from the list of PPAs.
++ */
++ for (as = up-&gt;next; as != 0; as = asnext) {
++ asnext = as-&gt;next;
++ as-&gt;next = 0;
++ as-&gt;ppa = 0;
++ if (as-&gt;flags &amp; US_BLOCKED) {
++ as-&gt;flags &amp;= ~US_BLOCKED;
++ flushq(WR(as-&gt;q), FLUSHDATA);
++ }
++ }
++ for (upp = &amp;ppas; *upp != 0; upp = &amp;(*upp)-&gt;nextppa)
++ if (*upp == up) {
++ *upp = up-&gt;nextppa;
++ break;
++ }
++#ifdef LACHTCP
++ /* Remove the statistics from the active list. */
++ for (ifp = ifstats, pifp = 0; ifp; ifp = ifp-&gt;ifs_next) {
++ if (ifp == &amp;up-&gt;ifstats) {
++ if (pifp)
++ pifp-&gt;ifs_next = ifp-&gt;ifs_next;
++ else
++ ifstats = ifp-&gt;ifs_next;
++ break;
++ }
++ pifp = ifp;
++ }
++#endif
++ } else {
++ /*
++ * If this stream is attached to a PPA,
++ * remove it from the PPA's list.
++ */
++ if ((as = up-&gt;ppa) != 0) {
++ for (; as-&gt;next != 0; as = as-&gt;next)
++ if (as-&gt;next == up) {
++ as-&gt;next = up-&gt;next;
++ break;
++ }
++ }
++ }
++
++#ifdef SOL2
++ if (up-&gt;kstats)
++ kstat_delete(up-&gt;kstats);
++ mutex_destroy(&amp;up-&gt;stats_lock);
++#endif
++
++ q-&gt;q_ptr = NULL;
++ WR(q)-&gt;q_ptr = NULL;
++
++ for (prevp = &amp;minor_devs; *prevp != 0; prevp = &amp;(*prevp)-&gt;nextmn) {
++ if (*prevp == up) {
++ *prevp = up-&gt;nextmn;
++ break;
++ }
++ }
++ FREE(up, sizeof(upperstr_t));
++ --ppp_count;
++
++ return 0;
++}
++
++/*
++ * A message from on high. We do one of three things:
++ * - qreply()
++ * - put the message on the lower write stream
++ * - queue it for our service routine
++ */
++static int
++pppuwput(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ upperstr_t *us, *ppa, *nps;
++ struct iocblk *iop;
++ struct linkblk *lb;
++#ifdef LACHTCP
++ struct ifreq *ifr;
++ int i;
++#endif
++ queue_t *lq;
++ int error, n, sap;
++ mblk_t *mq;
++ struct ppp_idle *pip;
++#ifdef PRIOQ
++ queue_t *tlq;
++#endif /* PRIOQ */
++#ifdef NO_DLPI
++ upperstr_t *os;
++#endif
++
++ us = (upperstr_t *) q-&gt;q_ptr;
++ if (us == 0) {
++ DPRINT(&quot;pppuwput: q_ptr = 0!\n&quot;);
++ return 0;
++ }
++ if (mp == 0) {
++ DPRINT1(&quot;pppuwput/%d: mp = 0!\n&quot;, us-&gt;mn);
++ return 0;
++ }
++ if (mp-&gt;b_datap == 0) {
++ DPRINT1(&quot;pppuwput/%d: mp-&gt;b_datap = 0!\n&quot;, us-&gt;mn);
++ return 0;
++ }
++ switch (mp-&gt;b_datap-&gt;db_type) {
++#ifndef NO_DLPI
++ case M_PCPROTO:
++ case M_PROTO:
++ dlpi_request(q, mp, us);
++ break;
++#endif /* NO_DLPI */
++
++ case M_DATA:
++ if (us-&gt;flags &amp; US_DBGLOG)
++ DPRINT3(&quot;ppp/%d: uwput M_DATA len=%d flags=%x\n&quot;,
++ us-&gt;mn, msgdsize(mp), us-&gt;flags);
++ if (us-&gt;ppa == 0 || msgdsize(mp) &gt; us-&gt;ppa-&gt;mtu + PPP_HDRLEN
++#ifndef NO_DLPI
++ || (us-&gt;flags &amp; US_CONTROL) == 0
++#endif /* NO_DLPI */
++ ) {
++ DPRINT1(&quot;pppuwput: junk data len=%d\n&quot;, msgdsize(mp));
++ freemsg(mp);
++ break;
++ }
++#ifdef NO_DLPI
++ if ((us-&gt;flags &amp; US_CONTROL) == 0 &amp;&amp; !pass_packet(us, mp, 1))
++ break;
++#endif
++ if (!send_data(mp, us))
++ putq(q, mp);
++ break;
++
++ case M_IOCTL:
++ iop = (struct iocblk *) mp-&gt;b_rptr;
++ error = EINVAL;
++ if (us-&gt;flags &amp; US_DBGLOG)
++ DPRINT3(&quot;ppp/%d: ioctl %x count=%d\n&quot;,
++ us-&gt;mn, iop-&gt;ioc_cmd, iop-&gt;ioc_count);
++ switch (iop-&gt;ioc_cmd) {
++#if defined(SOL2)
++ case DLIOCRAW: /* raw M_DATA mode */
++ us-&gt;flags |= US_RAWDATA;
++ error = 0;
++ break;
++#endif /* defined(SOL2) */
++ case I_LINK:
++ if ((us-&gt;flags &amp; US_CONTROL) == 0 || us-&gt;lowerq != 0)
++ break;
++ if (mp-&gt;b_cont == 0) {
++ DPRINT1(&quot;pppuwput/%d: ioctl I_LINK b_cont = 0!\n&quot;, us-&gt;mn);
++ break;
++ }
++ lb = (struct linkblk *) mp-&gt;b_cont-&gt;b_rptr;
++ lq = lb-&gt;l_qbot;
++ if (lq == 0) {
++ DPRINT1(&quot;pppuwput/%d: ioctl I_LINK l_qbot = 0!\n&quot;, us-&gt;mn);
++ break;
++ }
++ LOCK_LOWER_W;
++ us-&gt;lowerq = lq;
++ lq-&gt;q_ptr = (caddr_t) q;
++ RD(lq)-&gt;q_ptr = (caddr_t) us-&gt;q;
++ UNLOCK_LOWER;
++ iop-&gt;ioc_count = 0;
++ error = 0;
++ us-&gt;flags &amp;= ~US_LASTMOD;
++ /* Unblock upper streams which now feed this lower stream. */
++ qenable(q);
++ /* Send useful information down to the modules which
++ are now linked below us. */
++ putctl2(lq, M_CTL, PPPCTL_UNIT, us-&gt;ppa_id);
++ putctl4(lq, M_CTL, PPPCTL_MRU, us-&gt;mru);
++ putctl4(lq, M_CTL, PPPCTL_MTU, us-&gt;mtu);
++#ifdef PRIOQ
++ /* Lower tty driver's queue hiwat/lowat from default 4096/128
++ to 256/128 since we don't want queueing of data on
++ output to physical device */
++
++ freezestr(lq);
++ for (tlq = lq; tlq-&gt;q_next != NULL; tlq = tlq-&gt;q_next)
++ ;
++ strqset(tlq, QHIWAT, 0, 256);
++ strqset(tlq, QLOWAT, 0, 128);
++ unfreezestr(lq);
++#endif /* PRIOQ */
++ break;
++
++ case I_UNLINK:
++ if (mp-&gt;b_cont == 0) {
++ DPRINT1(&quot;pppuwput/%d: ioctl I_UNLINK b_cont = 0!\n&quot;, us-&gt;mn);
++ break;
++ }
++ lb = (struct linkblk *) mp-&gt;b_cont-&gt;b_rptr;
++#if DEBUG
++ if (us-&gt;lowerq != lb-&gt;l_qbot) {
++ DPRINT2(&quot;ppp unlink: lowerq=%x qbot=%x\n&quot;,
++ us-&gt;lowerq, lb-&gt;l_qbot);
++ break;
++ }
++#endif
++ iop-&gt;ioc_count = 0;
++ qwriter(q, mp, detach_lower, PERIM_OUTER);
++ error = -1;
++ break;
++
++ case PPPIO_NEWPPA:
++ if (us-&gt;flags &amp; US_CONTROL)
++ break;
++ if ((us-&gt;flags &amp; US_PRIV) == 0) {
++ error = EPERM;
++ break;
++ }
++ /* Arrange to return an int */
++ if ((mq = mp-&gt;b_cont) == 0
++ || mq-&gt;b_datap-&gt;db_lim - mq-&gt;b_rptr &lt; sizeof(int)) {
++ mq = allocb(sizeof(int), BPRI_HI);
++ if (mq == 0) {
++ error = ENOSR;
++ break;
++ }
++ if (mp-&gt;b_cont != 0)
++ freemsg(mp-&gt;b_cont);
++ mp-&gt;b_cont = mq;
++ mq-&gt;b_cont = 0;
++ }
++ iop-&gt;ioc_count = sizeof(int);
++ mq-&gt;b_wptr = mq-&gt;b_rptr + sizeof(int);
++ qwriter(q, mp, new_ppa, PERIM_OUTER);
++ error = -1;
++ break;
++
++ case PPPIO_ATTACH:
++ /* like dlpi_attach, for programs which can't write to
++ the stream (like pppstats) */
++ if (iop-&gt;ioc_count != sizeof(int) || us-&gt;ppa != 0)
++ break;
++ if (mp-&gt;b_cont == 0) {
++ DPRINT1(&quot;pppuwput/%d: ioctl PPPIO_ATTACH b_cont = 0!\n&quot;, us-&gt;mn);
++ break;
++ }
++ n = *(int *)mp-&gt;b_cont-&gt;b_rptr;
++ for (ppa = ppas; ppa != 0; ppa = ppa-&gt;nextppa)
++ if (ppa-&gt;ppa_id == n)
++ break;
++ if (ppa == 0)
++ break;
++ us-&gt;ppa = ppa;
++ iop-&gt;ioc_count = 0;
++ qwriter(q, mp, attach_ppa, PERIM_OUTER);
++ error = -1;
++ break;
++
++#ifdef NO_DLPI
++ case PPPIO_BIND:
++ /* Attach to a given SAP. */
++ if (iop-&gt;ioc_count != sizeof(int) || us-&gt;ppa == 0)
++ break;
++ if (mp-&gt;b_cont == 0) {
++ DPRINT1(&quot;pppuwput/%d: ioctl PPPIO_BIND b_cont = 0!\n&quot;, us-&gt;mn);
++ break;
++ }
++ n = *(int *)mp-&gt;b_cont-&gt;b_rptr;
++ /* n must be a valid PPP network protocol number. */
++ if (n &lt; 0x21 || n &gt; 0x3fff || (n &amp; 0x101) != 1)
++ break;
++ /* check that no other stream is bound to this sap already. */
++ for (os = us-&gt;ppa; os != 0; os = os-&gt;next)
++ if (os-&gt;sap == n)
++ break;
++ if (os != 0)
++ break;
++ us-&gt;sap = n;
++ iop-&gt;ioc_count = 0;
++ error = 0;
++ break;
++#endif /* NO_DLPI */
++
++ case PPPIO_MRU:
++ if (iop-&gt;ioc_count != sizeof(int) || (us-&gt;flags &amp; US_CONTROL) == 0)
++ break;
++ if (mp-&gt;b_cont == 0) {
++ DPRINT1(&quot;pppuwput/%d: ioctl PPPIO_MRU b_cont = 0!\n&quot;, us-&gt;mn);
++ break;
++ }
++ n = *(int *)mp-&gt;b_cont-&gt;b_rptr;
++ if (n &lt;= 0 || n &gt; PPP_MAXMRU)
++ break;
++ if (n &lt; PPP_MRU)
++ n = PPP_MRU;
++ us-&gt;mru = n;
++ if (us-&gt;lowerq)
++ putctl4(us-&gt;lowerq, M_CTL, PPPCTL_MRU, n);
++ error = 0;
++ iop-&gt;ioc_count = 0;
++ break;
++
++ case PPPIO_MTU:
++ if (iop-&gt;ioc_count != sizeof(int) || (us-&gt;flags &amp; US_CONTROL) == 0)
++ break;
++ if (mp-&gt;b_cont == 0) {
++ DPRINT1(&quot;pppuwput/%d: ioctl PPPIO_MTU b_cont = 0!\n&quot;, us-&gt;mn);
++ break;
++ }
++ n = *(int *)mp-&gt;b_cont-&gt;b_rptr;
++ if (n &lt;= 0 || n &gt; PPP_MAXMTU)
++ break;
++ us-&gt;mtu = n;
++#ifdef LACHTCP
++ /* The MTU reported in netstat, not used as IP max packet size! */
++ us-&gt;ifstats.ifs_mtu = n;
++#endif
++ if (us-&gt;lowerq)
++ putctl4(us-&gt;lowerq, M_CTL, PPPCTL_MTU, n);
++ error = 0;
++ iop-&gt;ioc_count = 0;
++ break;
++
++ case PPPIO_LASTMOD:
++ us-&gt;flags |= US_LASTMOD;
++ error = 0;
++ break;
++
++ case PPPIO_DEBUG:
++ if (iop-&gt;ioc_count != sizeof(int))
++ break;
++ if (mp-&gt;b_cont == 0) {
++ DPRINT1(&quot;pppuwput/%d: ioctl PPPIO_DEBUG b_cont = 0!\n&quot;, us-&gt;mn);
++ break;
++ }
++ n = *(int *)mp-&gt;b_cont-&gt;b_rptr;
++ if (n == PPPDBG_DUMP + PPPDBG_DRIVER) {
++ qwriter(q, NULL, debug_dump, PERIM_OUTER);
++ iop-&gt;ioc_count = 0;
++ error = -1;
++ } else if (n == PPPDBG_LOG + PPPDBG_DRIVER) {
++ DPRINT1(&quot;ppp/%d: debug log enabled\n&quot;, us-&gt;mn);
++ us-&gt;flags |= US_DBGLOG;
++ iop-&gt;ioc_count = 0;
++ error = 0;
++ } else {
++ if (us-&gt;ppa == 0 || us-&gt;ppa-&gt;lowerq == 0)
++ break;
++ putnext(us-&gt;ppa-&gt;lowerq, mp);
++ error = -1;
++ }
++ break;
++
++ case PPPIO_NPMODE:
++ if (iop-&gt;ioc_count != 2 * sizeof(int))
++ break;
++ if ((us-&gt;flags &amp; US_CONTROL) == 0)
++ break;
++ if (mp-&gt;b_cont == 0) {
++ DPRINT1(&quot;pppuwput/%d: ioctl PPPIO_NPMODE b_cont = 0!\n&quot;, us-&gt;mn);
++ break;
++ }
++ sap = ((int *)mp-&gt;b_cont-&gt;b_rptr)[0];
++ for (nps = us-&gt;next; nps != 0; nps = nps-&gt;next) {
++ if (us-&gt;flags &amp; US_DBGLOG)
++ DPRINT2(&quot;us = 0x%x, us-&gt;next-&gt;sap = 0x%x\n&quot;, nps, nps-&gt;sap);
++ if (nps-&gt;sap == sap)
++ break;
++ }
++ if (nps == 0) {
++ if (us-&gt;flags &amp; US_DBGLOG)
++ DPRINT2(&quot;ppp/%d: no stream for sap %x\n&quot;, us-&gt;mn, sap);
++ break;
++ }
++ /* XXX possibly should use qwriter here */
++ nps-&gt;npmode = (enum NPmode) ((int *)mp-&gt;b_cont-&gt;b_rptr)[1];
++ if (nps-&gt;npmode != NPMODE_QUEUE &amp;&amp; (nps-&gt;flags &amp; US_BLOCKED) != 0)
++ qenable(WR(nps-&gt;q));
++ iop-&gt;ioc_count = 0;
++ error = 0;
++ break;
++
++ case PPPIO_GIDLE:
++ if ((ppa = us-&gt;ppa) == 0)
++ break;
++ mq = allocb(sizeof(struct ppp_idle), BPRI_HI);
++ if (mq == 0) {
++ error = ENOSR;
++ break;
++ }
++ if (mp-&gt;b_cont != 0)
++ freemsg(mp-&gt;b_cont);
++ mp-&gt;b_cont = mq;
++ mq-&gt;b_cont = 0;
++ pip = (struct ppp_idle *) mq-&gt;b_wptr;
++ pip-&gt;xmit_idle = time - ppa-&gt;last_sent;
++ pip-&gt;recv_idle = time - ppa-&gt;last_recv;
++ mq-&gt;b_wptr += sizeof(struct ppp_idle);
++ iop-&gt;ioc_count = sizeof(struct ppp_idle);
++ error = 0;
++ break;
++
++#ifdef LACHTCP
++ case SIOCSIFNAME:
++ /* Sent from IP down to us. Attach the ifstats structure. */
++ if (iop-&gt;ioc_count != sizeof(struct ifreq) || us-&gt;ppa == 0)
++ break;
++ ifr = (struct ifreq *)mp-&gt;b_cont-&gt;b_rptr;
++ /* Find the unit number in the interface name. */
++ for (i = 0; i &lt; IFNAMSIZ; i++) {
++ if (ifr-&gt;ifr_name[i] == 0 ||
++ (ifr-&gt;ifr_name[i] &gt;= '0' &amp;&amp;
++ ifr-&gt;ifr_name[i] &lt;= '9'))
++ break;
++ else
++ us-&gt;ifname[i] = ifr-&gt;ifr_name[i];
++ }
++ us-&gt;ifname[i] = 0;
++
++ /* Convert the unit number to binary. */
++ for (n = 0; i &lt; IFNAMSIZ; i++) {
++ if (ifr-&gt;ifr_name[i] == 0) {
++ break;
++ }
++ else {
++ n = n * 10 + ifr-&gt;ifr_name[i] - '0';
++ }
++ }
++
++ /* Verify the ppa. */
++ if (us-&gt;ppa-&gt;ppa_id != n)
++ break;
++ ppa = us-&gt;ppa;
++
++ /* Set up the netstat block. */
++ strncpy (ppa-&gt;ifname, us-&gt;ifname, IFNAMSIZ);
++
++ ppa-&gt;ifstats.ifs_name = ppa-&gt;ifname;
++ ppa-&gt;ifstats.ifs_unit = n;
++ ppa-&gt;ifstats.ifs_active = us-&gt;state != DL_UNBOUND;
++ ppa-&gt;ifstats.ifs_mtu = ppa-&gt;mtu;
++
++ /* Link in statistics used by netstat. */
++ ppa-&gt;ifstats.ifs_next = ifstats;
++ ifstats = &amp;ppa-&gt;ifstats;
++
++ iop-&gt;ioc_count = 0;
++ error = 0;
++ break;
++
++ case SIOCGIFFLAGS:
++ if (!(us-&gt;flags &amp; US_CONTROL)) {
++ if (us-&gt;ppa)
++ us = us-&gt;ppa;
++ else
++ break;
++ }
++ ((struct iocblk_in *)iop)-&gt;ioc_ifflags = us-&gt;ifflags;
++ error = 0;
++ break;
++
++ case SIOCSIFFLAGS:
++ if (!(us-&gt;flags &amp; US_CONTROL)) {
++ if (us-&gt;ppa)
++ us = us-&gt;ppa;
++ else
++ break;
++ }
++ us-&gt;ifflags = ((struct iocblk_in *)iop)-&gt;ioc_ifflags;
++ error = 0;
++ break;
++
++ case SIOCSIFADDR:
++ if (!(us-&gt;flags &amp; US_CONTROL)) {
++ if (us-&gt;ppa)
++ us = us-&gt;ppa;
++ else
++ break;
++ }
++ us-&gt;ifflags |= IFF_RUNNING;
++ ((struct iocblk_in *)iop)-&gt;ioc_ifflags |= IFF_RUNNING;
++ error = 0;
++ break;
++
++ case SIOCSIFMTU:
++ /*
++ * Vanilla SVR4 systems don't handle SIOCSIFMTU, rather
++ * they take the MTU from the DL_INFO_ACK we sent in response
++ * to their DL_INFO_REQ. Fortunately, they will update the
++ * MTU if we send an unsolicited DL_INFO_ACK up.
++ */
++ if ((mq = allocb(sizeof(dl_info_req_t), BPRI_HI)) == 0)
++ break; /* should do bufcall */
++ ((union DL_primitives *)mq-&gt;b_rptr)-&gt;dl_primitive = DL_INFO_REQ;
++ mq-&gt;b_wptr = mq-&gt;b_rptr + sizeof(dl_info_req_t);
++ dlpi_request(q, mq, us);
++ error = 0;
++ break;
++
++ case SIOCGIFNETMASK:
++ case SIOCSIFNETMASK:
++ case SIOCGIFADDR:
++ case SIOCGIFDSTADDR:
++ case SIOCSIFDSTADDR:
++ case SIOCGIFMETRIC:
++ error = 0;
++ break;
++#endif /* LACHTCP */
++
++ default:
++ if (us-&gt;ppa == 0 || us-&gt;ppa-&gt;lowerq == 0)
++ break;
++ us-&gt;ioc_id = iop-&gt;ioc_id;
++ error = -1;
++ switch (iop-&gt;ioc_cmd) {
++ case PPPIO_GETSTAT:
++ case PPPIO_GETCSTAT:
++ if (us-&gt;flags &amp; US_LASTMOD) {
++ error = EINVAL;
++ break;
++ }
++ putnext(us-&gt;ppa-&gt;lowerq, mp);
++ break;
++ default:
++ if (us-&gt;flags &amp; US_PRIV)
++ putnext(us-&gt;ppa-&gt;lowerq, mp);
++ else {
++ DPRINT1(&quot;ppp ioctl %x rejected\n&quot;, iop-&gt;ioc_cmd);
++ error = EPERM;
++ }
++ break;
++ }
++ break;
++ }
++
++ if (error &gt; 0) {
++ iop-&gt;ioc_error = error;
++ mp-&gt;b_datap-&gt;db_type = M_IOCNAK;
++ qreply(q, mp);
++ } else if (error == 0) {
++ mp-&gt;b_datap-&gt;db_type = M_IOCACK;
++ qreply(q, mp);
++ }
++ break;
++
++ case M_FLUSH:
++ if (us-&gt;flags &amp; US_DBGLOG)
++ DPRINT2(&quot;ppp/%d: flush %x\n&quot;, us-&gt;mn, *mp-&gt;b_rptr);
++ if (*mp-&gt;b_rptr &amp; FLUSHW)
++ flushq(q, FLUSHDATA);
++ if (*mp-&gt;b_rptr &amp; FLUSHR) {
++ *mp-&gt;b_rptr &amp;= ~FLUSHW;
++ qreply(q, mp);
++ } else
++ freemsg(mp);
++ break;
++
++ default:
++ freemsg(mp);
++ break;
++ }
++ return 0;
++}
++
++#ifndef NO_DLPI
++static void
++dlpi_request(q, mp, us)
++ queue_t *q;
++ mblk_t *mp;
++ upperstr_t *us;
++{
++ union DL_primitives *d = (union DL_primitives *) mp-&gt;b_rptr;
++ int size = mp-&gt;b_wptr - mp-&gt;b_rptr;
++ mblk_t *reply, *np;
++ upperstr_t *ppa, *os;
++ int sap, len;
++ dl_info_ack_t *info;
++ dl_bind_ack_t *ackp;
++#if DL_CURRENT_VERSION &gt;= 2
++ dl_phys_addr_ack_t *paddrack;
++ static struct ether_addr eaddr = {0};
++#endif
++
++ if (us-&gt;flags &amp; US_DBGLOG)
++ DPRINT3(&quot;ppp/%d: dlpi prim %x len=%d\n&quot;, us-&gt;mn,
++ d-&gt;dl_primitive, size);
++ switch (d-&gt;dl_primitive) {
++ case DL_INFO_REQ:
++ if (size &lt; sizeof(dl_info_req_t))
++ goto badprim;
++ if ((reply = allocb(sizeof(dl_info_ack_t), BPRI_HI)) == 0)
++ break; /* should do bufcall */
++ reply-&gt;b_datap-&gt;db_type = M_PCPROTO;
++ info = (dl_info_ack_t *) reply-&gt;b_wptr;
++ reply-&gt;b_wptr += sizeof(dl_info_ack_t);
++ bzero((caddr_t) info, sizeof(dl_info_ack_t));
++ info-&gt;dl_primitive = DL_INFO_ACK;
++ info-&gt;dl_max_sdu = us-&gt;ppa? us-&gt;ppa-&gt;mtu: PPP_MAXMTU;
++ info-&gt;dl_min_sdu = 1;
++ info-&gt;dl_addr_length = sizeof(uint);
++ info-&gt;dl_mac_type = DL_ETHER; /* a bigger lie */
++ info-&gt;dl_current_state = us-&gt;state;
++ info-&gt;dl_service_mode = DL_CLDLS;
++ info-&gt;dl_provider_style = DL_STYLE2;
++#if DL_CURRENT_VERSION &gt;= 2
++ info-&gt;dl_sap_length = sizeof(uint);
++ info-&gt;dl_version = DL_CURRENT_VERSION;
++#endif
++ qreply(q, reply);
++ break;
++
++ case DL_ATTACH_REQ:
++ if (size &lt; sizeof(dl_attach_req_t))
++ goto badprim;
++ if (us-&gt;state != DL_UNATTACHED || us-&gt;ppa != 0) {
++ dlpi_error(q, us, DL_ATTACH_REQ, DL_OUTSTATE, 0);
++ break;
++ }
++ for (ppa = ppas; ppa != 0; ppa = ppa-&gt;nextppa)
++ if (ppa-&gt;ppa_id == d-&gt;attach_req.dl_ppa)
++ break;
++ if (ppa == 0) {
++ dlpi_error(q, us, DL_ATTACH_REQ, DL_BADPPA, 0);
++ break;
++ }
++ us-&gt;ppa = ppa;
++ qwriter(q, mp, attach_ppa, PERIM_OUTER);
++ return;
++
++ case DL_DETACH_REQ:
++ if (size &lt; sizeof(dl_detach_req_t))
++ goto badprim;
++ if (us-&gt;state != DL_UNBOUND || us-&gt;ppa == 0) {
++ dlpi_error(q, us, DL_DETACH_REQ, DL_OUTSTATE, 0);
++ break;
++ }
++ qwriter(q, mp, detach_ppa, PERIM_OUTER);
++ return;
++
++ case DL_BIND_REQ:
++ if (size &lt; sizeof(dl_bind_req_t))
++ goto badprim;
++ if (us-&gt;state != DL_UNBOUND || us-&gt;ppa == 0) {
++ dlpi_error(q, us, DL_BIND_REQ, DL_OUTSTATE, 0);
++ break;
++ }
++#if 0
++ /* apparently this test fails (unnecessarily?) on some systems */
++ if (d-&gt;bind_req.dl_service_mode != DL_CLDLS) {
++ dlpi_error(q, us, DL_BIND_REQ, DL_UNSUPPORTED, 0);
++ break;
++ }
++#endif
++
++ /* saps must be valid PPP network protocol numbers,
++ except that we accept ETHERTYPE_IP in place of PPP_IP. */
++ sap = d-&gt;bind_req.dl_sap;
++ us-&gt;req_sap = sap;
++
++#if defined(SOL2)
++ if (us-&gt;flags &amp; US_DBGLOG)
++ DPRINT2(&quot;DL_BIND_REQ: ip gives sap = 0x%x, us = 0x%x&quot;, sap, us);
++
++ if (sap == ETHERTYPE_IP) /* normal IFF_IPV4 */
++ sap = PPP_IP;
++ else if (sap == ETHERTYPE_IPV6) /* when IFF_IPV6 is set */
++ sap = PPP_IPV6;
++ else if (sap == ETHERTYPE_ALLSAP) /* snoop gives sap of 0 */
++ sap = PPP_ALLSAP;
++ else {
++ DPRINT2(&quot;DL_BIND_REQ: unrecognized sap = 0x%x, us = 0x%x&quot;, sap, us);
++ dlpi_error(q, us, DL_BIND_REQ, DL_BADADDR, 0);
++ break;
++ }
++#else
++ if (sap == ETHERTYPE_IP)
++ sap = PPP_IP;
++ if (sap &lt; 0x21 || sap &gt; 0x3fff || (sap &amp; 0x101) != 1) {
++ dlpi_error(q, us, DL_BIND_REQ, DL_BADADDR, 0);
++ break;
++ }
++#endif /* defined(SOL2) */
++
++ /* check that no other stream is bound to this sap already. */
++ for (os = us-&gt;ppa; os != 0; os = os-&gt;next)
++ if (os-&gt;sap == sap)
++ break;
++ if (os != 0) {
++ dlpi_error(q, us, DL_BIND_REQ, DL_NOADDR, 0);
++ break;
++ }
++
++ us-&gt;sap = sap;
++ us-&gt;state = DL_IDLE;
++
++ if ((reply = allocb(sizeof(dl_bind_ack_t) + sizeof(uint),
++ BPRI_HI)) == 0)
++ break; /* should do bufcall */
++ ackp = (dl_bind_ack_t *) reply-&gt;b_wptr;
++ reply-&gt;b_wptr += sizeof(dl_bind_ack_t) + sizeof(uint);
++ reply-&gt;b_datap-&gt;db_type = M_PCPROTO;
++ bzero((caddr_t) ackp, sizeof(dl_bind_ack_t));
++ ackp-&gt;dl_primitive = DL_BIND_ACK;
++ ackp-&gt;dl_sap = sap;
++ ackp-&gt;dl_addr_length = sizeof(uint);
++ ackp-&gt;dl_addr_offset = sizeof(dl_bind_ack_t);
++ *(uint *)(ackp+1) = sap;
++ qreply(q, reply);
++ break;
++
++ case DL_UNBIND_REQ:
++ if (size &lt; sizeof(dl_unbind_req_t))
++ goto badprim;
++ if (us-&gt;state != DL_IDLE) {
++ dlpi_error(q, us, DL_UNBIND_REQ, DL_OUTSTATE, 0);
++ break;
++ }
++ us-&gt;sap = -1;
++ us-&gt;state = DL_UNBOUND;
++#ifdef LACHTCP
++ us-&gt;ppa-&gt;ifstats.ifs_active = 0;
++#endif
++ dlpi_ok(q, DL_UNBIND_REQ);
++ break;
++
++ case DL_UNITDATA_REQ:
++ if (size &lt; sizeof(dl_unitdata_req_t))
++ goto badprim;
++ if (us-&gt;state != DL_IDLE) {
++ dlpi_error(q, us, DL_UNITDATA_REQ, DL_OUTSTATE, 0);
++ break;
++ }
++ if ((ppa = us-&gt;ppa) == 0) {
++ cmn_err(CE_CONT, &quot;ppp: in state dl_idle but ppa == 0?\n&quot;);
++ break;
++ }
++ len = mp-&gt;b_cont == 0? 0: msgdsize(mp-&gt;b_cont);
++ if (len &gt; ppa-&gt;mtu) {
++ DPRINT2(&quot;dlpi data too large (%d &gt; %d)\n&quot;, len, ppa-&gt;mtu);
++ break;
++ }
++
++#if defined(SOL2)
++ /*
++ * Should there be any promiscuous stream(s), send the data
++ * up for each promiscuous stream that we recognize.
++ */
++ if (mp-&gt;b_cont)
++ promisc_sendup(ppa, mp-&gt;b_cont, us-&gt;sap, 0);
++#endif /* defined(SOL2) */
++
++ mp-&gt;b_band = 0;
++#ifdef PRIOQ
++ /* Extract s_port &amp; d_port from IP-packet, the code is a bit
++ dirty here, but so am I, too... */
++ if (mp-&gt;b_datap-&gt;db_type == M_PROTO &amp;&amp; us-&gt;sap == PPP_IP
++ &amp;&amp; mp-&gt;b_cont != 0) {
++ u_char *bb, *tlh;
++ int iphlen, len;
++ u_short *ptr;
++ u_char band_unset, cur_band, syn;
++ u_short s_port, d_port;
++
++ bb = mp-&gt;b_cont-&gt;b_rptr; /* bb points to IP-header*/
++ len = mp-&gt;b_cont-&gt;b_wptr - mp-&gt;b_cont-&gt;b_rptr;
++ syn = 0;
++ s_port = IPPORT_DEFAULT;
++ d_port = IPPORT_DEFAULT;
++ if (len &gt;= 20) { /* 20 = minimum length of IP header */
++ iphlen = (bb[0] &amp; 0x0f) * 4;
++ tlh = bb + iphlen;
++ len -= iphlen;
++ switch (bb[9]) {
++ case IPPROTO_TCP:
++ if (len &gt;= 20) { /* min length of TCP header */
++ s_port = (tlh[0] &lt;&lt; 8) + tlh[1];
++ d_port = (tlh[2] &lt;&lt; 8) + tlh[3];
++ syn = tlh[13] &amp; 0x02;
++ }
++ break;
++ case IPPROTO_UDP:
++ if (len &gt;= 8) { /* min length of UDP header */
++ s_port = (tlh[0] &lt;&lt; 8) + tlh[1];
++ d_port = (tlh[2] &lt;&lt; 8) + tlh[3];
++ }
++ break;
++ }
++ }
++
++ /*
++ * Now calculate b_band for this packet from the
++ * port-priority table.
++ */
++ ptr = prioq_table;
++ cur_band = max_band;
++ band_unset = 1;
++ while (*ptr) {
++ while (*ptr &amp;&amp; band_unset)
++ if (s_port == *ptr || d_port == *ptr++) {
++ mp-&gt;b_band = cur_band;
++ band_unset = 0;
++ break;
++ }
++ ptr++;
++ cur_band--;
++ }
++ if (band_unset)
++ mp-&gt;b_band = def_band;
++ /* It may be usable to urge SYN packets a bit */
++ if (syn)
++ mp-&gt;b_band++;
++ }
++#endif /* PRIOQ */
++ /* this assumes PPP_HDRLEN &lt;= sizeof(dl_unitdata_req_t) */
++ if (mp-&gt;b_datap-&gt;db_ref &gt; 1) {
++ np = allocb(PPP_HDRLEN, BPRI_HI);
++ if (np == 0)
++ break; /* gak! */
++ np-&gt;b_cont = mp-&gt;b_cont;
++ mp-&gt;b_cont = 0;
++ freeb(mp);
++ mp = np;
++ } else
++ mp-&gt;b_datap-&gt;db_type = M_DATA;
++ /* XXX should use dl_dest_addr_offset/length here,
++ but we would have to translate ETHERTYPE_IP -&gt; PPP_IP */
++ mp-&gt;b_wptr = mp-&gt;b_rptr + PPP_HDRLEN;
++ mp-&gt;b_rptr[0] = PPP_ALLSTATIONS;
++ mp-&gt;b_rptr[1] = PPP_UI;
++ mp-&gt;b_rptr[2] = us-&gt;sap &gt;&gt; 8;
++ mp-&gt;b_rptr[3] = us-&gt;sap;
++ if (pass_packet(us, mp, 1)) {
++ if (!send_data(mp, us))
++ putq(q, mp);
++ }
++ return;
++
++#if DL_CURRENT_VERSION &gt;= 2
++ case DL_PHYS_ADDR_REQ:
++ if (size &lt; sizeof(dl_phys_addr_req_t))
++ goto badprim;
++
++ /*
++ * Don't check state because ifconfig sends this one down too
++ */
++
++ if ((reply = allocb(sizeof(dl_phys_addr_ack_t)+ETHERADDRL,
++ BPRI_HI)) == 0)
++ break; /* should do bufcall */
++ reply-&gt;b_datap-&gt;db_type = M_PCPROTO;
++ paddrack = (dl_phys_addr_ack_t *) reply-&gt;b_wptr;
++ reply-&gt;b_wptr += sizeof(dl_phys_addr_ack_t);
++ bzero((caddr_t) paddrack, sizeof(dl_phys_addr_ack_t)+ETHERADDRL);
++ paddrack-&gt;dl_primitive = DL_PHYS_ADDR_ACK;
++ paddrack-&gt;dl_addr_length = ETHERADDRL;
++ paddrack-&gt;dl_addr_offset = sizeof(dl_phys_addr_ack_t);
++ bcopy(&amp;eaddr, reply-&gt;b_wptr, ETHERADDRL);
++ reply-&gt;b_wptr += ETHERADDRL;
++ qreply(q, reply);
++ break;
++
++#if defined(SOL2)
++ case DL_PROMISCON_REQ:
++ if (size &lt; sizeof(dl_promiscon_req_t))
++ goto badprim;
++ us-&gt;flags |= US_PROMISC;
++ dlpi_ok(q, DL_PROMISCON_REQ);
++ break;
++
++ case DL_PROMISCOFF_REQ:
++ if (size &lt; sizeof(dl_promiscoff_req_t))
++ goto badprim;
++ us-&gt;flags &amp;= ~US_PROMISC;
++ dlpi_ok(q, DL_PROMISCOFF_REQ);
++ break;
++#else
++ case DL_PROMISCON_REQ: /* fall thru */
++ case DL_PROMISCOFF_REQ: /* fall thru */
++#endif /* defined(SOL2) */
++#endif /* DL_CURRENT_VERSION &gt;= 2 */
++
++#if DL_CURRENT_VERSION &gt;= 2
++ case DL_SET_PHYS_ADDR_REQ:
++ case DL_SUBS_BIND_REQ:
++ case DL_SUBS_UNBIND_REQ:
++ case DL_ENABMULTI_REQ:
++ case DL_DISABMULTI_REQ:
++ case DL_XID_REQ:
++ case DL_TEST_REQ:
++ case DL_REPLY_UPDATE_REQ:
++ case DL_REPLY_REQ:
++ case DL_DATA_ACK_REQ:
++#endif
++ case DL_CONNECT_REQ:
++ case DL_TOKEN_REQ:
++ dlpi_error(q, us, d-&gt;dl_primitive, DL_NOTSUPPORTED, 0);
++ break;
++
++ case DL_CONNECT_RES:
++ case DL_DISCONNECT_REQ:
++ case DL_RESET_REQ:
++ case DL_RESET_RES:
++ dlpi_error(q, us, d-&gt;dl_primitive, DL_OUTSTATE, 0);
++ break;
++
++ case DL_UDQOS_REQ:
++ dlpi_error(q, us, d-&gt;dl_primitive, DL_BADQOSTYPE, 0);
++ break;
++
++#if DL_CURRENT_VERSION &gt;= 2
++ case DL_TEST_RES:
++ case DL_XID_RES:
++ break;
++#endif
++
++ default:
++ cmn_err(CE_CONT, &quot;ppp: unknown dlpi prim 0x%x\n&quot;, d-&gt;dl_primitive);
++ /* fall through */
++ badprim:
++ dlpi_error(q, us, d-&gt;dl_primitive, DL_BADPRIM, 0);
++ break;
++ }
++ freemsg(mp);
++}
++
++static void
++dlpi_error(q, us, prim, err, uerr)
++ queue_t *q;
++ upperstr_t *us;
++ int prim, err, uerr;
++{
++ mblk_t *reply;
++ dl_error_ack_t *errp;
++
++ if (us-&gt;flags &amp; US_DBGLOG)
++ DPRINT3(&quot;ppp/%d: dlpi error, prim=%x, err=%x\n&quot;, us-&gt;mn, prim, err);
++ reply = allocb(sizeof(dl_error_ack_t), BPRI_HI);
++ if (reply == 0)
++ return; /* XXX should do bufcall */
++ reply-&gt;b_datap-&gt;db_type = M_PCPROTO;
++ errp = (dl_error_ack_t *) reply-&gt;b_wptr;
++ reply-&gt;b_wptr += sizeof(dl_error_ack_t);
++ errp-&gt;dl_primitive = DL_ERROR_ACK;
++ errp-&gt;dl_error_primitive = prim;
++ errp-&gt;dl_errno = err;
++ errp-&gt;dl_unix_errno = uerr;
++ qreply(q, reply);
++}
++
++static void
++dlpi_ok(q, prim)
++ queue_t *q;
++ int prim;
++{
++ mblk_t *reply;
++ dl_ok_ack_t *okp;
++
++ reply = allocb(sizeof(dl_ok_ack_t), BPRI_HI);
++ if (reply == 0)
++ return; /* XXX should do bufcall */
++ reply-&gt;b_datap-&gt;db_type = M_PCPROTO;
++ okp = (dl_ok_ack_t *) reply-&gt;b_wptr;
++ reply-&gt;b_wptr += sizeof(dl_ok_ack_t);
++ okp-&gt;dl_primitive = DL_OK_ACK;
++ okp-&gt;dl_correct_primitive = prim;
++ qreply(q, reply);
++}
++#endif /* NO_DLPI */
++
++static int
++pass_packet(us, mp, outbound)
++ upperstr_t *us;
++ mblk_t *mp;
++ int outbound;
++{
++ int pass;
++ upperstr_t *ppa;
++
++ if ((ppa = us-&gt;ppa) == 0) {
++ freemsg(mp);
++ return 0;
++ }
++
++#ifdef FILTER_PACKETS
++ pass = ip_hard_filter(us, mp, outbound);
++#else
++ /*
++ * Here is where we might, in future, decide whether to pass
++ * or drop the packet, and whether it counts as link activity.
++ */
++ pass = 1;
++#endif /* FILTER_PACKETS */
++
++ if (pass &lt; 0) {
++ /* pass only if link already up, and don't update time */
++ if (ppa-&gt;lowerq == 0) {
++ freemsg(mp);
++ return 0;
++ }
++ pass = 1;
++ } else if (pass) {
++ if (outbound)
++ ppa-&gt;last_sent = time;
++ else
++ ppa-&gt;last_recv = time;
++ }
++
++ return pass;
++}
++
++/*
++ * We have some data to send down to the lower stream (or up the
++ * control stream, if we don't have a lower stream attached).
++ * Returns 1 if the message was dealt with, 0 if it wasn't able
++ * to be sent on and should therefore be queued up.
++ */
++static int
++send_data(mp, us)
++ mblk_t *mp;
++ upperstr_t *us;
++{
++ upperstr_t *ppa;
++
++ if ((us-&gt;flags &amp; US_BLOCKED) || us-&gt;npmode == NPMODE_QUEUE)
++ return 0;
++ ppa = us-&gt;ppa;
++ if (ppa == 0 || us-&gt;npmode == NPMODE_DROP || us-&gt;npmode == NPMODE_ERROR) {
++ if (us-&gt;flags &amp; US_DBGLOG)
++ DPRINT2(&quot;ppp/%d: dropping pkt (npmode=%d)\n&quot;, us-&gt;mn, us-&gt;npmode);
++ freemsg(mp);
++ return 1;
++ }
++ if (ppa-&gt;lowerq == 0) {
++ /* try to send it up the control stream */
++ if (bcanputnext(ppa-&gt;q, mp-&gt;b_band)) {
++ /*
++ * The message seems to get corrupted for some reason if
++ * we just send the message up as it is, so we send a copy.
++ */
++ mblk_t *np = copymsg(mp);
++ freemsg(mp);
++ if (np != 0)
++ putnext(ppa-&gt;q, np);
++ return 1;
++ }
++ } else {
++ if (bcanputnext(ppa-&gt;lowerq, mp-&gt;b_band)) {
++ MT_ENTER(&amp;ppa-&gt;stats_lock);
++ ppa-&gt;stats.ppp_opackets++;
++ ppa-&gt;stats.ppp_obytes += msgdsize(mp);
++#ifdef INCR_OPACKETS
++ INCR_OPACKETS(ppa);
++#endif
++ MT_EXIT(&amp;ppa-&gt;stats_lock);
++ /*
++ * The lower queue is only ever detached while holding an
++ * exclusive lock on the whole driver. So we can be confident
++ * that the lower queue is still there.
++ */
++ putnext(ppa-&gt;lowerq, mp);
++ return 1;
++ }
++ }
++ us-&gt;flags |= US_BLOCKED;
++ return 0;
++}
++
++/*
++ * Allocate a new PPA id and link this stream into the list of PPAs.
++ * This procedure is called with an exclusive lock on all queues in
++ * this driver.
++ */
++static void
++new_ppa(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ upperstr_t *us, *up, **usp;
++ int ppa_id;
++
++ us = (upperstr_t *) q-&gt;q_ptr;
++ if (us == 0) {
++ DPRINT(&quot;new_ppa: q_ptr = 0!\n&quot;);
++ return;
++ }
++
++ usp = &amp;ppas;
++ ppa_id = 0;
++ while ((up = *usp) != 0 &amp;&amp; ppa_id == up-&gt;ppa_id) {
++ ++ppa_id;
++ usp = &amp;up-&gt;nextppa;
++ }
++ us-&gt;ppa_id = ppa_id;
++ us-&gt;ppa = us;
++ us-&gt;next = 0;
++ us-&gt;nextppa = *usp;
++ *usp = us;
++ us-&gt;flags |= US_CONTROL;
++ us-&gt;npmode = NPMODE_PASS;
++
++ us-&gt;mtu = PPP_MTU;
++ us-&gt;mru = PPP_MRU;
++
++#ifdef SOL2
++ /*
++ * Create a kstats record for our statistics, so netstat -i works.
++ */
++ if (us-&gt;kstats == 0) {
++ char unit[32];
++
++ sprintf(unit, &quot;ppp%d&quot;, us-&gt;ppa-&gt;ppa_id);
++ us-&gt;kstats = kstat_create(&quot;ppp&quot;, us-&gt;ppa-&gt;ppa_id, unit,
++ &quot;net&quot;, KSTAT_TYPE_NAMED, 4, 0);
++ if (us-&gt;kstats != 0) {
++ kstat_named_t *kn = KSTAT_NAMED_PTR(us-&gt;kstats);
++
++ strcpy(kn[0].name, &quot;ipackets&quot;);
++ kn[0].data_type = KSTAT_DATA_ULONG;
++ strcpy(kn[1].name, &quot;ierrors&quot;);
++ kn[1].data_type = KSTAT_DATA_ULONG;
++ strcpy(kn[2].name, &quot;opackets&quot;);
++ kn[2].data_type = KSTAT_DATA_ULONG;
++ strcpy(kn[3].name, &quot;oerrors&quot;);
++ kn[3].data_type = KSTAT_DATA_ULONG;
++ kstat_install(us-&gt;kstats);
++ }
++ }
++#endif /* SOL2 */
++
++ *(int *)mp-&gt;b_cont-&gt;b_rptr = ppa_id;
++ mp-&gt;b_datap-&gt;db_type = M_IOCACK;
++ qreply(q, mp);
++}
++
++static void
++attach_ppa(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ upperstr_t *us, *t;
++
++ us = (upperstr_t *) q-&gt;q_ptr;
++ if (us == 0) {
++ DPRINT(&quot;attach_ppa: q_ptr = 0!\n&quot;);
++ return;
++ }
++
++#ifndef NO_DLPI
++ us-&gt;state = DL_UNBOUND;
++#endif
++ for (t = us-&gt;ppa; t-&gt;next != 0; t = t-&gt;next)
++ ;
++ t-&gt;next = us;
++ us-&gt;next = 0;
++ if (mp-&gt;b_datap-&gt;db_type == M_IOCTL) {
++ mp-&gt;b_datap-&gt;db_type = M_IOCACK;
++ qreply(q, mp);
++ } else {
++#ifndef NO_DLPI
++ dlpi_ok(q, DL_ATTACH_REQ);
++#endif
++ }
++}
++
++static void
++detach_ppa(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ upperstr_t *us, *t;
++
++ us = (upperstr_t *) q-&gt;q_ptr;
++ if (us == 0) {
++ DPRINT(&quot;detach_ppa: q_ptr = 0!\n&quot;);
++ return;
++ }
++
++ for (t = us-&gt;ppa; t-&gt;next != 0; t = t-&gt;next)
++ if (t-&gt;next == us) {
++ t-&gt;next = us-&gt;next;
++ break;
++ }
++ us-&gt;next = 0;
++ us-&gt;ppa = 0;
++#ifndef NO_DLPI
++ us-&gt;state = DL_UNATTACHED;
++ dlpi_ok(q, DL_DETACH_REQ);
++#endif
++}
++
++/*
++ * We call this with qwriter in order to give the upper queue procedures
++ * the guarantee that the lower queue is not going to go away while
++ * they are executing.
++ */
++static void
++detach_lower(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ upperstr_t *us;
++
++ us = (upperstr_t *) q-&gt;q_ptr;
++ if (us == 0) {
++ DPRINT(&quot;detach_lower: q_ptr = 0!\n&quot;);
++ return;
++ }
++
++ LOCK_LOWER_W;
++ us-&gt;lowerq-&gt;q_ptr = 0;
++ RD(us-&gt;lowerq)-&gt;q_ptr = 0;
++ us-&gt;lowerq = 0;
++ UNLOCK_LOWER;
++
++ /* Unblock streams which now feed back up the control stream. */
++ qenable(us-&gt;q);
++
++ mp-&gt;b_datap-&gt;db_type = M_IOCACK;
++ qreply(q, mp);
++}
++
++static int
++pppuwsrv(q)
++ queue_t *q;
++{
++ upperstr_t *us, *as;
++ mblk_t *mp;
++
++ us = (upperstr_t *) q-&gt;q_ptr;
++ if (us == 0) {
++ DPRINT(&quot;pppuwsrv: q_ptr = 0!\n&quot;);
++ return 0;
++ }
++
++ /*
++ * If this is a control stream, then this service procedure
++ * probably got enabled because of flow control in the lower
++ * stream being enabled (or because of the lower stream going
++ * away). Therefore we enable the service procedure of all
++ * attached upper streams.
++ */
++ if (us-&gt;flags &amp; US_CONTROL) {
++ for (as = us-&gt;next; as != 0; as = as-&gt;next)
++ qenable(WR(as-&gt;q));
++ }
++
++ /* Try to send on any data queued here. */
++ us-&gt;flags &amp;= ~US_BLOCKED;
++ while ((mp = getq(q)) != 0) {
++ if (!send_data(mp, us)) {
++ putbq(q, mp);
++ break;
++ }
++ }
++
++ return 0;
++}
++
++/* should never get called... */
++static int
++ppplwput(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ putnext(q, mp);
++ return 0;
++}
++
++static int
++ppplwsrv(q)
++ queue_t *q;
++{
++ queue_t *uq;
++
++ /*
++ * Flow control has back-enabled this stream:
++ * enable the upper write service procedure for
++ * the upper control stream for this lower stream.
++ */
++ LOCK_LOWER_R;
++ uq = (queue_t *) q-&gt;q_ptr;
++ if (uq != 0)
++ qenable(uq);
++ UNLOCK_LOWER;
++ return 0;
++}
++
++/*
++ * This should only get called for control streams.
++ */
++static int
++pppurput(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ upperstr_t *ppa, *us;
++ int proto, len;
++ struct iocblk *iop;
++
++ ppa = (upperstr_t *) q-&gt;q_ptr;
++ if (ppa == 0) {
++ DPRINT(&quot;pppurput: q_ptr = 0!\n&quot;);
++ return 0;
++ }
++
++ switch (mp-&gt;b_datap-&gt;db_type) {
++ case M_CTL:
++ MT_ENTER(&amp;ppa-&gt;stats_lock);
++ switch (*mp-&gt;b_rptr) {
++ case PPPCTL_IERROR:
++#ifdef INCR_IERRORS
++ INCR_IERRORS(ppa);
++#endif
++ ppa-&gt;stats.ppp_ierrors++;
++ break;
++ case PPPCTL_OERROR:
++#ifdef INCR_OERRORS
++ INCR_OERRORS(ppa);
++#endif
++ ppa-&gt;stats.ppp_oerrors++;
++ break;
++ }
++ MT_EXIT(&amp;ppa-&gt;stats_lock);
++ freemsg(mp);
++ break;
++
++ case M_IOCACK:
++ case M_IOCNAK:
++ /*
++ * Attempt to match up the response with the stream
++ * that the request came from.
++ */
++ iop = (struct iocblk *) mp-&gt;b_rptr;
++ for (us = ppa; us != 0; us = us-&gt;next)
++ if (us-&gt;ioc_id == iop-&gt;ioc_id)
++ break;
++ if (us == 0)
++ freemsg(mp);
++ else
++ putnext(us-&gt;q, mp);
++ break;
++
++ case M_HANGUP:
++ /*
++ * The serial device has hung up. We don't want to send
++ * the M_HANGUP message up to pppd because that will stop
++ * us from using the control stream any more. Instead we
++ * send a zero-length message as an end-of-file indication.
++ */
++ freemsg(mp);
++ mp = allocb(1, BPRI_HI);
++ if (mp == 0) {
++ DPRINT1(&quot;ppp/%d: couldn't allocate eof message!\n&quot;, ppa-&gt;mn);
++ break;
++ }
++ putnext(ppa-&gt;q, mp);
++ break;
++
++ default:
++ if (mp-&gt;b_datap-&gt;db_type == M_DATA) {
++ len = msgdsize(mp);
++ if (mp-&gt;b_wptr - mp-&gt;b_rptr &lt; PPP_HDRLEN) {
++ PULLUP(mp, PPP_HDRLEN);
++ if (mp == 0) {
++ DPRINT1(&quot;ppp_urput: msgpullup failed (len=%d)\n&quot;, len);
++ break;
++ }
++ }
++ MT_ENTER(&amp;ppa-&gt;stats_lock);
++ ppa-&gt;stats.ppp_ipackets++;
++ ppa-&gt;stats.ppp_ibytes += len;
++#ifdef INCR_IPACKETS
++ INCR_IPACKETS(ppa);
++#endif
++ MT_EXIT(&amp;ppa-&gt;stats_lock);
++
++ proto = PPP_PROTOCOL(mp-&gt;b_rptr);
++
++#if defined(SOL2)
++ /*
++ * Should there be any promiscuous stream(s), send the data
++ * up for each promiscuous stream that we recognize.
++ */
++ promisc_sendup(ppa, mp, proto, 1);
++#endif /* defined(SOL2) */
++
++ if (proto &lt; 0x8000 &amp;&amp; (us = find_dest(ppa, proto)) != 0) {
++ /*
++ * A data packet for some network protocol.
++ * Queue it on the upper stream for that protocol.
++ * XXX could we just putnext it? (would require thought)
++ * The rblocked flag is there to ensure that we keep
++ * messages in order for each network protocol.
++ */
++ if (!pass_packet(us, mp, 0))
++ break;
++ if (!us-&gt;rblocked &amp;&amp; !canput(us-&gt;q))
++ us-&gt;rblocked = 1;
++ if (!us-&gt;rblocked)
++ putq(us-&gt;q, mp);
++ else
++ putq(q, mp);
++ break;
++ }
++ }
++ /*
++ * A control frame, a frame for an unknown protocol,
++ * or some other message type.
++ * Send it up to pppd via the control stream.
++ */
++ if (queclass(mp) == QPCTL || canputnext(ppa-&gt;q))
++ putnext(ppa-&gt;q, mp);
++ else
++ putq(q, mp);
++ break;
++ }
++
++ return 0;
++}
++
++static int
++pppursrv(q)
++ queue_t *q;
++{
++ upperstr_t *us, *as;
++ mblk_t *mp, *hdr;
++#ifndef NO_DLPI
++ dl_unitdata_ind_t *ud;
++#endif
++ int proto;
++
++ us = (upperstr_t *) q-&gt;q_ptr;
++ if (us == 0) {
++ DPRINT(&quot;pppursrv: q_ptr = 0!\n&quot;);
++ return 0;
++ }
++
++ if (us-&gt;flags &amp; US_CONTROL) {
++ /*
++ * A control stream.
++ * If there is no lower queue attached, run the write service
++ * routines of other upper streams attached to this PPA.
++ */
++ if (us-&gt;lowerq == 0) {
++ as = us;
++ do {
++ if (as-&gt;flags &amp; US_BLOCKED)
++ qenable(WR(as-&gt;q));
++ as = as-&gt;next;
++ } while (as != 0);
++ }
++
++ /*
++ * Messages get queued on this stream's read queue if they
++ * can't be queued on the read queue of the attached stream
++ * that they are destined for. This is for flow control -
++ * when this queue fills up, the lower read put procedure will
++ * queue messages there and the flow control will propagate
++ * down from there.
++ */
++ while ((mp = getq(q)) != 0) {
++ proto = PPP_PROTOCOL(mp-&gt;b_rptr);
++ if (proto &lt; 0x8000 &amp;&amp; (as = find_dest(us, proto)) != 0) {
++ if (!canput(as-&gt;q))
++ break;
++ putq(as-&gt;q, mp);
++ } else {
++ if (!canputnext(q))
++ break;
++ putnext(q, mp);
++ }
++ }
++ if (mp) {
++ putbq(q, mp);
++ } else {
++ /* can now put stuff directly on network protocol streams again */
++ for (as = us-&gt;next; as != 0; as = as-&gt;next)
++ as-&gt;rblocked = 0;
++ }
++
++ /*
++ * If this stream has a lower stream attached,
++ * enable the read queue's service routine.
++ * XXX we should really only do this if the queue length
++ * has dropped below the low-water mark.
++ */
++ if (us-&gt;lowerq != 0)
++ qenable(RD(us-&gt;lowerq));
++
++ } else {
++ /*
++ * A network protocol stream. Put a DLPI header on each
++ * packet and send it on.
++ * (Actually, it seems that the IP module will happily
++ * accept M_DATA messages without the DL_UNITDATA_IND header.)
++ */
++ while ((mp = getq(q)) != 0) {
++ if (!canputnext(q)) {
++ putbq(q, mp);
++ break;
++ }
++#ifndef NO_DLPI
++ proto = PPP_PROTOCOL(mp-&gt;b_rptr);
++ mp-&gt;b_rptr += PPP_HDRLEN;
++ hdr = allocb(sizeof(dl_unitdata_ind_t) + 2 * sizeof(uint),
++ BPRI_MED);
++ if (hdr == 0) {
++ /* XXX should put it back and use bufcall */
++ freemsg(mp);
++ continue;
++ }
++ hdr-&gt;b_datap-&gt;db_type = M_PROTO;
++ ud = (dl_unitdata_ind_t *) hdr-&gt;b_wptr;
++ hdr-&gt;b_wptr += sizeof(dl_unitdata_ind_t) + 2 * sizeof(uint);
++ hdr-&gt;b_cont = mp;
++ ud-&gt;dl_primitive = DL_UNITDATA_IND;
++ ud-&gt;dl_dest_addr_length = sizeof(uint);
++ ud-&gt;dl_dest_addr_offset = sizeof(dl_unitdata_ind_t);
++ ud-&gt;dl_src_addr_length = sizeof(uint);
++ ud-&gt;dl_src_addr_offset = ud-&gt;dl_dest_addr_offset + sizeof(uint);
++#if DL_CURRENT_VERSION &gt;= 2
++ ud-&gt;dl_group_address = 0;
++#endif
++ /* Send the DLPI client the data with the SAP they requested,
++ (e.g. ETHERTYPE_IP) rather than the PPP protocol number
++ (e.g. PPP_IP) */
++ ((uint *)(ud + 1))[0] = us-&gt;req_sap; /* dest SAP */
++ ((uint *)(ud + 1))[1] = us-&gt;req_sap; /* src SAP */
++ putnext(q, hdr);
++#else /* NO_DLPI */
++ putnext(q, mp);
++#endif /* NO_DLPI */
++ }
++ /*
++ * Now that we have consumed some packets from this queue,
++ * enable the control stream's read service routine so that we
++ * can process any packets for us that might have got queued
++ * there for flow control reasons.
++ */
++ if (us-&gt;ppa)
++ qenable(us-&gt;ppa-&gt;q);
++ }
++
++ return 0;
++}
++
++static upperstr_t *
++find_dest(ppa, proto)
++ upperstr_t *ppa;
++ int proto;
++{
++ upperstr_t *us;
++
++ for (us = ppa-&gt;next; us != 0; us = us-&gt;next)
++ if (proto == us-&gt;sap)
++ break;
++ return us;
++}
++
++#if defined (SOL2)
++/*
++ * Test upstream promiscuous conditions. As of now, only pass IPv4 and
++ * Ipv6 packets upstream (let PPP packets be decoded elsewhere).
++ */
++static upperstr_t *
++find_promisc(us, proto)
++ upperstr_t *us;
++ int proto;
++{
++
++ if ((proto != PPP_IP) &amp;&amp; (proto != PPP_IPV6))
++ return (upperstr_t *)0;
++
++ for ( ; us; us = us-&gt;next) {
++ if ((us-&gt;flags &amp; US_PROMISC) &amp;&amp; (us-&gt;state == DL_IDLE))
++ return us;
++ }
++
++ return (upperstr_t *)0;
++}
++
++/*
++ * Prepend an empty Ethernet header to msg for snoop, et al.
++ */
++static mblk_t *
++prepend_ether(us, mp, proto)
++ upperstr_t *us;
++ mblk_t *mp;
++ int proto;
++{
++ mblk_t *eh;
++ int type;
++
++ if ((eh = allocb(sizeof(struct ether_header), BPRI_HI)) == 0) {
++ freemsg(mp);
++ return (mblk_t *)0;
++ }
++
++ if (proto == PPP_IP)
++ type = ETHERTYPE_IP;
++ else if (proto == PPP_IPV6)
++ type = ETHERTYPE_IPV6;
++ else
++ type = proto; /* What else? Let decoder decide */
++
++ eh-&gt;b_wptr += sizeof(struct ether_header);
++ bzero((caddr_t)eh-&gt;b_rptr, sizeof(struct ether_header));
++ ((struct ether_header *)eh-&gt;b_rptr)-&gt;ether_type = htons((short)type);
++ eh-&gt;b_cont = mp;
++ return (eh);
++}
++
++/*
++ * Prepend DL_UNITDATA_IND mblk to msg
++ */
++static mblk_t *
++prepend_udind(us, mp, proto)
++ upperstr_t *us;
++ mblk_t *mp;
++ int proto;
++{
++ dl_unitdata_ind_t *dlu;
++ mblk_t *dh;
++ size_t size;
++
++ size = sizeof(dl_unitdata_ind_t);
++ if ((dh = allocb(size, BPRI_MED)) == 0) {
++ freemsg(mp);
++ return (mblk_t *)0;
++ }
++
++ dh-&gt;b_datap-&gt;db_type = M_PROTO;
++ dh-&gt;b_wptr = dh-&gt;b_datap-&gt;db_lim;
++ dh-&gt;b_rptr = dh-&gt;b_wptr - size;
++
++ dlu = (dl_unitdata_ind_t *)dh-&gt;b_rptr;
++ dlu-&gt;dl_primitive = DL_UNITDATA_IND;
++ dlu-&gt;dl_dest_addr_length = 0;
++ dlu-&gt;dl_dest_addr_offset = sizeof(dl_unitdata_ind_t);
++ dlu-&gt;dl_src_addr_length = 0;
++ dlu-&gt;dl_src_addr_offset = sizeof(dl_unitdata_ind_t);
++ dlu-&gt;dl_group_address = 0;
++
++ dh-&gt;b_cont = mp;
++ return (dh);
++}
++
++/*
++ * For any recognized promiscuous streams, send data upstream
++ */
++static void
++promisc_sendup(ppa, mp, proto, skip)
++ upperstr_t *ppa;
++ mblk_t *mp;
++ int proto, skip;
++{
++ mblk_t *dup_mp, *dup_dup_mp;
++ upperstr_t *prus, *nprus;
++
++ if ((prus = find_promisc(ppa, proto)) != 0) {
++ if (dup_mp = dupmsg(mp)) {
++
++ if (skip)
++ dup_mp-&gt;b_rptr += PPP_HDRLEN;
++
++ for ( ; nprus = find_promisc(prus-&gt;next, proto);
++ prus = nprus) {
++
++ if (dup_dup_mp = dupmsg(dup_mp)) {
++ if (canputnext(prus-&gt;q)) {
++ if (prus-&gt;flags &amp; US_RAWDATA) {
++ dup_dup_mp = prepend_ether(prus, dup_dup_mp, proto);
++ putnext(prus-&gt;q, dup_dup_mp);
++ } else {
++ dup_dup_mp = prepend_udind(prus, dup_dup_mp, proto);
++ putnext(prus-&gt;q, dup_dup_mp);
++ }
++ } else {
++ DPRINT(&quot;ppp_urput: data to promisc q dropped\n&quot;);
++ freemsg(dup_dup_mp);
++ }
++ }
++ }
++
++ if (canputnext(prus-&gt;q)) {
++ if (prus-&gt;flags &amp; US_RAWDATA) {
++ dup_mp = prepend_ether(prus, dup_mp, proto);
++ putnext(prus-&gt;q, dup_mp);
++ } else {
++ dup_mp = prepend_udind(prus, dup_mp, proto);
++ putnext(prus-&gt;q, dup_mp);
++ }
++ } else {
++ DPRINT(&quot;ppp_urput: data to promisc q dropped\n&quot;);
++ freemsg(dup_mp);
++ }
++ }
++ }
++}
++#endif /* defined(SOL2) */
++
++/*
++ * We simply put the message on to the associated upper control stream
++ * (either here or in ppplrsrv). That way we enter the perimeters
++ * before looking through the list of attached streams to decide which
++ * stream it should go up.
++ */
++static int
++ppplrput(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ queue_t *uq;
++ struct iocblk *iop;
++
++ switch (mp-&gt;b_datap-&gt;db_type) {
++ case M_IOCTL:
++ iop = (struct iocblk *) mp-&gt;b_rptr;
++ iop-&gt;ioc_error = EINVAL;
++ mp-&gt;b_datap-&gt;db_type = M_IOCNAK;
++ qreply(q, mp);
++ return 0;
++ case M_FLUSH:
++ if (*mp-&gt;b_rptr &amp; FLUSHR)
++ flushq(q, FLUSHDATA);
++ if (*mp-&gt;b_rptr &amp; FLUSHW) {
++ *mp-&gt;b_rptr &amp;= ~FLUSHR;
++ qreply(q, mp);
++ } else
++ freemsg(mp);
++ return 0;
++ }
++
++ /*
++ * If we can't get the lower lock straight away, queue this one
++ * rather than blocking, to avoid the possibility of deadlock.
++ */
++ if (!TRYLOCK_LOWER_R) {
++ putq(q, mp);
++ return 0;
++ }
++
++ /*
++ * Check that we're still connected to the driver.
++ */
++ uq = (queue_t *) q-&gt;q_ptr;
++ if (uq == 0) {
++ UNLOCK_LOWER;
++ DPRINT1(&quot;ppplrput: q = %x, uq = 0??\n&quot;, q);
++ freemsg(mp);
++ return 0;
++ }
++
++ /*
++ * Try to forward the message to the put routine for the upper
++ * control stream for this lower stream.
++ * If there are already messages queued here, queue this one so
++ * they don't get out of order.
++ */
++ if (queclass(mp) == QPCTL || (qsize(q) == 0 &amp;&amp; canput(uq)))
++ put(uq, mp);
++ else
++ putq(q, mp);
++
++ UNLOCK_LOWER;
++ return 0;
++}
++
++static int
++ppplrsrv(q)
++ queue_t *q;
++{
++ mblk_t *mp;
++ queue_t *uq;
++
++ /*
++ * Packets get queued here for flow control reasons
++ * or if the lrput routine couldn't get the lower lock
++ * without blocking.
++ */
++ LOCK_LOWER_R;
++ uq = (queue_t *) q-&gt;q_ptr;
++ if (uq == 0) {
++ UNLOCK_LOWER;
++ flushq(q, FLUSHALL);
++ DPRINT1(&quot;ppplrsrv: q = %x, uq = 0??\n&quot;, q);
++ return 0;
++ }
++ while ((mp = getq(q)) != 0) {
++ if (queclass(mp) == QPCTL || canput(uq))
++ put(uq, mp);
++ else {
++ putbq(q, mp);
++ break;
++ }
++ }
++ UNLOCK_LOWER;
++ return 0;
++}
++
++static int
++putctl2(q, type, code, val)
++ queue_t *q;
++ int type, code, val;
++{
++ mblk_t *mp;
++
++ mp = allocb(2, BPRI_HI);
++ if (mp == 0)
++ return 0;
++ mp-&gt;b_datap-&gt;db_type = type;
++ mp-&gt;b_wptr[0] = code;
++ mp-&gt;b_wptr[1] = val;
++ mp-&gt;b_wptr += 2;
++ putnext(q, mp);
++ return 1;
++}
++
++static int
++putctl4(q, type, code, val)
++ queue_t *q;
++ int type, code, val;
++{
++ mblk_t *mp;
++
++ mp = allocb(4, BPRI_HI);
++ if (mp == 0)
++ return 0;
++ mp-&gt;b_datap-&gt;db_type = type;
++ mp-&gt;b_wptr[0] = code;
++ ((short *)mp-&gt;b_wptr)[1] = val;
++ mp-&gt;b_wptr += 4;
++ putnext(q, mp);
++ return 1;
++}
++
++static void
++debug_dump(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ upperstr_t *us;
++ queue_t *uq, *lq;
++
++ DPRINT(&quot;ppp upper streams:\n&quot;);
++ for (us = minor_devs; us != 0; us = us-&gt;nextmn) {
++ uq = us-&gt;q;
++ DPRINT3(&quot; %d: q=%x rlev=%d&quot;,
++ us-&gt;mn, uq, (uq? qsize(uq): 0));
++ DPRINT3(&quot; wlev=%d flags=0x%b&quot;, (uq? qsize(WR(uq)): 0),
++ us-&gt;flags, &quot;\020\1priv\2control\3blocked\4last&quot;);
++ DPRINT3(&quot; state=%x sap=%x req_sap=%x&quot;, us-&gt;state, us-&gt;sap,
++ us-&gt;req_sap);
++ if (us-&gt;ppa == 0)
++ DPRINT(&quot; ppa=?\n&quot;);
++ else
++ DPRINT1(&quot; ppa=%d\n&quot;, us-&gt;ppa-&gt;ppa_id);
++ if (us-&gt;flags &amp; US_CONTROL) {
++ lq = us-&gt;lowerq;
++ DPRINT3(&quot; control for %d lq=%x rlev=%d&quot;,
++ us-&gt;ppa_id, lq, (lq? qsize(RD(lq)): 0));
++ DPRINT3(&quot; wlev=%d mru=%d mtu=%d\n&quot;,
++ (lq? qsize(lq): 0), us-&gt;mru, us-&gt;mtu);
++ }
++ }
++ mp-&gt;b_datap-&gt;db_type = M_IOCACK;
++ qreply(q, mp);
++}
++
++#ifdef FILTER_PACKETS
++#include &lt;netinet/in_systm.h&gt;
++#include &lt;netinet/ip.h&gt;
++#include &lt;netinet/udp.h&gt;
++#include &lt;netinet/tcp.h&gt;
++
++#define MAX_IPHDR 128 /* max TCP/IP header size */
++
++
++/* The following table contains a hard-coded list of protocol/port pairs.
++ * Any matching packets are either discarded unconditionally, or,
++ * if ok_if_link_up is non-zero when a connection does not currently exist
++ * (i.e., they go through if the connection is present, but never initiate
++ * a dial-out).
++ * This idea came from a post by <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dm at garage.uun.org</A> (David Mazieres)
++ */
++static struct pktfilt_tab {
++ int proto;
++ u_short port;
++ u_short ok_if_link_up;
++} pktfilt_tab[] = {
++ { IPPROTO_UDP, 520, 1 }, /* RIP, ok to pass if link is up */
++ { IPPROTO_UDP, 123, 1 }, /* NTP, don't keep up the link for it */
++ { -1, 0, 0 } /* terminator entry has port == -1 */
++};
++
++
++static int
++ip_hard_filter(us, mp, outbound)
++ upperstr_t *us;
++ mblk_t *mp;
++ int outbound;
++{
++ struct ip *ip;
++ struct pktfilt_tab *pft;
++ mblk_t *temp_mp;
++ int proto;
++ int len, hlen;
++
++
++ /* Note, the PPP header has already been pulled up in all cases */
++ proto = PPP_PROTOCOL(mp-&gt;b_rptr);
++ if (us-&gt;flags &amp; US_DBGLOG)
++ DPRINT3(&quot;ppp/%d: filter, proto=0x%x, out=%d\n&quot;, us-&gt;mn, proto, outbound);
++
++ switch (proto)
++ {
++ case PPP_IP:
++ if ((mp-&gt;b_wptr - mp-&gt;b_rptr) == PPP_HDRLEN &amp;&amp; mp-&gt;b_cont != 0) {
++ temp_mp = mp-&gt;b_cont;
++ len = msgdsize(temp_mp);
++ hlen = (len &lt; MAX_IPHDR) ? len : MAX_IPHDR;
++ PULLUP(temp_mp, hlen);
++ if (temp_mp == 0) {
++ DPRINT2(&quot;ppp/%d: filter, pullup next failed, len=%d\n&quot;,
++ us-&gt;mn, hlen);
++ mp-&gt;b_cont = 0; /* PULLUP() freed the rest */
++ freemsg(mp);
++ return 0;
++ }
++ ip = (struct ip *)mp-&gt;b_cont-&gt;b_rptr;
++ }
++ else {
++ len = msgdsize(mp);
++ hlen = (len &lt; (PPP_HDRLEN+MAX_IPHDR)) ? len : (PPP_HDRLEN+MAX_IPHDR);
++ PULLUP(mp, hlen);
++ if (mp == 0) {
++ DPRINT2(&quot;ppp/%d: filter, pullup failed, len=%d\n&quot;,
++ us-&gt;mn, hlen);
++ return 0;
++ }
++ ip = (struct ip *)(mp-&gt;b_rptr + PPP_HDRLEN);
++ }
++
++ /* For IP traffic, certain packets (e.g., RIP) may be either
++ * 1. ignored - dropped completely
++ * 2. will not initiate a connection, but
++ * will be passed if a connection is currently up.
++ */
++ for (pft=pktfilt_tab; pft-&gt;proto != -1; pft++) {
++ if (ip-&gt;ip_p == pft-&gt;proto) {
++ switch(pft-&gt;proto) {
++ case IPPROTO_UDP:
++ if (((struct udphdr *) &amp;((int *)ip)[ip-&gt;ip_hl])-&gt;uh_dport
++ == htons(pft-&gt;port)) goto endfor;
++ break;
++ case IPPROTO_TCP:
++ if (((struct tcphdr *) &amp;((int *)ip)[ip-&gt;ip_hl])-&gt;th_dport
++ == htons(pft-&gt;port)) goto endfor;
++ break;
++ }
++ }
++ }
++ endfor:
++ if (pft-&gt;proto != -1) {
++ if (us-&gt;flags &amp; US_DBGLOG)
++ DPRINT3(&quot;ppp/%d: found IP pkt, proto=0x%x (%d)\n&quot;,
++ us-&gt;mn, pft-&gt;proto, pft-&gt;port);
++ /* Discard if not connected, or if not pass_with_link_up */
++ /* else, if link is up let go by, but don't update time */
++ return pft-&gt;ok_if_link_up? -1: 0;
++ }
++ break;
++ } /* end switch (proto) */
++
++ return 1;
++}
++#endif /* FILTER_PACKETS */
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/modules/ppp.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/modules/ppp_ahdlc.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/modules/ppp_ahdlc.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/modules/ppp_ahdlc.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,878 @@
++/*
++ * ppp_ahdlc.c - STREAMS module for doing PPP asynchronous HDLC.
++ *
++ * Re-written by Adi Masputra &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">adi.masputra at sun.com</A>&gt;, based on
++ * the original ppp_ahdlc.c
++ *
++ * Copyright (c) 2000 by Sun Microsystems, Inc.
++ * All rights reserved.
++ *
++ * Permission to use, copy, modify, and distribute this software and its
++ * documentation is hereby granted, provided that the above copyright
++ * notice appears in all copies.
++ *
++ * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
++ * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
++ * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
++ * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
++ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
++ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
++ *
++ * Copyright (c) 1994 The Australian National University.
++ * All rights reserved.
++ *
++ * Permission to use, copy, modify, and distribute this software and its
++ * documentation is hereby granted, provided that the above copyright
++ * notice appears in all copies. This software is provided without any
++ * warranty, express or implied. The Australian National University
++ * makes no representations about the suitability of this software for
++ * any purpose.
++ *
++ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
++ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
++ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
++ * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
++ * OF SUCH DAMAGE.
++ *
++ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
++ * ON AN &quot;AS IS&quot; BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
++ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
++ * OR MODIFICATIONS.
++ *
++ * $Id: ppp_ahdlc.c 195720 2001-06-11 11:44:34Z gc $
++ */
++
++/*
++ * This file is used under Solaris 2, SVR4, SunOS 4, and Digital UNIX.
++ */
++#include &lt;sys/types.h&gt;
++#include &lt;sys/param.h&gt;
++#include &lt;sys/stream.h&gt;
++#include &lt;sys/errno.h&gt;
++
++#ifdef SVR4
++#include &lt;sys/conf.h&gt;
++#include &lt;sys/kmem.h&gt;
++#include &lt;sys/cmn_err.h&gt;
++#include &lt;sys/ddi.h&gt;
++#else
++#include &lt;sys/user.h&gt;
++#ifdef __osf__
++#include &lt;sys/cmn_err.h&gt;
++#endif
++#endif /* SVR4 */
++
++#include &lt;net/ppp_defs.h&gt;
++#include &lt;net/pppio.h&gt;
++#include &quot;ppp_mod.h&quot;
++
++/*
++ * Right now, mutex is only enabled for Solaris 2.x
++ */
++#if defined(SOL2)
++#define USE_MUTEX
++#endif /* SOL2 */
++
++/*
++ * intpointer_t and uintpointer_t are signed and unsigned integer types
++ * large enough to hold any data pointer; that is, data pointers can be
++ * assigned into or from these integer types without losing precision.
++ * On recent Solaris releases, these types are defined in sys/int_types.h,
++ * but not on SunOS 4.x or the earlier Solaris versions.
++ */
++#if defined(_LP64) || defined(_I32LPx)
++typedef long intpointer_t;
++typedef unsigned long uintpointer_t;
++#else
++typedef int intpointer_t;
++typedef unsigned int uintpointer_t;
++#endif
++
++MOD_OPEN_DECL(ahdlc_open);
++MOD_CLOSE_DECL(ahdlc_close);
++static int ahdlc_wput __P((queue_t *, mblk_t *));
++static int ahdlc_rput __P((queue_t *, mblk_t *));
++static void ahdlc_encode __P((queue_t *, mblk_t *));
++static void ahdlc_decode __P((queue_t *, mblk_t *));
++static int msg_byte __P((mblk_t *, unsigned int));
++
++#if defined(SOL2)
++/*
++ * Don't send HDLC start flag is last transmit is within 1.5 seconds -
++ * FLAG_TIME is defined is microseconds
++ */
++#define FLAG_TIME 1500
++#define ABS(x) (x &gt;= 0 ? x : (-x))
++#endif /* SOL2 */
++
++/*
++ * Extract byte i of message mp
++ */
++#define MSG_BYTE(mp, i) ((i) &lt; (mp)-&gt;b_wptr - (mp)-&gt;b_rptr? (mp)-&gt;b_rptr[i]: \
++ msg_byte((mp), (i)))
++
++/*
++ * Is this LCP packet one we have to transmit using LCP defaults?
++ */
++#define LCP_USE_DFLT(mp) (1 &lt;= (code = MSG_BYTE((mp), 4)) &amp;&amp; code &lt;= 7)
++
++/*
++ * Standard STREAMS declarations
++ */
++static struct module_info minfo = {
++ 0x7d23, &quot;ppp_ahdl&quot;, 0, INFPSZ, 32768, 512
++};
++
++static struct qinit rinit = {
++ ahdlc_rput, NULL, ahdlc_open, ahdlc_close, NULL, &amp;minfo, NULL
++};
++
++static struct qinit winit = {
++ ahdlc_wput, NULL, NULL, NULL, NULL, &amp;minfo, NULL
++};
++
++#if defined(SVR4) &amp;&amp; !defined(SOL2)
++int phdldevflag = 0;
++#define ppp_ahdlcinfo phdlinfo
++#endif /* defined(SVR4) &amp;&amp; !defined(SOL2) */
++
++struct streamtab ppp_ahdlcinfo = {
++ &amp;rinit, /* ptr to st_rdinit */
++ &amp;winit, /* ptr to st_wrinit */
++ NULL, /* ptr to st_muxrinit */
++ NULL, /* ptr to st_muxwinit */
++#if defined(SUNOS4)
++ NULL /* ptr to ptr to st_modlist */
++#endif /* SUNOS4 */
++};
++
++#if defined(SUNOS4)
++int ppp_ahdlc_count = 0; /* open counter */
++#endif /* SUNOS4 */
++
++/*
++ * Per-stream state structure
++ */
++typedef struct ahdlc_state {
++#if defined(USE_MUTEX)
++ kmutex_t lock; /* lock for this structure */
++#endif /* USE_MUTEX */
++ int flags; /* link flags */
++ mblk_t *rx_buf; /* ptr to receive buffer */
++ int rx_buf_size; /* receive buffer size */
++ ushort_t infcs; /* calculated rx HDLC FCS */
++ u_int32_t xaccm[8]; /* 256-bit xmit ACCM */
++ u_int32_t raccm; /* 32-bit rcv ACCM */
++ int mtu; /* interface MTU */
++ int mru; /* link MRU */
++ int unit; /* current PPP unit number */
++ struct pppstat stats; /* statistic structure */
++#if defined(SOL2)
++ clock_t flag_time; /* time in usec between flags */
++ clock_t lbolt; /* last updated lbolt */
++#endif /* SOL2 */
++} ahdlc_state_t;
++
++/*
++ * Values for flags
++ */
++#define ESCAPED 0x100 /* last saw escape char on input */
++#define IFLUSH 0x200 /* flushing input due to error */
++
++/*
++ * RCV_B7_1, etc., defined in net/pppio.h, are stored in flags also.
++ */
++#define RCV_FLAGS (RCV_B7_1|RCV_B7_0|RCV_ODDP|RCV_EVNP)
++
++/*
++ * FCS lookup table as calculated by genfcstab.
++ */
++static u_short fcstab[256] = {
++ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
++ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
++ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
++ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
++ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
++ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
++ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
++ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
++ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
++ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
++ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
++ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
++ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
++ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
++ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
++ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
++ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
++ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
++ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
++ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
++ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
++ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
++ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
++ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
++ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
++ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
++ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
++ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
++ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
++ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
++ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
++ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
++};
++
++static u_int32_t paritytab[8] =
++{
++ 0x96696996, 0x69969669, 0x69969669, 0x96696996,
++ 0x69969669, 0x96696996, 0x96696996, 0x69969669
++};
++
++/*
++ * STREAMS module open (entry) point
++ */
++MOD_OPEN(ahdlc_open)
++{
++ ahdlc_state_t *state;
++
++ /*
++ * Return if it's already opened
++ */
++ if (q-&gt;q_ptr) {
++ return 0;
++ }
++
++ /*
++ * This can only be opened as a module
++ */
++ if (sflag != MODOPEN) {
++ return 0;
++ }
++
++ state = (ahdlc_state_t *) ALLOC_NOSLEEP(sizeof(ahdlc_state_t));
++ if (state == 0)
++ OPEN_ERROR(ENOSR);
++ bzero((caddr_t) state, sizeof(ahdlc_state_t));
++
++ q-&gt;q_ptr = (caddr_t) state;
++ WR(q)-&gt;q_ptr = (caddr_t) state;
++
++#if defined(USE_MUTEX)
++ mutex_init(&amp;state-&gt;lock, NULL, MUTEX_DEFAULT, NULL);
++ mutex_enter(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++
++ state-&gt;xaccm[0] = ~0; /* escape 0x00 through 0x1f */
++ state-&gt;xaccm[3] = 0x60000000; /* escape 0x7d and 0x7e */
++ state-&gt;mru = PPP_MRU; /* default of 1500 bytes */
++#if defined(SOL2)
++ state-&gt;flag_time = drv_usectohz(FLAG_TIME);
++#endif /* SOL2 */
++
++#if defined(USE_MUTEX)
++ mutex_exit(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++
++#if defined(SUNOS4)
++ ppp_ahdlc_count++;
++#endif /* SUNOS4 */
++
++ qprocson(q);
++
++ return 0;
++}
++
++/*
++ * STREAMS module close (exit) point
++ */
++MOD_CLOSE(ahdlc_close)
++{
++ ahdlc_state_t *state;
++
++ qprocsoff(q);
++
++ state = (ahdlc_state_t *) q-&gt;q_ptr;
++
++ if (state == 0) {
++ DPRINT(&quot;state == 0 in ahdlc_close\n&quot;);
++ return 0;
++ }
++
++#if defined(USE_MUTEX)
++ mutex_enter(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++
++ if (state-&gt;rx_buf != 0) {
++ freemsg(state-&gt;rx_buf);
++ state-&gt;rx_buf = 0;
++ }
++
++#if defined(USE_MUTEX)
++ mutex_exit(&amp;state-&gt;lock);
++ mutex_destroy(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++
++ FREE(q-&gt;q_ptr, sizeof(ahdlc_state_t));
++ q-&gt;q_ptr = NULL;
++ OTHERQ(q)-&gt;q_ptr = NULL;
++
++#if defined(SUNOS4)
++ if (ppp_ahdlc_count)
++ ppp_ahdlc_count--;
++#endif /* SUNOS4 */
++
++ return 0;
++}
++
++/*
++ * Write side put routine
++ */
++static int
++ahdlc_wput(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ ahdlc_state_t *state;
++ struct iocblk *iop;
++ int error;
++ mblk_t *np;
++ struct ppp_stats *psp;
++
++ state = (ahdlc_state_t *) q-&gt;q_ptr;
++ if (state == 0) {
++ DPRINT(&quot;state == 0 in ahdlc_wput\n&quot;);
++ freemsg(mp);
++ return 0;
++ }
++
++ switch (mp-&gt;b_datap-&gt;db_type) {
++ case M_DATA:
++ /*
++ * A data packet - do character-stuffing and FCS, and
++ * send it onwards.
++ */
++ ahdlc_encode(q, mp);
++ freemsg(mp);
++ break;
++
++ case M_IOCTL:
++ iop = (struct iocblk *) mp-&gt;b_rptr;
++ error = EINVAL;
++ switch (iop-&gt;ioc_cmd) {
++ case PPPIO_XACCM:
++ if ((iop-&gt;ioc_count &lt; sizeof(u_int32_t)) ||
++ (iop-&gt;ioc_count &gt; sizeof(ext_accm))) {
++ break;
++ }
++ if (mp-&gt;b_cont == 0) {
++ DPRINT1(&quot;ahdlc_wput/%d: PPPIO_XACCM b_cont = 0!\n&quot;, state-&gt;unit);
++ break;
++ }
++#if defined(USE_MUTEX)
++ mutex_enter(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ bcopy((caddr_t)mp-&gt;b_cont-&gt;b_rptr, (caddr_t)state-&gt;xaccm,
++ iop-&gt;ioc_count);
++ state-&gt;xaccm[2] &amp;= ~0x40000000; /* don't escape 0x5e */
++ state-&gt;xaccm[3] |= 0x60000000; /* do escape 0x7d, 0x7e */
++#if defined(USE_MUTEX)
++ mutex_exit(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ iop-&gt;ioc_count = 0;
++ error = 0;
++ break;
++
++ case PPPIO_RACCM:
++ if (iop-&gt;ioc_count != sizeof(u_int32_t))
++ break;
++ if (mp-&gt;b_cont == 0) {
++ DPRINT1(&quot;ahdlc_wput/%d: PPPIO_RACCM b_cont = 0!\n&quot;, state-&gt;unit);
++ break;
++ }
++#if defined(USE_MUTEX)
++ mutex_enter(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ bcopy((caddr_t)mp-&gt;b_cont-&gt;b_rptr, (caddr_t)&amp;state-&gt;raccm,
++ sizeof(u_int32_t));
++#if defined(USE_MUTEX)
++ mutex_exit(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ iop-&gt;ioc_count = 0;
++ error = 0;
++ break;
++
++ case PPPIO_GCLEAN:
++ np = allocb(sizeof(int), BPRI_HI);
++ if (np == 0) {
++ error = ENOSR;
++ break;
++ }
++ if (mp-&gt;b_cont != 0)
++ freemsg(mp-&gt;b_cont);
++ mp-&gt;b_cont = np;
++#if defined(USE_MUTEX)
++ mutex_enter(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ *(int *)np-&gt;b_wptr = state-&gt;flags &amp; RCV_FLAGS;
++#if defined(USE_MUTEX)
++ mutex_exit(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ np-&gt;b_wptr += sizeof(int);
++ iop-&gt;ioc_count = sizeof(int);
++ error = 0;
++ break;
++
++ case PPPIO_GETSTAT:
++ np = allocb(sizeof(struct ppp_stats), BPRI_HI);
++ if (np == 0) {
++ error = ENOSR;
++ break;
++ }
++ if (mp-&gt;b_cont != 0)
++ freemsg(mp-&gt;b_cont);
++ mp-&gt;b_cont = np;
++ psp = (struct ppp_stats *) np-&gt;b_wptr;
++ np-&gt;b_wptr += sizeof(struct ppp_stats);
++ bzero((caddr_t)psp, sizeof(struct ppp_stats));
++ psp-&gt;p = state-&gt;stats;
++ iop-&gt;ioc_count = sizeof(struct ppp_stats);
++ error = 0;
++ break;
++
++ case PPPIO_LASTMOD:
++ /* we knew this anyway */
++ error = 0;
++ break;
++
++ default:
++ error = -1;
++ break;
++ }
++
++ if (error &lt; 0)
++ putnext(q, mp);
++ else if (error == 0) {
++ mp-&gt;b_datap-&gt;db_type = M_IOCACK;
++ qreply(q, mp);
++ } else {
++ mp-&gt;b_datap-&gt;db_type = M_IOCNAK;
++ iop-&gt;ioc_count = 0;
++ iop-&gt;ioc_error = error;
++ qreply(q, mp);
++ }
++ break;
++
++ case M_CTL:
++ switch (*mp-&gt;b_rptr) {
++ case PPPCTL_MTU:
++#if defined(USE_MUTEX)
++ mutex_enter(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ state-&gt;mtu = ((unsigned short *)mp-&gt;b_rptr)[1];
++#if defined(USE_MUTEX)
++ mutex_exit(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ freemsg(mp);
++ break;
++ case PPPCTL_MRU:
++#if defined(USE_MUTEX)
++ mutex_enter(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ state-&gt;mru = ((unsigned short *)mp-&gt;b_rptr)[1];
++#if defined(USE_MUTEX)
++ mutex_exit(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ freemsg(mp);
++ break;
++ case PPPCTL_UNIT:
++#if defined(USE_MUTEX)
++ mutex_enter(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ state-&gt;unit = mp-&gt;b_rptr[1];
++#if defined(USE_MUTEX)
++ mutex_exit(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ break;
++ default:
++ putnext(q, mp);
++ }
++ break;
++
++ default:
++ putnext(q, mp);
++ }
++
++ return 0;
++}
++
++/*
++ * Read side put routine
++ */
++static int
++ahdlc_rput(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ ahdlc_state_t *state;
++
++ state = (ahdlc_state_t *) q-&gt;q_ptr;
++ if (state == 0) {
++ DPRINT(&quot;state == 0 in ahdlc_rput\n&quot;);
++ freemsg(mp);
++ return 0;
++ }
++
++ switch (mp-&gt;b_datap-&gt;db_type) {
++ case M_DATA:
++ ahdlc_decode(q, mp);
++ freemsg(mp);
++ break;
++
++ case M_HANGUP:
++#if defined(USE_MUTEX)
++ mutex_enter(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ if (state-&gt;rx_buf != 0) {
++ /* XXX would like to send this up for debugging */
++ freemsg(state-&gt;rx_buf);
++ state-&gt;rx_buf = 0;
++ }
++ state-&gt;flags = IFLUSH;
++#if defined(USE_MUTEX)
++ mutex_exit(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ putnext(q, mp);
++ break;
++
++ default:
++ putnext(q, mp);
++ }
++ return 0;
++}
++
++/*
++ * Extract bit c from map m, to determine if c needs to be escaped
++ */
++#define IN_TX_MAP(c, m) ((m)[(c) &gt;&gt; 5] &amp; (1 &lt;&lt; ((c) &amp; 0x1f)))
++
++static void
++ahdlc_encode(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ ahdlc_state_t *state;
++ u_int32_t *xaccm, loc_xaccm[8];
++ ushort_t fcs;
++ size_t outmp_len;
++ mblk_t *outmp, *tmp;
++ uchar_t *dp, fcs_val;
++ int is_lcp, code;
++#if defined(SOL2)
++ clock_t lbolt;
++#endif /* SOL2 */
++
++ if (msgdsize(mp) &lt; 4) {
++ return;
++ }
++
++ state = (ahdlc_state_t *)q-&gt;q_ptr;
++#if defined(USE_MUTEX)
++ mutex_enter(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++
++ /*
++ * Allocate an output buffer large enough to handle a case where all
++ * characters need to be escaped
++ */
++ outmp_len = (msgdsize(mp) &lt;&lt; 1) + /* input block x 2 */
++ (sizeof(fcs) &lt;&lt; 2) + /* HDLC FCS x 4 */
++ (sizeof(uchar_t) &lt;&lt; 1); /* HDLC flags x 2 */
++
++ outmp = allocb(outmp_len, BPRI_MED);
++ if (outmp == NULL) {
++ state-&gt;stats.ppp_oerrors++;
++#if defined(USE_MUTEX)
++ mutex_exit(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ putctl1(RD(q)-&gt;q_next, M_CTL, PPPCTL_OERROR);
++ return;
++ }
++
++#if defined(SOL2)
++ /*
++ * Check if our last transmit happenned within flag_time, using
++ * the system's LBOLT value in clock ticks
++ */
++ if (drv_getparm(LBOLT, &amp;lbolt) != -1) {
++ if (ABS((clock_t)lbolt - state-&gt;lbolt) &gt; state-&gt;flag_time) {
++ *outmp-&gt;b_wptr++ = PPP_FLAG;
++ }
++ state-&gt;lbolt = lbolt;
++ } else {
++ *outmp-&gt;b_wptr++ = PPP_FLAG;
++ }
++#else
++ /*
++ * If the driver below still has a message to process, skip the
++ * HDLC flag, otherwise, put one in the beginning
++ */
++ if (qsize(q-&gt;q_next) == 0) {
++ *outmp-&gt;b_wptr++ = PPP_FLAG;
++ }
++#endif
++
++ /*
++ * All control characters must be escaped for LCP packets with code
++ * values between 1 (Conf-Req) and 7 (Code-Rej).
++ */
++ is_lcp = ((MSG_BYTE(mp, 0) == PPP_ALLSTATIONS) &amp;&amp;
++ (MSG_BYTE(mp, 1) == PPP_UI) &amp;&amp;
++ (MSG_BYTE(mp, 2) == (PPP_LCP &gt;&gt; 8)) &amp;&amp;
++ (MSG_BYTE(mp, 3) == (PPP_LCP &amp; 0xff)) &amp;&amp;
++ LCP_USE_DFLT(mp));
++
++ xaccm = state-&gt;xaccm;
++ if (is_lcp) {
++ bcopy((caddr_t)state-&gt;xaccm, (caddr_t)loc_xaccm, sizeof(loc_xaccm));
++ loc_xaccm[0] = ~0; /* force escape on 0x00 through 0x1f */
++ xaccm = loc_xaccm;
++ }
++
++ fcs = PPP_INITFCS; /* Initial FCS is 0xffff */
++
++ /*
++ * Process this block and the rest (if any) attached to the this one
++ */
++ for (tmp = mp; tmp; tmp = tmp-&gt;b_cont) {
++ if (tmp-&gt;b_datap-&gt;db_type == M_DATA) {
++ for (dp = tmp-&gt;b_rptr; dp &lt; tmp-&gt;b_wptr; dp++) {
++ fcs = PPP_FCS(fcs, *dp);
++ if (IN_TX_MAP(*dp, xaccm)) {
++ *outmp-&gt;b_wptr++ = PPP_ESCAPE;
++ *outmp-&gt;b_wptr++ = *dp ^ PPP_TRANS;
++ } else {
++ *outmp-&gt;b_wptr++ = *dp;
++ }
++ }
++ } else {
++ continue; /* skip if db_type is something other than M_DATA */
++ }
++ }
++
++ /*
++ * Append the HDLC FCS, making sure that escaping is done on any
++ * necessary bytes
++ */
++ fcs_val = (fcs ^ 0xffff) &amp; 0xff;
++ if (IN_TX_MAP(fcs_val, xaccm)) {
++ *outmp-&gt;b_wptr++ = PPP_ESCAPE;
++ *outmp-&gt;b_wptr++ = fcs_val ^ PPP_TRANS;
++ } else {
++ *outmp-&gt;b_wptr++ = fcs_val;
++ }
++
++ fcs_val = ((fcs ^ 0xffff) &gt;&gt; 8) &amp; 0xff;
++ if (IN_TX_MAP(fcs_val, xaccm)) {
++ *outmp-&gt;b_wptr++ = PPP_ESCAPE;
++ *outmp-&gt;b_wptr++ = fcs_val ^ PPP_TRANS;
++ } else {
++ *outmp-&gt;b_wptr++ = fcs_val;
++ }
++
++ /*
++ * And finally, append the HDLC flag, and send it away
++ */
++ *outmp-&gt;b_wptr++ = PPP_FLAG;
++
++ state-&gt;stats.ppp_obytes += msgdsize(outmp);
++ state-&gt;stats.ppp_opackets++;
++
++#if defined(USE_MUTEX)
++ mutex_exit(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++
++ putnext(q, outmp);
++ return;
++}
++
++/*
++ * Checks the 32-bit receive ACCM to see if the byte needs un-escaping
++ */
++#define IN_RX_MAP(c, m) ((((unsigned int) (uchar_t) (c)) &lt; 0x20) &amp;&amp; \
++ (m) &amp; (1 &lt;&lt; (c)))
++
++
++/*
++ * Process received characters.
++ */
++static void
++ahdlc_decode(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ ahdlc_state_t *state;
++ mblk_t *om;
++ uchar_t *dp;
++ ushort_t fcs;
++#if defined(SOL2)
++ mblk_t *zmp;
++#endif /* SOL2 */
++
++#if defined(SOL2)
++ /*
++ * In case the driver (or something below) doesn't send
++ * data upstream in one message block, concatenate everything
++ */
++ if (!((mp-&gt;b_wptr - mp-&gt;b_rptr == msgdsize(mp)) &amp;&amp;
++ ((intpointer_t)mp-&gt;b_rptr % sizeof(intpointer_t) == 0))) {
++
++ zmp = msgpullup(mp, -1);
++ freemsg(mp);
++ mp = zmp;
++ if (mp == 0)
++ return;
++ }
++#endif /* SOL2 */
++
++ state = (ahdlc_state_t *) q-&gt;q_ptr;
++
++#if defined(USE_MUTEX)
++ mutex_enter(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++
++ state-&gt;stats.ppp_ibytes += msgdsize(mp);
++
++ for (dp = mp-&gt;b_rptr; dp &lt; mp-&gt;b_wptr; dp++) {
++
++ /*
++ * This should detect the lack of 8-bit communication channel
++ * which is necessary for PPP to work. In addition, it also
++ * checks on the parity.
++ */
++ if (*dp &amp; 0x80)
++ state-&gt;flags |= RCV_B7_1;
++ else
++ state-&gt;flags |= RCV_B7_0;
++
++ if (paritytab[*dp &gt;&gt; 5] &amp; (1 &lt;&lt; (*dp &amp; 0x1f)))
++ state-&gt;flags |= RCV_ODDP;
++ else
++ state-&gt;flags |= RCV_EVNP;
++
++ /*
++ * So we have a HDLC flag ...
++ */
++ if (*dp == PPP_FLAG) {
++
++ /*
++ * If we think that it marks the beginning of the frame,
++ * then continue to process the next octects
++ */
++ if ((state-&gt;flags &amp; IFLUSH) ||
++ (state-&gt;rx_buf == 0) ||
++ (msgdsize(state-&gt;rx_buf) == 0)) {
++
++ state-&gt;flags &amp;= ~IFLUSH;
++ continue;
++ }
++
++ /*
++ * We get here because the above condition isn't true,
++ * in which case the HDLC flag was there to mark the end
++ * of the frame (or so we think)
++ */
++ om = state-&gt;rx_buf;
++
++ if (state-&gt;infcs == PPP_GOODFCS) {
++ state-&gt;stats.ppp_ipackets++;
++ adjmsg(om, -PPP_FCSLEN);
++ putnext(q, om);
++ } else {
++ DPRINT2(&quot;ppp%d: bad fcs (len=%d)\n&quot;,
++ state-&gt;unit, msgdsize(state-&gt;rx_buf));
++ freemsg(state-&gt;rx_buf);
++ state-&gt;flags &amp;= ~(IFLUSH | ESCAPED);
++ state-&gt;stats.ppp_ierrors++;
++ putctl1(q-&gt;q_next, M_CTL, PPPCTL_IERROR);
++ }
++
++ state-&gt;rx_buf = 0;
++ continue;
++ }
++
++ if (state-&gt;flags &amp; IFLUSH) {
++ continue;
++ }
++
++ /*
++ * Allocate a receive buffer, large enough to store a frame (after
++ * un-escaping) of at least 1500 octets. If MRU is negotiated to
++ * be more than the default, then allocate that much. In addition,
++ * we add an extra 32-bytes for a fudge factor
++ */
++ if (state-&gt;rx_buf == 0) {
++ state-&gt;rx_buf_size = (state-&gt;mru &lt; PPP_MRU ? PPP_MRU : state-&gt;mru);
++ state-&gt;rx_buf_size += (sizeof(u_int32_t) &lt;&lt; 3);
++ state-&gt;rx_buf = allocb(state-&gt;rx_buf_size, BPRI_MED);
++
++ /*
++ * If allocation fails, try again on the next frame
++ */
++ if (state-&gt;rx_buf == 0) {
++ state-&gt;flags |= IFLUSH;
++ continue;
++ }
++ state-&gt;flags &amp;= ~(IFLUSH | ESCAPED);
++ state-&gt;infcs = PPP_INITFCS;
++ }
++
++ if (*dp == PPP_ESCAPE) {
++ state-&gt;flags |= ESCAPED;
++ continue;
++ }
++
++ /*
++ * Make sure we un-escape the necessary characters, as well as the
++ * ones in our receive async control character map
++ */
++ if (state-&gt;flags &amp; ESCAPED) {
++ *dp ^= PPP_TRANS;
++ state-&gt;flags &amp;= ~ESCAPED;
++ } else if (IN_RX_MAP(*dp, state-&gt;raccm))
++ continue;
++
++ /*
++ * Unless the peer lied to us about the negotiated MRU, we should
++ * never get a frame which is too long. If it happens, toss it away
++ * and grab the next incoming one
++ */
++ if (msgdsize(state-&gt;rx_buf) &lt; state-&gt;rx_buf_size) {
++ state-&gt;infcs = PPP_FCS(state-&gt;infcs, *dp);
++ *state-&gt;rx_buf-&gt;b_wptr++ = *dp;
++ } else {
++ DPRINT2(&quot;ppp%d: frame too long (%d)\n&quot;,
++ state-&gt;unit, msgdsize(state-&gt;rx_buf));
++ freemsg(state-&gt;rx_buf);
++ state-&gt;rx_buf = 0;
++ state-&gt;flags |= IFLUSH;
++ }
++ }
++
++#if defined(USE_MUTEX)
++ mutex_exit(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++}
++
++static int
++msg_byte(mp, i)
++ mblk_t *mp;
++ unsigned int i;
++{
++ while (mp != 0 &amp;&amp; i &gt;= mp-&gt;b_wptr - mp-&gt;b_rptr)
++ mp = mp-&gt;b_cont;
++ if (mp == 0)
++ return -1;
++ return mp-&gt;b_rptr[i];
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/modules/ppp_ahdlc.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/modules/ppp_comp.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/modules/ppp_comp.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/modules/ppp_comp.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1126 @@
++/*
++ * ppp_comp.c - STREAMS module for kernel-level compression and CCP support.
++ *
++ * Copyright (c) 1994 The Australian National University.
++ * All rights reserved.
++ *
++ * Permission to use, copy, modify, and distribute this software and its
++ * documentation is hereby granted, provided that the above copyright
++ * notice appears in all copies. This software is provided without any
++ * warranty, express or implied. The Australian National University
++ * makes no representations about the suitability of this software for
++ * any purpose.
++ *
++ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
++ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
++ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
++ * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
++ * OF SUCH DAMAGE.
++ *
++ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
++ * ON AN &quot;AS IS&quot; BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
++ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
++ * OR MODIFICATIONS.
++ *
++ * $Id: ppp_comp.c 195720 2001-06-11 11:44:34Z gc $
++ */
++
++/*
++ * This file is used under SVR4, Solaris 2, SunOS 4, and Digital UNIX.
++ */
++
++#include &lt;sys/types.h&gt;
++#include &lt;sys/param.h&gt;
++#include &lt;sys/errno.h&gt;
++#include &lt;sys/stream.h&gt;
++
++#ifdef SVR4
++#include &lt;sys/conf.h&gt;
++#include &lt;sys/cmn_err.h&gt;
++#include &lt;sys/ddi.h&gt;
++#else
++#include &lt;sys/user.h&gt;
++#ifdef __osf__
++#include &lt;sys/cmn_err.h&gt;
++#endif
++#endif /* SVR4 */
++
++#include &lt;net/ppp_defs.h&gt;
++#include &lt;net/pppio.h&gt;
++#include &quot;ppp_mod.h&quot;
++
++#ifdef __osf__
++#include &lt;sys/mbuf.h&gt;
++#include &lt;sys/protosw.h&gt;
++#endif
++
++#include &lt;netinet/in.h&gt;
++#include &lt;netinet/in_systm.h&gt;
++#include &lt;netinet/ip.h&gt;
++#include &lt;net/vjcompress.h&gt;
++
++#define PACKETPTR mblk_t *
++#include &lt;net/ppp-comp.h&gt;
++
++MOD_OPEN_DECL(ppp_comp_open);
++MOD_CLOSE_DECL(ppp_comp_close);
++static int ppp_comp_rput __P((queue_t *, mblk_t *));
++static int ppp_comp_rsrv __P((queue_t *));
++static int ppp_comp_wput __P((queue_t *, mblk_t *));
++static int ppp_comp_wsrv __P((queue_t *));
++static void ppp_comp_ccp __P((queue_t *, mblk_t *, int));
++static int msg_byte __P((mblk_t *, unsigned int));
++
++/* Extract byte i of message mp. */
++#define MSG_BYTE(mp, i) ((i) &lt; (mp)-&gt;b_wptr - (mp)-&gt;b_rptr? (mp)-&gt;b_rptr[i]: \
++ msg_byte((mp), (i)))
++
++/* Is this LCP packet one we have to transmit using LCP defaults? */
++#define LCP_USE_DFLT(mp) (1 &lt;= (code = MSG_BYTE((mp), 4)) &amp;&amp; code &lt;= 7)
++
++#define PPP_COMP_ID 0xbadf
++static struct module_info minfo = {
++#ifdef PRIOQ
++ PPP_COMP_ID, &quot;ppp_comp&quot;, 0, INFPSZ, 16512, 16384,
++#else
++ PPP_COMP_ID, &quot;ppp_comp&quot;, 0, INFPSZ, 16384, 4096,
++#endif
++};
++
++static struct qinit r_init = {
++ ppp_comp_rput, ppp_comp_rsrv, ppp_comp_open, ppp_comp_close,
++ NULL, &amp;minfo, NULL
++};
++
++static struct qinit w_init = {
++ ppp_comp_wput, ppp_comp_wsrv, NULL, NULL, NULL, &amp;minfo, NULL
++};
++
++#if defined(SVR4) &amp;&amp; !defined(SOL2)
++int pcmpdevflag = 0;
++#define ppp_compinfo pcmpinfo
++#endif
++struct streamtab ppp_compinfo = {
++ &amp;r_init, &amp;w_init, NULL, NULL
++};
++
++int ppp_comp_count; /* number of module instances in use */
++
++#ifdef __osf__
++
++static void ppp_comp_alloc __P((comp_state_t *));
++typedef struct memreq {
++ unsigned char comp_opts[20];
++ int cmd;
++ int thread_status;
++ char *returned_mem;
++} memreq_t;
++
++#endif
++
++typedef struct comp_state {
++ int flags;
++ int mru;
++ int mtu;
++ int unit;
++ struct compressor *xcomp;
++ void *xstate;
++ struct compressor *rcomp;
++ void *rstate;
++ struct vjcompress vj_comp;
++ int vj_last_ierrors;
++ struct pppstat stats;
++#ifdef __osf__
++ memreq_t memreq;
++ thread_t thread;
++#endif
++} comp_state_t;
++
++
++#ifdef __osf__
++extern task_t first_task;
++#endif
++
++/* Bits in flags are as defined in pppio.h. */
++#define CCP_ERR (CCP_ERROR | CCP_FATALERROR)
++#define LAST_MOD 0x1000000 /* no ppp modules below us */
++#define DBGLOG 0x2000000 /* log debugging stuff */
++
++#define MAX_IPHDR 128 /* max TCP/IP header size */
++#define MAX_VJHDR 20 /* max VJ compressed header size (?) */
++
++#undef MIN /* just in case */
++#define MIN(a, b) ((a) &lt; (b)? (a): (b))
++
++/*
++ * List of compressors we know about.
++ */
++
++#if DO_BSD_COMPRESS
++extern struct compressor ppp_bsd_compress;
++#endif
++#if DO_DEFLATE
++extern struct compressor ppp_deflate, ppp_deflate_draft;
++#endif
++
++struct compressor *ppp_compressors[] = {
++#if DO_BSD_COMPRESS
++ &amp;ppp_bsd_compress,
++#endif
++#if DO_DEFLATE
++ &amp;ppp_deflate,
++ &amp;ppp_deflate_draft,
++#endif
++ NULL
++};
++
++/*
++ * STREAMS module entry points.
++ */
++MOD_OPEN(ppp_comp_open)
++{
++ comp_state_t *cp;
++#ifdef __osf__
++ thread_t thread;
++#endif
++
++ if (q-&gt;q_ptr == NULL) {
++ cp = (comp_state_t *) ALLOC_SLEEP(sizeof(comp_state_t));
++ if (cp == NULL)
++ OPEN_ERROR(ENOSR);
++ bzero((caddr_t)cp, sizeof(comp_state_t));
++ WR(q)-&gt;q_ptr = q-&gt;q_ptr = (caddr_t) cp;
++ cp-&gt;mru = PPP_MRU;
++ cp-&gt;mtu = PPP_MTU;
++ cp-&gt;xstate = NULL;
++ cp-&gt;rstate = NULL;
++ vj_compress_init(&amp;cp-&gt;vj_comp, -1);
++#ifdef __osf__
++ if (!(thread = kernel_thread_w_arg(first_task, ppp_comp_alloc, (void *)cp)))
++ OPEN_ERROR(ENOSR);
++ cp-&gt;thread = thread;
++#endif
++ ++ppp_comp_count;
++ qprocson(q);
++ }
++ return 0;
++}
++
++MOD_CLOSE(ppp_comp_close)
++{
++ comp_state_t *cp;
++
++ qprocsoff(q);
++ cp = (comp_state_t *) q-&gt;q_ptr;
++ if (cp != NULL) {
++ if (cp-&gt;xstate != NULL)
++ (*cp-&gt;xcomp-&gt;comp_free)(cp-&gt;xstate);
++ if (cp-&gt;rstate != NULL)
++ (*cp-&gt;rcomp-&gt;decomp_free)(cp-&gt;rstate);
++#ifdef __osf__
++ if (!cp-&gt;thread)
++ printf(&quot;ppp_comp_close: NULL thread!\n&quot;);
++ else
++ thread_terminate(cp-&gt;thread);
++#endif
++ FREE(cp, sizeof(comp_state_t));
++ q-&gt;q_ptr = NULL;
++ OTHERQ(q)-&gt;q_ptr = NULL;
++ --ppp_comp_count;
++ }
++ return 0;
++}
++
++#ifdef __osf__
++
++/* thread for calling back to a compressor's memory allocator
++ * Needed for Digital UNIX since it's VM can't handle requests
++ * for large amounts of memory without blocking. The thread
++ * provides a context in which we can call a memory allocator
++ * that may block.
++ */
++static void
++ppp_comp_alloc(comp_state_t *cp)
++{
++ int len, cmd;
++ unsigned char *compressor_options;
++ thread_t thread;
++ void *(*comp_allocator)();
++
++
++#if defined(MAJOR_VERSION) &amp;&amp; (MAJOR_VERSION &lt;= 2)
++
++ /* In 2.x and earlier the argument gets passed
++ * in the thread structure itself. Yuck.
++ */
++ thread = current_thread();
++ cp = thread-&gt;reply_port;
++ thread-&gt;reply_port = PORT_NULL;
++
++#endif
++
++ for (;;) {
++ assert_wait((vm_offset_t)&amp;cp-&gt;memreq.thread_status, TRUE);
++ thread_block();
++
++ if (thread_should_halt(current_thread()))
++ thread_halt_self();
++ cmd = cp-&gt;memreq.cmd;
++ compressor_options = &amp;cp-&gt;memreq.comp_opts[0];
++ len = compressor_options[1];
++ if (cmd == PPPIO_XCOMP) {
++ cp-&gt;memreq.returned_mem = cp-&gt;xcomp-&gt;comp_alloc(compressor_options, len);
++ if (!cp-&gt;memreq.returned_mem) {
++ cp-&gt;memreq.thread_status = ENOSR;
++ } else {
++ cp-&gt;memreq.thread_status = 0;
++ }
++ } else {
++ cp-&gt;memreq.returned_mem = cp-&gt;rcomp-&gt;decomp_alloc(compressor_options, len);
++ if (!cp-&gt;memreq.returned_mem) {
++ cp-&gt;memreq.thread_status = ENOSR;
++ } else {
++ cp-&gt;memreq.thread_status = 0;
++ }
++ }
++ }
++}
++
++#endif /* __osf__ */
++
++/* here's the deal with memory allocation under Digital UNIX.
++ * Some other may also benefit from this...
++ * We can't ask for huge chunks of memory in a context where
++ * the caller can't be put to sleep (like, here.) The alloc
++ * is likely to fail. Instead we do this: the first time we
++ * get called, kick off a thread to do the allocation. Return
++ * immediately to the caller with EAGAIN, as an indication that
++ * they should send down the ioctl again. By the time the
++ * second call comes in it's likely that the memory allocation
++ * thread will have returned with the requested memory. We will
++ * continue to return EAGAIN however until the thread has completed.
++ * When it has, we return zero (and the memory) if the allocator
++ * was successful and ENOSR otherwise.
++ *
++ * Callers of the RCOMP and XCOMP ioctls are encouraged (but not
++ * required) to loop for some number of iterations with a small
++ * delay in the loop body (for instance a 1/10-th second &quot;sleep&quot;
++ * via select.)
++ */
++static int
++ppp_comp_wput(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ struct iocblk *iop;
++ comp_state_t *cp;
++ int error, len, n;
++ int flags, mask;
++ mblk_t *np;
++ struct compressor **comp;
++ struct ppp_stats *psp;
++ struct ppp_comp_stats *csp;
++ unsigned char *opt_data;
++ int nxslots, nrslots;
++
++ cp = (comp_state_t *) q-&gt;q_ptr;
++ if (cp == 0) {
++ DPRINT(&quot;cp == 0 in ppp_comp_wput\n&quot;);
++ freemsg(mp);
++ return 0;
++ }
++
++ switch (mp-&gt;b_datap-&gt;db_type) {
++
++ case M_DATA:
++ putq(q, mp);
++ break;
++
++ case M_IOCTL:
++ iop = (struct iocblk *) mp-&gt;b_rptr;
++ error = EINVAL;
++ switch (iop-&gt;ioc_cmd) {
++
++ case PPPIO_CFLAGS:
++ /* set/get CCP state */
++ if (iop-&gt;ioc_count != 2 * sizeof(int))
++ break;
++ if (mp-&gt;b_cont == 0) {
++ DPRINT1(&quot;ppp_comp_wput/%d: PPPIO_CFLAGS b_cont = 0!\n&quot;, cp-&gt;unit);
++ break;
++ }
++ flags = ((int *) mp-&gt;b_cont-&gt;b_rptr)[0];
++ mask = ((int *) mp-&gt;b_cont-&gt;b_rptr)[1];
++ cp-&gt;flags = (cp-&gt;flags &amp; ~mask) | (flags &amp; mask);
++ if ((mask &amp; CCP_ISOPEN) &amp;&amp; (flags &amp; CCP_ISOPEN) == 0) {
++ if (cp-&gt;xstate != NULL) {
++ (*cp-&gt;xcomp-&gt;comp_free)(cp-&gt;xstate);
++ cp-&gt;xstate = NULL;
++ }
++ if (cp-&gt;rstate != NULL) {
++ (*cp-&gt;rcomp-&gt;decomp_free)(cp-&gt;rstate);
++ cp-&gt;rstate = NULL;
++ }
++ cp-&gt;flags &amp;= ~CCP_ISUP;
++ }
++ error = 0;
++ iop-&gt;ioc_count = sizeof(int);
++ ((int *) mp-&gt;b_cont-&gt;b_rptr)[0] = cp-&gt;flags;
++ mp-&gt;b_cont-&gt;b_wptr = mp-&gt;b_cont-&gt;b_rptr + sizeof(int);
++ break;
++
++ case PPPIO_VJINIT:
++ /*
++ * Initialize VJ compressor/decompressor
++ */
++ if (iop-&gt;ioc_count != 2)
++ break;
++ if (mp-&gt;b_cont == 0) {
++ DPRINT1(&quot;ppp_comp_wput/%d: PPPIO_VJINIT b_cont = 0!\n&quot;, cp-&gt;unit);
++ break;
++ }
++ nxslots = mp-&gt;b_cont-&gt;b_rptr[0] + 1;
++ nrslots = mp-&gt;b_cont-&gt;b_rptr[1] + 1;
++ if (nxslots &gt; MAX_STATES || nrslots &gt; MAX_STATES)
++ break;
++ vj_compress_init(&amp;cp-&gt;vj_comp, nxslots);
++ cp-&gt;vj_last_ierrors = cp-&gt;stats.ppp_ierrors;
++ error = 0;
++ iop-&gt;ioc_count = 0;
++ break;
++
++ case PPPIO_XCOMP:
++ case PPPIO_RCOMP:
++ if (iop-&gt;ioc_count &lt;= 0)
++ break;
++ if (mp-&gt;b_cont == 0) {
++ DPRINT1(&quot;ppp_comp_wput/%d: PPPIO_[XR]COMP b_cont = 0!\n&quot;, cp-&gt;unit);
++ break;
++ }
++ opt_data = mp-&gt;b_cont-&gt;b_rptr;
++ len = mp-&gt;b_cont-&gt;b_wptr - opt_data;
++ if (len &gt; iop-&gt;ioc_count)
++ len = iop-&gt;ioc_count;
++ if (opt_data[1] &lt; 2 || opt_data[1] &gt; len)
++ break;
++ for (comp = ppp_compressors; *comp != NULL; ++comp)
++ if ((*comp)-&gt;compress_proto == opt_data[0]) {
++ /* here's the handler! */
++ error = 0;
++#ifndef __osf__
++ if (iop-&gt;ioc_cmd == PPPIO_XCOMP) {
++ /* A previous call may have fetched memory for a compressor
++ * that's now being retired or reset. Free it using it's
++ * mechanism for freeing stuff.
++ */
++ if (cp-&gt;xstate != NULL) {
++ (*cp-&gt;xcomp-&gt;comp_free)(cp-&gt;xstate);
++ cp-&gt;xstate = NULL;
++ }
++ cp-&gt;xcomp = *comp;
++ cp-&gt;xstate = (*comp)-&gt;comp_alloc(opt_data, len);
++ if (cp-&gt;xstate == NULL)
++ error = ENOSR;
++ } else {
++ if (cp-&gt;rstate != NULL) {
++ (*cp-&gt;rcomp-&gt;decomp_free)(cp-&gt;rstate);
++ cp-&gt;rstate = NULL;
++ }
++ cp-&gt;rcomp = *comp;
++ cp-&gt;rstate = (*comp)-&gt;decomp_alloc(opt_data, len);
++ if (cp-&gt;rstate == NULL)
++ error = ENOSR;
++ }
++#else
++ if ((error = cp-&gt;memreq.thread_status) != EAGAIN)
++ if (iop-&gt;ioc_cmd == PPPIO_XCOMP) {
++ if (cp-&gt;xstate) {
++ (*cp-&gt;xcomp-&gt;comp_free)(cp-&gt;xstate);
++ cp-&gt;xstate = 0;
++ }
++ /* sanity check for compressor options
++ */
++ if (sizeof (cp-&gt;memreq.comp_opts) &lt; len) {
++ printf(&quot;can't handle options for compressor %d (%d)\n&quot;, opt_data[0],
++ opt_data[1]);
++ cp-&gt;memreq.thread_status = ENOSR;
++ cp-&gt;memreq.returned_mem = 0;
++ }
++ /* fill in request for the thread and kick it off
++ */
++ if (cp-&gt;memreq.thread_status == 0 &amp;&amp; !cp-&gt;memreq.returned_mem) {
++ bcopy(opt_data, cp-&gt;memreq.comp_opts, len);
++ cp-&gt;memreq.cmd = PPPIO_XCOMP;
++ cp-&gt;xcomp = *comp;
++ error = cp-&gt;memreq.thread_status = EAGAIN;
++ thread_wakeup((vm_offset_t)&amp;cp-&gt;memreq.thread_status);
++ } else {
++ cp-&gt;xstate = cp-&gt;memreq.returned_mem;
++ cp-&gt;memreq.returned_mem = 0;
++ cp-&gt;memreq.thread_status = 0;
++ }
++ } else {
++ if (cp-&gt;rstate) {
++ (*cp-&gt;rcomp-&gt;decomp_free)(cp-&gt;rstate);
++ cp-&gt;rstate = NULL;
++ }
++ if (sizeof (cp-&gt;memreq.comp_opts) &lt; len) {
++ printf(&quot;can't handle options for compressor %d (%d)\n&quot;, opt_data[0],
++ opt_data[1]);
++ cp-&gt;memreq.thread_status = ENOSR;
++ cp-&gt;memreq.returned_mem = 0;
++ }
++ if (cp-&gt;memreq.thread_status == 0 &amp;&amp; !cp-&gt;memreq.returned_mem) {
++ bcopy(opt_data, cp-&gt;memreq.comp_opts, len);
++ cp-&gt;memreq.cmd = PPPIO_RCOMP;
++ cp-&gt;rcomp = *comp;
++ error = cp-&gt;memreq.thread_status = EAGAIN;
++ thread_wakeup((vm_offset_t)&amp;cp-&gt;memreq.thread_status);
++ } else {
++ cp-&gt;rstate = cp-&gt;memreq.returned_mem;
++ cp-&gt;memreq.returned_mem = 0;
++ cp-&gt;memreq.thread_status = 0;
++ }
++ }
++#endif
++ break;
++ }
++ iop-&gt;ioc_count = 0;
++ break;
++
++ case PPPIO_GETSTAT:
++ if ((cp-&gt;flags &amp; LAST_MOD) == 0) {
++ error = -1; /* let the ppp_ahdl module handle it */
++ break;
++ }
++ np = allocb(sizeof(struct ppp_stats), BPRI_HI);
++ if (np == 0) {
++ error = ENOSR;
++ break;
++ }
++ if (mp-&gt;b_cont != 0)
++ freemsg(mp-&gt;b_cont);
++ mp-&gt;b_cont = np;
++ psp = (struct ppp_stats *) np-&gt;b_wptr;
++ np-&gt;b_wptr += sizeof(struct ppp_stats);
++ iop-&gt;ioc_count = sizeof(struct ppp_stats);
++ psp-&gt;p = cp-&gt;stats;
++ psp-&gt;vj = cp-&gt;vj_comp.stats;
++ error = 0;
++ break;
++
++ case PPPIO_GETCSTAT:
++ np = allocb(sizeof(struct ppp_comp_stats), BPRI_HI);
++ if (np == 0) {
++ error = ENOSR;
++ break;
++ }
++ if (mp-&gt;b_cont != 0)
++ freemsg(mp-&gt;b_cont);
++ mp-&gt;b_cont = np;
++ csp = (struct ppp_comp_stats *) np-&gt;b_wptr;
++ np-&gt;b_wptr += sizeof(struct ppp_comp_stats);
++ iop-&gt;ioc_count = sizeof(struct ppp_comp_stats);
++ bzero((caddr_t)csp, sizeof(struct ppp_comp_stats));
++ if (cp-&gt;xstate != 0)
++ (*cp-&gt;xcomp-&gt;comp_stat)(cp-&gt;xstate, &amp;csp-&gt;c);
++ if (cp-&gt;rstate != 0)
++ (*cp-&gt;rcomp-&gt;decomp_stat)(cp-&gt;rstate, &amp;csp-&gt;d);
++ error = 0;
++ break;
++
++ case PPPIO_DEBUG:
++ if (iop-&gt;ioc_count != sizeof(int))
++ break;
++ if (mp-&gt;b_cont == 0) {
++ DPRINT1(&quot;ppp_comp_wput/%d: PPPIO_DEBUG b_cont = 0!\n&quot;, cp-&gt;unit);
++ break;
++ }
++ n = *(int *)mp-&gt;b_cont-&gt;b_rptr;
++ if (n == PPPDBG_LOG + PPPDBG_COMP) {
++ DPRINT1(&quot;ppp_comp%d: debug log enabled\n&quot;, cp-&gt;unit);
++ cp-&gt;flags |= DBGLOG;
++ error = 0;
++ iop-&gt;ioc_count = 0;
++ } else {
++ error = -1;
++ }
++ break;
++
++ case PPPIO_LASTMOD:
++ cp-&gt;flags |= LAST_MOD;
++ error = 0;
++ break;
++
++ default:
++ error = -1;
++ break;
++ }
++
++ if (error &lt; 0)
++ putnext(q, mp);
++ else if (error == 0) {
++ mp-&gt;b_datap-&gt;db_type = M_IOCACK;
++ qreply(q, mp);
++ } else {
++ mp-&gt;b_datap-&gt;db_type = M_IOCNAK;
++ iop-&gt;ioc_error = error;
++ iop-&gt;ioc_count = 0;
++ qreply(q, mp);
++ }
++ break;
++
++ case M_CTL:
++ switch (*mp-&gt;b_rptr) {
++ case PPPCTL_MTU:
++ cp-&gt;mtu = ((unsigned short *)mp-&gt;b_rptr)[1];
++ break;
++ case PPPCTL_MRU:
++ cp-&gt;mru = ((unsigned short *)mp-&gt;b_rptr)[1];
++ break;
++ case PPPCTL_UNIT:
++ cp-&gt;unit = mp-&gt;b_rptr[1];
++ break;
++ }
++ putnext(q, mp);
++ break;
++
++ default:
++ putnext(q, mp);
++ }
++
++ return 0;
++}
++
++static int
++ppp_comp_wsrv(q)
++ queue_t *q;
++{
++ mblk_t *mp, *cmp = NULL;
++ comp_state_t *cp;
++ int len, proto, type, hlen, code;
++ struct ip *ip;
++ unsigned char *vjhdr, *dp;
++
++ cp = (comp_state_t *) q-&gt;q_ptr;
++ if (cp == 0) {
++ DPRINT(&quot;cp == 0 in ppp_comp_wsrv\n&quot;);
++ return 0;
++ }
++
++ while ((mp = getq(q)) != 0) {
++ /* assert(mp-&gt;b_datap-&gt;db_type == M_DATA) */
++#ifdef PRIOQ
++ if (!bcanputnext(q,mp-&gt;b_band))
++#else
++ if (!canputnext(q))
++#endif PRIOQ
++ {
++ putbq(q, mp);
++ break;
++ }
++
++ /*
++ * First check the packet length and work out what the protocol is.
++ */
++ len = msgdsize(mp);
++ if (len &lt; PPP_HDRLEN) {
++ DPRINT1(&quot;ppp_comp_wsrv: bogus short packet (%d)\n&quot;, len);
++ freemsg(mp);
++ cp-&gt;stats.ppp_oerrors++;
++ putctl1(RD(q)-&gt;q_next, M_CTL, PPPCTL_OERROR);
++ continue;
++ }
++ proto = (MSG_BYTE(mp, 2) &lt;&lt; 8) + MSG_BYTE(mp, 3);
++
++ /*
++ * Make sure we've got enough data in the first mblk
++ * and that we are its only user.
++ */
++ if (proto == PPP_CCP)
++ hlen = len;
++ else if (proto == PPP_IP)
++ hlen = PPP_HDRLEN + MAX_IPHDR;
++ else
++ hlen = PPP_HDRLEN;
++ if (hlen &gt; len)
++ hlen = len;
++ if (mp-&gt;b_wptr &lt; mp-&gt;b_rptr + hlen || mp-&gt;b_datap-&gt;db_ref &gt; 1) {
++ PULLUP(mp, hlen);
++ if (mp == 0) {
++ DPRINT1(&quot;ppp_comp_wsrv: pullup failed (%d)\n&quot;, hlen);
++ cp-&gt;stats.ppp_oerrors++;
++ putctl1(RD(q)-&gt;q_next, M_CTL, PPPCTL_OERROR);
++ continue;
++ }
++ }
++
++ /*
++ * Do VJ compression if requested.
++ */
++ if (proto == PPP_IP &amp;&amp; (cp-&gt;flags &amp; COMP_VJC)) {
++ ip = (struct ip *) (mp-&gt;b_rptr + PPP_HDRLEN);
++ if (ip-&gt;ip_p == IPPROTO_TCP) {
++ type = vj_compress_tcp(ip, len - PPP_HDRLEN, &amp;cp-&gt;vj_comp,
++ (cp-&gt;flags &amp; COMP_VJCCID), &amp;vjhdr);
++ switch (type) {
++ case TYPE_UNCOMPRESSED_TCP:
++ mp-&gt;b_rptr[3] = proto = PPP_VJC_UNCOMP;
++ break;
++ case TYPE_COMPRESSED_TCP:
++ dp = vjhdr - PPP_HDRLEN;
++ dp[1] = mp-&gt;b_rptr[1]; /* copy control field */
++ dp[0] = mp-&gt;b_rptr[0]; /* copy address field */
++ dp[2] = 0; /* set protocol field */
++ dp[3] = proto = PPP_VJC_COMP;
++ mp-&gt;b_rptr = dp;
++ break;
++ }
++ }
++ }
++
++ /*
++ * Do packet compression if enabled.
++ */
++ if (proto == PPP_CCP)
++ ppp_comp_ccp(q, mp, 0);
++ else if (proto != PPP_LCP &amp;&amp; (cp-&gt;flags &amp; CCP_COMP_RUN)
++ &amp;&amp; cp-&gt;xstate != NULL) {
++ len = msgdsize(mp);
++ (*cp-&gt;xcomp-&gt;compress)(cp-&gt;xstate, &amp;cmp, mp, len,
++ (cp-&gt;flags &amp; CCP_ISUP? cp-&gt;mtu + PPP_HDRLEN: 0));
++ if (cmp != NULL) {
++#ifdef PRIOQ
++ cmp-&gt;b_band=mp-&gt;b_band;
++#endif PRIOQ
++ freemsg(mp);
++ mp = cmp;
++ }
++ }
++
++ /*
++ * Do address/control and protocol compression if enabled.
++ */
++ if ((cp-&gt;flags &amp; COMP_AC)
++ &amp;&amp; !(proto == PPP_LCP &amp;&amp; LCP_USE_DFLT(mp))) {
++ mp-&gt;b_rptr += 2; /* drop the address &amp; ctrl fields */
++ if (proto &lt; 0x100 &amp;&amp; (cp-&gt;flags &amp; COMP_PROT))
++ ++mp-&gt;b_rptr; /* drop the high protocol byte */
++ } else if (proto &lt; 0x100 &amp;&amp; (cp-&gt;flags &amp; COMP_PROT)) {
++ /* shuffle up the address &amp; ctrl fields */
++ mp-&gt;b_rptr[2] = mp-&gt;b_rptr[1];
++ mp-&gt;b_rptr[1] = mp-&gt;b_rptr[0];
++ ++mp-&gt;b_rptr;
++ }
++
++ cp-&gt;stats.ppp_opackets++;
++ cp-&gt;stats.ppp_obytes += msgdsize(mp);
++ putnext(q, mp);
++ }
++
++ return 0;
++}
++
++static int
++ppp_comp_rput(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ comp_state_t *cp;
++ struct iocblk *iop;
++ struct ppp_stats *psp;
++
++ cp = (comp_state_t *) q-&gt;q_ptr;
++ if (cp == 0) {
++ DPRINT(&quot;cp == 0 in ppp_comp_rput\n&quot;);
++ freemsg(mp);
++ return 0;
++ }
++
++ switch (mp-&gt;b_datap-&gt;db_type) {
++
++ case M_DATA:
++ putq(q, mp);
++ break;
++
++ case M_IOCACK:
++ iop = (struct iocblk *) mp-&gt;b_rptr;
++ switch (iop-&gt;ioc_cmd) {
++ case PPPIO_GETSTAT:
++ /*
++ * Catch this on the way back from the ppp_ahdl module
++ * so we can fill in the VJ stats.
++ */
++ if (mp-&gt;b_cont == 0 || iop-&gt;ioc_count != sizeof(struct ppp_stats))
++ break;
++ psp = (struct ppp_stats *) mp-&gt;b_cont-&gt;b_rptr;
++ psp-&gt;vj = cp-&gt;vj_comp.stats;
++ break;
++ }
++ putnext(q, mp);
++ break;
++
++ case M_CTL:
++ switch (mp-&gt;b_rptr[0]) {
++ case PPPCTL_IERROR:
++ ++cp-&gt;stats.ppp_ierrors;
++ break;
++ case PPPCTL_OERROR:
++ ++cp-&gt;stats.ppp_oerrors;
++ break;
++ }
++ putnext(q, mp);
++ break;
++
++ default:
++ putnext(q, mp);
++ }
++
++ return 0;
++}
++
++static int
++ppp_comp_rsrv(q)
++ queue_t *q;
++{
++ int proto, rv, i;
++ mblk_t *mp, *dmp = NULL, *np;
++ uchar_t *dp, *iphdr;
++ comp_state_t *cp;
++ int len, hlen, vjlen;
++ u_int iphlen;
++
++ cp = (comp_state_t *) q-&gt;q_ptr;
++ if (cp == 0) {
++ DPRINT(&quot;cp == 0 in ppp_comp_rsrv\n&quot;);
++ return 0;
++ }
++
++ while ((mp = getq(q)) != 0) {
++ /* assert(mp-&gt;b_datap-&gt;db_type == M_DATA) */
++ if (!canputnext(q)) {
++ putbq(q, mp);
++ break;
++ }
++
++ len = msgdsize(mp);
++ cp-&gt;stats.ppp_ibytes += len;
++ cp-&gt;stats.ppp_ipackets++;
++
++ /*
++ * First work out the protocol and where the PPP header ends.
++ */
++ i = 0;
++ proto = MSG_BYTE(mp, 0);
++ if (proto == PPP_ALLSTATIONS) {
++ i = 2;
++ proto = MSG_BYTE(mp, 2);
++ }
++ if ((proto &amp; 1) == 0) {
++ ++i;
++ proto = (proto &lt;&lt; 8) + MSG_BYTE(mp, i);
++ }
++ hlen = i + 1;
++
++ /*
++ * Now reconstruct a complete, contiguous PPP header at the
++ * start of the packet.
++ */
++ if (hlen &lt; ((cp-&gt;flags &amp; DECOMP_AC)? 0: 2)
++ + ((cp-&gt;flags &amp; DECOMP_PROT)? 1: 2)) {
++ /* count these? */
++ goto bad;
++ }
++ if (mp-&gt;b_rptr + hlen &gt; mp-&gt;b_wptr) {
++ adjmsg(mp, hlen); /* XXX check this call */
++ hlen = 0;
++ }
++ if (hlen != PPP_HDRLEN) {
++ /*
++ * We need to put some bytes on the front of the packet
++ * to make a full-length PPP header.
++ * If we can put them in *mp, we do, otherwise we
++ * tack another mblk on the front.
++ * XXX we really shouldn't need to carry around
++ * the address and control at this stage.
++ */
++ dp = mp-&gt;b_rptr + hlen - PPP_HDRLEN;
++ if (dp &lt; mp-&gt;b_datap-&gt;db_base || mp-&gt;b_datap-&gt;db_ref &gt; 1) {
++ np = allocb(PPP_HDRLEN, BPRI_MED);
++ if (np == 0)
++ goto bad;
++ np-&gt;b_cont = mp;
++ mp-&gt;b_rptr += hlen;
++ mp = np;
++ dp = mp-&gt;b_wptr;
++ mp-&gt;b_wptr += PPP_HDRLEN;
++ } else
++ mp-&gt;b_rptr = dp;
++
++ dp[0] = PPP_ALLSTATIONS;
++ dp[1] = PPP_UI;
++ dp[2] = proto &gt;&gt; 8;
++ dp[3] = proto;
++ }
++
++ /*
++ * Now see if we have a compressed packet to decompress,
++ * or a CCP packet to take notice of.
++ */
++ proto = PPP_PROTOCOL(mp-&gt;b_rptr);
++ if (proto == PPP_CCP) {
++ len = msgdsize(mp);
++ if (mp-&gt;b_wptr &lt; mp-&gt;b_rptr + len) {
++ PULLUP(mp, len);
++ if (mp == 0)
++ goto bad;
++ }
++ ppp_comp_ccp(q, mp, 1);
++ } else if (proto == PPP_COMP) {
++ if ((cp-&gt;flags &amp; CCP_ISUP)
++ &amp;&amp; (cp-&gt;flags &amp; CCP_DECOMP_RUN) &amp;&amp; cp-&gt;rstate
++ &amp;&amp; (cp-&gt;flags &amp; CCP_ERR) == 0) {
++ rv = (*cp-&gt;rcomp-&gt;decompress)(cp-&gt;rstate, mp, &amp;dmp);
++ switch (rv) {
++ case DECOMP_OK:
++ freemsg(mp);
++ mp = dmp;
++ if (mp == NULL) {
++ /* no error, but no packet returned either. */
++ continue;
++ }
++ break;
++ case DECOMP_ERROR:
++ cp-&gt;flags |= CCP_ERROR;
++ ++cp-&gt;stats.ppp_ierrors;
++ putctl1(q-&gt;q_next, M_CTL, PPPCTL_IERROR);
++ break;
++ case DECOMP_FATALERROR:
++ cp-&gt;flags |= CCP_FATALERROR;
++ ++cp-&gt;stats.ppp_ierrors;
++ putctl1(q-&gt;q_next, M_CTL, PPPCTL_IERROR);
++ break;
++ }
++ }
++ } else if (cp-&gt;rstate &amp;&amp; (cp-&gt;flags &amp; CCP_DECOMP_RUN)) {
++ (*cp-&gt;rcomp-&gt;incomp)(cp-&gt;rstate, mp);
++ }
++
++ /*
++ * Now do VJ decompression.
++ */
++ proto = PPP_PROTOCOL(mp-&gt;b_rptr);
++ if (proto == PPP_VJC_COMP || proto == PPP_VJC_UNCOMP) {
++ len = msgdsize(mp) - PPP_HDRLEN;
++ if ((cp-&gt;flags &amp; DECOMP_VJC) == 0 || len &lt;= 0)
++ goto bad;
++
++ /*
++ * Advance past the ppp header.
++ * Here we assume that the whole PPP header is in the first mblk.
++ */
++ np = mp;
++ dp = np-&gt;b_rptr + PPP_HDRLEN;
++ if (dp &gt;= mp-&gt;b_wptr) {
++ np = np-&gt;b_cont;
++ dp = np-&gt;b_rptr;
++ }
++
++ /*
++ * Make sure we have sufficient contiguous data at this point.
++ */
++ hlen = (proto == PPP_VJC_COMP)? MAX_VJHDR: MAX_IPHDR;
++ if (hlen &gt; len)
++ hlen = len;
++ if (np-&gt;b_wptr &lt; dp + hlen || np-&gt;b_datap-&gt;db_ref &gt; 1) {
++ PULLUP(mp, hlen + PPP_HDRLEN);
++ if (mp == 0)
++ goto bad;
++ np = mp;
++ dp = np-&gt;b_rptr + PPP_HDRLEN;
++ }
++
++ if (proto == PPP_VJC_COMP) {
++ /*
++ * Decompress VJ-compressed packet.
++ * First reset compressor if an input error has occurred.
++ */
++ if (cp-&gt;stats.ppp_ierrors != cp-&gt;vj_last_ierrors) {
++ if (cp-&gt;flags &amp; DBGLOG)
++ DPRINT1(&quot;ppp%d: resetting VJ\n&quot;, cp-&gt;unit);
++ vj_uncompress_err(&amp;cp-&gt;vj_comp);
++ cp-&gt;vj_last_ierrors = cp-&gt;stats.ppp_ierrors;
++ }
++
++ vjlen = vj_uncompress_tcp(dp, np-&gt;b_wptr - dp, len,
++ &amp;cp-&gt;vj_comp, &amp;iphdr, &amp;iphlen);
++ if (vjlen &lt; 0) {
++ if (cp-&gt;flags &amp; DBGLOG)
++ DPRINT2(&quot;ppp%d: vj_uncomp_tcp failed, pkt len %d\n&quot;,
++ cp-&gt;unit, len);
++ ++cp-&gt;vj_last_ierrors; /* so we don't reset next time */
++ goto bad;
++ }
++
++ /* drop ppp and vj headers off */
++ if (mp != np) {
++ freeb(mp);
++ mp = np;
++ }
++ mp-&gt;b_rptr = dp + vjlen;
++
++ /* allocate a new mblk for the ppp and ip headers */
++ if ((np = allocb(iphlen + PPP_HDRLEN + 4, BPRI_MED)) == 0)
++ goto bad;
++ dp = np-&gt;b_rptr; /* prepend mblk with TCP/IP hdr */
++ dp[0] = PPP_ALLSTATIONS; /* reconstruct PPP header */
++ dp[1] = PPP_UI;
++ dp[2] = PPP_IP &gt;&gt; 8;
++ dp[3] = PPP_IP;
++ bcopy((caddr_t)iphdr, (caddr_t)dp + PPP_HDRLEN, iphlen);
++ np-&gt;b_wptr = dp + iphlen + PPP_HDRLEN;
++ np-&gt;b_cont = mp;
++
++ /* XXX there seems to be a bug which causes panics in strread
++ if we make an mbuf with only the IP header in it :-( */
++ if (mp-&gt;b_wptr - mp-&gt;b_rptr &gt; 4) {
++ bcopy((caddr_t)mp-&gt;b_rptr, (caddr_t)np-&gt;b_wptr, 4);
++ mp-&gt;b_rptr += 4;
++ np-&gt;b_wptr += 4;
++ } else {
++ bcopy((caddr_t)mp-&gt;b_rptr, (caddr_t)np-&gt;b_wptr,
++ mp-&gt;b_wptr - mp-&gt;b_rptr);
++ np-&gt;b_wptr += mp-&gt;b_wptr - mp-&gt;b_rptr;
++ np-&gt;b_cont = mp-&gt;b_cont;
++ freeb(mp);
++ }
++
++ mp = np;
++
++ } else {
++ /*
++ * &quot;Decompress&quot; a VJ-uncompressed packet.
++ */
++ cp-&gt;vj_last_ierrors = cp-&gt;stats.ppp_ierrors;
++ if (!vj_uncompress_uncomp(dp, hlen, &amp;cp-&gt;vj_comp)) {
++ if (cp-&gt;flags &amp; DBGLOG)
++ DPRINT2(&quot;ppp%d: vj_uncomp_uncomp failed, pkt len %d\n&quot;,
++ cp-&gt;unit, len);
++ ++cp-&gt;vj_last_ierrors; /* don't need to reset next time */
++ goto bad;
++ }
++ mp-&gt;b_rptr[3] = PPP_IP; /* fix up the PPP protocol field */
++ }
++ }
++
++ putnext(q, mp);
++ continue;
++
++ bad:
++ if (mp != 0)
++ freemsg(mp);
++ cp-&gt;stats.ppp_ierrors++;
++ putctl1(q-&gt;q_next, M_CTL, PPPCTL_IERROR);
++ }
++
++ return 0;
++}
++
++/*
++ * Handle a CCP packet being sent or received.
++ * Here all the data in the packet is in a single mbuf.
++ */
++static void
++ppp_comp_ccp(q, mp, rcvd)
++ queue_t *q;
++ mblk_t *mp;
++ int rcvd;
++{
++ int len, clen;
++ comp_state_t *cp;
++ unsigned char *dp;
++
++ len = msgdsize(mp);
++ if (len &lt; PPP_HDRLEN + CCP_HDRLEN)
++ return;
++
++ cp = (comp_state_t *) q-&gt;q_ptr;
++ dp = mp-&gt;b_rptr + PPP_HDRLEN;
++ len -= PPP_HDRLEN;
++ clen = CCP_LENGTH(dp);
++ if (clen &gt; len)
++ return;
++
++ switch (CCP_CODE(dp)) {
++ case CCP_CONFREQ:
++ case CCP_TERMREQ:
++ case CCP_TERMACK:
++ cp-&gt;flags &amp;= ~CCP_ISUP;
++ break;
++
++ case CCP_CONFACK:
++ if ((cp-&gt;flags &amp; (CCP_ISOPEN | CCP_ISUP)) == CCP_ISOPEN
++ &amp;&amp; clen &gt;= CCP_HDRLEN + CCP_OPT_MINLEN
++ &amp;&amp; clen &gt;= CCP_HDRLEN + CCP_OPT_LENGTH(dp + CCP_HDRLEN)) {
++ if (!rcvd) {
++ if (cp-&gt;xstate != NULL
++ &amp;&amp; (*cp-&gt;xcomp-&gt;comp_init)
++ (cp-&gt;xstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN,
++ cp-&gt;unit, 0, ((cp-&gt;flags &amp; DBGLOG) != 0)))
++ cp-&gt;flags |= CCP_COMP_RUN;
++ } else {
++ if (cp-&gt;rstate != NULL
++ &amp;&amp; (*cp-&gt;rcomp-&gt;decomp_init)
++ (cp-&gt;rstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN,
++ cp-&gt;unit, 0, cp-&gt;mru, ((cp-&gt;flags &amp; DBGLOG) != 0)))
++ cp-&gt;flags = (cp-&gt;flags &amp; ~CCP_ERR) | CCP_DECOMP_RUN;
++ }
++ }
++ break;
++
++ case CCP_RESETACK:
++ if (cp-&gt;flags &amp; CCP_ISUP) {
++ if (!rcvd) {
++ if (cp-&gt;xstate &amp;&amp; (cp-&gt;flags &amp; CCP_COMP_RUN))
++ (*cp-&gt;xcomp-&gt;comp_reset)(cp-&gt;xstate);
++ } else {
++ if (cp-&gt;rstate &amp;&amp; (cp-&gt;flags &amp; CCP_DECOMP_RUN)) {
++ (*cp-&gt;rcomp-&gt;decomp_reset)(cp-&gt;rstate);
++ cp-&gt;flags &amp;= ~CCP_ERROR;
++ }
++ }
++ }
++ break;
++ }
++}
++
++#if 0
++dump_msg(mp)
++ mblk_t *mp;
++{
++ dblk_t *db;
++
++ while (mp != 0) {
++ db = mp-&gt;b_datap;
++ DPRINT2(&quot;mp=%x cont=%x &quot;, mp, mp-&gt;b_cont);
++ DPRINT3(&quot;rptr=%x wptr=%x datap=%x\n&quot;, mp-&gt;b_rptr, mp-&gt;b_wptr, db);
++ DPRINT2(&quot; base=%x lim=%x&quot;, db-&gt;db_base, db-&gt;db_lim);
++ DPRINT2(&quot; ref=%d type=%d\n&quot;, db-&gt;db_ref, db-&gt;db_type);
++ mp = mp-&gt;b_cont;
++ }
++}
++#endif
++
++static int
++msg_byte(mp, i)
++ mblk_t *mp;
++ unsigned int i;
++{
++ while (mp != 0 &amp;&amp; i &gt;= mp-&gt;b_wptr - mp-&gt;b_rptr)
++ mp = mp-&gt;b_cont;
++ if (mp == 0)
++ return -1;
++ return mp-&gt;b_rptr[i];
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/modules/ppp_comp.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/modules/ppp_mod.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/modules/ppp_mod.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/modules/ppp_mod.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,190 @@
++/*
++ * Miscellaneous definitions for PPP STREAMS modules.
++ */
++
++/*
++ * Macros for allocating and freeing kernel memory.
++ */
++#ifdef SVR4 /* SVR4, including Solaris 2 */
++#include &lt;sys/kmem.h&gt;
++#define ALLOC_SLEEP(n) kmem_alloc((n), KM_SLEEP)
++#define ALLOC_NOSLEEP(n) kmem_alloc((n), KM_NOSLEEP)
++#define FREE(p, n) kmem_free((p), (n))
++#endif
++
++#ifdef SUNOS4
++#include &lt;sys/kmem_alloc.h&gt; /* SunOS 4.x */
++#define ALLOC_SLEEP(n) kmem_alloc((n), KMEM_SLEEP)
++#define ALLOC_NOSLEEP(n) kmem_alloc((n), KMEM_NOSLEEP)
++#define FREE(p, n) kmem_free((p), (n))
++#define NOTSUSER() (suser()? 0: EPERM)
++#define bcanputnext(q, band) canputnext((q))
++#endif /* SunOS 4 */
++
++#ifdef __osf__
++#include &lt;sys/malloc.h&gt;
++
++/* caution: this mirrors macros in sys/malloc.h, and uses interfaces
++ * which are subject to change.
++ * The problems are that:
++ * - the official MALLOC macro wants the lhs of the assignment as an argument,
++ * and it takes care of the assignment itself (yuck.)
++ * - PPP insists on using &quot;FREE&quot; which conflicts with a macro of the same name.
++ *
++ */
++#ifdef BUCKETINDX /* V2.0 */
++#define ALLOC_SLEEP(n) (void *)malloc((u_long)(n), BUCKETP(n), M_DEVBUF, M_WAITOK)
++#define ALLOC_NOSLEEP(n) (void *)malloc((u_long)(n), BUCKETP(n), M_DEVBUF, M_NOWAIT)
++#else
++#define ALLOC_SLEEP(n) (void *)malloc((u_long)(n), BUCKETINDEX(n), M_DEVBUF, M_WAITOK)
++#define ALLOC_NOSLEEP(n) (void *)malloc((u_long)(n), BUCKETINDEX(n), M_DEVBUF, M_NOWAIT)
++#endif
++
++#define bcanputnext(q, band) canputnext((q))
++
++#ifdef FREE
++#undef FREE
++#endif
++#define FREE(p, n) free((void *)(p), M_DEVBUF)
++
++#define NO_DLPI 1
++
++#ifndef IFT_PPP
++#define IFT_PPP 0x17
++#endif
++
++#include &lt;sys/proc.h&gt;
++#define NOTSUSER() (suser(u.u_procp-&gt;p_rcred, &amp;u.u_acflag) ? EPERM : 0)
++
++/* #include &quot;ppp_osf.h&quot; */
++
++#endif /* __osf__ */
++
++#ifdef AIX4
++#define ALLOC_SLEEP(n) xmalloc((n), 0, pinned_heap) /* AIX V4.x */
++#define ALLOC_NOSLEEP(n) xmalloc((n), 0, pinned_heap) /* AIX V4.x */
++#define FREE(p, n) xmfree((p), pinned_heap)
++#define NOTSUSER() (suser()? 0: EPERM)
++#endif /* AIX */
++
++/*
++ * Macros for printing debugging stuff.
++ */
++#ifdef DEBUG
++#if defined(SVR4) || defined(__osf__)
++#if defined(SNI)
++#include &lt;sys/strlog.h&gt;
++#define STRLOG_ID 4712
++#define DPRINT(f) strlog(STRLOG_ID, 0, 0, SL_TRACE, f)
++#define DPRINT1(f, a1) strlog(STRLOG_ID, 0, 0, SL_TRACE, f, a1)
++#define DPRINT2(f, a1, a2) strlog(STRLOG_ID, 0, 0, SL_TRACE, f, a1, a2)
++#define DPRINT3(f, a1, a2, a3) strlog(STRLOG_ID, 0, 0, SL_TRACE, f, a1, a2, a3)
++#else
++#define DPRINT(f) cmn_err(CE_CONT, f)
++#define DPRINT1(f, a1) cmn_err(CE_CONT, f, a1)
++#define DPRINT2(f, a1, a2) cmn_err(CE_CONT, f, a1, a2)
++#define DPRINT3(f, a1, a2, a3) cmn_err(CE_CONT, f, a1, a2, a3)
++#endif /* SNI */
++#else
++#define DPRINT(f) printf(f)
++#define DPRINT1(f, a1) printf(f, a1)
++#define DPRINT2(f, a1, a2) printf(f, a1, a2)
++#define DPRINT3(f, a1, a2, a3) printf(f, a1, a2, a3)
++#endif /* SVR4 or OSF */
++
++#else
++#define DPRINT(f) 0
++#define DPRINT1(f, a1) 0
++#define DPRINT2(f, a1, a2) 0
++#define DPRINT3(f, a1, a2, a3) 0
++#endif /* DEBUG */
++
++#ifndef SVR4
++typedef unsigned char uchar_t;
++typedef unsigned short ushort_t;
++#ifndef __osf__
++typedef int minor_t;
++#endif
++#endif
++
++/*
++ * If we don't have multithreading support, define substitutes.
++ */
++#ifndef D_MP
++# define qprocson(q)
++# define qprocsoff(q)
++# define put(q, mp) ((*(q)-&gt;q_qinfo-&gt;qi_putp)((q), (mp)))
++# define canputnext(q) canput((q)-&gt;q_next)
++# define qwriter(q, mp, func, scope) (func)((q), (mp))
++#endif
++
++#ifdef D_MP
++/* Use msgpullup if we have other multithreading support. */
++#define PULLUP(mp, len) \
++ do { \
++ mblk_t *np = msgpullup((mp), (len)); \
++ freemsg((mp)); \
++ mp = np; \
++ } while (0)
++
++#else
++/* Use pullupmsg if we don't have any multithreading support. */
++#define PULLUP(mp, len) \
++ do { \
++ if (!pullupmsg((mp), (len))) { \
++ freemsg((mp)); \
++ mp = 0; \
++ } \
++ } while (0)
++#endif
++
++/*
++ * How to declare the open and close procedures for a module.
++ */
++#ifdef SVR4
++#define MOD_OPEN_DECL(name) \
++static int name __P((queue_t *, dev_t *, int, int, cred_t *))
++
++#define MOD_CLOSE_DECL(name) \
++static int name __P((queue_t *, int, cred_t *))
++
++#define MOD_OPEN(name) \
++static int name(q, devp, flag, sflag, credp) \
++ queue_t *q; \
++ dev_t *devp; \
++ int flag, sflag; \
++ cred_t *credp;
++
++#define MOD_CLOSE(name) \
++static int name(q, flag, credp) \
++ queue_t *q; \
++ int flag; \
++ cred_t *credp;
++
++#define OPEN_ERROR(x) return (x)
++#define DRV_OPEN_OK(dev) return 0
++
++#define NOTSUSER() (drv_priv(credp))
++
++#else /* not SVR4 */
++#define MOD_OPEN_DECL(name) \
++static int name __P((queue_t *, int, int, int))
++
++#define MOD_CLOSE_DECL(name) \
++static int name __P((queue_t *, int))
++
++#define MOD_OPEN(name) \
++static int name(q, dev, flag, sflag) \
++ queue_t *q; \
++ int dev; \
++ int flag, sflag;
++
++#define MOD_CLOSE(name) \
++static int name(q, flag) \
++ queue_t *q; \
++ int flag;
++
++#define OPEN_ERROR(x) { u.u_error = (x); return OPENFAIL; }
++#define DRV_OPEN_OK(dev) return (dev)
++
++#endif /* SVR4 */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/modules/ppp_mod.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/modules/vjcompress.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/modules/vjcompress.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/modules/vjcompress.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,587 @@
++/*
++ * Routines to compress and uncompess tcp packets (for transmission
++ * over low speed serial lines.
++ *
++ * Copyright (c) 1989 Regents of the University of California.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by the University of California, Berkeley. The name of the
++ * University may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * Van Jacobson (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">van at helios.ee.lbl.gov</A>), Dec 31, 1989:
++ * - Initial distribution.
++ *
++ * Modified June 1993 by Paul Mackerras, <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">paulus at cs.anu.edu.au</A>,
++ * so that the entire packet being decompressed doesn't have
++ * to be in contiguous memory (just the compressed header).
++ */
++
++/*
++ * This version is used under SunOS 4.x, Digital UNIX, AIX 4.x,
++ * and SVR4 systems including Solaris 2.
++ *
++ * $Id: vjcompress.c 195720 2001-06-11 11:44:34Z gc $
++ */
++
++#include &lt;sys/types.h&gt;
++#include &lt;sys/param.h&gt;
++
++#ifdef SVR4
++#ifndef __GNUC__
++#include &lt;sys/byteorder.h&gt; /* for ntohl, etc. */
++#else
++/* make sure we don't get the gnu &quot;fixed&quot; one! */
++#include &quot;/usr/include/sys/byteorder.h&quot;
++#endif
++#endif
++
++#ifdef __osf__
++#include &lt;net/net_globals.h&gt;
++#endif
++#include &lt;netinet/in.h&gt;
++
++#ifdef AIX4
++#define _NETINET_IN_SYSTM_H_
++typedef u_long n_long;
++#else
++#include &lt;netinet/in_systm.h&gt;
++#endif
++
++#include &lt;netinet/ip.h&gt;
++#include &lt;netinet/tcp.h&gt;
++
++#include &lt;net/ppp_defs.h&gt;
++#include &lt;net/vjcompress.h&gt;
++
++#ifndef VJ_NO_STATS
++#define INCR(counter) ++comp-&gt;stats.counter
++#else
++#define INCR(counter)
++#endif
++
++#define BCMP(p1, p2, n) bcmp((char *)(p1), (char *)(p2), (int)(n))
++#undef BCOPY
++#define BCOPY(p1, p2, n) bcopy((char *)(p1), (char *)(p2), (int)(n))
++#ifndef KERNEL
++#define ovbcopy bcopy
++#endif
++
++#ifdef __osf__
++#define getip_hl(base) (((base).ip_vhl)&amp;0xf)
++#define getth_off(base) ((((base).th_xoff)&amp;0xf0)&gt;&gt;4)
++
++#else
++#define getip_hl(base) ((base).ip_hl)
++#define getth_off(base) ((base).th_off)
++#endif
++
++void
++vj_compress_init(comp, max_state)
++ struct vjcompress *comp;
++ int max_state;
++{
++ register u_int i;
++ register struct cstate *tstate = comp-&gt;tstate;
++
++ if (max_state == -1)
++ max_state = MAX_STATES - 1;
++ bzero((char *)comp, sizeof(*comp));
++ for (i = max_state; i &gt; 0; --i) {
++ tstate[i].cs_id = i;
++ tstate[i].cs_next = &amp;tstate[i - 1];
++ }
++ tstate[0].cs_next = &amp;tstate[max_state];
++ tstate[0].cs_id = 0;
++ comp-&gt;last_cs = &amp;tstate[0];
++ comp-&gt;last_recv = 255;
++ comp-&gt;last_xmit = 255;
++ comp-&gt;flags = VJF_TOSS;
++}
++
++
++/* ENCODE encodes a number that is known to be non-zero. ENCODEZ
++ * checks for zero (since zero has to be encoded in the long, 3 byte
++ * form).
++ */
++#define ENCODE(n) { \
++ if ((u_short)(n) &gt;= 256) { \
++ *cp++ = 0; \
++ cp[1] = (n); \
++ cp[0] = (n) &gt;&gt; 8; \
++ cp += 2; \
++ } else { \
++ *cp++ = (n); \
++ } \
++}
++#define ENCODEZ(n) { \
++ if ((u_short)(n) &gt;= 256 || (u_short)(n) == 0) { \
++ *cp++ = 0; \
++ cp[1] = (n); \
++ cp[0] = (n) &gt;&gt; 8; \
++ cp += 2; \
++ } else { \
++ *cp++ = (n); \
++ } \
++}
++
++#define DECODEL(f) { \
++ if (*cp == 0) {\
++ u_int32_t tmp = ntohl(f) + ((cp[1] &lt;&lt; 8) | cp[2]); \
++ (f) = htonl(tmp); \
++ cp += 3; \
++ } else { \
++ u_int32_t tmp = ntohl(f) + (u_int32_t)*cp++; \
++ (f) = htonl(tmp); \
++ } \
++}
++
++#define DECODES(f) { \
++ if (*cp == 0) {\
++ u_short tmp = ntohs(f) + ((cp[1] &lt;&lt; 8) | cp[2]); \
++ (f) = htons(tmp); \
++ cp += 3; \
++ } else { \
++ u_short tmp = ntohs(f) + (u_int32_t)*cp++; \
++ (f) = htons(tmp); \
++ } \
++}
++
++#define DECODEU(f) { \
++ if (*cp == 0) {\
++ (f) = htons((cp[1] &lt;&lt; 8) | cp[2]); \
++ cp += 3; \
++ } else { \
++ (f) = htons((u_int32_t)*cp++); \
++ } \
++}
++
++u_int
++vj_compress_tcp(ip, mlen, comp, compress_cid, vjhdrp)
++ register struct ip *ip;
++ u_int mlen;
++ struct vjcompress *comp;
++ int compress_cid;
++ u_char **vjhdrp;
++{
++ register struct cstate *cs = comp-&gt;last_cs-&gt;cs_next;
++ register u_int hlen = getip_hl(*ip);
++ register struct tcphdr *oth;
++ register struct tcphdr *th;
++ register u_int deltaS, deltaA;
++ register u_int changes = 0;
++ u_char new_seq[16];
++ register u_char *cp = new_seq;
++
++ /*
++ * Bail if this is an IP fragment or if the TCP packet isn't
++ * `compressible' (i.e., ACK isn't set or some other control bit is
++ * set). (We assume that the caller has already made sure the
++ * packet is IP proto TCP).
++ */
++ if ((ip-&gt;ip_off &amp; htons(0x3fff)) || mlen &lt; 40)
++ return (TYPE_IP);
++
++ th = (struct tcphdr *)&amp;((int *)ip)[hlen];
++ if ((th-&gt;th_flags &amp; (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK)
++ return (TYPE_IP);
++ /*
++ * Packet is compressible -- we're going to send either a
++ * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need
++ * to locate (or create) the connection state. Special case the
++ * most recently used connection since it's most likely to be used
++ * again &amp; we don't have to do any reordering if it's used.
++ */
++ INCR(vjs_packets);
++ if (ip-&gt;ip_src.s_addr != cs-&gt;cs_ip.ip_src.s_addr ||
++ ip-&gt;ip_dst.s_addr != cs-&gt;cs_ip.ip_dst.s_addr ||
++ *(int *)th != ((int *)&amp;cs-&gt;cs_ip)[getip_hl(cs-&gt;cs_ip)]) {
++ /*
++ * Wasn't the first -- search for it.
++ *
++ * States are kept in a circularly linked list with
++ * last_cs pointing to the end of the list. The
++ * list is kept in lru order by moving a state to the
++ * head of the list whenever it is referenced. Since
++ * the list is short and, empirically, the connection
++ * we want is almost always near the front, we locate
++ * states via linear search. If we don't find a state
++ * for the datagram, the oldest state is (re-)used.
++ */
++ register struct cstate *lcs;
++ register struct cstate *lastcs = comp-&gt;last_cs;
++
++ do {
++ lcs = cs; cs = cs-&gt;cs_next;
++ INCR(vjs_searches);
++ if (ip-&gt;ip_src.s_addr == cs-&gt;cs_ip.ip_src.s_addr
++ &amp;&amp; ip-&gt;ip_dst.s_addr == cs-&gt;cs_ip.ip_dst.s_addr
++ &amp;&amp; *(int *)th == ((int *)&amp;cs-&gt;cs_ip)[getip_hl(cs-&gt;cs_ip)])
++ goto found;
++ } while (cs != lastcs);
++
++ /*
++ * Didn't find it -- re-use oldest cstate. Send an
++ * uncompressed packet that tells the other side what
++ * connection number we're using for this conversation.
++ * Note that since the state list is circular, the oldest
++ * state points to the newest and we only need to set
++ * last_cs to update the lru linkage.
++ */
++ INCR(vjs_misses);
++ comp-&gt;last_cs = lcs;
++ hlen += getth_off(*th);
++ hlen &lt;&lt;= 2;
++ if (hlen &gt; mlen)
++ return (TYPE_IP);
++ goto uncompressed;
++
++ found:
++ /*
++ * Found it -- move to the front on the connection list.
++ */
++ if (cs == lastcs)
++ comp-&gt;last_cs = lcs;
++ else {
++ lcs-&gt;cs_next = cs-&gt;cs_next;
++ cs-&gt;cs_next = lastcs-&gt;cs_next;
++ lastcs-&gt;cs_next = cs;
++ }
++ }
++
++ /*
++ * Make sure that only what we expect to change changed. The first
++ * line of the `if' checks the IP protocol version, header length &amp;
++ * type of service. The 2nd line checks the &quot;Don't fragment&quot; bit.
++ * The 3rd line checks the time-to-live and protocol (the protocol
++ * check is unnecessary but costless). The 4th line checks the TCP
++ * header length. The 5th line checks IP options, if any. The 6th
++ * line checks TCP options, if any. If any of these things are
++ * different between the previous &amp; current datagram, we send the
++ * current datagram `uncompressed'.
++ */
++ oth = (struct tcphdr *)&amp;((int *)&amp;cs-&gt;cs_ip)[hlen];
++ deltaS = hlen;
++ hlen += getth_off(*th);
++ hlen &lt;&lt;= 2;
++ if (hlen &gt; mlen)
++ return (TYPE_IP);
++
++ if (((u_short *)ip)[0] != ((u_short *)&amp;cs-&gt;cs_ip)[0] ||
++ ((u_short *)ip)[3] != ((u_short *)&amp;cs-&gt;cs_ip)[3] ||
++ ((u_short *)ip)[4] != ((u_short *)&amp;cs-&gt;cs_ip)[4] ||
++ getth_off(*th) != getth_off(*oth) ||
++ (deltaS &gt; 5 &amp;&amp; BCMP(ip + 1, &amp;cs-&gt;cs_ip + 1, (deltaS - 5) &lt;&lt; 2)) ||
++ (getth_off(*th) &gt; 5 &amp;&amp; BCMP(th + 1, oth + 1, (getth_off(*th) - 5) &lt;&lt; 2)))
++ goto uncompressed;
++
++ /*
++ * Figure out which of the changing fields changed. The
++ * receiver expects changes in the order: urgent, window,
++ * ack, seq (the order minimizes the number of temporaries
++ * needed in this section of code).
++ */
++ if (th-&gt;th_flags &amp; TH_URG) {
++ deltaS = ntohs(th-&gt;th_urp);
++ ENCODEZ(deltaS);
++ changes |= NEW_U;
++ } else if (th-&gt;th_urp != oth-&gt;th_urp)
++ /* argh! URG not set but urp changed -- a sensible
++ * implementation should never do this but RFC793
++ * doesn't prohibit the change so we have to deal
++ * with it. */
++ goto uncompressed;
++
++ if ((deltaS = (u_short)(ntohs(th-&gt;th_win) - ntohs(oth-&gt;th_win))) &gt; 0) {
++ ENCODE(deltaS);
++ changes |= NEW_W;
++ }
++
++ if ((deltaA = ntohl(th-&gt;th_ack) - ntohl(oth-&gt;th_ack)) &gt; 0) {
++ if (deltaA &gt; 0xffff)
++ goto uncompressed;
++ ENCODE(deltaA);
++ changes |= NEW_A;
++ }
++
++ if ((deltaS = ntohl(th-&gt;th_seq) - ntohl(oth-&gt;th_seq)) &gt; 0) {
++ if (deltaS &gt; 0xffff)
++ goto uncompressed;
++ ENCODE(deltaS);
++ changes |= NEW_S;
++ }
++
++ switch(changes) {
++
++ case 0:
++ /*
++ * Nothing changed. If this packet contains data and the
++ * last one didn't, this is probably a data packet following
++ * an ack (normal on an interactive connection) and we send
++ * it compressed. Otherwise it's probably a retransmit,
++ * retransmitted ack or window probe. Send it uncompressed
++ * in case the other side missed the compressed version.
++ */
++ if (ip-&gt;ip_len != cs-&gt;cs_ip.ip_len &amp;&amp;
++ ntohs(cs-&gt;cs_ip.ip_len) == hlen)
++ break;
++
++ /* (fall through) */
++
++ case SPECIAL_I:
++ case SPECIAL_D:
++ /*
++ * actual changes match one of our special case encodings --
++ * send packet uncompressed.
++ */
++ goto uncompressed;
++
++ case NEW_S|NEW_A:
++ if (deltaS == deltaA &amp;&amp; deltaS == ntohs(cs-&gt;cs_ip.ip_len) - hlen) {
++ /* special case for echoed terminal traffic */
++ changes = SPECIAL_I;
++ cp = new_seq;
++ }
++ break;
++
++ case NEW_S:
++ if (deltaS == ntohs(cs-&gt;cs_ip.ip_len) - hlen) {
++ /* special case for data xfer */
++ changes = SPECIAL_D;
++ cp = new_seq;
++ }
++ break;
++ }
++
++ deltaS = ntohs(ip-&gt;ip_id) - ntohs(cs-&gt;cs_ip.ip_id);
++ if (deltaS != 1) {
++ ENCODEZ(deltaS);
++ changes |= NEW_I;
++ }
++ if (th-&gt;th_flags &amp; TH_PUSH)
++ changes |= TCP_PUSH_BIT;
++ /*
++ * Grab the cksum before we overwrite it below. Then update our
++ * state with this packet's header.
++ */
++ deltaA = ntohs(th-&gt;th_sum);
++ BCOPY(ip, &amp;cs-&gt;cs_ip, hlen);
++
++ /*
++ * We want to use the original packet as our compressed packet.
++ * (cp - new_seq) is the number of bytes we need for compressed
++ * sequence numbers. In addition we need one byte for the change
++ * mask, one for the connection id and two for the tcp checksum.
++ * So, (cp - new_seq) + 4 bytes of header are needed. hlen is how
++ * many bytes of the original packet to toss so subtract the two to
++ * get the new packet size.
++ */
++ deltaS = cp - new_seq;
++ cp = (u_char *)ip;
++ if (compress_cid == 0 || comp-&gt;last_xmit != cs-&gt;cs_id) {
++ comp-&gt;last_xmit = cs-&gt;cs_id;
++ hlen -= deltaS + 4;
++ *vjhdrp = (cp += hlen);
++ *cp++ = changes | NEW_C;
++ *cp++ = cs-&gt;cs_id;
++ } else {
++ hlen -= deltaS + 3;
++ *vjhdrp = (cp += hlen);
++ *cp++ = changes;
++ }
++ *cp++ = deltaA &gt;&gt; 8;
++ *cp++ = deltaA;
++ BCOPY(new_seq, cp, deltaS);
++ INCR(vjs_compressed);
++ return (TYPE_COMPRESSED_TCP);
++
++ /*
++ * Update connection state cs &amp; send uncompressed packet (that is,
++ * a regular ip/tcp packet but with the 'conversation id' we hope
++ * to use on future compressed packets in the protocol field).
++ */
++ uncompressed:
++ BCOPY(ip, &amp;cs-&gt;cs_ip, hlen);
++ ip-&gt;ip_p = cs-&gt;cs_id;
++ comp-&gt;last_xmit = cs-&gt;cs_id;
++ return (TYPE_UNCOMPRESSED_TCP);
++}
++
++/*
++ * Called when we may have missed a packet.
++ */
++void
++vj_uncompress_err(comp)
++ struct vjcompress *comp;
++{
++ comp-&gt;flags |= VJF_TOSS;
++ INCR(vjs_errorin);
++}
++
++/*
++ * &quot;Uncompress&quot; a packet of type TYPE_UNCOMPRESSED_TCP.
++ */
++int
++vj_uncompress_uncomp(buf, buflen, comp)
++ u_char *buf;
++ int buflen;
++ struct vjcompress *comp;
++{
++ register u_int hlen;
++ register struct cstate *cs;
++ register struct ip *ip;
++
++ ip = (struct ip *) buf;
++ hlen = getip_hl(*ip) &lt;&lt; 2;
++ if (ip-&gt;ip_p &gt;= MAX_STATES
++ || hlen + sizeof(struct tcphdr) &gt; buflen
++ || (hlen += getth_off(*((struct tcphdr *)&amp;((char *)ip)[hlen])) &lt;&lt; 2)
++ &gt; buflen
++ || hlen &gt; MAX_HDR) {
++ comp-&gt;flags |= VJF_TOSS;
++ INCR(vjs_errorin);
++ return (0);
++ }
++ cs = &amp;comp-&gt;rstate[comp-&gt;last_recv = ip-&gt;ip_p];
++ comp-&gt;flags &amp;=~ VJF_TOSS;
++ ip-&gt;ip_p = IPPROTO_TCP;
++ BCOPY(ip, &amp;cs-&gt;cs_ip, hlen);
++ cs-&gt;cs_hlen = hlen;
++ INCR(vjs_uncompressedin);
++ return (1);
++}
++
++/*
++ * Uncompress a packet of type TYPE_COMPRESSED_TCP.
++ * The packet starts at buf and is of total length total_len.
++ * The first buflen bytes are at buf; this must include the entire
++ * compressed TCP/IP header. This procedure returns the length
++ * of the VJ header, with a pointer to the uncompressed IP header
++ * in *hdrp and its length in *hlenp.
++ */
++int
++vj_uncompress_tcp(buf, buflen, total_len, comp, hdrp, hlenp)
++ u_char *buf;
++ int buflen, total_len;
++ struct vjcompress *comp;
++ u_char **hdrp;
++ u_int *hlenp;
++{
++ register u_char *cp;
++ register u_int hlen, changes;
++ register struct tcphdr *th;
++ register struct cstate *cs;
++ register u_short *bp;
++ register u_int vjlen;
++ register u_int32_t tmp;
++
++ INCR(vjs_compressedin);
++ cp = buf;
++ changes = *cp++;
++ if (changes &amp; NEW_C) {
++ /* Make sure the state index is in range, then grab the state.
++ * If we have a good state index, clear the 'discard' flag. */
++ if (*cp &gt;= MAX_STATES)
++ goto bad;
++
++ comp-&gt;flags &amp;=~ VJF_TOSS;
++ comp-&gt;last_recv = *cp++;
++ } else {
++ /* this packet has an implicit state index. If we've
++ * had a line error since the last time we got an
++ * explicit state index, we have to toss the packet. */
++ if (comp-&gt;flags &amp; VJF_TOSS) {
++ INCR(vjs_tossed);
++ return (-1);
++ }
++ }
++ cs = &amp;comp-&gt;rstate[comp-&gt;last_recv];
++ hlen = getip_hl(cs-&gt;cs_ip) &lt;&lt; 2;
++ th = (struct tcphdr *)&amp;((u_char *)&amp;cs-&gt;cs_ip)[hlen];
++ th-&gt;th_sum = htons((*cp &lt;&lt; 8) | cp[1]);
++ cp += 2;
++ if (changes &amp; TCP_PUSH_BIT)
++ th-&gt;th_flags |= TH_PUSH;
++ else
++ th-&gt;th_flags &amp;=~ TH_PUSH;
++
++ switch (changes &amp; SPECIALS_MASK) {
++ case SPECIAL_I:
++ {
++ register u_int32_t i = ntohs(cs-&gt;cs_ip.ip_len) - cs-&gt;cs_hlen;
++ /* some compilers can't nest inline assembler.. */
++ tmp = ntohl(th-&gt;th_ack) + i;
++ th-&gt;th_ack = htonl(tmp);
++ tmp = ntohl(th-&gt;th_seq) + i;
++ th-&gt;th_seq = htonl(tmp);
++ }
++ break;
++
++ case SPECIAL_D:
++ /* some compilers can't nest inline assembler.. */
++ tmp = ntohl(th-&gt;th_seq) + ntohs(cs-&gt;cs_ip.ip_len) - cs-&gt;cs_hlen;
++ th-&gt;th_seq = htonl(tmp);
++ break;
++
++ default:
++ if (changes &amp; NEW_U) {
++ th-&gt;th_flags |= TH_URG;
++ DECODEU(th-&gt;th_urp);
++ } else
++ th-&gt;th_flags &amp;=~ TH_URG;
++ if (changes &amp; NEW_W)
++ DECODES(th-&gt;th_win);
++ if (changes &amp; NEW_A)
++ DECODEL(th-&gt;th_ack);
++ if (changes &amp; NEW_S)
++ DECODEL(th-&gt;th_seq);
++ break;
++ }
++ if (changes &amp; NEW_I) {
++ DECODES(cs-&gt;cs_ip.ip_id);
++ } else {
++ cs-&gt;cs_ip.ip_id = ntohs(cs-&gt;cs_ip.ip_id) + 1;
++ cs-&gt;cs_ip.ip_id = htons(cs-&gt;cs_ip.ip_id);
++ }
++
++ /*
++ * At this point, cp points to the first byte of data in the
++ * packet. Fill in the IP total length and update the IP
++ * header checksum.
++ */
++ vjlen = cp - buf;
++ buflen -= vjlen;
++ if (buflen &lt; 0)
++ /* we must have dropped some characters (crc should detect
++ * this but the old slip framing won't) */
++ goto bad;
++
++ total_len += cs-&gt;cs_hlen - vjlen;
++ cs-&gt;cs_ip.ip_len = htons(total_len);
++
++ /* recompute the ip header checksum */
++ bp = (u_short *) &amp;cs-&gt;cs_ip;
++ cs-&gt;cs_ip.ip_sum = 0;
++ for (changes = 0; hlen &gt; 0; hlen -= 2)
++ changes += *bp++;
++ changes = (changes &amp; 0xffff) + (changes &gt;&gt; 16);
++ changes = (changes &amp; 0xffff) + (changes &gt;&gt; 16);
++ cs-&gt;cs_ip.ip_sum = ~ changes;
++
++ *hdrp = (u_char *) &amp;cs-&gt;cs_ip;
++ *hlenp = cs-&gt;cs_hlen;
++ return vjlen;
++
++ bad:
++ comp-&gt;flags |= VJF_TOSS;
++ INCR(vjs_errorin);
++ return (-1);
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/modules/vjcompress.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/Makefile
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/Makefile (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/Makefile 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,51 @@
++ #******************************************************************************
++ #
++ # Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ #
++ # Copyright 2000 Mandriva
++ #
++ # This software may be freely redistributed under the terms of the GNU
++ # public license.
++ #
++ # You should have received a copy of the GNU General Public License
++ # along with this program; if not, write to the Free Software
++ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ #
++ #*****************************************************************************
++
++top_dir = ../..
++
++include $(top_dir)/Makefile.common
++
++
++TARGETS = pppd
++
++BINTARGET = ../../pppd
++
++
++all: $(TARGETS)
++
++clean:
++ rm -f *.o *.a $(BINTARGET) pppd
++
++FLAGS = -Wall -Wno-deprecated-declarations -Werror -Os -fomit-frame-pointer -DDO_BSD_COMPRESS=0 -D_linux_=1 -DHAVE_MMAP -DNO_DRAND48 -D_BSD_SOURCE -D_GNU_SOURCE
++# (blino) for gcc-4.1.1, dereferencing type-punned pointer will break strict-aliasing rules, in options.c:711
++FLAGS += -fno-strict-aliasing
++
++INCS = -I../include -I.
++
++ifeq (GLIBC, $(L))
++LIBS = -static -lcrypt
++endif
++
++
++OBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap.o md5.o ccp.o auth.o options.o demand.o utils.o sys-linux.o ipxcp.o multilink.o tdb.o tty.o
++
++
++pppd: $(OBJS)
++ $(DIET) gcc -o $@ $^ $(LIBS)
++ $(STRIPCMD) $@
++ cp -f $@ $(BINTARGET)
++
++$(OBJS): %.o: %.c
++ $(DIET) gcc $(FLAGS) $(INCS) $(INCLUDES) -c $&lt; -o $@
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/Makefile
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/Makefile.linux
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/Makefile.linux (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/Makefile.linux 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,129 @@
++#
++# pppd makefile for Linux
++# $Id: Makefile.linux 195720 2001-06-11 11:44:34Z gc $
++#
++
++# Default installation locations
++BINDIR = $(DESTDIR)/usr/sbin
++MANDIR = $(DESTDIR)/usr/man
++
++PPPDSRCS = main.c magic.c fsm.c lcp.c ipcp.c upap.c chap.c md5.c ccp.c \
++ ipxcp.c auth.c options.c sys-linux.c md4.c chap_ms.c cbcp.c \
++ demand.c utils.c multilink.c tdb.c tty.c
++HEADERS = callout.h pathnames.h patchlevel.h chap.h md5.h chap_ms.h md4.h \
++ ipxcp.h cbcp.h tdb.h
++MANPAGES = pppd.8
++PPPDOBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap.o md5.o ccp.o \
++ auth.o options.o demand.o utils.o sys-linux.o ipxcp.o multilink.o \
++ tdb.o tty.o
++
++all: pppd
++
++#
++# include dependancies if present and backup if as a header file
++ifeq (.depend,$(wildcard .depend))
++include .depend
++endif
++
++CC = gcc
++#
++COPTS = -Wall $(RPM_OPT_FLAGS)
++LIBS = -lutil
++
++ifneq ($(wildcard /usr/lib/libcrypt.*),)
++LIBS += -lcrypt
++endif
++
++# Uncomment the next 2 lines to include support for Microsoft's
++# MS-CHAP authentication protocol.
++CHAPMS=y
++USE_CRYPT=y
++ifneq ($(wildcard /usr/lib/libcrypt.*),)
++HAVE_CRYPT_H=y
++endif
++
++# Uncomment the next line to include support for PPP packet filtering.
++# This requires that the libpcap library and headers be installed
++# and that the kernel driver support PPP packet filtering, which it
++# doesn't yet.
++#FILTER=y
++
++HAS_SHADOW=y
++USE_PAM=y
++#HAVE_INET6=y
++
++PLUGIN=y
++
++INCLUDE_DIRS= -I../include
++
++COMPILE_FLAGS= -D_linux_=1 -DHAVE_PATHS_H -DIPX_CHANGE -DHAVE_MULTILINK -DHAVE_MMAP
++
++CFLAGS= $(COPTS) $(COMPILE_FLAGS) $(INCLUDE_DIRS)
++
++ifdef CHAPMS
++CFLAGS += -DCHAPMS=1
++ifndef USE_CRYPT
++LIBS := -ldes $(LIBS)
++else
++CFLAGS += -DUSE_CRYPT=1
++ifneq ($(wildcard /usr/include/crypt.h),)
++CFLAGS += -DHAVE_CRYPT_H=1
++endif
++endif
++PPPDOBJS += md4.o chap_ms.o
++ifdef MSLANMAN
++CFLAGS += -DMSLANMAN=1
++endif
++endif
++
++ifdef HAS_SHADOW
++CFLAGS += -DHAS_SHADOW
++#LIBS := -lshadow $(LIBS)
++endif
++
++# For &quot;Pluggable Authentication Modules&quot;, see ftp.redhat.com:/pub/pam/.
++ifdef USE_PAM
++CFLAGS += -DUSE_PAM
++LIBS := -lpam -ldl $(LIBS)
++endif
++
++# Lock library binary for Linux is included in 'linux' subdirectory.
++ifdef LOCKLIB
++LIBS := -llock $(LIBS)
++CFLAGS += -DLOCKLIB=1
++endif
++
++ifdef PLUGIN
++CFLAGS += -DPLUGIN
++LDFLAGS += -Wl,-E
++LIBS += -ldl
++endif
++
++ifdef FILTER
++LIBS += -lpcap
++CFLAGS += -DPPP_FILTER -I/usr/include/pcap
++endif
++
++ifdef HAVE_INET6
++ PPPDSRCS += ipv6cp.c eui64.c
++ HEADERS += ipv6cp.h eui64.h
++ PPPDOBJS += ipv6cp.o eui64.o
++ CFLAGS += -DINET6=1
++endif
++
++
++INSTALL= install
++
++install: pppd
++ mkdir -p $(BINDIR) $(MANDIR)
++ $(INSTALL) -m 555 pppd $(BINDIR)/pppd
++ $(INSTALL) -c -m 444 pppd.8 $(MANDIR)/man8
++
++pppd: $(PPPDOBJS)
++ $(CC) $(CFLAGS) $(LDFLAGS) -o pppd $(PPPDOBJS) $(LIBS)
++
++clean:
++ rm -f $(PPPDOBJS) pppd *~ #* core
++
++depend:
++ $(CPP) -M $(CFLAGS) $(PPPDSRCS) &gt;.depend
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/Makefile.linux.make
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/Makefile.linux.make (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/Makefile.linux.make 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,131 @@
++#
++# pppd makefile for Linux
++# $Id: Makefile.linux.make 195720 2001-06-11 11:44:34Z gc $
++#
++
++# Default installation locations
++BINDIR = /usr/sbin
++MANDIR = /usr/man
++
++PPPDSRCS = main.c magic.c fsm.c lcp.c ipcp.c upap.c chap.c md5.c ccp.c \
++ ipxcp.c auth.c options.c sys-linux.c md4.c chap_ms.c cbcp.c \
++ demand.c utils.c multilink.c tdb.c tty.c
++HEADERS = callout.h pathnames.h patchlevel.h chap.h md5.h chap_ms.h md4.h \
++ ipxcp.h cbcp.h tdb.h
++MANPAGES = pppd.8
++PPPDOBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap.o md5.o ccp.o \
++ auth.o options.o demand.o utils.o sys-linux.o ipxcp.o multilink.o \
++ tdb.o tty.o
++
++all: pppd
++
++#
++# include dependancies if present and backup if as a header file
++ifeq (.depend,$(wildcard .depend))
++include .depend
++endif
++
++# CC = gcc
++#
++COPTS = -O2 -pipe -Wall -g
++LIBS =
++
++ifneq ($(wildcard /usr/lib/libcrypt.*),)
++LIBS += -lcrypt
++endif
++
++# Uncomment the next 2 lines to include support for Microsoft's
++# MS-CHAP authentication protocol.
++CHAPMS=y
++USE_CRYPT=y
++ifneq ($(wildcard /usr/lib/libcrypt.*),)
++HAVE_CRYPT_H=y
++endif
++
++# Uncomment the next line to include support for PPP packet filtering.
++# This requires that the libpcap library and headers be installed
++# and that the kernel driver support PPP packet filtering, which it
++# doesn't yet.
++#FILTER=y
++
++HAS_SHADOW=y
++#USE_PAM=y
++#HAVE_INET6=y
++
++PLUGIN=y
++
++INCLUDE_DIRS= -I../include
++
++COMPILE_FLAGS= -D_linux_=1 -DHAVE_PATHS_H -DIPX_CHANGE -DHAVE_MULTILINK -DHAVE_MMAP
++
++CFLAGS= $(COPTS) $(COMPILE_FLAGS) $(INCLUDE_DIRS)
++
++ifdef CHAPMS
++CFLAGS += -DCHAPMS=1
++ifndef USE_CRYPT
++LIBS := -ldes $(LIBS)
++else
++CFLAGS += -DUSE_CRYPT=1
++ifneq ($(wildcard /usr/include/crypt.h),)
++CFLAGS += -DHAVE_CRYPT_H=1
++endif
++endif
++PPPDOBJS += md4.o chap_ms.o
++ifdef MSLANMAN
++CFLAGS += -DMSLANMAN=1
++endif
++endif
++
++ifdef HAS_SHADOW
++CFLAGS += -DHAS_SHADOW
++#LIBS := -lshadow $(LIBS)
++endif
++
++# For &quot;Pluggable Authentication Modules&quot;, see ftp.redhat.com:/pub/pam/.
++ifdef USE_PAM
++CFLAGS += -DUSE_PAM
++LIBS := -lpam -ldl $(LIBS)
++endif
++
++# Lock library binary for Linux is included in 'linux' subdirectory.
++ifdef LOCKLIB
++LIBS := -llock $(LIBS)
++CFLAGS += -DLOCKLIB=1
++endif
++
++ifdef PLUGIN
++CFLAGS += -DPLUGIN
++LDFLAGS += -Wl,-E
++LIBS += -ldl
++endif
++
++ifdef FILTER
++LIBS += -lpcap
++CFLAGS += -DPPP_FILTER -I/usr/include/pcap
++endif
++
++ifdef HAVE_INET6
++ PPPDSRCS += ipv6cp.c eui64.c
++ HEADERS += ipv6cp.h eui64.h
++ PPPDOBJS += ipv6cp.o eui64.o
++ CFLAGS += -DINET6=1
++endif
++
++
++INSTALL= install -o root
++
++install: pppd
++ mkdir -p $(BINDIR) $(MANDIR)
++ $(INSTALL) -s -c -m 555 pppd $(BINDIR)/pppd
++ if chgrp pppusers $(BINDIR)/pppd 2&gt;/dev/null; then \
++ chmod o-rx,u+s $(BINDIR)/pppd; fi
++ $(INSTALL) -c -m 444 pppd.8 $(MANDIR)/man8
++
++pppd: $(PPPDOBJS)
++ $(CC) $(CFLAGS) $(LDFLAGS) -o pppd $(PPPDOBJS) $(LIBS)
++
++clean:
++ rm -f $(PPPDOBJS) pppd *~ #* core
++
++depend:
++ $(CPP) -M $(CFLAGS) $(PPPDSRCS) &gt;.depend
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/Makefile.linux.makeopt
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/Makefile.linux.makeopt (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/Makefile.linux.makeopt 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,129 @@
++#
++# pppd makefile for Linux
++# $Id: Makefile.linux.makeopt 195720 2001-06-11 11:44:34Z gc $
++#
++
++# Default installation locations
++BINDIR = $(DESTDIR)/usr/sbin
++MANDIR = $(DESTDIR)/usr/man
++
++PPPDSRCS = main.c magic.c fsm.c lcp.c ipcp.c upap.c chap.c md5.c ccp.c \
++ ipxcp.c auth.c options.c sys-linux.c md4.c chap_ms.c cbcp.c \
++ demand.c utils.c multilink.c tdb.c tty.c
++HEADERS = callout.h pathnames.h patchlevel.h chap.h md5.h chap_ms.h md4.h \
++ ipxcp.h cbcp.h tdb.h
++MANPAGES = pppd.8
++PPPDOBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap.o md5.o ccp.o \
++ auth.o options.o demand.o utils.o sys-linux.o ipxcp.o multilink.o \
++ tdb.o tty.o
++
++all: pppd
++
++#
++# include dependancies if present and backup if as a header file
++ifeq (.depend,$(wildcard .depend))
++include .depend
++endif
++
++CC = gcc
++#
++COPTS = -O2 -pipe -Wall -g
++LIBS = -lutil
++
++ifneq ($(wildcard /usr/lib/libcrypt.*),)
++LIBS += -lcrypt
++endif
++
++# Uncomment the next 2 lines to include support for Microsoft's
++# MS-CHAP authentication protocol.
++CHAPMS=y
++USE_CRYPT=y
++ifneq ($(wildcard /usr/lib/libcrypt.*),)
++HAVE_CRYPT_H=y
++endif
++
++# Uncomment the next line to include support for PPP packet filtering.
++# This requires that the libpcap library and headers be installed
++# and that the kernel driver support PPP packet filtering, which it
++# doesn't yet.
++#FILTER=y
++
++HAS_SHADOW=y
++USE_PAM=y
++#HAVE_INET6=y
++
++PLUGIN=y
++
++INCLUDE_DIRS= -I../include
++
++COMPILE_FLAGS= -D_linux_=1 -DHAVE_PATHS_H -DIPX_CHANGE -DHAVE_MULTILINK -DHAVE_MMAP
++
++CFLAGS= $(COPTS) $(COMPILE_FLAGS) $(INCLUDE_DIRS)
++
++ifdef CHAPMS
++CFLAGS += -DCHAPMS=1
++ifndef USE_CRYPT
++LIBS := -ldes $(LIBS)
++else
++CFLAGS += -DUSE_CRYPT=1
++ifneq ($(wildcard /usr/include/crypt.h),)
++CFLAGS += -DHAVE_CRYPT_H=1
++endif
++endif
++PPPDOBJS += md4.o chap_ms.o
++ifdef MSLANMAN
++CFLAGS += -DMSLANMAN=1
++endif
++endif
++
++ifdef HAS_SHADOW
++CFLAGS += -DHAS_SHADOW
++#LIBS := -lshadow $(LIBS)
++endif
++
++# For &quot;Pluggable Authentication Modules&quot;, see ftp.redhat.com:/pub/pam/.
++ifdef USE_PAM
++CFLAGS += -DUSE_PAM
++LIBS := -lpam -ldl $(LIBS)
++endif
++
++# Lock library binary for Linux is included in 'linux' subdirectory.
++ifdef LOCKLIB
++LIBS := -llock $(LIBS)
++CFLAGS += -DLOCKLIB=1
++endif
++
++ifdef PLUGIN
++CFLAGS += -DPLUGIN
++LDFLAGS += -Wl,-E
++LIBS += -ldl
++endif
++
++ifdef FILTER
++LIBS += -lpcap
++CFLAGS += -DPPP_FILTER -I/usr/include/pcap
++endif
++
++ifdef HAVE_INET6
++ PPPDSRCS += ipv6cp.c eui64.c
++ HEADERS += ipv6cp.h eui64.h
++ PPPDOBJS += ipv6cp.o eui64.o
++ CFLAGS += -DINET6=1
++endif
++
++
++INSTALL= install
++
++install: pppd
++ mkdir -p $(BINDIR) $(MANDIR)
++ $(INSTALL) -m 555 pppd $(BINDIR)/pppd
++ $(INSTALL) -c -m 444 pppd.8 $(MANDIR)/man8
++
++pppd: $(PPPDOBJS)
++ $(CC) $(CFLAGS) $(LDFLAGS) -o pppd $(PPPDOBJS) $(LIBS)
++
++clean:
++ rm -f $(PPPDOBJS) pppd *~ #* core
++
++depend:
++ $(CPP) -M $(CFLAGS) $(PPPDSRCS) &gt;.depend
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/Makefile.sol2
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/Makefile.sol2 (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/Makefile.sol2 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,48 @@
++#
++# Makefile for pppd under Solaris 2.
++# $Id: Makefile.sol2 195720 2001-06-11 11:44:34Z gc $
++#
++
++include ../solaris/Makedefs
++
++COPTS += -xO2 -xspace -W0,-Lt
++CFLAGS = -I../include -DSVR4 -DSOL2 $(COPTS)
++LIBS = -lsocket -lnsl
++
++OBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap.o md5.o tty.o \
++ ccp.o auth.o options.o demand.o utils.o sys-solaris.o tdb.o
++
++#
++# uncomment the following to enable plugins
++#
++CFLAGS += -DPLUGIN
++LIBS += -ldl
++
++#
++# Solaris 8 and above accomodates /var/run, so uncomment the
++# following to place pppd process IDs on that location
++#
++#CFLAGS += -D_PATH_VARRUN='&quot;/var/run/&quot;'
++
++#
++# uncomment the following to enable IPv6
++#
++# Solaris 8 and on includes support for IPv6
++#
++#CFLAGS += -DINET6
++#OBJS += ipv6cp.o eui64.o
++
++#
++# Make targets
++#
++all: pppd
++
++pppd: $(OBJS)
++ $(CC) -o pppd $(OBJS) $(LIBS)
++
++install:
++ $(INSTALL) -f $(BINDIR) -m 4755 -u root pppd
++ $(INSTALL) -f $(MANDIR)/man8 -m 444 pppd.8
++
++clean:
++ rm -f $(OBJS) pppd *~ core y.tab.c y.tab.h
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/Makefile.sunos4
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/Makefile.sunos4 (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/Makefile.sunos4 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,26 @@
++#
++# Makefile for pppd under SunOS 4.
++# $Id: Makefile.sunos4 195720 2001-06-11 11:44:34Z gc $
++#
++
++include ../sunos4/Makedefs
++
++LIBS =
++
++CFLAGS = $(COPTS) -I../include -DSUNOS4 -DGIDSET_TYPE=int \
++ -DLOCK_DIR=\&quot;/usr/spool/locks\&quot;
++
++all: pppd
++
++OBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap.o md5.o ccp.o \
++ auth.o options.o demand.o utils.o sys-sunos4.o tty.o
++
++pppd: $(OBJS)
++ $(CC) -o pppd $(OBJS) $(LIBS)
++
++install:
++ $(INSTALL) -c -m 4555 pppd $(BINDIR)/pppd
++ $(INSTALL) -c -m 444 pppd.8 $(MANDIR)/man8/pppd.8
++
++clean:
++ rm -f $(OBJS) pppd *~ core
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/auth.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/auth.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/auth.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1939 @@
++/*
++ * auth.c - PPP authentication and phase control.
++ *
++ * Copyright (c) 1993 The Australian National University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by the Australian National University. The name of the University
++ * may not be used to endorse or promote products derived from this
++ * software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * Copyright (c) 1989 Carnegie Mellon University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by Carnegie Mellon University. The name of the
++ * University may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ */
++
++#define RCSID &quot;$Id: auth.c 195734 2001-06-11 14:46:02Z gc $&quot;
++
++#include &lt;stdio.h&gt;
++#include &lt;stddef.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;pwd.h&gt;
++#include &lt;grp.h&gt;
++#include &lt;string.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;sys/socket.h&gt;
++#include &lt;utmp.h&gt;
++#include &lt;fcntl.h&gt;
++#if defined(_PATH_LASTLOG) &amp;&amp; defined(_linux_)
++#include &lt;lastlog.h&gt;
++#endif
++
++#include &lt;netdb.h&gt;
++#include &lt;netinet/in.h&gt;
++#include &lt;arpa/inet.h&gt;
++
++#ifdef USE_PAM
++#include &lt;security/pam_appl.h&gt;
++#endif
++
++#ifdef HAS_SHADOW
++#include &lt;shadow.h&gt;
++#ifndef PW_PPP
++#define PW_PPP PW_LOGIN
++#endif
++#endif
++
++#include &quot;pppd.h&quot;
++#include &quot;fsm.h&quot;
++#include &quot;lcp.h&quot;
++#include &quot;ipcp.h&quot;
++#include &quot;upap.h&quot;
++#include &quot;chap.h&quot;
++#ifdef CBCP_SUPPORT
++#include &quot;cbcp.h&quot;
++#endif
++#include &quot;pathnames.h&quot;
++
++#include &lt;time.h&gt;
++
++static const char rcsid[] = RCSID;
++
++/* Bits in scan_authfile return value */
++#define NONWILD_SERVER 1
++#define NONWILD_CLIENT 2
++
++#define ISWILD(word) (word[0] == '*' &amp;&amp; word[1] == 0)
++
++/* The name by which the peer authenticated itself to us. */
++char peer_authname[MAXNAMELEN];
++
++/* Records which authentication operations haven't completed yet. */
++static int auth_pending[NUM_PPP];
++
++/* Set if we have successfully called plogin() */
++static int logged_in;
++
++/* List of addresses which the peer may use. */
++static struct permitted_ip *addresses[NUM_PPP];
++
++/* Wordlist giving addresses which the peer may use
++ without authenticating itself. */
++static struct wordlist *noauth_addrs;
++
++/* Extra options to apply, from the secrets file entry for the peer. */
++static struct wordlist *extra_options;
++
++/* Number of network protocols which we have opened. */
++static int num_np_open;
++
++/* Number of network protocols which have come up. */
++static int num_np_up;
++
++/* Set if we got the contents of passwd[] from the pap-secrets file. */
++static int passwd_from_file;
++
++/* Set if we require authentication only because we have a default route. */
++static bool default_auth;
++
++/* Hook to enable a plugin to control the idle time limit */
++int (*idle_time_hook) __P((struct ppp_idle *)) = NULL;
++
++/* Hook for a plugin to say whether we can possibly authenticate any peer */
++int (*pap_check_hook) __P((void)) = NULL;
++
++/* Hook for a plugin to check the PAP user and password */
++int (*pap_auth_hook) __P((char *user, char *passwd, char **msgp,
++ struct wordlist **paddrs,
++ struct wordlist **popts)) = NULL;
++
++/* Hook for a plugin to know about the PAP user logout */
++void (*pap_logout_hook) __P((void)) = NULL;
++
++/* Hook for a plugin to get the PAP password for authenticating us */
++int (*pap_passwd_hook) __P((char *user, char *passwd)) = NULL;
++
++/*
++ * This is used to ensure that we don't start an auth-up/down
++ * script while one is already running.
++ */
++enum script_state {
++ s_down,
++ s_up
++};
++
++static enum script_state auth_state = s_down;
++static enum script_state auth_script_state = s_down;
++static pid_t auth_script_pid = 0;
++
++static int used_login; /* peer authenticated against login database */
++
++/*
++ * Option variables.
++ */
++bool uselogin = 0; /* Use /etc/passwd for checking PAP */
++bool cryptpap = 0; /* Passwords in pap-secrets are encrypted */
++bool refuse_pap = 0; /* Don't wanna auth. ourselves with PAP */
++bool refuse_chap = 0; /* Don't wanna auth. ourselves with CHAP */
++bool usehostname = 0; /* Use hostname for our_name */
++bool auth_required = 0; /* Always require authentication from peer */
++bool allow_any_ip = 0; /* Allow peer to use any IP address */
++bool explicit_remote = 0; /* User specified explicit remote name */
++char remote_name[MAXNAMELEN]; /* Peer's name for authentication */
++
++static char *uafname; /* name of most recent +ua file */
++
++/* Bits in auth_pending[] */
++#define PAP_WITHPEER 1
++#define PAP_PEER 2
++#define CHAP_WITHPEER 4
++#define CHAP_PEER 8
++
++extern char *crypt __P((const char *, const char *));
++
++/* Prototypes for procedures local to this file. */
++
++static void network_phase __P((int));
++static void check_idle __P((void *));
++static void connect_time_expired __P((void *));
++static int plogin __P((char *, char *, char **));
++static void plogout __P((void));
++static int null_login __P((int));
++static int get_pap_passwd __P((char *));
++static int have_pap_secret __P((int *));
++static int have_chap_secret __P((char *, char *, int, int *));
++static int ip_addr_check __P((u_int32_t, struct permitted_ip *));
++static int scan_authfile __P((FILE *, char *, char *, char *,
++ struct wordlist **, struct wordlist **,
++ char *));
++static void free_wordlist __P((struct wordlist *));
++static void auth_script __P((char *));
++static void auth_script_done __P((void *));
++static void set_allowed_addrs __P((int, struct wordlist *, struct wordlist *));
++static int some_ip_ok __P((struct wordlist *));
++static int setupapfile __P((char **));
++static int privgroup __P((char **));
++static int set_noauth_addr __P((char **));
++static void check_access __P((FILE *, char *));
++static int wordlist_count __P((struct wordlist *));
++
++/*
++ * Authentication-related options.
++ */
++option_t auth_options[] = {
++ { &quot;auth&quot;, o_bool, &amp;auth_required,
++ &quot;Require authentication from peer&quot;, OPT_PRIO | 1 },
++ { &quot;noauth&quot;, o_bool, &amp;auth_required,
++ &quot;Don't require peer to authenticate&quot;, OPT_PRIOSUB | OPT_PRIV,
++ &amp;allow_any_ip },
++ { &quot;require-pap&quot;, o_bool, &amp;lcp_wantoptions[0].neg_upap,
++ &quot;Require PAP authentication from peer&quot;,
++ OPT_PRIOSUB | 1, &amp;auth_required },
++ { &quot;+pap&quot;, o_bool, &amp;lcp_wantoptions[0].neg_upap,
++ &quot;Require PAP authentication from peer&quot;,
++ OPT_ALIAS | OPT_PRIOSUB | 1, &amp;auth_required },
++ { &quot;require-chap&quot;, o_bool, &amp;lcp_wantoptions[0].neg_chap,
++ &quot;Require CHAP authentication from peer&quot;,
++ OPT_PRIOSUB | 1, &amp;auth_required },
++ { &quot;+chap&quot;, o_bool, &amp;lcp_wantoptions[0].neg_chap,
++ &quot;Require CHAP authentication from peer&quot;,
++ OPT_ALIAS | OPT_PRIOSUB | 1, &amp;auth_required },
++
++ { &quot;refuse-pap&quot;, o_bool, &amp;refuse_pap,
++ &quot;Don't agree to auth to peer with PAP&quot;, 1 },
++ { &quot;-pap&quot;, o_bool, &amp;refuse_pap,
++ &quot;Don't allow PAP authentication with peer&quot;, OPT_ALIAS | 1 },
++
++ { &quot;refuse-chap&quot;, o_bool, &amp;refuse_chap,
++ &quot;Don't agree to auth to peer with CHAP&quot;, 1 },
++ { &quot;-chap&quot;, o_bool, &amp;refuse_chap,
++ &quot;Don't allow CHAP authentication with peer&quot;, OPT_ALIAS | 1 },
++
++ { &quot;name&quot;, o_string, our_name,
++ &quot;Set local name for authentication&quot;,
++ OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, MAXNAMELEN },
++
++ { &quot;+ua&quot;, o_special, (void *)setupapfile,
++ &quot;Get PAP user and password from file&quot;,
++ OPT_PRIO | OPT_A2STRVAL, &amp;uafname },
++
++ { &quot;user&quot;, o_string, user,
++ &quot;Set name for auth with peer&quot;, OPT_PRIO | OPT_STATIC, NULL, MAXNAMELEN },
++
++ { &quot;password&quot;, o_string, passwd,
++ &quot;Password for authenticating us to the peer&quot;,
++ OPT_PRIO | OPT_STATIC | OPT_HIDE, NULL, MAXSECRETLEN },
++
++ { &quot;usehostname&quot;, o_bool, &amp;usehostname,
++ &quot;Must use hostname for authentication&quot;, 1 },
++
++ { &quot;remotename&quot;, o_string, remote_name,
++ &quot;Set remote name for authentication&quot;, OPT_PRIO | OPT_STATIC,
++ &amp;explicit_remote, MAXNAMELEN },
++
++ { &quot;login&quot;, o_bool, &amp;uselogin,
++ &quot;Use system password database for PAP&quot;, 1 },
++
++ { &quot;papcrypt&quot;, o_bool, &amp;cryptpap,
++ &quot;PAP passwords are encrypted&quot;, 1 },
++
++ { &quot;privgroup&quot;, o_special, (void *)privgroup,
++ &quot;Allow group members to use privileged options&quot;, OPT_PRIV | OPT_A2LIST },
++
++ { &quot;allow-ip&quot;, o_special, (void *)set_noauth_addr,
++ &quot;Set IP address(es) which can be used without authentication&quot;,
++ OPT_PRIV | OPT_A2LIST },
++
++ { NULL }
++};
++
++/*
++ * setupapfile - specifies UPAP info for authenticating with peer.
++ */
++static int
++setupapfile(argv)
++ char **argv;
++{
++ FILE *ufile;
++ int l;
++ char u[MAXNAMELEN], p[MAXSECRETLEN];
++ char *fname;
++
++ lcp_allowoptions[0].neg_upap = 1;
++
++ /* open user info file */
++ fname = strdup(*argv);
++ if (fname == NULL)
++ novm(&quot;+ua file name&quot;);
++ seteuid(getuid());
++ ufile = fopen(fname, &quot;r&quot;);
++ seteuid(0);
++ if (ufile == NULL) {
++ option_error(&quot;unable to open user login data file %s&quot;, fname);
++ return 0;
++ }
++ check_access(ufile, fname);
++ uafname = fname;
++
++ /* get username */
++ if (fgets(u, MAXNAMELEN - 1, ufile) == NULL
++ || fgets(p, MAXSECRETLEN - 1, ufile) == NULL){
++ option_error(&quot;unable to read user login data file %s&quot;, fname);
++ return 0;
++ }
++ fclose(ufile);
++
++ /* get rid of newlines */
++ l = strlen(u);
++ if (l &gt; 0 &amp;&amp; u[l-1] == '\n')
++ u[l-1] = 0;
++ l = strlen(p);
++ if (l &gt; 0 &amp;&amp; p[l-1] == '\n')
++ p[l-1] = 0;
++
++ if (override_value(&quot;user&quot;, option_priority, fname))
++ strlcpy(user, u, sizeof(user));
++ if (override_value(&quot;passwd&quot;, option_priority, fname))
++ strlcpy(passwd, p, sizeof(passwd));
++
++ return (1);
++}
++
++
++/*
++ * privgroup - allow members of the group to have privileged access.
++ */
++static int
++privgroup(argv)
++ char **argv;
++{
++ struct group *g;
++ int i;
++
++ g = getgrnam(*argv);
++ if (g == 0) {
++ option_error(&quot;group %s is unknown&quot;, *argv);
++ return 0;
++ }
++ for (i = 0; i &lt; ngroups; ++i) {
++ if (groups[i] == g-&gt;gr_gid) {
++ privileged = 1;
++ break;
++ }
++ }
++ return 1;
++}
++
++
++/*
++ * set_noauth_addr - set address(es) that can be used without authentication.
++ * Equivalent to specifying an entry like `&quot;&quot; * &quot;&quot; addr' in pap-secrets.
++ */
++static int
++set_noauth_addr(argv)
++ char **argv;
++{
++ char *addr = *argv;
++ int l = strlen(addr) + 1;
++ struct wordlist *wp;
++
++ wp = (struct wordlist *) malloc(sizeof(struct wordlist) + l);
++ if (wp == NULL)
++ novm(&quot;allow-ip argument&quot;);
++ wp-&gt;word = (char *) (wp + 1);
++ wp-&gt;next = noauth_addrs;
++ BCOPY(addr, wp-&gt;word, l);
++ noauth_addrs = wp;
++ return 1;
++}
++
++
++/*
++ * An Open on LCP has requested a change from Dead to Establish phase.
++ * Do what's necessary to bring the physical layer up.
++ */
++void
++link_required(unit)
++ int unit;
++{
++}
++
++/*
++ * LCP has terminated the link; go to the Dead phase and take the
++ * physical layer down.
++ */
++void
++link_terminated(unit)
++ int unit;
++{
++ if (phase == PHASE_DEAD)
++ return;
++ if (pap_logout_hook) {
++ pap_logout_hook();
++ } else {
++ if (logged_in)
++ plogout();
++ }
++ new_phase(PHASE_DEAD);
++ notice(&quot;Connection terminated.&quot;);
++}
++
++/*
++ * LCP has gone down; it will either die or try to re-establish.
++ */
++void
++link_down(unit)
++ int unit;
++{
++ int i;
++ struct protent *protp;
++
++ auth_state = s_down;
++ if (auth_script_state == s_up &amp;&amp; auth_script_pid == 0) {
++ update_link_stats(unit);
++ auth_script_state = s_down;
++ auth_script(_PATH_AUTHDOWN);
++ }
++ for (i = 0; (protp = protocols[i]) != NULL; ++i) {
++ if (!protp-&gt;enabled_flag)
++ continue;
++ if (protp-&gt;protocol != PPP_LCP &amp;&amp; protp-&gt;lowerdown != NULL)
++ (*protp-&gt;lowerdown)(unit);
++ if (protp-&gt;protocol &lt; 0xC000 &amp;&amp; protp-&gt;close != NULL)
++ (*protp-&gt;close)(unit, &quot;LCP down&quot;);
++ }
++ num_np_open = 0;
++ num_np_up = 0;
++ if (phase != PHASE_DEAD)
++ new_phase(PHASE_TERMINATE);
++}
++
++/*
++ * The link is established.
++ * Proceed to the Dead, Authenticate or Network phase as appropriate.
++ */
++void
++link_established(unit)
++ int unit;
++{
++ int auth;
++ lcp_options *wo = &amp;lcp_wantoptions[unit];
++ lcp_options *go = &amp;lcp_gotoptions[unit];
++ lcp_options *ho = &amp;lcp_hisoptions[unit];
++ int i;
++ struct protent *protp;
++
++ /*
++ * Tell higher-level protocols that LCP is up.
++ */
++ for (i = 0; (protp = protocols[i]) != NULL; ++i)
++ if (protp-&gt;protocol != PPP_LCP &amp;&amp; protp-&gt;enabled_flag
++ &amp;&amp; protp-&gt;lowerup != NULL)
++ (*protp-&gt;lowerup)(unit);
++
++ if (auth_required &amp;&amp; !(go-&gt;neg_chap || go-&gt;neg_upap)) {
++ /*
++ * We wanted the peer to authenticate itself, and it refused:
++ * if we have some address(es) it can use without auth, fine,
++ * otherwise treat it as though it authenticated with PAP using
++ * a username * of &quot;&quot; and a password of &quot;&quot;. If that's not OK,
++ * boot it out.
++ */
++ if (noauth_addrs != NULL) {
++ set_allowed_addrs(unit, NULL, NULL);
++ } else if (!wo-&gt;neg_upap || uselogin || !null_login(unit)) {
++ warn(&quot;peer refused to authenticate: terminating link&quot;);
++ lcp_close(unit, &quot;peer refused to authenticate&quot;);
++ status = EXIT_PEER_AUTH_FAILED;
++ return;
++ }
++ }
++
++ new_phase(PHASE_AUTHENTICATE);
++ used_login = 0;
++ auth = 0;
++ if (go-&gt;neg_chap) {
++ ChapAuthPeer(unit, our_name, go-&gt;chap_mdtype);
++ auth |= CHAP_PEER;
++ } else if (go-&gt;neg_upap) {
++ upap_authpeer(unit);
++ auth |= PAP_PEER;
++ }
++ if (ho-&gt;neg_chap) {
++ ChapAuthWithPeer(unit, user, ho-&gt;chap_mdtype);
++ auth |= CHAP_WITHPEER;
++ } else if (ho-&gt;neg_upap) {
++ if (passwd[0] == 0) {
++ passwd_from_file = 1;
++ if (!get_pap_passwd(passwd))
++ error(&quot;No secret found for PAP login&quot;);
++ }
++ upap_authwithpeer(unit, user, passwd);
++ auth |= PAP_WITHPEER;
++ }
++ auth_pending[unit] = auth;
++
++ if (!auth)
++ network_phase(unit);
++}
++
++/*
++ * Proceed to the network phase.
++ */
++static void
++network_phase(unit)
++ int unit;
++{
++ lcp_options *go = &amp;lcp_gotoptions[unit];
++
++ /*
++ * If the peer had to authenticate, run the auth-up script now.
++ */
++ if (go-&gt;neg_chap || go-&gt;neg_upap) {
++ auth_state = s_up;
++ if (auth_script_state == s_down &amp;&amp; auth_script_pid == 0) {
++ auth_script_state = s_up;
++ auth_script(_PATH_AUTHUP);
++ }
++ }
++
++#ifdef CBCP_SUPPORT
++ /*
++ * If we negotiated callback, do it now.
++ */
++ if (go-&gt;neg_cbcp) {
++ new_phase(PHASE_CALLBACK);
++ (*cbcp_protent.open)(unit);
++ return;
++ }
++#endif
++
++ /*
++ * Process extra options from the secrets file
++ */
++ if (extra_options) {
++ options_from_list(extra_options, 1);
++ free_wordlist(extra_options);
++ extra_options = 0;
++ }
++ start_networks();
++}
++
++void
++start_networks()
++{
++ int i;
++ struct protent *protp;
++
++ new_phase(PHASE_NETWORK);
++
++#ifdef HAVE_MULTILINK
++ if (multilink) {
++ if (mp_join_bundle()) {
++ if (updetach &amp;&amp; !nodetach)
++ detach();
++ return;
++ }
++ }
++#endif /* HAVE_MULTILINK */
++
++#ifdef PPP_FILTER
++ if (!demand)
++ set_filters(&amp;pass_filter, &amp;active_filter);
++#endif
++ for (i = 0; (protp = protocols[i]) != NULL; ++i)
++ if (protp-&gt;protocol &lt; 0xC000 &amp;&amp; protp-&gt;enabled_flag
++ &amp;&amp; protp-&gt;open != NULL) {
++ (*protp-&gt;open)(0);
++ if (protp-&gt;protocol != PPP_CCP)
++ ++num_np_open;
++ }
++
++ if (num_np_open == 0)
++ /* nothing to do */
++ lcp_close(0, &quot;No network protocols running&quot;);
++}
++
++/*
++ * The peer has failed to authenticate himself using `protocol'.
++ */
++void
++auth_peer_fail(unit, protocol)
++ int unit, protocol;
++{
++ /*
++ * Authentication failure: take the link down
++ */
++ lcp_close(unit, &quot;Authentication failed&quot;);
++ status = EXIT_PEER_AUTH_FAILED;
++}
++
++/*
++ * The peer has been successfully authenticated using `protocol'.
++ */
++void
++auth_peer_success(unit, protocol, name, namelen)
++ int unit, protocol;
++ char *name;
++ int namelen;
++{
++ int bit;
++
++ switch (protocol) {
++ case PPP_CHAP:
++ bit = CHAP_PEER;
++ break;
++ case PPP_PAP:
++ bit = PAP_PEER;
++ break;
++ default:
++ warn(&quot;auth_peer_success: unknown protocol %x&quot;, protocol);
++ return;
++ }
++
++ /*
++ * Save the authenticated name of the peer for later.
++ */
++ if (namelen &gt; sizeof(peer_authname) - 1)
++ namelen = sizeof(peer_authname) - 1;
++ BCOPY(name, peer_authname, namelen);
++ peer_authname[namelen] = 0;
++ script_setenv(&quot;PEERNAME&quot;, peer_authname, 0);
++
++ /*
++ * If there is no more authentication still to be done,
++ * proceed to the network (or callback) phase.
++ */
++ if ((auth_pending[unit] &amp;= ~bit) == 0)
++ network_phase(unit);
++}
++
++/*
++ * We have failed to authenticate ourselves to the peer using `protocol'.
++ */
++void
++auth_withpeer_fail(unit, protocol)
++ int unit, protocol;
++{
++ if (passwd_from_file)
++ BZERO(passwd, MAXSECRETLEN);
++ /*
++ * We've failed to authenticate ourselves to our peer.
++ * Some servers keep sending CHAP challenges, but there
++ * is no point in persisting without any way to get updated
++ * authentication secrets.
++ */
++ lcp_close(unit, &quot;Failed to authenticate ourselves to peer&quot;);
++ status = EXIT_AUTH_TOPEER_FAILED;
++}
++
++/*
++ * We have successfully authenticated ourselves with the peer using `protocol'.
++ */
++void
++auth_withpeer_success(unit, protocol)
++ int unit, protocol;
++{
++ int bit;
++
++ switch (protocol) {
++ case PPP_CHAP:
++ bit = CHAP_WITHPEER;
++ break;
++ case PPP_PAP:
++ if (passwd_from_file)
++ BZERO(passwd, MAXSECRETLEN);
++ bit = PAP_WITHPEER;
++ break;
++ default:
++ warn(&quot;auth_withpeer_success: unknown protocol %x&quot;, protocol);
++ bit = 0;
++ }
++
++ /*
++ * If there is no more authentication still being done,
++ * proceed to the network (or callback) phase.
++ */
++ if ((auth_pending[unit] &amp;= ~bit) == 0)
++ network_phase(unit);
++}
++
++
++/*
++ * np_up - a network protocol has come up.
++ */
++void
++np_up(unit, proto)
++ int unit, proto;
++{
++ int tlim;
++
++ if (num_np_up == 0) {
++ /*
++ * At this point we consider that the link has come up successfully.
++ */
++ status = EXIT_OK;
++ unsuccess = 0;
++ new_phase(PHASE_RUNNING);
++
++ if (idle_time_hook != 0)
++ tlim = (*idle_time_hook)(NULL);
++ else
++ tlim = idle_time_limit;
++ if (tlim &gt; 0)
++ TIMEOUT(check_idle, NULL, tlim);
++
++ /*
++ * Set a timeout to close the connection once the maximum
++ * connect time has expired.
++ */
++ if (maxconnect &gt; 0)
++ TIMEOUT(connect_time_expired, 0, maxconnect);
++
++ /*
++ * Detach now, if the updetach option was given.
++ */
++ if (updetach &amp;&amp; !nodetach)
++ detach();
++ }
++ ++num_np_up;
++}
++
++/*
++ * np_down - a network protocol has gone down.
++ */
++void
++np_down(unit, proto)
++ int unit, proto;
++{
++ if (--num_np_up == 0) {
++ UNTIMEOUT(check_idle, NULL);
++ new_phase(PHASE_NETWORK);
++ }
++}
++
++/*
++ * np_finished - a network protocol has finished using the link.
++ */
++void
++np_finished(unit, proto)
++ int unit, proto;
++{
++ if (--num_np_open &lt;= 0) {
++ /* no further use for the link: shut up shop. */
++ lcp_close(0, &quot;No network protocols running&quot;);
++ }
++}
++
++/*
++ * check_idle - check whether the link has been idle for long
++ * enough that we can shut it down.
++ */
++static void
++check_idle(arg)
++ void *arg;
++{
++ struct ppp_idle idle;
++ time_t itime;
++ int tlim;
++
++ if (!get_idle_time(0, &amp;idle))
++ return;
++ if (idle_time_hook != 0) {
++ tlim = idle_time_hook(&amp;idle);
++ } else {
++ itime = MIN(idle.xmit_idle, idle.recv_idle);
++ tlim = idle_time_limit - itime;
++ }
++ if (tlim &lt;= 0) {
++ /* link is idle: shut it down. */
++ notice(&quot;Terminating connection due to lack of activity.&quot;);
++ lcp_close(0, &quot;Link inactive&quot;);
++ need_holdoff = 0;
++ status = EXIT_IDLE_TIMEOUT;
++ } else {
++ TIMEOUT(check_idle, NULL, tlim);
++ }
++}
++
++/*
++ * connect_time_expired - log a message and close the connection.
++ */
++static void
++connect_time_expired(arg)
++ void *arg;
++{
++ info(&quot;Connect time expired&quot;);
++ lcp_close(0, &quot;Connect time expired&quot;); /* Close connection */
++ status = EXIT_CONNECT_TIME;
++}
++
++/*
++ * auth_check_options - called to check authentication options.
++ */
++void
++auth_check_options()
++{
++ lcp_options *wo = &amp;lcp_wantoptions[0];
++ int can_auth;
++ int lacks_ip;
++
++ /* Default our_name to hostname, and user to our_name */
++ if (our_name[0] == 0 || usehostname)
++ strlcpy(our_name, hostname, sizeof(our_name));
++ if (user[0] == 0)
++ strlcpy(user, our_name, sizeof(user));
++
++ /*
++ * If we have a default route, require the peer to authenticate
++ * unless the noauth option was given or the real user is root.
++ */
++ if (!auth_required &amp;&amp; !allow_any_ip &amp;&amp; have_route_to(0) &amp;&amp; !privileged) {
++ auth_required = 1;
++ default_auth = 1;
++ }
++
++ /* If authentication is required, ask peer for CHAP or PAP. */
++ if (auth_required) {
++ allow_any_ip = 0;
++ if (!wo-&gt;neg_chap &amp;&amp; !wo-&gt;neg_upap) {
++ wo-&gt;neg_chap = 1;
++ wo-&gt;neg_upap = 1;
++ }
++ } else {
++ wo-&gt;neg_chap = 0;
++ wo-&gt;neg_upap = 0;
++ }
++
++ /*
++ * Check whether we have appropriate secrets to use
++ * to authenticate the peer.
++ */
++ lacks_ip = 0;
++ can_auth = wo-&gt;neg_upap &amp;&amp; (uselogin || have_pap_secret(&amp;lacks_ip));
++ if (!can_auth &amp;&amp; wo-&gt;neg_chap) {
++ can_auth = have_chap_secret((explicit_remote? remote_name: NULL),
++ our_name, 1, &amp;lacks_ip);
++ }
++
++ if (auth_required &amp;&amp; !can_auth &amp;&amp; noauth_addrs == NULL) {
++ if (default_auth) {
++ option_error(
++&quot;By default the remote system is required to authenticate itself&quot;);
++ option_error(
++&quot;(because this system has a default route to the internet)&quot;);
++ } else if (explicit_remote)
++ option_error(
++&quot;The remote system (%s) is required to authenticate itself&quot;,
++ remote_name);
++ else
++ option_error(
++&quot;The remote system is required to authenticate itself&quot;);
++ option_error(
++&quot;but I couldn't find any suitable secret (password) for it to use to do so.&quot;);
++ if (lacks_ip)
++ option_error(
++&quot;(None of the available passwords would let it use an IP address.)&quot;);
++
++ exit(1);
++ }
++}
++
++/*
++ * auth_reset - called when LCP is starting negotiations to recheck
++ * authentication options, i.e. whether we have appropriate secrets
++ * to use for authenticating ourselves and/or the peer.
++ */
++void
++auth_reset(unit)
++ int unit;
++{
++ lcp_options *go = &amp;lcp_gotoptions[unit];
++ lcp_options *ao = &amp;lcp_allowoptions[0];
++
++ ao-&gt;neg_upap = !refuse_pap &amp;&amp; (passwd[0] != 0 || get_pap_passwd(NULL));
++ ao-&gt;neg_chap = !refuse_chap
++ &amp;&amp; (passwd[0] != 0
++ || have_chap_secret(user, (explicit_remote? remote_name: NULL),
++ 0, NULL));
++
++ if (go-&gt;neg_upap &amp;&amp; !uselogin &amp;&amp; !have_pap_secret(NULL))
++ go-&gt;neg_upap = 0;
++ if (go-&gt;neg_chap) {
++ if (!have_chap_secret((explicit_remote? remote_name: NULL),
++ our_name, 1, NULL))
++ go-&gt;neg_chap = 0;
++ }
++}
++
++
++/*
++ * check_passwd - Check the user name and passwd against the PAP secrets
++ * file. If requested, also check against the system password database,
++ * and login the user if OK.
++ *
++ * returns:
++ * UPAP_AUTHNAK: Authentication failed.
++ * UPAP_AUTHACK: Authentication succeeded.
++ * In either case, msg points to an appropriate message.
++ */
++int
++check_passwd(unit, auser, userlen, apasswd, passwdlen, msg)
++ int unit;
++ char *auser;
++ int userlen;
++ char *apasswd;
++ int passwdlen;
++ char **msg;
++{
++ int ret;
++ char *filename;
++ FILE *f;
++ struct wordlist *addrs = NULL, *opts = NULL;
++ char passwd[256], user[256];
++ char secret[MAXWORDLEN];
++ static int attempts = 0;
++
++ /*
++ * Make copies of apasswd and auser, then null-terminate them.
++ * If there are unprintable characters in the password, make
++ * them visible.
++ */
++ slprintf(passwd, sizeof(passwd), &quot;%.*v&quot;, passwdlen, apasswd);
++ slprintf(user, sizeof(user), &quot;%.*v&quot;, userlen, auser);
++ *msg = &quot;&quot;;
++
++ /*
++ * Check if a plugin wants to handle this.
++ */
++ if (pap_auth_hook) {
++ ret = (*pap_auth_hook)(user, passwd, msg, &amp;addrs, &amp;opts);
++ if (ret &gt;= 0) {
++ if (ret)
++ set_allowed_addrs(unit, addrs, opts);
++ BZERO(passwd, sizeof(passwd));
++ if (addrs != 0)
++ free_wordlist(addrs);
++ return ret? UPAP_AUTHACK: UPAP_AUTHNAK;
++ }
++ }
++
++ /*
++ * Open the file of pap secrets and scan for a suitable secret
++ * for authenticating this user.
++ */
++ filename = _PATH_UPAPFILE;
++ addrs = opts = NULL;
++ ret = UPAP_AUTHNAK;
++ f = fopen(filename, &quot;r&quot;);
++ if (f == NULL) {
++ error(&quot;Can't open PAP password file %s: %m&quot;, filename);
++
++ } else {
++ check_access(f, filename);
++ if (scan_authfile(f, user, our_name, secret, &amp;addrs, &amp;opts, filename) &lt; 0) {
++ warn(&quot;no PAP secret found for %s&quot;, user);
++ } else {
++ /*
++ * If the secret is &quot;@login&quot;, it means to check
++ * the password against the login database.
++ */
++ int login_secret = strcmp(secret, &quot;@login&quot;) == 0;
++ ret = UPAP_AUTHACK;
++ if (uselogin || login_secret) {
++ /* login option or secret is @login */
++ ret = plogin(user, passwd, msg);
++ if (ret == UPAP_AUTHNAK)
++ warn(&quot;PAP login failure for %s&quot;, user);
++ else
++ used_login = 1;
++ }
++ if (secret[0] != 0 &amp;&amp; !login_secret) {
++ /* password given in pap-secrets - must match */
++ if ((cryptpap || strcmp(passwd, secret) != 0)
++ &amp;&amp; strcmp(crypt(passwd, secret), secret) != 0) {
++ ret = UPAP_AUTHNAK;
++ warn(&quot;PAP authentication failure for %s&quot;, user);
++ }
++ }
++ }
++ fclose(f);
++ }
++
++ if (ret == UPAP_AUTHNAK) {
++ if (**msg == 0)
++ *msg = &quot;Login incorrect&quot;;
++ /*
++ * XXX can we ever get here more than once??
++ * Frustrate passwd stealer programs.
++ * Allow 10 tries, but start backing off after 3 (stolen from login).
++ * On 10'th, drop the connection.
++ */
++ if (attempts++ &gt;= 10) {
++ warn(&quot;%d LOGIN FAILURES ON %s, %s&quot;, attempts, devnam, user);
++ lcp_close(unit, &quot;login failed&quot;);
++ }
++ if (attempts &gt; 3)
++ sleep((u_int) (attempts - 3) * 5);
++ if (opts != NULL)
++ free_wordlist(opts);
++
++ } else {
++ attempts = 0; /* Reset count */
++ if (**msg == 0)
++ *msg = &quot;Login ok&quot;;
++ set_allowed_addrs(unit, addrs, opts);
++ }
++
++ if (addrs != NULL)
++ free_wordlist(addrs);
++ BZERO(passwd, sizeof(passwd));
++ BZERO(secret, sizeof(secret));
++
++ return ret;
++}
++
++/*
++ * This function is needed for PAM.
++ */
++
++#ifdef USE_PAM
++/* Static variables used to communicate between the conversation function
++ * and the server_login function
++ */
++static char *PAM_username;
++static char *PAM_password;
++static int PAM_error = 0;
++static pam_handle_t *pamh = NULL;
++
++/* PAM conversation function
++ * Here we assume (for now, at least) that echo on means login name, and
++ * echo off means password.
++ */
++
++static int PAM_conv (int num_msg, const struct pam_message **msg,
++ struct pam_response **resp, void *appdata_ptr)
++{
++ int replies = 0;
++ struct pam_response *reply = NULL;
++
++#define COPY_STRING(s) (s) ? strdup(s) : NULL
++
++ reply = malloc(sizeof(struct pam_response) * num_msg);
++ if (!reply) return PAM_CONV_ERR;
++
++ for (replies = 0; replies &lt; num_msg; replies++) {
++ switch (msg[replies]-&gt;msg_style) {
++ case PAM_PROMPT_ECHO_ON:
++ reply[replies].resp_retcode = PAM_SUCCESS;
++ reply[replies].resp = COPY_STRING(PAM_username);
++ /* PAM frees resp */
++ break;
++ case PAM_PROMPT_ECHO_OFF:
++ reply[replies].resp_retcode = PAM_SUCCESS;
++ reply[replies].resp = COPY_STRING(PAM_password);
++ /* PAM frees resp */
++ break;
++ case PAM_TEXT_INFO:
++ /* fall through */
++ case PAM_ERROR_MSG:
++ /* ignore it, but pam still wants a NULL response... */
++ reply[replies].resp_retcode = PAM_SUCCESS;
++ reply[replies].resp = NULL;
++ break;
++ default:
++ /* Must be an error of some sort... */
++ free (reply);
++ PAM_error = 1;
++ return PAM_CONV_ERR;
++ }
++ }
++ *resp = reply;
++ return PAM_SUCCESS;
++}
++
++static struct pam_conv PAM_conversation = {
++ &amp;PAM_conv,
++ NULL
++};
++#endif /* USE_PAM */
++
++/*
++ * plogin - Check the user name and password against the system
++ * password database, and login the user if OK.
++ *
++ * returns:
++ * UPAP_AUTHNAK: Login failed.
++ * UPAP_AUTHACK: Login succeeded.
++ * In either case, msg points to an appropriate message.
++ */
++
++static int
++plogin(user, passwd, msg)
++ char *user;
++ char *passwd;
++ char **msg;
++{
++ char *tty;
++
++#ifdef USE_PAM
++ int pam_error;
++
++ pam_error = pam_start (&quot;ppp&quot;, user, &amp;PAM_conversation, &amp;pamh);
++ if (pam_error != PAM_SUCCESS) {
++ *msg = (char *) pam_strerror (pamh, pam_error);
++ reopen_log();
++ return UPAP_AUTHNAK;
++ }
++ /*
++ * Define the fields for the credential validation
++ */
++
++ PAM_username = user;
++ PAM_password = passwd;
++ PAM_error = 0;
++ pam_set_item (pamh, PAM_TTY, devnam); /* this might be useful to some modules */
++
++ /*
++ * Validate the user
++ */
++ pam_error = pam_authenticate (pamh, PAM_SILENT);
++ if (pam_error == PAM_SUCCESS &amp;&amp; !PAM_error) {
++ pam_error = pam_acct_mgmt (pamh, PAM_SILENT);
++ if (pam_error == PAM_SUCCESS)
++ pam_error = pam_open_session (pamh, PAM_SILENT);
++ }
++
++ *msg = (char *) pam_strerror (pamh, pam_error);
++
++ /*
++ * Clean up the mess
++ */
++ reopen_log(); /* apparently the PAM stuff does closelog() */
++ PAM_username = NULL;
++ PAM_password = NULL;
++ if (pam_error != PAM_SUCCESS)
++ return UPAP_AUTHNAK;
++#else /* #ifdef USE_PAM */
++
++/*
++ * Use the non-PAM methods directly
++ */
++
++#ifdef HAS_SHADOW
++ struct spwd *spwd;
++ struct spwd *getspnam();
++#endif
++ struct passwd *pw = getpwnam(user);
++
++ endpwent();
++ if (pw == NULL)
++ return (UPAP_AUTHNAK);
++
++#ifdef HAS_SHADOW
++ spwd = getspnam(user);
++ endspent();
++ if (spwd) {
++ /* check the age of the password entry */
++ long now = time(NULL) / 86400L;
++
++ if ((spwd-&gt;sp_expire &gt; 0 &amp;&amp; now &gt;= spwd-&gt;sp_expire)
++ || ((spwd-&gt;sp_max &gt;= 0 &amp;&amp; spwd-&gt;sp_max &lt; 10000)
++ &amp;&amp; spwd-&gt;sp_lstchg &gt;= 0
++ &amp;&amp; now &gt;= spwd-&gt;sp_lstchg + spwd-&gt;sp_max)) {
++ warn(&quot;Password for %s has expired&quot;, user);
++ return (UPAP_AUTHNAK);
++ }
++ pw-&gt;pw_passwd = spwd-&gt;sp_pwdp;
++ }
++#endif
++
++ /*
++ * If no passwd, don't let them login.
++ */
++ if (pw-&gt;pw_passwd == NULL || strlen(pw-&gt;pw_passwd) &lt; 2
++ || strcmp(crypt(passwd, pw-&gt;pw_passwd), pw-&gt;pw_passwd) != 0)
++ return (UPAP_AUTHNAK);
++
++#endif /* #ifdef USE_PAM */
++
++ /*
++ * Write a wtmp entry for this user.
++ */
++
++ tty = devnam;
++ if (strncmp(tty, &quot;/dev/&quot;, 5) == 0)
++ tty += 5;
++// logwtmp(tty, user, remote_name); /* Add wtmp login entry */
++
++#if defined(_PATH_LASTLOG) &amp;&amp; !defined(USE_PAM)
++ if (pw != (struct passwd *)NULL) {
++ struct lastlog ll;
++ int fd;
++
++ if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) &gt;= 0) {
++ (void)lseek(fd, (off_t)(pw-&gt;pw_uid * sizeof(ll)), SEEK_SET);
++ memset((void *)&amp;ll, 0, sizeof(ll));
++ (void)time(&amp;ll.ll_time);
++ (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
++ (void)write(fd, (char *)&amp;ll, sizeof(ll));
++ (void)close(fd);
++ }
++ }
++#endif /* _PATH_LASTLOG and not USE_PAM */
++
++ info(&quot;user %s logged in&quot;, user);
++ logged_in = 1;
++
++ return (UPAP_AUTHACK);
++}
++
++/*
++ * plogout - Logout the user.
++ */
++static void
++plogout()
++{
++#ifdef USE_PAM
++ int pam_error;
++
++ if (pamh != NULL) {
++ pam_error = pam_close_session (pamh, PAM_SILENT);
++ pam_end (pamh, pam_error);
++ pamh = NULL;
++ }
++ /* Apparently the pam stuff does closelog(). */
++ reopen_log();
++#else /* ! USE_PAM */
++ char *tty;
++
++ tty = devnam;
++ if (strncmp(tty, &quot;/dev/&quot;, 5) == 0)
++ tty += 5;
++// logwtmp(tty, &quot;&quot;, &quot;&quot;); /* Wipe out utmp logout entry */
++#endif /* ! USE_PAM */
++ logged_in = 0;
++}
++
++
++/*
++ * null_login - Check if a username of &quot;&quot; and a password of &quot;&quot; are
++ * acceptable, and iff so, set the list of acceptable IP addresses
++ * and return 1.
++ */
++static int
++null_login(unit)
++ int unit;
++{
++ char *filename;
++ FILE *f;
++ int i, ret;
++ struct wordlist *addrs, *opts;
++ char secret[MAXWORDLEN];
++
++ /*
++ * Open the file of pap secrets and scan for a suitable secret.
++ */
++ filename = _PATH_UPAPFILE;
++ addrs = NULL;
++ f = fopen(filename, &quot;r&quot;);
++ if (f == NULL)
++ return 0;
++ check_access(f, filename);
++
++ i = scan_authfile(f, &quot;&quot;, our_name, secret, &amp;addrs, &amp;opts, filename);
++ ret = i &gt;= 0 &amp;&amp; secret[0] == 0;
++ BZERO(secret, sizeof(secret));
++
++ if (ret)
++ set_allowed_addrs(unit, addrs, opts);
++ else if (opts != 0)
++ free_wordlist(opts);
++ if (addrs != 0)
++ free_wordlist(addrs);
++
++ fclose(f);
++ return ret;
++}
++
++
++/*
++ * get_pap_passwd - get a password for authenticating ourselves with
++ * our peer using PAP. Returns 1 on success, 0 if no suitable password
++ * could be found.
++ * Assumes passwd points to MAXSECRETLEN bytes of space (if non-null).
++ */
++static int
++get_pap_passwd(passwd)
++ char *passwd;
++{
++ char *filename;
++ FILE *f;
++ int ret;
++ char secret[MAXWORDLEN];
++
++ /*
++ * Check whether a plugin wants to supply this.
++ */
++ if (pap_passwd_hook) {
++ ret = (*pap_passwd_hook)(user, passwd);
++ if (ret &gt;= 0)
++ return ret;
++ }
++
++ filename = _PATH_UPAPFILE;
++ f = fopen(filename, &quot;r&quot;);
++ if (f == NULL)
++ return 0;
++ check_access(f, filename);
++ ret = scan_authfile(f, user,
++ (remote_name[0]? remote_name: NULL),
++ secret, NULL, NULL, filename);
++ fclose(f);
++ if (ret &lt; 0)
++ return 0;
++ if (passwd != NULL)
++ strlcpy(passwd, secret, MAXSECRETLEN);
++ BZERO(secret, sizeof(secret));
++ return 1;
++}
++
++
++/*
++ * have_pap_secret - check whether we have a PAP file with any
++ * secrets that we could possibly use for authenticating the peer.
++ */
++static int
++have_pap_secret(lacks_ipp)
++ int *lacks_ipp;
++{
++ FILE *f;
++ int ret;
++ char *filename;
++ struct wordlist *addrs;
++
++ /* let the plugin decide, if there is one */
++ if (pap_check_hook) {
++ ret = (*pap_check_hook)();
++ if (ret &gt;= 0)
++ return ret;
++ }
++
++ filename = _PATH_UPAPFILE;
++ f = fopen(filename, &quot;r&quot;);
++ if (f == NULL)
++ return 0;
++
++ ret = scan_authfile(f, (explicit_remote? remote_name: NULL), our_name,
++ NULL, &amp;addrs, NULL, filename);
++ fclose(f);
++ if (ret &gt;= 0 &amp;&amp; !some_ip_ok(addrs)) {
++ if (lacks_ipp != 0)
++ *lacks_ipp = 1;
++ ret = -1;
++ }
++ if (addrs != 0)
++ free_wordlist(addrs);
++
++ return ret &gt;= 0;
++}
++
++
++/*
++ * have_chap_secret - check whether we have a CHAP file with a
++ * secret that we could possibly use for authenticating `client'
++ * on `server'. Either can be the null string, meaning we don't
++ * know the identity yet.
++ */
++static int
++have_chap_secret(client, server, need_ip, lacks_ipp)
++ char *client;
++ char *server;
++ int need_ip;
++ int *lacks_ipp;
++{
++ FILE *f;
++ int ret;
++ char *filename;
++ struct wordlist *addrs;
++
++ filename = _PATH_CHAPFILE;
++ f = fopen(filename, &quot;r&quot;);
++ if (f == NULL)
++ return 0;
++
++ if (client != NULL &amp;&amp; client[0] == 0)
++ client = NULL;
++ else if (server != NULL &amp;&amp; server[0] == 0)
++ server = NULL;
++
++ ret = scan_authfile(f, client, server, NULL, &amp;addrs, NULL, filename);
++ fclose(f);
++ if (ret &gt;= 0 &amp;&amp; need_ip &amp;&amp; !some_ip_ok(addrs)) {
++ if (lacks_ipp != 0)
++ *lacks_ipp = 1;
++ ret = -1;
++ }
++ if (addrs != 0)
++ free_wordlist(addrs);
++
++ return ret &gt;= 0;
++}
++
++
++/*
++ * get_secret - open the CHAP secret file and return the secret
++ * for authenticating the given client on the given server.
++ * (We could be either client or server).
++ */
++int
++get_secret(unit, client, server, secret, secret_len, am_server)
++ int unit;
++ char *client;
++ char *server;
++ char *secret;
++ int *secret_len;
++ int am_server;
++{
++ FILE *f;
++ int ret, len;
++ char *filename;
++ struct wordlist *addrs, *opts;
++ char secbuf[MAXWORDLEN];
++
++ if (!am_server &amp;&amp; passwd[0] != 0) {
++ strlcpy(secbuf, passwd, sizeof(secbuf));
++ } else {
++ filename = _PATH_CHAPFILE;
++ addrs = NULL;
++ secbuf[0] = 0;
++
++ f = fopen(filename, &quot;r&quot;);
++ if (f == NULL) {
++ error(&quot;Can't open chap secret file %s: %m&quot;, filename);
++ return 0;
++ }
++ check_access(f, filename);
++
++ ret = scan_authfile(f, client, server, secbuf, &amp;addrs, &amp;opts, filename);
++ fclose(f);
++ if (ret &lt; 0)
++ return 0;
++
++ if (am_server)
++ set_allowed_addrs(unit, addrs, opts);
++ else if (opts != 0)
++ free_wordlist(opts);
++ if (addrs != 0)
++ free_wordlist(addrs);
++ }
++
++ len = strlen(secbuf);
++ if (len &gt; MAXSECRETLEN) {
++ error(&quot;Secret for %s on %s is too long&quot;, client, server);
++ len = MAXSECRETLEN;
++ }
++ BCOPY(secbuf, secret, len);
++ BZERO(secbuf, sizeof(secbuf));
++ *secret_len = len;
++
++ return 1;
++}
++
++/*
++ * set_allowed_addrs() - set the list of allowed addresses.
++ * Also looks for `--' indicating options to apply for this peer
++ * and leaves the following words in extra_options.
++ */
++static void
++set_allowed_addrs(unit, addrs, opts)
++ int unit;
++ struct wordlist *addrs;
++ struct wordlist *opts;
++{
++ int n;
++ struct wordlist *ap, **plink;
++ struct permitted_ip *ip;
++ char *ptr_word, *ptr_mask;
++ struct hostent *hp;
++ u_int32_t a, mask, offset;
++ struct ipcp_options *wo = &amp;ipcp_wantoptions[unit];
++ u_int32_t suggested_ip = 0;
++
++ if (addresses[unit] != NULL)
++ free(addresses[unit]);
++ addresses[unit] = NULL;
++ if (extra_options != NULL)
++ free_wordlist(extra_options);
++ extra_options = opts;
++
++ /*
++ * Count the number of IP addresses given.
++ */
++ n = wordlist_count(addrs) + wordlist_count(noauth_addrs);
++ if (n == 0)
++ return;
++ ip = (struct permitted_ip *) malloc((n + 1) * sizeof(struct permitted_ip));
++ if (ip == 0)
++ return;
++
++ /* temporarily append the noauth_addrs list to addrs */
++ for (plink = &amp;addrs; *plink != NULL; plink = &amp;(*plink)-&gt;next)
++ ;
++ *plink = noauth_addrs;
++
++ n = 0;
++ for (ap = addrs; ap != NULL; ap = ap-&gt;next) {
++ /* &quot;-&quot; means no addresses authorized, &quot;*&quot; means any address allowed */
++ ptr_word = ap-&gt;word;
++ if (strcmp(ptr_word, &quot;-&quot;) == 0)
++ break;
++ if (strcmp(ptr_word, &quot;*&quot;) == 0) {
++ ip[n].permit = 1;
++ ip[n].base = ip[n].mask = 0;
++ ++n;
++ break;
++ }
++
++ ip[n].permit = 1;
++ if (*ptr_word == '!') {
++ ip[n].permit = 0;
++ ++ptr_word;
++ }
++
++ mask = ~ (u_int32_t) 0;
++ offset = 0;
++ ptr_mask = strchr (ptr_word, '/');
++ if (ptr_mask != NULL) {
++ int bit_count;
++ char *endp;
++
++ bit_count = (int) strtol (ptr_mask+1, &amp;endp, 10);
++ if (bit_count &lt;= 0 || bit_count &gt; 32) {
++ warn(&quot;invalid address length %v in auth. address list&quot;,
++ ptr_mask+1);
++ continue;
++ }
++ bit_count = 32 - bit_count; /* # bits in host part */
++ if (*endp == '+') {
++ offset = ifunit + 1;
++ ++endp;
++ }
++ if (*endp != 0) {
++ warn(&quot;invalid address length syntax: %v&quot;, ptr_mask+1);
++ continue;
++ }
++ *ptr_mask = '\0';
++ mask &lt;&lt;= bit_count;
++ }
++
++ hp = gethostbyname(ptr_word);
++ if (hp != NULL &amp;&amp; hp-&gt;h_addrtype == AF_INET) {
++ a = *(u_int32_t *)hp-&gt;h_addr;
++ } else {
++ printf(&quot;*** getnetbyname is unsupported, please report bug! ***\n&quot;);
++ return;
++ }
++
++ if (ptr_mask != NULL)
++ *ptr_mask = '/';
++
++ if (a == (u_int32_t)-1L) {
++ warn(&quot;unknown host %s in auth. address list&quot;, ap-&gt;word);
++ continue;
++ }
++ if (offset != 0) {
++ if (offset &gt;= ~mask) {
++ warn(&quot;interface unit %d too large for subnet %v&quot;,
++ ifunit, ptr_word);
++ continue;
++ }
++ a = htonl((ntohl(a) &amp; mask) + offset);
++ mask = ~(u_int32_t)0;
++ }
++ ip[n].mask = htonl(mask);
++ ip[n].base = a &amp; ip[n].mask;
++ ++n;
++ if (~mask == 0 &amp;&amp; suggested_ip == 0)
++ suggested_ip = a;
++ }
++ *plink = NULL;
++
++ ip[n].permit = 0; /* make the last entry forbid all addresses */
++ ip[n].base = 0; /* to terminate the list */
++ ip[n].mask = 0;
++
++ addresses[unit] = ip;
++
++ /*
++ * If the address given for the peer isn't authorized, or if
++ * the user hasn't given one, AND there is an authorized address
++ * which is a single host, then use that if we find one.
++ */
++ if (suggested_ip != 0
++ &amp;&amp; (wo-&gt;hisaddr == 0 || !auth_ip_addr(unit, wo-&gt;hisaddr))) {
++ wo-&gt;hisaddr = suggested_ip;
++ /*
++ * Do we insist on this address? No, if there are other
++ * addresses authorized than the suggested one.
++ */
++ if (n &gt; 1)
++ wo-&gt;accept_remote = 1;
++ }
++}
++
++/*
++ * auth_ip_addr - check whether the peer is authorized to use
++ * a given IP address. Returns 1 if authorized, 0 otherwise.
++ */
++int
++auth_ip_addr(unit, addr)
++ int unit;
++ u_int32_t addr;
++{
++ int ok;
++
++ /* don't allow loopback or multicast address */
++ if (bad_ip_adrs(addr))
++ return 0;
++
++ if (addresses[unit] != NULL) {
++ ok = ip_addr_check(addr, addresses[unit]);
++ if (ok &gt;= 0)
++ return ok;
++ }
++ if (auth_required)
++ return 0; /* no addresses authorized */
++ return allow_any_ip || privileged || !have_route_to(addr);
++}
++
++static int
++ip_addr_check(addr, addrs)
++ u_int32_t addr;
++ struct permitted_ip *addrs;
++{
++ for (; ; ++addrs)
++ if ((addr &amp; addrs-&gt;mask) == addrs-&gt;base)
++ return addrs-&gt;permit;
++}
++
++/*
++ * bad_ip_adrs - return 1 if the IP address is one we don't want
++ * to use, such as an address in the loopback net or a multicast address.
++ * addr is in network byte order.
++ */
++int
++bad_ip_adrs(addr)
++ u_int32_t addr;
++{
++ addr = ntohl(addr);
++ return (addr &gt;&gt; IN_CLASSA_NSHIFT) == IN_LOOPBACKNET
++ || IN_MULTICAST(addr) || IN_BADCLASS(addr);
++}
++
++/*
++ * some_ip_ok - check a wordlist to see if it authorizes any
++ * IP address(es).
++ */
++static int
++some_ip_ok(addrs)
++ struct wordlist *addrs;
++{
++ for (; addrs != 0; addrs = addrs-&gt;next) {
++ if (addrs-&gt;word[0] == '-')
++ break;
++ if (addrs-&gt;word[0] != '!')
++ return 1; /* some IP address is allowed */
++ }
++ return 0;
++}
++
++/*
++ * check_access - complain if a secret file has too-liberal permissions.
++ */
++static void
++check_access(f, filename)
++ FILE *f;
++ char *filename;
++{
++ struct stat sbuf;
++
++ if (fstat(fileno(f), &amp;sbuf) &lt; 0) {
++ warn(&quot;cannot stat secret file %s: %m&quot;, filename);
++ } else if ((sbuf.st_mode &amp; (S_IRWXG | S_IRWXO)) != 0) {
++ warn(&quot;Warning - secret file %s has world and/or group access&quot;,
++ filename);
++ }
++}
++
++
++/*
++ * scan_authfile - Scan an authorization file for a secret suitable
++ * for authenticating `client' on `server'. The return value is -1
++ * if no secret is found, otherwise &gt;= 0. The return value has
++ * NONWILD_CLIENT set if the secret didn't have &quot;*&quot; for the client, and
++ * NONWILD_SERVER set if the secret didn't have &quot;*&quot; for the server.
++ * Any following words on the line up to a &quot;--&quot; (i.e. address authorization
++ * info) are placed in a wordlist and returned in *addrs. Any
++ * following words (extra options) are placed in a wordlist and
++ * returned in *opts.
++ * We assume secret is NULL or points to MAXWORDLEN bytes of space.
++ */
++static int
++scan_authfile(f, client, server, secret, addrs, opts, filename)
++ FILE *f;
++ char *client;
++ char *server;
++ char *secret;
++ struct wordlist **addrs;
++ struct wordlist **opts;
++ char *filename;
++{
++ int newline, xxx;
++ int got_flag, best_flag;
++ FILE *sf;
++ struct wordlist *ap, *addr_list, *alist, **app;
++ char word[MAXWORDLEN];
++ char atfile[MAXWORDLEN];
++ char lsecret[MAXWORDLEN];
++
++ if (addrs != NULL)
++ *addrs = NULL;
++ if (opts != NULL)
++ *opts = NULL;
++ addr_list = NULL;
++ if (!getword(f, word, &amp;newline, filename))
++ return -1; /* file is empty??? */
++ newline = 1;
++ best_flag = -1;
++ for (;;) {
++ /*
++ * Skip until we find a word at the start of a line.
++ */
++ while (!newline &amp;&amp; getword(f, word, &amp;newline, filename))
++ ;
++ if (!newline)
++ break; /* got to end of file */
++
++ /*
++ * Got a client - check if it's a match or a wildcard.
++ */
++ got_flag = 0;
++ if (client != NULL &amp;&amp; strcmp(word, client) != 0 &amp;&amp; !ISWILD(word)) {
++ newline = 0;
++ continue;
++ }
++ if (!ISWILD(word))
++ got_flag = NONWILD_CLIENT;
++
++ /*
++ * Now get a server and check if it matches.
++ */
++ if (!getword(f, word, &amp;newline, filename))
++ break;
++ if (newline)
++ continue;
++ if (!ISWILD(word)) {
++ if (server != NULL &amp;&amp; strcmp(word, server) != 0)
++ continue;
++ got_flag |= NONWILD_SERVER;
++ }
++
++ /*
++ * Got some sort of a match - see if it's better than what
++ * we have already.
++ */
++ if (got_flag &lt;= best_flag)
++ continue;
++
++ /*
++ * Get the secret.
++ */
++ if (!getword(f, word, &amp;newline, filename))
++ break;
++ if (newline)
++ continue;
++
++ if (secret != NULL) {
++ /*
++ * Special syntax: @/pathname means read secret from file.
++ */
++ if (word[0] == '@' &amp;&amp; word[1] == '/') {
++ strlcpy(atfile, word+1, sizeof(atfile));
++ if ((sf = fopen(atfile, &quot;r&quot;)) == NULL) {
++ warn(&quot;can't open indirect secret file %s&quot;, atfile);
++ continue;
++ }
++ check_access(sf, atfile);
++ if (!getword(sf, word, &amp;xxx, atfile)) {
++ warn(&quot;no secret in indirect secret file %s&quot;, atfile);
++ fclose(sf);
++ continue;
++ }
++ fclose(sf);
++ }
++ strlcpy(lsecret, word, sizeof(lsecret));
++ }
++
++ /*
++ * Now read address authorization info and make a wordlist.
++ */
++ app = &amp;alist;
++ for (;;) {
++ if (!getword(f, word, &amp;newline, filename) || newline)
++ break;
++ ap = (struct wordlist *)
++ malloc(sizeof(struct wordlist) + strlen(word) + 1);
++ if (ap == NULL)
++ novm(&quot;authorized addresses&quot;);
++ ap-&gt;word = (char *) (ap + 1);
++ strcpy(ap-&gt;word, word);
++ *app = ap;
++ app = &amp;ap-&gt;next;
++ }
++ *app = NULL;
++
++ /*
++ * This is the best so far; remember it.
++ */
++ best_flag = got_flag;
++ if (addr_list)
++ free_wordlist(addr_list);
++ addr_list = alist;
++ if (secret != NULL)
++ strlcpy(secret, lsecret, MAXWORDLEN);
++
++ if (!newline)
++ break;
++ }
++
++ /* scan for a -- word indicating the start of options */
++ for (app = &amp;addr_list; (ap = *app) != NULL; app = &amp;ap-&gt;next)
++ if (strcmp(ap-&gt;word, &quot;--&quot;) == 0)
++ break;
++ /* ap = start of options */
++ if (ap != NULL) {
++ ap = ap-&gt;next; /* first option */
++ free(*app); /* free the &quot;--&quot; word */
++ *app = NULL; /* terminate addr list */
++ }
++ if (opts != NULL)
++ *opts = ap;
++ else if (ap != NULL)
++ free_wordlist(ap);
++ if (addrs != NULL)
++ *addrs = addr_list;
++ else if (addr_list != NULL)
++ free_wordlist(addr_list);
++
++ return best_flag;
++}
++
++/*
++ * wordlist_count - return the number of items in a wordlist
++ */
++static int
++wordlist_count(wp)
++ struct wordlist *wp;
++{
++ int n;
++
++ for (n = 0; wp != NULL; wp = wp-&gt;next)
++ ++n;
++ return n;
++}
++
++/*
++ * free_wordlist - release memory allocated for a wordlist.
++ */
++static void
++free_wordlist(wp)
++ struct wordlist *wp;
++{
++ struct wordlist *next;
++
++ while (wp != NULL) {
++ next = wp-&gt;next;
++ free(wp);
++ wp = next;
++ }
++}
++
++/*
++ * auth_script_done - called when the auth-up or auth-down script
++ * has finished.
++ */
++static void
++auth_script_done(arg)
++ void *arg;
++{
++ auth_script_pid = 0;
++ switch (auth_script_state) {
++ case s_up:
++ if (auth_state == s_down) {
++ auth_script_state = s_down;
++ auth_script(_PATH_AUTHDOWN);
++ }
++ break;
++ case s_down:
++ if (auth_state == s_up) {
++ auth_script_state = s_up;
++ auth_script(_PATH_AUTHUP);
++ }
++ break;
++ }
++}
++
++/*
++ * auth_script - execute a script with arguments
++ * interface-name peer-name real-user tty speed
++ */
++static void
++auth_script(script)
++ char *script;
++{
++ char strspeed[32];
++ struct passwd *pw;
++ char struid[32];
++ char *user_name;
++ char *argv[8];
++
++ if ((pw = getpwuid(getuid())) != NULL &amp;&amp; pw-&gt;pw_name != NULL)
++ user_name = pw-&gt;pw_name;
++ else {
++ slprintf(struid, sizeof(struid), &quot;%d&quot;, getuid());
++ user_name = struid;
++ }
++ slprintf(strspeed, sizeof(strspeed), &quot;%d&quot;, baud_rate);
++
++ argv[0] = script;
++ argv[1] = ifname;
++ argv[2] = peer_authname;
++ argv[3] = user_name;
++ argv[4] = devnam;
++ argv[5] = strspeed;
++ argv[6] = NULL;
++
++ auth_script_pid = run_program(script, argv, 0, auth_script_done, NULL);
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/auth.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/cbcp.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/cbcp.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/cbcp.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,456 @@
++/*
++ * cbcp - Call Back Configuration Protocol.
++ *
++ * Copyright (c) 1995 Pedro Roque Marques
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by Pedro Roque Marques. The name of the author may not be used to
++ * endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ */
++
++#define RCSID &quot;$Id: cbcp.c 195720 2001-06-11 11:44:34Z gc $&quot;
++
++#include &lt;stdio.h&gt;
++#include &lt;string.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/time.h&gt;
++
++#include &quot;pppd.h&quot;
++#include &quot;cbcp.h&quot;
++#include &quot;fsm.h&quot;
++#include &quot;lcp.h&quot;
++
++static const char rcsid[] = RCSID;
++
++/*
++ * Options.
++ */
++static int setcbcp __P((char **));
++
++static option_t cbcp_option_list[] = {
++ { &quot;callback&quot;, o_special, setcbcp,
++ &quot;Ask for callback&quot;, OPT_PRIO | OPT_A2STRVAL, &amp;cbcp[0].us_number },
++ { NULL }
++};
++
++/*
++ * Protocol entry points.
++ */
++static void cbcp_init __P((int unit));
++static void cbcp_open __P((int unit));
++static void cbcp_lowerup __P((int unit));
++static void cbcp_input __P((int unit, u_char *pkt, int len));
++static void cbcp_protrej __P((int unit));
++static int cbcp_printpkt __P((u_char *pkt, int len,
++ void (*printer) __P((void *, char *, ...)),
++ void *arg));
++
++struct protent cbcp_protent = {
++ PPP_CBCP,
++ cbcp_init,
++ cbcp_input,
++ cbcp_protrej,
++ cbcp_lowerup,
++ NULL,
++ cbcp_open,
++ NULL,
++ cbcp_printpkt,
++ NULL,
++ 0,
++ &quot;CBCP&quot;,
++ NULL,
++ cbcp_option_list,
++ NULL,
++ NULL,
++ NULL
++};
++
++cbcp_state cbcp[NUM_PPP];
++
++/* internal prototypes */
++
++static void cbcp_recvreq __P((cbcp_state *us, char *pckt, int len));
++static void cbcp_resp __P((cbcp_state *us));
++static void cbcp_up __P((cbcp_state *us));
++static void cbcp_recvack __P((cbcp_state *us, char *pckt, int len));
++static void cbcp_send __P((cbcp_state *us, u_char code, u_char *buf, int len));
++
++/* option processing */
++static int
++setcbcp(argv)
++ char **argv;
++{
++ lcp_wantoptions[0].neg_cbcp = 1;
++ cbcp_protent.enabled_flag = 1;
++ cbcp[0].us_number = strdup(*argv);
++ if (cbcp[0].us_number == 0)
++ novm(&quot;callback number&quot;);
++ cbcp[0].us_type |= (1 &lt;&lt; CB_CONF_USER);
++ cbcp[0].us_type |= (1 &lt;&lt; CB_CONF_ADMIN);
++ return (1);
++}
++
++/* init state */
++static void
++cbcp_init(iface)
++ int iface;
++{
++ cbcp_state *us;
++
++ us = &amp;cbcp[iface];
++ memset(us, 0, sizeof(cbcp_state));
++ us-&gt;us_unit = iface;
++ us-&gt;us_type |= (1 &lt;&lt; CB_CONF_NO);
++}
++
++/* lower layer is up */
++static void
++cbcp_lowerup(iface)
++ int iface;
++{
++ cbcp_state *us = &amp;cbcp[iface];
++
++ dbglog(&quot;cbcp_lowerup&quot;);
++ dbglog(&quot;want: %d&quot;, us-&gt;us_type);
++
++ if (us-&gt;us_type == CB_CONF_USER)
++ dbglog(&quot;phone no: %s&quot;, us-&gt;us_number);
++}
++
++static void
++cbcp_open(unit)
++ int unit;
++{
++ dbglog(&quot;cbcp_open&quot;);
++}
++
++/* process an incomming packet */
++static void
++cbcp_input(unit, inpacket, pktlen)
++ int unit;
++ u_char *inpacket;
++ int pktlen;
++{
++ u_char *inp;
++ u_char code, id;
++ u_short len;
++
++ cbcp_state *us = &amp;cbcp[unit];
++
++ inp = inpacket;
++
++ if (pktlen &lt; CBCP_MINLEN) {
++ error(&quot;CBCP packet is too small&quot;);
++ return;
++ }
++
++ GETCHAR(code, inp);
++ GETCHAR(id, inp);
++ GETSHORT(len, inp);
++
++#if 0
++ if (len &gt; pktlen) {
++ error(&quot;CBCP packet: invalid length&quot;);
++ return;
++ }
++#endif
++
++ len -= CBCP_MINLEN;
++
++ switch(code) {
++ case CBCP_REQ:
++ us-&gt;us_id = id;
++ cbcp_recvreq(us, inp, len);
++ break;
++
++ case CBCP_RESP:
++ dbglog(&quot;CBCP_RESP received&quot;);
++ break;
++
++ case CBCP_ACK:
++ if (id != us-&gt;us_id)
++ dbglog(&quot;id doesn't match: expected %d recv %d&quot;,
++ us-&gt;us_id, id);
++
++ cbcp_recvack(us, inp, len);
++ break;
++
++ default:
++ break;
++ }
++}
++
++/* protocol was rejected by foe */
++void cbcp_protrej(int iface)
++{
++}
++
++char *cbcp_codenames[] = {
++ &quot;Request&quot;, &quot;Response&quot;, &quot;Ack&quot;
++};
++
++char *cbcp_optionnames[] = {
++ &quot;NoCallback&quot;,
++ &quot;UserDefined&quot;,
++ &quot;AdminDefined&quot;,
++ &quot;List&quot;
++};
++
++/* pretty print a packet */
++static int
++cbcp_printpkt(p, plen, printer, arg)
++ u_char *p;
++ int plen;
++ void (*printer) __P((void *, char *, ...));
++ void *arg;
++{
++ int code, opt, id, len, olen, delay;
++ u_char *pstart;
++
++ if (plen &lt; HEADERLEN)
++ return 0;
++ pstart = p;
++ GETCHAR(code, p);
++ GETCHAR(id, p);
++ GETSHORT(len, p);
++ if (len &lt; HEADERLEN || len &gt; plen)
++ return 0;
++
++ if (code &gt;= 1 &amp;&amp; code &lt;= sizeof(cbcp_codenames) / sizeof(char *))
++ printer(arg, &quot; %s&quot;, cbcp_codenames[code-1]);
++ else
++ printer(arg, &quot; code=0x%x&quot;, code);
++
++ printer(arg, &quot; id=0x%x&quot;, id);
++ len -= HEADERLEN;
++
++ switch (code) {
++ case CBCP_REQ:
++ case CBCP_RESP:
++ case CBCP_ACK:
++ while(len &gt;= 2) {
++ GETCHAR(opt, p);
++ GETCHAR(olen, p);
++
++ if (olen &lt; 2 || olen &gt; len) {
++ break;
++ }
++
++ printer(arg, &quot; &lt;&quot;);
++ len -= olen;
++
++ if (opt &gt;= 1 &amp;&amp; opt &lt;= sizeof(cbcp_optionnames) / sizeof(char *))
++ printer(arg, &quot; %s&quot;, cbcp_optionnames[opt-1]);
++ else
++ printer(arg, &quot; option=0x%x&quot;, opt);
++
++ if (olen &gt; 2) {
++ GETCHAR(delay, p);
++ printer(arg, &quot; delay = %d&quot;, delay);
++ }
++
++ if (olen &gt; 3) {
++ int addrt;
++ char str[256];
++
++ GETCHAR(addrt, p);
++ memcpy(str, p, olen - 4);
++ str[olen - 4] = 0;
++ printer(arg, &quot; number = %s&quot;, str);
++ }
++ printer(arg, &quot;&gt;&quot;);
++ break;
++ }
++
++ default:
++ break;
++ }
++
++ for (; len &gt; 0; --len) {
++ GETCHAR(code, p);
++ printer(arg, &quot; %.2x&quot;, code);
++ }
++
++ return p - pstart;
++}
++
++/* received CBCP request */
++static void
++cbcp_recvreq(us, pckt, pcktlen)
++ cbcp_state *us;
++ char *pckt;
++ int pcktlen;
++{
++ u_char type, opt_len, delay, addr_type;
++ char address[256];
++ int len = pcktlen;
++
++ address[0] = 0;
++
++ while (len) {
++ dbglog(&quot;length: %d&quot;, len);
++
++ GETCHAR(type, pckt);
++ GETCHAR(opt_len, pckt);
++
++ if (opt_len &gt; 2)
++ GETCHAR(delay, pckt);
++
++ us-&gt;us_allowed |= (1 &lt;&lt; type);
++
++ switch(type) {
++ case CB_CONF_NO:
++ dbglog(&quot;no callback allowed&quot;);
++ break;
++
++ case CB_CONF_USER:
++ dbglog(&quot;user callback allowed&quot;);
++ if (opt_len &gt; 4) {
++ GETCHAR(addr_type, pckt);
++ memcpy(address, pckt, opt_len - 4);
++ address[opt_len - 4] = 0;
++ if (address[0])
++ dbglog(&quot;address: %s&quot;, address);
++ }
++ break;
++
++ case CB_CONF_ADMIN:
++ dbglog(&quot;user admin defined allowed&quot;);
++ break;
++
++ case CB_CONF_LIST:
++ break;
++ }
++ len -= opt_len;
++ }
++
++ cbcp_resp(us);
++}
++
++static void
++cbcp_resp(us)
++ cbcp_state *us;
++{
++ u_char cb_type;
++ u_char buf[256];
++ u_char *bufp = buf;
++ int len = 0;
++
++ cb_type = us-&gt;us_allowed &amp; us-&gt;us_type;
++ dbglog(&quot;cbcp_resp cb_type=%d&quot;, cb_type);
++
++#if 0
++ if (!cb_type)
++ lcp_down(us-&gt;us_unit);
++#endif
++
++ if (cb_type &amp; ( 1 &lt;&lt; CB_CONF_USER ) ) {
++ dbglog(&quot;cbcp_resp CONF_USER&quot;);
++ PUTCHAR(CB_CONF_USER, bufp);
++ len = 3 + 1 + strlen(us-&gt;us_number) + 1;
++ PUTCHAR(len , bufp);
++ PUTCHAR(5, bufp); /* delay */
++ PUTCHAR(1, bufp);
++ BCOPY(us-&gt;us_number, bufp, strlen(us-&gt;us_number) + 1);
++ cbcp_send(us, CBCP_RESP, buf, len);
++ return;
++ }
++
++ if (cb_type &amp; ( 1 &lt;&lt; CB_CONF_ADMIN ) ) {
++ dbglog(&quot;cbcp_resp CONF_ADMIN&quot;);
++ PUTCHAR(CB_CONF_ADMIN, bufp);
++ len = 3;
++ PUTCHAR(len, bufp);
++ PUTCHAR(5, bufp); /* delay */
++ cbcp_send(us, CBCP_RESP, buf, len);
++ return;
++ }
++
++ if (cb_type &amp; ( 1 &lt;&lt; CB_CONF_NO ) ) {
++ dbglog(&quot;cbcp_resp CONF_NO&quot;);
++ PUTCHAR(CB_CONF_NO, bufp);
++ len = 3;
++ PUTCHAR(len , bufp);
++ PUTCHAR(0, bufp);
++ cbcp_send(us, CBCP_RESP, buf, len);
++ start_networks();
++ return;
++ }
++}
++
++static void
++cbcp_send(us, code, buf, len)
++ cbcp_state *us;
++ u_char code;
++ u_char *buf;
++ int len;
++{
++ u_char *outp;
++ int outlen;
++
++ outp = outpacket_buf;
++
++ outlen = 4 + len;
++
++ MAKEHEADER(outp, PPP_CBCP);
++
++ PUTCHAR(code, outp);
++ PUTCHAR(us-&gt;us_id, outp);
++ PUTSHORT(outlen, outp);
++
++ if (len)
++ BCOPY(buf, outp, len);
++
++ output(us-&gt;us_unit, outpacket_buf, outlen + PPP_HDRLEN);
++}
++
++static void
++cbcp_recvack(us, pckt, len)
++ cbcp_state *us;
++ char *pckt;
++ int len;
++{
++ u_char type, delay, addr_type;
++ int opt_len;
++ char address[256];
++
++ if (len) {
++ GETCHAR(type, pckt);
++ GETCHAR(opt_len, pckt);
++
++ if (opt_len &gt; 2)
++ GETCHAR(delay, pckt);
++
++ if (opt_len &gt; 4) {
++ GETCHAR(addr_type, pckt);
++ memcpy(address, pckt, opt_len - 4);
++ address[opt_len - 4] = 0;
++ if (address[0])
++ dbglog(&quot;peer will call: %s&quot;, address);
++ }
++ if (type == CB_CONF_NO)
++ return;
++ }
++
++ cbcp_up(us);
++}
++
++/* ok peer will do callback */
++static void
++cbcp_up(us)
++ cbcp_state *us;
++{
++ persist = 0;
++ lcp_close(0, &quot;Call me back, please&quot;);
++ status = EXIT_CALLBACK;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/cbcp.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/cbcp.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/cbcp.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/cbcp.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,26 @@
++#ifndef CBCP_H
++#define CBCP_H
++
++typedef struct cbcp_state {
++ int us_unit; /* Interface unit number */
++ u_char us_id; /* Current id */
++ u_char us_allowed;
++ int us_type;
++ char *us_number; /* Telefone Number */
++} cbcp_state;
++
++extern cbcp_state cbcp[];
++
++extern struct protent cbcp_protent;
++
++#define CBCP_MINLEN 4
++
++#define CBCP_REQ 1
++#define CBCP_RESP 2
++#define CBCP_ACK 3
++
++#define CB_CONF_NO 1
++#define CB_CONF_USER 2
++#define CB_CONF_ADMIN 3
++#define CB_CONF_LIST 4
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/cbcp.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/ccp.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/ccp.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/ccp.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1257 @@
++/*
++ * ccp.c - PPP Compression Control Protocol.
++ *
++ * Copyright (c) 1994 The Australian National University.
++ * All rights reserved.
++ *
++ * Permission to use, copy, modify, and distribute this software and its
++ * documentation is hereby granted, provided that the above copyright
++ * notice appears in all copies. This software is provided without any
++ * warranty, express or implied. The Australian National University
++ * makes no representations about the suitability of this software for
++ * any purpose.
++ *
++ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
++ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
++ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
++ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
++ * OF SUCH DAMAGE.
++ *
++ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
++ * ON AN &quot;AS IS&quot; BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
++ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
++ * OR MODIFICATIONS.
++ */
++
++#define RCSID &quot;$Id: ccp.c 195720 2001-06-11 11:44:34Z gc $&quot;
++
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++
++#include &quot;pppd.h&quot;
++#include &quot;fsm.h&quot;
++#include &quot;ccp.h&quot;
++#include &lt;net/ppp-comp.h&gt;
++
++static const char rcsid[] = RCSID;
++
++/*
++ * Unfortunately there is a bug in zlib which means that using a
++ * size of 8 (window size = 256) for Deflate compression will cause
++ * buffer overruns and kernel crashes in the deflate module.
++ * Until this is fixed we only accept sizes in the range 9 .. 15.
++ * Thanks to James Carlson for pointing this out.
++ */
++#define DEFLATE_MIN_WORKS 9
++
++/*
++ * Command-line options.
++ */
++static int setbsdcomp __P((char **));
++static int setdeflate __P((char **));
++static char bsd_value[8];
++static char deflate_value[8];
++
++static option_t ccp_option_list[] = {
++ { &quot;noccp&quot;, o_bool, &amp;ccp_protent.enabled_flag,
++ &quot;Disable CCP negotiation&quot; },
++ { &quot;-ccp&quot;, o_bool, &amp;ccp_protent.enabled_flag,
++ &quot;Disable CCP negotiation&quot;, OPT_ALIAS },
++
++ { &quot;bsdcomp&quot;, o_special, (void *)setbsdcomp,
++ &quot;Request BSD-Compress packet compression&quot;,
++ OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, bsd_value },
++ { &quot;nobsdcomp&quot;, o_bool, &amp;ccp_wantoptions[0].bsd_compress,
++ &quot;don't allow BSD-Compress&quot;, OPT_PRIOSUB | OPT_A2CLR,
++ &amp;ccp_allowoptions[0].bsd_compress },
++ { &quot;-bsdcomp&quot;, o_bool, &amp;ccp_wantoptions[0].bsd_compress,
++ &quot;don't allow BSD-Compress&quot;, OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR,
++ &amp;ccp_allowoptions[0].bsd_compress },
++
++ { &quot;deflate&quot;, o_special, (void *)setdeflate,
++ &quot;request Deflate compression&quot;,
++ OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, deflate_value },
++ { &quot;nodeflate&quot;, o_bool, &amp;ccp_wantoptions[0].deflate,
++ &quot;don't allow Deflate compression&quot;, OPT_PRIOSUB | OPT_A2CLR,
++ &amp;ccp_allowoptions[0].deflate },
++ { &quot;-deflate&quot;, o_bool, &amp;ccp_wantoptions[0].deflate,
++ &quot;don't allow Deflate compression&quot;, OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR,
++ &amp;ccp_allowoptions[0].deflate },
++
++ { &quot;nodeflatedraft&quot;, o_bool, &amp;ccp_wantoptions[0].deflate_draft,
++ &quot;don't use draft deflate #&quot;, OPT_A2COPY,
++ &amp;ccp_allowoptions[0].deflate_draft },
++
++ { &quot;predictor1&quot;, o_bool, &amp;ccp_wantoptions[0].predictor_1,
++ &quot;request Predictor-1&quot;, 1, &amp;ccp_allowoptions[0].predictor_1, OPT_PRIO },
++ { &quot;nopredictor1&quot;, o_bool, &amp;ccp_wantoptions[0].predictor_1,
++ &quot;don't allow Predictor-1&quot;, OPT_PRIOSUB | OPT_A2CLR,
++ &amp;ccp_allowoptions[0].predictor_1 },
++ { &quot;-predictor1&quot;, o_bool, &amp;ccp_wantoptions[0].predictor_1,
++ &quot;don't allow Predictor-1&quot;, OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR,
++ &amp;ccp_allowoptions[0].predictor_1 },
++
++ { NULL }
++};
++
++/*
++ * Protocol entry points from main code.
++ */
++static void ccp_init __P((int unit));
++static void ccp_open __P((int unit));
++static void ccp_close __P((int unit, char *));
++static void ccp_lowerup __P((int unit));
++static void ccp_lowerdown __P((int));
++static void ccp_input __P((int unit, u_char *pkt, int len));
++static void ccp_protrej __P((int unit));
++static int ccp_printpkt __P((u_char *pkt, int len,
++ void (*printer) __P((void *, char *, ...)),
++ void *arg));
++static void ccp_datainput __P((int unit, u_char *pkt, int len));
++
++struct protent ccp_protent = {
++ PPP_CCP,
++ ccp_init,
++ ccp_input,
++ ccp_protrej,
++ ccp_lowerup,
++ ccp_lowerdown,
++ ccp_open,
++ ccp_close,
++ ccp_printpkt,
++ ccp_datainput,
++ 1,
++ &quot;CCP&quot;,
++ &quot;Compressed&quot;,
++ ccp_option_list,
++ NULL,
++ NULL,
++ NULL
++};
++
++fsm ccp_fsm[NUM_PPP];
++ccp_options ccp_wantoptions[NUM_PPP]; /* what to request the peer to use */
++ccp_options ccp_gotoptions[NUM_PPP]; /* what the peer agreed to do */
++ccp_options ccp_allowoptions[NUM_PPP]; /* what we'll agree to do */
++ccp_options ccp_hisoptions[NUM_PPP]; /* what we agreed to do */
++
++/*
++ * Callbacks for fsm code.
++ */
++static void ccp_resetci __P((fsm *));
++static int ccp_cilen __P((fsm *));
++static void ccp_addci __P((fsm *, u_char *, int *));
++static int ccp_ackci __P((fsm *, u_char *, int));
++static int ccp_nakci __P((fsm *, u_char *, int));
++static int ccp_rejci __P((fsm *, u_char *, int));
++static int ccp_reqci __P((fsm *, u_char *, int *, int));
++static void ccp_up __P((fsm *));
++static void ccp_down __P((fsm *));
++static int ccp_extcode __P((fsm *, int, int, u_char *, int));
++static void ccp_rack_timeout __P((void *));
++static char *method_name __P((ccp_options *, ccp_options *));
++
++static fsm_callbacks ccp_callbacks = {
++ ccp_resetci,
++ ccp_cilen,
++ ccp_addci,
++ ccp_ackci,
++ ccp_nakci,
++ ccp_rejci,
++ ccp_reqci,
++ ccp_up,
++ ccp_down,
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ ccp_extcode,
++ &quot;CCP&quot;
++};
++
++/*
++ * Do we want / did we get any compression?
++ */
++#define ANY_COMPRESS(opt) ((opt).deflate || (opt).bsd_compress \
++ || (opt).predictor_1 || (opt).predictor_2)
++
++/*
++ * Local state (mainly for handling reset-reqs and reset-acks).
++ */
++static int ccp_localstate[NUM_PPP];
++#define RACK_PENDING 1 /* waiting for reset-ack */
++#define RREQ_REPEAT 2 /* send another reset-req if no reset-ack */
++
++#define RACKTIMEOUT 1 /* second */
++
++static int all_rejected[NUM_PPP]; /* we rejected all peer's options */
++
++/*
++ * Option parsing.
++ */
++static int
++setbsdcomp(argv)
++ char **argv;
++{
++ int rbits, abits;
++ char *str, *endp;
++
++ str = *argv;
++ abits = rbits = strtol(str, &amp;endp, 0);
++ if (endp != str &amp;&amp; *endp == ',') {
++ str = endp + 1;
++ abits = strtol(str, &amp;endp, 0);
++ }
++ if (*endp != 0 || endp == str) {
++ option_error(&quot;invalid parameter '%s' for bsdcomp option&quot;, *argv);
++ return 0;
++ }
++ if ((rbits != 0 &amp;&amp; (rbits &lt; BSD_MIN_BITS || rbits &gt; BSD_MAX_BITS))
++ || (abits != 0 &amp;&amp; (abits &lt; BSD_MIN_BITS || abits &gt; BSD_MAX_BITS))) {
++ option_error(&quot;bsdcomp option values must be 0 or %d .. %d&quot;,
++ BSD_MIN_BITS, BSD_MAX_BITS);
++ return 0;
++ }
++ if (rbits &gt; 0) {
++ ccp_wantoptions[0].bsd_compress = 1;
++ ccp_wantoptions[0].bsd_bits = rbits;
++ } else
++ ccp_wantoptions[0].bsd_compress = 0;
++ if (abits &gt; 0) {
++ ccp_allowoptions[0].bsd_compress = 1;
++ ccp_allowoptions[0].bsd_bits = abits;
++ } else
++ ccp_allowoptions[0].bsd_compress = 0;
++ slprintf(bsd_value, sizeof(bsd_value),
++ rbits == abits? &quot;%d&quot;: &quot;%d,%d&quot;, rbits, abits);
++
++ return 1;
++}
++
++static int
++setdeflate(argv)
++ char **argv;
++{
++ int rbits, abits;
++ char *str, *endp;
++
++ str = *argv;
++ abits = rbits = strtol(str, &amp;endp, 0);
++ if (endp != str &amp;&amp; *endp == ',') {
++ str = endp + 1;
++ abits = strtol(str, &amp;endp, 0);
++ }
++ if (*endp != 0 || endp == str) {
++ option_error(&quot;invalid parameter '%s' for deflate option&quot;, *argv);
++ return 0;
++ }
++ if ((rbits != 0 &amp;&amp; (rbits &lt; DEFLATE_MIN_SIZE || rbits &gt; DEFLATE_MAX_SIZE))
++ || (abits != 0 &amp;&amp; (abits &lt; DEFLATE_MIN_SIZE
++ || abits &gt; DEFLATE_MAX_SIZE))) {
++ option_error(&quot;deflate option values must be 0 or %d .. %d&quot;,
++ DEFLATE_MIN_SIZE, DEFLATE_MAX_SIZE);
++ return 0;
++ }
++ if (rbits == DEFLATE_MIN_SIZE || abits == DEFLATE_MIN_SIZE) {
++ if (rbits == DEFLATE_MIN_SIZE)
++ rbits = DEFLATE_MIN_WORKS;
++ if (abits == DEFLATE_MIN_SIZE)
++ abits = DEFLATE_MIN_WORKS;
++ warn(&quot;deflate option value of %d changed to %d to avoid zlib bug&quot;,
++ DEFLATE_MIN_SIZE, DEFLATE_MIN_WORKS);
++ }
++ if (rbits &gt; 0) {
++ ccp_wantoptions[0].deflate = 1;
++ ccp_wantoptions[0].deflate_size = rbits;
++ } else
++ ccp_wantoptions[0].deflate = 0;
++ if (abits &gt; 0) {
++ ccp_allowoptions[0].deflate = 1;
++ ccp_allowoptions[0].deflate_size = abits;
++ } else
++ ccp_allowoptions[0].deflate = 0;
++ slprintf(deflate_value, sizeof(deflate_value),
++ rbits == abits? &quot;%d&quot;: &quot;%d,%d&quot;, rbits, abits);
++
++ return 1;
++}
++
++/*
++ * ccp_init - initialize CCP.
++ */
++static void
++ccp_init(unit)
++ int unit;
++{
++ fsm *f = &amp;ccp_fsm[unit];
++
++ f-&gt;unit = unit;
++ f-&gt;protocol = PPP_CCP;
++ f-&gt;callbacks = &amp;ccp_callbacks;
++ fsm_init(f);
++
++ memset(&amp;ccp_wantoptions[unit], 0, sizeof(ccp_options));
++ memset(&amp;ccp_gotoptions[unit], 0, sizeof(ccp_options));
++ memset(&amp;ccp_allowoptions[unit], 0, sizeof(ccp_options));
++ memset(&amp;ccp_hisoptions[unit], 0, sizeof(ccp_options));
++
++ ccp_wantoptions[0].deflate = 1;
++ ccp_wantoptions[0].deflate_size = DEFLATE_MAX_SIZE;
++ ccp_wantoptions[0].deflate_correct = 1;
++ ccp_wantoptions[0].deflate_draft = 1;
++ ccp_allowoptions[0].deflate = 1;
++ ccp_allowoptions[0].deflate_size = DEFLATE_MAX_SIZE;
++ ccp_allowoptions[0].deflate_correct = 1;
++ ccp_allowoptions[0].deflate_draft = 1;
++
++ ccp_wantoptions[0].bsd_compress = 1;
++ ccp_wantoptions[0].bsd_bits = BSD_MAX_BITS;
++ ccp_allowoptions[0].bsd_compress = 1;
++ ccp_allowoptions[0].bsd_bits = BSD_MAX_BITS;
++
++ ccp_allowoptions[0].predictor_1 = 1;
++}
++
++/*
++ * ccp_open - CCP is allowed to come up.
++ */
++static void
++ccp_open(unit)
++ int unit;
++{
++ fsm *f = &amp;ccp_fsm[unit];
++
++ if (f-&gt;state != OPENED)
++ ccp_flags_set(unit, 1, 0);
++
++ /*
++ * Find out which compressors the kernel supports before
++ * deciding whether to open in silent mode.
++ */
++ ccp_resetci(f);
++ if (!ANY_COMPRESS(ccp_gotoptions[unit]))
++ f-&gt;flags |= OPT_SILENT;
++
++ fsm_open(f);
++}
++
++/*
++ * ccp_close - Terminate CCP.
++ */
++static void
++ccp_close(unit, reason)
++ int unit;
++ char *reason;
++{
++ ccp_flags_set(unit, 0, 0);
++ fsm_close(&amp;ccp_fsm[unit], reason);
++}
++
++/*
++ * ccp_lowerup - we may now transmit CCP packets.
++ */
++static void
++ccp_lowerup(unit)
++ int unit;
++{
++ fsm_lowerup(&amp;ccp_fsm[unit]);
++}
++
++/*
++ * ccp_lowerdown - we may not transmit CCP packets.
++ */
++static void
++ccp_lowerdown(unit)
++ int unit;
++{
++ fsm_lowerdown(&amp;ccp_fsm[unit]);
++}
++
++/*
++ * ccp_input - process a received CCP packet.
++ */
++static void
++ccp_input(unit, p, len)
++ int unit;
++ u_char *p;
++ int len;
++{
++ fsm *f = &amp;ccp_fsm[unit];
++ int oldstate;
++
++ /*
++ * Check for a terminate-request so we can print a message.
++ */
++ oldstate = f-&gt;state;
++ fsm_input(f, p, len);
++ if (oldstate == OPENED &amp;&amp; p[0] == TERMREQ &amp;&amp; f-&gt;state != OPENED)
++ notice(&quot;Compression disabled by peer.&quot;);
++
++ /*
++ * If we get a terminate-ack and we're not asking for compression,
++ * close CCP.
++ */
++ if (oldstate == REQSENT &amp;&amp; p[0] == TERMACK
++ &amp;&amp; !ANY_COMPRESS(ccp_gotoptions[unit]))
++ ccp_close(unit, &quot;No compression negotiated&quot;);
++}
++
++/*
++ * Handle a CCP-specific code.
++ */
++static int
++ccp_extcode(f, code, id, p, len)
++ fsm *f;
++ int code, id;
++ u_char *p;
++ int len;
++{
++ switch (code) {
++ case CCP_RESETREQ:
++ if (f-&gt;state != OPENED)
++ break;
++ /* send a reset-ack, which the transmitter will see and
++ reset its compression state. */
++ fsm_sdata(f, CCP_RESETACK, id, NULL, 0);
++ break;
++
++ case CCP_RESETACK:
++ if (ccp_localstate[f-&gt;unit] &amp; RACK_PENDING &amp;&amp; id == f-&gt;reqid) {
++ ccp_localstate[f-&gt;unit] &amp;= ~(RACK_PENDING | RREQ_REPEAT);
++ UNTIMEOUT(ccp_rack_timeout, f);
++ }
++ break;
++
++ default:
++ return 0;
++ }
++
++ return 1;
++}
++
++/*
++ * ccp_protrej - peer doesn't talk CCP.
++ */
++static void
++ccp_protrej(unit)
++ int unit;
++{
++ ccp_flags_set(unit, 0, 0);
++ fsm_lowerdown(&amp;ccp_fsm[unit]);
++}
++
++/*
++ * ccp_resetci - initialize at start of negotiation.
++ */
++static void
++ccp_resetci(f)
++ fsm *f;
++{
++ ccp_options *go = &amp;ccp_gotoptions[f-&gt;unit];
++ u_char opt_buf[16];
++
++ *go = ccp_wantoptions[f-&gt;unit];
++ all_rejected[f-&gt;unit] = 0;
++
++ /*
++ * Check whether the kernel knows about the various
++ * compression methods we might request.
++ */
++ if (go-&gt;bsd_compress) {
++ opt_buf[0] = CI_BSD_COMPRESS;
++ opt_buf[1] = CILEN_BSD_COMPRESS;
++ opt_buf[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, BSD_MIN_BITS);
++ if (ccp_test(f-&gt;unit, opt_buf, CILEN_BSD_COMPRESS, 0) &lt;= 0)
++ go-&gt;bsd_compress = 0;
++ }
++ if (go-&gt;deflate) {
++ if (go-&gt;deflate_correct) {
++ opt_buf[0] = CI_DEFLATE;
++ opt_buf[1] = CILEN_DEFLATE;
++ opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_WORKS);
++ opt_buf[3] = DEFLATE_CHK_SEQUENCE;
++ if (ccp_test(f-&gt;unit, opt_buf, CILEN_DEFLATE, 0) &lt;= 0)
++ go-&gt;deflate_correct = 0;
++ }
++ if (go-&gt;deflate_draft) {
++ opt_buf[0] = CI_DEFLATE_DRAFT;
++ opt_buf[1] = CILEN_DEFLATE;
++ opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_WORKS);
++ opt_buf[3] = DEFLATE_CHK_SEQUENCE;
++ if (ccp_test(f-&gt;unit, opt_buf, CILEN_DEFLATE, 0) &lt;= 0)
++ go-&gt;deflate_draft = 0;
++ }
++ if (!go-&gt;deflate_correct &amp;&amp; !go-&gt;deflate_draft)
++ go-&gt;deflate = 0;
++ }
++ if (go-&gt;predictor_1) {
++ opt_buf[0] = CI_PREDICTOR_1;
++ opt_buf[1] = CILEN_PREDICTOR_1;
++ if (ccp_test(f-&gt;unit, opt_buf, CILEN_PREDICTOR_1, 0) &lt;= 0)
++ go-&gt;predictor_1 = 0;
++ }
++ if (go-&gt;predictor_2) {
++ opt_buf[0] = CI_PREDICTOR_2;
++ opt_buf[1] = CILEN_PREDICTOR_2;
++ if (ccp_test(f-&gt;unit, opt_buf, CILEN_PREDICTOR_2, 0) &lt;= 0)
++ go-&gt;predictor_2 = 0;
++ }
++}
++
++/*
++ * ccp_cilen - Return total length of our configuration info.
++ */
++static int
++ccp_cilen(f)
++ fsm *f;
++{
++ ccp_options *go = &amp;ccp_gotoptions[f-&gt;unit];
++
++ return (go-&gt;bsd_compress? CILEN_BSD_COMPRESS: 0)
++ + (go-&gt;deflate? CILEN_DEFLATE: 0)
++ + (go-&gt;predictor_1? CILEN_PREDICTOR_1: 0)
++ + (go-&gt;predictor_2? CILEN_PREDICTOR_2: 0);
++}
++
++/*
++ * ccp_addci - put our requests in a packet.
++ */
++static void
++ccp_addci(f, p, lenp)
++ fsm *f;
++ u_char *p;
++ int *lenp;
++{
++ int res;
++ ccp_options *go = &amp;ccp_gotoptions[f-&gt;unit];
++ u_char *p0 = p;
++
++ /*
++ * Add the compression types that we can receive, in decreasing
++ * preference order. Get the kernel to allocate the first one
++ * in case it gets Acked.
++ */
++ if (go-&gt;deflate) {
++ p[0] = go-&gt;deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT;
++ p[1] = CILEN_DEFLATE;
++ p[2] = DEFLATE_MAKE_OPT(go-&gt;deflate_size);
++ p[3] = DEFLATE_CHK_SEQUENCE;
++ for (;;) {
++ res = ccp_test(f-&gt;unit, p, CILEN_DEFLATE, 0);
++ if (res &gt; 0) {
++ p += CILEN_DEFLATE;
++ break;
++ }
++ if (res &lt; 0 || go-&gt;deflate_size &lt;= DEFLATE_MIN_WORKS) {
++ go-&gt;deflate = 0;
++ break;
++ }
++ --go-&gt;deflate_size;
++ p[2] = DEFLATE_MAKE_OPT(go-&gt;deflate_size);
++ }
++ if (p != p0 &amp;&amp; go-&gt;deflate_correct &amp;&amp; go-&gt;deflate_draft) {
++ p[0] = CI_DEFLATE_DRAFT;
++ p[1] = CILEN_DEFLATE;
++ p[2] = p[2 - CILEN_DEFLATE];
++ p[3] = DEFLATE_CHK_SEQUENCE;
++ p += CILEN_DEFLATE;
++ }
++ }
++ if (go-&gt;bsd_compress) {
++ p[0] = CI_BSD_COMPRESS;
++ p[1] = CILEN_BSD_COMPRESS;
++ p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go-&gt;bsd_bits);
++ if (p != p0) {
++ p += CILEN_BSD_COMPRESS; /* not the first option */
++ } else {
++ for (;;) {
++ res = ccp_test(f-&gt;unit, p, CILEN_BSD_COMPRESS, 0);
++ if (res &gt; 0) {
++ p += CILEN_BSD_COMPRESS;
++ break;
++ }
++ if (res &lt; 0 || go-&gt;bsd_bits &lt;= BSD_MIN_BITS) {
++ go-&gt;bsd_compress = 0;
++ break;
++ }
++ --go-&gt;bsd_bits;
++ p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go-&gt;bsd_bits);
++ }
++ }
++ }
++ /* XXX Should Predictor 2 be preferable to Predictor 1? */
++ if (go-&gt;predictor_1) {
++ p[0] = CI_PREDICTOR_1;
++ p[1] = CILEN_PREDICTOR_1;
++ if (p == p0 &amp;&amp; ccp_test(f-&gt;unit, p, CILEN_PREDICTOR_1, 0) &lt;= 0) {
++ go-&gt;predictor_1 = 0;
++ } else {
++ p += CILEN_PREDICTOR_1;
++ }
++ }
++ if (go-&gt;predictor_2) {
++ p[0] = CI_PREDICTOR_2;
++ p[1] = CILEN_PREDICTOR_2;
++ if (p == p0 &amp;&amp; ccp_test(f-&gt;unit, p, CILEN_PREDICTOR_2, 0) &lt;= 0) {
++ go-&gt;predictor_2 = 0;
++ } else {
++ p += CILEN_PREDICTOR_2;
++ }
++ }
++
++ go-&gt;method = (p &gt; p0)? p0[0]: -1;
++
++ *lenp = p - p0;
++}
++
++/*
++ * ccp_ackci - process a received configure-ack, and return
++ * 1 iff the packet was OK.
++ */
++static int
++ccp_ackci(f, p, len)
++ fsm *f;
++ u_char *p;
++ int len;
++{
++ ccp_options *go = &amp;ccp_gotoptions[f-&gt;unit];
++ u_char *p0 = p;
++
++ if (go-&gt;deflate) {
++ if (len &lt; CILEN_DEFLATE
++ || p[0] != (go-&gt;deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT)
++ || p[1] != CILEN_DEFLATE
++ || p[2] != DEFLATE_MAKE_OPT(go-&gt;deflate_size)
++ || p[3] != DEFLATE_CHK_SEQUENCE)
++ return 0;
++ p += CILEN_DEFLATE;
++ len -= CILEN_DEFLATE;
++ /* XXX Cope with first/fast ack */
++ if (len == 0)
++ return 1;
++ if (go-&gt;deflate_correct &amp;&amp; go-&gt;deflate_draft) {
++ if (len &lt; CILEN_DEFLATE
++ || p[0] != CI_DEFLATE_DRAFT
++ || p[1] != CILEN_DEFLATE
++ || p[2] != DEFLATE_MAKE_OPT(go-&gt;deflate_size)
++ || p[3] != DEFLATE_CHK_SEQUENCE)
++ return 0;
++ p += CILEN_DEFLATE;
++ len -= CILEN_DEFLATE;
++ }
++ }
++ if (go-&gt;bsd_compress) {
++ if (len &lt; CILEN_BSD_COMPRESS
++ || p[0] != CI_BSD_COMPRESS || p[1] != CILEN_BSD_COMPRESS
++ || p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go-&gt;bsd_bits))
++ return 0;
++ p += CILEN_BSD_COMPRESS;
++ len -= CILEN_BSD_COMPRESS;
++ /* XXX Cope with first/fast ack */
++ if (p == p0 &amp;&amp; len == 0)
++ return 1;
++ }
++ if (go-&gt;predictor_1) {
++ if (len &lt; CILEN_PREDICTOR_1
++ || p[0] != CI_PREDICTOR_1 || p[1] != CILEN_PREDICTOR_1)
++ return 0;
++ p += CILEN_PREDICTOR_1;
++ len -= CILEN_PREDICTOR_1;
++ /* XXX Cope with first/fast ack */
++ if (p == p0 &amp;&amp; len == 0)
++ return 1;
++ }
++ if (go-&gt;predictor_2) {
++ if (len &lt; CILEN_PREDICTOR_2
++ || p[0] != CI_PREDICTOR_2 || p[1] != CILEN_PREDICTOR_2)
++ return 0;
++ p += CILEN_PREDICTOR_2;
++ len -= CILEN_PREDICTOR_2;
++ /* XXX Cope with first/fast ack */
++ if (p == p0 &amp;&amp; len == 0)
++ return 1;
++ }
++
++ if (len != 0)
++ return 0;
++ return 1;
++}
++
++/*
++ * ccp_nakci - process received configure-nak.
++ * Returns 1 iff the nak was OK.
++ */
++static int
++ccp_nakci(f, p, len)
++ fsm *f;
++ u_char *p;
++ int len;
++{
++ ccp_options *go = &amp;ccp_gotoptions[f-&gt;unit];
++ ccp_options no; /* options we've seen already */
++ ccp_options try; /* options to ask for next time */
++
++ memset(&amp;no, 0, sizeof(no));
++ try = *go;
++
++ if (go-&gt;deflate &amp;&amp; len &gt;= CILEN_DEFLATE
++ &amp;&amp; p[0] == (go-&gt;deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT)
++ &amp;&amp; p[1] == CILEN_DEFLATE) {
++ no.deflate = 1;
++ /*
++ * Peer wants us to use a different code size or something.
++ * Stop asking for Deflate if we don't understand his suggestion.
++ */
++ if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL
++ || DEFLATE_SIZE(p[2]) &lt; DEFLATE_MIN_WORKS
++ || p[3] != DEFLATE_CHK_SEQUENCE)
++ try.deflate = 0;
++ else if (DEFLATE_SIZE(p[2]) &lt; go-&gt;deflate_size)
++ try.deflate_size = DEFLATE_SIZE(p[2]);
++ p += CILEN_DEFLATE;
++ len -= CILEN_DEFLATE;
++ if (go-&gt;deflate_correct &amp;&amp; go-&gt;deflate_draft
++ &amp;&amp; len &gt;= CILEN_DEFLATE &amp;&amp; p[0] == CI_DEFLATE_DRAFT
++ &amp;&amp; p[1] == CILEN_DEFLATE) {
++ p += CILEN_DEFLATE;
++ len -= CILEN_DEFLATE;
++ }
++ }
++
++ if (go-&gt;bsd_compress &amp;&amp; len &gt;= CILEN_BSD_COMPRESS
++ &amp;&amp; p[0] == CI_BSD_COMPRESS &amp;&amp; p[1] == CILEN_BSD_COMPRESS) {
++ no.bsd_compress = 1;
++ /*
++ * Peer wants us to use a different number of bits
++ * or a different version.
++ */
++ if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION)
++ try.bsd_compress = 0;
++ else if (BSD_NBITS(p[2]) &lt; go-&gt;bsd_bits)
++ try.bsd_bits = BSD_NBITS(p[2]);
++ p += CILEN_BSD_COMPRESS;
++ len -= CILEN_BSD_COMPRESS;
++ }
++
++ /*
++ * Predictor-1 and 2 have no options, so they can't be Naked.
++ *
++ * There may be remaining options but we ignore them.
++ */
++
++ if (f-&gt;state != OPENED)
++ *go = try;
++ return 1;
++}
++
++/*
++ * ccp_rejci - reject some of our suggested compression methods.
++ */
++static int
++ccp_rejci(f, p, len)
++ fsm *f;
++ u_char *p;
++ int len;
++{
++ ccp_options *go = &amp;ccp_gotoptions[f-&gt;unit];
++ ccp_options try; /* options to request next time */
++
++ try = *go;
++
++ /*
++ * Cope with empty configure-rejects by ceasing to send
++ * configure-requests.
++ */
++ if (len == 0 &amp;&amp; all_rejected[f-&gt;unit])
++ return -1;
++
++ if (go-&gt;deflate &amp;&amp; len &gt;= CILEN_DEFLATE
++ &amp;&amp; p[0] == (go-&gt;deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT)
++ &amp;&amp; p[1] == CILEN_DEFLATE) {
++ if (p[2] != DEFLATE_MAKE_OPT(go-&gt;deflate_size)
++ || p[3] != DEFLATE_CHK_SEQUENCE)
++ return 0; /* Rej is bad */
++ if (go-&gt;deflate_correct)
++ try.deflate_correct = 0;
++ else
++ try.deflate_draft = 0;
++ p += CILEN_DEFLATE;
++ len -= CILEN_DEFLATE;
++ if (go-&gt;deflate_correct &amp;&amp; go-&gt;deflate_draft
++ &amp;&amp; len &gt;= CILEN_DEFLATE &amp;&amp; p[0] == CI_DEFLATE_DRAFT
++ &amp;&amp; p[1] == CILEN_DEFLATE) {
++ if (p[2] != DEFLATE_MAKE_OPT(go-&gt;deflate_size)
++ || p[3] != DEFLATE_CHK_SEQUENCE)
++ return 0; /* Rej is bad */
++ try.deflate_draft = 0;
++ p += CILEN_DEFLATE;
++ len -= CILEN_DEFLATE;
++ }
++ if (!try.deflate_correct &amp;&amp; !try.deflate_draft)
++ try.deflate = 0;
++ }
++ if (go-&gt;bsd_compress &amp;&amp; len &gt;= CILEN_BSD_COMPRESS
++ &amp;&amp; p[0] == CI_BSD_COMPRESS &amp;&amp; p[1] == CILEN_BSD_COMPRESS) {
++ if (p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go-&gt;bsd_bits))
++ return 0;
++ try.bsd_compress = 0;
++ p += CILEN_BSD_COMPRESS;
++ len -= CILEN_BSD_COMPRESS;
++ }
++ if (go-&gt;predictor_1 &amp;&amp; len &gt;= CILEN_PREDICTOR_1
++ &amp;&amp; p[0] == CI_PREDICTOR_1 &amp;&amp; p[1] == CILEN_PREDICTOR_1) {
++ try.predictor_1 = 0;
++ p += CILEN_PREDICTOR_1;
++ len -= CILEN_PREDICTOR_1;
++ }
++ if (go-&gt;predictor_2 &amp;&amp; len &gt;= CILEN_PREDICTOR_2
++ &amp;&amp; p[0] == CI_PREDICTOR_2 &amp;&amp; p[1] == CILEN_PREDICTOR_2) {
++ try.predictor_2 = 0;
++ p += CILEN_PREDICTOR_2;
++ len -= CILEN_PREDICTOR_2;
++ }
++
++ if (len != 0)
++ return 0;
++
++ if (f-&gt;state != OPENED)
++ *go = try;
++
++ return 1;
++}
++
++/*
++ * ccp_reqci - processed a received configure-request.
++ * Returns CONFACK, CONFNAK or CONFREJ and the packet modified
++ * appropriately.
++ */
++static int
++ccp_reqci(f, p, lenp, dont_nak)
++ fsm *f;
++ u_char *p;
++ int *lenp;
++ int dont_nak;
++{
++ int ret, newret, res;
++ u_char *p0, *retp;
++ int len, clen, type, nb;
++ ccp_options *ho = &amp;ccp_hisoptions[f-&gt;unit];
++ ccp_options *ao = &amp;ccp_allowoptions[f-&gt;unit];
++
++ ret = CONFACK;
++ retp = p0 = p;
++ len = *lenp;
++
++ memset(ho, 0, sizeof(ccp_options));
++ ho-&gt;method = (len &gt; 0)? p[0]: -1;
++
++ while (len &gt; 0) {
++ newret = CONFACK;
++ if (len &lt; 2 || p[1] &lt; 2 || p[1] &gt; len) {
++ /* length is bad */
++ clen = len;
++ newret = CONFREJ;
++
++ } else {
++ type = p[0];
++ clen = p[1];
++
++ switch (type) {
++ case CI_DEFLATE:
++ case CI_DEFLATE_DRAFT:
++ if (!ao-&gt;deflate || clen != CILEN_DEFLATE
++ || (!ao-&gt;deflate_correct &amp;&amp; type == CI_DEFLATE)
++ || (!ao-&gt;deflate_draft &amp;&amp; type == CI_DEFLATE_DRAFT)) {
++ newret = CONFREJ;
++ break;
++ }
++
++ ho-&gt;deflate = 1;
++ ho-&gt;deflate_size = nb = DEFLATE_SIZE(p[2]);
++ if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL
++ || p[3] != DEFLATE_CHK_SEQUENCE
++ || nb &gt; ao-&gt;deflate_size || nb &lt; DEFLATE_MIN_WORKS) {
++ newret = CONFNAK;
++ if (!dont_nak) {
++ p[2] = DEFLATE_MAKE_OPT(ao-&gt;deflate_size);
++ p[3] = DEFLATE_CHK_SEQUENCE;
++ /* fall through to test this #bits below */
++ } else
++ break;
++ }
++
++ /*
++ * Check whether we can do Deflate with the window
++ * size they want. If the window is too big, reduce
++ * it until the kernel can cope and nak with that.
++ * We only check this for the first option.
++ */
++ if (p == p0) {
++ for (;;) {
++ res = ccp_test(f-&gt;unit, p, CILEN_DEFLATE, 1);
++ if (res &gt; 0)
++ break; /* it's OK now */
++ if (res &lt; 0 || nb == DEFLATE_MIN_WORKS || dont_nak) {
++ newret = CONFREJ;
++ p[2] = DEFLATE_MAKE_OPT(ho-&gt;deflate_size);
++ break;
++ }
++ newret = CONFNAK;
++ --nb;
++ p[2] = DEFLATE_MAKE_OPT(nb);
++ }
++ }
++ break;
++
++ case CI_BSD_COMPRESS:
++ if (!ao-&gt;bsd_compress || clen != CILEN_BSD_COMPRESS) {
++ newret = CONFREJ;
++ break;
++ }
++
++ ho-&gt;bsd_compress = 1;
++ ho-&gt;bsd_bits = nb = BSD_NBITS(p[2]);
++ if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION
++ || nb &gt; ao-&gt;bsd_bits || nb &lt; BSD_MIN_BITS) {
++ newret = CONFNAK;
++ if (!dont_nak) {
++ p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, ao-&gt;bsd_bits);
++ /* fall through to test this #bits below */
++ } else
++ break;
++ }
++
++ /*
++ * Check whether we can do BSD-Compress with the code
++ * size they want. If the code size is too big, reduce
++ * it until the kernel can cope and nak with that.
++ * We only check this for the first option.
++ */
++ if (p == p0) {
++ for (;;) {
++ res = ccp_test(f-&gt;unit, p, CILEN_BSD_COMPRESS, 1);
++ if (res &gt; 0)
++ break;
++ if (res &lt; 0 || nb == BSD_MIN_BITS || dont_nak) {
++ newret = CONFREJ;
++ p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION,
++ ho-&gt;bsd_bits);
++ break;
++ }
++ newret = CONFNAK;
++ --nb;
++ p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, nb);
++ }
++ }
++ break;
++
++ case CI_PREDICTOR_1:
++ if (!ao-&gt;predictor_1 || clen != CILEN_PREDICTOR_1) {
++ newret = CONFREJ;
++ break;
++ }
++
++ ho-&gt;predictor_1 = 1;
++ if (p == p0
++ &amp;&amp; ccp_test(f-&gt;unit, p, CILEN_PREDICTOR_1, 1) &lt;= 0) {
++ newret = CONFREJ;
++ }
++ break;
++
++ case CI_PREDICTOR_2:
++ if (!ao-&gt;predictor_2 || clen != CILEN_PREDICTOR_2) {
++ newret = CONFREJ;
++ break;
++ }
++
++ ho-&gt;predictor_2 = 1;
++ if (p == p0
++ &amp;&amp; ccp_test(f-&gt;unit, p, CILEN_PREDICTOR_2, 1) &lt;= 0) {
++ newret = CONFREJ;
++ }
++ break;
++
++ default:
++ newret = CONFREJ;
++ }
++ }
++
++ if (newret == CONFNAK &amp;&amp; dont_nak)
++ newret = CONFREJ;
++ if (!(newret == CONFACK || (newret == CONFNAK &amp;&amp; ret == CONFREJ))) {
++ /* we're returning this option */
++ if (newret == CONFREJ &amp;&amp; ret == CONFNAK)
++ retp = p0;
++ ret = newret;
++ if (p != retp)
++ BCOPY(p, retp, clen);
++ retp += clen;
++ }
++
++ p += clen;
++ len -= clen;
++ }
++
++ if (ret != CONFACK) {
++ if (ret == CONFREJ &amp;&amp; *lenp == retp - p0)
++ all_rejected[f-&gt;unit] = 1;
++ else
++ *lenp = retp - p0;
++ }
++ return ret;
++}
++
++/*
++ * Make a string name for a compression method (or 2).
++ */
++static char *
++method_name(opt, opt2)
++ ccp_options *opt, *opt2;
++{
++ static char result[64];
++
++ if (!ANY_COMPRESS(*opt))
++ return &quot;(none)&quot;;
++ switch (opt-&gt;method) {
++ case CI_DEFLATE:
++ case CI_DEFLATE_DRAFT:
++ if (opt2 != NULL &amp;&amp; opt2-&gt;deflate_size != opt-&gt;deflate_size)
++ slprintf(result, sizeof(result), &quot;Deflate%s (%d/%d)&quot;,
++ (opt-&gt;method == CI_DEFLATE_DRAFT? &quot;(old#)&quot;: &quot;&quot;),
++ opt-&gt;deflate_size, opt2-&gt;deflate_size);
++ else
++ slprintf(result, sizeof(result), &quot;Deflate%s (%d)&quot;,
++ (opt-&gt;method == CI_DEFLATE_DRAFT? &quot;(old#)&quot;: &quot;&quot;),
++ opt-&gt;deflate_size);
++ break;
++ case CI_BSD_COMPRESS:
++ if (opt2 != NULL &amp;&amp; opt2-&gt;bsd_bits != opt-&gt;bsd_bits)
++ slprintf(result, sizeof(result), &quot;BSD-Compress (%d/%d)&quot;,
++ opt-&gt;bsd_bits, opt2-&gt;bsd_bits);
++ else
++ slprintf(result, sizeof(result), &quot;BSD-Compress (%d)&quot;,
++ opt-&gt;bsd_bits);
++ break;
++ case CI_PREDICTOR_1:
++ return &quot;Predictor 1&quot;;
++ case CI_PREDICTOR_2:
++ return &quot;Predictor 2&quot;;
++ default:
++ slprintf(result, sizeof(result), &quot;Method %d&quot;, opt-&gt;method);
++ }
++ return result;
++}
++
++/*
++ * CCP has come up - inform the kernel driver and log a message.
++ */
++static void
++ccp_up(f)
++ fsm *f;
++{
++ ccp_options *go = &amp;ccp_gotoptions[f-&gt;unit];
++ ccp_options *ho = &amp;ccp_hisoptions[f-&gt;unit];
++ char method1[64];
++
++ ccp_flags_set(f-&gt;unit, 1, 1);
++ if (ANY_COMPRESS(*go)) {
++ if (ANY_COMPRESS(*ho)) {
++ if (go-&gt;method == ho-&gt;method) {
++ notice(&quot;%s compression enabled&quot;, method_name(go, ho));
++ } else {
++ strlcpy(method1, method_name(go, NULL), sizeof(method1));
++ notice(&quot;%s / %s compression enabled&quot;,
++ method1, method_name(ho, NULL));
++ }
++ } else
++ notice(&quot;%s receive compression enabled&quot;, method_name(go, NULL));
++ } else if (ANY_COMPRESS(*ho))
++ notice(&quot;%s transmit compression enabled&quot;, method_name(ho, NULL));
++}
++
++/*
++ * CCP has gone down - inform the kernel driver.
++ */
++static void
++ccp_down(f)
++ fsm *f;
++{
++ if (ccp_localstate[f-&gt;unit] &amp; RACK_PENDING)
++ UNTIMEOUT(ccp_rack_timeout, f);
++ ccp_localstate[f-&gt;unit] = 0;
++ ccp_flags_set(f-&gt;unit, 1, 0);
++}
++
++/*
++ * Print the contents of a CCP packet.
++ */
++static char *ccp_codenames[] = {
++ &quot;ConfReq&quot;, &quot;ConfAck&quot;, &quot;ConfNak&quot;, &quot;ConfRej&quot;,
++ &quot;TermReq&quot;, &quot;TermAck&quot;, &quot;CodeRej&quot;,
++ NULL, NULL, NULL, NULL, NULL, NULL,
++ &quot;ResetReq&quot;, &quot;ResetAck&quot;,
++};
++
++static int
++ccp_printpkt(p, plen, printer, arg)
++ u_char *p;
++ int plen;
++ void (*printer) __P((void *, char *, ...));
++ void *arg;
++{
++ u_char *p0, *optend;
++ int code, id, len;
++ int optlen;
++
++ p0 = p;
++ if (plen &lt; HEADERLEN)
++ return 0;
++ code = p[0];
++ id = p[1];
++ len = (p[2] &lt;&lt; 8) + p[3];
++ if (len &lt; HEADERLEN || len &gt; plen)
++ return 0;
++
++ if (code &gt;= 1 &amp;&amp; code &lt;= sizeof(ccp_codenames) / sizeof(char *)
++ &amp;&amp; ccp_codenames[code-1] != NULL)
++ printer(arg, &quot; %s&quot;, ccp_codenames[code-1]);
++ else
++ printer(arg, &quot; code=0x%x&quot;, code);
++ printer(arg, &quot; id=0x%x&quot;, id);
++ len -= HEADERLEN;
++ p += HEADERLEN;
++
++ switch (code) {
++ case CONFREQ:
++ case CONFACK:
++ case CONFNAK:
++ case CONFREJ:
++ /* print list of possible compression methods */
++ while (len &gt;= 2) {
++ code = p[0];
++ optlen = p[1];
++ if (optlen &lt; 2 || optlen &gt; len)
++ break;
++ printer(arg, &quot; &lt;&quot;);
++ len -= optlen;
++ optend = p + optlen;
++ switch (code) {
++ case CI_DEFLATE:
++ case CI_DEFLATE_DRAFT:
++ if (optlen &gt;= CILEN_DEFLATE) {
++ printer(arg, &quot;deflate%s %d&quot;,
++ (code == CI_DEFLATE_DRAFT? &quot;(old#)&quot;: &quot;&quot;),
++ DEFLATE_SIZE(p[2]));
++ if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL)
++ printer(arg, &quot; method %d&quot;, DEFLATE_METHOD(p[2]));
++ if (p[3] != DEFLATE_CHK_SEQUENCE)
++ printer(arg, &quot; check %d&quot;, p[3]);
++ p += CILEN_DEFLATE;
++ }
++ break;
++ case CI_BSD_COMPRESS:
++ if (optlen &gt;= CILEN_BSD_COMPRESS) {
++ printer(arg, &quot;bsd v%d %d&quot;, BSD_VERSION(p[2]),
++ BSD_NBITS(p[2]));
++ p += CILEN_BSD_COMPRESS;
++ }
++ break;
++ case CI_PREDICTOR_1:
++ if (optlen &gt;= CILEN_PREDICTOR_1) {
++ printer(arg, &quot;predictor 1&quot;);
++ p += CILEN_PREDICTOR_1;
++ }
++ break;
++ case CI_PREDICTOR_2:
++ if (optlen &gt;= CILEN_PREDICTOR_2) {
++ printer(arg, &quot;predictor 2&quot;);
++ p += CILEN_PREDICTOR_2;
++ }
++ break;
++ }
++ while (p &lt; optend)
++ printer(arg, &quot; %.2x&quot;, *p++);
++ printer(arg, &quot;&gt;&quot;);
++ }
++ break;
++
++ case TERMACK:
++ case TERMREQ:
++ if (len &gt; 0 &amp;&amp; *p &gt;= ' ' &amp;&amp; *p &lt; 0x7f) {
++ print_string((char *)p, len, printer, arg);
++ p += len;
++ len = 0;
++ }
++ break;
++ }
++
++ /* dump out the rest of the packet in hex */
++ while (--len &gt;= 0)
++ printer(arg, &quot; %.2x&quot;, *p++);
++
++ return p - p0;
++}
++
++/*
++ * We have received a packet that the decompressor failed to
++ * decompress. Here we would expect to issue a reset-request, but
++ * Motorola has a patent on resetting the compressor as a result of
++ * detecting an error in the decompressed data after decompression.
++ * (See US patent 5,130,993; international patent publication number
++ * WO 91/10289; Australian patent 73296/91.)
++ *
++ * So we ask the kernel whether the error was detected after
++ * decompression; if it was, we take CCP down, thus disabling
++ * compression :-(, otherwise we issue the reset-request.
++ */
++static void
++ccp_datainput(unit, pkt, len)
++ int unit;
++ u_char *pkt;
++ int len;
++{
++ fsm *f;
++
++ f = &amp;ccp_fsm[unit];
++ if (f-&gt;state == OPENED) {
++ if (ccp_fatal_error(unit)) {
++ /*
++ * Disable compression by taking CCP down.
++ */
++ error(&quot;Lost compression sync: disabling compression&quot;);
++ ccp_close(unit, &quot;Lost compression sync&quot;);
++ } else {
++ /*
++ * Send a reset-request to reset the peer's compressor.
++ * We don't do that if we are still waiting for an
++ * acknowledgement to a previous reset-request.
++ */
++ if (!(ccp_localstate[f-&gt;unit] &amp; RACK_PENDING)) {
++ fsm_sdata(f, CCP_RESETREQ, f-&gt;reqid = ++f-&gt;id, NULL, 0);
++ TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT);
++ ccp_localstate[f-&gt;unit] |= RACK_PENDING;
++ } else
++ ccp_localstate[f-&gt;unit] |= RREQ_REPEAT;
++ }
++ }
++}
++
++/*
++ * Timeout waiting for reset-ack.
++ */
++static void
++ccp_rack_timeout(arg)
++ void *arg;
++{
++ fsm *f = arg;
++
++ if (f-&gt;state == OPENED &amp;&amp; ccp_localstate[f-&gt;unit] &amp; RREQ_REPEAT) {
++ fsm_sdata(f, CCP_RESETREQ, f-&gt;reqid, NULL, 0);
++ TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT);
++ ccp_localstate[f-&gt;unit] &amp;= ~RREQ_REPEAT;
++ } else
++ ccp_localstate[f-&gt;unit] &amp;= ~RACK_PENDING;
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/ccp.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/ccp.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/ccp.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/ccp.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,48 @@
++/*
++ * ccp.h - Definitions for PPP Compression Control Protocol.
++ *
++ * Copyright (c) 1994 The Australian National University.
++ * All rights reserved.
++ *
++ * Permission to use, copy, modify, and distribute this software and its
++ * documentation is hereby granted, provided that the above copyright
++ * notice appears in all copies. This software is provided without any
++ * warranty, express or implied. The Australian National University
++ * makes no representations about the suitability of this software for
++ * any purpose.
++ *
++ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
++ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
++ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
++ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
++ * OF SUCH DAMAGE.
++ *
++ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
++ * ON AN &quot;AS IS&quot; BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
++ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
++ * OR MODIFICATIONS.
++ *
++ * $Id: ccp.h 195720 2001-06-11 11:44:34Z gc $
++ */
++
++typedef struct ccp_options {
++ bool bsd_compress; /* do BSD Compress? */
++ bool deflate; /* do Deflate? */
++ bool predictor_1; /* do Predictor-1? */
++ bool predictor_2; /* do Predictor-2? */
++ bool deflate_correct; /* use correct code for deflate? */
++ bool deflate_draft; /* use draft RFC code for deflate? */
++ u_short bsd_bits; /* # bits/code for BSD Compress */
++ u_short deflate_size; /* lg(window size) for Deflate */
++ short method; /* code for chosen compression method */
++} ccp_options;
++
++extern fsm ccp_fsm[];
++extern ccp_options ccp_wantoptions[];
++extern ccp_options ccp_gotoptions[];
++extern ccp_options ccp_allowoptions[];
++extern ccp_options ccp_hisoptions[];
++
++extern struct protent ccp_protent;
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/ccp.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/chap.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/chap.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/chap.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,860 @@
++/*
++ * chap.c - Challenge Handshake Authentication Protocol.
++ *
++ * Copyright (c) 1993 The Australian National University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by the Australian National University. The name of the University
++ * may not be used to endorse or promote products derived from this
++ * software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * Copyright (c) 1991 Gregory M. Christy.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by Gregory M. Christy. The name of the author may not be used to
++ * endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ */
++
++#define RCSID &quot;$Id: chap.c 195720 2001-06-11 11:44:34Z gc $&quot;
++
++/*
++ * TODO:
++ */
++
++#include &lt;stdio.h&gt;
++#include &lt;string.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/time.h&gt;
++
++#include &quot;pppd.h&quot;
++#include &quot;chap.h&quot;
++#include &quot;md5.h&quot;
++#ifdef CHAPMS
++#include &quot;chap_ms.h&quot;
++#endif
++
++static const char rcsid[] = RCSID;
++
++/*
++ * Command-line options.
++ */
++static option_t chap_option_list[] = {
++ { &quot;chap-restart&quot;, o_int, &amp;chap[0].timeouttime,
++ &quot;Set timeout for CHAP&quot;, OPT_PRIO },
++ { &quot;chap-max-challenge&quot;, o_int, &amp;chap[0].max_transmits,
++ &quot;Set max #xmits for challenge&quot;, OPT_PRIO },
++ { &quot;chap-interval&quot;, o_int, &amp;chap[0].chal_interval,
++ &quot;Set interval for rechallenge&quot;, OPT_PRIO },
++#ifdef MSLANMAN
++ { &quot;ms-lanman&quot;, o_bool, &amp;ms_lanman,
++ &quot;Use LanMan passwd when using MS-CHAP&quot;, 1 },
++#endif
++ { NULL }
++};
++
++/*
++ * Protocol entry points.
++ */
++static void ChapInit __P((int));
++static void ChapLowerUp __P((int));
++static void ChapLowerDown __P((int));
++static void ChapInput __P((int, u_char *, int));
++static void ChapProtocolReject __P((int));
++static int ChapPrintPkt __P((u_char *, int,
++ void (*) __P((void *, char *, ...)), void *));
++
++struct protent chap_protent = {
++ PPP_CHAP,
++ ChapInit,
++ ChapInput,
++ ChapProtocolReject,
++ ChapLowerUp,
++ ChapLowerDown,
++ NULL,
++ NULL,
++ ChapPrintPkt,
++ NULL,
++ 1,
++ &quot;CHAP&quot;,
++ NULL,
++ chap_option_list,
++ NULL,
++ NULL,
++ NULL
++};
++
++chap_state chap[NUM_PPP]; /* CHAP state; one for each unit */
++
++static void ChapChallengeTimeout __P((void *));
++static void ChapResponseTimeout __P((void *));
++static void ChapReceiveChallenge __P((chap_state *, u_char *, int, int));
++static void ChapRechallenge __P((void *));
++static void ChapReceiveResponse __P((chap_state *, u_char *, int, int));
++static void ChapReceiveSuccess __P((chap_state *, u_char *, int, int));
++static void ChapReceiveFailure __P((chap_state *, u_char *, int, int));
++static void ChapSendStatus __P((chap_state *, int));
++static void ChapSendChallenge __P((chap_state *));
++static void ChapSendResponse __P((chap_state *));
++static void ChapGenChallenge __P((chap_state *));
++
++extern double drand48 __P((void));
++extern void srand48 __P((long));
++
++/*
++ * ChapInit - Initialize a CHAP unit.
++ */
++static void
++ChapInit(unit)
++ int unit;
++{
++ chap_state *cstate = &amp;chap[unit];
++
++ BZERO(cstate, sizeof(*cstate));
++ cstate-&gt;unit = unit;
++ cstate-&gt;clientstate = CHAPCS_INITIAL;
++ cstate-&gt;serverstate = CHAPSS_INITIAL;
++ cstate-&gt;timeouttime = CHAP_DEFTIMEOUT;
++ cstate-&gt;max_transmits = CHAP_DEFTRANSMITS;
++ /* random number generator is initialized in magic_init */
++}
++
++
++/*
++ * ChapAuthWithPeer - Authenticate us with our peer (start client).
++ *
++ */
++void
++ChapAuthWithPeer(unit, our_name, digest)
++ int unit;
++ char *our_name;
++ int digest;
++{
++ chap_state *cstate = &amp;chap[unit];
++
++ cstate-&gt;resp_name = our_name;
++ cstate-&gt;resp_type = digest;
++
++ if (cstate-&gt;clientstate == CHAPCS_INITIAL ||
++ cstate-&gt;clientstate == CHAPCS_PENDING) {
++ /* lower layer isn't up - wait until later */
++ cstate-&gt;clientstate = CHAPCS_PENDING;
++ return;
++ }
++
++ /*
++ * We get here as a result of LCP coming up.
++ * So even if CHAP was open before, we will
++ * have to re-authenticate ourselves.
++ */
++ cstate-&gt;clientstate = CHAPCS_LISTEN;
++}
++
++
++/*
++ * ChapAuthPeer - Authenticate our peer (start server).
++ */
++void
++ChapAuthPeer(unit, our_name, digest)
++ int unit;
++ char *our_name;
++ int digest;
++{
++ chap_state *cstate = &amp;chap[unit];
++
++ cstate-&gt;chal_name = our_name;
++ cstate-&gt;chal_type = digest;
++
++ if (cstate-&gt;serverstate == CHAPSS_INITIAL ||
++ cstate-&gt;serverstate == CHAPSS_PENDING) {
++ /* lower layer isn't up - wait until later */
++ cstate-&gt;serverstate = CHAPSS_PENDING;
++ return;
++ }
++
++ ChapGenChallenge(cstate);
++ ChapSendChallenge(cstate); /* crank it up dude! */
++ cstate-&gt;serverstate = CHAPSS_INITIAL_CHAL;
++}
++
++
++/*
++ * ChapChallengeTimeout - Timeout expired on sending challenge.
++ */
++static void
++ChapChallengeTimeout(arg)
++ void *arg;
++{
++ chap_state *cstate = (chap_state *) arg;
++
++ /* if we aren't sending challenges, don't worry. then again we */
++ /* probably shouldn't be here either */
++ if (cstate-&gt;serverstate != CHAPSS_INITIAL_CHAL &amp;&amp;
++ cstate-&gt;serverstate != CHAPSS_RECHALLENGE)
++ return;
++
++ if (cstate-&gt;chal_transmits &gt;= cstate-&gt;max_transmits) {
++ /* give up on peer */
++ error(&quot;Peer failed to respond to CHAP challenge&quot;);
++ cstate-&gt;serverstate = CHAPSS_BADAUTH;
++ auth_peer_fail(cstate-&gt;unit, PPP_CHAP);
++ return;
++ }
++
++ ChapSendChallenge(cstate); /* Re-send challenge */
++}
++
++
++/*
++ * ChapResponseTimeout - Timeout expired on sending response.
++ */
++static void
++ChapResponseTimeout(arg)
++ void *arg;
++{
++ chap_state *cstate = (chap_state *) arg;
++
++ /* if we aren't sending a response, don't worry. */
++ if (cstate-&gt;clientstate != CHAPCS_RESPONSE)
++ return;
++
++ ChapSendResponse(cstate); /* re-send response */
++}
++
++
++/*
++ * ChapRechallenge - Time to challenge the peer again.
++ */
++static void
++ChapRechallenge(arg)
++ void *arg;
++{
++ chap_state *cstate = (chap_state *) arg;
++
++ /* if we aren't sending a response, don't worry. */
++ if (cstate-&gt;serverstate != CHAPSS_OPEN)
++ return;
++
++ ChapGenChallenge(cstate);
++ ChapSendChallenge(cstate);
++ cstate-&gt;serverstate = CHAPSS_RECHALLENGE;
++}
++
++
++/*
++ * ChapLowerUp - The lower layer is up.
++ *
++ * Start up if we have pending requests.
++ */
++static void
++ChapLowerUp(unit)
++ int unit;
++{
++ chap_state *cstate = &amp;chap[unit];
++
++ if (cstate-&gt;clientstate == CHAPCS_INITIAL)
++ cstate-&gt;clientstate = CHAPCS_CLOSED;
++ else if (cstate-&gt;clientstate == CHAPCS_PENDING)
++ cstate-&gt;clientstate = CHAPCS_LISTEN;
++
++ if (cstate-&gt;serverstate == CHAPSS_INITIAL)
++ cstate-&gt;serverstate = CHAPSS_CLOSED;
++ else if (cstate-&gt;serverstate == CHAPSS_PENDING) {
++ ChapGenChallenge(cstate);
++ ChapSendChallenge(cstate);
++ cstate-&gt;serverstate = CHAPSS_INITIAL_CHAL;
++ }
++}
++
++
++/*
++ * ChapLowerDown - The lower layer is down.
++ *
++ * Cancel all timeouts.
++ */
++static void
++ChapLowerDown(unit)
++ int unit;
++{
++ chap_state *cstate = &amp;chap[unit];
++
++ /* Timeout(s) pending? Cancel if so. */
++ if (cstate-&gt;serverstate == CHAPSS_INITIAL_CHAL ||
++ cstate-&gt;serverstate == CHAPSS_RECHALLENGE)
++ UNTIMEOUT(ChapChallengeTimeout, cstate);
++ else if (cstate-&gt;serverstate == CHAPSS_OPEN
++ &amp;&amp; cstate-&gt;chal_interval != 0)
++ UNTIMEOUT(ChapRechallenge, cstate);
++ if (cstate-&gt;clientstate == CHAPCS_RESPONSE)
++ UNTIMEOUT(ChapResponseTimeout, cstate);
++
++ cstate-&gt;clientstate = CHAPCS_INITIAL;
++ cstate-&gt;serverstate = CHAPSS_INITIAL;
++}
++
++
++/*
++ * ChapProtocolReject - Peer doesn't grok CHAP.
++ */
++static void
++ChapProtocolReject(unit)
++ int unit;
++{
++ chap_state *cstate = &amp;chap[unit];
++
++ if (cstate-&gt;serverstate != CHAPSS_INITIAL &amp;&amp;
++ cstate-&gt;serverstate != CHAPSS_CLOSED)
++ auth_peer_fail(unit, PPP_CHAP);
++ if (cstate-&gt;clientstate != CHAPCS_INITIAL &amp;&amp;
++ cstate-&gt;clientstate != CHAPCS_CLOSED)
++ auth_withpeer_fail(unit, PPP_CHAP);
++ ChapLowerDown(unit); /* shutdown chap */
++}
++
++
++/*
++ * ChapInput - Input CHAP packet.
++ */
++static void
++ChapInput(unit, inpacket, packet_len)
++ int unit;
++ u_char *inpacket;
++ int packet_len;
++{
++ chap_state *cstate = &amp;chap[unit];
++ u_char *inp;
++ u_char code, id;
++ int len;
++
++ /*
++ * Parse header (code, id and length).
++ * If packet too short, drop it.
++ */
++ inp = inpacket;
++ if (packet_len &lt; CHAP_HEADERLEN) {
++ CHAPDEBUG((&quot;ChapInput: rcvd short header.&quot;));
++ return;
++ }
++ GETCHAR(code, inp);
++ GETCHAR(id, inp);
++ GETSHORT(len, inp);
++ if (len &lt; CHAP_HEADERLEN) {
++ CHAPDEBUG((&quot;ChapInput: rcvd illegal length.&quot;));
++ return;
++ }
++ if (len &gt; packet_len) {
++ CHAPDEBUG((&quot;ChapInput: rcvd short packet.&quot;));
++ return;
++ }
++ len -= CHAP_HEADERLEN;
++
++ /*
++ * Action depends on code (as in fact it usually does :-).
++ */
++ switch (code) {
++ case CHAP_CHALLENGE:
++ ChapReceiveChallenge(cstate, inp, id, len);
++ break;
++
++ case CHAP_RESPONSE:
++ ChapReceiveResponse(cstate, inp, id, len);
++ break;
++
++ case CHAP_FAILURE:
++ ChapReceiveFailure(cstate, inp, id, len);
++ break;
++
++ case CHAP_SUCCESS:
++ ChapReceiveSuccess(cstate, inp, id, len);
++ break;
++
++ default: /* Need code reject? */
++ warn(&quot;Unknown CHAP code (%d) received.&quot;, code);
++ break;
++ }
++}
++
++
++/*
++ * ChapReceiveChallenge - Receive Challenge and send Response.
++ */
++static void
++ChapReceiveChallenge(cstate, inp, id, len)
++ chap_state *cstate;
++ u_char *inp;
++ int id;
++ int len;
++{
++ int rchallenge_len;
++ u_char *rchallenge;
++ int secret_len;
++ char secret[MAXSECRETLEN];
++ char rhostname[256];
++ MD5_CTX mdContext;
++ u_char hash[MD5_SIGNATURE_SIZE];
++
++ if (cstate-&gt;clientstate == CHAPCS_CLOSED ||
++ cstate-&gt;clientstate == CHAPCS_PENDING) {
++ CHAPDEBUG((&quot;ChapReceiveChallenge: in state %d&quot;, cstate-&gt;clientstate));
++ return;
++ }
++
++ if (len &lt; 2) {
++ CHAPDEBUG((&quot;ChapReceiveChallenge: rcvd short packet.&quot;));
++ return;
++ }
++
++ GETCHAR(rchallenge_len, inp);
++ len -= sizeof (u_char) + rchallenge_len; /* now name field length */
++ if (len &lt; 0) {
++ CHAPDEBUG((&quot;ChapReceiveChallenge: rcvd short packet.&quot;));
++ return;
++ }
++ rchallenge = inp;
++ INCPTR(rchallenge_len, inp);
++
++ if (len &gt;= sizeof(rhostname))
++ len = sizeof(rhostname) - 1;
++ BCOPY(inp, rhostname, len);
++ rhostname[len] = '\000';
++
++ /* Microsoft doesn't send their name back in the PPP packet */
++ if (explicit_remote || (remote_name[0] != 0 &amp;&amp; rhostname[0] == 0)) {
++ strlcpy(rhostname, remote_name, sizeof(rhostname));
++ CHAPDEBUG((&quot;ChapReceiveChallenge: using '%q' as remote name&quot;,
++ rhostname));
++ }
++
++ /* get secret for authenticating ourselves with the specified host */
++ if (!get_secret(cstate-&gt;unit, cstate-&gt;resp_name, rhostname,
++ secret, &amp;secret_len, 0)) {
++ secret_len = 0; /* assume null secret if can't find one */
++ warn(&quot;No CHAP secret found for authenticating us to %q&quot;, rhostname);
++ }
++
++ /* cancel response send timeout if necessary */
++ if (cstate-&gt;clientstate == CHAPCS_RESPONSE)
++ UNTIMEOUT(ChapResponseTimeout, cstate);
++
++ cstate-&gt;resp_id = id;
++ cstate-&gt;resp_transmits = 0;
++
++ /* generate MD based on negotiated type */
++ switch (cstate-&gt;resp_type) {
++
++ case CHAP_DIGEST_MD5:
++ MD5Init(&amp;mdContext);
++ MD5Update(&amp;mdContext, &amp;cstate-&gt;resp_id, 1);
++ MD5Update(&amp;mdContext, secret, secret_len);
++ MD5Update(&amp;mdContext, rchallenge, rchallenge_len);
++ MD5Final(hash, &amp;mdContext);
++ BCOPY(hash, cstate-&gt;response, MD5_SIGNATURE_SIZE);
++ cstate-&gt;resp_length = MD5_SIGNATURE_SIZE;
++ break;
++
++#ifdef CHAPMS
++ case CHAP_MICROSOFT:
++ ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len);
++ break;
++#endif
++
++ default:
++ CHAPDEBUG((&quot;unknown digest type %d&quot;, cstate-&gt;resp_type));
++ return;
++ }
++
++ BZERO(secret, sizeof(secret));
++ ChapSendResponse(cstate);
++}
++
++
++/*
++ * ChapReceiveResponse - Receive and process response.
++ */
++static void
++ChapReceiveResponse(cstate, inp, id, len)
++ chap_state *cstate;
++ u_char *inp;
++ int id;
++ int len;
++{
++ u_char *remmd, remmd_len;
++ int secret_len, old_state;
++ int code;
++ char rhostname[256];
++ MD5_CTX mdContext;
++ char secret[MAXSECRETLEN];
++ u_char hash[MD5_SIGNATURE_SIZE];
++
++ if (cstate-&gt;serverstate == CHAPSS_CLOSED ||
++ cstate-&gt;serverstate == CHAPSS_PENDING) {
++ CHAPDEBUG((&quot;ChapReceiveResponse: in state %d&quot;, cstate-&gt;serverstate));
++ return;
++ }
++
++ if (id != cstate-&gt;chal_id)
++ return; /* doesn't match ID of last challenge */
++
++ /*
++ * If we have received a duplicate or bogus Response,
++ * we have to send the same answer (Success/Failure)
++ * as we did for the first Response we saw.
++ */
++ if (cstate-&gt;serverstate == CHAPSS_OPEN) {
++ ChapSendStatus(cstate, CHAP_SUCCESS);
++ return;
++ }
++ if (cstate-&gt;serverstate == CHAPSS_BADAUTH) {
++ ChapSendStatus(cstate, CHAP_FAILURE);
++ return;
++ }
++
++ if (len &lt; 2) {
++ CHAPDEBUG((&quot;ChapReceiveResponse: rcvd short packet.&quot;));
++ return;
++ }
++ GETCHAR(remmd_len, inp); /* get length of MD */
++ remmd = inp; /* get pointer to MD */
++ INCPTR(remmd_len, inp);
++
++ len -= sizeof (u_char) + remmd_len;
++ if (len &lt; 0) {
++ CHAPDEBUG((&quot;ChapReceiveResponse: rcvd short packet.&quot;));
++ return;
++ }
++
++ UNTIMEOUT(ChapChallengeTimeout, cstate);
++
++ if (len &gt;= sizeof(rhostname))
++ len = sizeof(rhostname) - 1;
++ BCOPY(inp, rhostname, len);
++ rhostname[len] = '\000';
++
++ /*
++ * Get secret for authenticating them with us,
++ * do the hash ourselves, and compare the result.
++ */
++ code = CHAP_FAILURE;
++ if (!get_secret(cstate-&gt;unit, (explicit_remote? remote_name: rhostname),
++ cstate-&gt;chal_name, secret, &amp;secret_len, 1)) {
++ warn(&quot;No CHAP secret found for authenticating %q&quot;, rhostname);
++ } else {
++
++ /* generate MD based on negotiated type */
++ switch (cstate-&gt;chal_type) {
++
++ case CHAP_DIGEST_MD5: /* only MD5 is defined for now */
++ if (remmd_len != MD5_SIGNATURE_SIZE)
++ break; /* it's not even the right length */
++ MD5Init(&amp;mdContext);
++ MD5Update(&amp;mdContext, &amp;cstate-&gt;chal_id, 1);
++ MD5Update(&amp;mdContext, secret, secret_len);
++ MD5Update(&amp;mdContext, cstate-&gt;challenge, cstate-&gt;chal_len);
++ MD5Final(hash, &amp;mdContext);
++
++ /* compare local and remote MDs and send the appropriate status */
++ if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0)
++ code = CHAP_SUCCESS; /* they are the same! */
++ break;
++
++ default:
++ CHAPDEBUG((&quot;unknown digest type %d&quot;, cstate-&gt;chal_type));
++ }
++ }
++
++ BZERO(secret, sizeof(secret));
++ ChapSendStatus(cstate, code);
++
++ if (code == CHAP_SUCCESS) {
++ old_state = cstate-&gt;serverstate;
++ cstate-&gt;serverstate = CHAPSS_OPEN;
++ if (old_state == CHAPSS_INITIAL_CHAL) {
++ auth_peer_success(cstate-&gt;unit, PPP_CHAP, rhostname, len);
++ }
++ if (cstate-&gt;chal_interval != 0)
++ TIMEOUT(ChapRechallenge, cstate, cstate-&gt;chal_interval);
++ notice(&quot;CHAP peer authentication succeeded for %q&quot;, rhostname);
++
++ } else {
++ error(&quot;CHAP peer authentication failed for remote host %q&quot;, rhostname);
++ cstate-&gt;serverstate = CHAPSS_BADAUTH;
++ auth_peer_fail(cstate-&gt;unit, PPP_CHAP);
++ }
++}
++
++/*
++ * ChapReceiveSuccess - Receive Success
++ */
++static void
++ChapReceiveSuccess(cstate, inp, id, len)
++ chap_state *cstate;
++ u_char *inp;
++ u_char id;
++ int len;
++{
++
++ if (cstate-&gt;clientstate == CHAPCS_OPEN)
++ /* presumably an answer to a duplicate response */
++ return;
++
++ if (cstate-&gt;clientstate != CHAPCS_RESPONSE) {
++ /* don't know what this is */
++ CHAPDEBUG((&quot;ChapReceiveSuccess: in state %d\n&quot;, cstate-&gt;clientstate));
++ return;
++ }
++
++ UNTIMEOUT(ChapResponseTimeout, cstate);
++
++ /*
++ * Print message.
++ */
++ if (len &gt; 0)
++ PRINTMSG(inp, len);
++
++ cstate-&gt;clientstate = CHAPCS_OPEN;
++
++ auth_withpeer_success(cstate-&gt;unit, PPP_CHAP);
++}
++
++
++/*
++ * ChapReceiveFailure - Receive failure.
++ */
++static void
++ChapReceiveFailure(cstate, inp, id, len)
++ chap_state *cstate;
++ u_char *inp;
++ u_char id;
++ int len;
++{
++ if (cstate-&gt;clientstate != CHAPCS_RESPONSE) {
++ /* don't know what this is */
++ CHAPDEBUG((&quot;ChapReceiveFailure: in state %d\n&quot;, cstate-&gt;clientstate));
++ return;
++ }
++
++ UNTIMEOUT(ChapResponseTimeout, cstate);
++
++ /*
++ * Print message.
++ */
++ if (len &gt; 0)
++ PRINTMSG(inp, len);
++
++ error(&quot;CHAP authentication failed&quot;);
++ auth_withpeer_fail(cstate-&gt;unit, PPP_CHAP);
++}
++
++
++/*
++ * ChapSendChallenge - Send an Authenticate challenge.
++ */
++static void
++ChapSendChallenge(cstate)
++ chap_state *cstate;
++{
++ u_char *outp;
++ int chal_len, name_len;
++ int outlen;
++
++ chal_len = cstate-&gt;chal_len;
++ name_len = strlen(cstate-&gt;chal_name);
++ outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;
++ outp = outpacket_buf;
++
++ MAKEHEADER(outp, PPP_CHAP); /* paste in a CHAP header */
++
++ PUTCHAR(CHAP_CHALLENGE, outp);
++ PUTCHAR(cstate-&gt;chal_id, outp);
++ PUTSHORT(outlen, outp);
++
++ PUTCHAR(chal_len, outp); /* put length of challenge */
++ BCOPY(cstate-&gt;challenge, outp, chal_len);
++ INCPTR(chal_len, outp);
++
++ BCOPY(cstate-&gt;chal_name, outp, name_len); /* append hostname */
++
++ output(cstate-&gt;unit, outpacket_buf, outlen + PPP_HDRLEN);
++
++ TIMEOUT(ChapChallengeTimeout, cstate, cstate-&gt;timeouttime);
++ ++cstate-&gt;chal_transmits;
++}
++
++
++/*
++ * ChapSendStatus - Send a status response (ack or nak).
++ */
++static void
++ChapSendStatus(cstate, code)
++ chap_state *cstate;
++ int code;
++{
++ u_char *outp;
++ int outlen, msglen;
++ char msg[256];
++
++ if (code == CHAP_SUCCESS)
++ slprintf(msg, sizeof(msg), &quot;Welcome to %s.&quot;, hostname);
++ else
++ slprintf(msg, sizeof(msg), &quot;I don't like you. Go 'way.&quot;);
++ msglen = strlen(msg);
++
++ outlen = CHAP_HEADERLEN + msglen;
++ outp = outpacket_buf;
++
++ MAKEHEADER(outp, PPP_CHAP); /* paste in a header */
++
++ PUTCHAR(code, outp);
++ PUTCHAR(cstate-&gt;chal_id, outp);
++ PUTSHORT(outlen, outp);
++ BCOPY(msg, outp, msglen);
++ output(cstate-&gt;unit, outpacket_buf, outlen + PPP_HDRLEN);
++}
++
++/*
++ * ChapGenChallenge is used to generate a pseudo-random challenge string of
++ * a pseudo-random length between min_len and max_len. The challenge
++ * string and its length are stored in *cstate, and various other fields of
++ * *cstate are initialized.
++ */
++
++static void
++ChapGenChallenge(cstate)
++ chap_state *cstate;
++{
++ int chal_len;
++ u_char *ptr = cstate-&gt;challenge;
++ int i;
++
++ /* pick a random challenge length between MIN_CHALLENGE_LENGTH and
++ MAX_CHALLENGE_LENGTH */
++ chal_len = (unsigned) ((drand48() *
++ (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) +
++ MIN_CHALLENGE_LENGTH);
++ cstate-&gt;chal_len = chal_len;
++ cstate-&gt;chal_id = ++cstate-&gt;id;
++ cstate-&gt;chal_transmits = 0;
++
++ /* generate a random string */
++ for (i = 0; i &lt; chal_len; i++)
++ *ptr++ = (char) (drand48() * 0xff);
++}
++
++/*
++ * ChapSendResponse - send a response packet with values as specified
++ * in *cstate.
++ */
++/* ARGSUSED */
++static void
++ChapSendResponse(cstate)
++ chap_state *cstate;
++{
++ u_char *outp;
++ int outlen, md_len, name_len;
++
++ md_len = cstate-&gt;resp_length;
++ name_len = strlen(cstate-&gt;resp_name);
++ outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;
++ outp = outpacket_buf;
++
++ MAKEHEADER(outp, PPP_CHAP);
++
++ PUTCHAR(CHAP_RESPONSE, outp); /* we are a response */
++ PUTCHAR(cstate-&gt;resp_id, outp); /* copy id from challenge packet */
++ PUTSHORT(outlen, outp); /* packet length */
++
++ PUTCHAR(md_len, outp); /* length of MD */
++ BCOPY(cstate-&gt;response, outp, md_len); /* copy MD to buffer */
++ INCPTR(md_len, outp);
++
++ BCOPY(cstate-&gt;resp_name, outp, name_len); /* append our name */
++
++ /* send the packet */
++ output(cstate-&gt;unit, outpacket_buf, outlen + PPP_HDRLEN);
++
++ cstate-&gt;clientstate = CHAPCS_RESPONSE;
++ TIMEOUT(ChapResponseTimeout, cstate, cstate-&gt;timeouttime);
++ ++cstate-&gt;resp_transmits;
++}
++
++/*
++ * ChapPrintPkt - print the contents of a CHAP packet.
++ */
++static char *ChapCodenames[] = {
++ &quot;Challenge&quot;, &quot;Response&quot;, &quot;Success&quot;, &quot;Failure&quot;
++};
++
++static int
++ChapPrintPkt(p, plen, printer, arg)
++ u_char *p;
++ int plen;
++ void (*printer) __P((void *, char *, ...));
++ void *arg;
++{
++ int code, id, len;
++ int clen, nlen;
++ u_char x;
++
++ if (plen &lt; CHAP_HEADERLEN)
++ return 0;
++ GETCHAR(code, p);
++ GETCHAR(id, p);
++ GETSHORT(len, p);
++ if (len &lt; CHAP_HEADERLEN || len &gt; plen)
++ return 0;
++
++ if (code &gt;= 1 &amp;&amp; code &lt;= sizeof(ChapCodenames) / sizeof(char *))
++ printer(arg, &quot; %s&quot;, ChapCodenames[code-1]);
++ else
++ printer(arg, &quot; code=0x%x&quot;, code);
++ printer(arg, &quot; id=0x%x&quot;, id);
++ len -= CHAP_HEADERLEN;
++ switch (code) {
++ case CHAP_CHALLENGE:
++ case CHAP_RESPONSE:
++ if (len &lt; 1)
++ break;
++ clen = p[0];
++ if (len &lt; clen + 1)
++ break;
++ ++p;
++ nlen = len - clen - 1;
++ printer(arg, &quot; &lt;&quot;);
++ for (; clen &gt; 0; --clen) {
++ GETCHAR(x, p);
++ printer(arg, &quot;%.2x&quot;, x);
++ }
++ printer(arg, &quot;&gt;, name = &quot;);
++ print_string((char *)p, nlen, printer, arg);
++ break;
++ case CHAP_FAILURE:
++ case CHAP_SUCCESS:
++ printer(arg, &quot; &quot;);
++ print_string((char *)p, len, printer, arg);
++ break;
++ default:
++ for (clen = len; clen &gt; 0; --clen) {
++ GETCHAR(x, p);
++ printer(arg, &quot; %.2x&quot;, x);
++ }
++ }
++
++ return len + CHAP_HEADERLEN;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/chap.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/chap.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/chap.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/chap.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,124 @@
++/*
++ * chap.h - Challenge Handshake Authentication Protocol definitions.
++ *
++ * Copyright (c) 1993 The Australian National University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by the Australian National University. The name of the University
++ * may not be used to endorse or promote products derived from this
++ * software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * Copyright (c) 1991 Gregory M. Christy
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by the author.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * $Id: chap.h 195720 2001-06-11 11:44:34Z gc $
++ */
++
++#ifndef __CHAP_INCLUDE__
++
++/* Code + ID + length */
++#define CHAP_HEADERLEN 4
++
++/*
++ * CHAP codes.
++ */
++
++#define CHAP_DIGEST_MD5 5 /* use MD5 algorithm */
++#define MD5_SIGNATURE_SIZE 16 /* 16 bytes in a MD5 message digest */
++#define CHAP_MICROSOFT 0x80 /* use Microsoft-compatible alg. */
++#define MS_CHAP_RESPONSE_LEN 49 /* Response length for MS-CHAP */
++
++#define CHAP_CHALLENGE 1
++#define CHAP_RESPONSE 2
++#define CHAP_SUCCESS 3
++#define CHAP_FAILURE 4
++
++/*
++ * Challenge lengths (for challenges we send) and other limits.
++ */
++#define MIN_CHALLENGE_LENGTH 16
++#define MAX_CHALLENGE_LENGTH 24
++#define MAX_RESPONSE_LENGTH 64 /* sufficient for MD5 or MS-CHAP */
++
++/*
++ * Each interface is described by a chap structure.
++ */
++
++typedef struct chap_state {
++ int unit; /* Interface unit number */
++ int clientstate; /* Client state */
++ int serverstate; /* Server state */
++ u_char challenge[MAX_CHALLENGE_LENGTH]; /* last challenge string sent */
++ u_char chal_len; /* challenge length */
++ u_char chal_id; /* ID of last challenge */
++ u_char chal_type; /* hash algorithm for challenges */
++ u_char id; /* Current id */
++ char *chal_name; /* Our name to use with challenge */
++ int chal_interval; /* Time until we challenge peer again */
++ int timeouttime; /* Timeout time in seconds */
++ int max_transmits; /* Maximum # of challenge transmissions */
++ int chal_transmits; /* Number of transmissions of challenge */
++ int resp_transmits; /* Number of transmissions of response */
++ u_char response[MAX_RESPONSE_LENGTH]; /* Response to send */
++ u_char resp_length; /* length of response */
++ u_char resp_id; /* ID for response messages */
++ u_char resp_type; /* hash algorithm for responses */
++ char *resp_name; /* Our name to send with response */
++} chap_state;
++
++
++/*
++ * Client (peer) states.
++ */
++#define CHAPCS_INITIAL 0 /* Lower layer down, not opened */
++#define CHAPCS_CLOSED 1 /* Lower layer up, not opened */
++#define CHAPCS_PENDING 2 /* Auth us to peer when lower up */
++#define CHAPCS_LISTEN 3 /* Listening for a challenge */
++#define CHAPCS_RESPONSE 4 /* Sent response, waiting for status */
++#define CHAPCS_OPEN 5 /* We've received Success */
++
++/*
++ * Server (authenticator) states.
++ */
++#define CHAPSS_INITIAL 0 /* Lower layer down, not opened */
++#define CHAPSS_CLOSED 1 /* Lower layer up, not opened */
++#define CHAPSS_PENDING 2 /* Auth peer when lower up */
++#define CHAPSS_INITIAL_CHAL 3 /* We've sent the first challenge */
++#define CHAPSS_OPEN 4 /* We've sent a Success msg */
++#define CHAPSS_RECHALLENGE 5 /* We've sent another challenge */
++#define CHAPSS_BADAUTH 6 /* We've sent a Failure msg */
++
++/*
++ * Timeouts.
++ */
++#define CHAP_DEFTIMEOUT 3 /* Timeout time in seconds */
++#define CHAP_DEFTRANSMITS 10 /* max # times to send challenge */
++
++extern chap_state chap[];
++
++void ChapAuthWithPeer __P((int, char *, int));
++void ChapAuthPeer __P((int, char *, int));
++
++extern struct protent chap_protent;
++
++#define __CHAP_INCLUDE__
++#endif /* __CHAP_INCLUDE__ */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/chap.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/chap_ms.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/chap_ms.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/chap_ms.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,338 @@
++/*
++ * chap_ms.c - Microsoft MS-CHAP compatible implementation.
++ *
++ * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
++ * <A HREF="http://www.strataware.com/">http://www.strataware.com/</A>
++ *
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by Eric Rosenquist. The name of the author may not be used to
++ * endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ */
++
++/*
++ * Modifications by Lauri Pesonen / <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">lpesonen at clinet.fi</A>, april 1997
++ *
++ * Implemented LANManager type password response to MS-CHAP challenges.
++ * Now pppd provides both NT style and LANMan style blocks, and the
++ * prefered is set by option &quot;ms-lanman&quot;. Default is to use NT.
++ * The hash text (StdText) was taken from Win95 RASAPI32.DLL.
++ *
++ * You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
++ */
++
++#define RCSID &quot;$Id: chap_ms.c 195720 2001-06-11 11:44:34Z gc $&quot;
++
++#ifdef CHAPMS
++
++#include &lt;stdio.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++#include &lt;ctype.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/time.h&gt;
++#include &lt;unistd.h&gt;
++#ifdef HAVE_CRYPT_H
++#include &lt;crypt.h&gt;
++#endif
++
++#include &quot;pppd.h&quot;
++#include &quot;chap.h&quot;
++#include &quot;chap_ms.h&quot;
++#include &quot;md4.h&quot;
++
++#ifndef USE_CRYPT
++#include &lt;des.h&gt;
++#endif
++
++static const char rcsid[] = RCSID;
++
++typedef struct {
++ u_char LANManResp[24];
++ u_char NTResp[24];
++ u_char UseNT; /* If 1, ignore the LANMan response field */
++} MS_ChapResponse;
++/* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse),
++ in case this struct gets padded. */
++
++
++static void ChallengeResponse __P((u_char *, u_char *, u_char *));
++static void DesEncrypt __P((u_char *, u_char *, u_char *));
++static void MakeKey __P((u_char *, u_char *));
++static u_char Get7Bits __P((u_char *, int));
++static void ChapMS_NT __P((char *, int, char *, int, MS_ChapResponse *));
++#ifdef MSLANMAN
++static void ChapMS_LANMan __P((char *, int, char *, int, MS_ChapResponse *));
++#endif
++
++#ifdef USE_CRYPT
++static void Expand __P((u_char *, u_char *));
++static void Collapse __P((u_char *, u_char *));
++#endif
++
++#ifdef MSLANMAN
++bool ms_lanman = 0; /* Use LanMan password instead of NT */
++ /* Has meaning only with MS-CHAP challenges */
++#endif
++
++static void
++ChallengeResponse(challenge, pwHash, response)
++ u_char *challenge; /* IN 8 octets */
++ u_char *pwHash; /* IN 16 octets */
++ u_char *response; /* OUT 24 octets */
++{
++ char ZPasswordHash[21];
++
++ BZERO(ZPasswordHash, sizeof(ZPasswordHash));
++ BCOPY(pwHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
++
++#if 0
++ dbglog(&quot;ChallengeResponse - ZPasswordHash %.*B&quot;,
++ sizeof(ZPasswordHash), ZPasswordHash);
++#endif
++
++ DesEncrypt(challenge, ZPasswordHash + 0, response + 0);
++ DesEncrypt(challenge, ZPasswordHash + 7, response + 8);
++ DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
++
++#if 0
++ dbglog(&quot;ChallengeResponse - response %.24B&quot;, response);
++#endif
++}
++
++
++#ifdef USE_CRYPT
++static void
++DesEncrypt(clear, key, cipher)
++ u_char *clear; /* IN 8 octets */
++ u_char *key; /* IN 7 octets */
++ u_char *cipher; /* OUT 8 octets */
++{
++ u_char des_key[8];
++ u_char crypt_key[66];
++ u_char des_input[66];
++
++ MakeKey(key, des_key);
++
++ Expand(des_key, crypt_key);
++ setkey(crypt_key);
++
++#if 0
++ CHAPDEBUG((LOG_INFO, &quot;DesEncrypt: 8 octet input : %.8B&quot;, clear));
++#endif
++
++ Expand(clear, des_input);
++ encrypt(des_input, 0);
++ Collapse(des_input, cipher);
++
++#if 0
++ CHAPDEBUG((LOG_INFO, &quot;DesEncrypt: 8 octet output: %.8B&quot;, cipher));
++#endif
++}
++
++#else /* USE_CRYPT */
++
++static void
++DesEncrypt(clear, key, cipher)
++ u_char *clear; /* IN 8 octets */
++ u_char *key; /* IN 7 octets */
++ u_char *cipher; /* OUT 8 octets */
++{
++ des_cblock des_key;
++ des_key_schedule key_schedule;
++
++ MakeKey(key, des_key);
++
++ des_set_key(&amp;des_key, key_schedule);
++
++#if 0
++ CHAPDEBUG((LOG_INFO, &quot;DesEncrypt: 8 octet input : %.8B&quot;, clear));
++#endif
++
++ des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
++
++#if 0
++ CHAPDEBUG((LOG_INFO, &quot;DesEncrypt: 8 octet output: %.8B&quot;, cipher));
++#endif
++}
++
++#endif /* USE_CRYPT */
++
++
++static u_char Get7Bits(input, startBit)
++ u_char *input;
++ int startBit;
++{
++ register unsigned int word;
++
++ word = (unsigned)input[startBit / 8] &lt;&lt; 8;
++ word |= (unsigned)input[startBit / 8 + 1];
++
++ word &gt;&gt;= 15 - (startBit % 8 + 7);
++
++ return word &amp; 0xFE;
++}
++
++#ifdef USE_CRYPT
++
++/* in == 8-byte string (expanded version of the 56-bit key)
++ * out == 64-byte string where each byte is either 1 or 0
++ * Note that the low-order &quot;bit&quot; is always ignored by by setkey()
++ */
++static void Expand(in, out)
++ u_char *in;
++ u_char *out;
++{
++ int j, c;
++ int i;
++
++ for(i = 0; i &lt; 64; in++){
++ c = *in;
++ for(j = 7; j &gt;= 0; j--)
++ *out++ = (c &gt;&gt; j) &amp; 01;
++ i += 8;
++ }
++}
++
++/* The inverse of Expand
++ */
++static void Collapse(in, out)
++ u_char *in;
++ u_char *out;
++{
++ int j;
++ int i;
++ unsigned int c;
++
++ for (i = 0; i &lt; 64; i += 8, out++) {
++ c = 0;
++ for (j = 7; j &gt;= 0; j--, in++)
++ c |= *in &lt;&lt; j;
++ *out = c &amp; 0xff;
++ }
++}
++#endif
++
++static void MakeKey(key, des_key)
++ u_char *key; /* IN 56 bit DES key missing parity bits */
++ u_char *des_key; /* OUT 64 bit DES key with parity bits added */
++{
++ des_key[0] = Get7Bits(key, 0);
++ des_key[1] = Get7Bits(key, 7);
++ des_key[2] = Get7Bits(key, 14);
++ des_key[3] = Get7Bits(key, 21);
++ des_key[4] = Get7Bits(key, 28);
++ des_key[5] = Get7Bits(key, 35);
++ des_key[6] = Get7Bits(key, 42);
++ des_key[7] = Get7Bits(key, 49);
++
++#ifndef USE_CRYPT
++ des_set_odd_parity((des_cblock *)des_key);
++#endif
++
++#if 0
++ CHAPDEBUG((LOG_INFO, &quot;MakeKey: 56-bit input : %.7B&quot;, key));
++ CHAPDEBUG((LOG_INFO, &quot;MakeKey: 64-bit output: %.8B&quot;, des_key));
++#endif
++}
++
++static void
++ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, response)
++ char *rchallenge;
++ int rchallenge_len;
++ char *secret;
++ int secret_len;
++ MS_ChapResponse *response;
++{
++ int i;
++#ifdef __NetBSD__
++ /* NetBSD uses the libc md4 routines which take bytes instead of bits */
++ int mdlen = secret_len * 2;
++#else
++ int mdlen = secret_len * 2 * 8;
++#endif
++ MD4_CTX md4Context;
++ u_char hash[MD4_SIGNATURE_SIZE];
++ u_char unicodePassword[MAX_NT_PASSWORD * 2];
++
++ /* Initialize the Unicode version of the secret (== password). */
++ /* This implicitly supports 8-bit ISO8859/1 characters. */
++ BZERO(unicodePassword, sizeof(unicodePassword));
++ for (i = 0; i &lt; secret_len; i++)
++ unicodePassword[i * 2] = (u_char)secret[i];
++
++ MD4Init(&amp;md4Context);
++ MD4Update(&amp;md4Context, unicodePassword, mdlen);
++
++ MD4Final(hash, &amp;md4Context); /* Tell MD4 we're done */
++
++ ChallengeResponse(rchallenge, hash, response-&gt;NTResp);
++}
++
++#ifdef MSLANMAN
++static u_char *StdText = (u_char *)&quot;KGS!@#$%&quot;; /* key from rasapi32.dll */
++
++static void
++ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, response)
++ char *rchallenge;
++ int rchallenge_len;
++ char *secret;
++ int secret_len;
++ MS_ChapResponse *response;
++{
++ int i;
++ u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
++ u_char PasswordHash[MD4_SIGNATURE_SIZE];
++
++ /* LANMan password is case insensitive */
++ BZERO(UcasePassword, sizeof(UcasePassword));
++ for (i = 0; i &lt; secret_len; i++)
++ UcasePassword[i] = (u_char)toupper(secret[i]);
++ DesEncrypt( StdText, UcasePassword + 0, PasswordHash + 0 );
++ DesEncrypt( StdText, UcasePassword + 7, PasswordHash + 8 );
++ ChallengeResponse(rchallenge, PasswordHash, response-&gt;LANManResp);
++}
++#endif
++
++void
++ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len)
++ chap_state *cstate;
++ char *rchallenge;
++ int rchallenge_len;
++ char *secret;
++ int secret_len;
++{
++ MS_ChapResponse response;
++
++#if 0
++ CHAPDEBUG((LOG_INFO, &quot;ChapMS: secret is '%.*s'&quot;, secret_len, secret));
++#endif
++ BZERO(&amp;response, sizeof(response));
++
++ /* Calculate both always */
++ ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &amp;response);
++
++#ifdef MSLANMAN
++ ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &amp;response);
++
++ /* prefered method is set by option */
++ response.UseNT = !ms_lanman;
++#else
++ response.UseNT = 1;
++#endif
++
++ BCOPY(&amp;response, cstate-&gt;response, MS_CHAP_RESPONSE_LEN);
++ cstate-&gt;resp_length = MS_CHAP_RESPONSE_LEN;
++}
++
++#endif /* CHAPMS */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/chap_ms.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/chap_ms.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/chap_ms.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/chap_ms.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,33 @@
++/*
++ * chap.h - Challenge Handshake Authentication Protocol definitions.
++ *
++ * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
++ * <A HREF="http://www.strataware.com/">http://www.strataware.com/</A>
++ *
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by Eric Rosenquist. The name of the author may not be used to
++ * endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * $Id: chap_ms.h 195720 2001-06-11 11:44:34Z gc $
++ */
++
++#ifndef __CHAPMS_INCLUDE__
++
++#define MD4_SIGNATURE_SIZE 16 /* 16 bytes in a MD4 message digest */
++#define MAX_NT_PASSWORD 256 /* Maximum number of (Unicode) chars in an NT password */
++
++void ChapMS __P((chap_state *, char *, int, char *, int));
++
++#define __CHAPMS_INCLUDE__
++#endif /* __CHAPMS_INCLUDE__ */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/chap_ms.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/demand.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/demand.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/demand.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,351 @@
++/*
++ * demand.c - Support routines for demand-dialling.
++ *
++ * Copyright (c) 1993 The Australian National University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by the Australian National University. The name of the University
++ * may not be used to endorse or promote products derived from this
++ * software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ */
++
++#define RCSID &quot;$Id: demand.c 195720 2001-06-11 11:44:34Z gc $&quot;
++
++#include &lt;stdio.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++#include &lt;errno.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;netdb.h&gt;
++#include &lt;sys/param.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/wait.h&gt;
++#include &lt;sys/time.h&gt;
++#include &lt;sys/resource.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;sys/socket.h&gt;
++#ifdef PPP_FILTER
++#include &lt;net/if.h&gt;
++#include &lt;net/bpf.h&gt;
++#include &lt;pcap.h&gt;
++#endif
++
++#include &quot;pppd.h&quot;
++#include &quot;fsm.h&quot;
++#include &quot;ipcp.h&quot;
++#include &quot;lcp.h&quot;
++
++static const char rcsid[] = RCSID;
++
++char *frame;
++int framelen;
++int framemax;
++int escape_flag;
++int flush_flag;
++int fcs;
++
++struct packet {
++ int length;
++ struct packet *next;
++ unsigned char data[1];
++};
++
++struct packet *pend_q;
++struct packet *pend_qtail;
++
++static int active_packet __P((unsigned char *, int));
++
++/*
++ * demand_conf - configure the interface for doing dial-on-demand.
++ */
++void
++demand_conf()
++{
++ int i;
++ struct protent *protp;
++
++/* framemax = lcp_allowoptions[0].mru;
++ if (framemax &lt; PPP_MRU) */
++ framemax = PPP_MRU;
++ framemax += PPP_HDRLEN + PPP_FCSLEN;
++ frame = malloc(framemax);
++ if (frame == NULL)
++ novm(&quot;demand frame&quot;);
++ framelen = 0;
++ pend_q = NULL;
++ escape_flag = 0;
++ flush_flag = 0;
++ fcs = PPP_INITFCS;
++
++ netif_set_mtu(0, MIN(lcp_allowoptions[0].mru, PPP_MRU));
++ ppp_send_config(0, PPP_MRU, (u_int32_t) 0, 0, 0);
++ ppp_recv_config(0, PPP_MRU, (u_int32_t) 0, 0, 0);
++
++#ifdef PPP_FILTER
++ set_filters(&amp;pass_filter, &amp;active_filter);
++#endif
++
++ /*
++ * Call the demand_conf procedure for each protocol that's got one.
++ */
++ for (i = 0; (protp = protocols[i]) != NULL; ++i)
++ if (protp-&gt;enabled_flag &amp;&amp; protp-&gt;demand_conf != NULL)
++ if (!((*protp-&gt;demand_conf)(0)))
++ die(1);
++}
++
++
++/*
++ * demand_block - set each network protocol to block further packets.
++ */
++void
++demand_block()
++{
++ int i;
++ struct protent *protp;
++
++ for (i = 0; (protp = protocols[i]) != NULL; ++i)
++ if (protp-&gt;enabled_flag &amp;&amp; protp-&gt;demand_conf != NULL)
++ sifnpmode(0, protp-&gt;protocol &amp; ~0x8000, NPMODE_QUEUE);
++ get_loop_output();
++}
++
++/*
++ * demand_discard - set each network protocol to discard packets
++ * with an error.
++ */
++void
++demand_discard()
++{
++ struct packet *pkt, *nextpkt;
++ int i;
++ struct protent *protp;
++
++ for (i = 0; (protp = protocols[i]) != NULL; ++i)
++ if (protp-&gt;enabled_flag &amp;&amp; protp-&gt;demand_conf != NULL)
++ sifnpmode(0, protp-&gt;protocol &amp; ~0x8000, NPMODE_ERROR);
++ get_loop_output();
++
++ /* discard all saved packets */
++ for (pkt = pend_q; pkt != NULL; pkt = nextpkt) {
++ nextpkt = pkt-&gt;next;
++ free(pkt);
++ }
++ pend_q = NULL;
++ framelen = 0;
++ flush_flag = 0;
++ escape_flag = 0;
++ fcs = PPP_INITFCS;
++}
++
++/*
++ * demand_unblock - set each enabled network protocol to pass packets.
++ */
++void
++demand_unblock()
++{
++ int i;
++ struct protent *protp;
++
++ for (i = 0; (protp = protocols[i]) != NULL; ++i)
++ if (protp-&gt;enabled_flag &amp;&amp; protp-&gt;demand_conf != NULL)
++ sifnpmode(0, protp-&gt;protocol &amp; ~0x8000, NPMODE_PASS);
++}
++
++/*
++ * FCS lookup table as calculated by genfcstab.
++ */
++static u_short fcstab[256] = {
++ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
++ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
++ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
++ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
++ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
++ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
++ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
++ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
++ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
++ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
++ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
++ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
++ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
++ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
++ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
++ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
++ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
++ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
++ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
++ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
++ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
++ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
++ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
++ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
++ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
++ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
++ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
++ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
++ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
++ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
++ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
++ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
++};
++
++/*
++ * loop_chars - process characters received from the loopback.
++ * Calls loop_frame when a complete frame has been accumulated.
++ * Return value is 1 if we need to bring up the link, 0 otherwise.
++ */
++int
++loop_chars(p, n)
++ unsigned char *p;
++ int n;
++{
++ int c, rv;
++
++ rv = 0;
++ for (; n &gt; 0; --n) {
++ c = *p++;
++ if (c == PPP_FLAG) {
++ if (!escape_flag &amp;&amp; !flush_flag
++ &amp;&amp; framelen &gt; 2 &amp;&amp; fcs == PPP_GOODFCS) {
++ framelen -= 2;
++ if (loop_frame((unsigned char *)frame, framelen))
++ rv = 1;
++ }
++ framelen = 0;
++ flush_flag = 0;
++ escape_flag = 0;
++ fcs = PPP_INITFCS;
++ continue;
++ }
++ if (flush_flag)
++ continue;
++ if (escape_flag) {
++ c ^= PPP_TRANS;
++ escape_flag = 0;
++ } else if (c == PPP_ESCAPE) {
++ escape_flag = 1;
++ continue;
++ }
++ if (framelen &gt;= framemax) {
++ flush_flag = 1;
++ continue;
++ }
++ frame[framelen++] = c;
++ fcs = PPP_FCS(fcs, c);
++ }
++ return rv;
++}
++
++/*
++ * loop_frame - given a frame obtained from the loopback,
++ * decide whether to bring up the link or not, and, if we want
++ * to transmit this frame later, put it on the pending queue.
++ * Return value is 1 if we need to bring up the link, 0 otherwise.
++ * We assume that the kernel driver has already applied the
++ * pass_filter, so we won't get packets it rejected.
++ * We apply the active_filter to see if we want this packet to
++ * bring up the link.
++ */
++int
++loop_frame(frame, len)
++ unsigned char *frame;
++ int len;
++{
++ struct packet *pkt;
++
++ /* dbglog(&quot;from loop: %P&quot;, frame, len); */
++ if (len &lt; PPP_HDRLEN)
++ return 0;
++ if ((PPP_PROTOCOL(frame) &amp; 0x8000) != 0)
++ return 0; /* shouldn't get any of these anyway */
++ if (!active_packet(frame, len))
++ return 0;
++
++ pkt = (struct packet *) malloc(sizeof(struct packet) + len);
++ if (pkt != NULL) {
++ pkt-&gt;length = len;
++ pkt-&gt;next = NULL;
++ memcpy(pkt-&gt;data, frame, len);
++ if (pend_q == NULL)
++ pend_q = pkt;
++ else
++ pend_qtail-&gt;next = pkt;
++ pend_qtail = pkt;
++ }
++ return 1;
++}
++
++/*
++ * demand_rexmit - Resend all those frames which we got via the
++ * loopback, now that the real serial link is up.
++ */
++void
++demand_rexmit(proto)
++ int proto;
++{
++ struct packet *pkt, *prev, *nextpkt;
++
++ prev = NULL;
++ pkt = pend_q;
++ pend_q = NULL;
++ for (; pkt != NULL; pkt = nextpkt) {
++ nextpkt = pkt-&gt;next;
++ if (PPP_PROTOCOL(pkt-&gt;data) == proto) {
++ output(0, pkt-&gt;data, pkt-&gt;length);
++ free(pkt);
++ } else {
++ if (prev == NULL)
++ pend_q = pkt;
++ else
++ prev-&gt;next = pkt;
++ prev = pkt;
++ }
++ }
++ pend_qtail = prev;
++ if (prev != NULL)
++ prev-&gt;next = NULL;
++}
++
++/*
++ * Scan a packet to decide whether it is an &quot;active&quot; packet,
++ * that is, whether it is worth bringing up the link for.
++ */
++static int
++active_packet(p, len)
++ unsigned char *p;
++ int len;
++{
++ int proto, i;
++ struct protent *protp;
++
++ if (len &lt; PPP_HDRLEN)
++ return 0;
++ proto = PPP_PROTOCOL(p);
++#ifdef PPP_FILTER
++ if (pass_filter.bf_len != 0
++ &amp;&amp; bpf_filter(pass_filter.bf_insns, p, len, len) == 0)
++ return 0;
++ if (active_filter.bf_len != 0
++ &amp;&amp; bpf_filter(active_filter.bf_insns, p, len, len) == 0)
++ return 0;
++#endif
++ for (i = 0; (protp = protocols[i]) != NULL; ++i) {
++ if (protp-&gt;protocol &lt; 0xC000 &amp;&amp; (protp-&gt;protocol &amp; ~0x8000) == proto) {
++ if (!protp-&gt;enabled_flag)
++ return 0;
++ if (protp-&gt;active_pkt == NULL)
++ return 1;
++ return (*protp-&gt;active_pkt)(p, len);
++ }
++ }
++ return 0; /* not a supported protocol !!?? */
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/demand.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/eui64.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/eui64.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/eui64.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,40 @@
++/*
++ eui64.c - EUI64 routines for IPv6CP.
++ Copyright (C) 1999 Tommi Komulainen &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">Tommi.Komulainen at iki.fi</A>&gt;
++
++ Redistribution and use in source and binary forms are permitted
++ provided that the above copyright notice and this paragraph are
++ duplicated in all such forms and that any documentation,
++ advertising materials, and other materials related to such
++ distribution and use acknowledge that the software was developed
++ by Tommi Komulainen. The name of the author may not be used
++ to endorse or promote products derived from this software without
++ specific prior written permission.
++ THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++
++
++ $Id: eui64.c 195720 2001-06-11 11:44:34Z gc $
++*/
++
++#define RCSID &quot;$Id: eui64.c 195720 2001-06-11 11:44:34Z gc $&quot;
++
++#include &quot;pppd.h&quot;
++
++static const char rcsid[] = RCSID;
++
++/*
++ * eui64_ntoa - Make an ascii representation of an interface identifier
++ */
++char *
++eui64_ntoa(e)
++ eui64_t e;
++{
++ static char buf[32];
++
++ snprintf(buf, 32, &quot;%02x%02x:%02x%02x:%02x%02x:%02x%02x&quot;,
++ e.e8[0], e.e8[1], e.e8[2], e.e8[3],
++ e.e8[4], e.e8[5], e.e8[6], e.e8[7]);
++ return buf;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/eui64.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/eui64.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/eui64.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/eui64.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,97 @@
++/*
++ eui64.h - EUI64 routines for IPv6CP.
++ Copyright (C) 1999 Tommi Komulainen &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">Tommi.Komulainen at iki.fi</A>&gt;
++
++ Redistribution and use in source and binary forms are permitted
++ provided that the above copyright notice and this paragraph are
++ duplicated in all such forms and that any documentation,
++ advertising materials, and other materials related to such
++ distribution and use acknowledge that the software was developed
++ by Tommi Komulainen. The name of the author may not be used
++ to endorse or promote products derived from this software without
++ specific prior written permission.
++ THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++
++
++ $Id: eui64.h 195720 2001-06-11 11:44:34Z gc $
++*/
++
++#ifndef __EUI64_H__
++#define __EUI64_H__
++
++#if !defined(INET6)
++#error &quot;this file should only be included when INET6 is defined&quot;
++#endif /* not defined(INET6) */
++
++#if defined(SOL2)
++#include &lt;netinet/in.h&gt;
++
++typedef union {
++ uint8_t e8[8]; /* lower 64-bit IPv6 address */
++ uint32_t e32[2]; /* lower 64-bit IPv6 address */
++} eui64_t;
++
++/*
++ * Declare the two below, since in.h only defines them when _KERNEL
++ * is declared - which shouldn't be true when dealing with user-land programs
++ */
++#define s6_addr8 _S6_un._S6_u8
++#define s6_addr32 _S6_un._S6_u32
++
++#else /* else if not defined(SOL2) */
++
++/*
++ * TODO:
++ *
++ * Maybe this should be done by processing struct in6_addr directly...
++ */
++typedef union
++{
++ u_int8_t e8[8];
++ u_int16_t e16[4];
++ u_int32_t e32[2];
++} eui64_t;
++
++#endif /* defined(SOL2) */
++
++#define eui64_iszero(e) (((e).e32[0] | (e).e32[1]) == 0)
++#define eui64_equals(e, o) (((e).e32[0] == (o).e32[0]) &amp;&amp; \
++ ((e).e32[1] == (o).e32[1]))
++#define eui64_zero(e) (e).e32[0] = (e).e32[1] = 0;
++
++#define eui64_copy(s, d) memcpy(&amp;(d), &amp;(s), sizeof(eui64_t))
++
++#define eui64_magic(e) do { \
++ (e).e32[0] = magic(); \
++ (e).e32[1] = magic(); \
++ (e).e8[0] &amp;= ~2; \
++ } while (0)
++#define eui64_magic_nz(x) do { \
++ eui64_magic(x); \
++ } while (eui64_iszero(x))
++#define eui64_magic_ne(x, y) do { \
++ eui64_magic(x); \
++ } while (eui64_equals(x, y))
++
++#define eui64_get(ll, cp) do { \
++ eui64_copy((*cp), (ll)); \
++ (cp) += sizeof(eui64_t); \
++ } while (0)
++
++#define eui64_put(ll, cp) do { \
++ eui64_copy((ll), (*cp)); \
++ (cp) += sizeof(eui64_t); \
++ } while (0)
++
++#define eui64_set32(e, l) do { \
++ (e).e32[0] = 0; \
++ (e).e32[1] = htonl(l); \
++ } while (0)
++#define eui64_setlo32(e, l) eui64_set32(e, l)
++
++char *eui64_ntoa __P((eui64_t)); /* Returns ascii representation of id */
++
++#endif /* __EUI64_H__ */
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/eui64.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/fsm.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/fsm.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/fsm.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,762 @@
++/*
++ * fsm.c - {Link, IP} Control Protocol Finite State Machine.
++ *
++ * Copyright (c) 1989 Carnegie Mellon University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by Carnegie Mellon University. The name of the
++ * University may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ */
++
++#define RCSID &quot;$Id: fsm.c 195720 2001-06-11 11:44:34Z gc $&quot;
++
++/*
++ * TODO:
++ * Randomize fsm id on link/init.
++ * Deal with variable outgoing MTU.
++ */
++
++#include &lt;stdio.h&gt;
++#include &lt;string.h&gt;
++#include &lt;sys/types.h&gt;
++
++#include &quot;pppd.h&quot;
++#include &quot;fsm.h&quot;
++
++static const char rcsid[] = RCSID;
++
++static void fsm_timeout __P((void *));
++static void fsm_rconfreq __P((fsm *, int, u_char *, int));
++static void fsm_rconfack __P((fsm *, int, u_char *, int));
++static void fsm_rconfnakrej __P((fsm *, int, int, u_char *, int));
++static void fsm_rtermreq __P((fsm *, int, u_char *, int));
++static void fsm_rtermack __P((fsm *));
++static void fsm_rcoderej __P((fsm *, u_char *, int));
++static void fsm_sconfreq __P((fsm *, int));
++
++#define PROTO_NAME(f) ((f)-&gt;callbacks-&gt;proto_name)
++
++int peer_mru[NUM_PPP];
++
++
++/*
++ * fsm_init - Initialize fsm.
++ *
++ * Initialize fsm state.
++ */
++void
++fsm_init(f)
++ fsm *f;
++{
++ f-&gt;state = INITIAL;
++ f-&gt;flags = 0;
++ f-&gt;id = 0; /* XXX Start with random id? */
++ f-&gt;timeouttime = DEFTIMEOUT;
++ f-&gt;maxconfreqtransmits = DEFMAXCONFREQS;
++ f-&gt;maxtermtransmits = DEFMAXTERMREQS;
++ f-&gt;maxnakloops = DEFMAXNAKLOOPS;
++ f-&gt;term_reason_len = 0;
++}
++
++
++/*
++ * fsm_lowerup - The lower layer is up.
++ */
++void
++fsm_lowerup(f)
++ fsm *f;
++{
++ switch( f-&gt;state ){
++ case INITIAL:
++ f-&gt;state = CLOSED;
++ break;
++
++ case STARTING:
++ if( f-&gt;flags &amp; OPT_SILENT )
++ f-&gt;state = STOPPED;
++ else {
++ /* Send an initial configure-request */
++ fsm_sconfreq(f, 0);
++ f-&gt;state = REQSENT;
++ }
++ break;
++
++ default:
++ FSMDEBUG((&quot;%s: Up event in state %d!&quot;, PROTO_NAME(f), f-&gt;state));
++ }
++}
++
++
++/*
++ * fsm_lowerdown - The lower layer is down.
++ *
++ * Cancel all timeouts and inform upper layers.
++ */
++void
++fsm_lowerdown(f)
++ fsm *f;
++{
++ switch( f-&gt;state ){
++ case CLOSED:
++ f-&gt;state = INITIAL;
++ break;
++
++ case STOPPED:
++ f-&gt;state = STARTING;
++ if( f-&gt;callbacks-&gt;starting )
++ (*f-&gt;callbacks-&gt;starting)(f);
++ break;
++
++ case CLOSING:
++ f-&gt;state = INITIAL;
++ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
++ break;
++
++ case STOPPING:
++ case REQSENT:
++ case ACKRCVD:
++ case ACKSENT:
++ f-&gt;state = STARTING;
++ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
++ break;
++
++ case OPENED:
++ if( f-&gt;callbacks-&gt;down )
++ (*f-&gt;callbacks-&gt;down)(f);
++ f-&gt;state = STARTING;
++ break;
++
++ default:
++ FSMDEBUG((&quot;%s: Down event in state %d!&quot;, PROTO_NAME(f), f-&gt;state));
++ }
++}
++
++
++/*
++ * fsm_open - Link is allowed to come up.
++ */
++void
++fsm_open(f)
++ fsm *f;
++{
++ switch( f-&gt;state ){
++ case INITIAL:
++ f-&gt;state = STARTING;
++ if( f-&gt;callbacks-&gt;starting )
++ (*f-&gt;callbacks-&gt;starting)(f);
++ break;
++
++ case CLOSED:
++ if( f-&gt;flags &amp; OPT_SILENT )
++ f-&gt;state = STOPPED;
++ else {
++ /* Send an initial configure-request */
++ fsm_sconfreq(f, 0);
++ f-&gt;state = REQSENT;
++ }
++ break;
++
++ case CLOSING:
++ f-&gt;state = STOPPING;
++ /* fall through */
++ case STOPPED:
++ case OPENED:
++ if( f-&gt;flags &amp; OPT_RESTART ){
++ fsm_lowerdown(f);
++ fsm_lowerup(f);
++ }
++ break;
++ }
++}
++
++
++/*
++ * fsm_close - Start closing connection.
++ *
++ * Cancel timeouts and either initiate close or possibly go directly to
++ * the CLOSED state.
++ */
++void
++fsm_close(f, reason)
++ fsm *f;
++ char *reason;
++{
++ f-&gt;term_reason = reason;
++ f-&gt;term_reason_len = (reason == NULL? 0: strlen(reason));
++ switch( f-&gt;state ){
++ case STARTING:
++ f-&gt;state = INITIAL;
++ break;
++ case STOPPED:
++ f-&gt;state = CLOSED;
++ break;
++ case STOPPING:
++ f-&gt;state = CLOSING;
++ break;
++
++ case REQSENT:
++ case ACKRCVD:
++ case ACKSENT:
++ case OPENED:
++ if( f-&gt;state != OPENED )
++ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
++ else if( f-&gt;callbacks-&gt;down )
++ (*f-&gt;callbacks-&gt;down)(f); /* Inform upper layers we're down */
++
++ /* Init restart counter, send Terminate-Request */
++ f-&gt;retransmits = f-&gt;maxtermtransmits;
++ fsm_sdata(f, TERMREQ, f-&gt;reqid = ++f-&gt;id,
++ (u_char *) f-&gt;term_reason, f-&gt;term_reason_len);
++ TIMEOUT(fsm_timeout, f, f-&gt;timeouttime);
++ --f-&gt;retransmits;
++
++ f-&gt;state = CLOSING;
++ break;
++ }
++}
++
++
++/*
++ * fsm_timeout - Timeout expired.
++ */
++static void
++fsm_timeout(arg)
++ void *arg;
++{
++ fsm *f = (fsm *) arg;
++
++ switch (f-&gt;state) {
++ case CLOSING:
++ case STOPPING:
++ if( f-&gt;retransmits &lt;= 0 ){
++ /*
++ * We've waited for an ack long enough. Peer probably heard us.
++ */
++ f-&gt;state = (f-&gt;state == CLOSING)? CLOSED: STOPPED;
++ if( f-&gt;callbacks-&gt;finished )
++ (*f-&gt;callbacks-&gt;finished)(f);
++ } else {
++ /* Send Terminate-Request */
++ fsm_sdata(f, TERMREQ, f-&gt;reqid = ++f-&gt;id,
++ (u_char *) f-&gt;term_reason, f-&gt;term_reason_len);
++ TIMEOUT(fsm_timeout, f, f-&gt;timeouttime);
++ --f-&gt;retransmits;
++ }
++ break;
++
++ case REQSENT:
++ case ACKRCVD:
++ case ACKSENT:
++ if (f-&gt;retransmits &lt;= 0) {
++ warn(&quot;%s: timeout sending Config-Requests\n&quot;, PROTO_NAME(f));
++ f-&gt;state = STOPPED;
++ if( (f-&gt;flags &amp; OPT_PASSIVE) == 0 &amp;&amp; f-&gt;callbacks-&gt;finished )
++ (*f-&gt;callbacks-&gt;finished)(f);
++
++ } else {
++ /* Retransmit the configure-request */
++ if (f-&gt;callbacks-&gt;retransmit)
++ (*f-&gt;callbacks-&gt;retransmit)(f);
++ fsm_sconfreq(f, 1); /* Re-send Configure-Request */
++ if( f-&gt;state == ACKRCVD )
++ f-&gt;state = REQSENT;
++ }
++ break;
++
++ default:
++ FSMDEBUG((&quot;%s: Timeout event in state %d!&quot;, PROTO_NAME(f), f-&gt;state));
++ }
++}
++
++
++/*
++ * fsm_input - Input packet.
++ */
++void
++fsm_input(f, inpacket, l)
++ fsm *f;
++ u_char *inpacket;
++ int l;
++{
++ u_char *inp;
++ u_char code, id;
++ int len;
++
++ /*
++ * Parse header (code, id and length).
++ * If packet too short, drop it.
++ */
++ inp = inpacket;
++ if (l &lt; HEADERLEN) {
++ FSMDEBUG((&quot;fsm_input(%x): Rcvd short header.&quot;, f-&gt;protocol));
++ return;
++ }
++ GETCHAR(code, inp);
++ GETCHAR(id, inp);
++ GETSHORT(len, inp);
++ if (len &lt; HEADERLEN) {
++ FSMDEBUG((&quot;fsm_input(%x): Rcvd illegal length.&quot;, f-&gt;protocol));
++ return;
++ }
++ if (len &gt; l) {
++ FSMDEBUG((&quot;fsm_input(%x): Rcvd short packet.&quot;, f-&gt;protocol));
++ return;
++ }
++ len -= HEADERLEN; /* subtract header length */
++
++ if( f-&gt;state == INITIAL || f-&gt;state == STARTING ){
++ FSMDEBUG((&quot;fsm_input(%x): Rcvd packet in state %d.&quot;,
++ f-&gt;protocol, f-&gt;state));
++ return;
++ }
++
++ /*
++ * Action depends on code.
++ */
++ switch (code) {
++ case CONFREQ:
++ fsm_rconfreq(f, id, inp, len);
++ break;
++
++ case CONFACK:
++ fsm_rconfack(f, id, inp, len);
++ break;
++
++ case CONFNAK:
++ case CONFREJ:
++ fsm_rconfnakrej(f, code, id, inp, len);
++ break;
++
++ case TERMREQ:
++ fsm_rtermreq(f, id, inp, len);
++ break;
++
++ case TERMACK:
++ fsm_rtermack(f);
++ break;
++
++ case CODEREJ:
++ fsm_rcoderej(f, inp, len);
++ break;
++
++ default:
++ if( !f-&gt;callbacks-&gt;extcode
++ || !(*f-&gt;callbacks-&gt;extcode)(f, code, id, inp, len) )
++ fsm_sdata(f, CODEREJ, ++f-&gt;id, inpacket, len + HEADERLEN);
++ break;
++ }
++}
++
++
++/*
++ * fsm_rconfreq - Receive Configure-Request.
++ */
++static void
++fsm_rconfreq(f, id, inp, len)
++ fsm *f;
++ u_char id;
++ u_char *inp;
++ int len;
++{
++ int code, reject_if_disagree;
++
++ switch( f-&gt;state ){
++ case CLOSED:
++ /* Go away, we're closed */
++ fsm_sdata(f, TERMACK, id, NULL, 0);
++ return;
++ case CLOSING:
++ case STOPPING:
++ return;
++
++ case OPENED:
++ /* Go down and restart negotiation */
++ if( f-&gt;callbacks-&gt;down )
++ (*f-&gt;callbacks-&gt;down)(f); /* Inform upper layers */
++ fsm_sconfreq(f, 0); /* Send initial Configure-Request */
++ break;
++
++ case STOPPED:
++ /* Negotiation started by our peer */
++ fsm_sconfreq(f, 0); /* Send initial Configure-Request */
++ f-&gt;state = REQSENT;
++ break;
++ }
++
++ /*
++ * Pass the requested configuration options
++ * to protocol-specific code for checking.
++ */
++ if (f-&gt;callbacks-&gt;reqci){ /* Check CI */
++ reject_if_disagree = (f-&gt;nakloops &gt;= f-&gt;maxnakloops);
++ code = (*f-&gt;callbacks-&gt;reqci)(f, inp, &amp;len, reject_if_disagree);
++ } else if (len)
++ code = CONFREJ; /* Reject all CI */
++ else
++ code = CONFACK;
++
++ /* send the Ack, Nak or Rej to the peer */
++ fsm_sdata(f, code, id, inp, len);
++
++ if (code == CONFACK) {
++ if (f-&gt;state == ACKRCVD) {
++ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
++ f-&gt;state = OPENED;
++ if (f-&gt;callbacks-&gt;up)
++ (*f-&gt;callbacks-&gt;up)(f); /* Inform upper layers */
++ } else
++ f-&gt;state = ACKSENT;
++ f-&gt;nakloops = 0;
++
++ } else {
++ /* we sent CONFACK or CONFREJ */
++ if (f-&gt;state != ACKRCVD)
++ f-&gt;state = REQSENT;
++ if( code == CONFNAK )
++ ++f-&gt;nakloops;
++ }
++}
++
++
++/*
++ * fsm_rconfack - Receive Configure-Ack.
++ */
++static void
++fsm_rconfack(f, id, inp, len)
++ fsm *f;
++ int id;
++ u_char *inp;
++ int len;
++{
++ if (id != f-&gt;reqid || f-&gt;seen_ack) /* Expected id? */
++ return; /* Nope, toss... */
++ if( !(f-&gt;callbacks-&gt;ackci? (*f-&gt;callbacks-&gt;ackci)(f, inp, len):
++ (len == 0)) ){
++ /* Ack is bad - ignore it */
++ error(&quot;Received bad configure-ack: %P&quot;, inp, len);
++ return;
++ }
++ f-&gt;seen_ack = 1;
++
++ switch (f-&gt;state) {
++ case CLOSED:
++ case STOPPED:
++ fsm_sdata(f, TERMACK, id, NULL, 0);
++ break;
++
++ case REQSENT:
++ f-&gt;state = ACKRCVD;
++ f-&gt;retransmits = f-&gt;maxconfreqtransmits;
++ break;
++
++ case ACKRCVD:
++ /* Huh? an extra valid Ack? oh well... */
++ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
++ fsm_sconfreq(f, 0);
++ f-&gt;state = REQSENT;
++ break;
++
++ case ACKSENT:
++ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
++ f-&gt;state = OPENED;
++ f-&gt;retransmits = f-&gt;maxconfreqtransmits;
++ if (f-&gt;callbacks-&gt;up)
++ (*f-&gt;callbacks-&gt;up)(f); /* Inform upper layers */
++ break;
++
++ case OPENED:
++ /* Go down and restart negotiation */
++ if (f-&gt;callbacks-&gt;down)
++ (*f-&gt;callbacks-&gt;down)(f); /* Inform upper layers */
++ fsm_sconfreq(f, 0); /* Send initial Configure-Request */
++ f-&gt;state = REQSENT;
++ break;
++ }
++}
++
++
++/*
++ * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
++ */
++static void
++fsm_rconfnakrej(f, code, id, inp, len)
++ fsm *f;
++ int code, id;
++ u_char *inp;
++ int len;
++{
++ int (*proc) __P((fsm *, u_char *, int));
++ int ret;
++
++ if (id != f-&gt;reqid || f-&gt;seen_ack) /* Expected id? */
++ return; /* Nope, toss... */
++ proc = (code == CONFNAK)? f-&gt;callbacks-&gt;nakci: f-&gt;callbacks-&gt;rejci;
++ if (!proc || !(ret = proc(f, inp, len))) {
++ /* Nak/reject is bad - ignore it */
++ error(&quot;Received bad configure-nak/rej: %P&quot;, inp, len);
++ return;
++ }
++ f-&gt;seen_ack = 1;
++
++ switch (f-&gt;state) {
++ case CLOSED:
++ case STOPPED:
++ fsm_sdata(f, TERMACK, id, NULL, 0);
++ break;
++
++ case REQSENT:
++ case ACKSENT:
++ /* They didn't agree to what we wanted - try another request */
++ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
++ if (ret &lt; 0)
++ f-&gt;state = STOPPED; /* kludge for stopping CCP */
++ else
++ fsm_sconfreq(f, 0); /* Send Configure-Request */
++ break;
++
++ case ACKRCVD:
++ /* Got a Nak/reject when we had already had an Ack?? oh well... */
++ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
++ fsm_sconfreq(f, 0);
++ f-&gt;state = REQSENT;
++ break;
++
++ case OPENED:
++ /* Go down and restart negotiation */
++ if (f-&gt;callbacks-&gt;down)
++ (*f-&gt;callbacks-&gt;down)(f); /* Inform upper layers */
++ fsm_sconfreq(f, 0); /* Send initial Configure-Request */
++ f-&gt;state = REQSENT;
++ break;
++ }
++}
++
++
++/*
++ * fsm_rtermreq - Receive Terminate-Req.
++ */
++static void
++fsm_rtermreq(f, id, p, len)
++ fsm *f;
++ int id;
++ u_char *p;
++ int len;
++{
++ switch (f-&gt;state) {
++ case ACKRCVD:
++ case ACKSENT:
++ f-&gt;state = REQSENT; /* Start over but keep trying */
++ break;
++
++ case OPENED:
++ if (len &gt; 0) {
++ info(&quot;%s terminated by peer (%0.*v)&quot;, PROTO_NAME(f), len, p);
++ } else
++ info(&quot;%s terminated by peer&quot;, PROTO_NAME(f));
++ if (f-&gt;callbacks-&gt;down)
++ (*f-&gt;callbacks-&gt;down)(f); /* Inform upper layers */
++ f-&gt;retransmits = 0;
++ f-&gt;state = STOPPING;
++ TIMEOUT(fsm_timeout, f, f-&gt;timeouttime);
++ break;
++ }
++
++ fsm_sdata(f, TERMACK, id, NULL, 0);
++}
++
++
++/*
++ * fsm_rtermack - Receive Terminate-Ack.
++ */
++static void
++fsm_rtermack(f)
++ fsm *f;
++{
++ switch (f-&gt;state) {
++ case CLOSING:
++ UNTIMEOUT(fsm_timeout, f);
++ f-&gt;state = CLOSED;
++ if( f-&gt;callbacks-&gt;finished )
++ (*f-&gt;callbacks-&gt;finished)(f);
++ break;
++ case STOPPING:
++ UNTIMEOUT(fsm_timeout, f);
++ f-&gt;state = STOPPED;
++ if( f-&gt;callbacks-&gt;finished )
++ (*f-&gt;callbacks-&gt;finished)(f);
++ break;
++
++ case ACKRCVD:
++ f-&gt;state = REQSENT;
++ break;
++
++ case OPENED:
++ if (f-&gt;callbacks-&gt;down)
++ (*f-&gt;callbacks-&gt;down)(f); /* Inform upper layers */
++ fsm_sconfreq(f, 0);
++ break;
++ }
++}
++
++
++/*
++ * fsm_rcoderej - Receive an Code-Reject.
++ */
++static void
++fsm_rcoderej(f, inp, len)
++ fsm *f;
++ u_char *inp;
++ int len;
++{
++ u_char code, id;
++
++ if (len &lt; HEADERLEN) {
++ FSMDEBUG((&quot;fsm_rcoderej: Rcvd short Code-Reject packet!&quot;));
++ return;
++ }
++ GETCHAR(code, inp);
++ GETCHAR(id, inp);
++ warn(&quot;%s: Rcvd Code-Reject for code %d, id %d&quot;, PROTO_NAME(f), code, id);
++
++ if( f-&gt;state == ACKRCVD )
++ f-&gt;state = REQSENT;
++}
++
++
++/*
++ * fsm_protreject - Peer doesn't speak this protocol.
++ *
++ * Treat this as a catastrophic error (RXJ-).
++ */
++void
++fsm_protreject(f)
++ fsm *f;
++{
++ switch( f-&gt;state ){
++ case CLOSING:
++ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
++ /* fall through */
++ case CLOSED:
++ f-&gt;state = CLOSED;
++ if( f-&gt;callbacks-&gt;finished )
++ (*f-&gt;callbacks-&gt;finished)(f);
++ break;
++
++ case STOPPING:
++ case REQSENT:
++ case ACKRCVD:
++ case ACKSENT:
++ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
++ /* fall through */
++ case STOPPED:
++ f-&gt;state = STOPPED;
++ if( f-&gt;callbacks-&gt;finished )
++ (*f-&gt;callbacks-&gt;finished)(f);
++ break;
++
++ case OPENED:
++ if( f-&gt;callbacks-&gt;down )
++ (*f-&gt;callbacks-&gt;down)(f);
++
++ /* Init restart counter, send Terminate-Request */
++ f-&gt;retransmits = f-&gt;maxtermtransmits;
++ fsm_sdata(f, TERMREQ, f-&gt;reqid = ++f-&gt;id,
++ (u_char *) f-&gt;term_reason, f-&gt;term_reason_len);
++ TIMEOUT(fsm_timeout, f, f-&gt;timeouttime);
++ --f-&gt;retransmits;
++
++ f-&gt;state = STOPPING;
++ break;
++
++ default:
++ FSMDEBUG((&quot;%s: Protocol-reject event in state %d!&quot;,
++ PROTO_NAME(f), f-&gt;state));
++ }
++}
++
++
++/*
++ * fsm_sconfreq - Send a Configure-Request.
++ */
++static void
++fsm_sconfreq(f, retransmit)
++ fsm *f;
++ int retransmit;
++{
++ u_char *outp;
++ int cilen;
++
++ if( f-&gt;state != REQSENT &amp;&amp; f-&gt;state != ACKRCVD &amp;&amp; f-&gt;state != ACKSENT ){
++ /* Not currently negotiating - reset options */
++ if( f-&gt;callbacks-&gt;resetci )
++ (*f-&gt;callbacks-&gt;resetci)(f);
++ f-&gt;nakloops = 0;
++ }
++
++ if( !retransmit ){
++ /* New request - reset retransmission counter, use new ID */
++ f-&gt;retransmits = f-&gt;maxconfreqtransmits;
++ f-&gt;reqid = ++f-&gt;id;
++ }
++
++ f-&gt;seen_ack = 0;
++
++ /*
++ * Make up the request packet
++ */
++ outp = outpacket_buf + PPP_HDRLEN + HEADERLEN;
++ if( f-&gt;callbacks-&gt;cilen &amp;&amp; f-&gt;callbacks-&gt;addci ){
++ cilen = (*f-&gt;callbacks-&gt;cilen)(f);
++ if( cilen &gt; peer_mru[f-&gt;unit] - HEADERLEN )
++ cilen = peer_mru[f-&gt;unit] - HEADERLEN;
++ if (f-&gt;callbacks-&gt;addci)
++ (*f-&gt;callbacks-&gt;addci)(f, outp, &amp;cilen);
++ } else
++ cilen = 0;
++
++ /* send the request to our peer */
++ fsm_sdata(f, CONFREQ, f-&gt;reqid, outp, cilen);
++
++ /* start the retransmit timer */
++ --f-&gt;retransmits;
++ TIMEOUT(fsm_timeout, f, f-&gt;timeouttime);
++}
++
++
++/*
++ * fsm_sdata - Send some data.
++ *
++ * Used for all packets sent to our peer by this module.
++ */
++void
++fsm_sdata(f, code, id, data, datalen)
++ fsm *f;
++ u_char code, id;
++ u_char *data;
++ int datalen;
++{
++ u_char *outp;
++ int outlen;
++
++ /* Adjust length to be smaller than MTU */
++ outp = outpacket_buf;
++ if (datalen &gt; peer_mru[f-&gt;unit] - HEADERLEN)
++ datalen = peer_mru[f-&gt;unit] - HEADERLEN;
++ if (datalen &amp;&amp; data != outp + PPP_HDRLEN + HEADERLEN)
++ BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen);
++ outlen = datalen + HEADERLEN;
++ MAKEHEADER(outp, f-&gt;protocol);
++ PUTCHAR(code, outp);
++ PUTCHAR(id, outp);
++ PUTSHORT(outlen, outp);
++ output(f-&gt;unit, outpacket_buf, outlen + PPP_HDRLEN);
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/fsm.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/fsm.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/fsm.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/fsm.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,144 @@
++/*
++ * fsm.h - {Link, IP} Control Protocol Finite State Machine definitions.
++ *
++ * Copyright (c) 1989 Carnegie Mellon University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by Carnegie Mellon University. The name of the
++ * University may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * $Id: fsm.h 195720 2001-06-11 11:44:34Z gc $
++ */
++
++/*
++ * Packet header = Code, id, length.
++ */
++#define HEADERLEN 4
++
++
++/*
++ * CP (LCP, IPCP, etc.) codes.
++ */
++#define CONFREQ 1 /* Configuration Request */
++#define CONFACK 2 /* Configuration Ack */
++#define CONFNAK 3 /* Configuration Nak */
++#define CONFREJ 4 /* Configuration Reject */
++#define TERMREQ 5 /* Termination Request */
++#define TERMACK 6 /* Termination Ack */
++#define CODEREJ 7 /* Code Reject */
++
++
++/*
++ * Each FSM is described by an fsm structure and fsm callbacks.
++ */
++typedef struct fsm {
++ int unit; /* Interface unit number */
++ int protocol; /* Data Link Layer Protocol field value */
++ int state; /* State */
++ int flags; /* Contains option bits */
++ u_char id; /* Current id */
++ u_char reqid; /* Current request id */
++ u_char seen_ack; /* Have received valid Ack/Nak/Rej to Req */
++ int timeouttime; /* Timeout time in milliseconds */
++ int maxconfreqtransmits; /* Maximum Configure-Request transmissions */
++ int retransmits; /* Number of retransmissions left */
++ int maxtermtransmits; /* Maximum Terminate-Request transmissions */
++ int nakloops; /* Number of nak loops since last ack */
++ int maxnakloops; /* Maximum number of nak loops tolerated */
++ struct fsm_callbacks *callbacks; /* Callback routines */
++ char *term_reason; /* Reason for closing protocol */
++ int term_reason_len; /* Length of term_reason */
++} fsm;
++
++
++typedef struct fsm_callbacks {
++ void (*resetci) /* Reset our Configuration Information */
++ __P((fsm *));
++ int (*cilen) /* Length of our Configuration Information */
++ __P((fsm *));
++ void (*addci) /* Add our Configuration Information */
++ __P((fsm *, u_char *, int *));
++ int (*ackci) /* ACK our Configuration Information */
++ __P((fsm *, u_char *, int));
++ int (*nakci) /* NAK our Configuration Information */
++ __P((fsm *, u_char *, int));
++ int (*rejci) /* Reject our Configuration Information */
++ __P((fsm *, u_char *, int));
++ int (*reqci) /* Request peer's Configuration Information */
++ __P((fsm *, u_char *, int *, int));
++ void (*up) /* Called when fsm reaches OPENED state */
++ __P((fsm *));
++ void (*down) /* Called when fsm leaves OPENED state */
++ __P((fsm *));
++ void (*starting) /* Called when we want the lower layer */
++ __P((fsm *));
++ void (*finished) /* Called when we don't want the lower layer */
++ __P((fsm *));
++ void (*protreject) /* Called when Protocol-Reject received */
++ __P((int));
++ void (*retransmit) /* Retransmission is necessary */
++ __P((fsm *));
++ int (*extcode) /* Called when unknown code received */
++ __P((fsm *, int, int, u_char *, int));
++ char *proto_name; /* String name for protocol (for messages) */
++} fsm_callbacks;
++
++
++/*
++ * Link states.
++ */
++#define INITIAL 0 /* Down, hasn't been opened */
++#define STARTING 1 /* Down, been opened */
++#define CLOSED 2 /* Up, hasn't been opened */
++#define STOPPED 3 /* Open, waiting for down event */
++#define CLOSING 4 /* Terminating the connection, not open */
++#define STOPPING 5 /* Terminating, but open */
++#define REQSENT 6 /* We've sent a Config Request */
++#define ACKRCVD 7 /* We've received a Config Ack */
++#define ACKSENT 8 /* We've sent a Config Ack */
++#define OPENED 9 /* Connection available */
++
++
++/*
++ * Flags - indicate options controlling FSM operation
++ */
++#define OPT_PASSIVE 1 /* Don't die if we don't get a response */
++#define OPT_RESTART 2 /* Treat 2nd OPEN as DOWN, UP */
++#define OPT_SILENT 4 /* Wait for peer to speak first */
++
++
++/*
++ * Timeouts.
++ */
++#define DEFTIMEOUT 3 /* Timeout time in seconds */
++#define DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */
++#define DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */
++#define DEFMAXNAKLOOPS 5 /* Maximum number of nak loops */
++
++
++/*
++ * Prototypes
++ */
++void fsm_init __P((fsm *));
++void fsm_lowerup __P((fsm *));
++void fsm_lowerdown __P((fsm *));
++void fsm_open __P((fsm *));
++void fsm_close __P((fsm *, char *));
++void fsm_input __P((fsm *, u_char *, int));
++void fsm_protreject __P((fsm *));
++void fsm_sdata __P((fsm *, int, int, u_char *, int));
++
++
++/*
++ * Variables
++ */
++extern int peer_mru[]; /* currently negotiated peer MRU (per unit) */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/fsm.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/ipcp.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/ipcp.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/ipcp.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,2054 @@
++/*
++ * ipcp.c - PPP IP Control Protocol.
++ *
++ * Copyright (c) 1989 Carnegie Mellon University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by Carnegie Mellon University. The name of the
++ * University may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ */
++
++#define RCSID &quot;$Id: ipcp.c 198597 2002-05-13 15:34:06Z gc $&quot;
++
++/*
++ * TODO:
++ */
++
++#include &lt;stdio.h&gt;
++#include &lt;string.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;netdb.h&gt;
++#include &lt;sys/param.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/socket.h&gt;
++#include &lt;netinet/in.h&gt;
++#include &lt;arpa/inet.h&gt;
++
++#include &quot;pppd.h&quot;
++#include &quot;fsm.h&quot;
++#include &quot;ipcp.h&quot;
++#include &quot;pathnames.h&quot;
++
++static const char rcsid[] = RCSID;
++
++/* global vars */
++ipcp_options ipcp_wantoptions[NUM_PPP]; /* Options that we want to request */
++ipcp_options ipcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */
++ipcp_options ipcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */
++ipcp_options ipcp_hisoptions[NUM_PPP]; /* Options that we ack'd */
++
++u_int32_t netmask = 0; /* IP netmask to set on interface */
++
++bool disable_defaultip = 0; /* Don't use hostname for default IP adrs */
++
++/* Hook for a plugin to know when IP protocol has come up */
++void (*ip_up_hook) __P((void)) = NULL;
++
++/* Hook for a plugin to know when IP protocol has come down */
++void (*ip_down_hook) __P((void)) = NULL;
++
++/* Hook for a plugin to choose the remote IP address */
++void (*ip_choose_hook) __P((u_int32_t *)) = NULL;
++
++/* local vars */
++static int default_route_set[NUM_PPP]; /* Have set up a default route */
++static int proxy_arp_set[NUM_PPP]; /* Have created proxy arp entry */
++static bool usepeerdns; /* Ask peer for DNS addrs */
++static int ipcp_is_up; /* have called np_up() */
++static bool ask_for_local; /* request our address from peer */
++static char vj_value[8]; /* string form of vj option value */
++static char netmask_str[20]; /* string form of netmask value */
++
++/*
++ * Callbacks for fsm code. (CI = Configuration Information)
++ */
++static void ipcp_resetci __P((fsm *)); /* Reset our CI */
++static int ipcp_cilen __P((fsm *)); /* Return length of our CI */
++static void ipcp_addci __P((fsm *, u_char *, int *)); /* Add our CI */
++static int ipcp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */
++static int ipcp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */
++static int ipcp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */
++static int ipcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
++static void ipcp_up __P((fsm *)); /* We're UP */
++static void ipcp_down __P((fsm *)); /* We're DOWN */
++static void ipcp_finished __P((fsm *)); /* Don't need lower layer */
++
++fsm ipcp_fsm[NUM_PPP]; /* IPCP fsm structure */
++
++static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */
++ ipcp_resetci, /* Reset our Configuration Information */
++ ipcp_cilen, /* Length of our Configuration Information */
++ ipcp_addci, /* Add our Configuration Information */
++ ipcp_ackci, /* ACK our Configuration Information */
++ ipcp_nakci, /* NAK our Configuration Information */
++ ipcp_rejci, /* Reject our Configuration Information */
++ ipcp_reqci, /* Request peer's Configuration Information */
++ ipcp_up, /* Called when fsm reaches OPENED state */
++ ipcp_down, /* Called when fsm leaves OPENED state */
++ NULL, /* Called when we want the lower layer up */
++ ipcp_finished, /* Called when we want the lower layer down */
++ NULL, /* Called when Protocol-Reject received */
++ NULL, /* Retransmission is necessary */
++ NULL, /* Called to handle protocol-specific codes */
++ &quot;IPCP&quot; /* String name of protocol */
++};
++
++/*
++ * Command-line options.
++ */
++static int setvjslots __P((char **));
++static int setdnsaddr __P((char **));
++static int setwinsaddr __P((char **));
++static int setnetmask __P((char **));
++static int setipaddr __P((char *, char **, int));
++static void printipaddr __P((option_t *, void (*)(void *, char *,...),void *));
++
++static option_t ipcp_option_list[] = {
++ { &quot;noip&quot;, o_bool, &amp;ipcp_protent.enabled_flag,
++ &quot;Disable IP and IPCP&quot; },
++ { &quot;-ip&quot;, o_bool, &amp;ipcp_protent.enabled_flag,
++ &quot;Disable IP and IPCP&quot;, OPT_ALIAS },
++
++ { &quot;novj&quot;, o_bool, &amp;ipcp_wantoptions[0].neg_vj,
++ &quot;Disable VJ compression&quot;, OPT_A2CLR, &amp;ipcp_allowoptions[0].neg_vj },
++ { &quot;-vj&quot;, o_bool, &amp;ipcp_wantoptions[0].neg_vj,
++ &quot;Disable VJ compression&quot;, OPT_ALIAS | OPT_A2CLR,
++ &amp;ipcp_allowoptions[0].neg_vj },
++
++ { &quot;novjccomp&quot;, o_bool, &amp;ipcp_wantoptions[0].cflag,
++ &quot;Disable VJ connection-ID compression&quot;, OPT_A2CLR,
++ &amp;ipcp_allowoptions[0].cflag },
++ { &quot;-vjccomp&quot;, o_bool, &amp;ipcp_wantoptions[0].cflag,
++ &quot;Disable VJ connection-ID compression&quot;, OPT_ALIAS | OPT_A2CLR,
++ &amp;ipcp_allowoptions[0].cflag },
++
++ { &quot;vj-max-slots&quot;, o_special, (void *)setvjslots,
++ &quot;Set maximum VJ header slots&quot;,
++ OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, vj_value },
++
++ { &quot;ipcp-accept-local&quot;, o_bool, &amp;ipcp_wantoptions[0].accept_local,
++ &quot;Accept peer's address for us&quot;, 1 },
++ { &quot;ipcp-accept-remote&quot;, o_bool, &amp;ipcp_wantoptions[0].accept_remote,
++ &quot;Accept peer's address for it&quot;, 1 },
++
++ { &quot;ipparam&quot;, o_string, &amp;ipparam,
++ &quot;Set ip script parameter&quot;, OPT_PRIO },
++
++ { &quot;noipdefault&quot;, o_bool, &amp;disable_defaultip,
++ &quot;Don't use name for default IP adrs&quot;, 1 },
++
++ { &quot;ms-dns&quot;, 1, (void *)setdnsaddr,
++ &quot;DNS address for the peer's use&quot; },
++ { &quot;ms-wins&quot;, 1, (void *)setwinsaddr,
++ &quot;Nameserver for SMB over TCP/IP for peer&quot; },
++
++ { &quot;ipcp-restart&quot;, o_int, &amp;ipcp_fsm[0].timeouttime,
++ &quot;Set timeout for IPCP&quot;, OPT_PRIO },
++ { &quot;ipcp-max-terminate&quot;, o_int, &amp;ipcp_fsm[0].maxtermtransmits,
++ &quot;Set max #xmits for term-reqs&quot;, OPT_PRIO },
++ { &quot;ipcp-max-configure&quot;, o_int, &amp;ipcp_fsm[0].maxconfreqtransmits,
++ &quot;Set max #xmits for conf-reqs&quot;, OPT_PRIO },
++ { &quot;ipcp-max-failure&quot;, o_int, &amp;ipcp_fsm[0].maxnakloops,
++ &quot;Set max #conf-naks for IPCP&quot;, OPT_PRIO },
++
++ { &quot;defaultroute&quot;, o_bool, &amp;ipcp_wantoptions[0].default_route,
++ &quot;Add default route&quot;, OPT_ENABLE|1, &amp;ipcp_allowoptions[0].default_route },
++ { &quot;nodefaultroute&quot;, o_bool, &amp;ipcp_allowoptions[0].default_route,
++ &quot;disable defaultroute option&quot;, OPT_A2CLR,
++ &amp;ipcp_wantoptions[0].default_route },
++ { &quot;-defaultroute&quot;, o_bool, &amp;ipcp_allowoptions[0].default_route,
++ &quot;disable defaultroute option&quot;, OPT_ALIAS | OPT_A2CLR,
++ &amp;ipcp_wantoptions[0].default_route },
++
++ { &quot;proxyarp&quot;, o_bool, &amp;ipcp_wantoptions[0].proxy_arp,
++ &quot;Add proxy ARP entry&quot;, OPT_ENABLE|1, &amp;ipcp_allowoptions[0].proxy_arp },
++ { &quot;noproxyarp&quot;, o_bool, &amp;ipcp_allowoptions[0].proxy_arp,
++ &quot;disable proxyarp option&quot;, OPT_A2CLR,
++ &amp;ipcp_wantoptions[0].proxy_arp },
++ { &quot;-proxyarp&quot;, o_bool, &amp;ipcp_allowoptions[0].proxy_arp,
++ &quot;disable proxyarp option&quot;, OPT_ALIAS | OPT_A2CLR,
++ &amp;ipcp_wantoptions[0].proxy_arp },
++
++ { &quot;usepeerdns&quot;, o_bool, &amp;usepeerdns,
++ &quot;Ask peer for DNS address(es)&quot;, 1 },
++
++ { &quot;netmask&quot;, o_special, (void *)setnetmask,
++ &quot;set netmask&quot;, OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, netmask_str },
++
++ { &quot;IP addresses&quot;, o_wild, (void *) &amp;setipaddr,
++ &quot;set local and remote IP addresses&quot;,
++ OPT_NOARG | OPT_A2PRINTER, (void *) &amp;printipaddr },
++
++ { NULL }
++};
++
++/*
++ * Protocol entry points from main code.
++ */
++static void ipcp_init __P((int));
++static void ipcp_open __P((int));
++static void ipcp_close __P((int, char *));
++static void ipcp_lowerup __P((int));
++static void ipcp_lowerdown __P((int));
++static void ipcp_input __P((int, u_char *, int));
++static void ipcp_protrej __P((int));
++static int ipcp_printpkt __P((u_char *, int,
++ void (*) __P((void *, char *, ...)), void *));
++static void ip_check_options __P((void));
++static int ip_demand_conf __P((int));
++static int ip_active_pkt __P((u_char *, int));
++static void create_resolv __P((u_int32_t, u_int32_t));
++
++struct protent ipcp_protent = {
++ PPP_IPCP,
++ ipcp_init,
++ ipcp_input,
++ ipcp_protrej,
++ ipcp_lowerup,
++ ipcp_lowerdown,
++ ipcp_open,
++ ipcp_close,
++ ipcp_printpkt,
++ NULL,
++ 1,
++ &quot;IPCP&quot;,
++ &quot;IP&quot;,
++ ipcp_option_list,
++ ip_check_options,
++ ip_demand_conf,
++ ip_active_pkt
++};
++
++static void ipcp_clear_addrs __P((int, u_int32_t, u_int32_t));
++static void ipcp_script __P((char *)); /* Run an up/down script */
++static void ipcp_script_done __P((void *));
++
++/*
++ * Lengths of configuration options.
++ */
++#define CILEN_VOID 2
++#define CILEN_COMPRESS 4 /* min length for compression protocol opt. */
++#define CILEN_VJ 6 /* length for RFC1332 Van-Jacobson opt. */
++#define CILEN_ADDR 6 /* new-style single address option */
++#define CILEN_ADDRS 10 /* old-style dual address option */
++
++
++#define CODENAME(x) ((x) == CONFACK ? &quot;ACK&quot; : \
++ (x) == CONFNAK ? &quot;NAK&quot; : &quot;REJ&quot;)
++
++/*
++ * This state variable is used to ensure that we don't
++ * run an ipcp-up/down script while one is already running.
++ */
++static enum script_state {
++ s_down,
++ s_up,
++} ipcp_script_state;
++static pid_t ipcp_script_pid;
++
++/*
++ * Make a string representation of a network IP address.
++ */
++char *
++ip_ntoa(ipaddr)
++u_int32_t ipaddr;
++{
++ static char b[64];
++
++ slprintf(b, sizeof(b), &quot;%I&quot;, ipaddr);
++ return b;
++}
++
++/*
++ * Option parsing.
++ */
++
++/*
++ * setvjslots - set maximum number of connection slots for VJ compression
++ */
++static int
++setvjslots(argv)
++ char **argv;
++{
++ int value;
++
++ if (!int_option(*argv, &amp;value))
++ return 0;
++ if (value &lt; 2 || value &gt; 16) {
++ option_error(&quot;vj-max-slots value must be between 2 and 16&quot;);
++ return 0;
++ }
++ ipcp_wantoptions [0].maxslotindex =
++ ipcp_allowoptions[0].maxslotindex = value - 1;
++ slprintf(vj_value, sizeof(vj_value), &quot;%d&quot;, value);
++ return 1;
++}
++
++/*
++ * setdnsaddr - set the dns address(es)
++ */
++static int
++setdnsaddr(argv)
++ char **argv;
++{
++ u_int32_t dns;
++ struct hostent *hp;
++
++ dns = inet_addr(*argv);
++ if (dns == (u_int32_t) -1) {
++ if ((hp = gethostbyname(*argv)) == NULL) {
++ option_error(&quot;invalid address parameter '%s' for ms-dns option&quot;,
++ *argv);
++ return 0;
++ }
++ dns = *(u_int32_t *)hp-&gt;h_addr;
++ }
++
++ /* We take the last 2 values given, the 2nd-last as the primary
++ and the last as the secondary. If only one is given it
++ becomes both primary and secondary. */
++ if (ipcp_allowoptions[0].dnsaddr[1] == 0)
++ ipcp_allowoptions[0].dnsaddr[0] = dns;
++ else
++ ipcp_allowoptions[0].dnsaddr[0] = ipcp_allowoptions[0].dnsaddr[1];
++
++ /* always set the secondary address value. */
++ ipcp_allowoptions[0].dnsaddr[1] = dns;
++
++ return (1);
++}
++
++/*
++ * setwinsaddr - set the wins address(es)
++ * This is primrarly used with the Samba package under UNIX or for pointing
++ * the caller to the existing WINS server on a Windows NT platform.
++ */
++static int
++setwinsaddr(argv)
++ char **argv;
++{
++ u_int32_t wins;
++ struct hostent *hp;
++
++ wins = inet_addr(*argv);
++ if (wins == (u_int32_t) -1) {
++ if ((hp = gethostbyname(*argv)) == NULL) {
++ option_error(&quot;invalid address parameter '%s' for ms-wins option&quot;,
++ *argv);
++ return 0;
++ }
++ wins = *(u_int32_t *)hp-&gt;h_addr;
++ }
++
++ /* We take the last 2 values given, the 2nd-last as the primary
++ and the last as the secondary. If only one is given it
++ becomes both primary and secondary. */
++ if (ipcp_allowoptions[0].winsaddr[1] == 0)
++ ipcp_allowoptions[0].winsaddr[0] = wins;
++ else
++ ipcp_allowoptions[0].winsaddr[0] = ipcp_allowoptions[0].winsaddr[1];
++
++ /* always set the secondary address value. */
++ ipcp_allowoptions[0].winsaddr[1] = wins;
++
++ return (1);
++}
++
++/*
++ * setipaddr - Set the IP address
++ * If doit is 0, the call is to check whether this option is
++ * potentially an IP address specification.
++ */
++static int
++setipaddr(arg, argv, doit)
++ char *arg;
++ char **argv;
++ int doit;
++{
++ struct hostent *hp;
++ char *colon;
++ u_int32_t local, remote;
++ ipcp_options *wo = &amp;ipcp_wantoptions[0];
++ static int prio_local = 0, prio_remote = 0;
++
++ /*
++ * IP address pair separated by &quot;:&quot;.
++ */
++ if ((colon = strchr(arg, ':')) == NULL)
++ return 0;
++ if (!doit)
++ return 1;
++
++ /*
++ * If colon first character, then no local addr.
++ */
++ if (colon != arg &amp;&amp; option_priority &gt;= prio_local) {
++ *colon = '\0';
++ if ((local = inet_addr(arg)) == (u_int32_t) -1) {
++ if ((hp = gethostbyname(arg)) == NULL) {
++ option_error(&quot;unknown host: %s&quot;, arg);
++ return 0;
++ }
++ local = *(u_int32_t *)hp-&gt;h_addr;
++ }
++ if (bad_ip_adrs(local)) {
++ option_error(&quot;bad local IP address %s&quot;, ip_ntoa(local));
++ return 0;
++ }
++ if (local != 0)
++ wo-&gt;ouraddr = local;
++ *colon = ':';
++ prio_local = option_priority;
++ }
++
++ /*
++ * If colon last character, then no remote addr.
++ */
++ if (*++colon != '\0' &amp;&amp; option_priority &gt;= prio_remote) {
++ if ((remote = inet_addr(colon)) == (u_int32_t) -1) {
++ if ((hp = gethostbyname(colon)) == NULL) {
++ option_error(&quot;unknown host: %s&quot;, colon);
++ return 0;
++ }
++ remote = *(u_int32_t *)hp-&gt;h_addr;
++ if (remote_name[0] == 0)
++ strlcpy(remote_name, colon, sizeof(remote_name));
++ }
++ if (bad_ip_adrs(remote)) {
++ option_error(&quot;bad remote IP address %s&quot;, ip_ntoa(remote));
++ return 0;
++ }
++ if (remote != 0)
++ wo-&gt;hisaddr = remote;
++ prio_remote = option_priority;
++ }
++
++ return 1;
++}
++
++static void
++printipaddr(opt, printer, arg)
++ option_t *opt;
++ void (*printer) __P((void *, char *, ...));
++ void *arg;
++{
++ ipcp_options *wo = &amp;ipcp_wantoptions[0];
++
++ if (wo-&gt;ouraddr != 0)
++ printer(arg, &quot;%I&quot;, wo-&gt;ouraddr);
++ printer(arg, &quot;:&quot;);
++ if (wo-&gt;hisaddr != 0)
++ printer(arg, &quot;%I&quot;, wo-&gt;hisaddr);
++}
++
++/*
++ * setnetmask - set the netmask to be used on the interface.
++ */
++static int
++setnetmask(argv)
++ char **argv;
++{
++ u_int32_t mask;
++ int n;
++ char *p;
++
++ /*
++ * Unfortunately, if we use inet_addr, we can't tell whether
++ * a result of all 1s is an error or a valid 255.255.255.255.
++ */
++ p = *argv;
++ n = parse_dotted_ip(p, &amp;mask);
++
++ mask = htonl(mask);
++
++ if (n == 0 || p[n] != 0 || (netmask &amp; ~mask) != 0) {
++ option_error(&quot;invalid netmask value '%s'&quot;, *argv);
++ return 0;
++ }
++
++ netmask = mask;
++ slprintf(netmask_str, sizeof(netmask_str), &quot;%I&quot;, mask);
++
++ return (1);
++}
++
++int
++parse_dotted_ip(p, vp)
++ char *p;
++ u_int32_t *vp;
++{
++ int n;
++ u_int32_t v, b;
++ char *endp, *p0 = p;
++
++ v = 0;
++ for (n = 3;; --n) {
++ b = strtoul(p, &amp;endp, 0);
++ if (endp == p)
++ return 0;
++ if (b &gt; 255) {
++ if (n &lt; 3)
++ return 0;
++ /* accept e.g. 0xffffff00 */
++ *vp = b;
++ return endp - p0;
++ }
++ v |= b &lt;&lt; (n * 8);
++ p = endp;
++ if (n == 0)
++ break;
++ if (*p != '.')
++ return 0;
++ ++p;
++ }
++ *vp = v;
++ return p - p0;
++}
++
++
++/*
++ * ipcp_init - Initialize IPCP.
++ */
++static void
++ipcp_init(unit)
++ int unit;
++{
++ fsm *f = &amp;ipcp_fsm[unit];
++ ipcp_options *wo = &amp;ipcp_wantoptions[unit];
++ ipcp_options *ao = &amp;ipcp_allowoptions[unit];
++
++ f-&gt;unit = unit;
++ f-&gt;protocol = PPP_IPCP;
++ f-&gt;callbacks = &amp;ipcp_callbacks;
++ fsm_init(&amp;ipcp_fsm[unit]);
++
++ memset(wo, 0, sizeof(*wo));
++ memset(ao, 0, sizeof(*ao));
++
++ wo-&gt;neg_addr = 1;
++ wo-&gt;neg_vj = 1;
++ wo-&gt;vj_protocol = IPCP_VJ_COMP;
++ wo-&gt;maxslotindex = MAX_STATES - 1; /* really max index */
++ wo-&gt;cflag = 1;
++
++
++ /* max slots and slot-id compression are currently hardwired in */
++ /* ppp_if.c to 16 and 1, this needs to be changed (among other */
++ /* things) gmc */
++
++ ao-&gt;neg_addr = 1;
++ ao-&gt;neg_vj = 1;
++ ao-&gt;maxslotindex = MAX_STATES - 1;
++ ao-&gt;cflag = 1;
++
++ /*
++ * XXX These control whether the user may use the proxyarp
++ * and defaultroute options.
++ */
++ ao-&gt;proxy_arp = 1;
++ ao-&gt;default_route = 1;
++}
++
++
++/*
++ * ipcp_open - IPCP is allowed to come up.
++ */
++static void
++ipcp_open(unit)
++ int unit;
++{
++ fsm_open(&amp;ipcp_fsm[unit]);
++}
++
++
++/*
++ * ipcp_close - Take IPCP down.
++ */
++static void
++ipcp_close(unit, reason)
++ int unit;
++ char *reason;
++{
++ fsm_close(&amp;ipcp_fsm[unit], reason);
++}
++
++
++/*
++ * ipcp_lowerup - The lower layer is up.
++ */
++static void
++ipcp_lowerup(unit)
++ int unit;
++{
++ fsm_lowerup(&amp;ipcp_fsm[unit]);
++}
++
++
++/*
++ * ipcp_lowerdown - The lower layer is down.
++ */
++static void
++ipcp_lowerdown(unit)
++ int unit;
++{
++ fsm_lowerdown(&amp;ipcp_fsm[unit]);
++}
++
++
++/*
++ * ipcp_input - Input IPCP packet.
++ */
++static void
++ipcp_input(unit, p, len)
++ int unit;
++ u_char *p;
++ int len;
++{
++ fsm_input(&amp;ipcp_fsm[unit], p, len);
++}
++
++
++/*
++ * ipcp_protrej - A Protocol-Reject was received for IPCP.
++ *
++ * Pretend the lower layer went down, so we shut up.
++ */
++static void
++ipcp_protrej(unit)
++ int unit;
++{
++ fsm_lowerdown(&amp;ipcp_fsm[unit]);
++}
++
++
++/*
++ * ipcp_resetci - Reset our CI.
++ * Called by fsm_sconfreq, Send Configure Request.
++ */
++static void
++ipcp_resetci(f)
++ fsm *f;
++{
++ ipcp_options *wo = &amp;ipcp_wantoptions[f-&gt;unit];
++ ipcp_options *go = &amp;ipcp_gotoptions[f-&gt;unit];
++
++ wo-&gt;req_addr = wo-&gt;neg_addr &amp;&amp; ipcp_allowoptions[f-&gt;unit].neg_addr;
++ if (wo-&gt;ouraddr == 0)
++ wo-&gt;accept_local = 1;
++ if (wo-&gt;hisaddr == 0)
++ wo-&gt;accept_remote = 1;
++ wo-&gt;req_dns1 = usepeerdns; /* Request DNS addresses from the peer */
++ wo-&gt;req_dns2 = usepeerdns;
++ *go = *wo;
++ if (!ask_for_local)
++ go-&gt;ouraddr = 0;
++ if (ip_choose_hook)
++ ip_choose_hook(&amp;wo-&gt;hisaddr);
++}
++
++
++/*
++ * ipcp_cilen - Return length of our CI.
++ * Called by fsm_sconfreq, Send Configure Request.
++ */
++static int
++ipcp_cilen(f)
++ fsm *f;
++{
++ ipcp_options *go = &amp;ipcp_gotoptions[f-&gt;unit];
++ ipcp_options *wo = &amp;ipcp_wantoptions[f-&gt;unit];
++ ipcp_options *ho = &amp;ipcp_hisoptions[f-&gt;unit];
++
++#define LENCIVJ(neg, old) (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0)
++#define LENCIADDR(neg, old) (neg ? (old? CILEN_ADDRS : CILEN_ADDR) : 0)
++#define LENCIDNS(neg) (neg ? (CILEN_ADDR) : 0)
++
++ /*
++ * First see if we want to change our options to the old
++ * forms because we have received old forms from the peer.
++ */
++ if (wo-&gt;neg_addr &amp;&amp; !go-&gt;neg_addr &amp;&amp; !go-&gt;old_addrs) {
++ /* use the old style of address negotiation */
++ go-&gt;neg_addr = 1;
++ go-&gt;old_addrs = 1;
++ }
++ if (wo-&gt;neg_vj &amp;&amp; !go-&gt;neg_vj &amp;&amp; !go-&gt;old_vj) {
++ /* try an older style of VJ negotiation */
++ /* use the old style only if the peer did */
++ if (ho-&gt;neg_vj &amp;&amp; ho-&gt;old_vj) {
++ go-&gt;neg_vj = 1;
++ go-&gt;old_vj = 1;
++ go-&gt;vj_protocol = ho-&gt;vj_protocol;
++ }
++ }
++
++ return (LENCIADDR(go-&gt;neg_addr, go-&gt;old_addrs) +
++ LENCIVJ(go-&gt;neg_vj, go-&gt;old_vj) +
++ LENCIDNS(go-&gt;req_dns1) +
++ LENCIDNS(go-&gt;req_dns2)) ;
++}
++
++
++/*
++ * ipcp_addci - Add our desired CIs to a packet.
++ * Called by fsm_sconfreq, Send Configure Request.
++ */
++static void
++ipcp_addci(f, ucp, lenp)
++ fsm *f;
++ u_char *ucp;
++ int *lenp;
++{
++ ipcp_options *go = &amp;ipcp_gotoptions[f-&gt;unit];
++ int len = *lenp;
++
++#define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \
++ if (neg) { \
++ int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \
++ if (len &gt;= vjlen) { \
++ PUTCHAR(opt, ucp); \
++ PUTCHAR(vjlen, ucp); \
++ PUTSHORT(val, ucp); \
++ if (!old) { \
++ PUTCHAR(maxslotindex, ucp); \
++ PUTCHAR(cflag, ucp); \
++ } \
++ len -= vjlen; \
++ } else \
++ neg = 0; \
++ }
++
++#define ADDCIADDR(opt, neg, old, val1, val2) \
++ if (neg) { \
++ int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \
++ if (len &gt;= addrlen) { \
++ u_int32_t l; \
++ PUTCHAR(opt, ucp); \
++ PUTCHAR(addrlen, ucp); \
++ l = ntohl(val1); \
++ PUTLONG(l, ucp); \
++ if (old) { \
++ l = ntohl(val2); \
++ PUTLONG(l, ucp); \
++ } \
++ len -= addrlen; \
++ } else \
++ neg = 0; \
++ }
++
++#define ADDCIDNS(opt, neg, addr) \
++ if (neg) { \
++ if (len &gt;= CILEN_ADDR) { \
++ u_int32_t l; \
++ PUTCHAR(opt, ucp); \
++ PUTCHAR(CILEN_ADDR, ucp); \
++ l = ntohl(addr); \
++ PUTLONG(l, ucp); \
++ len -= CILEN_ADDR; \
++ } else \
++ neg = 0; \
++ }
++
++ ADDCIADDR((go-&gt;old_addrs? CI_ADDRS: CI_ADDR), go-&gt;neg_addr,
++ go-&gt;old_addrs, go-&gt;ouraddr, go-&gt;hisaddr);
++
++ ADDCIVJ(CI_COMPRESSTYPE, go-&gt;neg_vj, go-&gt;vj_protocol, go-&gt;old_vj,
++ go-&gt;maxslotindex, go-&gt;cflag);
++
++ ADDCIDNS(CI_MS_DNS1, go-&gt;req_dns1, go-&gt;dnsaddr[0]);
++
++ ADDCIDNS(CI_MS_DNS2, go-&gt;req_dns2, go-&gt;dnsaddr[1]);
++
++ *lenp -= len;
++}
++
++
++/*
++ * ipcp_ackci - Ack our CIs.
++ * Called by fsm_rconfack, Receive Configure ACK.
++ *
++ * Returns:
++ * 0 - Ack was bad.
++ * 1 - Ack was good.
++ */
++static int
++ipcp_ackci(f, p, len)
++ fsm *f;
++ u_char *p;
++ int len;
++{
++ ipcp_options *go = &amp;ipcp_gotoptions[f-&gt;unit];
++ u_short cilen, citype, cishort;
++ u_int32_t cilong;
++ u_char cimaxslotindex, cicflag;
++
++ /*
++ * CIs must be in exactly the same order that we sent...
++ * Check packet length and CI length at each step.
++ * If we find any deviations, then this packet is bad.
++ */
++
++#define ACKCIVJ(opt, neg, val, old, maxslotindex, cflag) \
++ if (neg) { \
++ int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \
++ if ((len -= vjlen) &lt; 0) \
++ goto bad; \
++ GETCHAR(citype, p); \
++ GETCHAR(cilen, p); \
++ if (cilen != vjlen || \
++ citype != opt) \
++ goto bad; \
++ GETSHORT(cishort, p); \
++ if (cishort != val) \
++ goto bad; \
++ if (!old) { \
++ GETCHAR(cimaxslotindex, p); \
++ if (cimaxslotindex != maxslotindex) \
++ goto bad; \
++ GETCHAR(cicflag, p); \
++ if (cicflag != cflag) \
++ goto bad; \
++ } \
++ }
++
++#define ACKCIADDR(opt, neg, old, val1, val2) \
++ if (neg) { \
++ int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \
++ u_int32_t l; \
++ if ((len -= addrlen) &lt; 0) \
++ goto bad; \
++ GETCHAR(citype, p); \
++ GETCHAR(cilen, p); \
++ if (cilen != addrlen || \
++ citype != opt) \
++ goto bad; \
++ GETLONG(l, p); \
++ cilong = htonl(l); \
++ if (val1 != cilong) \
++ goto bad; \
++ if (old) { \
++ GETLONG(l, p); \
++ cilong = htonl(l); \
++ if (val2 != cilong) \
++ goto bad; \
++ } \
++ }
++
++#define ACKCIDNS(opt, neg, addr) \
++ if (neg) { \
++ u_int32_t l; \
++ if ((len -= CILEN_ADDR) &lt; 0) \
++ goto bad; \
++ GETCHAR(citype, p); \
++ GETCHAR(cilen, p); \
++ if (cilen != CILEN_ADDR || citype != opt) \
++ goto bad; \
++ GETLONG(l, p); \
++ cilong = htonl(l); \
++ if (addr != cilong) \
++ goto bad; \
++ }
++
++ ACKCIADDR((go-&gt;old_addrs? CI_ADDRS: CI_ADDR), go-&gt;neg_addr,
++ go-&gt;old_addrs, go-&gt;ouraddr, go-&gt;hisaddr);
++
++ ACKCIVJ(CI_COMPRESSTYPE, go-&gt;neg_vj, go-&gt;vj_protocol, go-&gt;old_vj,
++ go-&gt;maxslotindex, go-&gt;cflag);
++
++ ACKCIDNS(CI_MS_DNS1, go-&gt;req_dns1, go-&gt;dnsaddr[0]);
++
++ ACKCIDNS(CI_MS_DNS2, go-&gt;req_dns2, go-&gt;dnsaddr[1]);
++
++ /*
++ * If there are any remaining CIs, then this packet is bad.
++ */
++ if (len != 0)
++ goto bad;
++ return (1);
++
++bad:
++ IPCPDEBUG((&quot;ipcp_ackci: received bad Ack!&quot;));
++ return (0);
++}
++
++/*
++ * ipcp_nakci - Peer has sent a NAK for some of our CIs.
++ * This should not modify any state if the Nak is bad
++ * or if IPCP is in the OPENED state.
++ * Calback from fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
++ *
++ * Returns:
++ * 0 - Nak was bad.
++ * 1 - Nak was good.
++ */
++static int
++ipcp_nakci(f, p, len)
++ fsm *f;
++ u_char *p;
++ int len;
++{
++ ipcp_options *go = &amp;ipcp_gotoptions[f-&gt;unit];
++ u_char cimaxslotindex, cicflag;
++ u_char citype, cilen, *next;
++ u_short cishort;
++ u_int32_t ciaddr1, ciaddr2, l, cidnsaddr;
++ ipcp_options no; /* options we've seen Naks for */
++ ipcp_options try; /* options to request next time */
++
++ BZERO(&amp;no, sizeof(no));
++ try = *go;
++
++ /*
++ * Any Nak'd CIs must be in exactly the same order that we sent.
++ * Check packet length and CI length at each step.
++ * If we find any deviations, then this packet is bad.
++ */
++#define NAKCIADDR(opt, neg, old, code) \
++ if (go-&gt;neg &amp;&amp; \
++ len &gt;= (cilen = (old? CILEN_ADDRS: CILEN_ADDR)) &amp;&amp; \
++ p[1] == cilen &amp;&amp; \
++ p[0] == opt) { \
++ len -= cilen; \
++ INCPTR(2, p); \
++ GETLONG(l, p); \
++ ciaddr1 = htonl(l); \
++ if (old) { \
++ GETLONG(l, p); \
++ ciaddr2 = htonl(l); \
++ no.old_addrs = 1; \
++ } else \
++ ciaddr2 = 0; \
++ no.neg = 1; \
++ code \
++ }
++
++#define NAKCIVJ(opt, neg, code) \
++ if (go-&gt;neg &amp;&amp; \
++ ((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) &amp;&amp; \
++ len &gt;= cilen &amp;&amp; \
++ p[0] == opt) { \
++ len -= cilen; \
++ INCPTR(2, p); \
++ GETSHORT(cishort, p); \
++ no.neg = 1; \
++ code \
++ }
++
++#define NAKCIDNS(opt, neg, code) \
++ if (go-&gt;neg &amp;&amp; \
++ ((cilen = p[1]) == CILEN_ADDR) &amp;&amp; \
++ len &gt;= cilen &amp;&amp; \
++ p[0] == opt) { \
++ len -= cilen; \
++ INCPTR(2, p); \
++ GETLONG(l, p); \
++ cidnsaddr = htonl(l); \
++ no.neg = 1; \
++ code \
++ }
++
++ /*
++ * Accept the peer's idea of {our,his} address, if different
++ * from our idea, only if the accept_{local,remote} flag is set.
++ */
++ NAKCIADDR((go-&gt;old_addrs? CI_ADDRS: CI_ADDR), neg_addr, go-&gt;old_addrs,
++ if (go-&gt;accept_local &amp;&amp; ciaddr1) { /* Do we know our address? */
++ try.ouraddr = ciaddr1;
++ }
++ if (go-&gt;accept_remote &amp;&amp; ciaddr2) { /* Does he know his? */
++ try.hisaddr = ciaddr2;
++ }
++ );
++
++ /*
++ * Accept the peer's value of maxslotindex provided that it
++ * is less than what we asked for. Turn off slot-ID compression
++ * if the peer wants. Send old-style compress-type option if
++ * the peer wants.
++ */
++ NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
++ if (cilen == CILEN_VJ) {
++ GETCHAR(cimaxslotindex, p);
++ GETCHAR(cicflag, p);
++ if (cishort == IPCP_VJ_COMP) {
++ try.old_vj = 0;
++ if (cimaxslotindex &lt; go-&gt;maxslotindex)
++ try.maxslotindex = cimaxslotindex;
++ if (!cicflag)
++ try.cflag = 0;
++ } else {
++ try.neg_vj = 0;
++ }
++ } else {
++ if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) {
++ try.old_vj = 1;
++ try.vj_protocol = cishort;
++ } else {
++ try.neg_vj = 0;
++ }
++ }
++ );
++
++ NAKCIDNS(CI_MS_DNS1, req_dns1,
++ try.dnsaddr[0] = cidnsaddr;
++ );
++
++ NAKCIDNS(CI_MS_DNS2, req_dns2,
++ try.dnsaddr[1] = cidnsaddr;
++ );
++
++ /*
++ * There may be remaining CIs, if the peer is requesting negotiation
++ * on an option that we didn't include in our request packet.
++ * If they want to negotiate about IP addresses, we comply.
++ * If they want us to ask for compression, we refuse.
++ */
++ while (len &gt; CILEN_VOID) {
++ GETCHAR(citype, p);
++ GETCHAR(cilen, p);
++ if( (len -= cilen) &lt; 0 )
++ goto bad;
++ next = p + cilen - 2;
++
++ switch (citype) {
++ case CI_COMPRESSTYPE:
++ if (go-&gt;neg_vj || no.neg_vj ||
++ (cilen != CILEN_VJ &amp;&amp; cilen != CILEN_COMPRESS))
++ goto bad;
++ no.neg_vj = 1;
++ break;
++ case CI_ADDRS:
++ if ((go-&gt;neg_addr &amp;&amp; go-&gt;old_addrs) || no.old_addrs
++ || cilen != CILEN_ADDRS)
++ goto bad;
++ try.neg_addr = 1;
++ try.old_addrs = 1;
++ GETLONG(l, p);
++ ciaddr1 = htonl(l);
++ if (ciaddr1 &amp;&amp; go-&gt;accept_local)
++ try.ouraddr = ciaddr1;
++ GETLONG(l, p);
++ ciaddr2 = htonl(l);
++ if (ciaddr2 &amp;&amp; go-&gt;accept_remote)
++ try.hisaddr = ciaddr2;
++ no.old_addrs = 1;
++ break;
++ case CI_ADDR:
++ if (go-&gt;neg_addr || no.neg_addr || cilen != CILEN_ADDR)
++ goto bad;
++ try.old_addrs = 0;
++ GETLONG(l, p);
++ ciaddr1 = htonl(l);
++ if (ciaddr1 &amp;&amp; go-&gt;accept_local)
++ try.ouraddr = ciaddr1;
++ if (try.ouraddr != 0)
++ try.neg_addr = 1;
++ no.neg_addr = 1;
++ break;
++ }
++ p = next;
++ }
++
++ /*
++ * OK, the Nak is good. Now we can update state.
++ * If there are any remaining options, we ignore them.
++ */
++ if (f-&gt;state != OPENED)
++ *go = try;
++
++ return 1;
++
++bad:
++ IPCPDEBUG((&quot;ipcp_nakci: received bad Nak!&quot;));
++ return 0;
++}
++
++
++/*
++ * ipcp_rejci - Reject some of our CIs.
++ * Callback from fsm_rconfnakrej.
++ */
++static int
++ipcp_rejci(f, p, len)
++ fsm *f;
++ u_char *p;
++ int len;
++{
++ ipcp_options *go = &amp;ipcp_gotoptions[f-&gt;unit];
++ u_char cimaxslotindex, ciflag, cilen;
++ u_short cishort;
++ u_int32_t cilong;
++ ipcp_options try; /* options to request next time */
++
++ try = *go;
++ /*
++ * Any Rejected CIs must be in exactly the same order that we sent.
++ * Check packet length and CI length at each step.
++ * If we find any deviations, then this packet is bad.
++ */
++#define REJCIADDR(opt, neg, old, val1, val2) \
++ if (go-&gt;neg &amp;&amp; \
++ len &gt;= (cilen = old? CILEN_ADDRS: CILEN_ADDR) &amp;&amp; \
++ p[1] == cilen &amp;&amp; \
++ p[0] == opt) { \
++ u_int32_t l; \
++ len -= cilen; \
++ INCPTR(2, p); \
++ GETLONG(l, p); \
++ cilong = htonl(l); \
++ /* Check rejected value. */ \
++ if (cilong != val1) \
++ goto bad; \
++ if (old) { \
++ GETLONG(l, p); \
++ cilong = htonl(l); \
++ /* Check rejected value. */ \
++ if (cilong != val2) \
++ goto bad; \
++ } \
++ try.neg = 0; \
++ }
++
++#define REJCIVJ(opt, neg, val, old, maxslot, cflag) \
++ if (go-&gt;neg &amp;&amp; \
++ p[1] == (old? CILEN_COMPRESS : CILEN_VJ) &amp;&amp; \
++ len &gt;= p[1] &amp;&amp; \
++ p[0] == opt) { \
++ len -= p[1]; \
++ INCPTR(2, p); \
++ GETSHORT(cishort, p); \
++ /* Check rejected value. */ \
++ if (cishort != val) \
++ goto bad; \
++ if (!old) { \
++ GETCHAR(cimaxslotindex, p); \
++ if (cimaxslotindex != maxslot) \
++ goto bad; \
++ GETCHAR(ciflag, p); \
++ if (ciflag != cflag) \
++ goto bad; \
++ } \
++ try.neg = 0; \
++ }
++
++#define REJCIDNS(opt, neg, dnsaddr) \
++ if (go-&gt;neg &amp;&amp; \
++ ((cilen = p[1]) == CILEN_ADDR) &amp;&amp; \
++ len &gt;= cilen &amp;&amp; \
++ p[0] == opt) { \
++ u_int32_t l; \
++ len -= cilen; \
++ INCPTR(2, p); \
++ GETLONG(l, p); \
++ cilong = htonl(l); \
++ /* Check rejected value. */ \
++ if (cilong != dnsaddr) \
++ goto bad; \
++ try.neg = 0; \
++ }
++
++
++ REJCIADDR((go-&gt;old_addrs? CI_ADDRS: CI_ADDR), neg_addr,
++ go-&gt;old_addrs, go-&gt;ouraddr, go-&gt;hisaddr);
++
++ REJCIVJ(CI_COMPRESSTYPE, neg_vj, go-&gt;vj_protocol, go-&gt;old_vj,
++ go-&gt;maxslotindex, go-&gt;cflag);
++
++ REJCIDNS(CI_MS_DNS1, req_dns1, go-&gt;dnsaddr[0]);
++
++ REJCIDNS(CI_MS_DNS2, req_dns2, go-&gt;dnsaddr[1]);
++
++ /*
++ * If there are any remaining CIs, then this packet is bad.
++ */
++ if (len != 0)
++ goto bad;
++ /*
++ * Now we can update state.
++ */
++ if (f-&gt;state != OPENED)
++ *go = try;
++ return 1;
++
++bad:
++ IPCPDEBUG((&quot;ipcp_rejci: received bad Reject!&quot;));
++ return 0;
++}
++
++
++/*
++ * ipcp_reqci - Check the peer's requested CIs and send appropriate response.
++ * Callback from fsm_rconfreq, Receive Configure Request
++ *
++ * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
++ * appropriately. If reject_if_disagree is non-zero, doesn't return
++ * CONFNAK; returns CONFREJ if it can't return CONFACK.
++ */
++static int
++ipcp_reqci(f, inp, len, reject_if_disagree)
++ fsm *f;
++ u_char *inp; /* Requested CIs */
++ int *len; /* Length of requested CIs */
++ int reject_if_disagree;
++{
++ ipcp_options *wo = &amp;ipcp_wantoptions[f-&gt;unit];
++ ipcp_options *ho = &amp;ipcp_hisoptions[f-&gt;unit];
++ ipcp_options *ao = &amp;ipcp_allowoptions[f-&gt;unit];
++ ipcp_options *go = &amp;ipcp_gotoptions[f-&gt;unit];
++ u_char *cip, *next; /* Pointer to current and next CIs */
++ u_short cilen, citype; /* Parsed len, type */
++ u_short cishort; /* Parsed short value */
++ u_int32_t tl, ciaddr1, ciaddr2;/* Parsed address values */
++ int rc = CONFACK; /* Final packet return code */
++ int orc; /* Individual option return code */
++ u_char *p; /* Pointer to next char to parse */
++ u_char *ucp = inp; /* Pointer to current output char */
++ int l = *len; /* Length left */
++ u_char maxslotindex, cflag;
++ int d;
++
++ /*
++ * Reset all his options.
++ */
++ BZERO(ho, sizeof(*ho));
++
++ /*
++ * Process all his options.
++ */
++ next = inp;
++ while (l) {
++ orc = CONFACK; /* Assume success */
++ cip = p = next; /* Remember begining of CI */
++ if (l &lt; 2 || /* Not enough data for CI header or */
++ p[1] &lt; 2 || /* CI length too small or */
++ p[1] &gt; l) { /* CI length too big? */
++ IPCPDEBUG((&quot;ipcp_reqci: bad CI length!&quot;));
++ orc = CONFREJ; /* Reject bad CI */
++ cilen = l; /* Reject till end of packet */
++ l = 0; /* Don't loop again */
++ goto endswitch;
++ }
++ GETCHAR(citype, p); /* Parse CI type */
++ GETCHAR(cilen, p); /* Parse CI length */
++ l -= cilen; /* Adjust remaining length */
++ next += cilen; /* Step to next CI */
++
++ switch (citype) { /* Check CI type */
++ case CI_ADDRS:
++ if (!ao-&gt;neg_addr ||
++ cilen != CILEN_ADDRS) { /* Check CI length */
++ orc = CONFREJ; /* Reject CI */
++ break;
++ }
++
++ /*
++ * If he has no address, or if we both have his address but
++ * disagree about it, then NAK it with our idea.
++ * In particular, if we don't know his address, but he does,
++ * then accept it.
++ */
++ GETLONG(tl, p); /* Parse source address (his) */
++ ciaddr1 = htonl(tl);
++ if (ciaddr1 != wo-&gt;hisaddr
++ &amp;&amp; (ciaddr1 == 0 || !wo-&gt;accept_remote)) {
++ orc = CONFNAK;
++ if (!reject_if_disagree) {
++ DECPTR(sizeof(u_int32_t), p);
++ tl = ntohl(wo-&gt;hisaddr);
++ PUTLONG(tl, p);
++ }
++ } else if (ciaddr1 == 0 &amp;&amp; wo-&gt;hisaddr == 0) {
++ /*
++ * If neither we nor he knows his address, reject the option.
++ */
++ orc = CONFREJ;
++ wo-&gt;req_addr = 0; /* don't NAK with 0.0.0.0 later */
++ break;
++ }
++
++ /*
++ * If he doesn't know our address, or if we both have our address
++ * but disagree about it, then NAK it with our idea.
++ */
++ GETLONG(tl, p); /* Parse desination address (ours) */
++ ciaddr2 = htonl(tl);
++ if (ciaddr2 != wo-&gt;ouraddr) {
++ if (ciaddr2 == 0 || !wo-&gt;accept_local) {
++ orc = CONFNAK;
++ if (!reject_if_disagree) {
++ DECPTR(sizeof(u_int32_t), p);
++ tl = ntohl(wo-&gt;ouraddr);
++ PUTLONG(tl, p);
++ }
++ } else {
++ go-&gt;ouraddr = ciaddr2; /* accept peer's idea */
++ }
++ }
++
++ ho-&gt;neg_addr = 1;
++ ho-&gt;old_addrs = 1;
++ ho-&gt;hisaddr = ciaddr1;
++ ho-&gt;ouraddr = ciaddr2;
++ break;
++
++ case CI_ADDR:
++ if (!ao-&gt;neg_addr ||
++ cilen != CILEN_ADDR) { /* Check CI length */
++ orc = CONFREJ; /* Reject CI */
++ break;
++ }
++
++ /*
++ * If he has no address, or if we both have his address but
++ * disagree about it, then NAK it with our idea.
++ * In particular, if we don't know his address, but he does,
++ * then accept it.
++ */
++ GETLONG(tl, p); /* Parse source address (his) */
++ ciaddr1 = htonl(tl);
++ if (ciaddr1 != wo-&gt;hisaddr
++ &amp;&amp; (ciaddr1 == 0 || !wo-&gt;accept_remote)) {
++ orc = CONFNAK;
++ if (!reject_if_disagree) {
++ DECPTR(sizeof(u_int32_t), p);
++ tl = ntohl(wo-&gt;hisaddr);
++ PUTLONG(tl, p);
++ }
++ } else if (ciaddr1 == 0 &amp;&amp; wo-&gt;hisaddr == 0) {
++ /*
++ * Don't ACK an address of 0.0.0.0 - reject it instead.
++ */
++ orc = CONFREJ;
++ wo-&gt;req_addr = 0; /* don't NAK with 0.0.0.0 later */
++ break;
++ }
++
++ ho-&gt;neg_addr = 1;
++ ho-&gt;hisaddr = ciaddr1;
++ break;
++
++ case CI_MS_DNS1:
++ case CI_MS_DNS2:
++ /* Microsoft primary or secondary DNS request */
++ d = citype == CI_MS_DNS2;
++
++ /* If we do not have a DNS address then we cannot send it */
++ if (ao-&gt;dnsaddr[d] == 0 ||
++ cilen != CILEN_ADDR) { /* Check CI length */
++ orc = CONFREJ; /* Reject CI */
++ break;
++ }
++ GETLONG(tl, p);
++ if (htonl(tl) != ao-&gt;dnsaddr[d]) {
++ DECPTR(sizeof(u_int32_t), p);
++ tl = ntohl(ao-&gt;dnsaddr[d]);
++ PUTLONG(tl, p);
++ orc = CONFNAK;
++ }
++ break;
++
++ case CI_MS_WINS1:
++ case CI_MS_WINS2:
++ /* Microsoft primary or secondary WINS request */
++ d = citype == CI_MS_WINS2;
++
++ /* If we do not have a DNS address then we cannot send it */
++ if (ao-&gt;winsaddr[d] == 0 ||
++ cilen != CILEN_ADDR) { /* Check CI length */
++ orc = CONFREJ; /* Reject CI */
++ break;
++ }
++ GETLONG(tl, p);
++ if (htonl(tl) != ao-&gt;winsaddr[d]) {
++ DECPTR(sizeof(u_int32_t), p);
++ tl = ntohl(ao-&gt;winsaddr[d]);
++ PUTLONG(tl, p);
++ orc = CONFNAK;
++ }
++ break;
++
++ case CI_COMPRESSTYPE:
++ if (!ao-&gt;neg_vj ||
++ (cilen != CILEN_VJ &amp;&amp; cilen != CILEN_COMPRESS)) {
++ orc = CONFREJ;
++ break;
++ }
++ GETSHORT(cishort, p);
++
++ if (!(cishort == IPCP_VJ_COMP ||
++ (cishort == IPCP_VJ_COMP_OLD &amp;&amp; cilen == CILEN_COMPRESS))) {
++ orc = CONFREJ;
++ break;
++ }
++
++ ho-&gt;neg_vj = 1;
++ ho-&gt;vj_protocol = cishort;
++ if (cilen == CILEN_VJ) {
++ GETCHAR(maxslotindex, p);
++ if (maxslotindex &gt; ao-&gt;maxslotindex) {
++ orc = CONFNAK;
++ if (!reject_if_disagree){
++ DECPTR(1, p);
++ PUTCHAR(ao-&gt;maxslotindex, p);
++ }
++ }
++ GETCHAR(cflag, p);
++ if (cflag &amp;&amp; !ao-&gt;cflag) {
++ orc = CONFNAK;
++ if (!reject_if_disagree){
++ DECPTR(1, p);
++ PUTCHAR(wo-&gt;cflag, p);
++ }
++ }
++ ho-&gt;maxslotindex = maxslotindex;
++ ho-&gt;cflag = cflag;
++ } else {
++ ho-&gt;old_vj = 1;
++ ho-&gt;maxslotindex = MAX_STATES - 1;
++ ho-&gt;cflag = 1;
++ }
++ break;
++
++ default:
++ orc = CONFREJ;
++ break;
++ }
++endswitch:
++ if (orc == CONFACK &amp;&amp; /* Good CI */
++ rc != CONFACK) /* but prior CI wasnt? */
++ continue; /* Don't send this one */
++
++ if (orc == CONFNAK) { /* Nak this CI? */
++ if (reject_if_disagree) /* Getting fed up with sending NAKs? */
++ orc = CONFREJ; /* Get tough if so */
++ else {
++ if (rc == CONFREJ) /* Rejecting prior CI? */
++ continue; /* Don't send this one */
++ if (rc == CONFACK) { /* Ack'd all prior CIs? */
++ rc = CONFNAK; /* Not anymore... */
++ ucp = inp; /* Backup */
++ }
++ }
++ }
++
++ if (orc == CONFREJ &amp;&amp; /* Reject this CI */
++ rc != CONFREJ) { /* but no prior ones? */
++ rc = CONFREJ;
++ ucp = inp; /* Backup */
++ }
++
++ /* Need to move CI? */
++ if (ucp != cip)
++ BCOPY(cip, ucp, cilen); /* Move it */
++
++ /* Update output pointer */
++ INCPTR(cilen, ucp);
++ }
++
++ /*
++ * If we aren't rejecting this packet, and we want to negotiate
++ * their address, and they didn't send their address, then we
++ * send a NAK with a CI_ADDR option appended. We assume the
++ * input buffer is long enough that we can append the extra
++ * option safely.
++ */
++ if (rc != CONFREJ &amp;&amp; !ho-&gt;neg_addr &amp;&amp;
++ wo-&gt;req_addr &amp;&amp; !reject_if_disagree) {
++ if (rc == CONFACK) {
++ rc = CONFNAK;
++ ucp = inp; /* reset pointer */
++ wo-&gt;req_addr = 0; /* don't ask again */
++ }
++ PUTCHAR(CI_ADDR, ucp);
++ PUTCHAR(CILEN_ADDR, ucp);
++ tl = ntohl(wo-&gt;hisaddr);
++ PUTLONG(tl, ucp);
++ }
++
++ *len = ucp - inp; /* Compute output length */
++ IPCPDEBUG((&quot;ipcp: returning Configure-%s&quot;, CODENAME(rc)));
++ return (rc); /* Return final code */
++}
++
++
++/*
++ * ip_check_options - check that any IP-related options are OK,
++ * and assign appropriate defaults.
++ */
++static void
++ip_check_options()
++{
++ struct hostent *hp;
++ u_int32_t local;
++ ipcp_options *wo = &amp;ipcp_wantoptions[0];
++
++ /*
++ * Default our local IP address based on our hostname.
++ * If local IP address already given, don't bother.
++ */
++ if (wo-&gt;ouraddr == 0 &amp;&amp; !disable_defaultip) {
++ /*
++ * Look up our hostname (possibly with domain name appended)
++ * and take the first IP address as our local IP address.
++ * If there isn't an IP address for our hostname, too bad.
++ */
++ wo-&gt;accept_local = 1; /* don't insist on this default value */
++ if ((hp = gethostbyname(hostname)) != NULL) {
++ local = *(u_int32_t *)hp-&gt;h_addr;
++ if (local != 0 &amp;&amp; !bad_ip_adrs(local))
++ wo-&gt;ouraddr = local;
++ }
++ }
++ ask_for_local = wo-&gt;ouraddr != 0 || !disable_defaultip;
++}
++
++
++/*
++ * ip_demand_conf - configure the interface as though
++ * IPCP were up, for use with dial-on-demand.
++ */
++static int
++ip_demand_conf(u)
++ int u;
++{
++ ipcp_options *wo = &amp;ipcp_wantoptions[u];
++
++ if (wo-&gt;hisaddr == 0) {
++ /* make up an arbitrary address for the peer */
++ wo-&gt;hisaddr = htonl(0x0a707070 + ifunit);
++ wo-&gt;accept_remote = 1;
++ }
++ if (wo-&gt;ouraddr == 0) {
++ /* make up an arbitrary address for us */
++ wo-&gt;ouraddr = htonl(0x0a404040 + ifunit);
++ wo-&gt;accept_local = 1;
++ ask_for_local = 0; /* don't tell the peer this address */
++ }
++ if (!sifaddr(u, wo-&gt;ouraddr, wo-&gt;hisaddr, GetMask(wo-&gt;ouraddr)))
++ return 0;
++ if (!sifup(u))
++ return 0;
++ if (!sifnpmode(u, PPP_IP, NPMODE_QUEUE))
++ return 0;
++ if (wo-&gt;default_route)
++ if (sifdefaultroute(u, wo-&gt;ouraddr, wo-&gt;hisaddr))
++ default_route_set[u] = 1;
++ if (wo-&gt;proxy_arp)
++ if (sifproxyarp(u, wo-&gt;hisaddr))
++ proxy_arp_set[u] = 1;
++
++ notice(&quot;local IP address %I&quot;, wo-&gt;ouraddr);
++ notice(&quot;remote IP address %I&quot;, wo-&gt;hisaddr);
++
++ return 1;
++}
++
++
++/*
++ * ipcp_up - IPCP has come UP.
++ *
++ * Configure the IP network interface appropriately and bring it up.
++ */
++static void
++ipcp_up(f)
++ fsm *f;
++{
++ u_int32_t mask;
++ ipcp_options *ho = &amp;ipcp_hisoptions[f-&gt;unit];
++ ipcp_options *go = &amp;ipcp_gotoptions[f-&gt;unit];
++ ipcp_options *wo = &amp;ipcp_wantoptions[f-&gt;unit];
++
++ IPCPDEBUG((&quot;ipcp: up&quot;));
++
++ /*
++ * We must have a non-zero IP address for both ends of the link.
++ */
++ if (!ho-&gt;neg_addr)
++ ho-&gt;hisaddr = wo-&gt;hisaddr;
++
++ if (go-&gt;ouraddr == 0) {
++ error(&quot;Could not determine local IP address&quot;);
++ ipcp_close(f-&gt;unit, &quot;Could not determine local IP address&quot;);
++ return;
++ }
++ if (ho-&gt;hisaddr == 0) {
++ ho-&gt;hisaddr = htonl(0x0a404040 + ifunit);
++ warn(&quot;Could not determine remote IP address: defaulting to %I&quot;,
++ ho-&gt;hisaddr);
++ }
++ script_setenv(&quot;IPLOCAL&quot;, ip_ntoa(go-&gt;ouraddr), 0);
++ script_setenv(&quot;IPREMOTE&quot;, ip_ntoa(ho-&gt;hisaddr), 1);
++
++ if (usepeerdns &amp;&amp; (go-&gt;dnsaddr[0] || go-&gt;dnsaddr[1])) {
++ script_setenv(&quot;USEPEERDNS&quot;, &quot;1&quot;, 0);
++ if (go-&gt;dnsaddr[0])
++ script_setenv(&quot;DNS1&quot;, ip_ntoa(go-&gt;dnsaddr[0]), 0);
++ if (go-&gt;dnsaddr[1])
++ script_setenv(&quot;DNS2&quot;, ip_ntoa(go-&gt;dnsaddr[1]), 0);
++ create_resolv(go-&gt;dnsaddr[0], go-&gt;dnsaddr[1]);
++ }
++
++ /*
++ * Check that the peer is allowed to use the IP address it wants.
++ */
++ if (!auth_ip_addr(f-&gt;unit, ho-&gt;hisaddr)) {
++ error(&quot;Peer is not authorized to use remote address %I&quot;, ho-&gt;hisaddr);
++ ipcp_close(f-&gt;unit, &quot;Unauthorized remote IP address&quot;);
++ return;
++ }
++
++ /* set tcp compression */
++ sifvjcomp(f-&gt;unit, ho-&gt;neg_vj, ho-&gt;cflag, ho-&gt;maxslotindex);
++
++ /*
++ * If we are doing dial-on-demand, the interface is already
++ * configured, so we put out any saved-up packets, then set the
++ * interface to pass IP packets.
++ */
++ if (demand) {
++ if (go-&gt;ouraddr != wo-&gt;ouraddr || ho-&gt;hisaddr != wo-&gt;hisaddr) {
++ ipcp_clear_addrs(f-&gt;unit, wo-&gt;ouraddr, wo-&gt;hisaddr);
++ if (go-&gt;ouraddr != wo-&gt;ouraddr) {
++ warn(&quot;Local IP address changed to %I&quot;, go-&gt;ouraddr);
++ script_setenv(&quot;OLDIPLOCAL&quot;, ip_ntoa(wo-&gt;ouraddr), 0);
++ wo-&gt;ouraddr = go-&gt;ouraddr;
++ } else
++ script_unsetenv(&quot;OLDIPLOCAL&quot;);
++ if (ho-&gt;hisaddr != wo-&gt;hisaddr) {
++ warn(&quot;Remote IP address changed to %I&quot;, ho-&gt;hisaddr);
++ script_setenv(&quot;OLDIPREMOTE&quot;, ip_ntoa(wo-&gt;hisaddr), 0);
++ wo-&gt;hisaddr = ho-&gt;hisaddr;
++ } else
++ script_unsetenv(&quot;OLDIPREMOTE&quot;);
++
++ /* Set the interface to the new addresses */
++ mask = GetMask(go-&gt;ouraddr);
++ if (!sifaddr(f-&gt;unit, go-&gt;ouraddr, ho-&gt;hisaddr, mask)) {
++ if (debug)
++ warn(&quot;Interface configuration failed&quot;);
++ ipcp_close(f-&gt;unit, &quot;Interface configuration failed&quot;);
++ return;
++ }
++
++ /* assign a default route through the interface if required */
++ if (ipcp_wantoptions[f-&gt;unit].default_route)
++ if (sifdefaultroute(f-&gt;unit, go-&gt;ouraddr, ho-&gt;hisaddr))
++ default_route_set[f-&gt;unit] = 1;
++
++ /* Make a proxy ARP entry if requested. */
++ if (ipcp_wantoptions[f-&gt;unit].proxy_arp)
++ if (sifproxyarp(f-&gt;unit, ho-&gt;hisaddr))
++ proxy_arp_set[f-&gt;unit] = 1;
++
++ }
++ demand_rexmit(PPP_IP);
++ sifnpmode(f-&gt;unit, PPP_IP, NPMODE_PASS);
++
++ } else {
++ /*
++ * Set IP addresses and (if specified) netmask.
++ */
++ mask = GetMask(go-&gt;ouraddr);
++
++#if !(defined(SVR4) &amp;&amp; (defined(SNI) || defined(__USLC__)))
++ if (!sifaddr(f-&gt;unit, go-&gt;ouraddr, ho-&gt;hisaddr, mask)) {
++ if (debug)
++ warn(&quot;Interface configuration failed&quot;);
++ ipcp_close(f-&gt;unit, &quot;Interface configuration failed&quot;);
++ return;
++ }
++#endif
++
++ /* bring the interface up for IP */
++ if (!sifup(f-&gt;unit)) {
++ if (debug)
++ warn(&quot;Interface failed to come up&quot;);
++ ipcp_close(f-&gt;unit, &quot;Interface configuration failed&quot;);
++ return;
++ }
++
++#if (defined(SVR4) &amp;&amp; (defined(SNI) || defined(__USLC__)))
++ if (!sifaddr(f-&gt;unit, go-&gt;ouraddr, ho-&gt;hisaddr, mask)) {
++ if (debug)
++ warn(&quot;Interface configuration failed&quot;);
++ ipcp_close(f-&gt;unit, &quot;Interface configuration failed&quot;);
++ return;
++ }
++#endif
++ sifnpmode(f-&gt;unit, PPP_IP, NPMODE_PASS);
++
++ /* assign a default route through the interface if required */
++ if (ipcp_wantoptions[f-&gt;unit].default_route)
++ if (sifdefaultroute(f-&gt;unit, go-&gt;ouraddr, ho-&gt;hisaddr))
++ default_route_set[f-&gt;unit] = 1;
++
++ /* Make a proxy ARP entry if requested. */
++ if (ipcp_wantoptions[f-&gt;unit].proxy_arp)
++ if (sifproxyarp(f-&gt;unit, ho-&gt;hisaddr))
++ proxy_arp_set[f-&gt;unit] = 1;
++
++ ipcp_wantoptions[0].ouraddr = go-&gt;ouraddr;
++
++ notice(&quot;local IP address %I&quot;, go-&gt;ouraddr);
++ notice(&quot;remote IP address %I&quot;, ho-&gt;hisaddr);
++ if (go-&gt;dnsaddr[0])
++ notice(&quot;primary DNS address %I&quot;, go-&gt;dnsaddr[0]);
++ if (go-&gt;dnsaddr[1])
++ notice(&quot;secondary DNS address %I&quot;, go-&gt;dnsaddr[1]);
++ }
++
++ np_up(f-&gt;unit, PPP_IP);
++ ipcp_is_up = 1;
++
++ if (ip_up_hook)
++ ip_up_hook();
++
++ /*
++ * Execute the ip-up script, like this:
++ * /etc/ppp/ip-up interface tty speed local-IP remote-IP
++ */
++ if (ipcp_script_state == s_down &amp;&amp; ipcp_script_pid == 0) {
++ ipcp_script_state = s_up;
++ ipcp_script(_PATH_IPUP);
++ }
++}
++
++
++/*
++ * ipcp_down - IPCP has gone DOWN.
++ *
++ * Take the IP network interface down, clear its addresses
++ * and delete routes through it.
++ */
++static void
++ipcp_down(f)
++ fsm *f;
++{
++ IPCPDEBUG((&quot;ipcp: down&quot;));
++ /* XXX a bit IPv4-centric here, we only need to get the stats
++ * before the interface is marked down. */
++ update_link_stats(f-&gt;unit);
++ if (ip_down_hook)
++ ip_down_hook();
++ if (ipcp_is_up) {
++ ipcp_is_up = 0;
++ np_down(f-&gt;unit, PPP_IP);
++ }
++ sifvjcomp(f-&gt;unit, 0, 0, 0);
++
++ /*
++ * If we are doing dial-on-demand, set the interface
++ * to queue up outgoing packets (for now).
++ */
++ if (demand) {
++ sifnpmode(f-&gt;unit, PPP_IP, NPMODE_QUEUE);
++ } else {
++ sifnpmode(f-&gt;unit, PPP_IP, NPMODE_DROP);
++ sifdown(f-&gt;unit);
++ ipcp_clear_addrs(f-&gt;unit, ipcp_gotoptions[f-&gt;unit].ouraddr,
++ ipcp_hisoptions[f-&gt;unit].hisaddr);
++ }
++
++ /* Execute the ip-down script */
++ if (ipcp_script_state == s_up &amp;&amp; ipcp_script_pid == 0) {
++ ipcp_script_state = s_down;
++ ipcp_script(_PATH_IPDOWN);
++ }
++}
++
++
++/*
++ * ipcp_clear_addrs() - clear the interface addresses, routes,
++ * proxy arp entries, etc.
++ */
++static void
++ipcp_clear_addrs(unit, ouraddr, hisaddr)
++ int unit;
++ u_int32_t ouraddr; /* local address */
++ u_int32_t hisaddr; /* remote address */
++{
++ if (proxy_arp_set[unit]) {
++ cifproxyarp(unit, hisaddr);
++ proxy_arp_set[unit] = 0;
++ }
++ if (default_route_set[unit]) {
++ cifdefaultroute(unit, ouraddr, hisaddr);
++ default_route_set[unit] = 0;
++ }
++ cifaddr(unit, ouraddr, hisaddr);
++}
++
++
++/*
++ * ipcp_finished - possibly shut down the lower layers.
++ */
++static void
++ipcp_finished(f)
++ fsm *f;
++{
++ np_finished(f-&gt;unit, PPP_IP);
++}
++
++
++/*
++ * ipcp_script_done - called when the ip-up or ip-down script
++ * has finished.
++ */
++static void
++ipcp_script_done(arg)
++ void *arg;
++{
++ ipcp_script_pid = 0;
++ switch (ipcp_script_state) {
++ case s_up:
++ if (ipcp_fsm[0].state != OPENED) {
++ ipcp_script_state = s_down;
++ ipcp_script(_PATH_IPDOWN);
++ }
++ break;
++ case s_down:
++ if (ipcp_fsm[0].state == OPENED) {
++ ipcp_script_state = s_up;
++ ipcp_script(_PATH_IPUP);
++ }
++ break;
++ }
++}
++
++
++/*
++ * ipcp_script - Execute a script with arguments
++ * interface-name tty-name speed local-IP remote-IP.
++ */
++static void
++ipcp_script(script)
++ char *script;
++{
++ char strspeed[32], strlocal[32], strremote[32];
++ char *argv[8];
++
++ slprintf(strspeed, sizeof(strspeed), &quot;%d&quot;, baud_rate);
++ slprintf(strlocal, sizeof(strlocal), &quot;%I&quot;, ipcp_gotoptions[0].ouraddr);
++ slprintf(strremote, sizeof(strremote), &quot;%I&quot;, ipcp_hisoptions[0].hisaddr);
++
++ argv[0] = script;
++ argv[1] = ifname;
++ argv[2] = devnam;
++ argv[3] = strspeed;
++ argv[4] = strlocal;
++ argv[5] = strremote;
++ argv[6] = ipparam;
++ argv[7] = NULL;
++ ipcp_script_pid = run_program(script, argv, 0, ipcp_script_done, NULL);
++}
++
++/*
++ * create_resolv - create the replacement resolv.conf file
++ */
++static void
++create_resolv(peerdns1, peerdns2)
++ u_int32_t peerdns1, peerdns2;
++{
++ FILE *f;
++
++ f = fopen(_PATH_RESOLV, &quot;w&quot;);
++ if (f == NULL) {
++ error(&quot;Failed to create %s: %m&quot;, _PATH_RESOLV);
++ return;
++ }
++
++ if (peerdns1)
++ fprintf(f, &quot;nameserver %s\n&quot;, ip_ntoa(peerdns1));
++
++ if (peerdns2)
++ fprintf(f, &quot;nameserver %s\n&quot;, ip_ntoa(peerdns2));
++
++ if (ferror(f))
++ error(&quot;Write failed to %s: %m&quot;, _PATH_RESOLV);
++
++ fclose(f);
++}
++
++/*
++ * ipcp_printpkt - print the contents of an IPCP packet.
++ */
++static char *ipcp_codenames[] = {
++ &quot;ConfReq&quot;, &quot;ConfAck&quot;, &quot;ConfNak&quot;, &quot;ConfRej&quot;,
++ &quot;TermReq&quot;, &quot;TermAck&quot;, &quot;CodeRej&quot;
++};
++
++static int
++ipcp_printpkt(p, plen, printer, arg)
++ u_char *p;
++ int plen;
++ void (*printer) __P((void *, char *, ...));
++ void *arg;
++{
++ int code, id, len, olen;
++ u_char *pstart, *optend;
++ u_short cishort;
++ u_int32_t cilong;
++
++ if (plen &lt; HEADERLEN)
++ return 0;
++ pstart = p;
++ GETCHAR(code, p);
++ GETCHAR(id, p);
++ GETSHORT(len, p);
++ if (len &lt; HEADERLEN || len &gt; plen)
++ return 0;
++
++ if (code &gt;= 1 &amp;&amp; code &lt;= sizeof(ipcp_codenames) / sizeof(char *))
++ printer(arg, &quot; %s&quot;, ipcp_codenames[code-1]);
++ else
++ printer(arg, &quot; code=0x%x&quot;, code);
++ printer(arg, &quot; id=0x%x&quot;, id);
++ len -= HEADERLEN;
++ switch (code) {
++ case CONFREQ:
++ case CONFACK:
++ case CONFNAK:
++ case CONFREJ:
++ /* print option list */
++ while (len &gt;= 2) {
++ GETCHAR(code, p);
++ GETCHAR(olen, p);
++ p -= 2;
++ if (olen &lt; 2 || olen &gt; len) {
++ break;
++ }
++ printer(arg, &quot; &lt;&quot;);
++ len -= olen;
++ optend = p + olen;
++ switch (code) {
++ case CI_ADDRS:
++ if (olen == CILEN_ADDRS) {
++ p += 2;
++ GETLONG(cilong, p);
++ printer(arg, &quot;addrs %I&quot;, htonl(cilong));
++ GETLONG(cilong, p);
++ printer(arg, &quot; %I&quot;, htonl(cilong));
++ }
++ break;
++ case CI_COMPRESSTYPE:
++ if (olen &gt;= CILEN_COMPRESS) {
++ p += 2;
++ GETSHORT(cishort, p);
++ printer(arg, &quot;compress &quot;);
++ switch (cishort) {
++ case IPCP_VJ_COMP:
++ printer(arg, &quot;VJ&quot;);
++ break;
++ case IPCP_VJ_COMP_OLD:
++ printer(arg, &quot;old-VJ&quot;);
++ break;
++ default:
++ printer(arg, &quot;0x%x&quot;, cishort);
++ }
++ }
++ break;
++ case CI_ADDR:
++ if (olen == CILEN_ADDR) {
++ p += 2;
++ GETLONG(cilong, p);
++ printer(arg, &quot;addr %I&quot;, htonl(cilong));
++ }
++ break;
++ case CI_MS_DNS1:
++ case CI_MS_DNS2:
++ p += 2;
++ GETLONG(cilong, p);
++ printer(arg, &quot;ms-dns%d %I&quot;, code - CI_MS_DNS1 + 1,
++ htonl(cilong));
++ break;
++ case CI_MS_WINS1:
++ case CI_MS_WINS2:
++ p += 2;
++ GETLONG(cilong, p);
++ printer(arg, &quot;ms-wins %I&quot;, htonl(cilong));
++ break;
++ }
++ while (p &lt; optend) {
++ GETCHAR(code, p);
++ printer(arg, &quot; %.2x&quot;, code);
++ }
++ printer(arg, &quot;&gt;&quot;);
++ }
++ break;
++
++ case TERMACK:
++ case TERMREQ:
++ if (len &gt; 0 &amp;&amp; *p &gt;= ' ' &amp;&amp; *p &lt; 0x7f) {
++ printer(arg, &quot; &quot;);
++ print_string((char *)p, len, printer, arg);
++ p += len;
++ len = 0;
++ }
++ break;
++ }
++
++ /* print the rest of the bytes in the packet */
++ for (; len &gt; 0; --len) {
++ GETCHAR(code, p);
++ printer(arg, &quot; %.2x&quot;, code);
++ }
++
++ return p - pstart;
++}
++
++/*
++ * ip_active_pkt - see if this IP packet is worth bringing the link up for.
++ * We don't bring the link up for IP fragments or for TCP FIN packets
++ * with no data.
++ */
++#define IP_HDRLEN 20 /* bytes */
++#define IP_OFFMASK 0x1fff
++// #define IPPROTO_TCP 6
++#define TCP_HDRLEN 20
++#define TH_FIN 0x01
++
++/*
++ * We use these macros because the IP header may be at an odd address,
++ * and some compilers might use word loads to get th_off or ip_hl.
++ */
++
++#define net_short(x) (((x)[0] &lt;&lt; 8) + (x)[1])
++#define get_iphl(x) (((unsigned char *)(x))[0] &amp; 0xF)
++#define get_ipoff(x) net_short((unsigned char *)(x) + 6)
++#define get_ipproto(x) (((unsigned char *)(x))[9])
++#define get_tcpoff(x) (((unsigned char *)(x))[12] &gt;&gt; 4)
++#define get_tcpflags(x) (((unsigned char *)(x))[13])
++
++static int
++ip_active_pkt(pkt, len)
++ u_char *pkt;
++ int len;
++{
++ u_char *tcp;
++ int hlen;
++
++ len -= PPP_HDRLEN;
++ pkt += PPP_HDRLEN;
++ if (len &lt; IP_HDRLEN)
++ return 0;
++ if ((get_ipoff(pkt) &amp; IP_OFFMASK) != 0)
++ return 0;
++ if (get_ipproto(pkt) != IPPROTO_TCP)
++ return 1;
++ hlen = get_iphl(pkt) * 4;
++ if (len &lt; hlen + TCP_HDRLEN)
++ return 0;
++ tcp = pkt + hlen;
++ if ((get_tcpflags(tcp) &amp; TH_FIN) != 0 &amp;&amp; len == hlen + get_tcpoff(tcp) * 4)
++ return 0;
++ return 1;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/ipcp.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/ipcp.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/ipcp.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/ipcp.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,73 @@
++/*
++ * ipcp.h - IP Control Protocol definitions.
++ *
++ * Copyright (c) 1989 Carnegie Mellon University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by Carnegie Mellon University. The name of the
++ * University may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * $Id: ipcp.h 195720 2001-06-11 11:44:34Z gc $
++ */
++
++/*
++ * Options.
++ */
++#define CI_ADDRS 1 /* IP Addresses */
++#define CI_COMPRESSTYPE 2 /* Compression Type */
++#define CI_ADDR 3
++
++#define CI_MS_DNS1 129 /* Primary DNS value */
++#define CI_MS_WINS1 130 /* Primary WINS value */
++#define CI_MS_DNS2 131 /* Secondary DNS value */
++#define CI_MS_WINS2 132 /* Secondary WINS value */
++
++#define MAX_STATES 16 /* from slcompress.h */
++
++#define IPCP_VJMODE_OLD 1 /* &quot;old&quot; mode (option # = 0x0037) */
++#define IPCP_VJMODE_RFC1172 2 /* &quot;old-rfc&quot;mode (option # = 0x002d) */
++#define IPCP_VJMODE_RFC1332 3 /* &quot;new-rfc&quot;mode (option # = 0x002d, */
++ /* maxslot and slot number compression) */
++
++#define IPCP_VJ_COMP 0x002d /* current value for VJ compression option*/
++#define IPCP_VJ_COMP_OLD 0x0037 /* &quot;old&quot; (i.e, broken) value for VJ */
++ /* compression option*/
++
++typedef struct ipcp_options {
++ bool neg_addr; /* Negotiate IP Address? */
++ bool old_addrs; /* Use old (IP-Addresses) option? */
++ bool req_addr; /* Ask peer to send IP address? */
++ bool default_route; /* Assign default route through interface? */
++ bool proxy_arp; /* Make proxy ARP entry for peer? */
++ bool neg_vj; /* Van Jacobson Compression? */
++ bool old_vj; /* use old (short) form of VJ option? */
++ bool accept_local; /* accept peer's value for ouraddr */
++ bool accept_remote; /* accept peer's value for hisaddr */
++ bool req_dns1; /* Ask peer to send primary DNS address? */
++ bool req_dns2; /* Ask peer to send secondary DNS address? */
++ int vj_protocol; /* protocol value to use in VJ option */
++ int maxslotindex; /* values for RFC1332 VJ compression neg. */
++ bool cflag;
++ u_int32_t ouraddr, hisaddr; /* Addresses in NETWORK BYTE ORDER */
++ u_int32_t dnsaddr[2]; /* Primary and secondary MS DNS entries */
++ u_int32_t winsaddr[2]; /* Primary and secondary MS WINS entries */
++} ipcp_options;
++
++extern fsm ipcp_fsm[];
++extern ipcp_options ipcp_wantoptions[];
++extern ipcp_options ipcp_gotoptions[];
++extern ipcp_options ipcp_allowoptions[];
++extern ipcp_options ipcp_hisoptions[];
++
++char *ip_ntoa __P((u_int32_t));
++
++extern struct protent ipcp_protent;
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/ipcp.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/ipv6cp.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/ipv6cp.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/ipv6cp.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1512 @@
++/*
++ ipv6cp.c - PPP IPV6 Control Protocol.
++ Copyright (C) 1999 Tommi Komulainen &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">Tommi.Komulainen at iki.fi</A>&gt;
++
++ Redistribution and use in source and binary forms are permitted
++ provided that the above copyright notice and this paragraph are
++ duplicated in all such forms. The name of the author may not be
++ used to endorse or promote products derived from this software
++ without specific prior written permission.
++ THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++*/
++
++/* Original version, based on RFC2023 :
++
++ Copyright (c) 1995, 1996, 1997 <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">Francis.Dupont at inria.fr</A>, INRIA Rocquencourt,
++ <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">Alain.Durand at imag.fr</A>, IMAG,
++ <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">Jean-Luc.Richier at imag.fr</A>, IMAG-LSR.
++
++ Copyright (c) 1998, 1999 <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">Francis.Dupont at inria.fr</A>, GIE DYADE,
++ <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">Alain.Durand at imag.fr</A>, IMAG,
++ <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">Jean-Luc.Richier at imag.fr</A>, IMAG-LSR.
++
++ Ce travail a &#233;t&#233; fait au sein du GIE DYADE (Groupement d'Int&#233;r&#234;t
++ &#201;conomique ayant pour membres BULL S.A. et l'INRIA).
++
++ Ce logiciel informatique est disponible aux conditions
++ usuelles dans la recherche, c'est-&#224;-dire qu'il peut
++ &#234;tre utilis&#233;, copi&#233;, modifi&#233;, distribu&#233; &#224; l'unique
++ condition que ce texte soit conserv&#233; afin que
++ l'origine de ce logiciel soit reconnue.
++
++ Le nom de l'Institut National de Recherche en Informatique
++ et en Automatique (INRIA), de l'IMAG, ou d'une personne morale
++ ou physique ayant particip&#233; &#224; l'&#233;laboration de ce logiciel ne peut
++ &#234;tre utilis&#233; sans son accord pr&#233;alable explicite.
++
++ Ce logiciel est fourni tel quel sans aucune garantie,
++ support ou responsabilit&#233; d'aucune sorte.
++ Ce logiciel est d&#233;riv&#233; de sources d'origine
++ &quot;University of California at Berkeley&quot; et
++ &quot;Digital Equipment Corporation&quot; couvertes par des copyrights.
++
++ L'Institut d'Informatique et de Math&#233;matiques Appliqu&#233;es de Grenoble (IMAG)
++ est une f&#233;d&#233;ration d'unit&#233;s mixtes de recherche du CNRS, de l'Institut National
++ Polytechnique de Grenoble et de l'Universit&#233; Joseph Fourier regroupant
++ sept laboratoires dont le laboratoire Logiciels, Syst&#232;mes, R&#233;seaux (LSR).
++
++ This work has been done in the context of GIE DYADE (joint R &amp; D venture
++ between BULL S.A. and INRIA).
++
++ This software is available with usual &quot;research&quot; terms
++ with the aim of retain credits of the software.
++ Permission to use, copy, modify and distribute this software for any
++ purpose and without fee is hereby granted, provided that the above
++ copyright notice and this permission notice appear in all copies,
++ and the name of INRIA, IMAG, or any contributor not be used in advertising
++ or publicity pertaining to this material without the prior explicit
++ permission. The software is provided &quot;as is&quot; without any
++ warranties, support or liabilities of any kind.
++ This software is derived from source code from
++ &quot;University of California at Berkeley&quot; and
++ &quot;Digital Equipment Corporation&quot; protected by copyrights.
++
++ Grenoble's Institute of Computer Science and Applied Mathematics (IMAG)
++ is a federation of seven research units funded by the CNRS, National
++ Polytechnic Institute of Grenoble and University Joseph Fourier.
++ The research unit in Software, Systems, Networks (LSR) is member of IMAG.
++*/
++
++/*
++ * Derived from :
++ *
++ *
++ * ipcp.c - PPP IP Control Protocol.
++ *
++ * Copyright (c) 1989 Carnegie Mellon University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by Carnegie Mellon University. The name of the
++ * University may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * $Id: ipv6cp.c 215411 2007-04-25 12:26:16Z pixel $
++ */
++
++#define RCSID &quot;$Id: ipv6cp.c 215411 2007-04-25 12:26:16Z pixel $&quot;
++
++/*
++ * TODO:
++ *
++ * Proxy Neighbour Discovery.
++ *
++ * Better defines for selecting the ordering of
++ * interface up / set address. (currently checks for __linux__,
++ * since SVR4 &amp;&amp; (SNI || __USLC__) didn't work properly)
++ */
++
++#include &lt;stdio.h&gt;
++#include &lt;string.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;netdb.h&gt;
++#include &lt;sys/param.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/socket.h&gt;
++#include &lt;netinet/in.h&gt;
++#include &lt;arpa/inet.h&gt;
++
++#include &quot;pppd.h&quot;
++#include &quot;fsm.h&quot;
++#include &quot;ipcp.h&quot;
++#include &quot;ipv6cp.h&quot;
++#include &quot;magic.h&quot;
++#include &quot;pathnames.h&quot;
++
++static const char rcsid[] = RCSID;
++
++/* global vars */
++ipv6cp_options ipv6cp_wantoptions[NUM_PPP]; /* Options that we want to request */
++ipv6cp_options ipv6cp_gotoptions[NUM_PPP]; /* Options that peer ack'd */
++ipv6cp_options ipv6cp_allowoptions[NUM_PPP]; /* Options we allow peer to request */
++ipv6cp_options ipv6cp_hisoptions[NUM_PPP]; /* Options that we ack'd */
++int no_ifaceid_neg = 0;
++
++/* local vars */
++static int ipv6cp_is_up;
++
++/*
++ * Callbacks for fsm code. (CI = Configuration Information)
++ */
++static void ipv6cp_resetci __P((fsm *)); /* Reset our CI */
++static int ipv6cp_cilen __P((fsm *)); /* Return length of our CI */
++static void ipv6cp_addci __P((fsm *, u_char *, int *)); /* Add our CI */
++static int ipv6cp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */
++static int ipv6cp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */
++static int ipv6cp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */
++static int ipv6cp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
++static void ipv6cp_up __P((fsm *)); /* We're UP */
++static void ipv6cp_down __P((fsm *)); /* We're DOWN */
++static void ipv6cp_finished __P((fsm *)); /* Don't need lower layer */
++
++fsm ipv6cp_fsm[NUM_PPP]; /* IPV6CP fsm structure */
++
++static fsm_callbacks ipv6cp_callbacks = { /* IPV6CP callback routines */
++ ipv6cp_resetci, /* Reset our Configuration Information */
++ ipv6cp_cilen, /* Length of our Configuration Information */
++ ipv6cp_addci, /* Add our Configuration Information */
++ ipv6cp_ackci, /* ACK our Configuration Information */
++ ipv6cp_nakci, /* NAK our Configuration Information */
++ ipv6cp_rejci, /* Reject our Configuration Information */
++ ipv6cp_reqci, /* Request peer's Configuration Information */
++ ipv6cp_up, /* Called when fsm reaches OPENED state */
++ ipv6cp_down, /* Called when fsm leaves OPENED state */
++ NULL, /* Called when we want the lower layer up */
++ ipv6cp_finished, /* Called when we want the lower layer down */
++ NULL, /* Called when Protocol-Reject received */
++ NULL, /* Retransmission is necessary */
++ NULL, /* Called to handle protocol-specific codes */
++ &quot;IPV6CP&quot; /* String name of protocol */
++};
++
++/*
++ * Command-line options.
++ */
++static int setifaceid __P((char **arg));
++static void printifaceid __P((option_t *,
++ void (*)(void *, char *, ...), void *));
++
++static option_t ipv6cp_option_list[] = {
++ { &quot;ipv6&quot;, o_special, (void *)setifaceid,
++ &quot;Set interface identifiers for IPV6&quot;,
++ OPT_A2PRINTER, (void *)printifaceid },
++
++ { &quot;+ipv6&quot;, o_bool, &amp;ipv6cp_protent.enabled_flag,
++ &quot;Enable IPv6 and IPv6CP&quot;, OPT_PRIO | 1 },
++ { &quot;noipv6&quot;, o_bool, &amp;ipv6cp_protent.enabled_flag,
++ &quot;Disable IPv6 and IPv6CP&quot;, OPT_PRIOSUB },
++ { &quot;-ipv6&quot;, o_bool, &amp;ipv6cp_protent.enabled_flag,
++ &quot;Disable IPv6 and IPv6CP&quot;, OPT_PRIOSUB | OPT_ALIAS },
++
++ { &quot;ipv6cp-accept-local&quot;, o_bool, &amp;ipv6cp_allowoptions[0].accept_local,
++ &quot;Accept peer's interface identifier for us&quot;, 1 },
++
++ { &quot;ipv6cp-use-ipaddr&quot;, o_bool, &amp;ipv6cp_allowoptions[0].use_ip,
++ &quot;Use (default) IPv4 address as interface identifier&quot;, 1 },
++
++#if defined(SOL2)
++ { &quot;ipv6cp-use-persistent&quot;, o_bool, &amp;ipv6cp_wantoptions[0].use_persistent,
++ &quot;Use uniquely-available persistent value for link local address&quot;, 1 },
++#endif /* defined(SOL2) */
++
++ { &quot;ipv6cp-restart&quot;, o_int, &amp;ipv6cp_fsm[0].timeouttime,
++ &quot;Set timeout for IPv6CP&quot;, OPT_PRIO },
++ { &quot;ipv6cp-max-terminate&quot;, o_int, &amp;ipv6cp_fsm[0].maxtermtransmits,
++ &quot;Set max #xmits for term-reqs&quot;, OPT_PRIO },
++ { &quot;ipv6cp-max-configure&quot;, o_int, &amp;ipv6cp_fsm[0].maxconfreqtransmits,
++ &quot;Set max #xmits for conf-reqs&quot;, OPT_PRIO },
++ { &quot;ipv6cp-max-failure&quot;, o_int, &amp;ipv6cp_fsm[0].maxnakloops,
++ &quot;Set max #conf-naks for IPv6CP&quot;, OPT_PRIO },
++
++ { NULL }
++};
++
++
++/*
++ * Protocol entry points from main code.
++ */
++static void ipv6cp_init __P((int));
++static void ipv6cp_open __P((int));
++static void ipv6cp_close __P((int, char *));
++static void ipv6cp_lowerup __P((int));
++static void ipv6cp_lowerdown __P((int));
++static void ipv6cp_input __P((int, u_char *, int));
++static void ipv6cp_protrej __P((int));
++static int ipv6cp_printpkt __P((u_char *, int,
++ void (*) __P((void *, char *, ...)), void *));
++static void ipv6_check_options __P((void));
++static int ipv6_demand_conf __P((int));
++static int ipv6_active_pkt __P((u_char *, int));
++
++struct protent ipv6cp_protent = {
++ PPP_IPV6CP,
++ ipv6cp_init,
++ ipv6cp_input,
++ ipv6cp_protrej,
++ ipv6cp_lowerup,
++ ipv6cp_lowerdown,
++ ipv6cp_open,
++ ipv6cp_close,
++ ipv6cp_printpkt,
++ NULL,
++ 0,
++ &quot;IPV6CP&quot;,
++ &quot;IPV6&quot;,
++ ipv6cp_option_list,
++ ipv6_check_options,
++ ipv6_demand_conf,
++ ipv6_active_pkt
++};
++
++static void ipv6cp_clear_addrs __P((int, eui64_t, eui64_t));
++static void ipv6cp_script __P((char *));
++static void ipv6cp_script_done __P((void *));
++
++/*
++ * Lengths of configuration options.
++ */
++#define CILEN_VOID 2
++#define CILEN_COMPRESS 4 /* length for RFC2023 compress opt. */
++#define CILEN_IFACEID 10 /* RFC2472, interface identifier */
++
++#define CODENAME(x) ((x) == CONFACK ? &quot;ACK&quot; : \
++ (x) == CONFNAK ? &quot;NAK&quot; : &quot;REJ&quot;)
++
++/*
++ * This state variable is used to ensure that we don't
++ * run an ipcp-up/down script while one is already running.
++ */
++static enum script_state {
++ s_down,
++ s_up,
++} ipv6cp_script_state;
++static pid_t ipv6cp_script_pid;
++
++/*
++ * setifaceid - set the interface identifiers manually
++ */
++static int
++setifaceid(argv)
++ char **argv;
++{
++ char *comma, *arg, c;
++ ipv6cp_options *wo = &amp;ipv6cp_wantoptions[0];
++ struct in6_addr addr;
++ static int prio_local, prio_remote;
++
++#define VALIDID(a) ( (((a).s6_addr32[0] == 0) &amp;&amp; ((a).s6_addr32[1] == 0)) &amp;&amp; \
++ (((a).s6_addr32[2] != 0) || ((a).s6_addr32[3] != 0)) )
++
++ arg = *argv;
++ if ((comma = strchr(arg, ',')) == NULL)
++ comma = arg + strlen(arg);
++
++ /*
++ * If comma first character, then no local identifier
++ */
++ if (comma != arg) {
++ c = *comma;
++ *comma = '\0';
++
++ if (inet_pton(AF_INET6, arg, &amp;addr) == 0 || !VALIDID(addr)) {
++ option_error(&quot;Illegal interface identifier (local): %s&quot;, arg);
++ return 0;
++ }
++
++ if (option_priority &gt;= prio_local) {
++ eui64_copy(addr.s6_addr32[2], wo-&gt;ourid);
++ wo-&gt;opt_local = 1;
++ prio_local = option_priority;
++ }
++ *comma = c;
++ }
++
++ /*
++ * If comma last character, the no remote identifier
++ */
++ if (*comma != 0 &amp;&amp; *++comma != '\0') {
++ if (inet_pton(AF_INET6, comma, &amp;addr) == 0 || !VALIDID(addr)) {
++ option_error(&quot;Illegal interface identifier (remote): %s&quot;, comma);
++ return 0;
++ }
++ if (option_priority &gt;= prio_remote) {
++ eui64_copy(addr.s6_addr32[2], wo-&gt;hisid);
++ wo-&gt;opt_remote = 1;
++ prio_remote = option_priority;
++ }
++ }
++
++ if (override_value(&quot;+ipv6&quot;, option_priority, option_source))
++ ipv6cp_protent.enabled_flag = 1;
++ return 1;
++}
++
++static void
++printifaceid(opt, printer, arg)
++ option_t *opt;
++ void (*printer) __P((void *, char *, ...));
++ void *arg;
++{
++ ipv6cp_options *wo = &amp;ipv6cp_wantoptions[0];
++
++ if (wo-&gt;opt_local)
++ printer(arg, &quot;%s&quot;, llv6_ntoa(wo-&gt;ourid));
++ printer(arg, &quot;,&quot;);
++ if (wo-&gt;opt_remote)
++ printer(arg, &quot;%s&quot;, llv6_ntoa(wo-&gt;hisid));
++}
++
++/*
++ * Make a string representation of a network address.
++ */
++char *
++llv6_ntoa(ifaceid)
++ eui64_t ifaceid;
++{
++ static char b[64];
++
++ sprintf(b, &quot;fe80::%s&quot;, eui64_ntoa(ifaceid));
++ return b;
++}
++
++
++/*
++ * ipv6cp_init - Initialize IPV6CP.
++ */
++static void
++ipv6cp_init(unit)
++ int unit;
++{
++ fsm *f = &amp;ipv6cp_fsm[unit];
++ ipv6cp_options *wo = &amp;ipv6cp_wantoptions[unit];
++ ipv6cp_options *ao = &amp;ipv6cp_allowoptions[unit];
++
++ f-&gt;unit = unit;
++ f-&gt;protocol = PPP_IPV6CP;
++ f-&gt;callbacks = &amp;ipv6cp_callbacks;
++ fsm_init(&amp;ipv6cp_fsm[unit]);
++
++ memset(wo, 0, sizeof(*wo));
++ memset(ao, 0, sizeof(*ao));
++
++ wo-&gt;accept_local = 1;
++ wo-&gt;neg_ifaceid = 1;
++ ao-&gt;neg_ifaceid = 1;
++
++#ifdef IPV6CP_COMP
++ wo-&gt;neg_vj = 1;
++ ao-&gt;neg_vj = 1;
++ wo-&gt;vj_protocol = IPV6CP_COMP;
++#endif
++
++}
++
++
++/*
++ * ipv6cp_open - IPV6CP is allowed to come up.
++ */
++static void
++ipv6cp_open(unit)
++ int unit;
++{
++ fsm_open(&amp;ipv6cp_fsm[unit]);
++}
++
++
++/*
++ * ipv6cp_close - Take IPV6CP down.
++ */
++static void
++ipv6cp_close(unit, reason)
++ int unit;
++ char *reason;
++{
++ fsm_close(&amp;ipv6cp_fsm[unit], reason);
++}
++
++
++/*
++ * ipv6cp_lowerup - The lower layer is up.
++ */
++static void
++ipv6cp_lowerup(unit)
++ int unit;
++{
++ fsm_lowerup(&amp;ipv6cp_fsm[unit]);
++}
++
++
++/*
++ * ipv6cp_lowerdown - The lower layer is down.
++ */
++static void
++ipv6cp_lowerdown(unit)
++ int unit;
++{
++ fsm_lowerdown(&amp;ipv6cp_fsm[unit]);
++}
++
++
++/*
++ * ipv6cp_input - Input IPV6CP packet.
++ */
++static void
++ipv6cp_input(unit, p, len)
++ int unit;
++ u_char *p;
++ int len;
++{
++ fsm_input(&amp;ipv6cp_fsm[unit], p, len);
++}
++
++
++/*
++ * ipv6cp_protrej - A Protocol-Reject was received for IPV6CP.
++ *
++ * Pretend the lower layer went down, so we shut up.
++ */
++static void
++ipv6cp_protrej(unit)
++ int unit;
++{
++ fsm_lowerdown(&amp;ipv6cp_fsm[unit]);
++}
++
++
++/*
++ * ipv6cp_resetci - Reset our CI.
++ */
++static void
++ipv6cp_resetci(f)
++ fsm *f;
++{
++ ipv6cp_options *wo = &amp;ipv6cp_wantoptions[f-&gt;unit];
++ ipv6cp_options *go = &amp;ipv6cp_gotoptions[f-&gt;unit];
++
++ wo-&gt;req_ifaceid = wo-&gt;neg_ifaceid &amp;&amp; ipv6cp_allowoptions[f-&gt;unit].neg_ifaceid;
++
++ if (!wo-&gt;opt_local) {
++ eui64_magic_nz(wo-&gt;ourid);
++ }
++
++ *go = *wo;
++ eui64_zero(go-&gt;hisid); /* last proposed interface identifier */
++}
++
++
++/*
++ * ipv6cp_cilen - Return length of our CI.
++ */
++static int
++ipv6cp_cilen(f)
++ fsm *f;
++{
++ ipv6cp_options *go = &amp;ipv6cp_gotoptions[f-&gt;unit];
++
++#define LENCIVJ(neg) (neg ? CILEN_COMPRESS : 0)
++#define LENCIIFACEID(neg) (neg ? CILEN_IFACEID : 0)
++
++ return (LENCIIFACEID(go-&gt;neg_ifaceid) +
++ LENCIVJ(go-&gt;neg_vj));
++}
++
++
++/*
++ * ipv6cp_addci - Add our desired CIs to a packet.
++ */
++static void
++ipv6cp_addci(f, ucp, lenp)
++ fsm *f;
++ u_char *ucp;
++ int *lenp;
++{
++ ipv6cp_options *go = &amp;ipv6cp_gotoptions[f-&gt;unit];
++ int len = *lenp;
++
++#define ADDCIVJ(opt, neg, val) \
++ if (neg) { \
++ int vjlen = CILEN_COMPRESS; \
++ if (len &gt;= vjlen) { \
++ PUTCHAR(opt, ucp); \
++ PUTCHAR(vjlen, ucp); \
++ PUTSHORT(val, ucp); \
++ len -= vjlen; \
++ } else \
++ neg = 0; \
++ }
++
++#define ADDCIIFACEID(opt, neg, val1) \
++ if (neg) { \
++ int idlen = CILEN_IFACEID; \
++ if (len &gt;= idlen) { \
++ PUTCHAR(opt, ucp); \
++ PUTCHAR(idlen, ucp); \
++ eui64_put(val1, ucp); \
++ len -= idlen; \
++ } else \
++ neg = 0; \
++ }
++
++ ADDCIIFACEID(CI_IFACEID, go-&gt;neg_ifaceid, go-&gt;ourid);
++
++ ADDCIVJ(CI_COMPRESSTYPE, go-&gt;neg_vj, go-&gt;vj_protocol);
++
++ *lenp -= len;
++}
++
++
++/*
++ * ipv6cp_ackci - Ack our CIs.
++ *
++ * Returns:
++ * 0 - Ack was bad.
++ * 1 - Ack was good.
++ */
++static int
++ipv6cp_ackci(f, p, len)
++ fsm *f;
++ u_char *p;
++ int len;
++{
++ ipv6cp_options *go = &amp;ipv6cp_gotoptions[f-&gt;unit];
++ u_short cilen, citype, cishort;
++ eui64_t ifaceid;
++
++ /*
++ * CIs must be in exactly the same order that we sent...
++ * Check packet length and CI length at each step.
++ * If we find any deviations, then this packet is bad.
++ */
++
++#define ACKCIVJ(opt, neg, val) \
++ if (neg) { \
++ int vjlen = CILEN_COMPRESS; \
++ if ((len -= vjlen) &lt; 0) \
++ goto bad; \
++ GETCHAR(citype, p); \
++ GETCHAR(cilen, p); \
++ if (cilen != vjlen || \
++ citype != opt) \
++ goto bad; \
++ GETSHORT(cishort, p); \
++ if (cishort != val) \
++ goto bad; \
++ }
++
++#define ACKCIIFACEID(opt, neg, val1) \
++ if (neg) { \
++ int idlen = CILEN_IFACEID; \
++ if ((len -= idlen) &lt; 0) \
++ goto bad; \
++ GETCHAR(citype, p); \
++ GETCHAR(cilen, p); \
++ if (cilen != idlen || \
++ citype != opt) \
++ goto bad; \
++ eui64_get(ifaceid, p); \
++ if (! eui64_equals(val1, ifaceid)) \
++ goto bad; \
++ }
++
++ ACKCIIFACEID(CI_IFACEID, go-&gt;neg_ifaceid, go-&gt;ourid);
++
++ ACKCIVJ(CI_COMPRESSTYPE, go-&gt;neg_vj, go-&gt;vj_protocol);
++
++ /*
++ * If there are any remaining CIs, then this packet is bad.
++ */
++ if (len != 0)
++ goto bad;
++ return (1);
++
++bad:
++ IPV6CPDEBUG((&quot;ipv6cp_ackci: received bad Ack!&quot;));
++ return (0);
++}
++
++/*
++ * ipv6cp_nakci - Peer has sent a NAK for some of our CIs.
++ * This should not modify any state if the Nak is bad
++ * or if IPV6CP is in the OPENED state.
++ *
++ * Returns:
++ * 0 - Nak was bad.
++ * 1 - Nak was good.
++ */
++static int
++ipv6cp_nakci(f, p, len)
++ fsm *f;
++ u_char *p;
++ int len;
++{
++ ipv6cp_options *go = &amp;ipv6cp_gotoptions[f-&gt;unit];
++ u_char citype, cilen, *next;
++ u_short cishort;
++ eui64_t ifaceid;
++ ipv6cp_options no; /* options we've seen Naks for */
++ ipv6cp_options try; /* options to request next time */
++
++ BZERO(&amp;no, sizeof(no));
++ try = *go;
++
++ /*
++ * Any Nak'd CIs must be in exactly the same order that we sent.
++ * Check packet length and CI length at each step.
++ * If we find any deviations, then this packet is bad.
++ */
++#define NAKCIIFACEID(opt, neg, code) \
++ if (go-&gt;neg &amp;&amp; \
++ len &gt;= (cilen = CILEN_IFACEID) &amp;&amp; \
++ p[1] == cilen &amp;&amp; \
++ p[0] == opt) { \
++ len -= cilen; \
++ INCPTR(2, p); \
++ eui64_get(ifaceid, p); \
++ no.neg = 1; \
++ code \
++ }
++
++#define NAKCIVJ(opt, neg, code) \
++ if (go-&gt;neg &amp;&amp; \
++ ((cilen = p[1]) == CILEN_COMPRESS) &amp;&amp; \
++ len &gt;= cilen &amp;&amp; \
++ p[0] == opt) { \
++ len -= cilen; \
++ INCPTR(2, p); \
++ GETSHORT(cishort, p); \
++ no.neg = 1; \
++ code \
++ }
++
++ /*
++ * Accept the peer's idea of {our,his} interface identifier, if different
++ * from our idea, only if the accept_{local,remote} flag is set.
++ */
++ NAKCIIFACEID(CI_IFACEID, neg_ifaceid,
++ if (go-&gt;accept_local) {
++ while (eui64_iszero(ifaceid) ||
++ eui64_equals(ifaceid, go-&gt;hisid)) /* bad luck */
++ eui64_magic(ifaceid);
++ try.ourid = ifaceid;
++ IPV6CPDEBUG((&quot;local LL address %s&quot;, llv6_ntoa(ifaceid)));
++ }
++ );
++
++#ifdef IPV6CP_COMP
++ NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
++ {
++ if (cishort == IPV6CP_COMP) {
++ try.vj_protocol = cishort;
++ } else {
++ try.neg_vj = 0;
++ }
++ }
++ );
++#else
++ NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
++ {
++ try.neg_vj = 0;
++ }
++ );
++#endif
++
++ /*
++ * There may be remaining CIs, if the peer is requesting negotiation
++ * on an option that we didn't include in our request packet.
++ * If they want to negotiate about interface identifier, we comply.
++ * If they want us to ask for compression, we refuse.
++ */
++ while (len &gt; CILEN_VOID) {
++ GETCHAR(citype, p);
++ GETCHAR(cilen, p);
++ if( (len -= cilen) &lt; 0 )
++ goto bad;
++ next = p + cilen - 2;
++
++ switch (citype) {
++ case CI_COMPRESSTYPE:
++ if (go-&gt;neg_vj || no.neg_vj ||
++ (cilen != CILEN_COMPRESS))
++ goto bad;
++ no.neg_vj = 1;
++ break;
++ case CI_IFACEID:
++ if (go-&gt;neg_ifaceid || no.neg_ifaceid || cilen != CILEN_IFACEID)
++ goto bad;
++ try.neg_ifaceid = 1;
++ eui64_get(ifaceid, p);
++ if (go-&gt;accept_local) {
++ while (eui64_iszero(ifaceid) ||
++ eui64_equals(ifaceid, go-&gt;hisid)) /* bad luck */
++ eui64_magic(ifaceid);
++ try.ourid = ifaceid;
++ }
++ no.neg_ifaceid = 1;
++ break;
++ }
++ p = next;
++ }
++
++ /* If there is still anything left, this packet is bad. */
++ if (len != 0)
++ goto bad;
++
++ /*
++ * OK, the Nak is good. Now we can update state.
++ */
++ if (f-&gt;state != OPENED)
++ *go = try;
++
++ return 1;
++
++bad:
++ IPV6CPDEBUG((&quot;ipv6cp_nakci: received bad Nak!&quot;));
++ return 0;
++}
++
++
++/*
++ * ipv6cp_rejci - Reject some of our CIs.
++ */
++static int
++ipv6cp_rejci(f, p, len)
++ fsm *f;
++ u_char *p;
++ int len;
++{
++ ipv6cp_options *go = &amp;ipv6cp_gotoptions[f-&gt;unit];
++ u_char cilen;
++ u_short cishort;
++ eui64_t ifaceid;
++ ipv6cp_options try; /* options to request next time */
++
++ try = *go;
++ /*
++ * Any Rejected CIs must be in exactly the same order that we sent.
++ * Check packet length and CI length at each step.
++ * If we find any deviations, then this packet is bad.
++ */
++#define REJCIIFACEID(opt, neg, val1) \
++ if (go-&gt;neg &amp;&amp; \
++ len &gt;= (cilen = CILEN_IFACEID) &amp;&amp; \
++ p[1] == cilen &amp;&amp; \
++ p[0] == opt) { \
++ len -= cilen; \
++ INCPTR(2, p); \
++ eui64_get(ifaceid, p); \
++ /* Check rejected value. */ \
++ if (! eui64_equals(ifaceid, val1)) \
++ goto bad; \
++ try.neg = 0; \
++ }
++
++#define REJCIVJ(opt, neg, val) \
++ if (go-&gt;neg &amp;&amp; \
++ p[1] == CILEN_COMPRESS &amp;&amp; \
++ len &gt;= p[1] &amp;&amp; \
++ p[0] == opt) { \
++ len -= p[1]; \
++ INCPTR(2, p); \
++ GETSHORT(cishort, p); \
++ /* Check rejected value. */ \
++ if (cishort != val) \
++ goto bad; \
++ try.neg = 0; \
++ }
++
++ REJCIIFACEID(CI_IFACEID, neg_ifaceid, go-&gt;ourid);
++
++ REJCIVJ(CI_COMPRESSTYPE, neg_vj, go-&gt;vj_protocol);
++
++ /*
++ * If there are any remaining CIs, then this packet is bad.
++ */
++ if (len != 0)
++ goto bad;
++ /*
++ * Now we can update state.
++ */
++ if (f-&gt;state != OPENED)
++ *go = try;
++ return 1;
++
++bad:
++ IPV6CPDEBUG((&quot;ipv6cp_rejci: received bad Reject!&quot;));
++ return 0;
++}
++
++
++/*
++ * ipv6cp_reqci - Check the peer's requested CIs and send appropriate response.
++ *
++ * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
++ * appropriately. If reject_if_disagree is non-zero, doesn't return
++ * CONFNAK; returns CONFREJ if it can't return CONFACK.
++ */
++static int
++ipv6cp_reqci(f, inp, len, reject_if_disagree)
++ fsm *f;
++ u_char *inp; /* Requested CIs */
++ int *len; /* Length of requested CIs */
++ int reject_if_disagree;
++{
++ ipv6cp_options *wo = &amp;ipv6cp_wantoptions[f-&gt;unit];
++ ipv6cp_options *ho = &amp;ipv6cp_hisoptions[f-&gt;unit];
++ ipv6cp_options *ao = &amp;ipv6cp_allowoptions[f-&gt;unit];
++ ipv6cp_options *go = &amp;ipv6cp_gotoptions[f-&gt;unit];
++ u_char *cip, *next; /* Pointer to current and next CIs */
++ u_short cilen, citype; /* Parsed len, type */
++ u_short cishort; /* Parsed short value */
++ eui64_t ifaceid; /* Parsed interface identifier */
++ int rc = CONFACK; /* Final packet return code */
++ int orc; /* Individual option return code */
++ u_char *p; /* Pointer to next char to parse */
++ u_char *ucp = inp; /* Pointer to current output char */
++ int l = *len; /* Length left */
++
++ /*
++ * Reset all his options.
++ */
++ BZERO(ho, sizeof(*ho));
++
++ /*
++ * Process all his options.
++ */
++ next = inp;
++ while (l) {
++ orc = CONFACK; /* Assume success */
++ cip = p = next; /* Remember begining of CI */
++ if (l &lt; 2 || /* Not enough data for CI header or */
++ p[1] &lt; 2 || /* CI length too small or */
++ p[1] &gt; l) { /* CI length too big? */
++ IPV6CPDEBUG((&quot;ipv6cp_reqci: bad CI length!&quot;));
++ orc = CONFREJ; /* Reject bad CI */
++ cilen = l; /* Reject till end of packet */
++ l = 0; /* Don't loop again */
++ goto endswitch;
++ }
++ GETCHAR(citype, p); /* Parse CI type */
++ GETCHAR(cilen, p); /* Parse CI length */
++ l -= cilen; /* Adjust remaining length */
++ next += cilen; /* Step to next CI */
++
++ switch (citype) { /* Check CI type */
++ case CI_IFACEID:
++ IPV6CPDEBUG((&quot;ipv6cp: received interface identifier &quot;));
++
++ if (!ao-&gt;neg_ifaceid ||
++ cilen != CILEN_IFACEID) { /* Check CI length */
++ orc = CONFREJ; /* Reject CI */
++ break;
++ }
++
++ /*
++ * If he has no interface identifier, or if we both have same
++ * identifier then NAK it with new idea.
++ * In particular, if we don't know his identifier, but he does,
++ * then accept it.
++ */
++ eui64_get(ifaceid, p);
++ IPV6CPDEBUG((&quot;(%s)&quot;, llv6_ntoa(ifaceid)));
++ if (eui64_iszero(ifaceid) &amp;&amp; eui64_iszero(go-&gt;ourid)) {
++ orc = CONFREJ; /* Reject CI */
++ break;
++ }
++ if (!eui64_iszero(wo-&gt;hisid) &amp;&amp;
++ !eui64_equals(ifaceid, wo-&gt;hisid) &amp;&amp;
++ eui64_iszero(go-&gt;hisid)) {
++
++ orc = CONFNAK;
++ ifaceid = wo-&gt;hisid;
++ go-&gt;hisid = ifaceid;
++ DECPTR(sizeof(ifaceid), p);
++ eui64_put(ifaceid, p);
++ } else
++ if (eui64_iszero(ifaceid) || eui64_equals(ifaceid, go-&gt;ourid)) {
++ orc = CONFNAK;
++ if (eui64_iszero(go-&gt;hisid)) /* first time, try option */
++ ifaceid = wo-&gt;hisid;
++ while (eui64_iszero(ifaceid) ||
++ eui64_equals(ifaceid, go-&gt;ourid)) /* bad luck */
++ eui64_magic(ifaceid);
++ go-&gt;hisid = ifaceid;
++ DECPTR(sizeof(ifaceid), p);
++ eui64_put(ifaceid, p);
++ }
++
++ ho-&gt;neg_ifaceid = 1;
++ ho-&gt;hisid = ifaceid;
++ break;
++
++ case CI_COMPRESSTYPE:
++ IPV6CPDEBUG((&quot;ipv6cp: received COMPRESSTYPE &quot;));
++ if (!ao-&gt;neg_vj ||
++ (cilen != CILEN_COMPRESS)) {
++ orc = CONFREJ;
++ break;
++ }
++ GETSHORT(cishort, p);
++ IPV6CPDEBUG((&quot;(%d)&quot;, cishort));
++
++#ifdef IPV6CP_COMP
++ if (!(cishort == IPV6CP_COMP)) {
++ orc = CONFREJ;
++ break;
++ }
++
++ ho-&gt;neg_vj = 1;
++ ho-&gt;vj_protocol = cishort;
++ break;
++#else
++ orc = CONFREJ;
++ break;
++#endif
++
++ default:
++ orc = CONFREJ;
++ break;
++ }
++
++endswitch:
++ IPV6CPDEBUG((&quot; (%s)\n&quot;, CODENAME(orc)));
++
++ if (orc == CONFACK &amp;&amp; /* Good CI */
++ rc != CONFACK) /* but prior CI wasnt? */
++ continue; /* Don't send this one */
++
++ if (orc == CONFNAK) { /* Nak this CI? */
++ if (reject_if_disagree) /* Getting fed up with sending NAKs? */
++ orc = CONFREJ; /* Get tough if so */
++ else {
++ if (rc == CONFREJ) /* Rejecting prior CI? */
++ continue; /* Don't send this one */
++ if (rc == CONFACK) { /* Ack'd all prior CIs? */
++ rc = CONFNAK; /* Not anymore... */
++ ucp = inp; /* Backup */
++ }
++ }
++ }
++
++ if (orc == CONFREJ &amp;&amp; /* Reject this CI */
++ rc != CONFREJ) { /* but no prior ones? */
++ rc = CONFREJ;
++ ucp = inp; /* Backup */
++ }
++
++ /* Need to move CI? */
++ if (ucp != cip)
++ BCOPY(cip, ucp, cilen); /* Move it */
++
++ /* Update output pointer */
++ INCPTR(cilen, ucp);
++ }
++
++ /*
++ * If we aren't rejecting this packet, and we want to negotiate
++ * their identifier and they didn't send their identifier, then we
++ * send a NAK with a CI_IFACEID option appended. We assume the
++ * input buffer is long enough that we can append the extra
++ * option safely.
++ */
++ if (rc != CONFREJ &amp;&amp; !ho-&gt;neg_ifaceid &amp;&amp;
++ wo-&gt;req_ifaceid &amp;&amp; !reject_if_disagree) {
++ if (rc == CONFACK) {
++ rc = CONFNAK;
++ ucp = inp; /* reset pointer */
++ wo-&gt;req_ifaceid = 0; /* don't ask again */
++ }
++ PUTCHAR(CI_IFACEID, ucp);
++ PUTCHAR(CILEN_IFACEID, ucp);
++ eui64_put(wo-&gt;hisid, ucp);
++ }
++
++ *len = ucp - inp; /* Compute output length */
++ IPV6CPDEBUG((&quot;ipv6cp: returning Configure-%s&quot;, CODENAME(rc)));
++ return (rc); /* Return final code */
++}
++
++
++/*
++ * ipv6_check_options - check that any IP-related options are OK,
++ * and assign appropriate defaults.
++ */
++static void
++ipv6_check_options()
++{
++ ipv6cp_options *wo = &amp;ipv6cp_wantoptions[0];
++
++ if (!ipv6cp_protent.enabled_flag)
++ return;
++
++#if defined(SOL2)
++ /*
++ * Persistent link-local id is only used when user has not explicitly
++ * configure/hard-code the id
++ */
++ if ((wo-&gt;use_persistent) &amp;&amp; (!wo-&gt;opt_local) &amp;&amp; (!wo-&gt;opt_remote)) {
++
++ /*
++ * On systems where there are no Ethernet interfaces used, there
++ * may be other ways to obtain a persistent id. Right now, it
++ * will fall back to using magic [see eui64_magic] below when
++ * an EUI-48 from MAC address can't be obtained. Other possibilities
++ * include obtaining EEPROM serial numbers, or some other unique
++ * yet persistent number. On Sparc platforms, this is possible,
++ * but too bad there's no standards yet for x86 machines.
++ */
++ if (ether_to_eui64(&amp;wo-&gt;ourid)) {
++ wo-&gt;opt_local = 1;
++ }
++ }
++#endif
++
++ if (!wo-&gt;opt_local) { /* init interface identifier */
++ if (wo-&gt;use_ip &amp;&amp; eui64_iszero(wo-&gt;ourid)) {
++ eui64_setlo32(wo-&gt;ourid, ntohl(ipcp_wantoptions[0].ouraddr));
++ if (!eui64_iszero(wo-&gt;ourid))
++ wo-&gt;opt_local = 1;
++ }
++
++ while (eui64_iszero(wo-&gt;ourid))
++ eui64_magic(wo-&gt;ourid);
++ }
++
++ if (!wo-&gt;opt_remote) {
++ if (wo-&gt;use_ip &amp;&amp; eui64_iszero(wo-&gt;hisid)) {
++ eui64_setlo32(wo-&gt;hisid, ntohl(ipcp_wantoptions[0].hisaddr));
++ if (!eui64_iszero(wo-&gt;hisid))
++ wo-&gt;opt_remote = 1;
++ }
++ }
++
++ if (demand &amp;&amp; (eui64_iszero(wo-&gt;ourid) || eui64_iszero(wo-&gt;hisid))) {
++ option_error(&quot;local/remote LL address required for demand-dialling\n&quot;);
++ exit(1);
++ }
++}
++
++
++/*
++ * ipv6_demand_conf - configure the interface as though
++ * IPV6CP were up, for use with dial-on-demand.
++ */
++static int
++ipv6_demand_conf(u)
++ int u;
++{
++ ipv6cp_options *wo = &amp;ipv6cp_wantoptions[u];
++
++#if defined(__linux__) || defined(SOL2) || (defined(SVR4) &amp;&amp; (defined(SNI) || defined(__USLC__)))
++#if defined(SOL2)
++ if (!sif6up(u))
++ return 0;
++#else
++ if (!sifup(u))
++ return 0;
++#endif /* defined(SOL2) */
++#endif
++ if (!sif6addr(u, wo-&gt;ourid, wo-&gt;hisid))
++ return 0;
++#if !defined(__linux__) &amp;&amp; !(defined(SVR4) &amp;&amp; (defined(SNI) || defined(__USLC__)))
++ if (!sifup(u))
++ return 0;
++#endif
++ if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE))
++ return 0;
++
++ notice(&quot;ipv6_demand_conf&quot;);
++ notice(&quot;local LL address %s&quot;, llv6_ntoa(wo-&gt;ourid));
++ notice(&quot;remote LL address %s&quot;, llv6_ntoa(wo-&gt;hisid));
++
++ return 1;
++}
++
++
++/*
++ * ipv6cp_up - IPV6CP has come UP.
++ *
++ * Configure the IPv6 network interface appropriately and bring it up.
++ */
++static void
++ipv6cp_up(f)
++ fsm *f;
++{
++ ipv6cp_options *ho = &amp;ipv6cp_hisoptions[f-&gt;unit];
++ ipv6cp_options *go = &amp;ipv6cp_gotoptions[f-&gt;unit];
++ ipv6cp_options *wo = &amp;ipv6cp_wantoptions[f-&gt;unit];
++
++ IPV6CPDEBUG((&quot;ipv6cp: up&quot;));
++
++ /*
++ * We must have a non-zero LL address for both ends of the link.
++ */
++ if (!ho-&gt;neg_ifaceid)
++ ho-&gt;hisid = wo-&gt;hisid;
++
++ if(!no_ifaceid_neg) {
++ if (eui64_iszero(ho-&gt;hisid)) {
++ error(&quot;Could not determine remote LL address&quot;);
++ ipv6cp_close(f-&gt;unit, &quot;Could not determine remote LL address&quot;);
++ return;
++ }
++ if (eui64_iszero(go-&gt;ourid)) {
++ error(&quot;Could not determine local LL address&quot;);
++ ipv6cp_close(f-&gt;unit, &quot;Could not determine local LL address&quot;);
++ return;
++ }
++ if (eui64_equals(go-&gt;ourid, ho-&gt;hisid)) {
++ error(&quot;local and remote LL addresses are equal&quot;);
++ ipv6cp_close(f-&gt;unit, &quot;local and remote LL addresses are equal&quot;);
++ return;
++ }
++ }
++ script_setenv(&quot;LLLOCAL&quot;, llv6_ntoa(go-&gt;ourid), 0);
++ script_setenv(&quot;LLREMOTE&quot;, llv6_ntoa(ho-&gt;hisid), 0);
++
++#ifdef IPV6CP_COMP
++ /* set tcp compression */
++ sif6comp(f-&gt;unit, ho-&gt;neg_vj);
++#endif
++
++ /*
++ * If we are doing dial-on-demand, the interface is already
++ * configured, so we put out any saved-up packets, then set the
++ * interface to pass IPv6 packets.
++ */
++ if (demand) {
++ if (! eui64_equals(go-&gt;ourid, wo-&gt;ourid) ||
++ ! eui64_equals(ho-&gt;hisid, wo-&gt;hisid)) {
++ if (! eui64_equals(go-&gt;ourid, wo-&gt;ourid))
++ warn(&quot;Local LL address changed to %s&quot;,
++ llv6_ntoa(go-&gt;ourid));
++ if (! eui64_equals(ho-&gt;hisid, wo-&gt;hisid))
++ warn(&quot;Remote LL address changed to %s&quot;,
++ llv6_ntoa(ho-&gt;hisid));
++ ipv6cp_clear_addrs(f-&gt;unit, go-&gt;ourid, ho-&gt;hisid);
++
++ /* Set the interface to the new addresses */
++ if (!sif6addr(f-&gt;unit, go-&gt;ourid, ho-&gt;hisid)) {
++ if (debug)
++ warn(&quot;sif6addr failed&quot;);
++ ipv6cp_close(f-&gt;unit, &quot;Interface configuration failed&quot;);
++ return;
++ }
++
++ }
++ demand_rexmit(PPP_IPV6);
++ sifnpmode(f-&gt;unit, PPP_IPV6, NPMODE_PASS);
++
++ } else {
++ /*
++ * Set LL addresses
++ */
++#if !defined(__linux__) &amp;&amp; !defined(SOL2) &amp;&amp; !(defined(SVR4) &amp;&amp; (defined(SNI) || defined(__USLC__)))
++ if (!sif6addr(f-&gt;unit, go-&gt;ourid, ho-&gt;hisid)) {
++ if (debug)
++ warn(&quot;sif6addr failed&quot;);
++ ipv6cp_close(f-&gt;unit, &quot;Interface configuration failed&quot;);
++ return;
++ }
++#endif
++
++ /* bring the interface up for IPv6 */
++#if defined(SOL2)
++ if (!sif6up(f-&gt;unit)) {
++ if (debug)
++ warn(&quot;sifup failed (IPV6)&quot;);
++ ipv6cp_close(f-&gt;unit, &quot;Interface configuration failed&quot;);
++ return;
++ }
++#else
++ if (!sifup(f-&gt;unit)) {
++ if (debug)
++ warn(&quot;sifup failed (IPV6)&quot;);
++ ipv6cp_close(f-&gt;unit, &quot;Interface configuration failed&quot;);
++ return;
++ }
++#endif /* defined(SOL2) */
++
++#if defined(__linux__) || defined(SOL2) || (defined(SVR4) &amp;&amp; (defined(SNI) || defined(__USLC__)))
++ if (!sif6addr(f-&gt;unit, go-&gt;ourid, ho-&gt;hisid)) {
++ if (debug)
++ warn(&quot;sif6addr failed&quot;);
++ ipv6cp_close(f-&gt;unit, &quot;Interface configuration failed&quot;);
++ return;
++ }
++#endif
++ sifnpmode(f-&gt;unit, PPP_IPV6, NPMODE_PASS);
++
++ notice(&quot;local LL address %s&quot;, llv6_ntoa(go-&gt;ourid));
++ notice(&quot;remote LL address %s&quot;, llv6_ntoa(ho-&gt;hisid));
++ }
++
++ np_up(f-&gt;unit, PPP_IPV6);
++ ipv6cp_is_up = 1;
++
++ /*
++ * Execute the ipv6-up script, like this:
++ * /etc/ppp/ipv6-up interface tty speed local-LL remote-LL
++ */
++ if (ipv6cp_script_state == s_down &amp;&amp; ipv6cp_script_pid == 0) {
++ ipv6cp_script_state = s_up;
++ ipv6cp_script(_PATH_IPV6UP);
++ }
++}
++
++
++/*
++ * ipv6cp_down - IPV6CP has gone DOWN.
++ *
++ * Take the IPv6 network interface down, clear its addresses
++ * and delete routes through it.
++ */
++static void
++ipv6cp_down(f)
++ fsm *f;
++{
++ IPV6CPDEBUG((&quot;ipv6cp: down&quot;));
++ update_link_stats(f-&gt;unit);
++ if (ipv6cp_is_up) {
++ ipv6cp_is_up = 0;
++ np_down(f-&gt;unit, PPP_IPV6);
++ }
++#ifdef IPV6CP_COMP
++ sif6comp(f-&gt;unit, 0);
++#endif
++
++ /*
++ * If we are doing dial-on-demand, set the interface
++ * to queue up outgoing packets (for now).
++ */
++ if (demand) {
++ sifnpmode(f-&gt;unit, PPP_IPV6, NPMODE_QUEUE);
++ } else {
++ sifnpmode(f-&gt;unit, PPP_IPV6, NPMODE_DROP);
++#if !defined(__linux__) &amp;&amp; !(defined(SVR4) &amp;&amp; (defined(SNI) || defined(__USLC)))
++#if defined(SOL2)
++ sif6down(f-&gt;unit);
++#else
++ sifdown(f-&gt;unit);
++#endif /* defined(SOL2) */
++#endif
++ ipv6cp_clear_addrs(f-&gt;unit,
++ ipv6cp_gotoptions[f-&gt;unit].ourid,
++ ipv6cp_hisoptions[f-&gt;unit].hisid);
++#if defined(__linux__) || (defined(SVR4) &amp;&amp; (defined(SNI) || defined(__USLC)))
++ sifdown(f-&gt;unit);
++#endif
++ }
++
++ /* Execute the ipv6-down script */
++ if (ipv6cp_script_state == s_up &amp;&amp; ipv6cp_script_pid == 0) {
++ ipv6cp_script_state = s_down;
++ ipv6cp_script(_PATH_IPV6DOWN);
++ }
++}
++
++
++/*
++ * ipv6cp_clear_addrs() - clear the interface addresses, routes,
++ * proxy neighbour discovery entries, etc.
++ */
++static void
++ipv6cp_clear_addrs(unit, ourid, hisid)
++ int unit;
++ eui64_t ourid;
++ eui64_t hisid;
++{
++ cif6addr(unit, ourid, hisid);
++}
++
++
++/*
++ * ipv6cp_finished - possibly shut down the lower layers.
++ */
++static void
++ipv6cp_finished(f)
++ fsm *f;
++{
++ np_finished(f-&gt;unit, PPP_IPV6);
++}
++
++
++/*
++ * ipv6cp_script_done - called when the ipv6-up or ipv6-down script
++ * has finished.
++ */
++static void
++ipv6cp_script_done(arg)
++ void *arg;
++{
++ ipv6cp_script_pid = 0;
++ switch (ipv6cp_script_state) {
++ case s_up:
++ if (ipv6cp_fsm[0].state != OPENED) {
++ ipv6cp_script_state = s_down;
++ ipv6cp_script(_PATH_IPV6DOWN);
++ }
++ break;
++ case s_down:
++ if (ipv6cp_fsm[0].state == OPENED) {
++ ipv6cp_script_state = s_up;
++ ipv6cp_script(_PATH_IPV6UP);
++ }
++ break;
++ }
++}
++
++
++/*
++ * ipv6cp_script - Execute a script with arguments
++ * interface-name tty-name speed local-LL remote-LL.
++ */
++static void
++ipv6cp_script(script)
++ char *script;
++{
++ char strspeed[32], strlocal[32], strremote[32];
++ char *argv[8];
++
++ sprintf(strspeed, &quot;%d&quot;, baud_rate);
++ strcpy(strlocal, llv6_ntoa(ipv6cp_gotoptions[0].ourid));
++ strcpy(strremote, llv6_ntoa(ipv6cp_hisoptions[0].hisid));
++
++ argv[0] = script;
++ argv[1] = ifname;
++ argv[2] = devnam;
++ argv[3] = strspeed;
++ argv[4] = strlocal;
++ argv[5] = strremote;
++ argv[6] = ipparam;
++ argv[7] = NULL;
++
++ ipv6cp_script_pid = run_program(script, argv, 0, ipv6cp_script_done, NULL);
++}
++
++/*
++ * ipv6cp_printpkt - print the contents of an IPV6CP packet.
++ */
++static char *ipv6cp_codenames[] = {
++ &quot;ConfReq&quot;, &quot;ConfAck&quot;, &quot;ConfNak&quot;, &quot;ConfRej&quot;,
++ &quot;TermReq&quot;, &quot;TermAck&quot;, &quot;CodeRej&quot;
++};
++
++static int
++ipv6cp_printpkt(p, plen, printer, arg)
++ u_char *p;
++ int plen;
++ void (*printer) __P((void *, char *, ...));
++ void *arg;
++{
++ int code, id, len, olen;
++ u_char *pstart, *optend;
++ u_short cishort;
++ eui64_t ifaceid;
++
++ if (plen &lt; HEADERLEN)
++ return 0;
++ pstart = p;
++ GETCHAR(code, p);
++ GETCHAR(id, p);
++ GETSHORT(len, p);
++ if (len &lt; HEADERLEN || len &gt; plen)
++ return 0;
++
++ if (code &gt;= 1 &amp;&amp; code &lt;= sizeof(ipv6cp_codenames) / sizeof(char *))
++ printer(arg, &quot; %s&quot;, ipv6cp_codenames[code-1]);
++ else
++ printer(arg, &quot; code=0x%x&quot;, code);
++ printer(arg, &quot; id=0x%x&quot;, id);
++ len -= HEADERLEN;
++ switch (code) {
++ case CONFREQ:
++ case CONFACK:
++ case CONFNAK:
++ case CONFREJ:
++ /* print option list */
++ while (len &gt;= 2) {
++ GETCHAR(code, p);
++ GETCHAR(olen, p);
++ p -= 2;
++ if (olen &lt; 2 || olen &gt; len) {
++ break;
++ }
++ printer(arg, &quot; &lt;&quot;);
++ len -= olen;
++ optend = p + olen;
++ switch (code) {
++ case CI_COMPRESSTYPE:
++ if (olen &gt;= CILEN_COMPRESS) {
++ p += 2;
++ GETSHORT(cishort, p);
++ printer(arg, &quot;compress &quot;);
++ printer(arg, &quot;0x%x&quot;, cishort);
++ }
++ break;
++ case CI_IFACEID:
++ if (olen == CILEN_IFACEID) {
++ p += 2;
++ eui64_get(ifaceid, p);
++ printer(arg, &quot;addr %s&quot;, llv6_ntoa(ifaceid));
++ }
++ break;
++ }
++ while (p &lt; optend) {
++ GETCHAR(code, p);
++ printer(arg, &quot; %.2x&quot;, code);
++ }
++ printer(arg, &quot;&gt;&quot;);
++ }
++ break;
++
++ case TERMACK:
++ case TERMREQ:
++ if (len &gt; 0 &amp;&amp; *p &gt;= ' ' &amp;&amp; *p &lt; 0x7f) {
++ printer(arg, &quot; &quot;);
++ print_string((char *)p, len, printer, arg);
++ p += len;
++ len = 0;
++ }
++ break;
++ }
++
++ /* print the rest of the bytes in the packet */
++ for (; len &gt; 0; --len) {
++ GETCHAR(code, p);
++ printer(arg, &quot; %.2x&quot;, code);
++ }
++
++ return p - pstart;
++}
++
++/*
++ * ipv6_active_pkt - see if this IP packet is worth bringing the link up for.
++ * We don't bring the link up for IP fragments or for TCP FIN packets
++ * with no data.
++ */
++#define IP6_HDRLEN 40 /* bytes */
++#define IP6_NHDR_FRAG 44 /* fragment IPv6 header */
++#define IPPROTO_TCP 6
++#define TCP_HDRLEN 20
++#define TH_FIN 0x01
++
++/*
++ * We use these macros because the IP header may be at an odd address,
++ * and some compilers might use word loads to get th_off or ip_hl.
++ */
++
++#define get_ip6nh(x) (((unsigned char *)(x))[6])
++#define get_tcpoff(x) (((unsigned char *)(x))[12] &gt;&gt; 4)
++#define get_tcpflags(x) (((unsigned char *)(x))[13])
++
++static int
++ipv6_active_pkt(pkt, len)
++ u_char *pkt;
++ int len;
++{
++ u_char *tcp;
++
++ len -= PPP_HDRLEN;
++ pkt += PPP_HDRLEN;
++ if (len &lt; IP6_HDRLEN)
++ return 0;
++ if (get_ip6nh(pkt) == IP6_NHDR_FRAG)
++ return 0;
++ if (get_ip6nh(pkt) != IPPROTO_TCP)
++ return 1;
++ if (len &lt; IP6_HDRLEN + TCP_HDRLEN)
++ return 0;
++ tcp = pkt + IP6_HDRLEN;
++ if ((get_tcpflags(tcp) &amp; TH_FIN) != 0 &amp;&amp; len == IP6_HDRLEN + get_tcpoff(tcp) * 4)
++ return 0;
++ return 1;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/ipv6cp.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/ipv6cp.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/ipv6cp.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/ipv6cp.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,126 @@
++/*
++ ipv6cp.h - PPP IPV6 Control Protocol.
++ Copyright (C) 1999 Tommi Komulainen &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">Tommi.Komulainen at iki.fi</A>&gt;
++
++ Redistribution and use in source and binary forms are permitted
++ provided that the above copyright notice and this paragraph are
++ duplicated in all such forms. The name of the author may not be
++ used to endorse or promote products derived from this software
++ without specific prior written permission.
++ THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++*/
++
++/* Original version, based on RFC2023 :
++
++ Copyright (c) 1995, 1996, 1997 <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">Francis.Dupont at inria.fr</A>, INRIA Rocquencourt,
++ <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">Alain.Durand at imag.fr</A>, IMAG,
++ <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">Jean-Luc.Richier at imag.fr</A>, IMAG-LSR.
++
++ Copyright (c) 1998, 1999 <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">Francis.Dupont at inria.fr</A>, GIE DYADE,
++ <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">Alain.Durand at imag.fr</A>, IMAG,
++ <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">Jean-Luc.Richier at imag.fr</A>, IMAG-LSR.
++
++ Ce travail a &#233;t&#233; fait au sein du GIE DYADE (Groupement d'Int&#233;r&#234;t
++ &#201;conomique ayant pour membres BULL S.A. et l'INRIA).
++
++ Ce logiciel informatique est disponible aux conditions
++ usuelles dans la recherche, c'est-&#224;-dire qu'il peut
++ &#234;tre utilis&#233;, copi&#233;, modifi&#233;, distribu&#233; &#224; l'unique
++ condition que ce texte soit conserv&#233; afin que
++ l'origine de ce logiciel soit reconnue.
++
++ Le nom de l'Institut National de Recherche en Informatique
++ et en Automatique (INRIA), de l'IMAG, ou d'une personne morale
++ ou physique ayant particip&#233; &#224; l'&#233;laboration de ce logiciel ne peut
++ &#234;tre utilis&#233; sans son accord pr&#233;alable explicite.
++
++ Ce logiciel est fourni tel quel sans aucune garantie,
++ support ou responsabilit&#233; d'aucune sorte.
++ Ce logiciel est d&#233;riv&#233; de sources d'origine
++ &quot;University of California at Berkeley&quot; et
++ &quot;Digital Equipment Corporation&quot; couvertes par des copyrights.
++
++ L'Institut d'Informatique et de Math&#233;matiques Appliqu&#233;es de Grenoble (IMAG)
++ est une f&#233;d&#233;ration d'unit&#233;s mixtes de recherche du CNRS, de l'Institut National
++ Polytechnique de Grenoble et de l'Universit&#233; Joseph Fourier regroupant
++ sept laboratoires dont le laboratoire Logiciels, Syst&#232;mes, R&#233;seaux (LSR).
++
++ This work has been done in the context of GIE DYADE (joint R &amp; D venture
++ between BULL S.A. and INRIA).
++
++ This software is available with usual &quot;research&quot; terms
++ with the aim of retain credits of the software.
++ Permission to use, copy, modify and distribute this software for any
++ purpose and without fee is hereby granted, provided that the above
++ copyright notice and this permission notice appear in all copies,
++ and the name of INRIA, IMAG, or any contributor not be used in advertising
++ or publicity pertaining to this material without the prior explicit
++ permission. The software is provided &quot;as is&quot; without any
++ warranties, support or liabilities of any kind.
++ This software is derived from source code from
++ &quot;University of California at Berkeley&quot; and
++ &quot;Digital Equipment Corporation&quot; protected by copyrights.
++
++ Grenoble's Institute of Computer Science and Applied Mathematics (IMAG)
++ is a federation of seven research units funded by the CNRS, National
++ Polytechnic Institute of Grenoble and University Joseph Fourier.
++ The research unit in Software, Systems, Networks (LSR) is member of IMAG.
++*/
++
++/*
++ * Derived from :
++ *
++ *
++ * ipcp.h - IP Control Protocol definitions.
++ *
++ * Copyright (c) 1989 Carnegie Mellon University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by Carnegie Mellon University. The name of the
++ * University may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * $Id: ipv6cp.h 215411 2007-04-25 12:26:16Z pixel $
++ */
++
++/*
++ * Options.
++ */
++#define CI_IFACEID 1 /* Interface Identifier */
++#define CI_COMPRESSTYPE 2 /* Compression Type */
++
++/* No compression types yet defined.
++ *#define IPV6CP_COMP 0x004f
++ */
++typedef struct ipv6cp_options {
++ int neg_ifaceid; /* Negotiate interface identifier? */
++ int req_ifaceid; /* Ask peer to send interface identifier? */
++ int accept_local; /* accept peer's value for iface id? */
++ int opt_local; /* ourtoken set by option */
++ int opt_remote; /* histoken set by option */
++ int use_ip; /* use IP as interface identifier */
++#if defined(SOL2)
++ int use_persistent; /* use uniquely persistent value for address */
++#endif /* defined(SOL2) */
++ int neg_vj; /* Van Jacobson Compression? */
++ u_short vj_protocol; /* protocol value to use in VJ option */
++ eui64_t ourid, hisid; /* Interface identifiers */
++} ipv6cp_options;
++
++extern fsm ipv6cp_fsm[];
++extern ipv6cp_options ipv6cp_wantoptions[];
++extern ipv6cp_options ipv6cp_gotoptions[];
++extern ipv6cp_options ipv6cp_allowoptions[];
++extern ipv6cp_options ipv6cp_hisoptions[];
++
++extern struct protent ipv6cp_protent;
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/ipv6cp.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/ipxcp.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/ipxcp.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/ipxcp.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1570 @@
++/*
++ * ipxcp.c - PPP IPX Control Protocol.
++ *
++ * Copyright (c) 1989 Carnegie Mellon University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by Carnegie Mellon University. The name of the
++ * University may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ */
++
++#ifdef IPX_CHANGE
++
++#define RCSID &quot;$Id: ipxcp.c 195720 2001-06-11 11:44:34Z gc $&quot;
++
++/*
++ * TODO:
++ */
++
++#include &lt;stdio.h&gt;
++#include &lt;string.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;ctype.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/socket.h&gt;
++#include &lt;netinet/in.h&gt;
++
++#include &quot;pppd.h&quot;
++#include &quot;fsm.h&quot;
++#include &quot;ipxcp.h&quot;
++#include &quot;pathnames.h&quot;
++#include &quot;magic.h&quot;
++
++static const char rcsid[] = RCSID;
++
++/* global vars */
++ipxcp_options ipxcp_wantoptions[NUM_PPP]; /* Options that we want to request */
++ipxcp_options ipxcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */
++ipxcp_options ipxcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */
++ipxcp_options ipxcp_hisoptions[NUM_PPP]; /* Options that we ack'd */
++
++#define wo (&amp;ipxcp_wantoptions[0])
++#define ao (&amp;ipxcp_allowoptions[0])
++#define go (&amp;ipxcp_gotoptions[0])
++#define ho (&amp;ipxcp_hisoptions[0])
++
++/*
++ * Callbacks for fsm code. (CI = Configuration Information)
++ */
++static void ipxcp_resetci __P((fsm *)); /* Reset our CI */
++static int ipxcp_cilen __P((fsm *)); /* Return length of our CI */
++static void ipxcp_addci __P((fsm *, u_char *, int *)); /* Add our CI */
++static int ipxcp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */
++static int ipxcp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */
++static int ipxcp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */
++static int ipxcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
++static void ipxcp_up __P((fsm *)); /* We're UP */
++static void ipxcp_down __P((fsm *)); /* We're DOWN */
++static void ipxcp_finished __P((fsm *)); /* Don't need lower layer */
++static void ipxcp_script __P((fsm *, char *)); /* Run an up/down script */
++
++fsm ipxcp_fsm[NUM_PPP]; /* IPXCP fsm structure */
++
++static fsm_callbacks ipxcp_callbacks = { /* IPXCP callback routines */
++ ipxcp_resetci, /* Reset our Configuration Information */
++ ipxcp_cilen, /* Length of our Configuration Information */
++ ipxcp_addci, /* Add our Configuration Information */
++ ipxcp_ackci, /* ACK our Configuration Information */
++ ipxcp_nakci, /* NAK our Configuration Information */
++ ipxcp_rejci, /* Reject our Configuration Information */
++ ipxcp_reqci, /* Request peer's Configuration Information */
++ ipxcp_up, /* Called when fsm reaches OPENED state */
++ ipxcp_down, /* Called when fsm leaves OPENED state */
++ NULL, /* Called when we want the lower layer up */
++ ipxcp_finished, /* Called when we want the lower layer down */
++ NULL, /* Called when Protocol-Reject received */
++ NULL, /* Retransmission is necessary */
++ NULL, /* Called to handle protocol-specific codes */
++ &quot;IPXCP&quot; /* String name of protocol */
++};
++
++/*
++ * Command-line options.
++ */
++static int setipxnode __P((char **));
++static void printipxnode __P((option_t *,
++ void (*)(void *, char *, ...), void *));
++static int setipxname __P((char **));
++
++static option_t ipxcp_option_list[] = {
++ { &quot;ipx&quot;, o_bool, &amp;ipxcp_protent.enabled_flag,
++ &quot;Enable IPXCP (and IPX)&quot;, OPT_PRIO | 1 },
++ { &quot;+ipx&quot;, o_bool, &amp;ipxcp_protent.enabled_flag,
++ &quot;Enable IPXCP (and IPX)&quot;, OPT_PRIOSUB | OPT_ALIAS | 1 },
++ { &quot;noipx&quot;, o_bool, &amp;ipxcp_protent.enabled_flag,
++ &quot;Disable IPXCP (and IPX)&quot;, OPT_PRIOSUB },
++ { &quot;-ipx&quot;, o_bool, &amp;ipxcp_protent.enabled_flag,
++ &quot;Disable IPXCP (and IPX)&quot;, OPT_PRIOSUB | OPT_ALIAS },
++
++ { &quot;ipx-network&quot;, o_uint32, &amp;ipxcp_wantoptions[0].our_network,
++ &quot;Set our IPX network number&quot;, OPT_PRIO, &amp;ipxcp_wantoptions[0].neg_nn },
++
++ { &quot;ipxcp-accept-network&quot;, o_bool, &amp;ipxcp_wantoptions[0].accept_network,
++ &quot;Accept peer IPX network number&quot;, 1,
++ &amp;ipxcp_allowoptions[0].accept_network },
++
++ { &quot;ipx-node&quot;, o_special, (void *)setipxnode,
++ &quot;Set IPX node number&quot;, OPT_A2PRINTER, (void *)printipxnode },
++
++ { &quot;ipxcp-accept-local&quot;, o_bool, &amp;ipxcp_wantoptions[0].accept_local,
++ &quot;Accept our IPX address&quot;, 1,
++ &amp;ipxcp_allowoptions[0].accept_local },
++
++ { &quot;ipxcp-accept-remote&quot;, o_bool, &amp;ipxcp_wantoptions[0].accept_remote,
++ &quot;Accept peer's IPX address&quot;, 1,
++ &amp;ipxcp_allowoptions[0].accept_remote },
++
++ { &quot;ipx-routing&quot;, o_int, &amp;ipxcp_wantoptions[0].router,
++ &quot;Set IPX routing proto number&quot;, OPT_PRIO,
++ &amp;ipxcp_wantoptions[0].neg_router },
++
++ { &quot;ipx-router-name&quot;, o_special, setipxname,
++ &quot;Set IPX router name&quot;, OPT_PRIO | OPT_A2STRVAL | OPT_STATIC,
++ &amp;ipxcp_wantoptions[0].name },
++
++ { &quot;ipxcp-restart&quot;, o_int, &amp;ipxcp_fsm[0].timeouttime,
++ &quot;Set timeout for IPXCP&quot;, OPT_PRIO },
++ { &quot;ipxcp-max-terminate&quot;, o_int, &amp;ipxcp_fsm[0].maxtermtransmits,
++ &quot;Set max #xmits for IPXCP term-reqs&quot;, OPT_PRIO },
++ { &quot;ipxcp-max-configure&quot;, o_int, &amp;ipxcp_fsm[0].maxconfreqtransmits,
++ &quot;Set max #xmits for IPXCP conf-reqs&quot;, OPT_PRIO },
++ { &quot;ipxcp-max-failure&quot;, o_int, &amp;ipxcp_fsm[0].maxnakloops,
++ &quot;Set max #conf-naks for IPXCP&quot;, OPT_PRIO },
++
++ { NULL }
++};
++
++/*
++ * Protocol entry points.
++ */
++
++static void ipxcp_init __P((int));
++static void ipxcp_open __P((int));
++static void ipxcp_close __P((int, char *));
++static void ipxcp_lowerup __P((int));
++static void ipxcp_lowerdown __P((int));
++static void ipxcp_input __P((int, u_char *, int));
++static void ipxcp_protrej __P((int));
++static int ipxcp_printpkt __P((u_char *, int,
++ void (*) __P((void *, char *, ...)), void *));
++
++struct protent ipxcp_protent = {
++ PPP_IPXCP,
++ ipxcp_init,
++ ipxcp_input,
++ ipxcp_protrej,
++ ipxcp_lowerup,
++ ipxcp_lowerdown,
++ ipxcp_open,
++ ipxcp_close,
++ ipxcp_printpkt,
++ NULL,
++ 0,
++ &quot;IPXCP&quot;,
++ &quot;IPX&quot;,
++ ipxcp_option_list,
++ NULL,
++ NULL,
++ NULL
++};
++
++/*
++ * Lengths of configuration options.
++ */
++
++#define CILEN_VOID 2
++#define CILEN_COMPLETE 2 /* length of complete option */
++#define CILEN_NETN 6 /* network number length option */
++#define CILEN_NODEN 8 /* node number length option */
++#define CILEN_PROTOCOL 4 /* Minimum length of routing protocol */
++#define CILEN_NAME 3 /* Minimum length of router name */
++#define CILEN_COMPRESS 4 /* Minimum length of compression protocol */
++
++#define CODENAME(x) ((x) == CONFACK ? &quot;ACK&quot; : \
++ (x) == CONFNAK ? &quot;NAK&quot; : &quot;REJ&quot;)
++
++static int ipxcp_is_up;
++
++static char *ipx_ntoa __P((u_int32_t));
++
++/* Used in printing the node number */
++#define NODE(base) base[0], base[1], base[2], base[3], base[4], base[5]
++
++/* Used to generate the proper bit mask */
++#define BIT(num) (1 &lt;&lt; (num))
++
++/*
++ * Convert from internal to external notation
++ */
++
++static short int
++to_external(internal)
++short int internal;
++{
++ short int external;
++
++ if (internal &amp; BIT(IPX_NONE) )
++ external = IPX_NONE;
++ else
++ external = RIP_SAP;
++
++ return external;
++}
++
++/*
++ * Make a string representation of a network IP address.
++ */
++
++static char *
++ipx_ntoa(ipxaddr)
++u_int32_t ipxaddr;
++{
++ static char b[64];
++ slprintf(b, sizeof(b), &quot;%x&quot;, ipxaddr);
++ return b;
++}
++
++
++static u_char *
++setipxnodevalue(src,dst)
++u_char *src, *dst;
++{
++ int indx;
++ int item;
++
++ for (;;) {
++ if (!isxdigit (*src))
++ break;
++
++ for (indx = 0; indx &lt; 5; ++indx) {
++ dst[indx] &lt;&lt;= 4;
++ dst[indx] |= (dst[indx + 1] &gt;&gt; 4) &amp; 0x0F;
++ }
++
++ item = toupper (*src) - '0';
++ if (item &gt; 9)
++ item -= 7;
++
++ dst[5] = (dst[5] &lt;&lt; 4) | item;
++ ++src;
++ }
++ return src;
++}
++
++static int ipx_prio_our, ipx_prio_his;
++
++static int
++setipxnode(argv)
++ char **argv;
++{
++ char *end;
++ int have_his = 0;
++ u_char our_node[6];
++ u_char his_node[6];
++
++ memset (our_node, 0, 6);
++ memset (his_node, 0, 6);
++
++ end = setipxnodevalue (*argv, our_node);
++ if (*end == ':') {
++ have_his = 1;
++ end = setipxnodevalue (++end, his_node);
++ }
++
++ if (*end == '\0') {
++ ipxcp_wantoptions[0].neg_node = 1;
++ if (option_priority &gt;= ipx_prio_our) {
++ memcpy(&amp;ipxcp_wantoptions[0].our_node[0], our_node, 6);
++ ipx_prio_our = option_priority;
++ }
++ if (have_his &amp;&amp; option_priority &gt;= ipx_prio_his) {
++ memcpy(&amp;ipxcp_wantoptions[0].his_node[0], his_node, 6);
++ ipx_prio_his = option_priority;
++ }
++ return 1;
++ }
++
++ option_error(&quot;invalid parameter '%s' for ipx-node option&quot;, *argv);
++ return 0;
++}
++
++static void
++printipxnode(opt, printer, arg)
++ option_t *opt;
++ void (*printer) __P((void *, char *, ...));
++ void *arg;
++{
++ unsigned char *p;
++
++ p = ipxcp_wantoptions[0].our_node;
++ if (ipx_prio_our)
++ printer(arg, &quot;%.2x%.2x%.2x%.2x%.2x%.2x&quot;,
++ p[0], p[1], p[2], p[3], p[4], p[5]);
++ printer(arg, &quot;:&quot;);
++ p = ipxcp_wantoptions[0].his_node;
++ if (ipx_prio_his)
++ printer(arg, &quot;%.2x%.2x%.2x%.2x%.2x%.2x&quot;,
++ p[0], p[1], p[2], p[3], p[4], p[5]);
++}
++
++static int
++setipxname (argv)
++ char **argv;
++{
++ char *dest = ipxcp_wantoptions[0].name;
++ char *src = *argv;
++ int count;
++ char ch;
++
++ ipxcp_wantoptions[0].neg_name = 1;
++ ipxcp_allowoptions[0].neg_name = 1;
++ memset (dest, '\0', sizeof (ipxcp_wantoptions[0].name));
++
++ count = 0;
++ while (*src) {
++ ch = *src++;
++ if (! isalnum (ch) &amp;&amp; ch != '_') {
++ option_error(&quot;IPX router name must be alphanumeric or _&quot;);
++ return 0;
++ }
++
++ if (count &gt;= sizeof (ipxcp_wantoptions[0].name) - 1) {
++ option_error(&quot;IPX router name is limited to %d characters&quot;,
++ sizeof (ipxcp_wantoptions[0].name) - 1);
++ return 0;
++ }
++
++ dest[count++] = toupper (ch);
++ }
++ dest[count] = 0;
++
++ return 1;
++}
++
++/*
++ * ipxcp_init - Initialize IPXCP.
++ */
++static void
++ipxcp_init(unit)
++ int unit;
++{
++ fsm *f = &amp;ipxcp_fsm[unit];
++
++ f-&gt;unit = unit;
++ f-&gt;protocol = PPP_IPXCP;
++ f-&gt;callbacks = &amp;ipxcp_callbacks;
++ fsm_init(&amp;ipxcp_fsm[unit]);
++
++ memset (wo-&gt;name, 0, sizeof (wo-&gt;name));
++ memset (wo-&gt;our_node, 0, sizeof (wo-&gt;our_node));
++ memset (wo-&gt;his_node, 0, sizeof (wo-&gt;his_node));
++
++ wo-&gt;neg_nn = 1;
++ wo-&gt;neg_complete = 1;
++ wo-&gt;network = 0;
++
++ ao-&gt;neg_node = 1;
++ ao-&gt;neg_nn = 1;
++ ao-&gt;neg_name = 1;
++ ao-&gt;neg_complete = 1;
++ ao-&gt;neg_router = 1;
++
++ ao-&gt;accept_local = 0;
++ ao-&gt;accept_remote = 0;
++ ao-&gt;accept_network = 0;
++
++ wo-&gt;tried_rip = 0;
++ wo-&gt;tried_nlsp = 0;
++}
++
++/*
++ * Copy the node number
++ */
++
++static void
++copy_node (src, dst)
++u_char *src, *dst;
++{
++ memcpy (dst, src, sizeof (ipxcp_wantoptions[0].our_node));
++}
++
++/*
++ * Compare node numbers
++ */
++
++static int
++compare_node (src, dst)
++u_char *src, *dst;
++{
++ return memcmp (dst, src, sizeof (ipxcp_wantoptions[0].our_node)) == 0;
++}
++
++/*
++ * Is the node number zero?
++ */
++
++static int
++zero_node (node)
++u_char *node;
++{
++ int indx;
++ for (indx = 0; indx &lt; sizeof (ipxcp_wantoptions[0].our_node); ++indx)
++ if (node [indx] != 0)
++ return 0;
++ return 1;
++}
++
++/*
++ * Increment the node number
++ */
++
++static void
++inc_node (node)
++u_char *node;
++{
++ u_char *outp;
++ u_int32_t magic_num;
++
++ outp = node;
++ magic_num = magic();
++ *outp++ = '\0';
++ *outp++ = '\0';
++ PUTLONG (magic_num, outp);
++}
++
++/*
++ * ipxcp_open - IPXCP is allowed to come up.
++ */
++static void
++ipxcp_open(unit)
++ int unit;
++{
++ fsm_open(&amp;ipxcp_fsm[unit]);
++}
++
++/*
++ * ipxcp_close - Take IPXCP down.
++ */
++static void
++ipxcp_close(unit, reason)
++ int unit;
++ char *reason;
++{
++ fsm_close(&amp;ipxcp_fsm[unit], reason);
++}
++
++
++/*
++ * ipxcp_lowerup - The lower layer is up.
++ */
++static void
++ipxcp_lowerup(unit)
++ int unit;
++{
++ fsm_lowerup(&amp;ipxcp_fsm[unit]);
++}
++
++
++/*
++ * ipxcp_lowerdown - The lower layer is down.
++ */
++static void
++ipxcp_lowerdown(unit)
++ int unit;
++{
++ fsm_lowerdown(&amp;ipxcp_fsm[unit]);
++}
++
++
++/*
++ * ipxcp_input - Input IPXCP packet.
++ */
++static void
++ipxcp_input(unit, p, len)
++ int unit;
++ u_char *p;
++ int len;
++{
++ fsm_input(&amp;ipxcp_fsm[unit], p, len);
++}
++
++
++/*
++ * ipxcp_protrej - A Protocol-Reject was received for IPXCP.
++ *
++ * Pretend the lower layer went down, so we shut up.
++ */
++static void
++ipxcp_protrej(unit)
++ int unit;
++{
++ fsm_lowerdown(&amp;ipxcp_fsm[unit]);
++}
++
++
++/*
++ * ipxcp_resetci - Reset our CI.
++ */
++static void
++ipxcp_resetci(f)
++ fsm *f;
++{
++ wo-&gt;req_node = wo-&gt;neg_node &amp;&amp; ao-&gt;neg_node;
++ wo-&gt;req_nn = wo-&gt;neg_nn &amp;&amp; ao-&gt;neg_nn;
++
++ if (wo-&gt;our_network == 0) {
++ wo-&gt;neg_node = 1;
++ ao-&gt;accept_network = 1;
++ }
++/*
++ * If our node number is zero then change it.
++ */
++ if (zero_node (wo-&gt;our_node)) {
++ inc_node (wo-&gt;our_node);
++ ao-&gt;accept_local = 1;
++ wo-&gt;neg_node = 1;
++ }
++/*
++ * If his node number is zero then change it.
++ */
++ if (zero_node (wo-&gt;his_node)) {
++ inc_node (wo-&gt;his_node);
++ ao-&gt;accept_remote = 1;
++ }
++/*
++ * If no routing agent was specified then we do RIP/SAP according to the
++ * RFC documents. If you have specified something then OK. Otherwise, we
++ * do RIP/SAP.
++ */
++ if (ao-&gt;router == 0) {
++ ao-&gt;router |= BIT(RIP_SAP);
++ wo-&gt;router |= BIT(RIP_SAP);
++ }
++
++ /* Always specify a routing protocol unless it was REJected. */
++ wo-&gt;neg_router = 1;
++/*
++ * Start with these default values
++ */
++ *go = *wo;
++}
++
++/*
++ * ipxcp_cilen - Return length of our CI.
++ */
++
++static int
++ipxcp_cilen(f)
++ fsm *f;
++{
++ int len;
++
++ len = go-&gt;neg_nn ? CILEN_NETN : 0;
++ len += go-&gt;neg_node ? CILEN_NODEN : 0;
++ len += go-&gt;neg_name ? CILEN_NAME + strlen (go-&gt;name) - 1 : 0;
++
++ /* RFC says that defaults should not be included. */
++ if (go-&gt;neg_router &amp;&amp; to_external(go-&gt;router) != RIP_SAP)
++ len += CILEN_PROTOCOL;
++
++ return (len);
++}
++
++
++/*
++ * ipxcp_addci - Add our desired CIs to a packet.
++ */
++static void
++ipxcp_addci(f, ucp, lenp)
++ fsm *f;
++ u_char *ucp;
++ int *lenp;
++{
++/*
++ * Add the options to the record.
++ */
++ if (go-&gt;neg_nn) {
++ PUTCHAR (IPX_NETWORK_NUMBER, ucp);
++ PUTCHAR (CILEN_NETN, ucp);
++ PUTLONG (go-&gt;our_network, ucp);
++ }
++
++ if (go-&gt;neg_node) {
++ int indx;
++ PUTCHAR (IPX_NODE_NUMBER, ucp);
++ PUTCHAR (CILEN_NODEN, ucp);
++ for (indx = 0; indx &lt; sizeof (go-&gt;our_node); ++indx)
++ PUTCHAR (go-&gt;our_node[indx], ucp);
++ }
++
++ if (go-&gt;neg_name) {
++ int cilen = strlen (go-&gt;name);
++ int indx;
++ PUTCHAR (IPX_ROUTER_NAME, ucp);
++ PUTCHAR (CILEN_NAME + cilen - 1, ucp);
++ for (indx = 0; indx &lt; cilen; ++indx)
++ PUTCHAR (go-&gt;name [indx], ucp);
++ }
++
++ if (go-&gt;neg_router) {
++ short external = to_external (go-&gt;router);
++ if (external != RIP_SAP) {
++ PUTCHAR (IPX_ROUTER_PROTOCOL, ucp);
++ PUTCHAR (CILEN_PROTOCOL, ucp);
++ PUTSHORT (external, ucp);
++ }
++ }
++}
++
++/*
++ * ipxcp_ackci - Ack our CIs.
++ *
++ * Returns:
++ * 0 - Ack was bad.
++ * 1 - Ack was good.
++ */
++static int
++ipxcp_ackci(f, p, len)
++ fsm *f;
++ u_char *p;
++ int len;
++{
++ u_short cilen, citype, cishort;
++ u_char cichar;
++ u_int32_t cilong;
++
++#define ACKCIVOID(opt, neg) \
++ if (neg) { \
++ if ((len -= CILEN_VOID) &lt; 0) \
++ break; \
++ GETCHAR(citype, p); \
++ GETCHAR(cilen, p); \
++ if (cilen != CILEN_VOID || \
++ citype != opt) \
++ break; \
++ }
++
++#define ACKCICOMPLETE(opt,neg) ACKCIVOID(opt, neg)
++
++#define ACKCICHARS(opt, neg, val, cnt) \
++ if (neg) { \
++ int indx, count = cnt; \
++ len -= (count + 2); \
++ if (len &lt; 0) \
++ break; \
++ GETCHAR(citype, p); \
++ GETCHAR(cilen, p); \
++ if (cilen != (count + 2) || \
++ citype != opt) \
++ break; \
++ for (indx = 0; indx &lt; count; ++indx) {\
++ GETCHAR(cichar, p); \
++ if (cichar != ((u_char *) &amp;val)[indx]) \
++ break; \
++ }\
++ if (indx != count) \
++ break; \
++ }
++
++#define ACKCINODE(opt,neg,val) ACKCICHARS(opt,neg,val,sizeof(val))
++#define ACKCINAME(opt,neg,val) ACKCICHARS(opt,neg,val,strlen(val))
++
++#define ACKCINETWORK(opt, neg, val) \
++ if (neg) { \
++ if ((len -= CILEN_NETN) &lt; 0) \
++ break; \
++ GETCHAR(citype, p); \
++ GETCHAR(cilen, p); \
++ if (cilen != CILEN_NETN || \
++ citype != opt) \
++ break; \
++ GETLONG(cilong, p); \
++ if (cilong != val) \
++ break; \
++ }
++
++#define ACKCIPROTO(opt, neg, val) \
++ if (neg) { \
++ if (len &lt; 2) \
++ break; \
++ GETCHAR(citype, p); \
++ GETCHAR(cilen, p); \
++ if (cilen != CILEN_PROTOCOL || citype != opt) \
++ break; \
++ len -= cilen; \
++ if (len &lt; 0) \
++ break; \
++ GETSHORT(cishort, p); \
++ if (cishort != to_external (val) || cishort == RIP_SAP) \
++ break; \
++ }
++/*
++ * Process the ACK frame in the order in which the frame was assembled
++ */
++ do {
++ ACKCINETWORK (IPX_NETWORK_NUMBER, go-&gt;neg_nn, go-&gt;our_network);
++ ACKCINODE (IPX_NODE_NUMBER, go-&gt;neg_node, go-&gt;our_node);
++ ACKCINAME (IPX_ROUTER_NAME, go-&gt;neg_name, go-&gt;name);
++ if (len &gt; 0)
++ ACKCIPROTO (IPX_ROUTER_PROTOCOL, go-&gt;neg_router, go-&gt;router);
++/*
++ * This is the end of the record.
++ */
++ if (len == 0)
++ return (1);
++ } while (0);
++/*
++ * The frame is invalid
++ */
++ IPXCPDEBUG((&quot;ipxcp_ackci: received bad Ack!&quot;));
++ return (0);
++}
++
++/*
++ * ipxcp_nakci - Peer has sent a NAK for some of our CIs.
++ * This should not modify any state if the Nak is bad
++ * or if IPXCP is in the OPENED state.
++ *
++ * Returns:
++ * 0 - Nak was bad.
++ * 1 - Nak was good.
++ */
++
++static int
++ipxcp_nakci(f, p, len)
++ fsm *f;
++ u_char *p;
++ int len;
++{
++ u_char citype, cilen, *next;
++ u_short s;
++ u_int32_t l;
++ ipxcp_options no; /* options we've seen Naks for */
++ ipxcp_options try; /* options to request next time */
++
++ BZERO(&amp;no, sizeof(no));
++ try = *go;
++
++ while (len &gt; CILEN_VOID) {
++ GETCHAR (citype, p);
++ GETCHAR (cilen, p);
++ len -= cilen;
++ if (len &lt; 0)
++ goto bad;
++ next = &amp;p [cilen - CILEN_VOID];
++
++ switch (citype) {
++ case IPX_NETWORK_NUMBER:
++ if (!go-&gt;neg_nn || no.neg_nn || (cilen != CILEN_NETN))
++ goto bad;
++ no.neg_nn = 1;
++
++ GETLONG(l, p);
++ if (l &amp;&amp; ao-&gt;accept_network)
++ try.our_network = l;
++ break;
++
++ case IPX_NODE_NUMBER:
++ if (!go-&gt;neg_node || no.neg_node || (cilen != CILEN_NODEN))
++ goto bad;
++ no.neg_node = 1;
++
++ if (!zero_node (p) &amp;&amp; ao-&gt;accept_local &amp;&amp;
++ ! compare_node (p, ho-&gt;his_node))
++ copy_node (p, try.our_node);
++ break;
++
++ /* This has never been sent. Ignore the NAK frame */
++ case IPX_COMPRESSION_PROTOCOL:
++ goto bad;
++
++ case IPX_ROUTER_PROTOCOL:
++ if (!go-&gt;neg_router || (cilen &lt; CILEN_PROTOCOL))
++ goto bad;
++
++ GETSHORT (s, p);
++ if (s &gt; 15) /* This is just bad, but ignore for now. */
++ break;
++
++ s = BIT(s);
++ if (no.router &amp; s) /* duplicate NAKs are always bad */
++ goto bad;
++
++ if (no.router == 0) /* Reset on first NAK only */
++ try.router = 0;
++
++ no.router |= s;
++ try.router |= s;
++ try.neg_router = 1;
++ break;
++
++ /* These, according to the RFC, must never be NAKed. */
++ case IPX_ROUTER_NAME:
++ case IPX_COMPLETE:
++ goto bad;
++
++ /* These are for options which we have not seen. */
++ default:
++ break;
++ }
++ p = next;
++ }
++
++ /*
++ * Do not permit the peer to force a router protocol which we do not
++ * support. However, default to the condition that will accept &quot;NONE&quot;.
++ */
++ try.router &amp;= (ao-&gt;router | BIT(IPX_NONE));
++ if (try.router == 0 &amp;&amp; ao-&gt;router != 0)
++ try.router = BIT(IPX_NONE);
++
++ if (try.router != 0)
++ try.neg_router = 1;
++
++ /*
++ * OK, the Nak is good. Now we can update state.
++ * If there are any options left, we ignore them.
++ */
++ if (f-&gt;state != OPENED)
++ *go = try;
++
++ return 1;
++
++bad:
++ IPXCPDEBUG((&quot;ipxcp_nakci: received bad Nak!&quot;));
++ return 0;
++}
++
++/*
++ * ipxcp_rejci - Reject some of our CIs.
++ */
++static int
++ipxcp_rejci(f, p, len)
++ fsm *f;
++ u_char *p;
++ int len;
++{
++ u_short cilen, citype, cishort;
++ u_char cichar;
++ u_int32_t cilong;
++ ipxcp_options try; /* options to request next time */
++
++#define REJCINETWORK(opt, neg, val) \
++ if (neg &amp;&amp; p[0] == opt) { \
++ if ((len -= CILEN_NETN) &lt; 0) \
++ break; \
++ GETCHAR(citype, p); \
++ GETCHAR(cilen, p); \
++ if (cilen != CILEN_NETN || \
++ citype != opt) \
++ break; \
++ GETLONG(cilong, p); \
++ if (cilong != val) \
++ break; \
++ neg = 0; \
++ }
++
++#define REJCICHARS(opt, neg, val, cnt) \
++ if (neg &amp;&amp; p[0] == opt) { \
++ int indx, count = cnt; \
++ len -= (count + 2); \
++ if (len &lt; 0) \
++ break; \
++ GETCHAR(citype, p); \
++ GETCHAR(cilen, p); \
++ if (cilen != (count + 2) || \
++ citype != opt) \
++ break; \
++ for (indx = 0; indx &lt; count; ++indx) {\
++ GETCHAR(cichar, p); \
++ if (cichar != ((u_char *) &amp;val)[indx]) \
++ break; \
++ }\
++ if (indx != count) \
++ break; \
++ neg = 0; \
++ }
++
++#define REJCINODE(opt,neg,val) REJCICHARS(opt,neg,val,sizeof(val))
++#define REJCINAME(opt,neg,val) REJCICHARS(opt,neg,val,strlen(val))
++
++#define REJCIVOID(opt, neg) \
++ if (neg &amp;&amp; p[0] == opt) { \
++ if ((len -= CILEN_VOID) &lt; 0) \
++ break; \
++ GETCHAR(citype, p); \
++ GETCHAR(cilen, p); \
++ if (cilen != CILEN_VOID || citype != opt) \
++ break; \
++ neg = 0; \
++ }
++
++/* a reject for RIP/SAP is invalid since we don't send it and you can't
++ reject something which is not sent. (You can NAK, but you can't REJ.) */
++#define REJCIPROTO(opt, neg, val, bit) \
++ if (neg &amp;&amp; p[0] == opt) { \
++ if ((len -= CILEN_PROTOCOL) &lt; 0) \
++ break; \
++ GETCHAR(citype, p); \
++ GETCHAR(cilen, p); \
++ if (cilen != CILEN_PROTOCOL) \
++ break; \
++ GETSHORT(cishort, p); \
++ if (cishort != to_external (val) || cishort == RIP_SAP) \
++ break; \
++ neg = 0; \
++ }
++/*
++ * Any Rejected CIs must be in exactly the same order that we sent.
++ * Check packet length and CI length at each step.
++ * If we find any deviations, then this packet is bad.
++ */
++ try = *go;
++
++ do {
++ REJCINETWORK (IPX_NETWORK_NUMBER, try.neg_nn, try.our_network);
++ REJCINODE (IPX_NODE_NUMBER, try.neg_node, try.our_node);
++ REJCINAME (IPX_ROUTER_NAME, try.neg_name, try.name);
++ REJCIPROTO (IPX_ROUTER_PROTOCOL, try.neg_router, try.router, 0);
++/*
++ * This is the end of the record.
++ */
++ if (len == 0) {
++ if (f-&gt;state != OPENED)
++ *go = try;
++ return (1);
++ }
++ } while (0);
++/*
++ * The frame is invalid at this point.
++ */
++ IPXCPDEBUG((&quot;ipxcp_rejci: received bad Reject!&quot;));
++ return 0;
++}
++
++/*
++ * ipxcp_reqci - Check the peer's requested CIs and send appropriate response.
++ *
++ * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
++ * appropriately. If reject_if_disagree is non-zero, doesn't return
++ * CONFNAK; returns CONFREJ if it can't return CONFACK.
++ */
++static int
++ipxcp_reqci(f, inp, len, reject_if_disagree)
++ fsm *f;
++ u_char *inp; /* Requested CIs */
++ int *len; /* Length of requested CIs */
++ int reject_if_disagree;
++{
++ u_char *cip, *next; /* Pointer to current and next CIs */
++ u_short cilen, citype; /* Parsed len, type */
++ u_short cishort; /* Parsed short value */
++ u_int32_t cinetwork; /* Parsed address values */
++ int rc = CONFACK; /* Final packet return code */
++ int orc; /* Individual option return code */
++ u_char *p; /* Pointer to next char to parse */
++ u_char *ucp = inp; /* Pointer to current output char */
++ int l = *len; /* Length left */
++
++ /*
++ * Reset all his options.
++ */
++ BZERO(ho, sizeof(*ho));
++
++ /*
++ * Process all his options.
++ */
++ next = inp;
++ while (l) {
++ orc = CONFACK; /* Assume success */
++ cip = p = next; /* Remember begining of CI */
++ if (l &lt; 2 || /* Not enough data for CI header or */
++ p[1] &lt; 2 || /* CI length too small or */
++ p[1] &gt; l) { /* CI length too big? */
++ IPXCPDEBUG((&quot;ipxcp_reqci: bad CI length!&quot;));
++ orc = CONFREJ; /* Reject bad CI */
++ cilen = l; /* Reject till end of packet */
++ l = 0; /* Don't loop again */
++ goto endswitch;
++ }
++ GETCHAR(citype, p); /* Parse CI type */
++ GETCHAR(cilen, p); /* Parse CI length */
++ l -= cilen; /* Adjust remaining length */
++ next += cilen; /* Step to next CI */
++
++ switch (citype) { /* Check CI type */
++/*
++ * The network number must match. Choose the larger of the two.
++ */
++ case IPX_NETWORK_NUMBER:
++ /* if we wont negotiate the network number or the length is wrong
++ then reject the option */
++ if ( !ao-&gt;neg_nn || cilen != CILEN_NETN ) {
++ orc = CONFREJ;
++ break;
++ }
++ GETLONG(cinetwork, p);
++
++ /* If the network numbers match then acknowledge them. */
++ if (cinetwork != 0) {
++ ho-&gt;his_network = cinetwork;
++ ho-&gt;neg_nn = 1;
++ if (wo-&gt;our_network == cinetwork)
++ break;
++/*
++ * If the network number is not given or we don't accept their change or
++ * the network number is too small then NAK it.
++ */
++ if (! ao-&gt;accept_network || cinetwork &lt; wo-&gt;our_network) {
++ DECPTR (sizeof (u_int32_t), p);
++ PUTLONG (wo-&gt;our_network, p);
++ orc = CONFNAK;
++ }
++ break;
++ }
++/*
++ * The peer sent '0' for the network. Give it ours if we have one.
++ */
++ if (go-&gt;our_network != 0) {
++ DECPTR (sizeof (u_int32_t), p);
++ PUTLONG (wo-&gt;our_network, p);
++ orc = CONFNAK;
++/*
++ * We don't have one. Reject the value.
++ */
++ } else
++ orc = CONFREJ;
++
++ break;
++/*
++ * The node number is required
++ */
++ case IPX_NODE_NUMBER:
++ /* if we wont negotiate the node number or the length is wrong
++ then reject the option */
++ if ( cilen != CILEN_NODEN ) {
++ orc = CONFREJ;
++ break;
++ }
++
++ copy_node (p, ho-&gt;his_node);
++ ho-&gt;neg_node = 1;
++/*
++ * If the remote does not have a number and we do then NAK it with the value
++ * which we have for it. (We never have a default value of zero.)
++ */
++ if (zero_node (ho-&gt;his_node)) {
++ orc = CONFNAK;
++ copy_node (wo-&gt;his_node, p);
++ INCPTR (sizeof (wo-&gt;his_node), p);
++ break;
++ }
++/*
++ * If you have given me the expected network node number then I'll accept
++ * it now.
++ */
++ if (compare_node (wo-&gt;his_node, ho-&gt;his_node)) {
++ orc = CONFACK;
++ ho-&gt;neg_node = 1;
++ INCPTR (sizeof (wo-&gt;his_node), p);
++ break;
++ }
++/*
++ * If his node number is the same as ours then ask him to try the next
++ * value.
++ */
++ if (compare_node (ho-&gt;his_node, go-&gt;our_node)) {
++ inc_node (ho-&gt;his_node);
++ orc = CONFNAK;
++ copy_node (ho-&gt;his_node, p);
++ INCPTR (sizeof (wo-&gt;his_node), p);
++ break;
++ }
++/*
++ * If we don't accept a new value then NAK it.
++ */
++ if (! ao-&gt;accept_remote) {
++ copy_node (wo-&gt;his_node, p);
++ INCPTR (sizeof (wo-&gt;his_node), p);
++ orc = CONFNAK;
++ break;
++ }
++ orc = CONFACK;
++ ho-&gt;neg_node = 1;
++ INCPTR (sizeof (wo-&gt;his_node), p);
++ break;
++/*
++ * Compression is not desired at this time. It is always rejected.
++ */
++ case IPX_COMPRESSION_PROTOCOL:
++ orc = CONFREJ;
++ break;
++/*
++ * The routing protocol is a bitmask of various types. Any combination
++ * of the values RIP_SAP and NLSP are permissible. 'IPX_NONE' for no
++ * routing protocol must be specified only once.
++ */
++ case IPX_ROUTER_PROTOCOL:
++ if ( !ao-&gt;neg_router || cilen &lt; CILEN_PROTOCOL ) {
++ orc = CONFREJ;
++ break;
++ }
++
++ GETSHORT (cishort, p);
++
++ if (wo-&gt;neg_router == 0) {
++ wo-&gt;neg_router = 1;
++ wo-&gt;router = BIT(IPX_NONE);
++ }
++
++ if ((cishort == IPX_NONE &amp;&amp; ho-&gt;router != 0) ||
++ (ho-&gt;router &amp; BIT(IPX_NONE))) {
++ orc = CONFREJ;
++ break;
++ }
++
++ cishort = BIT(cishort);
++ if (ho-&gt;router &amp; cishort) {
++ orc = CONFREJ;
++ break;
++ }
++
++ ho-&gt;router |= cishort;
++ ho-&gt;neg_router = 1;
++
++ /* Finally do not allow a router protocol which we do not
++ support. */
++
++ if ((cishort &amp; (ao-&gt;router | BIT(IPX_NONE))) == 0) {
++ int protocol;
++
++ if (cishort == BIT(NLSP) &amp;&amp;
++ (ao-&gt;router &amp; BIT(RIP_SAP)) &amp;&amp;
++ !wo-&gt;tried_rip) {
++ protocol = RIP_SAP;
++ wo-&gt;tried_rip = 1;
++ } else
++ protocol = IPX_NONE;
++
++ DECPTR (sizeof (u_int16_t), p);
++ PUTSHORT (protocol, p);
++ orc = CONFNAK;
++ }
++ break;
++/*
++ * The router name is advisorary. Just accept it if it is not too large.
++ */
++ case IPX_ROUTER_NAME:
++ if (cilen &gt;= CILEN_NAME) {
++ int name_size = cilen - CILEN_NAME;
++ if (name_size &gt; sizeof (ho-&gt;name))
++ name_size = sizeof (ho-&gt;name) - 1;
++ memset (ho-&gt;name, 0, sizeof (ho-&gt;name));
++ memcpy (ho-&gt;name, p, name_size);
++ ho-&gt;name [name_size] = '\0';
++ ho-&gt;neg_name = 1;
++ orc = CONFACK;
++ break;
++ }
++ orc = CONFREJ;
++ break;
++/*
++ * This is advisorary.
++ */
++ case IPX_COMPLETE:
++ if (cilen != CILEN_COMPLETE)
++ orc = CONFREJ;
++ else {
++ ho-&gt;neg_complete = 1;
++ orc = CONFACK;
++ }
++ break;
++/*
++ * All other entries are not known at this time.
++ */
++ default:
++ orc = CONFREJ;
++ break;
++ }
++endswitch:
++ if (orc == CONFACK &amp;&amp; /* Good CI */
++ rc != CONFACK) /* but prior CI wasnt? */
++ continue; /* Don't send this one */
++
++ if (orc == CONFNAK) { /* Nak this CI? */
++ if (reject_if_disagree) /* Getting fed up with sending NAKs? */
++ orc = CONFREJ; /* Get tough if so */
++ if (rc == CONFREJ) /* Rejecting prior CI? */
++ continue; /* Don't send this one */
++ if (rc == CONFACK) { /* Ack'd all prior CIs? */
++ rc = CONFNAK; /* Not anymore... */
++ ucp = inp; /* Backup */
++ }
++ }
++
++ if (orc == CONFREJ &amp;&amp; /* Reject this CI */
++ rc != CONFREJ) { /* but no prior ones? */
++ rc = CONFREJ;
++ ucp = inp; /* Backup */
++ }
++
++ /* Need to move CI? */
++ if (ucp != cip)
++ BCOPY(cip, ucp, cilen); /* Move it */
++
++ /* Update output pointer */
++ INCPTR(cilen, ucp);
++ }
++
++ /*
++ * If we aren't rejecting this packet, and we want to negotiate
++ * their address, and they didn't send their address, then we
++ * send a NAK with a IPX_NODE_NUMBER option appended. We assume the
++ * input buffer is long enough that we can append the extra
++ * option safely.
++ */
++
++ if (rc != CONFREJ &amp;&amp; !ho-&gt;neg_node &amp;&amp;
++ wo-&gt;req_nn &amp;&amp; !reject_if_disagree) {
++ if (rc == CONFACK) {
++ rc = CONFNAK;
++ wo-&gt;req_nn = 0; /* don't ask again */
++ ucp = inp; /* reset pointer */
++ }
++
++ if (zero_node (wo-&gt;his_node))
++ inc_node (wo-&gt;his_node);
++
++ PUTCHAR (IPX_NODE_NUMBER, ucp);
++ PUTCHAR (CILEN_NODEN, ucp);
++ copy_node (wo-&gt;his_node, ucp);
++ INCPTR (sizeof (wo-&gt;his_node), ucp);
++ }
++
++ *len = ucp - inp; /* Compute output length */
++ IPXCPDEBUG((&quot;ipxcp: returning Configure-%s&quot;, CODENAME(rc)));
++ return (rc); /* Return final code */
++}
++
++/*
++ * ipxcp_up - IPXCP has come UP.
++ *
++ * Configure the IP network interface appropriately and bring it up.
++ */
++
++static void
++ipxcp_up(f)
++ fsm *f;
++{
++ int unit = f-&gt;unit;
++
++ IPXCPDEBUG((&quot;ipxcp: up&quot;));
++
++ /* The default router protocol is RIP/SAP. */
++ if (ho-&gt;router == 0)
++ ho-&gt;router = BIT(RIP_SAP);
++
++ if (go-&gt;router == 0)
++ go-&gt;router = BIT(RIP_SAP);
++
++ /* Fetch the network number */
++ if (!ho-&gt;neg_nn)
++ ho-&gt;his_network = wo-&gt;his_network;
++
++ if (!ho-&gt;neg_node)
++ copy_node (wo-&gt;his_node, ho-&gt;his_node);
++
++ if (!wo-&gt;neg_node &amp;&amp; !go-&gt;neg_node)
++ copy_node (wo-&gt;our_node, go-&gt;our_node);
++
++ if (zero_node (go-&gt;our_node)) {
++ static char errmsg[] = &quot;Could not determine local IPX node address&quot;;
++ if (debug)
++ error(errmsg);
++ ipxcp_close(f-&gt;unit, errmsg);
++ return;
++ }
++
++ go-&gt;network = go-&gt;our_network;
++ if (ho-&gt;his_network != 0 &amp;&amp; ho-&gt;his_network &gt; go-&gt;network)
++ go-&gt;network = ho-&gt;his_network;
++
++ if (go-&gt;network == 0) {
++ static char errmsg[] = &quot;Can not determine network number&quot;;
++ if (debug)
++ error(errmsg);
++ ipxcp_close (unit, errmsg);
++ return;
++ }
++
++ /* bring the interface up */
++ if (!sifup(unit)) {
++ if (debug)
++ warn(&quot;sifup failed (IPX)&quot;);
++ ipxcp_close(unit, &quot;Interface configuration failed&quot;);
++ return;
++ }
++ ipxcp_is_up = 1;
++
++ /* set the network number for IPX */
++ if (!sipxfaddr(unit, go-&gt;network, go-&gt;our_node)) {
++ if (debug)
++ warn(&quot;sipxfaddr failed&quot;);
++ ipxcp_close(unit, &quot;Interface configuration failed&quot;);
++ return;
++ }
++
++ np_up(f-&gt;unit, PPP_IPX);
++
++ /*
++ * Execute the ipx-up script, like this:
++ * /etc/ppp/ipx-up interface tty speed local-IPX remote-IPX
++ */
++
++ ipxcp_script (f, _PATH_IPXUP);
++}
++
++/*
++ * ipxcp_down - IPXCP has gone DOWN.
++ *
++ * Take the IP network interface down, clear its addresses
++ * and delete routes through it.
++ */
++
++static void
++ipxcp_down(f)
++ fsm *f;
++{
++ IPXCPDEBUG((&quot;ipxcp: down&quot;));
++
++ if (!ipxcp_is_up)
++ return;
++ ipxcp_is_up = 0;
++ np_down(f-&gt;unit, PPP_IPX);
++ cipxfaddr(f-&gt;unit);
++ sifnpmode(f-&gt;unit, PPP_IPX, NPMODE_DROP);
++ sifdown(f-&gt;unit);
++ ipxcp_script (f, _PATH_IPXDOWN);
++}
++
++
++/*
++ * ipxcp_finished - possibly shut down the lower layers.
++ */
++static void
++ipxcp_finished(f)
++ fsm *f;
++{
++ np_finished(f-&gt;unit, PPP_IPX);
++}
++
++
++/*
++ * ipxcp_script - Execute a script with arguments
++ * interface-name tty-name speed local-IPX remote-IPX networks.
++ */
++static void
++ipxcp_script(f, script)
++ fsm *f;
++ char *script;
++{
++ char strspeed[32], strlocal[32], strremote[32];
++ char strnetwork[32], strpid[32];
++ char *argv[14], strproto_lcl[32], strproto_rmt[32];
++
++ slprintf(strpid, sizeof(strpid), &quot;%d&quot;, getpid());
++ slprintf(strspeed, sizeof(strspeed),&quot;%d&quot;, baud_rate);
++
++ strproto_lcl[0] = '\0';
++ if (go-&gt;neg_router &amp;&amp; ((go-&gt;router &amp; BIT(IPX_NONE)) == 0)) {
++ if (go-&gt;router &amp; BIT(RIP_SAP))
++ strlcpy (strproto_lcl, &quot;RIP &quot;, sizeof(strproto_lcl));
++ if (go-&gt;router &amp; BIT(NLSP))
++ strlcat (strproto_lcl, &quot;NLSP &quot;, sizeof(strproto_lcl));
++ }
++
++ if (strproto_lcl[0] == '\0')
++ strlcpy (strproto_lcl, &quot;NONE &quot;, sizeof(strproto_lcl));
++
++ strproto_lcl[strlen (strproto_lcl)-1] = '\0';
++
++ strproto_rmt[0] = '\0';
++ if (ho-&gt;neg_router &amp;&amp; ((ho-&gt;router &amp; BIT(IPX_NONE)) == 0)) {
++ if (ho-&gt;router &amp; BIT(RIP_SAP))
++ strlcpy (strproto_rmt, &quot;RIP &quot;, sizeof(strproto_rmt));
++ if (ho-&gt;router &amp; BIT(NLSP))
++ strlcat (strproto_rmt, &quot;NLSP &quot;, sizeof(strproto_rmt));
++ }
++
++ if (strproto_rmt[0] == '\0')
++ strlcpy (strproto_rmt, &quot;NONE &quot;, sizeof(strproto_rmt));
++
++ strproto_rmt[strlen (strproto_rmt)-1] = '\0';
++
++ strlcpy (strnetwork, ipx_ntoa (go-&gt;network), sizeof(strnetwork));
++
++ slprintf (strlocal, sizeof(strlocal), &quot;%0.6B&quot;, go-&gt;our_node);
++
++ slprintf (strremote, sizeof(strremote), &quot;%0.6B&quot;, ho-&gt;his_node);
++
++ argv[0] = script;
++ argv[1] = ifname;
++ argv[2] = devnam;
++ argv[3] = strspeed;
++ argv[4] = strnetwork;
++ argv[5] = strlocal;
++ argv[6] = strremote;
++ argv[7] = strproto_lcl;
++ argv[8] = strproto_rmt;
++ argv[9] = go-&gt;name;
++ argv[10] = ho-&gt;name;
++ argv[11] = ipparam;
++ argv[12] = strpid;
++ argv[13] = NULL;
++ run_program(script, argv, 0, NULL, NULL);
++}
++
++/*
++ * ipxcp_printpkt - print the contents of an IPXCP packet.
++ */
++static char *ipxcp_codenames[] = {
++ &quot;ConfReq&quot;, &quot;ConfAck&quot;, &quot;ConfNak&quot;, &quot;ConfRej&quot;,
++ &quot;TermReq&quot;, &quot;TermAck&quot;, &quot;CodeRej&quot;
++};
++
++static int
++ipxcp_printpkt(p, plen, printer, arg)
++ u_char *p;
++ int plen;
++ void (*printer) __P((void *, char *, ...));
++ void *arg;
++{
++ int code, id, len, olen;
++ u_char *pstart, *optend;
++ u_short cishort;
++ u_int32_t cilong;
++
++ if (plen &lt; HEADERLEN)
++ return 0;
++ pstart = p;
++ GETCHAR(code, p);
++ GETCHAR(id, p);
++ GETSHORT(len, p);
++ if (len &lt; HEADERLEN || len &gt; plen)
++ return 0;
++
++ if (code &gt;= 1 &amp;&amp; code &lt;= sizeof(ipxcp_codenames) / sizeof(char *))
++ printer(arg, &quot; %s&quot;, ipxcp_codenames[code-1]);
++ else
++ printer(arg, &quot; code=0x%x&quot;, code);
++ printer(arg, &quot; id=0x%x&quot;, id);
++ len -= HEADERLEN;
++ switch (code) {
++ case CONFREQ:
++ case CONFACK:
++ case CONFNAK:
++ case CONFREJ:
++ /* print option list */
++ while (len &gt;= 2) {
++ GETCHAR(code, p);
++ GETCHAR(olen, p);
++ p -= 2;
++ if (olen &lt; CILEN_VOID || olen &gt; len) {
++ break;
++ }
++ printer(arg, &quot; &lt;&quot;);
++ len -= olen;
++ optend = p + olen;
++ switch (code) {
++ case IPX_NETWORK_NUMBER:
++ if (olen == CILEN_NETN) {
++ p += 2;
++ GETLONG(cilong, p);
++ printer (arg, &quot;network %s&quot;, ipx_ntoa (cilong));
++ }
++ break;
++ case IPX_NODE_NUMBER:
++ if (olen == CILEN_NODEN) {
++ p += 2;
++ printer (arg, &quot;node &quot;);
++ while (p &lt; optend) {
++ GETCHAR(code, p);
++ printer(arg, &quot;%.2x&quot;, (int) (unsigned int) (unsigned char) code);
++ }
++ }
++ break;
++ case IPX_COMPRESSION_PROTOCOL:
++ if (olen == CILEN_COMPRESS) {
++ p += 2;
++ GETSHORT (cishort, p);
++ printer (arg, &quot;compression %d&quot;, (int) cishort);
++ }
++ break;
++ case IPX_ROUTER_PROTOCOL:
++ if (olen == CILEN_PROTOCOL) {
++ p += 2;
++ GETSHORT (cishort, p);
++ printer (arg, &quot;router proto %d&quot;, (int) cishort);
++ }
++ break;
++ case IPX_ROUTER_NAME:
++ if (olen &gt;= CILEN_NAME) {
++ p += 2;
++ printer (arg, &quot;router name \&quot;&quot;);
++ while (p &lt; optend) {
++ GETCHAR(code, p);
++ if (code &gt;= 0x20 &amp;&amp; code &lt;= 0x7E)
++ printer (arg, &quot;%c&quot;, (int) (unsigned int) (unsigned char) code);
++ else
++ printer (arg, &quot; \\%.2x&quot;, (int) (unsigned int) (unsigned char) code);
++ }
++ printer (arg, &quot;\&quot;&quot;);
++ }
++ break;
++ case IPX_COMPLETE:
++ if (olen == CILEN_COMPLETE) {
++ p += 2;
++ printer (arg, &quot;complete&quot;);
++ }
++ break;
++ default:
++ break;
++ }
++
++ while (p &lt; optend) {
++ GETCHAR(code, p);
++ printer(arg, &quot; %.2x&quot;, (int) (unsigned int) (unsigned char) code);
++ }
++ printer(arg, &quot;&gt;&quot;);
++ }
++ break;
++
++ case TERMACK:
++ case TERMREQ:
++ if (len &gt; 0 &amp;&amp; *p &gt;= ' ' &amp;&amp; *p &lt; 0x7f) {
++ printer(arg, &quot; &quot;);
++ print_string(p, len, printer, arg);
++ p += len;
++ len = 0;
++ }
++ break;
++ }
++
++ /* print the rest of the bytes in the packet */
++ for (; len &gt; 0; --len) {
++ GETCHAR(code, p);
++ printer(arg, &quot; %.2x&quot;, (int) (unsigned int) (unsigned char) code);
++ }
++
++ return p - pstart;
++}
++#endif /* ifdef IPX_CHANGE */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/ipxcp.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/ipxcp.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/ipxcp.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/ipxcp.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,71 @@
++/*
++ * ipxcp.h - IPX Control Protocol definitions.
++ *
++ * Copyright (c) 1989 Carnegie Mellon University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by Carnegie Mellon University. The name of the
++ * University may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * $Id: ipxcp.h 195720 2001-06-11 11:44:34Z gc $
++ */
++
++/*
++ * Options.
++ */
++#define IPX_NETWORK_NUMBER 1 /* IPX Network Number */
++#define IPX_NODE_NUMBER 2
++#define IPX_COMPRESSION_PROTOCOL 3
++#define IPX_ROUTER_PROTOCOL 4
++#define IPX_ROUTER_NAME 5
++#define IPX_COMPLETE 6
++
++/* Values for the router protocol */
++#define IPX_NONE 0
++#define RIP_SAP 2
++#define NLSP 4
++
++typedef struct ipxcp_options {
++ bool neg_node; /* Negotiate IPX node number? */
++ bool req_node; /* Ask peer to send IPX node number? */
++
++ bool neg_nn; /* Negotiate IPX network number? */
++ bool req_nn; /* Ask peer to send IPX network number */
++
++ bool neg_name; /* Negotiate IPX router name */
++ bool neg_complete; /* Negotiate completion */
++ bool neg_router; /* Negotiate IPX router number */
++
++ bool accept_local; /* accept peer's value for ournode */
++ bool accept_remote; /* accept peer's value for hisnode */
++ bool accept_network; /* accept network number */
++
++ bool tried_nlsp; /* I have suggested NLSP already */
++ bool tried_rip; /* I have suggested RIP/SAP already */
++
++ u_int32_t his_network; /* base network number */
++ u_int32_t our_network; /* our value for network number */
++ u_int32_t network; /* the final network number */
++
++ u_char his_node[6]; /* peer's node number */
++ u_char our_node[6]; /* our node number */
++ u_char name [48]; /* name of the router */
++ int router; /* routing protocol */
++} ipxcp_options;
++
++extern fsm ipxcp_fsm[];
++extern ipxcp_options ipxcp_wantoptions[];
++extern ipxcp_options ipxcp_gotoptions[];
++extern ipxcp_options ipxcp_allowoptions[];
++extern ipxcp_options ipxcp_hisoptions[];
++
++extern struct protent ipxcp_protent;
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/ipxcp.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/lcp.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/lcp.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/lcp.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,2224 @@
++/*
++ * lcp.c - PPP Link Control Protocol.
++ *
++ * Copyright (c) 1989 Carnegie Mellon University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by Carnegie Mellon University. The name of the
++ * University may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ */
++
++#define RCSID &quot;$Id: lcp.c 195720 2001-06-11 11:44:34Z gc $&quot;
++
++/*
++ * TODO:
++ */
++
++#include &lt;stdio.h&gt;
++#include &lt;string.h&gt;
++#include &lt;stdlib.h&gt;
++
++#include &quot;pppd.h&quot;
++#include &quot;fsm.h&quot;
++#include &quot;lcp.h&quot;
++#include &quot;chap.h&quot;
++#include &quot;magic.h&quot;
++
++static const char rcsid[] = RCSID;
++
++/*
++ * When the link comes up we want to be able to wait for a short while,
++ * or until seeing some input from the peer, before starting to send
++ * configure-requests. We do this by delaying the fsm_lowerup call.
++ */
++/* steal a bit in fsm flags word */
++#define DELAYED_UP 0x100
++
++static void lcp_delayed_up __P((void *));
++
++/*
++ * LCP-related command-line options.
++ */
++int lcp_echo_interval = 0; /* Interval between LCP echo-requests */
++int lcp_echo_fails = 0; /* Tolerance to unanswered echo-requests */
++bool lax_recv = 0; /* accept control chars in asyncmap */
++bool noendpoint = 0; /* don't send/accept endpoint discriminator */
++
++static int noopt __P((char **));
++
++#ifdef HAVE_MULTILINK
++static int setendpoint __P((char **));
++static void printendpoint __P((option_t *, void (*)(void *, char *, ...),
++ void *));
++#endif /* HAVE_MULTILINK */
++
++static option_t lcp_option_list[] = {
++ /* LCP options */
++ { &quot;-all&quot;, o_special_noarg, (void *)noopt,
++ &quot;Don't request/allow any LCP options&quot; },
++
++ { &quot;noaccomp&quot;, o_bool, &amp;lcp_wantoptions[0].neg_accompression,
++ &quot;Disable address/control compression&quot;,
++ OPT_A2CLR, &amp;lcp_allowoptions[0].neg_accompression },
++ { &quot;-ac&quot;, o_bool, &amp;lcp_wantoptions[0].neg_accompression,
++ &quot;Disable address/control compression&quot;,
++ OPT_ALIAS | OPT_A2CLR, &amp;lcp_allowoptions[0].neg_accompression },
++
++ { &quot;asyncmap&quot;, o_uint32, &amp;lcp_wantoptions[0].asyncmap,
++ &quot;Set asyncmap (for received packets)&quot;,
++ OPT_OR, &amp;lcp_wantoptions[0].neg_asyncmap },
++ { &quot;-as&quot;, o_uint32, &amp;lcp_wantoptions[0].asyncmap,
++ &quot;Set asyncmap (for received packets)&quot;,
++ OPT_ALIAS | OPT_OR, &amp;lcp_wantoptions[0].neg_asyncmap },
++ { &quot;default-asyncmap&quot;, o_uint32, &amp;lcp_wantoptions[0].asyncmap,
++ &quot;Disable asyncmap negotiation&quot;,
++ OPT_OR | OPT_NOARG | OPT_VAL(~0U) | OPT_A2CLR,
++ &amp;lcp_allowoptions[0].neg_asyncmap },
++ { &quot;-am&quot;, o_uint32, &amp;lcp_wantoptions[0].asyncmap,
++ &quot;Disable asyncmap negotiation&quot;,
++ OPT_ALIAS | OPT_OR | OPT_NOARG | OPT_VAL(~0U) | OPT_A2CLR,
++ &amp;lcp_allowoptions[0].neg_asyncmap },
++
++ { &quot;nomagic&quot;, o_bool, &amp;lcp_wantoptions[0].neg_magicnumber,
++ &quot;Disable magic number negotiation (looped-back line detection)&quot;,
++ OPT_A2CLR, &amp;lcp_allowoptions[0].neg_magicnumber },
++ { &quot;-mn&quot;, o_bool, &amp;lcp_wantoptions[0].neg_magicnumber,
++ &quot;Disable magic number negotiation (looped-back line detection)&quot;,
++ OPT_ALIAS | OPT_A2CLR, &amp;lcp_allowoptions[0].neg_magicnumber },
++
++ { &quot;mru&quot;, o_int, &amp;lcp_wantoptions[0].mru,
++ &quot;Set MRU (maximum received packet size) for negotiation&quot;,
++ OPT_PRIO, &amp;lcp_wantoptions[0].neg_mru },
++ { &quot;default-mru&quot;, o_bool, &amp;lcp_wantoptions[0].neg_mru,
++ &quot;Disable MRU negotiation (use default 1500)&quot;,
++ OPT_PRIOSUB | OPT_A2CLR, &amp;lcp_allowoptions[0].neg_mru },
++ { &quot;-mru&quot;, o_bool, &amp;lcp_wantoptions[0].neg_mru,
++ &quot;Disable MRU negotiation (use default 1500)&quot;,
++ OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR, &amp;lcp_allowoptions[0].neg_mru },
++
++ { &quot;mtu&quot;, o_int, &amp;lcp_allowoptions[0].mru,
++ &quot;Set our MTU&quot;, OPT_LIMITS, NULL, MAXMRU, MINMRU },
++
++ { &quot;nopcomp&quot;, o_bool, &amp;lcp_wantoptions[0].neg_pcompression,
++ &quot;Disable protocol field compression&quot;,
++ OPT_A2CLR, &amp;lcp_allowoptions[0].neg_pcompression },
++ { &quot;-pc&quot;, o_bool, &amp;lcp_wantoptions[0].neg_pcompression,
++ &quot;Disable protocol field compression&quot;,
++ OPT_ALIAS | OPT_A2CLR, &amp;lcp_allowoptions[0].neg_pcompression },
++
++ { &quot;passive&quot;, o_bool, &amp;lcp_wantoptions[0].passive,
++ &quot;Set passive mode&quot;, 1 },
++ { &quot;-p&quot;, o_bool, &amp;lcp_wantoptions[0].passive,
++ &quot;Set passive mode&quot;, OPT_ALIAS | 1 },
++
++ { &quot;silent&quot;, o_bool, &amp;lcp_wantoptions[0].silent,
++ &quot;Set silent mode&quot;, 1 },
++
++ { &quot;lcp-echo-failure&quot;, o_int, &amp;lcp_echo_fails,
++ &quot;Set number of consecutive echo failures to indicate link failure&quot;,
++ OPT_PRIO },
++ { &quot;lcp-echo-interval&quot;, o_int, &amp;lcp_echo_interval,
++ &quot;Set time in seconds between LCP echo requests&quot;, OPT_PRIO },
++ { &quot;lcp-restart&quot;, o_int, &amp;lcp_fsm[0].timeouttime,
++ &quot;Set time in seconds between LCP retransmissions&quot;, OPT_PRIO },
++ { &quot;lcp-max-terminate&quot;, o_int, &amp;lcp_fsm[0].maxtermtransmits,
++ &quot;Set maximum number of LCP terminate-request transmissions&quot;, OPT_PRIO },
++ { &quot;lcp-max-configure&quot;, o_int, &amp;lcp_fsm[0].maxconfreqtransmits,
++ &quot;Set maximum number of LCP configure-request transmissions&quot;, OPT_PRIO },
++ { &quot;lcp-max-failure&quot;, o_int, &amp;lcp_fsm[0].maxnakloops,
++ &quot;Set limit on number of LCP configure-naks&quot;, OPT_PRIO },
++
++ { &quot;receive-all&quot;, o_bool, &amp;lax_recv,
++ &quot;Accept all received control characters&quot;, 1 },
++
++#ifdef HAVE_MULTILINK
++ { &quot;mrru&quot;, o_int, &amp;lcp_wantoptions[0].mrru,
++ &quot;Maximum received packet size for multilink bundle&quot;,
++ OPT_PRIO, &amp;lcp_wantoptions[0].neg_mrru },
++
++ { &quot;mpshortseq&quot;, o_bool, &amp;lcp_wantoptions[0].neg_ssnhf,
++ &quot;Use short sequence numbers in multilink headers&quot;,
++ OPT_PRIO | 1, &amp;lcp_allowoptions[0].neg_ssnhf },
++ { &quot;nompshortseq&quot;, o_bool, &amp;lcp_wantoptions[0].neg_ssnhf,
++ &quot;Don't use short sequence numbers in multilink headers&quot;,
++ OPT_PRIOSUB | OPT_A2CLR, &amp;lcp_allowoptions[0].neg_ssnhf },
++
++ { &quot;endpoint&quot;, o_special, (void *) setendpoint,
++ &quot;Endpoint discriminator for multilink&quot;,
++ OPT_PRIO | OPT_A2PRINTER, (void *) printendpoint },
++#endif /* HAVE_MULTILINK */
++
++ { &quot;noendpoint&quot;, o_bool, &amp;noendpoint,
++ &quot;Don't send or accept multilink endpoint discriminator&quot;, 1 },
++
++ {NULL}
++};
++
++/* global vars */
++fsm lcp_fsm[NUM_PPP]; /* LCP fsm structure (global)*/
++lcp_options lcp_wantoptions[NUM_PPP]; /* Options that we want to request */
++lcp_options lcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */
++lcp_options lcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */
++lcp_options lcp_hisoptions[NUM_PPP]; /* Options that we ack'd */
++
++static int lcp_echos_pending = 0; /* Number of outstanding echo msgs */
++static int lcp_echo_number = 0; /* ID number of next echo frame */
++static int lcp_echo_timer_running = 0; /* set if a timer is running */
++
++static u_char nak_buffer[PPP_MRU]; /* where we construct a nak packet */
++
++/*
++ * Callbacks for fsm code. (CI = Configuration Information)
++ */
++static void lcp_resetci __P((fsm *)); /* Reset our CI */
++static int lcp_cilen __P((fsm *)); /* Return length of our CI */
++static void lcp_addci __P((fsm *, u_char *, int *)); /* Add our CI to pkt */
++static int lcp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */
++static int lcp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */
++static int lcp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */
++static int lcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv peer CI */
++static void lcp_up __P((fsm *)); /* We're UP */
++static void lcp_down __P((fsm *)); /* We're DOWN */
++static void lcp_starting __P((fsm *)); /* We need lower layer up */
++static void lcp_finished __P((fsm *)); /* We need lower layer down */
++static int lcp_extcode __P((fsm *, int, int, u_char *, int));
++static void lcp_rprotrej __P((fsm *, u_char *, int));
++
++/*
++ * routines to send LCP echos to peer
++ */
++
++static void lcp_echo_lowerup __P((int));
++static void lcp_echo_lowerdown __P((int));
++static void LcpEchoTimeout __P((void *));
++static void lcp_received_echo_reply __P((fsm *, int, u_char *, int));
++static void LcpSendEchoRequest __P((fsm *));
++static void LcpLinkFailure __P((fsm *));
++static void LcpEchoCheck __P((fsm *));
++
++static fsm_callbacks lcp_callbacks = { /* LCP callback routines */
++ lcp_resetci, /* Reset our Configuration Information */
++ lcp_cilen, /* Length of our Configuration Information */
++ lcp_addci, /* Add our Configuration Information */
++ lcp_ackci, /* ACK our Configuration Information */
++ lcp_nakci, /* NAK our Configuration Information */
++ lcp_rejci, /* Reject our Configuration Information */
++ lcp_reqci, /* Request peer's Configuration Information */
++ lcp_up, /* Called when fsm reaches OPENED state */
++ lcp_down, /* Called when fsm leaves OPENED state */
++ lcp_starting, /* Called when we want the lower layer up */
++ lcp_finished, /* Called when we want the lower layer down */
++ NULL, /* Called when Protocol-Reject received */
++ NULL, /* Retransmission is necessary */
++ lcp_extcode, /* Called to handle LCP-specific codes */
++ &quot;LCP&quot; /* String name of protocol */
++};
++
++/*
++ * Protocol entry points.
++ * Some of these are called directly.
++ */
++
++static void lcp_init __P((int));
++static void lcp_input __P((int, u_char *, int));
++static void lcp_protrej __P((int));
++static int lcp_printpkt __P((u_char *, int,
++ void (*) __P((void *, char *, ...)), void *));
++
++struct protent lcp_protent = {
++ PPP_LCP,
++ lcp_init,
++ lcp_input,
++ lcp_protrej,
++ lcp_lowerup,
++ lcp_lowerdown,
++ lcp_open,
++ lcp_close,
++ lcp_printpkt,
++ NULL,
++ 1,
++ &quot;LCP&quot;,
++ NULL,
++ lcp_option_list,
++ NULL,
++ NULL,
++ NULL
++};
++
++int lcp_loopbackfail = DEFLOOPBACKFAIL;
++
++/*
++ * Length of each type of configuration option (in octets)
++ */
++#define CILEN_VOID 2
++#define CILEN_CHAR 3
++#define CILEN_SHORT 4 /* CILEN_VOID + 2 */
++#define CILEN_CHAP 5 /* CILEN_VOID + 2 + 1 */
++#define CILEN_LONG 6 /* CILEN_VOID + 4 */
++#define CILEN_LQR 8 /* CILEN_VOID + 2 + 4 */
++#define CILEN_CBCP 3
++
++#define CODENAME(x) ((x) == CONFACK ? &quot;ACK&quot; : \
++ (x) == CONFNAK ? &quot;NAK&quot; : &quot;REJ&quot;)
++
++/*
++ * noopt - Disable all options (why?).
++ */
++static int
++noopt(argv)
++ char **argv;
++{
++ BZERO((char *) &amp;lcp_wantoptions[0], sizeof (struct lcp_options));
++ BZERO((char *) &amp;lcp_allowoptions[0], sizeof (struct lcp_options));
++
++ return (1);
++}
++
++#ifdef HAVE_MULTILINK
++static int
++setendpoint(argv)
++ char **argv;
++{
++ if (str_to_epdisc(&amp;lcp_wantoptions[0].endpoint, *argv)) {
++ lcp_wantoptions[0].neg_endpoint = 1;
++ return 1;
++ }
++ option_error(&quot;Can't parse '%s' as an endpoint discriminator&quot;, *argv);
++ return 0;
++}
++
++static void
++printendpoint(opt, printer, arg)
++ option_t *opt;
++ void (*printer) __P((void *, char *, ...));
++ void *arg;
++{
++ printer(arg, &quot;%s&quot;, epdisc_to_str(&amp;lcp_wantoptions[0].endpoint));
++}
++#endif /* HAVE_MULTILINK */
++
++/*
++ * lcp_init - Initialize LCP.
++ */
++static void
++lcp_init(unit)
++ int unit;
++{
++ fsm *f = &amp;lcp_fsm[unit];
++ lcp_options *wo = &amp;lcp_wantoptions[unit];
++ lcp_options *ao = &amp;lcp_allowoptions[unit];
++
++ f-&gt;unit = unit;
++ f-&gt;protocol = PPP_LCP;
++ f-&gt;callbacks = &amp;lcp_callbacks;
++
++ fsm_init(f);
++
++ BZERO(wo, sizeof(*wo));
++ wo-&gt;neg_mru = 1;
++ wo-&gt;mru = DEFMRU;
++ wo-&gt;neg_asyncmap = 1;
++ wo-&gt;chap_mdtype = CHAP_DIGEST_MD5;
++ wo-&gt;neg_magicnumber = 1;
++ wo-&gt;neg_pcompression = 1;
++ wo-&gt;neg_accompression = 1;
++
++ BZERO(ao, sizeof(*ao));
++ ao-&gt;neg_mru = 1;
++ ao-&gt;mru = MAXMRU;
++ ao-&gt;neg_asyncmap = 1;
++ ao-&gt;neg_chap = 1;
++ ao-&gt;chap_mdtype = CHAP_DIGEST_MD5;
++ ao-&gt;neg_upap = 1;
++ ao-&gt;neg_magicnumber = 1;
++ ao-&gt;neg_pcompression = 1;
++ ao-&gt;neg_accompression = 1;
++#ifdef CBCP_SUPPORT
++ ao-&gt;neg_cbcp = 1;
++#endif
++ ao-&gt;neg_endpoint = 1;
++}
++
++
++/*
++ * lcp_open - LCP is allowed to come up.
++ */
++void
++lcp_open(unit)
++ int unit;
++{
++ fsm *f = &amp;lcp_fsm[unit];
++ lcp_options *wo = &amp;lcp_wantoptions[unit];
++
++ f-&gt;flags &amp;= ~(OPT_PASSIVE | OPT_SILENT);
++ if (wo-&gt;passive)
++ f-&gt;flags |= OPT_PASSIVE;
++ if (wo-&gt;silent)
++ f-&gt;flags |= OPT_SILENT;
++ fsm_open(f);
++}
++
++
++/*
++ * lcp_close - Take LCP down.
++ */
++void
++lcp_close(unit, reason)
++ int unit;
++ char *reason;
++{
++ fsm *f = &amp;lcp_fsm[unit];
++
++ if (phase != PHASE_DEAD)
++ new_phase(PHASE_TERMINATE);
++ if (f-&gt;state == STOPPED &amp;&amp; f-&gt;flags &amp; (OPT_PASSIVE|OPT_SILENT)) {
++ /*
++ * This action is not strictly according to the FSM in RFC1548,
++ * but it does mean that the program terminates if you do a
++ * lcp_close() in passive/silent mode when a connection hasn't
++ * been established.
++ */
++ f-&gt;state = CLOSED;
++ lcp_finished(f);
++
++ } else
++ fsm_close(&amp;lcp_fsm[unit], reason);
++}
++
++
++/*
++ * lcp_lowerup - The lower layer is up.
++ */
++void
++lcp_lowerup(unit)
++ int unit;
++{
++ lcp_options *wo = &amp;lcp_wantoptions[unit];
++ fsm *f = &amp;lcp_fsm[unit];
++
++ /*
++ * Don't use A/C or protocol compression on transmission,
++ * but accept A/C and protocol compressed packets
++ * if we are going to ask for A/C and protocol compression.
++ */
++ ppp_send_config(unit, PPP_MRU, 0xffffffff, 0, 0);
++ ppp_recv_config(unit, PPP_MRU, (lax_recv? 0: 0xffffffff),
++ wo-&gt;neg_pcompression, wo-&gt;neg_accompression);
++ peer_mru[unit] = PPP_MRU;
++
++ if (listen_time != 0) {
++ f-&gt;flags |= DELAYED_UP;
++ timeout(lcp_delayed_up, f, 0, listen_time * 1000);
++ } else
++ fsm_lowerup(f);
++}
++
++
++/*
++ * lcp_lowerdown - The lower layer is down.
++ */
++void
++lcp_lowerdown(unit)
++ int unit;
++{
++ fsm *f = &amp;lcp_fsm[unit];
++
++ if (f-&gt;flags &amp; DELAYED_UP)
++ f-&gt;flags &amp;= ~DELAYED_UP;
++ else
++ fsm_lowerdown(&amp;lcp_fsm[unit]);
++}
++
++
++/*
++ * lcp_delayed_up - Bring the lower layer up now.
++ */
++static void
++lcp_delayed_up(arg)
++ void *arg;
++{
++ fsm *f = arg;
++
++ if (f-&gt;flags &amp; DELAYED_UP) {
++ f-&gt;flags &amp;= ~DELAYED_UP;
++ fsm_lowerup(f);
++ }
++}
++
++
++/*
++ * lcp_input - Input LCP packet.
++ */
++static void
++lcp_input(unit, p, len)
++ int unit;
++ u_char *p;
++ int len;
++{
++ fsm *f = &amp;lcp_fsm[unit];
++
++ if (f-&gt;flags &amp; DELAYED_UP) {
++ f-&gt;flags &amp;= ~DELAYED_UP;
++ fsm_lowerup(f);
++ }
++ fsm_input(f, p, len);
++}
++
++
++/*
++ * lcp_extcode - Handle a LCP-specific code.
++ */
++static int
++lcp_extcode(f, code, id, inp, len)
++ fsm *f;
++ int code, id;
++ u_char *inp;
++ int len;
++{
++ u_char *magp;
++
++ switch( code ){
++ case PROTREJ:
++ lcp_rprotrej(f, inp, len);
++ break;
++
++ case ECHOREQ:
++ if (f-&gt;state != OPENED)
++ break;
++ magp = inp;
++ PUTLONG(lcp_gotoptions[f-&gt;unit].magicnumber, magp);
++ fsm_sdata(f, ECHOREP, id, inp, len);
++ break;
++
++ case ECHOREP:
++ lcp_received_echo_reply(f, id, inp, len);
++ break;
++
++ case DISCREQ:
++ break;
++
++ default:
++ return 0;
++ }
++ return 1;
++}
++
++
++/*
++ * lcp_rprotrej - Receive an Protocol-Reject.
++ *
++ * Figure out which protocol is rejected and inform it.
++ */
++static void
++lcp_rprotrej(f, inp, len)
++ fsm *f;
++ u_char *inp;
++ int len;
++{
++ int i;
++ struct protent *protp;
++ u_short prot;
++
++ if (len &lt; 2) {
++ LCPDEBUG((&quot;lcp_rprotrej: Rcvd short Protocol-Reject packet!&quot;));
++ return;
++ }
++
++ GETSHORT(prot, inp);
++
++ /*
++ * Protocol-Reject packets received in any state other than the LCP
++ * OPENED state SHOULD be silently discarded.
++ */
++ if( f-&gt;state != OPENED ){
++ LCPDEBUG((&quot;Protocol-Reject discarded: LCP in state %d&quot;, f-&gt;state));
++ return;
++ }
++
++ /*
++ * Upcall the proper Protocol-Reject routine.
++ */
++ for (i = 0; (protp = protocols[i]) != NULL; ++i)
++ if (protp-&gt;protocol == prot &amp;&amp; protp-&gt;enabled_flag) {
++ (*protp-&gt;protrej)(f-&gt;unit);
++ return;
++ }
++
++ warn(&quot;Protocol-Reject for unsupported protocol 0x%x&quot;, prot);
++}
++
++
++/*
++ * lcp_protrej - A Protocol-Reject was received.
++ */
++/*ARGSUSED*/
++static void
++lcp_protrej(unit)
++ int unit;
++{
++ /*
++ * Can't reject LCP!
++ */
++ error(&quot;Received Protocol-Reject for LCP!&quot;);
++ fsm_protreject(&amp;lcp_fsm[unit]);
++}
++
++
++/*
++ * lcp_sprotrej - Send a Protocol-Reject for some protocol.
++ */
++void
++lcp_sprotrej(unit, p, len)
++ int unit;
++ u_char *p;
++ int len;
++{
++ /*
++ * Send back the protocol and the information field of the
++ * rejected packet. We only get here if LCP is in the OPENED state.
++ */
++ p += 2;
++ len -= 2;
++
++ fsm_sdata(&amp;lcp_fsm[unit], PROTREJ, ++lcp_fsm[unit].id,
++ p, len);
++}
++
++
++/*
++ * lcp_resetci - Reset our CI.
++ */
++static void
++lcp_resetci(f)
++ fsm *f;
++{
++ lcp_options *wo = &amp;lcp_wantoptions[f-&gt;unit];
++ lcp_options *go = &amp;lcp_gotoptions[f-&gt;unit];
++ lcp_options *ao = &amp;lcp_allowoptions[f-&gt;unit];
++
++ wo-&gt;magicnumber = magic();
++ wo-&gt;numloops = 0;
++ *go = *wo;
++ if (!multilink) {
++ go-&gt;neg_mrru = 0;
++ go-&gt;neg_ssnhf = 0;
++ go-&gt;neg_endpoint = 0;
++ }
++ if (noendpoint)
++ ao-&gt;neg_endpoint = 0;
++ peer_mru[f-&gt;unit] = PPP_MRU;
++ auth_reset(f-&gt;unit);
++}
++
++
++/*
++ * lcp_cilen - Return length of our CI.
++ */
++static int
++lcp_cilen(f)
++ fsm *f;
++{
++ lcp_options *go = &amp;lcp_gotoptions[f-&gt;unit];
++
++#define LENCIVOID(neg) ((neg) ? CILEN_VOID : 0)
++#define LENCICHAP(neg) ((neg) ? CILEN_CHAP : 0)
++#define LENCISHORT(neg) ((neg) ? CILEN_SHORT : 0)
++#define LENCILONG(neg) ((neg) ? CILEN_LONG : 0)
++#define LENCILQR(neg) ((neg) ? CILEN_LQR: 0)
++#define LENCICBCP(neg) ((neg) ? CILEN_CBCP: 0)
++ /*
++ * NB: we only ask for one of CHAP and UPAP, even if we will
++ * accept either.
++ */
++ return (LENCISHORT(go-&gt;neg_mru &amp;&amp; go-&gt;mru != DEFMRU) +
++ LENCILONG(go-&gt;neg_asyncmap &amp;&amp; go-&gt;asyncmap != 0xFFFFFFFF) +
++ LENCICHAP(go-&gt;neg_chap) +
++ LENCISHORT(!go-&gt;neg_chap &amp;&amp; go-&gt;neg_upap) +
++ LENCILQR(go-&gt;neg_lqr) +
++ LENCICBCP(go-&gt;neg_cbcp) +
++ LENCILONG(go-&gt;neg_magicnumber) +
++ LENCIVOID(go-&gt;neg_pcompression) +
++ LENCIVOID(go-&gt;neg_accompression) +
++ LENCISHORT(go-&gt;neg_mrru) +
++ LENCIVOID(go-&gt;neg_ssnhf) +
++ (go-&gt;neg_endpoint? CILEN_CHAR + go-&gt;endpoint.length: 0));
++}
++
++
++/*
++ * lcp_addci - Add our desired CIs to a packet.
++ */
++static void
++lcp_addci(f, ucp, lenp)
++ fsm *f;
++ u_char *ucp;
++ int *lenp;
++{
++ lcp_options *go = &amp;lcp_gotoptions[f-&gt;unit];
++ u_char *start_ucp = ucp;
++
++#define ADDCIVOID(opt, neg) \
++ if (neg) { \
++ PUTCHAR(opt, ucp); \
++ PUTCHAR(CILEN_VOID, ucp); \
++ }
++#define ADDCISHORT(opt, neg, val) \
++ if (neg) { \
++ PUTCHAR(opt, ucp); \
++ PUTCHAR(CILEN_SHORT, ucp); \
++ PUTSHORT(val, ucp); \
++ }
++#define ADDCICHAP(opt, neg, val, digest) \
++ if (neg) { \
++ PUTCHAR(opt, ucp); \
++ PUTCHAR(CILEN_CHAP, ucp); \
++ PUTSHORT(val, ucp); \
++ PUTCHAR(digest, ucp); \
++ }
++#define ADDCILONG(opt, neg, val) \
++ if (neg) { \
++ PUTCHAR(opt, ucp); \
++ PUTCHAR(CILEN_LONG, ucp); \
++ PUTLONG(val, ucp); \
++ }
++#define ADDCILQR(opt, neg, val) \
++ if (neg) { \
++ PUTCHAR(opt, ucp); \
++ PUTCHAR(CILEN_LQR, ucp); \
++ PUTSHORT(PPP_LQR, ucp); \
++ PUTLONG(val, ucp); \
++ }
++#define ADDCICHAR(opt, neg, val) \
++ if (neg) { \
++ PUTCHAR(opt, ucp); \
++ PUTCHAR(CILEN_CHAR, ucp); \
++ PUTCHAR(val, ucp); \
++ }
++#define ADDCIENDP(opt, neg, class, val, len) \
++ if (neg) { \
++ int i; \
++ PUTCHAR(opt, ucp); \
++ PUTCHAR(CILEN_CHAR + len, ucp); \
++ PUTCHAR(class, ucp); \
++ for (i = 0; i &lt; len; ++i) \
++ PUTCHAR(val[i], ucp); \
++ }
++
++ ADDCISHORT(CI_MRU, go-&gt;neg_mru &amp;&amp; go-&gt;mru != DEFMRU, go-&gt;mru);
++ ADDCILONG(CI_ASYNCMAP, go-&gt;neg_asyncmap &amp;&amp; go-&gt;asyncmap != 0xFFFFFFFF,
++ go-&gt;asyncmap);
++ ADDCICHAP(CI_AUTHTYPE, go-&gt;neg_chap, PPP_CHAP, go-&gt;chap_mdtype);
++ ADDCISHORT(CI_AUTHTYPE, !go-&gt;neg_chap &amp;&amp; go-&gt;neg_upap, PPP_PAP);
++ ADDCILQR(CI_QUALITY, go-&gt;neg_lqr, go-&gt;lqr_period);
++ ADDCICHAR(CI_CALLBACK, go-&gt;neg_cbcp, CBCP_OPT);
++ ADDCILONG(CI_MAGICNUMBER, go-&gt;neg_magicnumber, go-&gt;magicnumber);
++ ADDCIVOID(CI_PCOMPRESSION, go-&gt;neg_pcompression);
++ ADDCIVOID(CI_ACCOMPRESSION, go-&gt;neg_accompression);
++ ADDCISHORT(CI_MRRU, go-&gt;neg_mrru, go-&gt;mrru);
++ ADDCIVOID(CI_SSNHF, go-&gt;neg_ssnhf);
++ ADDCIENDP(CI_EPDISC, go-&gt;neg_endpoint, go-&gt;endpoint.class,
++ go-&gt;endpoint.value, go-&gt;endpoint.length);
++
++ if (ucp - start_ucp != *lenp) {
++ /* this should never happen, because peer_mtu should be 1500 */
++ error(&quot;Bug in lcp_addci: wrong length&quot;);
++ }
++}
++
++
++/*
++ * lcp_ackci - Ack our CIs.
++ * This should not modify any state if the Ack is bad.
++ *
++ * Returns:
++ * 0 - Ack was bad.
++ * 1 - Ack was good.
++ */
++static int
++lcp_ackci(f, p, len)
++ fsm *f;
++ u_char *p;
++ int len;
++{
++ lcp_options *go = &amp;lcp_gotoptions[f-&gt;unit];
++ u_char cilen, citype, cichar;
++ u_short cishort;
++ u_int32_t cilong;
++
++ /*
++ * CIs must be in exactly the same order that we sent.
++ * Check packet length and CI length at each step.
++ * If we find any deviations, then this packet is bad.
++ */
++#define ACKCIVOID(opt, neg) \
++ if (neg) { \
++ if ((len -= CILEN_VOID) &lt; 0) \
++ goto bad; \
++ GETCHAR(citype, p); \
++ GETCHAR(cilen, p); \
++ if (cilen != CILEN_VOID || \
++ citype != opt) \
++ goto bad; \
++ }
++#define ACKCISHORT(opt, neg, val) \
++ if (neg) { \
++ if ((len -= CILEN_SHORT) &lt; 0) \
++ goto bad; \
++ GETCHAR(citype, p); \
++ GETCHAR(cilen, p); \
++ if (cilen != CILEN_SHORT || \
++ citype != opt) \
++ goto bad; \
++ GETSHORT(cishort, p); \
++ if (cishort != val) \
++ goto bad; \
++ }
++#define ACKCICHAR(opt, neg, val) \
++ if (neg) { \
++ if ((len -= CILEN_CHAR) &lt; 0) \
++ goto bad; \
++ GETCHAR(citype, p); \
++ GETCHAR(cilen, p); \
++ if (cilen != CILEN_CHAR || \
++ citype != opt) \
++ goto bad; \
++ GETCHAR(cichar, p); \
++ if (cichar != val) \
++ goto bad; \
++ }
++#define ACKCICHAP(opt, neg, val, digest) \
++ if (neg) { \
++ if ((len -= CILEN_CHAP) &lt; 0) \
++ goto bad; \
++ GETCHAR(citype, p); \
++ GETCHAR(cilen, p); \
++ if (cilen != CILEN_CHAP || \
++ citype != opt) \
++ goto bad; \
++ GETSHORT(cishort, p); \
++ if (cishort != val) \
++ goto bad; \
++ GETCHAR(cichar, p); \
++ if (cichar != digest) \
++ goto bad; \
++ }
++#define ACKCILONG(opt, neg, val) \
++ if (neg) { \
++ if ((len -= CILEN_LONG) &lt; 0) \
++ goto bad; \
++ GETCHAR(citype, p); \
++ GETCHAR(cilen, p); \
++ if (cilen != CILEN_LONG || \
++ citype != opt) \
++ goto bad; \
++ GETLONG(cilong, p); \
++ if (cilong != val) \
++ goto bad; \
++ }
++#define ACKCILQR(opt, neg, val) \
++ if (neg) { \
++ if ((len -= CILEN_LQR) &lt; 0) \
++ goto bad; \
++ GETCHAR(citype, p); \
++ GETCHAR(cilen, p); \
++ if (cilen != CILEN_LQR || \
++ citype != opt) \
++ goto bad; \
++ GETSHORT(cishort, p); \
++ if (cishort != PPP_LQR) \
++ goto bad; \
++ GETLONG(cilong, p); \
++ if (cilong != val) \
++ goto bad; \
++ }
++#define ACKCIENDP(opt, neg, class, val, vlen) \
++ if (neg) { \
++ int i; \
++ if ((len -= CILEN_CHAR + vlen) &lt; 0) \
++ goto bad; \
++ GETCHAR(citype, p); \
++ GETCHAR(cilen, p); \
++ if (cilen != CILEN_CHAR + vlen || \
++ citype != opt) \
++ goto bad; \
++ GETCHAR(cichar, p); \
++ if (cichar != class) \
++ goto bad; \
++ for (i = 0; i &lt; vlen; ++i) { \
++ GETCHAR(cichar, p); \
++ if (cichar != val[i]) \
++ goto bad; \
++ } \
++ }
++
++ ACKCISHORT(CI_MRU, go-&gt;neg_mru &amp;&amp; go-&gt;mru != DEFMRU, go-&gt;mru);
++ ACKCILONG(CI_ASYNCMAP, go-&gt;neg_asyncmap &amp;&amp; go-&gt;asyncmap != 0xFFFFFFFF,
++ go-&gt;asyncmap);
++ ACKCICHAP(CI_AUTHTYPE, go-&gt;neg_chap, PPP_CHAP, go-&gt;chap_mdtype);
++ ACKCISHORT(CI_AUTHTYPE, !go-&gt;neg_chap &amp;&amp; go-&gt;neg_upap, PPP_PAP);
++ ACKCILQR(CI_QUALITY, go-&gt;neg_lqr, go-&gt;lqr_period);
++ ACKCICHAR(CI_CALLBACK, go-&gt;neg_cbcp, CBCP_OPT);
++ ACKCILONG(CI_MAGICNUMBER, go-&gt;neg_magicnumber, go-&gt;magicnumber);
++ ACKCIVOID(CI_PCOMPRESSION, go-&gt;neg_pcompression);
++ ACKCIVOID(CI_ACCOMPRESSION, go-&gt;neg_accompression);
++ ACKCISHORT(CI_MRRU, go-&gt;neg_mrru, go-&gt;mrru);
++ ACKCIVOID(CI_SSNHF, go-&gt;neg_ssnhf);
++ ACKCIENDP(CI_EPDISC, go-&gt;neg_endpoint, go-&gt;endpoint.class,
++ go-&gt;endpoint.value, go-&gt;endpoint.length);
++
++ /*
++ * If there are any remaining CIs, then this packet is bad.
++ */
++ if (len != 0)
++ goto bad;
++ return (1);
++bad:
++ LCPDEBUG((&quot;lcp_acki: received bad Ack!&quot;));
++ return (0);
++}
++
++
++/*
++ * lcp_nakci - Peer has sent a NAK for some of our CIs.
++ * This should not modify any state if the Nak is bad
++ * or if LCP is in the OPENED state.
++ *
++ * Returns:
++ * 0 - Nak was bad.
++ * 1 - Nak was good.
++ */
++static int
++lcp_nakci(f, p, len)
++ fsm *f;
++ u_char *p;
++ int len;
++{
++ lcp_options *go = &amp;lcp_gotoptions[f-&gt;unit];
++ lcp_options *wo = &amp;lcp_wantoptions[f-&gt;unit];
++ u_char citype, cichar, *next;
++ u_short cishort;
++ u_int32_t cilong;
++ lcp_options no; /* options we've seen Naks for */
++ lcp_options try; /* options to request next time */
++ int looped_back = 0;
++ int cilen;
++
++ BZERO(&amp;no, sizeof(no));
++ try = *go;
++
++ /*
++ * Any Nak'd CIs must be in exactly the same order that we sent.
++ * Check packet length and CI length at each step.
++ * If we find any deviations, then this packet is bad.
++ */
++#define NAKCIVOID(opt, neg) \
++ if (go-&gt;neg &amp;&amp; \
++ len &gt;= CILEN_VOID &amp;&amp; \
++ p[1] == CILEN_VOID &amp;&amp; \
++ p[0] == opt) { \
++ len -= CILEN_VOID; \
++ INCPTR(CILEN_VOID, p); \
++ no.neg = 1; \
++ try.neg = 0; \
++ }
++#define NAKCICHAP(opt, neg, code) \
++ if (go-&gt;neg &amp;&amp; \
++ len &gt;= CILEN_CHAP &amp;&amp; \
++ p[1] == CILEN_CHAP &amp;&amp; \
++ p[0] == opt) { \
++ len -= CILEN_CHAP; \
++ INCPTR(2, p); \
++ GETSHORT(cishort, p); \
++ GETCHAR(cichar, p); \
++ no.neg = 1; \
++ code \
++ }
++#define NAKCICHAR(opt, neg, code) \
++ if (go-&gt;neg &amp;&amp; \
++ len &gt;= CILEN_CHAR &amp;&amp; \
++ p[1] == CILEN_CHAR &amp;&amp; \
++ p[0] == opt) { \
++ len -= CILEN_CHAR; \
++ INCPTR(2, p); \
++ GETCHAR(cichar, p); \
++ no.neg = 1; \
++ code \
++ }
++#define NAKCISHORT(opt, neg, code) \
++ if (go-&gt;neg &amp;&amp; \
++ len &gt;= CILEN_SHORT &amp;&amp; \
++ p[1] == CILEN_SHORT &amp;&amp; \
++ p[0] == opt) { \
++ len -= CILEN_SHORT; \
++ INCPTR(2, p); \
++ GETSHORT(cishort, p); \
++ no.neg = 1; \
++ code \
++ }
++#define NAKCILONG(opt, neg, code) \
++ if (go-&gt;neg &amp;&amp; \
++ len &gt;= CILEN_LONG &amp;&amp; \
++ p[1] == CILEN_LONG &amp;&amp; \
++ p[0] == opt) { \
++ len -= CILEN_LONG; \
++ INCPTR(2, p); \
++ GETLONG(cilong, p); \
++ no.neg = 1; \
++ code \
++ }
++#define NAKCILQR(opt, neg, code) \
++ if (go-&gt;neg &amp;&amp; \
++ len &gt;= CILEN_LQR &amp;&amp; \
++ p[1] == CILEN_LQR &amp;&amp; \
++ p[0] == opt) { \
++ len -= CILEN_LQR; \
++ INCPTR(2, p); \
++ GETSHORT(cishort, p); \
++ GETLONG(cilong, p); \
++ no.neg = 1; \
++ code \
++ }
++#define NAKCIENDP(opt, neg) \
++ if (go-&gt;neg &amp;&amp; \
++ len &gt;= CILEN_CHAR &amp;&amp; \
++ p[0] == opt &amp;&amp; \
++ p[1] &gt;= CILEN_CHAR &amp;&amp; \
++ p[1] &lt;= len) { \
++ len -= p[1]; \
++ INCPTR(p[1], p); \
++ no.neg = 1; \
++ try.neg = 0; \
++ }
++
++ /*
++ * We don't care if they want to send us smaller packets than
++ * we want. Therefore, accept any MRU less than what we asked for,
++ * but then ignore the new value when setting the MRU in the kernel.
++ * If they send us a bigger MRU than what we asked, accept it, up to
++ * the limit of the default MRU we'd get if we didn't negotiate.
++ */
++ if (go-&gt;neg_mru &amp;&amp; go-&gt;mru != DEFMRU) {
++ NAKCISHORT(CI_MRU, neg_mru,
++ if (cishort &lt;= wo-&gt;mru || cishort &lt;= DEFMRU)
++ try.mru = cishort;
++ );
++ }
++
++ /*
++ * Add any characters they want to our (receive-side) asyncmap.
++ */
++ if (go-&gt;neg_asyncmap &amp;&amp; go-&gt;asyncmap != 0xFFFFFFFF) {
++ NAKCILONG(CI_ASYNCMAP, neg_asyncmap,
++ try.asyncmap = go-&gt;asyncmap | cilong;
++ );
++ }
++
++ /*
++ * If they've nak'd our authentication-protocol, check whether
++ * they are proposing a different protocol, or a different
++ * hash algorithm for CHAP.
++ */
++ if ((go-&gt;neg_chap || go-&gt;neg_upap)
++ &amp;&amp; len &gt;= CILEN_SHORT
++ &amp;&amp; p[0] == CI_AUTHTYPE &amp;&amp; p[1] &gt;= CILEN_SHORT &amp;&amp; p[1] &lt;= len) {
++ cilen = p[1];
++ len -= cilen;
++ no.neg_chap = go-&gt;neg_chap;
++ no.neg_upap = go-&gt;neg_upap;
++ INCPTR(2, p);
++ GETSHORT(cishort, p);
++ if (cishort == PPP_PAP &amp;&amp; cilen == CILEN_SHORT) {
++ /*
++ * If we were asking for CHAP, they obviously don't want to do it.
++ * If we weren't asking for CHAP, then we were asking for PAP,
++ * in which case this Nak is bad.
++ */
++ if (!go-&gt;neg_chap)
++ goto bad;
++ try.neg_chap = 0;
++
++ } else if (cishort == PPP_CHAP &amp;&amp; cilen == CILEN_CHAP) {
++ GETCHAR(cichar, p);
++ if (go-&gt;neg_chap) {
++ /*
++ * We were asking for CHAP/MD5; they must want a different
++ * algorithm. If they can't do MD5, we can ask for M$-CHAP
++ * if we support it, otherwise we'll have to stop
++ * asking for CHAP.
++ */
++ if (cichar != go-&gt;chap_mdtype) {
++#ifdef CHAPMS
++ if (cichar == CHAP_MICROSOFT)
++ go-&gt;chap_mdtype = CHAP_MICROSOFT;
++ else
++#endif /* CHAPMS */
++ try.neg_chap = 0;
++ }
++ } else {
++ /*
++ * Stop asking for PAP if we were asking for it.
++ */
++ try.neg_upap = 0;
++ }
++
++ } else {
++ /*
++ * We don't recognize what they're suggesting.
++ * Stop asking for what we were asking for.
++ */
++ if (go-&gt;neg_chap)
++ try.neg_chap = 0;
++ else
++ try.neg_upap = 0;
++ p += cilen - CILEN_SHORT;
++ }
++ }
++
++ /*
++ * If they can't cope with our link quality protocol, we'll have
++ * to stop asking for LQR. We haven't got any other protocol.
++ * If they Nak the reporting period, take their value XXX ?
++ */
++ NAKCILQR(CI_QUALITY, neg_lqr,
++ if (cishort != PPP_LQR)
++ try.neg_lqr = 0;
++ else
++ try.lqr_period = cilong;
++ );
++
++ /*
++ * Only implementing CBCP...not the rest of the callback options
++ */
++ NAKCICHAR(CI_CALLBACK, neg_cbcp,
++ try.neg_cbcp = 0;
++ );
++
++ /*
++ * Check for a looped-back line.
++ */
++ NAKCILONG(CI_MAGICNUMBER, neg_magicnumber,
++ try.magicnumber = magic();
++ looped_back = 1;
++ );
++
++ /*
++ * Peer shouldn't send Nak for protocol compression or
++ * address/control compression requests; they should send
++ * a Reject instead. If they send a Nak, treat it as a Reject.
++ */
++ NAKCIVOID(CI_PCOMPRESSION, neg_pcompression);
++ NAKCIVOID(CI_ACCOMPRESSION, neg_accompression);
++
++ /*
++ * Nak for MRRU option - accept their value if it is smaller
++ * than the one we want.
++ */
++ if (go-&gt;neg_mrru) {
++ NAKCISHORT(CI_MRRU, neg_mrru,
++ if (cishort &lt;= wo-&gt;mrru)
++ try.mrru = cishort;
++ );
++ }
++
++ /*
++ * Nak for short sequence numbers shouldn't be sent, treat it
++ * like a reject.
++ */
++ NAKCIVOID(CI_SSNHF, neg_ssnhf);
++
++ /*
++ * Nak of the endpoint discriminator option is not permitted,
++ * treat it like a reject.
++ */
++ NAKCIENDP(CI_EPDISC, neg_endpoint);
++
++ /*
++ * There may be remaining CIs, if the peer is requesting negotiation
++ * on an option that we didn't include in our request packet.
++ * If we see an option that we requested, or one we've already seen
++ * in this packet, then this packet is bad.
++ * If we wanted to respond by starting to negotiate on the requested
++ * option(s), we could, but we don't, because except for the
++ * authentication type and quality protocol, if we are not negotiating
++ * an option, it is because we were told not to.
++ * For the authentication type, the Nak from the peer means
++ * `let me authenticate myself with you' which is a bit pointless.
++ * For the quality protocol, the Nak means `ask me to send you quality
++ * reports', but if we didn't ask for them, we don't want them.
++ * An option we don't recognize represents the peer asking to
++ * negotiate some option we don't support, so ignore it.
++ */
++ while (len &gt; CILEN_VOID) {
++ GETCHAR(citype, p);
++ GETCHAR(cilen, p);
++ if (cilen &lt; CILEN_VOID || (len -= cilen) &lt; 0)
++ goto bad;
++ next = p + cilen - 2;
++
++ switch (citype) {
++ case CI_MRU:
++ if ((go-&gt;neg_mru &amp;&amp; go-&gt;mru != DEFMRU)
++ || no.neg_mru || cilen != CILEN_SHORT)
++ goto bad;
++ GETSHORT(cishort, p);
++ if (cishort &lt; DEFMRU) {
++ try.neg_mru = 1;
++ try.mru = cishort;
++ }
++ break;
++ case CI_ASYNCMAP:
++ if ((go-&gt;neg_asyncmap &amp;&amp; go-&gt;asyncmap != 0xFFFFFFFF)
++ || no.neg_asyncmap || cilen != CILEN_LONG)
++ goto bad;
++ break;
++ case CI_AUTHTYPE:
++ if (go-&gt;neg_chap || no.neg_chap || go-&gt;neg_upap || no.neg_upap)
++ goto bad;
++ break;
++ case CI_MAGICNUMBER:
++ if (go-&gt;neg_magicnumber || no.neg_magicnumber ||
++ cilen != CILEN_LONG)
++ goto bad;
++ break;
++ case CI_PCOMPRESSION:
++ if (go-&gt;neg_pcompression || no.neg_pcompression
++ || cilen != CILEN_VOID)
++ goto bad;
++ break;
++ case CI_ACCOMPRESSION:
++ if (go-&gt;neg_accompression || no.neg_accompression
++ || cilen != CILEN_VOID)
++ goto bad;
++ break;
++ case CI_QUALITY:
++ if (go-&gt;neg_lqr || no.neg_lqr || cilen != CILEN_LQR)
++ goto bad;
++ break;
++ case CI_MRRU:
++ if (go-&gt;neg_mrru || no.neg_mrru || cilen != CILEN_SHORT)
++ goto bad;
++ break;
++ case CI_SSNHF:
++ if (go-&gt;neg_ssnhf || no.neg_ssnhf || cilen != CILEN_VOID)
++ goto bad;
++ try.neg_ssnhf = 1;
++ break;
++ case CI_EPDISC:
++ if (go-&gt;neg_endpoint || no.neg_endpoint || cilen &lt; CILEN_CHAR)
++ goto bad;
++ break;
++ }
++ p = next;
++ }
++
++ /*
++ * OK, the Nak is good. Now we can update state.
++ * If there are any options left we ignore them.
++ */
++ if (f-&gt;state != OPENED) {
++ if (looped_back) {
++ if (++try.numloops &gt;= lcp_loopbackfail) {
++ notice(&quot;Serial line is looped back.&quot;);
++ lcp_close(f-&gt;unit, &quot;Loopback detected&quot;);
++ status = EXIT_LOOPBACK;
++ }
++ } else
++ try.numloops = 0;
++ *go = try;
++ }
++
++ return 1;
++
++bad:
++ LCPDEBUG((&quot;lcp_nakci: received bad Nak!&quot;));
++ return 0;
++}
++
++
++/*
++ * lcp_rejci - Peer has Rejected some of our CIs.
++ * This should not modify any state if the Reject is bad
++ * or if LCP is in the OPENED state.
++ *
++ * Returns:
++ * 0 - Reject was bad.
++ * 1 - Reject was good.
++ */
++static int
++lcp_rejci(f, p, len)
++ fsm *f;
++ u_char *p;
++ int len;
++{
++ lcp_options *go = &amp;lcp_gotoptions[f-&gt;unit];
++ u_char cichar;
++ u_short cishort;
++ u_int32_t cilong;
++ lcp_options try; /* options to request next time */
++
++ try = *go;
++
++ /*
++ * Any Rejected CIs must be in exactly the same order that we sent.
++ * Check packet length and CI length at each step.
++ * If we find any deviations, then this packet is bad.
++ */
++#define REJCIVOID(opt, neg) \
++ if (go-&gt;neg &amp;&amp; \
++ len &gt;= CILEN_VOID &amp;&amp; \
++ p[1] == CILEN_VOID &amp;&amp; \
++ p[0] == opt) { \
++ len -= CILEN_VOID; \
++ INCPTR(CILEN_VOID, p); \
++ try.neg = 0; \
++ }
++#define REJCISHORT(opt, neg, val) \
++ if (go-&gt;neg &amp;&amp; \
++ len &gt;= CILEN_SHORT &amp;&amp; \
++ p[1] == CILEN_SHORT &amp;&amp; \
++ p[0] == opt) { \
++ len -= CILEN_SHORT; \
++ INCPTR(2, p); \
++ GETSHORT(cishort, p); \
++ /* Check rejected value. */ \
++ if (cishort != val) \
++ goto bad; \
++ try.neg = 0; \
++ }
++#define REJCICHAP(opt, neg, val, digest) \
++ if (go-&gt;neg &amp;&amp; \
++ len &gt;= CILEN_CHAP &amp;&amp; \
++ p[1] == CILEN_CHAP &amp;&amp; \
++ p[0] == opt) { \
++ len -= CILEN_CHAP; \
++ INCPTR(2, p); \
++ GETSHORT(cishort, p); \
++ GETCHAR(cichar, p); \
++ /* Check rejected value. */ \
++ if (cishort != val || cichar != digest) \
++ goto bad; \
++ try.neg = 0; \
++ try.neg_upap = 0; \
++ }
++#define REJCILONG(opt, neg, val) \
++ if (go-&gt;neg &amp;&amp; \
++ len &gt;= CILEN_LONG &amp;&amp; \
++ p[1] == CILEN_LONG &amp;&amp; \
++ p[0] == opt) { \
++ len -= CILEN_LONG; \
++ INCPTR(2, p); \
++ GETLONG(cilong, p); \
++ /* Check rejected value. */ \
++ if (cilong != val) \
++ goto bad; \
++ try.neg = 0; \
++ }
++#define REJCILQR(opt, neg, val) \
++ if (go-&gt;neg &amp;&amp; \
++ len &gt;= CILEN_LQR &amp;&amp; \
++ p[1] == CILEN_LQR &amp;&amp; \
++ p[0] == opt) { \
++ len -= CILEN_LQR; \
++ INCPTR(2, p); \
++ GETSHORT(cishort, p); \
++ GETLONG(cilong, p); \
++ /* Check rejected value. */ \
++ if (cishort != PPP_LQR || cilong != val) \
++ goto bad; \
++ try.neg = 0; \
++ }
++#define REJCICBCP(opt, neg, val) \
++ if (go-&gt;neg &amp;&amp; \
++ len &gt;= CILEN_CBCP &amp;&amp; \
++ p[1] == CILEN_CBCP &amp;&amp; \
++ p[0] == opt) { \
++ len -= CILEN_CBCP; \
++ INCPTR(2, p); \
++ GETCHAR(cichar, p); \
++ /* Check rejected value. */ \
++ if (cichar != val) \
++ goto bad; \
++ try.neg = 0; \
++ }
++#define REJCIENDP(opt, neg, class, val, vlen) \
++ if (go-&gt;neg &amp;&amp; \
++ len &gt;= CILEN_CHAR + vlen &amp;&amp; \
++ p[0] == opt &amp;&amp; \
++ p[1] == CILEN_CHAR + vlen) { \
++ int i; \
++ len -= CILEN_CHAR + vlen; \
++ INCPTR(2, p); \
++ GETCHAR(cichar, p); \
++ if (cichar != class) \
++ goto bad; \
++ for (i = 0; i &lt; vlen; ++i) { \
++ GETCHAR(cichar, p); \
++ if (cichar != val[i]) \
++ goto bad; \
++ } \
++ try.neg = 0; \
++ }
++
++ REJCISHORT(CI_MRU, neg_mru, go-&gt;mru);
++ REJCILONG(CI_ASYNCMAP, neg_asyncmap, go-&gt;asyncmap);
++ REJCICHAP(CI_AUTHTYPE, neg_chap, PPP_CHAP, go-&gt;chap_mdtype);
++ if (!go-&gt;neg_chap) {
++ REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP);
++ }
++ REJCILQR(CI_QUALITY, neg_lqr, go-&gt;lqr_period);
++ REJCICBCP(CI_CALLBACK, neg_cbcp, CBCP_OPT);
++ REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go-&gt;magicnumber);
++ REJCIVOID(CI_PCOMPRESSION, neg_pcompression);
++ REJCIVOID(CI_ACCOMPRESSION, neg_accompression);
++ REJCISHORT(CI_MRRU, neg_mrru, go-&gt;mrru);
++ REJCIVOID(CI_SSNHF, neg_ssnhf);
++ REJCIENDP(CI_EPDISC, neg_endpoint, go-&gt;endpoint.class,
++ go-&gt;endpoint.value, go-&gt;endpoint.length);
++
++ /*
++ * If there are any remaining CIs, then this packet is bad.
++ */
++ if (len != 0)
++ goto bad;
++ /*
++ * Now we can update state.
++ */
++ if (f-&gt;state != OPENED)
++ *go = try;
++ return 1;
++
++bad:
++ LCPDEBUG((&quot;lcp_rejci: received bad Reject!&quot;));
++ return 0;
++}
++
++
++/*
++ * lcp_reqci - Check the peer's requested CIs and send appropriate response.
++ *
++ * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
++ * appropriately. If reject_if_disagree is non-zero, doesn't return
++ * CONFNAK; returns CONFREJ if it can't return CONFACK.
++ */
++static int
++lcp_reqci(f, inp, lenp, reject_if_disagree)
++ fsm *f;
++ u_char *inp; /* Requested CIs */
++ int *lenp; /* Length of requested CIs */
++ int reject_if_disagree;
++{
++ lcp_options *go = &amp;lcp_gotoptions[f-&gt;unit];
++ lcp_options *ho = &amp;lcp_hisoptions[f-&gt;unit];
++ lcp_options *ao = &amp;lcp_allowoptions[f-&gt;unit];
++ u_char *cip, *next; /* Pointer to current and next CIs */
++ int cilen, citype, cichar; /* Parsed len, type, char value */
++ u_short cishort; /* Parsed short value */
++ u_int32_t cilong; /* Parse long value */
++ int rc = CONFACK; /* Final packet return code */
++ int orc; /* Individual option return code */
++ u_char *p; /* Pointer to next char to parse */
++ u_char *rejp; /* Pointer to next char in reject frame */
++ u_char *nakp; /* Pointer to next char in Nak frame */
++ int l = *lenp; /* Length left */
++
++ /*
++ * Reset all his options.
++ */
++ BZERO(ho, sizeof(*ho));
++
++ /*
++ * Process all his options.
++ */
++ next = inp;
++ nakp = nak_buffer;
++ rejp = inp;
++ while (l) {
++ orc = CONFACK; /* Assume success */
++ cip = p = next; /* Remember begining of CI */
++ if (l &lt; 2 || /* Not enough data for CI header or */
++ p[1] &lt; 2 || /* CI length too small or */
++ p[1] &gt; l) { /* CI length too big? */
++ LCPDEBUG((&quot;lcp_reqci: bad CI length!&quot;));
++ orc = CONFREJ; /* Reject bad CI */
++ cilen = l; /* Reject till end of packet */
++ l = 0; /* Don't loop again */
++ citype = 0;
++ goto endswitch;
++ }
++ GETCHAR(citype, p); /* Parse CI type */
++ GETCHAR(cilen, p); /* Parse CI length */
++ l -= cilen; /* Adjust remaining length */
++ next += cilen; /* Step to next CI */
++
++ switch (citype) { /* Check CI type */
++ case CI_MRU:
++ if (!ao-&gt;neg_mru || /* Allow option? */
++ cilen != CILEN_SHORT) { /* Check CI length */
++ orc = CONFREJ; /* Reject CI */
++ break;
++ }
++ GETSHORT(cishort, p); /* Parse MRU */
++
++ /*
++ * He must be able to receive at least our minimum.
++ * No need to check a maximum. If he sends a large number,
++ * we'll just ignore it.
++ */
++ if (cishort &lt; MINMRU) {
++ orc = CONFNAK; /* Nak CI */
++ PUTCHAR(CI_MRU, nakp);
++ PUTCHAR(CILEN_SHORT, nakp);
++ PUTSHORT(MINMRU, nakp); /* Give him a hint */
++ break;
++ }
++ ho-&gt;neg_mru = 1; /* Remember he sent MRU */
++ ho-&gt;mru = cishort; /* And remember value */
++ break;
++
++ case CI_ASYNCMAP:
++ if (!ao-&gt;neg_asyncmap ||
++ cilen != CILEN_LONG) {
++ orc = CONFREJ;
++ break;
++ }
++ GETLONG(cilong, p);
++
++ /*
++ * Asyncmap must have set at least the bits
++ * which are set in lcp_allowoptions[unit].asyncmap.
++ */
++ if ((ao-&gt;asyncmap &amp; ~cilong) != 0) {
++ orc = CONFNAK;
++ PUTCHAR(CI_ASYNCMAP, nakp);
++ PUTCHAR(CILEN_LONG, nakp);
++ PUTLONG(ao-&gt;asyncmap | cilong, nakp);
++ break;
++ }
++ ho-&gt;neg_asyncmap = 1;
++ ho-&gt;asyncmap = cilong;
++ break;
++
++ case CI_AUTHTYPE:
++ if (cilen &lt; CILEN_SHORT ||
++ !(ao-&gt;neg_upap || ao-&gt;neg_chap)) {
++ /*
++ * Reject the option if we're not willing to authenticate.
++ */
++ orc = CONFREJ;
++ break;
++ }
++ GETSHORT(cishort, p);
++
++ /*
++ * Authtype must be PAP or CHAP.
++ *
++ * Note: if both ao-&gt;neg_upap and ao-&gt;neg_chap are set,
++ * and the peer sends a Configure-Request with two
++ * authenticate-protocol requests, one for CHAP and one
++ * for UPAP, then we will reject the second request.
++ * Whether we end up doing CHAP or UPAP depends then on
++ * the ordering of the CIs in the peer's Configure-Request.
++ */
++
++ if (cishort == PPP_PAP) {
++ if (ho-&gt;neg_chap || /* we've already accepted CHAP */
++ cilen != CILEN_SHORT) {
++ LCPDEBUG((&quot;lcp_reqci: rcvd AUTHTYPE PAP, rejecting...&quot;));
++ orc = CONFREJ;
++ break;
++ }
++ if (!ao-&gt;neg_upap) { /* we don't want to do PAP */
++ orc = CONFNAK; /* NAK it and suggest CHAP */
++ PUTCHAR(CI_AUTHTYPE, nakp);
++ PUTCHAR(CILEN_CHAP, nakp);
++ PUTSHORT(PPP_CHAP, nakp);
++ PUTCHAR(ao-&gt;chap_mdtype, nakp);
++ /* XXX if we can do CHAP_MICROSOFT as well, we should
++ probably put in another option saying so */
++ break;
++ }
++ ho-&gt;neg_upap = 1;
++ break;
++ }
++ if (cishort == PPP_CHAP) {
++ if (ho-&gt;neg_upap || /* we've already accepted PAP */
++ cilen != CILEN_CHAP) {
++ LCPDEBUG((&quot;lcp_reqci: rcvd AUTHTYPE CHAP, rejecting...&quot;));
++ orc = CONFREJ;
++ break;
++ }
++ if (!ao-&gt;neg_chap) { /* we don't want to do CHAP */
++ orc = CONFNAK; /* NAK it and suggest PAP */
++ PUTCHAR(CI_AUTHTYPE, nakp);
++ PUTCHAR(CILEN_SHORT, nakp);
++ PUTSHORT(PPP_PAP, nakp);
++ break;
++ }
++ GETCHAR(cichar, p); /* get digest type*/
++ if (cichar != CHAP_DIGEST_MD5
++#ifdef CHAPMS
++ &amp;&amp; cichar != CHAP_MICROSOFT
++#endif
++ ) {
++ orc = CONFNAK;
++ PUTCHAR(CI_AUTHTYPE, nakp);
++ PUTCHAR(CILEN_CHAP, nakp);
++ PUTSHORT(PPP_CHAP, nakp);
++ PUTCHAR(ao-&gt;chap_mdtype, nakp);
++ break;
++ }
++ ho-&gt;chap_mdtype = cichar; /* save md type */
++ ho-&gt;neg_chap = 1;
++ break;
++ }
++
++ /*
++ * We don't recognize the protocol they're asking for.
++ * Nak it with something we're willing to do.
++ * (At this point we know ao-&gt;neg_upap || ao-&gt;neg_chap.)
++ */
++ orc = CONFNAK;
++ PUTCHAR(CI_AUTHTYPE, nakp);
++ if (ao-&gt;neg_chap) {
++ PUTCHAR(CILEN_CHAP, nakp);
++ PUTSHORT(PPP_CHAP, nakp);
++ PUTCHAR(ao-&gt;chap_mdtype, nakp);
++ } else {
++ PUTCHAR(CILEN_SHORT, nakp);
++ PUTSHORT(PPP_PAP, nakp);
++ }
++ break;
++
++ case CI_QUALITY:
++ if (!ao-&gt;neg_lqr ||
++ cilen != CILEN_LQR) {
++ orc = CONFREJ;
++ break;
++ }
++
++ GETSHORT(cishort, p);
++ GETLONG(cilong, p);
++
++ /*
++ * Check the protocol and the reporting period.
++ * XXX When should we Nak this, and what with?
++ */
++ if (cishort != PPP_LQR) {
++ orc = CONFNAK;
++ PUTCHAR(CI_QUALITY, nakp);
++ PUTCHAR(CILEN_LQR, nakp);
++ PUTSHORT(PPP_LQR, nakp);
++ PUTLONG(ao-&gt;lqr_period, nakp);
++ break;
++ }
++ break;
++
++ case CI_MAGICNUMBER:
++ if (!(ao-&gt;neg_magicnumber || go-&gt;neg_magicnumber) ||
++ cilen != CILEN_LONG) {
++ orc = CONFREJ;
++ break;
++ }
++ GETLONG(cilong, p);
++
++ /*
++ * He must have a different magic number.
++ */
++ if (go-&gt;neg_magicnumber &amp;&amp;
++ cilong == go-&gt;magicnumber) {
++ cilong = magic(); /* Don't put magic() inside macro! */
++ orc = CONFNAK;
++ PUTCHAR(CI_MAGICNUMBER, nakp);
++ PUTCHAR(CILEN_LONG, nakp);
++ PUTLONG(cilong, nakp);
++ break;
++ }
++ ho-&gt;neg_magicnumber = 1;
++ ho-&gt;magicnumber = cilong;
++ break;
++
++
++ case CI_PCOMPRESSION:
++ if (!ao-&gt;neg_pcompression ||
++ cilen != CILEN_VOID) {
++ orc = CONFREJ;
++ break;
++ }
++ ho-&gt;neg_pcompression = 1;
++ break;
++
++ case CI_ACCOMPRESSION:
++ if (!ao-&gt;neg_accompression ||
++ cilen != CILEN_VOID) {
++ orc = CONFREJ;
++ break;
++ }
++ ho-&gt;neg_accompression = 1;
++ break;
++
++ case CI_MRRU:
++ if (!ao-&gt;neg_mrru || !multilink ||
++ cilen != CILEN_SHORT) {
++ orc = CONFREJ;
++ break;
++ }
++
++ GETSHORT(cishort, p);
++ /* possibly should insist on a minimum/maximum MRRU here */
++ ho-&gt;neg_mrru = 1;
++ ho-&gt;mrru = cishort;
++ break;
++
++ case CI_SSNHF:
++ if (!ao-&gt;neg_ssnhf || !multilink ||
++ cilen != CILEN_VOID) {
++ orc = CONFREJ;
++ break;
++ }
++ ho-&gt;neg_ssnhf = 1;
++ break;
++
++ case CI_EPDISC:
++ if (!ao-&gt;neg_endpoint ||
++ cilen &lt; CILEN_CHAR ||
++ cilen &gt; CILEN_CHAR + MAX_ENDP_LEN) {
++ orc = CONFREJ;
++ break;
++ }
++ GETCHAR(cichar, p);
++ cilen -= CILEN_CHAR;
++ ho-&gt;neg_endpoint = 1;
++ ho-&gt;endpoint.class = cichar;
++ ho-&gt;endpoint.length = cilen;
++ BCOPY(p, ho-&gt;endpoint.value, cilen);
++ INCPTR(cilen, p);
++ break;
++
++ default:
++ LCPDEBUG((&quot;lcp_reqci: rcvd unknown option %d&quot;, citype));
++ orc = CONFREJ;
++ break;
++ }
++
++endswitch:
++ if (orc == CONFACK &amp;&amp; /* Good CI */
++ rc != CONFACK) /* but prior CI wasnt? */
++ continue; /* Don't send this one */
++
++ if (orc == CONFNAK) { /* Nak this CI? */
++ if (reject_if_disagree /* Getting fed up with sending NAKs? */
++ &amp;&amp; citype != CI_MAGICNUMBER) {
++ orc = CONFREJ; /* Get tough if so */
++ } else {
++ if (rc == CONFREJ) /* Rejecting prior CI? */
++ continue; /* Don't send this one */
++ rc = CONFNAK;
++ }
++ }
++ if (orc == CONFREJ) { /* Reject this CI */
++ rc = CONFREJ;
++ if (cip != rejp) /* Need to move rejected CI? */
++ BCOPY(cip, rejp, cilen); /* Move it */
++ INCPTR(cilen, rejp); /* Update output pointer */
++ }
++ }
++
++ /*
++ * If we wanted to send additional NAKs (for unsent CIs), the
++ * code would go here. The extra NAKs would go at *nakp.
++ * At present there are no cases where we want to ask the
++ * peer to negotiate an option.
++ */
++
++ switch (rc) {
++ case CONFACK:
++ *lenp = next - inp;
++ break;
++ case CONFNAK:
++ /*
++ * Copy the Nak'd options from the nak_buffer to the caller's buffer.
++ */
++ *lenp = nakp - nak_buffer;
++ BCOPY(nak_buffer, inp, *lenp);
++ break;
++ case CONFREJ:
++ *lenp = rejp - inp;
++ break;
++ }
++
++ LCPDEBUG((&quot;lcp_reqci: returning CONF%s.&quot;, CODENAME(rc)));
++ return (rc); /* Return final code */
++}
++
++
++/*
++ * lcp_up - LCP has come UP.
++ */
++static void
++lcp_up(f)
++ fsm *f;
++{
++ lcp_options *wo = &amp;lcp_wantoptions[f-&gt;unit];
++ lcp_options *ho = &amp;lcp_hisoptions[f-&gt;unit];
++ lcp_options *go = &amp;lcp_gotoptions[f-&gt;unit];
++ lcp_options *ao = &amp;lcp_allowoptions[f-&gt;unit];
++ int mtu;
++
++ if (!go-&gt;neg_magicnumber)
++ go-&gt;magicnumber = 0;
++ if (!ho-&gt;neg_magicnumber)
++ ho-&gt;magicnumber = 0;
++
++ /*
++ * Set our MTU to the smaller of the MTU we wanted and
++ * the MRU our peer wanted. If we negotiated an MRU,
++ * set our MRU to the larger of value we wanted and
++ * the value we got in the negotiation.
++ * Note on the MTU: the link MTU can be the MRU the peer wanted,
++ * the interface MTU is set to the lower of that and the
++ * MTU we want to use.
++ */
++ mtu = ho-&gt;neg_mru? ho-&gt;mru: PPP_MRU;
++#ifdef HAVE_MULTILINK
++ if (!(multilink &amp;&amp; go-&gt;neg_mrru &amp;&amp; ho-&gt;neg_mrru))
++#endif /* HAVE_MULTILINK */
++ netif_set_mtu(f-&gt;unit, MIN(mtu, ao-&gt;mru));
++ ppp_send_config(f-&gt;unit, mtu,
++ (ho-&gt;neg_asyncmap? ho-&gt;asyncmap: 0xffffffff),
++ ho-&gt;neg_pcompression, ho-&gt;neg_accompression);
++ ppp_recv_config(f-&gt;unit, (go-&gt;neg_mru? MAX(wo-&gt;mru, go-&gt;mru): PPP_MRU),
++ (lax_recv? 0: go-&gt;neg_asyncmap? go-&gt;asyncmap: 0xffffffff),
++ go-&gt;neg_pcompression, go-&gt;neg_accompression);
++
++ if (ho-&gt;neg_mru)
++ peer_mru[f-&gt;unit] = ho-&gt;mru;
++
++ lcp_echo_lowerup(f-&gt;unit); /* Enable echo messages */
++
++ link_established(f-&gt;unit);
++}
++
++
++/*
++ * lcp_down - LCP has gone DOWN.
++ *
++ * Alert other protocols.
++ */
++static void
++lcp_down(f)
++ fsm *f;
++{
++ lcp_options *go = &amp;lcp_gotoptions[f-&gt;unit];
++
++ lcp_echo_lowerdown(f-&gt;unit);
++
++ link_down(f-&gt;unit);
++
++ ppp_send_config(f-&gt;unit, PPP_MRU, 0xffffffff, 0, 0);
++ ppp_recv_config(f-&gt;unit, PPP_MRU,
++ (go-&gt;neg_asyncmap? go-&gt;asyncmap: 0xffffffff),
++ go-&gt;neg_pcompression, go-&gt;neg_accompression);
++ peer_mru[f-&gt;unit] = PPP_MRU;
++}
++
++
++/*
++ * lcp_starting - LCP needs the lower layer up.
++ */
++static void
++lcp_starting(f)
++ fsm *f;
++{
++ link_required(f-&gt;unit);
++}
++
++
++/*
++ * lcp_finished - LCP has finished with the lower layer.
++ */
++static void
++lcp_finished(f)
++ fsm *f;
++{
++ link_terminated(f-&gt;unit);
++}
++
++
++/*
++ * lcp_printpkt - print the contents of an LCP packet.
++ */
++static char *lcp_codenames[] = {
++ &quot;ConfReq&quot;, &quot;ConfAck&quot;, &quot;ConfNak&quot;, &quot;ConfRej&quot;,
++ &quot;TermReq&quot;, &quot;TermAck&quot;, &quot;CodeRej&quot;, &quot;ProtRej&quot;,
++ &quot;EchoReq&quot;, &quot;EchoRep&quot;, &quot;DiscReq&quot;
++};
++
++static int
++lcp_printpkt(p, plen, printer, arg)
++ u_char *p;
++ int plen;
++ void (*printer) __P((void *, char *, ...));
++ void *arg;
++{
++ int code, id, len, olen, i;
++ u_char *pstart, *optend;
++ u_short cishort;
++ u_int32_t cilong;
++
++ if (plen &lt; HEADERLEN)
++ return 0;
++ pstart = p;
++ GETCHAR(code, p);
++ GETCHAR(id, p);
++ GETSHORT(len, p);
++ if (len &lt; HEADERLEN || len &gt; plen)
++ return 0;
++
++ if (code &gt;= 1 &amp;&amp; code &lt;= sizeof(lcp_codenames) / sizeof(char *))
++ printer(arg, &quot; %s&quot;, lcp_codenames[code-1]);
++ else
++ printer(arg, &quot; code=0x%x&quot;, code);
++ printer(arg, &quot; id=0x%x&quot;, id);
++ len -= HEADERLEN;
++ switch (code) {
++ case CONFREQ:
++ case CONFACK:
++ case CONFNAK:
++ case CONFREJ:
++ /* print option list */
++ while (len &gt;= 2) {
++ GETCHAR(code, p);
++ GETCHAR(olen, p);
++ p -= 2;
++ if (olen &lt; 2 || olen &gt; len) {
++ break;
++ }
++ printer(arg, &quot; &lt;&quot;);
++ len -= olen;
++ optend = p + olen;
++ switch (code) {
++ case CI_MRU:
++ if (olen == CILEN_SHORT) {
++ p += 2;
++ GETSHORT(cishort, p);
++ printer(arg, &quot;mru %d&quot;, cishort);
++ }
++ break;
++ case CI_ASYNCMAP:
++ if (olen == CILEN_LONG) {
++ p += 2;
++ GETLONG(cilong, p);
++ printer(arg, &quot;asyncmap 0x%x&quot;, cilong);
++ }
++ break;
++ case CI_AUTHTYPE:
++ if (olen &gt;= CILEN_SHORT) {
++ p += 2;
++ printer(arg, &quot;auth &quot;);
++ GETSHORT(cishort, p);
++ switch (cishort) {
++ case PPP_PAP:
++ printer(arg, &quot;pap&quot;);
++ break;
++ case PPP_CHAP:
++ printer(arg, &quot;chap&quot;);
++ if (p &lt; optend) {
++ switch (*p) {
++ case CHAP_DIGEST_MD5:
++ printer(arg, &quot; MD5&quot;);
++ ++p;
++ break;
++#ifdef CHAPMS
++ case CHAP_MICROSOFT:
++ printer(arg, &quot; m$oft&quot;);
++ ++p;
++ break;
++#endif
++ }
++ }
++ break;
++ default:
++ printer(arg, &quot;0x%x&quot;, cishort);
++ }
++ }
++ break;
++ case CI_QUALITY:
++ if (olen &gt;= CILEN_SHORT) {
++ p += 2;
++ printer(arg, &quot;quality &quot;);
++ GETSHORT(cishort, p);
++ switch (cishort) {
++ case PPP_LQR:
++ printer(arg, &quot;lqr&quot;);
++ break;
++ default:
++ printer(arg, &quot;0x%x&quot;, cishort);
++ }
++ }
++ break;
++ case CI_CALLBACK:
++ if (olen &gt;= CILEN_CHAR) {
++ p += 2;
++ printer(arg, &quot;callback &quot;);
++ GETCHAR(cishort, p);
++ switch (cishort) {
++ case CBCP_OPT:
++ printer(arg, &quot;CBCP&quot;);
++ break;
++ default:
++ printer(arg, &quot;0x%x&quot;, cishort);
++ }
++ }
++ break;
++ case CI_MAGICNUMBER:
++ if (olen == CILEN_LONG) {
++ p += 2;
++ GETLONG(cilong, p);
++ printer(arg, &quot;magic 0x%x&quot;, cilong);
++ }
++ break;
++ case CI_PCOMPRESSION:
++ if (olen == CILEN_VOID) {
++ p += 2;
++ printer(arg, &quot;pcomp&quot;);
++ }
++ break;
++ case CI_ACCOMPRESSION:
++ if (olen == CILEN_VOID) {
++ p += 2;
++ printer(arg, &quot;accomp&quot;);
++ }
++ break;
++ case CI_MRRU:
++ if (olen == CILEN_SHORT) {
++ p += 2;
++ GETSHORT(cishort, p);
++ printer(arg, &quot;mrru %d&quot;, cishort);
++ }
++ break;
++ case CI_SSNHF:
++ if (olen == CILEN_VOID) {
++ p += 2;
++ printer(arg, &quot;ssnhf&quot;);
++ }
++ break;
++ case CI_EPDISC:
++#ifdef HAVE_MULTILINK
++ if (olen &gt;= CILEN_CHAR) {
++ struct epdisc epd;
++ p += 2;
++ GETCHAR(epd.class, p);
++ epd.length = olen - CILEN_CHAR;
++ if (epd.length &gt; MAX_ENDP_LEN)
++ epd.length = MAX_ENDP_LEN;
++ if (epd.length &gt; 0) {
++ BCOPY(p, epd.value, epd.length);
++ p += epd.length;
++ }
++ printer(arg, &quot;endpoint [%s]&quot;, epdisc_to_str(&amp;epd));
++ }
++#else
++ printer(arg, &quot;endpoint&quot;);
++#endif
++ break;
++ }
++ while (p &lt; optend) {
++ GETCHAR(code, p);
++ printer(arg, &quot; %.2x&quot;, code);
++ }
++ printer(arg, &quot;&gt;&quot;);
++ }
++ break;
++
++ case TERMACK:
++ case TERMREQ:
++ if (len &gt; 0 &amp;&amp; *p &gt;= ' ' &amp;&amp; *p &lt; 0x7f) {
++ printer(arg, &quot; &quot;);
++ print_string((char *)p, len, printer, arg);
++ p += len;
++ len = 0;
++ }
++ break;
++
++ case ECHOREQ:
++ case ECHOREP:
++ case DISCREQ:
++ if (len &gt;= 4) {
++ GETLONG(cilong, p);
++ printer(arg, &quot; magic=0x%x&quot;, cilong);
++ p += 4;
++ len -= 4;
++ }
++ break;
++ }
++
++ /* print the rest of the bytes in the packet */
++ for (i = 0; i &lt; len &amp;&amp; i &lt; 32; ++i) {
++ GETCHAR(code, p);
++ printer(arg, &quot; %.2x&quot;, code);
++ }
++ if (i &lt; len) {
++ printer(arg, &quot; ...&quot;);
++ p += len - i;
++ }
++
++ return p - pstart;
++}
++
++/*
++ * Time to shut down the link because there is nothing out there.
++ */
++
++static
++void LcpLinkFailure (f)
++ fsm *f;
++{
++ if (f-&gt;state == OPENED) {
++ info(&quot;No response to %d echo-requests&quot;, lcp_echos_pending);
++ notice(&quot;Serial link appears to be disconnected.&quot;);
++ lcp_close(f-&gt;unit, &quot;Peer not responding&quot;);
++ status = EXIT_PEER_DEAD;
++ }
++}
++
++/*
++ * Timer expired for the LCP echo requests from this process.
++ */
++
++static void
++LcpEchoCheck (f)
++ fsm *f;
++{
++ LcpSendEchoRequest (f);
++ if (f-&gt;state != OPENED)
++ return;
++
++ /*
++ * Start the timer for the next interval.
++ */
++ if (lcp_echo_timer_running)
++ warn(&quot;assertion lcp_echo_timer_running==0 failed&quot;);
++ TIMEOUT (LcpEchoTimeout, f, lcp_echo_interval);
++ lcp_echo_timer_running = 1;
++}
++
++/*
++ * LcpEchoTimeout - Timer expired on the LCP echo
++ */
++
++static void
++LcpEchoTimeout (arg)
++ void *arg;
++{
++ if (lcp_echo_timer_running != 0) {
++ lcp_echo_timer_running = 0;
++ LcpEchoCheck ((fsm *) arg);
++ }
++}
++
++/*
++ * LcpEchoReply - LCP has received a reply to the echo
++ */
++
++static void
++lcp_received_echo_reply (f, id, inp, len)
++ fsm *f;
++ int id;
++ u_char *inp;
++ int len;
++{
++ u_int32_t magic;
++
++ /* Check the magic number - don't count replies from ourselves. */
++ if (len &lt; 4) {
++ dbglog(&quot;lcp: received short Echo-Reply, length %d&quot;, len);
++ return;
++ }
++ GETLONG(magic, inp);
++ if (lcp_gotoptions[f-&gt;unit].neg_magicnumber
++ &amp;&amp; magic == lcp_gotoptions[f-&gt;unit].magicnumber) {
++ warn(&quot;appear to have received our own echo-reply!&quot;);
++ return;
++ }
++
++ /* Reset the number of outstanding echo frames */
++ lcp_echos_pending = 0;
++}
++
++/*
++ * LcpSendEchoRequest - Send an echo request frame to the peer
++ */
++
++static void
++LcpSendEchoRequest (f)
++ fsm *f;
++{
++ u_int32_t lcp_magic;
++ u_char pkt[4], *pktp;
++
++ /*
++ * Detect the failure of the peer at this point.
++ */
++ if (lcp_echo_fails != 0) {
++ if (lcp_echos_pending &gt;= lcp_echo_fails) {
++ LcpLinkFailure(f);
++ lcp_echos_pending = 0;
++ }
++ }
++
++ /*
++ * Make and send the echo request frame.
++ */
++ if (f-&gt;state == OPENED) {
++ lcp_magic = lcp_gotoptions[f-&gt;unit].magicnumber;
++ pktp = pkt;
++ PUTLONG(lcp_magic, pktp);
++ fsm_sdata(f, ECHOREQ, lcp_echo_number++ &amp; 0xFF, pkt, pktp - pkt);
++ ++lcp_echos_pending;
++ }
++}
++
++/*
++ * lcp_echo_lowerup - Start the timer for the LCP frame
++ */
++
++static void
++lcp_echo_lowerup (unit)
++ int unit;
++{
++ fsm *f = &amp;lcp_fsm[unit];
++
++ /* Clear the parameters for generating echo frames */
++ lcp_echos_pending = 0;
++ lcp_echo_number = 0;
++ lcp_echo_timer_running = 0;
++
++ /* If a timeout interval is specified then start the timer */
++ if (lcp_echo_interval != 0)
++ LcpEchoCheck (f);
++}
++
++/*
++ * lcp_echo_lowerdown - Stop the timer for the LCP frame
++ */
++
++static void
++lcp_echo_lowerdown (unit)
++ int unit;
++{
++ fsm *f = &amp;lcp_fsm[unit];
++
++ if (lcp_echo_timer_running != 0) {
++ UNTIMEOUT (LcpEchoTimeout, f);
++ lcp_echo_timer_running = 0;
++ }
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/lcp.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/lcp.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/lcp.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/lcp.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,95 @@
++/*
++ * lcp.h - Link Control Protocol definitions.
++ *
++ * Copyright (c) 1989 Carnegie Mellon University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by Carnegie Mellon University. The name of the
++ * University may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * $Id: lcp.h 195720 2001-06-11 11:44:34Z gc $
++ */
++
++/*
++ * Options.
++ */
++#define CI_MRU 1 /* Maximum Receive Unit */
++#define CI_ASYNCMAP 2 /* Async Control Character Map */
++#define CI_AUTHTYPE 3 /* Authentication Type */
++#define CI_QUALITY 4 /* Quality Protocol */
++#define CI_MAGICNUMBER 5 /* Magic Number */
++#define CI_PCOMPRESSION 7 /* Protocol Field Compression */
++#define CI_ACCOMPRESSION 8 /* Address/Control Field Compression */
++#define CI_CALLBACK 13 /* callback */
++#define CI_MRRU 17 /* max reconstructed receive unit; multilink */
++#define CI_SSNHF 18 /* short sequence numbers for multilink */
++#define CI_EPDISC 19 /* endpoint discriminator */
++
++/*
++ * LCP-specific packet types.
++ */
++#define PROTREJ 8 /* Protocol Reject */
++#define ECHOREQ 9 /* Echo Request */
++#define ECHOREP 10 /* Echo Reply */
++#define DISCREQ 11 /* Discard Request */
++#define CBCP_OPT 6 /* Use callback control protocol */
++
++/*
++ * The state of options is described by an lcp_options structure.
++ */
++typedef struct lcp_options {
++ bool passive; /* Don't die if we don't get a response */
++ bool silent; /* Wait for the other end to start first */
++ bool restart; /* Restart vs. exit after close */
++ bool neg_mru; /* Negotiate the MRU? */
++ bool neg_asyncmap; /* Negotiate the async map? */
++ bool neg_upap; /* Ask for UPAP authentication? */
++ bool neg_chap; /* Ask for CHAP authentication? */
++ bool neg_magicnumber; /* Ask for magic number? */
++ bool neg_pcompression; /* HDLC Protocol Field Compression? */
++ bool neg_accompression; /* HDLC Address/Control Field Compression? */
++ bool neg_lqr; /* Negotiate use of Link Quality Reports */
++ bool neg_cbcp; /* Negotiate use of CBCP */
++ bool neg_mrru; /* negotiate multilink MRRU */
++ bool neg_ssnhf; /* negotiate short sequence numbers */
++ bool neg_endpoint; /* negotiate endpoint discriminator */
++ int mru; /* Value of MRU */
++ int mrru; /* Value of MRRU, and multilink enable */
++ u_char chap_mdtype; /* which MD type (hashing algorithm) */
++ u_int32_t asyncmap; /* Value of async map */
++ u_int32_t magicnumber;
++ int numloops; /* Number of loops during magic number neg. */
++ u_int32_t lqr_period; /* Reporting period for LQR 1/100ths second */
++ struct epdisc endpoint; /* endpoint discriminator */
++} lcp_options;
++
++extern fsm lcp_fsm[];
++extern lcp_options lcp_wantoptions[];
++extern lcp_options lcp_gotoptions[];
++extern lcp_options lcp_allowoptions[];
++extern lcp_options lcp_hisoptions[];
++
++#define DEFMRU 1500 /* Try for this */
++#define MINMRU 128 /* No MRUs below this */
++#define MAXMRU 16384 /* Normally limit MRU to this */
++
++void lcp_open __P((int));
++void lcp_close __P((int, char *));
++void lcp_lowerup __P((int));
++void lcp_lowerdown __P((int));
++void lcp_sprotrej __P((int, u_char *, int)); /* send protocol reject */
++
++extern struct protent lcp_protent;
++
++/* Default number of times we receive our magic number from the peer
++ before deciding the link is looped-back. */
++#define DEFLOOPBACKFAIL 10
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/lcp.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/magic.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/magic.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/magic.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,88 @@
++/*
++ * magic.c - PPP Magic Number routines.
++ *
++ * Copyright (c) 1989 Carnegie Mellon University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by Carnegie Mellon University. The name of the
++ * University may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ */
++
++#define RCSID &quot;$Id: magic.c 195734 2001-06-11 14:46:02Z gc $&quot;
++
++#include &lt;stdlib.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/time.h&gt;
++
++#include &quot;pppd.h&quot;
++#include &quot;magic.h&quot;
++
++static const char rcsid[] = RCSID;
++
++extern long mrand48 __P((void));
++extern void srand48 __P((long));
++
++/*
++ * magic_init - Initialize the magic number generator.
++ *
++ * Attempts to compute a random number seed which will not repeat.
++ * The current method uses the current hostid, current process ID
++ * and current time, currently.
++ */
++void
++magic_init()
++{
++ long seed;
++ struct timeval t;
++
++ gettimeofday(&amp;t, NULL);
++ seed = get_host_seed() ^ t.tv_sec ^ t.tv_usec ^ getpid();
++ srand48(seed);
++}
++
++/*
++ * magic - Returns the next magic number.
++ */
++u_int32_t
++magic()
++{
++ return (u_int32_t) mrand48();
++}
++
++#ifdef NO_DRAND48
++/*
++ * Substitute procedures for those systems which don't have
++ * drand48 et al.
++ */
++
++double
++drand48()
++{
++ return (double)random() / (double)0x7fffffffL; /* 2**31-1 */
++}
++
++long
++mrand48()
++{
++ return random();
++}
++
++void
++srand48(seedval)
++long seedval;
++{
++ srandom((int)seedval);
++}
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/magic.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/magic.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/magic.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/magic.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,23 @@
++/*
++ * magic.h - PPP Magic Number definitions.
++ *
++ * Copyright (c) 1989 Carnegie Mellon University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by Carnegie Mellon University. The name of the
++ * University may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * $Id: magic.h 195720 2001-06-11 11:44:34Z gc $
++ */
++
++void magic_init __P((void)); /* Initialize the magic number generator */
++u_int32_t magic __P((void)); /* Returns the next magic number */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/magic.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/main.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/main.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/main.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1846 @@
++/*
++ * main.c - Point-to-Point Protocol main module
++ *
++ * Copyright (c) 1989 Carnegie Mellon University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by Carnegie Mellon University. The name of the
++ * University may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ */
++
++#define RCSID &quot;$Id: main.c 195734 2001-06-11 14:46:02Z gc $&quot;
++
++#include &lt;stdio.h&gt;
++#include &lt;ctype.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;signal.h&gt;
++#include &lt;errno.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;syslog.h&gt;
++#include &lt;netdb.h&gt;
++#include &lt;utmp.h&gt;
++#include &lt;pwd.h&gt;
++#include &lt;setjmp.h&gt;
++#include &lt;sys/param.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/wait.h&gt;
++#include &lt;sys/time.h&gt;
++#include &lt;sys/resource.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;sys/socket.h&gt;
++#include &lt;netinet/in.h&gt;
++#include &lt;arpa/inet.h&gt;
++
++#include &quot;pppd.h&quot;
++#include &quot;magic.h&quot;
++#include &quot;fsm.h&quot;
++#include &quot;lcp.h&quot;
++#include &quot;ipcp.h&quot;
++#ifdef INET6
++#include &quot;ipv6cp.h&quot;
++#endif
++#include &quot;upap.h&quot;
++#include &quot;chap.h&quot;
++#include &quot;ccp.h&quot;
++#include &quot;pathnames.h&quot;
++#include &quot;tdb.h&quot;
++
++#ifdef CBCP_SUPPORT
++#include &quot;cbcp.h&quot;
++#endif
++
++#ifdef IPX_CHANGE
++#include &quot;ipxcp.h&quot;
++#endif /* IPX_CHANGE */
++#ifdef AT_CHANGE
++#include &quot;atcp.h&quot;
++#endif
++
++static const char rcsid[] = RCSID;
++
++/* interface vars */
++char ifname[32]; /* Interface name */
++int ifunit; /* Interface unit number */
++
++struct channel *the_channel;
++
++char *progname; /* Name of this program */
++char hostname[MAXNAMELEN]; /* Our hostname */
++static char pidfilename[MAXPATHLEN]; /* name of pid file */
++static char linkpidfile[MAXPATHLEN]; /* name of linkname pid file */
++char ppp_devnam[MAXPATHLEN]; /* name of PPP tty (maybe ttypx) */
++uid_t uid; /* Our real user-id */
++struct notifier *pidchange = NULL;
++struct notifier *phasechange = NULL;
++struct notifier *exitnotify = NULL;
++struct notifier *sigreceived = NULL;
++
++int hungup; /* terminal has been hung up */
++int privileged; /* we're running as real uid root */
++int need_holdoff; /* need holdoff period before restarting */
++int detached; /* have detached from terminal */
++volatile int status; /* exit status for pppd */
++int unsuccess; /* # unsuccessful connection attempts */
++int do_callback; /* != 0 if we should do callback next */
++int doing_callback; /* != 0 if we are doing callback */
++TDB_CONTEXT *pppdb; /* database for storing status etc. */
++char db_key[32];
++
++int (*holdoff_hook) __P((void)) = NULL;
++int (*new_phase_hook) __P((int)) = NULL;
++
++static int conn_running; /* we have a [dis]connector running */
++static int devfd; /* fd of underlying device */
++static int fd_ppp = -1; /* fd for talking PPP */
++static int fd_loop; /* fd for getting demand-dial packets */
++
++int phase; /* where the link is at */
++int kill_link;
++int open_ccp_flag;
++int listen_time;
++int got_sigusr2;
++int got_sigterm;
++int got_sighup;
++
++static int waiting;
++static sigjmp_buf sigjmp;
++
++char **script_env; /* Env. variable values for scripts */
++int s_env_nalloc; /* # words avail at script_env */
++
++u_char outpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for outgoing packet */
++u_char inpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for incoming packet */
++
++static int n_children; /* # child processes still running */
++static int got_sigchld; /* set if we have received a SIGCHLD */
++
++int privopen; /* don't lock, open device as root */
++
++char *no_ppp_msg = &quot;Sorry - this system lacks PPP kernel support\n&quot;;
++
++GIDSET_TYPE groups[NGROUPS_MAX];/* groups the user is in */
++int ngroups; /* How many groups valid in groups */
++
++static struct timeval start_time; /* Time when link was started. */
++
++struct pppd_stats link_stats;
++int link_connect_time;
++int link_stats_valid;
++
++/*
++ * We maintain a list of child process pids and
++ * functions to call when they exit.
++ */
++struct subprocess {
++ pid_t pid;
++ char *prog;
++ void (*done) __P((void *));
++ void *arg;
++ struct subprocess *next;
++};
++
++static struct subprocess *children;
++
++/* Prototypes for procedures local to this file. */
++
++static void setup_signals __P((void));
++static void create_pidfile __P((void));
++static void create_linkpidfile __P((void));
++static void cleanup __P((void));
++static void get_input __P((void));
++static void calltimeout __P((void));
++static struct timeval *timeleft __P((struct timeval *));
++static void kill_my_pg __P((int));
++static void hup __P((int));
++static void term __P((int));
++static void chld __P((int));
++static void toggle_debug __P((int));
++static void open_ccp __P((int));
++static void bad_signal __P((int));
++static void holdoff_end __P((void *));
++static int reap_kids __P((int waitfor));
++static void update_db_entry __P((void));
++static void add_db_key __P((const char *));
++static void delete_db_key __P((const char *));
++static void cleanup_db __P((void));
++static void handle_events __P((void));
++
++extern char *ttyname __P((int));
++extern char *getlogin __P((void));
++int main __P((int, char *[]));
++
++#ifdef ultrix
++#undef O_NONBLOCK
++#define O_NONBLOCK O_NDELAY
++#endif
++
++#ifdef ULTRIX
++#define setlogmask(x)
++#endif
++
++/*
++ * PPP Data Link Layer &quot;protocol&quot; table.
++ * One entry per supported protocol.
++ * The last entry must be NULL.
++ */
++struct protent *protocols[] = {
++ &amp;lcp_protent,
++ &amp;pap_protent,
++ &amp;chap_protent,
++#ifdef CBCP_SUPPORT
++ &amp;cbcp_protent,
++#endif
++ &amp;ipcp_protent,
++#ifdef INET6
++ &amp;ipv6cp_protent,
++#endif
++ &amp;ccp_protent,
++#ifdef IPX_CHANGE
++ &amp;ipxcp_protent,
++#endif
++#ifdef AT_CHANGE
++ &amp;atcp_protent,
++#endif
++ NULL
++};
++
++/*
++ * If PPP_DRV_NAME is not defined, use the default &quot;ppp&quot; as the device name.
++ */
++#if !defined(PPP_DRV_NAME)
++#define PPP_DRV_NAME &quot;ppp&quot;
++#endif /* !defined(PPP_DRV_NAME) */
++
++int
++main(argc, argv)
++ int argc;
++ char *argv[];
++{
++ int i, t;
++ char *p;
++ struct passwd *pw;
++ struct protent *protp;
++ char numbuf[16];
++
++ new_phase(PHASE_INITIALIZE);
++
++ /*
++ * Ensure that fds 0, 1, 2 are open, to /dev/null if nowhere else.
++ * This way we can close 0, 1, 2 in detach() without clobbering
++ * a fd that we are using.
++ */
++ if ((i = open(&quot;/dev/null&quot;, O_RDWR)) &gt;= 0) {
++ while (0 &lt;= i &amp;&amp; i &lt;= 2)
++ i = dup(i);
++ if (i &gt;= 0)
++ close(i);
++ }
++
++ script_env = NULL;
++
++ /* Initialize syslog facilities */
++ reopen_log();
++
++ if (gethostname(hostname, MAXNAMELEN) &lt; 0 ) {
++ option_error(&quot;Couldn't get hostname: %m&quot;);
++ exit(1);
++ }
++ hostname[MAXNAMELEN-1] = 0;
++
++ /* make sure we don't create world or group writable files. */
++ umask(umask(0777) | 022);
++
++ uid = getuid();
++ privileged = uid == 0;
++ slprintf(numbuf, sizeof(numbuf), &quot;%d&quot;, uid);
++ script_setenv(&quot;ORIG_UID&quot;, numbuf, 0);
++
++ ngroups = getgroups(NGROUPS_MAX, groups);
++
++ /*
++ * Initialize magic number generator now so that protocols may
++ * use magic numbers in initialization.
++ */
++ magic_init();
++
++ /*
++ * Initialize each protocol.
++ */
++ for (i = 0; (protp = protocols[i]) != NULL; ++i)
++ (*protp-&gt;init)(0);
++
++ /*
++ * Initialize the default channel.
++ */
++ tty_init();
++
++ progname = *argv;
++
++ /*
++ * Parse, in order, the system options file, the user's options file,
++ * and the command line arguments.
++ */
++ if (!options_from_file(_PATH_SYSOPTIONS, !privileged, 0, 1)
++ || !options_from_user()
++ || !parse_args(argc-1, argv+1))
++ exit(EXIT_OPTION_ERROR);
++ devnam_fixed = 1; /* can no longer change device name */
++
++ /*
++ * Work out the device name, if it hasn't already been specified,
++ * and parse the tty's options file.
++ */
++ if (the_channel-&gt;process_extra_options)
++ (*the_channel-&gt;process_extra_options)();
++
++ if (debug)
++ setlogmask(LOG_UPTO(LOG_DEBUG));
++
++ /*
++ * Check that we are running as root.
++ */
++ if (geteuid() != 0) {
++ option_error(&quot;must be root to run %s, since it is not setuid-root&quot;,
++ argv[0]);
++ exit(EXIT_NOT_ROOT);
++ }
++
++ if (!ppp_available()) {
++ option_error(&quot;%s&quot;, no_ppp_msg);
++ exit(EXIT_NO_KERNEL_SUPPORT);
++ }
++
++ /*
++ * Check that the options given are valid and consistent.
++ */
++ check_options();
++ if (!sys_check_options())
++ exit(EXIT_OPTION_ERROR);
++ auth_check_options();
++#ifdef HAVE_MULTILINK
++ mp_check_options();
++#endif
++ for (i = 0; (protp = protocols[i]) != NULL; ++i)
++ if (protp-&gt;check_options != NULL)
++ (*protp-&gt;check_options)();
++ if (the_channel-&gt;check_options)
++ (*the_channel-&gt;check_options)();
++
++
++ if (dump_options || dryrun) {
++ init_pr_log(NULL, LOG_INFO);
++ print_options(pr_log, NULL);
++ end_pr_log();
++ if (dryrun)
++ die(0);
++ }
++
++ /*
++ * Initialize system-dependent stuff.
++ */
++ sys_init();
++
++ pppdb = tdb_open(_PATH_PPPDB, 0, 0, O_RDWR|O_CREAT, 0644);
++ if (pppdb != NULL) {
++ slprintf(db_key, sizeof(db_key), &quot;pppd%d&quot;, getpid());
++ update_db_entry();
++ } else {
++ warn(&quot;Warning: couldn't open ppp database %s&quot;, _PATH_PPPDB);
++ if (multilink) {
++ warn(&quot;Warning: disabling multilink&quot;);
++ multilink = 0;
++ }
++ }
++
++ /*
++ * Detach ourselves from the terminal, if required,
++ * and identify who is running us.
++ */
++ if (!nodetach &amp;&amp; !updetach)
++ detach();
++ p = getlogin();
++ if (p == NULL) {
++ pw = getpwuid(uid);
++ if (pw != NULL &amp;&amp; pw-&gt;pw_name != NULL)
++ p = pw-&gt;pw_name;
++ else
++ p = &quot;(unknown)&quot;;
++ }
++ syslog(LOG_NOTICE, &quot;pppd %s started by %s, uid %d&quot;, VERSION, p, uid);
++ script_setenv(&quot;PPPLOGNAME&quot;, p, 0);
++
++ if (devnam[0])
++ script_setenv(&quot;DEVICE&quot;, devnam, 1);
++ slprintf(numbuf, sizeof(numbuf), &quot;%d&quot;, getpid());
++ script_setenv(&quot;PPPD_PID&quot;, numbuf, 1);
++
++ setup_signals();
++
++ waiting = 0;
++
++ create_linkpidfile();
++
++ /*
++ * If we're doing dial-on-demand, set up the interface now.
++ */
++ if (demand) {
++ /*
++ * Open the loopback channel and set it up to be the ppp interface.
++ */
++ tdb_writelock(pppdb);
++ fd_loop = open_ppp_loopback();
++ set_ifunit(1);
++ tdb_writeunlock(pppdb);
++
++ /*
++ * Configure the interface and mark it up, etc.
++ */
++ demand_conf();
++ }
++
++ do_callback = 0;
++ for (;;) {
++
++ listen_time = 0;
++ need_holdoff = 1;
++ devfd = -1;
++ status = EXIT_OK;
++ ++unsuccess;
++ doing_callback = do_callback;
++ do_callback = 0;
++
++ if (demand &amp;&amp; !doing_callback) {
++ /*
++ * Don't do anything until we see some activity.
++ */
++ new_phase(PHASE_DORMANT);
++ demand_unblock();
++ add_fd(fd_loop);
++ for (;;) {
++ handle_events();
++ if (kill_link &amp;&amp; !persist)
++ break;
++ if (get_loop_output())
++ break;
++ }
++ remove_fd(fd_loop);
++ if (kill_link &amp;&amp; !persist)
++ break;
++
++ /*
++ * Now we want to bring up the link.
++ */
++ demand_block();
++ info(&quot;Starting link&quot;);
++ }
++
++ new_phase(PHASE_SERIALCONN);
++
++ devfd = the_channel-&gt;connect();
++ if (devfd &lt; 0)
++ goto fail;
++
++ /* set up the serial device as a ppp interface */
++ tdb_writelock(pppdb);
++ fd_ppp = the_channel-&gt;establish_ppp(devfd);
++ if (fd_ppp &lt; 0) {
++ tdb_writeunlock(pppdb);
++ status = EXIT_FATAL_ERROR;
++ goto disconnect;
++ }
++
++ if (!demand &amp;&amp; ifunit &gt;= 0)
++ set_ifunit(1);
++ tdb_writeunlock(pppdb);
++
++ /*
++ * Start opening the connection and wait for
++ * incoming events (reply, timeout, etc.).
++ */
++ notice(&quot;Connect: %s &lt;--&gt; %s&quot;, ifname, ppp_devnam);
++ gettimeofday(&amp;start_time, NULL);
++ link_stats_valid = 0;
++ script_unsetenv(&quot;CONNECT_TIME&quot;);
++ script_unsetenv(&quot;BYTES_SENT&quot;);
++ script_unsetenv(&quot;BYTES_RCVD&quot;);
++ lcp_lowerup(0);
++
++ add_fd(fd_ppp);
++ lcp_open(0); /* Start protocol */
++ status = EXIT_NEGOTIATION_FAILED;
++ new_phase(PHASE_ESTABLISH);
++ while (phase != PHASE_DEAD) {
++ handle_events();
++ get_input();
++ if (kill_link)
++ lcp_close(0, &quot;User request&quot;);
++ if (open_ccp_flag) {
++ if (phase == PHASE_NETWORK || phase == PHASE_RUNNING) {
++ ccp_fsm[0].flags = OPT_RESTART; /* clears OPT_SILENT */
++ (*ccp_protent.open)(0);
++ }
++ }
++ }
++
++ /*
++ * Print connect time and statistics.
++ */
++ if (link_stats_valid) {
++ int t = (link_connect_time + 5) / 6; /* 1/10ths of minutes */
++ info(&quot;Connect time %d.%d minutes.&quot;, t/10, t%10);
++ info(&quot;Sent %u bytes, received %u bytes.&quot;,
++ link_stats.bytes_out, link_stats.bytes_in);
++ }
++
++ /*
++ * Delete pid file before disestablishing ppp. Otherwise it
++ * can happen that another pppd gets the same unit and then
++ * we delete its pid file.
++ */
++ if (!demand) {
++ if (pidfilename[0] != 0
++ &amp;&amp; unlink(pidfilename) &lt; 0 &amp;&amp; errno != ENOENT)
++ warn(&quot;unable to delete pid file %s: %m&quot;, pidfilename);
++ pidfilename[0] = 0;
++ }
++
++ /*
++ * If we may want to bring the link up again, transfer
++ * the ppp unit back to the loopback. Set the
++ * real serial device back to its normal mode of operation.
++ */
++ remove_fd(fd_ppp);
++ clean_check();
++ the_channel-&gt;disestablish_ppp(devfd);
++ fd_ppp = -1;
++ if (!hungup)
++ lcp_lowerdown(0);
++ if (!demand)
++ script_unsetenv(&quot;IFNAME&quot;);
++
++ /*
++ * Run disconnector script, if requested.
++ * XXX we may not be able to do this if the line has hung up!
++ */
++ disconnect:
++ new_phase(PHASE_DISCONNECT);
++ the_channel-&gt;disconnect();
++
++ fail:
++ if (the_channel-&gt;cleanup)
++ (*the_channel-&gt;cleanup)();
++
++ if (!demand) {
++ if (pidfilename[0] != 0
++ &amp;&amp; unlink(pidfilename) &lt; 0 &amp;&amp; errno != ENOENT)
++ warn(&quot;unable to delete pid file %s: %m&quot;, pidfilename);
++ pidfilename[0] = 0;
++ }
++
++ if (!persist || (maxfail &gt; 0 &amp;&amp; unsuccess &gt;= maxfail))
++ break;
++
++ if (demand)
++ demand_discard();
++ t = need_holdoff? holdoff: 0;
++ if (holdoff_hook)
++ t = (*holdoff_hook)();
++ if (t &gt; 0) {
++ new_phase(PHASE_HOLDOFF);
++ TIMEOUT(holdoff_end, NULL, t);
++ do {
++ handle_events();
++ if (kill_link)
++ new_phase(PHASE_DORMANT); /* allow signal to end holdoff */
++ } while (phase == PHASE_HOLDOFF);
++ if (!persist)
++ break;
++ }
++ }
++
++ /* Wait for scripts to finish */
++ /* XXX should have a timeout here */
++ while (n_children &gt; 0) {
++ if (debug) {
++ struct subprocess *chp;
++ dbglog(&quot;Waiting for %d child processes...&quot;, n_children);
++ for (chp = children; chp != NULL; chp = chp-&gt;next)
++ dbglog(&quot; script %s, pid %d&quot;, chp-&gt;prog, chp-&gt;pid);
++ }
++ if (reap_kids(1) &lt; 0)
++ break;
++ }
++
++ die(status);
++ return 0;
++}
++
++/*
++ * handle_events - wait for something to happen and respond to it.
++ */
++static void
++handle_events()
++{
++ struct timeval timo;
++ sigset_t mask;
++
++ kill_link = open_ccp_flag = 0;
++ if (sigsetjmp(sigjmp, 1) == 0) {
++ sigprocmask(SIG_BLOCK, &amp;mask, NULL);
++ if (got_sighup || got_sigterm || got_sigusr2 || got_sigchld) {
++ sigprocmask(SIG_UNBLOCK, &amp;mask, NULL);
++ } else {
++ waiting = 1;
++ sigprocmask(SIG_UNBLOCK, &amp;mask, NULL);
++ wait_input(timeleft(&amp;timo));
++ }
++ }
++ waiting = 0;
++ calltimeout();
++ if (got_sighup) {
++ kill_link = 1;
++ got_sighup = 0;
++ if (status != EXIT_HANGUP)
++ status = EXIT_USER_REQUEST;
++ }
++ if (got_sigterm) {
++ kill_link = 1;
++ persist = 0;
++ status = EXIT_USER_REQUEST;
++ got_sigterm = 0;
++ }
++ if (got_sigchld) {
++ reap_kids(0); /* Don't leave dead kids lying around */
++ got_sigchld = 0;
++ }
++ if (got_sigusr2) {
++ open_ccp_flag = 1;
++ got_sigusr2 = 0;
++ }
++}
++
++/*
++ * setup_signals - initialize signal handling.
++ */
++static void
++setup_signals()
++{
++ struct sigaction sa;
++ sigset_t mask;
++
++ /*
++ * Compute mask of all interesting signals and install signal handlers
++ * for each. Only one signal handler may be active at a time. Therefore,
++ * all other signals should be masked when any handler is executing.
++ */
++ sigemptyset(&amp;mask);
++ sigaddset(&amp;mask, SIGHUP);
++ sigaddset(&amp;mask, SIGINT);
++ sigaddset(&amp;mask, SIGTERM);
++ sigaddset(&amp;mask, SIGCHLD);
++ sigaddset(&amp;mask, SIGUSR2);
++
++#define SIGNAL(s, handler) do { \
++ sa.sa_handler = handler; \
++ if (sigaction(s, &amp;sa, NULL) &lt; 0) \
++ fatal(&quot;Couldn't establish signal handler (%d): %m&quot;, s); \
++ } while (0)
++
++ sa.sa_mask = mask;
++ sa.sa_flags = 0;
++ SIGNAL(SIGHUP, hup); /* Hangup */
++ SIGNAL(SIGINT, term); /* Interrupt */
++ SIGNAL(SIGTERM, term); /* Terminate */
++ SIGNAL(SIGCHLD, chld);
++
++ SIGNAL(SIGUSR1, toggle_debug); /* Toggle debug flag */
++ SIGNAL(SIGUSR2, open_ccp); /* Reopen CCP */
++
++ /*
++ * Install a handler for other signals which would otherwise
++ * cause pppd to exit without cleaning up.
++ */
++ SIGNAL(SIGABRT, bad_signal);
++ SIGNAL(SIGALRM, bad_signal);
++ SIGNAL(SIGFPE, bad_signal);
++ SIGNAL(SIGILL, bad_signal);
++ SIGNAL(SIGPIPE, bad_signal);
++ SIGNAL(SIGQUIT, bad_signal);
++ SIGNAL(SIGSEGV, bad_signal);
++#ifdef SIGBUS
++ SIGNAL(SIGBUS, bad_signal);
++#endif
++#ifdef SIGEMT
++ SIGNAL(SIGEMT, bad_signal);
++#endif
++#ifdef SIGPOLL
++ SIGNAL(SIGPOLL, bad_signal);
++#endif
++#ifdef SIGPROF
++ SIGNAL(SIGPROF, bad_signal);
++#endif
++#ifdef SIGSYS
++ SIGNAL(SIGSYS, bad_signal);
++#endif
++#ifdef SIGTRAP
++ SIGNAL(SIGTRAP, bad_signal);
++#endif
++#ifdef SIGVTALRM
++ SIGNAL(SIGVTALRM, bad_signal);
++#endif
++#ifdef SIGXCPU
++ SIGNAL(SIGXCPU, bad_signal);
++#endif
++#ifdef SIGXFSZ
++ SIGNAL(SIGXFSZ, bad_signal);
++#endif
++
++ /*
++ * Apparently we can get a SIGPIPE when we call syslog, if
++ * syslogd has died and been restarted. Ignoring it seems
++ * be sufficient.
++ */
++ signal(SIGPIPE, SIG_IGN);
++}
++
++/*
++ * set_ifunit - do things we need to do once we know which ppp
++ * unit we are using.
++ */
++void
++set_ifunit(iskey)
++ int iskey;
++{
++ info(&quot;Using interface %s%d&quot;, PPP_DRV_NAME, ifunit);
++ slprintf(ifname, sizeof(ifname), &quot;%s%d&quot;, PPP_DRV_NAME, ifunit);
++ script_setenv(&quot;IFNAME&quot;, ifname, iskey);
++ if (iskey) {
++ create_pidfile(); /* write pid to file */
++ create_linkpidfile();
++ }
++}
++
++/*
++ * detach - detach us from the controlling terminal.
++ */
++void
++detach()
++{
++ int pid;
++ char numbuf[16];
++
++ if (detached)
++ return;
++ if ((pid = fork()) &lt; 0) {
++ error(&quot;Couldn't detach (fork failed: %m)&quot;);
++ die(1); /* or just return? */
++ }
++ if (pid != 0) {
++ /* parent */
++ notify(pidchange, pid);
++ exit(0); /* parent dies */
++ }
++ setsid();
++ chdir(&quot;/&quot;);
++ close(0);
++ close(1);
++ close(2);
++ detached = 1;
++ if (log_default)
++ log_to_fd = -1;
++ /* update pid files if they have been written already */
++ if (pidfilename[0])
++ create_pidfile();
++ if (linkpidfile[0])
++ create_linkpidfile();
++ slprintf(numbuf, sizeof(numbuf), &quot;%d&quot;, getpid());
++ script_setenv(&quot;PPPD_PID&quot;, numbuf, 1);
++}
++
++/*
++ * reopen_log - (re)open our connection to syslog.
++ */
++void
++reopen_log()
++{
++#ifdef ULTRIX
++ openlog(&quot;pppd&quot;, LOG_PID);
++#else
++ openlog(&quot;pppd&quot;, LOG_PID | LOG_NDELAY, LOG_PPP);
++ setlogmask(LOG_UPTO(LOG_INFO));
++#endif
++}
++
++/*
++ * Create a file containing our process ID.
++ */
++static void
++create_pidfile()
++{
++ FILE *pidfile;
++
++ slprintf(pidfilename, sizeof(pidfilename), &quot;%s%s.pid&quot;,
++ _PATH_VARRUN, ifname);
++ if ((pidfile = fopen(pidfilename, &quot;w&quot;)) != NULL) {
++ fprintf(pidfile, &quot;%d\n&quot;, getpid());
++ (void) fclose(pidfile);
++ } else {
++ error(&quot;Failed to create pid file %s: %m&quot;, pidfilename);
++ pidfilename[0] = 0;
++ }
++}
++
++static void
++create_linkpidfile()
++{
++ FILE *pidfile;
++
++ if (linkname[0] == 0)
++ return;
++ script_setenv(&quot;LINKNAME&quot;, linkname, 1);
++ slprintf(linkpidfile, sizeof(linkpidfile), &quot;%sppp-%s.pid&quot;,
++ _PATH_VARRUN, linkname);
++ if ((pidfile = fopen(linkpidfile, &quot;w&quot;)) != NULL) {
++ fprintf(pidfile, &quot;%d\n&quot;, getpid());
++ if (ifname[0])
++ fprintf(pidfile, &quot;%s\n&quot;, ifname);
++ (void) fclose(pidfile);
++ } else {
++ error(&quot;Failed to create pid file %s: %m&quot;, linkpidfile);
++ linkpidfile[0] = 0;
++ }
++}
++
++/*
++ * holdoff_end - called via a timeout when the holdoff period ends.
++ */
++static void
++holdoff_end(arg)
++ void *arg;
++{
++ new_phase(PHASE_DORMANT);
++}
++
++/* List of protocol names, to make our messages a little more informative. */
++struct protocol_list {
++ u_short proto;
++ const char *name;
++} protocol_list[] = {
++ { 0x21, &quot;IP&quot; },
++ { 0x23, &quot;OSI Network Layer&quot; },
++ { 0x25, &quot;Xerox NS IDP&quot; },
++ { 0x27, &quot;DECnet Phase IV&quot; },
++ { 0x29, &quot;Appletalk&quot; },
++ { 0x2b, &quot;Novell IPX&quot; },
++ { 0x2d, &quot;VJ compressed TCP/IP&quot; },
++ { 0x2f, &quot;VJ uncompressed TCP/IP&quot; },
++ { 0x31, &quot;Bridging PDU&quot; },
++ { 0x33, &quot;Stream Protocol ST-II&quot; },
++ { 0x35, &quot;Banyan Vines&quot; },
++ { 0x39, &quot;AppleTalk EDDP&quot; },
++ { 0x3b, &quot;AppleTalk SmartBuffered&quot; },
++ { 0x3d, &quot;Multi-Link&quot; },
++ { 0x3f, &quot;NETBIOS Framing&quot; },
++ { 0x41, &quot;Cisco Systems&quot; },
++ { 0x43, &quot;Ascom Timeplex&quot; },
++ { 0x45, &quot;Fujitsu Link Backup and Load Balancing (LBLB)&quot; },
++ { 0x47, &quot;DCA Remote Lan&quot; },
++ { 0x49, &quot;Serial Data Transport Protocol (PPP-SDTP)&quot; },
++ { 0x4b, &quot;SNA over 802.2&quot; },
++ { 0x4d, &quot;SNA&quot; },
++ { 0x4f, &quot;IP6 Header Compression&quot; },
++ { 0x6f, &quot;Stampede Bridging&quot; },
++ { 0xfb, &quot;single-link compression&quot; },
++ { 0xfd, &quot;1st choice compression&quot; },
++ { 0x0201, &quot;802.1d Hello Packets&quot; },
++ { 0x0203, &quot;IBM Source Routing BPDU&quot; },
++ { 0x0205, &quot;DEC LANBridge100 Spanning Tree&quot; },
++ { 0x0231, &quot;Luxcom&quot; },
++ { 0x0233, &quot;Sigma Network Systems&quot; },
++ { 0x8021, &quot;Internet Protocol Control Protocol&quot; },
++ { 0x8023, &quot;OSI Network Layer Control Protocol&quot; },
++ { 0x8025, &quot;Xerox NS IDP Control Protocol&quot; },
++ { 0x8027, &quot;DECnet Phase IV Control Protocol&quot; },
++ { 0x8029, &quot;Appletalk Control Protocol&quot; },
++ { 0x802b, &quot;Novell IPX Control Protocol&quot; },
++ { 0x8031, &quot;Bridging NCP&quot; },
++ { 0x8033, &quot;Stream Protocol Control Protocol&quot; },
++ { 0x8035, &quot;Banyan Vines Control Protocol&quot; },
++ { 0x803d, &quot;Multi-Link Control Protocol&quot; },
++ { 0x803f, &quot;NETBIOS Framing Control Protocol&quot; },
++ { 0x8041, &quot;Cisco Systems Control Protocol&quot; },
++ { 0x8043, &quot;Ascom Timeplex&quot; },
++ { 0x8045, &quot;Fujitsu LBLB Control Protocol&quot; },
++ { 0x8047, &quot;DCA Remote Lan Network Control Protocol (RLNCP)&quot; },
++ { 0x8049, &quot;Serial Data Control Protocol (PPP-SDCP)&quot; },
++ { 0x804b, &quot;SNA over 802.2 Control Protocol&quot; },
++ { 0x804d, &quot;SNA Control Protocol&quot; },
++ { 0x804f, &quot;IP6 Header Compression Control Protocol&quot; },
++ { 0x006f, &quot;Stampede Bridging Control Protocol&quot; },
++ { 0x80fb, &quot;Single Link Compression Control Protocol&quot; },
++ { 0x80fd, &quot;Compression Control Protocol&quot; },
++ { 0xc021, &quot;Link Control Protocol&quot; },
++ { 0xc023, &quot;Password Authentication Protocol&quot; },
++ { 0xc025, &quot;Link Quality Report&quot; },
++ { 0xc027, &quot;Shiva Password Authentication Protocol&quot; },
++ { 0xc029, &quot;CallBack Control Protocol (CBCP)&quot; },
++ { 0xc081, &quot;Container Control Protocol&quot; },
++ { 0xc223, &quot;Challenge Handshake Authentication Protocol&quot; },
++ { 0xc281, &quot;Proprietary Authentication Protocol&quot; },
++ { 0, NULL },
++};
++
++/*
++ * protocol_name - find a name for a PPP protocol.
++ */
++const char *
++protocol_name(proto)
++ int proto;
++{
++ struct protocol_list *lp;
++
++ for (lp = protocol_list; lp-&gt;proto != 0; ++lp)
++ if (proto == lp-&gt;proto)
++ return lp-&gt;name;
++ return NULL;
++}
++
++/*
++ * get_input - called when incoming data is available.
++ */
++static void
++get_input()
++{
++ int len, i;
++ u_char *p;
++ u_short protocol;
++ struct protent *protp;
++
++ p = inpacket_buf; /* point to beginning of packet buffer */
++
++ len = read_packet(inpacket_buf);
++ if (len &lt; 0)
++ return;
++
++ if (len == 0) {
++ notice(&quot;Modem hangup&quot;);
++ hungup = 1;
++ status = EXIT_HANGUP;
++ lcp_lowerdown(0); /* serial link is no longer available */
++ link_terminated(0);
++ return;
++ }
++
++ if (debug /*&amp;&amp; (debugflags &amp; DBG_INPACKET)*/)
++ dbglog(&quot;rcvd %P&quot;, p, len);
++
++ if (len &lt; PPP_HDRLEN) {
++ MAINDEBUG((&quot;io(): Received short packet.&quot;));
++ return;
++ }
++
++ p += 2; /* Skip address and control */
++ GETSHORT(protocol, p);
++ len -= PPP_HDRLEN;
++
++ /*
++ * Toss all non-LCP packets unless LCP is OPEN.
++ */
++ if (protocol != PPP_LCP &amp;&amp; lcp_fsm[0].state != OPENED) {
++ MAINDEBUG((&quot;get_input: Received non-LCP packet when LCP not open.&quot;));
++ return;
++ }
++
++ /*
++ * Until we get past the authentication phase, toss all packets
++ * except LCP, LQR and authentication packets.
++ */
++ if (phase &lt;= PHASE_AUTHENTICATE
++ &amp;&amp; !(protocol == PPP_LCP || protocol == PPP_LQR
++ || protocol == PPP_PAP || protocol == PPP_CHAP)) {
++ MAINDEBUG((&quot;get_input: discarding proto 0x%x in phase %d&quot;,
++ protocol, phase));
++ return;
++ }
++
++ /*
++ * Upcall the proper protocol input routine.
++ */
++ for (i = 0; (protp = protocols[i]) != NULL; ++i) {
++ if (protp-&gt;protocol == protocol &amp;&amp; protp-&gt;enabled_flag) {
++ (*protp-&gt;input)(0, p, len);
++ return;
++ }
++ if (protocol == (protp-&gt;protocol &amp; ~0x8000) &amp;&amp; protp-&gt;enabled_flag
++ &amp;&amp; protp-&gt;datainput != NULL) {
++ (*protp-&gt;datainput)(0, p, len);
++ return;
++ }
++ }
++
++ if (debug) {
++ const char *pname = protocol_name(protocol);
++ if (pname != NULL)
++ warn(&quot;Unsupported protocol '%s' (0x%x) received&quot;, pname, protocol);
++ else
++ warn(&quot;Unsupported protocol 0x%x received&quot;, protocol);
++ }
++ lcp_sprotrej(0, p - PPP_HDRLEN, len + PPP_HDRLEN);
++}
++
++/*
++ * new_phase - signal the start of a new phase of pppd's operation.
++ */
++void
++new_phase(p)
++ int p;
++{
++ phase = p;
++ if (new_phase_hook)
++ (*new_phase_hook)(p);
++ notify(phasechange, p);
++}
++
++/*
++ * die - clean up state and exit with the specified status.
++ */
++void
++die(status)
++ int status;
++{
++ cleanup();
++ notify(exitnotify, status);
++ syslog(LOG_INFO, &quot;Exit.&quot;);
++ exit(status);
++}
++
++/*
++ * cleanup - restore anything which needs to be restored before we exit
++ */
++/* ARGSUSED */
++static void
++cleanup()
++{
++ sys_cleanup();
++
++ if (fd_ppp &gt;= 0)
++ the_channel-&gt;disestablish_ppp(devfd);
++ if (the_channel-&gt;cleanup)
++ (*the_channel-&gt;cleanup)();
++
++ if (pidfilename[0] != 0 &amp;&amp; unlink(pidfilename) &lt; 0 &amp;&amp; errno != ENOENT)
++ warn(&quot;unable to delete pid file %s: %m&quot;, pidfilename);
++ pidfilename[0] = 0;
++ if (linkpidfile[0] != 0 &amp;&amp; unlink(linkpidfile) &lt; 0 &amp;&amp; errno != ENOENT)
++ warn(&quot;unable to delete pid file %s: %m&quot;, linkpidfile);
++ linkpidfile[0] = 0;
++
++ if (pppdb != NULL)
++ cleanup_db();
++}
++
++/*
++ * update_link_stats - get stats at link termination.
++ */
++void
++update_link_stats(u)
++ int u;
++{
++ struct timeval now;
++ char numbuf[32];
++
++ if (!get_ppp_stats(u, &amp;link_stats)
++ || gettimeofday(&amp;now, NULL) &lt; 0)
++ return;
++ link_connect_time = now.tv_sec - start_time.tv_sec;
++ link_stats_valid = 1;
++
++ slprintf(numbuf, sizeof(numbuf), &quot;%d&quot;, link_connect_time);
++ script_setenv(&quot;CONNECT_TIME&quot;, numbuf, 0);
++ slprintf(numbuf, sizeof(numbuf), &quot;%d&quot;, link_stats.bytes_out);
++ script_setenv(&quot;BYTES_SENT&quot;, numbuf, 0);
++ slprintf(numbuf, sizeof(numbuf), &quot;%d&quot;, link_stats.bytes_in);
++ script_setenv(&quot;BYTES_RCVD&quot;, numbuf, 0);
++}
++
++
++struct callout {
++ struct timeval c_time; /* time at which to call routine */
++ void *c_arg; /* argument to routine */
++ void (*c_func) __P((void *)); /* routine */
++ struct callout *c_next;
++};
++
++static struct callout *callout = NULL; /* Callout list */
++static struct timeval timenow; /* Current time */
++
++/*
++ * timeout - Schedule a timeout.
++ *
++ * Note that this timeout takes the number of milliseconds, NOT hz (as in
++ * the kernel).
++ */
++void
++timeout(func, arg, secs, usecs)
++ void (*func) __P((void *));
++ void *arg;
++ int secs, usecs;
++{
++ struct callout *newp, *p, **pp;
++
++ MAINDEBUG((&quot;Timeout %p:%p in %d.%03d seconds.&quot;, func, arg,
++ time / 1000, time % 1000));
++
++ /*
++ * Allocate timeout.
++ */
++ if ((newp = (struct callout *) malloc(sizeof(struct callout))) == NULL)
++ fatal(&quot;Out of memory in timeout()!&quot;);
++ newp-&gt;c_arg = arg;
++ newp-&gt;c_func = func;
++ gettimeofday(&amp;timenow, NULL);
++ newp-&gt;c_time.tv_sec = timenow.tv_sec + secs;
++ newp-&gt;c_time.tv_usec = timenow.tv_usec + usecs;
++ if (newp-&gt;c_time.tv_usec &gt;= 1000000) {
++ newp-&gt;c_time.tv_sec += newp-&gt;c_time.tv_usec / 1000000;
++ newp-&gt;c_time.tv_usec %= 1000000;
++ }
++
++ /*
++ * Find correct place and link it in.
++ */
++ for (pp = &amp;callout; (p = *pp); pp = &amp;p-&gt;c_next)
++ if (newp-&gt;c_time.tv_sec &lt; p-&gt;c_time.tv_sec
++ || (newp-&gt;c_time.tv_sec == p-&gt;c_time.tv_sec
++ &amp;&amp; newp-&gt;c_time.tv_usec &lt; p-&gt;c_time.tv_usec))
++ break;
++ newp-&gt;c_next = p;
++ *pp = newp;
++}
++
++
++/*
++ * untimeout - Unschedule a timeout.
++ */
++void
++untimeout(func, arg)
++ void (*func) __P((void *));
++ void *arg;
++{
++ struct callout **copp, *freep;
++
++ MAINDEBUG((&quot;Untimeout %p:%p.&quot;, func, arg));
++
++ /*
++ * Find first matching timeout and remove it from the list.
++ */
++ for (copp = &amp;callout; (freep = *copp); copp = &amp;freep-&gt;c_next)
++ if (freep-&gt;c_func == func &amp;&amp; freep-&gt;c_arg == arg) {
++ *copp = freep-&gt;c_next;
++ free((char *) freep);
++ break;
++ }
++}
++
++
++/*
++ * calltimeout - Call any timeout routines which are now due.
++ */
++static void
++calltimeout()
++{
++ struct callout *p;
++
++ while (callout != NULL) {
++ p = callout;
++
++ if (gettimeofday(&amp;timenow, NULL) &lt; 0)
++ fatal(&quot;Failed to get time of day: %m&quot;);
++ if (!(p-&gt;c_time.tv_sec &lt; timenow.tv_sec
++ || (p-&gt;c_time.tv_sec == timenow.tv_sec
++ &amp;&amp; p-&gt;c_time.tv_usec &lt;= timenow.tv_usec)))
++ break; /* no, it's not time yet */
++
++ callout = p-&gt;c_next;
++ (*p-&gt;c_func)(p-&gt;c_arg);
++
++ free((char *) p);
++ }
++}
++
++
++/*
++ * timeleft - return the length of time until the next timeout is due.
++ */
++static struct timeval *
++timeleft(tvp)
++ struct timeval *tvp;
++{
++ if (callout == NULL)
++ return NULL;
++
++ gettimeofday(&amp;timenow, NULL);
++ tvp-&gt;tv_sec = callout-&gt;c_time.tv_sec - timenow.tv_sec;
++ tvp-&gt;tv_usec = callout-&gt;c_time.tv_usec - timenow.tv_usec;
++ if (tvp-&gt;tv_usec &lt; 0) {
++ tvp-&gt;tv_usec += 1000000;
++ tvp-&gt;tv_sec -= 1;
++ }
++ if (tvp-&gt;tv_sec &lt; 0)
++ tvp-&gt;tv_sec = tvp-&gt;tv_usec = 0;
++
++ return tvp;
++}
++
++
++/*
++ * kill_my_pg - send a signal to our process group, and ignore it ourselves.
++ */
++static void
++kill_my_pg(sig)
++ int sig;
++{
++ struct sigaction act, oldact;
++
++ act.sa_handler = SIG_IGN;
++ act.sa_flags = 0;
++ kill(0, sig);
++ sigaction(sig, &amp;act, &amp;oldact);
++ sigaction(sig, &amp;oldact, NULL);
++}
++
++
++/*
++ * hup - Catch SIGHUP signal.
++ *
++ * Indicates that the physical layer has been disconnected.
++ * We don't rely on this indication; if the user has sent this
++ * signal, we just take the link down.
++ */
++static void
++hup(sig)
++ int sig;
++{
++ info(&quot;Hangup (SIGHUP)&quot;);
++ got_sighup = 1;
++ if (conn_running)
++ /* Send the signal to the [dis]connector process(es) also */
++ kill_my_pg(sig);
++ notify(sigreceived, sig);
++ if (waiting)
++ siglongjmp(sigjmp, 1);
++}
++
++
++/*
++ * term - Catch SIGTERM signal and SIGINT signal (^C/del).
++ *
++ * Indicates that we should initiate a graceful disconnect and exit.
++ */
++/*ARGSUSED*/
++static void
++term(sig)
++ int sig;
++{
++ info(&quot;Terminating on signal %d.&quot;, sig);
++ got_sigterm = 1;
++ if (conn_running)
++ /* Send the signal to the [dis]connector process(es) also */
++ kill_my_pg(sig);
++ notify(sigreceived, sig);
++ if (waiting)
++ siglongjmp(sigjmp, 1);
++}
++
++
++/*
++ * chld - Catch SIGCHLD signal.
++ * Sets a flag so we will call reap_kids in the mainline.
++ */
++static void
++chld(sig)
++ int sig;
++{
++ got_sigchld = 1;
++ if (waiting)
++ siglongjmp(sigjmp, 1);
++}
++
++
++/*
++ * toggle_debug - Catch SIGUSR1 signal.
++ *
++ * Toggle debug flag.
++ */
++/*ARGSUSED*/
++static void
++toggle_debug(sig)
++ int sig;
++{
++ debug = !debug;
++ if (debug) {
++ setlogmask(LOG_UPTO(LOG_DEBUG));
++ } else {
++ setlogmask(LOG_UPTO(LOG_WARNING));
++ }
++}
++
++
++/*
++ * open_ccp - Catch SIGUSR2 signal.
++ *
++ * Try to (re)negotiate compression.
++ */
++/*ARGSUSED*/
++static void
++open_ccp(sig)
++ int sig;
++{
++ got_sigusr2 = 1;
++ if (waiting)
++ siglongjmp(sigjmp, 1);
++}
++
++
++/*
++ * bad_signal - We've caught a fatal signal. Clean up state and exit.
++ */
++static void
++bad_signal(sig)
++ int sig;
++{
++ static int crashed = 0;
++
++ if (crashed)
++ _exit(127);
++ crashed = 1;
++ error(&quot;Fatal signal %d&quot;, sig);
++ if (conn_running)
++ kill_my_pg(SIGTERM);
++ notify(sigreceived, sig);
++ die(127);
++}
++
++
++/*
++ * device_script - run a program to talk to the specified fds
++ * (e.g. to run the connector or disconnector script).
++ * stderr gets connected to the log fd or to the _PATH_CONNERRS file.
++ */
++int
++device_script(program, in, out, dont_wait)
++ char *program;
++ int in, out;
++ int dont_wait;
++{
++ int pid, fd;
++ int status = -1;
++ int errfd;
++
++ ++conn_running;
++ pid = fork();
++
++ if (pid &lt; 0) {
++ --conn_running;
++ error(&quot;Failed to create child process: %m&quot;);
++ return -1;
++ }
++
++ if (pid != 0) {
++ if (dont_wait) {
++ record_child(pid, program, NULL, NULL);
++ status = 0;
++ } else {
++ while (waitpid(pid, &amp;status, 0) &lt; 0) {
++ if (errno == EINTR)
++ continue;
++ fatal(&quot;error waiting for (dis)connection process: %m&quot;);
++ }
++ --conn_running;
++ }
++ return (status == 0 ? 0 : -1);
++ }
++
++ /* here we are executing in the child */
++ /* make sure fds 0, 1, 2 are occupied */
++ while ((fd = dup(in)) &gt;= 0) {
++ if (fd &gt; 2) {
++ close(fd);
++ break;
++ }
++ }
++
++ /* dup in and out to fds &gt; 2 */
++ in = dup(in);
++ out = dup(out);
++ if (log_to_fd &gt;= 0) {
++ errfd = dup(log_to_fd);
++ } else {
++ errfd = open(_PATH_CONNERRS, O_WRONLY | O_APPEND | O_CREAT, 0600);
++ }
++
++ /* close fds 0 - 2 and any others we can think of */
++ close(0);
++ close(1);
++ close(2);
++ sys_close();
++ if (the_channel-&gt;close)
++ (*the_channel-&gt;close)();
++ closelog();
++
++ /* dup the in, out, err fds to 0, 1, 2 */
++ dup2(in, 0);
++ close(in);
++ dup2(out, 1);
++ close(out);
++ if (errfd &gt;= 0) {
++ dup2(errfd, 2);
++ close(errfd);
++ }
++
++ setuid(uid);
++ if (getuid() != uid) {
++ error(&quot;setuid failed&quot;);
++ exit(1);
++ }
++ setgid(getgid());
++ {
++ int argc = 0;
++ char * argv[500];
++ char * ptr = program;
++ while (ptr != NULL) {
++ argv[argc] = ptr;
++ argc++;
++ ptr = strchr(ptr, ' ');
++ if (ptr) {
++ ptr[0] = '\0';
++ ptr++;
++ }
++ }
++ argv[argc] = NULL;
++ execv(argv[0], argv);
++ error(&quot;could not exec %s: %m&quot;, program);
++ exit(99);
++ }
++ /* NOTREACHED */
++}
++
++
++/*
++ * run-program - execute a program with given arguments,
++ * but don't wait for it.
++ * If the program can't be executed, logs an error unless
++ * must_exist is 0 and the program file doesn't exist.
++ * Returns -1 if it couldn't fork, 0 if the file doesn't exist
++ * or isn't an executable plain file, or the process ID of the child.
++ * If done != NULL, (*done)(arg) will be called later (within
++ * reap_kids) iff the return value is &gt; 0.
++ */
++pid_t
++run_program(prog, args, must_exist, done, arg)
++ char *prog;
++ char **args;
++ int must_exist;
++ void (*done) __P((void *));
++ void *arg;
++{
++ int pid;
++ struct stat sbuf;
++
++ /*
++ * First check if the file exists and is executable.
++ * We don't use access() because that would use the
++ * real user-id, which might not be root, and the script
++ * might be accessible only to root.
++ */
++ errno = EINVAL;
++ if (stat(prog, &amp;sbuf) &lt; 0 || !S_ISREG(sbuf.st_mode)
++ || (sbuf.st_mode &amp; (S_IXUSR|S_IXGRP|S_IXOTH)) == 0) {
++ if (must_exist || errno != ENOENT)
++ warn(&quot;Can't execute %s: %m&quot;, prog);
++ return 0;
++ }
++
++ pid = fork();
++ if (pid == -1) {
++ error(&quot;Failed to create child process for %s: %m&quot;, prog);
++ return -1;
++ }
++ if (pid == 0) {
++ int new_fd;
++
++ /* Leave the current location */
++ (void) setsid(); /* No controlling tty. */
++ (void) umask (S_IRWXG|S_IRWXO);
++ (void) chdir (&quot;/&quot;); /* no current directory. */
++ setuid(0); /* set real UID = root */
++ setgid(getegid());
++
++ /* Ensure that nothing of our device environment is inherited. */
++ sys_close();
++ closelog();
++ close (0);
++ close (1);
++ close (2);
++ if (the_channel-&gt;close)
++ (*the_channel-&gt;close)();
++
++ /* Don't pass handles to the PPP device, even by accident. */
++ new_fd = open (_PATH_DEVNULL, O_RDWR);
++ if (new_fd &gt;= 0) {
++ if (new_fd != 0) {
++ dup2 (new_fd, 0); /* stdin &lt;- /dev/null */
++ close (new_fd);
++ }
++ dup2 (0, 1); /* stdout -&gt; /dev/null */
++ dup2 (0, 2); /* stderr -&gt; /dev/null */
++ }
++
++#ifdef BSD
++ /* Force the priority back to zero if pppd is running higher. */
++ if (setpriority (PRIO_PROCESS, 0, 0) &lt; 0)
++ warn(&quot;can't reset priority to 0: %m&quot;);
++#endif
++
++ /* SysV recommends a second fork at this point. */
++
++ /* run the program */
++ execve(prog, args, script_env);
++ if (must_exist || errno != ENOENT) {
++ /* have to reopen the log, there's nowhere else
++ for the message to go. */
++ reopen_log();
++ syslog(LOG_ERR, &quot;Can't execute %s: %m&quot;, prog);
++ closelog();
++ }
++ _exit(-1);
++ }
++
++ if (debug)
++ dbglog(&quot;Script %s started (pid %d)&quot;, prog, pid);
++ record_child(pid, prog, done, arg);
++
++ return pid;
++}
++
++
++/*
++ * record_child - add a child process to the list for reap_kids
++ * to use.
++ */
++void
++record_child(pid, prog, done, arg)
++ int pid;
++ char *prog;
++ void (*done) __P((void *));
++ void *arg;
++{
++ struct subprocess *chp;
++
++ ++n_children;
++
++ chp = (struct subprocess *) malloc(sizeof(struct subprocess));
++ if (chp == NULL) {
++ warn(&quot;losing track of %s process&quot;, prog);
++ } else {
++ chp-&gt;pid = pid;
++ chp-&gt;prog = prog;
++ chp-&gt;done = done;
++ chp-&gt;arg = arg;
++ chp-&gt;next = children;
++ children = chp;
++ }
++}
++
++
++/*
++ * reap_kids - get status from any dead child processes,
++ * and log a message for abnormal terminations.
++ */
++static int
++reap_kids(waitfor)
++ int waitfor;
++{
++ int pid, status;
++ struct subprocess *chp, **prevp;
++
++ if (n_children == 0)
++ return 0;
++ while ((pid = waitpid(-1, &amp;status, (waitfor? 0: WNOHANG))) != -1
++ &amp;&amp; pid != 0) {
++ for (prevp = &amp;children; (chp = *prevp) != NULL; prevp = &amp;chp-&gt;next) {
++ if (chp-&gt;pid == pid) {
++ --n_children;
++ *prevp = chp-&gt;next;
++ break;
++ }
++ }
++ if (WIFSIGNALED(status)) {
++ warn(&quot;Child process %s (pid %d) terminated with signal %d&quot;,
++ (chp? chp-&gt;prog: &quot;??&quot;), pid, WTERMSIG(status));
++ } else if (debug)
++ dbglog(&quot;Script %s finished (pid %d), status = 0x%x&quot;,
++ (chp? chp-&gt;prog: &quot;??&quot;), pid, status);
++ if (chp &amp;&amp; chp-&gt;done)
++ (*chp-&gt;done)(chp-&gt;arg);
++ if (chp)
++ free(chp);
++ }
++ if (pid == -1) {
++ if (errno == ECHILD)
++ return -1;
++ if (errno != EINTR)
++ error(&quot;Error waiting for child process: %m&quot;);
++ }
++ return 0;
++}
++
++/*
++ * add_notifier - add a new function to be called when something happens.
++ */
++void
++add_notifier(notif, func, arg)
++ struct notifier **notif;
++ notify_func func;
++ void *arg;
++{
++ struct notifier *np;
++
++ np = malloc(sizeof(struct notifier));
++ if (np == 0)
++ novm(&quot;notifier struct&quot;);
++ np-&gt;next = *notif;
++ np-&gt;func = func;
++ np-&gt;arg = arg;
++ *notif = np;
++}
++
++/*
++ * remove_notifier - remove a function from the list of things to
++ * be called when something happens.
++ */
++void
++remove_notifier(notif, func, arg)
++ struct notifier **notif;
++ notify_func func;
++ void *arg;
++{
++ struct notifier *np;
++
++ for (; (np = *notif) != 0; notif = &amp;np-&gt;next) {
++ if (np-&gt;func == func &amp;&amp; np-&gt;arg == arg) {
++ *notif = np-&gt;next;
++ free(np);
++ break;
++ }
++ }
++}
++
++/*
++ * notify - call a set of functions registered with add_notify.
++ */
++void
++notify(notif, val)
++ struct notifier *notif;
++ int val;
++{
++ struct notifier *np;
++
++ while ((np = notif) != 0) {
++ notif = np-&gt;next;
++ (*np-&gt;func)(np-&gt;arg, val);
++ }
++}
++
++/*
++ * novm - log an error message saying we ran out of memory, and die.
++ */
++void
++novm(msg)
++ char *msg;
++{
++ fatal(&quot;Virtual memory exhausted allocating %s\n&quot;, msg);
++}
++
++/*
++ * script_setenv - set an environment variable value to be used
++ * for scripts that we run (e.g. ip-up, auth-up, etc.)
++ */
++void
++script_setenv(var, value, iskey)
++ char *var, *value;
++ int iskey;
++{
++ size_t varl = strlen(var);
++ size_t vl = varl + strlen(value) + 2;
++ int i;
++ char *p, *newstring;
++
++ newstring = (char *) malloc(vl+1);
++ if (newstring == 0)
++ return;
++ *newstring++ = iskey;
++ slprintf(newstring, vl, &quot;%s=%s&quot;, var, value);
++
++ /* check if this variable is already set */
++ if (script_env != 0) {
++ for (i = 0; (p = script_env[i]) != 0; ++i) {
++ if (strncmp(p, var, varl) == 0 &amp;&amp; p[varl] == '=') {
++ if (p[-1] &amp;&amp; pppdb != NULL)
++ delete_db_key(p);
++ free(p-1);
++ script_env[i] = newstring;
++ if (iskey &amp;&amp; pppdb != NULL)
++ add_db_key(newstring);
++ update_db_entry();
++ return;
++ }
++ }
++ } else {
++ /* no space allocated for script env. ptrs. yet */
++ i = 0;
++ script_env = (char **) malloc(16 * sizeof(char *));
++ if (script_env == 0)
++ return;
++ s_env_nalloc = 16;
++ }
++
++ /* reallocate script_env with more space if needed */
++ if (i + 1 &gt;= s_env_nalloc) {
++ int new_n = i + 17;
++ char **newenv = (char **) realloc((void *)script_env,
++ new_n * sizeof(char *));
++ if (newenv == 0)
++ return;
++ script_env = newenv;
++ s_env_nalloc = new_n;
++ }
++
++ script_env[i] = newstring;
++ script_env[i+1] = 0;
++
++ if (pppdb != NULL) {
++ if (iskey)
++ add_db_key(newstring);
++ update_db_entry();
++ }
++}
++
++/*
++ * script_unsetenv - remove a variable from the environment
++ * for scripts.
++ */
++void
++script_unsetenv(var)
++ char *var;
++{
++ int vl = strlen(var);
++ int i;
++ char *p;
++
++ if (script_env == 0)
++ return;
++ for (i = 0; (p = script_env[i]) != 0; ++i) {
++ if (strncmp(p, var, vl) == 0 &amp;&amp; p[vl] == '=') {
++ if (p[-1] &amp;&amp; pppdb != NULL)
++ delete_db_key(p);
++ free(p-1);
++ while ((script_env[i] = script_env[i+1]) != 0)
++ ++i;
++ break;
++ }
++ }
++ if (pppdb != NULL)
++ update_db_entry();
++}
++
++/*
++ * update_db_entry - update our entry in the database.
++ */
++static void
++update_db_entry()
++{
++ TDB_DATA key, dbuf;
++ int vlen, i;
++ char *p, *q, *vbuf;
++
++ if (script_env == NULL)
++ return;
++ vlen = 0;
++ for (i = 0; (p = script_env[i]) != 0; ++i)
++ vlen += strlen(p) + 1;
++ vbuf = malloc(vlen);
++ if (vbuf == 0)
++ novm(&quot;database entry&quot;);
++ q = vbuf;
++ for (i = 0; (p = script_env[i]) != 0; ++i)
++ q += slprintf(q, vbuf + vlen - q, &quot;%s;&quot;, p);
++
++ key.dptr = db_key;
++ key.dsize = strlen(db_key);
++ dbuf.dptr = vbuf;
++ dbuf.dsize = vlen;
++ if (tdb_store(pppdb, key, dbuf, TDB_REPLACE))
++ error(&quot;tdb_store failed: %s&quot;, tdb_error(pppdb));
++
++}
++
++/*
++ * add_db_key - add a key that we can use to look up our database entry.
++ */
++static void
++add_db_key(str)
++ const char *str;
++{
++ TDB_DATA key, dbuf;
++
++ key.dptr = (char *) str;
++ key.dsize = strlen(str);
++ dbuf.dptr = db_key;
++ dbuf.dsize = strlen(db_key);
++ if (tdb_store(pppdb, key, dbuf, TDB_REPLACE))
++ error(&quot;tdb_store key failed: %s&quot;, tdb_error(pppdb));
++}
++
++/*
++ * delete_db_key - delete a key for looking up our database entry.
++ */
++static void
++delete_db_key(str)
++ const char *str;
++{
++ TDB_DATA key;
++
++ key.dptr = (char *) str;
++ key.dsize = strlen(str);
++ tdb_delete(pppdb, key);
++}
++
++/*
++ * cleanup_db - delete all the entries we put in the database.
++ */
++static void
++cleanup_db()
++{
++ TDB_DATA key;
++ int i;
++ char *p;
++
++ key.dptr = db_key;
++ key.dsize = strlen(db_key);
++ tdb_delete(pppdb, key);
++ for (i = 0; (p = script_env[i]) != 0; ++i)
++ if (p[-1])
++ delete_db_key(p);
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/main.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/md4.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/md4.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/md4.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,298 @@
++/*
++** ********************************************************************
++** md4.c -- Implementation of MD4 Message Digest Algorithm **
++** Updated: 2/16/90 by Ronald L. Rivest **
++** (C) 1990 RSA Data Security, Inc. **
++** ********************************************************************
++*/
++
++/*
++** To use MD4:
++** -- Include md4.h in your program
++** -- Declare an MDstruct MD to hold the state of the digest
++** computation.
++** -- Initialize MD using MDbegin(&amp;MD)
++** -- For each full block (64 bytes) X you wish to process, call
++** MD4Update(&amp;MD,X,512)
++** (512 is the number of bits in a full block.)
++** -- For the last block (less than 64 bytes) you wish to process,
++** MD4Update(&amp;MD,X,n)
++** where n is the number of bits in the partial block. A partial
++** block terminates the computation, so every MD computation
++** should terminate by processing a partial block, even if it
++** has n = 0.
++** -- The message digest is available in MD.buffer[0] ...
++** MD.buffer[3]. (Least-significant byte of each word
++** should be output first.)
++** -- You can print out the digest using MDprint(&amp;MD)
++*/
++
++/* Implementation notes:
++** This implementation assumes that ints are 32-bit quantities.
++*/
++
++#define TRUE 1
++#define FALSE 0
++
++/* Compile-time includes
++*/
++#include &lt;stdio.h&gt;
++#include &quot;md4.h&quot;
++#include &quot;pppd.h&quot;
++
++/* Compile-time declarations of MD4 &quot;magic constants&quot;.
++*/
++#define I0 0x67452301 /* Initial values for MD buffer */
++#define I1 0xefcdab89
++#define I2 0x98badcfe
++#define I3 0x10325476
++#define C2 013240474631 /* round 2 constant = sqrt(2) in octal */
++#define C3 015666365641 /* round 3 constant = sqrt(3) in octal */
++/* C2 and C3 are from Knuth, The Art of Programming, Volume 2
++** (Seminumerical Algorithms), Second Edition (1981), Addison-Wesley.
++** Table 2, page 660.
++*/
++
++#define fs1 3 /* round 1 shift amounts */
++#define fs2 7
++#define fs3 11
++#define fs4 19
++#define gs1 3 /* round 2 shift amounts */
++#define gs2 5
++#define gs3 9
++#define gs4 13
++#define hs1 3 /* round 3 shift amounts */
++#define hs2 9
++#define hs3 11
++#define hs4 15
++
++/* Compile-time macro declarations for MD4.
++** Note: The &quot;rot&quot; operator uses the variable &quot;tmp&quot;.
++** It assumes tmp is declared as unsigned int, so that the &gt;&gt;
++** operator will shift in zeros rather than extending the sign bit.
++*/
++#define f(X,Y,Z) ((X&amp;Y) | ((~X)&amp;Z))
++#define g(X,Y,Z) ((X&amp;Y) | (X&amp;Z) | (Y&amp;Z))
++#define h(X,Y,Z) (X^Y^Z)
++#define rot(X,S) (tmp=X,(tmp&lt;&lt;S) | (tmp&gt;&gt;(32-S)))
++#define ff(A,B,C,D,i,s) A = rot((A + f(B,C,D) + X[i]),s)
++#define gg(A,B,C,D,i,s) A = rot((A + g(B,C,D) + X[i] + C2),s)
++#define hh(A,B,C,D,i,s) A = rot((A + h(B,C,D) + X[i] + C3),s)
++
++/* MD4print(MDp)
++** Print message digest buffer MDp as 32 hexadecimal digits.
++** Order is from low-order byte of buffer[0] to high-order byte of
++** buffer[3].
++** Each byte is printed with high-order hexadecimal digit first.
++** This is a user-callable routine.
++*/
++void
++MD4Print(MDp)
++MD4_CTX *MDp;
++{
++ int i,j;
++ for (i=0;i&lt;4;i++)
++ for (j=0;j&lt;32;j=j+8)
++ printf(&quot;%02x&quot;,(MDp-&gt;buffer[i]&gt;&gt;j) &amp; 0xFF);
++}
++
++/* MD4Init(MDp)
++** Initialize message digest buffer MDp.
++** This is a user-callable routine.
++*/
++void
++MD4Init(MDp)
++MD4_CTX *MDp;
++{
++ int i;
++ MDp-&gt;buffer[0] = I0;
++ MDp-&gt;buffer[1] = I1;
++ MDp-&gt;buffer[2] = I2;
++ MDp-&gt;buffer[3] = I3;
++ for (i=0;i&lt;8;i++) MDp-&gt;count[i] = 0;
++ MDp-&gt;done = 0;
++}
++
++/* MDblock(MDp,X)
++** Update message digest buffer MDp-&gt;buffer using 16-word data block X.
++** Assumes all 16 words of X are full of data.
++** Does not update MDp-&gt;count.
++** This routine is not user-callable.
++*/
++static void
++MDblock(MDp,Xb)
++MD4_CTX *MDp;
++unsigned char *Xb;
++{
++ register unsigned int tmp, A, B, C, D;
++ unsigned int X[16];
++ int i;
++
++ for (i = 0; i &lt; 16; ++i) {
++ X[i] = Xb[0] + (Xb[1] &lt;&lt; 8) + (Xb[2] &lt;&lt; 16) + (Xb[3] &lt;&lt; 24);
++ Xb += 4;
++ }
++
++ A = MDp-&gt;buffer[0];
++ B = MDp-&gt;buffer[1];
++ C = MDp-&gt;buffer[2];
++ D = MDp-&gt;buffer[3];
++ /* Update the message digest buffer */
++ ff(A , B , C , D , 0 , fs1); /* Round 1 */
++ ff(D , A , B , C , 1 , fs2);
++ ff(C , D , A , B , 2 , fs3);
++ ff(B , C , D , A , 3 , fs4);
++ ff(A , B , C , D , 4 , fs1);
++ ff(D , A , B , C , 5 , fs2);
++ ff(C , D , A , B , 6 , fs3);
++ ff(B , C , D , A , 7 , fs4);
++ ff(A , B , C , D , 8 , fs1);
++ ff(D , A , B , C , 9 , fs2);
++ ff(C , D , A , B , 10 , fs3);
++ ff(B , C , D , A , 11 , fs4);
++ ff(A , B , C , D , 12 , fs1);
++ ff(D , A , B , C , 13 , fs2);
++ ff(C , D , A , B , 14 , fs3);
++ ff(B , C , D , A , 15 , fs4);
++ gg(A , B , C , D , 0 , gs1); /* Round 2 */
++ gg(D , A , B , C , 4 , gs2);
++ gg(C , D , A , B , 8 , gs3);
++ gg(B , C , D , A , 12 , gs4);
++ gg(A , B , C , D , 1 , gs1);
++ gg(D , A , B , C , 5 , gs2);
++ gg(C , D , A , B , 9 , gs3);
++ gg(B , C , D , A , 13 , gs4);
++ gg(A , B , C , D , 2 , gs1);
++ gg(D , A , B , C , 6 , gs2);
++ gg(C , D , A , B , 10 , gs3);
++ gg(B , C , D , A , 14 , gs4);
++ gg(A , B , C , D , 3 , gs1);
++ gg(D , A , B , C , 7 , gs2);
++ gg(C , D , A , B , 11 , gs3);
++ gg(B , C , D , A , 15 , gs4);
++ hh(A , B , C , D , 0 , hs1); /* Round 3 */
++ hh(D , A , B , C , 8 , hs2);
++ hh(C , D , A , B , 4 , hs3);
++ hh(B , C , D , A , 12 , hs4);
++ hh(A , B , C , D , 2 , hs1);
++ hh(D , A , B , C , 10 , hs2);
++ hh(C , D , A , B , 6 , hs3);
++ hh(B , C , D , A , 14 , hs4);
++ hh(A , B , C , D , 1 , hs1);
++ hh(D , A , B , C , 9 , hs2);
++ hh(C , D , A , B , 5 , hs3);
++ hh(B , C , D , A , 13 , hs4);
++ hh(A , B , C , D , 3 , hs1);
++ hh(D , A , B , C , 11 , hs2);
++ hh(C , D , A , B , 7 , hs3);
++ hh(B , C , D , A , 15 , hs4);
++ MDp-&gt;buffer[0] += A;
++ MDp-&gt;buffer[1] += B;
++ MDp-&gt;buffer[2] += C;
++ MDp-&gt;buffer[3] += D;
++}
++
++/* MD4Update(MDp,X,count)
++** Input: X -- a pointer to an array of unsigned characters.
++** count -- the number of bits of X to use.
++** (if not a multiple of 8, uses high bits of last byte.)
++** Update MDp using the number of bits of X given by count.
++** This is the basic input routine for an MD4 user.
++** The routine completes the MD computation when count &lt; 512, so
++** every MD computation should end with one call to MD4Update with a
++** count less than 512. A call with count 0 will be ignored if the
++** MD has already been terminated (done != 0), so an extra call with
++** count 0 can be given as a &quot;courtesy close&quot; to force termination
++** if desired.
++*/
++void
++MD4Update(MDp,X,count)
++MD4_CTX *MDp;
++unsigned char *X;
++unsigned int count;
++{
++ unsigned int i, tmp, bit, byte, mask;
++ unsigned char XX[64];
++ unsigned char *p;
++
++ /* return with no error if this is a courtesy close with count
++ ** zero and MDp-&gt;done is true.
++ */
++ if (count == 0 &amp;&amp; MDp-&gt;done) return;
++ /* check to see if MD is already done and report error */
++ if (MDp-&gt;done)
++ { printf(&quot;\nError: MD4Update MD already done.&quot;); return; }
++
++ /* Add count to MDp-&gt;count */
++ tmp = count;
++ p = MDp-&gt;count;
++ while (tmp)
++ { tmp += *p;
++ *p++ = tmp;
++ tmp = tmp &gt;&gt; 8;
++ }
++
++ /* Process data */
++ if (count == 512)
++ { /* Full block of data to handle */
++ MDblock(MDp,X);
++ }
++ else if (count &gt; 512) /* Check for count too large */
++ {
++ printf(&quot;\nError: MD4Update called with illegal count value %d.&quot;,
++ count);
++ return;
++ }
++ else /* partial block -- must be last block so finish up */
++ {
++ /* Find out how many bytes and residual bits there are */
++ byte = count &gt;&gt; 3;
++ bit = count &amp; 7;
++ /* Copy X into XX since we need to modify it */
++ for (i=0;i&lt;=byte;i++) XX[i] = X[i];
++ for (i=byte+1;i&lt;64;i++) XX[i] = 0;
++ /* Add padding '1' bit and low-order zeros in last byte */
++ mask = 1 &lt;&lt; (7 - bit);
++ XX[byte] = (XX[byte] | mask) &amp; ~( mask - 1);
++ /* If room for bit count, finish up with this block */
++ if (byte &lt;= 55)
++ {
++ for (i=0;i&lt;8;i++) XX[56+i] = MDp-&gt;count[i];
++ MDblock(MDp,XX);
++ }
++ else /* need to do two blocks to finish up */
++ {
++ MDblock(MDp,XX);
++ for (i=0;i&lt;56;i++) XX[i] = 0;
++ for (i=0;i&lt;8;i++) XX[56+i] = MDp-&gt;count[i];
++ MDblock(MDp,XX);
++ }
++ /* Set flag saying we're done with MD computation */
++ MDp-&gt;done = 1;
++ }
++}
++
++/*
++** Finish up MD4 computation and return message digest.
++*/
++void
++MD4Final(buf, MD)
++unsigned char *buf;
++MD4_CTX *MD;
++{
++ int i, j;
++ unsigned int w;
++
++ MD4Update(MD, NULL, 0);
++ for (i = 0; i &lt; 4; ++i) {
++ w = MD-&gt;buffer[i];
++ for (j = 0; j &lt; 4; ++j) {
++ *buf++ = w;
++ w &gt;&gt;= 8;
++ }
++ }
++}
++
++/*
++** End of md4.c
++****************************(cut)***********************************/
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/md4.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/md4.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/md4.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/md4.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,64 @@
++
++/*
++** ********************************************************************
++** md4.h -- Header file for implementation of **
++** MD4 Message Digest Algorithm **
++** Updated: 2/13/90 by Ronald L. Rivest **
++** (C) 1990 RSA Data Security, Inc. **
++** ********************************************************************
++*/
++
++#ifndef __P
++# if defined(__STDC__) || defined(__GNUC__)
++# define __P(x) x
++# else
++# define __P(x) ()
++# endif
++#endif
++
++
++/* MDstruct is the data structure for a message digest computation.
++*/
++typedef struct {
++ unsigned int buffer[4]; /* Holds 4-word result of MD computation */
++ unsigned char count[8]; /* Number of bits processed so far */
++ unsigned int done; /* Nonzero means MD computation finished */
++} MD4_CTX;
++
++/* MD4Init(MD4_CTX *)
++** Initialize the MD4_CTX prepatory to doing a message digest
++** computation.
++*/
++extern void MD4Init __P((MD4_CTX *MD));
++
++/* MD4Update(MD,X,count)
++** Input: X -- a pointer to an array of unsigned characters.
++** count -- the number of bits of X to use (an unsigned int).
++** Updates MD using the first &quot;count&quot; bits of X.
++** The array pointed to by X is not modified.
++** If count is not a multiple of 8, MD4Update uses high bits of
++** last byte.
++** This is the basic input routine for a user.
++** The routine terminates the MD computation when count &lt; 512, so
++** every MD computation should end with one call to MD4Update with a
++** count less than 512. Zero is OK for a count.
++*/
++extern void MD4Update __P((MD4_CTX *MD, unsigned char *X, unsigned int count));
++
++/* MD4Print(MD)
++** Prints message digest buffer MD as 32 hexadecimal digits.
++** Order is from low-order byte of buffer[0] to high-order byte
++** of buffer[3].
++** Each byte is printed with high-order hexadecimal digit first.
++*/
++extern void MD4Print __P((MD4_CTX *));
++
++/* MD4Final(buf, MD)
++** Returns message digest from MD and terminates the message
++** digest computation.
++*/
++extern void MD4Final __P((unsigned char *, MD4_CTX *));
++
++/*
++** End of md4.h
++****************************(cut)***********************************/
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/md4.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/md5.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/md5.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/md5.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,309 @@
++
++
++/*
++ ***********************************************************************
++ ** md5.c -- the source code for MD5 routines **
++ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
++ ** Created: 2/17/90 RLR **
++ ** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. **
++ ***********************************************************************
++ */
++
++/*
++ ***********************************************************************
++ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
++ ** **
++ ** License to copy and use this software is granted provided that **
++ ** it is identified as the &quot;RSA Data Security, Inc. MD5 Message- **
++ ** Digest Algorithm&quot; in all material mentioning or referencing this **
++ ** software or this function. **
++ ** **
++ ** License is also granted to make and use derivative works **
++ ** provided that such works are identified as &quot;derived from the RSA **
++ ** Data Security, Inc. MD5 Message-Digest Algorithm&quot; in all **
++ ** material mentioning or referencing the derived work. **
++ ** **
++ ** RSA Data Security, Inc. makes no representations concerning **
++ ** either the merchantability of this software or the suitability **
++ ** of this software for any particular purpose. It is provided &quot;as **
++ ** is&quot; without express or implied warranty of any kind. **
++ ** **
++ ** These notices must be retained in any copies of any part of this **
++ ** documentation and/or software. **
++ ***********************************************************************
++ */
++
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++
++#include &quot;md5.h&quot;
++
++/*
++ ***********************************************************************
++ ** Message-digest routines: **
++ ** To form the message digest for a message M **
++ ** (1) Initialize a context buffer mdContext using MD5Init **
++ ** (2) Call MD5Update on mdContext and M **
++ ** (3) Call MD5Final on mdContext **
++ ** The message digest is now in mdContext-&gt;digest[0...15] **
++ ***********************************************************************
++ */
++
++/* forward declaration */
++static void Transform ();
++
++static unsigned char PADDING[64] = {
++ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
++};
++
++/* F, G, H and I are basic MD5 functions */
++#define F(x, y, z) (((x) &amp; (y)) | ((~x) &amp; (z)))
++#define G(x, y, z) (((x) &amp; (z)) | ((y) &amp; (~z)))
++#define H(x, y, z) ((x) ^ (y) ^ (z))
++#define I(x, y, z) ((y) ^ ((x) | (~z)))
++
++/* ROTATE_LEFT rotates x left n bits */
++#define ROTATE_LEFT(x, n) (((x) &lt;&lt; (n)) | ((x) &gt;&gt; (32-(n))))
++
++/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
++/* Rotation is separate from addition to prevent recomputation */
++#define FF(a, b, c, d, x, s, ac) \
++ {(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
++ (a) = ROTATE_LEFT ((a), (s)); \
++ (a) += (b); \
++ }
++#define GG(a, b, c, d, x, s, ac) \
++ {(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
++ (a) = ROTATE_LEFT ((a), (s)); \
++ (a) += (b); \
++ }
++#define HH(a, b, c, d, x, s, ac) \
++ {(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
++ (a) = ROTATE_LEFT ((a), (s)); \
++ (a) += (b); \
++ }
++#define II(a, b, c, d, x, s, ac) \
++ {(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
++ (a) = ROTATE_LEFT ((a), (s)); \
++ (a) += (b); \
++ }
++
++#ifdef __STDC__
++#define UL(x) x##U
++#else
++#define UL(x) x
++#endif
++
++/* The routine MD5Init initializes the message-digest context
++ mdContext. All fields are set to zero.
++ */
++void MD5Init (mdContext)
++MD5_CTX *mdContext;
++{
++ mdContext-&gt;i[0] = mdContext-&gt;i[1] = (UINT4)0;
++
++ /* Load magic initialization constants.
++ */
++ mdContext-&gt;buf[0] = (UINT4)0x67452301;
++ mdContext-&gt;buf[1] = (UINT4)0xefcdab89;
++ mdContext-&gt;buf[2] = (UINT4)0x98badcfe;
++ mdContext-&gt;buf[3] = (UINT4)0x10325476;
++}
++
++/* The routine MD5Update updates the message-digest context to
++ account for the presence of each of the characters inBuf[0..inLen-1]
++ in the message whose digest is being computed.
++ */
++void MD5Update (mdContext, inBuf, inLen)
++MD5_CTX *mdContext;
++unsigned char *inBuf;
++unsigned int inLen;
++{
++ UINT4 in[16];
++ int mdi;
++ unsigned int i, ii;
++
++ /* compute number of bytes mod 64 */
++ mdi = (int)((mdContext-&gt;i[0] &gt;&gt; 3) &amp; 0x3F);
++
++ /* update number of bits */
++ if ((mdContext-&gt;i[0] + ((UINT4)inLen &lt;&lt; 3)) &lt; mdContext-&gt;i[0])
++ mdContext-&gt;i[1]++;
++ mdContext-&gt;i[0] += ((UINT4)inLen &lt;&lt; 3);
++ mdContext-&gt;i[1] += ((UINT4)inLen &gt;&gt; 29);
++
++ while (inLen--) {
++ /* add new character to buffer, increment mdi */
++ mdContext-&gt;in[mdi++] = *inBuf++;
++
++ /* transform if necessary */
++ if (mdi == 0x40) {
++ for (i = 0, ii = 0; i &lt; 16; i++, ii += 4)
++ in[i] = (((UINT4)mdContext-&gt;in[ii+3]) &lt;&lt; 24) |
++ (((UINT4)mdContext-&gt;in[ii+2]) &lt;&lt; 16) |
++ (((UINT4)mdContext-&gt;in[ii+1]) &lt;&lt; 8) |
++ ((UINT4)mdContext-&gt;in[ii]);
++ Transform (mdContext-&gt;buf, in);
++ mdi = 0;
++ }
++ }
++}
++
++/* The routine MD5Final terminates the message-digest computation and
++ ends with the desired message digest in mdContext-&gt;digest[0...15].
++ */
++void MD5Final (hash, mdContext)
++unsigned char hash[];
++MD5_CTX *mdContext;
++{
++ UINT4 in[16];
++ int mdi;
++ unsigned int i, ii;
++ unsigned int padLen;
++
++ /* save number of bits */
++ in[14] = mdContext-&gt;i[0];
++ in[15] = mdContext-&gt;i[1];
++
++ /* compute number of bytes mod 64 */
++ mdi = (int)((mdContext-&gt;i[0] &gt;&gt; 3) &amp; 0x3F);
++
++ /* pad out to 56 mod 64 */
++ padLen = (mdi &lt; 56) ? (56 - mdi) : (120 - mdi);
++ MD5Update (mdContext, PADDING, padLen);
++
++ /* append length in bits and transform */
++ for (i = 0, ii = 0; i &lt; 14; i++, ii += 4)
++ in[i] = (((UINT4)mdContext-&gt;in[ii+3]) &lt;&lt; 24) |
++ (((UINT4)mdContext-&gt;in[ii+2]) &lt;&lt; 16) |
++ (((UINT4)mdContext-&gt;in[ii+1]) &lt;&lt; 8) |
++ ((UINT4)mdContext-&gt;in[ii]);
++ Transform (mdContext-&gt;buf, in);
++
++ /* store buffer in digest */
++ for (i = 0, ii = 0; i &lt; 4; i++, ii += 4) {
++ mdContext-&gt;digest[ii] = (unsigned char)(mdContext-&gt;buf[i] &amp; 0xFF);
++ mdContext-&gt;digest[ii+1] =
++ (unsigned char)((mdContext-&gt;buf[i] &gt;&gt; 8) &amp; 0xFF);
++ mdContext-&gt;digest[ii+2] =
++ (unsigned char)((mdContext-&gt;buf[i] &gt;&gt; 16) &amp; 0xFF);
++ mdContext-&gt;digest[ii+3] =
++ (unsigned char)((mdContext-&gt;buf[i] &gt;&gt; 24) &amp; 0xFF);
++ }
++ memcpy(hash, mdContext-&gt;digest, 16);
++}
++
++/* Basic MD5 step. Transforms buf based on in.
++ */
++static void Transform (buf, in)
++UINT4 *buf;
++UINT4 *in;
++{
++ UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
++
++ /* Round 1 */
++#define S11 7
++#define S12 12
++#define S13 17
++#define S14 22
++ FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */
++ FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */
++ FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */
++ FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */
++ FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */
++ FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */
++ FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */
++ FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */
++ FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */
++ FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */
++ FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */
++ FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */
++ FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */
++ FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */
++ FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */
++ FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */
++
++ /* Round 2 */
++#define S21 5
++#define S22 9
++#define S23 14
++#define S24 20
++ GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */
++ GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */
++ GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */
++ GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */
++ GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */
++ GG ( d, a, b, c, in[10], S22, UL( 38016083)); /* 22 */
++ GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */
++ GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */
++ GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */
++ GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */
++ GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */
++ GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */
++ GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */
++ GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */
++ GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */
++ GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */
++
++ /* Round 3 */
++#define S31 4
++#define S32 11
++#define S33 16
++#define S34 23
++ HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */
++ HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */
++ HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */
++ HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */
++ HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */
++ HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */
++ HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */
++ HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */
++ HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */
++ HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */
++ HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */
++ HH ( b, c, d, a, in[ 6], S34, UL( 76029189)); /* 44 */
++ HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */
++ HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */
++ HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */
++ HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */
++
++ /* Round 4 */
++#define S41 6
++#define S42 10
++#define S43 15
++#define S44 21
++ II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */
++ II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */
++ II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */
++ II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */
++ II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */
++ II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */
++ II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */
++ II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */
++ II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */
++ II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */
++ II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */
++ II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */
++ II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */
++ II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */
++ II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */
++ II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */
++
++ buf[0] += a;
++ buf[1] += b;
++ buf[2] += c;
++ buf[3] += d;
++}
++
++/*
++ ***********************************************************************
++ ** End of md5.c **
++ ******************************** (cut) ********************************
++ */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/md5.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/md5.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/md5.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/md5.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,58 @@
++/*
++ ***********************************************************************
++ ** md5.h -- header file for implementation of MD5 **
++ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
++ ** Created: 2/17/90 RLR **
++ ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version **
++ ** Revised (for MD5): RLR 4/27/91 **
++ ** -- G modified to have y&amp;~z instead of y&amp;z **
++ ** -- FF, GG, HH modified to add in last register done **
++ ** -- Access pattern: round 2 works mod 5, round 3 works mod 3 **
++ ** -- distinct additive constant for each step **
++ ** -- round 4 added, working mod 7 **
++ ***********************************************************************
++ */
++
++/*
++ ***********************************************************************
++ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
++ ** **
++ ** License to copy and use this software is granted provided that **
++ ** it is identified as the &quot;RSA Data Security, Inc. MD5 Message- **
++ ** Digest Algorithm&quot; in all material mentioning or referencing this **
++ ** software or this function. **
++ ** **
++ ** License is also granted to make and use derivative works **
++ ** provided that such works are identified as &quot;derived from the RSA **
++ ** Data Security, Inc. MD5 Message-Digest Algorithm&quot; in all **
++ ** material mentioning or referencing the derived work. **
++ ** **
++ ** RSA Data Security, Inc. makes no representations concerning **
++ ** either the merchantability of this software or the suitability **
++ ** of this software for any particular purpose. It is provided &quot;as **
++ ** is&quot; without express or implied warranty of any kind. **
++ ** **
++ ** These notices must be retained in any copies of any part of this **
++ ** documentation and/or software. **
++ ***********************************************************************
++ */
++
++#ifndef __MD5_INCLUDE__
++
++/* typedef a 32-bit type */
++typedef unsigned int UINT4;
++
++/* Data structure for MD5 (Message-Digest) computation */
++typedef struct {
++ UINT4 i[2]; /* number of _bits_ handled mod 2^64 */
++ UINT4 buf[4]; /* scratch buffer */
++ unsigned char in[64]; /* input buffer */
++ unsigned char digest[16]; /* actual digest after MD5Final call */
++} MD5_CTX;
++
++void MD5Init ();
++void MD5Update ();
++void MD5Final ();
++
++#define __MD5_INCLUDE__
++#endif /* __MD5_INCLUDE__ */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/md5.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/multilink.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/multilink.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/multilink.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,397 @@
++/*
++ * multilink.c - support routines for multilink.
++ *
++ * Copyright (c) 2000 Paul Mackerras.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms. The name of the author may not be
++ * used to endorse or promote products derived from this software
++ * without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ */
++#include &lt;stdlib.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;string.h&gt;
++#include &lt;ctype.h&gt;
++#include &lt;netdb.h&gt;
++#include &lt;errno.h&gt;
++#include &lt;signal.h&gt;
++#include &lt;netinet/in.h&gt;
++
++#include &quot;pppd.h&quot;
++#include &quot;fsm.h&quot;
++#include &quot;lcp.h&quot;
++#include &quot;tdb.h&quot;
++
++bool endpoint_specified; /* user gave explicit endpoint discriminator */
++char *bundle_id; /* identifier for our bundle */
++
++extern TDB_CONTEXT *pppdb;
++extern char db_key[];
++
++static int get_default_epdisc __P((struct epdisc *));
++static int parse_num __P((char *str, const char *key, int *valp));
++static int owns_unit __P((TDB_DATA pid, int unit));
++
++#define set_ip_epdisc(ep, addr) do { \
++ ep-&gt;length = 4; \
++ ep-&gt;value[0] = addr &gt;&gt; 24; \
++ ep-&gt;value[1] = addr &gt;&gt; 16; \
++ ep-&gt;value[2] = addr &gt;&gt; 8; \
++ ep-&gt;value[3] = addr; \
++} while (0)
++
++#define LOCAL_IP_ADDR(addr) \
++ (((addr) &amp; 0xff000000) == 0x0a000000 /* 10.x.x.x */ \
++ || ((addr) &amp; 0xfff00000) == 0xac100000 /* 172.16.x.x */ \
++ || ((addr) &amp; 0xffff0000) == 0xc0a80000) /* 192.168.x.x */
++
++#define process_exists(n) (kill((n), 0) == 0 || errno != ESRCH)
++
++void
++mp_check_options()
++{
++ lcp_options *wo = &amp;lcp_wantoptions[0];
++ lcp_options *ao = &amp;lcp_allowoptions[0];
++
++ if (!multilink)
++ return;
++ /* if we're doing multilink, we have to negotiate MRRU */
++ if (!wo-&gt;neg_mrru) {
++ /* mrru not specified, default to mru */
++ wo-&gt;mrru = wo-&gt;mru;
++ wo-&gt;neg_mrru = 1;
++ }
++ ao-&gt;mrru = ao-&gt;mru;
++ ao-&gt;neg_mrru = 1;
++
++ if (!wo-&gt;neg_endpoint &amp;&amp; !noendpoint) {
++ /* get a default endpoint value */
++ wo-&gt;neg_endpoint = get_default_epdisc(&amp;wo-&gt;endpoint);
++ }
++}
++
++/*
++ * Make a new bundle or join us to an existing bundle
++ * if we are doing multilink.
++ */
++int
++mp_join_bundle()
++{
++ lcp_options *go = &amp;lcp_gotoptions[0];
++ lcp_options *ho = &amp;lcp_hisoptions[0];
++ lcp_options *ao = &amp;lcp_allowoptions[0];
++ int unit, pppd_pid;
++ int l, mtu;
++ char *p;
++ TDB_DATA key, pid, rec;
++
++ if (!go-&gt;neg_mrru || !ho-&gt;neg_mrru) {
++ /* not doing multilink */
++ if (go-&gt;neg_mrru)
++ notice(&quot;oops, multilink negotiated only for receive&quot;);
++ mtu = ho-&gt;neg_mru? ho-&gt;mru: PPP_MRU;
++ if (mtu &gt; ao-&gt;mru)
++ mtu = ao-&gt;mru;
++ if (demand) {
++ /* already have a bundle */
++ cfg_bundle(0, 0, 0, 0);
++ netif_set_mtu(0, mtu);
++ return 0;
++ }
++ make_new_bundle(0, 0, 0, 0);
++ set_ifunit(1);
++ netif_set_mtu(0, mtu);
++ return 0;
++ }
++
++ /*
++ * Find the appropriate bundle or join a new one.
++ * First we make up a name for the bundle.
++ * The length estimate is worst-case assuming every
++ * character has to be quoted.
++ */
++ l = 4 * strlen(peer_authname) + 10;
++ if (ho-&gt;neg_endpoint)
++ l += 3 * ho-&gt;endpoint.length + 8;
++ if (bundle_name)
++ l += 3 * strlen(bundle_name) + 2;
++ bundle_id = malloc(l);
++ if (bundle_id == 0)
++ novm(&quot;bundle identifier&quot;);
++
++ p = bundle_id;
++ p += slprintf(p, l-1, &quot;BUNDLE=\&quot;%q\&quot;&quot;, peer_authname);
++ if (ho-&gt;neg_endpoint || bundle_name)
++ *p++ = '/';
++ if (ho-&gt;neg_endpoint)
++ p += slprintf(p, bundle_id+l-p, &quot;%s&quot;,
++ epdisc_to_str(&amp;ho-&gt;endpoint));
++ if (bundle_name)
++ p += slprintf(p, bundle_id+l-p, &quot;/%v&quot;, bundle_name);
++
++ /*
++ * For demand mode, we only need to configure the bundle
++ * and attach the link.
++ */
++ mtu = MIN(ho-&gt;mrru, ao-&gt;mru);
++ if (demand) {
++ cfg_bundle(go-&gt;mrru, ho-&gt;mrru, go-&gt;neg_ssnhf, ho-&gt;neg_ssnhf);
++ netif_set_mtu(0, mtu);
++ script_setenv(&quot;BUNDLE&quot;, bundle_id + 7, 1);
++ return 0;
++ }
++
++ /*
++ * Check if the bundle ID is already in the database.
++ */
++ unit = -1;
++ tdb_writelock(pppdb);
++ key.dptr = bundle_id;
++ key.dsize = p - bundle_id;
++ pid = tdb_fetch(pppdb, key);
++ if (pid.dptr != NULL) {
++ /* bundle ID exists, see if the pppd record exists */
++ rec = tdb_fetch(pppdb, pid);
++ if (rec.dptr != NULL) {
++ /* it is, parse the interface number */
++ parse_num(rec.dptr, &quot;IFNAME=ppp&quot;, &amp;unit);
++ /* check the pid value */
++ if (!parse_num(rec.dptr, &quot;PPPD_PID=&quot;, &amp;pppd_pid)
++ || !process_exists(pppd_pid)
++ || !owns_unit(pid, unit))
++ unit = -1;
++ free(rec.dptr);
++ }
++ free(pid.dptr);
++ }
++
++ if (unit &gt;= 0) {
++ /* attach to existing unit */
++ if (bundle_attach(unit)) {
++ set_ifunit(0);
++ script_setenv(&quot;BUNDLE&quot;, bundle_id + 7, 0);
++ tdb_writeunlock(pppdb);
++ info(&quot;Link attached to %s&quot;, ifname);
++ return 1;
++ }
++ /* attach failed because bundle doesn't exist */
++ }
++
++ /* we have to make a new bundle */
++ make_new_bundle(go-&gt;mrru, ho-&gt;mrru, go-&gt;neg_ssnhf, ho-&gt;neg_ssnhf);
++ set_ifunit(1);
++ netif_set_mtu(0, mtu);
++ script_setenv(&quot;BUNDLE&quot;, bundle_id + 7, 1);
++ tdb_writeunlock(pppdb);
++ info(&quot;New bundle %s created&quot;, ifname);
++ return 0;
++}
++
++static int
++parse_num(str, key, valp)
++ char *str;
++ const char *key;
++ int *valp;
++{
++ char *p, *endp;
++ int i;
++
++ p = strstr(str, key);
++ if (p != 0) {
++ p += strlen(key);
++ i = strtol(p, &amp;endp, 10);
++ if (endp != p &amp;&amp; (*endp == 0 || *endp == ';')) {
++ *valp = i;
++ return 1;
++ }
++ }
++ return 0;
++}
++
++/*
++ * Check whether the pppd identified by `key' still owns ppp unit `unit'.
++ */
++static int
++owns_unit(key, unit)
++ TDB_DATA key;
++ int unit;
++{
++ char ifkey[32];
++ TDB_DATA kd, vd;
++ int ret = 0;
++
++ slprintf(ifkey, sizeof(ifkey), &quot;IFNAME=ppp%d&quot;, unit);
++ kd.dptr = ifkey;
++ kd.dsize = strlen(ifkey);
++ vd = tdb_fetch(pppdb, kd);
++ if (vd.dptr != NULL) {
++ ret = vd.dsize == key.dsize
++ &amp;&amp; memcmp(vd.dptr, key.dptr, vd.dsize) == 0;
++ free(vd.dptr);
++ }
++ return ret;
++}
++
++static int
++get_default_epdisc(ep)
++ struct epdisc *ep;
++{
++ char *p;
++ struct hostent *hp;
++ u_int32_t addr;
++
++ /* First try for an ethernet MAC address */
++ p = get_first_ethernet();
++ if (p != 0 &amp;&amp; get_if_hwaddr(ep-&gt;value, p) &gt;= 0) {
++ ep-&gt;class = EPD_MAC;
++ ep-&gt;length = 6;
++ return 1;
++ }
++
++ /* see if our hostname corresponds to a reasonable IP address */
++ hp = gethostbyname(hostname);
++ if (hp != NULL) {
++ addr = *(u_int32_t *)hp-&gt;h_addr;
++ if (!bad_ip_adrs(addr)) {
++ addr = ntohl(addr);
++ if (!LOCAL_IP_ADDR(addr)) {
++ ep-&gt;class = EPD_IP;
++ set_ip_epdisc(ep, addr);
++ return 1;
++ }
++ }
++ }
++
++ return 0;
++}
++
++/*
++ * epdisc_to_str - make a printable string from an endpoint discriminator.
++ */
++
++static char *endp_class_names[] = {
++ &quot;null&quot;, &quot;local&quot;, &quot;IP&quot;, &quot;MAC&quot;, &quot;magic&quot;, &quot;phone&quot;
++};
++
++char *
++epdisc_to_str(ep)
++ struct epdisc *ep;
++{
++ static char str[MAX_ENDP_LEN*3+8];
++ u_char *p = ep-&gt;value;
++ int i, mask = 0;
++ char *q, c, c2;
++
++ if (ep-&gt;class == EPD_NULL &amp;&amp; ep-&gt;length == 0)
++ return &quot;null&quot;;
++ if (ep-&gt;class == EPD_IP &amp;&amp; ep-&gt;length == 4) {
++ u_int32_t addr;
++
++ GETLONG(addr, p);
++ slprintf(str, sizeof(str), &quot;IP:%I&quot;, htonl(addr));
++ return str;
++ }
++
++ c = ':';
++ c2 = '.';
++ if (ep-&gt;class == EPD_MAC &amp;&amp; ep-&gt;length == 6)
++ c2 = ':';
++ else if (ep-&gt;class == EPD_MAGIC &amp;&amp; (ep-&gt;length % 4) == 0)
++ mask = 3;
++ q = str;
++ if (ep-&gt;class &lt;= EPD_PHONENUM)
++ q += slprintf(q, sizeof(str)-1, &quot;%s&quot;,
++ endp_class_names[ep-&gt;class]);
++ else
++ q += slprintf(q, sizeof(str)-1, &quot;%d&quot;, ep-&gt;class);
++ c = ':';
++ for (i = 0; i &lt; ep-&gt;length &amp;&amp; i &lt; MAX_ENDP_LEN; ++i) {
++ if ((i &amp; mask) == 0) {
++ *q++ = c;
++ c = c2;
++ }
++ q += slprintf(q, str + sizeof(str) - q, &quot;%.2x&quot;, ep-&gt;value[i]);
++ }
++ return str;
++}
++
++static int hexc_val(int c)
++{
++ if (c &gt;= 'a')
++ return c - 'a' + 10;
++ if (c &gt;= 'A')
++ return c - 'A' + 10;
++ return c - '0';
++}
++
++int
++str_to_epdisc(ep, str)
++ struct epdisc *ep;
++ char *str;
++{
++ int i, l;
++ char *p, *endp;
++
++ for (i = EPD_NULL; i &lt;= EPD_PHONENUM; ++i) {
++ int sl = strlen(endp_class_names[i]);
++ if (strncasecmp(str, endp_class_names[i], sl) == 0) {
++ str += sl;
++ break;
++ }
++ }
++ if (i &gt; EPD_PHONENUM) {
++ /* not a class name, try a decimal class number */
++ i = strtol(str, &amp;endp, 10);
++ if (endp == str)
++ return 0; /* can't parse class number */
++ str = endp;
++ }
++ ep-&gt;class = i;
++ if (*str == 0) {
++ ep-&gt;length = 0;
++ return 1;
++ }
++ if (*str != ':' &amp;&amp; *str != '.')
++ return 0;
++ ++str;
++
++ if (i == EPD_IP) {
++ u_int32_t addr;
++ i = parse_dotted_ip(str, &amp;addr);
++ if (i == 0 || str[i] != 0)
++ return 0;
++ set_ip_epdisc(ep, addr);
++ return 1;
++ }
++ if (i == EPD_MAC &amp;&amp; get_if_hwaddr(ep-&gt;value, str) &gt;= 0) {
++ ep-&gt;length = 6;
++ return 1;
++ }
++
++ p = str;
++ for (l = 0; l &lt; MAX_ENDP_LEN; ++l) {
++ if (*str == 0)
++ break;
++ if (p &lt;= str)
++ for (p = str; isxdigit(*p); ++p)
++ ;
++ i = p - str;
++ if (i == 0)
++ return 0;
++ ep-&gt;value[l] = hexc_val(*str++);
++ if ((i &amp; 1) == 0)
++ ep-&gt;value[l] = (ep-&gt;value[l] &lt;&lt; 4) + hexc_val(*str++);
++ if (*str == ':' || *str == '.')
++ ++str;
++ }
++ if (*str != 0 || (ep-&gt;class == EPD_MAC &amp;&amp; l != 6))
++ return 0;
++ ep-&gt;length = l;
++ return 1;
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/multilink.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/options.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/options.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/options.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1513 @@
++/*
++ * options.c - handles option processing for PPP.
++ *
++ * Copyright (c) 1989 Carnegie Mellon University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by Carnegie Mellon University. The name of the
++ * University may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ */
++
++#define RCSID &quot;$Id: options.c 195734 2001-06-11 14:46:02Z gc $&quot;
++
++#include &lt;ctype.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;errno.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;syslog.h&gt;
++#include &lt;string.h&gt;
++#include &lt;pwd.h&gt;
++#ifdef PLUGIN
++#include &lt;dlfcn.h&gt;
++#endif
++#ifdef PPP_FILTER
++#include &lt;pcap.h&gt;
++#include &lt;pcap-int.h&gt; /* XXX: To get struct pcap */
++#endif
++
++#include &quot;pppd.h&quot;
++#include &quot;pathnames.h&quot;
++
++#if defined(ultrix) || defined(NeXT)
++char *strdup __P((char *));
++#endif
++
++static const char rcsid[] = RCSID;
++
++struct option_value {
++ struct option_value *next;
++ const char *source;
++ char value[1];
++};
++
++/*
++ * Option variables and default values.
++ */
++#ifdef PPP_FILTER
++int dflag = 0; /* Tell libpcap we want debugging */
++#endif
++int debug = 0; /* Debug flag */
++int kdebugflag = 0; /* Tell kernel to print debug messages */
++int default_device = 1; /* Using /dev/tty or equivalent */
++char devnam[MAXPATHLEN]; /* Device name */
++bool nodetach = 0; /* Don't detach from controlling tty */
++bool updetach = 0; /* Detach once link is up */
++int maxconnect = 0; /* Maximum connect time */
++char user[MAXNAMELEN]; /* Username for PAP */
++char passwd[MAXSECRETLEN]; /* Password for PAP */
++bool persist = 0; /* Reopen link after it goes down */
++char our_name[MAXNAMELEN]; /* Our name for authentication purposes */
++bool demand = 0; /* do dial-on-demand */
++char *ipparam = NULL; /* Extra parameter for ip up/down scripts */
++int idle_time_limit = 0; /* Disconnect if idle for this many seconds */
++int holdoff = 30; /* # seconds to pause before reconnecting */
++bool holdoff_specified; /* true if a holdoff value has been given */
++int log_to_fd = 1; /* send log messages to this fd too */
++bool log_default = 1; /* log_to_fd is default (stdout) */
++int maxfail = 10; /* max # of unsuccessful connection attempts */
++char linkname[MAXPATHLEN]; /* logical name for link */
++bool tune_kernel; /* may alter kernel settings */
++int connect_delay = 1000; /* wait this many ms after connect script */
++int req_unit = -1; /* requested interface unit */
++bool multilink = 0; /* Enable multilink operation */
++char *bundle_name = NULL; /* bundle name for multilink */
++bool dump_options; /* print out option values */
++bool dryrun; /* print out option values and exit */
++char *domain; /* domain name set by domain option */
++
++extern option_t auth_options[];
++extern struct stat devstat;
++
++#ifdef PPP_FILTER
++struct bpf_program pass_filter;/* Filter program for packets to pass */
++struct bpf_program active_filter; /* Filter program for link-active pkts */
++pcap_t pc; /* Fake struct pcap so we can compile expr */
++#endif
++
++char *current_option; /* the name of the option being parsed */
++int privileged_option; /* set iff the current option came from root */
++char *option_source; /* string saying where the option came from */
++int option_priority = OPRIO_CFGFILE; /* priority of the current options */
++bool devnam_fixed; /* can no longer change device name */
++
++static int logfile_fd = -1; /* fd opened for log file */
++static char logfile_name[MAXPATHLEN]; /* name of log file */
++
++/*
++ * Prototypes
++ */
++static int setdomain __P((char **));
++static int readfile __P((char **));
++static int callfile __P((char **));
++static int showversion __P((char **));
++static int showhelp __P((char **));
++static void usage __P((void));
++static int setlogfile __P((char **));
++#ifdef PLUGIN
++static int loadplugin __P((char **));
++#endif
++
++#ifdef PPP_FILTER
++static int setpassfilter __P((char **));
++static int setactivefilter __P((char **));
++#endif
++
++static option_t *find_option __P((const char *name));
++static int process_option __P((option_t *, char *, char **));
++static int n_arguments __P((option_t *));
++static int number_option __P((char *, u_int32_t *, int));
++
++/*
++ * Structure to store extra lists of options.
++ */
++struct option_list {
++ option_t *options;
++ struct option_list *next;
++};
++
++static struct option_list *extra_options = NULL;
++
++/*
++ * Valid arguments.
++ */
++option_t general_options[] = {
++ { &quot;debug&quot;, o_int, &amp;debug,
++ &quot;Increase debugging level&quot;, OPT_INC | OPT_NOARG | 1 },
++ { &quot;-d&quot;, o_int, &amp;debug,
++ &quot;Increase debugging level&quot;,
++ OPT_ALIAS | OPT_INC | OPT_NOARG | 1 },
++
++ { &quot;kdebug&quot;, o_int, &amp;kdebugflag,
++ &quot;Set kernel driver debug level&quot;, OPT_PRIO },
++
++ { &quot;nodetach&quot;, o_bool, &amp;nodetach,
++ &quot;Don't detach from controlling tty&quot;, OPT_PRIO | 1 },
++ { &quot;-detach&quot;, o_bool, &amp;nodetach,
++ &quot;Don't detach from controlling tty&quot;, OPT_ALIAS | OPT_PRIOSUB | 1 },
++ { &quot;updetach&quot;, o_bool, &amp;updetach,
++ &quot;Detach from controlling tty once link is up&quot;,
++ OPT_PRIOSUB | OPT_A2CLR | 1, &amp;nodetach },
++
++ { &quot;holdoff&quot;, o_int, &amp;holdoff,
++ &quot;Set time in seconds before retrying connection&quot;, OPT_PRIO },
++
++ { &quot;idle&quot;, o_int, &amp;idle_time_limit,
++ &quot;Set time in seconds before disconnecting idle link&quot;, OPT_PRIO },
++
++ { &quot;maxconnect&quot;, o_int, &amp;maxconnect,
++ &quot;Set connection time limit&quot;,
++ OPT_PRIO | OPT_LLIMIT | OPT_NOINCR | OPT_ZEROINF },
++
++ { &quot;domain&quot;, o_special, (void *)setdomain,
++ &quot;Add given domain name to hostname&quot;,
++ OPT_PRIO | OPT_PRIV | OPT_A2STRVAL, &amp;domain },
++
++ { &quot;file&quot;, o_special, (void *)readfile,
++ &quot;Take options from a file&quot;, OPT_NOPRINT },
++ { &quot;call&quot;, o_special, (void *)callfile,
++ &quot;Take options from a privileged file&quot;, OPT_NOPRINT },
++
++ { &quot;persist&quot;, o_bool, &amp;persist,
++ &quot;Keep on reopening connection after close&quot;, OPT_PRIO | 1 },
++ { &quot;nopersist&quot;, o_bool, &amp;persist,
++ &quot;Turn off persist option&quot;, OPT_PRIOSUB },
++
++ { &quot;demand&quot;, o_bool, &amp;demand,
++ &quot;Dial on demand&quot;, OPT_INITONLY | 1, &amp;persist },
++
++ { &quot;--version&quot;, o_special_noarg, (void *)showversion,
++ &quot;Show version number&quot; },
++ { &quot;--help&quot;, o_special_noarg, (void *)showhelp,
++ &quot;Show brief listing of options&quot; },
++ { &quot;-h&quot;, o_special_noarg, (void *)showhelp,
++ &quot;Show brief listing of options&quot;, OPT_ALIAS },
++
++ { &quot;logfile&quot;, o_special, (void *)setlogfile,
++ &quot;Append log messages to this file&quot;,
++ OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, &amp;logfile_name },
++ { &quot;logfd&quot;, o_int, &amp;log_to_fd,
++ &quot;Send log messages to this file descriptor&quot;,
++ OPT_PRIOSUB | OPT_A2CLR, &amp;log_default },
++ { &quot;nolog&quot;, o_int, &amp;log_to_fd,
++ &quot;Don't send log messages to any file&quot;,
++ OPT_PRIOSUB | OPT_NOARG | OPT_VAL(-1) },
++ { &quot;nologfd&quot;, o_int, &amp;log_to_fd,
++ &quot;Don't send log messages to any file descriptor&quot;,
++ OPT_PRIOSUB | OPT_ALIAS | OPT_NOARG | OPT_VAL(-1) },
++
++ { &quot;linkname&quot;, o_string, linkname,
++ &quot;Set logical name for link&quot;,
++ OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, MAXPATHLEN },
++
++ { &quot;maxfail&quot;, o_int, &amp;maxfail,
++ &quot;Maximum number of unsuccessful connection attempts to allow&quot;,
++ OPT_PRIO },
++
++ { &quot;ktune&quot;, o_bool, &amp;tune_kernel,
++ &quot;Alter kernel settings as necessary&quot;, OPT_PRIO | 1 },
++ { &quot;noktune&quot;, o_bool, &amp;tune_kernel,
++ &quot;Don't alter kernel settings&quot;, OPT_PRIOSUB },
++
++ { &quot;connect-delay&quot;, o_int, &amp;connect_delay,
++ &quot;Maximum time (in ms) to wait after connect script finishes&quot;,
++ OPT_PRIO },
++
++ { &quot;unit&quot;, o_int, &amp;req_unit,
++ &quot;PPP interface unit number to use if possible&quot;,
++ OPT_PRIO | OPT_LLIMIT, 0, 0 },
++
++ { &quot;dump&quot;, o_bool, &amp;dump_options,
++ &quot;Print out option values after parsing all options&quot;, 1 },
++ { &quot;dryrun&quot;, o_bool, &amp;dryrun,
++ &quot;Stop after parsing, printing, and checking options&quot;, 1 },
++
++#ifdef HAVE_MULTILINK
++ { &quot;multilink&quot;, o_bool, &amp;multilink,
++ &quot;Enable multilink operation&quot;, OPT_PRIO | 1 },
++ { &quot;mp&quot;, o_bool, &amp;multilink,
++ &quot;Enable multilink operation&quot;, OPT_PRIOSUB | OPT_ALIAS | 1 },
++ { &quot;nomultilink&quot;, o_bool, &amp;multilink,
++ &quot;Disable multilink operation&quot;, OPT_PRIOSUB | 0 },
++ { &quot;nomp&quot;, o_bool, &amp;multilink,
++ &quot;Disable multilink operation&quot;, OPT_PRIOSUB | OPT_ALIAS | 0 },
++
++ { &quot;bundle&quot;, o_string, &amp;bundle_name,
++ &quot;Bundle name for multilink&quot;, OPT_PRIO },
++#endif /* HAVE_MULTILINK */
++
++#ifdef PLUGIN
++ { &quot;plugin&quot;, o_special, (void *)loadplugin,
++ &quot;Load a plug-in module into pppd&quot;, OPT_PRIV | OPT_A2LIST },
++#endif
++
++#ifdef PPP_FILTER
++ { &quot;pdebug&quot;, o_int, &amp;dflag,
++ &quot;libpcap debugging&quot;, OPT_PRIO },
++
++ { &quot;pass-filter&quot;, 1, setpassfilter,
++ &quot;set filter for packets to pass&quot;, OPT_PRIO },
++
++ { &quot;active-filter&quot;, 1, setactivefilter,
++ &quot;set filter for active pkts&quot;, OPT_PRIO },
++#endif
++
++ { NULL }
++};
++
++#ifndef IMPLEMENTATION
++#define IMPLEMENTATION &quot;&quot;
++#endif
++
++static char *usage_string = &quot;\
++pppd version %s\n\
++Usage: %s [ options ], where options are:\n\
++ &lt;device&gt; Communicate over the named device\n\
++ &lt;speed&gt; Set the baud rate to &lt;speed&gt;\n\
++ &lt;loc&gt;:&lt;rem&gt; Set the local and/or remote interface IP\n\
++ addresses. Either one may be omitted.\n\
++ asyncmap &lt;n&gt; Set the desired async map to hex &lt;n&gt;\n\
++ auth Require authentication from peer\n\
++ connect &lt;p&gt; Invoke shell command &lt;p&gt; to set up the serial line\n\
++ crtscts Use hardware RTS/CTS flow control\n\
++ defaultroute Add default route through interface\n\
++ file &lt;f&gt; Take options from file &lt;f&gt;\n\
++ modem Use modem control lines\n\
++ mru &lt;n&gt; Set MRU value to &lt;n&gt; for negotiation\n\
++See pppd(8) for more options.\n\
++&quot;;
++
++/*
++ * parse_args - parse a string of arguments from the command line.
++ */
++int
++parse_args(argc, argv)
++ int argc;
++ char **argv;
++{
++ char *arg;
++ option_t *opt;
++ int n;
++
++ privileged_option = privileged;
++ option_source = &quot;command line&quot;;
++ option_priority = OPRIO_CMDLINE;
++ while (argc &gt; 0) {
++ arg = *argv++;
++ --argc;
++ opt = find_option(arg);
++ if (opt == NULL) {
++ option_error(&quot;unrecognized option '%s'&quot;, arg);
++ usage();
++ return 0;
++ }
++ n = n_arguments(opt);
++ if (argc &lt; n) {
++ option_error(&quot;too few parameters for option %s&quot;, arg);
++ return 0;
++ }
++ if (!process_option(opt, arg, argv))
++ return 0;
++ argc -= n;
++ argv += n;
++ }
++ return 1;
++}
++
++/*
++ * options_from_file - Read a string of options from a file,
++ * and interpret them.
++ */
++int
++options_from_file(filename, must_exist, check_prot, priv)
++ char *filename;
++ int must_exist;
++ int check_prot;
++ int priv;
++{
++ FILE *f;
++ int i, newline, ret, err;
++ option_t *opt;
++ int oldpriv, n;
++ char *oldsource;
++ char *argv[MAXARGS];
++ char args[MAXARGS][MAXWORDLEN];
++ char cmd[MAXWORDLEN];
++
++ if (check_prot)
++ seteuid(getuid());
++ f = fopen(filename, &quot;r&quot;);
++ err = errno;
++ if (check_prot)
++ seteuid(0);
++ if (f == NULL) {
++ errno = err;
++ if (!must_exist) {
++ if (err != ENOENT &amp;&amp; err != ENOTDIR)
++ warn(&quot;Warning: can't open options file %s: %m&quot;, filename);
++ return 1;
++ }
++ option_error(&quot;Can't open options file %s: %m&quot;, filename);
++ return 0;
++ }
++
++ oldpriv = privileged_option;
++ privileged_option = priv;
++ oldsource = option_source;
++ option_source = strdup(filename);
++ if (option_source == NULL)
++ option_source = &quot;file&quot;;
++ ret = 0;
++ while (getword(f, cmd, &amp;newline, filename)) {
++ opt = find_option(cmd);
++ if (opt == NULL) {
++ option_error(&quot;In file %s: unrecognized option '%s'&quot;,
++ filename, cmd);
++ goto err;
++ }
++ n = n_arguments(opt);
++ for (i = 0; i &lt; n; ++i) {
++ if (!getword(f, args[i], &amp;newline, filename)) {
++ option_error(
++ &quot;In file %s: too few parameters for option '%s'&quot;,
++ filename, cmd);
++ goto err;
++ }
++ argv[i] = args[i];
++ }
++ if (!process_option(opt, cmd, argv))
++ goto err;
++ }
++ ret = 1;
++
++err:
++ fclose(f);
++ privileged_option = oldpriv;
++ option_source = oldsource;
++ return ret;
++}
++
++/*
++ * options_from_user - See if the use has a ~/.ppprc file,
++ * and if so, interpret options from it.
++ */
++int
++options_from_user()
++{
++ char *user, *path, *file;
++ int ret;
++ struct passwd *pw;
++ size_t pl;
++
++ pw = getpwuid(getuid());
++ if (pw == NULL || (user = pw-&gt;pw_dir) == NULL || user[0] == 0)
++ return 1;
++ file = _PATH_USEROPT;
++ pl = strlen(user) + strlen(file) + 2;
++ path = malloc(pl);
++ if (path == NULL)
++ novm(&quot;init file name&quot;);
++ slprintf(path, pl, &quot;%s/%s&quot;, user, file);
++ option_priority = OPRIO_CFGFILE;
++ ret = options_from_file(path, 0, 1, privileged);
++ free(path);
++ return ret;
++}
++
++/*
++ * options_for_tty - See if an options file exists for the serial
++ * device, and if so, interpret options from it.
++ * We only allow the per-tty options file to override anything from
++ * the command line if it is something that the user can't override
++ * once it has been set by root; this is done by giving configuration
++ * files a lower priority than the command line.
++ */
++int
++options_for_tty()
++{
++ char *dev, *path, *p;
++ int ret;
++ size_t pl;
++
++ dev = devnam;
++ if (strncmp(dev, &quot;/dev/&quot;, 5) == 0)
++ dev += 5;
++ if (dev[0] == 0 || strcmp(dev, &quot;tty&quot;) == 0)
++ return 1; /* don't look for /etc/ppp/options.tty */
++ pl = strlen(_PATH_TTYOPT) + strlen(dev) + 1;
++ path = malloc(pl);
++ if (path == NULL)
++ novm(&quot;tty init file name&quot;);
++ slprintf(path, pl, &quot;%s%s&quot;, _PATH_TTYOPT, dev);
++ /* Turn slashes into dots, for Solaris case (e.g. /dev/term/a) */
++ for (p = path + strlen(_PATH_TTYOPT); *p != 0; ++p)
++ if (*p == '/')
++ *p = '.';
++ option_priority = OPRIO_CFGFILE;
++ ret = options_from_file(path, 0, 0, 1);
++ free(path);
++ return ret;
++}
++
++/*
++ * options_from_list - process a string of options in a wordlist.
++ */
++int
++options_from_list(w, priv)
++ struct wordlist *w;
++ int priv;
++{
++ char *argv[MAXARGS];
++ option_t *opt;
++ int i, n, ret = 0;
++ struct wordlist *w0;
++
++ privileged_option = priv;
++ option_source = &quot;secrets file&quot;;
++ option_priority = OPRIO_SECFILE;
++
++ while (w != NULL) {
++ opt = find_option(w-&gt;word);
++ if (opt == NULL) {
++ option_error(&quot;In secrets file: unrecognized option '%s'&quot;,
++ w-&gt;word);
++ goto err;
++ }
++ n = n_arguments(opt);
++ w0 = w;
++ for (i = 0; i &lt; n; ++i) {
++ w = w-&gt;next;
++ if (w == NULL) {
++ option_error(
++ &quot;In secrets file: too few parameters for option '%s'&quot;,
++ w0-&gt;word);
++ goto err;
++ }
++ argv[i] = w-&gt;word;
++ }
++ if (!process_option(opt, w0-&gt;word, argv))
++ goto err;
++ w = w-&gt;next;
++ }
++ ret = 1;
++
++err:
++ return ret;
++}
++
++/*
++ * match_option - see if this option matches an option_t structure.
++ */
++static int
++match_option(name, opt, dowild)
++ char *name;
++ option_t *opt;
++ int dowild;
++{
++ int (*match) __P((char *, char **, int));
++
++ if (dowild != (opt-&gt;type == o_wild))
++ return 0;
++ if (!dowild)
++ return strcmp(name, opt-&gt;name) == 0;
++ match = (int (*) __P((char *, char **, int))) opt-&gt;addr;
++ return (*match)(name, NULL, 0);
++}
++
++/*
++ * find_option - scan the option lists for the various protocols
++ * looking for an entry with the given name.
++ * This could be optimized by using a hash table.
++ */
++static option_t *
++find_option(name)
++ const char *name;
++{
++ option_t *opt;
++ struct option_list *list;
++ int i, dowild;
++
++ for (dowild = 0; dowild &lt;= 1; ++dowild) {
++ for (opt = general_options; opt-&gt;name != NULL; ++opt)
++ if (match_option(name, opt, dowild))
++ return opt;
++ for (opt = auth_options; opt-&gt;name != NULL; ++opt)
++ if (match_option(name, opt, dowild))
++ return opt;
++ for (list = extra_options; list != NULL; list = list-&gt;next)
++ for (opt = list-&gt;options; opt-&gt;name != NULL; ++opt)
++ if (match_option(name, opt, dowild))
++ return opt;
++ for (opt = the_channel-&gt;options; opt-&gt;name != NULL; ++opt)
++ if (match_option(name, opt, dowild))
++ return opt;
++ for (i = 0; protocols[i] != NULL; ++i)
++ if ((opt = protocols[i]-&gt;options) != NULL)
++ for (; opt-&gt;name != NULL; ++opt)
++ if (match_option(name, opt, dowild))
++ return opt;
++ }
++ return NULL;
++}
++
++/*
++ * process_option - process one new-style option.
++ */
++static int
++process_option(opt, cmd, argv)
++ option_t *opt;
++ char *cmd;
++ char **argv;
++{
++ u_int32_t v;
++ int iv, a;
++ char *sv;
++ int (*parser) __P((char **));
++ int (*wildp) __P((char *, char **, int));
++ char *optopt = (opt-&gt;type == o_wild)? &quot;&quot;: &quot; option&quot;;
++ int prio = option_priority;
++ option_t *mainopt = opt;
++
++ if ((opt-&gt;flags &amp; OPT_PRIVFIX) &amp;&amp; privileged_option)
++ prio += OPRIO_ROOT;
++ while (mainopt-&gt;flags &amp; OPT_PRIOSUB)
++ --mainopt;
++ if (mainopt-&gt;flags &amp; OPT_PRIO) {
++ if (prio &lt; mainopt-&gt;priority) {
++ /* new value doesn't override old */
++ if (prio == OPRIO_CMDLINE &amp;&amp; mainopt-&gt;priority &gt; OPRIO_ROOT) {
++ option_error(&quot;%s%s set in %s cannot be overridden\n&quot;,
++ opt-&gt;name, optopt, mainopt-&gt;source);
++ return 0;
++ }
++ return 1;
++ }
++ if (prio &gt; OPRIO_ROOT &amp;&amp; mainopt-&gt;priority == OPRIO_CMDLINE)
++ warn(&quot;%s%s from %s overrides command line&quot;,
++ opt-&gt;name, optopt, option_source);
++ }
++
++ if ((opt-&gt;flags &amp; OPT_INITONLY) &amp;&amp; phase != PHASE_INITIALIZE) {
++ option_error(&quot;%s%s cannot be changed after initialization&quot;,
++ opt-&gt;name, optopt);
++ return 0;
++ }
++ if ((opt-&gt;flags &amp; OPT_PRIV) &amp;&amp; !privileged_option) {
++ option_error(&quot;using the %s%s requires root privilege&quot;,
++ opt-&gt;name, optopt);
++ return 0;
++ }
++ if ((opt-&gt;flags &amp; OPT_ENABLE) &amp;&amp; *(bool *)(opt-&gt;addr2) == 0) {
++ option_error(&quot;%s%s is disabled&quot;, opt-&gt;name, optopt);
++ return 0;
++ }
++ if ((opt-&gt;flags &amp; OPT_DEVEQUIV) &amp;&amp; devnam_fixed) {
++ option_error(&quot;the %s%s may not be changed in %s&quot;,
++ opt-&gt;name, optopt, option_source);
++ return 0;
++ }
++
++ switch (opt-&gt;type) {
++ case o_bool:
++ v = opt-&gt;flags &amp; OPT_VALUE;
++ *(bool *)(opt-&gt;addr) = v;
++ if (opt-&gt;addr2 &amp;&amp; (opt-&gt;flags &amp; OPT_A2COPY))
++ *(bool *)(opt-&gt;addr2) = v;
++ break;
++
++ case o_int:
++ iv = 0;
++ if ((opt-&gt;flags &amp; OPT_NOARG) == 0) {
++ if (!int_option(*argv, &amp;iv))
++ return 0;
++ if ((((opt-&gt;flags &amp; OPT_LLIMIT) &amp;&amp; iv &lt; opt-&gt;lower_limit)
++ || ((opt-&gt;flags &amp; OPT_ULIMIT) &amp;&amp; iv &gt; opt-&gt;upper_limit))
++ &amp;&amp; !((opt-&gt;flags &amp; OPT_ZEROOK &amp;&amp; iv == 0))) {
++ char *zok = (opt-&gt;flags &amp; OPT_ZEROOK)? &quot; zero or&quot;: &quot;&quot;;
++ switch (opt-&gt;flags &amp; OPT_LIMITS) {
++ case OPT_LLIMIT:
++ option_error(&quot;%s value must be%s &gt;= %d&quot;,
++ opt-&gt;name, zok, opt-&gt;lower_limit);
++ break;
++ case OPT_ULIMIT:
++ option_error(&quot;%s value must be%s &lt;= %d&quot;,
++ opt-&gt;name, zok, opt-&gt;upper_limit);
++ break;
++ case OPT_LIMITS:
++ option_error(&quot;%s value must be%s between %d and %d&quot;,
++ opt-&gt;name, opt-&gt;lower_limit, opt-&gt;upper_limit);
++ break;
++ }
++ return 0;
++ }
++ }
++ a = opt-&gt;flags &amp; OPT_VALUE;
++ if (a &gt;= 128)
++ a -= 256; /* sign extend */
++ iv += a;
++ if (opt-&gt;flags &amp; OPT_INC)
++ iv += *(int *)(opt-&gt;addr);
++ if ((opt-&gt;flags &amp; OPT_NOINCR) &amp;&amp; !privileged_option) {
++ int oldv = *(int *)(opt-&gt;addr);
++ if ((opt-&gt;flags &amp; OPT_ZEROINF) ?
++ (oldv != 0 &amp;&amp; (iv == 0 || iv &gt; oldv)) : (iv &gt; oldv)) {
++ option_error(&quot;%s value cannot be increased&quot;, opt-&gt;name);
++ return 0;
++ }
++ }
++ *(int *)(opt-&gt;addr) = iv;
++ if (opt-&gt;addr2 &amp;&amp; (opt-&gt;flags &amp; OPT_A2COPY))
++ *(int *)(opt-&gt;addr2) = iv;
++ break;
++
++ case o_uint32:
++ if (opt-&gt;flags &amp; OPT_NOARG) {
++ v = opt-&gt;flags &amp; OPT_VALUE;
++ if (v &amp; 0x80)
++ v |= 0xffffff00U;
++ } else if (!number_option(*argv, &amp;v, 16))
++ return 0;
++ if (opt-&gt;flags &amp; OPT_OR)
++ v |= *(u_int32_t *)(opt-&gt;addr);
++ *(u_int32_t *)(opt-&gt;addr) = v;
++ if (opt-&gt;addr2 &amp;&amp; (opt-&gt;flags &amp; OPT_A2COPY))
++ *(u_int32_t *)(opt-&gt;addr2) = v;
++ break;
++
++ case o_string:
++ if (opt-&gt;flags &amp; OPT_STATIC) {
++ strlcpy((char *)(opt-&gt;addr), *argv, opt-&gt;upper_limit);
++ } else {
++ sv = strdup(*argv);
++ if (sv == NULL)
++ novm(&quot;option argument&quot;);
++ *(char **)(opt-&gt;addr) = sv;
++ }
++ break;
++
++ case o_special_noarg:
++ case o_special:
++ parser = (int (*) __P((char **))) opt-&gt;addr;
++ if (!(*parser)(argv))
++ return 0;
++ if (opt-&gt;flags &amp; OPT_A2LIST) {
++ struct option_value *ovp, **pp;
++
++ ovp = malloc(sizeof(*ovp) + strlen(*argv));
++ if (ovp != 0) {
++ strcpy(ovp-&gt;value, *argv);
++ ovp-&gt;source = option_source;
++ ovp-&gt;next = NULL;
++ pp = (struct option_value **) &amp;opt-&gt;addr2;
++ while (*pp != 0)
++ pp = &amp;(*pp)-&gt;next;
++ *pp = ovp;
++ }
++ }
++ break;
++
++ case o_wild:
++ wildp = (int (*) __P((char *, char **, int))) opt-&gt;addr;
++ if (!(*wildp)(cmd, argv, 1))
++ return 0;
++ break;
++ }
++
++ if (opt-&gt;addr2 &amp;&amp; (opt-&gt;flags &amp; (OPT_A2COPY|OPT_ENABLE
++ |OPT_A2PRINTER|OPT_A2STRVAL|OPT_A2LIST)) == 0)
++ *(bool *)(opt-&gt;addr2) = !(opt-&gt;flags &amp; OPT_A2CLR);
++
++ mainopt-&gt;source = option_source;
++ mainopt-&gt;priority = prio;
++ mainopt-&gt;winner = opt - mainopt;
++
++ return 1;
++}
++
++/*
++ * override_value - if the option priorities would permit us to
++ * override the value of option, return 1 and update the priority
++ * and source of the option value. Otherwise returns 0.
++ */
++int
++override_value(option, priority, source)
++ const char *option;
++ int priority;
++ const char *source;
++{
++ option_t *opt;
++
++ opt = find_option(option);
++ if (opt == NULL)
++ return 0;
++ while (opt-&gt;flags &amp; OPT_PRIOSUB)
++ --opt;
++ if ((opt-&gt;flags &amp; OPT_PRIO) &amp;&amp; priority &lt; opt-&gt;priority)
++ return 0;
++ opt-&gt;priority = priority;
++ opt-&gt;source = source;
++ opt-&gt;winner = -1;
++ return 1;
++}
++
++/*
++ * n_arguments - tell how many arguments an option takes
++ */
++static int
++n_arguments(opt)
++ option_t *opt;
++{
++ return (opt-&gt;type == o_bool || opt-&gt;type == o_special_noarg
++ || (opt-&gt;flags &amp; OPT_NOARG))? 0: 1;
++}
++
++/*
++ * add_options - add a list of options to the set we grok.
++ */
++void
++add_options(opt)
++ option_t *opt;
++{
++ struct option_list *list;
++
++ list = malloc(sizeof(*list));
++ if (list == 0)
++ novm(&quot;option list entry&quot;);
++ list-&gt;options = opt;
++ list-&gt;next = extra_options;
++ extra_options = list;
++}
++
++/*
++ * check_options - check that options are valid and consistent.
++ */
++void
++check_options()
++{
++ if (logfile_fd &gt;= 0 &amp;&amp; logfile_fd != log_to_fd)
++ close(logfile_fd);
++}
++
++/*
++ * print_option - print out an option and its value
++ */
++static void
++print_option(opt, mainopt, printer, arg)
++ option_t *opt, *mainopt;
++ void (*printer) __P((void *, char *, ...));
++ void *arg;
++{
++ int i, v;
++ char *p;
++
++ if (opt-&gt;flags &amp; OPT_NOPRINT)
++ return;
++ switch (opt-&gt;type) {
++ case o_bool:
++ v = opt-&gt;flags &amp; OPT_VALUE;
++ if (*(bool *)opt-&gt;addr != v)
++ /* this can happen legitimately, e.g. lock
++ option turned off for default device */
++ break;
++ printer(arg, &quot;%s&quot;, opt-&gt;name);
++ break;
++ case o_int:
++ v = opt-&gt;flags &amp; OPT_VALUE;
++ if (v &gt;= 128)
++ v -= 256;
++ i = *(int *)opt-&gt;addr;
++ if (opt-&gt;flags &amp; OPT_NOARG) {
++ printer(arg, &quot;%s&quot;, opt-&gt;name);
++ if (i != v) {
++ if (opt-&gt;flags &amp; OPT_INC) {
++ for (; i &gt; v; i -= v)
++ printer(arg, &quot; %s&quot;, opt-&gt;name);
++ } else
++ printer(arg, &quot; # oops: %d not %d\n&quot;,
++ i, v);
++ }
++ } else {
++ printer(arg, &quot;%s %d&quot;, opt-&gt;name, i);
++ }
++ break;
++ case o_uint32:
++ printer(arg, &quot;%s&quot;, opt-&gt;name);
++ if ((opt-&gt;flags &amp; OPT_NOARG) == 0)
++ printer(arg, &quot; %x&quot;, *(u_int32_t *)opt-&gt;addr);
++ break;
++
++ case o_string:
++ if (opt-&gt;flags &amp; OPT_HIDE) {
++ p = &quot;??????&quot;;
++ } else {
++ p = (char *) opt-&gt;addr;
++ if ((opt-&gt;flags &amp; OPT_STATIC) == 0)
++ p = *(char **)p;
++ }
++ printer(arg, &quot;%s %q&quot;, opt-&gt;name, p);
++ break;
++
++ case o_special:
++ case o_special_noarg:
++ case o_wild:
++ if (opt-&gt;type != o_wild) {
++ printer(arg, &quot;%s&quot;, opt-&gt;name);
++ if (n_arguments(opt) == 0)
++ break;
++ printer(arg, &quot; &quot;);
++ }
++ if (opt-&gt;flags &amp; OPT_A2PRINTER) {
++ void (*oprt) __P((option_t *,
++ void ((*)__P((void *, char *, ...))),
++ void *));
++ oprt = opt-&gt;addr2;
++ (*oprt)(opt, printer, arg);
++ } else if (opt-&gt;flags &amp; OPT_A2STRVAL) {
++ p = (char *) opt-&gt;addr2;
++ if ((opt-&gt;flags &amp; OPT_STATIC) == 0)
++ p = *(char **)p;
++ printer(&quot;%q&quot;, p);
++ } else if (opt-&gt;flags &amp; OPT_A2LIST) {
++ struct option_value *ovp;
++
++ ovp = (struct option_value *) opt-&gt;addr2;
++ for (;;) {
++ printer(arg, &quot;%q&quot;, ovp-&gt;value);
++ if ((ovp = ovp-&gt;next) == NULL)
++ break;
++ printer(arg, &quot;\t\t# (from %s)\n%s &quot;,
++ ovp-&gt;source, opt-&gt;name);
++ }
++ } else {
++ printer(arg, &quot;xxx # [don't know how to print value]&quot;);
++ }
++ break;
++
++ default:
++ printer(arg, &quot;# %s value (type %d)&quot;, opt-&gt;name, opt-&gt;type);
++ break;
++ }
++ printer(arg, &quot;\t\t# (from %s)\n&quot;, mainopt-&gt;source);
++}
++
++/*
++ * print_option_list - print out options in effect from an
++ * array of options.
++ */
++static void
++print_option_list(opt, printer, arg)
++ option_t *opt;
++ void (*printer) __P((void *, char *, ...));
++ void *arg;
++{
++ while (opt-&gt;name != NULL) {
++ if (opt-&gt;priority != OPRIO_DEFAULT
++ &amp;&amp; opt-&gt;winner != (short int) -1)
++ print_option(opt + opt-&gt;winner, opt, printer, arg);
++ do {
++ ++opt;
++ } while (opt-&gt;flags &amp; OPT_PRIOSUB);
++ }
++}
++
++/*
++ * print_options - print out what options are in effect.
++ */
++void
++print_options(printer, arg)
++ void (*printer) __P((void *, char *, ...));
++ void *arg;
++{
++ struct option_list *list;
++ int i;
++
++ printer(arg, &quot;pppd options in effect:\n&quot;);
++ print_option_list(general_options, printer, arg);
++ print_option_list(auth_options, printer, arg);
++ for (list = extra_options; list != NULL; list = list-&gt;next)
++ print_option_list(list-&gt;options, printer, arg);
++ print_option_list(the_channel-&gt;options, printer, arg);
++ for (i = 0; protocols[i] != NULL; ++i)
++ print_option_list(protocols[i]-&gt;options, printer, arg);
++}
++
++/*
++ * usage - print out a message telling how to use the program.
++ */
++static void
++usage()
++{
++ if (phase == PHASE_INITIALIZE)
++ fprintf(stderr, usage_string, VERSION, progname);
++}
++
++/*
++ * showhelp - print out usage message and exit.
++ */
++static int
++showhelp(argv)
++ char **argv;
++{
++ if (phase == PHASE_INITIALIZE) {
++ usage();
++ exit(0);
++ }
++ return 0;
++}
++
++/*
++ * showversion - print out the version number and exit.
++ */
++static int
++showversion(argv)
++ char **argv;
++{
++ if (phase == PHASE_INITIALIZE) {
++ fprintf(stderr, &quot;pppd version %s\n&quot;, VERSION);
++ exit(0);
++ }
++ return 0;
++}
++
++/*
++ * option_error - print a message about an error in an option.
++ * The message is logged, and also sent to
++ * stderr if phase == PHASE_INITIALIZE.
++ */
++void
++option_error __V((char *fmt, ...))
++{
++ va_list args;
++ char buf[1024];
++
++#if defined(__STDC__)
++ va_start(args, fmt);
++#else
++ char *fmt;
++ va_start(args);
++ fmt = va_arg(args, char *);
++#endif
++ vslprintf(buf, sizeof(buf), fmt, args);
++ va_end(args);
++ if (phase == PHASE_INITIALIZE)
++ fprintf(stderr, &quot;%s: %s\n&quot;, progname, buf);
++ syslog(LOG_ERR, &quot;%s&quot;, buf);
++}
++
++#if 0
++/*
++ * readable - check if a file is readable by the real user.
++ */
++int
++readable(fd)
++ int fd;
++{
++ uid_t uid;
++ int i;
++ struct stat sbuf;
++
++ uid = getuid();
++ if (uid == 0)
++ return 1;
++ if (fstat(fd, &amp;sbuf) != 0)
++ return 0;
++ if (sbuf.st_uid == uid)
++ return sbuf.st_mode &amp; S_IRUSR;
++ if (sbuf.st_gid == getgid())
++ return sbuf.st_mode &amp; S_IRGRP;
++ for (i = 0; i &lt; ngroups; ++i)
++ if (sbuf.st_gid == groups[i])
++ return sbuf.st_mode &amp; S_IRGRP;
++ return sbuf.st_mode &amp; S_IROTH;
++}
++#endif
++
++/*
++ * Read a word from a file.
++ * Words are delimited by white-space or by quotes (&quot; or ').
++ * Quotes, white-space and \ may be escaped with \.
++ * \&lt;newline&gt; is ignored.
++ */
++int
++getword(f, word, newlinep, filename)
++ FILE *f;
++ char *word;
++ int *newlinep;
++ char *filename;
++{
++ int c, len, escape;
++ int quoted, comment;
++ int value, digit, got, n;
++
++#define isoctal(c) ((c) &gt;= '0' &amp;&amp; (c) &lt; '8')
++
++ *newlinep = 0;
++ len = 0;
++ escape = 0;
++ comment = 0;
++
++ /*
++ * First skip white-space and comments.
++ */
++ for (;;) {
++ c = getc(f);
++ if (c == EOF)
++ break;
++
++ /*
++ * A newline means the end of a comment; backslash-newline
++ * is ignored. Note that we cannot have escape &amp;&amp; comment.
++ */
++ if (c == '\n') {
++ if (!escape) {
++ *newlinep = 1;
++ comment = 0;
++ } else
++ escape = 0;
++ continue;
++ }
++
++ /*
++ * Ignore characters other than newline in a comment.
++ */
++ if (comment)
++ continue;
++
++ /*
++ * If this character is escaped, we have a word start.
++ */
++ if (escape)
++ break;
++
++ /*
++ * If this is the escape character, look at the next character.
++ */
++ if (c == '\\') {
++ escape = 1;
++ continue;
++ }
++
++ /*
++ * If this is the start of a comment, ignore the rest of the line.
++ */
++ if (c == '#') {
++ comment = 1;
++ continue;
++ }
++
++ /*
++ * A non-whitespace character is the start of a word.
++ */
++ if (!isspace(c))
++ break;
++ }
++
++ /*
++ * Save the delimiter for quoted strings.
++ */
++ if (!escape &amp;&amp; (c == '&quot;' || c == '\'')) {
++ quoted = c;
++ c = getc(f);
++ } else
++ quoted = 0;
++
++ /*
++ * Process characters until the end of the word.
++ */
++ while (c != EOF) {
++ if (escape) {
++ /*
++ * This character is escaped: backslash-newline is ignored,
++ * various other characters indicate particular values
++ * as for C backslash-escapes.
++ */
++ escape = 0;
++ if (c == '\n') {
++ c = getc(f);
++ continue;
++ }
++
++ got = 0;
++ switch (c) {
++ case 'a':
++ value = '\a';
++ break;
++ case 'b':
++ value = '\b';
++ break;
++ case 'f':
++ value = '\f';
++ break;
++ case 'n':
++ value = '\n';
++ break;
++ case 'r':
++ value = '\r';
++ break;
++ case 's':
++ value = ' ';
++ break;
++ case 't':
++ value = '\t';
++ break;
++
++ default:
++ if (isoctal(c)) {
++ /*
++ * \ddd octal sequence
++ */
++ value = 0;
++ for (n = 0; n &lt; 3 &amp;&amp; isoctal(c); ++n) {
++ value = (value &lt;&lt; 3) + (c &amp; 07);
++ c = getc(f);
++ }
++ got = 1;
++ break;
++ }
++
++ if (c == 'x') {
++ /*
++ * \x&lt;hex_string&gt; sequence
++ */
++ value = 0;
++ c = getc(f);
++ for (n = 0; n &lt; 2 &amp;&amp; isxdigit(c); ++n) {
++ digit = toupper(c) - '0';
++ if (digit &gt; 10)
++ digit += '0' + 10 - 'A';
++ value = (value &lt;&lt; 4) + digit;
++ c = getc (f);
++ }
++ got = 1;
++ break;
++ }
++
++ /*
++ * Otherwise the character stands for itself.
++ */
++ value = c;
++ break;
++ }
++
++ /*
++ * Store the resulting character for the escape sequence.
++ */
++ if (len &lt; MAXWORDLEN-1)
++ word[len] = value;
++ ++len;
++
++ if (!got)
++ c = getc(f);
++ continue;
++
++ }
++
++ /*
++ * Not escaped: see if we've reached the end of the word.
++ */
++ if (quoted) {
++ if (c == quoted)
++ break;
++ } else {
++ if (isspace(c) || c == '#') {
++ ungetc (c, f);
++ break;
++ }
++ }
++
++ /*
++ * Backslash starts an escape sequence.
++ */
++ if (c == '\\') {
++ escape = 1;
++ c = getc(f);
++ continue;
++ }
++
++ /*
++ * An ordinary character: store it in the word and get another.
++ */
++ if (len &lt; MAXWORDLEN-1)
++ word[len] = c;
++ ++len;
++
++ c = getc(f);
++ }
++
++ /*
++ * End of the word: check for errors.
++ */
++ if (c == EOF) {
++ if (ferror(f)) {
++ if (errno == 0)
++ errno = EIO;
++ option_error(&quot;Error reading %s: %m&quot;, filename);
++ die(1);
++ }
++ /*
++ * If len is zero, then we didn't find a word before the
++ * end of the file.
++ */
++ if (len == 0)
++ return 0;
++ }
++
++ /*
++ * Warn if the word was too long, and append a terminating null.
++ */
++ if (len &gt;= MAXWORDLEN) {
++ option_error(&quot;warning: word in file %s too long (%.20s...)&quot;,
++ filename, word);
++ len = MAXWORDLEN - 1;
++ }
++ word[len] = 0;
++
++ return 1;
++
++#undef isoctal
++
++}
++
++/*
++ * number_option - parse an unsigned numeric parameter for an option.
++ */
++static int
++number_option(str, valp, base)
++ char *str;
++ u_int32_t *valp;
++ int base;
++{
++ char *ptr;
++
++ *valp = strtoul(str, &amp;ptr, base);
++ if (ptr == str) {
++ option_error(&quot;invalid numeric parameter '%s' for %s option&quot;,
++ str, current_option);
++ return 0;
++ }
++ return 1;
++}
++
++
++/*
++ * int_option - like number_option, but valp is int *,
++ * the base is assumed to be 0, and *valp is not changed
++ * if there is an error.
++ */
++int
++int_option(str, valp)
++ char *str;
++ int *valp;
++{
++ u_int32_t v;
++
++ if (!number_option(str, &amp;v, 0))
++ return 0;
++ *valp = (int) v;
++ return 1;
++}
++
++
++/*
++ * The following procedures parse options.
++ */
++
++/*
++ * readfile - take commands from a file.
++ */
++static int
++readfile(argv)
++ char **argv;
++{
++ return options_from_file(*argv, 1, 1, privileged_option);
++}
++
++/*
++ * callfile - take commands from /etc/ppp/peers/&lt;name&gt;.
++ * Name may not contain /../, start with / or ../, or end in /..
++ */
++static int
++callfile(argv)
++ char **argv;
++{
++ char *fname, *arg, *p;
++ int l, ok;
++
++ arg = *argv;
++ ok = 1;
++ if (arg[0] == '/' || arg[0] == 0)
++ ok = 0;
++ else {
++ for (p = arg; *p != 0; ) {
++ if (p[0] == '.' &amp;&amp; p[1] == '.' &amp;&amp; (p[2] == '/' || p[2] == 0)) {
++ ok = 0;
++ break;
++ }
++ while (*p != '/' &amp;&amp; *p != 0)
++ ++p;
++ if (*p == '/')
++ ++p;
++ }
++ }
++ if (!ok) {
++ option_error(&quot;call option value may not contain .. or start with /&quot;);
++ return 0;
++ }
++
++ l = strlen(arg) + strlen(_PATH_PEERFILES) + 1;
++ if ((fname = (char *) malloc(l)) == NULL)
++ novm(&quot;call file name&quot;);
++ slprintf(fname, l, &quot;%s%s&quot;, _PATH_PEERFILES, arg);
++
++ ok = options_from_file(fname, 1, 1, 1);
++
++ free(fname);
++ return ok;
++}
++
++#ifdef PPP_FILTER
++/*
++ * setpassfilter - Set the pass filter for packets
++ */
++static int
++setpassfilter(argv)
++ char **argv;
++{
++ pc.linktype = DLT_PPP;
++ pc.snapshot = PPP_HDRLEN;
++
++ if (pcap_compile(&amp;pc, &amp;pass_filter, *argv, 1, netmask) == 0)
++ return 1;
++ option_error(&quot;error in pass-filter expression: %s\n&quot;, pcap_geterr(&amp;pc));
++ return 0;
++}
++
++/*
++ * setactivefilter - Set the active filter for packets
++ */
++static int
++setactivefilter(argv)
++ char **argv;
++{
++ pc.linktype = DLT_PPP;
++ pc.snapshot = PPP_HDRLEN;
++
++ if (pcap_compile(&amp;pc, &amp;active_filter, *argv, 1, netmask) == 0)
++ return 1;
++ option_error(&quot;error in active-filter expression: %s\n&quot;, pcap_geterr(&amp;pc));
++ return 0;
++}
++#endif
++
++/*
++ * setdomain - Set domain name to append to hostname
++ */
++static int
++setdomain(argv)
++ char **argv;
++{
++ gethostname(hostname, MAXNAMELEN);
++ if (**argv != 0) {
++ if (**argv != '.')
++ strncat(hostname, &quot;.&quot;, MAXNAMELEN - strlen(hostname));
++ domain = hostname + strlen(hostname);
++ strncat(hostname, *argv, MAXNAMELEN - strlen(hostname));
++ }
++ hostname[MAXNAMELEN-1] = 0;
++ return (1);
++}
++
++
++static int
++setlogfile(argv)
++ char **argv;
++{
++ int fd, err;
++
++ if (!privileged_option)
++ seteuid(getuid());
++ fd = open(*argv, O_WRONLY | O_APPEND | O_CREAT | O_EXCL, 0644);
++ if (fd &lt; 0 &amp;&amp; errno == EEXIST)
++ fd = open(*argv, O_WRONLY | O_APPEND);
++ err = errno;
++ if (!privileged_option)
++ seteuid(0);
++ if (fd &lt; 0) {
++ errno = err;
++ option_error(&quot;Can't open log file %s: %m&quot;, *argv);
++ return 0;
++ }
++ strlcpy(logfile_name, *argv, sizeof(logfile_name));
++ if (logfile_fd &gt;= 0)
++ close(logfile_fd);
++ logfile_fd = fd;
++ log_to_fd = fd;
++ log_default = 0;
++ return 1;
++}
++
++#ifdef PLUGIN
++static int
++loadplugin(argv)
++ char **argv;
++{
++ char *arg = *argv;
++ void *handle;
++ const char *err;
++ void (*init) __P((void));
++ char *path = arg;
++ const char *vers;
++
++ if (strchr(arg, '/') == 0) {
++ const char *base = _PATH_PLUGIN;
++ int l = strlen(base) + strlen(arg) + 2;
++ path = malloc(l);
++ if (path == 0)
++ novm(&quot;plugin file path&quot;);
++ strlcpy(path, base, l);
++ strlcat(path, &quot;/&quot;, l);
++ strlcat(path, arg, l);
++ }
++ handle = dlopen(path, RTLD_GLOBAL | RTLD_NOW);
++ if (handle == 0) {
++ err = dlerror();
++ if (err != 0)
++ option_error(&quot;%s&quot;, err);
++ option_error(&quot;Couldn't load plugin %s&quot;, arg);
++ goto err;
++ }
++ init = (void (*)(void))dlsym(handle, &quot;plugin_init&quot;);
++ if (init == 0) {
++ option_error(&quot;%s has no initialization entry point&quot;, arg);
++ goto errclose;
++ }
++ vers = (const char *) dlsym(handle, &quot;pppd_version&quot;);
++ if (vers == 0) {
++ warn(&quot;Warning: plugin %s has no version information&quot;, arg);
++ } else if (strcmp(vers, VERSION) != 0) {
++ option_error(&quot;Plugin %s is for pppd version %s, this is %s&quot;,
++ vers, VERSION);
++ goto errclose;
++ }
++ info(&quot;Plugin %s loaded.&quot;, arg);
++ (*init)();
++ return 1;
++
++ errclose:
++ dlclose(handle);
++ err:
++ if (path != arg)
++ free(path);
++ return 0;
++}
++#endif /* PLUGIN */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/options.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/patchlevel.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/patchlevel.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/patchlevel.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,4 @@
++/* $Id: patchlevel.h 195720 2001-06-11 11:44:34Z gc $ */
++
++#define VERSION &quot;2.4.1&quot;
++#define DATE &quot;25 March 2001&quot;
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/patchlevel.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/pathnames.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/pathnames.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/pathnames.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,25 @@
++/*
++ * define path names
++ *
++ * $Id: pathnames.h 195734 2001-06-11 14:46:02Z gc $
++ */
++
++#define _PATH_VARRUN &quot;/var/run/&quot;
++#define _PATH_DEVNULL &quot;/dev/null&quot;
++#define _ROOT_PATH
++
++#define _PATH_UPAPFILE _ROOT_PATH &quot;/etc/ppp/pap-secrets&quot;
++#define _PATH_CHAPFILE _ROOT_PATH &quot;/etc/ppp/chap-secrets&quot;
++#define _PATH_SYSOPTIONS _ROOT_PATH &quot;/etc/ppp/options&quot;
++#define _PATH_IPUP _ROOT_PATH &quot;/etc/ppp/ip-up&quot;
++#define _PATH_IPDOWN _ROOT_PATH &quot;/etc/ppp/ip-down&quot;
++#define _PATH_AUTHUP _ROOT_PATH &quot;/etc/ppp/auth-up&quot;
++#define _PATH_AUTHDOWN _ROOT_PATH &quot;/etc/ppp/auth-down&quot;
++#define _PATH_TTYOPT _ROOT_PATH &quot;/etc/ppp/options.&quot;
++#define _PATH_CONNERRS _ROOT_PATH &quot;/etc/ppp/connect-errors&quot;
++#define _PATH_PEERFILES _ROOT_PATH &quot;/etc/ppp/peers/&quot;
++#define _PATH_RESOLV _ROOT_PATH &quot;/etc/resolv.conf&quot;
++
++#define _PATH_USEROPT &quot;.ppprc&quot;
++
++#define _PATH_PPPDB _ROOT_PATH _PATH_VARRUN &quot;pppd.tdb&quot;
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/pathnames.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/plugins/Makefile.linux
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/plugins/Makefile.linux (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/plugins/Makefile.linux 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,19 @@
++CC = gcc
++CFLAGS = -g -O2 -I.. -I../../include -fPIC
++LDFLAGS = -shared
++INSTALL = install
++
++all: minconn.so passprompt.so
++
++minconn.so: minconn.c
++ $(CC) -o $@ $(LDFLAGS) $(CFLAGS) minconn.c
++
++passprompt.so: passprompt.c
++ $(CC) -o $@ $(LDFLAGS) $(CFLAGS) passprompt.c
++
++LIBDIR = /usr/lib/pppd
++
++install: minconn.so passprompt.so
++ version=`awk -F '&quot;' '/VERSION/ { print $$2; }' ../patchlevel.h`; \
++ $(INSTALL) -d $(LIBDIR)/$$version; \
++ $(INSTALL) $? $(LIBDIR)/$$version
+\ No newline at end of file
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/plugins/Makefile.sol2
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/plugins/Makefile.sol2 (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/plugins/Makefile.sol2 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,27 @@
++#
++# Makefile for plugins on Solaris 2
++#
++# $Id: Makefile.sol2 195720 2001-06-11 11:44:34Z gc $
++#
++
++include ../../svr4/Makedefs
++
++CFLAGS = -c -O -I.. -I../../include $(COPTS)
++LDFLAGS = -G
++
++all: minconn.so
++
++minconn.so: minconn.o
++ ld -o $@ $(LDFLAGS) -h $@ minconn.o
++
++minconn.o: minconn.c
++ $(CC) $(CFLAGS) -c $?
++
++passprompt.so: passprompt.o
++ ld -o $@ $(LDFLAGS) -h $@ passprompt.o
++
++passprompt.o: passprompt.c
++ $(CC) $(CFLAGS) -c $?
++
++clean:
++ rm -f *.o *.so
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/plugins/minconn.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/plugins/minconn.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/plugins/minconn.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,46 @@
++/*
++ * minconn.c - pppd plugin to implement a `minconnect' option.
++ *
++ * Copyright 1999 Paul Mackerras.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms. The name of the author
++ * may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ */
++#include &lt;stddef.h&gt;
++#include &lt;time.h&gt;
++#include &quot;pppd.h&quot;
++
++char pppd_version[] = VERSION;
++
++static int minconnect = 0;
++
++static option_t my_options[] = {
++ { &quot;minconnect&quot;, o_int, &amp;minconnect,
++ &quot;Set minimum connect time before idle timeout applies&quot; },
++ { NULL }
++};
++
++static int my_get_idle(struct ppp_idle *idle)
++{
++ time_t t;
++
++ if (idle == NULL)
++ return minconnect? minconnect: idle_time_limit;
++ t = idle-&gt;xmit_idle;
++ if (idle-&gt;recv_idle &lt; t)
++ t = idle-&gt;recv_idle;
++ return idle_time_limit - t;
++}
++
++void plugin_init(void)
++{
++ info(&quot;plugin_init&quot;);
++ add_options(my_options);
++ idle_time_hook = my_get_idle;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/plugins/minconn.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/plugins/passprompt.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/plugins/passprompt.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/plugins/passprompt.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,108 @@
++/*
++ * passprompt.c - pppd plugin to invoke an external PAP password prompter
++ *
++ * Copyright 1999 Paul Mackerras, Alan Curry.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++#include &lt;errno.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;sys/wait.h&gt;
++#include &lt;syslog.h&gt;
++#include &quot;pppd.h&quot;
++
++char pppd_version[] = VERSION;
++
++static char promptprog[PATH_MAX+1];
++
++static option_t options[] = {
++ { &quot;promptprog&quot;, o_string, promptprog,
++ &quot;External PAP password prompting program&quot;,
++ OPT_STATIC, NULL, PATH_MAX },
++ { NULL }
++};
++
++static int promptpass(char *user, char *passwd)
++{
++ int p[2];
++ pid_t kid;
++ int readgood, wstat;
++ size_t red;
++
++ if (promptprog[0] == 0 || access(promptprog, X_OK) &lt; 0)
++ return -1; /* sorry, can't help */
++
++ if (!passwd)
++ return 1;
++
++ if (pipe(p)) {
++ warn(&quot;Can't make a pipe for %s&quot;, promptprog);
++ return 0;
++ }
++ if ((kid = fork()) == (pid_t) -1) {
++ warn(&quot;Can't fork to run %s&quot;, promptprog);
++ close(p[0]);
++ close(p[1]);
++ return 0;
++ }
++ if (!kid) {
++ /* we are the child, exec the program */
++ char *argv[4], fdstr[32];
++ sys_close();
++ closelog();
++ close(p[0]);
++ seteuid(getuid());
++ setegid(getgid());
++ argv[0] = promptprog;
++ argv[1] = user;
++ argv[2] = remote_name;
++ sprintf(fdstr, &quot;%d&quot;, p[1]);
++ argv[3] = fdstr;
++ argv[4] = 0;
++ execv(*argv, argv);
++ _exit(127);
++ }
++
++ /* we are the parent, read the password from the pipe */
++ close(p[1]);
++ readgood = 0;
++ do {
++ red = read(p[0], passwd + readgood, MAXSECRETLEN-1 - readgood);
++ if (red == 0)
++ break;
++ if (red &lt; 0) {
++ error(&quot;Can't read secret from %s: %m&quot;, promptprog);
++ readgood = -1;
++ break;
++ }
++ readgood += red;
++ } while (readgood &lt; MAXSECRETLEN - 1);
++ passwd[readgood] = 0;
++ close(p[0]);
++
++ /* now wait for child to exit */
++ while (waitpid(kid, &amp;wstat, 0) &lt; 0) {
++ if (errno != EINTR) {
++ warn(&quot;error waiting for %s: %m&quot;, promptprog);
++ break;
++ }
++ }
++
++ if (readgood &lt; 0)
++ return 0;
++ if (!WIFEXITED(wstat))
++ warn(&quot;%s terminated abnormally&quot;, promptprog);
++ if (WEXITSTATUS(wstat))
++ warn(&quot;%s exited with code %d&quot;, promptprog, WEXITSTATUS(status));
++
++ return 1;
++}
++
++void plugin_init(void)
++{
++ add_options(options);
++ pap_passwd_hook = promptpass;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/plugins/passprompt.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/ppp.pam
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/ppp.pam (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/ppp.pam 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,6 @@
++#%PAM-1.0
++# Information for the PPPD process with the 'login' option.
++auth required pam_nologin.so
++auth required pam_unix.so
++account required pam_unix.so
++session required pam_unix.so
+\ No newline at end of file
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/pppd.8
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/pppd.8 (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/pppd.8 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1591 @@
++.\&quot; manual page [] for pppd 2.4
++.\&quot; $Id: pppd.8 195720 2001-06-11 11:44:34Z gc $
++.\&quot; SH section heading
++.\&quot; SS subsection heading
++.\&quot; LP paragraph
++.\&quot; IP indented paragraph
++.\&quot; TP hanging label
++.TH PPPD 8
++.SH NAME
++pppd \- Point to Point Protocol daemon
++.SH SYNOPSIS
++.B pppd
++[
++.I tty_name
++] [
++.I speed
++] [
++.I options
++]
++.SH DESCRIPTION
++.LP
++The Point-to-Point Protocol (PPP) provides a method for transmitting
++datagrams over serial point-to-point links. PPP
++is composed of three parts: a method for encapsulating datagrams over
++serial links, an extensible Link Control Protocol (LCP), and
++a family of Network Control Protocols (NCP) for establishing
++and configuring different network-layer protocols.
++.LP
++The encapsulation scheme is provided by driver code in the kernel.
++Pppd provides the basic LCP, authentication support, and an NCP for
++establishing and configuring the Internet Protocol (IP) (called the IP
++Control Protocol, IPCP).
++.SH FREQUENTLY USED OPTIONS
++.TP
++.I &lt;tty_name&gt;
++Communicate over the named device. The string &quot;/dev/&quot; is prepended if
++necessary. If no device name is given, or if the name of the terminal
++connected to the standard input is given, pppd will use that terminal,
++and will not fork to put itself in the background. A value for this
++option from a privileged source cannot be overridden by a
++non-privileged user.
++.TP
++.I &lt;speed&gt;
++Set the baud rate to &lt;speed&gt; (a decimal number). On systems such as
++4.4BSD and NetBSD, any speed can be specified. Other systems
++(e.g. SunOS) allow only a limited set of speeds.
++.TP
++.B asyncmap \fI&lt;map&gt;
++Set the async character map to &lt;map&gt;. This map describes which
++control characters cannot be successfully received over the serial
++line. Pppd will ask the peer to send these characters as a 2-byte
++escape sequence. The argument is a 32 bit hex number with each bit
++representing a character to escape. Bit 0 (00000001) represents the
++character 0x00; bit 31 (80000000) represents the character 0x1f or ^_.
++If multiple \fIasyncmap\fR options are given, the values are ORed
++together. If no \fIasyncmap\fR option is given, no async character
++map will be negotiated for the receive direction; the peer should then
++escape \fIall\fR control characters. To escape transmitted
++characters, use the \fIescape\fR option.
++.TP
++.B auth
++Require the peer to authenticate itself before allowing network
++packets to be sent or received. This option is the default if the
++system has a default route. If neither this option nor the
++\fInoauth\fR option is specified, pppd will only allow the peer to use
++IP addresses to which the system does not already have a route.
++.TP
++.B call \fIname
++Read options from the file /etc/ppp/peers/\fIname\fR. This file may
++contain privileged options, such as \fInoauth\fR, even if pppd
++is not being run by root. The \fIname\fR string may not begin with /
++or include .. as a pathname component. The format of the options file
++is described below.
++.TP
++.B connect \fIscript
++Use the executable or shell command specified by \fIscript\fR to set
++up the serial line. This script would typically use the chat(8)
++program to dial the modem and start the remote ppp session. A value
++for this option from a privileged source cannot be overridden by a
++non-privileged user.
++.TP
++.B crtscts
++Use hardware flow control (i.e. RTS/CTS) to control the flow of
++data on the serial port. If neither the \fIcrtscts\fR, the
++\fInocrtscts\fR, the \fIcdtrcts\fR nor the \fInocdtrcts\fR option
++is given, the hardware flow control setting for the serial port is
++left unchanged.
++Some serial ports (such as Macintosh serial ports) lack a true
++RTS output. Such serial ports use this mode to implement
++unidirectional flow control. The serial port will
++suspend transmission when requested by the modem (via CTS)
++but will be unable to request the modem stop sending to the
++computer. This mode retains the ability to use DTR as
++a modem control line.
++.TP
++.B defaultroute
++Add a default route to the system routing tables, using the peer as
++the gateway, when IPCP negotiation is successfully completed.
++This entry is removed when the PPP connection is broken. This option
++is privileged if the \fInodefaultroute\fR option has been specified.
++.TP
++.B disconnect \fIscript
++Run the executable or shell command specified by \fIscript\fR after
++pppd has terminated the link. This script could, for example, issue
++commands to the modem to cause it to hang up if hardware modem control
++signals were not available. The disconnect script is not run if the
++modem has already hung up. A value for this option from a privileged
++source cannot be overridden by a non-privileged user.
++.TP
++.B escape \fIxx,yy,...
++Specifies that certain characters should be escaped on transmission
++(regardless of whether the peer requests them to be escaped with its
++async control character map). The characters to be escaped are
++specified as a list of hex numbers separated by commas. Note that
++almost any character can be specified for the \fIescape\fR option,
++unlike the \fIasyncmap\fR option which only allows control characters
++to be specified. The characters which may not be escaped are those
++with hex values 0x20 - 0x3f or 0x5e.
++.TP
++.B file \fIname
++Read options from file \fIname\fR (the format is described below).
++The file must be readable by the user who has invoked pppd.
++.TP
++.B init \fIscript
++Run the executable or shell command specified by \fIscript\fR to
++initialize the serial line. This script would typically use the
++chat(8) program to configure the modem to enable auto answer. A value
++for this option from a privileged source cannot be overridden by a
++non-privileged user.
++.TP
++.B lock
++Specifies that pppd should create a UUCP-style lock file for the
++serial device to ensure exclusive access to the device.
++.TP
++.B mru \fIn
++Set the MRU [Maximum Receive Unit] value to \fIn\fR. Pppd
++will ask the peer to send packets of no more than \fIn\fR bytes. The
++minimum MRU value is 128. The default MRU value is 1500. A value of
++296 is recommended for slow links (40 bytes for TCP/IP header + 256
++bytes of data). (Note that for IPv6 MRU must be at least 1280)
++.TP
++.B mtu \fIn
++Set the MTU [Maximum Transmit Unit] value to \fIn\fR. Unless the
++peer requests a smaller value via MRU negotiation, pppd will
++request that the kernel networking code send data packets of no more
++than \fIn\fR bytes through the PPP network interface. (Note that for
++IPv6 MTU must be at least 1280)
++.TP
++.B passive
++Enables the &quot;passive&quot; option in the LCP. With this option, pppd will
++attempt to initiate a connection; if no reply is received from the
++peer, pppd will then just wait passively for a valid LCP packet from
++the peer, instead of exiting, as it would without this option.
++.SH OPTIONS
++.TP
++.I &lt;local_IP_address&gt;\fB:\fI&lt;remote_IP_address&gt;
++Set the local and/or remote interface IP addresses. Either one may be
++omitted. The IP addresses can be specified with a host name or in
++decimal dot notation (e.g. 150.234.56.78). The default local
++address is the (first) IP address of the system (unless the
++\fInoipdefault\fR
++option is given). The remote address will be obtained from the peer
++if not specified in any option. Thus, in simple cases, this option is
++not required. If a local and/or remote IP address is specified with
++this option, pppd
++will not accept a different value from the peer in the IPCP
++negotiation, unless the \fIipcp-accept-local\fR and/or
++\fIipcp-accept-remote\fR options are given, respectively.
++.TP
++.B ipv6 \fI&lt;local_interface_identifier&gt;\fR,\fI&lt;remote_interface_identifier&gt;
++Set the local and/or remote 64-bit interface identifier. Either one may be
++omitted. The identifier must be specified in standard ascii notation of
++IPv6 addresses (e.g. ::dead:beef). If the
++\fIipv6cp-use-ipaddr\fR
++option is given, the local identifier is the local IPv4 address (see above).
++On systems which supports a unique persistent id, such as EUI-48 derived
++from the Ethernet MAC address, \fIipv6cp-use-persistent\fR option can be
++used to replace the \fIipv6 &lt;local&gt;,&lt;remote&gt;\fR option. Otherwise the
++identifier is randomized.
++.TP
++.B active-filter \fIfilter-expression
++Specifies a packet filter to be applied to data packets to determine
++which packets are to be regarded as link activity, and therefore reset
++the idle timer, or cause the link to be brought up in demand-dialling
++mode. This option is useful in conjunction with the
++\fBidle\fR option if there are packets being sent or received
++regularly over the link (for example, routing information packets)
++which would otherwise prevent the link from ever appearing to be idle.
++The \fIfilter-expression\fR syntax is as described for tcpdump(1),
++except that qualifiers which are inappropriate for a PPP link, such as
++\fBether\fR and \fBarp\fR, are not permitted. Generally the filter
++expression should be enclosed in single-quotes to prevent whitespace
++in the expression from being interpreted by the shell. This option
++is currently only available under NetBSD, and then only
++if both the kernel and pppd were compiled with PPP_FILTER defined.
++.TP
++.B allow-ip \fIaddress(es)
++Allow peers to use the given IP address or subnet without
++authenticating themselves. The parameter is parsed as for each
++element of the list of allowed IP addresses in the secrets files (see
++the AUTHENTICATION section below).
++.TP
++.B bsdcomp \fInr,nt
++Request that the peer compress packets that it sends, using the
++BSD-Compress scheme, with a maximum code size of \fInr\fR bits, and
++agree to compress packets sent to the peer with a maximum code size of
++\fInt\fR bits. If \fInt\fR is not specified, it defaults to the value
++given for \fInr\fR. Values in the range 9 to 15 may be used for
++\fInr\fR and \fInt\fR; larger values give better compression but
++consume more kernel memory for compression dictionaries.
++Alternatively, a value of 0 for \fInr\fR or \fInt\fR disables
++compression in the corresponding direction. Use \fInobsdcomp\fR or
++\fIbsdcomp 0\fR to disable BSD-Compress compression entirely.
++.TP
++.B cdtrcts
++Use a non-standard hardware flow control (i.e. DTR/CTS) to control
++the flow of data on the serial port. If neither the \fIcrtscts\fR,
++the \fInocrtscts\fR, the \fIcdtrcts\fR nor the \fInocdtrcts\fR
++option is given, the hardware flow control setting for the serial
++port is left unchanged.
++Some serial ports (such as Macintosh serial ports) lack a true
++RTS output. Such serial ports use this mode to implement true
++bi-directional flow control. The sacrifice is that this flow
++control mode does not permit using DTR as a modem control line.
++.TP
++.B chap-interval \fIn
++If this option is given, pppd will rechallenge the peer every \fIn\fR
++seconds.
++.TP
++.B chap-max-challenge \fIn
++Set the maximum number of CHAP challenge transmissions to \fIn\fR
++(default 10).
++.TP
++.B chap-restart \fIn
++Set the CHAP restart interval (retransmission timeout for challenges)
++to \fIn\fR seconds (default 3).
++.TP
++.B connect-delay \fIn
++Wait for up \fIn\fR milliseconds after the connect script finishes for
++a valid PPP packet from the peer. At the end of this time, or when a
++valid PPP packet is received from the peer, pppd will commence
++negotiation by sending its first LCP packet. The default value is
++1000 (1 second). This wait period only applies if the \fBconnect\fR
++or \fBpty\fR option is used.
++.TP
++.B debug
++Enables connection debugging facilities.
++If this option is given, pppd will log the contents of all
++control packets sent or received in a readable form. The packets are
++logged through syslog with facility \fIdaemon\fR and level
++\fIdebug\fR. This information can be directed to a file by setting up
++/etc/syslog.conf appropriately (see syslog.conf(5)).
++.TP
++.B default-asyncmap
++Disable asyncmap negotiation, forcing all control characters to be
++escaped for both the transmit and the receive direction.
++.TP
++.B default-mru
++Disable MRU [Maximum Receive Unit] negotiation. With this option,
++pppd will use the default MRU value of 1500 bytes for both the
++transmit and receive direction.
++.TP
++.B deflate \fInr,nt
++Request that the peer compress packets that it sends, using the
++Deflate scheme, with a maximum window size of \fI2**nr\fR bytes, and
++agree to compress packets sent to the peer with a maximum window size
++of \fI2**nt\fR bytes. If \fInt\fR is not specified, it defaults to
++the value given for \fInr\fR. Values in the range 9 to 15 may be used
++for \fInr\fR and \fInt\fR; larger values give better compression but
++consume more kernel memory for compression dictionaries.
++Alternatively, a value of 0 for \fInr\fR or \fInt\fR disables
++compression in the corresponding direction. Use \fInodeflate\fR or
++\fIdeflate 0\fR to disable Deflate compression entirely. (Note: pppd
++requests Deflate compression in preference to BSD-Compress if the peer
++can do either.)
++.TP
++.B demand
++Initiate the link only on demand, i.e. when data traffic is present.
++With this option, the remote IP address must be specified by the user
++on the command line or in an options file. Pppd will initially
++configure the interface and enable it for IP traffic without
++connecting to the peer. When traffic is available, pppd will
++connect to the peer and perform negotiation, authentication, etc.
++When this is completed, pppd will commence passing data packets
++(i.e., IP packets) across the link.
++
++The \fIdemand\fR option implies the \fIpersist\fR option. If this
++behaviour is not desired, use the \fInopersist\fR option after the
++\fIdemand\fR option. The \fIidle\fR and \fIholdoff\fR
++options are also useful in conjuction with the \fIdemand\fR option.
++.TP
++.B domain \fId
++Append the domain name \fId\fR to the local host name for authentication
++purposes. For example, if gethostname() returns the name porsche, but
++the fully qualified domain name is porsche.Quotron.COM, you could
++specify \fIdomain Quotron.COM\fR. Pppd would then use the name
++\fIporsche.Quotron.COM\fR for looking up secrets in the secrets file,
++and as the default name to send to the peer when authenticating itself
++to the peer. This option is privileged.
++.TP
++.B dryrun
++With the \fBdryrun\fR option, pppd will print out all the option
++values which have been set and then exit, after parsing the command
++line and options files and checking the option values, but before
++initiating the link. The option values are logged at level info, and
++also printed to standard output unless the device on standard output
++is the device that pppd would be using to communicate with the peer.
++.TP
++.B dump
++With the \fBdump\fR option, pppd will print out all the option values
++which have been set. This option is like the \fBdryrun\fR option
++except that pppd proceeds as normal rather than exiting.
++.TP
++.B endpoint \fI&lt;epdisc&gt;
++Sets the endpoint discriminator sent by the local machine to the peer
++during multilink negotiation to \fI&lt;epdisc&gt;\fR. The default is to use
++the MAC address of the first ethernet interface on the system, if any,
++otherwise the IPv4 address corresponding to the hostname, if any,
++provided it is not in the multicast or locally-assigned IP address
++ranges, or the localhost address. The endpoint discriminator can be
++the string \fBnull\fR or of the form \fItype\fR:\fIvalue\fR, where
++type is a decimal number or one of the strings \fBlocal\fR, \fBIP\fR,
++\fBMAC\fR, \fBmagic\fR, or \fBphone\fR. The value is an IP address in
++dotted-decimal notation for the \fBIP\fR type, or a string of bytes in
++hexadecimal, separated by periods or colons for the other types. For
++the MAC type, the value may also be the name of an ethernet or similar
++network interface. This option is currently only available under
++Linux.
++.TP
++.B hide-password
++When logging the contents of PAP packets, this option causes pppd to
++exclude the password string from the log. This is the default.
++.TP
++.B holdoff \fIn
++Specifies how many seconds to wait before re-initiating the link after
++it terminates. This option only has any effect if the \fIpersist\fR
++or \fIdemand\fR option is used. The holdoff period is not applied if
++the link was terminated because it was idle.
++.TP
++.B idle \fIn
++Specifies that pppd should disconnect if the link is idle for \fIn\fR
++seconds. The link is idle when no data packets (i.e. IP packets) are
++being sent or received. Note: it is not advisable to use this option
++with the \fIpersist\fR option without the \fIdemand\fR option.
++If the \fBactive-filter\fR
++option is given, data packets which are rejected by the specified
++activity filter also count as the link being idle.
++.TP
++.B ipcp-accept-local
++With this option, pppd will accept the peer's idea of our local IP
++address, even if the local IP address was specified in an option.
++.TP
++.B ipcp-accept-remote
++With this option, pppd will accept the peer's idea of its (remote) IP
++address, even if the remote IP address was specified in an option.
++.TP
++.B ipcp-max-configure \fIn
++Set the maximum number of IPCP configure-request transmissions to
++\fIn\fR (default 10).
++.TP
++.B ipcp-max-failure \fIn
++Set the maximum number of IPCP configure-NAKs returned before starting
++to send configure-Rejects instead to \fIn\fR (default 10).
++.TP
++.B ipcp-max-terminate \fIn
++Set the maximum number of IPCP terminate-request transmissions to
++\fIn\fR (default 3).
++.TP
++.B ipcp-restart \fIn
++Set the IPCP restart interval (retransmission timeout) to \fIn\fR
++seconds (default 3).
++.TP
++.B ipparam \fIstring
++Provides an extra parameter to the ip-up and ip-down scripts. If this
++option is given, the \fIstring\fR supplied is given as the 6th
++parameter to those scripts.
++.TP
++.B ipv6cp-max-configure \fIn
++Set the maximum number of IPv6CP configure-request transmissions to
++\fIn\fR (default 10).
++.TP
++.B ipv6cp-max-failure \fIn
++Set the maximum number of IPv6CP configure-NAKs returned before starting
++to send configure-Rejects instead to \fIn\fR (default 10).
++.TP
++.B ipv6cp-max-terminate \fIn
++Set the maximum number of IPv6CP terminate-request transmissions to
++\fIn\fR (default 3).
++.TP
++.B ipv6cp-restart \fIn
++Set the IPv6CP restart interval (retransmission timeout) to \fIn\fR
++seconds (default 3).
++.TP
++.B ipx
++Enable the IPXCP and IPX protocols. This option is presently only
++supported under Linux, and only if your kernel has been configured to
++include IPX support.
++.TP
++.B ipx-network \fIn
++Set the IPX network number in the IPXCP configure request frame to
++\fIn\fR, a hexadecimal number (without a leading 0x). There is no
++valid default. If this option is not specified, the network number is
++obtained from the peer. If the peer does not have the network number,
++the IPX protocol will not be started.
++.TP
++.B ipx-node \fIn\fB:\fIm
++Set the IPX node numbers. The two node numbers are separated from each
++other with a colon character. The first number \fIn\fR is the local
++node number. The second number \fIm\fR is the peer's node number. Each
++node number is a hexadecimal number, at most 10 digits long. The node
++numbers on the ipx-network must be unique. There is no valid
++default. If this option is not specified then the node numbers are
++obtained from the peer.
++.TP
++.B ipx-router-name \fI&lt;string&gt;
++Set the name of the router. This is a string and is sent to the peer
++as information data.
++.TP
++.B ipx-routing \fIn
++Set the routing protocol to be received by this option. More than one
++instance of \fIipx-routing\fR may be specified. The '\fInone\fR'
++option (0) may be specified as the only instance of ipx-routing. The
++values may be \fI0\fR for \fINONE\fR, \fI2\fR for \fIRIP/SAP\fR, and
++\fI4\fR for \fINLSP\fR.
++.TP
++.B ipxcp-accept-local
++Accept the peer's NAK for the node number specified in the ipx-node
++option. If a node number was specified, and non-zero, the default is
++to insist that the value be used. If you include this option then you
++will permit the peer to override the entry of the node number.
++.TP
++.B ipxcp-accept-network
++Accept the peer's NAK for the network number specified in the
++ipx-network option. If a network number was specified, and non-zero, the
++default is to insist that the value be used. If you include this
++option then you will permit the peer to override the entry of the node
++number.
++.TP
++.B ipxcp-accept-remote
++Use the peer's network number specified in the configure request
++frame. If a node number was specified for the peer and this option was
++not specified, the peer will be forced to use the value which you have
++specified.
++.TP
++.B ipxcp-max-configure \fIn
++Set the maximum number of IPXCP configure request frames which the
++system will send to \fIn\fR. The default is 10.
++.TP
++.B ipxcp-max-failure \fIn
++Set the maximum number of IPXCP NAK frames which the local system will
++send before it rejects the options. The default value is 3.
++.TP
++.B ipxcp-max-terminate \fIn
++Set the maximum nuber of IPXCP terminate request frames before the
++local system considers that the peer is not listening to them. The
++default value is 3.
++.TP
++.B kdebug \fIn
++Enable debugging code in the kernel-level PPP driver. The argument
++values depend on the specific kernel driver, but in general a value of
++1 will enable general kernel debug messages. (Note that these
++messages are usually only useful for debugging the kernel driver
++itself.) For the Linux 2.2.x kernel driver, the value is a sum of
++bits: 1 to
++enable general debug messages, 2 to request that the contents of
++received packets be printed, and 4 to request that the contents of
++transmitted packets be printed. On most systems, messages printed by
++the kernel are logged by syslog(1) to a file as directed in the
++/etc/syslog.conf configuration file.
++.TP
++.B ktune
++Enables pppd to alter kernel settings as appropriate. Under Linux,
++pppd will enable IP forwarding (i.e. set /proc/sys/net/ipv4/ip_forward
++to 1) if the \fIproxyarp\fR option is used, and will enable the
++dynamic IP address option (i.e. set /proc/sys/net/ipv4/ip_dynaddr to
++1) in demand mode if the local address changes.
++.TP
++.B lcp-echo-failure \fIn
++If this option is given, pppd will presume the peer to be dead
++if \fIn\fR LCP echo-requests are sent without receiving a valid LCP
++echo-reply. If this happens, pppd will terminate the
++connection. Use of this option requires a non-zero value for the
++\fIlcp-echo-interval\fR parameter. This option can be used to enable
++pppd to terminate after the physical connection has been broken
++(e.g., the modem has hung up) in situations where no hardware modem
++control lines are available.
++.TP
++.B lcp-echo-interval \fIn
++If this option is given, pppd will send an LCP echo-request frame to
++the peer every \fIn\fR seconds. Normally the peer should respond to
++the echo-request by sending an echo-reply. This option can be used
++with the \fIlcp-echo-failure\fR option to detect that the peer is no
++longer connected.
++.TP
++.B lcp-max-configure \fIn
++Set the maximum number of LCP configure-request transmissions to
++\fIn\fR (default 10).
++.TP
++.B lcp-max-failure \fIn
++Set the maximum number of LCP configure-NAKs returned before starting
++to send configure-Rejects instead to \fIn\fR (default 10).
++.TP
++.B lcp-max-terminate \fIn
++Set the maximum number of LCP terminate-request transmissions to
++\fIn\fR (default 3).
++.TP
++.B lcp-restart \fIn
++Set the LCP restart interval (retransmission timeout) to \fIn\fR
++seconds (default 3).
++.TP
++.B linkname \fIname\fR
++Sets the logical name of the link to \fIname\fR. Pppd will create a
++file named \fBppp-\fIname\fB.pid\fR in /var/run (or /etc/ppp on some
++systems) containing its process ID. This can be useful in determining
++which instance of pppd is responsible for the link to a given peer
++system. This is a privileged option.
++.TP
++.B local
++Don't use the modem control lines. With this option, pppd will ignore
++the state of the CD (Carrier Detect) signal from the modem and will
++not change the state of the DTR (Data Terminal Ready) signal.
++.TP
++.B logfd \fIn
++Send log messages to file descriptor \fIn\fR. Pppd will send log
++messages to at most one file or file descriptor (as well as sending
++the log messages to syslog), so this option and the \fBlogfile\fR
++option are mutually exclusive. The default is for pppd to send log
++messages to stdout (file descriptor 1), unless the serial port is
++already open on stdout.
++.TP
++.B logfile \fIfilename
++Append log messages to the file \fIfilename\fR (as well as sending the
++log messages to syslog). The file is opened with the privileges of
++the user who invoked pppd, in append mode.
++.TP
++.B login
++Use the system password database for authenticating the peer using
++PAP, and record the user in the system wtmp file. Note that the peer
++must have an entry in the /etc/ppp/pap-secrets file as well as the
++system password database to be allowed access.
++.TP
++.B maxconnect \fIn
++Terminate the connection when it has been available for network
++traffic for \fIn\fR seconds (i.e. \fIn\fR seconds after the first
++network control protocol comes up).
++.TP
++.B maxfail \fIn
++Terminate after \fIn\fR consecutive failed connection attempts. A
++value of 0 means no limit. The default value is 10.
++.TP
++.B modem
++Use the modem control lines. This option is the default. With this
++option, pppd will wait for the CD (Carrier Detect) signal from the
++modem to be asserted when opening the serial device (unless a connect
++script is specified), and it will drop the DTR (Data Terminal Ready)
++signal briefly when the connection is terminated and before executing
++the connect script. On Ultrix, this option implies hardware flow
++control, as for the \fIcrtscts\fR option.
++.TP
++.B mp
++Enables the use of PPP multilink; this is an alias for the `multilink'
++option. This option is currently only available under Linux.
++.TP
++.B mpshortseq
++Enables the use of short (12-bit) sequence numbers in multilink
++headers, as opposed to 24-bit sequence numbers. This option is only
++available under Linux, and only has any effect if multilink is
++enabled (see the multilink option).
++.TP
++.B mrru \fIn
++Sets the Maximum Reconstructed Receive Unit to \fIn\fR. The MRRU is
++the maximum size for a received packet on a multilink bundle, and is
++analogous to the MRU for the individual links. This option is
++currently only available under Linux, and only has any effect if
++multilink is enabled (see the multilink option).
++.TP
++.B ms-dns \fI&lt;addr&gt;
++If pppd is acting as a server for Microsoft Windows clients, this
++option allows pppd to supply one or two DNS (Domain Name Server)
++addresses to the clients. The first instance of this option specifies
++the primary DNS address; the second instance (if given) specifies the
++secondary DNS address. (This option was present in some older
++versions of pppd under the name \fBdns-addr\fR.)
++.TP
++.B ms-wins \fI&lt;addr&gt;
++If pppd is acting as a server for Microsoft Windows or &quot;Samba&quot;
++clients, this option allows pppd to supply one or two WINS (Windows
++Internet Name Services) server addresses to the clients. The first
++instance of this option specifies the primary WINS address; the second
++instance (if given) specifies the secondary WINS address.
++.TP
++.B multilink
++Enables the use of the PPP multilink protocol. If the peer also
++supports multilink, then this link can become part of a bundle between
++the local system and the peer. If there is an existing bundle to the
++peer, pppd will join this link to that bundle, otherwise pppd will
++create a new bundle. See the MULTILINK section below. This option is
++currently only available under Linux.
++.TP
++.B name \fIname
++Set the name of the local system for authentication purposes to
++\fIname\fR. This is a privileged option. With this option, pppd will
++use lines in the secrets files which have \fIname\fR as the second
++field when looking for a secret to use in authenticating the peer. In
++addition, unless overridden with the \fIuser\fR option, \fIname\fR
++will be used as the name to send to the peer when authenticating the
++local system to the peer. (Note that pppd does not append the domain
++name to \fIname\fR.)
++.TP
++.B netmask \fIn
++Set the interface netmask to \fIn\fR, a 32 bit netmask in &quot;decimal dot&quot;
++notation (e.g. 255.255.255.0). If this option is given, the value
++specified is ORed with the default netmask. The default netmask is
++chosen based on the negotiated remote IP address; it is the
++appropriate network mask for the class of the remote IP address, ORed
++with the netmasks for any non point-to-point network interfaces in the
++system which are on the same network. (Note: on some platforms, pppd
++will always use 255.255.255.255 for the netmask, if that is the only
++appropriate value for a point-to-point interface.)
++.TP
++.B noaccomp
++Disable Address/Control compression in both directions (send and
++receive).
++.TP
++.B noauth
++Do not require the peer to authenticate itself. This option is
++privileged.
++.TP
++.B nobsdcomp
++Disables BSD-Compress compression; \fBpppd\fR will not request or
++agree to compress packets using the BSD-Compress scheme.
++.TP
++.B noccp
++Disable CCP (Compression Control Protocol) negotiation. This option
++should only be required if the peer is buggy and gets confused by
++requests from pppd for CCP negotiation.
++.TP
++.B nocrtscts
++Disable hardware flow control (i.e. RTS/CTS) on the serial port.
++If neither the \fIcrtscts\fR nor the \fInocrtscts\fR nor the
++\fIcdtrcts\fR nor the \fInocdtrcts\fR option is given, the hardware
++flow control setting for the serial port is left unchanged.
++.TP
++.B nocdtrcts
++This option is a synonym for \fInocrtscts\fR. Either of these options will
++disable both forms of hardware flow control.
++.TP
++.B nodefaultroute
++Disable the \fIdefaultroute\fR option. The system administrator who
++wishes to prevent users from creating default routes with pppd
++can do so by placing this option in the /etc/ppp/options file.
++.TP
++.B nodeflate
++Disables Deflate compression; pppd will not request or agree to
++compress packets using the Deflate scheme.
++.TP
++.B nodetach
++Don't detach from the controlling terminal. Without this option, if a
++serial device other than the terminal on the standard input is
++specified, pppd will fork to become a background process.
++.TP
++.B noendpoint
++Disables pppd from sending an endpoint discriminator to the peer or
++accepting one from the peer (see the MULTILINK section below). This
++option should only be required if the peer is buggy.
++.TP
++.B noip
++Disable IPCP negotiation and IP communication. This option should
++only be required if the peer is buggy and gets confused by requests
++from pppd for IPCP negotiation.
++.TP
++.B noipv6
++Disable IPv6CP negotiation and IPv6 communication. This option should
++only be required if the peer is buggy and gets confused by requests
++from pppd for IPv6CP negotiation.
++.TP
++.B noipdefault
++Disables the default behaviour when no local IP address is specified,
++which is to determine (if possible) the local IP address from the
++hostname. With this option, the peer will have to supply the local IP
++address during IPCP negotiation (unless it specified explicitly on the
++command line or in an options file).
++.TP
++.B noipx
++Disable the IPXCP and IPX protocols. This option should only be
++required if the peer is buggy and gets confused by requests from pppd
++for IPXCP negotiation.
++.TP
++.B noktune
++Opposite of the \fIktune\fR option; disables pppd from changing system
++settings.
++.TP
++.B nolog
++Do not send log messages to a file or file descriptor. This option
++cancels the \fBlogfd\fR and \fBlogfile\fR options.
++.TP
++.B nomagic
++Disable magic number negotiation. With this option, pppd cannot
++detect a looped-back line. This option should only be needed if the
++peer is buggy.
++.TP
++.B nomp
++Disables the use of PPP multilink. This option is currently only
++available under Linux.
++.TP
++.B nompshortseq
++Disables the use of short (12-bit) sequence numbers in the PPP
++multilink protocol, forcing the use of 24-bit sequence numbers. This
++option is currently only available under Linux, and only has any
++effect if multilink is enabled.
++.TP
++.B nomultilink
++Disables the use of PPP multilink. This option is currently only
++available under Linux.
++.TP
++.B nopcomp
++Disable protocol field compression negotiation in both the receive and
++the transmit direction.
++.TP
++.B nopersist
++Exit once a connection has been made and terminated. This is the
++default unless the \fIpersist\fR or \fIdemand\fR option has been
++specified.
++.TP
++.B nopredictor1
++Do not accept or agree to Predictor-1 compression.
++.TP
++.B noproxyarp
++Disable the \fIproxyarp\fR option. The system administrator who
++wishes to prevent users from creating proxy ARP entries with pppd can
++do so by placing this option in the /etc/ppp/options file.
++.TP
++.B notty
++Normally, pppd requires a terminal device. With this option, pppd
++will allocate itself a pseudo-tty master/slave pair and use the slave
++as its terminal device. Pppd will create a child process to act as a
++`character shunt' to transfer characters between the pseudo-tty master
++and its standard input and output. Thus pppd will transmit characters
++on its standard output and receive characters on its standard input
++even if they are not terminal devices. This option increases the
++latency and CPU overhead of transferring data over the ppp interface
++as all of the characters sent and received must flow through the
++character shunt process. An explicit device name may not be given if
++this option is used.
++.TP
++.B novj
++Disable Van Jacobson style TCP/IP header compression in both the
++transmit and the receive direction.
++.TP
++.B novjccomp
++Disable the connection-ID compression option in Van Jacobson style
++TCP/IP header compression. With this option, pppd will not omit the
++connection-ID byte from Van Jacobson compressed TCP/IP headers, nor
++ask the peer to do so.
++.TP
++.B papcrypt
++Indicates that all secrets in the /etc/ppp/pap-secrets file which are
++used for checking the identity of the peer are encrypted, and thus
++pppd should not accept a password which, before encryption, is
++identical to the secret from the /etc/ppp/pap-secrets file.
++.TP
++.B pap-max-authreq \fIn
++Set the maximum number of PAP authenticate-request transmissions to
++\fIn\fR (default 10).
++.TP
++.B pap-restart \fIn
++Set the PAP restart interval (retransmission timeout) to \fIn\fR
++seconds (default 3).
++.TP
++.B pap-timeout \fIn
++Set the maximum time that pppd will wait for the peer to authenticate
++itself with PAP to \fIn\fR seconds (0 means no limit).
++.TP
++.B pass-filter \fIfilter-expression
++Specifies a packet filter to applied to data packets being sent or
++received to determine which packets should be allowed to pass.
++Packets which are rejected by the filter are silently discarded. This
++option can be used to prevent specific network daemons (such as
++routed) using up link bandwidth, or to provide a basic firewall
++capability.
++The \fIfilter-expression\fR syntax is as described for tcpdump(1),
++except that qualifiers which are inappropriate for a PPP link, such as
++\fBether\fR and \fBarp\fR, are not permitted. Generally the filter
++expression should be enclosed in single-quotes to prevent whitespace
++in the expression from being interpreted by the shell. Note that it
++is possible to apply different constraints to incoming and outgoing
++packets using the \fBinbound\fR and \fBoutbound\fR qualifiers. This
++option is currently only available under NetBSD, and then only if both
++the kernel and pppd were compiled with PPP_FILTER defined.
++.TP
++.B persist
++Do not exit after a connection is terminated; instead try to reopen
++the connection.
++.TP
++.B plugin \fIfilename
++Load the shared library object file \fIfilename\fR as a plugin. This
++is a privileged option.
++.TP
++.B predictor1
++Request that the peer compress frames that it sends using Predictor-1
++compression, and agree to compress transmitted frames with Predictor-1
++if requested. This option has no effect unless the kernel driver
++supports Predictor-1 compression.
++.TP
++.B privgroup \fIgroup-name
++Allows members of group \fIgroup-name\fR to use privileged options.
++This is a privileged option. Use of this option requires care as
++there is no guarantee that members of \fIgroup-name\fR cannot use pppd
++to become root themselves. Consider it equivalent to putting the
++members of \fIgroup-name\fR in the kmem or disk group.
++.TP
++.B proxyarp
++Add an entry to this system's ARP [Address Resolution Protocol] table
++with the IP address of the peer and the Ethernet address of this
++system. This will have the effect of making the peer appear to other
++systems to be on the local ethernet.
++.TP
++.B pty \fIscript
++Specifies that the command \fIscript\fR is to be used to communicate
++rather than a specific terminal device. Pppd will allocate itself a
++pseudo-tty master/slave pair and use the slave as its terminal
++device. The \fIscript\fR will be run in a child process with the
++pseudo-tty master as its standard input and output. An explicit
++device name may not be given if this option is used. (Note: if the
++\fIrecord\fR option is used in conjuction with the \fIpty\fR option,
++the child process will have pipes on its standard input and output.)
++.TP
++.B receive-all
++With this option, pppd will accept all control characters from the
++peer, including those marked in the receive asyncmap. Without this
++option, pppd will discard those characters as specified in RFC1662.
++This option should only be needed if the peer is buggy.
++.TP
++.B record \fIfilename
++Specifies that pppd should record all characters sent and received to
++a file named \fIfilename\fR. This file is opened in append mode,
++using the user's user-ID and permissions. This option is implemented
++using a pseudo-tty and a process to transfer characters between the
++pseudo-tty and the real serial device, so it will increase the latency
++and CPU overhead of transferring data over the ppp interface. The
++characters are stored in a tagged format with timestamps, which can be
++displayed in readable form using the pppdump(8) program.
++.TP
++.B remotename \fIname
++Set the assumed name of the remote system for authentication purposes
++to \fIname\fR.
++.TP
++.B refuse-chap
++With this option, pppd will not agree to authenticate itself to the
++peer using CHAP.
++.TP
++.B refuse-pap
++With this option, pppd will not agree to authenticate itself to the
++peer using PAP.
++.TP
++.B require-chap
++Require the peer to authenticate itself using CHAP [Challenge
++Handshake Authentication Protocol] authentication.
++.TP
++.B require-pap
++Require the peer to authenticate itself using PAP [Password
++Authentication Protocol] authentication.
++.TP
++.B show-password
++When logging the contents of PAP packets, this option causes pppd to
++show the password string in the log message.
++.TP
++.B silent
++With this option, pppd will not transmit LCP packets to initiate a
++connection until a valid LCP packet is received from the peer (as for
++the `passive' option with ancient versions of pppd).
++.TP
++.B sync
++Use synchronous HDLC serial encoding instead of asynchronous.
++The device used by pppd with this option must have sync support.
++Currently supports Microgate SyncLink adapters
++under Linux and FreeBSD 2.2.8 and later.
++.TP
++.B updetach
++With this option, pppd will detach from its controlling terminal once
++it has successfully established the ppp connection (to the point where
++the first network control protocol, usually the IP control protocol,
++has come up).
++.TP
++.B usehostname
++Enforce the use of the hostname (with domain name appended, if given)
++as the name of the local system for authentication purposes (overrides
++the \fIname\fR option). This option is not normally needed since the
++\fIname\fR option is privileged.
++.TP
++.B usepeerdns
++Ask the peer for up to 2 DNS server addresses. The addresses supplied
++by the peer (if any) are passed to the /etc/ppp/ip-up script in the
++environment variables DNS1 and DNS2. In addition, pppd will create an
++/etc/ppp/resolv.conf file containing one or two nameserver lines with
++the address(es) supplied by the peer.
++.TP
++.B user \fIname
++Sets the name used for authenticating the local system to the peer to
++\fIname\fR.
++.TP
++.B vj-max-slots \fIn
++Sets the number of connection slots to be used by the Van Jacobson
++TCP/IP header compression and decompression code to \fIn\fR, which
++must be between 2 and 16 (inclusive).
++.TP
++.B welcome \fIscript
++Run the executable or shell command specified by \fIscript\fR before
++initiating PPP negotiation, after the connect script (if any) has
++completed. A value for this option from a privileged source cannot be
++overridden by a non-privileged user.
++.TP
++.B xonxoff
++Use software flow control (i.e. XON/XOFF) to control the flow of data on
++the serial port.
++.SH OPTIONS FILES
++Options can be taken from files as well as the command line. Pppd
++reads options from the files /etc/ppp/options, ~/.ppprc and
++/etc/ppp/options.\fIttyname\fR (in that order) before processing the
++options on the command line. (In fact, the command-line options are
++scanned to find the terminal name before the options.\fIttyname\fR
++file is read.) In forming the name of the options.\fIttyname\fR file,
++the initial /dev/ is removed from the terminal name, and any remaining
++/ characters are replaced with dots.
++.PP
++An options file is parsed into a series of words, delimited by
++whitespace. Whitespace can be included in a word by enclosing the
++word in double-quotes (&quot;). A backslash (\\) quotes the following character.
++A hash (#) starts a comment, which continues until the end of the
++line. There is no restriction on using the \fIfile\fR or \fIcall\fR
++options within an options file.
++.SH SECURITY
++.I pppd
++provides system administrators with sufficient access control that PPP
++access to a server machine can be provided to legitimate users without
++fear of compromising the security of the server or the network it's
++on. This control is provided through restrictions on which IP
++addresses the peer may use, based on its authenticated identity (if
++any), and through restrictions on which options a non-privileged user
++may use. Several of pppd's options are privileged, in particular
++those which permit potentially insecure configurations; these options
++are only accepted in files which are under the control of the system
++administrator, or if pppd is being run by root.
++.PP
++The default behaviour of pppd is to allow an unauthenticated peer to
++use a given IP address only if the system does not already have a
++route to that IP address. For example, a system with a
++permanent connection to the wider internet will normally have a
++default route, and thus all peers will have to authenticate themselves
++in order to set up a connection. On such a system, the \fIauth\fR
++option is the default. On the other hand, a system where the
++PPP link is the only connection to the internet will not normally have
++a default route, so the peer will be able to use almost any IP address
++without authenticating itself.
++.PP
++As indicated above, some security-sensitive options are privileged,
++which means that they may not be used by an ordinary non-privileged
++user running a setuid-root pppd, either on the command line, in the
++user's ~/.ppprc file, or in an options file read using the \fIfile\fR
++option. Privileged options may be used in /etc/ppp/options file or in
++an options file read using the \fIcall\fR option. If pppd is being
++run by the root user, privileged options can be used without
++restriction.
++.PP
++When opening the device, pppd uses either the invoking user's user ID
++or the root UID (that is, 0), depending on whether the device name was
++specified by the user or the system administrator. If the device name
++comes from a privileged source, that is, /etc/ppp/options or an
++options file read using the \fIcall\fR option, pppd uses full root
++privileges when opening the device. Thus, by creating an appropriate
++file under /etc/ppp/peers, the system administrator can allow users to
++establish a ppp connection via a device which they would not normally
++have permission to access. Otherwise pppd uses the invoking user's
++real UID when opening the device.
++.SH AUTHENTICATION
++Authentication is the process whereby one peer convinces the other of
++its identity. This involves the first peer sending its name to the
++other, together with some kind of secret information which could only
++come from the genuine authorized user of that name. In such an
++exchange, we will call the first peer the &quot;client&quot; and the other the
++&quot;server&quot;. The client has a name by which it identifies itself to the
++server, and the server also has a name by which it identifies itself
++to the client. Generally the genuine client shares some secret (or
++password) with the server, and authenticates itself by proving that it
++knows that secret. Very often, the names used for authentication
++correspond to the internet hostnames of the peers, but this is not
++essential.
++.LP
++At present, pppd supports two authentication protocols: the Password
++Authentication Protocol (PAP) and the Challenge Handshake
++Authentication Protocol (CHAP). PAP involves the client sending its
++name and a cleartext password to the server to authenticate itself.
++In contrast, the server initiates the CHAP authentication exchange by
++sending a challenge to the client (the challenge packet includes the
++server's name). The client must respond with a response which
++includes its name plus a hash value derived from the shared secret and
++the challenge, in order to prove that it knows the secret.
++.LP
++The PPP protocol, being symmetrical, allows both peers to require the
++other to authenticate itself. In that case, two separate and
++independent authentication exchanges will occur. The two exchanges
++could use different authentication protocols, and in principle,
++different names could be used in the two exchanges.
++.LP
++The default behaviour of pppd is to agree to authenticate if
++requested, and to not require authentication from the peer. However,
++pppd will not agree to authenticate itself with a particular protocol
++if it has no secrets which could be used to do so.
++.LP
++Pppd stores secrets for use in authentication in secrets
++files (/etc/ppp/pap-secrets for PAP, /etc/ppp/chap-secrets for CHAP).
++Both secrets files have the same format. The secrets files can
++contain secrets for pppd to use in authenticating itself to other
++systems, as well as secrets for pppd to use when authenticating other
++systems to itself.
++.LP
++Each line in a secrets file contains one secret. A given secret is
++specific to a particular combination of client and server - it can
++only be used by that client to authenticate itself to that server.
++Thus each line in a secrets file has at least 3 fields: the name of
++the client, the name of the server, and the secret. These fields may
++be followed by a list of the IP addresses that the specified client
++may use when connecting to the specified server.
++.LP
++A secrets file is parsed into words as for a options file, so the
++client name, server name and secrets fields must each be one word,
++with any embedded spaces or other special characters quoted or
++escaped. Note that case is significant in the client and server names
++and in the secret.
++.LP
++If the secret starts with an `@', what follows is assumed to be the
++name of a file from which to read the secret. A &quot;*&quot; as the client or
++server name matches any name. When selecting a secret, pppd takes the
++best match, i.e. the match with the fewest wildcards.
++.LP
++Any following words on the same line are taken to be a list of
++acceptable IP addresses for that client. If there are only 3 words on
++the line, or if the first word is &quot;-&quot;, then all IP addresses are
++disallowed. To allow any address, use &quot;*&quot;. A word starting with &quot;!&quot;
++indicates that the specified address is \fInot\fR acceptable. An
++address may be followed by &quot;/&quot; and a number \fIn\fR, to indicate a
++whole subnet, i.e. all addresses which have the same value in the most
++significant \fIn\fR bits. In this form, the address may be followed
++by a plus sign (&quot;+&quot;) to indicate that one address from the subnet is
++authorized, based on the ppp network interface unit number in use.
++In this case, the host part of the address will be set to the unit
++number plus one.
++.LP
++Thus a secrets file contains both secrets for use in authenticating
++other hosts, plus secrets which we use for authenticating ourselves to
++others. When pppd is authenticating the peer (checking the peer's
++identity), it chooses a secret with the peer's name in the first
++field and the name of the local system in the second field. The
++name of the local system defaults to the hostname, with the domain
++name appended if the \fIdomain\fR option is used. This default can be
++overridden with the \fIname\fR option, except when the
++\fIusehostname\fR option is used.
++.LP
++When pppd is choosing a secret to use in authenticating itself to the
++peer, it first determines what name it is going to use to identify
++itself to the peer. This name can be specified by the user with the
++\fIuser\fR option. If this option is not used, the name defaults to
++the name of the local system, determined as described in the previous
++paragraph. Then pppd looks for a secret with this name in the first
++field and the peer's name in the second field. Pppd will know the
++name of the peer if CHAP authentication is being used, because the
++peer will have sent it in the challenge packet. However, if PAP is being
++used, pppd will have to determine the peer's name from the options
++specified by the user. The user can specify the peer's name directly
++with the \fIremotename\fR option. Otherwise, if the remote IP address
++was specified by a name (rather than in numeric form), that name will
++be used as the peer's name. Failing that, pppd will use the null
++string as the peer's name.
++.LP
++When authenticating the peer with PAP, the supplied password is first
++compared with the secret from the secrets file. If the password
++doesn't match the secret, the password is encrypted using crypt() and
++checked against the secret again. Thus secrets for authenticating the
++peer can be stored in encrypted form if desired. If the
++\fIpapcrypt\fR option is given, the first (unencrypted) comparison is
++omitted, for better security.
++.LP
++Furthermore, if the \fIlogin\fR option was specified, the username and
++password are also checked against the system password database. Thus,
++the system administrator can set up the pap-secrets file to allow PPP
++access only to certain users, and to restrict the set of IP addresses
++that each user can use. Typically, when using the \fIlogin\fR option,
++the secret in /etc/ppp/pap-secrets would be &quot;&quot;, which will match any
++password supplied by the peer. This avoids the need to have the same
++secret in two places.
++.LP
++Authentication must be satisfactorily completed before IPCP (or any
++other Network Control Protocol) can be started. If the peer is
++required to authenticate itself, and fails to do so, pppd will
++terminated the link (by closing LCP). If IPCP negotiates an
++unacceptable IP address for the remote host, IPCP will be closed. IP
++packets can only be sent or received when IPCP is open.
++.LP
++In some cases it is desirable to allow some hosts which can't
++authenticate themselves to connect and use one of a restricted set of
++IP addresses, even when the local host generally requires
++authentication. If the peer refuses to authenticate itself when
++requested, pppd takes that as equivalent to authenticating with PAP
++using the empty string for the username and password. Thus, by adding
++a line to the pap-secrets file which specifies the empty string for
++the client and password, it is possible to allow restricted access to
++hosts which refuse to authenticate themselves.
++.SH ROUTING
++.LP
++When IPCP negotiation is completed successfully, pppd will inform the
++kernel of the local and remote IP addresses for the ppp interface.
++This is sufficient to create a host route to the remote end of the
++link, which will enable the peers to exchange IP packets.
++Communication with other machines generally requires further
++modification to routing tables and/or ARP (Address Resolution
++Protocol) tables. In most cases the \fIdefaultroute\fR and/or
++\fIproxyarp\fR options are sufficient for this, but in some cases
++further intervention is required. The /etc/ppp/ip-up script can be
++used for this.
++.LP
++Sometimes it is desirable to add a default route through the remote
++host, as in the case of a machine whose only connection to the
++Internet is through the ppp interface. The \fIdefaultroute\fR option
++causes pppd to create such a default route when IPCP comes up, and
++delete it when the link is terminated.
++.LP
++In some cases it is desirable to use proxy ARP, for example on a
++server machine connected to a LAN, in order to allow other hosts to
++communicate with the remote host. The \fIproxyarp\fR option causes
++pppd to look for a network interface on the same subnet as the remote
++host (an interface supporting broadcast and ARP, which is up and not a
++point-to-point or loopback interface). If found, pppd creates a
++permanent, published ARP entry with the IP address of the remote host
++and the hardware address of the network interface found.
++.LP
++When the \fIdemand\fR option is used, the interface IP addresses have
++already been set at the point when IPCP comes up. If pppd has not
++been able to negotiate the same addresses that it used to configure
++the interface (for example when the peer is an ISP that uses dynamic
++IP address assignment), pppd has to change the interface IP addresses
++to the negotiated addresses. This may disrupt existing connections,
++and the use of demand dialling with peers that do dynamic IP address
++assignment is not recommended.
++.SH MULTILINK
++Multilink PPP provides the capability to combine two or more PPP links
++between a pair of machines into a single `bundle', which appears as a
++single virtual PPP link which has the combined bandwidth of the
++individual links. Currently, multilink PPP is only supported under
++Linux.
++.LP
++Pppd detects that the link it is controlling is connected to the same
++peer as another link using the peer's endpoint discriminator and the
++authenticated identity of the peer (if it authenticates itself). The
++endpoint discriminator is a block of data which is hopefully unique
++for each peer. Several types of data can be used, including
++locally-assigned strings of bytes, IP addresses, MAC addresses,
++randomly strings of bytes, or E-164 phone numbers. The endpoint
++discriminator sent to the peer by pppd can be set using the endpoint
++option.
++.LP
++In circumstances the peer may send no endpoint discriminator or a
++non-unique value. The optional bundle option adds an extra string
++which is added to the peer's endpoint discriminator and authenticated
++identity when matching up links to be joined together in a bundle.
++The bundle option can also be used to allow the establishment of
++multiple bundles between the local system and the peer. Pppd uses a
++TDB database in /var/run/pppd.tdb to match up links.
++.LP
++Assuming that multilink is enabled and the peer is willing to
++negotiate multilink, then when pppd is invoked to bring up the first
++link to the peer, it will detect that no other link is connected to
++the peer and create a new bundle, that is, another ppp network
++interface unit. When another pppd is invoked to bring up another link
++to the peer, it will detect the existing bundle and join its link to
++it. Currently, if the first pppd terminates (for example, because of
++a hangup or a received signal) the bundle is destroyed.
++.SH EXAMPLES
++.LP
++The following examples assume that the /etc/ppp/options file contains
++the \fIauth\fR option (as in the default /etc/ppp/options file in the
++ppp distribution).
++.LP
++Probably the most common use of pppd is to dial out to an ISP. This
++can be done with a command such as
++.IP
++pppd call isp
++.LP
++where the /etc/ppp/peers/isp file is set up by the system
++administrator to contain something like this:
++.IP
++ttyS0 19200 crtscts
++.br
++connect '/usr/sbin/chat -v -f /etc/ppp/chat-isp'
++.br
++noauth
++.LP
++In this example, we are using chat to dial the ISP's modem and go
++through any logon sequence required. The /etc/ppp/chat-isp file
++contains the script used by chat; it could for example contain
++something like this:
++.IP
++ABORT &quot;NO CARRIER&quot;
++.br
++ABORT &quot;NO DIALTONE&quot;
++.br
++ABORT &quot;ERROR&quot;
++.br
++ABORT &quot;NO ANSWER&quot;
++.br
++ABORT &quot;BUSY&quot;
++.br
++ABORT &quot;Username/Password Incorrect&quot;
++.br
++&quot;&quot; &quot;at&quot;
++.br
++OK &quot;at&amp;d0&amp;c1&quot;
++.br
++OK &quot;atdt2468135&quot;
++.br
++&quot;name:&quot; &quot;^Umyuserid&quot;
++.br
++&quot;word:&quot; &quot;\\qmypassword&quot;
++.br
++&quot;ispts&quot; &quot;\\q^Uppp&quot;
++.br
++&quot;~-^Uppp-~&quot;
++.LP
++See the chat(8) man page for details of chat scripts.
++.LP
++Pppd can also be used to provide a dial-in ppp service for users. If
++the users already have login accounts, the simplest way to set up the
++ppp service is to let the users log in to their accounts and run pppd
++(installed setuid-root) with a command such as
++.IP
++pppd proxyarp
++.LP
++To allow a user to use the PPP facilities, you need to allocate an IP
++address for that user's machine and create an entry in
++/etc/ppp/pap-secrets or /etc/ppp/chap-secrets (depending on which
++authentication method the PPP implementation on the user's machine
++supports), so that the user's
++machine can authenticate itself. For example, if Joe has a machine
++called &quot;joespc&quot; which is to be allowed to dial in to the machine
++called &quot;server&quot; and use the IP address joespc.my.net, you would add an
++entry like this to /etc/ppp/pap-secrets or /etc/ppp/chap-secrets:
++.IP
++joespc server &quot;joe's secret&quot; joespc.my.net
++.LP
++Alternatively, you can create a username called (for example) &quot;ppp&quot;,
++whose login shell is pppd and whose home directory is /etc/ppp.
++Options to be used when pppd is run this way can be put in
++/etc/ppp/.ppprc.
++.LP
++If your serial connection is any more complicated than a piece of
++wire, you may need to arrange for some control characters to be
++escaped. In particular, it is often useful to escape XON (^Q) and
++XOFF (^S), using \fIasyncmap a0000\fR. If the path includes a telnet,
++you probably should escape ^] as well (\fIasyncmap 200a0000\fR). If
++the path includes an rlogin, you will need to use the \fIescape ff\fR
++option on the end which is running the rlogin client, since many
++rlogin implementations are not transparent; they will remove the
++sequence [0xff, 0xff, 0x73, 0x73, followed by any 8 bytes] from the
++stream.
++.SH DIAGNOSTICS
++.LP
++Messages are sent to the syslog daemon using facility LOG_DAEMON.
++(This can be overriden by recompiling pppd with the macro
++LOG_PPP defined as the desired facility.) In order to see the error
++and debug messages, you will need to edit your /etc/syslog.conf file
++to direct the messages to the desired output device or file.
++.LP
++The \fIdebug\fR option causes the contents of all control packets sent
++or received to be logged, that is, all LCP, PAP, CHAP or IPCP packets.
++This can be useful if the PPP negotiation does not succeed or if
++authentication fails.
++If debugging is enabled at compile time, the \fIdebug\fR option also
++causes other debugging messages to be logged.
++.LP
++Debugging can also be enabled or disabled by sending a SIGUSR1 signal
++to the pppd process. This signal acts as a toggle.
++.SH EXIT STATUS
++The exit status of pppd is set to indicate whether any error was
++detected, or the reason for the link being terminated. The values
++used are:
++.TP
++.B 0
++Pppd has detached, or otherwise the connection was successfully
++established and terminated at the peer's request.
++.TP
++.B 1
++An immediately fatal error of some kind occurred, such as an essential
++system call failing, or running out of virtual memory.
++.TP
++.B 2
++An error was detected in processing the options given, such as two
++mutually exclusive options being used.
++.TP
++.B 3
++Pppd is not setuid-root and the invoking user is not root.
++.TP
++.B 4
++The kernel does not support PPP, for example, the PPP kernel driver is
++not included or cannot be loaded.
++.TP
++.B 5
++Pppd terminated because it was sent a SIGINT, SIGTERM or SIGHUP
++signal.
++.TP
++.B 6
++The serial port could not be locked.
++.TP
++.B 7
++The serial port could not be opened.
++.TP
++.B 8
++The connect script failed (returned a non-zero exit status).
++.TP
++.B 9
++The command specified as the argument to the \fIpty\fR option could
++not be run.
++.TP
++.B 10
++The PPP negotiation failed, that is, it didn't reach the point where
++at least one network protocol (e.g. IP) was running.
++.TP
++.B 11
++The peer system failed (or refused) to authenticate itself.
++.TP
++.B 12
++The link was established successfully and terminated because it was
++idle.
++.TP
++.B 13
++The link was established successfully and terminated because the
++connect time limit was reached.
++.TP
++.B 14
++Callback was negotiated and an incoming call should arrive shortly.
++.TP
++.B 15
++The link was terminated because the peer is not responding to echo
++requests.
++.TP
++.B 16
++The link was terminated by the modem hanging up.
++.TP
++.B 17
++The PPP negotiation failed because serial loopback was detected.
++.TP
++.B 18
++The init script failed (returned a non-zero exit status).
++.TP
++.B 19
++We failed to authenticate ourselves to the peer.
++.SH SCRIPTS
++Pppd invokes scripts at various stages in its processing which can be
++used to perform site-specific ancillary processing. These scripts are
++usually shell scripts, but could be executable code files instead.
++Pppd does not wait for the scripts to finish. The scripts are
++executed as root (with the real and effective user-id set to 0), so
++that they can do things such as update routing tables or run
++privileged daemons. Be careful that the contents of these scripts do
++not compromise your system's security. Pppd runs the scripts with
++standard input, output and error redirected to /dev/null, and with an
++environment that is empty except for some environment variables that
++give information about the link. The environment variables that pppd
++sets are:
++.TP
++.B DEVICE
++The name of the serial tty device being used.
++.TP
++.B IFNAME
++The name of the network interface being used.
++.TP
++.B IPLOCAL
++The IP address for the local end of the link. This is only set when
++IPCP has come up.
++.TP
++.B IPREMOTE
++The IP address for the remote end of the link. This is only set when
++IPCP has come up.
++.TP
++.B PEERNAME
++The authenticated name of the peer. This is only set if the peer
++authenticates itself.
++.TP
++.B SPEED
++The baud rate of the tty device.
++.TP
++.B ORIG_UID
++The real user-id of the user who invoked pppd.
++.TP
++.B PPPLOGNAME
++The username of the real user-id that invoked pppd. This is always set.
++.P
++For the ip-down and auth-down scripts, pppd also sets the following
++variables giving statistics for the connection:
++.TP
++.B CONNECT_TIME
++The number of seconds from when the PPP negotiation started until the
++connection was terminated.
++.TP
++.B BYTES_SENT
++The number of bytes sent (at the level of the serial port) during the
++connection.
++.TP
++.B BYTES_RCVD
++The number of bytes received (at the level of the serial port) during
++the connection.
++.TP
++.B LINKNAME
++The logical name of the link, set with the \fIlinkname\fR option.
++.P
++Pppd invokes the following scripts, if they exist. It is not an error
++if they don't exist.
++.TP
++.B /etc/ppp/auth-up
++A program or script which is executed after the remote system
++successfully authenticates itself. It is executed with the parameters
++.IP
++\fIinterface-name peer-name user-name tty-device speed\fR
++.IP
++Note that this script is not executed if the peer doesn't authenticate
++itself, for example when the \fInoauth\fR option is used.
++.TP
++.B /etc/ppp/auth-down
++A program or script which is executed when the link goes down, if
++/etc/ppp/auth-up was previously executed. It is executed in the same
++manner with the same parameters as /etc/ppp/auth-up.
++.TP
++.B /etc/ppp/ip-up
++A program or script which is executed when the link is available for
++sending and receiving IP packets (that is, IPCP has come up). It is
++executed with the parameters
++.IP
++\fIinterface-name tty-device speed local-IP-address
++remote-IP-address ipparam\fR
++.TP
++.B /etc/ppp/ip-down
++A program or script which is executed when the link is no longer
++available for sending and receiving IP packets. This script can be
++used for undoing the effects of the /etc/ppp/ip-up script. It is
++invoked in the same manner and with the same parameters as the ip-up
++script.
++.TP
++.B /etc/ppp/ipv6-up
++Like /etc/ppp/ip-up, except that it is executed when the link is available
++for sending and receiving IPv6 packets. It is executed with the parameters
++.IP
++\fIinterface-name tty-device speed local-link-local-address
++remote-link-local-address ipparam\fR
++.TP
++.B /etc/ppp/ipv6-down
++Similar to /etc/ppp/ip-down, but it is executed when IPv6 packets can no
++longer be transmitted on the link. It is executed with the same parameters
++as the ipv6-up script.
++.TP
++.B /etc/ppp/ipx-up
++A program or script which is executed when the link is available for
++sending and receiving IPX packets (that is, IPXCP has come up). It is
++executed with the parameters
++.IP
++\fIinterface-name tty-device speed network-number local-IPX-node-address
++remote-IPX-node-address local-IPX-routing-protocol remote-IPX-routing-protocol
++local-IPX-router-name remote-IPX-router-name ipparam pppd-pid\fR
++.IP
++The local-IPX-routing-protocol and remote-IPX-routing-protocol field
++may be one of the following:
++.IP
++NONE to indicate that there is no routing protocol
++.br
++RIP to indicate that RIP/SAP should be used
++.br
++NLSP to indicate that Novell NLSP should be used
++.br
++RIP NLSP to indicate that both RIP/SAP and NLSP should be used
++.TP
++.B /etc/ppp/ipx-down
++A program or script which is executed when the link is no longer
++available for sending and receiving IPX packets. This script can be
++used for undoing the effects of the /etc/ppp/ipx-up script. It is
++invoked in the same manner and with the same parameters as the ipx-up
++script.
++.SH FILES
++.TP
++.B /var/run/ppp\fIn\fB.pid \fR(BSD or Linux), \fB/etc/ppp/ppp\fIn\fB.pid \fR(others)
++Process-ID for pppd process on ppp interface unit \fIn\fR.
++.TP
++.B /var/run/ppp-\fIname\fB.pid \fR(BSD or Linux), \fB/etc/ppp/ppp-\fIname\fB.pid \fR(others)
++Process-ID for pppd process for logical link \fIname\fR (see the
++\fIlinkname\fR option).
++.TP
++.B /etc/ppp/pap-secrets
++Usernames, passwords and IP addresses for PAP authentication. This
++file should be owned by root and not readable or writable by any other
++user. Pppd will log a warning if this is not the case.
++.TP
++.B /etc/ppp/chap-secrets
++Names, secrets and IP addresses for CHAP authentication. As for
++/etc/ppp/pap-secrets, this file should be owned by root and not
++readable or writable by any other user. Pppd will log a warning if
++this is not the case.
++.TP
++.B /etc/ppp/options
++System default options for pppd, read before user default options or
++command-line options.
++.TP
++.B ~/.ppprc
++User default options, read before /etc/ppp/options.\fIttyname\fR.
++.TP
++.B /etc/ppp/options.\fIttyname
++System default options for the serial port being used, read after
++~/.ppprc. In forming the \fIttyname\fR part of this
++filename, an initial /dev/ is stripped from the port name (if
++present), and any slashes in the remaining part are converted to
++dots.
++.TP
++.B /etc/ppp/peers
++A directory containing options files which may contain privileged
++options, even if pppd was invoked by a user other than root. The
++system administrator can create options files in this directory to
++permit non-privileged users to dial out without requiring the peer to
++authenticate, but only to certain trusted peers.
++.SH SEE ALSO
++.TP
++.B RFC1144
++Jacobson, V.
++\fICompressing TCP/IP headers for low-speed serial links.\fR
++February 1990.
++.TP
++.B RFC1321
++Rivest, R.
++.I The MD5 Message-Digest Algorithm.
++April 1992.
++.TP
++.B RFC1332
++McGregor, G.
++.I PPP Internet Protocol Control Protocol (IPCP).
++May 1992.
++.TP
++.B RFC1334
++Lloyd, B.; Simpson, W.A.
++.I PPP authentication protocols.
++October 1992.
++.TP
++.B RFC1661
++Simpson, W.A.
++.I The Point\-to\-Point Protocol (PPP).
++July 1994.
++.TP
++.B RFC1662
++Simpson, W.A.
++.I PPP in HDLC-like Framing.
++July 1994.
++.TP
++.B RFC2472
++Haskin, D.
++.I IP Version 6 over PPP
++December 1998.
++.SH NOTES
++The following signals have the specified effect when sent to pppd.
++.TP
++.B SIGINT, SIGTERM
++These signals cause pppd to terminate the link (by closing LCP),
++restore the serial device settings, and exit.
++.TP
++.B SIGHUP
++This signal causes pppd to terminate the link, restore the serial
++device settings, and close the serial device. If the \fIpersist\fR or
++\fIdemand\fR option has been specified, pppd will try to reopen the
++serial device and start another connection (after the holdoff period).
++Otherwise pppd will exit. If this signal is received during the
++holdoff period, it causes pppd to end the holdoff period immediately.
++.TP
++.B SIGUSR1
++This signal toggles the state of the \fIdebug\fR option.
++.TP
++.B SIGUSR2
++This signal causes pppd to renegotiate compression. This can be
++useful to re-enable compression after it has been disabled as a result
++of a fatal decompression error. (Fatal decompression errors generally
++indicate a bug in one or other implementation.)
++
++.SH AUTHORS
++Paul Mackerras (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">Paul.Mackerras at cs.anu.edu.au</A>), based on earlier work by
++Drew Perkins,
++Brad Clements,
++Karl Fox,
++Greg Christy,
++and
++Brad Parker.
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/pppd.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/pppd.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/pppd.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,787 @@
++/*
++ * pppd.h - PPP daemon global declarations.
++ *
++ * Copyright (c) 1989 Carnegie Mellon University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by Carnegie Mellon University. The name of the
++ * University may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * $Id: pppd.h 195720 2001-06-11 11:44:34Z gc $
++ */
++
++/*
++ * TODO:
++ */
++
++#ifndef __PPPD_H__
++#define __PPPD_H__
++
++#include &lt;stdio.h&gt; /* for FILE */
++#include &lt;limits.h&gt; /* for NGROUPS_MAX */
++#include &lt;sys/param.h&gt; /* for MAXPATHLEN and BSD4_4, if defined */
++#include &lt;sys/types.h&gt; /* for u_int32_t, if defined */
++#include &lt;sys/time.h&gt; /* for struct timeval */
++#include &lt;net/ppp_defs.h&gt;
++#include &quot;patchlevel.h&quot;
++
++#if defined(__STDC__)
++#include &lt;stdarg.h&gt;
++#define __V(x) x
++#else
++#include &lt;varargs.h&gt;
++#define __V(x) (va_alist) va_dcl
++#define const
++#define volatile
++#endif
++
++#ifdef INET6
++#include &quot;eui64.h&quot;
++#endif
++
++/*
++ * Limits.
++ */
++
++#define NUM_PPP 1 /* One PPP interface supported (per process) */
++#define MAXWORDLEN 1024 /* max length of word in file (incl null) */
++#define MAXARGS 1 /* max # args to a command */
++#define MAXNAMELEN 256 /* max length of hostname or name for auth */
++#define MAXSECRETLEN 256 /* max length of password or secret */
++
++/*
++ * Option descriptor structure.
++ */
++
++typedef unsigned char bool;
++
++enum opt_type {
++ o_special_noarg = 0,
++ o_special = 1,
++ o_bool,
++ o_int,
++ o_uint32,
++ o_string,
++ o_wild,
++};
++
++typedef struct {
++ char *name; /* name of the option */
++ enum opt_type type;
++ void *addr;
++ char *description;
++ int flags;
++ void *addr2;
++ int upper_limit;
++ int lower_limit;
++ const char *source;
++ short int priority;
++ short int winner;
++} option_t;
++
++/* Values for flags */
++#define OPT_VALUE 0xff /* mask for presupplied value */
++#define OPT_HEX 0x100 /* int option is in hex */
++#define OPT_NOARG 0x200 /* option doesn't take argument */
++#define OPT_OR 0x400 /* OR in argument to value */
++#define OPT_INC 0x800 /* increment value */
++#define OPT_PRIV 0x1000 /* privileged option */
++#define OPT_STATIC 0x2000 /* string option goes into static array */
++#define OPT_LLIMIT 0x4000 /* check value against lower limit */
++#define OPT_ULIMIT 0x8000 /* check value against upper limit */
++#define OPT_LIMITS (OPT_LLIMIT|OPT_ULIMIT)
++#define OPT_ZEROOK 0x10000 /* 0 value is OK even if not within limits */
++#define OPT_HIDE 0x10000 /* for o_string, print value as ?????? */
++#define OPT_A2LIST 0x10000 /* for o_special, keep list of values */
++#define OPT_NOINCR 0x20000 /* value mustn't be increased */
++#define OPT_ZEROINF 0x40000 /* with OPT_NOINCR, 0 == infinity */
++#define OPT_PRIO 0x80000 /* process option priorities for this option */
++#define OPT_PRIOSUB 0x100000 /* subsidiary member of priority group */
++#define OPT_ALIAS 0x200000 /* option is alias for previous option */
++#define OPT_A2COPY 0x400000 /* addr2 -&gt; second location to rcv value */
++#define OPT_ENABLE 0x800000 /* use *addr2 as enable for option */
++#define OPT_A2CLR 0x1000000 /* clear *(bool *)addr2 */
++#define OPT_PRIVFIX 0x2000000 /* user can't override if set by root */
++#define OPT_INITONLY 0x4000000 /* option can only be set in init phase */
++#define OPT_DEVEQUIV 0x8000000 /* equiv to device name */
++#define OPT_DEVNAM (OPT_INITONLY | OPT_DEVEQUIV)
++#define OPT_A2PRINTER 0x10000000 /* *addr2 is a fn for printing option */
++#define OPT_A2STRVAL 0x20000000 /* *addr2 points to current string value */
++#define OPT_NOPRINT 0x40000000 /* don't print this option at all */
++
++#define OPT_VAL(x) ((x) &amp; OPT_VALUE)
++
++/* Values for priority */
++#define OPRIO_DEFAULT 0 /* a default value */
++#define OPRIO_CFGFILE 1 /* value from a configuration file */
++#define OPRIO_CMDLINE 2 /* value from the command line */
++#define OPRIO_SECFILE 3 /* value from options in a secrets file */
++#define OPRIO_ROOT 100 /* added to priority if OPT_PRIVFIX &amp;&amp; root */
++
++#ifndef GIDSET_TYPE
++#define GIDSET_TYPE gid_t
++#endif
++
++/* Structure representing a list of permitted IP addresses. */
++struct permitted_ip {
++ int permit; /* 1 = permit, 0 = forbid */
++ u_int32_t base; /* match if (addr &amp; mask) == base */
++ u_int32_t mask; /* base and mask are in network byte order */
++};
++
++/*
++ * Unfortunately, the linux kernel driver uses a different structure
++ * for statistics from the rest of the ports.
++ * This structure serves as a common representation for the bits
++ * pppd needs.
++ */
++struct pppd_stats {
++ unsigned int bytes_in;
++ unsigned int bytes_out;
++};
++
++/* Used for storing a sequence of words. Usually malloced. */
++struct wordlist {
++ struct wordlist *next;
++ char *word;
++};
++
++/* An endpoint discriminator, used with multilink. */
++#define MAX_ENDP_LEN 20 /* maximum length of discriminator value */
++struct epdisc {
++ unsigned char class;
++ unsigned char length;
++ unsigned char value[MAX_ENDP_LEN];
++};
++
++/* values for epdisc.class */
++#define EPD_NULL 0 /* null discriminator, no data */
++#define EPD_LOCAL 1
++#define EPD_IP 2
++#define EPD_MAC 3
++#define EPD_MAGIC 4
++#define EPD_PHONENUM 5
++
++typedef void (*notify_func) __P((void *, int));
++
++struct notifier {
++ struct notifier *next;
++ notify_func func;
++ void *arg;
++};
++
++/*
++ * Global variables.
++ */
++
++extern int hungup; /* Physical layer has disconnected */
++extern int ifunit; /* Interface unit number */
++extern char ifname[]; /* Interface name */
++extern char hostname[]; /* Our hostname */
++extern u_char outpacket_buf[]; /* Buffer for outgoing packets */
++extern int phase; /* Current state of link - see values below */
++extern int baud_rate; /* Current link speed in bits/sec */
++extern char *progname; /* Name of this program */
++extern int redirect_stderr;/* Connector's stderr should go to file */
++extern char peer_authname[];/* Authenticated name of peer */
++extern int privileged; /* We were run by real-uid root */
++extern int need_holdoff; /* Need holdoff period after link terminates */
++extern char **script_env; /* Environment variables for scripts */
++extern int detached; /* Have detached from controlling tty */
++extern GIDSET_TYPE groups[NGROUPS_MAX]; /* groups the user is in */
++extern int ngroups; /* How many groups valid in groups */
++extern struct pppd_stats link_stats; /* byte/packet counts etc. for link */
++extern int link_stats_valid; /* set if link_stats is valid */
++extern int link_connect_time; /* time the link was up for */
++extern int using_pty; /* using pty as device (notty or pty opt.) */
++extern int log_to_fd; /* logging to this fd as well as syslog */
++extern bool log_default; /* log_to_fd is default (stdout) */
++extern char *no_ppp_msg; /* message to print if ppp not in kernel */
++extern volatile int status; /* exit status for pppd */
++extern bool devnam_fixed; /* can no longer change devnam */
++extern int unsuccess; /* # unsuccessful connection attempts */
++extern int do_callback; /* set if we want to do callback next */
++extern int doing_callback; /* set if this is a callback */
++extern char ppp_devnam[MAXPATHLEN];
++extern struct notifier *pidchange; /* for notifications of pid changing */
++extern struct notifier *phasechange; /* for notifications of phase changes */
++extern struct notifier *exitnotify; /* for notification that we're exiting */
++extern struct notifier *sigreceived; /* notification of received signal */
++extern int listen_time; /* time to listen first (ms) */
++
++/* Values for do_callback and doing_callback */
++#define CALLBACK_DIALIN 1 /* we are expecting the call back */
++#define CALLBACK_DIALOUT 2 /* we are dialling out to call back */
++
++/*
++ * Variables set by command-line options.
++ */
++
++extern int debug; /* Debug flag */
++extern int kdebugflag; /* Tell kernel to print debug messages */
++extern int default_device; /* Using /dev/tty or equivalent */
++extern char devnam[MAXPATHLEN]; /* Device name */
++extern int crtscts; /* Use hardware flow control */
++extern bool modem; /* Use modem control lines */
++extern int inspeed; /* Input/Output speed requested */
++extern u_int32_t netmask; /* IP netmask to set on interface */
++extern bool lockflag; /* Create lock file to lock the serial dev */
++extern bool nodetach; /* Don't detach from controlling tty */
++extern bool updetach; /* Detach from controlling tty when link up */
++extern char *initializer; /* Script to initialize physical link */
++extern char *connect_script; /* Script to establish physical link */
++extern char *disconnect_script; /* Script to disestablish physical link */
++extern char *welcomer; /* Script to welcome client after connection */
++extern char *ptycommand; /* Command to run on other side of pty */
++extern int maxconnect; /* Maximum connect time (seconds) */
++extern char user[MAXNAMELEN];/* Our name for authenticating ourselves */
++extern char passwd[MAXSECRETLEN]; /* Password for PAP or CHAP */
++extern bool auth_required; /* Peer is required to authenticate */
++extern bool persist; /* Reopen link after it goes down */
++extern bool uselogin; /* Use /etc/passwd for checking PAP */
++extern char our_name[MAXNAMELEN];/* Our name for authentication purposes */
++extern char remote_name[MAXNAMELEN]; /* Peer's name for authentication */
++extern bool explicit_remote;/* remote_name specified with remotename opt */
++extern bool demand; /* Do dial-on-demand */
++extern char *ipparam; /* Extra parameter for ip up/down scripts */
++extern bool cryptpap; /* Others' PAP passwords are encrypted */
++extern int idle_time_limit;/* Shut down link if idle for this long */
++extern int holdoff; /* Dead time before restarting */
++extern bool holdoff_specified; /* true if user gave a holdoff value */
++extern bool notty; /* Stdin/out is not a tty */
++extern char *pty_socket; /* Socket to connect to pty */
++extern char *record_file; /* File to record chars sent/received */
++extern bool sync_serial; /* Device is synchronous serial device */
++extern int maxfail; /* Max # of unsuccessful connection attempts */
++extern char linkname[MAXPATHLEN]; /* logical name for link */
++extern bool tune_kernel; /* May alter kernel settings as necessary */
++extern int connect_delay; /* Time to delay after connect script */
++extern int max_data_rate; /* max bytes/sec through charshunt */
++extern int req_unit; /* interface unit number to use */
++extern bool multilink; /* enable multilink operation */
++extern bool noendpoint; /* don't send or accept endpt. discrim. */
++extern char *bundle_name; /* bundle name for multilink */
++extern bool dump_options; /* print out option values */
++extern bool dryrun; /* check everything, print options, exit */
++
++#ifdef PPP_FILTER
++extern struct bpf_program pass_filter; /* Filter for pkts to pass */
++extern struct bpf_program active_filter; /* Filter for link-active pkts */
++#endif
++
++#ifdef MSLANMAN
++extern bool ms_lanman; /* Use LanMan password instead of NT */
++ /* Has meaning only with MS-CHAP challenges */
++#endif
++
++extern char *current_option; /* the name of the option being parsed */
++extern int privileged_option; /* set iff the current option came from root */
++extern char *option_source; /* string saying where the option came from */
++extern int option_priority; /* priority of current options */
++
++/*
++ * Values for phase.
++ */
++#define PHASE_DEAD 0
++#define PHASE_INITIALIZE 1
++#define PHASE_SERIALCONN 2
++#define PHASE_DORMANT 3
++#define PHASE_ESTABLISH 4
++#define PHASE_AUTHENTICATE 5
++#define PHASE_CALLBACK 6
++#define PHASE_NETWORK 7
++#define PHASE_RUNNING 8
++#define PHASE_TERMINATE 9
++#define PHASE_DISCONNECT 10
++#define PHASE_HOLDOFF 11
++
++/*
++ * The following struct gives the addresses of procedures to call
++ * for a particular protocol.
++ */
++struct protent {
++ u_short protocol; /* PPP protocol number */
++ /* Initialization procedure */
++ void (*init) __P((int unit));
++ /* Process a received packet */
++ void (*input) __P((int unit, u_char *pkt, int len));
++ /* Process a received protocol-reject */
++ void (*protrej) __P((int unit));
++ /* Lower layer has come up */
++ void (*lowerup) __P((int unit));
++ /* Lower layer has gone down */
++ void (*lowerdown) __P((int unit));
++ /* Open the protocol */
++ void (*open) __P((int unit));
++ /* Close the protocol */
++ void (*close) __P((int unit, char *reason));
++ /* Print a packet in readable form */
++ int (*printpkt) __P((u_char *pkt, int len,
++ void (*printer) __P((void *, char *, ...)),
++ void *arg));
++ /* Process a received data packet */
++ void (*datainput) __P((int unit, u_char *pkt, int len));
++ bool enabled_flag; /* 0 iff protocol is disabled */
++ char *name; /* Text name of protocol */
++ char *data_name; /* Text name of corresponding data protocol */
++ option_t *options; /* List of command-line options */
++ /* Check requested options, assign defaults */
++ void (*check_options) __P((void));
++ /* Configure interface for demand-dial */
++ int (*demand_conf) __P((int unit));
++ /* Say whether to bring up link for this pkt */
++ int (*active_pkt) __P((u_char *pkt, int len));
++};
++
++/* Table of pointers to supported protocols */
++extern struct protent *protocols[];
++
++/*
++ * This struct contains pointers to a set of procedures for
++ * doing operations on a &quot;channel&quot;. A channel provides a way
++ * to send and receive PPP packets - the canonical example is
++ * a serial port device in PPP line discipline (or equivalently
++ * with PPP STREAMS modules pushed onto it).
++ */
++struct channel {
++ /* set of options for this channel */
++ option_t *options;
++ /* find and process a per-channel options file */
++ void (*process_extra_options) __P((void));
++ /* check all the options that have been given */
++ void (*check_options) __P((void));
++ /* get the channel ready to do PPP, return a file descriptor */
++ int (*connect) __P((void));
++ /* we're finished with the channel */
++ void (*disconnect) __P((void));
++ /* put the channel into PPP `mode' */
++ int (*establish_ppp) __P((int));
++ /* take the channel out of PPP `mode', restore loopback if demand */
++ void (*disestablish_ppp) __P((int));
++ /* set the transmit-side PPP parameters of the channel */
++ void (*send_config) __P((int, u_int32_t, int, int));
++ /* set the receive-side PPP parameters of the channel */
++ void (*recv_config) __P((int, u_int32_t, int, int));
++ /* cleanup on error or normal exit */
++ void (*cleanup) __P((void));
++ /* close the device, called in children after fork */
++ void (*close) __P((void));
++};
++
++extern struct channel *the_channel;
++
++#define ppp_send_config(unit, mtu, accm, pc, acc) \
++do { \
++ if (the_channel-&gt;send_config) \
++ (*the_channel-&gt;send_config)((mtu), (accm), (pc), (acc)); \
++} while (0)
++
++#define ppp_recv_config(unit, mtu, accm, pc, acc) \
++do { \
++ if (the_channel-&gt;send_config) \
++ (*the_channel-&gt;recv_config)((mtu), (accm), (pc), (acc)); \
++} while (0)
++
++/*
++ * Prototypes.
++ */
++
++/* Procedures exported from main.c. */
++void set_ifunit __P((int)); /* set stuff that depends on ifunit */
++void detach __P((void)); /* Detach from controlling tty */
++void die __P((int)); /* Cleanup and exit */
++void quit __P((void)); /* like die(1) */
++void novm __P((char *)); /* Say we ran out of memory, and die */
++void timeout __P((void (*func)(void *), void *arg, int s, int us));
++ /* Call func(arg) after s.us seconds */
++void untimeout __P((void (*func)(void *), void *arg));
++ /* Cancel call to func(arg) */
++void record_child __P((int, char *, void (*) (void *), void *));
++int device_script __P((char *cmd, int in, int out, int dont_wait));
++ /* Run `cmd' with given stdin and stdout */
++pid_t run_program __P((char *prog, char **args, int must_exist,
++ void (*done)(void *), void *arg));
++ /* Run program prog with args in child */
++void reopen_log __P((void)); /* (re)open the connection to syslog */
++void update_link_stats __P((int)); /* Get stats at link termination */
++void script_setenv __P((char *, char *, int)); /* set script env var */
++void script_unsetenv __P((char *)); /* unset script env var */
++void new_phase __P((int)); /* signal start of new phase */
++void add_notifier __P((struct notifier **, notify_func, void *));
++void remove_notifier __P((struct notifier **, notify_func, void *));
++void notify __P((struct notifier *, int));
++
++/* Procedures exported from tty.c. */
++void tty_init __P((void));
++
++/* Procedures exported from utils.c. */
++void log_packet __P((u_char *, int, char *, int));
++ /* Format a packet and log it with syslog */
++void print_string __P((char *, int, void (*) (void *, char *, ...),
++ void *)); /* Format a string for output */
++int slprintf __P((char *, int, char *, ...)); /* sprintf++ */
++int vslprintf __P((char *, int, char *, va_list)); /* vsprintf++ */
++size_t strlcpy __P((char *, const char *, size_t)); /* safe strcpy */
++size_t strlcat __P((char *, const char *, size_t)); /* safe strncpy */
++void dbglog __P((char *, ...)); /* log a debug message */
++void info __P((char *, ...)); /* log an informational message */
++void notice __P((char *, ...)); /* log a notice-level message */
++void warn __P((char *, ...)); /* log a warning message */
++void error __P((char *, ...)); /* log an error message */
++void fatal __P((char *, ...)); /* log an error message and die(1) */
++void init_pr_log __P((char *, int)); /* initialize for using pr_log */
++void pr_log __P((void *, char *, ...)); /* printer fn, output to syslog */
++void end_pr_log __P((void)); /* finish up after using pr_log */
++
++/* Procedures exported from auth.c */
++void link_required __P((int)); /* we are starting to use the link */
++void link_terminated __P((int)); /* we are finished with the link */
++void link_down __P((int)); /* the LCP layer has left the Opened state */
++void link_established __P((int)); /* the link is up; authenticate now */
++void start_networks __P((void)); /* start all the network control protos */
++void np_up __P((int, int)); /* a network protocol has come up */
++void np_down __P((int, int)); /* a network protocol has gone down */
++void np_finished __P((int, int)); /* a network protocol no longer needs link */
++void auth_peer_fail __P((int, int));
++ /* peer failed to authenticate itself */
++void auth_peer_success __P((int, int, char *, int));
++ /* peer successfully authenticated itself */
++void auth_withpeer_fail __P((int, int));
++ /* we failed to authenticate ourselves */
++void auth_withpeer_success __P((int, int));
++ /* we successfully authenticated ourselves */
++void auth_check_options __P((void));
++ /* check authentication options supplied */
++void auth_reset __P((int)); /* check what secrets we have */
++int check_passwd __P((int, char *, int, char *, int, char **));
++ /* Check peer-supplied username/password */
++int get_secret __P((int, char *, char *, char *, int *, int));
++ /* get &quot;secret&quot; for chap */
++int auth_ip_addr __P((int, u_int32_t));
++ /* check if IP address is authorized */
++int bad_ip_adrs __P((u_int32_t));
++ /* check if IP address is unreasonable */
++
++/* Procedures exported from demand.c */
++void demand_conf __P((void)); /* config interface(s) for demand-dial */
++void demand_block __P((void)); /* set all NPs to queue up packets */
++void demand_unblock __P((void)); /* set all NPs to pass packets */
++void demand_discard __P((void)); /* set all NPs to discard packets */
++void demand_rexmit __P((int)); /* retransmit saved frames for an NP */
++int loop_chars __P((unsigned char *, int)); /* process chars from loopback */
++int loop_frame __P((unsigned char *, int)); /* should we bring link up? */
++
++/* Procedures exported from multilink.c */
++void mp_check_options __P((void)); /* Check multilink-related options */
++int mp_join_bundle __P((void)); /* join our link to an appropriate bundle */
++char *epdisc_to_str __P((struct epdisc *)); /* string from endpoint discrim. */
++int str_to_epdisc __P((struct epdisc *, char *)); /* endpt disc. from str */
++
++/* Procedures exported from sys-*.c */
++void sys_init __P((void)); /* Do system-dependent initialization */
++void sys_cleanup __P((void)); /* Restore system state before exiting */
++int sys_check_options __P((void)); /* Check options specified */
++void sys_close __P((void)); /* Clean up in a child before execing */
++int ppp_available __P((void)); /* Test whether ppp kernel support exists */
++int get_pty __P((int *, int *, char *, int)); /* Get pty master/slave */
++int open_ppp_loopback __P((void)); /* Open loopback for demand-dialling */
++int tty_establish_ppp __P((int)); /* Turn serial port into a ppp interface */
++void tty_disestablish_ppp __P((int)); /* Restore port to normal operation */
++void make_new_bundle __P((int, int, int, int)); /* Create new bundle */
++int bundle_attach __P((int)); /* Attach link to existing bundle */
++void cfg_bundle __P((int, int, int, int)); /* Configure existing bundle */
++void clean_check __P((void)); /* Check if line was 8-bit clean */
++void set_up_tty __P((int, int)); /* Set up port's speed, parameters, etc. */
++void restore_tty __P((int)); /* Restore port's original parameters */
++void setdtr __P((int, int)); /* Raise or lower port's DTR line */
++void output __P((int, u_char *, int)); /* Output a PPP packet */
++void wait_input __P((struct timeval *));
++ /* Wait for input, with timeout */
++void add_fd __P((int)); /* Add fd to set to wait for */
++void remove_fd __P((int)); /* Remove fd from set to wait for */
++int read_packet __P((u_char *)); /* Read PPP packet */
++int get_loop_output __P((void)); /* Read pkts from loopback */
++void tty_send_config __P((int, u_int32_t, int, int));
++ /* Configure i/f transmit parameters */
++void tty_set_xaccm __P((ext_accm));
++ /* Set extended transmit ACCM */
++void tty_recv_config __P((int, u_int32_t, int, int));
++ /* Configure i/f receive parameters */
++int ccp_test __P((int, u_char *, int, int));
++ /* Test support for compression scheme */
++void ccp_flags_set __P((int, int, int));
++ /* Set kernel CCP state */
++int ccp_fatal_error __P((int)); /* Test for fatal decomp error in kernel */
++int get_idle_time __P((int, struct ppp_idle *));
++ /* Find out how long link has been idle */
++int get_ppp_stats __P((int, struct pppd_stats *));
++ /* Return link statistics */
++void netif_set_mtu __P((int, int)); /* Set PPP interface MTU */
++int sifvjcomp __P((int, int, int, int));
++ /* Configure VJ TCP header compression */
++int sifup __P((int)); /* Configure i/f up for one protocol */
++int sifnpmode __P((int u, int proto, enum NPmode mode));
++ /* Set mode for handling packets for proto */
++int sifdown __P((int)); /* Configure i/f down for one protocol */
++int sifaddr __P((int, u_int32_t, u_int32_t, u_int32_t));
++ /* Configure IPv4 addresses for i/f */
++int cifaddr __P((int, u_int32_t, u_int32_t));
++ /* Reset i/f IP addresses */
++#ifdef INET6
++int sif6addr __P((int, eui64_t, eui64_t));
++ /* Configure IPv6 addresses for i/f */
++int cif6addr __P((int, eui64_t, eui64_t));
++ /* Remove an IPv6 address from i/f */
++#endif
++int sifdefaultroute __P((int, u_int32_t, u_int32_t));
++ /* Create default route through i/f */
++int cifdefaultroute __P((int, u_int32_t, u_int32_t));
++ /* Delete default route through i/f */
++int sifproxyarp __P((int, u_int32_t));
++ /* Add proxy ARP entry for peer */
++int cifproxyarp __P((int, u_int32_t));
++ /* Delete proxy ARP entry for peer */
++u_int32_t GetMask __P((u_int32_t)); /* Get appropriate netmask for address */
++int lock __P((char *)); /* Create lock file for device */
++int relock __P((int)); /* Rewrite lock file with new pid */
++void unlock __P((void)); /* Delete previously-created lock file */
++int get_host_seed __P((void)); /* Get host-dependent random number seed */
++int have_route_to __P((u_int32_t)); /* Check if route to addr exists */
++#ifdef PPP_FILTER
++int set_filters __P((struct bpf_program *pass, struct bpf_program *active));
++ /* Set filter programs in kernel */
++#endif
++#ifdef IPX_CHANGE
++int sipxfaddr __P((int, unsigned long, unsigned char *));
++int cipxfaddr __P((int));
++#endif
++int get_if_hwaddr __P((u_char *addr, char *name));
++char *get_first_ethernet __P((void));
++
++/* Procedures exported from options.c */
++int parse_args __P((int argc, char **argv));
++ /* Parse options from arguments given */
++int options_from_file __P((char *filename, int must_exist, int check_prot,
++ int privileged));
++ /* Parse options from an options file */
++int options_from_user __P((void)); /* Parse options from user's .ppprc */
++int options_for_tty __P((void)); /* Parse options from /etc/ppp/options.tty */
++int options_from_list __P((struct wordlist *, int privileged));
++ /* Parse options from a wordlist */
++int getword __P((FILE *f, char *word, int *newlinep, char *filename));
++ /* Read a word from a file */
++void option_error __P((char *fmt, ...));
++ /* Print an error message about an option */
++int int_option __P((char *, int *));
++ /* Simplified number_option for decimal ints */
++void add_options __P((option_t *)); /* Add extra options */
++void check_options __P((void)); /* check values after all options parsed */
++int override_value __P((const char *, int, const char *));
++ /* override value if permitted by priority */
++void print_options __P((void (*) __P((void *, char *, ...)), void *));
++ /* print out values of all options */
++
++int parse_dotted_ip __P((char *, u_int32_t *));
++
++/*
++ * Hooks to enable plugins to change various things.
++ */
++extern int (*new_phase_hook) __P((int));
++extern int (*idle_time_hook) __P((struct ppp_idle *));
++extern int (*holdoff_hook) __P((void));
++extern int (*pap_check_hook) __P((void));
++extern int (*pap_auth_hook) __P((char *user, char *passwd, char **msgp,
++ struct wordlist **paddrs,
++ struct wordlist **popts));
++extern void (*pap_logout_hook) __P((void));
++extern int (*pap_passwd_hook) __P((char *user, char *passwd));
++extern void (*ip_up_hook) __P((void));
++extern void (*ip_down_hook) __P((void));
++extern void (*ip_choose_hook) __P((u_int32_t *));
++
++/*
++ * Inline versions of get/put char/short/long.
++ * Pointer is advanced; we assume that both arguments
++ * are lvalues and will already be in registers.
++ * cp MUST be u_char *.
++ */
++#define GETCHAR(c, cp) { \
++ (c) = *(cp)++; \
++}
++#define PUTCHAR(c, cp) { \
++ *(cp)++ = (u_char) (c); \
++}
++
++
++#define GETSHORT(s, cp) { \
++ (s) = *(cp)++ &lt;&lt; 8; \
++ (s) |= *(cp)++; \
++}
++#define PUTSHORT(s, cp) { \
++ *(cp)++ = (u_char) ((s) &gt;&gt; 8); \
++ *(cp)++ = (u_char) (s); \
++}
++
++#define GETLONG(l, cp) { \
++ (l) = *(cp)++ &lt;&lt; 8; \
++ (l) |= *(cp)++; (l) &lt;&lt;= 8; \
++ (l) |= *(cp)++; (l) &lt;&lt;= 8; \
++ (l) |= *(cp)++; \
++}
++#define PUTLONG(l, cp) { \
++ *(cp)++ = (u_char) ((l) &gt;&gt; 24); \
++ *(cp)++ = (u_char) ((l) &gt;&gt; 16); \
++ *(cp)++ = (u_char) ((l) &gt;&gt; 8); \
++ *(cp)++ = (u_char) (l); \
++}
++
++#define INCPTR(n, cp) ((cp) += (n))
++#define DECPTR(n, cp) ((cp) -= (n))
++
++/*
++ * System dependent definitions for user-level 4.3BSD UNIX implementation.
++ */
++
++#define TIMEOUT(r, f, t) timeout((r), (f), (t), 0)
++#define UNTIMEOUT(r, f) untimeout((r), (f))
++
++#define BCOPY(s, d, l) memcpy(d, s, l)
++#define BZERO(s, n) memset(s, 0, n)
++
++#define PRINTMSG(m, l) { info(&quot;Remote message: %0.*v&quot;, l, m); }
++
++/*
++ * MAKEHEADER - Add Header fields to a packet.
++ */
++#define MAKEHEADER(p, t) { \
++ PUTCHAR(PPP_ALLSTATIONS, p); \
++ PUTCHAR(PPP_UI, p); \
++ PUTSHORT(t, p); }
++
++/*
++ * Exit status values.
++ */
++#define EXIT_OK 0
++#define EXIT_FATAL_ERROR 1
++#define EXIT_OPTION_ERROR 2
++#define EXIT_NOT_ROOT 3
++#define EXIT_NO_KERNEL_SUPPORT 4
++#define EXIT_USER_REQUEST 5
++#define EXIT_LOCK_FAILED 6
++#define EXIT_OPEN_FAILED 7
++#define EXIT_CONNECT_FAILED 8
++#define EXIT_PTYCMD_FAILED 9
++#define EXIT_NEGOTIATION_FAILED 10
++#define EXIT_PEER_AUTH_FAILED 11
++#define EXIT_IDLE_TIMEOUT 12
++#define EXIT_CONNECT_TIME 13
++#define EXIT_CALLBACK 14
++#define EXIT_PEER_DEAD 15
++#define EXIT_HANGUP 16
++#define EXIT_LOOPBACK 17
++#define EXIT_INIT_FAILED 18
++#define EXIT_AUTH_TOPEER_FAILED 19
++
++/*
++ * Debug macros. Slightly useful for finding bugs in pppd, not particularly
++ * useful for finding out why your connection isn't being established.
++ */
++#ifdef DEBUGALL
++#define DEBUGMAIN 1
++#define DEBUGFSM 1
++#define DEBUGLCP 1
++#define DEBUGIPCP 1
++#define DEBUGIPV6CP 1
++#define DEBUGUPAP 1
++#define DEBUGCHAP 1
++#endif
++
++#ifndef LOG_PPP /* we use LOG_LOCAL2 for syslog by default */
++#if defined(DEBUGMAIN) || defined(DEBUGFSM) || defined(DEBUGSYS) \
++ || defined(DEBUGLCP) || defined(DEBUGIPCP) || defined(DEBUGUPAP) \
++ || defined(DEBUGCHAP) || defined(DEBUG) || defined(DEBUGIPV6CP)
++#define LOG_PPP LOG_LOCAL2
++#else
++#define LOG_PPP LOG_DAEMON
++#endif
++#endif /* LOG_PPP */
++
++#ifdef DEBUGMAIN
++#define MAINDEBUG(x) if (debug) dbglog x
++#else
++#define MAINDEBUG(x)
++#endif
++
++#ifdef DEBUGSYS
++#define SYSDEBUG(x) if (debug) dbglog x
++#else
++#define SYSDEBUG(x)
++#endif
++
++#ifdef DEBUGFSM
++#define FSMDEBUG(x) if (debug) dbglog x
++#else
++#define FSMDEBUG(x)
++#endif
++
++#ifdef DEBUGLCP
++#define LCPDEBUG(x) if (debug) dbglog x
++#else
++#define LCPDEBUG(x)
++#endif
++
++#ifdef DEBUGIPCP
++#define IPCPDEBUG(x) if (debug) dbglog x
++#else
++#define IPCPDEBUG(x)
++#endif
++
++#ifdef DEBUGIPV6CP
++#define IPV6CPDEBUG(x) if (debug) dbglog x
++#else
++#define IPV6CPDEBUG(x)
++#endif
++
++#ifdef DEBUGUPAP
++#define UPAPDEBUG(x) if (debug) dbglog x
++#else
++#define UPAPDEBUG(x)
++#endif
++
++#ifdef DEBUGCHAP
++#define CHAPDEBUG(x) if (debug) dbglog x
++#else
++#define CHAPDEBUG(x)
++#endif
++
++#ifdef DEBUGIPXCP
++#define IPXCPDEBUG(x) if (debug) dbglog x
++#else
++#define IPXCPDEBUG(x)
++#endif
++
++#ifndef SIGTYPE
++#if defined(sun) || defined(SYSV) || defined(POSIX_SOURCE)
++#define SIGTYPE void
++#else
++#define SIGTYPE int
++#endif /* defined(sun) || defined(SYSV) || defined(POSIX_SOURCE) */
++#endif /* SIGTYPE */
++
++#ifndef MIN
++#define MIN(a, b) ((a) &lt; (b)? (a): (b))
++#endif
++#ifndef MAX
++#define MAX(a, b) ((a) &gt; (b)? (a): (b))
++#endif
++
++#endif /* __PPP_H__ */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/pppd.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/pppd.h.wtmp
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/pppd.h.wtmp (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/pppd.h.wtmp 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,789 @@
++/*
++ * pppd.h - PPP daemon global declarations.
++ *
++ * Copyright (c) 1989 Carnegie Mellon University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by Carnegie Mellon University. The name of the
++ * University may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * $Id: pppd.h.wtmp 195720 2001-06-11 11:44:34Z gc $
++ */
++
++/*
++ * TODO:
++ */
++
++#ifndef __PPPD_H__
++#define __PPPD_H__
++
++#include &lt;stdio.h&gt; /* for FILE */
++#include &lt;limits.h&gt; /* for NGROUPS_MAX */
++#include &lt;sys/param.h&gt; /* for MAXPATHLEN and BSD4_4, if defined */
++#include &lt;sys/types.h&gt; /* for u_int32_t, if defined */
++#include &lt;sys/time.h&gt; /* for struct timeval */
++#include &lt;net/ppp_defs.h&gt;
++#include &quot;patchlevel.h&quot;
++
++#if defined(__STDC__)
++#include &lt;stdarg.h&gt;
++#define __V(x) x
++#else
++#include &lt;varargs.h&gt;
++#define __V(x) (va_alist) va_dcl
++#define const
++#define volatile
++#endif
++
++#ifdef INET6
++#include &quot;eui64.h&quot;
++#endif
++
++/*
++ * Limits.
++ */
++
++#define NUM_PPP 1 /* One PPP interface supported (per process) */
++#define MAXWORDLEN 1024 /* max length of word in file (incl null) */
++#define MAXARGS 1 /* max # args to a command */
++#define MAXNAMELEN 256 /* max length of hostname or name for auth */
++#define MAXSECRETLEN 256 /* max length of password or secret */
++
++/*
++ * Option descriptor structure.
++ */
++
++typedef unsigned char bool;
++
++enum opt_type {
++ o_special_noarg = 0,
++ o_special = 1,
++ o_bool,
++ o_int,
++ o_uint32,
++ o_string,
++ o_wild,
++};
++
++typedef struct {
++ char *name; /* name of the option */
++ enum opt_type type;
++ void *addr;
++ char *description;
++ int flags;
++ void *addr2;
++ int upper_limit;
++ int lower_limit;
++ const char *source;
++ short int priority;
++ short int winner;
++} option_t;
++
++/* Values for flags */
++#define OPT_VALUE 0xff /* mask for presupplied value */
++#define OPT_HEX 0x100 /* int option is in hex */
++#define OPT_NOARG 0x200 /* option doesn't take argument */
++#define OPT_OR 0x400 /* OR in argument to value */
++#define OPT_INC 0x800 /* increment value */
++#define OPT_PRIV 0x1000 /* privileged option */
++#define OPT_STATIC 0x2000 /* string option goes into static array */
++#define OPT_LLIMIT 0x4000 /* check value against lower limit */
++#define OPT_ULIMIT 0x8000 /* check value against upper limit */
++#define OPT_LIMITS (OPT_LLIMIT|OPT_ULIMIT)
++#define OPT_ZEROOK 0x10000 /* 0 value is OK even if not within limits */
++#define OPT_HIDE 0x10000 /* for o_string, print value as ?????? */
++#define OPT_A2LIST 0x10000 /* for o_special, keep list of values */
++#define OPT_NOINCR 0x20000 /* value mustn't be increased */
++#define OPT_ZEROINF 0x40000 /* with OPT_NOINCR, 0 == infinity */
++#define OPT_PRIO 0x80000 /* process option priorities for this option */
++#define OPT_PRIOSUB 0x100000 /* subsidiary member of priority group */
++#define OPT_ALIAS 0x200000 /* option is alias for previous option */
++#define OPT_A2COPY 0x400000 /* addr2 -&gt; second location to rcv value */
++#define OPT_ENABLE 0x800000 /* use *addr2 as enable for option */
++#define OPT_A2CLR 0x1000000 /* clear *(bool *)addr2 */
++#define OPT_PRIVFIX 0x2000000 /* user can't override if set by root */
++#define OPT_INITONLY 0x4000000 /* option can only be set in init phase */
++#define OPT_DEVEQUIV 0x8000000 /* equiv to device name */
++#define OPT_DEVNAM (OPT_INITONLY | OPT_DEVEQUIV)
++#define OPT_A2PRINTER 0x10000000 /* *addr2 is a fn for printing option */
++#define OPT_A2STRVAL 0x20000000 /* *addr2 points to current string value */
++#define OPT_NOPRINT 0x40000000 /* don't print this option at all */
++
++#define OPT_VAL(x) ((x) &amp; OPT_VALUE)
++
++/* Values for priority */
++#define OPRIO_DEFAULT 0 /* a default value */
++#define OPRIO_CFGFILE 1 /* value from a configuration file */
++#define OPRIO_CMDLINE 2 /* value from the command line */
++#define OPRIO_SECFILE 3 /* value from options in a secrets file */
++#define OPRIO_ROOT 100 /* added to priority if OPT_PRIVFIX &amp;&amp; root */
++
++#ifndef GIDSET_TYPE
++#define GIDSET_TYPE gid_t
++#endif
++
++/* Structure representing a list of permitted IP addresses. */
++struct permitted_ip {
++ int permit; /* 1 = permit, 0 = forbid */
++ u_int32_t base; /* match if (addr &amp; mask) == base */
++ u_int32_t mask; /* base and mask are in network byte order */
++};
++
++/*
++ * Unfortunately, the linux kernel driver uses a different structure
++ * for statistics from the rest of the ports.
++ * This structure serves as a common representation for the bits
++ * pppd needs.
++ */
++struct pppd_stats {
++ unsigned int bytes_in;
++ unsigned int bytes_out;
++};
++
++/* Used for storing a sequence of words. Usually malloced. */
++struct wordlist {
++ struct wordlist *next;
++ char *word;
++};
++
++/* An endpoint discriminator, used with multilink. */
++#define MAX_ENDP_LEN 20 /* maximum length of discriminator value */
++struct epdisc {
++ unsigned char class;
++ unsigned char length;
++ unsigned char value[MAX_ENDP_LEN];
++};
++
++/* values for epdisc.class */
++#define EPD_NULL 0 /* null discriminator, no data */
++#define EPD_LOCAL 1
++#define EPD_IP 2
++#define EPD_MAC 3
++#define EPD_MAGIC 4
++#define EPD_PHONENUM 5
++
++typedef void (*notify_func) __P((void *, int));
++
++struct notifier {
++ struct notifier *next;
++ notify_func func;
++ void *arg;
++};
++
++/*
++ * Global variables.
++ */
++
++extern int hungup; /* Physical layer has disconnected */
++extern int ifunit; /* Interface unit number */
++extern char ifname[]; /* Interface name */
++extern char hostname[]; /* Our hostname */
++extern u_char outpacket_buf[]; /* Buffer for outgoing packets */
++extern int phase; /* Current state of link - see values below */
++extern int baud_rate; /* Current link speed in bits/sec */
++extern char *progname; /* Name of this program */
++extern int redirect_stderr;/* Connector's stderr should go to file */
++extern char peer_authname[];/* Authenticated name of peer */
++extern int privileged; /* We were run by real-uid root */
++extern int need_holdoff; /* Need holdoff period after link terminates */
++extern char **script_env; /* Environment variables for scripts */
++extern int detached; /* Have detached from controlling tty */
++extern GIDSET_TYPE groups[NGROUPS_MAX]; /* groups the user is in */
++extern int ngroups; /* How many groups valid in groups */
++extern struct pppd_stats link_stats; /* byte/packet counts etc. for link */
++extern int link_stats_valid; /* set if link_stats is valid */
++extern int link_connect_time; /* time the link was up for */
++extern int using_pty; /* using pty as device (notty or pty opt.) */
++extern int log_to_fd; /* logging to this fd as well as syslog */
++extern bool log_default; /* log_to_fd is default (stdout) */
++extern char *no_ppp_msg; /* message to print if ppp not in kernel */
++extern volatile int status; /* exit status for pppd */
++extern bool devnam_fixed; /* can no longer change devnam */
++extern int unsuccess; /* # unsuccessful connection attempts */
++extern int do_callback; /* set if we want to do callback next */
++extern int doing_callback; /* set if this is a callback */
++extern char ppp_devnam[MAXPATHLEN];
++extern struct notifier *pidchange; /* for notifications of pid changing */
++extern struct notifier *phasechange; /* for notifications of phase changes */
++extern struct notifier *exitnotify; /* for notification that we're exiting */
++extern struct notifier *sigreceived; /* notification of received signal */
++extern int listen_time; /* time to listen first (ms) */
++
++/* Values for do_callback and doing_callback */
++#define CALLBACK_DIALIN 1 /* we are expecting the call back */
++#define CALLBACK_DIALOUT 2 /* we are dialling out to call back */
++
++/*
++ * Variables set by command-line options.
++ */
++
++extern int debug; /* Debug flag */
++extern int kdebugflag; /* Tell kernel to print debug messages */
++extern int default_device; /* Using /dev/tty or equivalent */
++extern char devnam[MAXPATHLEN]; /* Device name */
++extern int crtscts; /* Use hardware flow control */
++extern bool modem; /* Use modem control lines */
++extern int inspeed; /* Input/Output speed requested */
++extern u_int32_t netmask; /* IP netmask to set on interface */
++extern bool lockflag; /* Create lock file to lock the serial dev */
++extern bool nodetach; /* Don't detach from controlling tty */
++extern bool updetach; /* Detach from controlling tty when link up */
++extern char *initializer; /* Script to initialize physical link */
++extern char *connect_script; /* Script to establish physical link */
++extern char *disconnect_script; /* Script to disestablish physical link */
++extern char *welcomer; /* Script to welcome client after connection */
++extern char *ptycommand; /* Command to run on other side of pty */
++extern int maxconnect; /* Maximum connect time (seconds) */
++extern char user[MAXNAMELEN];/* Our name for authenticating ourselves */
++extern char passwd[MAXSECRETLEN]; /* Password for PAP or CHAP */
++extern bool auth_required; /* Peer is required to authenticate */
++extern bool persist; /* Reopen link after it goes down */
++extern bool uselogin; /* Use /etc/passwd for checking PAP */
++extern char our_name[MAXNAMELEN];/* Our name for authentication purposes */
++extern char remote_name[MAXNAMELEN]; /* Peer's name for authentication */
++extern bool explicit_remote;/* remote_name specified with remotename opt */
++extern bool demand; /* Do dial-on-demand */
++extern char *ipparam; /* Extra parameter for ip up/down scripts */
++extern bool cryptpap; /* Others' PAP passwords are encrypted */
++extern int idle_time_limit;/* Shut down link if idle for this long */
++extern int holdoff; /* Dead time before restarting */
++extern bool holdoff_specified; /* true if user gave a holdoff value */
++extern bool notty; /* Stdin/out is not a tty */
++extern char *pty_socket; /* Socket to connect to pty */
++extern char *record_file; /* File to record chars sent/received */
++extern bool sync_serial; /* Device is synchronous serial device */
++extern int maxfail; /* Max # of unsuccessful connection attempts */
++extern char linkname[MAXPATHLEN]; /* logical name for link */
++extern bool tune_kernel; /* May alter kernel settings as necessary */
++extern int connect_delay; /* Time to delay after connect script */
++extern int max_data_rate; /* max bytes/sec through charshunt */
++extern int req_unit; /* interface unit number to use */
++extern bool multilink; /* enable multilink operation */
++extern bool noendpoint; /* don't send or accept endpt. discrim. */
++extern char *bundle_name; /* bundle name for multilink */
++extern bool dump_options; /* print out option values */
++extern bool dryrun; /* check everything, print options, exit */
++
++#ifdef PPP_FILTER
++extern struct bpf_program pass_filter; /* Filter for pkts to pass */
++extern struct bpf_program active_filter; /* Filter for link-active pkts */
++#endif
++
++#ifdef MSLANMAN
++extern bool ms_lanman; /* Use LanMan password instead of NT */
++ /* Has meaning only with MS-CHAP challenges */
++#endif
++
++extern char *current_option; /* the name of the option being parsed */
++extern int privileged_option; /* set iff the current option came from root */
++extern char *option_source; /* string saying where the option came from */
++extern int option_priority; /* priority of current options */
++
++/*
++ * Values for phase.
++ */
++#define PHASE_DEAD 0
++#define PHASE_INITIALIZE 1
++#define PHASE_SERIALCONN 2
++#define PHASE_DORMANT 3
++#define PHASE_ESTABLISH 4
++#define PHASE_AUTHENTICATE 5
++#define PHASE_CALLBACK 6
++#define PHASE_NETWORK 7
++#define PHASE_RUNNING 8
++#define PHASE_TERMINATE 9
++#define PHASE_DISCONNECT 10
++#define PHASE_HOLDOFF 11
++
++/*
++ * The following struct gives the addresses of procedures to call
++ * for a particular protocol.
++ */
++struct protent {
++ u_short protocol; /* PPP protocol number */
++ /* Initialization procedure */
++ void (*init) __P((int unit));
++ /* Process a received packet */
++ void (*input) __P((int unit, u_char *pkt, int len));
++ /* Process a received protocol-reject */
++ void (*protrej) __P((int unit));
++ /* Lower layer has come up */
++ void (*lowerup) __P((int unit));
++ /* Lower layer has gone down */
++ void (*lowerdown) __P((int unit));
++ /* Open the protocol */
++ void (*open) __P((int unit));
++ /* Close the protocol */
++ void (*close) __P((int unit, char *reason));
++ /* Print a packet in readable form */
++ int (*printpkt) __P((u_char *pkt, int len,
++ void (*printer) __P((void *, char *, ...)),
++ void *arg));
++ /* Process a received data packet */
++ void (*datainput) __P((int unit, u_char *pkt, int len));
++ bool enabled_flag; /* 0 iff protocol is disabled */
++ char *name; /* Text name of protocol */
++ char *data_name; /* Text name of corresponding data protocol */
++ option_t *options; /* List of command-line options */
++ /* Check requested options, assign defaults */
++ void (*check_options) __P((void));
++ /* Configure interface for demand-dial */
++ int (*demand_conf) __P((int unit));
++ /* Say whether to bring up link for this pkt */
++ int (*active_pkt) __P((u_char *pkt, int len));
++};
++
++/* Table of pointers to supported protocols */
++extern struct protent *protocols[];
++
++/*
++ * This struct contains pointers to a set of procedures for
++ * doing operations on a &quot;channel&quot;. A channel provides a way
++ * to send and receive PPP packets - the canonical example is
++ * a serial port device in PPP line discipline (or equivalently
++ * with PPP STREAMS modules pushed onto it).
++ */
++struct channel {
++ /* set of options for this channel */
++ option_t *options;
++ /* find and process a per-channel options file */
++ void (*process_extra_options) __P((void));
++ /* check all the options that have been given */
++ void (*check_options) __P((void));
++ /* get the channel ready to do PPP, return a file descriptor */
++ int (*connect) __P((void));
++ /* we're finished with the channel */
++ void (*disconnect) __P((void));
++ /* put the channel into PPP `mode' */
++ int (*establish_ppp) __P((int));
++ /* take the channel out of PPP `mode', restore loopback if demand */
++ void (*disestablish_ppp) __P((int));
++ /* set the transmit-side PPP parameters of the channel */
++ void (*send_config) __P((int, u_int32_t, int, int));
++ /* set the receive-side PPP parameters of the channel */
++ void (*recv_config) __P((int, u_int32_t, int, int));
++ /* cleanup on error or normal exit */
++ void (*cleanup) __P((void));
++ /* close the device, called in children after fork */
++ void (*close) __P((void));
++};
++
++extern struct channel *the_channel;
++
++#define ppp_send_config(unit, mtu, accm, pc, acc) \
++do { \
++ if (the_channel-&gt;send_config) \
++ (*the_channel-&gt;send_config)((mtu), (accm), (pc), (acc)); \
++} while (0)
++
++#define ppp_recv_config(unit, mtu, accm, pc, acc) \
++do { \
++ if (the_channel-&gt;send_config) \
++ (*the_channel-&gt;recv_config)((mtu), (accm), (pc), (acc)); \
++} while (0)
++
++/*
++ * Prototypes.
++ */
++
++/* Procedures exported from main.c. */
++void set_ifunit __P((int)); /* set stuff that depends on ifunit */
++void detach __P((void)); /* Detach from controlling tty */
++void die __P((int)); /* Cleanup and exit */
++void quit __P((void)); /* like die(1) */
++void novm __P((char *)); /* Say we ran out of memory, and die */
++void timeout __P((void (*func)(void *), void *arg, int s, int us));
++ /* Call func(arg) after s.us seconds */
++void untimeout __P((void (*func)(void *), void *arg));
++ /* Cancel call to func(arg) */
++void record_child __P((int, char *, void (*) (void *), void *));
++int device_script __P((char *cmd, int in, int out, int dont_wait));
++ /* Run `cmd' with given stdin and stdout */
++pid_t run_program __P((char *prog, char **args, int must_exist,
++ void (*done)(void *), void *arg));
++ /* Run program prog with args in child */
++void reopen_log __P((void)); /* (re)open the connection to syslog */
++void update_link_stats __P((int)); /* Get stats at link termination */
++void script_setenv __P((char *, char *, int)); /* set script env var */
++void script_unsetenv __P((char *)); /* unset script env var */
++void new_phase __P((int)); /* signal start of new phase */
++void add_notifier __P((struct notifier **, notify_func, void *));
++void remove_notifier __P((struct notifier **, notify_func, void *));
++void notify __P((struct notifier *, int));
++
++/* Procedures exported from tty.c. */
++void tty_init __P((void));
++
++/* Procedures exported from utils.c. */
++void log_packet __P((u_char *, int, char *, int));
++ /* Format a packet and log it with syslog */
++void print_string __P((char *, int, void (*) (void *, char *, ...),
++ void *)); /* Format a string for output */
++int slprintf __P((char *, int, char *, ...)); /* sprintf++ */
++int vslprintf __P((char *, int, char *, va_list)); /* vsprintf++ */
++size_t strlcpy __P((char *, const char *, size_t)); /* safe strcpy */
++size_t strlcat __P((char *, const char *, size_t)); /* safe strncpy */
++void dbglog __P((char *, ...)); /* log a debug message */
++void info __P((char *, ...)); /* log an informational message */
++void notice __P((char *, ...)); /* log a notice-level message */
++void warn __P((char *, ...)); /* log a warning message */
++void error __P((char *, ...)); /* log an error message */
++void fatal __P((char *, ...)); /* log an error message and die(1) */
++void init_pr_log __P((char *, int)); /* initialize for using pr_log */
++void pr_log __P((void *, char *, ...)); /* printer fn, output to syslog */
++void end_pr_log __P((void)); /* finish up after using pr_log */
++
++/* Procedures exported from auth.c */
++void link_required __P((int)); /* we are starting to use the link */
++void link_terminated __P((int)); /* we are finished with the link */
++void link_down __P((int)); /* the LCP layer has left the Opened state */
++void link_established __P((int)); /* the link is up; authenticate now */
++void start_networks __P((void)); /* start all the network control protos */
++void np_up __P((int, int)); /* a network protocol has come up */
++void np_down __P((int, int)); /* a network protocol has gone down */
++void np_finished __P((int, int)); /* a network protocol no longer needs link */
++void auth_peer_fail __P((int, int));
++ /* peer failed to authenticate itself */
++void auth_peer_success __P((int, int, char *, int));
++ /* peer successfully authenticated itself */
++void auth_withpeer_fail __P((int, int));
++ /* we failed to authenticate ourselves */
++void auth_withpeer_success __P((int, int));
++ /* we successfully authenticated ourselves */
++void auth_check_options __P((void));
++ /* check authentication options supplied */
++void auth_reset __P((int)); /* check what secrets we have */
++int check_passwd __P((int, char *, int, char *, int, char **));
++ /* Check peer-supplied username/password */
++int get_secret __P((int, char *, char *, char *, int *, int));
++ /* get &quot;secret&quot; for chap */
++int auth_ip_addr __P((int, u_int32_t));
++ /* check if IP address is authorized */
++int bad_ip_adrs __P((u_int32_t));
++ /* check if IP address is unreasonable */
++
++/* Procedures exported from demand.c */
++void demand_conf __P((void)); /* config interface(s) for demand-dial */
++void demand_block __P((void)); /* set all NPs to queue up packets */
++void demand_unblock __P((void)); /* set all NPs to pass packets */
++void demand_discard __P((void)); /* set all NPs to discard packets */
++void demand_rexmit __P((int)); /* retransmit saved frames for an NP */
++int loop_chars __P((unsigned char *, int)); /* process chars from loopback */
++int loop_frame __P((unsigned char *, int)); /* should we bring link up? */
++
++/* Procedures exported from multilink.c */
++void mp_check_options __P((void)); /* Check multilink-related options */
++int mp_join_bundle __P((void)); /* join our link to an appropriate bundle */
++char *epdisc_to_str __P((struct epdisc *)); /* string from endpoint discrim. */
++int str_to_epdisc __P((struct epdisc *, char *)); /* endpt disc. from str */
++
++/* Procedures exported from sys-*.c */
++void sys_init __P((void)); /* Do system-dependent initialization */
++void sys_cleanup __P((void)); /* Restore system state before exiting */
++int sys_check_options __P((void)); /* Check options specified */
++void sys_close __P((void)); /* Clean up in a child before execing */
++int ppp_available __P((void)); /* Test whether ppp kernel support exists */
++int get_pty __P((int *, int *, char *, int)); /* Get pty master/slave */
++int open_ppp_loopback __P((void)); /* Open loopback for demand-dialling */
++int tty_establish_ppp __P((int)); /* Turn serial port into a ppp interface */
++void tty_disestablish_ppp __P((int)); /* Restore port to normal operation */
++void make_new_bundle __P((int, int, int, int)); /* Create new bundle */
++int bundle_attach __P((int)); /* Attach link to existing bundle */
++void cfg_bundle __P((int, int, int, int)); /* Configure existing bundle */
++void clean_check __P((void)); /* Check if line was 8-bit clean */
++void set_up_tty __P((int, int)); /* Set up port's speed, parameters, etc. */
++void restore_tty __P((int)); /* Restore port's original parameters */
++void setdtr __P((int, int)); /* Raise or lower port's DTR line */
++void output __P((int, u_char *, int)); /* Output a PPP packet */
++void wait_input __P((struct timeval *));
++ /* Wait for input, with timeout */
++void add_fd __P((int)); /* Add fd to set to wait for */
++void remove_fd __P((int)); /* Remove fd from set to wait for */
++int read_packet __P((u_char *)); /* Read PPP packet */
++int get_loop_output __P((void)); /* Read pkts from loopback */
++void tty_send_config __P((int, u_int32_t, int, int));
++ /* Configure i/f transmit parameters */
++void tty_set_xaccm __P((ext_accm));
++ /* Set extended transmit ACCM */
++void tty_recv_config __P((int, u_int32_t, int, int));
++ /* Configure i/f receive parameters */
++int ccp_test __P((int, u_char *, int, int));
++ /* Test support for compression scheme */
++void ccp_flags_set __P((int, int, int));
++ /* Set kernel CCP state */
++int ccp_fatal_error __P((int)); /* Test for fatal decomp error in kernel */
++int get_idle_time __P((int, struct ppp_idle *));
++ /* Find out how long link has been idle */
++int get_ppp_stats __P((int, struct pppd_stats *));
++ /* Return link statistics */
++void netif_set_mtu __P((int, int)); /* Set PPP interface MTU */
++int sifvjcomp __P((int, int, int, int));
++ /* Configure VJ TCP header compression */
++int sifup __P((int)); /* Configure i/f up for one protocol */
++int sifnpmode __P((int u, int proto, enum NPmode mode));
++ /* Set mode for handling packets for proto */
++int sifdown __P((int)); /* Configure i/f down for one protocol */
++int sifaddr __P((int, u_int32_t, u_int32_t, u_int32_t));
++ /* Configure IPv4 addresses for i/f */
++int cifaddr __P((int, u_int32_t, u_int32_t));
++ /* Reset i/f IP addresses */
++#ifdef INET6
++int sif6addr __P((int, eui64_t, eui64_t));
++ /* Configure IPv6 addresses for i/f */
++int cif6addr __P((int, eui64_t, eui64_t));
++ /* Remove an IPv6 address from i/f */
++#endif
++int sifdefaultroute __P((int, u_int32_t, u_int32_t));
++ /* Create default route through i/f */
++int cifdefaultroute __P((int, u_int32_t, u_int32_t));
++ /* Delete default route through i/f */
++int sifproxyarp __P((int, u_int32_t));
++ /* Add proxy ARP entry for peer */
++int cifproxyarp __P((int, u_int32_t));
++ /* Delete proxy ARP entry for peer */
++u_int32_t GetMask __P((u_int32_t)); /* Get appropriate netmask for address */
++int lock __P((char *)); /* Create lock file for device */
++int relock __P((int)); /* Rewrite lock file with new pid */
++void unlock __P((void)); /* Delete previously-created lock file */
++void logwtmp __P((const char *, const char *, const char *));
++ /* Write entry to wtmp file */
++int get_host_seed __P((void)); /* Get host-dependent random number seed */
++int have_route_to __P((u_int32_t)); /* Check if route to addr exists */
++#ifdef PPP_FILTER
++int set_filters __P((struct bpf_program *pass, struct bpf_program *active));
++ /* Set filter programs in kernel */
++#endif
++#ifdef IPX_CHANGE
++int sipxfaddr __P((int, unsigned long, unsigned char *));
++int cipxfaddr __P((int));
++#endif
++int get_if_hwaddr __P((u_char *addr, char *name));
++char *get_first_ethernet __P((void));
++
++/* Procedures exported from options.c */
++int parse_args __P((int argc, char **argv));
++ /* Parse options from arguments given */
++int options_from_file __P((char *filename, int must_exist, int check_prot,
++ int privileged));
++ /* Parse options from an options file */
++int options_from_user __P((void)); /* Parse options from user's .ppprc */
++int options_for_tty __P((void)); /* Parse options from /etc/ppp/options.tty */
++int options_from_list __P((struct wordlist *, int privileged));
++ /* Parse options from a wordlist */
++int getword __P((FILE *f, char *word, int *newlinep, char *filename));
++ /* Read a word from a file */
++void option_error __P((char *fmt, ...));
++ /* Print an error message about an option */
++int int_option __P((char *, int *));
++ /* Simplified number_option for decimal ints */
++void add_options __P((option_t *)); /* Add extra options */
++void check_options __P((void)); /* check values after all options parsed */
++int override_value __P((const char *, int, const char *));
++ /* override value if permitted by priority */
++void print_options __P((void (*) __P((void *, char *, ...)), void *));
++ /* print out values of all options */
++
++int parse_dotted_ip __P((char *, u_int32_t *));
++
++/*
++ * Hooks to enable plugins to change various things.
++ */
++extern int (*new_phase_hook) __P((int));
++extern int (*idle_time_hook) __P((struct ppp_idle *));
++extern int (*holdoff_hook) __P((void));
++extern int (*pap_check_hook) __P((void));
++extern int (*pap_auth_hook) __P((char *user, char *passwd, char **msgp,
++ struct wordlist **paddrs,
++ struct wordlist **popts));
++extern void (*pap_logout_hook) __P((void));
++extern int (*pap_passwd_hook) __P((char *user, char *passwd));
++extern void (*ip_up_hook) __P((void));
++extern void (*ip_down_hook) __P((void));
++extern void (*ip_choose_hook) __P((u_int32_t *));
++
++/*
++ * Inline versions of get/put char/short/long.
++ * Pointer is advanced; we assume that both arguments
++ * are lvalues and will already be in registers.
++ * cp MUST be u_char *.
++ */
++#define GETCHAR(c, cp) { \
++ (c) = *(cp)++; \
++}
++#define PUTCHAR(c, cp) { \
++ *(cp)++ = (u_char) (c); \
++}
++
++
++#define GETSHORT(s, cp) { \
++ (s) = *(cp)++ &lt;&lt; 8; \
++ (s) |= *(cp)++; \
++}
++#define PUTSHORT(s, cp) { \
++ *(cp)++ = (u_char) ((s) &gt;&gt; 8); \
++ *(cp)++ = (u_char) (s); \
++}
++
++#define GETLONG(l, cp) { \
++ (l) = *(cp)++ &lt;&lt; 8; \
++ (l) |= *(cp)++; (l) &lt;&lt;= 8; \
++ (l) |= *(cp)++; (l) &lt;&lt;= 8; \
++ (l) |= *(cp)++; \
++}
++#define PUTLONG(l, cp) { \
++ *(cp)++ = (u_char) ((l) &gt;&gt; 24); \
++ *(cp)++ = (u_char) ((l) &gt;&gt; 16); \
++ *(cp)++ = (u_char) ((l) &gt;&gt; 8); \
++ *(cp)++ = (u_char) (l); \
++}
++
++#define INCPTR(n, cp) ((cp) += (n))
++#define DECPTR(n, cp) ((cp) -= (n))
++
++/*
++ * System dependent definitions for user-level 4.3BSD UNIX implementation.
++ */
++
++#define TIMEOUT(r, f, t) timeout((r), (f), (t), 0)
++#define UNTIMEOUT(r, f) untimeout((r), (f))
++
++#define BCOPY(s, d, l) memcpy(d, s, l)
++#define BZERO(s, n) memset(s, 0, n)
++
++#define PRINTMSG(m, l) { info(&quot;Remote message: %0.*v&quot;, l, m); }
++
++/*
++ * MAKEHEADER - Add Header fields to a packet.
++ */
++#define MAKEHEADER(p, t) { \
++ PUTCHAR(PPP_ALLSTATIONS, p); \
++ PUTCHAR(PPP_UI, p); \
++ PUTSHORT(t, p); }
++
++/*
++ * Exit status values.
++ */
++#define EXIT_OK 0
++#define EXIT_FATAL_ERROR 1
++#define EXIT_OPTION_ERROR 2
++#define EXIT_NOT_ROOT 3
++#define EXIT_NO_KERNEL_SUPPORT 4
++#define EXIT_USER_REQUEST 5
++#define EXIT_LOCK_FAILED 6
++#define EXIT_OPEN_FAILED 7
++#define EXIT_CONNECT_FAILED 8
++#define EXIT_PTYCMD_FAILED 9
++#define EXIT_NEGOTIATION_FAILED 10
++#define EXIT_PEER_AUTH_FAILED 11
++#define EXIT_IDLE_TIMEOUT 12
++#define EXIT_CONNECT_TIME 13
++#define EXIT_CALLBACK 14
++#define EXIT_PEER_DEAD 15
++#define EXIT_HANGUP 16
++#define EXIT_LOOPBACK 17
++#define EXIT_INIT_FAILED 18
++#define EXIT_AUTH_TOPEER_FAILED 19
++
++/*
++ * Debug macros. Slightly useful for finding bugs in pppd, not particularly
++ * useful for finding out why your connection isn't being established.
++ */
++#ifdef DEBUGALL
++#define DEBUGMAIN 1
++#define DEBUGFSM 1
++#define DEBUGLCP 1
++#define DEBUGIPCP 1
++#define DEBUGIPV6CP 1
++#define DEBUGUPAP 1
++#define DEBUGCHAP 1
++#endif
++
++#ifndef LOG_PPP /* we use LOG_LOCAL2 for syslog by default */
++#if defined(DEBUGMAIN) || defined(DEBUGFSM) || defined(DEBUGSYS) \
++ || defined(DEBUGLCP) || defined(DEBUGIPCP) || defined(DEBUGUPAP) \
++ || defined(DEBUGCHAP) || defined(DEBUG) || defined(DEBUGIPV6CP)
++#define LOG_PPP LOG_LOCAL2
++#else
++#define LOG_PPP LOG_DAEMON
++#endif
++#endif /* LOG_PPP */
++
++#ifdef DEBUGMAIN
++#define MAINDEBUG(x) if (debug) dbglog x
++#else
++#define MAINDEBUG(x)
++#endif
++
++#ifdef DEBUGSYS
++#define SYSDEBUG(x) if (debug) dbglog x
++#else
++#define SYSDEBUG(x)
++#endif
++
++#ifdef DEBUGFSM
++#define FSMDEBUG(x) if (debug) dbglog x
++#else
++#define FSMDEBUG(x)
++#endif
++
++#ifdef DEBUGLCP
++#define LCPDEBUG(x) if (debug) dbglog x
++#else
++#define LCPDEBUG(x)
++#endif
++
++#ifdef DEBUGIPCP
++#define IPCPDEBUG(x) if (debug) dbglog x
++#else
++#define IPCPDEBUG(x)
++#endif
++
++#ifdef DEBUGIPV6CP
++#define IPV6CPDEBUG(x) if (debug) dbglog x
++#else
++#define IPV6CPDEBUG(x)
++#endif
++
++#ifdef DEBUGUPAP
++#define UPAPDEBUG(x) if (debug) dbglog x
++#else
++#define UPAPDEBUG(x)
++#endif
++
++#ifdef DEBUGCHAP
++#define CHAPDEBUG(x) if (debug) dbglog x
++#else
++#define CHAPDEBUG(x)
++#endif
++
++#ifdef DEBUGIPXCP
++#define IPXCPDEBUG(x) if (debug) dbglog x
++#else
++#define IPXCPDEBUG(x)
++#endif
++
++#ifndef SIGTYPE
++#if defined(sun) || defined(SYSV) || defined(POSIX_SOURCE)
++#define SIGTYPE void
++#else
++#define SIGTYPE int
++#endif /* defined(sun) || defined(SYSV) || defined(POSIX_SOURCE) */
++#endif /* SIGTYPE */
++
++#ifndef MIN
++#define MIN(a, b) ((a) &lt; (b)? (a): (b))
++#endif
++#ifndef MAX
++#define MAX(a, b) ((a) &gt; (b)? (a): (b))
++#endif
++
++#endif /* __PPP_H__ */
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/sys-linux.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/sys-linux.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/sys-linux.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,2672 @@
++/*
++ * sys-linux.c - System-dependent procedures for setting up
++ * PPP interfaces on Linux systems
++ *
++ * Copyright (c) 1989 Carnegie Mellon University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by Carnegie Mellon University. The name of the
++ * University may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ */
++
++#include &lt;sys/ioctl.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/socket.h&gt;
++#include &lt;sys/time.h&gt;
++#include &lt;sys/errno.h&gt;
++#include &lt;sys/file.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;sys/utsname.h&gt;
++#include &lt;sys/sysmacros.h&gt;
++
++#include &lt;stdio.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;syslog.h&gt;
++#include &lt;string.h&gt;
++#include &lt;time.h&gt;
++#include &lt;memory.h&gt;
++#include &lt;utmp.h&gt;
++#include &lt;mntent.h&gt;
++#include &lt;signal.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;ctype.h&gt;
++#include &lt;termios.h&gt;
++#include &lt;unistd.h&gt;
++
++/* This is in netdevice.h. However, this compile will fail miserably if
++ you attempt to include netdevice.h because it has so many references
++ to __memcpy functions which it should not attempt to do. So, since I
++ really don't use it, but it must be defined, define it now. */
++
++#ifndef MAX_ADDR_LEN
++#define MAX_ADDR_LEN 7
++#endif
++
++#if (defined(__GLIBC__) &amp;&amp; __GLIBC__ &gt;= 2) || defined(__dietlibc__)
++#include &lt;asm/types.h&gt; /* glibc 2 conflicts with linux/types.h */
++#include &lt;net/if.h&gt;
++#include &lt;net/if_arp.h&gt;
++#include &lt;net/route.h&gt;
++#include &lt;netinet/if_ether.h&gt;
++#else
++#include &lt;linux/types.h&gt;
++#include &lt;linux/if.h&gt;
++#include &lt;linux/if_arp.h&gt;
++#include &lt;linux/route.h&gt;
++#include &lt;linux/if_ether.h&gt;
++#endif
++#include &lt;netinet/in.h&gt;
++#include &lt;arpa/inet.h&gt;
++
++#include &lt;linux/ppp_defs.h&gt;
++#include &lt;linux/if_ppp.h&gt;
++
++#include &quot;pppd.h&quot;
++#include &quot;fsm.h&quot;
++#include &quot;ipcp.h&quot;
++
++#ifdef IPX_CHANGE
++#include &quot;ipxcp.h&quot;
++#if __GLIBC__ &gt;= 2 &amp;&amp; \
++ !(defined(__powerpc__) &amp;&amp; __GLIBC__ == 2 &amp;&amp; __GLIBC_MINOR__ == 0)
++#include &lt;netipx/ipx.h&gt;
++#else
++#include &lt;linux/ipx.h&gt;
++#endif
++#endif /* IPX_CHANGE */
++
++#ifdef PPP_FILTER
++#include &lt;net/bpf.h&gt;
++#include &lt;linux/filter.h&gt;
++#endif /* PPP_FILTER */
++
++#ifdef LOCKLIB
++#include &lt;sys/locks.h&gt;
++#endif
++
++#ifdef INET6
++#ifndef _LINUX_IN6_H
++/*
++ * This is in linux/include/net/ipv6.h.
++ */
++
++struct in6_ifreq {
++ struct in6_addr ifr6_addr;
++ __u32 ifr6_prefixlen;
++ unsigned int ifr6_ifindex;
++};
++#endif
++
++#define IN6_LLADDR_FROM_EUI64(sin6, eui64) do { \
++ memset(&amp;sin6.s6_addr, 0, sizeof(struct in6_addr)); \
++ sin6.s6_addr16[0] = htons(0xfe80); \
++ eui64_copy(eui64, sin6.s6_addr32[2]); \
++ } while (0)
++
++#endif /* INET6 */
++
++/* We can get an EIO error on an ioctl if the modem has hung up */
++#define ok_error(num) ((num)==EIO)
++
++static int tty_disc = N_TTY; /* The TTY discipline */
++static int ppp_disc = N_PPP; /* The PPP discpline */
++static int initfdflags = -1; /* Initial file descriptor flags for fd */
++static int ppp_fd = -1; /* fd which is set to PPP discipline */
++static int sock_fd = -1; /* socket for doing interface ioctls */
++static int slave_fd = -1;
++static int master_fd = -1;
++#ifdef INET6
++static int sock6_fd = -1;
++#endif /* INET6 */
++static int ppp_dev_fd = -1; /* fd for /dev/ppp (new style driver) */
++static int chindex; /* channel index (new style driver) */
++
++static fd_set in_fds; /* set of fds that wait_input waits for */
++static int max_in_fd; /* highest fd set in in_fds */
++
++static int has_proxy_arp = 0;
++static int driver_version = 0;
++static int driver_modification = 0;
++static int driver_patch = 0;
++static int driver_is_old = 0;
++static int restore_term = 0; /* 1 =&gt; we've munged the terminal */
++static struct termios inittermios; /* Initial TTY termios */
++
++static int new_style_driver = 0;
++
++static char loop_name[20];
++static unsigned char inbuf[512]; /* buffer for chars read from loopback */
++
++static int if_is_up; /* Interface has been marked up */
++static u_int32_t default_route_gateway; /* Gateway for default route added */
++static u_int32_t proxy_arp_addr; /* Addr for proxy arp entry added */
++static char proxy_arp_dev[16]; /* Device for proxy arp entry */
++static u_int32_t our_old_addr; /* for detecting address changes */
++static int dynaddr_set; /* 1 if ip_dynaddr set */
++static int looped; /* 1 if using loop */
++static int link_mtu; /* mtu for the link (not bundle) */
++
++static struct utsname utsname; /* for the kernel version */
++static int kernel_version;
++#define KVERSION(j,n,p) ((j)*1000000 + (n)*1000 + (p))
++
++#define MAX_IFS 100
++
++#define FLAGS_GOOD (IFF_UP | IFF_BROADCAST)
++#define FLAGS_MASK (IFF_UP | IFF_BROADCAST | \
++ IFF_POINTOPOINT | IFF_LOOPBACK | IFF_NOARP)
++
++#define SIN_ADDR(x) (((struct sockaddr_in *) (&amp;(x)))-&gt;sin_addr.s_addr)
++
++/* Prototypes for procedures local to this file. */
++static int get_flags (int fd);
++static void set_flags (int fd, int flags);
++static int translate_speed (int bps);
++static int baud_rate_of (int speed);
++static void close_route_table (void);
++static int open_route_table (void);
++static int read_route_table (struct rtentry *rt);
++static int defaultroute_exists (struct rtentry *rt);
++static int get_ether_addr (u_int32_t ipaddr, struct sockaddr *hwaddr,
++ char *name, int namelen);
++static void decode_version (char *buf, int *version, int *mod, int *patch);
++static int set_kdebugflag(int level);
++static int ppp_registered(void);
++static int make_ppp_unit(void);
++static void restore_loop(void); /* Transfer ppp unit back to loopback */
++
++extern u_char inpacket_buf[]; /* borrowed from main.c */
++
++/*
++ * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
++ * if it exists.
++ */
++
++#define SET_SA_FAMILY(addr, family) \
++ memset ((char *) &amp;(addr), '\0', sizeof(addr)); \
++ addr.sa_family = (family);
++
++/*
++ * Determine if the PPP connection should still be present.
++ */
++
++extern int hungup;
++
++/* new_fd is the fd of a tty */
++static void set_ppp_fd (int new_fd)
++{
++ SYSDEBUG ((LOG_DEBUG, &quot;setting ppp_fd to %d\n&quot;, new_fd));
++ ppp_fd = new_fd;
++ if (!new_style_driver)
++ ppp_dev_fd = new_fd;
++}
++
++static int still_ppp(void)
++{
++ if (new_style_driver)
++ return !hungup &amp;&amp; ppp_fd &gt;= 0;
++ if (!hungup || ppp_fd == slave_fd)
++ return 1;
++ if (slave_fd &gt;= 0) {
++ set_ppp_fd(slave_fd);
++ return 1;
++ }
++ return 0;
++}
++
++/********************************************************************
++ *
++ * Functions to read and set the flags value in the device driver
++ */
++
++static int get_flags (int fd)
++{
++ int flags;
++
++ if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &amp;flags) &lt; 0) {
++ if ( ok_error (errno) )
++ flags = 0;
++ else
++ fatal(&quot;ioctl(PPPIOCGFLAGS): %m&quot;);
++ }
++
++ SYSDEBUG ((LOG_DEBUG, &quot;get flags = %x\n&quot;, flags));
++ return flags;
++}
++
++/********************************************************************/
++
++static void set_flags (int fd, int flags)
++{
++ SYSDEBUG ((LOG_DEBUG, &quot;set flags = %x\n&quot;, flags));
++
++ if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &amp;flags) &lt; 0) {
++ if (! ok_error (errno) )
++ fatal(&quot;ioctl(PPPIOCSFLAGS, %x): %m&quot;, flags, errno);
++ }
++}
++
++/********************************************************************
++ *
++ * sys_init - System-dependent initialization.
++ */
++
++void sys_init(void)
++{
++ int flags;
++
++ if (new_style_driver) {
++ ppp_dev_fd = open(&quot;/dev/ppp&quot;, O_RDWR);
++ if (ppp_dev_fd &lt; 0)
++ fatal(&quot;Couldn't open /dev/ppp: %m&quot;);
++ flags = fcntl(ppp_dev_fd, F_GETFL);
++ if (flags == -1
++ || fcntl(ppp_dev_fd, F_SETFL, flags | O_NONBLOCK) == -1)
++ warn(&quot;Couldn't set /dev/ppp to nonblock: %m&quot;);
++ }
++
++ /* Get an internet socket for doing socket ioctls. */
++ sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
++ if (sock_fd &lt; 0)
++ fatal(&quot;Couldn't create IP socket: %m(%d)&quot;, errno);
++
++#ifdef INET6
++ sock6_fd = socket(AF_INET6, SOCK_DGRAM, 0);
++ if (sock6_fd &lt; 0)
++ sock6_fd = -errno; /* save errno for later */
++#endif
++
++ FD_ZERO(&amp;in_fds);
++ max_in_fd = 0;
++}
++
++/********************************************************************
++ *
++ * sys_cleanup - restore any system state we modified before exiting:
++ * mark the interface down, delete default route and/or proxy arp entry.
++ * This shouldn't call die() because it's called from die().
++ */
++
++void sys_cleanup(void)
++{
++/*
++ * Take down the device
++ */
++ if (if_is_up) {
++ if_is_up = 0;
++ sifdown(0);
++ }
++/*
++ * Delete any routes through the device.
++ */
++ if (default_route_gateway != 0)
++ cifdefaultroute(0, 0, default_route_gateway);
++
++ if (has_proxy_arp)
++ cifproxyarp(0, proxy_arp_addr);
++}
++
++/********************************************************************
++ *
++ * sys_close - Clean up in a child process before execing.
++ */
++void
++sys_close(void)
++{
++ if (new_style_driver)
++ close(ppp_dev_fd);
++ if (sock_fd &gt;= 0)
++ close(sock_fd);
++ if (slave_fd &gt;= 0)
++ close(slave_fd);
++ if (master_fd &gt;= 0)
++ close(master_fd);
++ closelog();
++}
++
++/********************************************************************
++ *
++ * set_kdebugflag - Define the debugging level for the kernel
++ */
++
++static int set_kdebugflag (int requested_level)
++{
++ if (new_style_driver &amp;&amp; ifunit &lt; 0)
++ return 1;
++ if (ioctl(ppp_dev_fd, PPPIOCSDEBUG, &amp;requested_level) &lt; 0) {
++ if ( ! ok_error (errno) )
++ error(&quot;ioctl(PPPIOCSDEBUG): %m&quot;);
++ return (0);
++ }
++ SYSDEBUG ((LOG_INFO, &quot;set kernel debugging level to %d&quot;,
++ requested_level));
++ return (1);
++}
++
++/********************************************************************
++ *
++ * tty_establish_ppp - Turn the serial port into a ppp interface.
++ */
++
++int tty_establish_ppp (int tty_fd)
++{
++ int x;
++ int fd = -1;
++
++/*
++ * Ensure that the tty device is in exclusive mode.
++ */
++ if (ioctl(tty_fd, TIOCEXCL, 0) &lt; 0) {
++ if ( ! ok_error ( errno ))
++ warn(&quot;Couldn't make tty exclusive: %m&quot;);
++ }
++/*
++ * Demand mode - prime the old ppp device to relinquish the unit.
++ */
++ if (!new_style_driver &amp;&amp; looped
++ &amp;&amp; ioctl(slave_fd, PPPIOCXFERUNIT, 0) &lt; 0) {
++ error(&quot;ioctl(transfer ppp unit): %m&quot;);
++ return -1;
++ }
++/*
++ * Set the current tty to the PPP discpline
++ */
++
++#ifndef N_SYNC_PPP
++#define N_SYNC_PPP 14
++#endif
++ ppp_disc = (new_style_driver &amp;&amp; sync_serial)? N_SYNC_PPP: N_PPP;
++ if (ioctl(tty_fd, TIOCSETD, &amp;ppp_disc) &lt; 0) {
++ if ( ! ok_error (errno) ) {
++ error(&quot;Couldn't set tty to PPP discipline: %m&quot;);
++ return -1;
++ }
++ }
++
++ if (new_style_driver) {
++ /* Open another instance of /dev/ppp and connect the channel to it */
++ int flags;
++
++ if (ioctl(tty_fd, PPPIOCGCHAN, &amp;chindex) == -1) {
++ error(&quot;Couldn't get channel number: %m&quot;);
++ goto err;
++ }
++ dbglog(&quot;using channel %d&quot;, chindex);
++ fd = open(&quot;/dev/ppp&quot;, O_RDWR);
++ if (fd &lt; 0) {
++ error(&quot;Couldn't reopen /dev/ppp: %m&quot;);
++ goto err;
++ }
++ if (ioctl(fd, PPPIOCATTCHAN, &amp;chindex) &lt; 0) {
++ error(&quot;Couldn't attach to channel %d: %m&quot;, chindex);
++ goto err_close;
++ }
++ flags = fcntl(fd, F_GETFL);
++ if (flags == -1 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
++ warn(&quot;Couldn't set /dev/ppp (channel) to nonblock: %m&quot;);
++ set_ppp_fd(fd);
++
++ if (!looped)
++ ifunit = -1;
++ if (!looped &amp;&amp; !multilink) {
++ /*
++ * Create a new PPP unit.
++ */
++ if (make_ppp_unit() &lt; 0)
++ goto err_close;
++ }
++
++ if (looped)
++ set_flags(ppp_dev_fd, get_flags(ppp_dev_fd) &amp; ~SC_LOOP_TRAFFIC);
++
++ if (!multilink) {
++ add_fd(ppp_dev_fd);
++ if (ioctl(fd, PPPIOCCONNECT, &amp;ifunit) &lt; 0) {
++ error(&quot;Couldn't attach to PPP unit %d: %m&quot;, ifunit);
++ goto err_close;
++ }
++ }
++
++ } else {
++ /*
++ * Old-style driver: find out which interface we were given.
++ */
++ set_ppp_fd (tty_fd);
++ if (ioctl(tty_fd, PPPIOCGUNIT, &amp;x) &lt; 0) {
++ if (ok_error (errno))
++ goto err;
++ fatal(&quot;ioctl(PPPIOCGUNIT): %m(%d)&quot;, errno);
++ }
++ /* Check that we got the same unit again. */
++ if (looped &amp;&amp; x != ifunit)
++ fatal(&quot;transfer_ppp failed: wanted unit %d, got %d&quot;, ifunit, x);
++ ifunit = x;
++
++ /*
++ * Fetch the initial file flags and reset blocking mode on the file.
++ */
++ initfdflags = fcntl(tty_fd, F_GETFL);
++ if (initfdflags == -1 ||
++ fcntl(tty_fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) {
++ if ( ! ok_error (errno))
++ warn(&quot;Couldn't set device to non-blocking mode: %m&quot;);
++ }
++ }
++
++ looped = 0;
++
++ /*
++ * Enable debug in the driver if requested.
++ */
++ if (!looped)
++ set_kdebugflag (kdebugflag);
++
++#define SC_RCVB (SC_RCV_B7_0 | SC_RCV_B7_1 | SC_RCV_EVNP | SC_RCV_ODDP)
++#define SC_LOGB (SC_DEBUG | SC_LOG_INPKT | SC_LOG_OUTPKT | SC_LOG_RAWIN \
++ | SC_LOG_FLUSH)
++
++ set_flags(ppp_fd, ((get_flags(ppp_fd) &amp; ~(SC_RCVB | SC_LOGB))
++ | ((kdebugflag * SC_DEBUG) &amp; SC_LOGB)));
++
++ SYSDEBUG ((LOG_NOTICE, &quot;Using version %d.%d.%d of PPP driver&quot;,
++ driver_version, driver_modification, driver_patch));
++
++ return ppp_fd;
++
++ err_close:
++ close(fd);
++ err:
++ if (ioctl(tty_fd, TIOCSETD, &amp;tty_disc) &lt; 0 &amp;&amp; !ok_error(errno))
++ warn(&quot;Couldn't reset tty to normal line discipline: %m&quot;);
++ return -1;
++}
++
++/********************************************************************
++ *
++ * tty_disestablish_ppp - Restore the serial port to normal operation,
++ * and reconnect the ppp unit to the loopback if in demand mode.
++ * This shouldn't call die() because it's called from die().
++ */
++
++void tty_disestablish_ppp(int tty_fd)
++{
++ if (demand)
++ restore_loop();
++ if (!hungup) {
++/*
++ * Flush the tty output buffer so that the TIOCSETD doesn't hang.
++ */
++ if (tcflush(tty_fd, TCIOFLUSH) &lt; 0)
++ warn(&quot;tcflush failed: %m&quot;);
++/*
++ * Restore the previous line discipline
++ */
++ if (ioctl(tty_fd, TIOCSETD, &amp;tty_disc) &lt; 0) {
++ if ( ! ok_error (errno))
++ error(&quot;ioctl(TIOCSETD, N_TTY): %m&quot;);
++ }
++
++ if (ioctl(tty_fd, TIOCNXCL, 0) &lt; 0) {
++ if ( ! ok_error (errno))
++ warn(&quot;ioctl(TIOCNXCL): %m(%d)&quot;, errno);
++ }
++
++ /* Reset non-blocking mode on fd. */
++ if (initfdflags != -1 &amp;&amp; fcntl(tty_fd, F_SETFL, initfdflags) &lt; 0) {
++ if ( ! ok_error (errno))
++ warn(&quot;Couldn't restore device fd flags: %m&quot;);
++ }
++ }
++ initfdflags = -1;
++
++ if (new_style_driver) {
++ close(ppp_fd);
++ ppp_fd = -1;
++ if (!looped &amp;&amp; ifunit &gt;= 0 &amp;&amp; ioctl(ppp_dev_fd, PPPIOCDETACH) &lt; 0)
++ error(&quot;Couldn't release PPP unit: %m&quot;);
++ if (!multilink)
++ remove_fd(ppp_dev_fd);
++ }
++}
++
++/*
++ * make_ppp_unit - make a new ppp unit for ppp_dev_fd.
++ * Assumes new_style_driver.
++ */
++static int make_ppp_unit()
++{
++ int x;
++
++ ifunit = req_unit;
++ x = ioctl(ppp_dev_fd, PPPIOCNEWUNIT, &amp;ifunit);
++ if (x &lt; 0 &amp;&amp; req_unit &gt;= 0 &amp;&amp; errno == EEXIST) {
++ warn(&quot;Couldn't allocate PPP unit %d as it is already in use&quot;);
++ ifunit = -1;
++ x = ioctl(ppp_dev_fd, PPPIOCNEWUNIT, &amp;ifunit);
++ }
++ if (x &lt; 0)
++ error(&quot;Couldn't create new ppp unit: %m&quot;);
++ return x;
++}
++
++/*
++ * cfg_bundle - configure the existing bundle.
++ * Used in demand mode.
++ */
++void cfg_bundle(int mrru, int mtru, int rssn, int tssn)
++{
++ int flags;
++
++ if (!new_style_driver)
++ return;
++
++ /* set the mrru, mtu and flags */
++ if (ioctl(ppp_dev_fd, PPPIOCSMRRU, &amp;mrru) &lt; 0)
++ error(&quot;Couldn't set MRRU: %m&quot;);
++ flags = get_flags(ppp_dev_fd);
++ flags &amp;= ~(SC_MP_SHORTSEQ | SC_MP_XSHORTSEQ);
++ flags |= (rssn? SC_MP_SHORTSEQ: 0) | (tssn? SC_MP_XSHORTSEQ: 0)
++ | (mrru? SC_MULTILINK: 0);
++
++ set_flags(ppp_dev_fd, flags);
++
++ /* connect up the channel */
++ if (ioctl(ppp_fd, PPPIOCCONNECT, &amp;ifunit) &lt; 0)
++ fatal(&quot;Couldn't attach to PPP unit %d: %m&quot;, ifunit);
++ add_fd(ppp_dev_fd);
++}
++
++/*
++ * make_new_bundle - create a new PPP unit (i.e. a bundle)
++ * and connect our channel to it. This should only get called
++ * if `multilink' was set at the time establish_ppp was called.
++ * In demand mode this uses our existing bundle instead of making
++ * a new one.
++ */
++void make_new_bundle(int mrru, int mtru, int rssn, int tssn)
++{
++ if (!new_style_driver)
++ return;
++
++ /* make us a ppp unit */
++ if (make_ppp_unit() &lt; 0)
++ die(1);
++
++ /* set the mrru and flags */
++ cfg_bundle(mrru, mtru, rssn, tssn);
++}
++
++/*
++ * bundle_attach - attach our link to a given PPP unit.
++ * We assume the unit is controlled by another pppd.
++ */
++int bundle_attach(int ifnum)
++{
++ if (!new_style_driver)
++ return -1;
++
++ if (ioctl(ppp_dev_fd, PPPIOCATTACH, &amp;ifnum) &lt; 0) {
++ if (errno == ENXIO)
++ return 0; /* doesn't still exist */
++ fatal(&quot;Couldn't attach to interface unit %d: %m\n&quot;, ifnum);
++ }
++ if (ioctl(ppp_fd, PPPIOCCONNECT, &amp;ifnum) &lt; 0)
++ fatal(&quot;Couldn't connect to interface unit %d: %m&quot;, ifnum);
++ set_flags(ppp_dev_fd, get_flags(ppp_dev_fd) | SC_MULTILINK);
++
++ ifunit = ifnum;
++ return 1;
++}
++
++/********************************************************************
++ *
++ * clean_check - Fetch the flags for the device and generate
++ * appropriate error messages.
++ */
++void clean_check(void)
++{
++ int x;
++ char *s;
++
++ if (still_ppp()) {
++ if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &amp;x) == 0) {
++ s = NULL;
++ switch (~x &amp; (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) {
++ case SC_RCV_B7_0:
++ s = &quot;all had bit 7 set to 1&quot;;
++ break;
++
++ case SC_RCV_B7_1:
++ s = &quot;all had bit 7 set to 0&quot;;
++ break;
++
++ case SC_RCV_EVNP:
++ s = &quot;all had odd parity&quot;;
++ break;
++
++ case SC_RCV_ODDP:
++ s = &quot;all had even parity&quot;;
++ break;
++ }
++
++ if (s != NULL) {
++ warn(&quot;Receive serial link is not 8-bit clean:&quot;);
++ warn(&quot;Problem: %s&quot;, s);
++ }
++ }
++ }
++}
++
++
++/*
++ * List of valid speeds.
++ */
++
++struct speed {
++ int speed_int, speed_val;
++} speeds[] = {
++#ifdef B50
++ { 50, B50 },
++#endif
++#ifdef B75
++ { 75, B75 },
++#endif
++#ifdef B110
++ { 110, B110 },
++#endif
++#ifdef B134
++ { 134, B134 },
++#endif
++#ifdef B150
++ { 150, B150 },
++#endif
++#ifdef B200
++ { 200, B200 },
++#endif
++#ifdef B300
++ { 300, B300 },
++#endif
++#ifdef B600
++ { 600, B600 },
++#endif
++#ifdef B1200
++ { 1200, B1200 },
++#endif
++#ifdef B1800
++ { 1800, B1800 },
++#endif
++#ifdef B2000
++ { 2000, B2000 },
++#endif
++#ifdef B2400
++ { 2400, B2400 },
++#endif
++#ifdef B3600
++ { 3600, B3600 },
++#endif
++#ifdef B4800
++ { 4800, B4800 },
++#endif
++#ifdef B7200
++ { 7200, B7200 },
++#endif
++#ifdef B9600
++ { 9600, B9600 },
++#endif
++#ifdef B19200
++ { 19200, B19200 },
++#endif
++#ifdef B38400
++ { 38400, B38400 },
++#endif
++#ifdef B57600
++ { 57600, B57600 },
++#endif
++#ifdef B76800
++ { 76800, B76800 },
++#endif
++#ifdef B115200
++ { 115200, B115200 },
++#endif
++#ifdef EXTA
++ { 19200, EXTA },
++#endif
++#ifdef EXTB
++ { 38400, EXTB },
++#endif
++#ifdef B230400
++ { 230400, B230400 },
++#endif
++#ifdef B460800
++ { 460800, B460800 },
++#endif
++#ifdef B921600
++ { 921600, B921600 },
++#endif
++ { 0, 0 }
++};
++
++/********************************************************************
++ *
++ * Translate from bits/second to a speed_t.
++ */
++
++static int translate_speed (int bps)
++{
++ struct speed *speedp;
++
++ if (bps != 0) {
++ for (speedp = speeds; speedp-&gt;speed_int; speedp++) {
++ if (bps == speedp-&gt;speed_int)
++ return speedp-&gt;speed_val;
++ }
++ warn(&quot;speed %d not supported&quot;, bps);
++ }
++ return 0;
++}
++
++/********************************************************************
++ *
++ * Translate from a speed_t to bits/second.
++ */
++
++static int baud_rate_of (int speed)
++{
++ struct speed *speedp;
++
++ if (speed != 0) {
++ for (speedp = speeds; speedp-&gt;speed_int; speedp++) {
++ if (speed == speedp-&gt;speed_val)
++ return speedp-&gt;speed_int;
++ }
++ }
++ return 0;
++}
++
++/********************************************************************
++ *
++ * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
++ * at the requested speed, etc. If `local' is true, set CLOCAL
++ * regardless of whether the modem option was specified.
++ */
++
++void set_up_tty(int tty_fd, int local)
++{
++ int speed;
++ struct termios tios;
++
++ setdtr(tty_fd, 1);
++ if (tcgetattr(tty_fd, &amp;tios) &lt; 0) {
++ if (!ok_error(errno))
++ fatal(&quot;tcgetattr: %m(%d)&quot;, errno);
++ return;
++ }
++
++ if (!restore_term)
++ inittermios = tios;
++
++ tios.c_cflag &amp;= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
++ tios.c_cflag |= CS8 | CREAD | HUPCL;
++
++ tios.c_iflag = IGNBRK | IGNPAR;
++ tios.c_oflag = 0;
++ tios.c_lflag = 0;
++ tios.c_cc[VMIN] = 1;
++ tios.c_cc[VTIME] = 0;
++
++ if (local || !modem)
++ tios.c_cflag ^= (CLOCAL | HUPCL);
++
++ switch (crtscts) {
++ case 1:
++ tios.c_cflag |= CRTSCTS;
++ break;
++
++ case -2:
++ tios.c_iflag |= IXON | IXOFF;
++ tios.c_cc[VSTOP] = 0x13; /* DC3 = XOFF = ^S */
++ tios.c_cc[VSTART] = 0x11; /* DC1 = XON = ^Q */
++ break;
++
++ case -1:
++ tios.c_cflag &amp;= ~CRTSCTS;
++ break;
++
++ default:
++ break;
++ }
++
++ speed = translate_speed(inspeed);
++ if (speed) {
++ cfsetospeed (&amp;tios, speed);
++ cfsetispeed (&amp;tios, speed);
++ }
++/*
++ * We can't proceed if the serial port speed is B0,
++ * since that implies that the serial port is disabled.
++ */
++ else {
++ speed = cfgetospeed(&amp;tios);
++ if (speed == B0)
++ fatal(&quot;Baud rate for %s is 0; need explicit baud rate&quot;, devnam);
++ }
++
++ if (tcsetattr(tty_fd, TCSAFLUSH, &amp;tios) &lt; 0)
++ if (!ok_error(errno))
++ fatal(&quot;tcsetattr: %m&quot;);
++
++ baud_rate = baud_rate_of(speed);
++ restore_term = 1;
++}
++
++/********************************************************************
++ *
++ * setdtr - control the DTR line on the serial port.
++ * This is called from die(), so it shouldn't call die().
++ */
++
++void setdtr (int tty_fd, int on)
++{
++ int modembits = TIOCM_DTR;
++
++ ioctl(tty_fd, (on ? TIOCMBIS : TIOCMBIC), &amp;modembits);
++}
++
++/********************************************************************
++ *
++ * restore_tty - restore the terminal to the saved settings.
++ */
++
++void restore_tty (int tty_fd)
++{
++ if (restore_term) {
++ restore_term = 0;
++/*
++ * Turn off echoing, because otherwise we can get into
++ * a loop with the tty and the modem echoing to each other.
++ * We presume we are the sole user of this tty device, so
++ * when we close it, it will revert to its defaults anyway.
++ */
++ if (!default_device)
++ inittermios.c_lflag &amp;= ~(ECHO | ECHONL);
++
++ if (tcsetattr(tty_fd, TCSAFLUSH, &amp;inittermios) &lt; 0) {
++ if (! ok_error (errno))
++ warn(&quot;tcsetattr: %m&quot;);
++ }
++ }
++}
++
++/********************************************************************
++ *
++ * output - Output PPP packet.
++ */
++
++void output (int unit, unsigned char *p, int len)
++{
++ int fd = ppp_fd;
++ int proto;
++
++ if (debug)
++ dbglog(&quot;sent %P&quot;, p, len);
++
++ if (len &lt; PPP_HDRLEN)
++ return;
++ if (new_style_driver) {
++ p += 2;
++ len -= 2;
++ proto = (p[0] &lt;&lt; 8) + p[1];
++ if (ifunit &gt;= 0 &amp;&amp; !(proto &gt;= 0xc000 || proto == PPP_CCPFRAG))
++ fd = ppp_dev_fd;
++ }
++ if (write(fd, p, len) &lt; 0) {
++ if (errno == EWOULDBLOCK || errno == ENOBUFS
++ || errno == ENXIO || errno == EIO || errno == EINTR)
++ warn(&quot;write: warning: %m (%d)&quot;, errno);
++ else
++ error(&quot;write: %m (%d)&quot;, errno);
++ }
++}
++
++/********************************************************************
++ *
++ * wait_input - wait until there is data available,
++ * for the length of time specified by *timo (indefinite
++ * if timo is NULL).
++ */
++
++void wait_input(struct timeval *timo)
++{
++ fd_set ready, exc;
++ int n;
++
++ ready = in_fds;
++ exc = in_fds;
++ n = select(max_in_fd + 1, &amp;ready, NULL, &amp;exc, timo);
++ if (n &lt; 0 &amp;&amp; errno != EINTR)
++ fatal(&quot;select: %m(%d)&quot;, errno);
++}
++
++/*
++ * add_fd - add an fd to the set that wait_input waits for.
++ */
++void add_fd(int fd)
++{
++ FD_SET(fd, &amp;in_fds);
++ if (fd &gt; max_in_fd)
++ max_in_fd = fd;
++}
++
++/*
++ * remove_fd - remove an fd from the set that wait_input waits for.
++ */
++void remove_fd(int fd)
++{
++ FD_CLR(fd, &amp;in_fds);
++}
++
++
++/********************************************************************
++ *
++ * read_packet - get a PPP packet from the serial device.
++ */
++
++int read_packet (unsigned char *buf)
++{
++ int len, nr;
++
++ len = PPP_MRU + PPP_HDRLEN;
++ if (new_style_driver) {
++ *buf++ = PPP_ALLSTATIONS;
++ *buf++ = PPP_UI;
++ len -= 2;
++ }
++ nr = -1;
++ if (ppp_fd &gt;= 0) {
++ nr = read(ppp_fd, buf, len);
++ if (nr &lt; 0 &amp;&amp; errno != EWOULDBLOCK &amp;&amp; errno != EIO &amp;&amp; errno != EINTR)
++ error(&quot;read: %m&quot;);
++ if (nr &lt; 0 &amp;&amp; errno == ENXIO)
++ return 0;
++ }
++ if (nr &lt; 0 &amp;&amp; new_style_driver &amp;&amp; ifunit &gt;= 0) {
++ /* N.B. we read ppp_fd first since LCP packets come in there. */
++ nr = read(ppp_dev_fd, buf, len);
++ if (nr &lt; 0 &amp;&amp; errno != EWOULDBLOCK &amp;&amp; errno != EIO &amp;&amp; errno != EINTR)
++ error(&quot;read /dev/ppp: %m&quot;);
++ if (nr &lt; 0 &amp;&amp; errno == ENXIO)
++ return 0;
++ }
++ return (new_style_driver &amp;&amp; nr &gt; 0)? nr+2: nr;
++}
++
++/********************************************************************
++ *
++ * get_loop_output - get outgoing packets from the ppp device,
++ * and detect when we want to bring the real link up.
++ * Return value is 1 if we need to bring up the link, 0 otherwise.
++ */
++int
++get_loop_output(void)
++{
++ int rv = 0;
++ int n;
++
++ if (new_style_driver) {
++ while ((n = read_packet(inpacket_buf)) &gt; 0)
++ if (loop_frame(inpacket_buf, n))
++ rv = 1;
++ return rv;
++ }
++
++ while ((n = read(master_fd, inbuf, sizeof(inbuf))) &gt; 0)
++ if (loop_chars(inbuf, n))
++ rv = 1;
++
++ if (n == 0)
++ fatal(&quot;eof on loopback&quot;);
++
++ if (errno != EWOULDBLOCK)
++ fatal(&quot;read from loopback: %m(%d)&quot;, errno);
++
++ return rv;
++}
++
++/*
++ * netif_set_mtu - set the MTU on the PPP network interface.
++ */
++void
++netif_set_mtu(int unit, int mtu)
++{
++ struct ifreq ifr;
++
++ SYSDEBUG ((LOG_DEBUG, &quot;netif_set_mtu: mtu = %d\n&quot;, mtu));
++
++ memset (&amp;ifr, '\0', sizeof (ifr));
++ strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
++ ifr.ifr_mtu = mtu;
++
++ if (ifunit &gt;= 0 &amp;&amp; ioctl(sock_fd, SIOCSIFMTU, (caddr_t) &amp;ifr) &lt; 0)
++ fatal(&quot;ioctl(SIOCSIFMTU): %m&quot;);
++}
++
++/********************************************************************
++ *
++ * tty_send_config - configure the transmit characteristics of
++ * the ppp interface.
++ */
++
++void tty_send_config (int mtu,u_int32_t asyncmap,int pcomp,int accomp)
++{
++ u_int x;
++
++/*
++ * Set the asyncmap and other parameters for the ppp device
++ */
++ if (!still_ppp())
++ return;
++ link_mtu = mtu;
++ SYSDEBUG ((LOG_DEBUG, &quot;send_config: asyncmap = %lx\n&quot;, asyncmap));
++ if (ioctl(ppp_fd, PPPIOCSASYNCMAP, (caddr_t) &amp;asyncmap) &lt; 0) {
++ if (!ok_error(errno))
++ fatal(&quot;ioctl(PPPIOCSASYNCMAP): %m(%d)&quot;, errno);
++ return;
++ }
++
++ x = get_flags(ppp_fd);
++ x = pcomp ? x | SC_COMP_PROT : x &amp; ~SC_COMP_PROT;
++ x = accomp ? x | SC_COMP_AC : x &amp; ~SC_COMP_AC;
++ x = sync_serial ? x | SC_SYNC : x &amp; ~SC_SYNC;
++ set_flags(ppp_fd, x);
++}
++
++/********************************************************************
++ *
++ * tty_set_xaccm - set the extended transmit ACCM for the interface.
++ */
++
++void tty_set_xaccm (ext_accm accm)
++{
++ SYSDEBUG ((LOG_DEBUG, &quot;set_xaccm: %08lx %08lx %08lx %08lx\n&quot;,
++ accm[0], accm[1], accm[2], accm[3]));
++
++ if (!still_ppp())
++ return;
++ if (ioctl(ppp_fd, PPPIOCSXASYNCMAP, accm) &lt; 0 &amp;&amp; errno != ENOTTY) {
++ if ( ! ok_error (errno))
++ warn(&quot;ioctl(set extended ACCM): %m(%d)&quot;, errno);
++ }
++}
++
++/********************************************************************
++ *
++ * tty_recv_config - configure the receive-side characteristics of
++ * the ppp interface.
++ */
++
++void tty_recv_config (int mru,u_int32_t asyncmap,int pcomp,int accomp)
++{
++ SYSDEBUG ((LOG_DEBUG, &quot;recv_config: mru = %d\n&quot;, mru));
++/*
++ * If we were called because the link has gone down then there is nothing
++ * which may be done. Just return without incident.
++ */
++ if (!still_ppp())
++ return;
++/*
++ * Set the receiver parameters
++ */
++ if (ioctl(ppp_fd, PPPIOCSMRU, (caddr_t) &amp;mru) &lt; 0) {
++ if ( ! ok_error (errno))
++ error(&quot;ioctl(PPPIOCSMRU): %m(%d)&quot;, errno);
++ }
++ if (new_style_driver &amp;&amp; ifunit &gt;= 0
++ &amp;&amp; ioctl(ppp_dev_fd, PPPIOCSMRU, (caddr_t) &amp;mru) &lt; 0)
++ error(&quot;Couldn't set MRU in generic PPP layer: %m&quot;);
++
++ SYSDEBUG ((LOG_DEBUG, &quot;recv_config: asyncmap = %lx\n&quot;, asyncmap));
++ if (ioctl(ppp_fd, PPPIOCSRASYNCMAP, (caddr_t) &amp;asyncmap) &lt; 0) {
++ if (!ok_error(errno))
++ error(&quot;ioctl(PPPIOCSRASYNCMAP): %m(%d)&quot;, errno);
++ }
++}
++
++/********************************************************************
++ *
++ * ccp_test - ask kernel whether a given compression method
++ * is acceptable for use.
++ */
++
++int ccp_test (int unit, u_char *opt_ptr, int opt_len, int for_transmit)
++{
++ struct ppp_option_data data;
++
++ memset (&amp;data, '\0', sizeof (data));
++ data.ptr = opt_ptr;
++ data.length = opt_len;
++ data.transmit = for_transmit;
++
++ if (ioctl(ppp_dev_fd, PPPIOCSCOMPRESS, (caddr_t) &amp;data) &gt;= 0)
++ return 1;
++
++ return (errno == ENOBUFS)? 0: -1;
++}
++
++/********************************************************************
++ *
++ * ccp_flags_set - inform kernel about the current state of CCP.
++ */
++
++void ccp_flags_set (int unit, int isopen, int isup)
++{
++ if (still_ppp()) {
++ int x = get_flags(ppp_dev_fd);
++ x = isopen? x | SC_CCP_OPEN : x &amp;~ SC_CCP_OPEN;
++ x = isup? x | SC_CCP_UP : x &amp;~ SC_CCP_UP;
++ set_flags (ppp_dev_fd, x);
++ }
++}
++
++#ifdef PPP_FILTER
++/*
++ * set_filters - set the active and pass filters in the kernel driver.
++ */
++int set_filters(struct bpf_program *pass, struct bpf_program *active)
++{
++ struct sock_fprog fp;
++
++ fp.len = pass-&gt;bf_len;
++ fp.filter = (struct sock_filter *) pass-&gt;bf_insns;
++ if (ioctl(ppp_dev_fd, PPPIOCSPASS, &amp;fp) &lt; 0) {
++ if (errno == ENOTTY)
++ warn(&quot;kernel does not support PPP filtering&quot;);
++ else
++ error(&quot;Couldn't set pass-filter in kernel: %m&quot;);
++ return 0;
++ }
++ fp.len = active-&gt;bf_len;
++ fp.filter = (struct sock_filter *) active-&gt;bf_insns;
++ if (ioctl(ppp_dev_fd, PPPIOCSACTIVE, &amp;fp) &lt; 0) {
++ error(&quot;Couldn't set active-filter in kernel: %m&quot;);
++ return 0;
++ }
++ return 1;
++}
++#endif /* PPP_FILTER */
++
++/********************************************************************
++ *
++ * get_idle_time - return how long the link has been idle.
++ */
++int
++get_idle_time(u, ip)
++ int u;
++ struct ppp_idle *ip;
++{
++ return ioctl(ppp_dev_fd, PPPIOCGIDLE, ip) &gt;= 0;
++}
++
++/********************************************************************
++ *
++ * get_ppp_stats - return statistics for the link.
++ */
++int
++get_ppp_stats(u, stats)
++ int u;
++ struct pppd_stats *stats;
++{
++ struct ifpppstatsreq req;
++
++ memset (&amp;req, 0, sizeof (req));
++
++ req.stats_ptr = (caddr_t) &amp;req.stats;
++ strlcpy(req.ifr__name, ifname, sizeof(req.ifr__name));
++ if (ioctl(sock_fd, SIOCGPPPSTATS, &amp;req) &lt; 0) {
++ error(&quot;Couldn't get PPP statistics: %m&quot;);
++ return 0;
++ }
++ stats-&gt;bytes_in = req.stats.p.ppp_ibytes;
++ stats-&gt;bytes_out = req.stats.p.ppp_obytes;
++ return 1;
++}
++
++/********************************************************************
++ *
++ * ccp_fatal_error - returns 1 if decompression was disabled as a
++ * result of an error detected after decompression of a packet,
++ * 0 otherwise. This is necessary because of patent nonsense.
++ */
++
++int ccp_fatal_error (int unit)
++{
++ int x = get_flags(ppp_dev_fd);
++
++ return x &amp; SC_DC_FERROR;
++}
++
++/********************************************************************
++ *
++ * path_to_procfs - find the path to the proc file system mount point
++ */
++static char proc_path[MAXPATHLEN];
++static int proc_path_len;
++
++static char *path_to_procfs(const char *tail)
++{
++ struct mntent *mntent;
++ FILE *fp;
++
++ if (proc_path_len == 0) {
++ /* Default the mount location of /proc */
++ strlcpy (proc_path, &quot;/proc&quot;, sizeof(proc_path));
++ proc_path_len = 5;
++ fp = fopen(MOUNTED, &quot;r&quot;);
++ if (fp != NULL) {
++ while ((mntent = getmntent(fp)) != NULL) {
++ if (strcmp(mntent-&gt;mnt_type, MNTTYPE_IGNORE) == 0)
++ continue;
++ if (strcmp(mntent-&gt;mnt_type, &quot;proc&quot;) == 0) {
++ strlcpy(proc_path, mntent-&gt;mnt_dir, sizeof(proc_path));
++ proc_path_len = strlen(proc_path);
++ break;
++ }
++ }
++ fclose (fp);
++ }
++ }
++
++ strlcpy(proc_path + proc_path_len, tail,
++ sizeof(proc_path) - proc_path_len);
++ return proc_path;
++}
++
++/*
++ * /proc/net/route parsing stuff.
++ */
++#define ROUTE_MAX_COLS 12
++FILE *route_fd = (FILE *) 0;
++static char route_buffer[512];
++static int route_dev_col, route_dest_col, route_gw_col;
++static int route_flags_col, route_mask_col;
++static int route_num_cols;
++
++static int open_route_table (void);
++static void close_route_table (void);
++static int read_route_table (struct rtentry *rt);
++
++/********************************************************************
++ *
++ * close_route_table - close the interface to the route table
++ */
++
++static void close_route_table (void)
++{
++ if (route_fd != (FILE *) 0) {
++ fclose (route_fd);
++ route_fd = (FILE *) 0;
++ }
++}
++
++/********************************************************************
++ *
++ * open_route_table - open the interface to the route table
++ */
++static char route_delims[] = &quot; \t\n&quot;;
++
++static int open_route_table (void)
++{
++ char *path;
++
++ close_route_table();
++
++ path = path_to_procfs(&quot;/net/route&quot;);
++ route_fd = fopen (path, &quot;r&quot;);
++ if (route_fd == NULL) {
++ error(&quot;can't open routing table %s: %m&quot;, path);
++ return 0;
++ }
++
++ route_dev_col = 0; /* default to usual columns */
++ route_dest_col = 1;
++ route_gw_col = 2;
++ route_flags_col = 3;
++ route_mask_col = 7;
++ route_num_cols = 8;
++
++ /* parse header line */
++ if (fgets(route_buffer, sizeof(route_buffer), route_fd) != 0) {
++ char *p = route_buffer, *q;
++ int col;
++ for (col = 0; col &lt; ROUTE_MAX_COLS; ++col) {
++ int used = 1;
++ if ((q = strtok(p, route_delims)) == 0)
++ break;
++ if (strcasecmp(q, &quot;iface&quot;) == 0)
++ route_dev_col = col;
++ else if (strcasecmp(q, &quot;destination&quot;) == 0)
++ route_dest_col = col;
++ else if (strcasecmp(q, &quot;gateway&quot;) == 0)
++ route_gw_col = col;
++ else if (strcasecmp(q, &quot;flags&quot;) == 0)
++ route_flags_col = col;
++ else if (strcasecmp(q, &quot;mask&quot;) == 0)
++ route_mask_col = col;
++ else
++ used = 0;
++ if (used &amp;&amp; col &gt;= route_num_cols)
++ route_num_cols = col + 1;
++ p = NULL;
++ }
++ }
++
++ return 1;
++}
++
++/********************************************************************
++ *
++ * read_route_table - read the next entry from the route table
++ */
++
++static int read_route_table(struct rtentry *rt)
++{
++ char *cols[ROUTE_MAX_COLS], *p;
++ int col;
++
++ memset (rt, '\0', sizeof (struct rtentry));
++
++ if (fgets (route_buffer, sizeof (route_buffer), route_fd) == (char *) 0)
++ return 0;
++
++ p = route_buffer;
++ for (col = 0; col &lt; route_num_cols; ++col) {
++ cols[col] = strtok(p, route_delims);
++ if (cols[col] == NULL)
++ return 0; /* didn't get enough columns */
++ p = NULL;
++ }
++
++ SIN_ADDR(rt-&gt;rt_dst) = strtoul(cols[route_dest_col], NULL, 16);
++ SIN_ADDR(rt-&gt;rt_gateway) = strtoul(cols[route_gw_col], NULL, 16);
++ SIN_ADDR(rt-&gt;rt_genmask) = strtoul(cols[route_mask_col], NULL, 16);
++
++ rt-&gt;rt_flags = (short) strtoul(cols[route_flags_col], NULL, 16);
++ rt-&gt;rt_dev = cols[route_dev_col];
++
++ return 1;
++}
++
++/********************************************************************
++ *
++ * defaultroute_exists - determine if there is a default route
++ */
++
++static int defaultroute_exists (struct rtentry *rt)
++{
++ int result = 0;
++
++ if (!open_route_table())
++ return 0;
++
++ while (read_route_table(rt) != 0) {
++ if ((rt-&gt;rt_flags &amp; RTF_UP) == 0)
++ continue;
++
++ if (kernel_version &gt; KVERSION(2,1,0) &amp;&amp; SIN_ADDR(rt-&gt;rt_genmask) != 0)
++ continue;
++ if (SIN_ADDR(rt-&gt;rt_dst) == 0L) {
++ result = 1;
++ break;
++ }
++ }
++
++ close_route_table();
++ return result;
++}
++
++/*
++ * have_route_to - determine if the system has any route to
++ * a given IP address. `addr' is in network byte order.
++ * Return value is 1 if yes, 0 if no, -1 if don't know.
++ * For demand mode to work properly, we have to ignore routes
++ * through our own interface.
++ */
++int have_route_to(u_int32_t addr)
++{
++ struct rtentry rt;
++ int result = 0;
++
++ if (!open_route_table())
++ return -1; /* don't know */
++
++ while (read_route_table(&amp;rt)) {
++ if ((rt.rt_flags &amp; RTF_UP) == 0 || strcmp(rt.rt_dev, ifname) == 0)
++ continue;
++ if ((addr &amp; SIN_ADDR(rt.rt_genmask)) == SIN_ADDR(rt.rt_dst)) {
++ result = 1;
++ break;
++ }
++ }
++
++ close_route_table();
++ return result;
++}
++
++/********************************************************************
++ *
++ * sifdefaultroute - assign a default route through the address given.
++ */
++
++int sifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway)
++{
++ struct rtentry rt;
++
++ if (defaultroute_exists(&amp;rt) &amp;&amp; strcmp(rt.rt_dev, ifname) != 0) {
++ u_int32_t old_gateway = SIN_ADDR(rt.rt_gateway);
++
++ if (old_gateway != gateway)
++ error(&quot;not replacing existing default route to %s [%I]&quot;,
++ rt.rt_dev, old_gateway);
++ return 0;
++ }
++
++ memset (&amp;rt, '\0', sizeof (rt));
++ SET_SA_FAMILY (rt.rt_dst, AF_INET);
++ SET_SA_FAMILY (rt.rt_gateway, AF_INET);
++
++ if (kernel_version &gt; KVERSION(2,1,0)) {
++ SET_SA_FAMILY (rt.rt_genmask, AF_INET);
++ SIN_ADDR(rt.rt_genmask) = 0L;
++ }
++
++ SIN_ADDR(rt.rt_gateway) = gateway;
++
++ rt.rt_flags = RTF_UP | RTF_GATEWAY;
++ if (ioctl(sock_fd, SIOCADDRT, &amp;rt) &lt; 0) {
++ if ( ! ok_error ( errno ))
++ error(&quot;default route ioctl(SIOCADDRT): %m(%d)&quot;, errno);
++ return 0;
++ }
++
++ default_route_gateway = gateway;
++ return 1;
++}
++
++/********************************************************************
++ *
++ * cifdefaultroute - delete a default route through the address given.
++ */
++
++int cifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway)
++{
++ struct rtentry rt;
++
++ default_route_gateway = 0;
++
++ memset (&amp;rt, '\0', sizeof (rt));
++ SET_SA_FAMILY (rt.rt_dst, AF_INET);
++ SET_SA_FAMILY (rt.rt_gateway, AF_INET);
++
++ if (kernel_version &gt; KVERSION(2,1,0)) {
++ SET_SA_FAMILY (rt.rt_genmask, AF_INET);
++ SIN_ADDR(rt.rt_genmask) = 0L;
++ }
++
++ SIN_ADDR(rt.rt_gateway) = gateway;
++
++ rt.rt_flags = RTF_UP | RTF_GATEWAY;
++ if (ioctl(sock_fd, SIOCDELRT, &amp;rt) &lt; 0 &amp;&amp; errno != ESRCH) {
++ if (still_ppp()) {
++ if ( ! ok_error ( errno ))
++ error(&quot;default route ioctl(SIOCDELRT): %m (%d)&quot;, errno);
++ return 0;
++ }
++ }
++
++ return 1;
++}
++
++/********************************************************************
++ *
++ * sifproxyarp - Make a proxy ARP entry for the peer.
++ */
++
++int sifproxyarp (int unit, u_int32_t his_adr)
++{
++ struct arpreq arpreq;
++ char *forw_path;
++
++ if (has_proxy_arp == 0) {
++ memset (&amp;arpreq, '\0', sizeof(arpreq));
++
++ SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
++ SIN_ADDR(arpreq.arp_pa) = his_adr;
++ arpreq.arp_flags = ATF_PERM | ATF_PUBL;
++/*
++ * Get the hardware address of an interface on the same subnet
++ * as our local address.
++ */
++ if (!get_ether_addr(his_adr, &amp;arpreq.arp_ha, proxy_arp_dev,
++ sizeof(proxy_arp_dev))) {
++ error(&quot;Cannot determine ethernet address for proxy ARP&quot;);
++ return 0;
++ }
++ strlcpy(arpreq.arp_dev, proxy_arp_dev, sizeof(arpreq.arp_dev));
++
++ if (ioctl(sock_fd, SIOCSARP, (caddr_t)&amp;arpreq) &lt; 0) {
++ if ( ! ok_error ( errno ))
++ error(&quot;ioctl(SIOCSARP): %m(%d)&quot;, errno);
++ return 0;
++ }
++ proxy_arp_addr = his_adr;
++ has_proxy_arp = 1;
++
++ if (tune_kernel) {
++ forw_path = path_to_procfs(&quot;/sys/net/ipv4/ip_forward&quot;);
++ if (forw_path != 0) {
++ int fd = open(forw_path, O_WRONLY);
++ if (fd &gt;= 0) {
++ if (write(fd, &quot;1&quot;, 1) != 1)
++ error(&quot;Couldn't enable IP forwarding: %m&quot;);
++ close(fd);
++ }
++ }
++ }
++ }
++
++ return 1;
++}
++
++/********************************************************************
++ *
++ * cifproxyarp - Delete the proxy ARP entry for the peer.
++ */
++
++int cifproxyarp (int unit, u_int32_t his_adr)
++{
++ struct arpreq arpreq;
++
++ if (has_proxy_arp) {
++ has_proxy_arp = 0;
++ memset (&amp;arpreq, '\0', sizeof(arpreq));
++ SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
++ SIN_ADDR(arpreq.arp_pa) = his_adr;
++ arpreq.arp_flags = ATF_PERM | ATF_PUBL;
++ strlcpy(arpreq.arp_dev, proxy_arp_dev, sizeof(arpreq.arp_dev));
++
++ if (ioctl(sock_fd, SIOCDARP, (caddr_t)&amp;arpreq) &lt; 0) {
++ if ( ! ok_error ( errno ))
++ warn(&quot;ioctl(SIOCDARP): %m(%d)&quot;, errno);
++ return 0;
++ }
++ }
++ return 1;
++}
++
++/********************************************************************
++ *
++ * get_ether_addr - get the hardware address of an interface on the
++ * the same subnet as ipaddr.
++ */
++
++static int get_ether_addr (u_int32_t ipaddr,
++ struct sockaddr *hwaddr,
++ char *name, int namelen)
++{
++ struct ifreq *ifr, *ifend;
++ u_int32_t ina, mask;
++ char *aliasp;
++ struct ifreq ifreq;
++ struct ifconf ifc;
++ struct ifreq ifs[MAX_IFS];
++
++ ifc.ifc_len = sizeof(ifs);
++ ifc.ifc_req = ifs;
++ if (ioctl(sock_fd, SIOCGIFCONF, &amp;ifc) &lt; 0) {
++ if ( ! ok_error ( errno ))
++ error(&quot;ioctl(SIOCGIFCONF): %m(%d)&quot;, errno);
++ return 0;
++ }
++
++ SYSDEBUG ((LOG_DEBUG, &quot;proxy arp: scanning %d interfaces for IP %s&quot;,
++ ifc.ifc_len / sizeof(struct ifreq), ip_ntoa(ipaddr)));
++/*
++ * Scan through looking for an interface with an Internet
++ * address on the same subnet as `ipaddr'.
++ */
++ ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq));
++ for (ifr = ifc.ifc_req; ifr &lt; ifend; ifr++) {
++ if (ifr-&gt;ifr_addr.sa_family == AF_INET) {
++ ina = SIN_ADDR(ifr-&gt;ifr_addr);
++ strlcpy(ifreq.ifr_name, ifr-&gt;ifr_name, sizeof(ifreq.ifr_name));
++ SYSDEBUG ((LOG_DEBUG, &quot;proxy arp: examining interface %s&quot;,
++ ifreq.ifr_name));
++/*
++ * Check that the interface is up, and not point-to-point
++ * nor loopback.
++ */
++ if (ioctl(sock_fd, SIOCGIFFLAGS, &amp;ifreq) &lt; 0)
++ continue;
++
++ if (((ifreq.ifr_flags ^ FLAGS_GOOD) &amp; FLAGS_MASK) != 0)
++ continue;
++/*
++ * Get its netmask and check that it's on the right subnet.
++ */
++ if (ioctl(sock_fd, SIOCGIFNETMASK, &amp;ifreq) &lt; 0)
++ continue;
++
++ mask = SIN_ADDR(ifreq.ifr_addr);
++ SYSDEBUG ((LOG_DEBUG, &quot;proxy arp: interface addr %s mask %lx&quot;,
++ ip_ntoa(ina), ntohl(mask)));
++
++ if (((ipaddr ^ ina) &amp; mask) != 0)
++ continue;
++ break;
++ }
++ }
++
++ if (ifr &gt;= ifend)
++ return 0;
++
++ strlcpy(name, ifreq.ifr_name, namelen);
++
++ /* trim off the :1 in eth0:1 */
++ aliasp = strchr(name, ':');
++ if (aliasp != 0)
++ *aliasp = 0;
++
++ info(&quot;found interface %s for proxy arp&quot;, name);
++/*
++ * Now get the hardware address.
++ */
++ memset (&amp;ifreq.ifr_hwaddr, 0, sizeof (struct sockaddr));
++ if (ioctl (sock_fd, SIOCGIFHWADDR, &amp;ifreq) &lt; 0) {
++ error(&quot;SIOCGIFHWADDR(%s): %m(%d)&quot;, ifreq.ifr_name, errno);
++ return 0;
++ }
++
++ memcpy (hwaddr,
++ &amp;ifreq.ifr_hwaddr,
++ sizeof (struct sockaddr));
++
++ SYSDEBUG ((LOG_DEBUG,
++ &quot;proxy arp: found hwaddr %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x&quot;,
++ (int) ((unsigned char *) &amp;hwaddr-&gt;sa_data)[0],
++ (int) ((unsigned char *) &amp;hwaddr-&gt;sa_data)[1],
++ (int) ((unsigned char *) &amp;hwaddr-&gt;sa_data)[2],
++ (int) ((unsigned char *) &amp;hwaddr-&gt;sa_data)[3],
++ (int) ((unsigned char *) &amp;hwaddr-&gt;sa_data)[4],
++ (int) ((unsigned char *) &amp;hwaddr-&gt;sa_data)[5],
++ (int) ((unsigned char *) &amp;hwaddr-&gt;sa_data)[6],
++ (int) ((unsigned char *) &amp;hwaddr-&gt;sa_data)[7]));
++ return 1;
++}
++
++/*
++ * get_if_hwaddr - get the hardware address for the specified
++ * network interface device.
++ */
++int
++get_if_hwaddr(u_char *addr, char *name)
++{
++ struct ifreq ifreq;
++ int ret, sock_fd;
++
++ sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
++ if (sock_fd &lt; 0)
++ return 0;
++ memset(&amp;ifreq.ifr_hwaddr, 0, sizeof(struct sockaddr));
++ strlcpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));
++ ret = ioctl(sock_fd, SIOCGIFHWADDR, &amp;ifreq);
++ close(sock_fd);
++ if (ret &gt;= 0)
++ memcpy(addr, ifreq.ifr_hwaddr.sa_data, 6);
++ return ret;
++}
++
++/*
++ * get_first_ethernet - return the name of the first ethernet-style
++ * interface on this system.
++ */
++char *
++get_first_ethernet()
++{
++ return &quot;eth0&quot;;
++}
++
++/********************************************************************
++ *
++ * Return user specified netmask, modified by any mask we might determine
++ * for address `addr' (in network byte order).
++ * Here we scan through the system's list of interfaces, looking for
++ * any non-point-to-point interfaces which might appear to be on the same
++ * network as `addr'. If we find any, we OR in their netmask to the
++ * user-specified netmask.
++ */
++
++u_int32_t GetMask (u_int32_t addr)
++{
++ u_int32_t mask, nmask, ina;
++ struct ifreq *ifr, *ifend, ifreq;
++ struct ifconf ifc;
++ struct ifreq ifs[MAX_IFS];
++
++ addr = ntohl(addr);
++
++ if (IN_CLASSA(addr)) /* determine network mask for address class */
++ nmask = IN_CLASSA_NET;
++ else if (IN_CLASSB(addr))
++ nmask = IN_CLASSB_NET;
++ else
++ nmask = IN_CLASSC_NET;
++
++ /* class D nets are disallowed by bad_ip_adrs */
++ mask = netmask | htonl(nmask);
++/*
++ * Scan through the system's network interfaces.
++ */
++ ifc.ifc_len = sizeof(ifs);
++ ifc.ifc_req = ifs;
++ if (ioctl(sock_fd, SIOCGIFCONF, &amp;ifc) &lt; 0) {
++ if ( ! ok_error ( errno ))
++ warn(&quot;ioctl(SIOCGIFCONF): %m(%d)&quot;, errno);
++ return mask;
++ }
++
++ ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
++ for (ifr = ifc.ifc_req; ifr &lt; ifend; ifr++) {
++/*
++ * Check the interface's internet address.
++ */
++ if (ifr-&gt;ifr_addr.sa_family != AF_INET)
++ continue;
++ ina = SIN_ADDR(ifr-&gt;ifr_addr);
++ if (((ntohl(ina) ^ addr) &amp; nmask) != 0)
++ continue;
++/*
++ * Check that the interface is up, and not point-to-point nor loopback.
++ */
++ strlcpy(ifreq.ifr_name, ifr-&gt;ifr_name, sizeof(ifreq.ifr_name));
++ if (ioctl(sock_fd, SIOCGIFFLAGS, &amp;ifreq) &lt; 0)
++ continue;
++
++ if (((ifreq.ifr_flags ^ FLAGS_GOOD) &amp; FLAGS_MASK) != 0)
++ continue;
++/*
++ * Get its netmask and OR it into our mask.
++ */
++ if (ioctl(sock_fd, SIOCGIFNETMASK, &amp;ifreq) &lt; 0)
++ continue;
++ mask |= SIN_ADDR(ifreq.ifr_addr);
++ break;
++ }
++ return mask;
++}
++
++/********************************************************************
++ *
++ * Internal routine to decode the version.modification.patch level
++ */
++
++static void decode_version (char *buf, int *version,
++ int *modification, int *patch)
++{
++ char *endp;
++
++ *version = (int) strtoul (buf, &amp;endp, 10);
++ *modification = 0;
++ *patch = 0;
++
++ if (endp != buf &amp;&amp; *endp == '.') {
++ buf = endp + 1;
++ *modification = (int) strtoul (buf, &amp;endp, 10);
++ if (endp != buf &amp;&amp; *endp == '.') {
++ buf = endp + 1;
++ *patch = (int) strtoul (buf, &amp;buf, 10);
++ }
++ }
++}
++
++/********************************************************************
++ *
++ * Procedure to determine if the PPP line discipline is registered.
++ */
++
++static int
++ppp_registered(void)
++{
++ int local_fd;
++ int mfd = -1;
++ int ret = 0;
++ char slave[16];
++
++ /*
++ * We used to open the serial device and set it to the ppp line
++ * discipline here, in order to create a ppp unit. But that is
++ * not a good idea - the user might have specified a device that
++ * they can't open (permission, or maybe it doesn't really exist).
++ * So we grab a pty master/slave pair and use that.
++ */
++ if (!get_pty(&amp;mfd, &amp;local_fd, slave, 0)) {
++ no_ppp_msg = &quot;Couldn't determine if PPP is supported (no free ptys)&quot;;
++ return 0;
++ }
++
++ /*
++ * Try to put the device into the PPP discipline.
++ */
++ if (ioctl(local_fd, TIOCSETD, &amp;ppp_disc) &lt; 0) {
++ error(&quot;ioctl(TIOCSETD(PPP)): %m(%d)&quot;, errno);
++ } else
++ ret = 1;
++
++ close(local_fd);
++ close(mfd);
++ return ret;
++}
++
++/********************************************************************
++ *
++ * ppp_available - check whether the system has any ppp interfaces
++ * (in fact we check whether we can do an ioctl on ppp0).
++ */
++
++int ppp_available(void)
++{
++ int s, ok, fd;
++ struct ifreq ifr;
++ int size;
++ int my_version, my_modification, my_patch;
++ int osmaj, osmin, ospatch;
++
++ no_ppp_msg =
++ &quot;This system lacks kernel support for PPP. This could be because\n&quot;
++ &quot;the PPP kernel module could not be loaded, or because PPP was not\n&quot;
++ &quot;included in the kernel configuration. If PPP was included as a\n&quot;
++ &quot;module, try `/sbin/modprobe -v ppp'. If that fails, check that\n&quot;
++ &quot;ppp.o exists in /lib/modules/`uname -r`/net.\n&quot;
++ &quot;See README.linux file in the ppp distribution for more details.\n&quot;;
++
++ /* get the kernel version now, since we are called before sys_init */
++ uname(&amp;utsname);
++ osmaj = osmin = ospatch = 0;
++ sscanf(utsname.release, &quot;%d.%d.%d&quot;, &amp;osmaj, &amp;osmin, &amp;ospatch);
++ kernel_version = KVERSION(osmaj, osmin, ospatch);
++
++ fd = open(&quot;/dev/ppp&quot;, O_RDWR);
++#if 0
++ if (fd &lt; 0 &amp;&amp; errno == ENOENT) {
++ /* try making it and see if that helps. */
++ if (mknod(&quot;/dev/ppp&quot;, S_IFCHR | S_IRUSR | S_IWUSR,
++ makedev(108, 0)) &gt;= 0) {
++ fd = open(&quot;/dev/ppp&quot;, O_RDWR);
++ if (fd &gt;= 0)
++ info(&quot;Created /dev/ppp device node&quot;);
++ else
++ unlink(&quot;/dev/ppp&quot;); /* didn't work, undo the mknod */
++ } else if (errno == EEXIST) {
++ fd = open(&quot;/dev/ppp&quot;, O_RDWR);
++ }
++ }
++#endif /* 0 */
++ if (fd &gt;= 0) {
++ new_style_driver = 1;
++
++ /* XXX should get from driver */
++ driver_version = 2;
++ driver_modification = 4;
++ driver_patch = 0;
++ close(fd);
++ return 1;
++ }
++ if (kernel_version &gt;= KVERSION(2,3,13)) {
++ if (errno == ENOENT)
++ no_ppp_msg =
++ &quot;pppd is unable to open the /dev/ppp device.\n&quot;
++ &quot;You need to create the /dev/ppp device node by\n&quot;
++ &quot;executing the following command as root:\n&quot;
++ &quot; mknod /dev/ppp c 108 0\n&quot;;
++ return 0;
++ }
++
++/*
++ * Open a socket for doing the ioctl operations.
++ */
++ s = socket(AF_INET, SOCK_DGRAM, 0);
++ if (s &lt; 0)
++ return 0;
++
++ strlcpy (ifr.ifr_name, &quot;ppp0&quot;, sizeof (ifr.ifr_name));
++ ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &amp;ifr) &gt;= 0;
++/*
++ * If the device did not exist then attempt to create one by putting the
++ * current tty into the PPP discipline. If this works then obtain the
++ * flags for the device again.
++ */
++ if (!ok) {
++ if (ppp_registered()) {
++ strlcpy (ifr.ifr_name, &quot;ppp0&quot;, sizeof (ifr.ifr_name));
++ ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &amp;ifr) &gt;= 0;
++ }
++ }
++/*
++ * Ensure that the hardware address is for PPP and not something else
++ */
++ if (ok)
++ ok = ioctl (s, SIOCGIFHWADDR, (caddr_t) &amp;ifr) &gt;= 0;
++
++ if (ok &amp;&amp; ((ifr.ifr_hwaddr.sa_family &amp; ~0xFF) != ARPHRD_PPP))
++ ok = 0;
++
++/*
++ * This is the PPP device. Validate the version of the driver at this
++ * point to ensure that this program will work with the driver.
++ */
++ if (ok) {
++ char abBuffer [1024];
++
++ ifr.ifr_data = abBuffer;
++ size = ioctl (s, SIOCGPPPVER, (caddr_t) &amp;ifr);
++ if (size &lt; 0) {
++ error(&quot;Couldn't read driver version: %m&quot;);
++ ok = 0;
++ no_ppp_msg = &quot;Sorry, couldn't verify kernel driver version\n&quot;;
++
++ } else {
++ decode_version(abBuffer,
++ &amp;driver_version,
++ &amp;driver_modification,
++ &amp;driver_patch);
++/*
++ * Validate the version of the driver against the version that we used.
++ */
++ decode_version(VERSION,
++ &amp;my_version,
++ &amp;my_modification,
++ &amp;my_patch);
++
++ /* The version numbers must match */
++ if (driver_version != my_version)
++ ok = 0;
++
++ /* The modification levels must be legal */
++ if (driver_modification &lt; 3) {
++ if (driver_modification &gt;= 2) {
++ /* we can cope with 2.2.0 and above */
++ driver_is_old = 1;
++ } else {
++ ok = 0;
++ }
++ }
++
++ close (s);
++ if (!ok) {
++ slprintf(route_buffer, sizeof(route_buffer),
++ &quot;Sorry - PPP driver version %d.%d.%d is out of date\n&quot;,
++ driver_version, driver_modification, driver_patch);
++
++ no_ppp_msg = route_buffer;
++ }
++ }
++ }
++ return ok;
++}
++
++/********************************************************************
++ *
++ * sifvjcomp - config tcp header compression
++ */
++
++int sifvjcomp (int u, int vjcomp, int cidcomp, int maxcid)
++{
++ u_int x = get_flags(ppp_dev_fd);
++
++ if (vjcomp) {
++ if (ioctl (ppp_dev_fd, PPPIOCSMAXCID, (caddr_t) &amp;maxcid) &lt; 0) {
++ if (! ok_error (errno))
++ error(&quot;ioctl(PPPIOCSMAXCID): %m(%d)&quot;, errno);
++ vjcomp = 0;
++ }
++ }
++
++ x = vjcomp ? x | SC_COMP_TCP : x &amp;~ SC_COMP_TCP;
++ x = cidcomp ? x &amp; ~SC_NO_TCP_CCID : x | SC_NO_TCP_CCID;
++ set_flags (ppp_dev_fd, x);
++
++ return 1;
++}
++
++/********************************************************************
++ *
++ * sifup - Config the interface up and enable IP packets to pass.
++ */
++
++int sifup(int u)
++{
++ struct ifreq ifr;
++
++ memset (&amp;ifr, '\0', sizeof (ifr));
++ strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
++ if (ioctl(sock_fd, SIOCGIFFLAGS, (caddr_t) &amp;ifr) &lt; 0) {
++ if (! ok_error (errno))
++ error(&quot;ioctl (SIOCGIFFLAGS): %m(%d)&quot;, errno);
++ return 0;
++ }
++
++ ifr.ifr_flags |= (IFF_UP | IFF_POINTOPOINT);
++ if (ioctl(sock_fd, SIOCSIFFLAGS, (caddr_t) &amp;ifr) &lt; 0) {
++ if (! ok_error (errno))
++ error(&quot;ioctl(SIOCSIFFLAGS): %m(%d)&quot;, errno);
++ return 0;
++ }
++ if_is_up++;
++
++ return 1;
++}
++
++/********************************************************************
++ *
++ * sifdown - Disable the indicated protocol and config the interface
++ * down if there are no remaining protocols.
++ */
++
++int sifdown (int u)
++{
++ struct ifreq ifr;
++
++ if (if_is_up &amp;&amp; --if_is_up &gt; 0)
++ return 1;
++
++ memset (&amp;ifr, '\0', sizeof (ifr));
++ strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
++ if (ioctl(sock_fd, SIOCGIFFLAGS, (caddr_t) &amp;ifr) &lt; 0) {
++ if (! ok_error (errno))
++ error(&quot;ioctl (SIOCGIFFLAGS): %m(%d)&quot;, errno);
++ return 0;
++ }
++
++ ifr.ifr_flags &amp;= ~IFF_UP;
++ ifr.ifr_flags |= IFF_POINTOPOINT;
++ if (ioctl(sock_fd, SIOCSIFFLAGS, (caddr_t) &amp;ifr) &lt; 0) {
++ if (! ok_error (errno))
++ error(&quot;ioctl(SIOCSIFFLAGS): %m(%d)&quot;, errno);
++ return 0;
++ }
++ return 1;
++}
++
++/********************************************************************
++ *
++ * sifaddr - Config the interface IP addresses and netmask.
++ */
++
++int sifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr,
++ u_int32_t net_mask)
++{
++ struct ifreq ifr;
++ struct rtentry rt;
++
++ memset (&amp;ifr, '\0', sizeof (ifr));
++ memset (&amp;rt, '\0', sizeof (rt));
++
++ SET_SA_FAMILY (ifr.ifr_addr, AF_INET);
++ SET_SA_FAMILY (ifr.ifr_dstaddr, AF_INET);
++ SET_SA_FAMILY (ifr.ifr_netmask, AF_INET);
++
++ strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
++/*
++ * Set our IP address
++ */
++ SIN_ADDR(ifr.ifr_addr) = our_adr;
++ if (ioctl(sock_fd, SIOCSIFADDR, (caddr_t) &amp;ifr) &lt; 0) {
++ if (errno != EEXIST) {
++ if (! ok_error (errno))
++ error(&quot;ioctl(SIOCSIFADDR): %m(%d)&quot;, errno);
++ }
++ else {
++ warn(&quot;ioctl(SIOCSIFADDR): Address already exists&quot;);
++ }
++ return (0);
++ }
++/*
++ * Set the gateway address
++ */
++ SIN_ADDR(ifr.ifr_dstaddr) = his_adr;
++ if (ioctl(sock_fd, SIOCSIFDSTADDR, (caddr_t) &amp;ifr) &lt; 0) {
++ if (! ok_error (errno))
++ error(&quot;ioctl(SIOCSIFDSTADDR): %m(%d)&quot;, errno);
++ return (0);
++ }
++/*
++ * Set the netmask.
++ * For recent kernels, force the netmask to 255.255.255.255.
++ */
++ if (kernel_version &gt;= KVERSION(2,1,16))
++ net_mask = ~0L;
++ if (net_mask != 0) {
++ SIN_ADDR(ifr.ifr_netmask) = net_mask;
++ if (ioctl(sock_fd, SIOCSIFNETMASK, (caddr_t) &amp;ifr) &lt; 0) {
++ if (! ok_error (errno))
++ error(&quot;ioctl(SIOCSIFNETMASK): %m(%d)&quot;, errno);
++ return (0);
++ }
++ }
++/*
++ * Add the device route
++ */
++ if (kernel_version &lt; KVERSION(2,1,16)) {
++ SET_SA_FAMILY (rt.rt_dst, AF_INET);
++ SET_SA_FAMILY (rt.rt_gateway, AF_INET);
++ rt.rt_dev = ifname;
++
++ SIN_ADDR(rt.rt_gateway) = 0L;
++ SIN_ADDR(rt.rt_dst) = his_adr;
++ rt.rt_flags = RTF_UP | RTF_HOST;
++
++ if (kernel_version &gt; KVERSION(2,1,0)) {
++ SET_SA_FAMILY (rt.rt_genmask, AF_INET);
++ SIN_ADDR(rt.rt_genmask) = -1L;
++ }
++
++ if (ioctl(sock_fd, SIOCADDRT, &amp;rt) &lt; 0) {
++ if (! ok_error (errno))
++ error(&quot;ioctl(SIOCADDRT) device route: %m(%d)&quot;, errno);
++ return (0);
++ }
++ }
++
++ /* set ip_dynaddr in demand mode if address changes */
++ if (demand &amp;&amp; tune_kernel &amp;&amp; !dynaddr_set
++ &amp;&amp; our_old_addr &amp;&amp; our_old_addr != our_adr) {
++ /* set ip_dynaddr if possible */
++ char *path;
++ int fd;
++
++ path = path_to_procfs(&quot;/sys/net/ipv4/ip_dynaddr&quot;);
++ if (path != 0 &amp;&amp; (fd = open(path, O_WRONLY)) &gt;= 0) {
++ if (write(fd, &quot;1&quot;, 1) != 1)
++ error(&quot;Couldn't enable dynamic IP addressing: %m&quot;);
++ close(fd);
++ }
++ dynaddr_set = 1; /* only 1 attempt */
++ }
++ our_old_addr = 0;
++
++ return 1;
++}
++
++/********************************************************************
++ *
++ * cifaddr - Clear the interface IP addresses, and delete routes
++ * through the interface if possible.
++ */
++
++int cifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr)
++{
++ struct ifreq ifr;
++
++ if (kernel_version &lt; KVERSION(2,1,16)) {
++/*
++ * Delete the route through the device
++ */
++ struct rtentry rt;
++ memset (&amp;rt, '\0', sizeof (rt));
++
++ SET_SA_FAMILY (rt.rt_dst, AF_INET);
++ SET_SA_FAMILY (rt.rt_gateway, AF_INET);
++ rt.rt_dev = ifname;
++
++ SIN_ADDR(rt.rt_gateway) = 0;
++ SIN_ADDR(rt.rt_dst) = his_adr;
++ rt.rt_flags = RTF_UP | RTF_HOST;
++
++ if (kernel_version &gt; KVERSION(2,1,0)) {
++ SET_SA_FAMILY (rt.rt_genmask, AF_INET);
++ SIN_ADDR(rt.rt_genmask) = -1L;
++ }
++
++ if (ioctl(sock_fd, SIOCDELRT, &amp;rt) &lt; 0 &amp;&amp; errno != ESRCH) {
++ if (still_ppp() &amp;&amp; ! ok_error (errno))
++ error(&quot;ioctl(SIOCDELRT) device route: %m(%d)&quot;, errno);
++ return (0);
++ }
++ }
++
++ /* This way it is possible to have an IPX-only or IPv6-only interface */
++ memset(&amp;ifr, 0, sizeof(ifr));
++ SET_SA_FAMILY(ifr.ifr_addr, AF_INET);
++ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
++
++ if (ioctl(sock_fd, SIOCSIFADDR, (caddr_t) &amp;ifr) &lt; 0) {
++ if (! ok_error (errno)) {
++ error(&quot;ioctl(SIOCSIFADDR): %m(%d)&quot;, errno);
++ return 0;
++ }
++ }
++
++ our_old_addr = our_adr;
++
++ return 1;
++}
++
++#ifdef INET6
++/********************************************************************
++ *
++ * sif6addr - Config the interface with an IPv6 link-local address
++ */
++int sif6addr (int unit, eui64_t our_eui64, eui64_t his_eui64)
++{
++ struct in6_ifreq ifr6;
++ struct ifreq ifr;
++ struct in6_rtmsg rt6;
++
++ if (sock6_fd &lt; 0) {
++ errno = -sock6_fd;
++ error(&quot;IPv6 socket creation failed: %m&quot;);
++ return 0;
++ }
++ memset(&amp;ifr, 0, sizeof (ifr));
++ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
++ if (ioctl(sock6_fd, SIOCGIFINDEX, (caddr_t) &amp;ifr) &lt; 0) {
++ error(&quot;sif6addr: ioctl(SIOCGIFINDEX): %m (%d)&quot;, errno);
++ return 0;
++ }
++
++ /* Local interface */
++ memset(&amp;ifr6, 0, sizeof(ifr6));
++ IN6_LLADDR_FROM_EUI64(ifr6.ifr6_addr, our_eui64);
++ ifr6.ifr6_ifindex = ifr.ifr_ifindex;
++ ifr6.ifr6_prefixlen = 10;
++
++ if (ioctl(sock6_fd, SIOCSIFADDR, &amp;ifr6) &lt; 0) {
++ error(&quot;sif6addr: ioctl(SIOCSIFADDR): %m (%d)&quot;, errno);
++ return 0;
++ }
++
++ /* Route to remote host */
++ memset(&amp;rt6, 0, sizeof(rt6));
++ IN6_LLADDR_FROM_EUI64(rt6.rtmsg_dst, his_eui64);
++ rt6.rtmsg_flags = RTF_UP;
++ rt6.rtmsg_dst_len = 10;
++ rt6.rtmsg_ifindex = ifr.ifr_ifindex;
++ rt6.rtmsg_metric = 1;
++
++ if (ioctl(sock6_fd, SIOCADDRT, &amp;rt6) &lt; 0) {
++ error(&quot;sif6addr: ioctl(SIOCADDRT): %m (%d)&quot;, errno);
++ return 0;
++ }
++
++ return 1;
++}
++
++
++/********************************************************************
++ *
++ * cif6addr - Remove IPv6 address from interface
++ */
++int cif6addr (int unit, eui64_t our_eui64, eui64_t his_eui64)
++{
++ struct ifreq ifr;
++ struct in6_ifreq ifr6;
++
++ if (sock6_fd &lt; 0) {
++ errno = -sock6_fd;
++ error(&quot;IPv6 socket creation failed: %m&quot;);
++ return 0;
++ }
++ memset(&amp;ifr, 0, sizeof(ifr));
++ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
++ if (ioctl(sock6_fd, SIOCGIFINDEX, (caddr_t) &amp;ifr) &lt; 0) {
++ error(&quot;cif6addr: ioctl(SIOCGIFINDEX): %m (%d)&quot;, errno);
++ return 0;
++ }
++
++ memset(&amp;ifr6, 0, sizeof(ifr6));
++ IN6_LLADDR_FROM_EUI64(ifr6.ifr6_addr, our_eui64);
++ ifr6.ifr6_ifindex = ifr.ifr_ifindex;
++ ifr6.ifr6_prefixlen = 10;
++
++ if (ioctl(sock6_fd, SIOCDIFADDR, &amp;ifr6) &lt; 0) {
++ if (errno != EADDRNOTAVAIL) {
++ if (! ok_error (errno))
++ error(&quot;cif6addr: ioctl(SIOCDIFADDR): %m (%d)&quot;, errno);
++ }
++ else {
++ warn(&quot;cif6addr: ioctl(SIOCDIFADDR): No such address&quot;);
++ }
++ return (0);
++ }
++ return 1;
++}
++#endif /* INET6 */
++
++/*
++ * get_pty - get a pty master/slave pair and chown the slave side
++ * to the uid given. Assumes slave_name points to &gt;= 16 bytes of space.
++ */
++int
++get_pty(master_fdp, slave_fdp, slave_name, uid)
++ int *master_fdp;
++ int *slave_fdp;
++ char *slave_name;
++ int uid;
++{
++ int i, mfd, sfd = -1;
++ char pty_name[16];
++ struct termios tios;
++
++#ifdef TIOCGPTN
++ /*
++ * Try the unix98 way first.
++ */
++ mfd = open(&quot;/dev/ptmx&quot;, O_RDWR);
++ if (mfd &gt;= 0) {
++ int ptn;
++ if (ioctl(mfd, TIOCGPTN, &amp;ptn) &gt;= 0) {
++ slprintf(pty_name, sizeof(pty_name), &quot;/dev/pts/%d&quot;, ptn);
++ chmod(pty_name, S_IRUSR | S_IWUSR);
++#ifdef TIOCSPTLCK
++ ptn = 0;
++ if (ioctl(mfd, TIOCSPTLCK, &amp;ptn) &lt; 0)
++ warn(&quot;Couldn't unlock pty slave %s: %m&quot;, pty_name);
++#endif
++ if ((sfd = open(pty_name, O_RDWR | O_NOCTTY)) &lt; 0)
++ warn(&quot;Couldn't open pty slave %s: %m&quot;, pty_name);
++ }
++ }
++#endif /* TIOCGPTN */
++
++ if (sfd &lt; 0) {
++ /* the old way - scan through the pty name space */
++ for (i = 0; i &lt; 64; ++i) {
++ slprintf(pty_name, sizeof(pty_name), &quot;/dev/pty%c%x&quot;,
++ 'p' + i / 16, i % 16);
++ mfd = open(pty_name, O_RDWR, 0);
++ if (mfd &gt;= 0) {
++ pty_name[5] = 't';
++ sfd = open(pty_name, O_RDWR | O_NOCTTY, 0);
++ if (sfd &gt;= 0) {
++ fchown(sfd, uid, -1);
++ fchmod(sfd, S_IRUSR | S_IWUSR);
++ break;
++ }
++ close(mfd);
++ }
++ }
++ }
++
++ if (sfd &lt; 0)
++ return 0;
++
++ strlcpy(slave_name, pty_name, 16);
++ *master_fdp = mfd;
++ *slave_fdp = sfd;
++ if (tcgetattr(sfd, &amp;tios) == 0) {
++ tios.c_cflag &amp;= ~(CSIZE | CSTOPB | PARENB);
++ tios.c_cflag |= CS8 | CREAD | CLOCAL;
++ tios.c_iflag = IGNPAR;
++ tios.c_oflag = 0;
++ tios.c_lflag = 0;
++ if (tcsetattr(sfd, TCSAFLUSH, &amp;tios) &lt; 0)
++ warn(&quot;couldn't set attributes on pty: %m&quot;);
++ } else
++ warn(&quot;couldn't get attributes on pty: %m&quot;);
++
++ return 1;
++}
++
++/********************************************************************
++ *
++ * open_loopback - open the device we use for getting packets
++ * in demand mode. Under Linux, we use a pty master/slave pair.
++ */
++int
++open_ppp_loopback(void)
++{
++ int flags;
++
++ looped = 1;
++ if (new_style_driver) {
++ /* allocate ourselves a ppp unit */
++ if (make_ppp_unit() &lt; 0)
++ die(1);
++ set_flags(ppp_dev_fd, SC_LOOP_TRAFFIC);
++ set_kdebugflag(kdebugflag);
++ ppp_fd = -1;
++ return ppp_dev_fd;
++ }
++
++ if (!get_pty(&amp;master_fd, &amp;slave_fd, loop_name, 0))
++ fatal(&quot;No free pty for loopback&quot;);
++ SYSDEBUG((&quot;using %s for loopback&quot;, loop_name));
++
++ set_ppp_fd(slave_fd);
++
++ flags = fcntl(master_fd, F_GETFL);
++ if (flags == -1 ||
++ fcntl(master_fd, F_SETFL, flags | O_NONBLOCK) == -1)
++ warn(&quot;couldn't set master loopback to nonblock: %m(%d)&quot;, errno);
++
++ flags = fcntl(ppp_fd, F_GETFL);
++ if (flags == -1 ||
++ fcntl(ppp_fd, F_SETFL, flags | O_NONBLOCK) == -1)
++ warn(&quot;couldn't set slave loopback to nonblock: %m(%d)&quot;, errno);
++
++ if (ioctl(ppp_fd, TIOCSETD, &amp;ppp_disc) &lt; 0)
++ fatal(&quot;ioctl(TIOCSETD): %m(%d)&quot;, errno);
++/*
++ * Find out which interface we were given.
++ */
++ if (ioctl(ppp_fd, PPPIOCGUNIT, &amp;ifunit) &lt; 0)
++ fatal(&quot;ioctl(PPPIOCGUNIT): %m(%d)&quot;, errno);
++/*
++ * Enable debug in the driver if requested.
++ */
++ set_kdebugflag (kdebugflag);
++
++ return master_fd;
++}
++
++/********************************************************************
++ *
++ * restore_loop - reattach the ppp unit to the loopback.
++ *
++ * The kernel ppp driver automatically reattaches the ppp unit to
++ * the loopback if the serial port is set to a line discipline other
++ * than ppp, or if it detects a modem hangup. The former will happen
++ * in disestablish_ppp if the latter hasn't already happened, so we
++ * shouldn't need to do anything.
++ *
++ * Just to be sure, set the real serial port to the normal discipline.
++ */
++
++static void
++restore_loop(void)
++{
++ looped = 1;
++ if (new_style_driver) {
++ set_flags(ppp_dev_fd, get_flags(ppp_dev_fd) | SC_LOOP_TRAFFIC);
++ return;
++ }
++ if (ppp_fd != slave_fd) {
++ (void) ioctl(ppp_fd, TIOCSETD, &amp;tty_disc);
++ set_ppp_fd(slave_fd);
++ }
++}
++
++/********************************************************************
++ *
++ * sifnpmode - Set the mode for handling packets for a given NP.
++ */
++
++int
++sifnpmode(u, proto, mode)
++ int u;
++ int proto;
++ enum NPmode mode;
++{
++ struct npioctl npi;
++
++ npi.protocol = proto;
++ npi.mode = mode;
++ if (ioctl(ppp_dev_fd, PPPIOCSNPMODE, (caddr_t) &amp;npi) &lt; 0) {
++ if (! ok_error (errno))
++ error(&quot;ioctl(PPPIOCSNPMODE, %d, %d): %m (%d)&quot;,
++ proto, mode, errno);
++ return 0;
++ }
++ return 1;
++}
++
++
++/********************************************************************
++ *
++ * sipxfaddr - Config the interface IPX networknumber
++ */
++
++int sipxfaddr (int unit, unsigned long int network, unsigned char * node )
++{
++ int result = 1;
++
++#ifdef IPX_CHANGE
++ int skfd;
++ struct ifreq ifr;
++ struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) &amp;ifr.ifr_addr;
++
++ skfd = socket (AF_IPX, SOCK_DGRAM, 0);
++ if (skfd &lt; 0) {
++ if (! ok_error (errno))
++ dbglog(&quot;socket(AF_IPX): %m (%d)&quot;, errno);
++ result = 0;
++ }
++ else {
++ memset (&amp;ifr, '\0', sizeof (ifr));
++ strlcpy (ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
++
++ memcpy (sipx-&gt;sipx_node, node, IPX_NODE_LEN);
++ sipx-&gt;sipx_family = AF_IPX;
++ sipx-&gt;sipx_port = 0;
++ sipx-&gt;sipx_network = htonl (network);
++ sipx-&gt;sipx_type = IPX_FRAME_ETHERII;
++ sipx-&gt;sipx_action = IPX_CRTITF;
++/*
++ * Set the IPX device
++ */
++ if (ioctl(skfd, SIOCSIFADDR, (caddr_t) &amp;ifr) &lt; 0) {
++ result = 0;
++ if (errno != EEXIST) {
++ if (! ok_error (errno))
++ dbglog(&quot;ioctl(SIOCSIFADDR, CRTITF): %m (%d)&quot;, errno);
++ }
++ else {
++ warn(&quot;ioctl(SIOCSIFADDR, CRTITF): Address already exists&quot;);
++ }
++ }
++ close (skfd);
++ }
++#endif
++ return result;
++}
++
++/********************************************************************
++ *
++ * cipxfaddr - Clear the information for the IPX network. The IPX routes
++ * are removed and the device is no longer able to pass IPX
++ * frames.
++ */
++
++int cipxfaddr (int unit)
++{
++ int result = 1;
++
++#ifdef IPX_CHANGE
++ int skfd;
++ struct ifreq ifr;
++ struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) &amp;ifr.ifr_addr;
++
++ skfd = socket (AF_IPX, SOCK_DGRAM, 0);
++ if (skfd &lt; 0) {
++ if (! ok_error (errno))
++ dbglog(&quot;socket(AF_IPX): %m (%d)&quot;, errno);
++ result = 0;
++ }
++ else {
++ memset (&amp;ifr, '\0', sizeof (ifr));
++ strlcpy (ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
++
++ sipx-&gt;sipx_type = IPX_FRAME_ETHERII;
++ sipx-&gt;sipx_action = IPX_DLTITF;
++ sipx-&gt;sipx_family = AF_IPX;
++/*
++ * Set the IPX device
++ */
++ if (ioctl(skfd, SIOCSIFADDR, (caddr_t) &amp;ifr) &lt; 0) {
++ if (! ok_error (errno))
++ info(&quot;ioctl(SIOCSIFADDR, IPX_DLTITF): %m (%d)&quot;, errno);
++ result = 0;
++ }
++ close (skfd);
++ }
++#endif
++ return result;
++}
++
++/*
++ * Use the hostname as part of the random number seed.
++ */
++int
++get_host_seed()
++{
++ int h;
++ char *p = hostname;
++
++ h = 407;
++ for (p = hostname; *p != 0; ++p)
++ h = h * 37 + *p;
++ return h;
++}
++
++/********************************************************************
++ *
++ * sys_check_options - check the options that the user specified
++ */
++
++int
++sys_check_options(void)
++{
++#ifdef IPX_CHANGE
++/*
++ * Disable the IPX protocol if the support is not present in the kernel.
++ */
++ char *path;
++
++ if (ipxcp_protent.enabled_flag) {
++ struct stat stat_buf;
++ if ((path = path_to_procfs(&quot;/net/ipx_interface&quot;)) == 0
++ || lstat(path, &amp;stat_buf) &lt; 0) {
++ error(&quot;IPX support is not present in the kernel\n&quot;);
++ ipxcp_protent.enabled_flag = 0;
++ }
++ }
++#endif
++ if (demand &amp;&amp; driver_is_old) {
++ option_error(&quot;demand dialling is not supported by kernel driver &quot;
++ &quot;version %d.%d.%d&quot;, driver_version, driver_modification,
++ driver_patch);
++ return 0;
++ }
++ if (multilink &amp;&amp; !new_style_driver) {
++ warn(&quot;Warning: multilink is not supported by the kernel driver&quot;);
++ multilink = 0;
++ }
++ return 1;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/sys-linux.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/sys-linux.c.wtmp
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/sys-linux.c.wtmp (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/sys-linux.c.wtmp 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,2750 @@
++/*
++ * sys-linux.c - System-dependent procedures for setting up
++ * PPP interfaces on Linux systems
++ *
++ * Copyright (c) 1989 Carnegie Mellon University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by Carnegie Mellon University. The name of the
++ * University may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ */
++
++#include &lt;sys/ioctl.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/socket.h&gt;
++#include &lt;sys/time.h&gt;
++#include &lt;sys/errno.h&gt;
++#include &lt;sys/file.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;sys/utsname.h&gt;
++#include &lt;sys/sysmacros.h&gt;
++
++#include &lt;stdio.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;syslog.h&gt;
++#include &lt;string.h&gt;
++#include &lt;time.h&gt;
++#include &lt;memory.h&gt;
++#include &lt;utmp.h&gt;
++#include &lt;mntent.h&gt;
++#include &lt;signal.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;ctype.h&gt;
++#include &lt;termios.h&gt;
++#include &lt;unistd.h&gt;
++
++/* This is in netdevice.h. However, this compile will fail miserably if
++ you attempt to include netdevice.h because it has so many references
++ to __memcpy functions which it should not attempt to do. So, since I
++ really don't use it, but it must be defined, define it now. */
++
++#ifndef MAX_ADDR_LEN
++#define MAX_ADDR_LEN 7
++#endif
++
++#if __GLIBC__ &gt;= 2
++#include &lt;asm/types.h&gt; /* glibc 2 conflicts with linux/types.h */
++#include &lt;net/if.h&gt;
++#include &lt;net/if_arp.h&gt;
++#include &lt;net/route.h&gt;
++#include &lt;netinet/if_ether.h&gt;
++#else
++#include &lt;linux/types.h&gt;
++#include &lt;linux/if.h&gt;
++#include &lt;linux/if_arp.h&gt;
++#include &lt;linux/route.h&gt;
++#include &lt;linux/if_ether.h&gt;
++#endif
++#include &lt;netinet/in.h&gt;
++#include &lt;arpa/inet.h&gt;
++
++#include &lt;linux/ppp_defs.h&gt;
++#include &lt;linux/if_ppp.h&gt;
++
++#include &quot;pppd.h&quot;
++#include &quot;fsm.h&quot;
++#include &quot;ipcp.h&quot;
++
++#ifdef IPX_CHANGE
++#include &quot;ipxcp.h&quot;
++#if __GLIBC__ &gt;= 2 &amp;&amp; \
++ !(defined(__powerpc__) &amp;&amp; __GLIBC__ == 2 &amp;&amp; __GLIBC_MINOR__ == 0)
++#include &lt;netipx/ipx.h&gt;
++#else
++#include &lt;linux/ipx.h&gt;
++#endif
++#endif /* IPX_CHANGE */
++
++#ifdef PPP_FILTER
++#include &lt;net/bpf.h&gt;
++#include &lt;linux/filter.h&gt;
++#endif /* PPP_FILTER */
++
++#ifdef LOCKLIB
++#include &lt;sys/locks.h&gt;
++#endif
++
++#ifdef INET6
++#ifndef _LINUX_IN6_H
++/*
++ * This is in linux/include/net/ipv6.h.
++ */
++
++struct in6_ifreq {
++ struct in6_addr ifr6_addr;
++ __u32 ifr6_prefixlen;
++ unsigned int ifr6_ifindex;
++};
++#endif
++
++#define IN6_LLADDR_FROM_EUI64(sin6, eui64) do { \
++ memset(&amp;sin6.s6_addr, 0, sizeof(struct in6_addr)); \
++ sin6.s6_addr16[0] = htons(0xfe80); \
++ eui64_copy(eui64, sin6.s6_addr32[2]); \
++ } while (0)
++
++#endif /* INET6 */
++
++/* We can get an EIO error on an ioctl if the modem has hung up */
++#define ok_error(num) ((num)==EIO)
++
++static int tty_disc = N_TTY; /* The TTY discipline */
++static int ppp_disc = N_PPP; /* The PPP discpline */
++static int initfdflags = -1; /* Initial file descriptor flags for fd */
++static int ppp_fd = -1; /* fd which is set to PPP discipline */
++static int sock_fd = -1; /* socket for doing interface ioctls */
++static int slave_fd = -1;
++static int master_fd = -1;
++#ifdef INET6
++static int sock6_fd = -1;
++#endif /* INET6 */
++static int ppp_dev_fd = -1; /* fd for /dev/ppp (new style driver) */
++static int chindex; /* channel index (new style driver) */
++
++static fd_set in_fds; /* set of fds that wait_input waits for */
++static int max_in_fd; /* highest fd set in in_fds */
++
++static int has_proxy_arp = 0;
++static int driver_version = 0;
++static int driver_modification = 0;
++static int driver_patch = 0;
++static int driver_is_old = 0;
++static int restore_term = 0; /* 1 =&gt; we've munged the terminal */
++static struct termios inittermios; /* Initial TTY termios */
++
++static int new_style_driver = 0;
++
++static char loop_name[20];
++static unsigned char inbuf[512]; /* buffer for chars read from loopback */
++
++static int if_is_up; /* Interface has been marked up */
++static u_int32_t default_route_gateway; /* Gateway for default route added */
++static u_int32_t proxy_arp_addr; /* Addr for proxy arp entry added */
++static char proxy_arp_dev[16]; /* Device for proxy arp entry */
++static u_int32_t our_old_addr; /* for detecting address changes */
++static int dynaddr_set; /* 1 if ip_dynaddr set */
++static int looped; /* 1 if using loop */
++static int link_mtu; /* mtu for the link (not bundle) */
++
++static struct utsname utsname; /* for the kernel version */
++static int kernel_version;
++#define KVERSION(j,n,p) ((j)*1000000 + (n)*1000 + (p))
++
++#define MAX_IFS 100
++
++#define FLAGS_GOOD (IFF_UP | IFF_BROADCAST)
++#define FLAGS_MASK (IFF_UP | IFF_BROADCAST | \
++ IFF_POINTOPOINT | IFF_LOOPBACK | IFF_NOARP)
++
++#define SIN_ADDR(x) (((struct sockaddr_in *) (&amp;(x)))-&gt;sin_addr.s_addr)
++
++/* Prototypes for procedures local to this file. */
++static int get_flags (int fd);
++static void set_flags (int fd, int flags);
++static int translate_speed (int bps);
++static int baud_rate_of (int speed);
++static void close_route_table (void);
++static int open_route_table (void);
++static int read_route_table (struct rtentry *rt);
++static int defaultroute_exists (struct rtentry *rt);
++static int get_ether_addr (u_int32_t ipaddr, struct sockaddr *hwaddr,
++ char *name, int namelen);
++static void decode_version (char *buf, int *version, int *mod, int *patch);
++static int set_kdebugflag(int level);
++static int ppp_registered(void);
++static int make_ppp_unit(void);
++static void restore_loop(void); /* Transfer ppp unit back to loopback */
++
++extern u_char inpacket_buf[]; /* borrowed from main.c */
++
++/*
++ * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
++ * if it exists.
++ */
++
++#define SET_SA_FAMILY(addr, family) \
++ memset ((char *) &amp;(addr), '\0', sizeof(addr)); \
++ addr.sa_family = (family);
++
++/*
++ * Determine if the PPP connection should still be present.
++ */
++
++extern int hungup;
++
++/* new_fd is the fd of a tty */
++static void set_ppp_fd (int new_fd)
++{
++ SYSDEBUG ((LOG_DEBUG, &quot;setting ppp_fd to %d\n&quot;, new_fd));
++ ppp_fd = new_fd;
++ if (!new_style_driver)
++ ppp_dev_fd = new_fd;
++}
++
++static int still_ppp(void)
++{
++ if (new_style_driver)
++ return !hungup &amp;&amp; ppp_fd &gt;= 0;
++ if (!hungup || ppp_fd == slave_fd)
++ return 1;
++ if (slave_fd &gt;= 0) {
++ set_ppp_fd(slave_fd);
++ return 1;
++ }
++ return 0;
++}
++
++/********************************************************************
++ *
++ * Functions to read and set the flags value in the device driver
++ */
++
++static int get_flags (int fd)
++{
++ int flags;
++
++ if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &amp;flags) &lt; 0) {
++ if ( ok_error (errno) )
++ flags = 0;
++ else
++ fatal(&quot;ioctl(PPPIOCGFLAGS): %m&quot;);
++ }
++
++ SYSDEBUG ((LOG_DEBUG, &quot;get flags = %x\n&quot;, flags));
++ return flags;
++}
++
++/********************************************************************/
++
++static void set_flags (int fd, int flags)
++{
++ SYSDEBUG ((LOG_DEBUG, &quot;set flags = %x\n&quot;, flags));
++
++ if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &amp;flags) &lt; 0) {
++ if (! ok_error (errno) )
++ fatal(&quot;ioctl(PPPIOCSFLAGS, %x): %m&quot;, flags, errno);
++ }
++}
++
++/********************************************************************
++ *
++ * sys_init - System-dependent initialization.
++ */
++
++void sys_init(void)
++{
++ int flags;
++
++ if (new_style_driver) {
++ ppp_dev_fd = open(&quot;/dev/ppp&quot;, O_RDWR);
++ if (ppp_dev_fd &lt; 0)
++ fatal(&quot;Couldn't open /dev/ppp: %m&quot;);
++ flags = fcntl(ppp_dev_fd, F_GETFL);
++ if (flags == -1
++ || fcntl(ppp_dev_fd, F_SETFL, flags | O_NONBLOCK) == -1)
++ warn(&quot;Couldn't set /dev/ppp to nonblock: %m&quot;);
++ }
++
++ /* Get an internet socket for doing socket ioctls. */
++ sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
++ if (sock_fd &lt; 0)
++ fatal(&quot;Couldn't create IP socket: %m(%d)&quot;, errno);
++
++#ifdef INET6
++ sock6_fd = socket(AF_INET6, SOCK_DGRAM, 0);
++ if (sock6_fd &lt; 0)
++ sock6_fd = -errno; /* save errno for later */
++#endif
++
++ FD_ZERO(&amp;in_fds);
++ max_in_fd = 0;
++}
++
++/********************************************************************
++ *
++ * sys_cleanup - restore any system state we modified before exiting:
++ * mark the interface down, delete default route and/or proxy arp entry.
++ * This shouldn't call die() because it's called from die().
++ */
++
++void sys_cleanup(void)
++{
++/*
++ * Take down the device
++ */
++ if (if_is_up) {
++ if_is_up = 0;
++ sifdown(0);
++ }
++/*
++ * Delete any routes through the device.
++ */
++ if (default_route_gateway != 0)
++ cifdefaultroute(0, 0, default_route_gateway);
++
++ if (has_proxy_arp)
++ cifproxyarp(0, proxy_arp_addr);
++}
++
++/********************************************************************
++ *
++ * sys_close - Clean up in a child process before execing.
++ */
++void
++sys_close(void)
++{
++ if (new_style_driver)
++ close(ppp_dev_fd);
++ if (sock_fd &gt;= 0)
++ close(sock_fd);
++ if (slave_fd &gt;= 0)
++ close(slave_fd);
++ if (master_fd &gt;= 0)
++ close(master_fd);
++ closelog();
++}
++
++/********************************************************************
++ *
++ * set_kdebugflag - Define the debugging level for the kernel
++ */
++
++static int set_kdebugflag (int requested_level)
++{
++ if (new_style_driver &amp;&amp; ifunit &lt; 0)
++ return 1;
++ if (ioctl(ppp_dev_fd, PPPIOCSDEBUG, &amp;requested_level) &lt; 0) {
++ if ( ! ok_error (errno) )
++ error(&quot;ioctl(PPPIOCSDEBUG): %m&quot;);
++ return (0);
++ }
++ SYSDEBUG ((LOG_INFO, &quot;set kernel debugging level to %d&quot;,
++ requested_level));
++ return (1);
++}
++
++/********************************************************************
++ *
++ * tty_establish_ppp - Turn the serial port into a ppp interface.
++ */
++
++int tty_establish_ppp (int tty_fd)
++{
++ int x;
++ int fd = -1;
++
++/*
++ * Ensure that the tty device is in exclusive mode.
++ */
++ if (ioctl(tty_fd, TIOCEXCL, 0) &lt; 0) {
++ if ( ! ok_error ( errno ))
++ warn(&quot;Couldn't make tty exclusive: %m&quot;);
++ }
++/*
++ * Demand mode - prime the old ppp device to relinquish the unit.
++ */
++ if (!new_style_driver &amp;&amp; looped
++ &amp;&amp; ioctl(slave_fd, PPPIOCXFERUNIT, 0) &lt; 0) {
++ error(&quot;ioctl(transfer ppp unit): %m&quot;);
++ return -1;
++ }
++/*
++ * Set the current tty to the PPP discpline
++ */
++
++#ifndef N_SYNC_PPP
++#define N_SYNC_PPP 14
++#endif
++ ppp_disc = (new_style_driver &amp;&amp; sync_serial)? N_SYNC_PPP: N_PPP;
++ if (ioctl(tty_fd, TIOCSETD, &amp;ppp_disc) &lt; 0) {
++ if ( ! ok_error (errno) ) {
++ error(&quot;Couldn't set tty to PPP discipline: %m&quot;);
++ return -1;
++ }
++ }
++
++ if (new_style_driver) {
++ /* Open another instance of /dev/ppp and connect the channel to it */
++ int flags;
++
++ if (ioctl(tty_fd, PPPIOCGCHAN, &amp;chindex) == -1) {
++ error(&quot;Couldn't get channel number: %m&quot;);
++ goto err;
++ }
++ dbglog(&quot;using channel %d&quot;, chindex);
++ fd = open(&quot;/dev/ppp&quot;, O_RDWR);
++ if (fd &lt; 0) {
++ error(&quot;Couldn't reopen /dev/ppp: %m&quot;);
++ goto err;
++ }
++ if (ioctl(fd, PPPIOCATTCHAN, &amp;chindex) &lt; 0) {
++ error(&quot;Couldn't attach to channel %d: %m&quot;, chindex);
++ goto err_close;
++ }
++ flags = fcntl(fd, F_GETFL);
++ if (flags == -1 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
++ warn(&quot;Couldn't set /dev/ppp (channel) to nonblock: %m&quot;);
++ set_ppp_fd(fd);
++
++ if (!looped)
++ ifunit = -1;
++ if (!looped &amp;&amp; !multilink) {
++ /*
++ * Create a new PPP unit.
++ */
++ if (make_ppp_unit() &lt; 0)
++ goto err_close;
++ }
++
++ if (looped)
++ set_flags(ppp_dev_fd, get_flags(ppp_dev_fd) &amp; ~SC_LOOP_TRAFFIC);
++
++ if (!multilink) {
++ add_fd(ppp_dev_fd);
++ if (ioctl(fd, PPPIOCCONNECT, &amp;ifunit) &lt; 0) {
++ error(&quot;Couldn't attach to PPP unit %d: %m&quot;, ifunit);
++ goto err_close;
++ }
++ }
++
++ } else {
++ /*
++ * Old-style driver: find out which interface we were given.
++ */
++ set_ppp_fd (tty_fd);
++ if (ioctl(tty_fd, PPPIOCGUNIT, &amp;x) &lt; 0) {
++ if (ok_error (errno))
++ goto err;
++ fatal(&quot;ioctl(PPPIOCGUNIT): %m(%d)&quot;, errno);
++ }
++ /* Check that we got the same unit again. */
++ if (looped &amp;&amp; x != ifunit)
++ fatal(&quot;transfer_ppp failed: wanted unit %d, got %d&quot;, ifunit, x);
++ ifunit = x;
++
++ /*
++ * Fetch the initial file flags and reset blocking mode on the file.
++ */
++ initfdflags = fcntl(tty_fd, F_GETFL);
++ if (initfdflags == -1 ||
++ fcntl(tty_fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) {
++ if ( ! ok_error (errno))
++ warn(&quot;Couldn't set device to non-blocking mode: %m&quot;);
++ }
++ }
++
++ looped = 0;
++
++ /*
++ * Enable debug in the driver if requested.
++ */
++ if (!looped)
++ set_kdebugflag (kdebugflag);
++
++#define SC_RCVB (SC_RCV_B7_0 | SC_RCV_B7_1 | SC_RCV_EVNP | SC_RCV_ODDP)
++#define SC_LOGB (SC_DEBUG | SC_LOG_INPKT | SC_LOG_OUTPKT | SC_LOG_RAWIN \
++ | SC_LOG_FLUSH)
++
++ set_flags(ppp_fd, ((get_flags(ppp_fd) &amp; ~(SC_RCVB | SC_LOGB))
++ | ((kdebugflag * SC_DEBUG) &amp; SC_LOGB)));
++
++ SYSDEBUG ((LOG_NOTICE, &quot;Using version %d.%d.%d of PPP driver&quot;,
++ driver_version, driver_modification, driver_patch));
++
++ return ppp_fd;
++
++ err_close:
++ close(fd);
++ err:
++ if (ioctl(tty_fd, TIOCSETD, &amp;tty_disc) &lt; 0 &amp;&amp; !ok_error(errno))
++ warn(&quot;Couldn't reset tty to normal line discipline: %m&quot;);
++ return -1;
++}
++
++/********************************************************************
++ *
++ * tty_disestablish_ppp - Restore the serial port to normal operation,
++ * and reconnect the ppp unit to the loopback if in demand mode.
++ * This shouldn't call die() because it's called from die().
++ */
++
++void tty_disestablish_ppp(int tty_fd)
++{
++ if (demand)
++ restore_loop();
++ if (!hungup) {
++/*
++ * Flush the tty output buffer so that the TIOCSETD doesn't hang.
++ */
++ if (tcflush(tty_fd, TCIOFLUSH) &lt; 0)
++ warn(&quot;tcflush failed: %m&quot;);
++/*
++ * Restore the previous line discipline
++ */
++ if (ioctl(tty_fd, TIOCSETD, &amp;tty_disc) &lt; 0) {
++ if ( ! ok_error (errno))
++ error(&quot;ioctl(TIOCSETD, N_TTY): %m&quot;);
++ }
++
++ if (ioctl(tty_fd, TIOCNXCL, 0) &lt; 0) {
++ if ( ! ok_error (errno))
++ warn(&quot;ioctl(TIOCNXCL): %m(%d)&quot;, errno);
++ }
++
++ /* Reset non-blocking mode on fd. */
++ if (initfdflags != -1 &amp;&amp; fcntl(tty_fd, F_SETFL, initfdflags) &lt; 0) {
++ if ( ! ok_error (errno))
++ warn(&quot;Couldn't restore device fd flags: %m&quot;);
++ }
++ }
++ initfdflags = -1;
++
++ if (new_style_driver) {
++ close(ppp_fd);
++ ppp_fd = -1;
++ if (!looped &amp;&amp; ifunit &gt;= 0 &amp;&amp; ioctl(ppp_dev_fd, PPPIOCDETACH) &lt; 0)
++ error(&quot;Couldn't release PPP unit: %m&quot;);
++ if (!multilink)
++ remove_fd(ppp_dev_fd);
++ }
++}
++
++/*
++ * make_ppp_unit - make a new ppp unit for ppp_dev_fd.
++ * Assumes new_style_driver.
++ */
++static int make_ppp_unit()
++{
++ int x;
++
++ ifunit = req_unit;
++ x = ioctl(ppp_dev_fd, PPPIOCNEWUNIT, &amp;ifunit);
++ if (x &lt; 0 &amp;&amp; req_unit &gt;= 0 &amp;&amp; errno == EEXIST) {
++ warn(&quot;Couldn't allocate PPP unit %d as it is already in use&quot;);
++ ifunit = -1;
++ x = ioctl(ppp_dev_fd, PPPIOCNEWUNIT, &amp;ifunit);
++ }
++ if (x &lt; 0)
++ error(&quot;Couldn't create new ppp unit: %m&quot;);
++ return x;
++}
++
++/*
++ * cfg_bundle - configure the existing bundle.
++ * Used in demand mode.
++ */
++void cfg_bundle(int mrru, int mtru, int rssn, int tssn)
++{
++ int flags;
++
++ if (!new_style_driver)
++ return;
++
++ /* set the mrru, mtu and flags */
++ if (ioctl(ppp_dev_fd, PPPIOCSMRRU, &amp;mrru) &lt; 0)
++ error(&quot;Couldn't set MRRU: %m&quot;);
++ flags = get_flags(ppp_dev_fd);
++ flags &amp;= ~(SC_MP_SHORTSEQ | SC_MP_XSHORTSEQ);
++ flags |= (rssn? SC_MP_SHORTSEQ: 0) | (tssn? SC_MP_XSHORTSEQ: 0)
++ | (mrru? SC_MULTILINK: 0);
++
++ set_flags(ppp_dev_fd, flags);
++
++ /* connect up the channel */
++ if (ioctl(ppp_fd, PPPIOCCONNECT, &amp;ifunit) &lt; 0)
++ fatal(&quot;Couldn't attach to PPP unit %d: %m&quot;, ifunit);
++ add_fd(ppp_dev_fd);
++}
++
++/*
++ * make_new_bundle - create a new PPP unit (i.e. a bundle)
++ * and connect our channel to it. This should only get called
++ * if `multilink' was set at the time establish_ppp was called.
++ * In demand mode this uses our existing bundle instead of making
++ * a new one.
++ */
++void make_new_bundle(int mrru, int mtru, int rssn, int tssn)
++{
++ if (!new_style_driver)
++ return;
++
++ /* make us a ppp unit */
++ if (make_ppp_unit() &lt; 0)
++ die(1);
++
++ /* set the mrru and flags */
++ cfg_bundle(mrru, mtru, rssn, tssn);
++}
++
++/*
++ * bundle_attach - attach our link to a given PPP unit.
++ * We assume the unit is controlled by another pppd.
++ */
++int bundle_attach(int ifnum)
++{
++ if (!new_style_driver)
++ return -1;
++
++ if (ioctl(ppp_dev_fd, PPPIOCATTACH, &amp;ifnum) &lt; 0) {
++ if (errno == ENXIO)
++ return 0; /* doesn't still exist */
++ fatal(&quot;Couldn't attach to interface unit %d: %m\n&quot;, ifnum);
++ }
++ if (ioctl(ppp_fd, PPPIOCCONNECT, &amp;ifnum) &lt; 0)
++ fatal(&quot;Couldn't connect to interface unit %d: %m&quot;, ifnum);
++ set_flags(ppp_dev_fd, get_flags(ppp_dev_fd) | SC_MULTILINK);
++
++ ifunit = ifnum;
++ return 1;
++}
++
++/********************************************************************
++ *
++ * clean_check - Fetch the flags for the device and generate
++ * appropriate error messages.
++ */
++void clean_check(void)
++{
++ int x;
++ char *s;
++
++ if (still_ppp()) {
++ if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &amp;x) == 0) {
++ s = NULL;
++ switch (~x &amp; (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) {
++ case SC_RCV_B7_0:
++ s = &quot;all had bit 7 set to 1&quot;;
++ break;
++
++ case SC_RCV_B7_1:
++ s = &quot;all had bit 7 set to 0&quot;;
++ break;
++
++ case SC_RCV_EVNP:
++ s = &quot;all had odd parity&quot;;
++ break;
++
++ case SC_RCV_ODDP:
++ s = &quot;all had even parity&quot;;
++ break;
++ }
++
++ if (s != NULL) {
++ warn(&quot;Receive serial link is not 8-bit clean:&quot;);
++ warn(&quot;Problem: %s&quot;, s);
++ }
++ }
++ }
++}
++
++
++/*
++ * List of valid speeds.
++ */
++
++struct speed {
++ int speed_int, speed_val;
++} speeds[] = {
++#ifdef B50
++ { 50, B50 },
++#endif
++#ifdef B75
++ { 75, B75 },
++#endif
++#ifdef B110
++ { 110, B110 },
++#endif
++#ifdef B134
++ { 134, B134 },
++#endif
++#ifdef B150
++ { 150, B150 },
++#endif
++#ifdef B200
++ { 200, B200 },
++#endif
++#ifdef B300
++ { 300, B300 },
++#endif
++#ifdef B600
++ { 600, B600 },
++#endif
++#ifdef B1200
++ { 1200, B1200 },
++#endif
++#ifdef B1800
++ { 1800, B1800 },
++#endif
++#ifdef B2000
++ { 2000, B2000 },
++#endif
++#ifdef B2400
++ { 2400, B2400 },
++#endif
++#ifdef B3600
++ { 3600, B3600 },
++#endif
++#ifdef B4800
++ { 4800, B4800 },
++#endif
++#ifdef B7200
++ { 7200, B7200 },
++#endif
++#ifdef B9600
++ { 9600, B9600 },
++#endif
++#ifdef B19200
++ { 19200, B19200 },
++#endif
++#ifdef B38400
++ { 38400, B38400 },
++#endif
++#ifdef B57600
++ { 57600, B57600 },
++#endif
++#ifdef B76800
++ { 76800, B76800 },
++#endif
++#ifdef B115200
++ { 115200, B115200 },
++#endif
++#ifdef EXTA
++ { 19200, EXTA },
++#endif
++#ifdef EXTB
++ { 38400, EXTB },
++#endif
++#ifdef B230400
++ { 230400, B230400 },
++#endif
++#ifdef B460800
++ { 460800, B460800 },
++#endif
++#ifdef B921600
++ { 921600, B921600 },
++#endif
++ { 0, 0 }
++};
++
++/********************************************************************
++ *
++ * Translate from bits/second to a speed_t.
++ */
++
++static int translate_speed (int bps)
++{
++ struct speed *speedp;
++
++ if (bps != 0) {
++ for (speedp = speeds; speedp-&gt;speed_int; speedp++) {
++ if (bps == speedp-&gt;speed_int)
++ return speedp-&gt;speed_val;
++ }
++ warn(&quot;speed %d not supported&quot;, bps);
++ }
++ return 0;
++}
++
++/********************************************************************
++ *
++ * Translate from a speed_t to bits/second.
++ */
++
++static int baud_rate_of (int speed)
++{
++ struct speed *speedp;
++
++ if (speed != 0) {
++ for (speedp = speeds; speedp-&gt;speed_int; speedp++) {
++ if (speed == speedp-&gt;speed_val)
++ return speedp-&gt;speed_int;
++ }
++ }
++ return 0;
++}
++
++/********************************************************************
++ *
++ * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
++ * at the requested speed, etc. If `local' is true, set CLOCAL
++ * regardless of whether the modem option was specified.
++ */
++
++void set_up_tty(int tty_fd, int local)
++{
++ int speed;
++ struct termios tios;
++
++ setdtr(tty_fd, 1);
++ if (tcgetattr(tty_fd, &amp;tios) &lt; 0) {
++ if (!ok_error(errno))
++ fatal(&quot;tcgetattr: %m(%d)&quot;, errno);
++ return;
++ }
++
++ if (!restore_term)
++ inittermios = tios;
++
++ tios.c_cflag &amp;= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
++ tios.c_cflag |= CS8 | CREAD | HUPCL;
++
++ tios.c_iflag = IGNBRK | IGNPAR;
++ tios.c_oflag = 0;
++ tios.c_lflag = 0;
++ tios.c_cc[VMIN] = 1;
++ tios.c_cc[VTIME] = 0;
++
++ if (local || !modem)
++ tios.c_cflag ^= (CLOCAL | HUPCL);
++
++ switch (crtscts) {
++ case 1:
++ tios.c_cflag |= CRTSCTS;
++ break;
++
++ case -2:
++ tios.c_iflag |= IXON | IXOFF;
++ tios.c_cc[VSTOP] = 0x13; /* DC3 = XOFF = ^S */
++ tios.c_cc[VSTART] = 0x11; /* DC1 = XON = ^Q */
++ break;
++
++ case -1:
++ tios.c_cflag &amp;= ~CRTSCTS;
++ break;
++
++ default:
++ break;
++ }
++
++ speed = translate_speed(inspeed);
++ if (speed) {
++ cfsetospeed (&amp;tios, speed);
++ cfsetispeed (&amp;tios, speed);
++ }
++/*
++ * We can't proceed if the serial port speed is B0,
++ * since that implies that the serial port is disabled.
++ */
++ else {
++ speed = cfgetospeed(&amp;tios);
++ if (speed == B0)
++ fatal(&quot;Baud rate for %s is 0; need explicit baud rate&quot;, devnam);
++ }
++
++ if (tcsetattr(tty_fd, TCSAFLUSH, &amp;tios) &lt; 0)
++ if (!ok_error(errno))
++ fatal(&quot;tcsetattr: %m&quot;);
++
++ baud_rate = baud_rate_of(speed);
++ restore_term = 1;
++}
++
++/********************************************************************
++ *
++ * setdtr - control the DTR line on the serial port.
++ * This is called from die(), so it shouldn't call die().
++ */
++
++void setdtr (int tty_fd, int on)
++{
++ int modembits = TIOCM_DTR;
++
++ ioctl(tty_fd, (on ? TIOCMBIS : TIOCMBIC), &amp;modembits);
++}
++
++/********************************************************************
++ *
++ * restore_tty - restore the terminal to the saved settings.
++ */
++
++void restore_tty (int tty_fd)
++{
++ if (restore_term) {
++ restore_term = 0;
++/*
++ * Turn off echoing, because otherwise we can get into
++ * a loop with the tty and the modem echoing to each other.
++ * We presume we are the sole user of this tty device, so
++ * when we close it, it will revert to its defaults anyway.
++ */
++ if (!default_device)
++ inittermios.c_lflag &amp;= ~(ECHO | ECHONL);
++
++ if (tcsetattr(tty_fd, TCSAFLUSH, &amp;inittermios) &lt; 0) {
++ if (! ok_error (errno))
++ warn(&quot;tcsetattr: %m&quot;);
++ }
++ }
++}
++
++/********************************************************************
++ *
++ * output - Output PPP packet.
++ */
++
++void output (int unit, unsigned char *p, int len)
++{
++ int fd = ppp_fd;
++ int proto;
++
++ if (debug)
++ dbglog(&quot;sent %P&quot;, p, len);
++
++ if (len &lt; PPP_HDRLEN)
++ return;
++ if (new_style_driver) {
++ p += 2;
++ len -= 2;
++ proto = (p[0] &lt;&lt; 8) + p[1];
++ if (ifunit &gt;= 0 &amp;&amp; !(proto &gt;= 0xc000 || proto == PPP_CCPFRAG))
++ fd = ppp_dev_fd;
++ }
++ if (write(fd, p, len) &lt; 0) {
++ if (errno == EWOULDBLOCK || errno == ENOBUFS
++ || errno == ENXIO || errno == EIO || errno == EINTR)
++ warn(&quot;write: warning: %m (%d)&quot;, errno);
++ else
++ error(&quot;write: %m (%d)&quot;, errno);
++ }
++}
++
++/********************************************************************
++ *
++ * wait_input - wait until there is data available,
++ * for the length of time specified by *timo (indefinite
++ * if timo is NULL).
++ */
++
++void wait_input(struct timeval *timo)
++{
++ fd_set ready, exc;
++ int n;
++
++ ready = in_fds;
++ exc = in_fds;
++ n = select(max_in_fd + 1, &amp;ready, NULL, &amp;exc, timo);
++ if (n &lt; 0 &amp;&amp; errno != EINTR)
++ fatal(&quot;select: %m(%d)&quot;, errno);
++}
++
++/*
++ * add_fd - add an fd to the set that wait_input waits for.
++ */
++void add_fd(int fd)
++{
++ FD_SET(fd, &amp;in_fds);
++ if (fd &gt; max_in_fd)
++ max_in_fd = fd;
++}
++
++/*
++ * remove_fd - remove an fd from the set that wait_input waits for.
++ */
++void remove_fd(int fd)
++{
++ FD_CLR(fd, &amp;in_fds);
++}
++
++
++/********************************************************************
++ *
++ * read_packet - get a PPP packet from the serial device.
++ */
++
++int read_packet (unsigned char *buf)
++{
++ int len, nr;
++
++ len = PPP_MRU + PPP_HDRLEN;
++ if (new_style_driver) {
++ *buf++ = PPP_ALLSTATIONS;
++ *buf++ = PPP_UI;
++ len -= 2;
++ }
++ nr = -1;
++ if (ppp_fd &gt;= 0) {
++ nr = read(ppp_fd, buf, len);
++ if (nr &lt; 0 &amp;&amp; errno != EWOULDBLOCK &amp;&amp; errno != EIO &amp;&amp; errno != EINTR)
++ error(&quot;read: %m&quot;);
++ if (nr &lt; 0 &amp;&amp; errno == ENXIO)
++ return 0;
++ }
++ if (nr &lt; 0 &amp;&amp; new_style_driver &amp;&amp; ifunit &gt;= 0) {
++ /* N.B. we read ppp_fd first since LCP packets come in there. */
++ nr = read(ppp_dev_fd, buf, len);
++ if (nr &lt; 0 &amp;&amp; errno != EWOULDBLOCK &amp;&amp; errno != EIO &amp;&amp; errno != EINTR)
++ error(&quot;read /dev/ppp: %m&quot;);
++ if (nr &lt; 0 &amp;&amp; errno == ENXIO)
++ return 0;
++ }
++ return (new_style_driver &amp;&amp; nr &gt; 0)? nr+2: nr;
++}
++
++/********************************************************************
++ *
++ * get_loop_output - get outgoing packets from the ppp device,
++ * and detect when we want to bring the real link up.
++ * Return value is 1 if we need to bring up the link, 0 otherwise.
++ */
++int
++get_loop_output(void)
++{
++ int rv = 0;
++ int n;
++
++ if (new_style_driver) {
++ while ((n = read_packet(inpacket_buf)) &gt; 0)
++ if (loop_frame(inpacket_buf, n))
++ rv = 1;
++ return rv;
++ }
++
++ while ((n = read(master_fd, inbuf, sizeof(inbuf))) &gt; 0)
++ if (loop_chars(inbuf, n))
++ rv = 1;
++
++ if (n == 0)
++ fatal(&quot;eof on loopback&quot;);
++
++ if (errno != EWOULDBLOCK)
++ fatal(&quot;read from loopback: %m(%d)&quot;, errno);
++
++ return rv;
++}
++
++/*
++ * netif_set_mtu - set the MTU on the PPP network interface.
++ */
++void
++netif_set_mtu(int unit, int mtu)
++{
++ struct ifreq ifr;
++
++ SYSDEBUG ((LOG_DEBUG, &quot;netif_set_mtu: mtu = %d\n&quot;, mtu));
++
++ memset (&amp;ifr, '\0', sizeof (ifr));
++ strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
++ ifr.ifr_mtu = mtu;
++
++ if (ifunit &gt;= 0 &amp;&amp; ioctl(sock_fd, SIOCSIFMTU, (caddr_t) &amp;ifr) &lt; 0)
++ fatal(&quot;ioctl(SIOCSIFMTU): %m&quot;);
++}
++
++/********************************************************************
++ *
++ * tty_send_config - configure the transmit characteristics of
++ * the ppp interface.
++ */
++
++void tty_send_config (int mtu,u_int32_t asyncmap,int pcomp,int accomp)
++{
++ u_int x;
++
++/*
++ * Set the asyncmap and other parameters for the ppp device
++ */
++ if (!still_ppp())
++ return;
++ link_mtu = mtu;
++ SYSDEBUG ((LOG_DEBUG, &quot;send_config: asyncmap = %lx\n&quot;, asyncmap));
++ if (ioctl(ppp_fd, PPPIOCSASYNCMAP, (caddr_t) &amp;asyncmap) &lt; 0) {
++ if (!ok_error(errno))
++ fatal(&quot;ioctl(PPPIOCSASYNCMAP): %m(%d)&quot;, errno);
++ return;
++ }
++
++ x = get_flags(ppp_fd);
++ x = pcomp ? x | SC_COMP_PROT : x &amp; ~SC_COMP_PROT;
++ x = accomp ? x | SC_COMP_AC : x &amp; ~SC_COMP_AC;
++ x = sync_serial ? x | SC_SYNC : x &amp; ~SC_SYNC;
++ set_flags(ppp_fd, x);
++}
++
++/********************************************************************
++ *
++ * tty_set_xaccm - set the extended transmit ACCM for the interface.
++ */
++
++void tty_set_xaccm (ext_accm accm)
++{
++ SYSDEBUG ((LOG_DEBUG, &quot;set_xaccm: %08lx %08lx %08lx %08lx\n&quot;,
++ accm[0], accm[1], accm[2], accm[3]));
++
++ if (!still_ppp())
++ return;
++ if (ioctl(ppp_fd, PPPIOCSXASYNCMAP, accm) &lt; 0 &amp;&amp; errno != ENOTTY) {
++ if ( ! ok_error (errno))
++ warn(&quot;ioctl(set extended ACCM): %m(%d)&quot;, errno);
++ }
++}
++
++/********************************************************************
++ *
++ * tty_recv_config - configure the receive-side characteristics of
++ * the ppp interface.
++ */
++
++void tty_recv_config (int mru,u_int32_t asyncmap,int pcomp,int accomp)
++{
++ SYSDEBUG ((LOG_DEBUG, &quot;recv_config: mru = %d\n&quot;, mru));
++/*
++ * If we were called because the link has gone down then there is nothing
++ * which may be done. Just return without incident.
++ */
++ if (!still_ppp())
++ return;
++/*
++ * Set the receiver parameters
++ */
++ if (ioctl(ppp_fd, PPPIOCSMRU, (caddr_t) &amp;mru) &lt; 0) {
++ if ( ! ok_error (errno))
++ error(&quot;ioctl(PPPIOCSMRU): %m(%d)&quot;, errno);
++ }
++ if (new_style_driver &amp;&amp; ifunit &gt;= 0
++ &amp;&amp; ioctl(ppp_dev_fd, PPPIOCSMRU, (caddr_t) &amp;mru) &lt; 0)
++ error(&quot;Couldn't set MRU in generic PPP layer: %m&quot;);
++
++ SYSDEBUG ((LOG_DEBUG, &quot;recv_config: asyncmap = %lx\n&quot;, asyncmap));
++ if (ioctl(ppp_fd, PPPIOCSRASYNCMAP, (caddr_t) &amp;asyncmap) &lt; 0) {
++ if (!ok_error(errno))
++ error(&quot;ioctl(PPPIOCSRASYNCMAP): %m(%d)&quot;, errno);
++ }
++}
++
++/********************************************************************
++ *
++ * ccp_test - ask kernel whether a given compression method
++ * is acceptable for use.
++ */
++
++int ccp_test (int unit, u_char *opt_ptr, int opt_len, int for_transmit)
++{
++ struct ppp_option_data data;
++
++ memset (&amp;data, '\0', sizeof (data));
++ data.ptr = opt_ptr;
++ data.length = opt_len;
++ data.transmit = for_transmit;
++
++ if (ioctl(ppp_dev_fd, PPPIOCSCOMPRESS, (caddr_t) &amp;data) &gt;= 0)
++ return 1;
++
++ return (errno == ENOBUFS)? 0: -1;
++}
++
++/********************************************************************
++ *
++ * ccp_flags_set - inform kernel about the current state of CCP.
++ */
++
++void ccp_flags_set (int unit, int isopen, int isup)
++{
++ if (still_ppp()) {
++ int x = get_flags(ppp_dev_fd);
++ x = isopen? x | SC_CCP_OPEN : x &amp;~ SC_CCP_OPEN;
++ x = isup? x | SC_CCP_UP : x &amp;~ SC_CCP_UP;
++ set_flags (ppp_dev_fd, x);
++ }
++}
++
++#ifdef PPP_FILTER
++/*
++ * set_filters - set the active and pass filters in the kernel driver.
++ */
++int set_filters(struct bpf_program *pass, struct bpf_program *active)
++{
++ struct sock_fprog fp;
++
++ fp.len = pass-&gt;bf_len;
++ fp.filter = (struct sock_filter *) pass-&gt;bf_insns;
++ if (ioctl(ppp_dev_fd, PPPIOCSPASS, &amp;fp) &lt; 0) {
++ if (errno == ENOTTY)
++ warn(&quot;kernel does not support PPP filtering&quot;);
++ else
++ error(&quot;Couldn't set pass-filter in kernel: %m&quot;);
++ return 0;
++ }
++ fp.len = active-&gt;bf_len;
++ fp.filter = (struct sock_filter *) active-&gt;bf_insns;
++ if (ioctl(ppp_dev_fd, PPPIOCSACTIVE, &amp;fp) &lt; 0) {
++ error(&quot;Couldn't set active-filter in kernel: %m&quot;);
++ return 0;
++ }
++ return 1;
++}
++#endif /* PPP_FILTER */
++
++/********************************************************************
++ *
++ * get_idle_time - return how long the link has been idle.
++ */
++int
++get_idle_time(u, ip)
++ int u;
++ struct ppp_idle *ip;
++{
++ return ioctl(ppp_dev_fd, PPPIOCGIDLE, ip) &gt;= 0;
++}
++
++/********************************************************************
++ *
++ * get_ppp_stats - return statistics for the link.
++ */
++int
++get_ppp_stats(u, stats)
++ int u;
++ struct pppd_stats *stats;
++{
++ struct ifpppstatsreq req;
++
++ memset (&amp;req, 0, sizeof (req));
++
++ req.stats_ptr = (caddr_t) &amp;req.stats;
++ strlcpy(req.ifr__name, ifname, sizeof(req.ifr__name));
++ if (ioctl(sock_fd, SIOCGPPPSTATS, &amp;req) &lt; 0) {
++ error(&quot;Couldn't get PPP statistics: %m&quot;);
++ return 0;
++ }
++ stats-&gt;bytes_in = req.stats.p.ppp_ibytes;
++ stats-&gt;bytes_out = req.stats.p.ppp_obytes;
++ return 1;
++}
++
++/********************************************************************
++ *
++ * ccp_fatal_error - returns 1 if decompression was disabled as a
++ * result of an error detected after decompression of a packet,
++ * 0 otherwise. This is necessary because of patent nonsense.
++ */
++
++int ccp_fatal_error (int unit)
++{
++ int x = get_flags(ppp_dev_fd);
++
++ return x &amp; SC_DC_FERROR;
++}
++
++/********************************************************************
++ *
++ * path_to_procfs - find the path to the proc file system mount point
++ */
++static char proc_path[MAXPATHLEN];
++static int proc_path_len;
++
++static char *path_to_procfs(const char *tail)
++{
++ struct mntent *mntent;
++ FILE *fp;
++
++ if (proc_path_len == 0) {
++ /* Default the mount location of /proc */
++ strlcpy (proc_path, &quot;/proc&quot;, sizeof(proc_path));
++ proc_path_len = 5;
++ fp = fopen(MOUNTED, &quot;r&quot;);
++ if (fp != NULL) {
++ while ((mntent = getmntent(fp)) != NULL) {
++ if (strcmp(mntent-&gt;mnt_type, MNTTYPE_IGNORE) == 0)
++ continue;
++ if (strcmp(mntent-&gt;mnt_type, &quot;proc&quot;) == 0) {
++ strlcpy(proc_path, mntent-&gt;mnt_dir, sizeof(proc_path));
++ proc_path_len = strlen(proc_path);
++ break;
++ }
++ }
++ fclose (fp);
++ }
++ }
++
++ strlcpy(proc_path + proc_path_len, tail,
++ sizeof(proc_path) - proc_path_len);
++ return proc_path;
++}
++
++/*
++ * /proc/net/route parsing stuff.
++ */
++#define ROUTE_MAX_COLS 12
++FILE *route_fd = (FILE *) 0;
++static char route_buffer[512];
++static int route_dev_col, route_dest_col, route_gw_col;
++static int route_flags_col, route_mask_col;
++static int route_num_cols;
++
++static int open_route_table (void);
++static void close_route_table (void);
++static int read_route_table (struct rtentry *rt);
++
++/********************************************************************
++ *
++ * close_route_table - close the interface to the route table
++ */
++
++static void close_route_table (void)
++{
++ if (route_fd != (FILE *) 0) {
++ fclose (route_fd);
++ route_fd = (FILE *) 0;
++ }
++}
++
++/********************************************************************
++ *
++ * open_route_table - open the interface to the route table
++ */
++static char route_delims[] = &quot; \t\n&quot;;
++
++static int open_route_table (void)
++{
++ char *path;
++
++ close_route_table();
++
++ path = path_to_procfs(&quot;/net/route&quot;);
++ route_fd = fopen (path, &quot;r&quot;);
++ if (route_fd == NULL) {
++ error(&quot;can't open routing table %s: %m&quot;, path);
++ return 0;
++ }
++
++ route_dev_col = 0; /* default to usual columns */
++ route_dest_col = 1;
++ route_gw_col = 2;
++ route_flags_col = 3;
++ route_mask_col = 7;
++ route_num_cols = 8;
++
++ /* parse header line */
++ if (fgets(route_buffer, sizeof(route_buffer), route_fd) != 0) {
++ char *p = route_buffer, *q;
++ int col;
++ for (col = 0; col &lt; ROUTE_MAX_COLS; ++col) {
++ int used = 1;
++ if ((q = strtok(p, route_delims)) == 0)
++ break;
++ if (strcasecmp(q, &quot;iface&quot;) == 0)
++ route_dev_col = col;
++ else if (strcasecmp(q, &quot;destination&quot;) == 0)
++ route_dest_col = col;
++ else if (strcasecmp(q, &quot;gateway&quot;) == 0)
++ route_gw_col = col;
++ else if (strcasecmp(q, &quot;flags&quot;) == 0)
++ route_flags_col = col;
++ else if (strcasecmp(q, &quot;mask&quot;) == 0)
++ route_mask_col = col;
++ else
++ used = 0;
++ if (used &amp;&amp; col &gt;= route_num_cols)
++ route_num_cols = col + 1;
++ p = NULL;
++ }
++ }
++
++ return 1;
++}
++
++/********************************************************************
++ *
++ * read_route_table - read the next entry from the route table
++ */
++
++static int read_route_table(struct rtentry *rt)
++{
++ char *cols[ROUTE_MAX_COLS], *p;
++ int col;
++
++ memset (rt, '\0', sizeof (struct rtentry));
++
++ if (fgets (route_buffer, sizeof (route_buffer), route_fd) == (char *) 0)
++ return 0;
++
++ p = route_buffer;
++ for (col = 0; col &lt; route_num_cols; ++col) {
++ cols[col] = strtok(p, route_delims);
++ if (cols[col] == NULL)
++ return 0; /* didn't get enough columns */
++ p = NULL;
++ }
++
++ SIN_ADDR(rt-&gt;rt_dst) = strtoul(cols[route_dest_col], NULL, 16);
++ SIN_ADDR(rt-&gt;rt_gateway) = strtoul(cols[route_gw_col], NULL, 16);
++ SIN_ADDR(rt-&gt;rt_genmask) = strtoul(cols[route_mask_col], NULL, 16);
++
++ rt-&gt;rt_flags = (short) strtoul(cols[route_flags_col], NULL, 16);
++ rt-&gt;rt_dev = cols[route_dev_col];
++
++ return 1;
++}
++
++/********************************************************************
++ *
++ * defaultroute_exists - determine if there is a default route
++ */
++
++static int defaultroute_exists (struct rtentry *rt)
++{
++ int result = 0;
++
++ if (!open_route_table())
++ return 0;
++
++ while (read_route_table(rt) != 0) {
++ if ((rt-&gt;rt_flags &amp; RTF_UP) == 0)
++ continue;
++
++ if (kernel_version &gt; KVERSION(2,1,0) &amp;&amp; SIN_ADDR(rt-&gt;rt_genmask) != 0)
++ continue;
++ if (SIN_ADDR(rt-&gt;rt_dst) == 0L) {
++ result = 1;
++ break;
++ }
++ }
++
++ close_route_table();
++ return result;
++}
++
++/*
++ * have_route_to - determine if the system has any route to
++ * a given IP address. `addr' is in network byte order.
++ * Return value is 1 if yes, 0 if no, -1 if don't know.
++ * For demand mode to work properly, we have to ignore routes
++ * through our own interface.
++ */
++int have_route_to(u_int32_t addr)
++{
++ struct rtentry rt;
++ int result = 0;
++
++ if (!open_route_table())
++ return -1; /* don't know */
++
++ while (read_route_table(&amp;rt)) {
++ if ((rt.rt_flags &amp; RTF_UP) == 0 || strcmp(rt.rt_dev, ifname) == 0)
++ continue;
++ if ((addr &amp; SIN_ADDR(rt.rt_genmask)) == SIN_ADDR(rt.rt_dst)) {
++ result = 1;
++ break;
++ }
++ }
++
++ close_route_table();
++ return result;
++}
++
++/********************************************************************
++ *
++ * sifdefaultroute - assign a default route through the address given.
++ */
++
++int sifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway)
++{
++ struct rtentry rt;
++
++ if (defaultroute_exists(&amp;rt) &amp;&amp; strcmp(rt.rt_dev, ifname) != 0) {
++ u_int32_t old_gateway = SIN_ADDR(rt.rt_gateway);
++
++ if (old_gateway != gateway)
++ error(&quot;not replacing existing default route to %s [%I]&quot;,
++ rt.rt_dev, old_gateway);
++ return 0;
++ }
++
++ memset (&amp;rt, '\0', sizeof (rt));
++ SET_SA_FAMILY (rt.rt_dst, AF_INET);
++ SET_SA_FAMILY (rt.rt_gateway, AF_INET);
++
++ if (kernel_version &gt; KVERSION(2,1,0)) {
++ SET_SA_FAMILY (rt.rt_genmask, AF_INET);
++ SIN_ADDR(rt.rt_genmask) = 0L;
++ }
++
++ SIN_ADDR(rt.rt_gateway) = gateway;
++
++ rt.rt_flags = RTF_UP | RTF_GATEWAY;
++ if (ioctl(sock_fd, SIOCADDRT, &amp;rt) &lt; 0) {
++ if ( ! ok_error ( errno ))
++ error(&quot;default route ioctl(SIOCADDRT): %m(%d)&quot;, errno);
++ return 0;
++ }
++
++ default_route_gateway = gateway;
++ return 1;
++}
++
++/********************************************************************
++ *
++ * cifdefaultroute - delete a default route through the address given.
++ */
++
++int cifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway)
++{
++ struct rtentry rt;
++
++ default_route_gateway = 0;
++
++ memset (&amp;rt, '\0', sizeof (rt));
++ SET_SA_FAMILY (rt.rt_dst, AF_INET);
++ SET_SA_FAMILY (rt.rt_gateway, AF_INET);
++
++ if (kernel_version &gt; KVERSION(2,1,0)) {
++ SET_SA_FAMILY (rt.rt_genmask, AF_INET);
++ SIN_ADDR(rt.rt_genmask) = 0L;
++ }
++
++ SIN_ADDR(rt.rt_gateway) = gateway;
++
++ rt.rt_flags = RTF_UP | RTF_GATEWAY;
++ if (ioctl(sock_fd, SIOCDELRT, &amp;rt) &lt; 0 &amp;&amp; errno != ESRCH) {
++ if (still_ppp()) {
++ if ( ! ok_error ( errno ))
++ error(&quot;default route ioctl(SIOCDELRT): %m (%d)&quot;, errno);
++ return 0;
++ }
++ }
++
++ return 1;
++}
++
++/********************************************************************
++ *
++ * sifproxyarp - Make a proxy ARP entry for the peer.
++ */
++
++int sifproxyarp (int unit, u_int32_t his_adr)
++{
++ struct arpreq arpreq;
++ char *forw_path;
++
++ if (has_proxy_arp == 0) {
++ memset (&amp;arpreq, '\0', sizeof(arpreq));
++
++ SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
++ SIN_ADDR(arpreq.arp_pa) = his_adr;
++ arpreq.arp_flags = ATF_PERM | ATF_PUBL;
++/*
++ * Get the hardware address of an interface on the same subnet
++ * as our local address.
++ */
++ if (!get_ether_addr(his_adr, &amp;arpreq.arp_ha, proxy_arp_dev,
++ sizeof(proxy_arp_dev))) {
++ error(&quot;Cannot determine ethernet address for proxy ARP&quot;);
++ return 0;
++ }
++ strlcpy(arpreq.arp_dev, proxy_arp_dev, sizeof(arpreq.arp_dev));
++
++ if (ioctl(sock_fd, SIOCSARP, (caddr_t)&amp;arpreq) &lt; 0) {
++ if ( ! ok_error ( errno ))
++ error(&quot;ioctl(SIOCSARP): %m(%d)&quot;, errno);
++ return 0;
++ }
++ proxy_arp_addr = his_adr;
++ has_proxy_arp = 1;
++
++ if (tune_kernel) {
++ forw_path = path_to_procfs(&quot;/sys/net/ipv4/ip_forward&quot;);
++ if (forw_path != 0) {
++ int fd = open(forw_path, O_WRONLY);
++ if (fd &gt;= 0) {
++ if (write(fd, &quot;1&quot;, 1) != 1)
++ error(&quot;Couldn't enable IP forwarding: %m&quot;);
++ close(fd);
++ }
++ }
++ }
++ }
++
++ return 1;
++}
++
++/********************************************************************
++ *
++ * cifproxyarp - Delete the proxy ARP entry for the peer.
++ */
++
++int cifproxyarp (int unit, u_int32_t his_adr)
++{
++ struct arpreq arpreq;
++
++ if (has_proxy_arp) {
++ has_proxy_arp = 0;
++ memset (&amp;arpreq, '\0', sizeof(arpreq));
++ SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
++ SIN_ADDR(arpreq.arp_pa) = his_adr;
++ arpreq.arp_flags = ATF_PERM | ATF_PUBL;
++ strlcpy(arpreq.arp_dev, proxy_arp_dev, sizeof(arpreq.arp_dev));
++
++ if (ioctl(sock_fd, SIOCDARP, (caddr_t)&amp;arpreq) &lt; 0) {
++ if ( ! ok_error ( errno ))
++ warn(&quot;ioctl(SIOCDARP): %m(%d)&quot;, errno);
++ return 0;
++ }
++ }
++ return 1;
++}
++
++/********************************************************************
++ *
++ * get_ether_addr - get the hardware address of an interface on the
++ * the same subnet as ipaddr.
++ */
++
++static int get_ether_addr (u_int32_t ipaddr,
++ struct sockaddr *hwaddr,
++ char *name, int namelen)
++{
++ struct ifreq *ifr, *ifend;
++ u_int32_t ina, mask;
++ char *aliasp;
++ struct ifreq ifreq;
++ struct ifconf ifc;
++ struct ifreq ifs[MAX_IFS];
++
++ ifc.ifc_len = sizeof(ifs);
++ ifc.ifc_req = ifs;
++ if (ioctl(sock_fd, SIOCGIFCONF, &amp;ifc) &lt; 0) {
++ if ( ! ok_error ( errno ))
++ error(&quot;ioctl(SIOCGIFCONF): %m(%d)&quot;, errno);
++ return 0;
++ }
++
++ SYSDEBUG ((LOG_DEBUG, &quot;proxy arp: scanning %d interfaces for IP %s&quot;,
++ ifc.ifc_len / sizeof(struct ifreq), ip_ntoa(ipaddr)));
++/*
++ * Scan through looking for an interface with an Internet
++ * address on the same subnet as `ipaddr'.
++ */
++ ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq));
++ for (ifr = ifc.ifc_req; ifr &lt; ifend; ifr++) {
++ if (ifr-&gt;ifr_addr.sa_family == AF_INET) {
++ ina = SIN_ADDR(ifr-&gt;ifr_addr);
++ strlcpy(ifreq.ifr_name, ifr-&gt;ifr_name, sizeof(ifreq.ifr_name));
++ SYSDEBUG ((LOG_DEBUG, &quot;proxy arp: examining interface %s&quot;,
++ ifreq.ifr_name));
++/*
++ * Check that the interface is up, and not point-to-point
++ * nor loopback.
++ */
++ if (ioctl(sock_fd, SIOCGIFFLAGS, &amp;ifreq) &lt; 0)
++ continue;
++
++ if (((ifreq.ifr_flags ^ FLAGS_GOOD) &amp; FLAGS_MASK) != 0)
++ continue;
++/*
++ * Get its netmask and check that it's on the right subnet.
++ */
++ if (ioctl(sock_fd, SIOCGIFNETMASK, &amp;ifreq) &lt; 0)
++ continue;
++
++ mask = SIN_ADDR(ifreq.ifr_addr);
++ SYSDEBUG ((LOG_DEBUG, &quot;proxy arp: interface addr %s mask %lx&quot;,
++ ip_ntoa(ina), ntohl(mask)));
++
++ if (((ipaddr ^ ina) &amp; mask) != 0)
++ continue;
++ break;
++ }
++ }
++
++ if (ifr &gt;= ifend)
++ return 0;
++
++ strlcpy(name, ifreq.ifr_name, namelen);
++
++ /* trim off the :1 in eth0:1 */
++ aliasp = strchr(name, ':');
++ if (aliasp != 0)
++ *aliasp = 0;
++
++ info(&quot;found interface %s for proxy arp&quot;, name);
++/*
++ * Now get the hardware address.
++ */
++ memset (&amp;ifreq.ifr_hwaddr, 0, sizeof (struct sockaddr));
++ if (ioctl (sock_fd, SIOCGIFHWADDR, &amp;ifreq) &lt; 0) {
++ error(&quot;SIOCGIFHWADDR(%s): %m(%d)&quot;, ifreq.ifr_name, errno);
++ return 0;
++ }
++
++ memcpy (hwaddr,
++ &amp;ifreq.ifr_hwaddr,
++ sizeof (struct sockaddr));
++
++ SYSDEBUG ((LOG_DEBUG,
++ &quot;proxy arp: found hwaddr %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x&quot;,
++ (int) ((unsigned char *) &amp;hwaddr-&gt;sa_data)[0],
++ (int) ((unsigned char *) &amp;hwaddr-&gt;sa_data)[1],
++ (int) ((unsigned char *) &amp;hwaddr-&gt;sa_data)[2],
++ (int) ((unsigned char *) &amp;hwaddr-&gt;sa_data)[3],
++ (int) ((unsigned char *) &amp;hwaddr-&gt;sa_data)[4],
++ (int) ((unsigned char *) &amp;hwaddr-&gt;sa_data)[5],
++ (int) ((unsigned char *) &amp;hwaddr-&gt;sa_data)[6],
++ (int) ((unsigned char *) &amp;hwaddr-&gt;sa_data)[7]));
++ return 1;
++}
++
++/*
++ * get_if_hwaddr - get the hardware address for the specified
++ * network interface device.
++ */
++int
++get_if_hwaddr(u_char *addr, char *name)
++{
++ struct ifreq ifreq;
++ int ret, sock_fd;
++
++ sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
++ if (sock_fd &lt; 0)
++ return 0;
++ memset(&amp;ifreq.ifr_hwaddr, 0, sizeof(struct sockaddr));
++ strlcpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));
++ ret = ioctl(sock_fd, SIOCGIFHWADDR, &amp;ifreq);
++ close(sock_fd);
++ if (ret &gt;= 0)
++ memcpy(addr, ifreq.ifr_hwaddr.sa_data, 6);
++ return ret;
++}
++
++/*
++ * get_first_ethernet - return the name of the first ethernet-style
++ * interface on this system.
++ */
++char *
++get_first_ethernet()
++{
++ return &quot;eth0&quot;;
++}
++
++/********************************************************************
++ *
++ * Return user specified netmask, modified by any mask we might determine
++ * for address `addr' (in network byte order).
++ * Here we scan through the system's list of interfaces, looking for
++ * any non-point-to-point interfaces which might appear to be on the same
++ * network as `addr'. If we find any, we OR in their netmask to the
++ * user-specified netmask.
++ */
++
++u_int32_t GetMask (u_int32_t addr)
++{
++ u_int32_t mask, nmask, ina;
++ struct ifreq *ifr, *ifend, ifreq;
++ struct ifconf ifc;
++ struct ifreq ifs[MAX_IFS];
++
++ addr = ntohl(addr);
++
++ if (IN_CLASSA(addr)) /* determine network mask for address class */
++ nmask = IN_CLASSA_NET;
++ else if (IN_CLASSB(addr))
++ nmask = IN_CLASSB_NET;
++ else
++ nmask = IN_CLASSC_NET;
++
++ /* class D nets are disallowed by bad_ip_adrs */
++ mask = netmask | htonl(nmask);
++/*
++ * Scan through the system's network interfaces.
++ */
++ ifc.ifc_len = sizeof(ifs);
++ ifc.ifc_req = ifs;
++ if (ioctl(sock_fd, SIOCGIFCONF, &amp;ifc) &lt; 0) {
++ if ( ! ok_error ( errno ))
++ warn(&quot;ioctl(SIOCGIFCONF): %m(%d)&quot;, errno);
++ return mask;
++ }
++
++ ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
++ for (ifr = ifc.ifc_req; ifr &lt; ifend; ifr++) {
++/*
++ * Check the interface's internet address.
++ */
++ if (ifr-&gt;ifr_addr.sa_family != AF_INET)
++ continue;
++ ina = SIN_ADDR(ifr-&gt;ifr_addr);
++ if (((ntohl(ina) ^ addr) &amp; nmask) != 0)
++ continue;
++/*
++ * Check that the interface is up, and not point-to-point nor loopback.
++ */
++ strlcpy(ifreq.ifr_name, ifr-&gt;ifr_name, sizeof(ifreq.ifr_name));
++ if (ioctl(sock_fd, SIOCGIFFLAGS, &amp;ifreq) &lt; 0)
++ continue;
++
++ if (((ifreq.ifr_flags ^ FLAGS_GOOD) &amp; FLAGS_MASK) != 0)
++ continue;
++/*
++ * Get its netmask and OR it into our mask.
++ */
++ if (ioctl(sock_fd, SIOCGIFNETMASK, &amp;ifreq) &lt; 0)
++ continue;
++ mask |= SIN_ADDR(ifreq.ifr_addr);
++ break;
++ }
++ return mask;
++}
++
++/********************************************************************
++ *
++ * Internal routine to decode the version.modification.patch level
++ */
++
++static void decode_version (char *buf, int *version,
++ int *modification, int *patch)
++{
++ char *endp;
++
++ *version = (int) strtoul (buf, &amp;endp, 10);
++ *modification = 0;
++ *patch = 0;
++
++ if (endp != buf &amp;&amp; *endp == '.') {
++ buf = endp + 1;
++ *modification = (int) strtoul (buf, &amp;endp, 10);
++ if (endp != buf &amp;&amp; *endp == '.') {
++ buf = endp + 1;
++ *patch = (int) strtoul (buf, &amp;buf, 10);
++ }
++ }
++}
++
++/********************************************************************
++ *
++ * Procedure to determine if the PPP line discipline is registered.
++ */
++
++static int
++ppp_registered(void)
++{
++ int local_fd;
++ int mfd = -1;
++ int ret = 0;
++ char slave[16];
++
++ /*
++ * We used to open the serial device and set it to the ppp line
++ * discipline here, in order to create a ppp unit. But that is
++ * not a good idea - the user might have specified a device that
++ * they can't open (permission, or maybe it doesn't really exist).
++ * So we grab a pty master/slave pair and use that.
++ */
++ if (!get_pty(&amp;mfd, &amp;local_fd, slave, 0)) {
++ no_ppp_msg = &quot;Couldn't determine if PPP is supported (no free ptys)&quot;;
++ return 0;
++ }
++
++ /*
++ * Try to put the device into the PPP discipline.
++ */
++ if (ioctl(local_fd, TIOCSETD, &amp;ppp_disc) &lt; 0) {
++ error(&quot;ioctl(TIOCSETD(PPP)): %m(%d)&quot;, errno);
++ } else
++ ret = 1;
++
++ close(local_fd);
++ close(mfd);
++ return ret;
++}
++
++/********************************************************************
++ *
++ * ppp_available - check whether the system has any ppp interfaces
++ * (in fact we check whether we can do an ioctl on ppp0).
++ */
++
++int ppp_available(void)
++{
++ int s, ok, fd;
++ struct ifreq ifr;
++ int size;
++ int my_version, my_modification, my_patch;
++ int osmaj, osmin, ospatch;
++
++ no_ppp_msg =
++ &quot;This system lacks kernel support for PPP. This could be because\n&quot;
++ &quot;the PPP kernel module could not be loaded, or because PPP was not\n&quot;
++ &quot;included in the kernel configuration. If PPP was included as a\n&quot;
++ &quot;module, try `/sbin/modprobe -v ppp'. If that fails, check that\n&quot;
++ &quot;ppp.o exists in /lib/modules/`uname -r`/net.\n&quot;
++ &quot;See README.linux file in the ppp distribution for more details.\n&quot;;
++
++ /* get the kernel version now, since we are called before sys_init */
++ uname(&amp;utsname);
++ osmaj = osmin = ospatch = 0;
++ sscanf(utsname.release, &quot;%d.%d.%d&quot;, &amp;osmaj, &amp;osmin, &amp;ospatch);
++ kernel_version = KVERSION(osmaj, osmin, ospatch);
++
++ fd = open(&quot;/dev/ppp&quot;, O_RDWR);
++#if 0
++ if (fd &lt; 0 &amp;&amp; errno == ENOENT) {
++ /* try making it and see if that helps. */
++ if (mknod(&quot;/dev/ppp&quot;, S_IFCHR | S_IRUSR | S_IWUSR,
++ makedev(108, 0)) &gt;= 0) {
++ fd = open(&quot;/dev/ppp&quot;, O_RDWR);
++ if (fd &gt;= 0)
++ info(&quot;Created /dev/ppp device node&quot;);
++ else
++ unlink(&quot;/dev/ppp&quot;); /* didn't work, undo the mknod */
++ } else if (errno == EEXIST) {
++ fd = open(&quot;/dev/ppp&quot;, O_RDWR);
++ }
++ }
++#endif /* 0 */
++ if (fd &gt;= 0) {
++ new_style_driver = 1;
++
++ /* XXX should get from driver */
++ driver_version = 2;
++ driver_modification = 4;
++ driver_patch = 0;
++ close(fd);
++ return 1;
++ }
++ if (kernel_version &gt;= KVERSION(2,3,13)) {
++ if (errno == ENOENT)
++ no_ppp_msg =
++ &quot;pppd is unable to open the /dev/ppp device.\n&quot;
++ &quot;You need to create the /dev/ppp device node by\n&quot;
++ &quot;executing the following command as root:\n&quot;
++ &quot; mknod /dev/ppp c 108 0\n&quot;;
++ return 0;
++ }
++
++/*
++ * Open a socket for doing the ioctl operations.
++ */
++ s = socket(AF_INET, SOCK_DGRAM, 0);
++ if (s &lt; 0)
++ return 0;
++
++ strlcpy (ifr.ifr_name, &quot;ppp0&quot;, sizeof (ifr.ifr_name));
++ ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &amp;ifr) &gt;= 0;
++/*
++ * If the device did not exist then attempt to create one by putting the
++ * current tty into the PPP discipline. If this works then obtain the
++ * flags for the device again.
++ */
++ if (!ok) {
++ if (ppp_registered()) {
++ strlcpy (ifr.ifr_name, &quot;ppp0&quot;, sizeof (ifr.ifr_name));
++ ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &amp;ifr) &gt;= 0;
++ }
++ }
++/*
++ * Ensure that the hardware address is for PPP and not something else
++ */
++ if (ok)
++ ok = ioctl (s, SIOCGIFHWADDR, (caddr_t) &amp;ifr) &gt;= 0;
++
++ if (ok &amp;&amp; ((ifr.ifr_hwaddr.sa_family &amp; ~0xFF) != ARPHRD_PPP))
++ ok = 0;
++
++/*
++ * This is the PPP device. Validate the version of the driver at this
++ * point to ensure that this program will work with the driver.
++ */
++ if (ok) {
++ char abBuffer [1024];
++
++ ifr.ifr_data = abBuffer;
++ size = ioctl (s, SIOCGPPPVER, (caddr_t) &amp;ifr);
++ if (size &lt; 0) {
++ error(&quot;Couldn't read driver version: %m&quot;);
++ ok = 0;
++ no_ppp_msg = &quot;Sorry, couldn't verify kernel driver version\n&quot;;
++
++ } else {
++ decode_version(abBuffer,
++ &amp;driver_version,
++ &amp;driver_modification,
++ &amp;driver_patch);
++/*
++ * Validate the version of the driver against the version that we used.
++ */
++ decode_version(VERSION,
++ &amp;my_version,
++ &amp;my_modification,
++ &amp;my_patch);
++
++ /* The version numbers must match */
++ if (driver_version != my_version)
++ ok = 0;
++
++ /* The modification levels must be legal */
++ if (driver_modification &lt; 3) {
++ if (driver_modification &gt;= 2) {
++ /* we can cope with 2.2.0 and above */
++ driver_is_old = 1;
++ } else {
++ ok = 0;
++ }
++ }
++
++ close (s);
++ if (!ok) {
++ slprintf(route_buffer, sizeof(route_buffer),
++ &quot;Sorry - PPP driver version %d.%d.%d is out of date\n&quot;,
++ driver_version, driver_modification, driver_patch);
++
++ no_ppp_msg = route_buffer;
++ }
++ }
++ }
++ return ok;
++}
++
++/********************************************************************
++ *
++ * Update the wtmp file with the appropriate user name and tty device.
++ */
++
++void logwtmp (const char *line, const char *name, const char *host)
++{
++ struct utmp ut, *utp;
++ pid_t mypid = getpid();
++#if __GLIBC__ &lt; 2
++ int wtmp;
++#endif
++
++/*
++ * Update the signon database for users.
++ * Christoph Lameter: Copied from poeigl-1.36 Jan 3, 1996
++ */
++ utmpname(_PATH_UTMP);
++ setutent();
++ while ((utp = getutent()) &amp;&amp; (utp-&gt;ut_pid != mypid))
++ /* nothing */;
++
++ /* Is this call really necessary? There is another one after the 'put' */
++ endutent();
++
++ if (utp)
++ memcpy(&amp;ut, utp, sizeof(ut));
++ else
++ /* some gettys/telnetds don't initialize utmp... */
++ memset(&amp;ut, 0, sizeof(ut));
++
++ if (ut.ut_id[0] == 0)
++ strncpy(ut.ut_id, line + 3, sizeof(ut.ut_id));
++
++ strncpy(ut.ut_user, name, sizeof(ut.ut_user));
++ strncpy(ut.ut_line, line, sizeof(ut.ut_line));
++
++ time(&amp;ut.ut_time);
++
++ ut.ut_type = USER_PROCESS;
++ ut.ut_pid = mypid;
++
++ /* Insert the host name if one is supplied */
++ if (*host)
++ strncpy (ut.ut_host, host, sizeof(ut.ut_host));
++
++ /* Insert the IP address of the remote system if IP is enabled */
++ if (ipcp_protent.enabled_flag &amp;&amp; ipcp_hisoptions[0].neg_addr)
++ memcpy(&amp;ut.ut_addr, (char *) &amp;ipcp_hisoptions[0].hisaddr,
++ sizeof(ut.ut_addr));
++
++ /* CL: Makes sure that the logout works */
++ if (*host == 0 &amp;&amp; *name==0)
++ ut.ut_host[0]=0;
++
++ pututline(&amp;ut);
++ endutent();
++/*
++ * Update the wtmp file.
++ */
++#if __GLIBC__ &gt;= 2
++ updwtmp(_PATH_WTMP, &amp;ut);
++#else
++ wtmp = open(_PATH_WTMP, O_APPEND|O_WRONLY);
++ if (wtmp &gt;= 0) {
++ flock(wtmp, LOCK_EX);
++
++ if (write (wtmp, (char *)&amp;ut, sizeof(ut)) != sizeof(ut))
++ warn(&quot;error writing %s: %m&quot;, _PATH_WTMP);
++
++ flock(wtmp, LOCK_UN);
++
++ close (wtmp);
++ }
++#endif
++}
++
++
++/********************************************************************
++ *
++ * sifvjcomp - config tcp header compression
++ */
++
++int sifvjcomp (int u, int vjcomp, int cidcomp, int maxcid)
++{
++ u_int x = get_flags(ppp_dev_fd);
++
++ if (vjcomp) {
++ if (ioctl (ppp_dev_fd, PPPIOCSMAXCID, (caddr_t) &amp;maxcid) &lt; 0) {
++ if (! ok_error (errno))
++ error(&quot;ioctl(PPPIOCSMAXCID): %m(%d)&quot;, errno);
++ vjcomp = 0;
++ }
++ }
++
++ x = vjcomp ? x | SC_COMP_TCP : x &amp;~ SC_COMP_TCP;
++ x = cidcomp ? x &amp; ~SC_NO_TCP_CCID : x | SC_NO_TCP_CCID;
++ set_flags (ppp_dev_fd, x);
++
++ return 1;
++}
++
++/********************************************************************
++ *
++ * sifup - Config the interface up and enable IP packets to pass.
++ */
++
++int sifup(int u)
++{
++ struct ifreq ifr;
++
++ memset (&amp;ifr, '\0', sizeof (ifr));
++ strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
++ if (ioctl(sock_fd, SIOCGIFFLAGS, (caddr_t) &amp;ifr) &lt; 0) {
++ if (! ok_error (errno))
++ error(&quot;ioctl (SIOCGIFFLAGS): %m(%d)&quot;, errno);
++ return 0;
++ }
++
++ ifr.ifr_flags |= (IFF_UP | IFF_POINTOPOINT);
++ if (ioctl(sock_fd, SIOCSIFFLAGS, (caddr_t) &amp;ifr) &lt; 0) {
++ if (! ok_error (errno))
++ error(&quot;ioctl(SIOCSIFFLAGS): %m(%d)&quot;, errno);
++ return 0;
++ }
++ if_is_up++;
++
++ return 1;
++}
++
++/********************************************************************
++ *
++ * sifdown - Disable the indicated protocol and config the interface
++ * down if there are no remaining protocols.
++ */
++
++int sifdown (int u)
++{
++ struct ifreq ifr;
++
++ if (if_is_up &amp;&amp; --if_is_up &gt; 0)
++ return 1;
++
++ memset (&amp;ifr, '\0', sizeof (ifr));
++ strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
++ if (ioctl(sock_fd, SIOCGIFFLAGS, (caddr_t) &amp;ifr) &lt; 0) {
++ if (! ok_error (errno))
++ error(&quot;ioctl (SIOCGIFFLAGS): %m(%d)&quot;, errno);
++ return 0;
++ }
++
++ ifr.ifr_flags &amp;= ~IFF_UP;
++ ifr.ifr_flags |= IFF_POINTOPOINT;
++ if (ioctl(sock_fd, SIOCSIFFLAGS, (caddr_t) &amp;ifr) &lt; 0) {
++ if (! ok_error (errno))
++ error(&quot;ioctl(SIOCSIFFLAGS): %m(%d)&quot;, errno);
++ return 0;
++ }
++ return 1;
++}
++
++/********************************************************************
++ *
++ * sifaddr - Config the interface IP addresses and netmask.
++ */
++
++int sifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr,
++ u_int32_t net_mask)
++{
++ struct ifreq ifr;
++ struct rtentry rt;
++
++ memset (&amp;ifr, '\0', sizeof (ifr));
++ memset (&amp;rt, '\0', sizeof (rt));
++
++ SET_SA_FAMILY (ifr.ifr_addr, AF_INET);
++ SET_SA_FAMILY (ifr.ifr_dstaddr, AF_INET);
++ SET_SA_FAMILY (ifr.ifr_netmask, AF_INET);
++
++ strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
++/*
++ * Set our IP address
++ */
++ SIN_ADDR(ifr.ifr_addr) = our_adr;
++ if (ioctl(sock_fd, SIOCSIFADDR, (caddr_t) &amp;ifr) &lt; 0) {
++ if (errno != EEXIST) {
++ if (! ok_error (errno))
++ error(&quot;ioctl(SIOCSIFADDR): %m(%d)&quot;, errno);
++ }
++ else {
++ warn(&quot;ioctl(SIOCSIFADDR): Address already exists&quot;);
++ }
++ return (0);
++ }
++/*
++ * Set the gateway address
++ */
++ SIN_ADDR(ifr.ifr_dstaddr) = his_adr;
++ if (ioctl(sock_fd, SIOCSIFDSTADDR, (caddr_t) &amp;ifr) &lt; 0) {
++ if (! ok_error (errno))
++ error(&quot;ioctl(SIOCSIFDSTADDR): %m(%d)&quot;, errno);
++ return (0);
++ }
++/*
++ * Set the netmask.
++ * For recent kernels, force the netmask to 255.255.255.255.
++ */
++ if (kernel_version &gt;= KVERSION(2,1,16))
++ net_mask = ~0L;
++ if (net_mask != 0) {
++ SIN_ADDR(ifr.ifr_netmask) = net_mask;
++ if (ioctl(sock_fd, SIOCSIFNETMASK, (caddr_t) &amp;ifr) &lt; 0) {
++ if (! ok_error (errno))
++ error(&quot;ioctl(SIOCSIFNETMASK): %m(%d)&quot;, errno);
++ return (0);
++ }
++ }
++/*
++ * Add the device route
++ */
++ if (kernel_version &lt; KVERSION(2,1,16)) {
++ SET_SA_FAMILY (rt.rt_dst, AF_INET);
++ SET_SA_FAMILY (rt.rt_gateway, AF_INET);
++ rt.rt_dev = ifname;
++
++ SIN_ADDR(rt.rt_gateway) = 0L;
++ SIN_ADDR(rt.rt_dst) = his_adr;
++ rt.rt_flags = RTF_UP | RTF_HOST;
++
++ if (kernel_version &gt; KVERSION(2,1,0)) {
++ SET_SA_FAMILY (rt.rt_genmask, AF_INET);
++ SIN_ADDR(rt.rt_genmask) = -1L;
++ }
++
++ if (ioctl(sock_fd, SIOCADDRT, &amp;rt) &lt; 0) {
++ if (! ok_error (errno))
++ error(&quot;ioctl(SIOCADDRT) device route: %m(%d)&quot;, errno);
++ return (0);
++ }
++ }
++
++ /* set ip_dynaddr in demand mode if address changes */
++ if (demand &amp;&amp; tune_kernel &amp;&amp; !dynaddr_set
++ &amp;&amp; our_old_addr &amp;&amp; our_old_addr != our_adr) {
++ /* set ip_dynaddr if possible */
++ char *path;
++ int fd;
++
++ path = path_to_procfs(&quot;/sys/net/ipv4/ip_dynaddr&quot;);
++ if (path != 0 &amp;&amp; (fd = open(path, O_WRONLY)) &gt;= 0) {
++ if (write(fd, &quot;1&quot;, 1) != 1)
++ error(&quot;Couldn't enable dynamic IP addressing: %m&quot;);
++ close(fd);
++ }
++ dynaddr_set = 1; /* only 1 attempt */
++ }
++ our_old_addr = 0;
++
++ return 1;
++}
++
++/********************************************************************
++ *
++ * cifaddr - Clear the interface IP addresses, and delete routes
++ * through the interface if possible.
++ */
++
++int cifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr)
++{
++ struct ifreq ifr;
++
++ if (kernel_version &lt; KVERSION(2,1,16)) {
++/*
++ * Delete the route through the device
++ */
++ struct rtentry rt;
++ memset (&amp;rt, '\0', sizeof (rt));
++
++ SET_SA_FAMILY (rt.rt_dst, AF_INET);
++ SET_SA_FAMILY (rt.rt_gateway, AF_INET);
++ rt.rt_dev = ifname;
++
++ SIN_ADDR(rt.rt_gateway) = 0;
++ SIN_ADDR(rt.rt_dst) = his_adr;
++ rt.rt_flags = RTF_UP | RTF_HOST;
++
++ if (kernel_version &gt; KVERSION(2,1,0)) {
++ SET_SA_FAMILY (rt.rt_genmask, AF_INET);
++ SIN_ADDR(rt.rt_genmask) = -1L;
++ }
++
++ if (ioctl(sock_fd, SIOCDELRT, &amp;rt) &lt; 0 &amp;&amp; errno != ESRCH) {
++ if (still_ppp() &amp;&amp; ! ok_error (errno))
++ error(&quot;ioctl(SIOCDELRT) device route: %m(%d)&quot;, errno);
++ return (0);
++ }
++ }
++
++ /* This way it is possible to have an IPX-only or IPv6-only interface */
++ memset(&amp;ifr, 0, sizeof(ifr));
++ SET_SA_FAMILY(ifr.ifr_addr, AF_INET);
++ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
++
++ if (ioctl(sock_fd, SIOCSIFADDR, (caddr_t) &amp;ifr) &lt; 0) {
++ if (! ok_error (errno)) {
++ error(&quot;ioctl(SIOCSIFADDR): %m(%d)&quot;, errno);
++ return 0;
++ }
++ }
++
++ our_old_addr = our_adr;
++
++ return 1;
++}
++
++#ifdef INET6
++/********************************************************************
++ *
++ * sif6addr - Config the interface with an IPv6 link-local address
++ */
++int sif6addr (int unit, eui64_t our_eui64, eui64_t his_eui64)
++{
++ struct in6_ifreq ifr6;
++ struct ifreq ifr;
++ struct in6_rtmsg rt6;
++
++ if (sock6_fd &lt; 0) {
++ errno = -sock6_fd;
++ error(&quot;IPv6 socket creation failed: %m&quot;);
++ return 0;
++ }
++ memset(&amp;ifr, 0, sizeof (ifr));
++ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
++ if (ioctl(sock6_fd, SIOCGIFINDEX, (caddr_t) &amp;ifr) &lt; 0) {
++ error(&quot;sif6addr: ioctl(SIOCGIFINDEX): %m (%d)&quot;, errno);
++ return 0;
++ }
++
++ /* Local interface */
++ memset(&amp;ifr6, 0, sizeof(ifr6));
++ IN6_LLADDR_FROM_EUI64(ifr6.ifr6_addr, our_eui64);
++ ifr6.ifr6_ifindex = ifr.ifr_ifindex;
++ ifr6.ifr6_prefixlen = 10;
++
++ if (ioctl(sock6_fd, SIOCSIFADDR, &amp;ifr6) &lt; 0) {
++ error(&quot;sif6addr: ioctl(SIOCSIFADDR): %m (%d)&quot;, errno);
++ return 0;
++ }
++
++ /* Route to remote host */
++ memset(&amp;rt6, 0, sizeof(rt6));
++ IN6_LLADDR_FROM_EUI64(rt6.rtmsg_dst, his_eui64);
++ rt6.rtmsg_flags = RTF_UP;
++ rt6.rtmsg_dst_len = 10;
++ rt6.rtmsg_ifindex = ifr.ifr_ifindex;
++ rt6.rtmsg_metric = 1;
++
++ if (ioctl(sock6_fd, SIOCADDRT, &amp;rt6) &lt; 0) {
++ error(&quot;sif6addr: ioctl(SIOCADDRT): %m (%d)&quot;, errno);
++ return 0;
++ }
++
++ return 1;
++}
++
++
++/********************************************************************
++ *
++ * cif6addr - Remove IPv6 address from interface
++ */
++int cif6addr (int unit, eui64_t our_eui64, eui64_t his_eui64)
++{
++ struct ifreq ifr;
++ struct in6_ifreq ifr6;
++
++ if (sock6_fd &lt; 0) {
++ errno = -sock6_fd;
++ error(&quot;IPv6 socket creation failed: %m&quot;);
++ return 0;
++ }
++ memset(&amp;ifr, 0, sizeof(ifr));
++ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
++ if (ioctl(sock6_fd, SIOCGIFINDEX, (caddr_t) &amp;ifr) &lt; 0) {
++ error(&quot;cif6addr: ioctl(SIOCGIFINDEX): %m (%d)&quot;, errno);
++ return 0;
++ }
++
++ memset(&amp;ifr6, 0, sizeof(ifr6));
++ IN6_LLADDR_FROM_EUI64(ifr6.ifr6_addr, our_eui64);
++ ifr6.ifr6_ifindex = ifr.ifr_ifindex;
++ ifr6.ifr6_prefixlen = 10;
++
++ if (ioctl(sock6_fd, SIOCDIFADDR, &amp;ifr6) &lt; 0) {
++ if (errno != EADDRNOTAVAIL) {
++ if (! ok_error (errno))
++ error(&quot;cif6addr: ioctl(SIOCDIFADDR): %m (%d)&quot;, errno);
++ }
++ else {
++ warn(&quot;cif6addr: ioctl(SIOCDIFADDR): No such address&quot;);
++ }
++ return (0);
++ }
++ return 1;
++}
++#endif /* INET6 */
++
++/*
++ * get_pty - get a pty master/slave pair and chown the slave side
++ * to the uid given. Assumes slave_name points to &gt;= 16 bytes of space.
++ */
++int
++get_pty(master_fdp, slave_fdp, slave_name, uid)
++ int *master_fdp;
++ int *slave_fdp;
++ char *slave_name;
++ int uid;
++{
++ int i, mfd, sfd = -1;
++ char pty_name[16];
++ struct termios tios;
++
++#ifdef TIOCGPTN
++ /*
++ * Try the unix98 way first.
++ */
++ mfd = open(&quot;/dev/ptmx&quot;, O_RDWR);
++ if (mfd &gt;= 0) {
++ int ptn;
++ if (ioctl(mfd, TIOCGPTN, &amp;ptn) &gt;= 0) {
++ slprintf(pty_name, sizeof(pty_name), &quot;/dev/pts/%d&quot;, ptn);
++ chmod(pty_name, S_IRUSR | S_IWUSR);
++#ifdef TIOCSPTLCK
++ ptn = 0;
++ if (ioctl(mfd, TIOCSPTLCK, &amp;ptn) &lt; 0)
++ warn(&quot;Couldn't unlock pty slave %s: %m&quot;, pty_name);
++#endif
++ if ((sfd = open(pty_name, O_RDWR | O_NOCTTY)) &lt; 0)
++ warn(&quot;Couldn't open pty slave %s: %m&quot;, pty_name);
++ }
++ }
++#endif /* TIOCGPTN */
++
++ if (sfd &lt; 0) {
++ /* the old way - scan through the pty name space */
++ for (i = 0; i &lt; 64; ++i) {
++ slprintf(pty_name, sizeof(pty_name), &quot;/dev/pty%c%x&quot;,
++ 'p' + i / 16, i % 16);
++ mfd = open(pty_name, O_RDWR, 0);
++ if (mfd &gt;= 0) {
++ pty_name[5] = 't';
++ sfd = open(pty_name, O_RDWR | O_NOCTTY, 0);
++ if (sfd &gt;= 0) {
++ fchown(sfd, uid, -1);
++ fchmod(sfd, S_IRUSR | S_IWUSR);
++ break;
++ }
++ close(mfd);
++ }
++ }
++ }
++
++ if (sfd &lt; 0)
++ return 0;
++
++ strlcpy(slave_name, pty_name, 16);
++ *master_fdp = mfd;
++ *slave_fdp = sfd;
++ if (tcgetattr(sfd, &amp;tios) == 0) {
++ tios.c_cflag &amp;= ~(CSIZE | CSTOPB | PARENB);
++ tios.c_cflag |= CS8 | CREAD | CLOCAL;
++ tios.c_iflag = IGNPAR;
++ tios.c_oflag = 0;
++ tios.c_lflag = 0;
++ if (tcsetattr(sfd, TCSAFLUSH, &amp;tios) &lt; 0)
++ warn(&quot;couldn't set attributes on pty: %m&quot;);
++ } else
++ warn(&quot;couldn't get attributes on pty: %m&quot;);
++
++ return 1;
++}
++
++/********************************************************************
++ *
++ * open_loopback - open the device we use for getting packets
++ * in demand mode. Under Linux, we use a pty master/slave pair.
++ */
++int
++open_ppp_loopback(void)
++{
++ int flags;
++
++ looped = 1;
++ if (new_style_driver) {
++ /* allocate ourselves a ppp unit */
++ if (make_ppp_unit() &lt; 0)
++ die(1);
++ set_flags(ppp_dev_fd, SC_LOOP_TRAFFIC);
++ set_kdebugflag(kdebugflag);
++ ppp_fd = -1;
++ return ppp_dev_fd;
++ }
++
++ if (!get_pty(&amp;master_fd, &amp;slave_fd, loop_name, 0))
++ fatal(&quot;No free pty for loopback&quot;);
++ SYSDEBUG((&quot;using %s for loopback&quot;, loop_name));
++
++ set_ppp_fd(slave_fd);
++
++ flags = fcntl(master_fd, F_GETFL);
++ if (flags == -1 ||
++ fcntl(master_fd, F_SETFL, flags | O_NONBLOCK) == -1)
++ warn(&quot;couldn't set master loopback to nonblock: %m(%d)&quot;, errno);
++
++ flags = fcntl(ppp_fd, F_GETFL);
++ if (flags == -1 ||
++ fcntl(ppp_fd, F_SETFL, flags | O_NONBLOCK) == -1)
++ warn(&quot;couldn't set slave loopback to nonblock: %m(%d)&quot;, errno);
++
++ if (ioctl(ppp_fd, TIOCSETD, &amp;ppp_disc) &lt; 0)
++ fatal(&quot;ioctl(TIOCSETD): %m(%d)&quot;, errno);
++/*
++ * Find out which interface we were given.
++ */
++ if (ioctl(ppp_fd, PPPIOCGUNIT, &amp;ifunit) &lt; 0)
++ fatal(&quot;ioctl(PPPIOCGUNIT): %m(%d)&quot;, errno);
++/*
++ * Enable debug in the driver if requested.
++ */
++ set_kdebugflag (kdebugflag);
++
++ return master_fd;
++}
++
++/********************************************************************
++ *
++ * restore_loop - reattach the ppp unit to the loopback.
++ *
++ * The kernel ppp driver automatically reattaches the ppp unit to
++ * the loopback if the serial port is set to a line discipline other
++ * than ppp, or if it detects a modem hangup. The former will happen
++ * in disestablish_ppp if the latter hasn't already happened, so we
++ * shouldn't need to do anything.
++ *
++ * Just to be sure, set the real serial port to the normal discipline.
++ */
++
++static void
++restore_loop(void)
++{
++ looped = 1;
++ if (new_style_driver) {
++ set_flags(ppp_dev_fd, get_flags(ppp_dev_fd) | SC_LOOP_TRAFFIC);
++ return;
++ }
++ if (ppp_fd != slave_fd) {
++ (void) ioctl(ppp_fd, TIOCSETD, &amp;tty_disc);
++ set_ppp_fd(slave_fd);
++ }
++}
++
++/********************************************************************
++ *
++ * sifnpmode - Set the mode for handling packets for a given NP.
++ */
++
++int
++sifnpmode(u, proto, mode)
++ int u;
++ int proto;
++ enum NPmode mode;
++{
++ struct npioctl npi;
++
++ npi.protocol = proto;
++ npi.mode = mode;
++ if (ioctl(ppp_dev_fd, PPPIOCSNPMODE, (caddr_t) &amp;npi) &lt; 0) {
++ if (! ok_error (errno))
++ error(&quot;ioctl(PPPIOCSNPMODE, %d, %d): %m (%d)&quot;,
++ proto, mode, errno);
++ return 0;
++ }
++ return 1;
++}
++
++
++/********************************************************************
++ *
++ * sipxfaddr - Config the interface IPX networknumber
++ */
++
++int sipxfaddr (int unit, unsigned long int network, unsigned char * node )
++{
++ int result = 1;
++
++#ifdef IPX_CHANGE
++ int skfd;
++ struct ifreq ifr;
++ struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) &amp;ifr.ifr_addr;
++
++ skfd = socket (AF_IPX, SOCK_DGRAM, 0);
++ if (skfd &lt; 0) {
++ if (! ok_error (errno))
++ dbglog(&quot;socket(AF_IPX): %m (%d)&quot;, errno);
++ result = 0;
++ }
++ else {
++ memset (&amp;ifr, '\0', sizeof (ifr));
++ strlcpy (ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
++
++ memcpy (sipx-&gt;sipx_node, node, IPX_NODE_LEN);
++ sipx-&gt;sipx_family = AF_IPX;
++ sipx-&gt;sipx_port = 0;
++ sipx-&gt;sipx_network = htonl (network);
++ sipx-&gt;sipx_type = IPX_FRAME_ETHERII;
++ sipx-&gt;sipx_action = IPX_CRTITF;
++/*
++ * Set the IPX device
++ */
++ if (ioctl(skfd, SIOCSIFADDR, (caddr_t) &amp;ifr) &lt; 0) {
++ result = 0;
++ if (errno != EEXIST) {
++ if (! ok_error (errno))
++ dbglog(&quot;ioctl(SIOCSIFADDR, CRTITF): %m (%d)&quot;, errno);
++ }
++ else {
++ warn(&quot;ioctl(SIOCSIFADDR, CRTITF): Address already exists&quot;);
++ }
++ }
++ close (skfd);
++ }
++#endif
++ return result;
++}
++
++/********************************************************************
++ *
++ * cipxfaddr - Clear the information for the IPX network. The IPX routes
++ * are removed and the device is no longer able to pass IPX
++ * frames.
++ */
++
++int cipxfaddr (int unit)
++{
++ int result = 1;
++
++#ifdef IPX_CHANGE
++ int skfd;
++ struct ifreq ifr;
++ struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) &amp;ifr.ifr_addr;
++
++ skfd = socket (AF_IPX, SOCK_DGRAM, 0);
++ if (skfd &lt; 0) {
++ if (! ok_error (errno))
++ dbglog(&quot;socket(AF_IPX): %m (%d)&quot;, errno);
++ result = 0;
++ }
++ else {
++ memset (&amp;ifr, '\0', sizeof (ifr));
++ strlcpy (ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
++
++ sipx-&gt;sipx_type = IPX_FRAME_ETHERII;
++ sipx-&gt;sipx_action = IPX_DLTITF;
++ sipx-&gt;sipx_family = AF_IPX;
++/*
++ * Set the IPX device
++ */
++ if (ioctl(skfd, SIOCSIFADDR, (caddr_t) &amp;ifr) &lt; 0) {
++ if (! ok_error (errno))
++ info(&quot;ioctl(SIOCSIFADDR, IPX_DLTITF): %m (%d)&quot;, errno);
++ result = 0;
++ }
++ close (skfd);
++ }
++#endif
++ return result;
++}
++
++/*
++ * Use the hostname as part of the random number seed.
++ */
++int
++get_host_seed()
++{
++ int h;
++ char *p = hostname;
++
++ h = 407;
++ for (p = hostname; *p != 0; ++p)
++ h = h * 37 + *p;
++ return h;
++}
++
++/********************************************************************
++ *
++ * sys_check_options - check the options that the user specified
++ */
++
++int
++sys_check_options(void)
++{
++#ifdef IPX_CHANGE
++/*
++ * Disable the IPX protocol if the support is not present in the kernel.
++ */
++ char *path;
++
++ if (ipxcp_protent.enabled_flag) {
++ struct stat stat_buf;
++ if ((path = path_to_procfs(&quot;/net/ipx_interface&quot;)) == 0
++ || lstat(path, &amp;stat_buf) &lt; 0) {
++ error(&quot;IPX support is not present in the kernel\n&quot;);
++ ipxcp_protent.enabled_flag = 0;
++ }
++ }
++#endif
++ if (demand &amp;&amp; driver_is_old) {
++ option_error(&quot;demand dialling is not supported by kernel driver &quot;
++ &quot;version %d.%d.%d&quot;, driver_version, driver_modification,
++ driver_patch);
++ return 0;
++ }
++ if (multilink &amp;&amp; !new_style_driver) {
++ warn(&quot;Warning: multilink is not supported by the kernel driver&quot;);
++ multilink = 0;
++ }
++ return 1;
++}
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/sys-solaris.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/sys-solaris.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/sys-solaris.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,2737 @@
++/*
++ * System-dependent procedures for pppd under Solaris 2.
++ *
++ * Parts re-written by Adi Masputra &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">adi.masputra at sun.com</A>&gt;, based on
++ * the original sys-svr4.c
++ *
++ * Copyright (c) 2000 by Sun Microsystems, Inc.
++ * All rights reserved.
++ *
++ * Permission to use, copy, modify, and distribute this software and its
++ * documentation is hereby granted, provided that the above copyright
++ * notice appears in all copies.
++ *
++ * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
++ * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
++ * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
++ * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
++ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
++ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
++ *
++ * Copyright (c) 1994 The Australian National University.
++ * All rights reserved.
++ *
++ * Permission to use, copy, modify, and distribute this software and its
++ * documentation is hereby granted, provided that the above copyright
++ * notice appears in all copies. This software is provided without any
++ * warranty, express or implied. The Australian National University
++ * makes no representations about the suitability of this software for
++ * any purpose.
++ *
++ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
++ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
++ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
++ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
++ * OF SUCH DAMAGE.
++ *
++ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
++ * ON AN &quot;AS IS&quot; BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
++ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
++ * OR MODIFICATIONS.
++ */
++
++#define RCSID &quot;$Id: sys-solaris.c 195720 2001-06-11 11:44:34Z gc $&quot;
++
++#include &lt;limits.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;stddef.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;ctype.h&gt;
++#include &lt;errno.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;termios.h&gt;
++#ifndef CRTSCTS
++#include &lt;sys/termiox.h&gt;
++#endif
++#include &lt;signal.h&gt;
++#include &lt;utmpx.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/ioccom.h&gt;
++#include &lt;sys/stream.h&gt;
++#include &lt;sys/stropts.h&gt;
++#include &lt;sys/socket.h&gt;
++#include &lt;sys/sockio.h&gt;
++#include &lt;sys/sysmacros.h&gt;
++#include &lt;sys/systeminfo.h&gt;
++#include &lt;sys/dlpi.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;sys/mkdev.h&gt;
++#include &lt;net/if.h&gt;
++#include &lt;net/if_arp.h&gt;
++#include &lt;net/route.h&gt;
++#include &lt;net/ppp_defs.h&gt;
++#include &lt;net/pppio.h&gt;
++#include &lt;netinet/in.h&gt;
++#ifdef SOL2
++#include &lt;sys/tihdr.h&gt;
++#include &lt;sys/tiuser.h&gt;
++#include &lt;inet/common.h&gt;
++#include &lt;inet/mib2.h&gt;
++#include &lt;sys/ethernet.h&gt;
++#endif
++
++#include &quot;pppd.h&quot;
++#include &quot;fsm.h&quot;
++#include &quot;lcp.h&quot;
++#include &quot;ipcp.h&quot;
++#include &quot;ccp.h&quot;
++
++#if !defined(PPP_DRV_NAME)
++#define PPP_DRV_NAME &quot;ppp&quot;
++#endif /* !defined(PPP_DRV_NAME) */
++
++#if !defined(PPP_DEV_NAME)
++#define PPP_DEV_NAME &quot;/dev/&quot; PPP_DRV_NAME
++#endif /* !defined(PPP_DEV_NAME) */
++
++#if !defined(AHDLC_MOD_NAME)
++#define AHDLC_MOD_NAME &quot;ppp_ahdl&quot;
++#endif /* !defined(AHDLC_MOD_NAME) */
++
++#if !defined(COMP_MOD_NAME)
++#define COMP_MOD_NAME &quot;ppp_comp&quot;
++#endif /* !defined(COMP_MOD_NAME) */
++
++#if !defined(IP_DEV_NAME)
++#define IP_DEV_NAME &quot;/dev/ip&quot;
++#endif /* !defined(IP_DEV_NAME) */
++
++#if !defined(IP_MOD_NAME)
++#define IP_MOD_NAME &quot;ip&quot;
++#endif /* !defined(IP_MOD_NAME) */
++
++#if !defined(UDP_DEV_NAME) &amp;&amp; defined(SOL2)
++#define UDP_DEV_NAME &quot;/dev/udp&quot;
++#endif /* !defined(UDP_DEV_NAME) &amp;&amp; defined(SOL2) */
++
++#if !defined(UDP6_DEV_NAME) &amp;&amp; defined(SOL2)
++#define UDP6_DEV_NAME &quot;/dev/udp6&quot;
++#endif /* !defined(UDP6_DEV_NAME) &amp;&amp; defined(SOL2) */
++
++static const char rcsid[] = RCSID;
++
++#if defined(SOL2)
++/*
++ * &quot;/dev/udp&quot; is used as a multiplexor to PLINK the interface stream
++ * under. It is used in place of &quot;/dev/ip&quot; since STREAMS will not let
++ * a driver be PLINK'ed under itself, and &quot;/dev/ip&quot; is typically the
++ * driver at the bottom of the tunneling interfaces stream.
++ */
++static char *mux_dev_name = UDP_DEV_NAME;
++#else
++static char *mux_dev_name = IP_DEV_NAME;
++#endif
++static int pppfd;
++static int fdmuxid = -1;
++static int ipfd;
++static int ipmuxid = -1;
++
++#if defined(INET6) &amp;&amp; defined(SOL2)
++static int ip6fd; /* IP file descriptor */
++static int ip6muxid = -1; /* Multiplexer file descriptor */
++static int if6_is_up = 0; /* IPv6 interface has been marked up */
++
++#define _IN6_LLX_FROM_EUI64(l, s, eui64, as) do { \
++ s-&gt;sin6_addr.s6_addr32[0] = htonl(as); \
++ eui64_copy(eui64, s-&gt;sin6_addr.s6_addr32[2]); \
++ s-&gt;sin6_family = AF_INET6; \
++ l.lifr_addr.ss_family = AF_INET6; \
++ l.lifr_addrlen = 10; \
++ l.lifr_addr = laddr; \
++ } while (0)
++
++#define IN6_LLADDR_FROM_EUI64(l, s, eui64) \
++ _IN6_LLX_FROM_EUI64(l, s, eui64, 0xfe800000)
++
++#define IN6_LLTOKEN_FROM_EUI64(l, s, eui64) \
++ _IN6_LLX_FROM_EUI64(l, s, eui64, 0)
++
++#endif /* defined(INET6) &amp;&amp; defined(SOL2) */
++
++#if defined(INET6) &amp;&amp; defined(SOL2)
++static char first_ether_name[LIFNAMSIZ]; /* Solaris 8 and above */
++#else
++static char first_ether_name[IFNAMSIZ]; /* Before Solaris 8 */
++#define MAXIFS 256 /* Max # of interfaces */
++#endif /* defined(INET6) &amp;&amp; defined(SOL2) */
++
++static int restore_term;
++static struct termios inittermios;
++#ifndef CRTSCTS
++static struct termiox inittermiox;
++static int termiox_ok;
++#endif
++static struct winsize wsinfo; /* Initial window size info */
++static pid_t tty_sid; /* original session ID for terminal */
++
++extern u_char inpacket_buf[]; /* borrowed from main.c */
++
++#define MAX_POLLFDS 32
++static struct pollfd pollfds[MAX_POLLFDS];
++static int n_pollfds;
++
++static int link_mtu, link_mru;
++
++#define NMODULES 32
++static int tty_nmodules;
++static char tty_modules[NMODULES][FMNAMESZ+1];
++static int tty_npushed;
++
++static int if_is_up; /* Interface has been marked up */
++static u_int32_t remote_addr; /* IP address of peer */
++static u_int32_t default_route_gateway; /* Gateway for default route added */
++static u_int32_t proxy_arp_addr; /* Addr for proxy arp entry added */
++
++/* Prototypes for procedures local to this file. */
++static int translate_speed __P((int));
++static int baud_rate_of __P((int));
++static int get_ether_addr __P((u_int32_t, struct sockaddr *));
++static int get_hw_addr __P((char *, u_int32_t, struct sockaddr *));
++static int get_hw_addr_dlpi __P((char *, struct sockaddr *));
++static int dlpi_attach __P((int, int));
++static int dlpi_info_req __P((int));
++static int dlpi_get_reply __P((int, union DL_primitives *, int, int));
++static int strioctl __P((int, int, void *, int, int));
++
++#ifdef SOL2
++/*
++ * sifppa - Sets interface ppa
++ *
++ * without setting the ppa, ip module will return EINVAL upon setting the
++ * interface UP (SIOCSxIFFLAGS). This is because ip module in 2.8 expects
++ * two DLPI_INFO_REQ to be sent down to the driver (below ip) before
++ * IFF_UP can be set. Plumbing the device causes one DLPI_INFO_REQ to
++ * be sent down, and the second DLPI_INFO_REQ is sent upon receiving
++ * IF_UNITSEL (old) or SIOCSLIFNAME (new) ioctls. Such setting of the ppa
++ * is required because the ppp DLPI provider advertises itself as
++ * a DLPI style 2 type, which requires a point of attachment to be
++ * specified. The only way the user can specify a point of attachment
++ * is via SIOCSLIFNAME or IF_UNITSEL.
++ *
++ * Such changes in the behavior of ip module was made to meet new or
++ * evolving standards requirements.
++ *
++ */
++static int
++sifppa(fd, ppa)
++ int fd;
++ int ppa;
++{
++ return (int)ioctl(fd, IF_UNITSEL, (char *)&amp;ppa);
++}
++#endif /* SOL2 */
++
++#if defined(SOL2) &amp;&amp; defined(INET6)
++/*
++ * get_first_ethernet - returns the first Ethernet interface name found in
++ * the system, or NULL if none is found
++ *
++ * NOTE: This is the lifreq version (Solaris 8 and above)
++ */
++char *
++get_first_ethernet()
++{
++ struct lifnum lifn;
++ struct lifconf lifc;
++ struct lifreq *plifreq;
++ struct lifreq lifr;
++ int fd, num_ifs, i, found;
++ uint_t fl, req_size;
++ char *req;
++
++ fd = socket(AF_INET, SOCK_DGRAM, 0);
++ if (fd &lt; 0) {
++ return 0;
++ }
++
++ /*
++ * Find out how many interfaces are running
++ */
++ lifn.lifn_family = AF_UNSPEC;
++ lifn.lifn_flags = LIFC_NOXMIT;
++ if (ioctl(fd, SIOCGLIFNUM, &amp;lifn) &lt; 0) {
++ close(fd);
++ error(&quot;could not determine number of interfaces: %m&quot;);
++ return 0;
++ }
++
++ num_ifs = lifn.lifn_count;
++ req_size = num_ifs * sizeof(struct lifreq);
++ req = malloc(req_size);
++ if (req == NULL) {
++ close(fd);
++ error(&quot;out of memory&quot;);
++ return 0;
++ }
++
++ /*
++ * Get interface configuration info for all interfaces
++ */
++ lifc.lifc_family = AF_UNSPEC;
++ lifc.lifc_flags = LIFC_NOXMIT;
++ lifc.lifc_len = req_size;
++ lifc.lifc_buf = req;
++ if (ioctl(fd, SIOCGLIFCONF, &amp;lifc) &lt; 0) {
++ close(fd);
++ free(req);
++ error(&quot;SIOCGLIFCONF: %m&quot;);
++ return 0;
++ }
++
++ /*
++ * And traverse each interface to look specifically for the first
++ * occurence of an Ethernet interface which has been marked up
++ */
++ plifreq = lifc.lifc_req;
++ found = 0;
++ for (i = lifc.lifc_len / sizeof(struct lifreq); i &gt; 0; i--, plifreq++) {
++
++ if (strchr(plifreq-&gt;lifr_name, ':') != NULL)
++ continue;
++
++ memset(&amp;lifr, 0, sizeof(lifr));
++ strncpy(lifr.lifr_name, plifreq-&gt;lifr_name, sizeof(lifr.lifr_name));
++ if (ioctl(fd, SIOCGLIFFLAGS, &amp;lifr) &lt; 0) {
++ close(fd);
++ free(req);
++ error(&quot;SIOCGLIFFLAGS: %m&quot;);
++ return 0;
++ }
++ fl = lifr.lifr_flags;
++
++ if ((fl &amp; (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
++ != (IFF_UP | IFF_BROADCAST))
++ continue;
++
++ found = 1;
++ break;
++ }
++ free(req);
++ close(fd);
++
++ if (found) {
++ strncpy(first_ether_name, lifr.lifr_name, sizeof(first_ether_name));
++ return (char *)first_ether_name;
++ } else
++ return NULL;
++}
++#else
++/*
++ * get_first_ethernet - returns the first Ethernet interface name found in
++ * the system, or NULL if none is found
++ *
++ * NOTE: This is the ifreq version (before Solaris 8).
++ */
++char *
++get_first_ethernet()
++{
++ struct ifconf ifc;
++ struct ifreq *pifreq;
++ struct ifreq ifr;
++ int fd, num_ifs, i, found;
++ uint_t fl, req_size;
++ char *req;
++
++ fd = socket(AF_INET, SOCK_DGRAM, 0);
++ if (fd &lt; 0) {
++ return 0;
++ }
++
++ /*
++ * Find out how many interfaces are running
++ */
++ if (ioctl(fd, SIOCGIFNUM, (char *)&amp;num_ifs) &lt; 0) {
++ num_ifs = MAXIFS;
++ }
++
++ req_size = num_ifs * sizeof(struct ifreq);
++ req = malloc(req_size);
++ if (req == NULL) {
++ close(fd);
++ error(&quot;out of memory&quot;);
++ return 0;
++ }
++
++ /*
++ * Get interface configuration info for all interfaces
++ */
++ ifc.ifc_len = req_size;
++ ifc.ifc_buf = req;
++ if (ioctl(fd, SIOCGIFCONF, &amp;ifc) &lt; 0) {
++ close(fd);
++ free(req);
++ error(&quot;SIOCGIFCONF: %m&quot;);
++ return 0;
++ }
++
++ /*
++ * And traverse each interface to look specifically for the first
++ * occurence of an Ethernet interface which has been marked up
++ */
++ pifreq = ifc.ifc_req;
++ found = 0;
++ for (i = ifc.ifc_len / sizeof(struct ifreq); i &gt; 0; i--, pifreq++) {
++
++ if (strchr(pifreq-&gt;ifr_name, ':') != NULL)
++ continue;
++
++ memset(&amp;ifr, 0, sizeof(ifr));
++ strncpy(ifr.ifr_name, pifreq-&gt;ifr_name, sizeof(ifr.ifr_name));
++ if (ioctl(fd, SIOCGIFFLAGS, &amp;ifr) &lt; 0) {
++ close(fd);
++ free(req);
++ error(&quot;SIOCGIFFLAGS: %m&quot;);
++ return 0;
++ }
++ fl = ifr.ifr_flags;
++
++ if ((fl &amp; (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
++ != (IFF_UP | IFF_BROADCAST))
++ continue;
++
++ found = 1;
++ break;
++ }
++ free(req);
++ close(fd);
++
++ if (found) {
++ strncpy(first_ether_name, ifr.ifr_name, sizeof(first_ether_name));
++ return (char *)first_ether_name;
++ } else
++ return NULL;
++}
++#endif /* defined(SOL2) &amp;&amp; defined(INET6) */
++
++#if defined(SOL2)
++/*
++ * get_if_hwaddr - get the hardware address for the specified
++ * network interface device.
++ */
++int
++get_if_hwaddr(u_char *addr, char *if_name)
++{
++ struct sockaddr s_eth_addr;
++ struct ether_addr *eth_addr = (struct ether_addr *)&amp;s_eth_addr.sa_data;
++
++ if (if_name == NULL)
++ return -1;
++
++ /*
++ * Send DL_INFO_REQ to the driver to solicit its MAC address
++ */
++ if (!get_hw_addr_dlpi(if_name, &amp;s_eth_addr)) {
++ error(&quot;could not obtain hardware address for %s&quot;, if_name);
++ return -1;
++ }
++
++ memcpy(addr, eth_addr-&gt;ether_addr_octet, 6);
++ return 1;
++}
++#endif /* SOL2 */
++
++#if defined(SOL2) &amp;&amp; defined(INET6)
++/*
++ * slifname - Sets interface ppa and flags
++ *
++ * in addition to the comments stated in sifppa(), IFF_IPV6 bit must
++ * be set in order to declare this as an IPv6 interface
++ */
++static int
++slifname(fd, ppa)
++ int fd;
++ int ppa;
++{
++ struct lifreq lifr;
++ int ret;
++
++ memset(&amp;lifr, 0, sizeof(lifr));
++ ret = ioctl(fd, SIOCGLIFFLAGS, &amp;lifr);
++ if (ret &lt; 0)
++ goto slifname_done;
++
++ lifr.lifr_flags |= IFF_IPV6;
++ lifr.lifr_flags &amp;= ~(IFF_BROADCAST | IFF_IPV4);
++ lifr.lifr_ppa = ppa;
++ strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
++
++ ret = ioctl(fd, SIOCSLIFNAME, &amp;lifr);
++
++slifname_done:
++ return ret;
++
++
++}
++
++
++/*
++ * ether_to_eui64 - Convert 48-bit Ethernet address into 64-bit EUI
++ *
++ * walks the list of valid ethernet interfaces, and convert the first
++ * found 48-bit MAC address into EUI 64. caller also assumes that
++ * the system has a properly configured Ethernet interface for this
++ * function to return non-zero.
++ */
++int
++ether_to_eui64(eui64_t *p_eui64)
++{
++ struct sockaddr s_eth_addr;
++ struct ether_addr *eth_addr = (struct ether_addr *)&amp;s_eth_addr.sa_data;
++ char *if_name;
++
++ if ((if_name = get_first_ethernet()) == NULL) {
++ error(&quot;no persistent id can be found&quot;);
++ return 0;
++ }
++
++ /*
++ * Send DL_INFO_REQ to the driver to solicit its MAC address
++ */
++ if (!get_hw_addr_dlpi(if_name, &amp;s_eth_addr)) {
++ error(&quot;could not obtain hardware address for %s&quot;, if_name);
++ return 0;
++ }
++
++ /*
++ * And convert the EUI-48 into EUI-64, per RFC 2472 [sec 4.1]
++ */
++ p_eui64-&gt;e8[0] = (eth_addr-&gt;ether_addr_octet[0] &amp; 0xFF) | 0x02;
++ p_eui64-&gt;e8[1] = (eth_addr-&gt;ether_addr_octet[1] &amp; 0xFF);
++ p_eui64-&gt;e8[2] = (eth_addr-&gt;ether_addr_octet[2] &amp; 0xFF);
++ p_eui64-&gt;e8[3] = 0xFF;
++ p_eui64-&gt;e8[4] = 0xFE;
++ p_eui64-&gt;e8[5] = (eth_addr-&gt;ether_addr_octet[3] &amp; 0xFF);
++ p_eui64-&gt;e8[6] = (eth_addr-&gt;ether_addr_octet[4] &amp; 0xFF);
++ p_eui64-&gt;e8[7] = (eth_addr-&gt;ether_addr_octet[5] &amp; 0xFF);
++
++ return 1;
++}
++#endif /* defined(SOL2) &amp;&amp; defined(INET6) */
++
++/*
++ * sys_init - System-dependent initialization.
++ */
++void
++sys_init()
++{
++ int ifd, x;
++ struct ifreq ifr;
++#if defined(INET6) &amp;&amp; defined(SOL2)
++ int i6fd;
++ struct lifreq lifr;
++#endif /* defined(INET6) &amp;&amp; defined(SOL2) */
++#if !defined(SOL2)
++ struct {
++ union DL_primitives prim;
++ char space[64];
++ } reply;
++#endif /* !defined(SOL2) */
++
++ ipfd = open(mux_dev_name, O_RDWR, 0);
++ if (ipfd &lt; 0)
++ fatal(&quot;Couldn't open IP device: %m&quot;);
++
++#if defined(INET6) &amp;&amp; defined(SOL2)
++ ip6fd = open(UDP6_DEV_NAME, O_RDWR, 0);
++ if (ip6fd &lt; 0)
++ fatal(&quot;Couldn't open IP device (2): %m&quot;);
++#endif /* defined(INET6) &amp;&amp; defined(SOL2) */
++
++ if (default_device &amp;&amp; !notty)
++ tty_sid = getsid((pid_t)0);
++
++ pppfd = open(PPP_DEV_NAME, O_RDWR | O_NONBLOCK, 0);
++ if (pppfd &lt; 0)
++ fatal(&quot;Can't open %s: %m&quot;, PPP_DEV_NAME);
++ if (kdebugflag &amp; 1) {
++ x = PPPDBG_LOG + PPPDBG_DRIVER;
++ strioctl(pppfd, PPPIO_DEBUG, &amp;x, sizeof(int), 0);
++ }
++
++ /* Assign a new PPA and get its unit number. */
++ if (strioctl(pppfd, PPPIO_NEWPPA, &amp;ifunit, 0, sizeof(int)) &lt; 0)
++ fatal(&quot;Can't create new PPP interface: %m&quot;);
++
++#if defined(SOL2)
++ /*
++ * Since sys_init() is called prior to ifname being set in main(),
++ * we need to get the ifname now, otherwise slifname(), and others,
++ * will fail, or maybe, I should move them to a later point ?
++ * &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">adi.masputra at sun.com</A>&gt;
++ */
++ sprintf(ifname, PPP_DRV_NAME &quot;%d&quot;, ifunit);
++#endif /* defined(SOL2) */
++ /*
++ * Open the ppp device again and link it under the ip multiplexor.
++ * IP will assign a unit number which hopefully is the same as ifunit.
++ * I don't know any way to be certain they will be the same. :-(
++ */
++ ifd = open(PPP_DEV_NAME, O_RDWR, 0);
++ if (ifd &lt; 0)
++ fatal(&quot;Can't open %s (2): %m&quot;, PPP_DEV_NAME);
++ if (kdebugflag &amp; 1) {
++ x = PPPDBG_LOG + PPPDBG_DRIVER;
++ strioctl(ifd, PPPIO_DEBUG, &amp;x, sizeof(int), 0);
++ }
++
++#if defined(INET6) &amp;&amp; defined(SOL2)
++ i6fd = open(PPP_DEV_NAME, O_RDWR, 0);
++ if (i6fd &lt; 0) {
++ close(ifd);
++ fatal(&quot;Can't open %s (3): %m&quot;, PPP_DEV_NAME);
++ }
++ if (kdebugflag &amp; 1) {
++ x = PPPDBG_LOG + PPPDBG_DRIVER;
++ strioctl(i6fd, PPPIO_DEBUG, &amp;x, sizeof(int), 0);
++ }
++#endif /* defined(INET6) &amp;&amp; defined(SOL2) */
++
++#if defined(SOL2)
++ if (ioctl(ifd, I_PUSH, IP_MOD_NAME) &lt; 0) {
++ close(ifd);
++#if defined(INET6)
++ close(i6fd);
++#endif /* defined(INET6) */
++ fatal(&quot;Can't push IP module: %m&quot;);
++ }
++
++ /*
++ * Assign ppa according to the unit number returned by ppp device
++ * after plumbing is completed above.
++ */
++ if (sifppa(ifd, ifunit) &lt; 0) {
++ close (ifd);
++#if defined(INET6)
++ close(i6fd);
++#endif /* defined(INET6) */
++ fatal(&quot;Can't set ppa for unit %d: %m&quot;, ifunit);
++ }
++
++#if defined(INET6)
++ /*
++ * An IPv6 interface is created anyway, even when the user does not
++ * explicitly enable it. Note that the interface will be marked
++ * IPv6 during slifname().
++ */
++ if (ioctl(i6fd, I_PUSH, IP_MOD_NAME) &lt; 0) {
++ close(ifd);
++ close(i6fd);
++ fatal(&quot;Can't push IP module (2): %m&quot;);
++ }
++
++ /*
++ * Assign ppa according to the unit number returned by ppp device
++ * after plumbing is completed above. In addition, mark the interface
++ * as an IPv6 interface.
++ */
++ if (slifname(i6fd, ifunit) &lt; 0) {
++ close(ifd);
++ close(i6fd);
++ fatal(&quot;Can't set ifname for unit %d: %m&quot;, ifunit);
++ }
++#endif /* defined(INET6) */
++
++ ipmuxid = ioctl(ipfd, I_PLINK, ifd);
++ close(ifd);
++ if (ipmuxid &lt; 0) {
++#if defined(INET6)
++ close(i6fd);
++#endif /* defined(INET6) */
++ fatal(&quot;Can't I_PLINK PPP device to IP: %m&quot;);
++ }
++
++ memset(&amp;ifr, 0, sizeof(ifr));
++ sprintf(ifr.ifr_name, &quot;%s&quot;, ifname);
++ ifr.ifr_ip_muxid = ipmuxid;
++
++ /*
++ * In Sol 8 and later, STREAMS dynamic module plumbing feature exists.
++ * This is so that an arbitrary module can be inserted, or deleted,
++ * between ip module and the device driver without tearing down the
++ * existing stream. Such feature requires the mux ids, which is set
++ * by SIOCSIFMUXID (or SIOCLSIFMUXID).
++ */
++ if (ioctl(ipfd, SIOCSIFMUXID, &amp;ifr) &lt; 0) {
++ ioctl(ipfd, I_PUNLINK, ipmuxid);
++#if defined(INET6)
++ close(i6fd);
++#endif /* defined(INET6) */
++ fatal(&quot;SIOCSIFMUXID: %m&quot;);
++ }
++
++#else /* else if !defined(SOL2) */
++
++ if (dlpi_attach(ifd, ifunit) &lt; 0 ||
++ dlpi_get_reply(ifd, &amp;reply.prim, DL_OK_ACK, sizeof(reply)) &lt; 0) {
++ close(ifd);
++ fatal(&quot;Can't attach to ppp%d: %m&quot;, ifunit);
++ }
++
++ ipmuxid = ioctl(ipfd, I_LINK, ifd);
++ close(ifd);
++ if (ipmuxid &lt; 0)
++ fatal(&quot;Can't link PPP device to IP: %m&quot;);
++#endif /* defined(SOL2) */
++
++#if defined(INET6) &amp;&amp; defined(SOL2)
++ ip6muxid = ioctl(ip6fd, I_PLINK, i6fd);
++ close(i6fd);
++ if (ip6muxid &lt; 0) {
++ ioctl(ipfd, I_PUNLINK, ipmuxid);
++ fatal(&quot;Can't I_PLINK PPP device to IP (2): %m&quot;);
++ }
++
++ memset(&amp;lifr, 0, sizeof(lifr));
++ sprintf(lifr.lifr_name, &quot;%s&quot;, ifname);
++ lifr.lifr_ip_muxid = ip6muxid;
++
++ /*
++ * Let IP know of the mux id [see comment for SIOCSIFMUXID above]
++ */
++ if (ioctl(ip6fd, SIOCSLIFMUXID, &amp;lifr) &lt; 0) {
++ ioctl(ipfd, I_PUNLINK, ipmuxid);
++ ioctl(ip6fd, I_PUNLINK, ip6muxid);
++ fatal(&quot;Can't link PPP device to IP (2): %m&quot;);
++ }
++#endif /* defined(INET6) &amp;&amp; defined(SOL2) */
++
++#if !defined(SOL2)
++ /* Set the interface name for the link. */
++ slprintf(ifr.ifr_name, sizeof(ifr.ifr_name), PPP_DRV_NAME &quot;%d&quot;, ifunit);
++ ifr.ifr_metric = ipmuxid;
++ if (strioctl(ipfd, SIOCSIFNAME, (char *)&amp;ifr, sizeof ifr, 0) &lt; 0)
++ fatal(&quot;Can't set interface name %s: %m&quot;, ifr.ifr_name);
++#endif /* !defined(SOL2) */
++
++ n_pollfds = 0;
++}
++
++/*
++ * sys_cleanup - restore any system state we modified before exiting:
++ * mark the interface down, delete default route and/or proxy arp entry.
++ * This should call die() because it's called from die().
++ */
++void
++sys_cleanup()
++{
++#if defined(SOL2)
++ struct ifreq ifr;
++#if defined(INET6)
++ struct lifreq lifr;
++#endif /* defined(INET6) */
++#endif /* defined(SOL2) */
++
++#if defined(SOL2) &amp;&amp; defined(INET6)
++ if (if6_is_up)
++ sif6down(0);
++#endif /* defined(SOL2) &amp;&amp; defined(INET6) */
++ if (if_is_up)
++ sifdown(0);
++ if (default_route_gateway)
++ cifdefaultroute(0, default_route_gateway, default_route_gateway);
++ if (proxy_arp_addr)
++ cifproxyarp(0, proxy_arp_addr);
++#if defined(SOL2)
++ /*
++ * Make sure we ask ip what the muxid, because 'ifconfig modlist' will
++ * unlink and re-link the modules, causing the muxid to change.
++ */
++ memset(&amp;ifr, 0, sizeof(ifr));
++ sprintf(ifr.ifr_name, &quot;%s&quot;, ifname);
++ if (ioctl(ipfd, SIOCGIFFLAGS, &amp;ifr) &lt; 0) {
++ error(&quot;SIOCGIFFLAGS: %m&quot;);
++ return;
++ }
++
++ if (ioctl(ipfd, SIOCGIFMUXID, &amp;ifr) &lt; 0) {
++ error(&quot;SIOCGIFMUXID: %m&quot;);
++ return;
++ }
++
++ ipmuxid = ifr.ifr_ip_muxid;
++
++ if (ioctl(ipfd, I_PUNLINK, ipmuxid) &lt; 0) {
++ error(&quot;Can't I_PUNLINK PPP from IP: %m&quot;);
++ return;
++ }
++#if defined(INET6)
++ /*
++ * Make sure we ask ip what the muxid, because 'ifconfig modlist' will
++ * unlink and re-link the modules, causing the muxid to change.
++ */
++ memset(&amp;lifr, 0, sizeof(lifr));
++ sprintf(lifr.lifr_name, &quot;%s&quot;, ifname);
++ if (ioctl(ip6fd, SIOCGLIFFLAGS, &amp;lifr) &lt; 0) {
++ error(&quot;SIOCGLIFFLAGS: %m&quot;);
++ return;
++ }
++
++ if (ioctl(ip6fd, SIOCGLIFMUXID, &amp;lifr) &lt; 0) {
++ error(&quot;SIOCGLIFMUXID: %m&quot;);
++ return;
++ }
++
++ ip6muxid = lifr.lifr_ip_muxid;
++
++ if (ioctl(ip6fd, I_PUNLINK, ip6muxid) &lt; 0) {
++ error(&quot;Can't I_PUNLINK PPP from IP (2): %m&quot;);
++ }
++#endif /* defined(INET6) */
++#endif /* defined(SOL2) */
++}
++
++/*
++ * sys_close - Clean up in a child process before execing.
++ */
++void
++sys_close()
++{
++ close(ipfd);
++#if defined(INET6) &amp;&amp; defined(SOL2)
++ close(ip6fd);
++#endif /* defined(INET6) &amp;&amp; defined(SOL2) */
++ if (pppfd &gt;= 0)
++ close(pppfd);
++}
++
++/*
++ * sys_check_options - check the options that the user specified
++ */
++int
++sys_check_options()
++{
++ return 1;
++}
++
++#if 0
++/*
++ * daemon - Detach us from controlling terminal session.
++ */
++int
++daemon(nochdir, noclose)
++ int nochdir, noclose;
++{
++ int pid;
++
++ if ((pid = fork()) &lt; 0)
++ return -1;
++ if (pid != 0)
++ exit(0); /* parent dies */
++ setsid();
++ if (!nochdir)
++ chdir(&quot;/&quot;);
++ if (!noclose) {
++ fclose(stdin); /* don't need stdin, stdout, stderr */
++ fclose(stdout);
++ fclose(stderr);
++ }
++ return 0;
++}
++#endif
++
++/*
++ * ppp_available - check whether the system has any ppp interfaces
++ */
++int
++ppp_available()
++{
++ struct stat buf;
++
++ return stat(PPP_DEV_NAME, &amp;buf) &gt;= 0;
++}
++
++/*
++ * any_compressions - see if compression is enabled or not
++ *
++ * In the STREAMS implementation of kernel-portion pppd,
++ * the comp STREAMS module performs the ACFC, PFC, as well
++ * CCP and VJ compressions. However, if the user has explicitly
++ * declare to not enable them from the command line, there is
++ * no point of having the comp module be pushed on the stream.
++ */
++static int
++any_compressions()
++{
++ if ((!lcp_wantoptions[0].neg_accompression) &amp;&amp;
++ (!lcp_wantoptions[0].neg_pcompression) &amp;&amp;
++ (!ccp_protent.enabled_flag) &amp;&amp;
++ (!ipcp_wantoptions[0].neg_vj)) {
++ return 0;
++ }
++ return 1;
++}
++
++/*
++ * tty_establish_ppp - Turn the serial port into a ppp interface.
++ */
++int
++tty_establish_ppp(fd)
++ int fd;
++{
++ int i;
++
++ /* Pop any existing modules off the tty stream. */
++ for (i = 0;; ++i)
++ if (ioctl(fd, I_LOOK, tty_modules[i]) &lt; 0
++ || strcmp(tty_modules[i], &quot;ptem&quot;) == 0
++ || ioctl(fd, I_POP, 0) &lt; 0)
++ break;
++ tty_nmodules = i;
++
++ /* Push the async hdlc module and the compressor module. */
++ tty_npushed = 0;
++
++ if(!sync_serial) {
++ if (ioctl(fd, I_PUSH, AHDLC_MOD_NAME) &lt; 0) {
++ error(&quot;Couldn't push PPP Async HDLC module: %m&quot;);
++ return -1;
++ }
++ ++tty_npushed;
++ }
++ if (kdebugflag &amp; 4) {
++ i = PPPDBG_LOG + PPPDBG_AHDLC;
++ strioctl(pppfd, PPPIO_DEBUG, &amp;i, sizeof(int), 0);
++ }
++ /*
++ * There's no need to push comp module if we don't intend
++ * to compress anything
++ */
++ if (any_compressions()) {
++ if (ioctl(fd, I_PUSH, COMP_MOD_NAME) &lt; 0)
++ error(&quot;Couldn't push PPP compression module: %m&quot;);
++ else
++ ++tty_npushed;
++ }
++
++ if (kdebugflag &amp; 2) {
++ i = PPPDBG_LOG;
++ if (any_compressions())
++ i += PPPDBG_COMP;
++ strioctl(pppfd, PPPIO_DEBUG, &amp;i, sizeof(int), 0);
++ }
++
++ /* Link the serial port under the PPP multiplexor. */
++ if ((fdmuxid = ioctl(pppfd, I_LINK, fd)) &lt; 0) {
++ error(&quot;Can't link tty to PPP mux: %m&quot;);
++ return -1;
++ }
++
++ return pppfd;
++}
++
++/*
++ * tty_disestablish_ppp - Restore the serial port to normal operation.
++ * It attempts to reconstruct the stream with the previously popped
++ * modules. This shouldn't call die() because it's called from die().
++ */
++void
++tty_disestablish_ppp(fd)
++ int fd;
++{
++ int i;
++
++ if (fdmuxid &gt;= 0) {
++ if (ioctl(pppfd, I_UNLINK, fdmuxid) &lt; 0) {
++ if (!hungup)
++ error(&quot;Can't unlink tty from PPP mux: %m&quot;);
++ }
++ fdmuxid = -1;
++
++ if (!hungup) {
++ while (tty_npushed &gt; 0 &amp;&amp; ioctl(fd, I_POP, 0) &gt;= 0)
++ --tty_npushed;
++ for (i = tty_nmodules - 1; i &gt;= 0; --i)
++ if (ioctl(fd, I_PUSH, tty_modules[i]) &lt; 0)
++ error(&quot;Couldn't restore tty module %s: %m&quot;,
++ tty_modules[i]);
++ }
++ if (hungup &amp;&amp; default_device &amp;&amp; tty_sid &gt; 0) {
++ /*
++ * If we have received a hangup, we need to send a SIGHUP
++ * to the terminal's controlling process. The reason is
++ * that the original stream head for the terminal hasn't
++ * seen the M_HANGUP message (it went up through the ppp
++ * driver to the stream head for our fd to /dev/ppp).
++ */
++ kill(tty_sid, SIGHUP);
++ }
++ }
++}
++
++/*
++ * Check whether the link seems not to be 8-bit clean.
++ */
++void
++clean_check()
++{
++ int x;
++ char *s;
++
++ if (strioctl(pppfd, PPPIO_GCLEAN, &amp;x, 0, sizeof(x)) &lt; 0)
++ return;
++ s = NULL;
++ switch (~x) {
++ case RCV_B7_0:
++ s = &quot;bit 7 set to 1&quot;;
++ break;
++ case RCV_B7_1:
++ s = &quot;bit 7 set to 0&quot;;
++ break;
++ case RCV_EVNP:
++ s = &quot;odd parity&quot;;
++ break;
++ case RCV_ODDP:
++ s = &quot;even parity&quot;;
++ break;
++ }
++ if (s != NULL) {
++ warn(&quot;Serial link is not 8-bit clean:&quot;);
++ warn(&quot;All received characters had %s&quot;, s);
++ }
++}
++
++/*
++ * List of valid speeds.
++ */
++struct speed {
++ int speed_int, speed_val;
++} speeds[] = {
++#ifdef B50
++ { 50, B50 },
++#endif
++#ifdef B75
++ { 75, B75 },
++#endif
++#ifdef B110
++ { 110, B110 },
++#endif
++#ifdef B134
++ { 134, B134 },
++#endif
++#ifdef B150
++ { 150, B150 },
++#endif
++#ifdef B200
++ { 200, B200 },
++#endif
++#ifdef B300
++ { 300, B300 },
++#endif
++#ifdef B600
++ { 600, B600 },
++#endif
++#ifdef B1200
++ { 1200, B1200 },
++#endif
++#ifdef B1800
++ { 1800, B1800 },
++#endif
++#ifdef B2000
++ { 2000, B2000 },
++#endif
++#ifdef B2400
++ { 2400, B2400 },
++#endif
++#ifdef B3600
++ { 3600, B3600 },
++#endif
++#ifdef B4800
++ { 4800, B4800 },
++#endif
++#ifdef B7200
++ { 7200, B7200 },
++#endif
++#ifdef B9600
++ { 9600, B9600 },
++#endif
++#ifdef B19200
++ { 19200, B19200 },
++#endif
++#ifdef B38400
++ { 38400, B38400 },
++#endif
++#ifdef EXTA
++ { 19200, EXTA },
++#endif
++#ifdef EXTB
++ { 38400, EXTB },
++#endif
++#ifdef B57600
++ { 57600, B57600 },
++#endif
++#ifdef B76800
++ { 76800, B76800 },
++#endif
++#ifdef B115200
++ { 115200, B115200 },
++#endif
++#ifdef B153600
++ { 153600, B153600 },
++#endif
++#ifdef B230400
++ { 230400, B230400 },
++#endif
++#ifdef B307200
++ { 307200, B307200 },
++#endif
++#ifdef B460800
++ { 460800, B460800 },
++#endif
++ { 0, 0 }
++};
++
++/*
++ * Translate from bits/second to a speed_t.
++ */
++static int
++translate_speed(bps)
++ int bps;
++{
++ struct speed *speedp;
++
++ if (bps == 0)
++ return 0;
++ for (speedp = speeds; speedp-&gt;speed_int; speedp++)
++ if (bps == speedp-&gt;speed_int)
++ return speedp-&gt;speed_val;
++ warn(&quot;speed %d not supported&quot;, bps);
++ return 0;
++}
++
++/*
++ * Translate from a speed_t to bits/second.
++ */
++static int
++baud_rate_of(speed)
++ int speed;
++{
++ struct speed *speedp;
++
++ if (speed == 0)
++ return 0;
++ for (speedp = speeds; speedp-&gt;speed_int; speedp++)
++ if (speed == speedp-&gt;speed_val)
++ return speedp-&gt;speed_int;
++ return 0;
++}
++
++/*
++ * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
++ * at the requested speed, etc. If `local' is true, set CLOCAL
++ * regardless of whether the modem option was specified.
++ */
++void
++set_up_tty(fd, local)
++ int fd, local;
++{
++ int speed;
++ struct termios tios;
++#if !defined (CRTSCTS)
++ struct termiox tiox;
++#endif
++
++ if (!sync_serial &amp;&amp; tcgetattr(fd, &amp;tios) &lt; 0)
++ fatal(&quot;tcgetattr: %m&quot;);
++
++#ifndef CRTSCTS
++ termiox_ok = 1;
++ if (!sync_serial &amp;&amp; ioctl (fd, TCGETX, &amp;tiox) &lt; 0) {
++ termiox_ok = 0;
++ if (errno != ENOTTY)
++ error(&quot;TCGETX: %m&quot;);
++ }
++#endif
++
++ if (!restore_term) {
++ inittermios = tios;
++#ifndef CRTSCTS
++ inittermiox = tiox;
++#endif
++ if (!sync_serial)
++ ioctl(fd, TIOCGWINSZ, &amp;wsinfo);
++ }
++
++ tios.c_cflag &amp;= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
++#ifdef CRTSCTS
++ if (crtscts &gt; 0)
++ tios.c_cflag |= CRTSCTS;
++ else if (crtscts &lt; 0)
++ tios.c_cflag &amp;= ~CRTSCTS;
++#else
++ if (crtscts != 0 &amp;&amp; !termiox_ok) {
++ error(&quot;Can't set RTS/CTS flow control&quot;);
++ } else if (crtscts &gt; 0) {
++ tiox.x_hflag |= RTSXOFF|CTSXON;
++ } else if (crtscts &lt; 0) {
++ tiox.x_hflag &amp;= ~(RTSXOFF|CTSXON);
++ }
++#endif
++
++ tios.c_cflag |= CS8 | CREAD | HUPCL;
++ if (local || !modem)
++ tios.c_cflag |= CLOCAL;
++ tios.c_iflag = IGNBRK | IGNPAR;
++ tios.c_oflag = 0;
++ tios.c_lflag = 0;
++ tios.c_cc[VMIN] = 1;
++ tios.c_cc[VTIME] = 0;
++
++ if (crtscts == -2) {
++ tios.c_iflag |= IXON | IXOFF;
++ tios.c_cc[VSTOP] = 0x13; /* DC3 = XOFF = ^S */
++ tios.c_cc[VSTART] = 0x11; /* DC1 = XON = ^Q */
++ }
++
++ speed = translate_speed(inspeed);
++ if (speed) {
++ cfsetospeed(&amp;tios, speed);
++ cfsetispeed(&amp;tios, speed);
++ } else {
++ speed = cfgetospeed(&amp;tios);
++ /*
++ * We can't proceed if the serial port speed is 0,
++ * since that implies that the serial port is disabled.
++ */
++ if ((speed == B0) &amp;&amp; !sync_serial)
++ fatal(&quot;Baud rate for %s is 0; need explicit baud rate&quot;, devnam);
++ }
++
++ if (!sync_serial &amp;&amp; tcsetattr(fd, TCSAFLUSH, &amp;tios) &lt; 0)
++ fatal(&quot;tcsetattr: %m&quot;);
++
++#ifndef CRTSCTS
++ if (!sync_serial &amp;&amp; termiox_ok &amp;&amp; ioctl (fd, TCSETXF, &amp;tiox) &lt; 0){
++ error(&quot;TCSETXF: %m&quot;);
++ }
++#endif
++
++ baud_rate = inspeed = baud_rate_of(speed);
++ if (!sync_serial)
++ restore_term = 1;
++}
++
++/*
++ * restore_tty - restore the terminal to the saved settings.
++ */
++void
++restore_tty(fd)
++ int fd;
++{
++ if (restore_term) {
++ if (!default_device) {
++ /*
++ * Turn off echoing, because otherwise we can get into
++ * a loop with the tty and the modem echoing to each other.
++ * We presume we are the sole user of this tty device, so
++ * when we close it, it will revert to its defaults anyway.
++ */
++ inittermios.c_lflag &amp;= ~(ECHO | ECHONL);
++ }
++ if (!sync_serial &amp;&amp; tcsetattr(fd, TCSAFLUSH, &amp;inittermios) &lt; 0)
++ if (!hungup &amp;&amp; errno != ENXIO)
++ warn(&quot;tcsetattr: %m&quot;);
++#ifndef CRTSCTS
++ if (!sync_serial &amp;&amp; ioctl (fd, TCSETXF, &amp;inittermiox) &lt; 0){
++ if (!hungup &amp;&amp; errno != ENXIO)
++ error(&quot;TCSETXF: %m&quot;);
++ }
++#endif
++ if (!sync_serial)
++ ioctl(fd, TIOCSWINSZ, &amp;wsinfo);
++ restore_term = 0;
++ }
++}
++
++/*
++ * setdtr - control the DTR line on the serial port.
++ * This is called from die(), so it shouldn't call die().
++ */
++void
++setdtr(fd, on)
++int fd, on;
++{
++ int modembits = TIOCM_DTR;
++
++ ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &amp;modembits);
++}
++
++/*
++ * open_loopback - open the device we use for getting packets
++ * in demand mode. Under Solaris 2, we use our existing fd
++ * to the ppp driver.
++ */
++int
++open_ppp_loopback()
++{
++ return pppfd;
++}
++
++/*
++ * output - Output PPP packet.
++ */
++void
++output(unit, p, len)
++ int unit;
++ u_char *p;
++ int len;
++{
++ struct strbuf data;
++ int retries;
++ struct pollfd pfd;
++
++ if (debug)
++ dbglog(&quot;sent %P&quot;, p, len);
++
++ data.len = len;
++ data.buf = (caddr_t) p;
++ retries = 4;
++ while (putmsg(pppfd, NULL, &amp;data, 0) &lt; 0) {
++ if (--retries &lt; 0 || (errno != EWOULDBLOCK &amp;&amp; errno != EAGAIN)) {
++ if (errno != ENXIO)
++ error(&quot;Couldn't send packet: %m&quot;);
++ break;
++ }
++ pfd.fd = pppfd;
++ pfd.events = POLLOUT;
++ poll(&amp;pfd, 1, 250); /* wait for up to 0.25 seconds */
++ }
++}
++
++
++/*
++ * wait_input - wait until there is data available,
++ * for the length of time specified by *timo (indefinite
++ * if timo is NULL).
++ */
++void
++wait_input(timo)
++ struct timeval *timo;
++{
++ int t;
++
++ t = timo == NULL? -1: timo-&gt;tv_sec * 1000 + timo-&gt;tv_usec / 1000;
++ if (poll(pollfds, n_pollfds, t) &lt; 0 &amp;&amp; errno != EINTR)
++ fatal(&quot;poll: %m&quot;);
++}
++
++/*
++ * add_fd - add an fd to the set that wait_input waits for.
++ */
++void add_fd(fd)
++ int fd;
++{
++ int n;
++
++ for (n = 0; n &lt; n_pollfds; ++n)
++ if (pollfds[n].fd == fd)
++ return;
++ if (n_pollfds &lt; MAX_POLLFDS) {
++ pollfds[n_pollfds].fd = fd;
++ pollfds[n_pollfds].events = POLLIN | POLLPRI | POLLHUP;
++ ++n_pollfds;
++ } else
++ error(&quot;Too many inputs!&quot;);
++}
++
++/*
++ * remove_fd - remove an fd from the set that wait_input waits for.
++ */
++void remove_fd(fd)
++ int fd;
++{
++ int n;
++
++ for (n = 0; n &lt; n_pollfds; ++n) {
++ if (pollfds[n].fd == fd) {
++ while (++n &lt; n_pollfds)
++ pollfds[n-1] = pollfds[n];
++ --n_pollfds;
++ break;
++ }
++ }
++}
++
++#if 0
++/*
++ * wait_loop_output - wait until there is data available on the
++ * loopback, for the length of time specified by *timo (indefinite
++ * if timo is NULL).
++ */
++void
++wait_loop_output(timo)
++ struct timeval *timo;
++{
++ wait_input(timo);
++}
++
++/*
++ * wait_time - wait for a given length of time or until a
++ * signal is received.
++ */
++void
++wait_time(timo)
++ struct timeval *timo;
++{
++ int n;
++
++ n = select(0, NULL, NULL, NULL, timo);
++ if (n &lt; 0 &amp;&amp; errno != EINTR)
++ fatal(&quot;select: %m&quot;);
++}
++#endif
++
++
++/*
++ * read_packet - get a PPP packet from the serial device.
++ */
++int
++read_packet(buf)
++ u_char *buf;
++{
++ struct strbuf ctrl, data;
++ int flags, len;
++ unsigned char ctrlbuf[sizeof(union DL_primitives) + 64];
++
++ for (;;) {
++ data.maxlen = PPP_MRU + PPP_HDRLEN;
++ data.buf = (caddr_t) buf;
++ ctrl.maxlen = sizeof(ctrlbuf);
++ ctrl.buf = (caddr_t) ctrlbuf;
++ flags = 0;
++ len = getmsg(pppfd, &amp;ctrl, &amp;data, &amp;flags);
++ if (len &lt; 0) {
++ if (errno == EAGAIN || errno == EINTR)
++ return -1;
++ fatal(&quot;Error reading packet: %m&quot;);
++ }
++
++ if (ctrl.len &lt;= 0)
++ return data.len;
++
++ /*
++ * Got a M_PROTO or M_PCPROTO message. Interpret it
++ * as a DLPI primitive??
++ */
++ if (debug)
++ dbglog(&quot;got dlpi prim 0x%x, len=%d&quot;,
++ ((union DL_primitives *)ctrlbuf)-&gt;dl_primitive, ctrl.len);
++
++ }
++}
++
++/*
++ * get_loop_output - get outgoing packets from the ppp device,
++ * and detect when we want to bring the real link up.
++ * Return value is 1 if we need to bring up the link, 0 otherwise.
++ */
++int
++get_loop_output()
++{
++ int len;
++ int rv = 0;
++
++ while ((len = read_packet(inpacket_buf)) &gt; 0) {
++ if (loop_frame(inpacket_buf, len))
++ rv = 1;
++ }
++ return rv;
++}
++
++/*
++ * netif_set_mtu - set the MTU on the PPP network interface.
++ */
++void
++netif_set_mtu(unit, mtu)
++ int unit, mtu;
++{
++ struct ifreq ifr;
++#if defined(INET6) &amp;&amp; defined(SOL2)
++ struct lifreq lifr;
++ int fd;
++#endif /* defined(INET6) &amp;&amp; defined(SOL2) */
++
++ memset(&amp;ifr, 0, sizeof(ifr));
++ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
++ ifr.ifr_metric = link_mtu;
++ if (ioctl(ipfd, SIOCSIFMTU, &amp;ifr) &lt; 0) {
++ error(&quot;Couldn't set IP MTU (%s): %m&quot;, ifr.ifr_name);
++ }
++
++#if defined(INET6) &amp;&amp; defined(SOL2)
++ fd = socket(AF_INET6, SOCK_DGRAM, 0);
++ if (fd &lt; 0)
++ error(&quot;Couldn't open IPv6 socket: %m&quot;);
++
++ memset(&amp;lifr, 0, sizeof(lifr));
++ strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
++ lifr.lifr_mtu = link_mtu;
++ if (ioctl(fd, SIOCSLIFMTU, &amp;lifr) &lt; 0) {
++ close(fd);
++ error(&quot;Couldn't set IPv6 MTU (%s): %m&quot;, ifr.ifr_name);
++ }
++ close(fd);
++#endif /* defined(INET6) &amp;&amp; defined(SOL2) */
++}
++
++/*
++ * tty_send_config - configure the transmit characteristics of
++ * the ppp interface.
++ */
++void
++tty_send_config(mtu, asyncmap, pcomp, accomp)
++ int mtu;
++ u_int32_t asyncmap;
++ int pcomp, accomp;
++{
++ int cf[2];
++
++ link_mtu = mtu;
++ if (strioctl(pppfd, PPPIO_MTU, &amp;mtu, sizeof(mtu), 0) &lt; 0) {
++ if (hungup &amp;&amp; errno == ENXIO)
++ return;
++ error(&quot;Couldn't set MTU: %m&quot;);
++ }
++ if (fdmuxid &gt;= 0) {
++ if (!sync_serial) {
++ if (strioctl(pppfd, PPPIO_XACCM, &amp;asyncmap, sizeof(asyncmap), 0) &lt; 0) {
++ error(&quot;Couldn't set transmit ACCM: %m&quot;);
++ }
++ }
++ cf[0] = (pcomp? COMP_PROT: 0) + (accomp? COMP_AC: 0);
++ cf[1] = COMP_PROT | COMP_AC;
++ if (any_compressions() &amp;&amp;
++ strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) &lt; 0) {
++ error(&quot;Couldn't set prot/AC compression: %m&quot;);
++ }
++ }
++}
++
++/*
++ * ppp_set_xaccm - set the extended transmit ACCM for the interface.
++ */
++void
++tty_set_xaccm(accm)
++ ext_accm accm;
++{
++ if (sync_serial)
++ return;
++
++ if (fdmuxid &gt;= 0
++ &amp;&amp; strioctl(pppfd, PPPIO_XACCM, accm, sizeof(ext_accm), 0) &lt; 0) {
++ if (!hungup || errno != ENXIO)
++ warn(&quot;Couldn't set extended ACCM: %m&quot;);
++ }
++}
++
++/*
++ * ppp_recv_config - configure the receive-side characteristics of
++ * the ppp interface.
++ */
++void
++tty_recv_config(mru, asyncmap, pcomp, accomp)
++ int mru;
++ u_int32_t asyncmap;
++ int pcomp, accomp;
++{
++ int cf[2];
++
++ link_mru = mru;
++ if (strioctl(pppfd, PPPIO_MRU, &amp;mru, sizeof(mru), 0) &lt; 0) {
++ if (hungup &amp;&amp; errno == ENXIO)
++ return;
++ error(&quot;Couldn't set MRU: %m&quot;);
++ }
++ if (fdmuxid &gt;= 0) {
++ if (!sync_serial) {
++ if (strioctl(pppfd, PPPIO_RACCM, &amp;asyncmap, sizeof(asyncmap), 0) &lt; 0) {
++ error(&quot;Couldn't set receive ACCM: %m&quot;);
++ }
++ }
++ cf[0] = (pcomp? DECOMP_PROT: 0) + (accomp? DECOMP_AC: 0);
++ cf[1] = DECOMP_PROT | DECOMP_AC;
++ if (any_compressions() &amp;&amp;
++ strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) &lt; 0) {
++ error(&quot;Couldn't set prot/AC decompression: %m&quot;);
++ }
++ }
++}
++
++/*
++ * ccp_test - ask kernel whether a given compression method
++ * is acceptable for use.
++ */
++int
++ccp_test(unit, opt_ptr, opt_len, for_transmit)
++ int unit, opt_len, for_transmit;
++ u_char *opt_ptr;
++{
++ if (strioctl(pppfd, (for_transmit? PPPIO_XCOMP: PPPIO_RCOMP),
++ opt_ptr, opt_len, 0) &gt;= 0)
++ return 1;
++ return (errno == ENOSR)? 0: -1;
++}
++
++/*
++ * ccp_flags_set - inform kernel about the current state of CCP.
++ */
++void
++ccp_flags_set(unit, isopen, isup)
++ int unit, isopen, isup;
++{
++ int cf[2];
++
++ cf[0] = (isopen? CCP_ISOPEN: 0) + (isup? CCP_ISUP: 0);
++ cf[1] = CCP_ISOPEN | CCP_ISUP | CCP_ERROR | CCP_FATALERROR;
++ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) &lt; 0) {
++ if (!hungup || errno != ENXIO)
++ error(&quot;Couldn't set kernel CCP state: %m&quot;);
++ }
++}
++
++/*
++ * get_idle_time - return how long the link has been idle.
++ */
++int
++get_idle_time(u, ip)
++ int u;
++ struct ppp_idle *ip;
++{
++ return strioctl(pppfd, PPPIO_GIDLE, ip, 0, sizeof(struct ppp_idle)) &gt;= 0;
++}
++
++/*
++ * get_ppp_stats - return statistics for the link.
++ */
++int
++get_ppp_stats(u, stats)
++ int u;
++ struct pppd_stats *stats;
++{
++ struct ppp_stats s;
++
++ if (!sync_serial &amp;&amp;
++ strioctl(pppfd, PPPIO_GETSTAT, &amp;s, 0, sizeof(s)) &lt; 0) {
++ error(&quot;Couldn't get link statistics: %m&quot;);
++ return 0;
++ }
++ stats-&gt;bytes_in = s.p.ppp_ibytes;
++ stats-&gt;bytes_out = s.p.ppp_obytes;
++ return 1;
++}
++
++#if 0
++/*
++ * set_filters - transfer the pass and active filters to the kernel.
++ */
++int
++set_filters(pass, active)
++ struct bpf_program *pass, *active;
++{
++ int ret = 1;
++
++ if (pass-&gt;bf_len &gt; 0) {
++ if (strioctl(pppfd, PPPIO_PASSFILT, pass,
++ sizeof(struct bpf_program), 0) &lt; 0) {
++ error(&quot;Couldn't set pass-filter in kernel: %m&quot;);
++ ret = 0;
++ }
++ }
++ if (active-&gt;bf_len &gt; 0) {
++ if (strioctl(pppfd, PPPIO_ACTIVEFILT, active,
++ sizeof(struct bpf_program), 0) &lt; 0) {
++ error(&quot;Couldn't set active-filter in kernel: %m&quot;);
++ ret = 0;
++ }
++ }
++ return ret;
++}
++#endif
++
++/*
++ * ccp_fatal_error - returns 1 if decompression was disabled as a
++ * result of an error detected after decompression of a packet,
++ * 0 otherwise. This is necessary because of patent nonsense.
++ */
++int
++ccp_fatal_error(unit)
++ int unit;
++{
++ int cf[2];
++
++ cf[0] = cf[1] = 0;
++ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) &lt; 0) {
++ if (errno != ENXIO &amp;&amp; errno != EINVAL)
++ error(&quot;Couldn't get compression flags: %m&quot;);
++ return 0;
++ }
++ return cf[0] &amp; CCP_FATALERROR;
++}
++
++/*
++ * sifvjcomp - config tcp header compression
++ */
++int
++sifvjcomp(u, vjcomp, xcidcomp, xmaxcid)
++ int u, vjcomp, xcidcomp, xmaxcid;
++{
++ int cf[2];
++ char maxcid[2];
++
++ if (vjcomp) {
++ maxcid[0] = xcidcomp;
++ maxcid[1] = 15; /* XXX should be rmaxcid */
++ if (strioctl(pppfd, PPPIO_VJINIT, maxcid, sizeof(maxcid), 0) &lt; 0) {
++ error(&quot;Couldn't initialize VJ compression: %m&quot;);
++ }
++ }
++
++ cf[0] = (vjcomp? COMP_VJC + DECOMP_VJC: 0) /* XXX this is wrong */
++ + (xcidcomp? COMP_VJCCID + DECOMP_VJCCID: 0);
++ cf[1] = COMP_VJC + DECOMP_VJC + COMP_VJCCID + DECOMP_VJCCID;
++ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) &lt; 0) {
++ if (vjcomp)
++ error(&quot;Couldn't enable VJ compression: %m&quot;);
++ }
++
++ return 1;
++}
++
++/*
++ * sifup - Config the interface up and enable IP packets to pass.
++ */
++int
++sifup(u)
++ int u;
++{
++ struct ifreq ifr;
++
++ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
++ if (ioctl(ipfd, SIOCGIFFLAGS, &amp;ifr) &lt; 0) {
++ error(&quot;Couldn't mark interface up (get): %m&quot;);
++ return 0;
++ }
++ ifr.ifr_flags |= IFF_UP;
++ if (ioctl(ipfd, SIOCSIFFLAGS, &amp;ifr) &lt; 0) {
++ error(&quot;Couldn't mark interface up (set): %m&quot;);
++ return 0;
++ }
++ if_is_up = 1;
++ return 1;
++}
++
++/*
++ * sifdown - Config the interface down and disable IP.
++ */
++int
++sifdown(u)
++ int u;
++{
++ struct ifreq ifr;
++
++ if (ipmuxid &lt; 0)
++ return 1;
++ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
++ if (ioctl(ipfd, SIOCGIFFLAGS, &amp;ifr) &lt; 0) {
++ error(&quot;Couldn't mark interface down (get): %m&quot;);
++ return 0;
++ }
++ ifr.ifr_flags &amp;= ~IFF_UP;
++ if (ioctl(ipfd, SIOCSIFFLAGS, &amp;ifr) &lt; 0) {
++ error(&quot;Couldn't mark interface down (set): %m&quot;);
++ return 0;
++ }
++ if_is_up = 0;
++ return 1;
++}
++
++/*
++ * sifnpmode - Set the mode for handling packets for a given NP.
++ */
++int
++sifnpmode(u, proto, mode)
++ int u;
++ int proto;
++ enum NPmode mode;
++{
++ int npi[2];
++
++ npi[0] = proto;
++ npi[1] = (int) mode;
++ if (strioctl(pppfd, PPPIO_NPMODE, &amp;npi, 2 * sizeof(int), 0) &lt; 0) {
++ error(&quot;ioctl(set NP %d mode to %d): %m&quot;, proto, mode);
++ return 0;
++ }
++ return 1;
++}
++
++#if defined(SOL2) &amp;&amp; defined(INET6)
++/*
++ * sif6up - Config the IPv6 interface up and enable IPv6 packets to pass.
++ */
++int
++sif6up(u)
++ int u;
++{
++ struct lifreq lifr;
++ int fd;
++
++ fd = socket(AF_INET6, SOCK_DGRAM, 0);
++ if (fd &lt; 0) {
++ return 0;
++ }
++
++ memset(&amp;lifr, 0, sizeof(lifr));
++ strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
++ if (ioctl(fd, SIOCGLIFFLAGS, &amp;lifr) &lt; 0) {
++ close(fd);
++ return 0;
++ }
++
++ lifr.lifr_flags |= IFF_UP;
++ strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
++ if (ioctl(fd, SIOCSLIFFLAGS, &amp;lifr) &lt; 0) {
++ close(fd);
++ return 0;
++ }
++
++ if6_is_up = 1;
++ close(fd);
++ return 1;
++}
++
++/*
++ * sifdown - Config the IPv6 interface down and disable IPv6.
++ */
++int
++sif6down(u)
++ int u;
++{
++ struct lifreq lifr;
++ int fd;
++
++ fd = socket(AF_INET6, SOCK_DGRAM, 0);
++ if (fd &lt; 0)
++ return 0;
++
++ memset(&amp;lifr, 0, sizeof(lifr));
++ strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
++ if (ioctl(fd, SIOCGLIFFLAGS, &amp;lifr) &lt; 0) {
++ close(fd);
++ return 0;
++ }
++
++ lifr.lifr_flags &amp;= ~IFF_UP;
++ strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
++ if (ioctl(fd, SIOCGLIFFLAGS, &amp;lifr) &lt; 0) {
++ close(fd);
++ return 0;
++ }
++
++ if6_is_up = 0;
++ close(fd);
++ return 1;
++}
++
++/*
++ * sif6addr - Config the interface with an IPv6 link-local address
++ */
++int
++sif6addr(u, o, h)
++ int u;
++ eui64_t o, h;
++{
++ struct lifreq lifr;
++ struct sockaddr_storage laddr;
++ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&amp;laddr;
++ int fd;
++
++ fd = socket(AF_INET6, SOCK_DGRAM, 0);
++ if (fd &lt; 0)
++ return 0;
++
++ memset(&amp;lifr, 0, sizeof(lifr));
++ strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
++
++ /*
++ * Do this because /dev/ppp responds to DL_PHYS_ADDR_REQ with
++ * zero values, hence the interface token came to be zero too,
++ * and without this, in.ndpd will complain
++ */
++ IN6_LLTOKEN_FROM_EUI64(lifr, sin6, o);
++ if (ioctl(fd, SIOCSLIFTOKEN, &amp;lifr) &lt; 0) {
++ close(fd);
++ return 0;
++ }
++
++ /*
++ * Set the interface address and destination address
++ */
++ IN6_LLADDR_FROM_EUI64(lifr, sin6, o);
++ if (ioctl(fd, SIOCSLIFADDR, &amp;lifr) &lt; 0) {
++ close(fd);
++ return 0;
++ }
++
++ memset(&amp;lifr, 0, sizeof(lifr));
++ strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
++ IN6_LLADDR_FROM_EUI64(lifr, sin6, h);
++ if (ioctl(fd, SIOCSLIFDSTADDR, &amp;lifr) &lt; 0) {
++ close(fd);
++ return 0;
++ }
++
++ return 1;
++}
++
++/*
++ * cif6addr - Remove the IPv6 address from interface
++ */
++int
++cif6addr(u, o, h)
++ int u;
++ eui64_t o, h;
++{
++ return 1;
++}
++
++#endif /* defined(SOL2) &amp;&amp; defined(INET6) */
++
++
++#define INET_ADDR(x) (((struct sockaddr_in *) &amp;(x))-&gt;sin_addr.s_addr)
++
++/*
++ * sifaddr - Config the interface IP addresses and netmask.
++ */
++int
++sifaddr(u, o, h, m)
++ int u;
++ u_int32_t o, h, m;
++{
++ struct ifreq ifr;
++ int ret = 1;
++
++ memset(&amp;ifr, 0, sizeof(ifr));
++ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
++ ifr.ifr_addr.sa_family = AF_INET;
++ INET_ADDR(ifr.ifr_addr) = m;
++ if (ioctl(ipfd, SIOCSIFNETMASK, &amp;ifr) &lt; 0) {
++ error(&quot;Couldn't set IP netmask: %m&quot;);
++ ret = 0;
++ }
++ ifr.ifr_addr.sa_family = AF_INET;
++ INET_ADDR(ifr.ifr_addr) = o;
++ if (ioctl(ipfd, SIOCSIFADDR, &amp;ifr) &lt; 0) {
++ error(&quot;Couldn't set local IP address: %m&quot;);
++ ret = 0;
++ }
++
++ /*
++ * On some systems, we have to explicitly set the point-to-point
++ * flag bit before we can set a destination address.
++ */
++ if (ioctl(ipfd, SIOCGIFFLAGS, &amp;ifr) &gt;= 0
++ &amp;&amp; (ifr.ifr_flags &amp; IFF_POINTOPOINT) == 0) {
++ ifr.ifr_flags |= IFF_POINTOPOINT;
++ if (ioctl(ipfd, SIOCSIFFLAGS, &amp;ifr) &lt; 0) {
++ error(&quot;Couldn't mark interface pt-to-pt: %m&quot;);
++ ret = 0;
++ }
++ }
++ ifr.ifr_dstaddr.sa_family = AF_INET;
++ INET_ADDR(ifr.ifr_dstaddr) = h;
++ if (ioctl(ipfd, SIOCSIFDSTADDR, &amp;ifr) &lt; 0) {
++ error(&quot;Couldn't set remote IP address: %m&quot;);
++ ret = 0;
++ }
++#if 0 /* now done in ppp_send_config */
++ ifr.ifr_metric = link_mtu;
++ if (ioctl(ipfd, SIOCSIFMTU, &amp;ifr) &lt; 0) {
++ error(&quot;Couldn't set IP MTU: %m&quot;);
++ }
++#endif
++
++ remote_addr = h;
++ return ret;
++}
++
++/*
++ * cifaddr - Clear the interface IP addresses, and delete routes
++ * through the interface if possible.
++ */
++int
++cifaddr(u, o, h)
++ int u;
++ u_int32_t o, h;
++{
++#if defined(__USLC__) /* was: #if 0 */
++ cifroute(unit, ouraddr, hisaddr);
++ if (ipmuxid &gt;= 0) {
++ notice(&quot;Removing ppp interface unit&quot;);
++ if (ioctl(ipfd, I_UNLINK, ipmuxid) &lt; 0) {
++ error(&quot;Can't remove ppp interface unit: %m&quot;);
++ return 0;
++ }
++ ipmuxid = -1;
++ }
++#endif
++ remote_addr = 0;
++ return 1;
++}
++
++/*
++ * sifdefaultroute - assign a default route through the address given.
++ */
++int
++sifdefaultroute(u, l, g)
++ int u;
++ u_int32_t l, g;
++{
++ struct rtentry rt;
++
++#if defined(__USLC__)
++ g = l; /* use the local address as gateway */
++#endif
++ memset(&amp;rt, 0, sizeof(rt));
++ rt.rt_dst.sa_family = AF_INET;
++ INET_ADDR(rt.rt_dst) = 0;
++ rt.rt_gateway.sa_family = AF_INET;
++ INET_ADDR(rt.rt_gateway) = g;
++ rt.rt_flags = RTF_GATEWAY;
++
++ if (ioctl(ipfd, SIOCADDRT, &amp;rt) &lt; 0) {
++ error(&quot;Can't add default route: %m&quot;);
++ return 0;
++ }
++
++ default_route_gateway = g;
++ return 1;
++}
++
++/*
++ * cifdefaultroute - delete a default route through the address given.
++ */
++int
++cifdefaultroute(u, l, g)
++ int u;
++ u_int32_t l, g;
++{
++ struct rtentry rt;
++
++#if defined(__USLC__)
++ g = l; /* use the local address as gateway */
++#endif
++ memset(&amp;rt, 0, sizeof(rt));
++ rt.rt_dst.sa_family = AF_INET;
++ INET_ADDR(rt.rt_dst) = 0;
++ rt.rt_gateway.sa_family = AF_INET;
++ INET_ADDR(rt.rt_gateway) = g;
++ rt.rt_flags = RTF_GATEWAY;
++
++ if (ioctl(ipfd, SIOCDELRT, &amp;rt) &lt; 0) {
++ error(&quot;Can't delete default route: %m&quot;);
++ return 0;
++ }
++
++ default_route_gateway = 0;
++ return 1;
++}
++
++/*
++ * sifproxyarp - Make a proxy ARP entry for the peer.
++ */
++int
++sifproxyarp(unit, hisaddr)
++ int unit;
++ u_int32_t hisaddr;
++{
++ struct arpreq arpreq;
++
++ memset(&amp;arpreq, 0, sizeof(arpreq));
++ if (!get_ether_addr(hisaddr, &amp;arpreq.arp_ha))
++ return 0;
++
++ arpreq.arp_pa.sa_family = AF_INET;
++ INET_ADDR(arpreq.arp_pa) = hisaddr;
++ arpreq.arp_flags = ATF_PERM | ATF_PUBL;
++ if (ioctl(ipfd, SIOCSARP, (caddr_t) &amp;arpreq) &lt; 0) {
++ error(&quot;Couldn't set proxy ARP entry: %m&quot;);
++ return 0;
++ }
++
++ proxy_arp_addr = hisaddr;
++ return 1;
++}
++
++/*
++ * cifproxyarp - Delete the proxy ARP entry for the peer.
++ */
++int
++cifproxyarp(unit, hisaddr)
++ int unit;
++ u_int32_t hisaddr;
++{
++ struct arpreq arpreq;
++
++ memset(&amp;arpreq, 0, sizeof(arpreq));
++ arpreq.arp_pa.sa_family = AF_INET;
++ INET_ADDR(arpreq.arp_pa) = hisaddr;
++ if (ioctl(ipfd, SIOCDARP, (caddr_t)&amp;arpreq) &lt; 0) {
++ error(&quot;Couldn't delete proxy ARP entry: %m&quot;);
++ return 0;
++ }
++
++ proxy_arp_addr = 0;
++ return 1;
++}
++
++/*
++ * get_ether_addr - get the hardware address of an interface on the
++ * the same subnet as ipaddr.
++ */
++#define MAX_IFS 32
++
++static int
++get_ether_addr(ipaddr, hwaddr)
++ u_int32_t ipaddr;
++ struct sockaddr *hwaddr;
++{
++ struct ifreq *ifr, *ifend, ifreq;
++ int nif;
++ struct ifconf ifc;
++ u_int32_t ina, mask;
++
++ /*
++ * Scan through the system's network interfaces.
++ */
++#ifdef SIOCGIFNUM
++ if (ioctl(ipfd, SIOCGIFNUM, &amp;nif) &lt; 0)
++#endif
++ nif = MAX_IFS;
++ ifc.ifc_len = nif * sizeof(struct ifreq);
++ ifc.ifc_buf = (caddr_t) malloc(ifc.ifc_len);
++ if (ifc.ifc_buf == 0)
++ return 0;
++ if (ioctl(ipfd, SIOCGIFCONF, &amp;ifc) &lt; 0) {
++ warn(&quot;Couldn't get system interface list: %m&quot;);
++ free(ifc.ifc_buf);
++ return 0;
++ }
++ ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
++ for (ifr = ifc.ifc_req; ifr &lt; ifend; ++ifr) {
++ if (ifr-&gt;ifr_addr.sa_family != AF_INET)
++ continue;
++ /*
++ * Check that the interface is up, and not point-to-point or loopback.
++ */
++ strlcpy(ifreq.ifr_name, ifr-&gt;ifr_name, sizeof(ifreq.ifr_name));
++ if (ioctl(ipfd, SIOCGIFFLAGS, &amp;ifreq) &lt; 0)
++ continue;
++ if ((ifreq.ifr_flags &amp;
++ (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
++ != (IFF_UP|IFF_BROADCAST))
++ continue;
++ /*
++ * Get its netmask and check that it's on the right subnet.
++ */
++ if (ioctl(ipfd, SIOCGIFNETMASK, &amp;ifreq) &lt; 0)
++ continue;
++ ina = INET_ADDR(ifr-&gt;ifr_addr);
++ mask = INET_ADDR(ifreq.ifr_addr);
++ if ((ipaddr &amp; mask) == (ina &amp; mask))
++ break;
++ }
++
++ if (ifr &gt;= ifend) {
++ warn(&quot;No suitable interface found for proxy ARP&quot;);
++ free(ifc.ifc_buf);
++ return 0;
++ }
++
++ info(&quot;found interface %s for proxy ARP&quot;, ifr-&gt;ifr_name);
++ if (!get_hw_addr(ifr-&gt;ifr_name, ina, hwaddr)) {
++ error(&quot;Couldn't get hardware address for %s&quot;, ifr-&gt;ifr_name);
++ free(ifc.ifc_buf);
++ return 0;
++ }
++
++ free(ifc.ifc_buf);
++ return 1;
++}
++
++/*
++ * get_hw_addr_dlpi - obtain the hardware address using DLPI
++ */
++static int
++get_hw_addr_dlpi(name, hwaddr)
++ char *name;
++ struct sockaddr *hwaddr;
++{
++ char *p, *q;
++ int unit, iffd, adrlen;
++ unsigned char *adrp;
++ char ifdev[24];
++ struct {
++ union DL_primitives prim;
++ char space[64];
++ } reply;
++
++ /*
++ * We have to open the device and ask it for its hardware address.
++ * First split apart the device name and unit.
++ */
++ slprintf(ifdev, sizeof(ifdev), &quot;/dev/%s&quot;, name);
++ for (q = ifdev + strlen(ifdev); --q &gt;= ifdev; )
++ if (!isdigit(*q))
++ break;
++ unit = atoi(q+1);
++ q[1] = 0;
++
++ /*
++ * Open the device and do a DLPI attach and phys_addr_req.
++ */
++ iffd = open(ifdev, O_RDWR);
++ if (iffd &lt; 0) {
++ error(&quot;Can't open %s: %m&quot;, ifdev);
++ return 0;
++ }
++ if (dlpi_attach(iffd, unit) &lt; 0
++ || dlpi_get_reply(iffd, &amp;reply.prim, DL_OK_ACK, sizeof(reply)) &lt; 0
++ || dlpi_info_req(iffd) &lt; 0
++ || dlpi_get_reply(iffd, &amp;reply.prim, DL_INFO_ACK, sizeof(reply)) &lt; 0) {
++ close(iffd);
++ return 0;
++ }
++
++ adrlen = reply.prim.info_ack.dl_addr_length;
++ adrp = (unsigned char *)&amp;reply + reply.prim.info_ack.dl_addr_offset;
++
++#if DL_CURRENT_VERSION &gt;= 2
++ if (reply.prim.info_ack.dl_sap_length &lt; 0)
++ adrlen += reply.prim.info_ack.dl_sap_length;
++ else
++ adrp += reply.prim.info_ack.dl_sap_length;
++#endif
++
++ hwaddr-&gt;sa_family = AF_UNSPEC;
++ memcpy(hwaddr-&gt;sa_data, adrp, adrlen);
++
++ return 1;
++}
++/*
++ * get_hw_addr - obtain the hardware address for a named interface.
++ */
++static int
++get_hw_addr(name, ina, hwaddr)
++ char *name;
++ u_int32_t ina;
++ struct sockaddr *hwaddr;
++{
++ /* New way - get the address by doing an arp request. */
++ int s;
++ struct arpreq req;
++
++ s = socket(AF_INET, SOCK_DGRAM, 0);
++ if (s &lt; 0)
++ return 0;
++ memset(&amp;req, 0, sizeof(req));
++ req.arp_pa.sa_family = AF_INET;
++ INET_ADDR(req.arp_pa) = ina;
++ if (ioctl(s, SIOCGARP, &amp;req) &lt; 0) {
++ error(&quot;Couldn't get ARP entry for %s: %m&quot;, ip_ntoa(ina));
++ return 0;
++ }
++ *hwaddr = req.arp_ha;
++ hwaddr-&gt;sa_family = AF_UNSPEC;
++
++ return 1;
++}
++
++static int
++dlpi_attach(fd, ppa)
++ int fd, ppa;
++{
++ dl_attach_req_t req;
++ struct strbuf buf;
++
++ req.dl_primitive = DL_ATTACH_REQ;
++ req.dl_ppa = ppa;
++ buf.len = sizeof(req);
++ buf.buf = (void *) &amp;req;
++ return putmsg(fd, &amp;buf, NULL, RS_HIPRI);
++}
++
++static int
++dlpi_info_req(fd)
++ int fd;
++{
++ dl_info_req_t req;
++ struct strbuf buf;
++
++ req.dl_primitive = DL_INFO_REQ;
++ buf.len = sizeof(req);
++ buf.buf = (void *) &amp;req;
++ return putmsg(fd, &amp;buf, NULL, RS_HIPRI);
++}
++
++static int
++dlpi_get_reply(fd, reply, expected_prim, maxlen)
++ union DL_primitives *reply;
++ int fd, expected_prim, maxlen;
++{
++ struct strbuf buf;
++ int flags, n;
++ struct pollfd pfd;
++
++ /*
++ * Use poll to wait for a message with a timeout.
++ */
++ pfd.fd = fd;
++ pfd.events = POLLIN | POLLPRI;
++ do {
++ n = poll(&amp;pfd, 1, 1000);
++ } while (n == -1 &amp;&amp; errno == EINTR);
++ if (n &lt;= 0)
++ return -1;
++
++ /*
++ * Get the reply.
++ */
++ buf.maxlen = maxlen;
++ buf.buf = (void *) reply;
++ flags = 0;
++ if (getmsg(fd, &amp;buf, NULL, &amp;flags) &lt; 0)
++ return -1;
++
++ if (buf.len &lt; sizeof(ulong)) {
++ if (debug)
++ dbglog(&quot;dlpi response short (len=%d)\n&quot;, buf.len);
++ return -1;
++ }
++
++ if (reply-&gt;dl_primitive == expected_prim)
++ return 0;
++
++ if (debug) {
++ if (reply-&gt;dl_primitive == DL_ERROR_ACK) {
++ dbglog(&quot;dlpi error %d (unix errno %d) for prim %x\n&quot;,
++ reply-&gt;error_ack.dl_errno, reply-&gt;error_ack.dl_unix_errno,
++ reply-&gt;error_ack.dl_error_primitive);
++ } else {
++ dbglog(&quot;dlpi unexpected response prim %x\n&quot;,
++ reply-&gt;dl_primitive);
++ }
++ }
++
++ return -1;
++}
++
++/*
++ * Return user specified netmask, modified by any mask we might determine
++ * for address `addr' (in network byte order).
++ * Here we scan through the system's list of interfaces, looking for
++ * any non-point-to-point interfaces which might appear to be on the same
++ * network as `addr'. If we find any, we OR in their netmask to the
++ * user-specified netmask.
++ */
++u_int32_t
++GetMask(addr)
++ u_int32_t addr;
++{
++ u_int32_t mask, nmask, ina;
++ struct ifreq *ifr, *ifend, ifreq;
++ int nif;
++ struct ifconf ifc;
++
++ addr = ntohl(addr);
++ if (IN_CLASSA(addr)) /* determine network mask for address class */
++ nmask = IN_CLASSA_NET;
++ else if (IN_CLASSB(addr))
++ nmask = IN_CLASSB_NET;
++ else
++ nmask = IN_CLASSC_NET;
++ /* class D nets are disallowed by bad_ip_adrs */
++ mask = netmask | htonl(nmask);
++
++ /*
++ * Scan through the system's network interfaces.
++ */
++#ifdef SIOCGIFNUM
++ if (ioctl(ipfd, SIOCGIFNUM, &amp;nif) &lt; 0)
++#endif
++ nif = MAX_IFS;
++ ifc.ifc_len = nif * sizeof(struct ifreq);
++ ifc.ifc_buf = (caddr_t) malloc(ifc.ifc_len);
++ if (ifc.ifc_buf == 0)
++ return mask;
++ if (ioctl(ipfd, SIOCGIFCONF, &amp;ifc) &lt; 0) {
++ warn(&quot;Couldn't get system interface list: %m&quot;);
++ free(ifc.ifc_buf);
++ return mask;
++ }
++ ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
++ for (ifr = ifc.ifc_req; ifr &lt; ifend; ++ifr) {
++ /*
++ * Check the interface's internet address.
++ */
++ if (ifr-&gt;ifr_addr.sa_family != AF_INET)
++ continue;
++ ina = INET_ADDR(ifr-&gt;ifr_addr);
++ if ((ntohl(ina) &amp; nmask) != (addr &amp; nmask))
++ continue;
++ /*
++ * Check that the interface is up, and not point-to-point or loopback.
++ */
++ strlcpy(ifreq.ifr_name, ifr-&gt;ifr_name, sizeof(ifreq.ifr_name));
++ if (ioctl(ipfd, SIOCGIFFLAGS, &amp;ifreq) &lt; 0)
++ continue;
++ if ((ifreq.ifr_flags &amp; (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK))
++ != IFF_UP)
++ continue;
++ /*
++ * Get its netmask and OR it into our mask.
++ */
++ if (ioctl(ipfd, SIOCGIFNETMASK, &amp;ifreq) &lt; 0)
++ continue;
++ mask |= INET_ADDR(ifreq.ifr_addr);
++ }
++
++ free(ifc.ifc_buf);
++ return mask;
++}
++
++/*
++ * logwtmp - write an accounting record to the /var/adm/wtmp file.
++ */
++void
++logwtmp(line, name, host)
++ const char *line, *name, *host;
++{
++ static struct utmpx utmpx;
++
++ if (name[0] != 0) {
++ /* logging in */
++ strncpy(utmpx.ut_user, name, sizeof(utmpx.ut_user));
++ strncpy(utmpx.ut_id, ifname, sizeof(utmpx.ut_id));
++ strncpy(utmpx.ut_line, line, sizeof(utmpx.ut_line));
++ utmpx.ut_pid = getpid();
++ utmpx.ut_type = USER_PROCESS;
++ } else {
++ utmpx.ut_type = DEAD_PROCESS;
++ }
++ gettimeofday(&amp;utmpx.ut_tv, NULL);
++ updwtmpx(&quot;/var/adm/wtmpx&quot;, &amp;utmpx);
++}
++
++/*
++ * get_host_seed - return the serial number of this machine.
++ */
++int
++get_host_seed()
++{
++ char buf[32];
++
++ if (sysinfo(SI_HW_SERIAL, buf, sizeof(buf)) &lt; 0) {
++ error(&quot;sysinfo: %m&quot;);
++ return 0;
++ }
++ return (int) strtoul(buf, NULL, 16);
++}
++
++static int
++strioctl(fd, cmd, ptr, ilen, olen)
++ int fd, cmd, ilen, olen;
++ void *ptr;
++{
++ struct strioctl str;
++
++ str.ic_cmd = cmd;
++ str.ic_timout = 0;
++ str.ic_len = ilen;
++ str.ic_dp = ptr;
++ if (ioctl(fd, I_STR, &amp;str) == -1)
++ return -1;
++ if (str.ic_len != olen)
++ dbglog(&quot;strioctl: expected %d bytes, got %d for cmd %x\n&quot;,
++ olen, str.ic_len, cmd);
++ return 0;
++}
++
++#if 0
++/*
++ * lock - create a lock file for the named lock device
++ */
++
++#define LOCK_PREFIX &quot;/var/spool/locks/LK.&quot;
++static char lock_file[40]; /* name of lock file created */
++
++int
++lock(dev)
++ char *dev;
++{
++ int n, fd, pid;
++ struct stat sbuf;
++ char ascii_pid[12];
++
++ if (stat(dev, &amp;sbuf) &lt; 0) {
++ error(&quot;Can't get device number for %s: %m&quot;, dev);
++ return -1;
++ }
++ if ((sbuf.st_mode &amp; S_IFMT) != S_IFCHR) {
++ error(&quot;Can't lock %s: not a character device&quot;, dev);
++ return -1;
++ }
++ slprintf(lock_file, sizeof(lock_file), &quot;%s%03d.%03d.%03d&quot;,
++ LOCK_PREFIX, major(sbuf.st_dev),
++ major(sbuf.st_rdev), minor(sbuf.st_rdev));
++
++ while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) &lt; 0) {
++ if (errno == EEXIST
++ &amp;&amp; (fd = open(lock_file, O_RDONLY, 0)) &gt;= 0) {
++ /* Read the lock file to find out who has the device locked */
++ n = read(fd, ascii_pid, 11);
++ if (n &lt;= 0) {
++ error(&quot;Can't read pid from lock file %s&quot;, lock_file);
++ close(fd);
++ } else {
++ ascii_pid[n] = 0;
++ pid = atoi(ascii_pid);
++ if (pid &gt; 0 &amp;&amp; kill(pid, 0) == -1 &amp;&amp; errno == ESRCH) {
++ /* pid no longer exists - remove the lock file */
++ if (unlink(lock_file) == 0) {
++ close(fd);
++ notice(&quot;Removed stale lock on %s (pid %d)&quot;,
++ dev, pid);
++ continue;
++ } else
++ warn(&quot;Couldn't remove stale lock on %s&quot;,
++ dev);
++ } else
++ notice(&quot;Device %s is locked by pid %d&quot;,
++ dev, pid);
++ }
++ close(fd);
++ } else
++ error(&quot;Can't create lock file %s: %m&quot;, lock_file);
++ lock_file[0] = 0;
++ return -1;
++ }
++
++ slprintf(ascii_pid, sizeof(ascii_pid), &quot;%10d\n&quot;, getpid());
++ write(fd, ascii_pid, 11);
++
++ close(fd);
++ return 1;
++}
++
++/*
++ * unlock - remove our lockfile
++ */
++void
++unlock()
++{
++ if (lock_file[0]) {
++ unlink(lock_file);
++ lock_file[0] = 0;
++ }
++}
++#endif
++
++/*
++ * cifroute - delete a route through the addresses given.
++ */
++int
++cifroute(u, our, his)
++ int u;
++ u_int32_t our, his;
++{
++ struct rtentry rt;
++
++ memset(&amp;rt, 0, sizeof(rt));
++ rt.rt_dst.sa_family = AF_INET;
++ INET_ADDR(rt.rt_dst) = his;
++ rt.rt_gateway.sa_family = AF_INET;
++ INET_ADDR(rt.rt_gateway) = our;
++ rt.rt_flags = RTF_HOST;
++
++ if (ioctl(ipfd, SIOCDELRT, &amp;rt) &lt; 0) {
++ error(&quot;Can't delete route: %m&quot;);
++ return 0;
++ }
++
++ return 1;
++}
++
++/*
++ * have_route_to - determine if the system has a route to the specified
++ * IP address. Returns 0 if not, 1 if so, -1 if we can't tell.
++ * `addr' is in network byte order.
++ * For demand mode to work properly, we have to ignore routes
++ * through our own interface.
++ */
++#ifndef T_CURRENT /* needed for Solaris 2.5 */
++#define T_CURRENT MI_T_CURRENT
++#endif
++
++int
++have_route_to(addr)
++ u_int32_t addr;
++{
++#ifdef SOL2
++ int fd, r, flags, i;
++ struct {
++ struct T_optmgmt_req req;
++ struct opthdr hdr;
++ } req;
++ union {
++ struct T_optmgmt_ack ack;
++ unsigned char space[64];
++ } ack;
++ struct opthdr *rh;
++ struct strbuf cbuf, dbuf;
++ int nroutes;
++ mib2_ipRouteEntry_t routes[8];
++ mib2_ipRouteEntry_t *rp;
++
++ fd = open(mux_dev_name, O_RDWR);
++ if (fd &lt; 0) {
++ warn(&quot;have_route_to: couldn't open %s: %m&quot;, mux_dev_name);
++ return -1;
++ }
++
++ req.req.PRIM_type = T_OPTMGMT_REQ;
++ req.req.OPT_offset = (char *) &amp;req.hdr - (char *) &amp;req;
++ req.req.OPT_length = sizeof(req.hdr);
++ req.req.MGMT_flags = T_CURRENT;
++
++ req.hdr.level = MIB2_IP;
++ req.hdr.name = 0;
++ req.hdr.len = 0;
++
++ cbuf.buf = (char *) &amp;req;
++ cbuf.len = sizeof(req);
++
++ if (putmsg(fd, &amp;cbuf, NULL, 0) == -1) {
++ warn(&quot;have_route_to: putmsg: %m&quot;);
++ close(fd);
++ return -1;
++ }
++
++ for (;;) {
++ cbuf.buf = (char *) &amp;ack;
++ cbuf.maxlen = sizeof(ack);
++ dbuf.buf = (char *) routes;
++ dbuf.maxlen = sizeof(routes);
++ flags = 0;
++ r = getmsg(fd, &amp;cbuf, &amp;dbuf, &amp;flags);
++ if (r == -1) {
++ warn(&quot;have_route_to: getmsg: %m&quot;);
++ close(fd);
++ return -1;
++ }
++
++ if (cbuf.len &lt; sizeof(struct T_optmgmt_ack)
++ || ack.ack.PRIM_type != T_OPTMGMT_ACK
++ || ack.ack.MGMT_flags != T_SUCCESS
++ || ack.ack.OPT_length &lt; sizeof(struct opthdr)) {
++ dbglog(&quot;have_route_to: bad message len=%d prim=%d&quot;,
++ cbuf.len, ack.ack.PRIM_type);
++ close(fd);
++ return -1;
++ }
++
++ rh = (struct opthdr *) ((char *)&amp;ack + ack.ack.OPT_offset);
++ if (rh-&gt;level == 0 &amp;&amp; rh-&gt;name == 0)
++ break;
++ if (rh-&gt;level != MIB2_IP || rh-&gt;name != MIB2_IP_21) {
++ while (r == MOREDATA)
++ r = getmsg(fd, NULL, &amp;dbuf, &amp;flags);
++ continue;
++ }
++
++ for (;;) {
++ nroutes = dbuf.len / sizeof(mib2_ipRouteEntry_t);
++ for (rp = routes, i = 0; i &lt; nroutes; ++i, ++rp) {
++ if (rp-&gt;ipRouteMask != ~0) {
++ dbglog(&quot;have_route_to: dest=%x gw=%x mask=%x\n&quot;,
++ rp-&gt;ipRouteDest, rp-&gt;ipRouteNextHop,
++ rp-&gt;ipRouteMask);
++ if (((addr ^ rp-&gt;ipRouteDest) &amp; rp-&gt;ipRouteMask) == 0
++ &amp;&amp; rp-&gt;ipRouteNextHop != remote_addr)
++ return 1;
++ }
++ }
++ if (r == 0)
++ break;
++ r = getmsg(fd, NULL, &amp;dbuf, &amp;flags);
++ }
++ }
++ close(fd);
++ return 0;
++#else
++ return -1;
++#endif /* SOL2 */
++}
++
++/*
++ * get_pty - get a pty master/slave pair and chown the slave side to
++ * the uid given. Assumes slave_name points to MAXPATHLEN bytes of space.
++ */
++int
++get_pty(master_fdp, slave_fdp, slave_name, uid)
++ int *master_fdp;
++ int *slave_fdp;
++ char *slave_name;
++ int uid;
++{
++ int mfd, sfd;
++ char *pty_name;
++ struct termios tios;
++
++ mfd = open(&quot;/dev/ptmx&quot;, O_RDWR);
++ if (mfd &lt; 0) {
++ error(&quot;Couldn't open pty master: %m&quot;);
++ return 0;
++ }
++
++ pty_name = ptsname(mfd);
++ if (pty_name == NULL) {
++ error(&quot;Couldn't get name of pty slave&quot;);
++ close(mfd);
++ return 0;
++ }
++ if (chown(pty_name, uid, -1) &lt; 0)
++ warn(&quot;Couldn't change owner of pty slave: %m&quot;);
++ if (chmod(pty_name, S_IRUSR | S_IWUSR) &lt; 0)
++ warn(&quot;Couldn't change permissions on pty slave: %m&quot;);
++ if (unlockpt(mfd) &lt; 0)
++ warn(&quot;Couldn't unlock pty slave: %m&quot;);
++
++ sfd = open(pty_name, O_RDWR);
++ if (sfd &lt; 0) {
++ error(&quot;Couldn't open pty slave %s: %m&quot;, pty_name);
++ close(mfd);
++ return 0;
++ }
++ if (ioctl(sfd, I_PUSH, &quot;ptem&quot;) &lt; 0)
++ warn(&quot;Couldn't push ptem module on pty slave: %m&quot;);
++
++ dbglog(&quot;Using %s&quot;, pty_name);
++ strlcpy(slave_name, pty_name, MAXPATHLEN);
++ *master_fdp = mfd;
++ *slave_fdp = sfd;
++
++ return 1;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/sys-solaris.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/sys-sunos4.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/sys-sunos4.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/sys-sunos4.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1559 @@
++/*
++ * System-dependent procedures for pppd under SunOS 4.
++ *
++ * Copyright (c) 1994 The Australian National University.
++ * All rights reserved.
++ *
++ * Permission to use, copy, modify, and distribute this software and its
++ * documentation is hereby granted, provided that the above copyright
++ * notice appears in all copies. This software is provided without any
++ * warranty, express or implied. The Australian National University
++ * makes no representations about the suitability of this software for
++ * any purpose.
++ *
++ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
++ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
++ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
++ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
++ * OF SUCH DAMAGE.
++ *
++ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
++ * ON AN &quot;AS IS&quot; BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
++ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
++ * OR MODIFICATIONS.
++ */
++
++#define RCSID &quot;$Id: sys-sunos4.c 195720 2001-06-11 11:44:34Z gc $&quot;
++
++#include &lt;stdio.h&gt;
++#include &lt;stddef.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++#include &lt;ctype.h&gt;
++#include &lt;errno.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;termios.h&gt;
++#include &lt;signal.h&gt;
++#include &lt;malloc.h&gt;
++#include &lt;utmp.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/param.h&gt;
++#include &lt;sys/socket.h&gt;
++#include &lt;sys/sockio.h&gt;
++#include &lt;sys/stream.h&gt;
++#include &lt;sys/stropts.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;sys/time.h&gt;
++#include &lt;sys/poll.h&gt;
++#include &lt;net/if.h&gt;
++#include &lt;net/if_arp.h&gt;
++#include &lt;net/nit_if.h&gt;
++#include &lt;net/route.h&gt;
++#include &lt;net/ppp_defs.h&gt;
++#include &lt;net/pppio.h&gt;
++#include &lt;netinet/in.h&gt;
++
++#include &quot;pppd.h&quot;
++
++#if defined(sun) &amp;&amp; defined(sparc)
++#include &lt;alloca.h&gt;
++#ifndef __GNUC__
++extern void *alloca();
++#endif
++#endif /*sparc*/
++
++static const char rcsid[] = RCSID;
++
++static int pppfd;
++static int fdmuxid = -1;
++static int iffd;
++static int sockfd;
++
++static int restore_term;
++static struct termios inittermios;
++static struct winsize wsinfo; /* Initial window size info */
++static pid_t parent_pid; /* PID of our parent */
++
++extern u_char inpacket_buf[]; /* borrowed from main.c */
++
++#define MAX_POLLFDS 32
++static struct pollfd pollfds[MAX_POLLFDS];
++static int n_pollfds;
++
++static int link_mtu, link_mru;
++
++#define NMODULES 32
++static int tty_nmodules;
++static char tty_modules[NMODULES][FMNAMESZ+1];
++
++static int if_is_up; /* Interface has been marked up */
++static u_int32_t ifaddrs[2]; /* local and remote addresses */
++static u_int32_t default_route_gateway; /* Gateway for default route added */
++static u_int32_t proxy_arp_addr; /* Addr for proxy arp entry added */
++
++/* Prototypes for procedures local to this file. */
++static int translate_speed __P((int));
++static int baud_rate_of __P((int));
++static int get_ether_addr __P((u_int32_t, struct sockaddr *));
++static int strioctl __P((int, int, void *, int, int));
++
++
++/*
++ * sys_init - System-dependent initialization.
++ */
++void
++sys_init()
++{
++ int x;
++
++ /* Get an internet socket for doing socket ioctl's on. */
++ if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) &lt; 0)
++ fatal(&quot;Couldn't create IP socket: %m&quot;);
++
++ /*
++ * We may want to send a SIGHUP to the session leader associated
++ * with our controlling terminal later. Because SunOS doesn't
++ * have getsid(), we make do with sending the signal to our
++ * parent process.
++ */
++ parent_pid = getppid();
++
++ /*
++ * Open the ppp device.
++ */
++ pppfd = open(&quot;/dev/ppp&quot;, O_RDWR | O_NONBLOCK, 0);
++ if (pppfd &lt; 0)
++ fatal(&quot;Can't open /dev/ppp: %m&quot;);
++ if (kdebugflag) {
++ x = PPPDBG_LOG + PPPDBG_DRIVER;
++ strioctl(pppfd, PPPIO_DEBUG, &amp;x, sizeof(int), 0);
++ }
++
++ /* Assign a new PPA and get its unit number. */
++ if (strioctl(pppfd, PPPIO_NEWPPA, &amp;ifunit, 0, sizeof(int)) &lt; 0)
++ fatal(&quot;Can't create new PPP interface: %m&quot;);
++
++ /*
++ * Open the ppp device again and push the if_ppp module on it.
++ */
++ iffd = open(&quot;/dev/ppp&quot;, O_RDWR, 0);
++ if (iffd &lt; 0)
++ fatal(&quot;Can't open /dev/ppp (2): %m&quot;);
++ if (kdebugflag) {
++ x = PPPDBG_LOG + PPPDBG_DRIVER;
++ strioctl(iffd, PPPIO_DEBUG, &amp;x, sizeof(int), 0);
++ }
++ if (strioctl(iffd, PPPIO_ATTACH, &amp;ifunit, sizeof(int), 0) &lt; 0)
++ fatal(&quot;Couldn't attach ppp interface to device: %m&quot;);
++ if (ioctl(iffd, I_PUSH, &quot;if_ppp&quot;) &lt; 0)
++ fatal(&quot;Can't push ppp interface module: %m&quot;);
++ if (kdebugflag) {
++ x = PPPDBG_LOG + PPPDBG_IF;
++ strioctl(iffd, PPPIO_DEBUG, &amp;x, sizeof(int), 0);
++ }
++ if (strioctl(iffd, PPPIO_NEWPPA, &amp;ifunit, sizeof(int), 0) &lt; 0)
++ fatal(&quot;Couldn't create ppp interface unit: %m&quot;);
++ x = PPP_IP;
++ if (strioctl(iffd, PPPIO_BIND, &amp;x, sizeof(int), 0) &lt; 0)
++ fatal(&quot;Couldn't bind ppp interface to IP SAP: %m&quot;);
++
++ n_pollfds = 0;
++}
++
++/*
++ * sys_cleanup - restore any system state we modified before exiting:
++ * mark the interface down, delete default route and/or proxy arp entry.
++ * This shouldn't call die() because it's called from die().
++ */
++void
++sys_cleanup()
++{
++ if (if_is_up)
++ sifdown(0);
++ if (ifaddrs[0])
++ cifaddr(0, ifaddrs[0], ifaddrs[1]);
++ if (default_route_gateway)
++ cifdefaultroute(0, 0, default_route_gateway);
++ if (proxy_arp_addr)
++ cifproxyarp(0, proxy_arp_addr);
++}
++
++/*
++ * sys_close - Clean up in a child process before execing.
++ */
++void
++sys_close()
++{
++ close(iffd);
++ close(pppfd);
++ close(sockfd);
++}
++
++/*
++ * sys_check_options - check the options that the user specified
++ */
++int
++sys_check_options()
++{
++ return 1;
++}
++
++#if 0
++/*
++ * daemon - Detach us from controlling terminal session.
++ */
++int
++daemon(nochdir, noclose)
++ int nochdir, noclose;
++{
++ int pid;
++
++ if ((pid = fork()) &lt; 0)
++ return -1;
++ if (pid != 0)
++ exit(0); /* parent dies */
++ setsid();
++ if (!nochdir)
++ chdir(&quot;/&quot;);
++ if (!noclose) {
++ fclose(stdin); /* don't need stdin, stdout, stderr */
++ fclose(stdout);
++ fclose(stderr);
++ }
++ return 0;
++}
++#endif
++
++/*
++ * ppp_available - check whether the system has any ppp interfaces
++ */
++int
++ppp_available()
++{
++ struct stat buf;
++
++ return stat(&quot;/dev/ppp&quot;, &amp;buf) &gt;= 0;
++}
++
++/*
++ * tty_establish_ppp - Turn the serial port into a ppp interface.
++ */
++int
++tty_establish_ppp(fd)
++ int fd;
++{
++ int i;
++
++ /* Pop any existing modules off the tty stream. */
++ for (i = 0;; ++i)
++ if (ioctl(fd, I_LOOK, tty_modules[i]) &lt; 0
++ || ioctl(fd, I_POP, 0) &lt; 0)
++ break;
++ tty_nmodules = i;
++
++ /* Push the async hdlc module and the compressor module. */
++ if (ioctl(fd, I_PUSH, &quot;ppp_ahdl&quot;) &lt; 0)
++ fatal(&quot;Couldn't push PPP Async HDLC module: %m&quot;);
++ if (ioctl(fd, I_PUSH, &quot;ppp_comp&quot;) &lt; 0)
++ error(&quot;Couldn't push PPP compression module: %m&quot;);
++
++ /* Link the serial port under the PPP multiplexor. */
++ if ((fdmuxid = ioctl(pppfd, I_LINK, fd)) &lt; 0)
++ fatal(&quot;Can't link tty to PPP mux: %m&quot;);
++
++ return pppfd;
++}
++
++/*
++ * disestablish_ppp - Restore the serial port to normal operation.
++ * It attempts to reconstruct the stream with the previously popped
++ * modules. This shouldn't call die() because it's called from die().
++ */
++void
++tty_disestablish_ppp(fd)
++ int fd;
++{
++ int i;
++
++ if (fdmuxid &gt;= 0) {
++ if (ioctl(pppfd, I_UNLINK, fdmuxid) &lt; 0) {
++ if (!hungup)
++ error(&quot;Can't unlink tty from PPP mux: %m&quot;);
++ }
++ fdmuxid = -1;
++
++ if (!hungup) {
++ while (ioctl(fd, I_POP, 0) &gt;= 0)
++ ;
++ for (i = tty_nmodules - 1; i &gt;= 0; --i)
++ if (ioctl(fd, I_PUSH, tty_modules[i]) &lt; 0)
++ error(&quot;Couldn't restore tty module %s: %m&quot;,
++ tty_modules[i]);
++ }
++ if (hungup &amp;&amp; default_device &amp;&amp; parent_pid &gt; 0) {
++ /*
++ * If we have received a hangup, we need to send a SIGHUP
++ * to the terminal's controlling process. The reason is
++ * that the original stream head for the terminal hasn't
++ * seen the M_HANGUP message (it went up through the ppp
++ * driver to the stream head for our fd to /dev/ppp).
++ * Actually we send the signal to the process that invoked
++ * pppd, since SunOS doesn't have getsid().
++ */
++ kill(parent_pid, SIGHUP);
++ }
++ }
++}
++
++/*
++ * Check whether the link seems not to be 8-bit clean.
++ */
++void
++clean_check()
++{
++ int x;
++ char *s;
++
++ if (strioctl(pppfd, PPPIO_GCLEAN, &amp;x, 0, sizeof(x)) &lt; 0)
++ return;
++ s = NULL;
++ switch (~x) {
++ case RCV_B7_0:
++ s = &quot;bit 7 set to 1&quot;;
++ break;
++ case RCV_B7_1:
++ s = &quot;bit 7 set to 0&quot;;
++ break;
++ case RCV_EVNP:
++ s = &quot;odd parity&quot;;
++ break;
++ case RCV_ODDP:
++ s = &quot;even parity&quot;;
++ break;
++ }
++ if (s != NULL) {
++ warn(&quot;Serial link is not 8-bit clean:&quot;);
++ warn(&quot;All received characters had %s&quot;, s);
++ }
++}
++
++/*
++ * List of valid speeds.
++ */
++struct speed {
++ int speed_int, speed_val;
++} speeds[] = {
++#ifdef B50
++ { 50, B50 },
++#endif
++#ifdef B75
++ { 75, B75 },
++#endif
++#ifdef B110
++ { 110, B110 },
++#endif
++#ifdef B134
++ { 134, B134 },
++#endif
++#ifdef B150
++ { 150, B150 },
++#endif
++#ifdef B200
++ { 200, B200 },
++#endif
++#ifdef B300
++ { 300, B300 },
++#endif
++#ifdef B600
++ { 600, B600 },
++#endif
++#ifdef B1200
++ { 1200, B1200 },
++#endif
++#ifdef B1800
++ { 1800, B1800 },
++#endif
++#ifdef B2000
++ { 2000, B2000 },
++#endif
++#ifdef B2400
++ { 2400, B2400 },
++#endif
++#ifdef B3600
++ { 3600, B3600 },
++#endif
++#ifdef B4800
++ { 4800, B4800 },
++#endif
++#ifdef B7200
++ { 7200, B7200 },
++#endif
++#ifdef B9600
++ { 9600, B9600 },
++#endif
++#ifdef B19200
++ { 19200, B19200 },
++#endif
++#ifdef B38400
++ { 38400, B38400 },
++#endif
++#ifdef EXTA
++ { 19200, EXTA },
++#endif
++#ifdef EXTB
++ { 38400, EXTB },
++#endif
++#ifdef B57600
++ { 57600, B57600 },
++#endif
++#ifdef B115200
++ { 115200, B115200 },
++#endif
++ { 0, 0 }
++};
++
++/*
++ * Translate from bits/second to a speed_t.
++ */
++static int
++translate_speed(bps)
++ int bps;
++{
++ struct speed *speedp;
++
++ if (bps == 0)
++ return 0;
++ for (speedp = speeds; speedp-&gt;speed_int; speedp++)
++ if (bps == speedp-&gt;speed_int)
++ return speedp-&gt;speed_val;
++ warn(&quot;speed %d not supported&quot;, bps);
++ return 0;
++}
++
++/*
++ * Translate from a speed_t to bits/second.
++ */
++static int
++baud_rate_of(speed)
++ int speed;
++{
++ struct speed *speedp;
++
++ if (speed == 0)
++ return 0;
++ for (speedp = speeds; speedp-&gt;speed_int; speedp++)
++ if (speed == speedp-&gt;speed_val)
++ return speedp-&gt;speed_int;
++ return 0;
++}
++
++/*
++ * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
++ * at the requested speed, etc. If `local' is true, set CLOCAL
++ * regardless of whether the modem option was specified.
++ */
++void
++set_up_tty(fd, local)
++ int fd, local;
++{
++ int speed;
++ struct termios tios;
++
++ if (tcgetattr(fd, &amp;tios) &lt; 0)
++ fatal(&quot;tcgetattr: %m&quot;);
++
++ if (!restore_term) {
++ inittermios = tios;
++ ioctl(fd, TIOCGWINSZ, &amp;wsinfo);
++ }
++
++ tios.c_cflag &amp;= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
++ if (crtscts &gt; 0)
++ tios.c_cflag |= CRTSCTS;
++ else if (crtscts &lt; 0)
++ tios.c_cflag &amp;= ~CRTSCTS;
++
++ tios.c_cflag |= CS8 | CREAD | HUPCL;
++ if (local || !modem)
++ tios.c_cflag |= CLOCAL;
++ tios.c_iflag = IGNBRK | IGNPAR;
++ tios.c_oflag = 0;
++ tios.c_lflag = 0;
++ tios.c_cc[VMIN] = 1;
++ tios.c_cc[VTIME] = 0;
++
++ if (crtscts == -2) {
++ tios.c_iflag |= IXON | IXOFF;
++ tios.c_cc[VSTOP] = 0x13; /* DC3 = XOFF = ^S */
++ tios.c_cc[VSTART] = 0x11; /* DC1 = XON = ^Q */
++ }
++
++ speed = translate_speed(inspeed);
++ if (speed) {
++ cfsetospeed(&amp;tios, speed);
++ cfsetispeed(&amp;tios, speed);
++ } else {
++ speed = cfgetospeed(&amp;tios);
++ /*
++ * We can't proceed if the serial port speed is 0,
++ * since that implies that the serial port is disabled.
++ */
++ if (speed == B0)
++ fatal(&quot;Baud rate for %s is 0; need explicit baud rate&quot;, devnam);
++ }
++
++ if (tcsetattr(fd, TCSAFLUSH, &amp;tios) &lt; 0)
++ fatal(&quot;tcsetattr: %m&quot;);
++
++ baud_rate = inspeed = baud_rate_of(speed);
++ restore_term = 1;
++}
++
++/*
++ * restore_tty - restore the terminal to the saved settings.
++ */
++void
++restore_tty(fd)
++ int fd;
++{
++ if (restore_term) {
++ if (!default_device) {
++ /*
++ * Turn off echoing, because otherwise we can get into
++ * a loop with the tty and the modem echoing to each other.
++ * We presume we are the sole user of this tty device, so
++ * when we close it, it will revert to its defaults anyway.
++ */
++ inittermios.c_lflag &amp;= ~(ECHO | ECHONL);
++ }
++ if (tcsetattr(fd, TCSAFLUSH, &amp;inittermios) &lt; 0)
++ if (!hungup &amp;&amp; errno != ENXIO)
++ warn(&quot;tcsetattr: %m&quot;);
++ ioctl(fd, TIOCSWINSZ, &amp;wsinfo);
++ restore_term = 0;
++ }
++}
++
++/*
++ * setdtr - control the DTR line on the serial port.
++ * This is called from die(), so it shouldn't call die().
++ */
++void
++setdtr(fd, on)
++int fd, on;
++{
++ int modembits = TIOCM_DTR;
++
++ ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &amp;modembits);
++}
++
++/*
++ * open_loopback - open the device we use for getting packets
++ * in demand mode. Under SunOS, we use our existing fd
++ * to the ppp driver.
++ */
++int
++open_ppp_loopback()
++{
++ return pppfd;
++}
++
++/*
++ * output - Output PPP packet.
++ */
++void
++output(unit, p, len)
++ int unit;
++ u_char *p;
++ int len;
++{
++ struct strbuf data;
++ int retries;
++ struct pollfd pfd;
++
++ if (debug)
++ dbglog(&quot;sent %P&quot;, p, len);
++
++ data.len = len;
++ data.buf = (caddr_t) p;
++ retries = 4;
++ while (putmsg(pppfd, NULL, &amp;data, 0) &lt; 0) {
++ if (--retries &lt; 0 || (errno != EWOULDBLOCK &amp;&amp; errno != EAGAIN)) {
++ if (errno != ENXIO)
++ error(&quot;Couldn't send packet: %m&quot;);
++ break;
++ }
++ pfd.fd = pppfd;
++ pfd.events = POLLOUT;
++ poll(&amp;pfd, 1, 250); /* wait for up to 0.25 seconds */
++ }
++}
++
++
++/*
++ * wait_input - wait until there is data available,
++ * for the length of time specified by *timo (indefinite
++ * if timo is NULL).
++ */
++void
++wait_input(timo)
++ struct timeval *timo;
++{
++ int t;
++
++ t = timo == NULL? -1: timo-&gt;tv_sec * 1000 + timo-&gt;tv_usec / 1000;
++ if (poll(pollfds, n_pollfds, t) &lt; 0 &amp;&amp; errno != EINTR) {
++ if (errno != EAGAIN)
++ fatal(&quot;poll: %m&quot;);
++ /* we can get EAGAIN on a heavily loaded system,
++ * just wait a short time and try again. */
++ usleep(50000);
++ }
++}
++
++/*
++ * add_fd - add an fd to the set that wait_input waits for.
++ */
++void add_fd(fd)
++ int fd;
++{
++ int n;
++
++ for (n = 0; n &lt; n_pollfds; ++n)
++ if (pollfds[n].fd == fd)
++ return;
++ if (n_pollfds &lt; MAX_POLLFDS) {
++ pollfds[n_pollfds].fd = fd;
++ pollfds[n_pollfds].events = POLLIN | POLLPRI | POLLHUP;
++ ++n_pollfds;
++ } else
++ error(&quot;Too many inputs!&quot;);
++}
++
++/*
++ * remove_fd - remove an fd from the set that wait_input waits for.
++ */
++void remove_fd(fd)
++ int fd;
++{
++ int n;
++
++ for (n = 0; n &lt; n_pollfds; ++n) {
++ if (pollfds[n].fd == fd) {
++ while (++n &lt; n_pollfds)
++ pollfds[n-1] = pollfds[n];
++ --n_pollfds;
++ break;
++ }
++ }
++}
++
++#if 0
++/*
++ * wait_loop_output - wait until there is data available on the
++ * loopback, for the length of time specified by *timo (indefinite
++ * if timo is NULL).
++ */
++void
++wait_loop_output(timo)
++ struct timeval *timo;
++{
++ wait_input(timo);
++}
++
++/*
++ * wait_time - wait for a given length of time or until a
++ * signal is received.
++ */
++void
++wait_time(timo)
++ struct timeval *timo;
++{
++ int n;
++
++ n = select(0, NULL, NULL, NULL, timo);
++ if (n &lt; 0 &amp;&amp; errno != EINTR)
++ fatal(&quot;select: %m&quot;);
++}
++#endif
++
++/*
++ * read_packet - get a PPP packet from the serial device.
++ */
++int
++read_packet(buf)
++ u_char *buf;
++{
++ struct strbuf ctrl, data;
++ int flags, len;
++ unsigned char ctrlbuf[64];
++
++ for (;;) {
++ data.maxlen = PPP_MRU + PPP_HDRLEN;
++ data.buf = (caddr_t) buf;
++ ctrl.maxlen = sizeof(ctrlbuf);
++ ctrl.buf = (caddr_t) ctrlbuf;
++ flags = 0;
++ len = getmsg(pppfd, &amp;ctrl, &amp;data, &amp;flags);
++ if (len &lt; 0) {
++ if (errno == EAGAIN || errno == EINTR)
++ return -1;
++ fatal(&quot;Error reading packet: %m&quot;);
++ }
++
++ if (ctrl.len &lt;= 0)
++ return data.len;
++
++ /*
++ * Got a M_PROTO or M_PCPROTO message. Huh?
++ */
++ if (debug)
++ dbglog(&quot;got ctrl msg len=%d&quot;, ctrl.len);
++
++ }
++}
++
++/*
++ * get_loop_output - get outgoing packets from the ppp device,
++ * and detect when we want to bring the real link up.
++ * Return value is 1 if we need to bring up the link, 0 otherwise.
++ */
++int
++get_loop_output()
++{
++ int len;
++ int rv = 0;
++
++ while ((len = read_packet(inpacket_buf)) &gt; 0) {
++ if (loop_frame(inpacket_buf, len))
++ rv = 1;
++ }
++ return rv;
++}
++
++/*
++ * ppp_send_config - configure the transmit characteristics of
++ * the ppp interface.
++ */
++void
++ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
++ int unit, mtu;
++ u_int32_t asyncmap;
++ int pcomp, accomp;
++{
++ int cf[2];
++ struct ifreq ifr;
++
++ link_mtu = mtu;
++ if (strioctl(pppfd, PPPIO_MTU, &amp;mtu, sizeof(mtu), 0) &lt; 0) {
++ if (hungup &amp;&amp; errno == ENXIO)
++ return;
++ error(&quot;Couldn't set MTU: %m&quot;);
++ }
++ if (strioctl(pppfd, PPPIO_XACCM, &amp;asyncmap, sizeof(asyncmap), 0) &lt; 0) {
++ error(&quot;Couldn't set transmit ACCM: %m&quot;);
++ }
++ cf[0] = (pcomp? COMP_PROT: 0) + (accomp? COMP_AC: 0);
++ cf[1] = COMP_PROT | COMP_AC;
++ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) &lt; 0) {
++ error(&quot;Couldn't set prot/AC compression: %m&quot;);
++ }
++
++ /* set mtu for ip as well */
++ memset(&amp;ifr, 0, sizeof(ifr));
++ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
++ ifr.ifr_metric = link_mtu;
++ if (ioctl(sockfd, SIOCSIFMTU, &amp;ifr) &lt; 0) {
++ error(&quot;Couldn't set IP MTU: %m&quot;);
++ }
++}
++
++/*
++ * ppp_set_xaccm - set the extended transmit ACCM for the interface.
++ */
++void
++ppp_set_xaccm(unit, accm)
++ int unit;
++ ext_accm accm;
++{
++ if (strioctl(pppfd, PPPIO_XACCM, accm, sizeof(ext_accm), 0) &lt; 0) {
++ if (!hungup || errno != ENXIO)
++ warn(&quot;Couldn't set extended ACCM: %m&quot;);
++ }
++}
++
++/*
++ * ppp_recv_config - configure the receive-side characteristics of
++ * the ppp interface.
++ */
++void
++ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
++ int unit, mru;
++ u_int32_t asyncmap;
++ int pcomp, accomp;
++{
++ int cf[2];
++
++ link_mru = mru;
++ if (strioctl(pppfd, PPPIO_MRU, &amp;mru, sizeof(mru), 0) &lt; 0) {
++ if (hungup &amp;&amp; errno == ENXIO)
++ return;
++ error(&quot;Couldn't set MRU: %m&quot;);
++ }
++ if (strioctl(pppfd, PPPIO_RACCM, &amp;asyncmap, sizeof(asyncmap), 0) &lt; 0) {
++ error(&quot;Couldn't set receive ACCM: %m&quot;);
++ }
++ cf[0] = (pcomp? DECOMP_PROT: 0) + (accomp? DECOMP_AC: 0);
++ cf[1] = DECOMP_PROT | DECOMP_AC;
++ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) &lt; 0) {
++ error(&quot;Couldn't set prot/AC decompression: %m&quot;);
++ }
++}
++
++/*
++ * ccp_test - ask kernel whether a given compression method
++ * is acceptable for use.
++ */
++int
++ccp_test(unit, opt_ptr, opt_len, for_transmit)
++ int unit, opt_len, for_transmit;
++ u_char *opt_ptr;
++{
++ if (strioctl(pppfd, (for_transmit? PPPIO_XCOMP: PPPIO_RCOMP),
++ opt_ptr, opt_len, 0) &gt;= 0)
++ return 1;
++ return (errno == ENOSR)? 0: -1;
++}
++
++/*
++ * ccp_flags_set - inform kernel about the current state of CCP.
++ */
++void
++ccp_flags_set(unit, isopen, isup)
++ int unit, isopen, isup;
++{
++ int cf[2];
++
++ cf[0] = (isopen? CCP_ISOPEN: 0) + (isup? CCP_ISUP: 0);
++ cf[1] = CCP_ISOPEN | CCP_ISUP | CCP_ERROR | CCP_FATALERROR;
++ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) &lt; 0) {
++ if (!hungup || errno != ENXIO)
++ error(&quot;Couldn't set kernel CCP state: %m&quot;);
++ }
++}
++
++/*
++ * get_idle_time - return how long the link has been idle.
++ */
++int
++get_idle_time(u, ip)
++ int u;
++ struct ppp_idle *ip;
++{
++ return strioctl(pppfd, PPPIO_GIDLE, ip, 0, sizeof(struct ppp_idle)) &gt;= 0;
++}
++
++/*
++ * get_ppp_stats - return statistics for the link.
++ */
++int
++get_ppp_stats(u, stats)
++ int u;
++ struct pppd_stats *stats;
++{
++ struct ppp_stats s;
++
++ if (strioctl(pppfd, PPPIO_GETSTAT, &amp;s, 0, sizeof(s)) &lt; 0) {
++ error(&quot;Couldn't get link statistics: %m&quot;);
++ return 0;
++ }
++ stats-&gt;bytes_in = s.p.ppp_ibytes;
++ stats-&gt;bytes_out = s.p.ppp_obytes;
++ return 1;
++}
++
++
++/*
++ * ccp_fatal_error - returns 1 if decompression was disabled as a
++ * result of an error detected after decompression of a packet,
++ * 0 otherwise. This is necessary because of patent nonsense.
++ */
++int
++ccp_fatal_error(unit)
++ int unit;
++{
++ int cf[2];
++
++ cf[0] = cf[1] = 0;
++ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) &lt; 0) {
++ if (errno != ENXIO &amp;&amp; errno != EINVAL)
++ error(&quot;Couldn't get compression flags: %m&quot;);
++ return 0;
++ }
++ return cf[0] &amp; CCP_FATALERROR;
++}
++
++/*
++ * sifvjcomp - config tcp header compression
++ */
++int
++sifvjcomp(u, vjcomp, xcidcomp, xmaxcid)
++ int u, vjcomp, xcidcomp, xmaxcid;
++{
++ int cf[2];
++ char maxcid[2];
++
++ if (vjcomp) {
++ maxcid[0] = xcidcomp;
++ maxcid[1] = 15; /* XXX should be rmaxcid */
++ if (strioctl(pppfd, PPPIO_VJINIT, maxcid, sizeof(maxcid), 0) &lt; 0) {
++ error(&quot;Couldn't initialize VJ compression: %m&quot;);
++ }
++ }
++
++ cf[0] = (vjcomp? COMP_VJC + DECOMP_VJC: 0) /* XXX this is wrong */
++ + (xcidcomp? COMP_VJCCID + DECOMP_VJCCID: 0);
++ cf[1] = COMP_VJC + DECOMP_VJC + COMP_VJCCID + DECOMP_VJCCID;
++ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) &lt; 0) {
++ if (vjcomp)
++ error(&quot;Couldn't enable VJ compression: %m&quot;);
++ }
++
++ return 1;
++}
++
++/*
++ * sifup - Config the interface up and enable IP packets to pass.
++ */
++int
++sifup(u)
++ int u;
++{
++ struct ifreq ifr;
++
++ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
++ if (ioctl(sockfd, SIOCGIFFLAGS, &amp;ifr) &lt; 0) {
++ error(&quot;Couldn't mark interface up (get): %m&quot;);
++ return 0;
++ }
++ ifr.ifr_flags |= IFF_UP;
++ if (ioctl(sockfd, SIOCSIFFLAGS, &amp;ifr) &lt; 0) {
++ error(&quot;Couldn't mark interface up (set): %m&quot;);
++ return 0;
++ }
++ if_is_up = 1;
++ return 1;
++}
++
++/*
++ * sifdown - Config the interface down and disable IP.
++ */
++int
++sifdown(u)
++ int u;
++{
++ struct ifreq ifr;
++
++ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
++ if (ioctl(sockfd, SIOCGIFFLAGS, &amp;ifr) &lt; 0) {
++ error(&quot;Couldn't mark interface down (get): %m&quot;);
++ return 0;
++ }
++ if ((ifr.ifr_flags &amp; IFF_UP) != 0) {
++ ifr.ifr_flags &amp;= ~IFF_UP;
++ if (ioctl(sockfd, SIOCSIFFLAGS, &amp;ifr) &lt; 0) {
++ error(&quot;Couldn't mark interface down (set): %m&quot;);
++ return 0;
++ }
++ }
++ if_is_up = 0;
++ return 1;
++}
++
++/*
++ * sifnpmode - Set the mode for handling packets for a given NP.
++ */
++int
++sifnpmode(u, proto, mode)
++ int u;
++ int proto;
++ enum NPmode mode;
++{
++ int npi[2];
++
++ npi[0] = proto;
++ npi[1] = (int) mode;
++ if (strioctl(pppfd, PPPIO_NPMODE, npi, 2 * sizeof(int), 0) &lt; 0) {
++ error(&quot;ioctl(set NP %d mode to %d): %m&quot;, proto, mode);
++ return 0;
++ }
++ return 1;
++}
++
++#define INET_ADDR(x) (((struct sockaddr_in *) &amp;(x))-&gt;sin_addr.s_addr)
++
++/*
++ * sifaddr - Config the interface IP addresses and netmask.
++ */
++int
++sifaddr(u, o, h, m)
++ int u;
++ u_int32_t o, h, m;
++{
++ struct ifreq ifr;
++
++ memset(&amp;ifr, 0, sizeof(ifr));
++ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
++ ifr.ifr_addr.sa_family = AF_INET;
++ INET_ADDR(ifr.ifr_addr) = m;
++ if (ioctl(sockfd, SIOCSIFNETMASK, &amp;ifr) &lt; 0) {
++ error(&quot;Couldn't set IP netmask: %m&quot;);
++ }
++ ifr.ifr_addr.sa_family = AF_INET;
++ INET_ADDR(ifr.ifr_addr) = o;
++ if (ioctl(sockfd, SIOCSIFADDR, &amp;ifr) &lt; 0) {
++ error(&quot;Couldn't set local IP address: %m&quot;);
++ }
++ ifr.ifr_dstaddr.sa_family = AF_INET;
++ INET_ADDR(ifr.ifr_dstaddr) = h;
++ if (ioctl(sockfd, SIOCSIFDSTADDR, &amp;ifr) &lt; 0) {
++ error(&quot;Couldn't set remote IP address: %m&quot;);
++ }
++#if 0 /* now done in ppp_send_config */
++ ifr.ifr_metric = link_mtu;
++ if (ioctl(sockfd, SIOCSIFMTU, &amp;ifr) &lt; 0) {
++ error(&quot;Couldn't set IP MTU: %m&quot;);
++ }
++#endif
++ ifaddrs[0] = o;
++ ifaddrs[1] = h;
++
++ return 1;
++}
++
++/*
++ * cifaddr - Clear the interface IP addresses, and delete routes
++ * through the interface if possible.
++ */
++int
++cifaddr(u, o, h)
++ int u;
++ u_int32_t o, h;
++{
++ struct rtentry rt;
++
++ bzero(&amp;rt, sizeof(rt));
++ rt.rt_dst.sa_family = AF_INET;
++ INET_ADDR(rt.rt_dst) = h;
++ rt.rt_gateway.sa_family = AF_INET;
++ INET_ADDR(rt.rt_gateway) = o;
++ rt.rt_flags = RTF_HOST;
++ if (ioctl(sockfd, SIOCDELRT, &amp;rt) &lt; 0)
++ error(&quot;Couldn't delete route through interface: %m&quot;);
++ ifaddrs[0] = 0;
++ return 1;
++}
++
++/*
++ * sifdefaultroute - assign a default route through the address given.
++ */
++int
++sifdefaultroute(u, l, g)
++ int u;
++ u_int32_t l, g;
++{
++ struct rtentry rt;
++
++ bzero(&amp;rt, sizeof(rt));
++ rt.rt_dst.sa_family = AF_INET;
++ INET_ADDR(rt.rt_dst) = 0;
++ rt.rt_gateway.sa_family = AF_INET;
++ INET_ADDR(rt.rt_gateway) = g;
++ rt.rt_flags = RTF_GATEWAY;
++
++ if (ioctl(sockfd, SIOCADDRT, &amp;rt) &lt; 0) {
++ error(&quot;Can't add default route: %m&quot;);
++ return 0;
++ }
++
++ default_route_gateway = g;
++ return 1;
++}
++
++/*
++ * cifdefaultroute - delete a default route through the address given.
++ */
++int
++cifdefaultroute(u, l, g)
++ int u;
++ u_int32_t l, g;
++{
++ struct rtentry rt;
++
++ bzero(&amp;rt, sizeof(rt));
++ rt.rt_dst.sa_family = AF_INET;
++ INET_ADDR(rt.rt_dst) = 0;
++ rt.rt_gateway.sa_family = AF_INET;
++ INET_ADDR(rt.rt_gateway) = g;
++ rt.rt_flags = RTF_GATEWAY;
++
++ if (ioctl(sockfd, SIOCDELRT, &amp;rt) &lt; 0) {
++ error(&quot;Can't delete default route: %m&quot;);
++ return 0;
++ }
++
++ default_route_gateway = 0;
++ return 1;
++}
++
++/*
++ * sifproxyarp - Make a proxy ARP entry for the peer.
++ */
++int
++sifproxyarp(unit, hisaddr)
++ int unit;
++ u_int32_t hisaddr;
++{
++ struct arpreq arpreq;
++
++ bzero(&amp;arpreq, sizeof(arpreq));
++ if (!get_ether_addr(hisaddr, &amp;arpreq.arp_ha))
++ return 0;
++
++ arpreq.arp_pa.sa_family = AF_INET;
++ INET_ADDR(arpreq.arp_pa) = hisaddr;
++ arpreq.arp_flags = ATF_PERM | ATF_PUBL;
++ if (ioctl(sockfd, SIOCSARP, (caddr_t) &amp;arpreq) &lt; 0) {
++ error(&quot;Couldn't set proxy ARP entry: %m&quot;);
++ return 0;
++ }
++
++ proxy_arp_addr = hisaddr;
++ return 1;
++}
++
++/*
++ * cifproxyarp - Delete the proxy ARP entry for the peer.
++ */
++int
++cifproxyarp(unit, hisaddr)
++ int unit;
++ u_int32_t hisaddr;
++{
++ struct arpreq arpreq;
++
++ bzero(&amp;arpreq, sizeof(arpreq));
++ arpreq.arp_pa.sa_family = AF_INET;
++ INET_ADDR(arpreq.arp_pa) = hisaddr;
++ if (ioctl(sockfd, SIOCDARP, (caddr_t)&amp;arpreq) &lt; 0) {
++ error(&quot;Couldn't delete proxy ARP entry: %m&quot;);
++ return 0;
++ }
++
++ proxy_arp_addr = 0;
++ return 1;
++}
++
++/*
++ * get_ether_addr - get the hardware address of an interface on the
++ * the same subnet as ipaddr.
++ */
++#define MAX_IFS 32
++
++static int
++get_ether_addr(ipaddr, hwaddr)
++ u_int32_t ipaddr;
++ struct sockaddr *hwaddr;
++{
++ struct ifreq *ifr, *ifend;
++ u_int32_t ina, mask;
++ struct ifreq ifreq;
++ struct ifconf ifc;
++ struct ifreq ifs[MAX_IFS];
++ int nit_fd;
++
++ ifc.ifc_len = sizeof(ifs);
++ ifc.ifc_req = ifs;
++ if (ioctl(sockfd, SIOCGIFCONF, &amp;ifc) &lt; 0) {
++ error(&quot;ioctl(SIOCGIFCONF): %m&quot;);
++ return 0;
++ }
++
++ /*
++ * Scan through looking for an interface with an Internet
++ * address on the same subnet as `ipaddr'.
++ */
++ ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
++ for (ifr = ifc.ifc_req; ifr &lt; ifend; ifr = (struct ifreq *)
++ ((char *)&amp;ifr-&gt;ifr_addr + sizeof(struct sockaddr))) {
++ if (ifr-&gt;ifr_addr.sa_family == AF_INET) {
++
++ /*
++ * Check that the interface is up, and not point-to-point
++ * or loopback.
++ */
++ strlcpy(ifreq.ifr_name, ifr-&gt;ifr_name, sizeof(ifreq.ifr_name));
++ if (ioctl(sockfd, SIOCGIFFLAGS, &amp;ifreq) &lt; 0)
++ continue;
++ if ((ifreq.ifr_flags &amp;
++ (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
++ != (IFF_UP|IFF_BROADCAST))
++ continue;
++
++ /*
++ * Get its netmask and check that it's on the right subnet.
++ */
++ if (ioctl(sockfd, SIOCGIFNETMASK, &amp;ifreq) &lt; 0)
++ continue;
++ ina = ((struct sockaddr_in *) &amp;ifr-&gt;ifr_addr)-&gt;sin_addr.s_addr;
++ mask = ((struct sockaddr_in *) &amp;ifreq.ifr_addr)-&gt;sin_addr.s_addr;
++ if ((ipaddr &amp; mask) != (ina &amp; mask))
++ continue;
++
++ break;
++ }
++ }
++
++ if (ifr &gt;= ifend)
++ return 0;
++ info(&quot;found interface %s for proxy arp&quot;, ifr-&gt;ifr_name);
++
++ /*
++ * Grab the physical address for this interface.
++ */
++ if ((nit_fd = open(&quot;/dev/nit&quot;, O_RDONLY)) &lt; 0) {
++ error(&quot;Couldn't open /dev/nit: %m&quot;);
++ return 0;
++ }
++ strlcpy(ifreq.ifr_name, ifr-&gt;ifr_name, sizeof(ifreq.ifr_name));
++ if (ioctl(nit_fd, NIOCBIND, &amp;ifreq) &lt; 0
++ || ioctl(nit_fd, SIOCGIFADDR, &amp;ifreq) &lt; 0) {
++ error(&quot;Couldn't get hardware address for %s: %m&quot;,
++ ifreq.ifr_name);
++ close(nit_fd);
++ return 0;
++ }
++
++ hwaddr-&gt;sa_family = AF_UNSPEC;
++ memcpy(hwaddr-&gt;sa_data, ifreq.ifr_addr.sa_data, 6);
++ close(nit_fd);
++ return 1;
++}
++
++/*
++ * have_route_to - determine if the system has any route to
++ * a given IP address.
++ * For demand mode to work properly, we have to ignore routes
++ * through our own interface.
++ */
++int have_route_to(addr)
++ u_int32_t addr;
++{
++ return -1;
++}
++
++#define WTMPFILE &quot;/usr/adm/wtmp&quot;
++
++void
++logwtmp(line, name, host)
++ const char *line, *name, *host;
++{
++ int fd;
++ struct stat buf;
++ struct utmp ut;
++
++ if ((fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) &lt; 0)
++ return;
++ if (!fstat(fd, &amp;buf)) {
++ strncpy(ut.ut_line, line, sizeof(ut.ut_line));
++ strncpy(ut.ut_name, name, sizeof(ut.ut_name));
++ strncpy(ut.ut_host, host, sizeof(ut.ut_host));
++ (void)time(&amp;ut.ut_time);
++ if (write(fd, (char *)&amp;ut, sizeof(struct utmp)) != sizeof(struct utmp))
++ (void)ftruncate(fd, buf.st_size);
++ }
++ close(fd);
++}
++
++/*
++ * Return user specified netmask, modified by any mask we might determine
++ * for address `addr' (in network byte order).
++ * Here we scan through the system's list of interfaces, looking for
++ * any non-point-to-point interfaces which might appear to be on the same
++ * network as `addr'. If we find any, we OR in their netmask to the
++ * user-specified netmask.
++ */
++u_int32_t
++GetMask(addr)
++ u_int32_t addr;
++{
++ u_int32_t mask, nmask, ina;
++ struct ifreq *ifr, *ifend, ifreq;
++ struct ifconf ifc;
++
++ addr = ntohl(addr);
++ if (IN_CLASSA(addr)) /* determine network mask for address class */
++ nmask = IN_CLASSA_NET;
++ else if (IN_CLASSB(addr))
++ nmask = IN_CLASSB_NET;
++ else
++ nmask = IN_CLASSC_NET;
++ /* class D nets are disallowed by bad_ip_adrs */
++ mask = netmask | htonl(nmask);
++
++ /*
++ * Scan through the system's network interfaces.
++ */
++ ifc.ifc_len = MAX_IFS * sizeof(struct ifreq);
++ ifc.ifc_req = alloca(ifc.ifc_len);
++ if (ifc.ifc_req == 0)
++ return mask;
++ if (ioctl(sockfd, SIOCGIFCONF, &amp;ifc) &lt; 0) {
++ warn(&quot;Couldn't get system interface list: %m&quot;);
++ return mask;
++ }
++ ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
++ for (ifr = ifc.ifc_req; ifr &lt; ifend; ++ifr) {
++ /*
++ * Check the interface's internet address.
++ */
++ if (ifr-&gt;ifr_addr.sa_family != AF_INET)
++ continue;
++ ina = INET_ADDR(ifr-&gt;ifr_addr);
++ if ((ntohl(ina) &amp; nmask) != (addr &amp; nmask))
++ continue;
++ /*
++ * Check that the interface is up, and not point-to-point or loopback.
++ */
++ strlcpy(ifreq.ifr_name, ifr-&gt;ifr_name, sizeof(ifreq.ifr_name));
++ if (ioctl(sockfd, SIOCGIFFLAGS, &amp;ifreq) &lt; 0)
++ continue;
++ if ((ifreq.ifr_flags &amp; (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK))
++ != IFF_UP)
++ continue;
++ /*
++ * Get its netmask and OR it into our mask.
++ */
++ if (ioctl(sockfd, SIOCGIFNETMASK, &amp;ifreq) &lt; 0)
++ continue;
++ mask |= INET_ADDR(ifreq.ifr_addr);
++ }
++
++ return mask;
++}
++
++static int
++strioctl(fd, cmd, ptr, ilen, olen)
++ int fd, cmd, ilen, olen;
++ void *ptr;
++{
++ struct strioctl str;
++
++ str.ic_cmd = cmd;
++ str.ic_timout = 0;
++ str.ic_len = ilen;
++ str.ic_dp = ptr;
++ if (ioctl(fd, I_STR, &amp;str) == -1)
++ return -1;
++ if (str.ic_len != olen)
++ dbglog(&quot;strioctl: expected %d bytes, got %d for cmd %x\n&quot;,
++ olen, str.ic_len, cmd);
++ return 0;
++}
++
++/*
++ * Use the hostid as part of the random number seed.
++ */
++int
++get_host_seed()
++{
++ return gethostid();
++}
++
++#if 0
++/*
++ * Code for locking/unlocking the serial device.
++ * This code is derived from chat.c.
++ */
++
++#if !defined(HDB) &amp;&amp; !defined(SUNOS3)
++#define HDB 1 /* ascii lock files are the default */
++#endif
++
++#ifndef LOCK_DIR
++# if HDB
++# define PIDSTRING
++# define LOCK_PREFIX &quot;/usr/spool/locks/LCK..&quot;
++# else /* HDB */
++# define LOCK_PREFIX &quot;/usr/spool/uucp/LCK..&quot;
++# endif /* HDB */
++#endif /* LOCK_DIR */
++
++static char *lock_file; /* name of lock file created */
++
++/*
++ * lock - create a lock file for the named device.
++ */
++int
++lock(dev)
++ char *dev;
++{
++ char hdb_lock_buffer[12];
++ int fd, pid, n;
++ char *p;
++ size_t l;
++
++ if ((p = strrchr(dev, '/')) != NULL)
++ dev = p + 1;
++ l = strlen(LOCK_PREFIX) + strlen(dev) + 1;
++ lock_file = malloc(l);
++ if (lock_file == NULL)
++ novm(&quot;lock file name&quot;);
++ slprintf(lock_file, l, &quot;%s%s&quot;, LOCK_PREFIX, dev);
++
++ while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) &lt; 0) {
++ if (errno == EEXIST
++ &amp;&amp; (fd = open(lock_file, O_RDONLY, 0)) &gt;= 0) {
++ /* Read the lock file to find out who has the device locked */
++#ifdef PIDSTRING
++ n = read(fd, hdb_lock_buffer, 11);
++ if (n &gt; 0) {
++ hdb_lock_buffer[n] = 0;
++ pid = atoi(hdb_lock_buffer);
++ }
++#else
++ n = read(fd, &amp;pid, sizeof(pid));
++#endif
++ if (n &lt;= 0) {
++ error(&quot;Can't read pid from lock file %s&quot;, lock_file);
++ close(fd);
++ } else {
++ if (kill(pid, 0) == -1 &amp;&amp; errno == ESRCH) {
++ /* pid no longer exists - remove the lock file */
++ if (unlink(lock_file) == 0) {
++ close(fd);
++ notice(&quot;Removed stale lock on %s (pid %d)&quot;,
++ dev, pid);
++ continue;
++ } else
++ warn(&quot;Couldn't remove stale lock on %s&quot;,
++ dev);
++ } else
++ notice(&quot;Device %s is locked by pid %d&quot;,
++ dev, pid);
++ }
++ close(fd);
++ } else
++ error(&quot;Can't create lock file %s: %m&quot;, lock_file);
++ free(lock_file);
++ lock_file = NULL;
++ return -1;
++ }
++
++#ifdef PIDSTRING
++ slprintf(hdb_lock_buffer, sizeof(hdb_lock_buffer), &quot;%10d\n&quot;, getpid());
++ write(fd, hdb_lock_buffer, 11);
++#else
++ pid = getpid();
++ write(fd, &amp;pid, sizeof pid);
++#endif
++
++ close(fd);
++ return 0;
++}
++
++/*
++ * unlock - remove our lockfile
++ */
++void
++unlock()
++{
++ if (lock_file) {
++ unlink(lock_file);
++ free(lock_file);
++ lock_file = NULL;
++ }
++}
++#endif /* lock stuff removed */
++
++/*
++ * get_pty - get a pty master/slave pair and chown the slave side
++ * to the uid given. Assumes slave_name points to &gt;= 12 bytes of space.
++ */
++int
++get_pty(master_fdp, slave_fdp, slave_name, uid)
++ int *master_fdp;
++ int *slave_fdp;
++ char *slave_name;
++ int uid;
++{
++ int i, mfd, sfd;
++ char pty_name[12];
++ struct termios tios;
++
++ sfd = -1;
++ for (i = 0; i &lt; 64; ++i) {
++ slprintf(pty_name, sizeof(pty_name), &quot;/dev/pty%c%x&quot;,
++ 'p' + i / 16, i % 16);
++ mfd = open(pty_name, O_RDWR, 0);
++ if (mfd &gt;= 0) {
++ pty_name[5] = 't';
++ sfd = open(pty_name, O_RDWR | O_NOCTTY, 0);
++ if (sfd &gt;= 0)
++ break;
++ close(mfd);
++ }
++ }
++ if (sfd &lt; 0)
++ return 0;
++
++ strlcpy(slave_name, pty_name, 12);
++ *master_fdp = mfd;
++ *slave_fdp = sfd;
++ fchown(sfd, uid, -1);
++ fchmod(sfd, S_IRUSR | S_IWUSR);
++ if (tcgetattr(sfd, &amp;tios) == 0) {
++ tios.c_cflag &amp;= ~(CSIZE | CSTOPB | PARENB);
++ tios.c_cflag |= CS8 | CREAD;
++ tios.c_iflag = IGNPAR | CLOCAL;
++ tios.c_oflag = 0;
++ tios.c_lflag = 0;
++ if (tcsetattr(sfd, TCSAFLUSH, &amp;tios) &lt; 0)
++ warn(&quot;couldn't set attributes on pty: %m&quot;);
++ } else
++ warn(&quot;couldn't get attributes on pty: %m&quot;);
++
++ return 1;
++}
++
++/*
++ * SunOS doesn't have strtoul :-(
++ */
++unsigned long
++strtoul(str, ptr, base)
++ char *str, **ptr;
++ int base;
++{
++ return (unsigned long) strtol(str, ptr, base);
++}
++
++/*
++ * Or strerror :-(
++ */
++extern char *sys_errlist[];
++extern int sys_nerr;
++
++char *
++strerror(n)
++ int n;
++{
++ static char unknown[32];
++
++ if (n &gt; 0 &amp;&amp; n &lt; sys_nerr)
++ return sys_errlist[n];
++ slprintf(unknown, sizeof(unknown), &quot;Error %d&quot;, n);
++ return unknown;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/sys-sunos4.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/tdb.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/tdb.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/tdb.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1282 @@
++/*
++ * Database functions
++ * Copyright (C) Andrew Tridgell 1999
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms AND provided that this software or
++ * any derived work is only used as part of the PPP daemon (pppd)
++ * and related utilities.
++ * The name of the author may not be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * Note: this software is also available under the Gnu Public License
++ * version 2 or later.
++ */
++
++#include &lt;stdlib.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;string.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;errno.h&gt;
++#include &lt;sys/mman.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &quot;tdb.h&quot;
++
++#define TDB_VERSION (0x26011967 + 1)
++#define TDB_MAGIC (0x26011999U)
++#define TDB_FREE_MAGIC (~TDB_MAGIC)
++#define TDB_ALIGN 4
++#define MIN_REC_SIZE (2*sizeof(struct list_struct) + TDB_ALIGN)
++#define DEFAULT_HASH_SIZE 128
++#define TDB_PAGE_SIZE 0x2000
++#define TDB_LEN_MULTIPLIER 10
++#define FREELIST_TOP (sizeof(struct tdb_header))
++
++#define LOCK_SET 1
++#define LOCK_CLEAR 0
++
++/* lock offsets */
++#define GLOBAL_LOCK 0
++#define ACTIVE_LOCK 4
++#define LIST_LOCK_BASE 1024
++
++#define BUCKET(hash) ((hash) % tdb-&gt;header.hash_size)
++
++#ifndef MAP_FILE
++#define MAP_FILE 0
++#endif
++
++/* the body of the database is made of one list_struct for the free space
++ plus a separate data list for each hash value */
++struct list_struct {
++ tdb_len rec_len; /* total byte length of record */
++ tdb_off next; /* offset of the next record in the list */
++ tdb_len key_len; /* byte length of key */
++ tdb_len data_len; /* byte length of data */
++ unsigned full_hash; /* the full 32 bit hash of the key */
++ unsigned magic; /* try to catch errors */
++ /*
++ the following union is implied
++ union {
++ char record[rec_len];
++ struct {
++ char key[key_len];
++ char data[data_len];
++ }
++ }
++ */
++};
++
++/* a null data record - useful for error returns */
++static TDB_DATA null_data;
++
++/* a byte range locking function - return 0 on success
++ this functions locks/unlocks 1 byte at the specified offset */
++static int tdb_brlock(TDB_CONTEXT *tdb, tdb_off offset,
++ int set, int rw_type, int lck_type)
++{
++#if NOLOCK
++ return 0;
++#else
++ struct flock fl;
++
++ if (tdb-&gt;fd == -1) return 0; /* for in memory tdb */
++
++ if (tdb-&gt;read_only) return -1;
++
++ fl.l_type = set==LOCK_SET?rw_type:F_UNLCK;
++ fl.l_whence = SEEK_SET;
++ fl.l_start = offset;
++ fl.l_len = 1;
++ fl.l_pid = 0;
++
++ if (fcntl(tdb-&gt;fd, lck_type, &amp;fl) != 0) {
++#if TDB_DEBUG
++ if (lck_type == F_SETLKW) {
++ printf(&quot;lock %d failed at %d (%s)\n&quot;,
++ set, offset, strerror(errno));
++ }
++#endif
++ tdb-&gt;ecode = TDB_ERR_LOCK;
++ return -1;
++ }
++ return 0;
++#endif
++}
++
++/* lock a list in the database. list -1 is the alloc list */
++static int tdb_lock(TDB_CONTEXT *tdb, int list)
++{
++ if (list &lt; -1 || list &gt;= (int)tdb-&gt;header.hash_size) {
++#if TDB_DEBUG
++ printf(&quot;bad list %d\n&quot;, list);
++#endif
++ return -1;
++ }
++ if (tdb-&gt;locked[list+1] == 0) {
++ if (tdb_brlock(tdb, LIST_LOCK_BASE + 4*list, LOCK_SET,
++ F_WRLCK, F_SETLKW) != 0) {
++ return -1;
++ }
++ }
++ tdb-&gt;locked[list+1]++;
++ return 0;
++}
++
++/* unlock the database. */
++static int tdb_unlock(TDB_CONTEXT *tdb, int list)
++{
++ if (list &lt; -1 || list &gt;= (int)tdb-&gt;header.hash_size) {
++#if TDB_DEBUG
++ printf(&quot;bad unlock list %d\n&quot;, list);
++#endif
++ return -1;
++ }
++
++ if (tdb-&gt;locked[list+1] == 0) {
++#if TDB_DEBUG
++ printf(&quot;not locked %d\n&quot;, list);
++#endif
++ tdb-&gt;ecode = TDB_ERR_LOCK;
++ return -1;
++ }
++ if (tdb-&gt;locked[list+1] == 1) {
++ if (tdb_brlock(tdb, LIST_LOCK_BASE + 4*list, LOCK_CLEAR,
++ F_WRLCK, F_SETLKW) != 0) {
++ return -1;
++ }
++ }
++ tdb-&gt;locked[list+1]--;
++ return 0;
++}
++
++/* the hash algorithm - turn a key into an integer
++ This is based on the hash agorithm from gdbm */
++static unsigned tdb_hash(TDB_DATA *key)
++{
++ unsigned value; /* Used to compute the hash value. */
++ unsigned i; /* Used to cycle through random values. */
++
++ /* Set the initial value from the key size. */
++ value = 0x238F13AF * key-&gt;dsize;
++ for (i=0; i &lt; key-&gt;dsize; i++) {
++ value = (value + (key-&gt;dptr[i] &lt;&lt; (i*5 % 24)));
++ }
++
++ value = (1103515243 * value + 12345);
++
++ return value;
++}
++
++/* find the top of the hash chain for an open database */
++static tdb_off tdb_hash_top(TDB_CONTEXT *tdb, unsigned hash)
++{
++ tdb_off ret;
++ hash = BUCKET(hash);
++ ret = FREELIST_TOP + (hash+1)*sizeof(tdb_off);
++ return ret;
++}
++
++
++/* check for an out of bounds access - if it is out of bounds then
++ see if the database has been expanded by someone else and expand
++ if necessary */
++static int tdb_oob(TDB_CONTEXT *tdb, tdb_off offset)
++{
++ struct stat st;
++ if ((offset &lt;= tdb-&gt;map_size) || (tdb-&gt;fd == -1)) return 0;
++
++ fstat(tdb-&gt;fd, &amp;st);
++ if (st.st_size &lt;= (ssize_t)offset) {
++ tdb-&gt;ecode = TDB_ERR_IO;
++ return -1;
++ }
++
++#if HAVE_MMAP
++ if (tdb-&gt;map_ptr) {
++ munmap(tdb-&gt;map_ptr, tdb-&gt;map_size);
++ tdb-&gt;map_ptr = NULL;
++ }
++#endif
++
++ tdb-&gt;map_size = st.st_size;
++#if HAVE_MMAP
++ tdb-&gt;map_ptr = (void *)mmap(NULL, tdb-&gt;map_size,
++ tdb-&gt;read_only?PROT_READ:PROT_READ|PROT_WRITE,
++ MAP_SHARED | MAP_FILE, tdb-&gt;fd, 0);
++#endif
++ return 0;
++}
++
++
++/* write a lump of data at a specified offset */
++static int tdb_write(TDB_CONTEXT *tdb, tdb_off offset, const char *buf, tdb_len len)
++{
++ if (tdb_oob(tdb, offset + len) != 0) {
++ /* oops - trying to write beyond the end of the database! */
++ return -1;
++ }
++
++ if (tdb-&gt;map_ptr) {
++ memcpy(offset + (char *)tdb-&gt;map_ptr, buf, len);
++ } else {
++ if (lseek(tdb-&gt;fd, offset, SEEK_SET) != offset ||
++ write(tdb-&gt;fd, buf, len) != (ssize_t)len) {
++ tdb-&gt;ecode = TDB_ERR_IO;
++ return -1;
++ }
++ }
++ return 0;
++}
++
++/* read a lump of data at a specified offset */
++static int tdb_read(TDB_CONTEXT *tdb, tdb_off offset, char *buf, tdb_len len)
++{
++ if (tdb_oob(tdb, offset + len) != 0) {
++ /* oops - trying to read beyond the end of the database! */
++ return -1;
++ }
++
++ if (tdb-&gt;map_ptr) {
++ memcpy(buf, offset + (char *)tdb-&gt;map_ptr, len);
++ } else {
++ if (lseek(tdb-&gt;fd, offset, SEEK_SET) != offset ||
++ read(tdb-&gt;fd, buf, len) != (ssize_t)len) {
++ tdb-&gt;ecode = TDB_ERR_IO;
++ return -1;
++ }
++ }
++ return 0;
++}
++
++
++/* read a lump of data, allocating the space for it */
++static char *tdb_alloc_read(TDB_CONTEXT *tdb, tdb_off offset, tdb_len len)
++{
++ char *buf;
++
++ buf = (char *)malloc(len);
++
++ if (!buf) {
++ tdb-&gt;ecode = TDB_ERR_OOM;
++ return NULL;
++ }
++
++ if (tdb_read(tdb, offset, buf, len) == -1) {
++ free(buf);
++ return NULL;
++ }
++
++ return buf;
++}
++
++/* convenience routine for writing a record */
++static int rec_write(TDB_CONTEXT *tdb, tdb_off offset, struct list_struct *rec)
++{
++ return tdb_write(tdb, offset, (char *)rec, sizeof(*rec));
++}
++
++/* convenience routine for writing a tdb_off */
++static int ofs_write(TDB_CONTEXT *tdb, tdb_off offset, tdb_off *d)
++{
++ return tdb_write(tdb, offset, (char *)d, sizeof(*d));
++}
++
++/* read a tdb_off from the store */
++static int ofs_read(TDB_CONTEXT *tdb, tdb_off offset, tdb_off *d)
++{
++ return tdb_read(tdb, offset, (char *)d, sizeof(*d));
++}
++
++/* read a record and check for simple errors */
++static int rec_read(TDB_CONTEXT *tdb, tdb_off offset, struct list_struct *rec)
++{
++ if (tdb_read(tdb, offset, (char *)rec, sizeof(*rec)) == -1) return -1;
++ if (rec-&gt;magic != TDB_MAGIC) {
++#if TDB_DEBUG
++ printf(&quot;bad magic 0x%08x at offset %d\n&quot;,
++ rec-&gt;magic, offset);
++#endif
++ tdb-&gt;ecode = TDB_ERR_CORRUPT;
++ return -1;
++ }
++ if (tdb_oob(tdb, rec-&gt;next) != 0) {
++ return -1;
++ }
++ return 0;
++}
++
++/* expand the database at least length bytes by expanding the
++ underlying file and doing the mmap again if necessary */
++static int tdb_expand(TDB_CONTEXT *tdb, tdb_off length)
++{
++ struct list_struct rec;
++ tdb_off offset, ptr;
++ char b = 0;
++
++ tdb_lock(tdb,-1);
++
++ /* make sure we know about any previous expansions by another
++ process */
++ tdb_oob(tdb,tdb-&gt;map_size + 1);
++
++ /* always make room for at least 10 more records */
++ length *= TDB_LEN_MULTIPLIER;
++
++ /* and round the database up to a multiple of TDB_PAGE_SIZE */
++ length = ((tdb-&gt;map_size + length + TDB_PAGE_SIZE) &amp; ~(TDB_PAGE_SIZE - 1)) - tdb-&gt;map_size;
++
++ /* expand the file itself */
++ if (tdb-&gt;fd != -1) {
++ lseek(tdb-&gt;fd, tdb-&gt;map_size + length - 1, SEEK_SET);
++ if (write(tdb-&gt;fd, &amp;b, 1) != 1) goto fail;
++ }
++
++ /* form a new freelist record */
++ offset = FREELIST_TOP;
++ rec.rec_len = length - sizeof(rec);
++ rec.magic = TDB_FREE_MAGIC;
++ if (ofs_read(tdb, offset, &amp;rec.next) == -1) {
++ goto fail;
++ }
++
++#if HAVE_MMAP
++ if (tdb-&gt;fd != -1 &amp;&amp; tdb-&gt;map_ptr) {
++ munmap(tdb-&gt;map_ptr, tdb-&gt;map_size);
++ tdb-&gt;map_ptr = NULL;
++ }
++#endif
++
++ tdb-&gt;map_size += length;
++
++ if (tdb-&gt;fd == -1) {
++ tdb-&gt;map_ptr = realloc(tdb-&gt;map_ptr, tdb-&gt;map_size);
++ }
++
++ /* write it out */
++ if (rec_write(tdb, tdb-&gt;map_size - length, &amp;rec) == -1) {
++ goto fail;
++ }
++
++ /* link it into the free list */
++ ptr = tdb-&gt;map_size - length;
++ if (ofs_write(tdb, offset, &amp;ptr) == -1) goto fail;
++
++#if HAVE_MMAP
++ if (tdb-&gt;fd != -1) {
++ tdb-&gt;map_ptr = (void *)mmap(NULL, tdb-&gt;map_size,
++ PROT_READ|PROT_WRITE,
++ MAP_SHARED | MAP_FILE, tdb-&gt;fd, 0);
++ }
++#endif
++
++ tdb_unlock(tdb, -1);
++ return 0;
++
++ fail:
++ tdb_unlock(tdb,-1);
++ return -1;
++}
++
++/* allocate some space from the free list. The offset returned points
++ to a unconnected list_struct within the database with room for at
++ least length bytes of total data
++
++ 0 is returned if the space could not be allocated
++ */
++static tdb_off tdb_allocate(TDB_CONTEXT *tdb, tdb_len length)
++{
++ tdb_off offset, rec_ptr, last_ptr;
++ struct list_struct rec, lastrec, newrec;
++
++ tdb_lock(tdb, -1);
++
++ again:
++ last_ptr = 0;
++ offset = FREELIST_TOP;
++
++ /* read in the freelist top */
++ if (ofs_read(tdb, offset, &amp;rec_ptr) == -1) {
++ goto fail;
++ }
++
++ /* keep looking until we find a freelist record that is big
++ enough */
++ while (rec_ptr) {
++ if (tdb_read(tdb, rec_ptr, (char *)&amp;rec, sizeof(rec)) == -1) {
++ goto fail;
++ }
++
++ if (rec.magic != TDB_FREE_MAGIC) {
++#if TDB_DEBUG
++ printf(&quot;bad magic 0x%08x in free list\n&quot;, rec.magic);
++#endif
++ goto fail;
++ }
++
++ if (rec.rec_len &gt;= length) {
++ /* found it - now possibly split it up */
++ if (rec.rec_len &gt; length + MIN_REC_SIZE) {
++ length = (length + TDB_ALIGN) &amp; ~(TDB_ALIGN-1);
++
++ newrec.rec_len = rec.rec_len - (sizeof(rec) + length);
++ newrec.next = rec.next;
++ newrec.magic = TDB_FREE_MAGIC;
++
++ rec.rec_len = length;
++ rec.next = rec_ptr + sizeof(rec) + rec.rec_len;
++
++ if (rec_write(tdb, rec.next, &amp;newrec) == -1) {
++ goto fail;
++ }
++
++ if (rec_write(tdb, rec_ptr, &amp;rec) == -1) {
++ goto fail;
++ }
++ }
++
++ /* remove it from the list */
++ if (last_ptr == 0) {
++ offset = FREELIST_TOP;
++
++ if (ofs_write(tdb, offset, &amp;rec.next) == -1) {
++ goto fail;
++ }
++ } else {
++ lastrec.next = rec.next;
++ if (rec_write(tdb, last_ptr, &amp;lastrec) == -1) {
++ goto fail;
++ }
++ }
++
++ /* all done - return the new record offset */
++ tdb_unlock(tdb, -1);
++ return rec_ptr;
++ }
++
++ /* move to the next record */
++ lastrec = rec;
++ last_ptr = rec_ptr;
++ rec_ptr = rec.next;
++ }
++
++ /* we didn't find enough space. See if we can expand the
++ database and if we can then try again */
++ if (tdb_expand(tdb, length + sizeof(rec)) == 0) goto again;
++
++ fail:
++#if TDB_DEBUG
++ printf(&quot;tdb_allocate failed for size %u\n&quot;, length);
++#endif
++ tdb_unlock(tdb, -1);
++ return 0;
++}
++
++/* initialise a new database with a specified hash size */
++static int tdb_new_database(TDB_CONTEXT *tdb, int hash_size)
++{
++ struct tdb_header header;
++ tdb_off offset;
++ int i, size = 0;
++ tdb_off buf[16];
++
++ /* create the header */
++ memset(&amp;header, 0, sizeof(header));
++ memcpy(header.magic_food, TDB_MAGIC_FOOD, strlen(TDB_MAGIC_FOOD)+1);
++ header.version = TDB_VERSION;
++ header.hash_size = hash_size;
++ lseek(tdb-&gt;fd, 0, SEEK_SET);
++ ftruncate(tdb-&gt;fd, 0);
++
++ if (tdb-&gt;fd != -1 &amp;&amp; write(tdb-&gt;fd, &amp;header, sizeof(header)) !=
++ sizeof(header)) {
++ tdb-&gt;ecode = TDB_ERR_IO;
++ return -1;
++ } else size += sizeof(header);
++
++ /* the freelist and hash pointers */
++ offset = 0;
++ memset(buf, 0, sizeof(buf));
++
++ for (i=0;(hash_size+1)-i &gt;= 16; i += 16) {
++ if (tdb-&gt;fd != -1 &amp;&amp; write(tdb-&gt;fd, buf, sizeof(buf)) !=
++ sizeof(buf)) {
++ tdb-&gt;ecode = TDB_ERR_IO;
++ return -1;
++ } else size += sizeof(buf);
++ }
++
++ for (;i&lt;hash_size+1; i++) {
++ if (tdb-&gt;fd != -1 &amp;&amp; write(tdb-&gt;fd, buf, sizeof(tdb_off)) !=
++ sizeof(tdb_off)) {
++ tdb-&gt;ecode = TDB_ERR_IO;
++ return -1;
++ } else size += sizeof(tdb_off);
++ }
++
++ if (tdb-&gt;fd == -1) {
++ tdb-&gt;map_ptr = calloc(size, 1);
++ tdb-&gt;map_size = size;
++ if (tdb-&gt;map_ptr == NULL) {
++ tdb-&gt;ecode = TDB_ERR_IO;
++ return -1;
++ }
++ memcpy(&amp;tdb-&gt;header, &amp;header, sizeof(header));
++ }
++
++#if TDB_DEBUG
++ printf(&quot;initialised database of hash_size %u\n&quot;,
++ hash_size);
++#endif
++ return 0;
++}
++
++/* Returns 0 on fail. On success, return offset of record, and fills
++ in rec */
++static tdb_off tdb_find(TDB_CONTEXT *tdb, TDB_DATA key, unsigned int hash,
++ struct list_struct *rec)
++{
++ tdb_off offset, rec_ptr;
++
++ /* find the top of the hash chain */
++ offset = tdb_hash_top(tdb, hash);
++
++ /* read in the hash top */
++ if (ofs_read(tdb, offset, &amp;rec_ptr) == -1)
++ return 0;
++
++ /* keep looking until we find the right record */
++ while (rec_ptr) {
++ if (rec_read(tdb, rec_ptr, rec) == -1)
++ return 0;
++
++ if (hash == rec-&gt;full_hash &amp;&amp; key.dsize == rec-&gt;key_len) {
++ char *k;
++ /* a very likely hit - read the key */
++ k = tdb_alloc_read(tdb, rec_ptr + sizeof(*rec),
++ rec-&gt;key_len);
++
++ if (!k)
++ return 0;
++
++ if (memcmp(key.dptr, k, key.dsize) == 0) {
++ free(k);
++ return rec_ptr;
++ }
++ free(k);
++ }
++
++ /* move to the next record */
++ rec_ptr = rec-&gt;next;
++ }
++ return 0;
++}
++
++/*
++ return an error string for the last tdb error
++*/
++char *tdb_error(TDB_CONTEXT *tdb)
++{
++ int i;
++ static struct {
++ enum TDB_ERROR ecode;
++ char *estring;
++ } emap[] = {
++ {TDB_SUCCESS, &quot;Success&quot;},
++ {TDB_ERR_CORRUPT, &quot;Corrupt database&quot;},
++ {TDB_ERR_IO, &quot;IO Error&quot;},
++ {TDB_ERR_LOCK, &quot;Locking error&quot;},
++ {TDB_ERR_OOM, &quot;Out of memory&quot;},
++ {TDB_ERR_EXISTS, &quot;Record exists&quot;},
++ {-1, NULL}};
++ if (tdb != NULL) {
++ for (i=0;emap[i].estring;i++) {
++ if (tdb-&gt;ecode == emap[i].ecode) return emap[i].estring;
++ }
++ } else {
++ return &quot;Invalid tdb context&quot;;
++ }
++ return &quot;Invalid error code&quot;;
++}
++
++
++/* update an entry in place - this only works if the new data size
++ is &lt;= the old data size and the key exists.
++ on failure return -1
++*/
++int tdb_update(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf)
++{
++ unsigned hash;
++ struct list_struct rec;
++ tdb_off rec_ptr;
++ int ret = -1;
++
++ if (tdb == NULL) {
++#ifdef TDB_DEBUG
++ printf(&quot;tdb_update() called with null context\n&quot;);
++#endif
++ return -1;
++ }
++
++ /* find which hash bucket it is in */
++ hash = tdb_hash(&amp;key);
++
++ tdb_lock(tdb, BUCKET(hash));
++ rec_ptr = tdb_find(tdb, key, hash, &amp;rec);
++
++ if (!rec_ptr)
++ goto out;
++
++ /* must be long enough */
++ if (rec.rec_len &lt; key.dsize + dbuf.dsize)
++ goto out;
++
++ if (tdb_write(tdb, rec_ptr + sizeof(rec) + rec.key_len,
++ dbuf.dptr, dbuf.dsize) == -1)
++ goto out;
++
++ if (dbuf.dsize != rec.data_len) {
++ /* update size */
++ rec.data_len = dbuf.dsize;
++ ret = rec_write(tdb, rec_ptr, &amp;rec);
++ } else
++ ret = 0;
++
++ out:
++ tdb_unlock(tdb, BUCKET(hash));
++ return ret;
++}
++
++/* find an entry in the database given a key */
++TDB_DATA tdb_fetch(TDB_CONTEXT *tdb, TDB_DATA key)
++{
++ unsigned hash;
++ tdb_off rec_ptr;
++ struct list_struct rec;
++ TDB_DATA ret = null_data;
++
++ if (tdb == NULL) {
++#ifdef TDB_DEBUG
++ printf(&quot;tdb_fetch() called with null context\n&quot;);
++#endif
++ return null_data;
++ }
++
++ /* find which hash bucket it is in */
++ hash = tdb_hash(&amp;key);
++
++ tdb_lock(tdb, BUCKET(hash));
++ rec_ptr = tdb_find(tdb, key, hash, &amp;rec);
++
++ if (rec_ptr) {
++ ret.dptr = tdb_alloc_read(tdb,
++ rec_ptr + sizeof(rec) + rec.key_len,
++ rec.data_len);
++ ret.dsize = rec.data_len;
++ }
++
++ tdb_unlock(tdb, BUCKET(hash));
++ return ret;
++}
++
++/* check if an entry in the database exists
++
++ note that 1 is returned if the key is found and 0 is returned if not found
++ this doesn't match the conventions in the rest of this module, but is
++ compatible with gdbm
++*/
++int tdb_exists(TDB_CONTEXT *tdb, TDB_DATA key)
++{
++ unsigned hash;
++ tdb_off rec_ptr;
++ struct list_struct rec;
++
++ if (tdb == NULL) {
++#ifdef TDB_DEBUG
++ printf(&quot;tdb_exists() called with null context\n&quot;);
++#endif
++ return 0;
++ }
++
++ /* find which hash bucket it is in */
++ hash = tdb_hash(&amp;key);
++
++ tdb_lock(tdb, BUCKET(hash));
++ rec_ptr = tdb_find(tdb, key, hash, &amp;rec);
++ tdb_unlock(tdb, BUCKET(hash));
++
++ return rec_ptr != 0;
++}
++
++/* traverse the entire database - calling fn(tdb, key, data) on each element.
++ return -1 on error or the record count traversed
++ if fn is NULL then it is not called
++ a non-zero return value from fn() indicates that the traversal should stop
++ */
++int tdb_traverse(TDB_CONTEXT *tdb, int (*fn)(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void* state), void* state)
++{
++ int count = 0;
++ unsigned h;
++ tdb_off offset, rec_ptr;
++ struct list_struct rec;
++ char *data;
++ TDB_DATA key, dbuf;
++
++ if (tdb == NULL) {
++#ifdef TDB_DEBUG
++ printf(&quot;tdb_traverse() called with null context\n&quot;);
++#endif
++ return -1;
++ }
++
++ /* loop over all hash chains */
++ for (h = 0; h &lt; tdb-&gt;header.hash_size; h++) {
++ tdb_lock(tdb, BUCKET(h));
++
++ /* read in the hash top */
++ offset = tdb_hash_top(tdb, h);
++ if (ofs_read(tdb, offset, &amp;rec_ptr) == -1) {
++ goto fail;
++ }
++
++ /* traverse all records for this hash */
++ while (rec_ptr) {
++ if (rec_read(tdb, rec_ptr, &amp;rec) == -1) {
++ goto fail;
++ }
++
++ /* now read the full record */
++ data = tdb_alloc_read(tdb, rec_ptr + sizeof(rec),
++ rec.key_len + rec.data_len);
++ if (!data) {
++ goto fail;
++ }
++
++ key.dptr = data;
++ key.dsize = rec.key_len;
++ dbuf.dptr = data + rec.key_len;
++ dbuf.dsize = rec.data_len;
++ count++;
++
++ if (fn &amp;&amp; fn(tdb, key, dbuf, state) != 0) {
++ /* they want us to stop traversing */
++ free(data);
++ tdb_unlock(tdb, BUCKET(h));
++ return count;
++ }
++
++ /* a miss - drat */
++ free(data);
++
++ /* move to the next record */
++ rec_ptr = rec.next;
++ }
++ tdb_unlock(tdb, BUCKET(h));
++ }
++
++ /* return the number traversed */
++ return count;
++
++ fail:
++ tdb_unlock(tdb, BUCKET(h));
++ return -1;
++}
++
++
++/* find the first entry in the database and return its key */
++TDB_DATA tdb_firstkey(TDB_CONTEXT *tdb)
++{
++ tdb_off offset, rec_ptr;
++ struct list_struct rec;
++ unsigned hash;
++ TDB_DATA ret;
++
++ if (tdb == NULL) {
++#ifdef TDB_DEBUG
++ printf(&quot;tdb_firstkey() called with null context\n&quot;);
++#endif
++ return null_data;
++ }
++
++ /* look for a non-empty hash chain */
++ for (hash = 0, rec_ptr = 0;
++ hash &lt; tdb-&gt;header.hash_size;
++ hash++) {
++ /* find the top of the hash chain */
++ offset = tdb_hash_top(tdb, hash);
++
++ tdb_lock(tdb, BUCKET(hash));
++
++ /* read in the hash top */
++ if (ofs_read(tdb, offset, &amp;rec_ptr) == -1) {
++ goto fail;
++ }
++
++ if (rec_ptr) break;
++
++ tdb_unlock(tdb, BUCKET(hash));
++ }
++
++ if (rec_ptr == 0) return null_data;
++
++ /* we've found a non-empty chain, now read the record */
++ if (rec_read(tdb, rec_ptr, &amp;rec) == -1) {
++ goto fail;
++ }
++
++ /* allocate and read the key space */
++ ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec), rec.key_len);
++ ret.dsize = rec.key_len;
++ tdb_unlock(tdb, BUCKET(hash));
++ return ret;
++
++ fail:
++ tdb_unlock(tdb, BUCKET(hash));
++ return null_data;
++}
++
++/* find the next entry in the database, returning its key */
++TDB_DATA tdb_nextkey(TDB_CONTEXT *tdb, TDB_DATA key)
++{
++ unsigned hash, hbucket;
++ tdb_off rec_ptr, offset;
++ struct list_struct rec;
++ TDB_DATA ret;
++
++ if (tdb == NULL) {
++#ifdef TDB_DEBUG
++ printf(&quot;tdb_nextkey() called with null context\n&quot;);
++#endif
++ return null_data;
++ }
++
++ /* find which hash bucket it is in */
++ hash = tdb_hash(&amp;key);
++ hbucket = BUCKET(hash);
++
++ tdb_lock(tdb, hbucket);
++ rec_ptr = tdb_find(tdb, key, hash, &amp;rec);
++ if (rec_ptr) {
++ /* we want the next record after this one */
++ rec_ptr = rec.next;
++ }
++
++ /* not found or last in hash: look for next non-empty hash chain */
++ while (rec_ptr == 0) {
++ tdb_unlock(tdb, hbucket);
++
++ if (++hbucket &gt;= tdb-&gt;header.hash_size - 1)
++ return null_data;
++
++ offset = tdb_hash_top(tdb, hbucket);
++ tdb_lock(tdb, hbucket);
++ /* read in the hash top */
++ if (ofs_read(tdb, offset, &amp;rec_ptr) == -1) {
++ tdb_unlock(tdb, hbucket);
++ return null_data;
++ }
++ }
++
++ /* Read the record. */
++ if (rec_read(tdb, rec_ptr, &amp;rec) == -1) {
++ tdb_unlock(tdb, hbucket);
++ return null_data;
++ }
++ /* allocate and read the key */
++ ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec), rec.key_len);
++ ret.dsize = rec.key_len;
++ tdb_unlock(tdb, hbucket);
++
++ return ret;
++}
++
++/* delete an entry in the database given a key */
++int tdb_delete(TDB_CONTEXT *tdb, TDB_DATA key)
++{
++ unsigned hash;
++ tdb_off offset, rec_ptr, last_ptr;
++ struct list_struct rec, lastrec;
++ char *data = NULL;
++
++ if (tdb == NULL) {
++#ifdef TDB_DEBUG
++ printf(&quot;tdb_delete() called with null context\n&quot;);
++#endif
++ return -1;
++ }
++
++ /* find which hash bucket it is in */
++ hash = tdb_hash(&amp;key);
++
++ tdb_lock(tdb, BUCKET(hash));
++
++ /* find the top of the hash chain */
++ offset = tdb_hash_top(tdb, hash);
++
++ /* read in the hash top */
++ if (ofs_read(tdb, offset, &amp;rec_ptr) == -1) {
++ goto fail;
++ }
++
++ last_ptr = 0;
++
++ /* keep looking until we find the right record */
++ while (rec_ptr) {
++ if (rec_read(tdb, rec_ptr, &amp;rec) == -1) {
++ goto fail;
++ }
++
++ if (hash == rec.full_hash &amp;&amp; key.dsize == rec.key_len) {
++ /* a very likely hit - read the record and full key */
++ data = tdb_alloc_read(tdb, rec_ptr + sizeof(rec),
++ rec.key_len);
++ if (!data) {
++ goto fail;
++ }
++
++ if (memcmp(key.dptr, data, key.dsize) == 0) {
++ /* a definite match - delete it */
++ if (last_ptr == 0) {
++ offset = tdb_hash_top(tdb, hash);
++ if (ofs_write(tdb, offset, &amp;rec.next) == -1) {
++ goto fail;
++ }
++ } else {
++ lastrec.next = rec.next;
++ if (rec_write(tdb, last_ptr, &amp;lastrec) == -1) {
++ goto fail;
++ }
++ }
++ tdb_unlock(tdb, BUCKET(hash));
++ tdb_lock(tdb, -1);
++ /* and recover the space */
++ offset = FREELIST_TOP;
++ if (ofs_read(tdb, offset, &amp;rec.next) == -1) {
++ goto fail2;
++ }
++ rec.magic = TDB_FREE_MAGIC;
++ if (rec_write(tdb, rec_ptr, &amp;rec) == -1) {
++ goto fail2;
++ }
++ if (ofs_write(tdb, offset, &amp;rec_ptr) == -1) {
++ goto fail2;
++ }
++
++ /* yipee - all done */
++ free(data);
++ tdb_unlock(tdb, -1);
++ return 0;
++ }
++
++ /* a miss - drat */
++ free(data);
++ data = NULL;
++ }
++
++ /* move to the next record */
++ last_ptr = rec_ptr;
++ lastrec = rec;
++ rec_ptr = rec.next;
++ }
++
++ fail:
++ if (data) free(data);
++ tdb_unlock(tdb, BUCKET(hash));
++ return -1;
++
++ fail2:
++ if (data) free(data);
++ tdb_unlock(tdb, -1);
++ return -1;
++}
++
++
++/* store an element in the database, replacing any existing element
++ with the same key
++
++ return 0 on success, -1 on failure
++*/
++int tdb_store(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)
++{
++ struct list_struct rec;
++ unsigned hash;
++ tdb_off rec_ptr, offset;
++ char *p = NULL;
++
++ if (tdb == NULL) {
++#ifdef TDB_DEBUG
++ printf(&quot;tdb_store() called with null context\n&quot;);
++#endif
++ return -1;
++ }
++
++ /* find which hash bucket it is in */
++ hash = tdb_hash(&amp;key);
++
++ /* check for it existing */
++ if (flag == TDB_INSERT &amp;&amp; tdb_exists(tdb, key)) {
++ tdb-&gt;ecode = TDB_ERR_EXISTS;
++ return -1;
++ }
++
++ /* first try in-place update */
++ if (flag != TDB_INSERT &amp;&amp; tdb_update(tdb, key, dbuf) == 0) {
++ return 0;
++ }
++
++ rec_ptr = tdb_allocate(tdb, key.dsize + dbuf.dsize);
++ if (rec_ptr == 0) {
++ return -1;
++ }
++
++ tdb_lock(tdb, BUCKET(hash));
++
++ /* delete any existing record - if it doesn't exist we don't care */
++ if (flag != TDB_INSERT) {
++ tdb_delete(tdb, key);
++ }
++
++ /* read the newly created record */
++ if (tdb_read(tdb, rec_ptr, (char *)&amp;rec, sizeof(rec)) == -1) {
++ goto fail;
++ }
++
++ if (rec.magic != TDB_FREE_MAGIC) goto fail;
++
++ /* find the top of the hash chain */
++ offset = tdb_hash_top(tdb, hash);
++
++ /* read in the hash top diretcly into our next pointer */
++ if (ofs_read(tdb, offset, &amp;rec.next) == -1) {
++ goto fail;
++ }
++
++ rec.key_len = key.dsize;
++ rec.data_len = dbuf.dsize;
++ rec.full_hash = hash;
++ rec.magic = TDB_MAGIC;
++
++ p = (char *)malloc(sizeof(rec) + key.dsize + dbuf.dsize);
++ if (!p) {
++ tdb-&gt;ecode = TDB_ERR_OOM;
++ goto fail;
++ }
++
++ memcpy(p, &amp;rec, sizeof(rec));
++ memcpy(p+sizeof(rec), key.dptr, key.dsize);
++ memcpy(p+sizeof(rec)+key.dsize, dbuf.dptr, dbuf.dsize);
++
++ if (tdb_write(tdb, rec_ptr, p, sizeof(rec)+key.dsize+dbuf.dsize) == -1)
++ goto fail;
++
++ free(p);
++ p = NULL;
++
++ /* and point the top of the hash chain at it */
++ if (ofs_write(tdb, offset, &amp;rec_ptr) == -1) goto fail;
++
++ tdb_unlock(tdb, BUCKET(hash));
++ return 0;
++
++ fail:
++#if TDB_DEBUG
++ printf(&quot;store failed for hash 0x%08x in bucket %u\n&quot;, hash, BUCKET(hash));
++#endif
++ if (p) free(p);
++ tdb_unlock(tdb, BUCKET(hash));
++ return -1;
++}
++
++
++/* open the database, creating it if necessary
++
++ The open_flags and mode are passed straight to the open call on the database
++ file. A flags value of O_WRONLY is invalid
++
++ The hash size is advisory, use zero for a default value.
++
++ return is NULL on error
++*/
++TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
++ int open_flags, mode_t mode)
++{
++ TDB_CONTEXT tdb, *ret;
++ struct stat st;
++
++ memset(&amp;tdb, 0, sizeof(tdb));
++
++ tdb.fd = -1;
++ tdb.name = NULL;
++ tdb.map_ptr = NULL;
++
++ if ((open_flags &amp; O_ACCMODE) == O_WRONLY) {
++ goto fail;
++ }
++
++ if (hash_size == 0) hash_size = DEFAULT_HASH_SIZE;
++
++ tdb.read_only = ((open_flags &amp; O_ACCMODE) == O_RDONLY);
++
++ if (name != NULL) {
++ tdb.fd = open(name, open_flags, mode);
++ if (tdb.fd == -1) {
++ goto fail;
++ }
++ }
++
++ /* ensure there is only one process initialising at once */
++ tdb_brlock(&amp;tdb, GLOBAL_LOCK, LOCK_SET, F_WRLCK, F_SETLKW);
++
++ if (tdb_flags &amp; TDB_CLEAR_IF_FIRST) {
++ /* we need to zero the database if we are the only
++ one with it open */
++ if (tdb_brlock(&amp;tdb, ACTIVE_LOCK, LOCK_SET, F_WRLCK, F_SETLK) == 0) {
++ ftruncate(tdb.fd, 0);
++ tdb_brlock(&amp;tdb, ACTIVE_LOCK, LOCK_CLEAR, F_WRLCK, F_SETLK);
++ }
++ }
++
++ /* leave this lock in place */
++ tdb_brlock(&amp;tdb, ACTIVE_LOCK, LOCK_SET, F_RDLCK, F_SETLKW);
++
++ if (read(tdb.fd, &amp;tdb.header, sizeof(tdb.header)) != sizeof(tdb.header) ||
++ strcmp(tdb.header.magic_food, TDB_MAGIC_FOOD) != 0 ||
++ tdb.header.version != TDB_VERSION) {
++ /* its not a valid database - possibly initialise it */
++ if (!(open_flags &amp; O_CREAT)) {
++ goto fail;
++ }
++ if (tdb_new_database(&amp;tdb, hash_size) == -1) goto fail;
++
++ lseek(tdb.fd, 0, SEEK_SET);
++ if (tdb.fd != -1 &amp;&amp; read(tdb.fd, &amp;tdb.header,
++ sizeof(tdb.header)) !=
++ sizeof(tdb.header))
++ goto fail;
++ }
++
++ if (tdb.fd != -1) {
++ fstat(tdb.fd, &amp;st);
++
++ /* map the database and fill in the return structure */
++ tdb.name = (char *)strdup(name);
++ tdb.map_size = st.st_size;
++ }
++
++ tdb.locked = (int *)calloc(tdb.header.hash_size+1,
++ sizeof(tdb.locked[0]));
++ if (!tdb.locked) {
++ goto fail;
++ }
++
++#if HAVE_MMAP
++ if (tdb.fd != -1) {
++ tdb.map_ptr = (void *)mmap(NULL, st.st_size,
++ tdb.read_only? PROT_READ : PROT_READ|PROT_WRITE,
++ MAP_SHARED | MAP_FILE, tdb.fd, 0);
++ }
++#endif
++
++ ret = (TDB_CONTEXT *)malloc(sizeof(tdb));
++ if (!ret) goto fail;
++
++ *ret = tdb;
++
++#if TDB_DEBUG
++ printf(&quot;mapped database of hash_size %u map_size=%u\n&quot;,
++ hash_size, tdb.map_size);
++#endif
++
++ tdb_brlock(&amp;tdb, GLOBAL_LOCK, LOCK_CLEAR, F_WRLCK, F_SETLKW);
++ return ret;
++
++ fail:
++ if (tdb.name) free(tdb.name);
++ if (tdb.fd != -1) close(tdb.fd);
++ if (tdb.map_ptr) munmap(tdb.map_ptr, tdb.map_size);
++
++ return NULL;
++}
++
++/* close a database */
++int tdb_close(TDB_CONTEXT *tdb)
++{
++ if (!tdb) return -1;
++
++ if (tdb-&gt;name) free(tdb-&gt;name);
++ if (tdb-&gt;fd != -1) close(tdb-&gt;fd);
++ if (tdb-&gt;locked) free(tdb-&gt;locked);
++
++ if (tdb-&gt;map_ptr) {
++ if (tdb-&gt;fd != -1) {
++ munmap(tdb-&gt;map_ptr, tdb-&gt;map_size);
++ } else {
++ free(tdb-&gt;map_ptr);
++ }
++ }
++
++ memset(tdb, 0, sizeof(*tdb));
++ free(tdb);
++
++ return 0;
++}
++
++/* lock the database. If we already have it locked then don't do anything */
++int tdb_writelock(TDB_CONTEXT *tdb)
++{
++ if (tdb == NULL) {
++#ifdef TDB_DEBUG
++ printf(&quot;tdb_writelock() called with null context\n&quot;);
++#endif
++ return -1;
++ }
++
++ return tdb_lock(tdb, -1);
++}
++
++/* unlock the database. */
++int tdb_writeunlock(TDB_CONTEXT *tdb)
++{
++ if (tdb == NULL) {
++#ifdef TDB_DEBUG
++ printf(&quot;tdb_writeunlock() called with null context\n&quot;);
++#endif
++ return -1;
++ }
++
++ return tdb_unlock(tdb, -1);
++}
++
++/* lock one hash chain. This is meant to be used to reduce locking
++ contention - it cannot guarantee how many records will be locked */
++int tdb_lockchain(TDB_CONTEXT *tdb, TDB_DATA key)
++{
++ if (tdb == NULL) {
++#ifdef TDB_DEBUG
++ printf(&quot;tdb_lockchain() called with null context\n&quot;);
++#endif
++ return -1;
++ }
++
++ return tdb_lock(tdb, BUCKET(tdb_hash(&amp;key)));
++}
++
++
++/* unlock one hash chain */
++int tdb_unlockchain(TDB_CONTEXT *tdb, TDB_DATA key)
++{
++ if (tdb == NULL) {
++#ifdef TDB_DEBUG
++ printf(&quot;tdb_unlockchain() called with null context\n&quot;);
++#endif
++ return -1;
++ }
++
++ return tdb_unlock(tdb, BUCKET(tdb_hash(&amp;key)));
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/tdb.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/tdb.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/tdb.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/tdb.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,77 @@
++#define STANDALONE 1
++/*
++ * Database functions
++ * Copyright (C) Andrew Tridgell 1999
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms AND provided that this software or
++ * any derived work is only used as part of the PPP daemon (pppd)
++ * and related utilities.
++ * The name of the author may not be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * Note: this software is also available under the Gnu Public License
++ * version 2 or later.
++ */
++
++typedef unsigned tdb_len;
++typedef unsigned tdb_off;
++
++#define TDB_MAGIC_FOOD &quot;TDB file\n&quot;
++
++/* this is stored at the front of every database */
++struct tdb_header {
++ char magic_food[32]; /* for /etc/magic */
++ unsigned version; /* version of the code */
++ unsigned hash_size; /* number of hash entries */
++};
++
++typedef struct {
++ char *dptr;
++ size_t dsize;
++} TDB_DATA;
++
++/* this is the context structure that is returned from a db open */
++typedef struct {
++ char *name; /* the name of the database */
++ void *map_ptr; /* where it is currently mapped */
++ int fd; /* open file descriptor for the database */
++ tdb_len map_size; /* how much space has been mapped */
++ int read_only; /* opened read-only */
++ int *locked; /* set if we have a chain locked */
++ int ecode; /* error code for last tdb error */
++ struct tdb_header header; /* a cached copy of the header */
++} TDB_CONTEXT;
++
++/* flags to tdb_store() */
++#define TDB_REPLACE 1
++#define TDB_INSERT 2
++
++/* flags for tdb_open() */
++#define TDB_CLEAR_IF_FIRST 1
++
++/* error codes */
++enum TDB_ERROR {TDB_SUCCESS=0, TDB_ERR_CORRUPT, TDB_ERR_IO, TDB_ERR_LOCK,
++ TDB_ERR_OOM, TDB_ERR_EXISTS};
++
++#if STANDALONE
++TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
++ int open_flags, mode_t mode);
++char *tdb_error(TDB_CONTEXT *tdb);
++int tdb_writelock(TDB_CONTEXT *tdb);
++int tdb_writeunlock(TDB_CONTEXT *tdb);
++TDB_DATA tdb_fetch(TDB_CONTEXT *tdb, TDB_DATA key);
++int tdb_delete(TDB_CONTEXT *tdb, TDB_DATA key);
++int tdb_store(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, int flag);
++int tdb_close(TDB_CONTEXT *tdb);
++TDB_DATA tdb_firstkey(TDB_CONTEXT *tdb);
++TDB_DATA tdb_nextkey(TDB_CONTEXT *tdb, TDB_DATA key);
++int tdb_traverse(TDB_CONTEXT *tdb,
++ int (*fn)(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state),
++ void *state);
++int tdb_exists(TDB_CONTEXT *tdb, TDB_DATA key);
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/tdb.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/tty.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/tty.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/tty.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1164 @@
++/*
++ * tty.c - code for handling serial ports in pppd.
++ *
++ * Copyright (C) 2000 Paul Mackerras.
++ * All rights reserved.
++ *
++ * Portions Copyright (c) 1989 Carnegie Mellon University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by Carnegie Mellon University. The name of the
++ * University may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ */
++
++#define RCSID &quot;$Id: tty.c 195720 2001-06-11 11:44:34Z gc $&quot;
++
++#include &lt;stdio.h&gt;
++#include &lt;ctype.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;signal.h&gt;
++#include &lt;errno.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;syslog.h&gt;
++#include &lt;netdb.h&gt;
++#include &lt;utmp.h&gt;
++#include &lt;pwd.h&gt;
++#include &lt;setjmp.h&gt;
++#include &lt;sys/param.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/wait.h&gt;
++#include &lt;sys/time.h&gt;
++#include &lt;sys/resource.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;sys/socket.h&gt;
++#include &lt;netinet/in.h&gt;
++#include &lt;arpa/inet.h&gt;
++
++#include &quot;pppd.h&quot;
++#include &quot;fsm.h&quot;
++#include &quot;lcp.h&quot;
++
++void tty_process_extra_options __P((void));
++void tty_check_options __P((void));
++int connect_tty __P((void));
++void disconnect_tty __P((void));
++void tty_close_fds __P((void));
++void cleanup_tty __P((void));
++void tty_do_send_config __P((int, u_int32_t, int, int));
++
++static int setdevname __P((char *, char **, int));
++static int setspeed __P((char *, char **, int));
++static int setxonxoff __P((char **));
++static int setescape __P((char **));
++static void printescape __P((option_t *, void (*)(void *, char *,...),void *));
++static void finish_tty __P((void));
++static int start_charshunt __P((int, int));
++static void stop_charshunt __P((void *, int));
++static void charshunt_done __P((void *));
++static void charshunt __P((int, int, char *));
++static int record_write __P((FILE *, int code, u_char *buf, int nb,
++ struct timeval *));
++static int open_socket __P((char *));
++static void maybe_relock __P((void *, int));
++
++static int pty_master; /* fd for master side of pty */
++static int pty_slave; /* fd for slave side of pty */
++static int real_ttyfd; /* fd for actual serial port (not pty) */
++static int ttyfd; /* Serial port file descriptor */
++static char speed_str[16]; /* Serial port speed as string */
++
++mode_t tty_mode = (mode_t)-1; /* Original access permissions to tty */
++int baud_rate; /* Actual bits/second for serial device */
++char *callback_script; /* script for doing callback */
++int charshunt_pid; /* Process ID for charshunt */
++int locked; /* lock() has succeeded */
++struct stat devstat; /* result of stat() on devnam */
++
++/* option variables */
++int crtscts = 0; /* Use hardware flow control */
++bool modem = 1; /* Use modem control lines */
++int inspeed = 0; /* Input/Output speed requested */
++bool lockflag = 0; /* Create lock file to lock the serial dev */
++char *initializer = NULL; /* Script to initialize physical link */
++char *connect_script = NULL; /* Script to establish physical link */
++char *disconnect_script = NULL; /* Script to disestablish physical link */
++char *welcomer = NULL; /* Script to run after phys link estab. */
++char *ptycommand = NULL; /* Command to run on other side of pty */
++bool notty = 0; /* Stdin/out is not a tty */
++char *record_file = NULL; /* File to record chars sent/received */
++int max_data_rate; /* max bytes/sec through charshunt */
++bool sync_serial = 0; /* Device is synchronous serial device */
++char *pty_socket = NULL; /* Socket to connect to pty */
++int using_pty = 0; /* we're allocating a pty as the device */
++
++extern uid_t uid;
++extern int kill_link;
++
++/* XXX */
++extern int privopen; /* don't lock, open device as root */
++
++u_int32_t xmit_accm[8]; /* extended transmit ACCM */
++
++/* option descriptors */
++option_t tty_options[] = {
++ /* device name must be first, or change connect_tty() below! */
++ { &quot;device name&quot;, o_wild, (void *) &amp;setdevname,
++ &quot;Serial port device name&quot;,
++ OPT_DEVNAM | OPT_PRIVFIX | OPT_NOARG | OPT_A2STRVAL | OPT_STATIC,
++ devnam},
++
++ { &quot;tty speed&quot;, o_wild, (void *) &amp;setspeed,
++ &quot;Baud rate for serial port&quot;,
++ OPT_PRIO | OPT_NOARG | OPT_A2STRVAL | OPT_STATIC, speed_str },
++
++ { &quot;lock&quot;, o_bool, &amp;lockflag,
++ &quot;Lock serial device with UUCP-style lock file&quot;, OPT_PRIO | 1 },
++ { &quot;nolock&quot;, o_bool, &amp;lockflag,
++ &quot;Don't lock serial device&quot;, OPT_PRIOSUB | OPT_PRIV },
++
++ { &quot;init&quot;, o_string, &amp;initializer,
++ &quot;A program to initialize the device&quot;, OPT_PRIO | OPT_PRIVFIX },
++
++ { &quot;connect&quot;, o_string, &amp;connect_script,
++ &quot;A program to set up a connection&quot;, OPT_PRIO | OPT_PRIVFIX },
++
++ { &quot;disconnect&quot;, o_string, &amp;disconnect_script,
++ &quot;Program to disconnect serial device&quot;, OPT_PRIO | OPT_PRIVFIX },
++
++ { &quot;welcome&quot;, o_string, &amp;welcomer,
++ &quot;Script to welcome client&quot;, OPT_PRIO | OPT_PRIVFIX },
++
++ { &quot;pty&quot;, o_string, &amp;ptycommand,
++ &quot;Script to run on pseudo-tty master side&quot;,
++ OPT_PRIO | OPT_PRIVFIX | OPT_DEVNAM },
++
++ { &quot;notty&quot;, o_bool, &amp;notty,
++ &quot;Input/output is not a tty&quot;, OPT_DEVNAM | 1 },
++
++ { &quot;socket&quot;, o_string, &amp;pty_socket,
++ &quot;Send and receive over socket, arg is host:port&quot;,
++ OPT_PRIO | OPT_DEVNAM },
++
++ { &quot;record&quot;, o_string, &amp;record_file,
++ &quot;Record characters sent/received to file&quot;, OPT_PRIO },
++
++ { &quot;crtscts&quot;, o_int, &amp;crtscts,
++ &quot;Set hardware (RTS/CTS) flow control&quot;,
++ OPT_PRIO | OPT_NOARG | OPT_VAL(1) },
++ { &quot;cdtrcts&quot;, o_int, &amp;crtscts,
++ &quot;Set alternate hardware (DTR/CTS) flow control&quot;,
++ OPT_PRIOSUB | OPT_NOARG | OPT_VAL(2) },
++ { &quot;nocrtscts&quot;, o_int, &amp;crtscts,
++ &quot;Disable hardware flow control&quot;,
++ OPT_PRIOSUB | OPT_NOARG | OPT_VAL(-1) },
++ { &quot;-crtscts&quot;, o_int, &amp;crtscts,
++ &quot;Disable hardware flow control&quot;,
++ OPT_PRIOSUB | OPT_ALIAS | OPT_NOARG | OPT_VAL(-1) },
++ { &quot;nocdtrcts&quot;, o_int, &amp;crtscts,
++ &quot;Disable hardware flow control&quot;,
++ OPT_PRIOSUB | OPT_ALIAS | OPT_NOARG | OPT_VAL(-1) },
++ { &quot;xonxoff&quot;, o_special_noarg, (void *)setxonxoff,
++ &quot;Set software (XON/XOFF) flow control&quot;, OPT_PRIOSUB },
++
++ { &quot;modem&quot;, o_bool, &amp;modem,
++ &quot;Use modem control lines&quot;, OPT_PRIO | 1 },
++ { &quot;local&quot;, o_bool, &amp;modem,
++ &quot;Don't use modem control lines&quot;, OPT_PRIOSUB | 0 },
++
++ { &quot;sync&quot;, o_bool, &amp;sync_serial,
++ &quot;Use synchronous HDLC serial encoding&quot;, 1 },
++
++ { &quot;datarate&quot;, o_int, &amp;max_data_rate,
++ &quot;Maximum data rate in bytes/sec (with pty, notty or record option)&quot;,
++ OPT_PRIO },
++
++ { &quot;escape&quot;, o_special, (void *)setescape,
++ &quot;List of character codes to escape on transmission&quot;,
++ OPT_A2PRINTER, (void *)printescape },
++
++ { NULL }
++};
++
++
++struct channel tty_channel = {
++ tty_options,
++ &amp;tty_process_extra_options,
++ &amp;tty_check_options,
++ &amp;connect_tty,
++ &amp;disconnect_tty,
++ &amp;tty_establish_ppp,
++ &amp;tty_disestablish_ppp,
++ &amp;tty_do_send_config,
++ &amp;tty_recv_config,
++ &amp;cleanup_tty,
++ &amp;tty_close_fds
++};
++
++/*
++ * setspeed - Set the serial port baud rate.
++ * If doit is 0, the call is to check whether this option is
++ * potentially a speed value.
++ */
++static int
++setspeed(arg, argv, doit)
++ char *arg;
++ char **argv;
++ int doit;
++{
++ char *ptr;
++ int spd;
++
++ spd = strtol(arg, &amp;ptr, 0);
++ if (ptr == arg || *ptr != 0 || spd == 0)
++ return 0;
++ if (doit) {
++ inspeed = spd;
++ slprintf(speed_str, sizeof(speed_str), &quot;%d&quot;, spd);
++ }
++ return 1;
++}
++
++
++/*
++ * setdevname - Set the device name.
++ * If doit is 0, the call is to check whether this option is
++ * potentially a device name.
++ */
++static int
++setdevname(cp, argv, doit)
++ char *cp;
++ char **argv;
++ int doit;
++{
++ struct stat statbuf;
++ char dev[MAXPATHLEN];
++
++ if (*cp == 0)
++ return 0;
++
++ if (strncmp(&quot;/dev/&quot;, cp, 5) != 0) {
++ strlcpy(dev, &quot;/dev/&quot;, sizeof(dev));
++ strlcat(dev, cp, sizeof(dev));
++ cp = dev;
++ }
++
++ /*
++ * Check if there is a character device by this name.
++ */
++ if (stat(cp, &amp;statbuf) &lt; 0) {
++ if (!doit)
++ return errno != ENOENT;
++ option_error(&quot;Couldn't stat %s: %m&quot;, cp);
++ return 0;
++ }
++ if (!S_ISCHR(statbuf.st_mode)) {
++ if (doit)
++ option_error(&quot;%s is not a character device&quot;, cp);
++ return 0;
++ }
++
++ if (doit) {
++ strlcpy(devnam, cp, sizeof(devnam));
++ devstat = statbuf;
++ default_device = 0;
++ }
++
++ return 1;
++}
++
++static int
++setxonxoff(argv)
++ char **argv;
++{
++ lcp_wantoptions[0].asyncmap |= 0x000A0000; /* escape ^S and ^Q */
++ lcp_wantoptions[0].neg_asyncmap = 1;
++
++ crtscts = -2;
++ return 1;
++}
++
++/*
++ * setescape - add chars to the set we escape on transmission.
++ */
++static int
++setescape(argv)
++ char **argv;
++{
++ int n, ret;
++ char *p, *endp;
++
++ p = *argv;
++ ret = 1;
++ while (*p) {
++ n = strtol(p, &amp;endp, 16);
++ if (p == endp) {
++ option_error(&quot;escape parameter contains invalid hex number '%s'&quot;,
++ p);
++ return 0;
++ }
++ p = endp;
++ if (n &lt; 0 || n == 0x5E || n &gt; 0xFF) {
++ option_error(&quot;can't escape character 0x%x&quot;, n);
++ ret = 0;
++ } else
++ xmit_accm[n &gt;&gt; 5] |= 1 &lt;&lt; (n &amp; 0x1F);
++ while (*p == ',' || *p == ' ')
++ ++p;
++ }
++ lcp_allowoptions[0].asyncmap = xmit_accm[0];
++ return ret;
++}
++
++static void
++printescape(opt, printer, arg)
++ option_t *opt;
++ void (*printer) __P((void *, char *, ...));
++ void *arg;
++{
++ int n;
++ int first = 1;
++
++ for (n = 0; n &lt; 256; ++n) {
++ if (n == 0x7d)
++ n += 2; /* skip 7d, 7e */
++ if (xmit_accm[n &gt;&gt; 5] &amp; (1 &lt;&lt; (n &amp; 0x1f))) {
++ if (!first)
++ printer(arg, &quot;,&quot;);
++ else
++ first = 0;
++ printer(arg, &quot;%x&quot;, n);
++ }
++ }
++ if (first)
++ printer(arg, &quot;oops # nothing escaped&quot;);
++}
++
++/*
++ * tty_init - do various tty-related initializations.
++ */
++void tty_init()
++{
++ add_notifier(&amp;pidchange, maybe_relock, 0);
++ the_channel = &amp;tty_channel;
++ xmit_accm[3] = 0x60000000;
++}
++
++/*
++ * tty_process_extra_options - work out which tty device we are using
++ * and read its options file.
++ */
++void tty_process_extra_options()
++{
++ using_pty = notty || ptycommand != NULL || pty_socket != NULL;
++ if (using_pty)
++ return;
++ if (default_device) {
++ char *p;
++ if (!isatty(0) || (p = ttyname(0)) == NULL) {
++ option_error(&quot;no device specified and stdin is not a tty&quot;);
++ exit(EXIT_OPTION_ERROR);
++ }
++ strlcpy(devnam, p, sizeof(devnam));
++ if (stat(devnam, &amp;devstat) &lt; 0)
++ fatal(&quot;Couldn't stat default device %s: %m&quot;, devnam);
++ }
++
++
++ /*
++ * Parse the tty options file.
++ * The per-tty options file should not change
++ * ptycommand, pty_socket, notty or devnam.
++ * options_for_tty doesn't override options set on the command line,
++ * except for some privileged options.
++ */
++ if (!options_for_tty())
++ exit(EXIT_OPTION_ERROR);
++}
++
++/*
++ * tty_check_options - do consistency checks on the options we were given.
++ */
++void
++tty_check_options()
++{
++ struct stat statbuf;
++ int fdflags;
++
++ if (demand &amp;&amp; connect_script == 0) {
++ option_error(&quot;connect script is required for demand-dialling\n&quot;);
++ exit(EXIT_OPTION_ERROR);
++ }
++ /* default holdoff to 0 if no connect script has been given */
++ if (connect_script == 0 &amp;&amp; !holdoff_specified)
++ holdoff = 0;
++
++ if (using_pty) {
++ if (!default_device) {
++ option_error(&quot;%s option precludes specifying device name&quot;,
++ notty? &quot;notty&quot;: &quot;pty&quot;);
++ exit(EXIT_OPTION_ERROR);
++ }
++ if (ptycommand != NULL &amp;&amp; notty) {
++ option_error(&quot;pty option is incompatible with notty option&quot;);
++ exit(EXIT_OPTION_ERROR);
++ }
++ if (pty_socket != NULL &amp;&amp; (ptycommand != NULL || notty)) {
++ option_error(&quot;socket option is incompatible with pty and notty&quot;);
++ exit(EXIT_OPTION_ERROR);
++ }
++ default_device = notty;
++ lockflag = 0;
++ modem = 0;
++ if (notty &amp;&amp; log_to_fd &lt;= 1)
++ log_to_fd = -1;
++ } else {
++ /*
++ * If the user has specified a device which is the same as
++ * the one on stdin, pretend they didn't specify any.
++ * If the device is already open read/write on stdin,
++ * we assume we don't need to lock it, and we can open it
++ * as root.
++ */
++ if (fstat(0, &amp;statbuf) &gt;= 0 &amp;&amp; S_ISCHR(statbuf.st_mode)
++ &amp;&amp; statbuf.st_rdev == devstat.st_rdev) {
++ default_device = 1;
++ fdflags = fcntl(0, F_GETFL);
++ if (fdflags != -1 &amp;&amp; (fdflags &amp; O_ACCMODE) == O_RDWR)
++ privopen = 1;
++ }
++ }
++ if (default_device)
++ nodetach = 1;
++
++ /*
++ * Don't send log messages to the serial port, it tends to
++ * confuse the peer. :-)
++ */
++ if (log_to_fd &gt;= 0 &amp;&amp; fstat(log_to_fd, &amp;statbuf) &gt;= 0
++ &amp;&amp; S_ISCHR(statbuf.st_mode) &amp;&amp; statbuf.st_rdev == devstat.st_rdev)
++ log_to_fd = -1;
++}
++
++/*
++ * connect_tty - get the serial port ready to start doing PPP.
++ * That is, open the serial port, set its speed and mode, and run
++ * the connector and/or welcomer.
++ */
++int connect_tty()
++{
++ char *connector;
++ int fdflags;
++ struct stat statbuf;
++ char numbuf[16];
++
++ /*
++ * Get a pty master/slave pair if the pty, notty, socket,
++ * or record options were specified.
++ */
++ strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam));
++ pty_master = -1;
++ pty_slave = -1;
++ real_ttyfd = -1;
++ if (using_pty || record_file != NULL) {
++ if (!get_pty(&amp;pty_master, &amp;pty_slave, ppp_devnam, uid)) {
++ error(&quot;Couldn't allocate pseudo-tty&quot;);
++ status = EXIT_FATAL_ERROR;
++ return -1;
++ }
++ set_up_tty(pty_slave, 1);
++ }
++
++ /*
++ * Lock the device if we've been asked to.
++ */
++ status = EXIT_LOCK_FAILED;
++ if (lockflag &amp;&amp; !privopen) {
++ if (lock(devnam) &lt; 0)
++ return -1;
++ locked = 1;
++ }
++
++ /*
++ * Open the serial device and set it up to be the ppp interface.
++ * First we open it in non-blocking mode so we can set the
++ * various termios flags appropriately. If we aren't dialling
++ * out and we want to use the modem lines, we reopen it later
++ * in order to wait for the carrier detect signal from the modem.
++ */
++ hungup = 0;
++ kill_link = 0;
++ connector = doing_callback? callback_script: connect_script;
++ if (devnam[0] != 0) {
++ for (;;) {
++ /* If the user specified the device name, become the
++ user before opening it. */
++ int err, prio;
++
++ prio = privopen? OPRIO_ROOT: tty_options[0].priority;
++ if (prio &lt; OPRIO_ROOT)
++ seteuid(uid);
++ ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0);
++ err = errno;
++ if (prio &lt; OPRIO_ROOT)
++ seteuid(0);
++ if (ttyfd &gt;= 0)
++ break;
++ errno = err;
++ if (err != EINTR) {
++ error(&quot;Failed to open %s: %m&quot;, devnam);
++ status = EXIT_OPEN_FAILED;
++ }
++ if (!persist || err != EINTR)
++ return -1;
++ }
++ real_ttyfd = ttyfd;
++ if ((fdflags = fcntl(ttyfd, F_GETFL)) == -1
++ || fcntl(ttyfd, F_SETFL, fdflags &amp; ~O_NONBLOCK) &lt; 0)
++ warn(&quot;Couldn't reset non-blocking mode on device: %m&quot;);
++
++ /*
++ * Do the equivalent of `mesg n' to stop broadcast messages.
++ */
++ if (fstat(ttyfd, &amp;statbuf) &lt; 0
++ || fchmod(ttyfd, statbuf.st_mode &amp; ~(S_IWGRP | S_IWOTH)) &lt; 0) {
++ warn(&quot;Couldn't restrict write permissions to %s: %m&quot;, devnam);
++ } else
++ tty_mode = statbuf.st_mode;
++
++ /*
++ * Set line speed, flow control, etc.
++ * If we have a non-null connection or initializer script,
++ * on most systems we set CLOCAL for now so that we can talk
++ * to the modem before carrier comes up. But this has the
++ * side effect that we might miss it if CD drops before we
++ * get to clear CLOCAL below. On systems where we can talk
++ * successfully to the modem with CLOCAL clear and CD down,
++ * we could clear CLOCAL at this point.
++ */
++ set_up_tty(ttyfd, ((connector != NULL &amp;&amp; connector[0] != 0)
++ || initializer != NULL));
++ }
++
++ /*
++ * If the pty, socket, notty and/or record option was specified,
++ * start up the character shunt now.
++ */
++ status = EXIT_PTYCMD_FAILED;
++ if (ptycommand != NULL) {
++ if (record_file != NULL) {
++ int ipipe[2], opipe[2], ok;
++
++ if (pipe(ipipe) &lt; 0 || pipe(opipe) &lt; 0)
++ fatal(&quot;Couldn't create pipes for record option: %m&quot;);
++ ok = device_script(ptycommand, opipe[0], ipipe[1], 1) == 0
++ &amp;&amp; start_charshunt(ipipe[0], opipe[1]);
++ close(ipipe[0]);
++ close(ipipe[1]);
++ close(opipe[0]);
++ close(opipe[1]);
++ if (!ok)
++ return -1;
++ } else {
++ if (device_script(ptycommand, pty_master, pty_master, 1) &lt; 0)
++ return -1;
++ ttyfd = pty_slave;
++ close(pty_master);
++ pty_master = -1;
++ }
++ } else if (pty_socket != NULL) {
++ int fd = open_socket(pty_socket);
++ if (fd &lt; 0)
++ return -1;
++ if (!start_charshunt(fd, fd))
++ return -1;
++ } else if (notty) {
++ if (!start_charshunt(0, 1))
++ return -1;
++ } else if (record_file != NULL) {
++ if (!start_charshunt(ttyfd, ttyfd))
++ return -1;
++ }
++
++ /* run connection script */
++ if ((connector &amp;&amp; connector[0]) || initializer) {
++ if (real_ttyfd != -1) {
++ /* XXX do this if doing_callback == CALLBACK_DIALIN? */
++ if (!default_device &amp;&amp; modem) {
++ setdtr(real_ttyfd, 0); /* in case modem is off hook */
++ sleep(1);
++ setdtr(real_ttyfd, 1);
++ }
++ }
++
++ if (initializer &amp;&amp; initializer[0]) {
++ if (device_script(initializer, ttyfd, ttyfd, 0) &lt; 0) {
++ error(&quot;Initializer script failed&quot;);
++ status = EXIT_INIT_FAILED;
++ return -1;
++ }
++ if (kill_link) {
++ disconnect_tty();
++ return -1;
++ }
++ info(&quot;Serial port initialized.&quot;);
++ }
++
++ if (connector &amp;&amp; connector[0]) {
++ if (device_script(connector, ttyfd, ttyfd, 0) &lt; 0) {
++ error(&quot;Connect script failed&quot;);
++ status = EXIT_CONNECT_FAILED;
++ return -1;
++ }
++ if (kill_link) {
++ disconnect_tty();
++ return -1;
++ }
++ info(&quot;Serial connection established.&quot;);
++ }
++
++ /* set line speed, flow control, etc.;
++ clear CLOCAL if modem option */
++ if (real_ttyfd != -1)
++ set_up_tty(real_ttyfd, 0);
++
++ if (doing_callback == CALLBACK_DIALIN)
++ connector = NULL;
++ }
++
++ /* reopen tty if necessary to wait for carrier */
++ if (connector == NULL &amp;&amp; modem &amp;&amp; devnam[0] != 0) {
++ int i;
++ for (;;) {
++ if ((i = open(devnam, O_RDWR)) &gt;= 0)
++ break;
++ if (errno != EINTR) {
++ error(&quot;Failed to reopen %s: %m&quot;, devnam);
++ status = EXIT_OPEN_FAILED;
++ }
++ if (!persist || errno != EINTR || hungup || kill_link)
++ return -1;
++ }
++ close(i);
++ }
++
++ slprintf(numbuf, sizeof(numbuf), &quot;%d&quot;, baud_rate);
++ script_setenv(&quot;SPEED&quot;, numbuf, 0);
++
++ /* run welcome script, if any */
++ if (welcomer &amp;&amp; welcomer[0]) {
++ if (device_script(welcomer, ttyfd, ttyfd, 0) &lt; 0)
++ warn(&quot;Welcome script failed&quot;);
++ }
++
++ /*
++ * If we are initiating this connection, wait for a short
++ * time for something from the peer. This can avoid bouncing
++ * our packets off his tty before he has it set up.
++ */
++ if (connector != NULL || ptycommand != NULL)
++ listen_time = connect_delay;
++
++ return ttyfd;
++}
++
++
++void disconnect_tty()
++{
++ if (disconnect_script == NULL || hungup)
++ return;
++ if (real_ttyfd &gt;= 0)
++ set_up_tty(real_ttyfd, 1);
++ if (device_script(disconnect_script, ttyfd, ttyfd, 0) &lt; 0) {
++ warn(&quot;disconnect script failed&quot;);
++ } else {
++ info(&quot;Serial link disconnected.&quot;);
++ }
++}
++
++void tty_close_fds()
++{
++ if (pty_master &gt;= 0)
++ close(pty_master);
++ if (pty_slave &gt;= 0)
++ close(pty_slave);
++ if (real_ttyfd &gt;= 0) {
++ close(real_ttyfd);
++ real_ttyfd = -1;
++ }
++ /* N.B. ttyfd will == either pty_slave or real_ttyfd */
++}
++
++void cleanup_tty()
++{
++ if (real_ttyfd &gt;= 0)
++ finish_tty();
++ tty_close_fds();
++ if (locked) {
++ unlock();
++ locked = 0;
++ }
++}
++
++/*
++ * tty_do_send_config - set transmit-side PPP configuration.
++ * We set the extended transmit ACCM here as well.
++ */
++void
++tty_do_send_config(mtu, accm, pcomp, accomp)
++ int mtu;
++ u_int32_t accm;
++ int pcomp, accomp;
++{
++ tty_set_xaccm(xmit_accm);
++ tty_send_config(mtu, accm, pcomp, accomp);
++}
++
++/*
++ * finish_tty - restore the terminal device to its original settings
++ */
++static void
++finish_tty()
++{
++ /* drop dtr to hang up */
++ if (!default_device &amp;&amp; modem) {
++ setdtr(real_ttyfd, 0);
++ /*
++ * This sleep is in case the serial port has CLOCAL set by default,
++ * and consequently will reassert DTR when we close the device.
++ */
++ sleep(1);
++ }
++
++ restore_tty(real_ttyfd);
++
++ if (tty_mode != (mode_t) -1) {
++ if (fchmod(real_ttyfd, tty_mode) != 0) {
++ /* XXX if devnam is a symlink, this will change the link */
++ chmod(devnam, tty_mode);
++ }
++ }
++
++ close(real_ttyfd);
++ real_ttyfd = -1;
++}
++
++/*
++ * maybe_relock - our PID has changed, maybe update the lock file.
++ */
++static void
++maybe_relock(arg, pid)
++ void *arg;
++ int pid;
++{
++ if (locked)
++ relock(pid);
++}
++
++/*
++ * open_socket - establish a stream socket connection to the nominated
++ * host and port.
++ */
++static int
++open_socket(dest)
++ char *dest;
++{
++ char *sep, *endp = NULL;
++ int sock, port = -1;
++ u_int32_t host;
++ struct hostent *hent;
++ struct sockaddr_in sad;
++
++ /* parse host:port and resolve host to an IP address */
++ sep = strchr(dest, ':');
++ if (sep != NULL)
++ port = strtol(sep+1, &amp;endp, 10);
++ if (port &lt; 0 || endp == sep+1 || sep == dest) {
++ error(&quot;Can't parse host:port for socket destination&quot;);
++ return -1;
++ }
++ *sep = 0;
++ host = inet_addr(dest);
++ if (host == (u_int32_t) -1) {
++ hent = gethostbyname(dest);
++ if (hent == NULL) {
++ error(&quot;%s: unknown host in socket option&quot;, dest);
++ *sep = ':';
++ return -1;
++ }
++ host = *(u_int32_t *)(hent-&gt;h_addr_list[0]);
++ }
++ *sep = ':';
++
++ /* get a socket and connect it to the other end */
++ sock = socket(PF_INET, SOCK_STREAM, 0);
++ if (sock &lt; 0) {
++ error(&quot;Can't create socket: %m&quot;);
++ return -1;
++ }
++ memset(&amp;sad, 0, sizeof(sad));
++ sad.sin_family = AF_INET;
++ sad.sin_port = htons(port);
++ sad.sin_addr.s_addr = host;
++ if (connect(sock, (struct sockaddr *)&amp;sad, sizeof(sad)) &lt; 0) {
++ error(&quot;Can't connect to %s: %m&quot;, dest);
++ close(sock);
++ return -1;
++ }
++
++ return sock;
++}
++
++
++/*
++ * start_charshunt - create a child process to run the character shunt.
++ */
++static int
++start_charshunt(ifd, ofd)
++ int ifd, ofd;
++{
++ int cpid;
++
++ cpid = fork();
++ if (cpid == -1) {
++ error(&quot;Can't fork process for character shunt: %m&quot;);
++ return 0;
++ }
++ if (cpid == 0) {
++ /* child */
++ close(pty_slave);
++ setuid(uid);
++ if (getuid() != uid)
++ fatal(&quot;setuid failed&quot;);
++ setgid(getgid());
++ if (!nodetach)
++ log_to_fd = -1;
++ charshunt(ifd, ofd, record_file);
++ exit(0);
++ }
++ charshunt_pid = cpid;
++ add_notifier(&amp;sigreceived, stop_charshunt, 0);
++ close(pty_master);
++ pty_master = -1;
++ ttyfd = pty_slave;
++ record_child(cpid, &quot;pppd (charshunt)&quot;, charshunt_done, NULL);
++ return 1;
++}
++
++static void
++charshunt_done(arg)
++ void *arg;
++{
++ charshunt_pid = 0;
++}
++
++static void
++stop_charshunt(arg, sig)
++ void *arg;
++ int sig;
++{
++ if (charshunt_pid)
++ kill(charshunt_pid, (sig == SIGINT? sig: SIGTERM));
++}
++
++/*
++ * charshunt - the character shunt, which passes characters between
++ * the pty master side and the serial port (or stdin/stdout).
++ * This runs as the user (not as root).
++ * (We assume ofd &gt;= ifd which is true the way this gets called. :-).
++ */
++static void
++charshunt(ifd, ofd, record_file)
++ int ifd, ofd;
++ char *record_file;
++{
++ int n, nfds;
++ fd_set ready, writey;
++ u_char *ibufp, *obufp;
++ int nibuf, nobuf;
++ int flags;
++ int pty_readable, stdin_readable;
++ struct timeval lasttime;
++ FILE *recordf = NULL;
++ int ilevel, olevel, max_level;
++ struct timeval levelt, tout, *top;
++ extern u_char inpacket_buf[];
++
++ /*
++ * Reset signal handlers.
++ */
++ signal(SIGHUP, SIG_IGN); /* Hangup */
++ signal(SIGINT, SIG_DFL); /* Interrupt */
++ signal(SIGTERM, SIG_DFL); /* Terminate */
++ signal(SIGCHLD, SIG_DFL);
++ signal(SIGUSR1, SIG_DFL);
++ signal(SIGUSR2, SIG_DFL);
++ signal(SIGABRT, SIG_DFL);
++ signal(SIGALRM, SIG_DFL);
++ signal(SIGFPE, SIG_DFL);
++ signal(SIGILL, SIG_DFL);
++ signal(SIGPIPE, SIG_DFL);
++ signal(SIGQUIT, SIG_DFL);
++ signal(SIGSEGV, SIG_DFL);
++#ifdef SIGBUS
++ signal(SIGBUS, SIG_DFL);
++#endif
++#ifdef SIGEMT
++ signal(SIGEMT, SIG_DFL);
++#endif
++#ifdef SIGPOLL
++ signal(SIGPOLL, SIG_DFL);
++#endif
++#ifdef SIGPROF
++ signal(SIGPROF, SIG_DFL);
++#endif
++#ifdef SIGSYS
++ signal(SIGSYS, SIG_DFL);
++#endif
++#ifdef SIGTRAP
++ signal(SIGTRAP, SIG_DFL);
++#endif
++#ifdef SIGVTALRM
++ signal(SIGVTALRM, SIG_DFL);
++#endif
++#ifdef SIGXCPU
++ signal(SIGXCPU, SIG_DFL);
++#endif
++#ifdef SIGXFSZ
++ signal(SIGXFSZ, SIG_DFL);
++#endif
++
++ /*
++ * Open the record file if required.
++ */
++ if (record_file != NULL) {
++ recordf = fopen(record_file, &quot;a&quot;);
++ if (recordf == NULL)
++ error(&quot;Couldn't create record file %s: %m&quot;, record_file);
++ }
++
++ /* set all the fds to non-blocking mode */
++ flags = fcntl(pty_master, F_GETFL);
++ if (flags == -1
++ || fcntl(pty_master, F_SETFL, flags | O_NONBLOCK) == -1)
++ warn(&quot;couldn't set pty master to nonblock: %m&quot;);
++ flags = fcntl(ifd, F_GETFL);
++ if (flags == -1
++ || fcntl(ifd, F_SETFL, flags | O_NONBLOCK) == -1)
++ warn(&quot;couldn't set %s to nonblock: %m&quot;, (ifd==0? &quot;stdin&quot;: &quot;tty&quot;));
++ if (ofd != ifd) {
++ flags = fcntl(ofd, F_GETFL);
++ if (flags == -1
++ || fcntl(ofd, F_SETFL, flags | O_NONBLOCK) == -1)
++ warn(&quot;couldn't set stdout to nonblock: %m&quot;);
++ }
++
++ nibuf = nobuf = 0;
++ ibufp = obufp = NULL;
++ pty_readable = stdin_readable = 1;
++
++ ilevel = olevel = 0;
++ gettimeofday(&amp;levelt, NULL);
++ if (max_data_rate) {
++ max_level = max_data_rate / 10;
++ if (max_level &lt; 100)
++ max_level = 100;
++ } else
++ max_level = PPP_MRU + PPP_HDRLEN + 1;
++
++ nfds = (ofd &gt; pty_master? ofd: pty_master) + 1;
++ if (recordf != NULL) {
++ gettimeofday(&amp;lasttime, NULL);
++ putc(7, recordf); /* put start marker */
++ putc(lasttime.tv_sec &gt;&gt; 24, recordf);
++ putc(lasttime.tv_sec &gt;&gt; 16, recordf);
++ putc(lasttime.tv_sec &gt;&gt; 8, recordf);
++ putc(lasttime.tv_sec, recordf);
++ lasttime.tv_usec = 0;
++ }
++
++ while (nibuf != 0 || nobuf != 0 || pty_readable || stdin_readable) {
++ top = 0;
++ tout.tv_sec = 0;
++ tout.tv_usec = 10000;
++ FD_ZERO(&amp;ready);
++ FD_ZERO(&amp;writey);
++ if (nibuf != 0) {
++ if (ilevel &gt;= max_level)
++ top = &amp;tout;
++ else
++ FD_SET(pty_master, &amp;writey);
++ } else if (stdin_readable)
++ FD_SET(ifd, &amp;ready);
++ if (nobuf != 0) {
++ if (olevel &gt;= max_level)
++ top = &amp;tout;
++ else
++ FD_SET(ofd, &amp;writey);
++ } else if (pty_readable)
++ FD_SET(pty_master, &amp;ready);
++ if (select(nfds, &amp;ready, &amp;writey, NULL, top) &lt; 0) {
++ if (errno != EINTR)
++ fatal(&quot;select&quot;);
++ continue;
++ }
++ if (max_data_rate) {
++ double dt;
++ int nbt;
++ struct timeval now;
++
++ gettimeofday(&amp;now, NULL);
++ dt = (now.tv_sec - levelt.tv_sec
++ + (now.tv_usec - levelt.tv_usec) / 1e6);
++ nbt = (int)(dt * max_data_rate);
++ ilevel = (nbt &lt; 0 || nbt &gt; ilevel)? 0: ilevel - nbt;
++ olevel = (nbt &lt; 0 || nbt &gt; olevel)? 0: olevel - nbt;
++ levelt = now;
++ } else
++ ilevel = olevel = 0;
++ if (FD_ISSET(ifd, &amp;ready)) {
++ ibufp = inpacket_buf;
++ nibuf = read(ifd, ibufp, PPP_MRU + PPP_HDRLEN);
++ if (nibuf &lt; 0 &amp;&amp; errno == EIO)
++ nibuf = 0;
++ if (nibuf &lt; 0) {
++ if (!(errno == EINTR || errno == EAGAIN)) {
++ error(&quot;Error reading standard input: %m&quot;);
++ break;
++ }
++ nibuf = 0;
++ } else if (nibuf == 0) {
++ /* end of file from stdin */
++ stdin_readable = 0;
++ /* do a 0-length write, hopefully this will generate
++ an EOF (hangup) on the slave side. */
++ write(pty_master, inpacket_buf, 0);
++ if (recordf)
++ if (!record_write(recordf, 4, NULL, 0, &amp;lasttime))
++ recordf = NULL;
++ } else {
++ FD_SET(pty_master, &amp;writey);
++ if (recordf)
++ if (!record_write(recordf, 2, ibufp, nibuf, &amp;lasttime))
++ recordf = NULL;
++ }
++ }
++ if (FD_ISSET(pty_master, &amp;ready)) {
++ obufp = outpacket_buf;
++ nobuf = read(pty_master, obufp, PPP_MRU + PPP_HDRLEN);
++ if (nobuf &lt; 0 &amp;&amp; errno == EIO)
++ nobuf = 0;
++ if (nobuf &lt; 0) {
++ if (!(errno == EINTR || errno == EAGAIN)) {
++ error(&quot;Error reading pseudo-tty master: %m&quot;);
++ break;
++ }
++ nobuf = 0;
++ } else if (nobuf == 0) {
++ /* end of file from the pty - slave side has closed */
++ pty_readable = 0;
++ stdin_readable = 0; /* pty is not writable now */
++ nibuf = 0;
++ close(ofd);
++ if (recordf)
++ if (!record_write(recordf, 3, NULL, 0, &amp;lasttime))
++ recordf = NULL;
++ } else {
++ FD_SET(ofd, &amp;writey);
++ if (recordf)
++ if (!record_write(recordf, 1, obufp, nobuf, &amp;lasttime))
++ recordf = NULL;
++ }
++ }
++ if (FD_ISSET(ofd, &amp;writey)) {
++ n = nobuf;
++ if (olevel + n &gt; max_level)
++ n = max_level - olevel;
++ n = write(ofd, obufp, n);
++ if (n &lt; 0) {
++ if (errno == EIO) {
++ pty_readable = 0;
++ nobuf = 0;
++ } else if (errno != EAGAIN &amp;&amp; errno != EINTR) {
++ error(&quot;Error writing standard output: %m&quot;);
++ break;
++ }
++ } else {
++ obufp += n;
++ nobuf -= n;
++ olevel += n;
++ }
++ }
++ if (FD_ISSET(pty_master, &amp;writey)) {
++ n = nibuf;
++ if (ilevel + n &gt; max_level)
++ n = max_level - ilevel;
++ n = write(pty_master, ibufp, n);
++ if (n &lt; 0) {
++ if (errno == EIO) {
++ stdin_readable = 0;
++ nibuf = 0;
++ } else if (errno != EAGAIN &amp;&amp; errno != EINTR) {
++ error(&quot;Error writing pseudo-tty master: %m&quot;);
++ break;
++ }
++ } else {
++ ibufp += n;
++ nibuf -= n;
++ ilevel += n;
++ }
++ }
++ }
++ exit(0);
++}
++
++static int
++record_write(f, code, buf, nb, tp)
++ FILE *f;
++ int code;
++ u_char *buf;
++ int nb;
++ struct timeval *tp;
++{
++ struct timeval now;
++ int diff;
++
++ gettimeofday(&amp;now, NULL);
++ now.tv_usec /= 100000; /* actually 1/10 s, not usec now */
++ diff = (now.tv_sec - tp-&gt;tv_sec) * 10 + (now.tv_usec - tp-&gt;tv_usec);
++ if (diff &gt; 0) {
++ if (diff &gt; 255) {
++ putc(5, f);
++ putc(diff &gt;&gt; 24, f);
++ putc(diff &gt;&gt; 16, f);
++ putc(diff &gt;&gt; 8, f);
++ putc(diff, f);
++ } else {
++ putc(6, f);
++ putc(diff, f);
++ }
++ *tp = now;
++ }
++ putc(code, f);
++ if (buf != NULL) {
++ putc(nb &gt;&gt; 8, f);
++ putc(nb, f);
++ fwrite(buf, nb, 1, f);
++ }
++ fflush(f);
++ if (ferror(f)) {
++ error(&quot;Error writing record file: %m&quot;);
++ return 0;
++ }
++ return 1;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/tty.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/upap.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/upap.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/upap.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,640 @@
++/*
++ * upap.c - User/Password Authentication Protocol.
++ *
++ * Copyright (c) 1989 Carnegie Mellon University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by Carnegie Mellon University. The name of the
++ * University may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ */
++
++#define RCSID &quot;$Id: upap.c 195720 2001-06-11 11:44:34Z gc $&quot;
++
++/*
++ * TODO:
++ */
++
++#include &lt;stdio.h&gt;
++#include &lt;string.h&gt;
++
++#include &quot;pppd.h&quot;
++#include &quot;upap.h&quot;
++
++static const char rcsid[] = RCSID;
++
++static bool hide_password = 1;
++
++/*
++ * Command-line options.
++ */
++static option_t pap_option_list[] = {
++ { &quot;hide-password&quot;, o_bool, &amp;hide_password,
++ &quot;Don't output passwords to log&quot;, OPT_PRIO | 1 },
++ { &quot;show-password&quot;, o_bool, &amp;hide_password,
++ &quot;Show password string in debug log messages&quot;, OPT_PRIOSUB | 0 },
++
++ { &quot;pap-restart&quot;, o_int, &amp;upap[0].us_timeouttime,
++ &quot;Set retransmit timeout for PAP&quot;, OPT_PRIO },
++ { &quot;pap-max-authreq&quot;, o_int, &amp;upap[0].us_maxtransmits,
++ &quot;Set max number of transmissions for auth-reqs&quot;, OPT_PRIO },
++ { &quot;pap-timeout&quot;, o_int, &amp;upap[0].us_reqtimeout,
++ &quot;Set time limit for peer PAP authentication&quot;, OPT_PRIO },
++
++ { NULL }
++};
++
++/*
++ * Protocol entry points.
++ */
++static void upap_init __P((int));
++static void upap_lowerup __P((int));
++static void upap_lowerdown __P((int));
++static void upap_input __P((int, u_char *, int));
++static void upap_protrej __P((int));
++static int upap_printpkt __P((u_char *, int,
++ void (*) __P((void *, char *, ...)), void *));
++
++struct protent pap_protent = {
++ PPP_PAP,
++ upap_init,
++ upap_input,
++ upap_protrej,
++ upap_lowerup,
++ upap_lowerdown,
++ NULL,
++ NULL,
++ upap_printpkt,
++ NULL,
++ 1,
++ &quot;PAP&quot;,
++ NULL,
++ pap_option_list,
++ NULL,
++ NULL,
++ NULL
++};
++
++upap_state upap[NUM_PPP]; /* UPAP state; one for each unit */
++
++static void upap_timeout __P((void *));
++static void upap_reqtimeout __P((void *));
++static void upap_rauthreq __P((upap_state *, u_char *, int, int));
++static void upap_rauthack __P((upap_state *, u_char *, int, int));
++static void upap_rauthnak __P((upap_state *, u_char *, int, int));
++static void upap_sauthreq __P((upap_state *));
++static void upap_sresp __P((upap_state *, int, int, char *, int));
++
++
++/*
++ * upap_init - Initialize a UPAP unit.
++ */
++static void
++upap_init(unit)
++ int unit;
++{
++ upap_state *u = &amp;upap[unit];
++
++ u-&gt;us_unit = unit;
++ u-&gt;us_user = NULL;
++ u-&gt;us_userlen = 0;
++ u-&gt;us_passwd = NULL;
++ u-&gt;us_passwdlen = 0;
++ u-&gt;us_clientstate = UPAPCS_INITIAL;
++ u-&gt;us_serverstate = UPAPSS_INITIAL;
++ u-&gt;us_id = 0;
++ u-&gt;us_timeouttime = UPAP_DEFTIMEOUT;
++ u-&gt;us_maxtransmits = 10;
++ u-&gt;us_reqtimeout = UPAP_DEFREQTIME;
++}
++
++
++/*
++ * upap_authwithpeer - Authenticate us with our peer (start client).
++ *
++ * Set new state and send authenticate's.
++ */
++void
++upap_authwithpeer(unit, user, password)
++ int unit;
++ char *user, *password;
++{
++ upap_state *u = &amp;upap[unit];
++
++ /* Save the username and password we're given */
++ u-&gt;us_user = user;
++ u-&gt;us_userlen = strlen(user);
++ u-&gt;us_passwd = password;
++ u-&gt;us_passwdlen = strlen(password);
++ u-&gt;us_transmits = 0;
++
++ /* Lower layer up yet? */
++ if (u-&gt;us_clientstate == UPAPCS_INITIAL ||
++ u-&gt;us_clientstate == UPAPCS_PENDING) {
++ u-&gt;us_clientstate = UPAPCS_PENDING;
++ return;
++ }
++
++ upap_sauthreq(u); /* Start protocol */
++}
++
++
++/*
++ * upap_authpeer - Authenticate our peer (start server).
++ *
++ * Set new state.
++ */
++void
++upap_authpeer(unit)
++ int unit;
++{
++ upap_state *u = &amp;upap[unit];
++
++ /* Lower layer up yet? */
++ if (u-&gt;us_serverstate == UPAPSS_INITIAL ||
++ u-&gt;us_serverstate == UPAPSS_PENDING) {
++ u-&gt;us_serverstate = UPAPSS_PENDING;
++ return;
++ }
++
++ u-&gt;us_serverstate = UPAPSS_LISTEN;
++ if (u-&gt;us_reqtimeout &gt; 0)
++ TIMEOUT(upap_reqtimeout, u, u-&gt;us_reqtimeout);
++}
++
++
++/*
++ * upap_timeout - Retransmission timer for sending auth-reqs expired.
++ */
++static void
++upap_timeout(arg)
++ void *arg;
++{
++ upap_state *u = (upap_state *) arg;
++
++ if (u-&gt;us_clientstate != UPAPCS_AUTHREQ)
++ return;
++
++ if (u-&gt;us_transmits &gt;= u-&gt;us_maxtransmits) {
++ /* give up in disgust */
++ error(&quot;No response to PAP authenticate-requests&quot;);
++ u-&gt;us_clientstate = UPAPCS_BADAUTH;
++ auth_withpeer_fail(u-&gt;us_unit, PPP_PAP);
++ return;
++ }
++
++ upap_sauthreq(u); /* Send Authenticate-Request */
++}
++
++
++/*
++ * upap_reqtimeout - Give up waiting for the peer to send an auth-req.
++ */
++static void
++upap_reqtimeout(arg)
++ void *arg;
++{
++ upap_state *u = (upap_state *) arg;
++
++ if (u-&gt;us_serverstate != UPAPSS_LISTEN)
++ return; /* huh?? */
++
++ auth_peer_fail(u-&gt;us_unit, PPP_PAP);
++ u-&gt;us_serverstate = UPAPSS_BADAUTH;
++}
++
++
++/*
++ * upap_lowerup - The lower layer is up.
++ *
++ * Start authenticating if pending.
++ */
++static void
++upap_lowerup(unit)
++ int unit;
++{
++ upap_state *u = &amp;upap[unit];
++
++ if (u-&gt;us_clientstate == UPAPCS_INITIAL)
++ u-&gt;us_clientstate = UPAPCS_CLOSED;
++ else if (u-&gt;us_clientstate == UPAPCS_PENDING) {
++ upap_sauthreq(u); /* send an auth-request */
++ }
++
++ if (u-&gt;us_serverstate == UPAPSS_INITIAL)
++ u-&gt;us_serverstate = UPAPSS_CLOSED;
++ else if (u-&gt;us_serverstate == UPAPSS_PENDING) {
++ u-&gt;us_serverstate = UPAPSS_LISTEN;
++ if (u-&gt;us_reqtimeout &gt; 0)
++ TIMEOUT(upap_reqtimeout, u, u-&gt;us_reqtimeout);
++ }
++}
++
++
++/*
++ * upap_lowerdown - The lower layer is down.
++ *
++ * Cancel all timeouts.
++ */
++static void
++upap_lowerdown(unit)
++ int unit;
++{
++ upap_state *u = &amp;upap[unit];
++
++ if (u-&gt;us_clientstate == UPAPCS_AUTHREQ) /* Timeout pending? */
++ UNTIMEOUT(upap_timeout, u); /* Cancel timeout */
++ if (u-&gt;us_serverstate == UPAPSS_LISTEN &amp;&amp; u-&gt;us_reqtimeout &gt; 0)
++ UNTIMEOUT(upap_reqtimeout, u);
++
++ u-&gt;us_clientstate = UPAPCS_INITIAL;
++ u-&gt;us_serverstate = UPAPSS_INITIAL;
++}
++
++
++/*
++ * upap_protrej - Peer doesn't speak this protocol.
++ *
++ * This shouldn't happen. In any case, pretend lower layer went down.
++ */
++static void
++upap_protrej(unit)
++ int unit;
++{
++ upap_state *u = &amp;upap[unit];
++
++ if (u-&gt;us_clientstate == UPAPCS_AUTHREQ) {
++ error(&quot;PAP authentication failed due to protocol-reject&quot;);
++ auth_withpeer_fail(unit, PPP_PAP);
++ }
++ if (u-&gt;us_serverstate == UPAPSS_LISTEN) {
++ error(&quot;PAP authentication of peer failed (protocol-reject)&quot;);
++ auth_peer_fail(unit, PPP_PAP);
++ }
++ upap_lowerdown(unit);
++}
++
++
++/*
++ * upap_input - Input UPAP packet.
++ */
++static void
++upap_input(unit, inpacket, l)
++ int unit;
++ u_char *inpacket;
++ int l;
++{
++ upap_state *u = &amp;upap[unit];
++ u_char *inp;
++ u_char code, id;
++ int len;
++
++ /*
++ * Parse header (code, id and length).
++ * If packet too short, drop it.
++ */
++ inp = inpacket;
++ if (l &lt; UPAP_HEADERLEN) {
++ UPAPDEBUG((&quot;pap_input: rcvd short header.&quot;));
++ return;
++ }
++ GETCHAR(code, inp);
++ GETCHAR(id, inp);
++ GETSHORT(len, inp);
++ if (len &lt; UPAP_HEADERLEN) {
++ UPAPDEBUG((&quot;pap_input: rcvd illegal length.&quot;));
++ return;
++ }
++ if (len &gt; l) {
++ UPAPDEBUG((&quot;pap_input: rcvd short packet.&quot;));
++ return;
++ }
++ len -= UPAP_HEADERLEN;
++
++ /*
++ * Action depends on code.
++ */
++ switch (code) {
++ case UPAP_AUTHREQ:
++ upap_rauthreq(u, inp, id, len);
++ break;
++
++ case UPAP_AUTHACK:
++ upap_rauthack(u, inp, id, len);
++ break;
++
++ case UPAP_AUTHNAK:
++ upap_rauthnak(u, inp, id, len);
++ break;
++
++ default: /* XXX Need code reject */
++ break;
++ }
++}
++
++
++/*
++ * upap_rauth - Receive Authenticate.
++ */
++static void
++upap_rauthreq(u, inp, id, len)
++ upap_state *u;
++ u_char *inp;
++ int id;
++ int len;
++{
++ u_char ruserlen, rpasswdlen;
++ char *ruser, *rpasswd;
++ int retcode;
++ char *msg;
++ int msglen;
++
++ if (u-&gt;us_serverstate &lt; UPAPSS_LISTEN)
++ return;
++
++ /*
++ * If we receive a duplicate authenticate-request, we are
++ * supposed to return the same status as for the first request.
++ */
++ if (u-&gt;us_serverstate == UPAPSS_OPEN) {
++ upap_sresp(u, UPAP_AUTHACK, id, &quot;&quot;, 0); /* return auth-ack */
++ return;
++ }
++ if (u-&gt;us_serverstate == UPAPSS_BADAUTH) {
++ upap_sresp(u, UPAP_AUTHNAK, id, &quot;&quot;, 0); /* return auth-nak */
++ return;
++ }
++
++ /*
++ * Parse user/passwd.
++ */
++ if (len &lt; 1) {
++ UPAPDEBUG((&quot;pap_rauth: rcvd short packet.&quot;));
++ return;
++ }
++ GETCHAR(ruserlen, inp);
++ len -= sizeof (u_char) + ruserlen + sizeof (u_char);
++ if (len &lt; 0) {
++ UPAPDEBUG((&quot;pap_rauth: rcvd short packet.&quot;));
++ return;
++ }
++ ruser = (char *) inp;
++ INCPTR(ruserlen, inp);
++ GETCHAR(rpasswdlen, inp);
++ if (len &lt; rpasswdlen) {
++ UPAPDEBUG((&quot;pap_rauth: rcvd short packet.&quot;));
++ return;
++ }
++ rpasswd = (char *) inp;
++
++ /*
++ * Check the username and password given.
++ */
++ retcode = check_passwd(u-&gt;us_unit, ruser, ruserlen, rpasswd,
++ rpasswdlen, &amp;msg);
++ BZERO(rpasswd, rpasswdlen);
++ msglen = strlen(msg);
++ if (msglen &gt; 255)
++ msglen = 255;
++
++ upap_sresp(u, retcode, id, msg, msglen);
++
++ if (retcode == UPAP_AUTHACK) {
++ u-&gt;us_serverstate = UPAPSS_OPEN;
++ auth_peer_success(u-&gt;us_unit, PPP_PAP, ruser, ruserlen);
++ } else {
++ u-&gt;us_serverstate = UPAPSS_BADAUTH;
++ auth_peer_fail(u-&gt;us_unit, PPP_PAP);
++ }
++
++ if (u-&gt;us_reqtimeout &gt; 0)
++ UNTIMEOUT(upap_reqtimeout, u);
++}
++
++
++/*
++ * upap_rauthack - Receive Authenticate-Ack.
++ */
++static void
++upap_rauthack(u, inp, id, len)
++ upap_state *u;
++ u_char *inp;
++ int id;
++ int len;
++{
++ u_char msglen;
++ char *msg;
++
++ if (u-&gt;us_clientstate != UPAPCS_AUTHREQ) /* XXX */
++ return;
++
++ /*
++ * Parse message.
++ */
++ if (len &lt; 1) {
++ UPAPDEBUG((&quot;pap_rauthack: ignoring missing msg-length.&quot;));
++ } else {
++ GETCHAR(msglen, inp);
++ if (msglen &gt; 0) {
++ len -= sizeof (u_char);
++ if (len &lt; msglen) {
++ UPAPDEBUG((&quot;pap_rauthack: rcvd short packet.&quot;));
++ return;
++ }
++ msg = (char *) inp;
++ PRINTMSG(msg, msglen);
++ }
++ }
++
++ u-&gt;us_clientstate = UPAPCS_OPEN;
++
++ auth_withpeer_success(u-&gt;us_unit, PPP_PAP);
++}
++
++
++/*
++ * upap_rauthnak - Receive Authenticate-Nakk.
++ */
++static void
++upap_rauthnak(u, inp, id, len)
++ upap_state *u;
++ u_char *inp;
++ int id;
++ int len;
++{
++ u_char msglen;
++ char *msg;
++
++ if (u-&gt;us_clientstate != UPAPCS_AUTHREQ) /* XXX */
++ return;
++
++ /*
++ * Parse message.
++ */
++ if (len &lt; 1) {
++ UPAPDEBUG((&quot;pap_rauthnak: ignoring missing msg-length.&quot;));
++ } else {
++ GETCHAR(msglen, inp);
++ if (msglen &gt; 0) {
++ len -= sizeof (u_char);
++ if (len &lt; msglen) {
++ UPAPDEBUG((&quot;pap_rauthnak: rcvd short packet.&quot;));
++ return;
++ }
++ msg = (char *) inp;
++ PRINTMSG(msg, msglen);
++ }
++ }
++
++ u-&gt;us_clientstate = UPAPCS_BADAUTH;
++
++ error(&quot;PAP authentication failed&quot;);
++ auth_withpeer_fail(u-&gt;us_unit, PPP_PAP);
++}
++
++
++/*
++ * upap_sauthreq - Send an Authenticate-Request.
++ */
++static void
++upap_sauthreq(u)
++ upap_state *u;
++{
++ u_char *outp;
++ int outlen;
++
++ outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) +
++ u-&gt;us_userlen + u-&gt;us_passwdlen;
++ outp = outpacket_buf;
++
++ MAKEHEADER(outp, PPP_PAP);
++
++ PUTCHAR(UPAP_AUTHREQ, outp);
++ PUTCHAR(++u-&gt;us_id, outp);
++ PUTSHORT(outlen, outp);
++ PUTCHAR(u-&gt;us_userlen, outp);
++ BCOPY(u-&gt;us_user, outp, u-&gt;us_userlen);
++ INCPTR(u-&gt;us_userlen, outp);
++ PUTCHAR(u-&gt;us_passwdlen, outp);
++ BCOPY(u-&gt;us_passwd, outp, u-&gt;us_passwdlen);
++
++ output(u-&gt;us_unit, outpacket_buf, outlen + PPP_HDRLEN);
++
++ TIMEOUT(upap_timeout, u, u-&gt;us_timeouttime);
++ ++u-&gt;us_transmits;
++ u-&gt;us_clientstate = UPAPCS_AUTHREQ;
++}
++
++
++/*
++ * upap_sresp - Send a response (ack or nak).
++ */
++static void
++upap_sresp(u, code, id, msg, msglen)
++ upap_state *u;
++ u_char code, id;
++ char *msg;
++ int msglen;
++{
++ u_char *outp;
++ int outlen;
++
++ outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
++ outp = outpacket_buf;
++ MAKEHEADER(outp, PPP_PAP);
++
++ PUTCHAR(code, outp);
++ PUTCHAR(id, outp);
++ PUTSHORT(outlen, outp);
++ PUTCHAR(msglen, outp);
++ BCOPY(msg, outp, msglen);
++ output(u-&gt;us_unit, outpacket_buf, outlen + PPP_HDRLEN);
++}
++
++/*
++ * upap_printpkt - print the contents of a PAP packet.
++ */
++static char *upap_codenames[] = {
++ &quot;AuthReq&quot;, &quot;AuthAck&quot;, &quot;AuthNak&quot;
++};
++
++static int
++upap_printpkt(p, plen, printer, arg)
++ u_char *p;
++ int plen;
++ void (*printer) __P((void *, char *, ...));
++ void *arg;
++{
++ int code, id, len;
++ int mlen, ulen, wlen;
++ char *user, *pwd, *msg;
++ u_char *pstart;
++
++ if (plen &lt; UPAP_HEADERLEN)
++ return 0;
++ pstart = p;
++ GETCHAR(code, p);
++ GETCHAR(id, p);
++ GETSHORT(len, p);
++ if (len &lt; UPAP_HEADERLEN || len &gt; plen)
++ return 0;
++
++ if (code &gt;= 1 &amp;&amp; code &lt;= sizeof(upap_codenames) / sizeof(char *))
++ printer(arg, &quot; %s&quot;, upap_codenames[code-1]);
++ else
++ printer(arg, &quot; code=0x%x&quot;, code);
++ printer(arg, &quot; id=0x%x&quot;, id);
++ len -= UPAP_HEADERLEN;
++ switch (code) {
++ case UPAP_AUTHREQ:
++ if (len &lt; 1)
++ break;
++ ulen = p[0];
++ if (len &lt; ulen + 2)
++ break;
++ wlen = p[ulen + 1];
++ if (len &lt; ulen + wlen + 2)
++ break;
++ user = (char *) (p + 1);
++ pwd = (char *) (p + ulen + 2);
++ p += ulen + wlen + 2;
++ len -= ulen + wlen + 2;
++ printer(arg, &quot; user=&quot;);
++ print_string(user, ulen, printer, arg);
++ printer(arg, &quot; password=&quot;);
++ if (!hide_password)
++ print_string(pwd, wlen, printer, arg);
++ else
++ printer(arg, &quot;&lt;hidden&gt;&quot;);
++ break;
++ case UPAP_AUTHACK:
++ case UPAP_AUTHNAK:
++ if (len &lt; 1)
++ break;
++ mlen = p[0];
++ if (len &lt; mlen + 1)
++ break;
++ msg = (char *) (p + 1);
++ p += mlen + 1;
++ len -= mlen + 1;
++ printer(arg, &quot; &quot;);
++ print_string(msg, mlen, printer, arg);
++ break;
++ }
++
++ /* print the rest of the bytes in the packet */
++ for (; len &gt; 0; --len) {
++ GETCHAR(code, p);
++ printer(arg, &quot; %.2x&quot;, code);
++ }
++
++ return p - pstart;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/upap.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/upap.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/upap.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/upap.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,87 @@
++/*
++ * upap.h - User/Password Authentication Protocol definitions.
++ *
++ * Copyright (c) 1989 Carnegie Mellon University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by Carnegie Mellon University. The name of the
++ * University may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * $Id: upap.h 195720 2001-06-11 11:44:34Z gc $
++ */
++
++/*
++ * Packet header = Code, id, length.
++ */
++#define UPAP_HEADERLEN 4
++
++
++/*
++ * UPAP codes.
++ */
++#define UPAP_AUTHREQ 1 /* Authenticate-Request */
++#define UPAP_AUTHACK 2 /* Authenticate-Ack */
++#define UPAP_AUTHNAK 3 /* Authenticate-Nak */
++
++
++/*
++ * Each interface is described by upap structure.
++ */
++typedef struct upap_state {
++ int us_unit; /* Interface unit number */
++ char *us_user; /* User */
++ int us_userlen; /* User length */
++ char *us_passwd; /* Password */
++ int us_passwdlen; /* Password length */
++ int us_clientstate; /* Client state */
++ int us_serverstate; /* Server state */
++ u_char us_id; /* Current id */
++ int us_timeouttime; /* Timeout (seconds) for auth-req retrans. */
++ int us_transmits; /* Number of auth-reqs sent */
++ int us_maxtransmits; /* Maximum number of auth-reqs to send */
++ int us_reqtimeout; /* Time to wait for auth-req from peer */
++} upap_state;
++
++
++/*
++ * Client states.
++ */
++#define UPAPCS_INITIAL 0 /* Connection down */
++#define UPAPCS_CLOSED 1 /* Connection up, haven't requested auth */
++#define UPAPCS_PENDING 2 /* Connection down, have requested auth */
++#define UPAPCS_AUTHREQ 3 /* We've sent an Authenticate-Request */
++#define UPAPCS_OPEN 4 /* We've received an Ack */
++#define UPAPCS_BADAUTH 5 /* We've received a Nak */
++
++/*
++ * Server states.
++ */
++#define UPAPSS_INITIAL 0 /* Connection down */
++#define UPAPSS_CLOSED 1 /* Connection up, haven't requested auth */
++#define UPAPSS_PENDING 2 /* Connection down, have requested auth */
++#define UPAPSS_LISTEN 3 /* Listening for an Authenticate */
++#define UPAPSS_OPEN 4 /* We've sent an Ack */
++#define UPAPSS_BADAUTH 5 /* We've sent a Nak */
++
++
++/*
++ * Timeouts.
++ */
++#define UPAP_DEFTIMEOUT 3 /* Timeout (seconds) for retransmitting req */
++#define UPAP_DEFREQTIME 30 /* Time to wait for auth-req from peer */
++
++extern upap_state upap[];
++
++void upap_authwithpeer __P((int, char *, char *));
++void upap_authpeer __P((int));
++
++extern struct protent pap_protent;
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/upap.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppd/utils.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppd/utils.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppd/utils.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,949 @@
++/*
++ * utils.c - various utility functions used in pppd.
++ *
++ * Copyright (c) 1999 The Australian National University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by the Australian National University. The name of the University
++ * may not be used to endorse or promote products derived from this
++ * software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ */
++
++#define RCSID &quot;$Id: utils.c 203596 2003-08-19 08:57:26Z gbeauchesne $&quot;
++
++#include &lt;stdio.h&gt;
++#include &lt;ctype.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;signal.h&gt;
++#include &lt;errno.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;syslog.h&gt;
++#include &lt;netdb.h&gt;
++#include &lt;utmp.h&gt;
++#include &lt;pwd.h&gt;
++#include &lt;sys/param.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/wait.h&gt;
++#include &lt;sys/time.h&gt;
++#include &lt;sys/resource.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;sys/socket.h&gt;
++#include &lt;netinet/in.h&gt;
++#ifdef SVR4
++#include &lt;sys/mkdev.h&gt;
++#endif
++
++#include &quot;pppd.h&quot;
++#include &lt;time.h&gt;
++
++static const char rcsid[] = RCSID;
++
++#if defined(SUNOS4)
++extern char *strerror();
++#endif
++
++static void logit __P((int, char *, va_list));
++static void log_write __P((int, char *));
++static void vslp_printer __P((void *, char *, ...));
++static void format_packet __P((u_char *, int, void (*) (void *, char *, ...),
++ void *));
++
++struct buffer_info {
++ char *ptr;
++ int len;
++};
++
++/*
++ * strlcpy - like strcpy/strncpy, doesn't overflow destination buffer,
++ * always leaves destination null-terminated (for len &gt; 0).
++ */
++size_t
++strlcpy(dest, src, len)
++ char *dest;
++ const char *src;
++ size_t len;
++{
++ size_t ret = strlen(src);
++
++ if (len != 0) {
++ if (ret &lt; len)
++ strcpy(dest, src);
++ else {
++ strncpy(dest, src, len - 1);
++ dest[len-1] = 0;
++ }
++ }
++ return ret;
++}
++
++/*
++ * strlcat - like strcat/strncat, doesn't overflow destination buffer,
++ * always leaves destination null-terminated (for len &gt; 0).
++ */
++size_t
++strlcat(dest, src, len)
++ char *dest;
++ const char *src;
++ size_t len;
++{
++ size_t dlen = strlen(dest);
++
++ return dlen + strlcpy(dest + dlen, src, (len &gt; dlen? len - dlen: 0));
++}
++
++
++/*
++ * slprintf - format a message into a buffer. Like sprintf except we
++ * also specify the length of the output buffer, and we handle
++ * %r (recursive format), %m (error message), %v (visible string),
++ * %q (quoted string), %t (current time) and %I (IP address) formats.
++ * Doesn't do floating-point formats.
++ * Returns the number of chars put into buf.
++ */
++int
++slprintf __V((char *buf, int buflen, char *fmt, ...))
++{
++ va_list args;
++ int n;
++
++#if defined(__STDC__)
++ va_start(args, fmt);
++#else
++ char *buf;
++ int buflen;
++ char *fmt;
++ va_start(args);
++ buf = va_arg(args, char *);
++ buflen = va_arg(args, int);
++ fmt = va_arg(args, char *);
++#endif
++ n = vslprintf(buf, buflen, fmt, args);
++ va_end(args);
++ return n;
++}
++
++/*
++ * vslprintf - like slprintf, takes a va_list instead of a list of args.
++ */
++#define OUTCHAR(c) (buflen &gt; 0? (--buflen, *buf++ = (c)): 0)
++
++int
++vslprintf(buf, buflen, fmt, args)
++ char *buf;
++ int buflen;
++ char *fmt;
++ va_list args;
++{
++ int c, i, n;
++ int width, prec, fillch;
++ int base, len, neg, quoted;
++ unsigned long val = 0;
++ char *str, *f, *buf0;
++ unsigned char *p;
++ char num[32];
++ time_t t;
++ u_int32_t ip;
++ static char hexchars[] = &quot;0123456789abcdef&quot;;
++ struct buffer_info bufinfo;
++
++ buf0 = buf;
++ --buflen;
++ while (buflen &gt; 0) {
++ for (f = fmt; *f != '%' &amp;&amp; *f != 0; ++f)
++ ;
++ if (f &gt; fmt) {
++ len = f - fmt;
++ if (len &gt; buflen)
++ len = buflen;
++ memcpy(buf, fmt, len);
++ buf += len;
++ buflen -= len;
++ fmt = f;
++ }
++ if (*fmt == 0)
++ break;
++ c = *++fmt;
++ width = 0;
++ prec = -1;
++ fillch = ' ';
++ if (c == '0') {
++ fillch = '0';
++ c = *++fmt;
++ }
++ if (c == '*') {
++ width = va_arg(args, int);
++ c = *++fmt;
++ } else {
++ while (isdigit(c)) {
++ width = width * 10 + c - '0';
++ c = *++fmt;
++ }
++ }
++ if (c == '.') {
++ c = *++fmt;
++ if (c == '*') {
++ prec = va_arg(args, int);
++ c = *++fmt;
++ } else {
++ prec = 0;
++ while (isdigit(c)) {
++ prec = prec * 10 + c - '0';
++ c = *++fmt;
++ }
++ }
++ }
++ str = 0;
++ base = 0;
++ neg = 0;
++ ++fmt;
++ switch (c) {
++ case 'd':
++ i = va_arg(args, int);
++ if (i &lt; 0) {
++ neg = 1;
++ val = -i;
++ } else
++ val = i;
++ base = 10;
++ break;
++ case 'u':
++ val = va_arg(args, unsigned int);
++ base = 10;
++ break;
++ case 'o':
++ val = va_arg(args, unsigned int);
++ base = 8;
++ break;
++ case 'x':
++ case 'X':
++ val = va_arg(args, unsigned int);
++ base = 16;
++ break;
++ case 'p':
++ val = (unsigned long) va_arg(args, void *);
++ base = 16;
++ neg = 2;
++ break;
++ case 's':
++ str = va_arg(args, char *);
++ break;
++ case 'c':
++ num[0] = va_arg(args, int);
++ num[1] = 0;
++ str = num;
++ break;
++ case 'm':
++ str = strerror(errno);
++ break;
++ case 'I':
++ ip = va_arg(args, u_int32_t);
++ ip = ntohl(ip);
++ slprintf(num, sizeof(num), &quot;%d.%d.%d.%d&quot;, (ip &gt;&gt; 24) &amp; 0xff,
++ (ip &gt;&gt; 16) &amp; 0xff, (ip &gt;&gt; 8) &amp; 0xff, ip &amp; 0xff);
++ str = num;
++ break;
++ case 'r':
++ f = va_arg(args, char *);
++#if !defined(__powerpc__) &amp;&amp; !defined(__x86_64__)
++ n = vslprintf(buf, buflen + 1, f, va_arg(args, va_list));
++#else
++ /* On the powerpc, a va_list is an array of 1 structure */
++ n = vslprintf(buf, buflen + 1, f, va_arg(args, void *));
++#endif
++ buf += n;
++ buflen -= n;
++ continue;
++ case 't':
++ time(&amp;t);
++ str = ctime(&amp;t);
++ str += 4; /* chop off the day name */
++ str[15] = 0; /* chop off year and newline */
++ break;
++ case 'v': /* &quot;visible&quot; string */
++ case 'q': /* quoted string */
++ quoted = c == 'q';
++ p = va_arg(args, unsigned char *);
++ if (fillch == '0' &amp;&amp; prec &gt;= 0) {
++ n = prec;
++ } else {
++ n = strlen((char *)p);
++ if (prec &gt;= 0 &amp;&amp; n &gt; prec)
++ n = prec;
++ }
++ while (n &gt; 0 &amp;&amp; buflen &gt; 0) {
++ c = *p++;
++ --n;
++ if (!quoted &amp;&amp; c &gt;= 0x80) {
++ OUTCHAR('M');
++ OUTCHAR('-');
++ c -= 0x80;
++ }
++ if (quoted &amp;&amp; (c == '&quot;' || c == '\\'))
++ OUTCHAR('\\');
++ if (c &lt; 0x20 || (0x7f &lt;= c &amp;&amp; c &lt; 0xa0)) {
++ if (quoted) {
++ OUTCHAR('\\');
++ switch (c) {
++ case '\t': OUTCHAR('t'); break;
++ case '\n': OUTCHAR('n'); break;
++ case '\b': OUTCHAR('b'); break;
++ case '\f': OUTCHAR('f'); break;
++ default:
++ OUTCHAR('x');
++ OUTCHAR(hexchars[c &gt;&gt; 4]);
++ OUTCHAR(hexchars[c &amp; 0xf]);
++ }
++ } else {
++ if (c == '\t')
++ OUTCHAR(c);
++ else {
++ OUTCHAR('^');
++ OUTCHAR(c ^ 0x40);
++ }
++ }
++ } else
++ OUTCHAR(c);
++ }
++ continue;
++ case 'P': /* print PPP packet */
++ bufinfo.ptr = buf;
++ bufinfo.len = buflen + 1;
++ p = va_arg(args, unsigned char *);
++ n = va_arg(args, int);
++ format_packet(p, n, vslp_printer, &amp;bufinfo);
++ buf = bufinfo.ptr;
++ buflen = bufinfo.len - 1;
++ continue;
++ case 'B':
++ p = va_arg(args, unsigned char *);
++ for (n = prec; n &gt; 0; --n) {
++ c = *p++;
++ if (fillch == ' ')
++ OUTCHAR(' ');
++ OUTCHAR(hexchars[(c &gt;&gt; 4) &amp; 0xf]);
++ OUTCHAR(hexchars[c &amp; 0xf]);
++ }
++ continue;
++ default:
++ *buf++ = '%';
++ if (c != '%')
++ --fmt; /* so %z outputs %z etc. */
++ --buflen;
++ continue;
++ }
++ if (base != 0) {
++ str = num + sizeof(num);
++ *--str = 0;
++ while (str &gt; num + neg) {
++ *--str = hexchars[val % base];
++ val = val / base;
++ if (--prec &lt;= 0 &amp;&amp; val == 0)
++ break;
++ }
++ switch (neg) {
++ case 1:
++ *--str = '-';
++ break;
++ case 2:
++ *--str = 'x';
++ *--str = '0';
++ break;
++ }
++ len = num + sizeof(num) - 1 - str;
++ } else {
++ len = strlen(str);
++ if (prec &gt;= 0 &amp;&amp; len &gt; prec)
++ len = prec;
++ }
++ if (width &gt; 0) {
++ if (width &gt; buflen)
++ width = buflen;
++ if ((n = width - len) &gt; 0) {
++ buflen -= n;
++ for (; n &gt; 0; --n)
++ *buf++ = fillch;
++ }
++ }
++ if (len &gt; buflen)
++ len = buflen;
++ memcpy(buf, str, len);
++ buf += len;
++ buflen -= len;
++ }
++ *buf = 0;
++ return buf - buf0;
++}
++
++/*
++ * vslp_printer - used in processing a %P format
++ */
++static void
++vslp_printer __V((void *arg, char *fmt, ...))
++{
++ int n;
++ va_list pvar;
++ struct buffer_info *bi;
++
++#if defined(__STDC__)
++ va_start(pvar, fmt);
++#else
++ void *arg;
++ char *fmt;
++ va_start(pvar);
++ arg = va_arg(pvar, void *);
++ fmt = va_arg(pvar, char *);
++#endif
++
++ bi = (struct buffer_info *) arg;
++ n = vslprintf(bi-&gt;ptr, bi-&gt;len, fmt, pvar);
++ va_end(pvar);
++
++ bi-&gt;ptr += n;
++ bi-&gt;len -= n;
++}
++
++#ifdef unused
++/*
++ * log_packet - format a packet and log it.
++ */
++
++void
++log_packet(p, len, prefix, level)
++ u_char *p;
++ int len;
++ char *prefix;
++ int level;
++{
++ init_pr_log(prefix, level);
++ format_packet(p, len, pr_log, &amp;level);
++ end_pr_log();
++}
++#endif /* unused */
++
++/*
++ * format_packet - make a readable representation of a packet,
++ * calling `printer(arg, format, ...)' to output it.
++ */
++static void
++format_packet(p, len, printer, arg)
++ u_char *p;
++ int len;
++ void (*printer) __P((void *, char *, ...));
++ void *arg;
++{
++ int i, n;
++ u_short proto;
++ struct protent *protp;
++
++ if (len &gt;= PPP_HDRLEN &amp;&amp; p[0] == PPP_ALLSTATIONS &amp;&amp; p[1] == PPP_UI) {
++ p += 2;
++ GETSHORT(proto, p);
++ len -= PPP_HDRLEN;
++ for (i = 0; (protp = protocols[i]) != NULL; ++i)
++ if (proto == protp-&gt;protocol)
++ break;
++ if (protp != NULL) {
++ printer(arg, &quot;[%s&quot;, protp-&gt;name);
++ n = (*protp-&gt;printpkt)(p, len, printer, arg);
++ printer(arg, &quot;]&quot;);
++ p += n;
++ len -= n;
++ } else {
++ for (i = 0; (protp = protocols[i]) != NULL; ++i)
++ if (proto == (protp-&gt;protocol &amp; ~0x8000))
++ break;
++ if (protp != 0 &amp;&amp; protp-&gt;data_name != 0) {
++ printer(arg, &quot;[%s data]&quot;, protp-&gt;data_name);
++ if (len &gt; 8)
++ printer(arg, &quot;%.8B ...&quot;, p);
++ else
++ printer(arg, &quot;%.*B&quot;, len, p);
++ len = 0;
++ } else
++ printer(arg, &quot;[proto=0x%x]&quot;, proto);
++ }
++ }
++
++ if (len &gt; 32)
++ printer(arg, &quot;%.32B ...&quot;, p);
++ else
++ printer(arg, &quot;%.*B&quot;, len, p);
++}
++
++/*
++ * init_pr_log, end_pr_log - initialize and finish use of pr_log.
++ */
++
++static char line[256]; /* line to be logged accumulated here */
++static char *linep; /* current pointer within line */
++static int llevel; /* level for logging */
++
++void
++init_pr_log(prefix, level)
++ char *prefix;
++ int level;
++{
++ linep = line;
++ if (prefix != NULL) {
++ strlcpy(line, prefix, sizeof(line));
++ linep = line + strlen(line);
++ }
++ llevel = level;
++}
++
++void
++end_pr_log()
++{
++ if (linep != line) {
++ *linep = 0;
++ log_write(llevel, line);
++ }
++}
++
++/*
++ * pr_log - printer routine for outputting to syslog
++ */
++void
++pr_log __V((void *arg, char *fmt, ...))
++{
++ int l, n;
++ va_list pvar;
++ char *p, *eol;
++ char buf[256];
++
++#if defined(__STDC__)
++ va_start(pvar, fmt);
++#else
++ void *arg;
++ char *fmt;
++ va_start(pvar);
++ arg = va_arg(pvar, void *);
++ fmt = va_arg(pvar, char *);
++#endif
++
++ n = vslprintf(buf, sizeof(buf), fmt, pvar);
++ va_end(pvar);
++
++ p = buf;
++ eol = strchr(buf, '\n');
++ if (linep != line) {
++ l = (eol == NULL)? n: eol - buf;
++ if (linep + l &lt; line + sizeof(line)) {
++ if (l &gt; 0) {
++ memcpy(linep, buf, l);
++ linep += l;
++ }
++ if (eol == NULL)
++ return;
++ p = eol + 1;
++ eol = strchr(p, '\n');
++ }
++ *linep = 0;
++ log_write(llevel, line);
++ linep = line;
++ }
++
++ while (eol != NULL) {
++ *eol = 0;
++ log_write(llevel, p);
++ p = eol + 1;
++ eol = strchr(p, '\n');
++ }
++
++ /* assumes sizeof(buf) &lt;= sizeof(line) */
++ l = buf + n - p;
++ if (l &gt; 0) {
++ memcpy(line, p, n);
++ linep = line + l;
++ }
++}
++
++/*
++ * print_string - print a readable representation of a string using
++ * printer.
++ */
++void
++print_string(p, len, printer, arg)
++ char *p;
++ int len;
++ void (*printer) __P((void *, char *, ...));
++ void *arg;
++{
++ int c;
++
++ printer(arg, &quot;\&quot;&quot;);
++ for (; len &gt; 0; --len) {
++ c = *p++;
++ if (' ' &lt;= c &amp;&amp; c &lt;= '~') {
++ if (c == '\\' || c == '&quot;')
++ printer(arg, &quot;\\&quot;);
++ printer(arg, &quot;%c&quot;, c);
++ } else {
++ switch (c) {
++ case '\n':
++ printer(arg, &quot;\\n&quot;);
++ break;
++ case '\r':
++ printer(arg, &quot;\\r&quot;);
++ break;
++ case '\t':
++ printer(arg, &quot;\\t&quot;);
++ break;
++ default:
++ printer(arg, &quot;\\%.3o&quot;, c);
++ }
++ }
++ }
++ printer(arg, &quot;\&quot;&quot;);
++}
++
++/*
++ * logit - does the hard work for fatal et al.
++ */
++static void
++logit(level, fmt, args)
++ int level;
++ char *fmt;
++ va_list args;
++{
++ int n;
++ char buf[1024];
++
++ n = vslprintf(buf, sizeof(buf), fmt, args);
++ log_write(level, buf);
++}
++
++static void
++log_write(level, buf)
++ int level;
++ char *buf;
++{
++ syslog(level, &quot;%s&quot;, buf);
++ if (log_to_fd &gt;= 0 &amp;&amp; (level != LOG_DEBUG || debug)) {
++ int n = strlen(buf);
++
++ if (n &gt; 0 &amp;&amp; buf[n-1] == '\n')
++ --n;
++ if (write(log_to_fd, buf, n) != n
++ || write(log_to_fd, &quot;\n&quot;, 1) != 1)
++ log_to_fd = -1;
++ }
++}
++
++/*
++ * fatal - log an error message and die horribly.
++ */
++void
++fatal __V((char *fmt, ...))
++{
++ va_list pvar;
++
++#if defined(__STDC__)
++ va_start(pvar, fmt);
++#else
++ char *fmt;
++ va_start(pvar);
++ fmt = va_arg(pvar, char *);
++#endif
++
++ logit(LOG_ERR, fmt, pvar);
++ va_end(pvar);
++
++ die(1); /* as promised */
++}
++
++/*
++ * error - log an error message.
++ */
++void
++error __V((char *fmt, ...))
++{
++ va_list pvar;
++
++#if defined(__STDC__)
++ va_start(pvar, fmt);
++#else
++ char *fmt;
++ va_start(pvar);
++ fmt = va_arg(pvar, char *);
++#endif
++
++ logit(LOG_ERR, fmt, pvar);
++ va_end(pvar);
++}
++
++/*
++ * warn - log a warning message.
++ */
++void
++warn __V((char *fmt, ...))
++{
++ va_list pvar;
++
++#if defined(__STDC__)
++ va_start(pvar, fmt);
++#else
++ char *fmt;
++ va_start(pvar);
++ fmt = va_arg(pvar, char *);
++#endif
++
++ logit(LOG_WARNING, fmt, pvar);
++ va_end(pvar);
++}
++
++/*
++ * notice - log a notice-level message.
++ */
++void
++notice __V((char *fmt, ...))
++{
++ va_list pvar;
++
++#if defined(__STDC__)
++ va_start(pvar, fmt);
++#else
++ char *fmt;
++ va_start(pvar);
++ fmt = va_arg(pvar, char *);
++#endif
++
++ logit(LOG_NOTICE, fmt, pvar);
++ va_end(pvar);
++}
++
++/*
++ * info - log an informational message.
++ */
++void
++info __V((char *fmt, ...))
++{
++ va_list pvar;
++
++#if defined(__STDC__)
++ va_start(pvar, fmt);
++#else
++ char *fmt;
++ va_start(pvar);
++ fmt = va_arg(pvar, char *);
++#endif
++
++ logit(LOG_INFO, fmt, pvar);
++ va_end(pvar);
++}
++
++/*
++ * dbglog - log a debug message.
++ */
++void
++dbglog __V((char *fmt, ...))
++{
++ va_list pvar;
++
++#if defined(__STDC__)
++ va_start(pvar, fmt);
++#else
++ char *fmt;
++ va_start(pvar);
++ fmt = va_arg(pvar, char *);
++#endif
++
++ logit(LOG_DEBUG, fmt, pvar);
++ va_end(pvar);
++}
++
++/* Procedures for locking the serial device using a lock file. */
++#ifndef LOCK_DIR
++#ifdef _linux_
++#define LOCK_DIR &quot;/var/lock&quot;
++#else
++#ifdef SVR4
++#define LOCK_DIR &quot;/var/spool/locks&quot;
++#else
++#define LOCK_DIR &quot;/var/spool/lock&quot;
++#endif
++#endif
++#endif /* LOCK_DIR */
++
++static char lock_file[MAXPATHLEN];
++
++/*
++ * lock - create a lock file for the named device
++ */
++int
++lock(dev)
++ char *dev;
++{
++#ifdef LOCKLIB
++ int result;
++
++ result = mklock (dev, (void *) 0);
++ if (result == 0) {
++ strlcpy(lock_file, sizeof(lock_file), dev);
++ return 0;
++ }
++
++ if (result &gt; 0)
++ notice(&quot;Device %s is locked by pid %d&quot;, dev, result);
++ else
++ error(&quot;Can't create lock file %s&quot;, lock_file);
++ return -1;
++
++#else /* LOCKLIB */
++
++ char lock_buffer[12];
++ int fd, pid, n;
++
++#ifdef SVR4
++ struct stat sbuf;
++
++ if (stat(dev, &amp;sbuf) &lt; 0) {
++ error(&quot;Can't get device number for %s: %m&quot;, dev);
++ return -1;
++ }
++ if ((sbuf.st_mode &amp; S_IFMT) != S_IFCHR) {
++ error(&quot;Can't lock %s: not a character device&quot;, dev);
++ return -1;
++ }
++ slprintf(lock_file, sizeof(lock_file), &quot;%s/LK.%03d.%03d.%03d&quot;,
++ LOCK_DIR, major(sbuf.st_dev),
++ major(sbuf.st_rdev), minor(sbuf.st_rdev));
++#else
++ char *p;
++
++ if ((p = strrchr(dev, '/')) != NULL)
++ dev = p + 1;
++ slprintf(lock_file, sizeof(lock_file), &quot;%s/LCK..%s&quot;, LOCK_DIR, dev);
++#endif
++
++ while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) &lt; 0) {
++ if (errno != EEXIST) {
++ error(&quot;Can't create lock file %s: %m&quot;, lock_file);
++ break;
++ }
++
++ /* Read the lock file to find out who has the device locked. */
++ fd = open(lock_file, O_RDONLY, 0);
++ if (fd &lt; 0) {
++ if (errno == ENOENT) /* This is just a timing problem. */
++ continue;
++ error(&quot;Can't open existing lock file %s: %m&quot;, lock_file);
++ break;
++ }
++#ifndef LOCK_BINARY
++ n = read(fd, lock_buffer, 11);
++#else
++ n = read(fd, &amp;pid, sizeof(pid));
++#endif /* LOCK_BINARY */
++ close(fd);
++ fd = -1;
++ if (n &lt;= 0) {
++ error(&quot;Can't read pid from lock file %s&quot;, lock_file);
++ break;
++ }
++
++ /* See if the process still exists. */
++#ifndef LOCK_BINARY
++ lock_buffer[n] = 0;
++ pid = atoi(lock_buffer);
++#endif /* LOCK_BINARY */
++ if (pid == getpid())
++ return 1; /* somebody else locked it for us */
++ if (pid == 0
++ || (kill(pid, 0) == -1 &amp;&amp; errno == ESRCH)) {
++ if (unlink (lock_file) == 0) {
++ notice(&quot;Removed stale lock on %s (pid %d)&quot;, dev, pid);
++ continue;
++ }
++ warn(&quot;Couldn't remove stale lock on %s&quot;, dev);
++ } else
++ notice(&quot;Device %s is locked by pid %d&quot;, dev, pid);
++ break;
++ }
++
++ if (fd &lt; 0) {
++ lock_file[0] = 0;
++ return -1;
++ }
++
++ pid = getpid();
++#ifndef LOCK_BINARY
++ slprintf(lock_buffer, sizeof(lock_buffer), &quot;%10d\n&quot;, pid);
++ write (fd, lock_buffer, 11);
++#else
++ write(fd, &amp;pid, sizeof (pid));
++#endif
++ close(fd);
++ return 0;
++
++#endif
++}
++
++/*
++ * relock - called to update our lockfile when we are about to detach,
++ * thus changing our pid (we fork, the child carries on, and the parent dies).
++ * Note that this is called by the parent, with pid equal to the pid
++ * of the child. This avoids a potential race which would exist if
++ * we had the child rewrite the lockfile (the parent might die first,
++ * and another process could think the lock was stale if it checked
++ * between when the parent died and the child rewrote the lockfile).
++ */
++int
++relock(pid)
++ int pid;
++{
++#ifdef LOCKLIB
++ /* XXX is there a way to do this? */
++ return -1;
++#else /* LOCKLIB */
++
++ int fd;
++ char lock_buffer[12];
++
++ if (lock_file[0] == 0)
++ return -1;
++ fd = open(lock_file, O_WRONLY, 0);
++ if (fd &lt; 0) {
++ error(&quot;Couldn't reopen lock file %s: %m&quot;, lock_file);
++ lock_file[0] = 0;
++ return -1;
++ }
++
++#ifndef LOCK_BINARY
++ slprintf(lock_buffer, sizeof(lock_buffer), &quot;%10d\n&quot;, pid);
++ write (fd, lock_buffer, 11);
++#else
++ write(fd, &amp;pid, sizeof(pid));
++#endif /* LOCK_BINARY */
++ close(fd);
++ return 0;
++
++#endif /* LOCKLIB */
++}
++
++/*
++ * unlock - remove our lockfile
++ */
++void
++unlock()
++{
++ if (lock_file[0]) {
++#ifdef LOCKLIB
++ (void) rmlock(lock_file, (void *) 0);
++#else
++ unlink(lock_file);
++#endif
++ lock_file[0] = 0;
++ }
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppd/utils.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppdump/Makefile.linux
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppdump/Makefile.linux (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppdump/Makefile.linux 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,17 @@
++CFLAGS= -I../include/net $(RPM_OPT_FLAGS)
++OBJS = pppdump.o bsd-comp.o deflate.o zlib.o
++
++INSTALL= install
++
++all: pppdump
++
++pppdump: $(OBJS)
++ $(CC) $(RPM_OPT_FLAGS) -o pppdump $(OBJS)
++
++clean:
++ rm -f pppdump $(OBJS) *~
++
++install:
++ mkdir -p $(BINDIR) $(MANDIR)/man8
++ $(INSTALL) -s -c pppdump $(BINDIR)
++ $(INSTALL) -c pppdump.8 $(MANDIR)/man8
+
+Added: drakx/trunk/mdk-stage1/ppp/pppdump/Makefile.linux.makeopt
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppdump/Makefile.linux.makeopt (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppdump/Makefile.linux.makeopt 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,17 @@
++CFLAGS= -O -I../include/net
++OBJS = pppdump.o bsd-comp.o deflate.o zlib.o
++
++INSTALL= install
++
++all: pppdump
++
++pppdump: $(OBJS)
++ $(CC) -o pppdump $(OBJS)
++
++clean:
++ rm -f pppdump $(OBJS) *~
++
++install:
++ mkdir -p $(BINDIR) $(MANDIR)/man8
++ $(INSTALL) -s -c pppdump $(BINDIR)
++ $(INSTALL) -c -m 444 pppdump.8 $(MANDIR)/man8
+
+Added: drakx/trunk/mdk-stage1/ppp/pppdump/Makefile.linux.pppdump-Makefile
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppdump/Makefile.linux.pppdump-Makefile (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppdump/Makefile.linux.pppdump-Makefile 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,17 @@
++CFLAGS= -O -I../include/net
++OBJS = pppdump.o bsd-comp.o deflate.o zlib.o
++
++INSTALL= install
++
++all: pppdump
++
++pppdump: $(OBJS)
++ $(CC) $(RPM_OPT_FLAGS) -o pppdump $(OBJS)
++
++clean:
++ rm -f pppdump $(OBJS) *~
++
++install:
++ mkdir -p $(BINDIR) $(MANDIR)/man8
++ $(INSTALL) -s -c pppdump $(BINDIR)
++ $(INSTALL) -c -m 444 pppdump.8 $(MANDIR)/man8
+
+Added: drakx/trunk/mdk-stage1/ppp/pppdump/Makefile.sol2
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppdump/Makefile.sol2 (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppdump/Makefile.sol2 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,21 @@
++#
++# pppdump Makefile for SVR4 systems
++# $Id: Makefile.sol2 195720 2001-06-11 11:44:34Z gc $
++#
++
++include ../solaris/Makedefs
++
++CFLAGS= $(COPTS) -I../include/net
++OBJS = pppdump.o bsd-comp.o deflate.o zlib.o
++
++all: pppdump
++
++pppdump: $(OBJS)
++ $(CC) -o pppdump $(OBJS)
++
++clean:
++ rm -f $(OBJS) pppdump *~
++
++install:
++ $(INSTALL) -f $(BINDIR) pppdump
++ $(INSTALL) -m 444 -f $(MANDIR)/man8 pppdump.8
+
+Added: drakx/trunk/mdk-stage1/ppp/pppdump/Makefile.sunos4
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppdump/Makefile.sunos4 (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppdump/Makefile.sunos4 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,21 @@
++#
++# pppstats makefile
++# $Id: Makefile.sunos4 195720 2001-06-11 11:44:34Z gc $
++#
++
++include ../sunos4/Makedefs
++
++OBJS = pppdump.o bsd-comp.o deflate.o zlib.o
++CFLAGS = $(COPTS) -I../include/net
++
++all: pppdump
++
++pppdump: $(OBJS)
++ $(CC) -o pppdump $(OBJS)
++
++clean:
++ rm -f pppdump $(OBJS) *~
++
++install: pppdump
++ $(INSTALL) -c pppdump $(BINDIR)/pppdump
++ $(INSTALL) -c -m 444 pppdump.8 $(MANDIR)/man8/pppdump.8
+
+Added: drakx/trunk/mdk-stage1/ppp/pppdump/bsd-comp.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppdump/bsd-comp.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppdump/bsd-comp.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,750 @@
++/* Because this code is derived from the 4.3BSD compress source:
++ *
++ *
++ * Copyright (c) 1985, 1986 The Regents of the University of California.
++ * All rights reserved.
++ *
++ * This code is derived from software contributed to Berkeley by
++ * James A. Woods, derived from original work by Spencer Thomas
++ * and Joseph Orost.
++ *
++ * 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.
++ */
++
++/*
++ * $Id: bsd-comp.c 195720 2001-06-11 11:44:34Z gc $
++ */
++
++#include &lt;sys/types.h&gt;
++#include &lt;stddef.h&gt;
++#include &lt;stdlib.h&gt;
++#include &quot;ppp_defs.h&quot;
++#include &quot;ppp-comp.h&quot;
++
++#if DO_BSD_COMPRESS
++
++/*
++ * PPP &quot;BSD compress&quot; compression
++ * The differences between this compression and the classic BSD LZW
++ * source are obvious from the requirement that the classic code worked
++ * with files while this handles arbitrarily long streams that
++ * are broken into packets. They are:
++ *
++ * When the code size expands, a block of junk is not emitted by
++ * the compressor and not expected by the decompressor.
++ *
++ * New codes are not necessarily assigned every time an old
++ * code is output by the compressor. This is because a packet
++ * end forces a code to be emitted, but does not imply that a
++ * new sequence has been seen.
++ *
++ * The compression ratio is checked at the first end of a packet
++ * after the appropriate gap. Besides simplifying and speeding
++ * things up, this makes it more likely that the transmitter
++ * and receiver will agree when the dictionary is cleared when
++ * compression is not going well.
++ */
++
++/*
++ * A dictionary for doing BSD compress.
++ */
++struct bsd_db {
++ int totlen; /* length of this structure */
++ u_int hsize; /* size of the hash table */
++ u_char hshift; /* used in hash function */
++ u_char n_bits; /* current bits/code */
++ u_char maxbits;
++ u_char debug;
++ u_char unit;
++ u_short seqno; /* sequence number of next packet */
++ u_int hdrlen; /* header length to preallocate */
++ u_int mru;
++ u_int maxmaxcode; /* largest valid code */
++ u_int max_ent; /* largest code in use */
++ u_int in_count; /* uncompressed bytes, aged */
++ u_int bytes_out; /* compressed bytes, aged */
++ u_int ratio; /* recent compression ratio */
++ u_int checkpoint; /* when to next check the ratio */
++ u_int clear_count; /* times dictionary cleared */
++ u_int incomp_count; /* incompressible packets */
++ u_int incomp_bytes; /* incompressible bytes */
++ u_int uncomp_count; /* uncompressed packets */
++ u_int uncomp_bytes; /* uncompressed bytes */
++ u_int comp_count; /* compressed packets */
++ u_int comp_bytes; /* compressed bytes */
++ u_short *lens; /* array of lengths of codes */
++ struct bsd_dict {
++ union { /* hash value */
++ u_int32_t fcode;
++ struct {
++#ifdef BSD_LITTLE_ENDIAN
++ u_short prefix; /* preceding code */
++ u_char suffix; /* last character of new code */
++ u_char pad;
++#else
++ u_char pad;
++ u_char suffix; /* last character of new code */
++ u_short prefix; /* preceding code */
++#endif
++ } hs;
++ } f;
++ u_short codem1; /* output of hash table -1 */
++ u_short cptr; /* map code to hash table entry */
++ } dict[1];
++};
++
++#define BSD_OVHD 2 /* BSD compress overhead/packet */
++#define BSD_INIT_BITS BSD_MIN_BITS
++
++static void *bsd_decomp_alloc __P((u_char *options, int opt_len));
++static void bsd_free __P((void *state));
++static int bsd_decomp_init __P((void *state, u_char *options, int opt_len,
++ int unit, int hdrlen, int mru, int debug));
++static void bsd_incomp __P((void *state, u_char *dmsg, int len));
++static int bsd_decompress __P((void *state, u_char *cmp, int inlen,
++ u_char *dmp, int *outlen));
++static void bsd_reset __P((void *state));
++static void bsd_comp_stats __P((void *state, struct compstat *stats));
++
++/*
++ * Exported procedures.
++ */
++struct compressor ppp_bsd_compress = {
++ CI_BSD_COMPRESS, /* compress_proto */
++ bsd_decomp_alloc, /* decomp_alloc */
++ bsd_free, /* decomp_free */
++ bsd_decomp_init, /* decomp_init */
++ bsd_reset, /* decomp_reset */
++ bsd_decompress, /* decompress */
++ bsd_incomp, /* incomp */
++ bsd_comp_stats, /* decomp_stat */
++};
++
++/*
++ * the next two codes should not be changed lightly, as they must not
++ * lie within the contiguous general code space.
++ */
++#define CLEAR 256 /* table clear output code */
++#define FIRST 257 /* first free entry */
++#define LAST 255
++
++#define MAXCODE(b) ((1 &lt;&lt; (b)) - 1)
++#define BADCODEM1 MAXCODE(BSD_MAX_BITS)
++
++#define BSD_HASH(prefix,suffix,hshift) ((((u_int32_t)(suffix)) &lt;&lt; (hshift)) \
++ ^ (u_int32_t)(prefix))
++#define BSD_KEY(prefix,suffix) ((((u_int32_t)(suffix)) &lt;&lt; 16) \
++ + (u_int32_t)(prefix))
++
++#define CHECK_GAP 10000 /* Ratio check interval */
++
++#define RATIO_SCALE_LOG 8
++#define RATIO_SCALE (1&lt;&lt;RATIO_SCALE_LOG)
++#define RATIO_MAX (0x7fffffff&gt;&gt;RATIO_SCALE_LOG)
++
++/*
++ * clear the dictionary
++ */
++static void
++bsd_clear(db)
++ struct bsd_db *db;
++{
++ db-&gt;clear_count++;
++ db-&gt;max_ent = FIRST-1;
++ db-&gt;n_bits = BSD_INIT_BITS;
++ db-&gt;ratio = 0;
++ db-&gt;bytes_out = 0;
++ db-&gt;in_count = 0;
++ db-&gt;checkpoint = CHECK_GAP;
++}
++
++/*
++ * If the dictionary is full, then see if it is time to reset it.
++ *
++ * Compute the compression ratio using fixed-point arithmetic
++ * with 8 fractional bits.
++ *
++ * Since we have an infinite stream instead of a single file,
++ * watch only the local compression ratio.
++ *
++ * Since both peers must reset the dictionary at the same time even in
++ * the absence of CLEAR codes (while packets are incompressible), they
++ * must compute the same ratio.
++ */
++static int /* 1=output CLEAR */
++bsd_check(db)
++ struct bsd_db *db;
++{
++ u_int new_ratio;
++
++ if (db-&gt;in_count &gt;= db-&gt;checkpoint) {
++ /* age the ratio by limiting the size of the counts */
++ if (db-&gt;in_count &gt;= RATIO_MAX
++ || db-&gt;bytes_out &gt;= RATIO_MAX) {
++ db-&gt;in_count -= db-&gt;in_count/4;
++ db-&gt;bytes_out -= db-&gt;bytes_out/4;
++ }
++
++ db-&gt;checkpoint = db-&gt;in_count + CHECK_GAP;
++
++ if (db-&gt;max_ent &gt;= db-&gt;maxmaxcode) {
++ /* Reset the dictionary only if the ratio is worse,
++ * or if it looks as if it has been poisoned
++ * by incompressible data.
++ *
++ * This does not overflow, because
++ * db-&gt;in_count &lt;= RATIO_MAX.
++ */
++ new_ratio = db-&gt;in_count &lt;&lt; RATIO_SCALE_LOG;
++ if (db-&gt;bytes_out != 0)
++ new_ratio /= db-&gt;bytes_out;
++
++ if (new_ratio &lt; db-&gt;ratio || new_ratio &lt; 1 * RATIO_SCALE) {
++ bsd_clear(db);
++ return 1;
++ }
++ db-&gt;ratio = new_ratio;
++ }
++ }
++ return 0;
++}
++
++/*
++ * Return statistics.
++ */
++static void
++bsd_comp_stats(state, stats)
++ void *state;
++ struct compstat *stats;
++{
++ struct bsd_db *db = (struct bsd_db *) state;
++ u_int out;
++
++ stats-&gt;unc_bytes = db-&gt;uncomp_bytes;
++ stats-&gt;unc_packets = db-&gt;uncomp_count;
++ stats-&gt;comp_bytes = db-&gt;comp_bytes;
++ stats-&gt;comp_packets = db-&gt;comp_count;
++ stats-&gt;inc_bytes = db-&gt;incomp_bytes;
++ stats-&gt;inc_packets = db-&gt;incomp_count;
++ stats-&gt;ratio = db-&gt;in_count;
++ out = db-&gt;bytes_out;
++ if (stats-&gt;ratio &lt;= 0x7fffff)
++ stats-&gt;ratio &lt;&lt;= 8;
++ else
++ out &gt;&gt;= 8;
++ if (out != 0)
++ stats-&gt;ratio /= out;
++}
++
++/*
++ * Reset state, as on a CCP ResetReq.
++ */
++static void
++bsd_reset(state)
++ void *state;
++{
++ struct bsd_db *db = (struct bsd_db *) state;
++
++ db-&gt;seqno = 0;
++ bsd_clear(db);
++ db-&gt;clear_count = 0;
++}
++
++/*
++ * Allocate space for a (de) compressor.
++ */
++static void *
++bsd_alloc(options, opt_len, decomp)
++ u_char *options;
++ int opt_len, decomp;
++{
++ int bits;
++ u_int newlen, hsize, hshift, maxmaxcode;
++ struct bsd_db *db;
++
++ if (opt_len != 3 || options[0] != CI_BSD_COMPRESS || options[1] != 3
++ || BSD_VERSION(options[2]) != BSD_CURRENT_VERSION)
++ return NULL;
++
++ bits = BSD_NBITS(options[2]);
++ switch (bits) {
++ case 9: /* needs 82152 for both directions */
++ case 10: /* needs 84144 */
++ case 11: /* needs 88240 */
++ case 12: /* needs 96432 */
++ hsize = 5003;
++ hshift = 4;
++ break;
++ case 13: /* needs 176784 */
++ hsize = 9001;
++ hshift = 5;
++ break;
++ case 14: /* needs 353744 */
++ hsize = 18013;
++ hshift = 6;
++ break;
++ case 15: /* needs 691440 */
++ hsize = 35023;
++ hshift = 7;
++ break;
++ case 16: /* needs 1366160--far too much, */
++ /* hsize = 69001; */ /* and 69001 is too big for cptr */
++ /* hshift = 8; */ /* in struct bsd_db */
++ /* break; */
++ default:
++ return NULL;
++ }
++
++ maxmaxcode = MAXCODE(bits);
++ newlen = sizeof(*db) + (hsize-1) * (sizeof(db-&gt;dict[0]));
++ db = (struct bsd_db *) malloc(newlen);
++ if (!db)
++ return NULL;
++ memset(db, 0, sizeof(*db) - sizeof(db-&gt;dict));
++
++ if (!decomp) {
++ db-&gt;lens = NULL;
++ } else {
++ db-&gt;lens = (u_short *) malloc((maxmaxcode+1) * sizeof(db-&gt;lens[0]));
++ if (!db-&gt;lens) {
++ free(db);
++ return NULL;
++ }
++ }
++
++ db-&gt;totlen = newlen;
++ db-&gt;hsize = hsize;
++ db-&gt;hshift = hshift;
++ db-&gt;maxmaxcode = maxmaxcode;
++ db-&gt;maxbits = bits;
++
++ return (void *) db;
++}
++
++static void
++bsd_free(state)
++ void *state;
++{
++ struct bsd_db *db = (struct bsd_db *) state;
++
++ if (db-&gt;lens)
++ free(db-&gt;lens);
++ free(db);
++}
++
++static void *
++bsd_decomp_alloc(options, opt_len)
++ u_char *options;
++ int opt_len;
++{
++ return bsd_alloc(options, opt_len, 1);
++}
++
++/*
++ * Initialize the database.
++ */
++static int
++bsd_init(db, options, opt_len, unit, hdrlen, mru, debug, decomp)
++ struct bsd_db *db;
++ u_char *options;
++ int opt_len, unit, hdrlen, mru, debug, decomp;
++{
++ int i;
++
++ if (opt_len &lt; CILEN_BSD_COMPRESS
++ || options[0] != CI_BSD_COMPRESS || options[1] != CILEN_BSD_COMPRESS
++ || BSD_VERSION(options[2]) != BSD_CURRENT_VERSION
++ || BSD_NBITS(options[2]) != db-&gt;maxbits
++ || decomp &amp;&amp; db-&gt;lens == NULL)
++ return 0;
++
++ if (decomp) {
++ i = LAST+1;
++ while (i != 0)
++ db-&gt;lens[--i] = 1;
++ }
++ i = db-&gt;hsize;
++ while (i != 0) {
++ db-&gt;dict[--i].codem1 = BADCODEM1;
++ db-&gt;dict[i].cptr = 0;
++ }
++
++ db-&gt;unit = unit;
++ db-&gt;hdrlen = hdrlen;
++ db-&gt;mru = mru;
++ if (debug)
++ db-&gt;debug = 1;
++
++ bsd_reset(db);
++
++ return 1;
++}
++
++static int
++bsd_decomp_init(state, options, opt_len, unit, hdrlen, mru, debug)
++ void *state;
++ u_char *options;
++ int opt_len, unit, hdrlen, mru, debug;
++{
++ return bsd_init((struct bsd_db *) state, options, opt_len,
++ unit, hdrlen, mru, debug, 1);
++}
++
++
++/*
++ * Update the &quot;BSD Compress&quot; dictionary on the receiver for
++ * incompressible data by pretending to compress the incoming data.
++ */
++static void
++bsd_incomp(state, dmsg, mlen)
++ void *state;
++ u_char *dmsg;
++ int mlen;
++{
++ struct bsd_db *db = (struct bsd_db *) state;
++ u_int hshift = db-&gt;hshift;
++ u_int max_ent = db-&gt;max_ent;
++ u_int n_bits = db-&gt;n_bits;
++ struct bsd_dict *dictp;
++ u_int32_t fcode;
++ u_char c;
++ long hval, disp;
++ int slen, ilen;
++ u_int bitno = 7;
++ u_char *rptr;
++ u_int ent;
++
++ rptr = dmsg;
++ ent = rptr[0]; /* get the protocol */
++ if (ent == 0) {
++ ++rptr;
++ --mlen;
++ ent = rptr[0];
++ }
++ if ((ent &amp; 1) == 0 || ent &lt; 0x21 || ent &gt; 0xf9)
++ return;
++
++ db-&gt;seqno++;
++ ilen = 1; /* count the protocol as 1 byte */
++ ++rptr;
++ slen = dmsg + mlen - rptr;
++ ilen += slen;
++ for (; slen &gt; 0; --slen) {
++ c = *rptr++;
++ fcode = BSD_KEY(ent, c);
++ hval = BSD_HASH(ent, c, hshift);
++ dictp = &amp;db-&gt;dict[hval];
++
++ /* validate and then check the entry */
++ if (dictp-&gt;codem1 &gt;= max_ent)
++ goto nomatch;
++ if (dictp-&gt;f.fcode == fcode) {
++ ent = dictp-&gt;codem1+1;
++ continue; /* found (prefix,suffix) */
++ }
++
++ /* continue probing until a match or invalid entry */
++ disp = (hval == 0) ? 1 : hval;
++ do {
++ hval += disp;
++ if (hval &gt;= db-&gt;hsize)
++ hval -= db-&gt;hsize;
++ dictp = &amp;db-&gt;dict[hval];
++ if (dictp-&gt;codem1 &gt;= max_ent)
++ goto nomatch;
++ } while (dictp-&gt;f.fcode != fcode);
++ ent = dictp-&gt;codem1+1;
++ continue; /* finally found (prefix,suffix) */
++
++ nomatch: /* output (count) the prefix */
++ bitno += n_bits;
++
++ /* code -&gt; hashtable */
++ if (max_ent &lt; db-&gt;maxmaxcode) {
++ struct bsd_dict *dictp2;
++ /* expand code size if needed */
++ if (max_ent &gt;= MAXCODE(n_bits))
++ db-&gt;n_bits = ++n_bits;
++
++ /* Invalidate previous hash table entry
++ * assigned this code, and then take it over.
++ */
++ dictp2 = &amp;db-&gt;dict[max_ent+1];
++ if (db-&gt;dict[dictp2-&gt;cptr].codem1 == max_ent)
++ db-&gt;dict[dictp2-&gt;cptr].codem1 = BADCODEM1;
++ dictp2-&gt;cptr = hval;
++ dictp-&gt;codem1 = max_ent;
++ dictp-&gt;f.fcode = fcode;
++
++ db-&gt;max_ent = ++max_ent;
++ db-&gt;lens[max_ent] = db-&gt;lens[ent]+1;
++ }
++ ent = c;
++ }
++ bitno += n_bits; /* output (count) the last code */
++ db-&gt;bytes_out += bitno/8;
++ db-&gt;in_count += ilen;
++ (void)bsd_check(db);
++
++ ++db-&gt;incomp_count;
++ db-&gt;incomp_bytes += ilen;
++ ++db-&gt;uncomp_count;
++ db-&gt;uncomp_bytes += ilen;
++
++ /* Increase code size if we would have without the packet
++ * boundary and as the decompressor will.
++ */
++ if (max_ent &gt;= MAXCODE(n_bits) &amp;&amp; max_ent &lt; db-&gt;maxmaxcode)
++ db-&gt;n_bits++;
++}
++
++
++/*
++ * Decompress &quot;BSD Compress&quot;
++ *
++ * Because of patent problems, we return DECOMP_ERROR for errors
++ * found by inspecting the input data and for system problems, but
++ * DECOMP_FATALERROR for any errors which could possibly be said to
++ * be being detected &quot;after&quot; decompression. For DECOMP_ERROR,
++ * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
++ * infringing a patent of Motorola's if we do, so we take CCP down
++ * instead.
++ *
++ * Given that the frame has the correct sequence number and a good FCS,
++ * errors such as invalid codes in the input most likely indicate a
++ * bug, so we return DECOMP_FATALERROR for them in order to turn off
++ * compression, even though they are detected by inspecting the input.
++ */
++static int
++bsd_decompress(state, cmsg, inlen, dmp, outlenp)
++ void *state;
++ u_char *cmsg, *dmp;
++ int inlen, *outlenp;
++{
++ struct bsd_db *db = (struct bsd_db *) state;
++ u_int max_ent = db-&gt;max_ent;
++ u_int32_t accm = 0;
++ u_int bitno = 32; /* 1st valid bit in accm */
++ u_int n_bits = db-&gt;n_bits;
++ u_int tgtbitno = 32-n_bits; /* bitno when we have a code */
++ struct bsd_dict *dictp;
++ int explen, i, seq, len;
++ u_int incode, oldcode, finchar;
++ u_char *p, *rptr, *wptr;
++ int ilen;
++ int dlen, space, codelen, extra;
++
++ rptr = cmsg;
++ if (*rptr == 0)
++ ++rptr;
++ ++rptr; /* skip protocol (assumed 0xfd) */
++ seq = (rptr[0] &lt;&lt; 8) + rptr[1];
++ rptr += BSD_OVHD;
++ ilen = len = cmsg + inlen - rptr;
++
++ /*
++ * Check the sequence number and give up if it is not what we expect.
++ */
++ if (seq != db-&gt;seqno++) {
++ if (db-&gt;debug)
++ printf(&quot;bsd_decomp%d: bad sequence # %d, expected %d\n&quot;,
++ db-&gt;unit, seq, db-&gt;seqno - 1);
++ return DECOMP_ERROR;
++ }
++
++ wptr = dmp + db-&gt;hdrlen;
++
++ oldcode = CLEAR;
++ explen = 0;
++ while (len &gt; 0) {
++ /*
++ * Accumulate bytes until we have a complete code.
++ * Then get the next code, relying on the 32-bit,
++ * unsigned accm to mask the result.
++ */
++ bitno -= 8;
++ accm |= *rptr++ &lt;&lt; bitno;
++ --len;
++ if (tgtbitno &lt; bitno)
++ continue;
++ incode = accm &gt;&gt; tgtbitno;
++ accm &lt;&lt;= n_bits;
++ bitno += n_bits;
++
++ if (incode == CLEAR) {
++ /*
++ * The dictionary must only be cleared at
++ * the end of a packet. But there could be an
++ * empty message block at the end.
++ */
++ if (len &gt; 0) {
++ if (db-&gt;debug)
++ printf(&quot;bsd_decomp%d: bad CLEAR\n&quot;, db-&gt;unit);
++ return DECOMP_FATALERROR;
++ }
++ bsd_clear(db);
++ explen = ilen = 0;
++ break;
++ }
++
++ if (incode &gt; max_ent + 2 || incode &gt; db-&gt;maxmaxcode
++ || incode &gt; max_ent &amp;&amp; oldcode == CLEAR) {
++ if (db-&gt;debug) {
++ printf(&quot;bsd_decomp%d: bad code 0x%x oldcode=0x%x &quot;,
++ db-&gt;unit, incode, oldcode);
++ printf(&quot;max_ent=0x%x dlen=%d seqno=%d\n&quot;,
++ max_ent, dlen, db-&gt;seqno);
++ }
++ return DECOMP_FATALERROR; /* probably a bug */
++ }
++
++ /* Special case for KwKwK string. */
++ if (incode &gt; max_ent) {
++ finchar = oldcode;
++ extra = 1;
++ } else {
++ finchar = incode;
++ extra = 0;
++ }
++
++ codelen = db-&gt;lens[finchar];
++ explen += codelen + extra;
++ if (explen &gt; db-&gt;mru + 1) {
++ if (db-&gt;debug)
++ printf(&quot;bsd_decomp%d: ran out of mru\n&quot;, db-&gt;unit);
++ return DECOMP_FATALERROR;
++ }
++
++ /*
++ * Decode this code and install it in the decompressed buffer.
++ */
++ p = (wptr += codelen);
++ while (finchar &gt; LAST) {
++ dictp = &amp;db-&gt;dict[db-&gt;dict[finchar].cptr];
++#ifdef DEBUG
++ --codelen;
++ if (codelen &lt;= 0) {
++ printf(&quot;bsd_decomp%d: fell off end of chain &quot;, db-&gt;unit);
++ printf(&quot;0x%x at 0x%x by 0x%x, max_ent=0x%x\n&quot;,
++ incode, finchar, db-&gt;dict[finchar].cptr, max_ent);
++ return DECOMP_FATALERROR;
++ }
++ if (dictp-&gt;codem1 != finchar-1) {
++ printf(&quot;bsd_decomp%d: bad code chain 0x%x finchar=0x%x &quot;,
++ db-&gt;unit, incode, finchar);
++ printf(&quot;oldcode=0x%x cptr=0x%x codem1=0x%x\n&quot;, oldcode,
++ db-&gt;dict[finchar].cptr, dictp-&gt;codem1);
++ return DECOMP_FATALERROR;
++ }
++#endif
++ *--p = dictp-&gt;f.hs.suffix;
++ finchar = dictp-&gt;f.hs.prefix;
++ }
++ *--p = finchar;
++
++#ifdef DEBUG
++ if (--codelen != 0)
++ printf(&quot;bsd_decomp%d: short by %d after code 0x%x, max_ent=0x%x\n&quot;,
++ db-&gt;unit, codelen, incode, max_ent);
++#endif
++
++ if (extra) /* the KwKwK case again */
++ *wptr++ = finchar;
++
++ /*
++ * If not first code in a packet, and
++ * if not out of code space, then allocate a new code.
++ *
++ * Keep the hash table correct so it can be used
++ * with uncompressed packets.
++ */
++ if (oldcode != CLEAR &amp;&amp; max_ent &lt; db-&gt;maxmaxcode) {
++ struct bsd_dict *dictp2;
++ u_int32_t fcode;
++ int hval, disp;
++
++ fcode = BSD_KEY(oldcode,finchar);
++ hval = BSD_HASH(oldcode,finchar,db-&gt;hshift);
++ dictp = &amp;db-&gt;dict[hval];
++
++ /* look for a free hash table entry */
++ if (dictp-&gt;codem1 &lt; max_ent) {
++ disp = (hval == 0) ? 1 : hval;
++ do {
++ hval += disp;
++ if (hval &gt;= db-&gt;hsize)
++ hval -= db-&gt;hsize;
++ dictp = &amp;db-&gt;dict[hval];
++ } while (dictp-&gt;codem1 &lt; max_ent);
++ }
++
++ /*
++ * Invalidate previous hash table entry
++ * assigned this code, and then take it over
++ */
++ dictp2 = &amp;db-&gt;dict[max_ent+1];
++ if (db-&gt;dict[dictp2-&gt;cptr].codem1 == max_ent) {
++ db-&gt;dict[dictp2-&gt;cptr].codem1 = BADCODEM1;
++ }
++ dictp2-&gt;cptr = hval;
++ dictp-&gt;codem1 = max_ent;
++ dictp-&gt;f.fcode = fcode;
++
++ db-&gt;max_ent = ++max_ent;
++ db-&gt;lens[max_ent] = db-&gt;lens[oldcode]+1;
++
++ /* Expand code size if needed. */
++ if (max_ent &gt;= MAXCODE(n_bits) &amp;&amp; max_ent &lt; db-&gt;maxmaxcode) {
++ db-&gt;n_bits = ++n_bits;
++ tgtbitno = 32-n_bits;
++ }
++ }
++ oldcode = incode;
++ }
++ *outlenp = wptr - (dmp + db-&gt;hdrlen);
++
++ /*
++ * Keep the checkpoint right so that incompressible packets
++ * clear the dictionary at the right times.
++ */
++ db-&gt;bytes_out += ilen;
++ db-&gt;in_count += explen;
++ if (bsd_check(db) &amp;&amp; db-&gt;debug) {
++ printf(&quot;bsd_decomp%d: peer should have cleared dictionary\n&quot;,
++ db-&gt;unit);
++ }
++
++ ++db-&gt;comp_count;
++ db-&gt;comp_bytes += ilen + BSD_OVHD;
++ ++db-&gt;uncomp_count;
++ db-&gt;uncomp_bytes += explen;
++
++ return DECOMP_OK;
++}
++#endif /* DO_BSD_COMPRESS */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppdump/bsd-comp.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppdump/deflate.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppdump/deflate.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppdump/deflate.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,344 @@
++/*
++ * ppp_deflate.c - interface the zlib procedures for Deflate compression
++ * and decompression (as used by gzip) to the PPP code.
++ *
++ * Copyright (c) 1994 The Australian National University.
++ * All rights reserved.
++ *
++ * Permission to use, copy, modify, and distribute this software and its
++ * documentation is hereby granted, provided that the above copyright
++ * notice appears in all copies. This software is provided without any
++ * warranty, express or implied. The Australian National University
++ * makes no representations about the suitability of this software for
++ * any purpose.
++ *
++ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
++ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
++ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
++ * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
++ * OF SUCH DAMAGE.
++ *
++ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
++ * ON AN &quot;AS IS&quot; BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
++ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
++ * OR MODIFICATIONS.
++ *
++ * $Id: deflate.c 195720 2001-06-11 11:44:34Z gc $
++ */
++
++#include &lt;sys/types.h&gt;
++#include &lt;stddef.h&gt;
++#include &lt;stdlib.h&gt;
++#include &quot;ppp_defs.h&quot;
++#include &quot;ppp-comp.h&quot;
++#include &quot;zlib.h&quot;
++
++#if DO_DEFLATE
++
++#define DEFLATE_DEBUG 1
++
++/*
++ * State for a Deflate (de)compressor.
++ */
++struct deflate_state {
++ int seqno;
++ int w_size;
++ int unit;
++ int hdrlen;
++ int mru;
++ int debug;
++ z_stream strm;
++ struct compstat stats;
++};
++
++#define DEFLATE_OVHD 2 /* Deflate overhead/packet */
++
++static void *z_alloc __P((void *, u_int items, u_int size));
++static void z_free __P((void *, void *ptr, u_int nb));
++static void *z_decomp_alloc __P((u_char *options, int opt_len));
++static void z_decomp_free __P((void *state));
++static int z_decomp_init __P((void *state, u_char *options, int opt_len,
++ int unit, int hdrlen, int mru, int debug));
++static void z_incomp __P((void *state, u_char *dmsg, int len));
++static int z_decompress __P((void *state, u_char *cmp, int inlen,
++ u_char *dmp, int *outlenp));
++static void z_decomp_reset __P((void *state));
++static void z_comp_stats __P((void *state, struct compstat *stats));
++
++/*
++ * Procedures exported to if_ppp.c.
++ */
++struct compressor ppp_deflate = {
++ CI_DEFLATE, /* compress_proto */
++ z_decomp_alloc, /* decomp_alloc */
++ z_decomp_free, /* decomp_free */
++ z_decomp_init, /* decomp_init */
++ z_decomp_reset, /* decomp_reset */
++ z_decompress, /* decompress */
++ z_incomp, /* incomp */
++ z_comp_stats, /* decomp_stat */
++};
++
++/*
++ * Space allocation and freeing routines for use by zlib routines.
++ */
++static void *
++z_alloc(notused, items, size)
++ void *notused;
++ u_int items, size;
++{
++ return malloc(items * size);
++}
++
++static void
++z_free(notused, ptr, nbytes)
++ void *notused;
++ void *ptr;
++ u_int nbytes;
++{
++ free(ptr);
++}
++
++static void
++z_comp_stats(arg, stats)
++ void *arg;
++ struct compstat *stats;
++{
++ struct deflate_state *state = (struct deflate_state *) arg;
++ u_int out;
++
++ *stats = state-&gt;stats;
++ stats-&gt;ratio = stats-&gt;unc_bytes;
++ out = stats-&gt;comp_bytes + stats-&gt;unc_bytes;
++ if (stats-&gt;ratio &lt;= 0x7ffffff)
++ stats-&gt;ratio &lt;&lt;= 8;
++ else
++ out &gt;&gt;= 8;
++ if (out != 0)
++ stats-&gt;ratio /= out;
++}
++
++/*
++ * Allocate space for a decompressor.
++ */
++static void *
++z_decomp_alloc(options, opt_len)
++ u_char *options;
++ int opt_len;
++{
++ struct deflate_state *state;
++ int w_size;
++
++ if (opt_len != CILEN_DEFLATE || options[0] != CI_DEFLATE
++ || options[1] != CILEN_DEFLATE
++ || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
++ || options[3] != DEFLATE_CHK_SEQUENCE)
++ return NULL;
++ w_size = DEFLATE_SIZE(options[2]);
++ if (w_size &lt; DEFLATE_MIN_SIZE || w_size &gt; DEFLATE_MAX_SIZE)
++ return NULL;
++
++ state = (struct deflate_state *) malloc(sizeof(*state));
++ if (state == NULL)
++ return NULL;
++
++ state-&gt;strm.next_out = NULL;
++ state-&gt;strm.zalloc = (alloc_func) z_alloc;
++ state-&gt;strm.zfree = (free_func) z_free;
++ if (inflateInit2(&amp;state-&gt;strm, -w_size) != Z_OK) {
++ free(state);
++ return NULL;
++ }
++
++ state-&gt;w_size = w_size;
++ memset(&amp;state-&gt;stats, 0, sizeof(state-&gt;stats));
++ return (void *) state;
++}
++
++static void
++z_decomp_free(arg)
++ void *arg;
++{
++ struct deflate_state *state = (struct deflate_state *) arg;
++
++ inflateEnd(&amp;state-&gt;strm);
++ free(state);
++}
++
++static int
++z_decomp_init(arg, options, opt_len, unit, hdrlen, mru, debug)
++ void *arg;
++ u_char *options;
++ int opt_len, unit, hdrlen, mru, debug;
++{
++ struct deflate_state *state = (struct deflate_state *) arg;
++
++ if (opt_len &lt; CILEN_DEFLATE || options[0] != CI_DEFLATE
++ || options[1] != CILEN_DEFLATE
++ || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
++ || DEFLATE_SIZE(options[2]) != state-&gt;w_size
++ || options[3] != DEFLATE_CHK_SEQUENCE)
++ return 0;
++
++ state-&gt;seqno = 0;
++ state-&gt;unit = unit;
++ state-&gt;hdrlen = hdrlen;
++ state-&gt;debug = debug;
++ state-&gt;mru = mru;
++
++ inflateReset(&amp;state-&gt;strm);
++
++ return 1;
++}
++
++static void
++z_decomp_reset(arg)
++ void *arg;
++{
++ struct deflate_state *state = (struct deflate_state *) arg;
++
++ state-&gt;seqno = 0;
++ inflateReset(&amp;state-&gt;strm);
++}
++
++/*
++ * Decompress a Deflate-compressed packet.
++ *
++ * Because of patent problems, we return DECOMP_ERROR for errors
++ * found by inspecting the input data and for system problems, but
++ * DECOMP_FATALERROR for any errors which could possibly be said to
++ * be being detected &quot;after&quot; decompression. For DECOMP_ERROR,
++ * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
++ * infringing a patent of Motorola's if we do, so we take CCP down
++ * instead.
++ *
++ * Given that the frame has the correct sequence number and a good FCS,
++ * errors such as invalid codes in the input most likely indicate a
++ * bug, so we return DECOMP_FATALERROR for them in order to turn off
++ * compression, even though they are detected by inspecting the input.
++ */
++static int
++z_decompress(arg, mi, inlen, mo, outlenp)
++ void *arg;
++ u_char *mi, *mo;
++ int inlen, *outlenp;
++{
++ struct deflate_state *state = (struct deflate_state *) arg;
++ u_char *rptr, *wptr;
++ int rlen, olen, ospace;
++ int seq, i, flush, r, decode_proto;
++
++ rptr = mi;
++ if (*rptr == 0)
++ ++rptr;
++ ++rptr;
++
++ /* Check the sequence number. */
++ seq = (rptr[0] &lt;&lt; 8) + rptr[1];
++ rptr += 2;
++ if (seq != state-&gt;seqno) {
++#if !DEFLATE_DEBUG
++ if (state-&gt;debug)
++#endif
++ printf(&quot;z_decompress%d: bad seq # %d, expected %d\n&quot;,
++ state-&gt;unit, seq, state-&gt;seqno);
++ return DECOMP_ERROR;
++ }
++ ++state-&gt;seqno;
++
++ /*
++ * Set up to call inflate.
++ */
++ wptr = mo;
++ state-&gt;strm.next_in = rptr;
++ state-&gt;strm.avail_in = mi + inlen - rptr;
++ rlen = state-&gt;strm.avail_in + PPP_HDRLEN + DEFLATE_OVHD;
++ state-&gt;strm.next_out = wptr;
++ state-&gt;strm.avail_out = state-&gt;mru + 2;
++
++ r = inflate(&amp;state-&gt;strm, Z_PACKET_FLUSH);
++ if (r != Z_OK) {
++#if !DEFLATE_DEBUG
++ if (state-&gt;debug)
++#endif
++ printf(&quot;z_decompress%d: inflate returned %d (%s)\n&quot;,
++ state-&gt;unit, r, (state-&gt;strm.msg? state-&gt;strm.msg: &quot;&quot;));
++ return DECOMP_FATALERROR;
++ }
++ olen = state-&gt;mru + 2 - state-&gt;strm.avail_out;
++ *outlenp = olen;
++
++ if ((wptr[0] &amp; 1) != 0)
++ ++olen; /* for suppressed protocol high byte */
++ olen += 2; /* for address, control */
++
++#if DEFLATE_DEBUG
++ if (olen &gt; state-&gt;mru + PPP_HDRLEN)
++ printf(&quot;ppp_deflate%d: exceeded mru (%d &gt; %d)\n&quot;,
++ state-&gt;unit, olen, state-&gt;mru + PPP_HDRLEN);
++#endif
++
++ state-&gt;stats.unc_bytes += olen;
++ state-&gt;stats.unc_packets++;
++ state-&gt;stats.comp_bytes += rlen;
++ state-&gt;stats.comp_packets++;
++
++ return DECOMP_OK;
++}
++
++/*
++ * Incompressible data has arrived - add it to the history.
++ */
++static void
++z_incomp(arg, mi, mlen)
++ void *arg;
++ u_char *mi;
++ int mlen;
++{
++ struct deflate_state *state = (struct deflate_state *) arg;
++ u_char *rptr;
++ int rlen, proto, r;
++
++ /*
++ * Check that the protocol is one we handle.
++ */
++ rptr = mi;
++ proto = rptr[0];
++ if ((proto &amp; 1) == 0)
++ proto = (proto &lt;&lt; 8) + rptr[1];
++ if (proto &gt; 0x3fff || proto == 0xfd || proto == 0xfb)
++ return;
++
++ ++state-&gt;seqno;
++
++ if (rptr[0] == 0)
++ ++rptr;
++ rlen = mi + mlen - rptr;
++ state-&gt;strm.next_in = rptr;
++ state-&gt;strm.avail_in = rlen;
++ r = inflateIncomp(&amp;state-&gt;strm);
++ if (r != Z_OK) {
++ /* gak! */
++#if !DEFLATE_DEBUG
++ if (state-&gt;debug)
++#endif
++ printf(&quot;z_incomp%d: inflateIncomp returned %d (%s)\n&quot;,
++ state-&gt;unit, r, (state-&gt;strm.msg? state-&gt;strm.msg: &quot;&quot;));
++ return;
++ }
++
++ /*
++ * Update stats.
++ */
++ if (proto &lt;= 0xff)
++ ++rlen;
++ rlen += 2;
++ state-&gt;stats.inc_bytes += rlen;
++ state-&gt;stats.inc_packets++;
++ state-&gt;stats.unc_bytes += rlen;
++ state-&gt;stats.unc_packets++;
++}
++
++#endif /* DO_DEFLATE */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppdump/deflate.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppdump/ppp-comp.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppdump/ppp-comp.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppdump/ppp-comp.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,150 @@
++/*
++ * ppp-comp.h - Definitions for doing PPP packet compression.
++ *
++ * Copyright (c) 1994 The Australian National University.
++ * All rights reserved.
++ *
++ * Permission to use, copy, modify, and distribute this software and its
++ * documentation is hereby granted, provided that the above copyright
++ * notice appears in all copies. This software is provided without any
++ * warranty, express or implied. The Australian National University
++ * makes no representations about the suitability of this software for
++ * any purpose.
++ *
++ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
++ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
++ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
++ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
++ * OF SUCH DAMAGE.
++ *
++ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
++ * ON AN &quot;AS IS&quot; BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
++ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
++ * OR MODIFICATIONS.
++ *
++ * $Id: ppp-comp.h 195720 2001-06-11 11:44:34Z gc $
++ */
++
++#ifndef _NET_PPP_COMP_H
++#define _NET_PPP_COMP_H
++
++/*
++ * The following symbols control whether we include code for
++ * various compression methods.
++ */
++#ifndef DO_BSD_COMPRESS
++#define DO_BSD_COMPRESS 1 /* by default, include BSD-Compress */
++#endif
++#ifndef DO_DEFLATE
++#define DO_DEFLATE 1 /* by default, include Deflate */
++#endif
++#define DO_PREDICTOR_1 0
++#define DO_PREDICTOR_2 0
++
++/*
++ * Structure giving methods for compression/decompression.
++ */
++struct compressor {
++ int compress_proto; /* CCP compression protocol number */
++
++ /* Allocate space for a decompressor (receive side) */
++ void *(*decomp_alloc) __P((u_char *options, int opt_len));
++ /* Free space used by a decompressor */
++ void (*decomp_free) __P((void *state));
++ /* Initialize a decompressor */
++ int (*decomp_init) __P((void *state, u_char *options, int opt_len,
++ int unit, int hdrlen, int mru, int debug));
++ /* Reset a decompressor */
++ void (*decomp_reset) __P((void *state));
++ /* Decompress a packet. */
++ int (*decompress) __P((void *state, u_char *mp, int inlen,
++ u_char *dmp, int *outlen));
++ /* Update state for an incompressible packet received */
++ void (*incomp) __P((void *state, u_char *mp, int len));
++ /* Return decompression statistics */
++ void (*decomp_stat) __P((void *state, struct compstat *stats));
++};
++
++/*
++ * Return values for decompress routine.
++ * We need to make these distinctions so that we can disable certain
++ * useful functionality, namely sending a CCP reset-request as a result
++ * of an error detected after decompression. This is to avoid infringing
++ * a patent held by Motorola.
++ * Don't you just lurve software patents.
++ */
++#define DECOMP_OK 0 /* everything went OK */
++#define DECOMP_ERROR 1 /* error detected before decomp. */
++#define DECOMP_FATALERROR 2 /* error detected after decomp. */
++
++/*
++ * CCP codes.
++ */
++#define CCP_CONFREQ 1
++#define CCP_CONFACK 2
++#define CCP_CONFNAK 3
++#define CCP_CONFREJ 4
++#define CCP_TERMREQ 5
++#define CCP_TERMACK 6
++#define CCP_RESETREQ 14
++#define CCP_RESETACK 15
++
++/*
++ * Max # bytes for a CCP option
++ */
++#define CCP_MAX_OPTION_LENGTH 32
++
++/*
++ * Parts of a CCP packet.
++ */
++#define CCP_CODE(dp) ((dp)[0])
++#define CCP_ID(dp) ((dp)[1])
++#define CCP_LENGTH(dp) (((dp)[2] &lt;&lt; 8) + (dp)[3])
++#define CCP_HDRLEN 4
++
++#define CCP_OPT_CODE(dp) ((dp)[0])
++#define CCP_OPT_LENGTH(dp) ((dp)[1])
++#define CCP_OPT_MINLEN 2
++
++/*
++ * Definitions for BSD-Compress.
++ */
++#define CI_BSD_COMPRESS 21 /* config. option for BSD-Compress */
++#define CILEN_BSD_COMPRESS 3 /* length of config. option */
++
++/* Macros for handling the 3rd byte of the BSD-Compress config option. */
++#define BSD_NBITS(x) ((x) &amp; 0x1F) /* number of bits requested */
++#define BSD_VERSION(x) ((x) &gt;&gt; 5) /* version of option format */
++#define BSD_CURRENT_VERSION 1 /* current version number */
++#define BSD_MAKE_OPT(v, n) (((v) &lt;&lt; 5) | (n))
++
++#define BSD_MIN_BITS 9 /* smallest code size supported */
++#define BSD_MAX_BITS 15 /* largest code size supported */
++
++/*
++ * Definitions for Deflate.
++ */
++#define CI_DEFLATE 26 /* config option for Deflate */
++#define CI_DEFLATE_DRAFT 24 /* value used in original draft RFC */
++#define CILEN_DEFLATE 4 /* length of its config option */
++
++#define DEFLATE_MIN_SIZE 8
++#define DEFLATE_MAX_SIZE 15
++#define DEFLATE_METHOD_VAL 8
++#define DEFLATE_SIZE(x) (((x) &gt;&gt; 4) + DEFLATE_MIN_SIZE)
++#define DEFLATE_METHOD(x) ((x) &amp; 0x0F)
++#define DEFLATE_MAKE_OPT(w) ((((w) - DEFLATE_MIN_SIZE) &lt;&lt; 4) \
++ + DEFLATE_METHOD_VAL)
++#define DEFLATE_CHK_SEQUENCE 0
++
++/*
++ * Definitions for other, as yet unsupported, compression methods.
++ */
++#define CI_PREDICTOR_1 1 /* config option for Predictor-1 */
++#define CILEN_PREDICTOR_1 2 /* length of its config option */
++#define CI_PREDICTOR_2 2 /* config option for Predictor-2 */
++#define CILEN_PREDICTOR_2 2 /* length of its config option */
++
++#endif /* _NET_PPP_COMP_H */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppdump/ppp-comp.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppdump/pppdump.8
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppdump/pppdump.8 (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppdump/pppdump.8 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,62 @@
++.\&quot; @(#) $Id: pppdump.8 195720 2001-06-11 11:44:34Z gc $
++.TH PPPDUMP 8 &quot;1 April 1999&quot;
++.SH NAME
++pppdump \- convert PPP record file to readable format
++.SH SYNOPSIS
++.B pppdump
++[
++.B -h
++|
++.B -p
++[
++.B -d
++]] [
++.B -r
++] [
++.B -m \fImru
++] [
++.I file \fR...
++]
++.ti 12
++.SH DESCRIPTION
++The
++.B pppdump
++utility converts the files written using the \fIrecord\fR option of
++.B pppd
++into a human-readable format. If one or more filenames are specified,
++.B pppdump
++will read each in turn; otherwise it will read its standard input. In
++each case the result is written to standard output.
++.PP
++The options are as follows:
++.TP
++.B -h
++Prints the bytes sent and received in hexadecimal. If neither this
++option nor the \fB-p\fR option is specified, the bytes are printed as
++the characters themselves, with non-printing and non-ASCII characters
++printed as escape sequences.
++.TP
++.B -p
++Collects the bytes sent and received into PPP packets, interpreting
++the async HDLC framing and escape characters and checking the FCS
++(frame check sequence) of each packet. The packets are printed as hex
++values and as characters (non-printable characters are printed as
++`.').
++.TP
++.B -d
++With the \fB-p\fR option, this option causes
++.B pppdump
++to decompress packets which have been compressed with the BSD-Compress
++or Deflate methods.
++.TP
++.B -r
++Reverses the direction indicators, so that `sent' is printed for
++bytes or packets received, and `rcvd' is printed for bytes or packets
++sent.
++.TP
++.B -m \fImru
++Use \fImru\fR as the MRU (maximum receive unit) for both directions of
++the link when checking for over-length PPP packets (with the \fB-p\fR
++option).
++.SH SEE ALSO
++pppd(8)
+
+Added: drakx/trunk/mdk-stage1/ppp/pppdump/pppdump.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppdump/pppdump.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppdump/pppdump.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,502 @@
++/*
++ * pppdump - print out the contents of a record file generated by
++ * pppd in readable form.
++ *
++ * Copyright (C) 1999 Paul Mackerras. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms. The name of the author
++ * may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ */
++#include &lt;stdio.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;time.h&gt;
++#include &lt;sys/types.h&gt;
++#include &quot;ppp_defs.h&quot;
++#include &quot;ppp-comp.h&quot;
++
++int hexmode;
++int pppmode;
++int reverse;
++int decompress;
++int mru = 1500;
++int abs_times;
++time_t start_time;
++int start_time_tenths;
++int tot_sent, tot_rcvd;
++
++extern int optind;
++extern char *optarg;
++
++main(ac, av)
++ int ac;
++ char **av;
++{
++ int i;
++ char *p;
++ FILE *f;
++
++ while ((i = getopt(ac, av, &quot;hprdm:a&quot;)) != -1) {
++ switch (i) {
++ case 'h':
++ hexmode = 1;
++ break;
++ case 'p':
++ pppmode = 1;
++ break;
++ case 'r':
++ reverse = 1;
++ break;
++ case 'd':
++ decompress = 1;
++ break;
++ case 'm':
++ mru = atoi(optarg);
++ break;
++ case 'a':
++ abs_times = 1;
++ break;
++ default:
++ fprintf(stderr, &quot;Usage: %s [-h | -p[d]] [-r] [-m mru] [-a] [file ...]\n&quot;, av[0]);
++ exit(1);
++ }
++ }
++ if (optind &gt;= ac)
++ dumplog(stdin);
++ else {
++ for (i = optind; i &lt; ac; ++i) {
++ p = av[i];
++ if ((f = fopen(p, &quot;r&quot;)) == NULL) {
++ perror(p);
++ exit(1);
++ }
++ if (pppmode)
++ dumpppp(f);
++ else
++ dumplog(f);
++ fclose(f);
++ }
++ }
++ exit(0);
++}
++
++dumplog(f)
++ FILE *f;
++{
++ int c, n, k, col;
++ int nb, c2;
++ unsigned char buf[16];
++
++ while ((c = getc(f)) != EOF) {
++ switch (c) {
++ case 1:
++ case 2:
++ if (reverse)
++ c = 3 - c;
++ printf(&quot;%s %c&quot;, c==1? &quot;sent&quot;: &quot;rcvd&quot;, hexmode? ' ': '&quot;');
++ col = 6;
++ n = getc(f);
++ n = (n &lt;&lt; 8) + getc(f);
++ *(c==1? &amp;tot_sent: &amp;tot_rcvd) += n;
++ nb = 0;
++ for (; n &gt; 0; --n) {
++ c = getc(f);
++ if (c == EOF) {
++ printf(&quot;\nEOF\n&quot;);
++ exit(0);
++ }
++ if (hexmode) {
++ if (nb &gt;= 16) {
++ printf(&quot; &quot;);
++ for (k = 0; k &lt; nb; ++k) {
++ c2 = buf[k];
++ putchar((' ' &lt;= c2 &amp;&amp; c2 &lt;= '~')? c2: '.');
++ }
++ printf(&quot;\n &quot;);
++ nb = 0;
++ }
++ buf[nb++] = c;
++ printf(&quot; %.2x&quot;, c);
++ } else {
++ k = (' ' &lt;= c &amp;&amp; c &lt;= '~')? (c != '\\' &amp;&amp; c != '&quot;')? 1: 2: 3;
++ if ((col += k) &gt;= 78) {
++ printf(&quot;\n &quot;);
++ col = 6 + k;
++ }
++ switch (k) {
++ case 1:
++ putchar(c);
++ break;
++ case 2:
++ printf(&quot;\\%c&quot;, c);
++ break;
++ case 3:
++ printf(&quot;\\%.2x&quot;, c);
++ break;
++ }
++ }
++ }
++ if (hexmode) {
++ for (k = nb; k &lt; 16; ++k)
++ printf(&quot; &quot;);
++ printf(&quot; &quot;);
++ for (k = 0; k &lt; nb; ++k) {
++ c2 = buf[k];
++ putchar((' ' &lt;= c2 &amp;&amp; c2 &lt;= '~')? c2: '.');
++ }
++ } else
++ putchar('&quot;');
++ printf(&quot;\n&quot;);
++ break;
++ case 3:
++ case 4:
++ printf(&quot;end %s\n&quot;, c==3? &quot;send&quot;: &quot;recv&quot;);
++ break;
++ case 5:
++ case 6:
++ case 7:
++ show_time(f, c);
++ break;
++ default:
++ printf(&quot;?%.2x\n&quot;);
++ }
++ }
++}
++
++/*
++ * FCS lookup table as calculated by genfcstab.
++ */
++static u_short fcstab[256] = {
++ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
++ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
++ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
++ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
++ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
++ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
++ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
++ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
++ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
++ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
++ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
++ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
++ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
++ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
++ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
++ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
++ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
++ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
++ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
++ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
++ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
++ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
++ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
++ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
++ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
++ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
++ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
++ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
++ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
++ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
++ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
++ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
++};
++
++struct pkt {
++ int cnt;
++ int esc;
++ int flags;
++ struct compressor *comp;
++ void *state;
++ unsigned char buf[8192];
++} spkt, rpkt;
++
++/* Values for flags */
++#define CCP_ISUP 1
++#define CCP_ERROR 2
++#define CCP_FATALERROR 4
++#define CCP_ERR (CCP_ERROR | CCP_FATALERROR)
++#define CCP_DECOMP_RUN 8
++
++unsigned char dbuf[8192];
++
++dumpppp(f)
++ FILE *f;
++{
++ int c, n, k;
++ int nb, nl, dn, proto, rv;
++ char *dir, *q;
++ unsigned char *p, *r, *endp;
++ unsigned char *d;
++ unsigned short fcs;
++ struct pkt *pkt;
++
++ spkt.cnt = rpkt.cnt = 0;
++ spkt.esc = rpkt.esc = 0;
++ while ((c = getc(f)) != EOF) {
++ switch (c) {
++ case 1:
++ case 2:
++ if (reverse)
++ c = 3 - c;
++ dir = c==1? &quot;sent&quot;: &quot;rcvd&quot;;
++ pkt = c==1? &amp;spkt: &amp;rpkt;
++ n = getc(f);
++ n = (n &lt;&lt; 8) + getc(f);
++ *(c==1? &amp;tot_sent: &amp;tot_rcvd) += n;
++ for (; n &gt; 0; --n) {
++ c = getc(f);
++ switch (c) {
++ case EOF:
++ printf(&quot;\nEOF\n&quot;);
++ if (spkt.cnt &gt; 0)
++ printf(&quot;[%d bytes in incomplete send packet]\n&quot;,
++ spkt.cnt);
++ if (rpkt.cnt &gt; 0)
++ printf(&quot;[%d bytes in incomplete recv packet]\n&quot;,
++ rpkt.cnt);
++ exit(0);
++ case '~':
++ if (pkt-&gt;cnt &gt; 0) {
++ q = dir;
++ if (pkt-&gt;esc) {
++ printf(&quot;%s aborted packet:\n &quot;, dir);
++ q = &quot; &quot;;
++ }
++ nb = pkt-&gt;cnt;
++ p = pkt-&gt;buf;
++ pkt-&gt;cnt = 0;
++ pkt-&gt;esc = 0;
++ if (nb &lt;= 2) {
++ printf(&quot;%s short packet [%d bytes]:&quot;, q, nb);
++ for (k = 0; k &lt; nb; ++k)
++ printf(&quot; %.2x&quot;, p[k]);
++ printf(&quot;\n&quot;);
++ break;
++ }
++ fcs = PPP_INITFCS;
++ for (k = 0; k &lt; nb; ++k)
++ fcs = PPP_FCS(fcs, p[k]);
++ fcs &amp;= 0xFFFF;
++ nb -= 2;
++ endp = p + nb;
++ r = p;
++ if (r[0] == 0xff &amp;&amp; r[1] == 3)
++ r += 2;
++ if ((r[0] &amp; 1) == 0)
++ ++r;
++ ++r;
++ if (endp - r &gt; mru)
++ printf(&quot; ERROR: length (%d) &gt; MRU (%d)\n&quot;,
++ endp - r, mru);
++ if (decompress &amp;&amp; fcs == PPP_GOODFCS) {
++ /* See if this is a CCP or compressed packet */
++ d = dbuf;
++ r = p;
++ if (r[0] == 0xff &amp;&amp; r[1] == 3) {
++ *d++ = *r++;
++ *d++ = *r++;
++ }
++ proto = r[0];
++ if ((proto &amp; 1) == 0)
++ proto = (proto &lt;&lt; 8) + r[1];
++ if (proto == PPP_CCP) {
++ handle_ccp(pkt, r + 2, endp - r - 2);
++ } else if (proto == PPP_COMP) {
++ if ((pkt-&gt;flags &amp; CCP_ISUP)
++ &amp;&amp; (pkt-&gt;flags &amp; CCP_DECOMP_RUN)
++ &amp;&amp; pkt-&gt;state
++ &amp;&amp; (pkt-&gt;flags &amp; CCP_ERR) == 0) {
++ rv = pkt-&gt;comp-&gt;decompress(pkt-&gt;state, r,
++ endp - r, d, &amp;dn);
++ switch (rv) {
++ case DECOMP_OK:
++ p = dbuf;
++ nb = d + dn - p;
++ if ((d[0] &amp; 1) == 0)
++ --dn;
++ --dn;
++ if (dn &gt; mru)
++ printf(&quot; ERROR: decompressed length (%d) &gt; MRU (%d)\n&quot;, dn, mru);
++ break;
++ case DECOMP_ERROR:
++ printf(&quot; DECOMPRESSION ERROR\n&quot;);
++ pkt-&gt;flags |= CCP_ERROR;
++ break;
++ case DECOMP_FATALERROR:
++ printf(&quot; FATAL DECOMPRESSION ERROR\n&quot;);
++ pkt-&gt;flags |= CCP_FATALERROR;
++ break;
++ }
++ }
++ } else if (pkt-&gt;state
++ &amp;&amp; (pkt-&gt;flags &amp; CCP_DECOMP_RUN)) {
++ pkt-&gt;comp-&gt;incomp(pkt-&gt;state, r, endp - r);
++ }
++ }
++ do {
++ nl = nb &lt; 16? nb: 16;
++ printf(&quot;%s &quot;, q);
++ for (k = 0; k &lt; nl; ++k)
++ printf(&quot; %.2x&quot;, p[k]);
++ for (; k &lt; 16; ++k)
++ printf(&quot; &quot;);
++ printf(&quot; &quot;);
++ for (k = 0; k &lt; nl; ++k) {
++ c = p[k];
++ putchar((' ' &lt;= c &amp;&amp; c &lt;= '~')? c: '.');
++ }
++ printf(&quot;\n&quot;);
++ q = &quot; &quot;;
++ p += nl;
++ nb -= nl;
++ } while (nb &gt; 0);
++ if (fcs != PPP_GOODFCS)
++ printf(&quot; BAD FCS: (residue = %x)\n&quot;, fcs);
++ }
++ break;
++ case '}':
++ if (!pkt-&gt;esc) {
++ pkt-&gt;esc = 1;
++ break;
++ }
++ /* else fall through */
++ default:
++ if (pkt-&gt;esc) {
++ c ^= 0x20;
++ pkt-&gt;esc = 0;
++ }
++ pkt-&gt;buf[pkt-&gt;cnt++] = c;
++ break;
++ }
++ }
++ break;
++ case 3:
++ case 4:
++ if (reverse)
++ c = 7 - c;
++ dir = c==3? &quot;send&quot;: &quot;recv&quot;;
++ pkt = c==3? &amp;spkt: &amp;rpkt;
++ printf(&quot;end %s&quot;, dir);
++ if (pkt-&gt;cnt &gt; 0)
++ printf(&quot; [%d bytes in incomplete packet]&quot;, pkt-&gt;cnt);
++ printf(&quot;\n&quot;);
++ break;
++ case 5:
++ case 6:
++ case 7:
++ show_time(f, c);
++ break;
++ default:
++ printf(&quot;?%.2x\n&quot;);
++ }
++ }
++}
++
++extern struct compressor ppp_bsd_compress, ppp_deflate;
++
++struct compressor *compressors[] = {
++#if DO_BSD_COMPRESS
++ &amp;ppp_bsd_compress,
++#endif
++#if DO_DEFLATE
++ &amp;ppp_deflate,
++#endif
++ NULL
++};
++
++handle_ccp(cp, dp, len)
++ struct pkt *cp;
++ u_char *dp;
++ int len;
++{
++ int clen;
++ struct compressor **comp;
++
++ if (len &lt; CCP_HDRLEN)
++ return;
++ clen = CCP_LENGTH(dp);
++ if (clen &gt; len)
++ return;
++
++ switch (CCP_CODE(dp)) {
++ case CCP_CONFACK:
++ cp-&gt;flags &amp;= ~(CCP_DECOMP_RUN | CCP_ISUP);
++ if (clen &lt; CCP_HDRLEN + CCP_OPT_MINLEN
++ || clen &lt; CCP_HDRLEN + CCP_OPT_LENGTH(dp + CCP_HDRLEN))
++ break;
++ dp += CCP_HDRLEN;
++ clen -= CCP_HDRLEN;
++ for (comp = compressors; *comp != NULL; ++comp) {
++ if ((*comp)-&gt;compress_proto == dp[0]) {
++ if (cp-&gt;state != NULL) {
++ (*cp-&gt;comp-&gt;decomp_free)(cp-&gt;state);
++ cp-&gt;state = NULL;
++ }
++ cp-&gt;comp = *comp;
++ cp-&gt;state = (*comp)-&gt;decomp_alloc(dp, CCP_OPT_LENGTH(dp));
++ cp-&gt;flags |= CCP_ISUP;
++ if (cp-&gt;state != NULL
++ &amp;&amp; (*cp-&gt;comp-&gt;decomp_init)
++ (cp-&gt;state, dp, clen, 0, 0, 8192, 1))
++ cp-&gt;flags = (cp-&gt;flags &amp; ~CCP_ERR) | CCP_DECOMP_RUN;
++ break;
++ }
++ }
++ break;
++
++ case CCP_CONFNAK:
++ case CCP_CONFREJ:
++ cp-&gt;flags &amp;= ~(CCP_DECOMP_RUN | CCP_ISUP);
++ break;
++
++ case CCP_RESETACK:
++ if (cp-&gt;flags &amp; CCP_ISUP) {
++ if (cp-&gt;state &amp;&amp; (cp-&gt;flags &amp; CCP_DECOMP_RUN)) {
++ (*cp-&gt;comp-&gt;decomp_reset)(cp-&gt;state);
++ cp-&gt;flags &amp;= ~CCP_ERROR;
++ }
++ }
++ break;
++ }
++}
++
++show_time(f, c)
++ FILE *f;
++ int c;
++{
++ time_t t;
++ int n;
++ struct tm *tm;
++
++ if (c == 7) {
++ t = getc(f);
++ t = (t &lt;&lt; 8) + getc(f);
++ t = (t &lt;&lt; 8) + getc(f);
++ t = (t &lt;&lt; 8) + getc(f);
++ printf(&quot;start %s&quot;, ctime(&amp;t));
++ start_time = t;
++ start_time_tenths = 0;
++ tot_sent = tot_rcvd = 0;
++ } else {
++ n = getc(f);
++ if (c == 5) {
++ for (c = 3; c &gt; 0; --c)
++ n = (n &lt;&lt; 8) + getc(f);
++ }
++ if (abs_times) {
++ n += start_time_tenths;
++ start_time += n / 10;
++ start_time_tenths = n % 10;
++ tm = localtime(&amp;start_time);
++ printf(&quot;time %.2d:%.2d:%.2d.%d&quot;, tm-&gt;tm_hour, tm-&gt;tm_min,
++ tm-&gt;tm_sec, start_time_tenths);
++ printf(&quot; (sent %d, rcvd %d)\n&quot;, tot_sent, tot_rcvd);
++ } else
++ printf(&quot;time %.1fs\n&quot;, (double) n / 10);
++ }
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppdump/pppdump.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppdump/zlib.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppdump/zlib.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppdump/zlib.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,4614 @@
++/*
++ * This file is derived from various .h and .c files from the zlib-0.95
++ * distribution by Jean-loup Gailly and Mark Adler, with some additions
++ * by Paul Mackerras to aid in implementing Deflate compression and
++ * decompression for PPP packets. See zlib.h for conditions of
++ * distribution and use.
++ *
++ * Changes that have been made include:
++ * - changed functions not used outside this file to &quot;local&quot;
++ * - added minCompression parameter to deflateInit2
++ * - added Z_PACKET_FLUSH (see zlib.h for details)
++ * - added inflateIncomp
++ *
++ * $Id: zlib.c 195720 2001-06-11 11:44:34Z gc $
++ */
++
++
++/*+++++*/
++/* zutil.h -- internal interface and configuration of the compression library
++ * Copyright (C) 1995 Jean-loup Gailly.
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* WARNING: this file should *not* be used by applications. It is
++ part of the implementation of the compression library and is
++ subject to change. Applications should only use zlib.h.
++ */
++
++/* From: zutil.h,v 1.9 1995/05/03 17:27:12 jloup Exp */
++
++#define _Z_UTIL_H
++
++#include &quot;zlib.h&quot;
++
++#ifdef STDC
++# include &lt;string.h&gt;
++#endif
++
++#ifndef local
++# define local static
++#endif
++/* compile with -Dlocal if your debugger can't find static symbols */
++
++#define FAR
++
++typedef unsigned char uch;
++typedef uch FAR uchf;
++typedef unsigned short ush;
++typedef ush FAR ushf;
++typedef unsigned long ulg;
++
++extern char *z_errmsg[]; /* indexed by 1-zlib_error */
++
++#define ERR_RETURN(strm,err) return (strm-&gt;msg=z_errmsg[1-err], err)
++/* To be used only when the state is known to be valid */
++
++#ifndef NULL
++#define NULL ((void *) 0)
++#endif
++
++ /* common constants */
++
++#define DEFLATED 8
++
++#ifndef DEF_WBITS
++# define DEF_WBITS MAX_WBITS
++#endif
++/* default windowBits for decompression. MAX_WBITS is for compression only */
++
++#if MAX_MEM_LEVEL &gt;= 8
++# define DEF_MEM_LEVEL 8
++#else
++# define DEF_MEM_LEVEL MAX_MEM_LEVEL
++#endif
++/* default memLevel */
++
++#define STORED_BLOCK 0
++#define STATIC_TREES 1
++#define DYN_TREES 2
++/* The three kinds of block type */
++
++#define MIN_MATCH 3
++#define MAX_MATCH 258
++/* The minimum and maximum match lengths */
++
++ /* functions */
++
++#if defined(STDC) &amp;&amp; !defined(HAVE_MEMCPY) &amp;&amp; !defined(NO_MEMCPY)
++# define HAVE_MEMCPY
++#endif
++#ifdef HAVE_MEMCPY
++# define zmemcpy memcpy
++# define zmemzero(dest, len) memset(dest, 0, len)
++#else
++# define zmemcpy(d, s, n) bcopy((s), (d), (n))
++# define zmemzero bzero
++#endif
++
++/* Diagnostic functions */
++#ifdef DEBUG_ZLIB
++# include &lt;stdio.h&gt;
++# ifndef verbose
++# define verbose 0
++# endif
++# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
++# define Trace(x) fprintf x
++# define Tracev(x) {if (verbose) fprintf x ;}
++# define Tracevv(x) {if (verbose&gt;1) fprintf x ;}
++# define Tracec(c,x) {if (verbose &amp;&amp; (c)) fprintf x ;}
++# define Tracecv(c,x) {if (verbose&gt;1 &amp;&amp; (c)) fprintf x ;}
++#else
++# define Assert(cond,msg)
++# define Trace(x)
++# define Tracev(x)
++# define Tracevv(x)
++# define Tracec(c,x)
++# define Tracecv(c,x)
++#endif
++
++
++typedef uLong (*check_func) OF((uLong check, Bytef *buf, uInt len));
++
++/* voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); */
++/* void zcfree OF((voidpf opaque, voidpf ptr)); */
++
++#define ZALLOC(strm, items, size) \
++ (*((strm)-&gt;zalloc))((strm)-&gt;opaque, (items), (size))
++#define ZFREE(strm, addr, size) \
++ (*((strm)-&gt;zfree))((strm)-&gt;opaque, (voidpf)(addr), (size))
++#define TRY_FREE(s, p, n) {if (p) ZFREE(s, p, n);}
++
++/* deflate.h -- internal compression state
++ * Copyright (C) 1995 Jean-loup Gailly
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* WARNING: this file should *not* be used by applications. It is
++ part of the implementation of the compression library and is
++ subject to change. Applications should only use zlib.h.
++ */
++
++
++/*+++++*/
++/* From: deflate.h,v 1.5 1995/05/03 17:27:09 jloup Exp */
++
++/* ===========================================================================
++ * Internal compression state.
++ */
++
++/* Data type */
++#define BINARY 0
++#define ASCII 1
++#define UNKNOWN 2
++
++#define LENGTH_CODES 29
++/* number of length codes, not counting the special END_BLOCK code */
++
++#define LITERALS 256
++/* number of literal bytes 0..255 */
++
++#define L_CODES (LITERALS+1+LENGTH_CODES)
++/* number of Literal or Length codes, including the END_BLOCK code */
++
++#define D_CODES 30
++/* number of distance codes */
++
++#define BL_CODES 19
++/* number of codes used to transfer the bit lengths */
++
++#define HEAP_SIZE (2*L_CODES+1)
++/* maximum heap size */
++
++#define MAX_BITS 15
++/* All codes must not exceed MAX_BITS bits */
++
++#define INIT_STATE 42
++#define BUSY_STATE 113
++#define FLUSH_STATE 124
++#define FINISH_STATE 666
++/* Stream status */
++
++
++/* Data structure describing a single value and its code string. */
++typedef struct ct_data_s {
++ union {
++ ush freq; /* frequency count */
++ ush code; /* bit string */
++ } fc;
++ union {
++ ush dad; /* father node in Huffman tree */
++ ush len; /* length of bit string */
++ } dl;
++} FAR ct_data;
++
++#define Freq fc.freq
++#define Code fc.code
++#define Dad dl.dad
++#define Len dl.len
++
++typedef struct static_tree_desc_s static_tree_desc;
++
++typedef struct tree_desc_s {
++ ct_data *dyn_tree; /* the dynamic tree */
++ int max_code; /* largest code with non zero frequency */
++ static_tree_desc *stat_desc; /* the corresponding static tree */
++} FAR tree_desc;
++
++typedef ush Pos;
++typedef Pos FAR Posf;
++typedef unsigned IPos;
++
++/* A Pos is an index in the character window. We use short instead of int to
++ * save space in the various tables. IPos is used only for parameter passing.
++ */
++
++typedef struct deflate_state {
++ z_stream *strm; /* pointer back to this zlib stream */
++ int status; /* as the name implies */
++ Bytef *pending_buf; /* output still pending */
++ Bytef *pending_out; /* next pending byte to output to the stream */
++ int pending; /* nb of bytes in the pending buffer */
++ uLong adler; /* adler32 of uncompressed data */
++ int noheader; /* suppress zlib header and adler32 */
++ Byte data_type; /* UNKNOWN, BINARY or ASCII */
++ Byte method; /* STORED (for zip only) or DEFLATED */
++ int minCompr; /* min size decrease for Z_FLUSH_NOSTORE */
++
++ /* used by deflate.c: */
++
++ uInt w_size; /* LZ77 window size (32K by default) */
++ uInt w_bits; /* log2(w_size) (8..16) */
++ uInt w_mask; /* w_size - 1 */
++
++ Bytef *window;
++ /* Sliding window. Input bytes are read into the second half of the window,
++ * and move to the first half later to keep a dictionary of at least wSize
++ * bytes. With this organization, matches are limited to a distance of
++ * wSize-MAX_MATCH bytes, but this ensures that IO is always
++ * performed with a length multiple of the block size. Also, it limits
++ * the window size to 64K, which is quite useful on MSDOS.
++ * To do: use the user input buffer as sliding window.
++ */
++
++ ulg window_size;
++ /* Actual size of window: 2*wSize, except when the user input buffer
++ * is directly used as sliding window.
++ */
++
++ Posf *prev;
++ /* Link to older string with same hash index. To limit the size of this
++ * array to 64K, this link is maintained only for the last 32K strings.
++ * An index in this array is thus a window index modulo 32K.
++ */
++
++ Posf *head; /* Heads of the hash chains or NIL. */
++
++ uInt ins_h; /* hash index of string to be inserted */
++ uInt hash_size; /* number of elements in hash table */
++ uInt hash_bits; /* log2(hash_size) */
++ uInt hash_mask; /* hash_size-1 */
++
++ uInt hash_shift;
++ /* Number of bits by which ins_h must be shifted at each input
++ * step. It must be such that after MIN_MATCH steps, the oldest
++ * byte no longer takes part in the hash key, that is:
++ * hash_shift * MIN_MATCH &gt;= hash_bits
++ */
++
++ long block_start;
++ /* Window position at the beginning of the current output block. Gets
++ * negative when the window is moved backwards.
++ */
++
++ uInt match_length; /* length of best match */
++ IPos prev_match; /* previous match */
++ int match_available; /* set if previous match exists */
++ uInt strstart; /* start of string to insert */
++ uInt match_start; /* start of matching string */
++ uInt lookahead; /* number of valid bytes ahead in window */
++
++ uInt prev_length;
++ /* Length of the best match at previous step. Matches not greater than this
++ * are discarded. This is used in the lazy match evaluation.
++ */
++
++ uInt max_chain_length;
++ /* To speed up deflation, hash chains are never searched beyond this
++ * length. A higher limit improves compression ratio but degrades the
++ * speed.
++ */
++
++ uInt max_lazy_match;
++ /* Attempt to find a better match only when the current match is strictly
++ * smaller than this value. This mechanism is used only for compression
++ * levels &gt;= 4.
++ */
++# define max_insert_length max_lazy_match
++ /* Insert new strings in the hash table only if the match length is not
++ * greater than this length. This saves time but degrades compression.
++ * max_insert_length is used only for compression levels &lt;= 3.
++ */
++
++ int level; /* compression level (1..9) */
++ int strategy; /* favor or force Huffman coding*/
++
++ uInt good_match;
++ /* Use a faster search when the previous match is longer than this */
++
++ int nice_match; /* Stop searching when current match exceeds this */
++
++ /* used by trees.c: */
++ /* Didn't use ct_data typedef below to supress compiler warning */
++ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
++ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
++ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
++
++ struct tree_desc_s l_desc; /* desc. for literal tree */
++ struct tree_desc_s d_desc; /* desc. for distance tree */
++ struct tree_desc_s bl_desc; /* desc. for bit length tree */
++
++ ush bl_count[MAX_BITS+1];
++ /* number of codes at each bit length for an optimal tree */
++
++ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
++ int heap_len; /* number of elements in the heap */
++ int heap_max; /* element of largest frequency */
++ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
++ * The same heap array is used to build all trees.
++ */
++
++ uch depth[2*L_CODES+1];
++ /* Depth of each subtree used as tie breaker for trees of equal frequency
++ */
++
++ uchf *l_buf; /* buffer for literals or lengths */
++
++ uInt lit_bufsize;
++ /* Size of match buffer for literals/lengths. There are 4 reasons for
++ * limiting lit_bufsize to 64K:
++ * - frequencies can be kept in 16 bit counters
++ * - if compression is not successful for the first block, all input
++ * data is still in the window so we can still emit a stored block even
++ * when input comes from standard input. (This can also be done for
++ * all blocks if lit_bufsize is not greater than 32K.)
++ * - if compression is not successful for a file smaller than 64K, we can
++ * even emit a stored file instead of a stored block (saving 5 bytes).
++ * This is applicable only for zip (not gzip or zlib).
++ * - creating new Huffman trees less frequently may not provide fast
++ * adaptation to changes in the input data statistics. (Take for
++ * example a binary file with poorly compressible code followed by
++ * a highly compressible string table.) Smaller buffer sizes give
++ * fast adaptation but have of course the overhead of transmitting
++ * trees more frequently.
++ * - I can't count above 4
++ */
++
++ uInt last_lit; /* running index in l_buf */
++
++ ushf *d_buf;
++ /* Buffer for distances. To simplify the code, d_buf and l_buf have
++ * the same number of elements. To use different lengths, an extra flag
++ * array would be necessary.
++ */
++
++ ulg opt_len; /* bit length of current block with optimal trees */
++ ulg static_len; /* bit length of current block with static trees */
++ ulg compressed_len; /* total bit length of compressed file */
++ uInt matches; /* number of string matches in current block */
++ int last_eob_len; /* bit length of EOB code for last block */
++
++#ifdef DEBUG_ZLIB
++ ulg bits_sent; /* bit length of the compressed data */
++#endif
++
++ ush bi_buf;
++ /* Output buffer. bits are inserted starting at the bottom (least
++ * significant bits).
++ */
++ int bi_valid;
++ /* Number of valid bits in bi_buf. All bits above the last valid bit
++ * are always zero.
++ */
++
++ uInt blocks_in_packet;
++ /* Number of blocks produced since the last time Z_PACKET_FLUSH
++ * was used.
++ */
++
++} FAR deflate_state;
++
++/* Output a byte on the stream.
++ * IN assertion: there is enough room in pending_buf.
++ */
++#define put_byte(s, c) {s-&gt;pending_buf[s-&gt;pending++] = (c);}
++
++
++#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
++/* Minimum amount of lookahead, except at the end of the input file.
++ * See deflate.c for comments about the MIN_MATCH+1.
++ */
++
++#define MAX_DIST(s) ((s)-&gt;w_size-MIN_LOOKAHEAD)
++/* In order to simplify the code, particularly on 16 bit machines, match
++ * distances are limited to MAX_DIST instead of WSIZE.
++ */
++
++ /* in trees.c */
++local void ct_init OF((deflate_state *s));
++local int ct_tally OF((deflate_state *s, int dist, int lc));
++local ulg ct_flush_block OF((deflate_state *s, charf *buf, ulg stored_len,
++ int flush));
++local void ct_align OF((deflate_state *s));
++local void ct_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
++ int eof));
++local void ct_stored_type_only OF((deflate_state *s));
++
++
++/*+++++*/
++/* deflate.c -- compress data using the deflation algorithm
++ * Copyright (C) 1995 Jean-loup Gailly.
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/*
++ * ALGORITHM
++ *
++ * The &quot;deflation&quot; process depends on being able to identify portions
++ * of the input text which are identical to earlier input (within a
++ * sliding window trailing behind the input currently being processed).
++ *
++ * The most straightforward technique turns out to be the fastest for
++ * most input files: try all possible matches and select the longest.
++ * The key feature of this algorithm is that insertions into the string
++ * dictionary are very simple and thus fast, and deletions are avoided
++ * completely. Insertions are performed at each input character, whereas
++ * string matches are performed only when the previous match ends. So it
++ * is preferable to spend more time in matches to allow very fast string
++ * insertions and avoid deletions. The matching algorithm for small
++ * strings is inspired from that of Rabin &amp; Karp. A brute force approach
++ * is used to find longer strings when a small match has been found.
++ * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
++ * (by Leonid Broukhis).
++ * A previous version of this file used a more sophisticated algorithm
++ * (by Fiala and Greene) which is guaranteed to run in linear amortized
++ * time, but has a larger average cost, uses more memory and is patented.
++ * However the F&amp;G algorithm may be faster for some highly redundant
++ * files if the parameter max_chain_length (described below) is too large.
++ *
++ * ACKNOWLEDGEMENTS
++ *
++ * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
++ * I found it in 'freeze' written by Leonid Broukhis.
++ * Thanks to many people for bug reports and testing.
++ *
++ * REFERENCES
++ *
++ * Deutsch, L.P.,&quot;'Deflate' Compressed Data Format Specification&quot;.
++ * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
++ *
++ * A description of the Rabin and Karp algorithm is given in the book
++ * &quot;Algorithms&quot; by R. Sedgewick, Addison-Wesley, p252.
++ *
++ * Fiala,E.R., and Greene,D.H.
++ * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
++ *
++ */
++
++/* From: deflate.c,v 1.8 1995/05/03 17:27:08 jloup Exp */
++
++local char zlib_copyright[] = &quot; deflate Copyright 1995 Jean-loup Gailly &quot;;
++/*
++ If you use the zlib library in a product, an acknowledgment is welcome
++ in the documentation of your product. If for some reason you cannot
++ include such an acknowledgment, I would appreciate that you keep this
++ copyright string in the executable of your product.
++ */
++
++#define NIL 0
++/* Tail of hash chains */
++
++#ifndef TOO_FAR
++# define TOO_FAR 4096
++#endif
++/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
++
++#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
++/* Minimum amount of lookahead, except at the end of the input file.
++ * See deflate.c for comments about the MIN_MATCH+1.
++ */
++
++/* Values for max_lazy_match, good_match and max_chain_length, depending on
++ * the desired pack level (0..9). The values given below have been tuned to
++ * exclude worst case performance for pathological files. Better values may be
++ * found for specific files.
++ */
++
++typedef struct config_s {
++ ush good_length; /* reduce lazy search above this match length */
++ ush max_lazy; /* do not perform lazy search above this match length */
++ ush nice_length; /* quit search above this match length */
++ ush max_chain;
++} config;
++
++local config configuration_table[10] = {
++/* good lazy nice chain */
++/* 0 */ {0, 0, 0, 0}, /* store only */
++/* 1 */ {4, 4, 8, 4}, /* maximum speed, no lazy matches */
++/* 2 */ {4, 5, 16, 8},
++/* 3 */ {4, 6, 32, 32},
++
++/* 4 */ {4, 4, 16, 16}, /* lazy matches */
++/* 5 */ {8, 16, 32, 32},
++/* 6 */ {8, 16, 128, 128},
++/* 7 */ {8, 32, 128, 256},
++/* 8 */ {32, 128, 258, 1024},
++/* 9 */ {32, 258, 258, 4096}}; /* maximum compression */
++
++/* Note: the deflate() code requires max_lazy &gt;= MIN_MATCH and max_chain &gt;= 4
++ * For deflate_fast() (levels &lt;= 3) good is ignored and lazy has a different
++ * meaning.
++ */
++
++#define EQUAL 0
++/* result of memcmp for equal strings */
++
++/* ===========================================================================
++ * Prototypes for local functions.
++ */
++
++local void fill_window OF((deflate_state *s));
++local int deflate_fast OF((deflate_state *s, int flush));
++local int deflate_slow OF((deflate_state *s, int flush));
++local void lm_init OF((deflate_state *s));
++local int longest_match OF((deflate_state *s, IPos cur_match));
++local void putShortMSB OF((deflate_state *s, uInt b));
++local void flush_pending OF((z_stream *strm));
++local int read_buf OF((z_stream *strm, charf *buf, unsigned size));
++#ifdef ASMV
++ void match_init OF((void)); /* asm code initialization */
++#endif
++
++#ifdef DEBUG_ZLIB
++local void check_match OF((deflate_state *s, IPos start, IPos match,
++ int length));
++#endif
++
++
++/* ===========================================================================
++ * Update a hash value with the given input byte
++ * IN assertion: all calls to to UPDATE_HASH are made with consecutive
++ * input characters, so that a running hash key can be computed from the
++ * previous key instead of complete recalculation each time.
++ */
++#define UPDATE_HASH(s,h,c) (h = (((h)&lt;&lt;s-&gt;hash_shift) ^ (c)) &amp; s-&gt;hash_mask)
++
++
++/* ===========================================================================
++ * Insert string str in the dictionary and set match_head to the previous head
++ * of the hash chain (the most recent string with same hash key). Return
++ * the previous length of the hash chain.
++ * IN assertion: all calls to to INSERT_STRING are made with consecutive
++ * input characters and the first MIN_MATCH bytes of str are valid
++ * (except for the last MIN_MATCH-1 bytes of the input file).
++ */
++#define INSERT_STRING(s, str, match_head) \
++ (UPDATE_HASH(s, s-&gt;ins_h, s-&gt;window[(str) + (MIN_MATCH-1)]), \
++ s-&gt;prev[(str) &amp; s-&gt;w_mask] = match_head = s-&gt;head[s-&gt;ins_h], \
++ s-&gt;head[s-&gt;ins_h] = (str))
++
++/* ===========================================================================
++ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
++ * prev[] will be initialized on the fly.
++ */
++#define CLEAR_HASH(s) \
++ s-&gt;head[s-&gt;hash_size-1] = NIL; \
++ zmemzero((charf *)s-&gt;head, (unsigned)(s-&gt;hash_size-1)*sizeof(*s-&gt;head));
++
++/* ========================================================================= */
++int deflateInit (strm, level)
++ z_stream *strm;
++ int level;
++{
++ return deflateInit2 (strm, level, DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
++ 0, 0);
++ /* To do: ignore strm-&gt;next_in if we use it as window */
++}
++
++/* ========================================================================= */
++int deflateInit2 (strm, level, method, windowBits, memLevel,
++ strategy, minCompression)
++ z_stream *strm;
++ int level;
++ int method;
++ int windowBits;
++ int memLevel;
++ int strategy;
++ int minCompression;
++{
++ deflate_state *s;
++ int noheader = 0;
++
++ if (strm == Z_NULL) return Z_STREAM_ERROR;
++
++ strm-&gt;msg = Z_NULL;
++/* if (strm-&gt;zalloc == Z_NULL) strm-&gt;zalloc = zcalloc; */
++/* if (strm-&gt;zfree == Z_NULL) strm-&gt;zfree = zcfree; */
++
++ if (level == Z_DEFAULT_COMPRESSION) level = 6;
++
++ if (windowBits &lt; 0) { /* undocumented feature: suppress zlib header */
++ noheader = 1;
++ windowBits = -windowBits;
++ }
++ if (memLevel &lt; 1 || memLevel &gt; MAX_MEM_LEVEL || method != DEFLATED ||
++ windowBits &lt; 8 || windowBits &gt; 15 || level &lt; 1 || level &gt; 9) {
++ return Z_STREAM_ERROR;
++ }
++ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
++ if (s == Z_NULL) return Z_MEM_ERROR;
++ strm-&gt;state = (struct internal_state FAR *)s;
++ s-&gt;strm = strm;
++
++ s-&gt;noheader = noheader;
++ s-&gt;w_bits = windowBits;
++ s-&gt;w_size = 1 &lt;&lt; s-&gt;w_bits;
++ s-&gt;w_mask = s-&gt;w_size - 1;
++
++ s-&gt;hash_bits = memLevel + 7;
++ s-&gt;hash_size = 1 &lt;&lt; s-&gt;hash_bits;
++ s-&gt;hash_mask = s-&gt;hash_size - 1;
++ s-&gt;hash_shift = ((s-&gt;hash_bits+MIN_MATCH-1)/MIN_MATCH);
++
++ s-&gt;window = (Bytef *) ZALLOC(strm, s-&gt;w_size, 2*sizeof(Byte));
++ s-&gt;prev = (Posf *) ZALLOC(strm, s-&gt;w_size, sizeof(Pos));
++ s-&gt;head = (Posf *) ZALLOC(strm, s-&gt;hash_size, sizeof(Pos));
++
++ s-&gt;lit_bufsize = 1 &lt;&lt; (memLevel + 6); /* 16K elements by default */
++
++ s-&gt;pending_buf = (uchf *) ZALLOC(strm, s-&gt;lit_bufsize, 2*sizeof(ush));
++
++ if (s-&gt;window == Z_NULL || s-&gt;prev == Z_NULL || s-&gt;head == Z_NULL ||
++ s-&gt;pending_buf == Z_NULL) {
++ strm-&gt;msg = z_errmsg[1-Z_MEM_ERROR];
++ deflateEnd (strm);
++ return Z_MEM_ERROR;
++ }
++ s-&gt;d_buf = (ushf *) &amp;(s-&gt;pending_buf[s-&gt;lit_bufsize]);
++ s-&gt;l_buf = (uchf *) &amp;(s-&gt;pending_buf[3*s-&gt;lit_bufsize]);
++ /* We overlay pending_buf and d_buf+l_buf. This works since the average
++ * output size for (length,distance) codes is &lt;= 32 bits (worst case
++ * is 15+15+13=33).
++ */
++
++ s-&gt;level = level;
++ s-&gt;strategy = strategy;
++ s-&gt;method = (Byte)method;
++ s-&gt;minCompr = minCompression;
++ s-&gt;blocks_in_packet = 0;
++
++ return deflateReset(strm);
++}
++
++/* ========================================================================= */
++int deflateReset (strm)
++ z_stream *strm;
++{
++ deflate_state *s;
++
++ if (strm == Z_NULL || strm-&gt;state == Z_NULL ||
++ strm-&gt;zalloc == Z_NULL || strm-&gt;zfree == Z_NULL) return Z_STREAM_ERROR;
++
++ strm-&gt;total_in = strm-&gt;total_out = 0;
++ strm-&gt;msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
++ strm-&gt;data_type = Z_UNKNOWN;
++
++ s = (deflate_state *)strm-&gt;state;
++ s-&gt;pending = 0;
++ s-&gt;pending_out = s-&gt;pending_buf;
++
++ if (s-&gt;noheader &lt; 0) {
++ s-&gt;noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */
++ }
++ s-&gt;status = s-&gt;noheader ? BUSY_STATE : INIT_STATE;
++ s-&gt;adler = 1;
++
++ ct_init(s);
++ lm_init(s);
++
++ return Z_OK;
++}
++
++/* =========================================================================
++ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
++ * IN assertion: the stream state is correct and there is enough room in
++ * pending_buf.
++ */
++local void putShortMSB (s, b)
++ deflate_state *s;
++ uInt b;
++{
++ put_byte(s, (Byte)(b &gt;&gt; 8));
++ put_byte(s, (Byte)(b &amp; 0xff));
++}
++
++/* =========================================================================
++ * Flush as much pending output as possible.
++ */
++local void flush_pending(strm)
++ z_stream *strm;
++{
++ deflate_state *state = (deflate_state *) strm-&gt;state;
++ unsigned len = state-&gt;pending;
++
++ if (len &gt; strm-&gt;avail_out) len = strm-&gt;avail_out;
++ if (len == 0) return;
++
++ if (strm-&gt;next_out != NULL) {
++ zmemcpy(strm-&gt;next_out, state-&gt;pending_out, len);
++ strm-&gt;next_out += len;
++ }
++ state-&gt;pending_out += len;
++ strm-&gt;total_out += len;
++ strm-&gt;avail_out -= len;
++ state-&gt;pending -= len;
++ if (state-&gt;pending == 0) {
++ state-&gt;pending_out = state-&gt;pending_buf;
++ }
++}
++
++/* ========================================================================= */
++int deflate (strm, flush)
++ z_stream *strm;
++ int flush;
++{
++ deflate_state *state = (deflate_state *) strm-&gt;state;
++
++ if (strm == Z_NULL || state == Z_NULL) return Z_STREAM_ERROR;
++
++ if (strm-&gt;next_in == Z_NULL &amp;&amp; strm-&gt;avail_in != 0) {
++ ERR_RETURN(strm, Z_STREAM_ERROR);
++ }
++ if (strm-&gt;avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
++
++ state-&gt;strm = strm; /* just in case */
++
++ /* Write the zlib header */
++ if (state-&gt;status == INIT_STATE) {
++
++ uInt header = (DEFLATED + ((state-&gt;w_bits-8)&lt;&lt;4)) &lt;&lt; 8;
++ uInt level_flags = (state-&gt;level-1) &gt;&gt; 1;
++
++ if (level_flags &gt; 3) level_flags = 3;
++ header |= (level_flags &lt;&lt; 6);
++ header += 31 - (header % 31);
++
++ state-&gt;status = BUSY_STATE;
++ putShortMSB(state, header);
++ }
++
++ /* Flush as much pending output as possible */
++ if (state-&gt;pending != 0) {
++ flush_pending(strm);
++ if (strm-&gt;avail_out == 0) return Z_OK;
++ }
++
++ /* If we came back in here to get the last output from
++ * a previous flush, we're done for now.
++ */
++ if (state-&gt;status == FLUSH_STATE) {
++ state-&gt;status = BUSY_STATE;
++ if (flush != Z_NO_FLUSH &amp;&amp; flush != Z_FINISH)
++ return Z_OK;
++ }
++
++ /* User must not provide more input after the first FINISH: */
++ if (state-&gt;status == FINISH_STATE &amp;&amp; strm-&gt;avail_in != 0) {
++ ERR_RETURN(strm, Z_BUF_ERROR);
++ }
++
++ /* Start a new block or continue the current one.
++ */
++ if (strm-&gt;avail_in != 0 || state-&gt;lookahead != 0 ||
++ (flush == Z_FINISH &amp;&amp; state-&gt;status != FINISH_STATE)) {
++ int quit;
++
++ if (flush == Z_FINISH) {
++ state-&gt;status = FINISH_STATE;
++ }
++ if (state-&gt;level &lt;= 3) {
++ quit = deflate_fast(state, flush);
++ } else {
++ quit = deflate_slow(state, flush);
++ }
++ if (quit || strm-&gt;avail_out == 0)
++ return Z_OK;
++ /* If flush != Z_NO_FLUSH &amp;&amp; avail_out == 0, the next call
++ * of deflate should use the same flush parameter to make sure
++ * that the flush is complete. So we don't have to output an
++ * empty block here, this will be done at next call. This also
++ * ensures that for a very small output buffer, we emit at most
++ * one empty block.
++ */
++ }
++
++ /* If a flush was requested, we have a little more to output now. */
++ if (flush != Z_NO_FLUSH &amp;&amp; flush != Z_FINISH
++ &amp;&amp; state-&gt;status != FINISH_STATE) {
++ switch (flush) {
++ case Z_PARTIAL_FLUSH:
++ ct_align(state);
++ break;
++ case Z_PACKET_FLUSH:
++ /* Output just the 3-bit `stored' block type value,
++ but not a zero length. */
++ ct_stored_type_only(state);
++ break;
++ default:
++ ct_stored_block(state, (char*)0, 0L, 0);
++ /* For a full flush, this empty block will be recognized
++ * as a special marker by inflate_sync().
++ */
++ if (flush == Z_FULL_FLUSH) {
++ CLEAR_HASH(state); /* forget history */
++ }
++ }
++ flush_pending(strm);
++ if (strm-&gt;avail_out == 0) {
++ /* We'll have to come back to get the rest of the output;
++ * this ensures we don't output a second zero-length stored
++ * block (or whatever).
++ */
++ state-&gt;status = FLUSH_STATE;
++ return Z_OK;
++ }
++ }
++
++ Assert(strm-&gt;avail_out &gt; 0, &quot;bug2&quot;);
++
++ if (flush != Z_FINISH) return Z_OK;
++ if (state-&gt;noheader) return Z_STREAM_END;
++
++ /* Write the zlib trailer (adler32) */
++ putShortMSB(state, (uInt)(state-&gt;adler &gt;&gt; 16));
++ putShortMSB(state, (uInt)(state-&gt;adler &amp; 0xffff));
++ flush_pending(strm);
++ /* If avail_out is zero, the application will call deflate again
++ * to flush the rest.
++ */
++ state-&gt;noheader = -1; /* write the trailer only once! */
++ return state-&gt;pending != 0 ? Z_OK : Z_STREAM_END;
++}
++
++/* ========================================================================= */
++int deflateEnd (strm)
++ z_stream *strm;
++{
++ deflate_state *state = (deflate_state *) strm-&gt;state;
++
++ if (strm == Z_NULL || state == Z_NULL) return Z_STREAM_ERROR;
++
++ TRY_FREE(strm, state-&gt;window, state-&gt;w_size * 2 * sizeof(Byte));
++ TRY_FREE(strm, state-&gt;prev, state-&gt;w_size * sizeof(Pos));
++ TRY_FREE(strm, state-&gt;head, state-&gt;hash_size * sizeof(Pos));
++ TRY_FREE(strm, state-&gt;pending_buf, state-&gt;lit_bufsize * 2 * sizeof(ush));
++
++ ZFREE(strm, state, sizeof(deflate_state));
++ strm-&gt;state = Z_NULL;
++
++ return Z_OK;
++}
++
++/* ===========================================================================
++ * Read a new buffer from the current input stream, update the adler32
++ * and total number of bytes read.
++ */
++local int read_buf(strm, buf, size)
++ z_stream *strm;
++ charf *buf;
++ unsigned size;
++{
++ unsigned len = strm-&gt;avail_in;
++ deflate_state *state = (deflate_state *) strm-&gt;state;
++
++ if (len &gt; size) len = size;
++ if (len == 0) return 0;
++
++ strm-&gt;avail_in -= len;
++
++ if (!state-&gt;noheader) {
++ state-&gt;adler = adler32(state-&gt;adler, strm-&gt;next_in, len);
++ }
++ zmemcpy(buf, strm-&gt;next_in, len);
++ strm-&gt;next_in += len;
++ strm-&gt;total_in += len;
++
++ return (int)len;
++}
++
++/* ===========================================================================
++ * Initialize the &quot;longest match&quot; routines for a new zlib stream
++ */
++local void lm_init (s)
++ deflate_state *s;
++{
++ s-&gt;window_size = (ulg)2L*s-&gt;w_size;
++
++ CLEAR_HASH(s);
++
++ /* Set the default configuration parameters:
++ */
++ s-&gt;max_lazy_match = configuration_table[s-&gt;level].max_lazy;
++ s-&gt;good_match = configuration_table[s-&gt;level].good_length;
++ s-&gt;nice_match = configuration_table[s-&gt;level].nice_length;
++ s-&gt;max_chain_length = configuration_table[s-&gt;level].max_chain;
++
++ s-&gt;strstart = 0;
++ s-&gt;block_start = 0L;
++ s-&gt;lookahead = 0;
++ s-&gt;match_length = MIN_MATCH-1;
++ s-&gt;match_available = 0;
++ s-&gt;ins_h = 0;
++#ifdef ASMV
++ match_init(); /* initialize the asm code */
++#endif
++}
++
++/* ===========================================================================
++ * Set match_start to the longest match starting at the given string and
++ * return its length. Matches shorter or equal to prev_length are discarded,
++ * in which case the result is equal to prev_length and match_start is
++ * garbage.
++ * IN assertions: cur_match is the head of the hash chain for the current
++ * string (strstart) and its distance is &lt;= MAX_DIST, and prev_length &gt;= 1
++ */
++#ifndef ASMV
++/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
++ * match.S. The code will be functionally equivalent.
++ */
++local int longest_match(s, cur_match)
++ deflate_state *s;
++ IPos cur_match; /* current match */
++{
++ unsigned chain_length = s-&gt;max_chain_length;/* max hash chain length */
++ register Bytef *scan = s-&gt;window + s-&gt;strstart; /* current string */
++ register Bytef *match; /* matched string */
++ register int len; /* length of current match */
++ int best_len = s-&gt;prev_length; /* best match length so far */
++ IPos limit = s-&gt;strstart &gt; (IPos)MAX_DIST(s) ?
++ s-&gt;strstart - (IPos)MAX_DIST(s) : NIL;
++ /* Stop when cur_match becomes &lt;= limit. To simplify the code,
++ * we prevent matches with the string of window index 0.
++ */
++ Posf *prev = s-&gt;prev;
++ uInt wmask = s-&gt;w_mask;
++
++#ifdef UNALIGNED_OK
++ /* Compare two bytes at a time. Note: this is not always beneficial.
++ * Try with and without -DUNALIGNED_OK to check.
++ */
++ register Bytef *strend = s-&gt;window + s-&gt;strstart + MAX_MATCH - 1;
++ register ush scan_start = *(ushf*)scan;
++ register ush scan_end = *(ushf*)(scan+best_len-1);
++#else
++ register Bytef *strend = s-&gt;window + s-&gt;strstart + MAX_MATCH;
++ register Byte scan_end1 = scan[best_len-1];
++ register Byte scan_end = scan[best_len];
++#endif
++
++ /* The code is optimized for HASH_BITS &gt;= 8 and MAX_MATCH-2 multiple of 16.
++ * It is easy to get rid of this optimization if necessary.
++ */
++ Assert(s-&gt;hash_bits &gt;= 8 &amp;&amp; MAX_MATCH == 258, &quot;Code too clever&quot;);
++
++ /* Do not waste too much time if we already have a good match: */
++ if (s-&gt;prev_length &gt;= s-&gt;good_match) {
++ chain_length &gt;&gt;= 2;
++ }
++ Assert((ulg)s-&gt;strstart &lt;= s-&gt;window_size-MIN_LOOKAHEAD, &quot;need lookahead&quot;);
++
++ do {
++ Assert(cur_match &lt; s-&gt;strstart, &quot;no future&quot;);
++ match = s-&gt;window + cur_match;
++
++ /* Skip to next match if the match length cannot increase
++ * or if the match length is less than 2:
++ */
++#if (defined(UNALIGNED_OK) &amp;&amp; MAX_MATCH == 258)
++ /* This code assumes sizeof(unsigned short) == 2. Do not use
++ * UNALIGNED_OK if your compiler uses a different size.
++ */
++ if (*(ushf*)(match+best_len-1) != scan_end ||
++ *(ushf*)match != scan_start) continue;
++
++ /* It is not necessary to compare scan[2] and match[2] since they are
++ * always equal when the other bytes match, given that the hash keys
++ * are equal and that HASH_BITS &gt;= 8. Compare 2 bytes at a time at
++ * strstart+3, +5, ... up to strstart+257. We check for insufficient
++ * lookahead only every 4th comparison; the 128th check will be made
++ * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
++ * necessary to put more guard bytes at the end of the window, or
++ * to check more often for insufficient lookahead.
++ */
++ Assert(scan[2] == match[2], &quot;scan[2]?&quot;);
++ scan++, match++;
++ do {
++ } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &amp;&amp;
++ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &amp;&amp;
++ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &amp;&amp;
++ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &amp;&amp;
++ scan &lt; strend);
++ /* The funny &quot;do {}&quot; generates better code on most compilers */
++
++ /* Here, scan &lt;= window+strstart+257 */
++ Assert(scan &lt;= s-&gt;window+(unsigned)(s-&gt;window_size-1), &quot;wild scan&quot;);
++ if (*scan == *match) scan++;
++
++ len = (MAX_MATCH - 1) - (int)(strend-scan);
++ scan = strend - (MAX_MATCH-1);
++
++#else /* UNALIGNED_OK */
++
++ if (match[best_len] != scan_end ||
++ match[best_len-1] != scan_end1 ||
++ *match != *scan ||
++ *++match != scan[1]) continue;
++
++ /* The check at best_len-1 can be removed because it will be made
++ * again later. (This heuristic is not always a win.)
++ * It is not necessary to compare scan[2] and match[2] since they
++ * are always equal when the other bytes match, given that
++ * the hash keys are equal and that HASH_BITS &gt;= 8.
++ */
++ scan += 2, match++;
++ Assert(*scan == *match, &quot;match[2]?&quot;);
++
++ /* We check for insufficient lookahead only every 8th comparison;
++ * the 256th check will be made at strstart+258.
++ */
++ do {
++ } while (*++scan == *++match &amp;&amp; *++scan == *++match &amp;&amp;
++ *++scan == *++match &amp;&amp; *++scan == *++match &amp;&amp;
++ *++scan == *++match &amp;&amp; *++scan == *++match &amp;&amp;
++ *++scan == *++match &amp;&amp; *++scan == *++match &amp;&amp;
++ scan &lt; strend);
++
++ Assert(scan &lt;= s-&gt;window+(unsigned)(s-&gt;window_size-1), &quot;wild scan&quot;);
++
++ len = MAX_MATCH - (int)(strend - scan);
++ scan = strend - MAX_MATCH;
++
++#endif /* UNALIGNED_OK */
++
++ if (len &gt; best_len) {
++ s-&gt;match_start = cur_match;
++ best_len = len;
++ if (len &gt;= s-&gt;nice_match) break;
++#ifdef UNALIGNED_OK
++ scan_end = *(ushf*)(scan+best_len-1);
++#else
++ scan_end1 = scan[best_len-1];
++ scan_end = scan[best_len];
++#endif
++ }
++ } while ((cur_match = prev[cur_match &amp; wmask]) &gt; limit
++ &amp;&amp; --chain_length != 0);
++
++ return best_len;
++}
++#endif /* ASMV */
++
++#ifdef DEBUG_ZLIB
++/* ===========================================================================
++ * Check that the match at match_start is indeed a match.
++ */
++local void check_match(s, start, match, length)
++ deflate_state *s;
++ IPos start, match;
++ int length;
++{
++ /* check that the match is indeed a match */
++ if (memcmp((charf *)s-&gt;window + match,
++ (charf *)s-&gt;window + start, length) != EQUAL) {
++ fprintf(stderr,
++ &quot; start %u, match %u, length %d\n&quot;,
++ start, match, length);
++ do { fprintf(stderr, &quot;%c%c&quot;, s-&gt;window[match++],
++ s-&gt;window[start++]); } while (--length != 0);
++ z_error(&quot;invalid match&quot;);
++ }
++ if (verbose &gt; 1) {
++ fprintf(stderr,&quot;\\[%d,%d]&quot;, start-match, length);
++ do { putc(s-&gt;window[start++], stderr); } while (--length != 0);
++ }
++}
++#else
++# define check_match(s, start, match, length)
++#endif
++
++/* ===========================================================================
++ * Fill the window when the lookahead becomes insufficient.
++ * Updates strstart and lookahead.
++ *
++ * IN assertion: lookahead &lt; MIN_LOOKAHEAD
++ * OUT assertions: strstart &lt;= window_size-MIN_LOOKAHEAD
++ * At least one byte has been read, or avail_in == 0; reads are
++ * performed for at least two bytes (required for the zip translate_eol
++ * option -- not supported here).
++ */
++local void fill_window(s)
++ deflate_state *s;
++{
++ register unsigned n, m;
++ register Posf *p;
++ unsigned more; /* Amount of free space at the end of the window. */
++ uInt wsize = s-&gt;w_size;
++
++ do {
++ more = (unsigned)(s-&gt;window_size -(ulg)s-&gt;lookahead -(ulg)s-&gt;strstart);
++
++ /* Deal with !@#$% 64K limit: */
++ if (more == 0 &amp;&amp; s-&gt;strstart == 0 &amp;&amp; s-&gt;lookahead == 0) {
++ more = wsize;
++ } else if (more == (unsigned)(-1)) {
++ /* Very unlikely, but possible on 16 bit machine if strstart == 0
++ * and lookahead == 1 (input done one byte at time)
++ */
++ more--;
++
++ /* If the window is almost full and there is insufficient lookahead,
++ * move the upper half to the lower one to make room in the upper half.
++ */
++ } else if (s-&gt;strstart &gt;= wsize+MAX_DIST(s)) {
++
++ /* By the IN assertion, the window is not empty so we can't confuse
++ * more == 0 with more == 64K on a 16 bit machine.
++ */
++ zmemcpy((charf *)s-&gt;window, (charf *)s-&gt;window+wsize,
++ (unsigned)wsize);
++ s-&gt;match_start -= wsize;
++ s-&gt;strstart -= wsize; /* we now have strstart &gt;= MAX_DIST */
++
++ s-&gt;block_start -= (long) wsize;
++
++ /* Slide the hash table (could be avoided with 32 bit values
++ at the expense of memory usage):
++ */
++ n = s-&gt;hash_size;
++ p = &amp;s-&gt;head[n];
++ do {
++ m = *--p;
++ *p = (Pos)(m &gt;= wsize ? m-wsize : NIL);
++ } while (--n);
++
++ n = wsize;
++ p = &amp;s-&gt;prev[n];
++ do {
++ m = *--p;
++ *p = (Pos)(m &gt;= wsize ? m-wsize : NIL);
++ /* If n is not on any hash chain, prev[n] is garbage but
++ * its value will never be used.
++ */
++ } while (--n);
++
++ more += wsize;
++ }
++ if (s-&gt;strm-&gt;avail_in == 0) return;
++
++ /* If there was no sliding:
++ * strstart &lt;= WSIZE+MAX_DIST-1 &amp;&amp; lookahead &lt;= MIN_LOOKAHEAD - 1 &amp;&amp;
++ * more == window_size - lookahead - strstart
++ * =&gt; more &gt;= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
++ * =&gt; more &gt;= window_size - 2*WSIZE + 2
++ * In the BIG_MEM or MMAP case (not yet supported),
++ * window_size == input_size + MIN_LOOKAHEAD &amp;&amp;
++ * strstart + s-&gt;lookahead &lt;= input_size =&gt; more &gt;= MIN_LOOKAHEAD.
++ * Otherwise, window_size == 2*WSIZE so more &gt;= 2.
++ * If there was sliding, more &gt;= WSIZE. So in all cases, more &gt;= 2.
++ */
++ Assert(more &gt;= 2, &quot;more &lt; 2&quot;);
++
++ n = read_buf(s-&gt;strm, (charf *)s-&gt;window + s-&gt;strstart + s-&gt;lookahead,
++ more);
++ s-&gt;lookahead += n;
++
++ /* Initialize the hash value now that we have some input: */
++ if (s-&gt;lookahead &gt;= MIN_MATCH) {
++ s-&gt;ins_h = s-&gt;window[s-&gt;strstart];
++ UPDATE_HASH(s, s-&gt;ins_h, s-&gt;window[s-&gt;strstart+1]);
++#if MIN_MATCH != 3
++ Call UPDATE_HASH() MIN_MATCH-3 more times
++#endif
++ }
++ /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
++ * but this is not important since only literal bytes will be emitted.
++ */
++
++ } while (s-&gt;lookahead &lt; MIN_LOOKAHEAD &amp;&amp; s-&gt;strm-&gt;avail_in != 0);
++}
++
++/* ===========================================================================
++ * Flush the current block, with given end-of-file flag.
++ * IN assertion: strstart is set to the end of the current match.
++ */
++#define FLUSH_BLOCK_ONLY(s, flush) { \
++ ct_flush_block(s, (s-&gt;block_start &gt;= 0L ? \
++ (charf *)&amp;s-&gt;window[(unsigned)s-&gt;block_start] : \
++ (charf *)Z_NULL), (long)s-&gt;strstart - s-&gt;block_start, (flush)); \
++ s-&gt;block_start = s-&gt;strstart; \
++ flush_pending(s-&gt;strm); \
++ Tracev((stderr,&quot;[FLUSH]&quot;)); \
++}
++
++/* Same but force premature exit if necessary. */
++#define FLUSH_BLOCK(s, flush) { \
++ FLUSH_BLOCK_ONLY(s, flush); \
++ if (s-&gt;strm-&gt;avail_out == 0) return 1; \
++}
++
++/* ===========================================================================
++ * Compress as much as possible from the input stream, return true if
++ * processing was terminated prematurely (no more input or output space).
++ * This function does not perform lazy evaluationof matches and inserts
++ * new strings in the dictionary only for unmatched strings or for short
++ * matches. It is used only for the fast compression options.
++ */
++local int deflate_fast(s, flush)
++ deflate_state *s;
++ int flush;
++{
++ IPos hash_head = NIL; /* head of the hash chain */
++ int bflush; /* set if current block must be flushed */
++
++ s-&gt;prev_length = MIN_MATCH-1;
++
++ for (;;) {
++ /* Make sure that we always have enough lookahead, except
++ * at the end of the input file. We need MAX_MATCH bytes
++ * for the next match, plus MIN_MATCH bytes to insert the
++ * string following the next match.
++ */
++ if (s-&gt;lookahead &lt; MIN_LOOKAHEAD) {
++ fill_window(s);
++ if (s-&gt;lookahead &lt; MIN_LOOKAHEAD &amp;&amp; flush == Z_NO_FLUSH) return 1;
++
++ if (s-&gt;lookahead == 0) break; /* flush the current block */
++ }
++
++ /* Insert the string window[strstart .. strstart+2] in the
++ * dictionary, and set hash_head to the head of the hash chain:
++ */
++ if (s-&gt;lookahead &gt;= MIN_MATCH) {
++ INSERT_STRING(s, s-&gt;strstart, hash_head);
++ }
++
++ /* Find the longest match, discarding those &lt;= prev_length.
++ * At this point we have always match_length &lt; MIN_MATCH
++ */
++ if (hash_head != NIL &amp;&amp; s-&gt;strstart - hash_head &lt;= MAX_DIST(s)) {
++ /* To simplify the code, we prevent matches with the string
++ * of window index 0 (in particular we have to avoid a match
++ * of the string with itself at the start of the input file).
++ */
++ if (s-&gt;strategy != Z_HUFFMAN_ONLY) {
++ s-&gt;match_length = longest_match (s, hash_head);
++ }
++ /* longest_match() sets match_start */
++
++ if (s-&gt;match_length &gt; s-&gt;lookahead) s-&gt;match_length = s-&gt;lookahead;
++ }
++ if (s-&gt;match_length &gt;= MIN_MATCH) {
++ check_match(s, s-&gt;strstart, s-&gt;match_start, s-&gt;match_length);
++
++ bflush = ct_tally(s, s-&gt;strstart - s-&gt;match_start,
++ s-&gt;match_length - MIN_MATCH);
++
++ s-&gt;lookahead -= s-&gt;match_length;
++
++ /* Insert new strings in the hash table only if the match length
++ * is not too large. This saves time but degrades compression.
++ */
++ if (s-&gt;match_length &lt;= s-&gt;max_insert_length &amp;&amp;
++ s-&gt;lookahead &gt;= MIN_MATCH) {
++ s-&gt;match_length--; /* string at strstart already in hash table */
++ do {
++ s-&gt;strstart++;
++ INSERT_STRING(s, s-&gt;strstart, hash_head);
++ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
++ * always MIN_MATCH bytes ahead.
++ */
++ } while (--s-&gt;match_length != 0);
++ s-&gt;strstart++;
++ } else {
++ s-&gt;strstart += s-&gt;match_length;
++ s-&gt;match_length = 0;
++ s-&gt;ins_h = s-&gt;window[s-&gt;strstart];
++ UPDATE_HASH(s, s-&gt;ins_h, s-&gt;window[s-&gt;strstart+1]);
++#if MIN_MATCH != 3
++ Call UPDATE_HASH() MIN_MATCH-3 more times
++#endif
++ /* If lookahead &lt; MIN_MATCH, ins_h is garbage, but it does not
++ * matter since it will be recomputed at next deflate call.
++ */
++ }
++ } else {
++ /* No match, output a literal byte */
++ Tracevv((stderr,&quot;%c&quot;, s-&gt;window[s-&gt;strstart]));
++ bflush = ct_tally (s, 0, s-&gt;window[s-&gt;strstart]);
++ s-&gt;lookahead--;
++ s-&gt;strstart++;
++ }
++ if (bflush) FLUSH_BLOCK(s, Z_NO_FLUSH);
++ }
++ FLUSH_BLOCK(s, flush);
++ return 0; /* normal exit */
++}
++
++/* ===========================================================================
++ * Same as above, but achieves better compression. We use a lazy
++ * evaluation for matches: a match is finally adopted only if there is
++ * no better match at the next window position.
++ */
++local int deflate_slow(s, flush)
++ deflate_state *s;
++ int flush;
++{
++ IPos hash_head = NIL; /* head of hash chain */
++ int bflush; /* set if current block must be flushed */
++
++ /* Process the input block. */
++ for (;;) {
++ /* Make sure that we always have enough lookahead, except
++ * at the end of the input file. We need MAX_MATCH bytes
++ * for the next match, plus MIN_MATCH bytes to insert the
++ * string following the next match.
++ */
++ if (s-&gt;lookahead &lt; MIN_LOOKAHEAD) {
++ fill_window(s);
++ if (s-&gt;lookahead &lt; MIN_LOOKAHEAD &amp;&amp; flush == Z_NO_FLUSH) return 1;
++
++ if (s-&gt;lookahead == 0) break; /* flush the current block */
++ }
++
++ /* Insert the string window[strstart .. strstart+2] in the
++ * dictionary, and set hash_head to the head of the hash chain:
++ */
++ if (s-&gt;lookahead &gt;= MIN_MATCH) {
++ INSERT_STRING(s, s-&gt;strstart, hash_head);
++ }
++
++ /* Find the longest match, discarding those &lt;= prev_length.
++ */
++ s-&gt;prev_length = s-&gt;match_length, s-&gt;prev_match = s-&gt;match_start;
++ s-&gt;match_length = MIN_MATCH-1;
++
++ if (hash_head != NIL &amp;&amp; s-&gt;prev_length &lt; s-&gt;max_lazy_match &amp;&amp;
++ s-&gt;strstart - hash_head &lt;= MAX_DIST(s)) {
++ /* To simplify the code, we prevent matches with the string
++ * of window index 0 (in particular we have to avoid a match
++ * of the string with itself at the start of the input file).
++ */
++ if (s-&gt;strategy != Z_HUFFMAN_ONLY) {
++ s-&gt;match_length = longest_match (s, hash_head);
++ }
++ /* longest_match() sets match_start */
++ if (s-&gt;match_length &gt; s-&gt;lookahead) s-&gt;match_length = s-&gt;lookahead;
++
++ if (s-&gt;match_length &lt;= 5 &amp;&amp; (s-&gt;strategy == Z_FILTERED ||
++ (s-&gt;match_length == MIN_MATCH &amp;&amp;
++ s-&gt;strstart - s-&gt;match_start &gt; TOO_FAR))) {
++
++ /* If prev_match is also MIN_MATCH, match_start is garbage
++ * but we will ignore the current match anyway.
++ */
++ s-&gt;match_length = MIN_MATCH-1;
++ }
++ }
++ /* If there was a match at the previous step and the current
++ * match is not better, output the previous match:
++ */
++ if (s-&gt;prev_length &gt;= MIN_MATCH &amp;&amp; s-&gt;match_length &lt;= s-&gt;prev_length) {
++ uInt max_insert = s-&gt;strstart + s-&gt;lookahead - MIN_MATCH;
++ /* Do not insert strings in hash table beyond this. */
++
++ check_match(s, s-&gt;strstart-1, s-&gt;prev_match, s-&gt;prev_length);
++
++ bflush = ct_tally(s, s-&gt;strstart -1 - s-&gt;prev_match,
++ s-&gt;prev_length - MIN_MATCH);
++
++ /* Insert in hash table all strings up to the end of the match.
++ * strstart-1 and strstart are already inserted. If there is not
++ * enough lookahead, the last two strings are not inserted in
++ * the hash table.
++ */
++ s-&gt;lookahead -= s-&gt;prev_length-1;
++ s-&gt;prev_length -= 2;
++ do {
++ if (++s-&gt;strstart &lt;= max_insert) {
++ INSERT_STRING(s, s-&gt;strstart, hash_head);
++ }
++ } while (--s-&gt;prev_length != 0);
++ s-&gt;match_available = 0;
++ s-&gt;match_length = MIN_MATCH-1;
++ s-&gt;strstart++;
++
++ if (bflush) FLUSH_BLOCK(s, Z_NO_FLUSH);
++
++ } else if (s-&gt;match_available) {
++ /* If there was no match at the previous position, output a
++ * single literal. If there was a match but the current match
++ * is longer, truncate the previous match to a single literal.
++ */
++ Tracevv((stderr,&quot;%c&quot;, s-&gt;window[s-&gt;strstart-1]));
++ if (ct_tally (s, 0, s-&gt;window[s-&gt;strstart-1])) {
++ FLUSH_BLOCK_ONLY(s, Z_NO_FLUSH);
++ }
++ s-&gt;strstart++;
++ s-&gt;lookahead--;
++ if (s-&gt;strm-&gt;avail_out == 0) return 1;
++ } else {
++ /* There is no previous match to compare with, wait for
++ * the next step to decide.
++ */
++ s-&gt;match_available = 1;
++ s-&gt;strstart++;
++ s-&gt;lookahead--;
++ }
++ }
++ Assert (flush != Z_NO_FLUSH, &quot;no flush?&quot;);
++ if (s-&gt;match_available) {
++ Tracevv((stderr,&quot;%c&quot;, s-&gt;window[s-&gt;strstart-1]));
++ ct_tally (s, 0, s-&gt;window[s-&gt;strstart-1]);
++ s-&gt;match_available = 0;
++ }
++ FLUSH_BLOCK(s, flush);
++ return 0;
++}
++
++
++/*+++++*/
++/* trees.c -- output deflated data using Huffman coding
++ * Copyright (C) 1995 Jean-loup Gailly
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/*
++ * ALGORITHM
++ *
++ * The &quot;deflation&quot; process uses several Huffman trees. The more
++ * common source values are represented by shorter bit sequences.
++ *
++ * Each code tree is stored in a compressed form which is itself
++ * a Huffman encoding of the lengths of all the code strings (in
++ * ascending order by source values). The actual code strings are
++ * reconstructed from the lengths in the inflate process, as described
++ * in the deflate specification.
++ *
++ * REFERENCES
++ *
++ * Deutsch, L.P.,&quot;'Deflate' Compressed Data Format Specification&quot;.
++ * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
++ *
++ * Storer, James A.
++ * Data Compression: Methods and Theory, pp. 49-50.
++ * Computer Science Press, 1988. ISBN 0-7167-8156-5.
++ *
++ * Sedgewick, R.
++ * Algorithms, p290.
++ * Addison-Wesley, 1983. ISBN 0-201-06672-6.
++ */
++
++/* From: trees.c,v 1.5 1995/05/03 17:27:12 jloup Exp */
++
++#ifdef DEBUG_ZLIB
++# include &lt;ctype.h&gt;
++#endif
++
++/* ===========================================================================
++ * Constants
++ */
++
++#define MAX_BL_BITS 7
++/* Bit length codes must not exceed MAX_BL_BITS bits */
++
++#define END_BLOCK 256
++/* end of block literal code */
++
++#define REP_3_6 16
++/* repeat previous bit length 3-6 times (2 bits of repeat count) */
++
++#define REPZ_3_10 17
++/* repeat a zero length 3-10 times (3 bits of repeat count) */
++
++#define REPZ_11_138 18
++/* repeat a zero length 11-138 times (7 bits of repeat count) */
++
++local int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
++ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
++
++local int extra_dbits[D_CODES] /* extra bits for each distance code */
++ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
++
++local int extra_blbits[BL_CODES]/* extra bits for each bit length code */
++ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
++
++local uch bl_order[BL_CODES]
++ = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
++/* The lengths of the bit length codes are sent in order of decreasing
++ * probability, to avoid transmitting the lengths for unused bit length codes.
++ */
++
++#define Buf_size (8 * 2*sizeof(char))
++/* Number of bits used within bi_buf. (bi_buf might be implemented on
++ * more than 16 bits on some systems.)
++ */
++
++/* ===========================================================================
++ * Local data. These are initialized only once.
++ * To do: initialize at compile time to be completely reentrant. ???
++ */
++
++local ct_data static_ltree[L_CODES+2];
++/* The static literal tree. Since the bit lengths are imposed, there is no
++ * need for the L_CODES extra codes used during heap construction. However
++ * The codes 286 and 287 are needed to build a canonical tree (see ct_init
++ * below).
++ */
++
++local ct_data static_dtree[D_CODES];
++/* The static distance tree. (Actually a trivial tree since all codes use
++ * 5 bits.)
++ */
++
++local uch dist_code[512];
++/* distance codes. The first 256 values correspond to the distances
++ * 3 .. 258, the last 256 values correspond to the top 8 bits of
++ * the 15 bit distances.
++ */
++
++local uch length_code[MAX_MATCH-MIN_MATCH+1];
++/* length code for each normalized match length (0 == MIN_MATCH) */
++
++local int base_length[LENGTH_CODES];
++/* First normalized length for each code (0 = MIN_MATCH) */
++
++local int base_dist[D_CODES];
++/* First normalized distance for each code (0 = distance of 1) */
++
++struct static_tree_desc_s {
++ ct_data *static_tree; /* static tree or NULL */
++ intf *extra_bits; /* extra bits for each code or NULL */
++ int extra_base; /* base index for extra_bits */
++ int elems; /* max number of elements in the tree */
++ int max_length; /* max bit length for the codes */
++};
++
++local static_tree_desc static_l_desc =
++{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
++
++local static_tree_desc static_d_desc =
++{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS};
++
++local static_tree_desc static_bl_desc =
++{(ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS};
++
++/* ===========================================================================
++ * Local (static) routines in this file.
++ */
++
++local void ct_static_init OF((void));
++local void init_block OF((deflate_state *s));
++local void pqdownheap OF((deflate_state *s, ct_data *tree, int k));
++local void gen_bitlen OF((deflate_state *s, tree_desc *desc));
++local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count));
++local void build_tree OF((deflate_state *s, tree_desc *desc));
++local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code));
++local void send_tree OF((deflate_state *s, ct_data *tree, int max_code));
++local int build_bl_tree OF((deflate_state *s));
++local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
++ int blcodes));
++local void compress_block OF((deflate_state *s, ct_data *ltree,
++ ct_data *dtree));
++local void set_data_type OF((deflate_state *s));
++local unsigned bi_reverse OF((unsigned value, int length));
++local void bi_windup OF((deflate_state *s));
++local void bi_flush OF((deflate_state *s));
++local void copy_block OF((deflate_state *s, charf *buf, unsigned len,
++ int header));
++
++#ifndef DEBUG_ZLIB
++# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
++ /* Send a code of the given tree. c and tree must not have side effects */
++
++#else /* DEBUG_ZLIB */
++# define send_code(s, c, tree) \
++ { if (verbose&gt;1) fprintf(stderr,&quot;\ncd %3d &quot;,(c)); \
++ send_bits(s, tree[c].Code, tree[c].Len); }
++#endif
++
++#define d_code(dist) \
++ ((dist) &lt; 256 ? dist_code[dist] : dist_code[256+((dist)&gt;&gt;7)])
++/* Mapping from a distance to a distance code. dist is the distance - 1 and
++ * must not have side effects. dist_code[256] and dist_code[257] are never
++ * used.
++ */
++
++/* ===========================================================================
++ * Output a short LSB first on the stream.
++ * IN assertion: there is enough room in pendingBuf.
++ */
++#define put_short(s, w) { \
++ put_byte(s, (uch)((w) &amp; 0xff)); \
++ put_byte(s, (uch)((ush)(w) &gt;&gt; 8)); \
++}
++
++/* ===========================================================================
++ * Send a value on a given number of bits.
++ * IN assertion: length &lt;= 16 and value fits in length bits.
++ */
++#ifdef DEBUG_ZLIB
++local void send_bits OF((deflate_state *s, int value, int length));
++
++local void send_bits(s, value, length)
++ deflate_state *s;
++ int value; /* value to send */
++ int length; /* number of bits */
++{
++ Tracev((stderr,&quot; l %2d v %4x &quot;, length, value));
++ Assert(length &gt; 0 &amp;&amp; length &lt;= 15, &quot;invalid length&quot;);
++ s-&gt;bits_sent += (ulg)length;
++
++ /* If not enough room in bi_buf, use (valid) bits from bi_buf and
++ * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
++ * unused bits in value.
++ */
++ if (s-&gt;bi_valid &gt; (int)Buf_size - length) {
++ s-&gt;bi_buf |= (value &lt;&lt; s-&gt;bi_valid);
++ put_short(s, s-&gt;bi_buf);
++ s-&gt;bi_buf = (ush)value &gt;&gt; (Buf_size - s-&gt;bi_valid);
++ s-&gt;bi_valid += length - Buf_size;
++ } else {
++ s-&gt;bi_buf |= value &lt;&lt; s-&gt;bi_valid;
++ s-&gt;bi_valid += length;
++ }
++}
++#else /* !DEBUG_ZLIB */
++
++#define send_bits(s, value, length) \
++{ int len = length;\
++ if (s-&gt;bi_valid &gt; (int)Buf_size - len) {\
++ int val = value;\
++ s-&gt;bi_buf |= (val &lt;&lt; s-&gt;bi_valid);\
++ put_short(s, s-&gt;bi_buf);\
++ s-&gt;bi_buf = (ush)val &gt;&gt; (Buf_size - s-&gt;bi_valid);\
++ s-&gt;bi_valid += len - Buf_size;\
++ } else {\
++ s-&gt;bi_buf |= (value) &lt;&lt; s-&gt;bi_valid;\
++ s-&gt;bi_valid += len;\
++ }\
++}
++#endif /* DEBUG_ZLIB */
++
++
++#define MAX(a,b) (a &gt;= b ? a : b)
++/* the arguments must not have side effects */
++
++/* ===========================================================================
++ * Initialize the various 'constant' tables.
++ * To do: do this at compile time.
++ */
++local void ct_static_init()
++{
++ int n; /* iterates over tree elements */
++ int bits; /* bit counter */
++ int length; /* length value */
++ int code; /* code value */
++ int dist; /* distance index */
++ ush bl_count[MAX_BITS+1];
++ /* number of codes at each bit length for an optimal tree */
++
++ /* Initialize the mapping length (0..255) -&gt; length code (0..28) */
++ length = 0;
++ for (code = 0; code &lt; LENGTH_CODES-1; code++) {
++ base_length[code] = length;
++ for (n = 0; n &lt; (1&lt;&lt;extra_lbits[code]); n++) {
++ length_code[length++] = (uch)code;
++ }
++ }
++ Assert (length == 256, &quot;ct_static_init: length != 256&quot;);
++ /* Note that the length 255 (match length 258) can be represented
++ * in two different ways: code 284 + 5 bits or code 285, so we
++ * overwrite length_code[255] to use the best encoding:
++ */
++ length_code[length-1] = (uch)code;
++
++ /* Initialize the mapping dist (0..32K) -&gt; dist code (0..29) */
++ dist = 0;
++ for (code = 0 ; code &lt; 16; code++) {
++ base_dist[code] = dist;
++ for (n = 0; n &lt; (1&lt;&lt;extra_dbits[code]); n++) {
++ dist_code[dist++] = (uch)code;
++ }
++ }
++ Assert (dist == 256, &quot;ct_static_init: dist != 256&quot;);
++ dist &gt;&gt;= 7; /* from now on, all distances are divided by 128 */
++ for ( ; code &lt; D_CODES; code++) {
++ base_dist[code] = dist &lt;&lt; 7;
++ for (n = 0; n &lt; (1&lt;&lt;(extra_dbits[code]-7)); n++) {
++ dist_code[256 + dist++] = (uch)code;
++ }
++ }
++ Assert (dist == 256, &quot;ct_static_init: 256+dist != 512&quot;);
++
++ /* Construct the codes of the static literal tree */
++ for (bits = 0; bits &lt;= MAX_BITS; bits++) bl_count[bits] = 0;
++ n = 0;
++ while (n &lt;= 143) static_ltree[n++].Len = 8, bl_count[8]++;
++ while (n &lt;= 255) static_ltree[n++].Len = 9, bl_count[9]++;
++ while (n &lt;= 279) static_ltree[n++].Len = 7, bl_count[7]++;
++ while (n &lt;= 287) static_ltree[n++].Len = 8, bl_count[8]++;
++ /* Codes 286 and 287 do not exist, but we must include them in the
++ * tree construction to get a canonical Huffman tree (longest code
++ * all ones)
++ */
++ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
++
++ /* The static distance tree is trivial: */
++ for (n = 0; n &lt; D_CODES; n++) {
++ static_dtree[n].Len = 5;
++ static_dtree[n].Code = bi_reverse(n, 5);
++ }
++}
++
++/* ===========================================================================
++ * Initialize the tree data structures for a new zlib stream.
++ */
++local void ct_init(s)
++ deflate_state *s;
++{
++ if (static_dtree[0].Len == 0) {
++ ct_static_init(); /* To do: at compile time */
++ }
++
++ s-&gt;compressed_len = 0L;
++
++ s-&gt;l_desc.dyn_tree = s-&gt;dyn_ltree;
++ s-&gt;l_desc.stat_desc = &amp;static_l_desc;
++
++ s-&gt;d_desc.dyn_tree = s-&gt;dyn_dtree;
++ s-&gt;d_desc.stat_desc = &amp;static_d_desc;
++
++ s-&gt;bl_desc.dyn_tree = s-&gt;bl_tree;
++ s-&gt;bl_desc.stat_desc = &amp;static_bl_desc;
++
++ s-&gt;bi_buf = 0;
++ s-&gt;bi_valid = 0;
++ s-&gt;last_eob_len = 8; /* enough lookahead for inflate */
++#ifdef DEBUG_ZLIB
++ s-&gt;bits_sent = 0L;
++#endif
++ s-&gt;blocks_in_packet = 0;
++
++ /* Initialize the first block of the first file: */
++ init_block(s);
++}
++
++/* ===========================================================================
++ * Initialize a new block.
++ */
++local void init_block(s)
++ deflate_state *s;
++{
++ int n; /* iterates over tree elements */
++
++ /* Initialize the trees. */
++ for (n = 0; n &lt; L_CODES; n++) s-&gt;dyn_ltree[n].Freq = 0;
++ for (n = 0; n &lt; D_CODES; n++) s-&gt;dyn_dtree[n].Freq = 0;
++ for (n = 0; n &lt; BL_CODES; n++) s-&gt;bl_tree[n].Freq = 0;
++
++ s-&gt;dyn_ltree[END_BLOCK].Freq = 1;
++ s-&gt;opt_len = s-&gt;static_len = 0L;
++ s-&gt;last_lit = s-&gt;matches = 0;
++}
++
++#define SMALLEST 1
++/* Index within the heap array of least frequent node in the Huffman tree */
++
++
++/* ===========================================================================
++ * Remove the smallest element from the heap and recreate the heap with
++ * one less element. Updates heap and heap_len.
++ */
++#define pqremove(s, tree, top) \
++{\
++ top = s-&gt;heap[SMALLEST]; \
++ s-&gt;heap[SMALLEST] = s-&gt;heap[s-&gt;heap_len--]; \
++ pqdownheap(s, tree, SMALLEST); \
++}
++
++/* ===========================================================================
++ * Compares to subtrees, using the tree depth as tie breaker when
++ * the subtrees have equal frequency. This minimizes the worst case length.
++ */
++#define smaller(tree, n, m, depth) \
++ (tree[n].Freq &lt; tree[m].Freq || \
++ (tree[n].Freq == tree[m].Freq &amp;&amp; depth[n] &lt;= depth[m]))
++
++/* ===========================================================================
++ * Restore the heap property by moving down the tree starting at node k,
++ * exchanging a node with the smallest of its two sons if necessary, stopping
++ * when the heap property is re-established (each father smaller than its
++ * two sons).
++ */
++local void pqdownheap(s, tree, k)
++ deflate_state *s;
++ ct_data *tree; /* the tree to restore */
++ int k; /* node to move down */
++{
++ int v = s-&gt;heap[k];
++ int j = k &lt;&lt; 1; /* left son of k */
++ while (j &lt;= s-&gt;heap_len) {
++ /* Set j to the smallest of the two sons: */
++ if (j &lt; s-&gt;heap_len &amp;&amp;
++ smaller(tree, s-&gt;heap[j+1], s-&gt;heap[j], s-&gt;depth)) {
++ j++;
++ }
++ /* Exit if v is smaller than both sons */
++ if (smaller(tree, v, s-&gt;heap[j], s-&gt;depth)) break;
++
++ /* Exchange v with the smallest son */
++ s-&gt;heap[k] = s-&gt;heap[j]; k = j;
++
++ /* And continue down the tree, setting j to the left son of k */
++ j &lt;&lt;= 1;
++ }
++ s-&gt;heap[k] = v;
++}
++
++/* ===========================================================================
++ * Compute the optimal bit lengths for a tree and update the total bit length
++ * for the current block.
++ * IN assertion: the fields freq and dad are set, heap[heap_max] and
++ * above are the tree nodes sorted by increasing frequency.
++ * OUT assertions: the field len is set to the optimal bit length, the
++ * array bl_count contains the frequencies for each bit length.
++ * The length opt_len is updated; static_len is also updated if stree is
++ * not null.
++ */
++local void gen_bitlen(s, desc)
++ deflate_state *s;
++ tree_desc *desc; /* the tree descriptor */
++{
++ ct_data *tree = desc-&gt;dyn_tree;
++ int max_code = desc-&gt;max_code;
++ ct_data *stree = desc-&gt;stat_desc-&gt;static_tree;
++ intf *extra = desc-&gt;stat_desc-&gt;extra_bits;
++ int base = desc-&gt;stat_desc-&gt;extra_base;
++ int max_length = desc-&gt;stat_desc-&gt;max_length;
++ int h; /* heap index */
++ int n, m; /* iterate over the tree elements */
++ int bits; /* bit length */
++ int xbits; /* extra bits */
++ ush f; /* frequency */
++ int overflow = 0; /* number of elements with bit length too large */
++
++ for (bits = 0; bits &lt;= MAX_BITS; bits++) s-&gt;bl_count[bits] = 0;
++
++ /* In a first pass, compute the optimal bit lengths (which may
++ * overflow in the case of the bit length tree).
++ */
++ tree[s-&gt;heap[s-&gt;heap_max]].Len = 0; /* root of the heap */
++
++ for (h = s-&gt;heap_max+1; h &lt; HEAP_SIZE; h++) {
++ n = s-&gt;heap[h];
++ bits = tree[tree[n].Dad].Len + 1;
++ if (bits &gt; max_length) bits = max_length, overflow++;
++ tree[n].Len = (ush)bits;
++ /* We overwrite tree[n].Dad which is no longer needed */
++
++ if (n &gt; max_code) continue; /* not a leaf node */
++
++ s-&gt;bl_count[bits]++;
++ xbits = 0;
++ if (n &gt;= base) xbits = extra[n-base];
++ f = tree[n].Freq;
++ s-&gt;opt_len += (ulg)f * (bits + xbits);
++ if (stree) s-&gt;static_len += (ulg)f * (stree[n].Len + xbits);
++ }
++ if (overflow == 0) return;
++
++ Trace((stderr,&quot;\nbit length overflow\n&quot;));
++ /* This happens for example on obj2 and pic of the Calgary corpus */
++
++ /* Find the first bit length which could increase: */
++ do {
++ bits = max_length-1;
++ while (s-&gt;bl_count[bits] == 0) bits--;
++ s-&gt;bl_count[bits]--; /* move one leaf down the tree */
++ s-&gt;bl_count[bits+1] += 2; /* move one overflow item as its brother */
++ s-&gt;bl_count[max_length]--;
++ /* The brother of the overflow item also moves one step up,
++ * but this does not affect bl_count[max_length]
++ */
++ overflow -= 2;
++ } while (overflow &gt; 0);
++
++ /* Now recompute all bit lengths, scanning in increasing frequency.
++ * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
++ * lengths instead of fixing only the wrong ones. This idea is taken
++ * from 'ar' written by Haruhiko Okumura.)
++ */
++ for (bits = max_length; bits != 0; bits--) {
++ n = s-&gt;bl_count[bits];
++ while (n != 0) {
++ m = s-&gt;heap[--h];
++ if (m &gt; max_code) continue;
++ if (tree[m].Len != (unsigned) bits) {
++ Trace((stderr,&quot;code %d bits %d-&gt;%d\n&quot;, m, tree[m].Len, bits));
++ s-&gt;opt_len += ((long)bits - (long)tree[m].Len)
++ *(long)tree[m].Freq;
++ tree[m].Len = (ush)bits;
++ }
++ n--;
++ }
++ }
++}
++
++/* ===========================================================================
++ * Generate the codes for a given tree and bit counts (which need not be
++ * optimal).
++ * IN assertion: the array bl_count contains the bit length statistics for
++ * the given tree and the field len is set for all tree elements.
++ * OUT assertion: the field code is set for all tree elements of non
++ * zero code length.
++ */
++local void gen_codes (tree, max_code, bl_count)
++ ct_data *tree; /* the tree to decorate */
++ int max_code; /* largest code with non zero frequency */
++ ushf *bl_count; /* number of codes at each bit length */
++{
++ ush next_code[MAX_BITS+1]; /* next code value for each bit length */
++ ush code = 0; /* running code value */
++ int bits; /* bit index */
++ int n; /* code index */
++
++ /* The distribution counts are first used to generate the code values
++ * without bit reversal.
++ */
++ for (bits = 1; bits &lt;= MAX_BITS; bits++) {
++ next_code[bits] = code = (code + bl_count[bits-1]) &lt;&lt; 1;
++ }
++ /* Check that the bit counts in bl_count are consistent. The last code
++ * must be all ones.
++ */
++ Assert (code + bl_count[MAX_BITS]-1 == (1&lt;&lt;MAX_BITS)-1,
++ &quot;inconsistent bit counts&quot;);
++ Tracev((stderr,&quot;\ngen_codes: max_code %d &quot;, max_code));
++
++ for (n = 0; n &lt;= max_code; n++) {
++ int len = tree[n].Len;
++ if (len == 0) continue;
++ /* Now reverse the bits */
++ tree[n].Code = bi_reverse(next_code[len]++, len);
++
++ Tracec(tree != static_ltree, (stderr,&quot;\nn %3d %c l %2d c %4x (%x) &quot;,
++ n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
++ }
++}
++
++/* ===========================================================================
++ * Construct one Huffman tree and assigns the code bit strings and lengths.
++ * Update the total bit length for the current block.
++ * IN assertion: the field freq is set for all tree elements.
++ * OUT assertions: the fields len and code are set to the optimal bit length
++ * and corresponding code. The length opt_len is updated; static_len is
++ * also updated if stree is not null. The field max_code is set.
++ */
++local void build_tree(s, desc)
++ deflate_state *s;
++ tree_desc *desc; /* the tree descriptor */
++{
++ ct_data *tree = desc-&gt;dyn_tree;
++ ct_data *stree = desc-&gt;stat_desc-&gt;static_tree;
++ int elems = desc-&gt;stat_desc-&gt;elems;
++ int n, m; /* iterate over heap elements */
++ int max_code = -1; /* largest code with non zero frequency */
++ int node; /* new node being created */
++
++ /* Construct the initial heap, with least frequent element in
++ * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
++ * heap[0] is not used.
++ */
++ s-&gt;heap_len = 0, s-&gt;heap_max = HEAP_SIZE;
++
++ for (n = 0; n &lt; elems; n++) {
++ if (tree[n].Freq != 0) {
++ s-&gt;heap[++(s-&gt;heap_len)] = max_code = n;
++ s-&gt;depth[n] = 0;
++ } else {
++ tree[n].Len = 0;
++ }
++ }
++
++ /* The pkzip format requires that at least one distance code exists,
++ * and that at least one bit should be sent even if there is only one
++ * possible code. So to avoid special checks later on we force at least
++ * two codes of non zero frequency.
++ */
++ while (s-&gt;heap_len &lt; 2) {
++ node = s-&gt;heap[++(s-&gt;heap_len)] = (max_code &lt; 2 ? ++max_code : 0);
++ tree[node].Freq = 1;
++ s-&gt;depth[node] = 0;
++ s-&gt;opt_len--; if (stree) s-&gt;static_len -= stree[node].Len;
++ /* node is 0 or 1 so it does not have extra bits */
++ }
++ desc-&gt;max_code = max_code;
++
++ /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
++ * establish sub-heaps of increasing lengths:
++ */
++ for (n = s-&gt;heap_len/2; n &gt;= 1; n--) pqdownheap(s, tree, n);
++
++ /* Construct the Huffman tree by repeatedly combining the least two
++ * frequent nodes.
++ */
++ node = elems; /* next internal node of the tree */
++ do {
++ pqremove(s, tree, n); /* n = node of least frequency */
++ m = s-&gt;heap[SMALLEST]; /* m = node of next least frequency */
++
++ s-&gt;heap[--(s-&gt;heap_max)] = n; /* keep the nodes sorted by frequency */
++ s-&gt;heap[--(s-&gt;heap_max)] = m;
++
++ /* Create a new node father of n and m */
++ tree[node].Freq = tree[n].Freq + tree[m].Freq;
++ s-&gt;depth[node] = (uch) (MAX(s-&gt;depth[n], s-&gt;depth[m]) + 1);
++ tree[n].Dad = tree[m].Dad = (ush)node;
++#ifdef DUMP_BL_TREE
++ if (tree == s-&gt;bl_tree) {
++ fprintf(stderr,&quot;\nnode %d(%d), sons %d(%d) %d(%d)&quot;,
++ node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
++ }
++#endif
++ /* and insert the new node in the heap */
++ s-&gt;heap[SMALLEST] = node++;
++ pqdownheap(s, tree, SMALLEST);
++
++ } while (s-&gt;heap_len &gt;= 2);
++
++ s-&gt;heap[--(s-&gt;heap_max)] = s-&gt;heap[SMALLEST];
++
++ /* At this point, the fields freq and dad are set. We can now
++ * generate the bit lengths.
++ */
++ gen_bitlen(s, (tree_desc *)desc);
++
++ /* The field len is now set, we can generate the bit codes */
++ gen_codes ((ct_data *)tree, max_code, s-&gt;bl_count);
++}
++
++/* ===========================================================================
++ * Scan a literal or distance tree to determine the frequencies of the codes
++ * in the bit length tree.
++ */
++local void scan_tree (s, tree, max_code)
++ deflate_state *s;
++ ct_data *tree; /* the tree to be scanned */
++ int max_code; /* and its largest code of non zero frequency */
++{
++ int n; /* iterates over all tree elements */
++ int prevlen = -1; /* last emitted length */
++ int curlen; /* length of current code */
++ int nextlen = tree[0].Len; /* length of next code */
++ int count = 0; /* repeat count of the current code */
++ int max_count = 7; /* max repeat count */
++ int min_count = 4; /* min repeat count */
++
++ if (nextlen == 0) max_count = 138, min_count = 3;
++ tree[max_code+1].Len = (ush)0xffff; /* guard */
++
++ for (n = 0; n &lt;= max_code; n++) {
++ curlen = nextlen; nextlen = tree[n+1].Len;
++ if (++count &lt; max_count &amp;&amp; curlen == nextlen) {
++ continue;
++ } else if (count &lt; min_count) {
++ s-&gt;bl_tree[curlen].Freq += count;
++ } else if (curlen != 0) {
++ if (curlen != prevlen) s-&gt;bl_tree[curlen].Freq++;
++ s-&gt;bl_tree[REP_3_6].Freq++;
++ } else if (count &lt;= 10) {
++ s-&gt;bl_tree[REPZ_3_10].Freq++;
++ } else {
++ s-&gt;bl_tree[REPZ_11_138].Freq++;
++ }
++ count = 0; prevlen = curlen;
++ if (nextlen == 0) {
++ max_count = 138, min_count = 3;
++ } else if (curlen == nextlen) {
++ max_count = 6, min_count = 3;
++ } else {
++ max_count = 7, min_count = 4;
++ }
++ }
++}
++
++/* ===========================================================================
++ * Send a literal or distance tree in compressed form, using the codes in
++ * bl_tree.
++ */
++local void send_tree (s, tree, max_code)
++ deflate_state *s;
++ ct_data *tree; /* the tree to be scanned */
++ int max_code; /* and its largest code of non zero frequency */
++{
++ int n; /* iterates over all tree elements */
++ int prevlen = -1; /* last emitted length */
++ int curlen; /* length of current code */
++ int nextlen = tree[0].Len; /* length of next code */
++ int count = 0; /* repeat count of the current code */
++ int max_count = 7; /* max repeat count */
++ int min_count = 4; /* min repeat count */
++
++ /* tree[max_code+1].Len = -1; */ /* guard already set */
++ if (nextlen == 0) max_count = 138, min_count = 3;
++
++ for (n = 0; n &lt;= max_code; n++) {
++ curlen = nextlen; nextlen = tree[n+1].Len;
++ if (++count &lt; max_count &amp;&amp; curlen == nextlen) {
++ continue;
++ } else if (count &lt; min_count) {
++ do { send_code(s, curlen, s-&gt;bl_tree); } while (--count != 0);
++
++ } else if (curlen != 0) {
++ if (curlen != prevlen) {
++ send_code(s, curlen, s-&gt;bl_tree); count--;
++ }
++ Assert(count &gt;= 3 &amp;&amp; count &lt;= 6, &quot; 3_6?&quot;);
++ send_code(s, REP_3_6, s-&gt;bl_tree); send_bits(s, count-3, 2);
++
++ } else if (count &lt;= 10) {
++ send_code(s, REPZ_3_10, s-&gt;bl_tree); send_bits(s, count-3, 3);
++
++ } else {
++ send_code(s, REPZ_11_138, s-&gt;bl_tree); send_bits(s, count-11, 7);
++ }
++ count = 0; prevlen = curlen;
++ if (nextlen == 0) {
++ max_count = 138, min_count = 3;
++ } else if (curlen == nextlen) {
++ max_count = 6, min_count = 3;
++ } else {
++ max_count = 7, min_count = 4;
++ }
++ }
++}
++
++/* ===========================================================================
++ * Construct the Huffman tree for the bit lengths and return the index in
++ * bl_order of the last bit length code to send.
++ */
++local int build_bl_tree(s)
++ deflate_state *s;
++{
++ int max_blindex; /* index of last bit length code of non zero freq */
++
++ /* Determine the bit length frequencies for literal and distance trees */
++ scan_tree(s, (ct_data *)s-&gt;dyn_ltree, s-&gt;l_desc.max_code);
++ scan_tree(s, (ct_data *)s-&gt;dyn_dtree, s-&gt;d_desc.max_code);
++
++ /* Build the bit length tree: */
++ build_tree(s, (tree_desc *)(&amp;(s-&gt;bl_desc)));
++ /* opt_len now includes the length of the tree representations, except
++ * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
++ */
++
++ /* Determine the number of bit length codes to send. The pkzip format
++ * requires that at least 4 bit length codes be sent. (appnote.txt says
++ * 3 but the actual value used is 4.)
++ */
++ for (max_blindex = BL_CODES-1; max_blindex &gt;= 3; max_blindex--) {
++ if (s-&gt;bl_tree[bl_order[max_blindex]].Len != 0) break;
++ }
++ /* Update opt_len to include the bit length tree and counts */
++ s-&gt;opt_len += 3*(max_blindex+1) + 5+5+4;
++ Tracev((stderr, &quot;\ndyn trees: dyn %ld, stat %ld&quot;,
++ s-&gt;opt_len, s-&gt;static_len));
++
++ return max_blindex;
++}
++
++/* ===========================================================================
++ * Send the header for a block using dynamic Huffman trees: the counts, the
++ * lengths of the bit length codes, the literal tree and the distance tree.
++ * IN assertion: lcodes &gt;= 257, dcodes &gt;= 1, blcodes &gt;= 4.
++ */
++local void send_all_trees(s, lcodes, dcodes, blcodes)
++ deflate_state *s;
++ int lcodes, dcodes, blcodes; /* number of codes for each tree */
++{
++ int rank; /* index in bl_order */
++
++ Assert (lcodes &gt;= 257 &amp;&amp; dcodes &gt;= 1 &amp;&amp; blcodes &gt;= 4, &quot;not enough codes&quot;);
++ Assert (lcodes &lt;= L_CODES &amp;&amp; dcodes &lt;= D_CODES &amp;&amp; blcodes &lt;= BL_CODES,
++ &quot;too many codes&quot;);
++ Tracev((stderr, &quot;\nbl counts: &quot;));
++ send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
++ send_bits(s, dcodes-1, 5);
++ send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */
++ for (rank = 0; rank &lt; blcodes; rank++) {
++ Tracev((stderr, &quot;\nbl code %2d &quot;, bl_order[rank]));
++ send_bits(s, s-&gt;bl_tree[bl_order[rank]].Len, 3);
++ }
++ Tracev((stderr, &quot;\nbl tree: sent %ld&quot;, s-&gt;bits_sent));
++
++ send_tree(s, (ct_data *)s-&gt;dyn_ltree, lcodes-1); /* literal tree */
++ Tracev((stderr, &quot;\nlit tree: sent %ld&quot;, s-&gt;bits_sent));
++
++ send_tree(s, (ct_data *)s-&gt;dyn_dtree, dcodes-1); /* distance tree */
++ Tracev((stderr, &quot;\ndist tree: sent %ld&quot;, s-&gt;bits_sent));
++}
++
++/* ===========================================================================
++ * Send a stored block
++ */
++local void ct_stored_block(s, buf, stored_len, eof)
++ deflate_state *s;
++ charf *buf; /* input block */
++ ulg stored_len; /* length of input block */
++ int eof; /* true if this is the last block for a file */
++{
++ send_bits(s, (STORED_BLOCK&lt;&lt;1)+eof, 3); /* send block type */
++ s-&gt;compressed_len = (s-&gt;compressed_len + 3 + 7) &amp; ~7L;
++ s-&gt;compressed_len += (stored_len + 4) &lt;&lt; 3;
++
++ copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
++}
++
++/* Send just the `stored block' type code without any length bytes or data.
++ */
++local void ct_stored_type_only(s)
++ deflate_state *s;
++{
++ send_bits(s, (STORED_BLOCK &lt;&lt; 1), 3);
++ bi_windup(s);
++ s-&gt;compressed_len = (s-&gt;compressed_len + 3) &amp; ~7L;
++}
++
++
++/* ===========================================================================
++ * Send one empty static block to give enough lookahead for inflate.
++ * This takes 10 bits, of which 7 may remain in the bit buffer.
++ * The current inflate code requires 9 bits of lookahead. If the EOB
++ * code for the previous block was coded on 5 bits or less, inflate
++ * may have only 5+3 bits of lookahead to decode this EOB.
++ * (There are no problems if the previous block is stored or fixed.)
++ */
++local void ct_align(s)
++ deflate_state *s;
++{
++ send_bits(s, STATIC_TREES&lt;&lt;1, 3);
++ send_code(s, END_BLOCK, static_ltree);
++ s-&gt;compressed_len += 10L; /* 3 for block type, 7 for EOB */
++ bi_flush(s);
++ /* Of the 10 bits for the empty block, we have already sent
++ * (10 - bi_valid) bits. The lookahead for the EOB of the previous
++ * block was thus its length plus what we have just sent.
++ */
++ if (s-&gt;last_eob_len + 10 - s-&gt;bi_valid &lt; 9) {
++ send_bits(s, STATIC_TREES&lt;&lt;1, 3);
++ send_code(s, END_BLOCK, static_ltree);
++ s-&gt;compressed_len += 10L;
++ bi_flush(s);
++ }
++ s-&gt;last_eob_len = 7;
++}
++
++/* ===========================================================================
++ * Determine the best encoding for the current block: dynamic trees, static
++ * trees or store, and output the encoded block to the zip file. This function
++ * returns the total compressed length for the file so far.
++ */
++local ulg ct_flush_block(s, buf, stored_len, flush)
++ deflate_state *s;
++ charf *buf; /* input block, or NULL if too old */
++ ulg stored_len; /* length of input block */
++ int flush; /* Z_FINISH if this is the last block for a file */
++{
++ ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
++ int max_blindex; /* index of last bit length code of non zero freq */
++ int eof = flush == Z_FINISH;
++
++ ++s-&gt;blocks_in_packet;
++
++ /* Check if the file is ascii or binary */
++ if (s-&gt;data_type == UNKNOWN) set_data_type(s);
++
++ /* Construct the literal and distance trees */
++ build_tree(s, (tree_desc *)(&amp;(s-&gt;l_desc)));
++ Tracev((stderr, &quot;\nlit data: dyn %ld, stat %ld&quot;, s-&gt;opt_len,
++ s-&gt;static_len));
++
++ build_tree(s, (tree_desc *)(&amp;(s-&gt;d_desc)));
++ Tracev((stderr, &quot;\ndist data: dyn %ld, stat %ld&quot;, s-&gt;opt_len,
++ s-&gt;static_len));
++ /* At this point, opt_len and static_len are the total bit lengths of
++ * the compressed block data, excluding the tree representations.
++ */
++
++ /* Build the bit length tree for the above two trees, and get the index
++ * in bl_order of the last bit length code to send.
++ */
++ max_blindex = build_bl_tree(s);
++
++ /* Determine the best encoding. Compute first the block length in bytes */
++ opt_lenb = (s-&gt;opt_len+3+7)&gt;&gt;3;
++ static_lenb = (s-&gt;static_len+3+7)&gt;&gt;3;
++
++ Tracev((stderr, &quot;\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u &quot;,
++ opt_lenb, s-&gt;opt_len, static_lenb, s-&gt;static_len, stored_len,
++ s-&gt;last_lit));
++
++ if (static_lenb &lt;= opt_lenb) opt_lenb = static_lenb;
++
++ /* If compression failed and this is the first and last block,
++ * and if the .zip file can be seeked (to rewrite the local header),
++ * the whole file is transformed into a stored file:
++ */
++#ifdef STORED_FILE_OK
++# ifdef FORCE_STORED_FILE
++ if (eof &amp;&amp; compressed_len == 0L) /* force stored file */
++# else
++ if (stored_len &lt;= opt_lenb &amp;&amp; eof &amp;&amp; s-&gt;compressed_len==0L &amp;&amp; seekable())
++# endif
++ {
++ /* Since LIT_BUFSIZE &lt;= 2*WSIZE, the input data must be there: */
++ if (buf == (charf*)0) error (&quot;block vanished&quot;);
++
++ copy_block(buf, (unsigned)stored_len, 0); /* without header */
++ s-&gt;compressed_len = stored_len &lt;&lt; 3;
++ s-&gt;method = STORED;
++ } else
++#endif /* STORED_FILE_OK */
++
++ /* For Z_PACKET_FLUSH, if we don't achieve the required minimum
++ * compression, and this block contains all the data since the last
++ * time we used Z_PACKET_FLUSH, then just omit this block completely
++ * from the output.
++ */
++ if (flush == Z_PACKET_FLUSH &amp;&amp; s-&gt;blocks_in_packet == 1
++ &amp;&amp; opt_lenb &gt; stored_len - s-&gt;minCompr) {
++ s-&gt;blocks_in_packet = 0;
++ /* output nothing */
++ } else
++
++#ifdef FORCE_STORED
++ if (buf != (char*)0) /* force stored block */
++#else
++ if (stored_len+4 &lt;= opt_lenb &amp;&amp; buf != (char*)0)
++ /* 4: two words for the lengths */
++#endif
++ {
++ /* The test buf != NULL is only necessary if LIT_BUFSIZE &gt; WSIZE.
++ * Otherwise we can't have processed more than WSIZE input bytes since
++ * the last block flush, because compression would have been
++ * successful. If LIT_BUFSIZE &lt;= WSIZE, it is never too late to
++ * transform a block into a stored block.
++ */
++ ct_stored_block(s, buf, stored_len, eof);
++ } else
++
++#ifdef FORCE_STATIC
++ if (static_lenb &gt;= 0) /* force static trees */
++#else
++ if (static_lenb == opt_lenb)
++#endif
++ {
++ send_bits(s, (STATIC_TREES&lt;&lt;1)+eof, 3);
++ compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
++ s-&gt;compressed_len += 3 + s-&gt;static_len;
++ } else {
++ send_bits(s, (DYN_TREES&lt;&lt;1)+eof, 3);
++ send_all_trees(s, s-&gt;l_desc.max_code+1, s-&gt;d_desc.max_code+1,
++ max_blindex+1);
++ compress_block(s, (ct_data *)s-&gt;dyn_ltree, (ct_data *)s-&gt;dyn_dtree);
++ s-&gt;compressed_len += 3 + s-&gt;opt_len;
++ }
++ Assert (s-&gt;compressed_len == s-&gt;bits_sent, &quot;bad compressed size&quot;);
++ init_block(s);
++
++ if (eof) {
++ bi_windup(s);
++ s-&gt;compressed_len += 7; /* align on byte boundary */
++ }
++ Tracev((stderr,&quot;\ncomprlen %lu(%lu) &quot;, s-&gt;compressed_len&gt;&gt;3,
++ s-&gt;compressed_len-7*eof));
++
++ return s-&gt;compressed_len &gt;&gt; 3;
++}
++
++/* ===========================================================================
++ * Save the match info and tally the frequency counts. Return true if
++ * the current block must be flushed.
++ */
++local int ct_tally (s, dist, lc)
++ deflate_state *s;
++ int dist; /* distance of matched string */
++ int lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
++{
++ s-&gt;d_buf[s-&gt;last_lit] = (ush)dist;
++ s-&gt;l_buf[s-&gt;last_lit++] = (uch)lc;
++ if (dist == 0) {
++ /* lc is the unmatched char */
++ s-&gt;dyn_ltree[lc].Freq++;
++ } else {
++ s-&gt;matches++;
++ /* Here, lc is the match length - MIN_MATCH */
++ dist--; /* dist = match distance - 1 */
++ Assert((ush)dist &lt; (ush)MAX_DIST(s) &amp;&amp;
++ (ush)lc &lt;= (ush)(MAX_MATCH-MIN_MATCH) &amp;&amp;
++ (ush)d_code(dist) &lt; (ush)D_CODES, &quot;ct_tally: bad match&quot;);
++
++ s-&gt;dyn_ltree[length_code[lc]+LITERALS+1].Freq++;
++ s-&gt;dyn_dtree[d_code(dist)].Freq++;
++ }
++
++ /* Try to guess if it is profitable to stop the current block here */
++ if (s-&gt;level &gt; 2 &amp;&amp; (s-&gt;last_lit &amp; 0xfff) == 0) {
++ /* Compute an upper bound for the compressed length */
++ ulg out_length = (ulg)s-&gt;last_lit*8L;
++ ulg in_length = (ulg)s-&gt;strstart - s-&gt;block_start;
++ int dcode;
++ for (dcode = 0; dcode &lt; D_CODES; dcode++) {
++ out_length += (ulg)s-&gt;dyn_dtree[dcode].Freq *
++ (5L+extra_dbits[dcode]);
++ }
++ out_length &gt;&gt;= 3;
++ Tracev((stderr,&quot;\nlast_lit %u, in %ld, out ~%ld(%ld%%) &quot;,
++ s-&gt;last_lit, in_length, out_length,
++ 100L - out_length*100L/in_length));
++ if (s-&gt;matches &lt; s-&gt;last_lit/2 &amp;&amp; out_length &lt; in_length/2) return 1;
++ }
++ return (s-&gt;last_lit == s-&gt;lit_bufsize-1);
++ /* We avoid equality with lit_bufsize because of wraparound at 64K
++ * on 16 bit machines and because stored blocks are restricted to
++ * 64K-1 bytes.
++ */
++}
++
++/* ===========================================================================
++ * Send the block data compressed using the given Huffman trees
++ */
++local void compress_block(s, ltree, dtree)
++ deflate_state *s;
++ ct_data *ltree; /* literal tree */
++ ct_data *dtree; /* distance tree */
++{
++ unsigned dist; /* distance of matched string */
++ int lc; /* match length or unmatched char (if dist == 0) */
++ unsigned lx = 0; /* running index in l_buf */
++ unsigned code; /* the code to send */
++ int extra; /* number of extra bits to send */
++
++ if (s-&gt;last_lit != 0) do {
++ dist = s-&gt;d_buf[lx];
++ lc = s-&gt;l_buf[lx++];
++ if (dist == 0) {
++ send_code(s, lc, ltree); /* send a literal byte */
++ Tracecv(isgraph(lc), (stderr,&quot; '%c' &quot;, lc));
++ } else {
++ /* Here, lc is the match length - MIN_MATCH */
++ code = length_code[lc];
++ send_code(s, code+LITERALS+1, ltree); /* send the length code */
++ extra = extra_lbits[code];
++ if (extra != 0) {
++ lc -= base_length[code];
++ send_bits(s, lc, extra); /* send the extra length bits */
++ }
++ dist--; /* dist is now the match distance - 1 */
++ code = d_code(dist);
++ Assert (code &lt; D_CODES, &quot;bad d_code&quot;);
++
++ send_code(s, code, dtree); /* send the distance code */
++ extra = extra_dbits[code];
++ if (extra != 0) {
++ dist -= base_dist[code];
++ send_bits(s, dist, extra); /* send the extra distance bits */
++ }
++ } /* literal or match pair ? */
++
++ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
++ Assert(s-&gt;pending &lt; s-&gt;lit_bufsize + 2*lx, &quot;pendingBuf overflow&quot;);
++
++ } while (lx &lt; s-&gt;last_lit);
++
++ send_code(s, END_BLOCK, ltree);
++ s-&gt;last_eob_len = ltree[END_BLOCK].Len;
++}
++
++/* ===========================================================================
++ * Set the data type to ASCII or BINARY, using a crude approximation:
++ * binary if more than 20% of the bytes are &lt;= 6 or &gt;= 128, ascii otherwise.
++ * IN assertion: the fields freq of dyn_ltree are set and the total of all
++ * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
++ */
++local void set_data_type(s)
++ deflate_state *s;
++{
++ int n = 0;
++ unsigned ascii_freq = 0;
++ unsigned bin_freq = 0;
++ while (n &lt; 7) bin_freq += s-&gt;dyn_ltree[n++].Freq;
++ while (n &lt; 128) ascii_freq += s-&gt;dyn_ltree[n++].Freq;
++ while (n &lt; LITERALS) bin_freq += s-&gt;dyn_ltree[n++].Freq;
++ s-&gt;data_type = (Byte)(bin_freq &gt; (ascii_freq &gt;&gt; 2) ? BINARY : ASCII);
++}
++
++/* ===========================================================================
++ * Reverse the first len bits of a code, using straightforward code (a faster
++ * method would use a table)
++ * IN assertion: 1 &lt;= len &lt;= 15
++ */
++local unsigned bi_reverse(code, len)
++ unsigned code; /* the value to invert */
++ int len; /* its bit length */
++{
++ register unsigned res = 0;
++ do {
++ res |= code &amp; 1;
++ code &gt;&gt;= 1, res &lt;&lt;= 1;
++ } while (--len &gt; 0);
++ return res &gt;&gt; 1;
++}
++
++/* ===========================================================================
++ * Flush the bit buffer, keeping at most 7 bits in it.
++ */
++local void bi_flush(s)
++ deflate_state *s;
++{
++ if (s-&gt;bi_valid == 16) {
++ put_short(s, s-&gt;bi_buf);
++ s-&gt;bi_buf = 0;
++ s-&gt;bi_valid = 0;
++ } else if (s-&gt;bi_valid &gt;= 8) {
++ put_byte(s, (Byte)s-&gt;bi_buf);
++ s-&gt;bi_buf &gt;&gt;= 8;
++ s-&gt;bi_valid -= 8;
++ }
++}
++
++/* ===========================================================================
++ * Flush the bit buffer and align the output on a byte boundary
++ */
++local void bi_windup(s)
++ deflate_state *s;
++{
++ if (s-&gt;bi_valid &gt; 8) {
++ put_short(s, s-&gt;bi_buf);
++ } else if (s-&gt;bi_valid &gt; 0) {
++ put_byte(s, (Byte)s-&gt;bi_buf);
++ }
++ s-&gt;bi_buf = 0;
++ s-&gt;bi_valid = 0;
++#ifdef DEBUG_ZLIB
++ s-&gt;bits_sent = (s-&gt;bits_sent+7) &amp; ~7;
++#endif
++}
++
++/* ===========================================================================
++ * Copy a stored block, storing first the length and its
++ * one's complement if requested.
++ */
++local void copy_block(s, buf, len, header)
++ deflate_state *s;
++ charf *buf; /* the input data */
++ unsigned len; /* its length */
++ int header; /* true if block header must be written */
++{
++ bi_windup(s); /* align on byte boundary */
++ s-&gt;last_eob_len = 8; /* enough lookahead for inflate */
++
++ if (header) {
++ put_short(s, (ush)len);
++ put_short(s, (ush)~len);
++#ifdef DEBUG_ZLIB
++ s-&gt;bits_sent += 2*16;
++#endif
++ }
++#ifdef DEBUG_ZLIB
++ s-&gt;bits_sent += (ulg)len&lt;&lt;3;
++#endif
++ while (len--) {
++ put_byte(s, *buf++);
++ }
++}
++
++
++/*+++++*/
++/* infblock.h -- header to use infblock.c
++ * Copyright (C) 1995 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* WARNING: this file should *not* be used by applications. It is
++ part of the implementation of the compression library and is
++ subject to change. Applications should only use zlib.h.
++ */
++
++struct inflate_blocks_state;
++typedef struct inflate_blocks_state FAR inflate_blocks_statef;
++
++local inflate_blocks_statef * inflate_blocks_new OF((
++ z_stream *z,
++ check_func c, /* check function */
++ uInt w)); /* window size */
++
++local int inflate_blocks OF((
++ inflate_blocks_statef *,
++ z_stream *,
++ int)); /* initial return code */
++
++local void inflate_blocks_reset OF((
++ inflate_blocks_statef *,
++ z_stream *,
++ uLongf *)); /* check value on output */
++
++local int inflate_blocks_free OF((
++ inflate_blocks_statef *,
++ z_stream *,
++ uLongf *)); /* check value on output */
++
++local int inflate_addhistory OF((
++ inflate_blocks_statef *,
++ z_stream *));
++
++local int inflate_packet_flush OF((
++ inflate_blocks_statef *));
++
++/*+++++*/
++/* inftrees.h -- header to use inftrees.c
++ * Copyright (C) 1995 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* WARNING: this file should *not* be used by applications. It is
++ part of the implementation of the compression library and is
++ subject to change. Applications should only use zlib.h.
++ */
++
++/* Huffman code lookup table entry--this entry is four bytes for machines
++ that have 16-bit pointers (e.g. PC's in the small or medium model). */
++
++typedef struct inflate_huft_s FAR inflate_huft;
++
++struct inflate_huft_s {
++ union {
++ struct {
++ Byte Exop; /* number of extra bits or operation */
++ Byte Bits; /* number of bits in this code or subcode */
++ } what;
++ uInt Nalloc; /* number of these allocated here */
++ Bytef *pad; /* pad structure to a power of 2 (4 bytes for */
++ } word; /* 16-bit, 8 bytes for 32-bit machines) */
++ union {
++ uInt Base; /* literal, length base, or distance base */
++ inflate_huft *Next; /* pointer to next level of table */
++ } more;
++};
++
++#ifdef DEBUG_ZLIB
++ local uInt inflate_hufts;
++#endif
++
++local int inflate_trees_bits OF((
++ uIntf *, /* 19 code lengths */
++ uIntf *, /* bits tree desired/actual depth */
++ inflate_huft * FAR *, /* bits tree result */
++ z_stream *)); /* for zalloc, zfree functions */
++
++local int inflate_trees_dynamic OF((
++ uInt, /* number of literal/length codes */
++ uInt, /* number of distance codes */
++ uIntf *, /* that many (total) code lengths */
++ uIntf *, /* literal desired/actual bit depth */
++ uIntf *, /* distance desired/actual bit depth */
++ inflate_huft * FAR *, /* literal/length tree result */
++ inflate_huft * FAR *, /* distance tree result */
++ z_stream *)); /* for zalloc, zfree functions */
++
++local int inflate_trees_fixed OF((
++ uIntf *, /* literal desired/actual bit depth */
++ uIntf *, /* distance desired/actual bit depth */
++ inflate_huft * FAR *, /* literal/length tree result */
++ inflate_huft * FAR *)); /* distance tree result */
++
++local int inflate_trees_free OF((
++ inflate_huft *, /* tables to free */
++ z_stream *)); /* for zfree function */
++
++
++/*+++++*/
++/* infcodes.h -- header to use infcodes.c
++ * Copyright (C) 1995 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* WARNING: this file should *not* be used by applications. It is
++ part of the implementation of the compression library and is
++ subject to change. Applications should only use zlib.h.
++ */
++
++struct inflate_codes_state;
++typedef struct inflate_codes_state FAR inflate_codes_statef;
++
++local inflate_codes_statef *inflate_codes_new OF((
++ uInt, uInt,
++ inflate_huft *, inflate_huft *,
++ z_stream *));
++
++local int inflate_codes OF((
++ inflate_blocks_statef *,
++ z_stream *,
++ int));
++
++local void inflate_codes_free OF((
++ inflate_codes_statef *,
++ z_stream *));
++
++
++/*+++++*/
++/* inflate.c -- zlib interface to inflate modules
++ * Copyright (C) 1995 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* inflate private state */
++struct internal_state {
++
++ /* mode */
++ enum {
++ METHOD, /* waiting for method byte */
++ FLAG, /* waiting for flag byte */
++ BLOCKS, /* decompressing blocks */
++ CHECK4, /* four check bytes to go */
++ CHECK3, /* three check bytes to go */
++ CHECK2, /* two check bytes to go */
++ CHECK1, /* one check byte to go */
++ DONE, /* finished check, done */
++ BAD} /* got an error--stay here */
++ mode; /* current inflate mode */
++
++ /* mode dependent information */
++ union {
++ uInt method; /* if FLAGS, method byte */
++ struct {
++ uLong was; /* computed check value */
++ uLong need; /* stream check value */
++ } check; /* if CHECK, check values to compare */
++ uInt marker; /* if BAD, inflateSync's marker bytes count */
++ } sub; /* submode */
++
++ /* mode independent information */
++ int nowrap; /* flag for no wrapper */
++ uInt wbits; /* log2(window size) (8..15, defaults to 15) */
++ inflate_blocks_statef
++ *blocks; /* current inflate_blocks state */
++
++};
++
++
++int inflateReset(z)
++z_stream *z;
++{
++ uLong c;
++
++ if (z == Z_NULL || z-&gt;state == Z_NULL)
++ return Z_STREAM_ERROR;
++ z-&gt;total_in = z-&gt;total_out = 0;
++ z-&gt;msg = Z_NULL;
++ z-&gt;state-&gt;mode = z-&gt;state-&gt;nowrap ? BLOCKS : METHOD;
++ inflate_blocks_reset(z-&gt;state-&gt;blocks, z, &amp;c);
++ Trace((stderr, &quot;inflate: reset\n&quot;));
++ return Z_OK;
++}
++
++
++int inflateEnd(z)
++z_stream *z;
++{
++ uLong c;
++
++ if (z == Z_NULL || z-&gt;state == Z_NULL || z-&gt;zfree == Z_NULL)
++ return Z_STREAM_ERROR;
++ if (z-&gt;state-&gt;blocks != Z_NULL)
++ inflate_blocks_free(z-&gt;state-&gt;blocks, z, &amp;c);
++ ZFREE(z, z-&gt;state, sizeof(struct internal_state));
++ z-&gt;state = Z_NULL;
++ Trace((stderr, &quot;inflate: end\n&quot;));
++ return Z_OK;
++}
++
++
++int inflateInit2(z, w)
++z_stream *z;
++int w;
++{
++ /* initialize state */
++ if (z == Z_NULL)
++ return Z_STREAM_ERROR;
++/* if (z-&gt;zalloc == Z_NULL) z-&gt;zalloc = zcalloc; */
++/* if (z-&gt;zfree == Z_NULL) z-&gt;zfree = zcfree; */
++ if ((z-&gt;state = (struct internal_state FAR *)
++ ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
++ return Z_MEM_ERROR;
++ z-&gt;state-&gt;blocks = Z_NULL;
++
++ /* handle undocumented nowrap option (no zlib header or check) */
++ z-&gt;state-&gt;nowrap = 0;
++ if (w &lt; 0)
++ {
++ w = - w;
++ z-&gt;state-&gt;nowrap = 1;
++ }
++
++ /* set window size */
++ if (w &lt; 8 || w &gt; 15)
++ {
++ inflateEnd(z);
++ return Z_STREAM_ERROR;
++ }
++ z-&gt;state-&gt;wbits = (uInt)w;
++
++ /* create inflate_blocks state */
++ if ((z-&gt;state-&gt;blocks =
++ inflate_blocks_new(z, z-&gt;state-&gt;nowrap ? Z_NULL : adler32, 1 &lt;&lt; w))
++ == Z_NULL)
++ {
++ inflateEnd(z);
++ return Z_MEM_ERROR;
++ }
++ Trace((stderr, &quot;inflate: allocated\n&quot;));
++
++ /* reset state */
++ inflateReset(z);
++ return Z_OK;
++}
++
++
++int inflateInit(z)
++z_stream *z;
++{
++ return inflateInit2(z, DEF_WBITS);
++}
++
++
++#define NEEDBYTE {if(z-&gt;avail_in==0)goto empty;r=Z_OK;}
++#define NEXTBYTE (z-&gt;avail_in--,z-&gt;total_in++,*z-&gt;next_in++)
++
++int inflate(z, f)
++z_stream *z;
++int f;
++{
++ int r;
++ uInt b;
++
++ if (z == Z_NULL || z-&gt;next_in == Z_NULL)
++ return Z_STREAM_ERROR;
++ r = Z_BUF_ERROR;
++ while (1) switch (z-&gt;state-&gt;mode)
++ {
++ case METHOD:
++ NEEDBYTE
++ if (((z-&gt;state-&gt;sub.method = NEXTBYTE) &amp; 0xf) != DEFLATED)
++ {
++ z-&gt;state-&gt;mode = BAD;
++ z-&gt;msg = &quot;unknown compression method&quot;;
++ z-&gt;state-&gt;sub.marker = 5; /* can't try inflateSync */
++ break;
++ }
++ if ((z-&gt;state-&gt;sub.method &gt;&gt; 4) + 8 &gt; z-&gt;state-&gt;wbits)
++ {
++ z-&gt;state-&gt;mode = BAD;
++ z-&gt;msg = &quot;invalid window size&quot;;
++ z-&gt;state-&gt;sub.marker = 5; /* can't try inflateSync */
++ break;
++ }
++ z-&gt;state-&gt;mode = FLAG;
++ case FLAG:
++ NEEDBYTE
++ if ((b = NEXTBYTE) &amp; 0x20)
++ {
++ z-&gt;state-&gt;mode = BAD;
++ z-&gt;msg = &quot;invalid reserved bit&quot;;
++ z-&gt;state-&gt;sub.marker = 5; /* can't try inflateSync */
++ break;
++ }
++ if (((z-&gt;state-&gt;sub.method &lt;&lt; 8) + b) % 31)
++ {
++ z-&gt;state-&gt;mode = BAD;
++ z-&gt;msg = &quot;incorrect header check&quot;;
++ z-&gt;state-&gt;sub.marker = 5; /* can't try inflateSync */
++ break;
++ }
++ Trace((stderr, &quot;inflate: zlib header ok\n&quot;));
++ z-&gt;state-&gt;mode = BLOCKS;
++ case BLOCKS:
++ r = inflate_blocks(z-&gt;state-&gt;blocks, z, r);
++ if (f == Z_PACKET_FLUSH &amp;&amp; z-&gt;avail_in == 0 &amp;&amp; z-&gt;avail_out != 0)
++ r = inflate_packet_flush(z-&gt;state-&gt;blocks);
++ if (r == Z_DATA_ERROR)
++ {
++ z-&gt;state-&gt;mode = BAD;
++ z-&gt;state-&gt;sub.marker = 0; /* can try inflateSync */
++ break;
++ }
++ if (r != Z_STREAM_END)
++ return r;
++ r = Z_OK;
++ inflate_blocks_reset(z-&gt;state-&gt;blocks, z, &amp;z-&gt;state-&gt;sub.check.was);
++ if (z-&gt;state-&gt;nowrap)
++ {
++ z-&gt;state-&gt;mode = DONE;
++ break;
++ }
++ z-&gt;state-&gt;mode = CHECK4;
++ case CHECK4:
++ NEEDBYTE
++ z-&gt;state-&gt;sub.check.need = (uLong)NEXTBYTE &lt;&lt; 24;
++ z-&gt;state-&gt;mode = CHECK3;
++ case CHECK3:
++ NEEDBYTE
++ z-&gt;state-&gt;sub.check.need += (uLong)NEXTBYTE &lt;&lt; 16;
++ z-&gt;state-&gt;mode = CHECK2;
++ case CHECK2:
++ NEEDBYTE
++ z-&gt;state-&gt;sub.check.need += (uLong)NEXTBYTE &lt;&lt; 8;
++ z-&gt;state-&gt;mode = CHECK1;
++ case CHECK1:
++ NEEDBYTE
++ z-&gt;state-&gt;sub.check.need += (uLong)NEXTBYTE;
++
++ if (z-&gt;state-&gt;sub.check.was != z-&gt;state-&gt;sub.check.need)
++ {
++ z-&gt;state-&gt;mode = BAD;
++ z-&gt;msg = &quot;incorrect data check&quot;;
++ z-&gt;state-&gt;sub.marker = 5; /* can't try inflateSync */
++ break;
++ }
++ Trace((stderr, &quot;inflate: zlib check ok\n&quot;));
++ z-&gt;state-&gt;mode = DONE;
++ case DONE:
++ return Z_STREAM_END;
++ case BAD:
++ return Z_DATA_ERROR;
++ default:
++ return Z_STREAM_ERROR;
++ }
++
++ empty:
++ if (f != Z_PACKET_FLUSH)
++ return r;
++ z-&gt;state-&gt;mode = BAD;
++ z-&gt;state-&gt;sub.marker = 0; /* can try inflateSync */
++ return Z_DATA_ERROR;
++}
++
++/*
++ * This subroutine adds the data at next_in/avail_in to the output history
++ * without performing any output. The output buffer must be &quot;caught up&quot;;
++ * i.e. no pending output (hence s-&gt;read equals s-&gt;write), and the state must
++ * be BLOCKS (i.e. we should be willing to see the start of a series of
++ * BLOCKS). On exit, the output will also be caught up, and the checksum
++ * will have been updated if need be.
++ */
++
++int inflateIncomp(z)
++z_stream *z;
++{
++ if (z-&gt;state-&gt;mode != BLOCKS)
++ return Z_DATA_ERROR;
++ return inflate_addhistory(z-&gt;state-&gt;blocks, z);
++}
++
++
++int inflateSync(z)
++z_stream *z;
++{
++ uInt n; /* number of bytes to look at */
++ Bytef *p; /* pointer to bytes */
++ uInt m; /* number of marker bytes found in a row */
++ uLong r, w; /* temporaries to save total_in and total_out */
++
++ /* set up */
++ if (z == Z_NULL || z-&gt;state == Z_NULL)
++ return Z_STREAM_ERROR;
++ if (z-&gt;state-&gt;mode != BAD)
++ {
++ z-&gt;state-&gt;mode = BAD;
++ z-&gt;state-&gt;sub.marker = 0;
++ }
++ if ((n = z-&gt;avail_in) == 0)
++ return Z_BUF_ERROR;
++ p = z-&gt;next_in;
++ m = z-&gt;state-&gt;sub.marker;
++
++ /* search */
++ while (n &amp;&amp; m &lt; 4)
++ {
++ if (*p == (Byte)(m &lt; 2 ? 0 : 0xff))
++ m++;
++ else if (*p)
++ m = 0;
++ else
++ m = 4 - m;
++ p++, n--;
++ }
++
++ /* restore */
++ z-&gt;total_in += p - z-&gt;next_in;
++ z-&gt;next_in = p;
++ z-&gt;avail_in = n;
++ z-&gt;state-&gt;sub.marker = m;
++
++ /* return no joy or set up to restart on a new block */
++ if (m != 4)
++ return Z_DATA_ERROR;
++ r = z-&gt;total_in; w = z-&gt;total_out;
++ inflateReset(z);
++ z-&gt;total_in = r; z-&gt;total_out = w;
++ z-&gt;state-&gt;mode = BLOCKS;
++ return Z_OK;
++}
++
++#undef NEEDBYTE
++#undef NEXTBYTE
++
++/*+++++*/
++/* infutil.h -- types and macros common to blocks and codes
++ * Copyright (C) 1995 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* WARNING: this file should *not* be used by applications. It is
++ part of the implementation of the compression library and is
++ subject to change. Applications should only use zlib.h.
++ */
++
++/* inflate blocks semi-private state */
++struct inflate_blocks_state {
++
++ /* mode */
++ enum {
++ TYPE, /* get type bits (3, including end bit) */
++ LENS, /* get lengths for stored */
++ STORED, /* processing stored block */
++ TABLE, /* get table lengths */
++ BTREE, /* get bit lengths tree for a dynamic block */
++ DTREE, /* get length, distance trees for a dynamic block */
++ CODES, /* processing fixed or dynamic block */
++ DRY, /* output remaining window bytes */
++ DONEB, /* finished last block, done */
++ BADB} /* got a data error--stuck here */
++ mode; /* current inflate_block mode */
++
++ /* mode dependent information */
++ union {
++ uInt left; /* if STORED, bytes left to copy */
++ struct {
++ uInt table; /* table lengths (14 bits) */
++ uInt index; /* index into blens (or border) */
++ uIntf *blens; /* bit lengths of codes */
++ uInt bb; /* bit length tree depth */
++ inflate_huft *tb; /* bit length decoding tree */
++ int nblens; /* # elements allocated at blens */
++ } trees; /* if DTREE, decoding info for trees */
++ struct {
++ inflate_huft *tl, *td; /* trees to free */
++ inflate_codes_statef
++ *codes;
++ } decode; /* if CODES, current state */
++ } sub; /* submode */
++ uInt last; /* true if this block is the last block */
++
++ /* mode independent information */
++ uInt bitk; /* bits in bit buffer */
++ uLong bitb; /* bit buffer */
++ Bytef *window; /* sliding window */
++ Bytef *end; /* one byte after sliding window */
++ Bytef *read; /* window read pointer */
++ Bytef *write; /* window write pointer */
++ check_func checkfn; /* check function */
++ uLong check; /* check on output */
++
++};
++
++
++/* defines for inflate input/output */
++/* update pointers and return */
++#define UPDBITS {s-&gt;bitb=b;s-&gt;bitk=k;}
++#define UPDIN {z-&gt;avail_in=n;z-&gt;total_in+=p-z-&gt;next_in;z-&gt;next_in=p;}
++#define UPDOUT {s-&gt;write=q;}
++#define UPDATE {UPDBITS UPDIN UPDOUT}
++#define LEAVE {UPDATE return inflate_flush(s,z,r);}
++/* get bytes and bits */
++#define LOADIN {p=z-&gt;next_in;n=z-&gt;avail_in;b=s-&gt;bitb;k=s-&gt;bitk;}
++#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
++#define NEXTBYTE (n--,*p++)
++#define NEEDBITS(j) {while(k&lt;(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)&lt;&lt;k;k+=8;}}
++#define DUMPBITS(j) {b&gt;&gt;=(j);k-=(j);}
++/* output bytes */
++#define WAVAIL (q&lt;s-&gt;read?s-&gt;read-q-1:s-&gt;end-q)
++#define LOADOUT {q=s-&gt;write;m=WAVAIL;}
++#define WRAP {if(q==s-&gt;end&amp;&amp;s-&gt;read!=s-&gt;window){q=s-&gt;window;m=WAVAIL;}}
++#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
++#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
++#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
++/* load local pointers */
++#define LOAD {LOADIN LOADOUT}
++
++/* And'ing with mask[n] masks the lower n bits */
++local uInt inflate_mask[] = {
++ 0x0000,
++ 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
++ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
++};
++
++/* copy as much as possible from the sliding window to the output area */
++local int inflate_flush OF((
++ inflate_blocks_statef *,
++ z_stream *,
++ int));
++
++/*+++++*/
++/* inffast.h -- header to use inffast.c
++ * Copyright (C) 1995 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* WARNING: this file should *not* be used by applications. It is
++ part of the implementation of the compression library and is
++ subject to change. Applications should only use zlib.h.
++ */
++
++local int inflate_fast OF((
++ uInt,
++ uInt,
++ inflate_huft *,
++ inflate_huft *,
++ inflate_blocks_statef *,
++ z_stream *));
++
++
++/*+++++*/
++/* infblock.c -- interpret and process block types to last block
++ * Copyright (C) 1995 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* Table for deflate from PKZIP's appnote.txt. */
++local uInt border[] = { /* Order of the bit length code lengths */
++ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
++
++/*
++ Notes beyond the 1.93a appnote.txt:
++
++ 1. Distance pointers never point before the beginning of the output
++ stream.
++ 2. Distance pointers can point back across blocks, up to 32k away.
++ 3. There is an implied maximum of 7 bits for the bit length table and
++ 15 bits for the actual data.
++ 4. If only one code exists, then it is encoded using one bit. (Zero
++ would be more efficient, but perhaps a little confusing.) If two
++ codes exist, they are coded using one bit each (0 and 1).
++ 5. There is no way of sending zero distance codes--a dummy must be
++ sent if there are none. (History: a pre 2.0 version of PKZIP would
++ store blocks with no distance codes, but this was discovered to be
++ too harsh a criterion.) Valid only for 1.93a. 2.04c does allow
++ zero distance codes, which is sent as one code of zero bits in
++ length.
++ 6. There are up to 286 literal/length codes. Code 256 represents the
++ end-of-block. Note however that the static length tree defines
++ 288 codes just to fill out the Huffman codes. Codes 286 and 287
++ cannot be used though, since there is no length base or extra bits
++ defined for them. Similarily, there are up to 30 distance codes.
++ However, static trees define 32 codes (all 5 bits) to fill out the
++ Huffman codes, but the last two had better not show up in the data.
++ 7. Unzip can check dynamic Huffman blocks for complete code sets.
++ The exception is that a single code would not be complete (see #4).
++ 8. The five bits following the block type is really the number of
++ literal codes sent minus 257.
++ 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
++ (1+6+6). Therefore, to output three times the length, you output
++ three codes (1+1+1), whereas to output four times the same length,
++ you only need two codes (1+3). Hmm.
++ 10. In the tree reconstruction algorithm, Code = Code + Increment
++ only if BitLength(i) is not zero. (Pretty obvious.)
++ 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19)
++ 12. Note: length code 284 can represent 227-258, but length code 285
++ really is 258. The last length deserves its own, short code
++ since it gets used a lot in very redundant files. The length
++ 258 is special since 258 - 3 (the min match length) is 255.
++ 13. The literal/length and distance code bit lengths are read as a
++ single stream of lengths. It is possible (and advantageous) for
++ a repeat code (16, 17, or 18) to go across the boundary between
++ the two sets of lengths.
++ */
++
++
++local void inflate_blocks_reset(s, z, c)
++inflate_blocks_statef *s;
++z_stream *z;
++uLongf *c;
++{
++ if (s-&gt;checkfn != Z_NULL)
++ *c = s-&gt;check;
++ if (s-&gt;mode == BTREE || s-&gt;mode == DTREE)
++ ZFREE(z, s-&gt;sub.trees.blens, s-&gt;sub.trees.nblens * sizeof(uInt));
++ if (s-&gt;mode == CODES)
++ {
++ inflate_codes_free(s-&gt;sub.decode.codes, z);
++ inflate_trees_free(s-&gt;sub.decode.td, z);
++ inflate_trees_free(s-&gt;sub.decode.tl, z);
++ }
++ s-&gt;mode = TYPE;
++ s-&gt;bitk = 0;
++ s-&gt;bitb = 0;
++ s-&gt;read = s-&gt;write = s-&gt;window;
++ if (s-&gt;checkfn != Z_NULL)
++ s-&gt;check = (*s-&gt;checkfn)(0L, Z_NULL, 0);
++ Trace((stderr, &quot;inflate: blocks reset\n&quot;));
++}
++
++
++local inflate_blocks_statef *inflate_blocks_new(z, c, w)
++z_stream *z;
++check_func c;
++uInt w;
++{
++ inflate_blocks_statef *s;
++
++ if ((s = (inflate_blocks_statef *)ZALLOC
++ (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
++ return s;
++ if ((s-&gt;window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
++ {
++ ZFREE(z, s, sizeof(struct inflate_blocks_state));
++ return Z_NULL;
++ }
++ s-&gt;end = s-&gt;window + w;
++ s-&gt;checkfn = c;
++ s-&gt;mode = TYPE;
++ Trace((stderr, &quot;inflate: blocks allocated\n&quot;));
++ inflate_blocks_reset(s, z, &amp;s-&gt;check);
++ return s;
++}
++
++
++local int inflate_blocks(s, z, r)
++inflate_blocks_statef *s;
++z_stream *z;
++int r;
++{
++ uInt t; /* temporary storage */
++ uLong b; /* bit buffer */
++ uInt k; /* bits in bit buffer */
++ Bytef *p; /* input data pointer */
++ uInt n; /* bytes available there */
++ Bytef *q; /* output window write pointer */
++ uInt m; /* bytes to end of window or read pointer */
++
++ /* copy input/output information to locals (UPDATE macro restores) */
++ LOAD
++
++ /* process input based on current state */
++ while (1) switch (s-&gt;mode)
++ {
++ case TYPE:
++ NEEDBITS(3)
++ t = (uInt)b &amp; 7;
++ s-&gt;last = t &amp; 1;
++ switch (t &gt;&gt; 1)
++ {
++ case 0: /* stored */
++ Trace((stderr, &quot;inflate: stored block%s\n&quot;,
++ s-&gt;last ? &quot; (last)&quot; : &quot;&quot;));
++ DUMPBITS(3)
++ t = k &amp; 7; /* go to byte boundary */
++ DUMPBITS(t)
++ s-&gt;mode = LENS; /* get length of stored block */
++ break;
++ case 1: /* fixed */
++ Trace((stderr, &quot;inflate: fixed codes block%s\n&quot;,
++ s-&gt;last ? &quot; (last)&quot; : &quot;&quot;));
++ {
++ uInt bl, bd;
++ inflate_huft *tl, *td;
++
++ inflate_trees_fixed(&amp;bl, &amp;bd, &amp;tl, &amp;td);
++ s-&gt;sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
++ if (s-&gt;sub.decode.codes == Z_NULL)
++ {
++ r = Z_MEM_ERROR;
++ LEAVE
++ }
++ s-&gt;sub.decode.tl = Z_NULL; /* don't try to free these */
++ s-&gt;sub.decode.td = Z_NULL;
++ }
++ DUMPBITS(3)
++ s-&gt;mode = CODES;
++ break;
++ case 2: /* dynamic */
++ Trace((stderr, &quot;inflate: dynamic codes block%s\n&quot;,
++ s-&gt;last ? &quot; (last)&quot; : &quot;&quot;));
++ DUMPBITS(3)
++ s-&gt;mode = TABLE;
++ break;
++ case 3: /* illegal */
++ DUMPBITS(3)
++ s-&gt;mode = BADB;
++ z-&gt;msg = &quot;invalid block type&quot;;
++ r = Z_DATA_ERROR;
++ LEAVE
++ }
++ break;
++ case LENS:
++ NEEDBITS(32)
++ if (((~b) &gt;&gt; 16) != (b &amp; 0xffff))
++ {
++ s-&gt;mode = BADB;
++ z-&gt;msg = &quot;invalid stored block lengths&quot;;
++ r = Z_DATA_ERROR;
++ LEAVE
++ }
++ s-&gt;sub.left = (uInt)b &amp; 0xffff;
++ b = k = 0; /* dump bits */
++ Tracev((stderr, &quot;inflate: stored length %u\n&quot;, s-&gt;sub.left));
++ s-&gt;mode = s-&gt;sub.left ? STORED : TYPE;
++ break;
++ case STORED:
++ if (n == 0)
++ LEAVE
++ NEEDOUT
++ t = s-&gt;sub.left;
++ if (t &gt; n) t = n;
++ if (t &gt; m) t = m;
++ zmemcpy(q, p, t);
++ p += t; n -= t;
++ q += t; m -= t;
++ if ((s-&gt;sub.left -= t) != 0)
++ break;
++ Tracev((stderr, &quot;inflate: stored end, %lu total out\n&quot;,
++ z-&gt;total_out + (q &gt;= s-&gt;read ? q - s-&gt;read :
++ (s-&gt;end - s-&gt;read) + (q - s-&gt;window))));
++ s-&gt;mode = s-&gt;last ? DRY : TYPE;
++ break;
++ case TABLE:
++ NEEDBITS(14)
++ s-&gt;sub.trees.table = t = (uInt)b &amp; 0x3fff;
++#ifndef PKZIP_BUG_WORKAROUND
++ if ((t &amp; 0x1f) &gt; 29 || ((t &gt;&gt; 5) &amp; 0x1f) &gt; 29)
++ {
++ s-&gt;mode = BADB;
++ z-&gt;msg = &quot;too many length or distance symbols&quot;;
++ r = Z_DATA_ERROR;
++ LEAVE
++ }
++#endif
++ t = 258 + (t &amp; 0x1f) + ((t &gt;&gt; 5) &amp; 0x1f);
++ if (t &lt; 19)
++ t = 19;
++ if ((s-&gt;sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
++ {
++ r = Z_MEM_ERROR;
++ LEAVE
++ }
++ s-&gt;sub.trees.nblens = t;
++ DUMPBITS(14)
++ s-&gt;sub.trees.index = 0;
++ Tracev((stderr, &quot;inflate: table sizes ok\n&quot;));
++ s-&gt;mode = BTREE;
++ case BTREE:
++ while (s-&gt;sub.trees.index &lt; 4 + (s-&gt;sub.trees.table &gt;&gt; 10))
++ {
++ NEEDBITS(3)
++ s-&gt;sub.trees.blens[border[s-&gt;sub.trees.index++]] = (uInt)b &amp; 7;
++ DUMPBITS(3)
++ }
++ while (s-&gt;sub.trees.index &lt; 19)
++ s-&gt;sub.trees.blens[border[s-&gt;sub.trees.index++]] = 0;
++ s-&gt;sub.trees.bb = 7;
++ t = inflate_trees_bits(s-&gt;sub.trees.blens, &amp;s-&gt;sub.trees.bb,
++ &amp;s-&gt;sub.trees.tb, z);
++ if (t != Z_OK)
++ {
++ r = t;
++ if (r == Z_DATA_ERROR)
++ s-&gt;mode = BADB;
++ LEAVE
++ }
++ s-&gt;sub.trees.index = 0;
++ Tracev((stderr, &quot;inflate: bits tree ok\n&quot;));
++ s-&gt;mode = DTREE;
++ case DTREE:
++ while (t = s-&gt;sub.trees.table,
++ s-&gt;sub.trees.index &lt; 258 + (t &amp; 0x1f) + ((t &gt;&gt; 5) &amp; 0x1f))
++ {
++ inflate_huft *h;
++ uInt i, j, c;
++
++ t = s-&gt;sub.trees.bb;
++ NEEDBITS(t)
++ h = s-&gt;sub.trees.tb + ((uInt)b &amp; inflate_mask[t]);
++ t = h-&gt;word.what.Bits;
++ c = h-&gt;more.Base;
++ if (c &lt; 16)
++ {
++ DUMPBITS(t)
++ s-&gt;sub.trees.blens[s-&gt;sub.trees.index++] = c;
++ }
++ else /* c == 16..18 */
++ {
++ i = c == 18 ? 7 : c - 14;
++ j = c == 18 ? 11 : 3;
++ NEEDBITS(t + i)
++ DUMPBITS(t)
++ j += (uInt)b &amp; inflate_mask[i];
++ DUMPBITS(i)
++ i = s-&gt;sub.trees.index;
++ t = s-&gt;sub.trees.table;
++ if (i + j &gt; 258 + (t &amp; 0x1f) + ((t &gt;&gt; 5) &amp; 0x1f) ||
++ (c == 16 &amp;&amp; i &lt; 1))
++ {
++ s-&gt;mode = BADB;
++ z-&gt;msg = &quot;invalid bit length repeat&quot;;
++ r = Z_DATA_ERROR;
++ LEAVE
++ }
++ c = c == 16 ? s-&gt;sub.trees.blens[i - 1] : 0;
++ do {
++ s-&gt;sub.trees.blens[i++] = c;
++ } while (--j);
++ s-&gt;sub.trees.index = i;
++ }
++ }
++ inflate_trees_free(s-&gt;sub.trees.tb, z);
++ s-&gt;sub.trees.tb = Z_NULL;
++ {
++ uInt bl, bd;
++ inflate_huft *tl, *td;
++ inflate_codes_statef *c;
++
++ bl = 9; /* must be &lt;= 9 for lookahead assumptions */
++ bd = 6; /* must be &lt;= 9 for lookahead assumptions */
++ t = s-&gt;sub.trees.table;
++ t = inflate_trees_dynamic(257 + (t &amp; 0x1f), 1 + ((t &gt;&gt; 5) &amp; 0x1f),
++ s-&gt;sub.trees.blens, &amp;bl, &amp;bd, &amp;tl, &amp;td, z);
++ if (t != Z_OK)
++ {
++ if (t == (uInt)Z_DATA_ERROR)
++ s-&gt;mode = BADB;
++ r = t;
++ LEAVE
++ }
++ Tracev((stderr, &quot;inflate: trees ok\n&quot;));
++ if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
++ {
++ inflate_trees_free(td, z);
++ inflate_trees_free(tl, z);
++ r = Z_MEM_ERROR;
++ LEAVE
++ }
++ ZFREE(z, s-&gt;sub.trees.blens, s-&gt;sub.trees.nblens * sizeof(uInt));
++ s-&gt;sub.decode.codes = c;
++ s-&gt;sub.decode.tl = tl;
++ s-&gt;sub.decode.td = td;
++ }
++ s-&gt;mode = CODES;
++ case CODES:
++ UPDATE
++ if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
++ return inflate_flush(s, z, r);
++ r = Z_OK;
++ inflate_codes_free(s-&gt;sub.decode.codes, z);
++ inflate_trees_free(s-&gt;sub.decode.td, z);
++ inflate_trees_free(s-&gt;sub.decode.tl, z);
++ LOAD
++ Tracev((stderr, &quot;inflate: codes end, %lu total out\n&quot;,
++ z-&gt;total_out + (q &gt;= s-&gt;read ? q - s-&gt;read :
++ (s-&gt;end - s-&gt;read) + (q - s-&gt;window))));
++ if (!s-&gt;last)
++ {
++ s-&gt;mode = TYPE;
++ break;
++ }
++ if (k &gt; 7) /* return unused byte, if any */
++ {
++ Assert(k &lt; 16, &quot;inflate_codes grabbed too many bytes&quot;)
++ k -= 8;
++ n++;
++ p--; /* can always return one */
++ }
++ s-&gt;mode = DRY;
++ case DRY:
++ FLUSH
++ if (s-&gt;read != s-&gt;write)
++ LEAVE
++ s-&gt;mode = DONEB;
++ case DONEB:
++ r = Z_STREAM_END;
++ LEAVE
++ case BADB:
++ r = Z_DATA_ERROR;
++ LEAVE
++ default:
++ r = Z_STREAM_ERROR;
++ LEAVE
++ }
++}
++
++
++local int inflate_blocks_free(s, z, c)
++inflate_blocks_statef *s;
++z_stream *z;
++uLongf *c;
++{
++ inflate_blocks_reset(s, z, c);
++ ZFREE(z, s-&gt;window, s-&gt;end - s-&gt;window);
++ ZFREE(z, s, sizeof(struct inflate_blocks_state));
++ Trace((stderr, &quot;inflate: blocks freed\n&quot;));
++ return Z_OK;
++}
++
++/*
++ * This subroutine adds the data at next_in/avail_in to the output history
++ * without performing any output. The output buffer must be &quot;caught up&quot;;
++ * i.e. no pending output (hence s-&gt;read equals s-&gt;write), and the state must
++ * be BLOCKS (i.e. we should be willing to see the start of a series of
++ * BLOCKS). On exit, the output will also be caught up, and the checksum
++ * will have been updated if need be.
++ */
++local int inflate_addhistory(s, z)
++inflate_blocks_statef *s;
++z_stream *z;
++{
++ uLong b; /* bit buffer */ /* NOT USED HERE */
++ uInt k; /* bits in bit buffer */ /* NOT USED HERE */
++ uInt t; /* temporary storage */
++ Bytef *p; /* input data pointer */
++ uInt n; /* bytes available there */
++ Bytef *q; /* output window write pointer */
++ uInt m; /* bytes to end of window or read pointer */
++
++ if (s-&gt;read != s-&gt;write)
++ return Z_STREAM_ERROR;
++ if (s-&gt;mode != TYPE)
++ return Z_DATA_ERROR;
++
++ /* we're ready to rock */
++ LOAD
++ /* while there is input ready, copy to output buffer, moving
++ * pointers as needed.
++ */
++ while (n) {
++ t = n; /* how many to do */
++ /* is there room until end of buffer? */
++ if (t &gt; m) t = m;
++ /* update check information */
++ if (s-&gt;checkfn != Z_NULL)
++ s-&gt;check = (*s-&gt;checkfn)(s-&gt;check, q, t);
++ zmemcpy(q, p, t);
++ q += t;
++ p += t;
++ n -= t;
++ z-&gt;total_out += t;
++ s-&gt;read = q; /* drag read pointer forward */
++/* WRAP */ /* expand WRAP macro by hand to handle s-&gt;read */
++ if (q == s-&gt;end) {
++ s-&gt;read = q = s-&gt;window;
++ m = WAVAIL;
++ }
++ }
++ UPDATE
++ return Z_OK;
++}
++
++
++/*
++ * At the end of a Deflate-compressed PPP packet, we expect to have seen
++ * a `stored' block type value but not the (zero) length bytes.
++ */
++local int inflate_packet_flush(s)
++ inflate_blocks_statef *s;
++{
++ if (s-&gt;mode != LENS)
++ return Z_DATA_ERROR;
++ s-&gt;mode = TYPE;
++ return Z_OK;
++}
++
++
++/*+++++*/
++/* inftrees.c -- generate Huffman trees for efficient decoding
++ * Copyright (C) 1995 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* simplify the use of the inflate_huft type with some defines */
++#define base more.Base
++#define next more.Next
++#define exop word.what.Exop
++#define bits word.what.Bits
++
++
++local int huft_build OF((
++ uIntf *, /* code lengths in bits */
++ uInt, /* number of codes */
++ uInt, /* number of &quot;simple&quot; codes */
++ uIntf *, /* list of base values for non-simple codes */
++ uIntf *, /* list of extra bits for non-simple codes */
++ inflate_huft * FAR*,/* result: starting table */
++ uIntf *, /* maximum lookup bits (returns actual) */
++ z_stream *)); /* for zalloc function */
++
++local voidpf falloc OF((
++ voidpf, /* opaque pointer (not used) */
++ uInt, /* number of items */
++ uInt)); /* size of item */
++
++local void ffree OF((
++ voidpf q, /* opaque pointer (not used) */
++ voidpf p, /* what to free (not used) */
++ uInt n)); /* number of bytes (not used) */
++
++/* Tables for deflate from PKZIP's appnote.txt. */
++local uInt cplens[] = { /* Copy lengths for literal codes 257..285 */
++ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
++ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
++ /* actually lengths - 2; also see note #13 above about 258 */
++local uInt cplext[] = { /* Extra bits for literal codes 257..285 */
++ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
++ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 192, 192}; /* 192==invalid */
++local uInt cpdist[] = { /* Copy offsets for distance codes 0..29 */
++ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
++ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
++ 8193, 12289, 16385, 24577};
++local uInt cpdext[] = { /* Extra bits for distance codes */
++ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
++ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
++ 12, 12, 13, 13};
++
++/*
++ Huffman code decoding is performed using a multi-level table lookup.
++ The fastest way to decode is to simply build a lookup table whose
++ size is determined by the longest code. However, the time it takes
++ to build this table can also be a factor if the data being decoded
++ is not very long. The most common codes are necessarily the
++ shortest codes, so those codes dominate the decoding time, and hence
++ the speed. The idea is you can have a shorter table that decodes the
++ shorter, more probable codes, and then point to subsidiary tables for
++ the longer codes. The time it costs to decode the longer codes is
++ then traded against the time it takes to make longer tables.
++
++ This results of this trade are in the variables lbits and dbits
++ below. lbits is the number of bits the first level table for literal/
++ length codes can decode in one step, and dbits is the same thing for
++ the distance codes. Subsequent tables are also less than or equal to
++ those sizes. These values may be adjusted either when all of the
++ codes are shorter than that, in which case the longest code length in
++ bits is used, or when the shortest code is *longer* than the requested
++ table size, in which case the length of the shortest code in bits is
++ used.
++
++ There are two different values for the two tables, since they code a
++ different number of possibilities each. The literal/length table
++ codes 286 possible values, or in a flat code, a little over eight
++ bits. The distance table codes 30 possible values, or a little less
++ than five bits, flat. The optimum values for speed end up being
++ about one bit more than those, so lbits is 8+1 and dbits is 5+1.
++ The optimum values may differ though from machine to machine, and
++ possibly even between compilers. Your mileage may vary.
++ */
++
++
++/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
++#define BMAX 15 /* maximum bit length of any code */
++#define N_MAX 288 /* maximum number of codes in any set */
++
++#ifdef DEBUG_ZLIB
++ uInt inflate_hufts;
++#endif
++
++local int huft_build(b, n, s, d, e, t, m, zs)
++uIntf *b; /* code lengths in bits (all assumed &lt;= BMAX) */
++uInt n; /* number of codes (assumed &lt;= N_MAX) */
++uInt s; /* number of simple-valued codes (0..s-1) */
++uIntf *d; /* list of base values for non-simple codes */
++uIntf *e; /* list of extra bits for non-simple codes */
++inflate_huft * FAR *t; /* result: starting table */
++uIntf *m; /* maximum lookup bits, returns actual */
++z_stream *zs; /* for zalloc function */
++/* Given a list of code lengths and a maximum table size, make a set of
++ tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR
++ if the given code set is incomplete (the tables are still built in this
++ case), Z_DATA_ERROR if the input is invalid (all zero length codes or an
++ over-subscribed set of lengths), or Z_MEM_ERROR if not enough memory. */
++{
++
++ uInt a; /* counter for codes of length k */
++ uInt c[BMAX+1]; /* bit length count table */
++ uInt f; /* i repeats in table every f entries */
++ int g; /* maximum code length */
++ int h; /* table level */
++ register uInt i; /* counter, current code */
++ register uInt j; /* counter */
++ register int k; /* number of bits in current code */
++ int l; /* bits per table (returned in m) */
++ register uIntf *p; /* pointer into c[], b[], or v[] */
++ inflate_huft *q; /* points to current table */
++ struct inflate_huft_s r; /* table entry for structure assignment */
++ inflate_huft *u[BMAX]; /* table stack */
++ uInt v[N_MAX]; /* values in order of bit length */
++ register int w; /* bits before this table == (l * h) */
++ uInt x[BMAX+1]; /* bit offsets, then code stack */
++ uIntf *xp; /* pointer into x */
++ int y; /* number of dummy codes added */
++ uInt z; /* number of entries in current table */
++
++
++ /* Generate counts for each bit length */
++ p = c;
++#define C0 *p++ = 0;
++#define C2 C0 C0 C0 C0
++#define C4 C2 C2 C2 C2
++ C4 /* clear c[]--assume BMAX+1 is 16 */
++ p = b; i = n;
++ do {
++ c[*p++]++; /* assume all entries &lt;= BMAX */
++ } while (--i);
++ if (c[0] == n) /* null input--all zero length codes */
++ {
++ *t = (inflate_huft *)Z_NULL;
++ *m = 0;
++ return Z_OK;
++ }
++
++
++ /* Find minimum and maximum length, bound *m by those */
++ l = *m;
++ for (j = 1; j &lt;= BMAX; j++)
++ if (c[j])
++ break;
++ k = j; /* minimum code length */
++ if ((uInt)l &lt; j)
++ l = j;
++ for (i = BMAX; i; i--)
++ if (c[i])
++ break;
++ g = i; /* maximum code length */
++ if ((uInt)l &gt; i)
++ l = i;
++ *m = l;
++
++
++ /* Adjust last length count to fill out codes, if needed */
++ for (y = 1 &lt;&lt; j; j &lt; i; j++, y &lt;&lt;= 1)
++ if ((y -= c[j]) &lt; 0)
++ return Z_DATA_ERROR;
++ if ((y -= c[i]) &lt; 0)
++ return Z_DATA_ERROR;
++ c[i] += y;
++
++
++ /* Generate starting offsets into the value table for each length */
++ x[1] = j = 0;
++ p = c + 1; xp = x + 2;
++ while (--i) { /* note that i == g from above */
++ *xp++ = (j += *p++);
++ }
++
++
++ /* Make a table of values in order of bit lengths */
++ p = b; i = 0;
++ do {
++ if ((j = *p++) != 0)
++ v[x[j]++] = i;
++ } while (++i &lt; n);
++
++
++ /* Generate the Huffman codes and for each, make the table entries */
++ x[0] = i = 0; /* first Huffman code is zero */
++ p = v; /* grab values in bit order */
++ h = -1; /* no tables yet--level -1 */
++ w = -l; /* bits decoded == (l * h) */
++ u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */
++ q = (inflate_huft *)Z_NULL; /* ditto */
++ z = 0; /* ditto */
++
++ /* go through the bit lengths (k already is bits in shortest code) */
++ for (; k &lt;= g; k++)
++ {
++ a = c[k];
++ while (a--)
++ {
++ /* here i is the Huffman code of length k bits for value *p */
++ /* make tables up to required level */
++ while (k &gt; w + l)
++ {
++ h++;
++ w += l; /* previous table always l bits */
++
++ /* compute minimum size table less than or equal to l bits */
++ z = (z = g - w) &gt; (uInt)l ? l : z; /* table size upper limit */
++ if ((f = 1 &lt;&lt; (j = k - w)) &gt; a + 1) /* try a k-w bit table */
++ { /* too few codes for k-w bit table */
++ f -= a + 1; /* deduct codes from patterns left */
++ xp = c + k;
++ if (j &lt; z)
++ while (++j &lt; z) /* try smaller tables up to z bits */
++ {
++ if ((f &lt;&lt;= 1) &lt;= *++xp)
++ break; /* enough codes to use up j bits */
++ f -= *xp; /* else deduct codes from patterns */
++ }
++ }
++ z = 1 &lt;&lt; j; /* table entries for j-bit table */
++
++ /* allocate and link in new table */
++ if ((q = (inflate_huft *)ZALLOC
++ (zs,z + 1,sizeof(inflate_huft))) == Z_NULL)
++ {
++ if (h)
++ inflate_trees_free(u[0], zs);
++ return Z_MEM_ERROR; /* not enough memory */
++ }
++ q-&gt;word.Nalloc = z + 1;
++#ifdef DEBUG_ZLIB
++ inflate_hufts += z + 1;
++#endif
++ *t = q + 1; /* link to list for huft_free() */
++ *(t = &amp;(q-&gt;next)) = Z_NULL;
++ u[h] = ++q; /* table starts after link */
++
++ /* connect to last table, if there is one */
++ if (h)
++ {
++ x[h] = i; /* save pattern for backing up */
++ r.bits = (Byte)l; /* bits to dump before this table */
++ r.exop = (Byte)j; /* bits in this table */
++ r.next = q; /* pointer to this table */
++ j = i &gt;&gt; (w - l); /* (get around Turbo C bug) */
++ u[h-1][j] = r; /* connect to last table */
++ }
++ }
++
++ /* set up table entry in r */
++ r.bits = (Byte)(k - w);
++ if (p &gt;= v + n)
++ r.exop = 128 + 64; /* out of values--invalid code */
++ else if (*p &lt; s)
++ {
++ r.exop = (Byte)(*p &lt; 256 ? 0 : 32 + 64); /* 256 is end-of-block */
++ r.base = *p++; /* simple code is just the value */
++ }
++ else
++ {
++ r.exop = (Byte)e[*p - s] + 16 + 64; /* non-simple--look up in lists */
++ r.base = d[*p++ - s];
++ }
++
++ /* fill code-like entries with r */
++ f = 1 &lt;&lt; (k - w);
++ for (j = i &gt;&gt; w; j &lt; z; j += f)
++ q[j] = r;
++
++ /* backwards increment the k-bit code i */
++ for (j = 1 &lt;&lt; (k - 1); i &amp; j; j &gt;&gt;= 1)
++ i ^= j;
++ i ^= j;
++
++ /* backup over finished tables */
++ while ((i &amp; ((1 &lt;&lt; w) - 1)) != x[h])
++ {
++ h--; /* don't need to update q */
++ w -= l;
++ }
++ }
++ }
++
++
++ /* Return Z_BUF_ERROR if we were given an incomplete table */
++ return y != 0 &amp;&amp; g != 1 ? Z_BUF_ERROR : Z_OK;
++}
++
++
++local int inflate_trees_bits(c, bb, tb, z)
++uIntf *c; /* 19 code lengths */
++uIntf *bb; /* bits tree desired/actual depth */
++inflate_huft * FAR *tb; /* bits tree result */
++z_stream *z; /* for zfree function */
++{
++ int r;
++
++ r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z);
++ if (r == Z_DATA_ERROR)
++ z-&gt;msg = &quot;oversubscribed dynamic bit lengths tree&quot;;
++ else if (r == Z_BUF_ERROR)
++ {
++ inflate_trees_free(*tb, z);
++ z-&gt;msg = &quot;incomplete dynamic bit lengths tree&quot;;
++ r = Z_DATA_ERROR;
++ }
++ return r;
++}
++
++
++local int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z)
++uInt nl; /* number of literal/length codes */
++uInt nd; /* number of distance codes */
++uIntf *c; /* that many (total) code lengths */
++uIntf *bl; /* literal desired/actual bit depth */
++uIntf *bd; /* distance desired/actual bit depth */
++inflate_huft * FAR *tl; /* literal/length tree result */
++inflate_huft * FAR *td; /* distance tree result */
++z_stream *z; /* for zfree function */
++{
++ int r;
++
++ /* build literal/length tree */
++ if ((r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z)) != Z_OK)
++ {
++ if (r == Z_DATA_ERROR)
++ z-&gt;msg = &quot;oversubscribed literal/length tree&quot;;
++ else if (r == Z_BUF_ERROR)
++ {
++ inflate_trees_free(*tl, z);
++ z-&gt;msg = &quot;incomplete literal/length tree&quot;;
++ r = Z_DATA_ERROR;
++ }
++ return r;
++ }
++
++ /* build distance tree */
++ if ((r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z)) != Z_OK)
++ {
++ if (r == Z_DATA_ERROR)
++ z-&gt;msg = &quot;oversubscribed literal/length tree&quot;;
++ else if (r == Z_BUF_ERROR) {
++#ifdef PKZIP_BUG_WORKAROUND
++ r = Z_OK;
++ }
++#else
++ inflate_trees_free(*td, z);
++ z-&gt;msg = &quot;incomplete literal/length tree&quot;;
++ r = Z_DATA_ERROR;
++ }
++ inflate_trees_free(*tl, z);
++ return r;
++#endif
++ }
++
++ /* done */
++ return Z_OK;
++}
++
++
++/* build fixed tables only once--keep them here */
++local int fixed_lock = 0;
++local int fixed_built = 0;
++#define FIXEDH 530 /* number of hufts used by fixed tables */
++local uInt fixed_left = FIXEDH;
++local inflate_huft fixed_mem[FIXEDH];
++local uInt fixed_bl;
++local uInt fixed_bd;
++local inflate_huft *fixed_tl;
++local inflate_huft *fixed_td;
++
++
++local voidpf falloc(q, n, s)
++voidpf q; /* opaque pointer (not used) */
++uInt n; /* number of items */
++uInt s; /* size of item */
++{
++ Assert(s == sizeof(inflate_huft) &amp;&amp; n &lt;= fixed_left,
++ &quot;inflate_trees falloc overflow&quot;);
++ if (q) s++; /* to make some compilers happy */
++ fixed_left -= n;
++ return (voidpf)(fixed_mem + fixed_left);
++}
++
++
++local void ffree(q, p, n)
++voidpf q;
++voidpf p;
++uInt n;
++{
++ Assert(0, &quot;inflate_trees ffree called!&quot;);
++ if (q) q = p; /* to make some compilers happy */
++}
++
++
++local int inflate_trees_fixed(bl, bd, tl, td)
++uIntf *bl; /* literal desired/actual bit depth */
++uIntf *bd; /* distance desired/actual bit depth */
++inflate_huft * FAR *tl; /* literal/length tree result */
++inflate_huft * FAR *td; /* distance tree result */
++{
++ /* build fixed tables if not built already--lock out other instances */
++ while (++fixed_lock &gt; 1)
++ fixed_lock--;
++ if (!fixed_built)
++ {
++ int k; /* temporary variable */
++ unsigned c[288]; /* length list for huft_build */
++ z_stream z; /* for falloc function */
++
++ /* set up fake z_stream for memory routines */
++ z.zalloc = falloc;
++ z.zfree = ffree;
++ z.opaque = Z_NULL;
++
++ /* literal table */
++ for (k = 0; k &lt; 144; k++)
++ c[k] = 8;
++ for (; k &lt; 256; k++)
++ c[k] = 9;
++ for (; k &lt; 280; k++)
++ c[k] = 7;
++ for (; k &lt; 288; k++)
++ c[k] = 8;
++ fixed_bl = 7;
++ huft_build(c, 288, 257, cplens, cplext, &amp;fixed_tl, &amp;fixed_bl, &amp;z);
++
++ /* distance table */
++ for (k = 0; k &lt; 30; k++)
++ c[k] = 5;
++ fixed_bd = 5;
++ huft_build(c, 30, 0, cpdist, cpdext, &amp;fixed_td, &amp;fixed_bd, &amp;z);
++
++ /* done */
++ fixed_built = 1;
++ }
++ fixed_lock--;
++ *bl = fixed_bl;
++ *bd = fixed_bd;
++ *tl = fixed_tl;
++ *td = fixed_td;
++ return Z_OK;
++}
++
++
++local int inflate_trees_free(t, z)
++inflate_huft *t; /* table to free */
++z_stream *z; /* for zfree function */
++/* Free the malloc'ed tables built by huft_build(), which makes a linked
++ list of the tables it made, with the links in a dummy first entry of
++ each table. */
++{
++ register inflate_huft *p, *q;
++
++ /* Go through linked list, freeing from the malloced (t[-1]) address. */
++ p = t;
++ while (p != Z_NULL)
++ {
++ q = (--p)-&gt;next;
++ ZFREE(z, p, p-&gt;word.Nalloc * sizeof(inflate_huft));
++ p = q;
++ }
++ return Z_OK;
++}
++
++/*+++++*/
++/* infcodes.c -- process literals and length/distance pairs
++ * Copyright (C) 1995 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* simplify the use of the inflate_huft type with some defines */
++#define base more.Base
++#define next more.Next
++#define exop word.what.Exop
++#define bits word.what.Bits
++
++/* inflate codes private state */
++struct inflate_codes_state {
++
++ /* mode */
++ enum { /* waiting for &quot;i:&quot;=input, &quot;o:&quot;=output, &quot;x:&quot;=nothing */
++ START, /* x: set up for LEN */
++ LEN, /* i: get length/literal/eob next */
++ LENEXT, /* i: getting length extra (have base) */
++ DIST, /* i: get distance next */
++ DISTEXT, /* i: getting distance extra */
++ COPY, /* o: copying bytes in window, waiting for space */
++ LIT, /* o: got literal, waiting for output space */
++ WASH, /* o: got eob, possibly still output waiting */
++ END, /* x: got eob and all data flushed */
++ BADCODE} /* x: got error */
++ mode; /* current inflate_codes mode */
++
++ /* mode dependent information */
++ uInt len;
++ union {
++ struct {
++ inflate_huft *tree; /* pointer into tree */
++ uInt need; /* bits needed */
++ } code; /* if LEN or DIST, where in tree */
++ uInt lit; /* if LIT, literal */
++ struct {
++ uInt get; /* bits to get for extra */
++ uInt dist; /* distance back to copy from */
++ } copy; /* if EXT or COPY, where and how much */
++ } sub; /* submode */
++
++ /* mode independent information */
++ Byte lbits; /* ltree bits decoded per branch */
++ Byte dbits; /* dtree bits decoder per branch */
++ inflate_huft *ltree; /* literal/length/eob tree */
++ inflate_huft *dtree; /* distance tree */
++
++};
++
++
++local inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
++uInt bl, bd;
++inflate_huft *tl, *td;
++z_stream *z;
++{
++ inflate_codes_statef *c;
++
++ if ((c = (inflate_codes_statef *)
++ ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
++ {
++ c-&gt;mode = START;
++ c-&gt;lbits = (Byte)bl;
++ c-&gt;dbits = (Byte)bd;
++ c-&gt;ltree = tl;
++ c-&gt;dtree = td;
++ Tracev((stderr, &quot;inflate: codes new\n&quot;));
++ }
++ return c;
++}
++
++
++local int inflate_codes(s, z, r)
++inflate_blocks_statef *s;
++z_stream *z;
++int r;
++{
++ uInt j; /* temporary storage */
++ inflate_huft *t; /* temporary pointer */
++ uInt e; /* extra bits or operation */
++ uLong b; /* bit buffer */
++ uInt k; /* bits in bit buffer */
++ Bytef *p; /* input data pointer */
++ uInt n; /* bytes available there */
++ Bytef *q; /* output window write pointer */
++ uInt m; /* bytes to end of window or read pointer */
++ Bytef *f; /* pointer to copy strings from */
++ inflate_codes_statef *c = s-&gt;sub.decode.codes; /* codes state */
++
++ /* copy input/output information to locals (UPDATE macro restores) */
++ LOAD
++
++ /* process input and output based on current state */
++ while (1) switch (c-&gt;mode)
++ { /* waiting for &quot;i:&quot;=input, &quot;o:&quot;=output, &quot;x:&quot;=nothing */
++ case START: /* x: set up for LEN */
++#ifndef SLOW
++ if (m &gt;= 258 &amp;&amp; n &gt;= 10)
++ {
++ UPDATE
++ r = inflate_fast(c-&gt;lbits, c-&gt;dbits, c-&gt;ltree, c-&gt;dtree, s, z);
++ LOAD
++ if (r != Z_OK)
++ {
++ c-&gt;mode = r == Z_STREAM_END ? WASH : BADCODE;
++ break;
++ }
++ }
++#endif /* !SLOW */
++ c-&gt;sub.code.need = c-&gt;lbits;
++ c-&gt;sub.code.tree = c-&gt;ltree;
++ c-&gt;mode = LEN;
++ case LEN: /* i: get length/literal/eob next */
++ j = c-&gt;sub.code.need;
++ NEEDBITS(j)
++ t = c-&gt;sub.code.tree + ((uInt)b &amp; inflate_mask[j]);
++ DUMPBITS(t-&gt;bits)
++ e = (uInt)(t-&gt;exop);
++ if (e == 0) /* literal */
++ {
++ c-&gt;sub.lit = t-&gt;base;
++ Tracevv((stderr, t-&gt;base &gt;= 0x20 &amp;&amp; t-&gt;base &lt; 0x7f ?
++ &quot;inflate: literal '%c'\n&quot; :
++ &quot;inflate: literal 0x%02x\n&quot;, t-&gt;base));
++ c-&gt;mode = LIT;
++ break;
++ }
++ if (e &amp; 16) /* length */
++ {
++ c-&gt;sub.copy.get = e &amp; 15;
++ c-&gt;len = t-&gt;base;
++ c-&gt;mode = LENEXT;
++ break;
++ }
++ if ((e &amp; 64) == 0) /* next table */
++ {
++ c-&gt;sub.code.need = e;
++ c-&gt;sub.code.tree = t-&gt;next;
++ break;
++ }
++ if (e &amp; 32) /* end of block */
++ {
++ Tracevv((stderr, &quot;inflate: end of block\n&quot;));
++ c-&gt;mode = WASH;
++ break;
++ }
++ c-&gt;mode = BADCODE; /* invalid code */
++ z-&gt;msg = &quot;invalid literal/length code&quot;;
++ r = Z_DATA_ERROR;
++ LEAVE
++ case LENEXT: /* i: getting length extra (have base) */
++ j = c-&gt;sub.copy.get;
++ NEEDBITS(j)
++ c-&gt;len += (uInt)b &amp; inflate_mask[j];
++ DUMPBITS(j)
++ c-&gt;sub.code.need = c-&gt;dbits;
++ c-&gt;sub.code.tree = c-&gt;dtree;
++ Tracevv((stderr, &quot;inflate: length %u\n&quot;, c-&gt;len));
++ c-&gt;mode = DIST;
++ case DIST: /* i: get distance next */
++ j = c-&gt;sub.code.need;
++ NEEDBITS(j)
++ t = c-&gt;sub.code.tree + ((uInt)b &amp; inflate_mask[j]);
++ DUMPBITS(t-&gt;bits)
++ e = (uInt)(t-&gt;exop);
++ if (e &amp; 16) /* distance */
++ {
++ c-&gt;sub.copy.get = e &amp; 15;
++ c-&gt;sub.copy.dist = t-&gt;base;
++ c-&gt;mode = DISTEXT;
++ break;
++ }
++ if ((e &amp; 64) == 0) /* next table */
++ {
++ c-&gt;sub.code.need = e;
++ c-&gt;sub.code.tree = t-&gt;next;
++ break;
++ }
++ c-&gt;mode = BADCODE; /* invalid code */
++ z-&gt;msg = &quot;invalid distance code&quot;;
++ r = Z_DATA_ERROR;
++ LEAVE
++ case DISTEXT: /* i: getting distance extra */
++ j = c-&gt;sub.copy.get;
++ NEEDBITS(j)
++ c-&gt;sub.copy.dist += (uInt)b &amp; inflate_mask[j];
++ DUMPBITS(j)
++ Tracevv((stderr, &quot;inflate: distance %u\n&quot;, c-&gt;sub.copy.dist));
++ c-&gt;mode = COPY;
++ case COPY: /* o: copying bytes in window, waiting for space */
++#ifndef __TURBOC__ /* Turbo C bug for following expression */
++ f = (uInt)(q - s-&gt;window) &lt; c-&gt;sub.copy.dist ?
++ s-&gt;end - (c-&gt;sub.copy.dist - (q - s-&gt;window)) :
++ q - c-&gt;sub.copy.dist;
++#else
++ f = q - c-&gt;sub.copy.dist;
++ if ((uInt)(q - s-&gt;window) &lt; c-&gt;sub.copy.dist)
++ f = s-&gt;end - (c-&gt;sub.copy.dist - (q - s-&gt;window));
++#endif
++ while (c-&gt;len)
++ {
++ NEEDOUT
++ OUTBYTE(*f++)
++ if (f == s-&gt;end)
++ f = s-&gt;window;
++ c-&gt;len--;
++ }
++ c-&gt;mode = START;
++ break;
++ case LIT: /* o: got literal, waiting for output space */
++ NEEDOUT
++ OUTBYTE(c-&gt;sub.lit)
++ c-&gt;mode = START;
++ break;
++ case WASH: /* o: got eob, possibly more output */
++ FLUSH
++ if (s-&gt;read != s-&gt;write)
++ LEAVE
++ c-&gt;mode = END;
++ case END:
++ r = Z_STREAM_END;
++ LEAVE
++ case BADCODE: /* x: got error */
++ r = Z_DATA_ERROR;
++ LEAVE
++ default:
++ r = Z_STREAM_ERROR;
++ LEAVE
++ }
++}
++
++
++local void inflate_codes_free(c, z)
++inflate_codes_statef *c;
++z_stream *z;
++{
++ ZFREE(z, c, sizeof(struct inflate_codes_state));
++ Tracev((stderr, &quot;inflate: codes free\n&quot;));
++}
++
++/*+++++*/
++/* inflate_util.c -- data and routines common to blocks and codes
++ * Copyright (C) 1995 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* copy as much as possible from the sliding window to the output area */
++local int inflate_flush(s, z, r)
++inflate_blocks_statef *s;
++z_stream *z;
++int r;
++{
++ uInt n;
++ Bytef *p, *q;
++
++ /* local copies of source and destination pointers */
++ p = z-&gt;next_out;
++ q = s-&gt;read;
++
++ /* compute number of bytes to copy as far as end of window */
++ n = (uInt)((q &lt;= s-&gt;write ? s-&gt;write : s-&gt;end) - q);
++ if (n &gt; z-&gt;avail_out) n = z-&gt;avail_out;
++ if (n &amp;&amp; r == Z_BUF_ERROR) r = Z_OK;
++
++ /* update counters */
++ z-&gt;avail_out -= n;
++ z-&gt;total_out += n;
++
++ /* update check information */
++ if (s-&gt;checkfn != Z_NULL)
++ s-&gt;check = (*s-&gt;checkfn)(s-&gt;check, q, n);
++
++ /* copy as far as end of window */
++ if (p != NULL) {
++ zmemcpy(p, q, n);
++ p += n;
++ }
++ q += n;
++
++ /* see if more to copy at beginning of window */
++ if (q == s-&gt;end)
++ {
++ /* wrap pointers */
++ q = s-&gt;window;
++ if (s-&gt;write == s-&gt;end)
++ s-&gt;write = s-&gt;window;
++
++ /* compute bytes to copy */
++ n = (uInt)(s-&gt;write - q);
++ if (n &gt; z-&gt;avail_out) n = z-&gt;avail_out;
++ if (n &amp;&amp; r == Z_BUF_ERROR) r = Z_OK;
++
++ /* update counters */
++ z-&gt;avail_out -= n;
++ z-&gt;total_out += n;
++
++ /* update check information */
++ if (s-&gt;checkfn != Z_NULL)
++ s-&gt;check = (*s-&gt;checkfn)(s-&gt;check, q, n);
++
++ /* copy */
++ if (p != NULL) {
++ zmemcpy(p, q, n);
++ p += n;
++ }
++ q += n;
++ }
++
++ /* update pointers */
++ z-&gt;next_out = p;
++ s-&gt;read = q;
++
++ /* done */
++ return r;
++}
++
++
++/*+++++*/
++/* inffast.c -- process literals and length/distance pairs fast
++ * Copyright (C) 1995 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* simplify the use of the inflate_huft type with some defines */
++#define base more.Base
++#define next more.Next
++#define exop word.what.Exop
++#define bits word.what.Bits
++
++/* macros for bit input with no checking and for returning unused bytes */
++#define GRABBITS(j) {while(k&lt;(j)){b|=((uLong)NEXTBYTE)&lt;&lt;k;k+=8;}}
++#define UNGRAB {n+=(c=k&gt;&gt;3);p-=c;k&amp;=7;}
++
++/* Called with number of bytes left to write in window at least 258
++ (the maximum string length) and number of input bytes available
++ at least ten. The ten bytes are six bytes for the longest length/
++ distance pair plus four bytes for overloading the bit buffer. */
++
++local int inflate_fast(bl, bd, tl, td, s, z)
++uInt bl, bd;
++inflate_huft *tl, *td;
++inflate_blocks_statef *s;
++z_stream *z;
++{
++ inflate_huft *t; /* temporary pointer */
++ uInt e; /* extra bits or operation */
++ uLong b; /* bit buffer */
++ uInt k; /* bits in bit buffer */
++ Bytef *p; /* input data pointer */
++ uInt n; /* bytes available there */
++ Bytef *q; /* output window write pointer */
++ uInt m; /* bytes to end of window or read pointer */
++ uInt ml; /* mask for literal/length tree */
++ uInt md; /* mask for distance tree */
++ uInt c; /* bytes to copy */
++ uInt d; /* distance back to copy from */
++ Bytef *r; /* copy source pointer */
++
++ /* load input, output, bit values */
++ LOAD
++
++ /* initialize masks */
++ ml = inflate_mask[bl];
++ md = inflate_mask[bd];
++
++ /* do until not enough input or output space for fast loop */
++ do { /* assume called with m &gt;= 258 &amp;&amp; n &gt;= 10 */
++ /* get literal/length code */
++ GRABBITS(20) /* max bits for literal/length code */
++ if ((e = (t = tl + ((uInt)b &amp; ml))-&gt;exop) == 0)
++ {
++ DUMPBITS(t-&gt;bits)
++ Tracevv((stderr, t-&gt;base &gt;= 0x20 &amp;&amp; t-&gt;base &lt; 0x7f ?
++ &quot;inflate: * literal '%c'\n&quot; :
++ &quot;inflate: * literal 0x%02x\n&quot;, t-&gt;base));
++ *q++ = (Byte)t-&gt;base;
++ m--;
++ continue;
++ }
++ do {
++ DUMPBITS(t-&gt;bits)
++ if (e &amp; 16)
++ {
++ /* get extra bits for length */
++ e &amp;= 15;
++ c = t-&gt;base + ((uInt)b &amp; inflate_mask[e]);
++ DUMPBITS(e)
++ Tracevv((stderr, &quot;inflate: * length %u\n&quot;, c));
++
++ /* decode distance base of block to copy */
++ GRABBITS(15); /* max bits for distance code */
++ e = (t = td + ((uInt)b &amp; md))-&gt;exop;
++ do {
++ DUMPBITS(t-&gt;bits)
++ if (e &amp; 16)
++ {
++ /* get extra bits to add to distance base */
++ e &amp;= 15;
++ GRABBITS(e) /* get extra bits (up to 13) */
++ d = t-&gt;base + ((uInt)b &amp; inflate_mask[e]);
++ DUMPBITS(e)
++ Tracevv((stderr, &quot;inflate: * distance %u\n&quot;, d));
++
++ /* do the copy */
++ m -= c;
++ if ((uInt)(q - s-&gt;window) &gt;= d) /* offset before dest */
++ { /* just copy */
++ r = q - d;
++ *q++ = *r++; c--; /* minimum count is three, */
++ *q++ = *r++; c--; /* so unroll loop a little */
++ }
++ else /* else offset after destination */
++ {
++ e = d - (q - s-&gt;window); /* bytes from offset to end */
++ r = s-&gt;end - e; /* pointer to offset */
++ if (c &gt; e) /* if source crosses, */
++ {
++ c -= e; /* copy to end of window */
++ do {
++ *q++ = *r++;
++ } while (--e);
++ r = s-&gt;window; /* copy rest from start of window */
++ }
++ }
++ do { /* copy all or what's left */
++ *q++ = *r++;
++ } while (--c);
++ break;
++ }
++ else if ((e &amp; 64) == 0)
++ e = (t = t-&gt;next + ((uInt)b &amp; inflate_mask[e]))-&gt;exop;
++ else
++ {
++ z-&gt;msg = &quot;invalid distance code&quot;;
++ UNGRAB
++ UPDATE
++ return Z_DATA_ERROR;
++ }
++ } while (1);
++ break;
++ }
++ if ((e &amp; 64) == 0)
++ {
++ if ((e = (t = t-&gt;next + ((uInt)b &amp; inflate_mask[e]))-&gt;exop) == 0)
++ {
++ DUMPBITS(t-&gt;bits)
++ Tracevv((stderr, t-&gt;base &gt;= 0x20 &amp;&amp; t-&gt;base &lt; 0x7f ?
++ &quot;inflate: * literal '%c'\n&quot; :
++ &quot;inflate: * literal 0x%02x\n&quot;, t-&gt;base));
++ *q++ = (Byte)t-&gt;base;
++ m--;
++ break;
++ }
++ }
++ else if (e &amp; 32)
++ {
++ Tracevv((stderr, &quot;inflate: * end of block\n&quot;));
++ UNGRAB
++ UPDATE
++ return Z_STREAM_END;
++ }
++ else
++ {
++ z-&gt;msg = &quot;invalid literal/length code&quot;;
++ UNGRAB
++ UPDATE
++ return Z_DATA_ERROR;
++ }
++ } while (1);
++ } while (m &gt;= 258 &amp;&amp; n &gt;= 10);
++
++ /* not enough input or output--restore pointers and return */
++ UNGRAB
++ UPDATE
++ return Z_OK;
++}
++
++
++/*+++++*/
++/* zutil.c -- target dependent utility functions for the compression library
++ * Copyright (C) 1995 Jean-loup Gailly.
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* From: zutil.c,v 1.8 1995/05/03 17:27:12 jloup Exp */
++
++char *zlib_version = ZLIB_VERSION;
++
++char *z_errmsg[] = {
++&quot;stream end&quot;, /* Z_STREAM_END 1 */
++&quot;&quot;, /* Z_OK 0 */
++&quot;file error&quot;, /* Z_ERRNO (-1) */
++&quot;stream error&quot;, /* Z_STREAM_ERROR (-2) */
++&quot;data error&quot;, /* Z_DATA_ERROR (-3) */
++&quot;insufficient memory&quot;, /* Z_MEM_ERROR (-4) */
++&quot;buffer error&quot;, /* Z_BUF_ERROR (-5) */
++&quot;&quot;};
++
++
++/*+++++*/
++/* adler32.c -- compute the Adler-32 checksum of a data stream
++ * Copyright (C) 1995 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* From: adler32.c,v 1.6 1995/05/03 17:27:08 jloup Exp */
++
++#define BASE 65521L /* largest prime smaller than 65536 */
++#define NMAX 5552
++/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) &lt;= 2^32-1 */
++
++#define DO1(buf) {s1 += *buf++; s2 += s1;}
++#define DO2(buf) DO1(buf); DO1(buf);
++#define DO4(buf) DO2(buf); DO2(buf);
++#define DO8(buf) DO4(buf); DO4(buf);
++#define DO16(buf) DO8(buf); DO8(buf);
++
++/* ========================================================================= */
++uLong adler32(adler, buf, len)
++ uLong adler;
++ Bytef *buf;
++ uInt len;
++{
++ unsigned long s1 = adler &amp; 0xffff;
++ unsigned long s2 = (adler &gt;&gt; 16) &amp; 0xffff;
++ int k;
++
++ if (buf == Z_NULL) return 1L;
++
++ while (len &gt; 0) {
++ k = len &lt; NMAX ? len : NMAX;
++ len -= k;
++ while (k &gt;= 16) {
++ DO16(buf);
++ k -= 16;
++ }
++ if (k != 0) do {
++ DO1(buf);
++ } while (--k);
++ s1 %= BASE;
++ s2 %= BASE;
++ }
++ return (s2 &lt;&lt; 16) | s1;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppdump/zlib.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppdump/zlib.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppdump/zlib.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppdump/zlib.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,631 @@
++/* $Id: zlib.h 195720 2001-06-11 11:44:34Z gc $ */
++
++/*
++ * This file is derived from zlib.h and zconf.h from the zlib-0.95
++ * distribution by Jean-loup Gailly and Mark Adler, with some additions
++ * by Paul Mackerras to aid in implementing Deflate compression and
++ * decompression for PPP packets.
++ */
++
++/* zlib.h -- interface of the 'zlib' general purpose compression library
++ version 0.95, Aug 16th, 1995.
++
++ Copyright (C) 1995 Jean-loup Gailly and Mark Adler
++
++ This software is provided 'as-is', without any express or implied
++ warranty. In no event will the authors be held liable for any damages
++ arising from the use of this software.
++
++ Permission is granted to anyone to use this software for any purpose,
++ including commercial applications, and to alter it and redistribute it
++ freely, subject to the following restrictions:
++
++ 1. The origin of this software must not be misrepresented; you must not
++ claim that you wrote the original software. If you use this software
++ in a product, an acknowledgment in the product documentation would be
++ appreciated but is not required.
++ 2. Altered source versions must be plainly marked as such, and must not be
++ misrepresented as being the original software.
++ 3. This notice may not be removed or altered from any source distribution.
++
++ Jean-loup Gailly Mark Adler
++ <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gzip at prep.ai.mit.edu</A> <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">madler at alumni.caltech.edu</A>
++ */
++
++#ifndef _ZLIB_H
++#define _ZLIB_H
++
++/* #include &quot;zconf.h&quot; */ /* included directly here */
++
++/* zconf.h -- configuration of the zlib compression library
++ * Copyright (C) 1995 Jean-loup Gailly.
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* From: zconf.h,v 1.12 1995/05/03 17:27:12 jloup Exp */
++
++/*
++ The library does not install any signal handler. It is recommended to
++ add at least a handler for SIGSEGV when decompressing; the library checks
++ the consistency of the input data whenever possible but may go nuts
++ for some forms of corrupted input.
++ */
++
++/*
++ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
++ * than 64k bytes at a time (needed on systems with 16-bit int).
++ * Compile with -DUNALIGNED_OK if it is OK to access shorts or ints
++ * at addresses which are not a multiple of their size.
++ * Under DOS, -DFAR=far or -DFAR=__far may be needed.
++ */
++
++#ifndef STDC
++# if defined(MSDOS) || defined(__STDC__) || defined(__cplusplus)
++# define STDC
++# endif
++#endif
++
++#ifdef __MWERKS__ /* Metrowerks CodeWarrior declares fileno() in unix.h */
++# include &lt;unix.h&gt;
++#endif
++
++/* Maximum value for memLevel in deflateInit2 */
++#ifndef MAX_MEM_LEVEL
++# ifdef MAXSEG_64K
++# define MAX_MEM_LEVEL 8
++# else
++# define MAX_MEM_LEVEL 9
++# endif
++#endif
++
++#ifndef FAR
++# define FAR
++#endif
++
++/* Maximum value for windowBits in deflateInit2 and inflateInit2 */
++#ifndef MAX_WBITS
++# define MAX_WBITS 15 /* 32K LZ77 window */
++#endif
++
++/* The memory requirements for deflate are (in bytes):
++ 1 &lt;&lt; (windowBits+2) + 1 &lt;&lt; (memLevel+9)
++ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
++ plus a few kilobytes for small objects. For example, if you want to reduce
++ the default memory requirements from 256K to 128K, compile with
++ make CFLAGS=&quot;-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7&quot;
++ Of course this will generally degrade compression (there's no free lunch).
++
++ The memory requirements for inflate are (in bytes) 1 &lt;&lt; windowBits
++ that is, 32K for windowBits=15 (default value) plus a few kilobytes
++ for small objects.
++*/
++
++ /* Type declarations */
++
++#ifndef OF /* function prototypes */
++# ifdef STDC
++# define OF(args) args
++# else
++# define OF(args) ()
++# endif
++#endif
++
++typedef unsigned char Byte; /* 8 bits */
++typedef unsigned int uInt; /* 16 bits or more */
++typedef unsigned long uLong; /* 32 bits or more */
++
++typedef Byte FAR Bytef;
++typedef char FAR charf;
++typedef int FAR intf;
++typedef uInt FAR uIntf;
++typedef uLong FAR uLongf;
++
++#ifdef STDC
++ typedef void FAR *voidpf;
++ typedef void *voidp;
++#else
++ typedef Byte FAR *voidpf;
++ typedef Byte *voidp;
++#endif
++
++/* end of original zconf.h */
++
++#define ZLIB_VERSION &quot;0.95P&quot;
++
++/*
++ The 'zlib' compression library provides in-memory compression and
++ decompression functions, including integrity checks of the uncompressed
++ data. This version of the library supports only one compression method
++ (deflation) but other algorithms may be added later and will have the same
++ stream interface.
++
++ For compression the application must provide the output buffer and
++ may optionally provide the input buffer for optimization. For decompression,
++ the application must provide the input buffer and may optionally provide
++ the output buffer for optimization.
++
++ Compression can be done in a single step if the buffers are large
++ enough (for example if an input file is mmap'ed), or can be done by
++ repeated calls of the compression function. In the latter case, the
++ application must provide more input and/or consume the output
++ (providing more output space) before each call.
++*/
++
++typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
++typedef void (*free_func) OF((voidpf opaque, voidpf address, uInt nbytes));
++
++struct internal_state;
++
++typedef struct z_stream_s {
++ Bytef *next_in; /* next input byte */
++ uInt avail_in; /* number of bytes available at next_in */
++ uLong total_in; /* total nb of input bytes read so far */
++
++ Bytef *next_out; /* next output byte should be put there */
++ uInt avail_out; /* remaining free space at next_out */
++ uLong total_out; /* total nb of bytes output so far */
++
++ char *msg; /* last error message, NULL if no error */
++ struct internal_state FAR *state; /* not visible by applications */
++
++ alloc_func zalloc; /* used to allocate the internal state */
++ free_func zfree; /* used to free the internal state */
++ voidp opaque; /* private data object passed to zalloc and zfree */
++
++ Byte data_type; /* best guess about the data type: ascii or binary */
++
++} z_stream;
++
++/*
++ The application must update next_in and avail_in when avail_in has
++ dropped to zero. It must update next_out and avail_out when avail_out
++ has dropped to zero. The application must initialize zalloc, zfree and
++ opaque before calling the init function. All other fields are set by the
++ compression library and must not be updated by the application.
++
++ The opaque value provided by the application will be passed as the first
++ parameter for calls of zalloc and zfree. This can be useful for custom
++ memory management. The compression library attaches no meaning to the
++ opaque value.
++
++ zalloc must return Z_NULL if there is not enough memory for the object.
++ On 16-bit systems, the functions zalloc and zfree must be able to allocate
++ exactly 65536 bytes, but will not be required to allocate more than this
++ if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
++ pointers returned by zalloc for objects of exactly 65536 bytes *must*
++ have their offset normalized to zero. The default allocation function
++ provided by this library ensures this (see zutil.c). To reduce memory
++ requirements and avoid any allocation of 64K objects, at the expense of
++ compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
++
++ The fields total_in and total_out can be used for statistics or
++ progress reports. After compression, total_in holds the total size of
++ the uncompressed data and may be saved for use in the decompressor
++ (particularly if the decompressor wants to decompress everything in
++ a single step).
++*/
++
++ /* constants */
++
++#define Z_NO_FLUSH 0
++#define Z_PARTIAL_FLUSH 1
++#define Z_FULL_FLUSH 2
++#define Z_SYNC_FLUSH 3 /* experimental: partial_flush + byte align */
++#define Z_FINISH 4
++#define Z_PACKET_FLUSH 5
++/* See deflate() below for the usage of these constants */
++
++#define Z_OK 0
++#define Z_STREAM_END 1
++#define Z_ERRNO (-1)
++#define Z_STREAM_ERROR (-2)
++#define Z_DATA_ERROR (-3)
++#define Z_MEM_ERROR (-4)
++#define Z_BUF_ERROR (-5)
++/* error codes for the compression/decompression functions */
++
++#define Z_BEST_SPEED 1
++#define Z_BEST_COMPRESSION 9
++#define Z_DEFAULT_COMPRESSION (-1)
++/* compression levels */
++
++#define Z_FILTERED 1
++#define Z_HUFFMAN_ONLY 2
++#define Z_DEFAULT_STRATEGY 0
++
++#define Z_BINARY 0
++#define Z_ASCII 1
++#define Z_UNKNOWN 2
++/* Used to set the data_type field */
++
++#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
++
++extern char *zlib_version;
++/* The application can compare zlib_version and ZLIB_VERSION for consistency.
++ If the first character differs, the library code actually used is
++ not compatible with the zlib.h header file used by the application.
++ */
++
++ /* basic functions */
++
++extern int deflateInit OF((z_stream *strm, int level));
++/*
++ Initializes the internal stream state for compression. The fields
++ zalloc, zfree and opaque must be initialized before by the caller.
++ If zalloc and zfree are set to Z_NULL, deflateInit updates them to
++ use default allocation functions.
++
++ The compression level must be Z_DEFAULT_COMPRESSION, or between 1 and 9:
++ 1 gives best speed, 9 gives best compression. Z_DEFAULT_COMPRESSION requests
++ a default compromise between speed and compression (currently equivalent
++ to level 6).
++
++ deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
++ enough memory, Z_STREAM_ERROR if level is not a valid compression level.
++ msg is set to null if there is no error message. deflateInit does not
++ perform any compression: this will be done by deflate().
++*/
++
++
++extern int deflate OF((z_stream *strm, int flush));
++/*
++ Performs one or both of the following actions:
++
++ - Compress more input starting at next_in and update next_in and avail_in
++ accordingly. If not all input can be processed (because there is not
++ enough room in the output buffer), next_in and avail_in are updated and
++ processing will resume at this point for the next call of deflate().
++
++ - Provide more output starting at next_out and update next_out and avail_out
++ accordingly. This action is forced if the parameter flush is non zero.
++ Forcing flush frequently degrades the compression ratio, so this parameter
++ should be set only when necessary (in interactive applications).
++ Some output may be provided even if flush is not set.
++
++ Before the call of deflate(), the application should ensure that at least
++ one of the actions is possible, by providing more input and/or consuming
++ more output, and updating avail_in or avail_out accordingly; avail_out
++ should never be zero before the call. The application can consume the
++ compressed output when it wants, for example when the output buffer is full
++ (avail_out == 0), or after each call of deflate().
++
++ If the parameter flush is set to Z_PARTIAL_FLUSH, the current compression
++ block is terminated and flushed to the output buffer so that the
++ decompressor can get all input data available so far. For method 9, a future
++ variant on method 8, the current block will be flushed but not terminated.
++ If flush is set to Z_FULL_FLUSH, the compression block is terminated, a
++ special marker is output and the compression dictionary is discarded; this
++ is useful to allow the decompressor to synchronize if one compressed block
++ has been damaged (see inflateSync below). Flushing degrades compression and
++ so should be used only when necessary. Using Z_FULL_FLUSH too often can
++ seriously degrade the compression. If deflate returns with avail_out == 0,
++ this function must be called again with the same value of the flush
++ parameter and more output space (updated avail_out), until the flush is
++ complete (deflate returns with non-zero avail_out).
++
++ If the parameter flush is set to Z_PACKET_FLUSH, the compression
++ block is terminated, and a zero-length stored block is output,
++ omitting the length bytes (the effect of this is that the 3-bit type
++ code 000 for a stored block is output, and the output is then
++ byte-aligned). This is designed for use at the end of a PPP packet.
++ In addition, if the current compression block contains all the data
++ since the last Z_PACKET_FLUSH, it is never output as a stored block.
++ If the current compression block output as a static or dynamic block
++ would not be at least `minCompression' bytes smaller than the
++ original data, then nothing is output for that block. (The type
++ code for the zero-length stored block is still output, resulting in
++ a single zero byte being output for the whole packet.)
++ `MinCompression' is a parameter to deflateInit2, or 0 if deflateInit
++ is used.
++
++ If the parameter flush is set to Z_FINISH, all pending input is processed,
++ all pending output is flushed and deflate returns with Z_STREAM_END if there
++ was enough output space; if deflate returns with Z_OK, this function must be
++ called again with Z_FINISH and more output space (updated avail_out) but no
++ more input data, until it returns with Z_STREAM_END or an error. After
++ deflate has returned Z_STREAM_END, the only possible operations on the
++ stream are deflateReset or deflateEnd.
++
++ Z_FINISH can be used immediately after deflateInit if all the compression
++ is to be done in a single step. In this case, avail_out must be at least
++ 0.1% larger than avail_in plus 12 bytes. If deflate does not return
++ Z_STREAM_END, then it must be called again as described above.
++
++ deflate() may update data_type if it can make a good guess about
++ the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
++ binary. This field is only for information purposes and does not affect
++ the compression algorithm in any manner.
++
++ deflate() returns Z_OK if some progress has been made (more input
++ processed or more output produced), Z_STREAM_END if all input has been
++ consumed and all output has been produced (only when flush is set to
++ Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
++ if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible.
++*/
++
++
++extern int deflateEnd OF((z_stream *strm));
++/*
++ All dynamically allocated data structures for this stream are freed.
++ This function discards any unprocessed input and does not flush any
++ pending output.
++
++ deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
++ stream state was inconsistent. In the error case, msg may be set
++ but then points to a static string (which must not be deallocated).
++*/
++
++
++extern int inflateInit OF((z_stream *strm));
++/*
++ Initializes the internal stream state for decompression. The fields
++ zalloc and zfree must be initialized before by the caller. If zalloc and
++ zfree are set to Z_NULL, inflateInit updates them to use default allocation
++ functions.
++
++ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
++ enough memory. msg is set to null if there is no error message.
++ inflateInit does not perform any decompression: this will be done by
++ inflate().
++*/
++
++
++extern int inflate OF((z_stream *strm, int flush));
++/*
++ Performs one or both of the following actions:
++
++ - Decompress more input starting at next_in and update next_in and avail_in
++ accordingly. If not all input can be processed (because there is not
++ enough room in the output buffer), next_in is updated and processing
++ will resume at this point for the next call of inflate().
++
++ - Provide more output starting at next_out and update next_out and avail_out
++ accordingly. inflate() always provides as much output as possible
++ (until there is no more input data or no more space in the output buffer).
++
++ Before the call of inflate(), the application should ensure that at least
++ one of the actions is possible, by providing more input and/or consuming
++ more output, and updating the next_* and avail_* values accordingly.
++ The application can consume the uncompressed output when it wants, for
++ example when the output buffer is full (avail_out == 0), or after each
++ call of inflate().
++
++ If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH,
++ inflate flushes as much output as possible to the output buffer. The
++ flushing behavior of inflate is not specified for values of the flush
++ parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the
++ current implementation actually flushes as much output as possible
++ anyway. For Z_PACKET_FLUSH, inflate checks that once all the input data
++ has been consumed, it is expecting to see the length field of a stored
++ block; if not, it returns Z_DATA_ERROR.
++
++ inflate() should normally be called until it returns Z_STREAM_END or an
++ error. However if all decompression is to be performed in a single step
++ (a single call of inflate), the parameter flush should be set to
++ Z_FINISH. In this case all pending input is processed and all pending
++ output is flushed; avail_out must be large enough to hold all the
++ uncompressed data. (The size of the uncompressed data may have been saved
++ by the compressor for this purpose.) The next operation on this stream must
++ be inflateEnd to deallocate the decompression state. The use of Z_FINISH
++ is never required, but can be used to inform inflate that a faster routine
++ may be used for the single inflate() call.
++
++ inflate() returns Z_OK if some progress has been made (more input
++ processed or more output produced), Z_STREAM_END if the end of the
++ compressed data has been reached and all uncompressed output has been
++ produced, Z_DATA_ERROR if the input data was corrupted, Z_STREAM_ERROR if
++ the stream structure was inconsistent (for example if next_in or next_out
++ was NULL), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no
++ progress is possible or if there was not enough room in the output buffer
++ when Z_FINISH is used. In the Z_DATA_ERROR case, the application may then
++ call inflateSync to look for a good compression block. */
++
++
++extern int inflateEnd OF((z_stream *strm));
++/*
++ All dynamically allocated data structures for this stream are freed.
++ This function discards any unprocessed input and does not flush any
++ pending output.
++
++ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
++ was inconsistent. In the error case, msg may be set but then points to a
++ static string (which must not be deallocated).
++*/
++
++ /* advanced functions */
++
++/*
++ The following functions are needed only in some special applications.
++*/
++
++extern int deflateInit2 OF((z_stream *strm,
++ int level,
++ int method,
++ int windowBits,
++ int memLevel,
++ int strategy,
++ int minCompression));
++/*
++ This is another version of deflateInit with more compression options. The
++ fields next_in, zalloc and zfree must be initialized before by the caller.
++
++ The method parameter is the compression method. It must be 8 in this
++ version of the library. (Method 9 will allow a 64K history buffer and
++ partial block flushes.)
++
++ The windowBits parameter is the base two logarithm of the window size
++ (the size of the history buffer). It should be in the range 8..15 for this
++ version of the library (the value 16 will be allowed for method 9). Larger
++ values of this parameter result in better compression at the expense of
++ memory usage. The default value is 15 if deflateInit is used instead.
++
++ The memLevel parameter specifies how much memory should be allocated
++ for the internal compression state. memLevel=1 uses minimum memory but
++ is slow and reduces compression ratio; memLevel=9 uses maximum memory
++ for optimal speed. The default value is 8. See zconf.h for total memory
++ usage as a function of windowBits and memLevel.
++
++ The strategy parameter is used to tune the compression algorithm. Use
++ the value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data
++ produced by a filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman
++ encoding only (no string match). Filtered data consists mostly of small
++ values with a somewhat random distribution. In this case, the
++ compression algorithm is tuned to compress them better. The strategy
++ parameter only affects the compression ratio but not the correctness of
++ the compressed output even if it is not set appropriately.
++
++ The minCompression parameter specifies the minimum reduction in size
++ required for a compressed block to be output when Z_PACKET_FLUSH is
++ used (see the description of deflate above).
++
++ If next_in is not null, the library will use this buffer to hold also
++ some history information; the buffer must either hold the entire input
++ data, or have at least 1&lt;&lt;(windowBits+1) bytes and be writable. If next_in
++ is null, the library will allocate its own history buffer (and leave next_in
++ null). next_out need not be provided here but must be provided by the
++ application for the next call of deflate().
++
++ If the history buffer is provided by the application, next_in must
++ must never be changed by the application since the compressor maintains
++ information inside this buffer from call to call; the application
++ must provide more input only by increasing avail_in. next_in is always
++ reset by the library in this case.
++
++ deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
++ not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
++ an invalid method). msg is set to null if there is no error message.
++ deflateInit2 does not perform any compression: this will be done by
++ deflate().
++*/
++
++extern int deflateCopy OF((z_stream *dest,
++ z_stream *source));
++/*
++ Sets the destination stream as a complete copy of the source stream. If
++ the source stream is using an application-supplied history buffer, a new
++ buffer is allocated for the destination stream. The compressed output
++ buffer is always application-supplied. It's the responsibility of the
++ application to provide the correct values of next_out and avail_out for the
++ next call of deflate.
++
++ This function is useful when several compression strategies will be
++ tried, for example when there are several ways of pre-processing the input
++ data with a filter. The streams that will be discarded should then be freed
++ by calling deflateEnd. Note that deflateCopy duplicates the internal
++ compression state which can be quite large, so this strategy is slow and
++ can consume lots of memory.
++
++ deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
++ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
++ (such as zalloc being NULL). msg is left unchanged in both source and
++ destination.
++*/
++
++extern int deflateReset OF((z_stream *strm));
++/*
++ This function is equivalent to deflateEnd followed by deflateInit,
++ but does not free and reallocate all the internal compression state.
++ The stream will keep the same compression level and any other attributes
++ that may have been set by deflateInit2.
++
++ deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
++ stream state was inconsistent (such as zalloc or state being NULL).
++*/
++
++extern int inflateInit2 OF((z_stream *strm,
++ int windowBits));
++/*
++ This is another version of inflateInit with more compression options. The
++ fields next_out, zalloc and zfree must be initialized before by the caller.
++
++ The windowBits parameter is the base two logarithm of the maximum window
++ size (the size of the history buffer). It should be in the range 8..15 for
++ this version of the library (the value 16 will be allowed soon). The
++ default value is 15 if inflateInit is used instead. If a compressed stream
++ with a larger window size is given as input, inflate() will return with
++ the error code Z_DATA_ERROR instead of trying to allocate a larger window.
++
++ If next_out is not null, the library will use this buffer for the history
++ buffer; the buffer must either be large enough to hold the entire output
++ data, or have at least 1&lt;&lt;windowBits bytes. If next_out is null, the
++ library will allocate its own buffer (and leave next_out null). next_in
++ need not be provided here but must be provided by the application for the
++ next call of inflate().
++
++ If the history buffer is provided by the application, next_out must
++ never be changed by the application since the decompressor maintains
++ history information inside this buffer from call to call; the application
++ can only reset next_out to the beginning of the history buffer when
++ avail_out is zero and all output has been consumed.
++
++ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
++ not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
++ windowBits &lt; 8). msg is set to null if there is no error message.
++ inflateInit2 does not perform any decompression: this will be done by
++ inflate().
++*/
++
++extern int inflateSync OF((z_stream *strm));
++/*
++ Skips invalid compressed data until the special marker (see deflate()
++ above) can be found, or until all available input is skipped. No output
++ is provided.
++
++ inflateSync returns Z_OK if the special marker has been found, Z_BUF_ERROR
++ if no more input was provided, Z_DATA_ERROR if no marker has been found,
++ or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
++ case, the application may save the current current value of total_in which
++ indicates where valid compressed data was found. In the error case, the
++ application may repeatedly call inflateSync, providing more input each time,
++ until success or end of the input data.
++*/
++
++extern int inflateReset OF((z_stream *strm));
++/*
++ This function is equivalent to inflateEnd followed by inflateInit,
++ but does not free and reallocate all the internal decompression state.
++ The stream will keep attributes that may have been set by inflateInit2.
++
++ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
++ stream state was inconsistent (such as zalloc or state being NULL).
++*/
++
++extern int inflateIncomp OF((z_stream *strm));
++/*
++ This function adds the data at next_in (avail_in bytes) to the output
++ history without performing any output. There must be no pending output,
++ and the decompressor must be expecting to see the start of a block.
++ Calling this function is equivalent to decompressing a stored block
++ containing the data at next_in (except that the data is not output).
++*/
++
++ /* checksum functions */
++
++/*
++ This function is not related to compression but is exported
++ anyway because it might be useful in applications using the
++ compression library.
++*/
++
++extern uLong adler32 OF((uLong adler, Bytef *buf, uInt len));
++
++/*
++ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
++ return the updated checksum. If buf is NULL, this function returns
++ the required initial value for the checksum.
++ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
++ much faster. Usage example:
++
++ uLong adler = adler32(0L, Z_NULL, 0);
++
++ while (read_buffer(buffer, length) != EOF) {
++ adler = adler32(adler, buffer, length);
++ }
++ if (adler != original_adler) error();
++*/
++
++#ifndef _Z_UTIL_H
++ struct internal_state {int dummy;}; /* hack for buggy compilers */
++#endif
++
++#endif /* _ZLIB_H */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppdump/zlib.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/pppstats/Makefile.linux
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppstats/Makefile.linux (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppstats/Makefile.linux 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,32 @@
++#
++# pppstats makefile
++# $Id: Makefile.linux 195720 2001-06-11 11:44:34Z gc $
++#
++
++PPPSTATSRCS = pppstats.c
++PPPSTATOBJS = pppstats.o
++
++#CC = gcc
++COPTS = -O
++COMPILE_FLAGS = -D_linux_ -I../include
++LIBS =
++
++INSTALL= install -o root -g daemon
++
++CFLAGS = $(COPTS) $(COMPILE_FLAGS)
++
++all: pppstats
++
++install: pppstats
++ $(INSTALL) -s -c pppstats $(BINDIR)/pppstats
++ $(INSTALL) -c -m 444 pppstats.8 $(MANDIR)/man8/pppstats.8
++
++pppstats: $(PPPSTATSRCS)
++ $(CC) $(CFLAGS) -o pppstats pppstats.c $(LIBS)
++
++clean:
++ rm -f pppstats *~ #* core
++
++depend:
++ cpp -M $(CFLAGS) $(PPPSTATSRCS) &gt;.depend
++# makedepend $(CFLAGS) $(PPPSTATSRCS)
+
+Added: drakx/trunk/mdk-stage1/ppp/pppstats/Makefile.sol2
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppstats/Makefile.sol2 (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppstats/Makefile.sol2 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,20 @@
++#
++# pppstats Makefile for SVR4 systems
++# $Id: Makefile.sol2 195720 2001-06-11 11:44:34Z gc $
++#
++
++include ../solaris/Makedefs
++
++CFLAGS = -DSTREAMS -I../include $(COPTS)
++
++all: pppstats
++
++pppstats: pppstats.c
++ $(CC) $(CFLAGS) -o pppstats pppstats.c
++
++install: pppstats
++ $(INSTALL) -f $(BINDIR) pppstats
++ $(INSTALL) -m 444 -f $(MANDIR)/man8 pppstats.8
++
++clean:
++ rm -f pppstats *~ core
+
+Added: drakx/trunk/mdk-stage1/ppp/pppstats/Makefile.sunos4
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppstats/Makefile.sunos4 (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppstats/Makefile.sunos4 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,30 @@
++#
++# pppstats makefile
++# $Id: Makefile.sunos4 195720 2001-06-11 11:44:34Z gc $
++#
++
++include ../sunos4/Makedefs
++
++PPPSTATSRCS = pppstats.c
++PPPSTATOBJS = pppstats.o
++
++COMPILE_FLAGS = -DSTREAMS -DSUNOS4
++LIBS =
++
++CFLAGS = -I../include $(COPTS) $(COMPILE_FLAGS)
++
++all: pppstats
++
++install: pppstats
++ $(INSTALL) -c pppstats $(BINDIR)/pppstats
++ $(INSTALL) -c -m 444 pppstats.8 $(MANDIR)/man8/pppstats.8
++
++pppstats: $(PPPSTATSRCS)
++ $(CC) $(CFLAGS) -o pppstats pppstats.c $(LIBS)
++
++clean:
++ rm -f pppstats *~ #* core
++
++depend:
++ cpp -M $(CFLAGS) $(PPPSTATSRCS) &gt;.depend
++# makedepend $(CFLAGS) $(PPPSTATSRCS)
+
+Added: drakx/trunk/mdk-stage1/ppp/pppstats/pppstats.8
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppstats/pppstats.8 (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppstats/pppstats.8 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,217 @@
++.\&quot; @(#) $Id: pppstats.8 195720 2001-06-11 11:44:34Z gc $
++.TH PPPSTATS 8 &quot;26 June 1995&quot;
++.SH NAME
++pppstats \- print PPP statistics
++.SH SYNOPSIS
++.B pppstats
++[
++.B -a
++] [
++.B -v
++] [
++.B -r
++] [
++.B -z
++] [
++.B -c
++.I &lt;count&gt;
++] [
++.B -w
++.I &lt;secs&gt;
++] [
++.I interface
++]
++.ti 12
++.SH DESCRIPTION
++The
++.B pppstats
++utility reports PPP-related statistics at regular intervals for the
++specified PPP interface. If the interface is unspecified, it will
++default to ppp0.
++The display is split horizontally
++into input and output sections containing columns of statistics
++describing the properties and volume of packets received and
++transmitted by the interface.
++.PP
++The options are as follows:
++.TP
++.B -a
++Display absolute values rather than deltas. With this option, all
++reports show statistics for the time since the link was initiated.
++Without this option, the second and subsequent reports show statistics
++for the time since the last report.
++.TP
++.B -c \fIcount
++Repeat the display
++.I count
++times. If this option is not specified, the default repeat count is 1
++if the
++.B -w
++option is not specified, otherwise infinity.
++.TP
++.B -r
++Display additional statistics summarizing the compression ratio
++achieved by the packet compression algorithm in use.
++.TP
++.B -v
++Display additional statistics relating to the performance of the Van
++Jacobson TCP header compression algorithm.
++.TP
++.B -w \fIwait
++Pause
++.I wait
++seconds between each display. If this option is not specified, the
++default interval is 5 seconds.
++.TP
++.B -z
++Instead of the standard display, show statistics indicating the
++performance of the packet compression algorithm in use.
++.PP
++The following fields are printed on the input side when the
++.B -z
++option is not used:
++.TP
++.B IN
++The total number of bytes received by this interface.
++.TP
++.B PACK
++The total number of packets received by this interface.
++.TP
++.B VJCOMP
++The number of header-compressed TCP packets received by this interface.
++.TP
++.B VJUNC
++The number of header-uncompressed TCP packets received by this
++interface. Not reported when the
++.B -r
++option is specified.
++.TP
++.B VJERR
++The number of corrupted or bogus header-compressed TCP packets
++received by this interface. Not reported when the
++.B -r
++option is specified.
++.TP
++.B VJTOSS
++The number of VJ header-compressed TCP packets dropped on reception by
++this interface because of preceding errors. Only reported when the
++.B -v
++option is specified.
++.TP
++.B NON-VJ
++The total number of non-TCP packets received by this interface. Only
++reported when the
++.B -v
++option is specified.
++.TP
++.B RATIO
++The compression ratio achieved for received packets by the
++packet compression scheme in use, defined as the uncompressed size
++divided by the compressed size.
++Only reported when the
++.B -r
++option is specified.
++.TP
++.B UBYTE
++The total number of bytes received, after decompression of compressed
++packets. Only reported when the
++.B -r
++option is specified.
++.PP
++The following fields are printed on the output side:
++.TP
++.B OUT
++The total number of bytes transmitted from this interface.
++.TP
++.B PACK
++The total number of packets transmitted from this interface.
++.TP
++.B VJCOMP
++The number of TCP packets transmitted from this interface with
++VJ-compressed TCP headers.
++.TP
++.B VJUNC
++The number of TCP packets transmitted from this interface with
++VJ-uncompressed TCP headers.
++Not reported when the
++.B -r
++option is specified.
++.TP
++.B NON-VJ
++The total number of non-TCP packets transmitted from this interface.
++Not reported when the
++.B -r
++option is specified.
++.TP
++.B VJSRCH
++The number of searches for the cached header entry for a VJ header
++compressed TCP packet. Only reported when the
++.B -v
++option is specified.
++.TP
++.B VJMISS
++The number of failed searches for the cached header entry for a
++VJ header compressed TCP packet. Only reported when the
++.B -v
++option is specified.
++.TP
++.B RATIO
++The compression ratio achieved for transmitted packets by the
++packet compression scheme in use, defined as the size
++before compression divided by the compressed size.
++Only reported when the
++.B -r
++option is specified.
++.TP
++.B UBYTE
++The total number of bytes to be transmitted, before packet compression
++is applied. Only reported when the
++.B -r
++option is specified.
++.PP
++When the
++.B -z
++option is specified,
++.Nm pppstats
++instead displays the following fields, relating to the packet
++compression algorithm currently in use. If packet compression is not
++in use, these fields will all display zeroes. The fields displayed on
++the input side are:
++.TP
++.B COMPRESSED BYTE
++The number of bytes of compressed packets received.
++.TP
++.B COMPRESSED PACK
++The number of compressed packets received.
++.TP
++.B INCOMPRESSIBLE BYTE
++The number of bytes of incompressible packets (that is, those which
++were transmitted in uncompressed form) received.
++.TP
++.B INCOMPRESSIBLE PACK
++The number of incompressible packets received.
++.TP
++.B COMP RATIO
++The recent compression ratio for incoming packets, defined as the
++uncompressed size divided by the compressed size (including both
++compressible and incompressible packets).
++.PP
++The fields displayed on the output side are:
++.TP
++.B COMPRESSED BYTE
++The number of bytes of compressed packets transmitted.
++.TP
++.B COMPRESSED PACK
++The number of compressed packets transmitted.
++.TP
++.B INCOMPRESSIBLE BYTE
++The number of bytes of incompressible packets transmitted (that is,
++those which were transmitted in uncompressed form).
++.TP
++.B INCOMPRESSIBLE PACK
++The number of incompressible packets transmitted.
++.TP
++.B COMP RATIO
++The recent compression ratio for outgoing packets.
++.SH SEE ALSO
++pppd(8)
+
+Added: drakx/trunk/mdk-stage1/ppp/pppstats/pppstats.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/pppstats/pppstats.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/pppstats/pppstats.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,557 @@
++/*
++ * print PPP statistics:
++ * pppstats [-a|-d] [-v|-r|-z] [-c count] [-w wait] [interface]
++ *
++ * -a Show absolute values rather than deltas
++ * -d Show data rate (kB/s) rather than bytes
++ * -v Show more stats for VJ TCP header compression
++ * -r Show compression ratio
++ * -z Show compression statistics instead of default display
++ *
++ * History:
++ * <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">perkins at cps.msu.edu</A>: Added compression statistics and alternate
++ * display. 11/94
++ * Brad Parker (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">brad at cayman.com</A>) 6/92
++ *
++ * from the original &quot;slstats&quot; by Van Jacobson
++ *
++ * Copyright (c) 1989 Regents of the University of California.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright notice and this paragraph are
++ * duplicated in all such forms and that any documentation,
++ * advertising materials, and other materials related to such
++ * distribution and use acknowledge that the software was developed
++ * by the University of California, Berkeley. The name of the
++ * University may not be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ */
++
++#ifndef __STDC__
++#define const
++#endif
++
++#ifndef lint
++static const char rcsid[] = &quot;$Id: pppstats.c 195720 2001-06-11 11:44:34Z gc $&quot;;
++#endif
++
++#include &lt;stdio.h&gt;
++#include &lt;stddef.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++#include &lt;ctype.h&gt;
++#include &lt;errno.h&gt;
++#include &lt;signal.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;sys/param.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/ioctl.h&gt;
++
++#ifndef STREAMS
++#if defined(_linux_) &amp;&amp; defined(__powerpc__) \
++ &amp;&amp; (__GLIBC__ == 2 &amp;&amp; __GLIBC_MINOR__ == 0)
++/* kludge alert! */
++#undef __GLIBC__
++#endif
++#include &lt;sys/socket.h&gt; /* *BSD, Linux, NeXT, Ultrix etc. */
++#ifndef _linux_
++#include &lt;net/if.h&gt;
++#include &lt;net/ppp_defs.h&gt;
++#include &lt;net/if_ppp.h&gt;
++#else
++/* Linux */
++#if __GLIBC__ &gt;= 2
++#include &lt;asm/types.h&gt; /* glibc 2 conflicts with linux/types.h */
++#include &lt;net/if.h&gt;
++#else
++#include &lt;linux/types.h&gt;
++#include &lt;linux/if.h&gt;
++#endif
++#include &lt;linux/ppp_defs.h&gt;
++#include &lt;linux/if_ppp.h&gt;
++#endif /* _linux_ */
++
++#else /* STREAMS */
++#include &lt;sys/stropts.h&gt; /* SVR4, Solaris 2, SunOS 4, OSF/1, etc. */
++#include &lt;net/ppp_defs.h&gt;
++#include &lt;net/pppio.h&gt;
++
++#endif /* STREAMS */
++
++int vflag, rflag, zflag; /* select type of display */
++int aflag; /* print absolute values, not deltas */
++int dflag; /* print data rates, not bytes */
++int interval, count;
++int infinite;
++int unit;
++int s; /* socket or /dev/ppp file descriptor */
++int signalled; /* set if alarm goes off &quot;early&quot; */
++char *progname;
++char *interface;
++
++#if defined(SUNOS4) || defined(ULTRIX) || defined(NeXT)
++extern int optind;
++extern char *optarg;
++#endif
++
++/*
++ * If PPP_DRV_NAME is not defined, use the legacy &quot;ppp&quot; as the
++ * device name.
++ */
++#if !defined(PPP_DRV_NAME)
++#define PPP_DRV_NAME &quot;ppp&quot;
++#endif /* !defined(PPP_DRV_NAME) */
++
++static void usage __P((void));
++static void catchalarm __P((int));
++static void get_ppp_stats __P((struct ppp_stats *));
++static void get_ppp_cstats __P((struct ppp_comp_stats *));
++static void intpr __P((void));
++
++int main __P((int, char *argv[]));
++
++static void
++usage()
++{
++ fprintf(stderr, &quot;Usage: %s [-a|-d] [-v|-r|-z] [-c count] [-w wait] [interface]\n&quot;,
++ progname);
++ exit(1);
++}
++
++/*
++ * Called if an interval expires before intpr has completed a loop.
++ * Sets a flag to not wait for the alarm.
++ */
++static void
++catchalarm(arg)
++ int arg;
++{
++ signalled = 1;
++}
++
++
++#ifndef STREAMS
++static void
++get_ppp_stats(curp)
++ struct ppp_stats *curp;
++{
++ struct ifpppstatsreq req;
++
++ memset (&amp;req, 0, sizeof (req));
++
++#ifdef _linux_
++ req.stats_ptr = (caddr_t) &amp;req.stats;
++#undef ifr_name
++#define ifr_name ifr__name
++#endif
++
++ strncpy(req.ifr_name, interface, sizeof(req.ifr_name));
++ if (ioctl(s, SIOCGPPPSTATS, &amp;req) &lt; 0) {
++ fprintf(stderr, &quot;%s: &quot;, progname);
++ if (errno == ENOTTY)
++ fprintf(stderr, &quot;kernel support missing\n&quot;);
++ else
++ perror(&quot;couldn't get PPP statistics&quot;);
++ exit(1);
++ }
++ *curp = req.stats;
++}
++
++static void
++get_ppp_cstats(csp)
++ struct ppp_comp_stats *csp;
++{
++ struct ifpppcstatsreq creq;
++
++ memset (&amp;creq, 0, sizeof (creq));
++
++#ifdef _linux_
++ creq.stats_ptr = (caddr_t) &amp;creq.stats;
++#undef ifr_name
++#define ifr_name ifr__name
++#endif
++
++ strncpy(creq.ifr_name, interface, sizeof(creq.ifr_name));
++ if (ioctl(s, SIOCGPPPCSTATS, &amp;creq) &lt; 0) {
++ fprintf(stderr, &quot;%s: &quot;, progname);
++ if (errno == ENOTTY) {
++ fprintf(stderr, &quot;no kernel compression support\n&quot;);
++ if (zflag)
++ exit(1);
++ rflag = 0;
++ } else {
++ perror(&quot;couldn't get PPP compression stats&quot;);
++ exit(1);
++ }
++ }
++
++#ifdef _linux_
++ if (creq.stats.c.bytes_out == 0) {
++ creq.stats.c.bytes_out = creq.stats.c.comp_bytes + creq.stats.c.inc_bytes;
++ creq.stats.c.in_count = creq.stats.c.unc_bytes;
++ }
++ if (creq.stats.c.bytes_out == 0)
++ creq.stats.c.ratio = 0.0;
++ else
++ creq.stats.c.ratio = 256.0 * creq.stats.c.in_count /
++ creq.stats.c.bytes_out;
++
++ if (creq.stats.d.bytes_out == 0) {
++ creq.stats.d.bytes_out = creq.stats.d.comp_bytes + creq.stats.d.inc_bytes;
++ creq.stats.d.in_count = creq.stats.d.unc_bytes;
++ }
++ if (creq.stats.d.bytes_out == 0)
++ creq.stats.d.ratio = 0.0;
++ else
++ creq.stats.d.ratio = 256.0 * creq.stats.d.in_count /
++ creq.stats.d.bytes_out;
++#endif
++
++ *csp = creq.stats;
++}
++
++#else /* STREAMS */
++
++int
++strioctl(fd, cmd, ptr, ilen, olen)
++ int fd, cmd, ilen, olen;
++ char *ptr;
++{
++ struct strioctl str;
++
++ str.ic_cmd = cmd;
++ str.ic_timout = 0;
++ str.ic_len = ilen;
++ str.ic_dp = ptr;
++ if (ioctl(fd, I_STR, &amp;str) == -1)
++ return -1;
++ if (str.ic_len != olen)
++ fprintf(stderr, &quot;strioctl: expected %d bytes, got %d for cmd %x\n&quot;,
++ olen, str.ic_len, cmd);
++ return 0;
++}
++
++static void
++get_ppp_stats(curp)
++ struct ppp_stats *curp;
++{
++ if (strioctl(s, PPPIO_GETSTAT, curp, 0, sizeof(*curp)) &lt; 0) {
++ fprintf(stderr, &quot;%s: &quot;, progname);
++ if (errno == EINVAL)
++ fprintf(stderr, &quot;kernel support missing\n&quot;);
++ else
++ perror(&quot;couldn't get PPP statistics&quot;);
++ exit(1);
++ }
++}
++
++static void
++get_ppp_cstats(csp)
++ struct ppp_comp_stats *csp;
++{
++ if (strioctl(s, PPPIO_GETCSTAT, csp, 0, sizeof(*csp)) &lt; 0) {
++ fprintf(stderr, &quot;%s: &quot;, progname);
++ if (errno == ENOTTY) {
++ fprintf(stderr, &quot;no kernel compression support\n&quot;);
++ if (zflag)
++ exit(1);
++ rflag = 0;
++ } else {
++ perror(&quot;couldn't get PPP compression statistics&quot;);
++ exit(1);
++ }
++ }
++}
++
++#endif /* STREAMS */
++
++#define MAX0(a) ((int)(a) &gt; 0? (a): 0)
++#define V(offset) MAX0(cur.offset - old.offset)
++#define W(offset) MAX0(ccs.offset - ocs.offset)
++
++#define RATIO(c, i, u) ((c) == 0? 1.0: (u) / ((double)(c) + (i)))
++#define CRATE(x) RATIO(W(x.comp_bytes), W(x.inc_bytes), W(x.unc_bytes))
++
++#define KBPS(n) ((n) / (interval * 1000.0))
++
++/*
++ * Print a running summary of interface statistics.
++ * Repeat display every interval seconds, showing statistics
++ * collected over that interval. Assumes that interval is non-zero.
++ * First line printed is cumulative.
++ */
++static void
++intpr()
++{
++ register int line = 0;
++ sigset_t oldmask, mask;
++ char *bunit;
++ int ratef = 0;
++ struct ppp_stats cur, old;
++ struct ppp_comp_stats ccs, ocs;
++
++ memset(&amp;old, 0, sizeof(old));
++ memset(&amp;ocs, 0, sizeof(ocs));
++
++ while (1) {
++ get_ppp_stats(&amp;cur);
++ if (zflag || rflag)
++ get_ppp_cstats(&amp;ccs);
++
++ (void)signal(SIGALRM, catchalarm);
++ signalled = 0;
++ (void)alarm(interval);
++
++ if ((line % 20) == 0) {
++ if (zflag) {
++ printf(&quot;IN: COMPRESSED INCOMPRESSIBLE COMP | &quot;);
++ printf(&quot;OUT: COMPRESSED INCOMPRESSIBLE COMP\n&quot;);
++ bunit = dflag? &quot;KB/S&quot;: &quot;BYTE&quot;;
++ printf(&quot; %s PACK %s PACK RATIO | &quot;, bunit, bunit);
++ printf(&quot; %s PACK %s PACK RATIO&quot;, bunit, bunit);
++ } else {
++ printf(&quot;%8.8s %6.6s %6.6s&quot;,
++ &quot;IN&quot;, &quot;PACK&quot;, &quot;VJCOMP&quot;);
++
++ if (!rflag)
++ printf(&quot; %6.6s %6.6s&quot;, &quot;VJUNC&quot;, &quot;VJERR&quot;);
++ if (vflag)
++ printf(&quot; %6.6s %6.6s&quot;, &quot;VJTOSS&quot;, &quot;NON-VJ&quot;);
++ if (rflag)
++ printf(&quot; %6.6s %6.6s&quot;, &quot;RATIO&quot;, &quot;UBYTE&quot;);
++ printf(&quot; | %8.8s %6.6s %6.6s&quot;,
++ &quot;OUT&quot;, &quot;PACK&quot;, &quot;VJCOMP&quot;);
++
++ if (!rflag)
++ printf(&quot; %6.6s %6.6s&quot;, &quot;VJUNC&quot;, &quot;NON-VJ&quot;);
++ if (vflag)
++ printf(&quot; %6.6s %6.6s&quot;, &quot;VJSRCH&quot;, &quot;VJMISS&quot;);
++ if (rflag)
++ printf(&quot; %6.6s %6.6s&quot;, &quot;RATIO&quot;, &quot;UBYTE&quot;);
++ }
++ putchar('\n');
++ }
++
++ if (zflag) {
++ if (ratef) {
++ printf(&quot;%8.3f %6u %8.3f %6u %6.2f&quot;,
++ KBPS(W(d.comp_bytes)),
++ W(d.comp_packets),
++ KBPS(W(d.inc_bytes)),
++ W(d.inc_packets),
++ ccs.d.ratio / 256.0);
++ printf(&quot; | %8.3f %6u %8.3f %6u %6.2f&quot;,
++ KBPS(W(c.comp_bytes)),
++ W(c.comp_packets),
++ KBPS(W(c.inc_bytes)),
++ W(c.inc_packets),
++ ccs.c.ratio / 256.0);
++ } else {
++ printf(&quot;%8u %6u %8u %6u %6.2f&quot;,
++ W(d.comp_bytes),
++ W(d.comp_packets),
++ W(d.inc_bytes),
++ W(d.inc_packets),
++ ccs.d.ratio / 256.0);
++ printf(&quot; | %8u %6u %8u %6u %6.2f&quot;,
++ W(c.comp_bytes),
++ W(c.comp_packets),
++ W(c.inc_bytes),
++ W(c.inc_packets),
++ ccs.c.ratio / 256.0);
++ }
++
++ } else {
++ if (ratef)
++ printf(&quot;%8.3f&quot;, KBPS(V(p.ppp_ibytes)));
++ else
++ printf(&quot;%8u&quot;, V(p.ppp_ibytes));
++ printf(&quot; %6u %6u&quot;,
++ V(p.ppp_ipackets),
++ V(vj.vjs_compressedin));
++ if (!rflag)
++ printf(&quot; %6u %6u&quot;,
++ V(vj.vjs_uncompressedin),
++ V(vj.vjs_errorin));
++ if (vflag)
++ printf(&quot; %6u %6u&quot;,
++ V(vj.vjs_tossed),
++ V(p.ppp_ipackets) - V(vj.vjs_compressedin)
++ - V(vj.vjs_uncompressedin) - V(vj.vjs_errorin));
++ if (rflag) {
++ printf(&quot; %6.2f &quot;, CRATE(d));
++ if (ratef)
++ printf(&quot;%6.2f&quot;, KBPS(W(d.unc_bytes)));
++ else
++ printf(&quot;%6u&quot;, W(d.unc_bytes));
++ }
++ if (ratef)
++ printf(&quot; | %8.3f&quot;, KBPS(V(p.ppp_obytes)));
++ else
++ printf(&quot; | %8u&quot;, V(p.ppp_obytes));
++ printf(&quot; %6u %6u&quot;,
++ V(p.ppp_opackets),
++ V(vj.vjs_compressed));
++ if (!rflag)
++ printf(&quot; %6u %6u&quot;,
++ V(vj.vjs_packets) - V(vj.vjs_compressed),
++ V(p.ppp_opackets) - V(vj.vjs_packets));
++ if (vflag)
++ printf(&quot; %6u %6u&quot;,
++ V(vj.vjs_searches),
++ V(vj.vjs_misses));
++ if (rflag) {
++ printf(&quot; %6.2f &quot;, CRATE(c));
++ if (ratef)
++ printf(&quot;%6.2f&quot;, KBPS(W(c.unc_bytes)));
++ else
++ printf(&quot;%6u&quot;, W(c.unc_bytes));
++ }
++
++ }
++
++ putchar('\n');
++ fflush(stdout);
++ line++;
++
++ count--;
++ if (!infinite &amp;&amp; !count)
++ break;
++
++ sigemptyset(&amp;mask);
++ sigaddset(&amp;mask, SIGALRM);
++ sigprocmask(SIG_BLOCK, &amp;mask, &amp;oldmask);
++ if (!signalled) {
++ sigemptyset(&amp;mask);
++ sigsuspend(&amp;mask);
++ }
++ sigprocmask(SIG_SETMASK, &amp;oldmask, NULL);
++ signalled = 0;
++ (void)alarm(interval);
++
++ if (!aflag) {
++ old = cur;
++ ocs = ccs;
++ ratef = dflag;
++ }
++ }
++}
++
++int
++main(argc, argv)
++ int argc;
++ char *argv[];
++{
++ int c;
++#ifdef STREAMS
++ char *dev;
++#endif
++
++ interface = PPP_DRV_NAME &quot;0&quot;;
++ if ((progname = strrchr(argv[0], '/')) == NULL)
++ progname = argv[0];
++ else
++ ++progname;
++
++ while ((c = getopt(argc, argv, &quot;advrzc:w:&quot;)) != -1) {
++ switch (c) {
++ case 'a':
++ ++aflag;
++ break;
++ case 'd':
++ ++dflag;
++ break;
++ case 'v':
++ ++vflag;
++ break;
++ case 'r':
++ ++rflag;
++ break;
++ case 'z':
++ ++zflag;
++ break;
++ case 'c':
++ count = atoi(optarg);
++ if (count &lt;= 0)
++ usage();
++ break;
++ case 'w':
++ interval = atoi(optarg);
++ if (interval &lt;= 0)
++ usage();
++ break;
++ default:
++ usage();
++ }
++ }
++ argc -= optind;
++ argv += optind;
++
++ if (!interval &amp;&amp; count)
++ interval = 5;
++ if (interval &amp;&amp; !count)
++ infinite = 1;
++ if (!interval &amp;&amp; !count)
++ count = 1;
++ if (aflag)
++ dflag = 0;
++
++ if (argc &gt; 1)
++ usage();
++ if (argc &gt; 0)
++ interface = argv[0];
++
++ if (sscanf(interface, PPP_DRV_NAME &quot;%d&quot;, &amp;unit) != 1) {
++ fprintf(stderr, &quot;%s: invalid interface '%s' specified\n&quot;,
++ progname, interface);
++ }
++
++#ifndef STREAMS
++ {
++ struct ifreq ifr;
++
++ s = socket(AF_INET, SOCK_DGRAM, 0);
++ if (s &lt; 0) {
++ fprintf(stderr, &quot;%s: &quot;, progname);
++ perror(&quot;couldn't create IP socket&quot;);
++ exit(1);
++ }
++
++#ifdef _linux_
++#undef ifr_name
++#define ifr_name ifr_ifrn.ifrn_name
++#endif
++ strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name));
++ if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&amp;ifr) &lt; 0) {
++ fprintf(stderr, &quot;%s: nonexistent interface '%s' specified\n&quot;,
++ progname, interface);
++ exit(1);
++ }
++ }
++
++#else /* STREAMS */
++#ifdef __osf__
++ dev = &quot;/dev/streams/ppp&quot;;
++#else
++ dev = &quot;/dev/&quot; PPP_DRV_NAME;
++#endif
++ if ((s = open(dev, O_RDONLY)) &lt; 0) {
++ fprintf(stderr, &quot;%s: couldn't open &quot;, progname);
++ perror(dev);
++ exit(1);
++ }
++ if (strioctl(s, PPPIO_ATTACH, &amp;unit, sizeof(int), 0) &lt; 0) {
++ fprintf(stderr, &quot;%s: ppp%d is not available\n&quot;, progname, unit);
++ exit(1);
++ }
++
++#endif /* STREAMS */
++
++ intpr();
++ exit(0);
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/pppstats/pppstats.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/sample/auth-down
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/sample/auth-down (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/sample/auth-down 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,17 @@
++#!/bin/sh
++#
++# A program or script which is executed after the remote system
++# successfully authenticates itself. It is executed with the parameters
++# &lt;interface-name&gt; &lt;peer-name&gt; &lt;user-name&gt; &lt;tty-device&gt; &lt;speed&gt;
++#
++
++#
++# The environment is cleared before executing this script
++# so the path must be reset
++#
++PATH=/usr/sbin:/sbin:/usr/bin:/bin
++export PATH
++
++echo auth-down `date +'%y/%m/%d %T'` $* &gt;&gt; /var/log/pppstats
++
++# last line
+
+Added: drakx/trunk/mdk-stage1/ppp/sample/auth-up
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/sample/auth-up (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/sample/auth-up 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,17 @@
++#!/bin/sh
++#
++# A program or script which is executed after the remote system
++# successfully authenticates itself. It is executed with the parameters
++# &lt;interface-name&gt; &lt;peer-name&gt; &lt;user-name&gt; &lt;tty-device&gt; &lt;speed&gt;
++#
++
++#
++# The environment is cleared before executing this script
++# so the path must be reset
++#
++PATH=/usr/sbin:/sbin:/usr/bin:/bin
++export PATH
++
++echo auth-up `date +'%y/%m/%d %T'` $* &gt;&gt; /var/log/pppstats
++
++# last line
+
+Added: drakx/trunk/mdk-stage1/ppp/sample/ip-down
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/sample/ip-down (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/sample/ip-down 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,22 @@
++#!/bin/sh
++#
++# This script is run by the pppd _after_ the link is brought down.
++# It should be used to delete routes, unset IP addresses etc.
++#
++# This script is called with the following arguments:
++# Arg Name Example
++# $1 Interface name ppp0
++# $2 The tty ttyS1
++# $3 The link speed 38400
++# $4 Local IP number 12.34.56.78
++# $5 Peer IP number 12.34.56.99
++#
++
++#
++# The environment is cleared before executing this script
++# so the path must be reset
++#
++PATH=/usr/sbin:/sbin:/usr/bin:/bin
++export PATH
++
++# last line
+
+Added: drakx/trunk/mdk-stage1/ppp/sample/ip-up
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/sample/ip-up (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/sample/ip-up 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,23 @@
++#!/bin/sh
++#
++# This script is run by the pppd after the link is established.
++# It should be used to add routes, set IP address, run the mailq
++# etc.
++#
++# This script is called with the following arguments:
++# Arg Name Example
++# $1 Interface name ppp0
++# $2 The tty ttyS1
++# $3 The link speed 38400
++# $4 Local IP number 12.34.56.78
++# $5 Peer IP number 12.34.56.99
++#
++
++#
++# The environment is cleared before executing this script
++# so the path must be reset
++#
++PATH=/usr/sbin:/sbin:/usr/bin:/bin
++export PATH
++
++# last line
+
+Added: drakx/trunk/mdk-stage1/ppp/sample/options
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/sample/options (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/sample/options 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,153 @@
++# /etc/ppp/options
++
++# The name of this server. Often, the FQDN is used here.
++#name &lt;host&gt;
++
++# Enforce the use of the hostname as the name of the local system for
++# authentication purposes (overrides the name option).
++usehostname
++
++# If no local IP address is given, pppd will use the first IP address
++# that belongs to the local hostname. If &quot;noipdefault&quot; is given, this
++# is disabled and the peer will have to supply an IP address.
++noipdefault
++
++# With this option, pppd will accept the peer's idea of our local IP
++# address, even if the local IP address was specified in an option.
++#ipcp-accept-local
++
++# With this option, pppd will accept the peer's idea of its (remote) IP
++# address, even if the remote IP address was specified in an option.
++#ipcp-accept-remote
++
++# Specify which DNS Servers the incoming Win95 or WinNT Connection should use
++# Two Servers can be remotely configured
++#ms-dns 192.168.1.1
++#ms-dns 192.168.1.2
++
++# Specify which WINS Servers the incoming connection Win95 or WinNT should use
++#wins-addr 192.168.1.50
++#wins-addr 192.168.1.51
++
++# enable this on a server that already has a permanent default route
++#nodefaultroute
++
++# Run the executable or shell command specified after pppd has terminated
++# the link. This script could, for example, issue commands to the modem
++# to cause it to hang up if hardware modem control signals were not
++# available.
++# If mgetty is running, it will reset the modem anyway. So there is no need
++# to do it here.
++#disconnect &quot;chat -- \d+++\d\c OK ath0 OK&quot;
++
++# Increase debugging level (same as -d). The debug output is written
++# to syslog LOG_LOCAL2.
++debug
++
++# Enable debugging code in the kernel-level PPP driver. The argument n
++# is a number which is the sum of the following values: 1 to enable
++# general debug messages, 2 to request that the contents of received
++# packets be printed, and 4 to request that the contents of transmitted
++# packets be printed.
++#kdebug n
++
++# Require the peer to authenticate itself before allowing network
++# packets to be sent or received.
++# Please do not disable this setting. It is expected to be standard in
++# future releases of pppd. Use the call option (see manpage) to disable
++# authentication for specific peers.
++#auth
++
++# authentication can either be pap or chap. As most people only want to
++# use pap, you can also disable chap:
++#require-pap
++#refuse-chap
++
++# Use hardware flow control (i.e. RTS/CTS) to control the flow of data
++# on the serial port.
++crtscts
++
++# Specifies that pppd should use a UUCP-style lock on the serial device
++# to ensure exclusive access to the device.
++lock
++
++# Use the modem control lines.
++modem
++
++# async character map -- 32-bit hex; each bit is a character
++# that needs to be escaped for pppd to receive it. 0x00000001
++# represents '\x01', and 0x80000000 represents '\x1f'.
++# To allow pppd to work over a rlogin/telnet connection, ou should escape
++# XON (^Q), XOFF (^S) and ^]: (The peer should use &quot;escape ff&quot;.)
++#asyncmap 200a0000
++asyncmap 0
++
++# Specifies that certain characters should be escaped on transmission
++# (regardless of whether the peer requests them to be escaped with its
++# async control character map). The characters to be escaped are
++# specified as a list of hex numbers separated by commas. Note that
++# almost any character can be specified for the escape option, unlike
++# the asyncmap option which only allows control characters to be
++# specified. The characters which may not be escaped are those with hex
++# values 0x20 - 0x3f or 0x5e.
++#escape 11,13,ff
++
++# Set the MRU [Maximum Receive Unit] value to &lt;n&gt; for negotiation. pppd
++# will ask the peer to send packets of no more than &lt;n&gt; bytes. The
++# minimum MRU value is 128. The default MRU value is 1500. A value of
++# 296 is recommended for slow links (40 bytes for TCP/IP header + 256
++# bytes of data).
++#mru 542
++
++# Set the MTU [Maximum Transmit Unit] value to &lt;n&gt;. Unless the peer
++# requests a smaller value via MRU negotiation, pppd will request that
++# the kernel networking code send data packets of no more than n bytes
++# through the PPP network interface.
++#mtu &lt;n&gt;
++
++# Set the interface netmask to &lt;n&gt;, a 32 bit netmask in &quot;decimal dot&quot;
++# notation (e.g. 255.255.255.0).
++#netmask 255.255.255.0
++
++# Don't fork to become a background process (otherwise pppd will do so
++# if a serial device is specified).
++nodetach
++
++# Set the assumed name of the remote system for authentication purposes
++# to &lt;n&gt;.
++#remotename &lt;n&gt;
++
++# Add an entry to this system's ARP [Address Resolution Protocol]
++# table with the IP address of the peer and the Ethernet address of this
++# system. {proxyarp,noproxyarp}
++proxyarp
++
++# Use the system password database for authenticating the peer using
++# PAP. Note: mgetty already provides this option. If this is specified
++# then dialin from users using a script under Linux to fire up ppp wont work.
++#login
++
++# If this option is given, pppd will send an LCP echo-request frame to
++# the peer every n seconds. Under Linux, the echo-request is sent when
++# no packets have been received from the peer for n seconds. Normally
++# the peer should respond to the echo-request by sending an echo-reply.
++# This option can be used with the lcp-echo-failure option to detect
++# that the peer is no longer connected.
++lcp-echo-interval 30
++
++# If this option is given, pppd will presume the peer to be dead if n
++# LCP echo-requests are sent without receiving a valid LCP echo-reply.
++# If this happens, pppd will terminate the connection. Use of this
++# option requires a non-zero value for the lcp-echo-interval parameter.
++# This option can be used to enable pppd to terminate after the physical
++# connection has been broken (e.g., the modem has hung up) in
++# situations where no hardware modem control lines are available.
++lcp-echo-failure 4
++
++# Specifies that pppd should disconnect if the link is idle for n seconds.
++idle 600
++
++# Disable the IPXCP and IPX protocols.
++noipx
++
++# ---&lt;End of File&gt;---
+
+Added: drakx/trunk/mdk-stage1/ppp/sample/options.ttyXX
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/sample/options.ttyXX (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/sample/options.ttyXX 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,14 @@
++# If you need to set up multiple serial lines then copy this file to
++# options.&lt;ttyname&gt; for each tty with a modem on it.
++#
++# The options.tty file will assign an IP address to each PPP connection
++# as it comes up. They must all be distinct!
++#
++# Example:
++# options.ttyS1 for com2 under DOS.
++#
++# Edit the following line so that the first IP address
++# mentioned is the ip address of the serial port while the second
++# is the IP address of your host
++#
++hostname-s1:hostname
+
+Added: drakx/trunk/mdk-stage1/ppp/sample/pap-secrets
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/sample/pap-secrets (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/sample/pap-secrets 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,28 @@
++# Secrets for authentication using PAP
++# client server secret IP addresses
++
++# OUTBOUND CONNECTIONS
++# Here you should add your userid password to connect to your providers via
++# pap. The * means that the password is to be used for ANY host you connect
++# to. Thus you do not have to worry about the foreign machine name. Just
++# replace password with your password.
++# If you have different providers with different passwords then you better
++# remove the following line.
++#hostname * password
++
++# INBOUND CONNECTIONS
++#client hostname &lt;password&gt; 192.168.1.1
++
++# If you add &quot;auth login -chap +pap&quot; to /etc/mgetty+sendfax/login.config,
++# all users in /etc/passwd can use their password for pap-authentication.
++#
++# Every regular user can use PPP and has to use passwords from /etc/passwd
++#* hostname &quot;&quot;
++# UserIDs that cannot use PPP at all. Check your /etc/passwd and add any
++# other accounts that should not be able to use pppd! Replace hostname
++# with your local hostname.
++#guest hostname &quot;*&quot; -
++#master hostname &quot;*&quot; -
++#root hostname &quot;*&quot; -
++#support hostname &quot;*&quot; -
++#stats hostname &quot;*&quot; -
+
+Added: drakx/trunk/mdk-stage1/ppp/scripts/README
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/scripts/README (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/scripts/README 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,143 @@
++This directory contains a set of scripts which have been used on Linux
++as well as Solaris 2.x systems to initiate or maintain a connection
++with PPP. The files in this directory were contributed by Al Longyear
++(<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">longyear at netcom.com</A>) and Adi Masputra (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">adi.masputra at sun.com</A>)
++
++------------------------------------------------------------------------
++
++1. README
++
++This file. You are reading it. It is just documentation.
++
++------------------------------------------------------------------------
++
++2. ppp-on
++
++This script will initiate a connection to the PPP system. It will run
++the chat program with the connection script as a parameter. This is a
++possible security hole. However, it is simple. It is meant to replace
++the previous version of ppp-on which was not very functional.
++
++The ppp-on script has entries for the account name, password, IP
++addresses, and telephone numbers. The parameters are passed to the
++pppd process and, then in turn, to the second part of the connect
++script, as a set of environment variables.
++
++Please make sure that you put the full path name to the ppp-on-dialer
++script in the reference to it in ppp-on.
++
++------------------------------------------------------------------------
++
++3. ppp-on-dialer
++
++This is the second part to the simple calling script, ppp-on. It
++executes the chat program to connect the user with a standard UNIX
++style getty/login connection sequence.
++
++------------------------------------------------------------------------
++
++4. callback
++
++This script may be used in lieu of the ppp-on-dialer to permit the
++common modem callback sequence. You may need to make changes to the
++expected prompt string for the modem.
++
++The script works by disabling the system's detection of the DCD
++condition and working on the modem status message &quot;NO CARRIER&quot; which
++is generated when the modem disconnects.
++
++It is crude. It does work for my modem connection. Use as you see fit.
++
++------------------------------------------------------------------------
++
++5. redialer
++
++The redialer script is a replacement for the ppp-on-dialer script. It
++will do 'attack dialing' or 'demon dialing' of one or more telephone
++numbers. The first number which responds will be used for a
++connection.
++
++There is a limit of ten attempts and a 15 second delay between dialing
++attempts. Both values are set in the script.
++
++------------------------------------------------------------------------
++
++6. ppp-off
++
++This is a script which will terminate the active ppp connection. Use
++as either &quot;ppp-off&quot; to terminate ppp0, or &quot;ppp-off &lt;device&gt;&quot; to
++terminate the connection on &lt;device&gt;. For example, &quot;ppp-off ppp2&quot; will
++terminate the ppp2 connection.
++
++------------------------------------------------------------------------
++
++7. secure-card
++
++This script was written by Jim Isaacson &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">jcisaac at crl.com</A>&gt;. It is a script
++for the 'expect' programming language used with Tcl. You need to have
++expect and Tcl installed before this script may be used.
++
++This script will operate with a device marketed under the name &quot;SecureCARD&quot;.
++This little device is mated with its controller. On the credit card size
++device, there is a sequence number which changes on a random basis. In order
++for you to connect you need to enter a fixed portion of your account name
++and the number which is displayed on this card device. The number must match
++the value at the controller in order for the account name to be used.
++
++The problem is that chat uses fixed response strings. In addition, the
++timing for running the script may prevent the use of a script that reads the
++value before it starts the dial sequence. What was needed was a script which
++asked the user at the user's console at the time that it is needed.
++
++This led to the use of expect.
++
++------------------------------------------------------------------------
++
++8. ppp-on-rsh
++
++This script will initiate a PPP connection to a remote machine using rsh.
++This is implemented by creating a master/slave pseudo-tty with the slave
++pointing to rsh, specifically with the 'pty' and 'notty' options of pppd.
++It is assumed that the remote machine contains some sort of trust
++mechanisms (such as ~/.rhosts, et al) to allow the local machine to
++connect via rsh as root.
++
++------------------------------------------------------------------------
++
++9. ppp-on-ssh
++
++This script will initiate a PPP connection to a remote machine using the
++secure shell, or ssh. I've only tested this on ssh 1.x, so those of you
++who are running ssh 2.x mahy need to modify the ssh options slightly.
++This is implemented by creating a master/slave pseudo-ttyt with the slave
++pointing to ssh, specifically with the 'pty' and 'notty' options of pppd.
++It is assumed that the remote machine can accept the ssh connection from
++the local host, in the sense that all ssh authentication mechanisms have
++been properly configured, so that a remote root user can open a ssh
++connection.
++
++------------------------------------------------------------------------
++
++10. options-rsh-loc &amp; options-rsh-rem
++
++These options files accompany the ppp-on-rsh script mentioned above. In
++theory, you'd want to copy the options-rsh-rem to the remote machine where
++in.rshd is running. The only extra option required on the remote machine
++options file is the 'notty' option. In addition, all ASCII control characters
++[0x00 to 0x1f], plus 0xff, are escaped. This may need to be modified
++depending on the rsh (or pseudo-tty) implementation which may differ across
++platforms, for further optimizations.
++
++------------------------------------------------------------------------
++
++11. options-ssh-loc &amp; options-ssh-rem
++
++These options files accompany the ppp-on-ssh script mentioned above. I've
++only tested this on ssh 1.x, so those of you who are running ssh 2.x need
++to modify the ssh options slightly. In theory, you'd want to copy the
++options-ssh-rem to the remote machine where sshd daemon is running. The only
++extra options required on the remote machine options file is the 'notty'
++option. In addition, all ASCII control characters [0x00 to 0x1f], plus 0xff,
++are escaped. This may need to be modified depending on the ssh (or
++pseudo-tty) implementation which may differ across platforms, for further
++optimizations.
+
+Added: drakx/trunk/mdk-stage1/ppp/scripts/callback
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/scripts/callback (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/scripts/callback 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,77 @@
++#!/bin/sh
++###################################################################
++#
++# Script to dial the remote system, negotiate the connection, and send
++# it the id. Then wait for the modem to disconnect. Reset the modem
++# to answer mode and wait for the system to call back.
++#
++# The telephone number and modempass are used when establishing the
++# connection to the modem.
++#
++PHONE=555-1212
++MODEMPASS=modem_identifier
++#
++# Once the modem calls back, the account name and password are used for
++# a UNIX style login operation.
++#
++ACCOUNT=my_account_name
++PASSWORD=my_password
++
++###################################################################
++#
++# Step 1. Dial the modem and negotiate the initial dialog.
++# note: the modem is configured to ignore loss of DCD at this point.
++# it is important that this be performed because the loss of DCD
++# will normally prevent system from working since 'modem' is used
++# for pppd.
++#
++# The script is terminated normally when the carrier is lost.
++#
++chat -v \
++ TIMEOUT 3 \
++ ABORT '\nBUSY\r' \
++ ABORT '\nNO ANSWER\r' \
++ ABORT '\nRINGING\r\n\r\nRINGING\r' \
++ '' AT \
++ 'OK-+++\c-OK' 'AT&amp;C0&amp;D2S0=0H0 \
++ TIMEOUT 30 \
++ OK ATDT$TELEPHONE \
++ CONNECT '' \
++ assword: $MODEMPASS \
++ &quot;\nNO CARRIER\r&quot;
++
++if [ &quot;$?&quot; = &quot;0&quot; ]; then
++
++###################################################################
++#
++# Step 2. Wait for the call back from the remote. This will wait for at most
++# 30 seconds for the call back should the first attempt fail or
++# something happen with the callback logic at the remote.
++#
++# note: when the callback occurs, the DCD setting is re-enabled.
++#
++# If some voice call should happen during this period, the system will
++# answer the telephone and then hang up on them. I realize that this is
++# rude, but there is little that this script can do.
++#
++ chat -v \
++ TIMEOUT 30 \
++ ABORT '\nVOICE\r' \
++ '\nRING\r' 'AT&amp;C1A' \
++ CONNECT '' \
++ TIMEOUT 10 \
++ ogin:--ogin: $ACCOUNT \
++ TIMEOUT 45 \
++ assword: $PASSWORD
++
++ if [ &quot;$?&quot; = &quot;0&quot; ]; then
++ exit 0
++ fi
++fi
++
++###################################################################
++#
++# The script has failed. Terminate the connection mode.
++#
++chat -v TIMEOUT 3 &quot;&quot; AT 'OK-+++\c-OK' 'AT&amp;C1&amp;D2S0=0H0' OK
++exit 1
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/scripts/callback
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: drakx/trunk/mdk-stage1/ppp/scripts/chat-callback
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/scripts/chat-callback (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/scripts/chat-callback 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,98 @@
++# =====================================================================================
++# Chat script to dial our Company PPP account.
++# They uses a call-back system to identify us and to reverse
++# charge the call cost.
++# =====================================================================================
++#
++ECHO OFF
++# All the usual abort strings
++ABORT &quot;NO CARRIER&quot;
++ABORT &quot;VOICE&quot;
++ABORT &quot;BUSY&quot;
++ABORT &quot;NO DIALTONE&quot;
++ABORT &quot;NO ANSWER&quot;
++#
++# If calling outside allowed time we get this:
++#
++ABORT &quot;Access denied&quot;
++#
++# Modem initialisation stuff
++#
++TIMEOUT 5
++SAY &quot;Initialising modem ...\n&quot;
++'' ATE1
++'OK\r\n' ATS0=1S11=60X4&amp;K4S42.1=1
++#
++# Now dial our ISP and wait for connection
++#
++SAY &quot;Dialling our ISP ...\n&quot;
++'OK\r\n' ATDT09834657
++TIMEOUT 60
++CONNECT \c
++SAY &quot;Connected ...\n&quot;
++#
++# This is the first stage login, we identify ourself so that the remote
++# system will agree to call us back.
++#
++TIMEOUT 30
++SAY &quot;Sending Callback login ID ...\n&quot;
++name:-BREAK-name: callme
++#
++# From now on, we must assume no carrier is normal as well
++# as receiving a HANGUP signal because it will be the
++# case if our ISP clears the call to call us back.
++#
++CLR_ABORT &quot;NO CARRIER&quot;
++HANGUP OFF
++#
++ABORT &quot;Invalid&quot;
++#
++# Now send password and wait to see what happens
++#
++SAY &quot;Sending Callback password ...\n&quot;
++word:--word: xvsgsgs
++&quot;You will be&quot; \c
++#
++# What can happen now is:
++# either: we get &quot;You will be called back...&quot; which is the successful case
++# or: we get &quot;Invalid login&quot; and we abort (bad login ID or password)
++# or: we get &quot;NO CARRIER&quot; because of an error, this will not abort
++# and we will time out after 30 seconds
++# or: we get nothing and we will time out after 30 seconds
++#
++#
++# We reach here if we got &quot;You will be called back...&quot;
++#
++CLR_ABORT &quot;Invalid&quot;
++SAY &quot;Now waiting for Call back ...\n&quot;
++#
++# The remote system will now hangup and we will get both &quot;NO CARRIER&quot;
++# and a hangup signal which are ignored. We now wait for a connection
++# for up to 120 seconds. What happens here if somebody else calls before
++# the remote system is a bit dangerous:
++#
++# If a malicious user connects and says 'name:', he will see 'PPPuser'
++# If he then says 'word:' he will see the passowrd 'blipblop'. I may not
++# know to which systems these belong to, though. It is up to you to consider
++# that case and decide wether the risk is too big or not ....
++#
++TIMEOUT 120
++&quot;CONNECT&quot; \c
++#
++# We have been called, re-arm ABORT on NO CARRIER and normal hangup signal
++# behaviour
++#
++HANGUP ON
++ABORT &quot;NO CARRIER&quot;
++#
++# Second stage login in order to start PPP
++#
++SAY &quot;Remote system called back, logging in ...\n&quot;
++SAY &quot;Sending login ID ...\n&quot;
++name:-BREAK-name: PPPuser
++SAY &quot;Sending password ...\n&quot;
++word:--word: blipblop
++SAY &quot;Asking to start PPP ...\n&quot;
++'CnetSrv' &quot;ppp default&quot;
++&quot;Entering PPP mode&quot; \c
++SAY &quot;ISP PPP started ...\n&quot;
+
+Added: drakx/trunk/mdk-stage1/ppp/scripts/chatchat/README
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/scripts/chatchat/README (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/scripts/chatchat/README 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,134 @@
++v 0.1 <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gpk at onramp.net</A> 3/27/99
++
++I Intro
++
++ This document covers the use of the modified &quot;chat&quot; program and its
++adjunct &quot;chatchat&quot; to login using the Security Dynamics SecurID card
++on a linux system.
++
++ This set of files comprises a modified version of the chat program
++(the one distributed with ppp-2.3.5) and a new program called chatchat
++that allows you to supply data from the keyboard to the chat program.
++
++ The SecurID card generates passwords that have a lifetime of one
++minute and are used as a first layer in dial up security. The only
++software I know of for this card is for windows, so I wrote my own.
++This software allows you to type in the time-sensitive password right
++when your chat script is asked to supply the passcode by the remote
++system.
++
++
++II How It Works
++
++ This version of chat his an additional command that can be put into
++its options that says &quot;Don't reply with this string. Open this pipe,
++read the contents, and reply with that instead.&quot; Chatchat creates a
++pipe and lets you type your passcode into it, then chat picks that up
++and sends it out just as though the passcode was hardcoded into the
++options.
++
++
++III Installation
++
++ I've provided intel binaries and source code the the modified chat
++program and the chatchat program. I'll recommend that you copy the
++chat.c program into your ppp-2.3.5/chat directory (save your original
++chat.c program first!) and re-make it using the Makefile that comes
++with chat. Copy the new chat somewhere into your path. (On my system
++chat lives in /usr/sbin/chat, so I've copied the modified one into
++/usr/sbin/chat.new and changed my dial in script to call chat.new
++instead of chat.
++
++ Second, compile chatchat.c and install it somewhere in your path:
++
++ gcc -g -o chatchat chatchat.c
++ cp chatchat /usr/sbin
++
++ Third, modify your chat script to use the chatchat program. Mine
++looks something like this:
++
++
++ --------------------
++
++#!/bin/sh
++#
++# This is part 2 of the ppp-on script. It will perform the connection
++# protocol for the desired connection.
++# use atm0 to turn down the speaker volume on my sportster x2 voice modem
++# gpk 11/2/97
++
++exec /usr/sbin/chat.new -V -v \
++ ABORT &quot;BUSY&quot; \
++ ABORT &quot;NO DIAL TONE&quot; \
++ ABORT &quot;NO ANSWER&quot; \
++ TIMEOUT 50 \
++ &quot;&quot; &quot;atm0&quot; \
++ OK ATDT$TELEPHONE \
++ CONNECT '' \
++ name: \\da0xxxxxx \
++ word: @/var/tmp/p \
++ compress. ''
++
++
++ -----------------------
++
++ This is a standard chat script:
++
++* abort if the modem is busy, you don't get a dial tone, no one
++ answers, or 50 seconds elapses.
++
++* use atm0 to mute the modem
++
++* dial the modem, when it connects, wait to be asked for account name
++
++* when we see &quot;name:&quot; prompt, delay briefly then respond with your
++ account name (fill in your account name)
++
++Now we get to the new stuff:
++
++* when we see &quot;word:&quot; in the password prompt, instead of responding
++ with &quot;@/var/tmp/p&quot;, the modified chat program will open the pipe
++ /var/tmp/p, read the passcode out of there, and send it
++
++* when we see &quot;compress.&quot; (the last word before ppp starts), reply
++ with nothing. The script ends and we start ppp.
++
++Note:
++
++* Make sure there is some whitespace between the filename and the \.
++
++
++IV Usage
++
++ To use this install the modified chat and chatchat programs, and
++modify your chat script similar to the above. Before you dial in,
++start that chatchat program giving it the same pipe as in your config
++file. In the above case:
++
++chatchat /var/tmp/p
++
++ Wait until you have one or two tick marks left on your card's
++current number, then start your dial up process that eventually calls
++chat. When chat goes to open and read the pipe, chatchat will prompt:
++
++
++type PIN into SecurID card and
++ enter resulting passcode:
++
++ At that point, type your PIN number into your Securid card, press
++the diamond, and type the resulting numbers in as your passcode. If
++you've left the -V -v options on your chat command you'll see
++everything so out, otherwise it works silently.
++
++ If you type the number wrong or run out of time, the server will
++respond with an authentication failure. In that case you will have to
++hang up and start again. I don't know how to build a conditional script
++that says either expect &quot;compress&quot; next, but if you see &quot;name:&quot; again,
++do this instead.
++
++
++V Additional Information
++
++ You can obtain additional information about chat and ppp from the
++man pages for chat and pppd, as well as the PPP-HOWTO.
++
+
+Added: drakx/trunk/mdk-stage1/ppp/scripts/chatchat/chatchat.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/scripts/chatchat/chatchat.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/scripts/chatchat/chatchat.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,409 @@
++/* *************************************************************************
++* NAME: chatchat.c
++*
++* DESCRIPTION:
++*
++* This program creates a pipe for the chat process to read. The user
++* can supply information (like a password) that will be picked up
++* by chat and sent just like the regular contents of a chat script.
++*
++* Usage is:
++*
++* chatchat &lt;filename&gt;
++*
++* where &lt;filename&gt; matches the option given in the chat script.
++*
++* for instance the chat script fragment:
++*
++* ...
++* name: \\dmyname \
++* word: @/var/tmp/p \
++* ...
++* ^
++* (note: leave some whitespace after the filename)
++*
++* expect &quot;name:&quot;, reply with a delay followed by &quot;myname&quot;
++* expect &quot;word:&quot;, reply with the data read from the pipe /var/tmp/p
++*
++* the matching usage of chatchat would be:
++*
++* chatchat /var/tmp/p
++*
++* eg:
++*
++* $chatchat /var/tmp/p
++* ...
++* some other process eventually starts:
++* chat ...
++* chat parses the &quot;@/var/tmp/p&quot; option and opens
++* /var/tmp/p
++* (chatchat prompts:)
++*
++* type PIN into SecurID card
++* enter resulting passcode: [user inputs something]
++*
++* chat reads /var/tmp/p &amp; gets what the
++* user typed at chatchat's &quot;enter string&quot; prompt
++* chat removes the pipe file
++* chat sends the user's input as a response in
++* place of &quot;@/var/tmp/p&quot;
++*
++* PROCESS:
++*
++* gcc -g -o chatchat chatchat.c
++*
++*
++* GLOBALS: none
++*
++* REFERENCES:
++*
++* see the man pages and documentation that come with the 'chat' program
++* (part of the ppp package). you will need to use the modified chat
++* program that accepts the '@' operator.
++*
++* LIMITATIONS:
++*
++* REVISION HISTORY:
++*
++* STR Description Author
++*
++* 23-Mar-99 initial coding gpk
++* 12-May-99 unlink the pipe after closing paulus
++*
++* TARGET: ANSI C
++* This program is in the public domain.
++*
++*
++* ************************************************************************* */
++
++
++
++
++#include &lt;sys/time.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;string.h&gt;
++
++/* MAXINPUT - the data typed into chatchat must be fewer */
++/* characters than this. */
++
++#define MAXINPUT 80
++
++
++
++
++
++
++/* *************************************************************************
++
++
++ NAME: main
++
++
++ USAGE:
++
++ int argc;
++ char * argv[];
++
++ main(argc, argv[]);
++
++ returns: int
++
++ DESCRIPTION:
++ if the pipe file name is given on the command line,
++ create the pipe, prompt the user and put whatever
++ is typed into the pipe.
++
++ returns -1 on error
++ else # characters entered
++ REFERENCES:
++
++ LIMITATIONS:
++
++ GLOBAL VARIABLES:
++
++ accessed: none
++
++ modified: none
++
++ FUNCTIONS CALLED:
++
++ REVISION HISTORY:
++
++ STR Description of Revision Author
++
++ 25-Mar-99 initial coding gpk
++
++ ************************************************************************* */
++
++int main(int argc, char * argv[])
++{
++ int retval;
++
++ int create_and_write_pipe(char * pipename);
++
++ if (argc != 2)
++ {
++ fprintf(stderr, &quot;usage: %s pipename\n&quot;, argv[0]);
++ retval = -1;
++ }
++ else
++ {
++ retval = create_and_write_pipe(argv[1]);
++ }
++ return (retval);
++}
++
++
++
++
++/* *************************************************************************
++
++
++ NAME: create_and_write_pipe
++
++
++ USAGE:
++
++ int some_int;
++ char * pipename;
++
++ some_int = create_and_write_pipe(pipename);
++
++ returns: int
++
++ DESCRIPTION:
++ given the pipename, create the pipe, open it,
++ prompt the user for a string to put into the
++ pipe, write the string, and close the pipe
++
++ on error, print out an error message and return -1
++
++ returns -1 on error
++ else #bytes written into the pipe
++ REFERENCES:
++
++ LIMITATIONS:
++
++ GLOBAL VARIABLES:
++
++ accessed: none
++
++ modified: none
++
++ FUNCTIONS CALLED:
++
++ REVISION HISTORY:
++
++ STR Description of Revision Author
++
++ 25-Mar-99 initial coding gpk
++ 12-May-99 remove pipe after closing paulus
++
++ ************************************************************************* */
++
++int create_and_write_pipe(char * pipename)
++{
++ int retval, created, pipefd, nread, nwritten;
++ char input[MAXINPUT];
++ char errstring[180];
++
++ int create_pipe(char * pipename);
++ int write_to_pipe(int pipefd, char * input, int nchar);
++
++ created = create_pipe(pipename);
++
++ if (-1 == created)
++ {
++ sprintf(errstring, &quot;unable to create pipe '%s'&quot;, pipename);
++ perror(errstring);
++ retval = -1;
++ }
++ else
++ {
++
++ /* note: this open won't succeed until chat has the pipe */
++ /* open and ready to read. this makes for nice timing. */
++
++ pipefd = open(pipename, O_WRONLY);
++
++ if (-1 == pipefd)
++ {
++ sprintf(errstring, &quot;unable to open pipe '%s'&quot;, pipename);
++ perror(errstring);
++ retval = -1;
++ }
++ else
++ {
++ fprintf(stderr, &quot;%s \n %s&quot;,
++ &quot;type PIN into SecurID card and&quot;,
++ &quot;enter resulting passcode:&quot;);
++ nread = read(STDIN_FILENO, (void *)input, MAXINPUT);
++
++
++ if (0 &gt;= nread)
++ {
++ perror(&quot;unable to read from stdin&quot;);
++ retval = -1;
++ }
++ else
++ {
++ /* munch off the newline character, chat supplies */
++ /* a return when it sends the string out. */
++ input[nread -1] = 0;
++ nread--;
++ nwritten = write_to_pipe(pipefd, input, nread);
++ /* printf(&quot;wrote [%d]: '%s'\n&quot;, nwritten, input); */
++ retval = nwritten;
++ }
++ close(pipefd);
++
++ /* Now make the pipe go away. It won't actually go away
++ completely until chat closes it. */
++ if (unlink(pipename) &lt; 0)
++ perror(&quot;Warning: couldn't remove pipe&quot;);
++ }
++ }
++ return(retval);
++}
++
++
++
++
++
++
++
++/* *************************************************************************
++
++
++ NAME: create_pipe
++
++
++ USAGE:
++
++ int some_int;
++ char * pipename;
++
++ some_int = create_pipe(pipename);
++
++ returns: int
++
++ DESCRIPTION:
++ create a pipe of the given name
++
++ if there is an error (like the pipe already exists)
++ print an error message and return
++
++ return -1 on failure else success
++
++ REFERENCES:
++
++ LIMITATIONS:
++
++ GLOBAL VARIABLES:
++
++ accessed: none
++
++ modified: none
++
++ FUNCTIONS CALLED:
++
++ REVISION HISTORY:
++
++ STR Description of Revision Author
++
++ 25-Mar-99 initial coding gpk
++
++ ************************************************************************* */
++
++int create_pipe(char * pipename)
++{
++ mode_t old_umask;
++ int created;
++
++ /* hijack the umask temporarily to get the mode I want */
++ /* on the pipe. */
++
++ old_umask = umask(000);
++
++ created = mknod(pipename, S_IFIFO | S_IRWXU | S_IWGRP | S_IWOTH,
++ (dev_t)NULL);
++
++ /* now restore umask. */
++
++ (void)umask(old_umask);
++
++ if (-1 == created)
++ {
++ perror(&quot;unable to create pipe&quot;);
++ }
++
++ return(created);
++}
++
++
++
++
++
++
++/* *************************************************************************
++
++
++ NAME: write_to_pipe
++
++
++ USAGE:
++
++ int some_int;
++ int pipefd;
++ char * input;
++ int nchar;
++
++ some_int = write_to_pipe(pipefd, input, nchar);
++
++ returns: int
++
++ DESCRIPTION:
++ write nchars of data from input to pipefd
++
++ on error print a message to stderr
++
++ return -1 on error, else # bytes written
++ REFERENCES:
++
++ LIMITATIONS:
++
++ GLOBAL VARIABLES:
++
++ accessed: none
++
++ modified: none
++
++ FUNCTIONS CALLED:
++
++ REVISION HISTORY:
++
++ STR Description of Revision Author
++
++ 25-Mar-99 initial coding gpk
++ 12-May-99 don't write count word first paulus
++
++ ************************************************************************* */
++
++int write_to_pipe(int pipefd, char * input, int nchar)
++{
++ int nwritten;
++
++ /* nwritten = write(pipefd, (void *)&amp;nchar, sizeof(nchar)); */
++ nwritten = write(pipefd, (void *)input, nchar);
++
++ if (-1 == nwritten)
++ {
++ perror(&quot;unable to write to pipe&quot;);
++ }
++
++ return(nwritten);
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/scripts/chatchat/chatchat.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/scripts/ip-down.local.add
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/scripts/ip-down.local.add (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/scripts/ip-down.local.add 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,20 @@
++
++#
++# This sample code shows you one way to modify your setup to allow automatic
++# configuration of your resolv.conf for peer supplied DNS addresses when using
++# the `usepeerdns' option.
++#
++# In my case I just added this to my /etc/ppp/ip-down.local script. You may need to
++# create an executable script if one does not exist.
++#
++# Nick Walker (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">nickwalker at email.com</A>)
++#
++
++if [ -n &quot;$USEPEERDNS&quot; -a -f /etc/ppp/resolv.conf ]; then
++ if [ -f /etc/ppp/resolv.prev ]; then
++ cp -f /etc/ppp/resolv.prev /etc/resolv.conf
++ else
++ rm -f /etc/resolv.conf
++ fi
++fi
++
+
+Added: drakx/trunk/mdk-stage1/ppp/scripts/ip-up.local.add
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/scripts/ip-up.local.add (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/scripts/ip-up.local.add 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,24 @@
++
++#
++# This sample code shows you one way to modify your setup to allow automatic
++# configuration of your resolv.conf for peer supplied DNS addresses when using
++# the `usepeerdns' option.
++#
++# In my case I just added this to my /etc/ppp/ip-up.local script. You may need to
++# create an executable script if one does not exist.
++#
++# Nick Walker (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">nickwalker at email.com</A>)
++#
++
++if [ -n &quot;$USEPEERDNS&quot; -a -f /etc/ppp/resolv.conf ]; then
++ rm -f /etc/ppp/resolv.prev
++ if [ -f /etc/resolv.conf ]; then
++ cp /etc/resolv.conf /etc/ppp/resolv.prev
++ grep domain /etc/ppp/resolv.prev &gt; /etc/resolv.conf
++ grep search /etc/ppp/resolv.prev &gt;&gt; /etc/resolv.conf
++ cat /etc/ppp/resolv.conf &gt;&gt; /etc/resolv.conf
++ else
++ cp /etc/ppp/resolv.conf /etc
++ fi
++fi
++
+
+Added: drakx/trunk/mdk-stage1/ppp/scripts/options-rsh-loc
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/scripts/options-rsh-loc (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/scripts/options-rsh-loc 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1 @@
++debug asyncmap FFFFFFFF escape FF kdebug 0 noipdefault nodefaultroute noauth mtu 1460
+
+Added: drakx/trunk/mdk-stage1/ppp/scripts/options-rsh-rem
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/scripts/options-rsh-rem (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/scripts/options-rsh-rem 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1 @@
++notty debug asyncmap FFFFFFFF escape FF kdebug 0 noipdefault nodefaultroute noauth mtu 1460
+
+Added: drakx/trunk/mdk-stage1/ppp/scripts/options-ssh-loc
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/scripts/options-ssh-loc (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/scripts/options-ssh-loc 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1 @@
++debug asyncmap FFFFFFFF escape FF kdebug 0 noipdefault nodefaultroute noauth mtu 1400
+
+Added: drakx/trunk/mdk-stage1/ppp/scripts/options-ssh-rem
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/scripts/options-ssh-rem (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/scripts/options-ssh-rem 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1 @@
++notty debug asyncmap FFFFFFFF escape FF kdebug 0 noipdefault nodefaultroute noauth mtu 1400
+
+Added: drakx/trunk/mdk-stage1/ppp/scripts/ppp-off
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/scripts/ppp-off (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/scripts/ppp-off 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,34 @@
++#!/bin/sh
++######################################################################
++#
++# Determine the device to be terminated.
++#
++if [ &quot;$1&quot; = &quot;&quot; ]; then
++ DEVICE=ppp0
++else
++ DEVICE=$1
++fi
++
++######################################################################
++#
++# If the ppp0 pid file is present then the program is running. Stop it.
++if [ -r /var/run/$DEVICE.pid ]; then
++ kill -INT `cat /var/run/$DEVICE.pid`
++#
++# If the kill did not work then there is no process running for this
++# pid. It may also mean that the lock file will be left. You may wish
++# to delete the lock file at the same time.
++ if [ ! &quot;$?&quot; = &quot;0&quot; ]; then
++ rm -f /var/run/$DEVICE.pid
++ echo &quot;ERROR: Removed stale pid file&quot;
++ exit 1
++ fi
++#
++# Success. Let pppd clean up its own junk.
++ echo &quot;PPP link to $DEVICE terminated.&quot;
++ exit 0
++fi
++#
++# The ppp process is not running for ppp0
++echo &quot;ERROR: PPP link is not active on $DEVICE&quot;
++exit 1
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/scripts/ppp-off
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: drakx/trunk/mdk-stage1/ppp/scripts/ppp-on
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/scripts/ppp-on (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/scripts/ppp-on 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,36 @@
++#!/bin/sh
++#
++# Script to initiate a ppp connection. This is the first part of the
++# pair of scripts. This is not a secure pair of scripts as the codes
++# are visible with the 'ps' command. However, it is simple.
++#
++# These are the parameters. Change as needed.
++TELEPHONE=555-1212 # The telephone number for the connection
++ACCOUNT=george # The account name for logon (as in 'George Burns')
++PASSWORD=gracie # The password for this account (and 'Gracie Allen')
++LOCAL_IP=0.0.0.0 # Local IP address if known. Dynamic = 0.0.0.0
++REMOTE_IP=0.0.0.0 # Remote IP address if desired. Normally 0.0.0.0
++NETMASK=255.255.255.0 # The proper netmask if needed
++#
++# Export them so that they will be available at 'ppp-on-dialer' time.
++export TELEPHONE ACCOUNT PASSWORD
++#
++# This is the location of the script which dials the phone and logs
++# in. Please use the absolute file name as the $PATH variable is not
++# used on the connect option. (To do so on a 'root' account would be
++# a security hole so don't ask.)
++#
++DIALER_SCRIPT=/etc/ppp/ppp-on-dialer
++#
++# Initiate the connection
++#
++# I put most of the common options on this command. Please, don't
++# forget the 'lock' option or some programs such as mgetty will not
++# work. The asyncmap and escape will permit the PPP link to work with
++# a telnet or rlogin connection. You are welcome to make any changes
++# as desired. Don't use the 'defaultroute' option if you currently
++# have a default route to an ethernet gateway.
++#
++exec /usr/sbin/pppd debug lock modem crtscts /dev/ttyS0 38400 \
++ asyncmap 20A0000 escape FF kdebug 0 $LOCAL_IP:$REMOTE_IP \
++ noipdefault netmask $NETMASK defaultroute connect $DIALER_SCRIPT
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/scripts/ppp-on
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: drakx/trunk/mdk-stage1/ppp/scripts/ppp-on-dialer
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/scripts/ppp-on-dialer (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/scripts/ppp-on-dialer 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,17 @@
++#!/bin/sh
++#
++# This is part 2 of the ppp-on script. It will perform the connection
++# protocol for the desired connection.
++#
++exec chat -v \
++ TIMEOUT 3 \
++ ABORT '\nBUSY\r' \
++ ABORT '\nNO ANSWER\r' \
++ ABORT '\nRINGING\r\n\r\nRINGING\r' \
++ '' \rAT \
++ 'OK-+++\c-OK' ATH0 \
++ TIMEOUT 30 \
++ OK ATDT$TELEPHONE \
++ CONNECT '' \
++ ogin:--ogin: $ACCOUNT \
++ assword: $PASSWORD
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/scripts/ppp-on-dialer
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: drakx/trunk/mdk-stage1/ppp/scripts/ppp-on-rsh
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/scripts/ppp-on-rsh (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/scripts/ppp-on-rsh 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,72 @@
++#!/bin/sh
++#
++# A sample script to establish PPP session(s) via rsh
++#
++# Adi Masputra &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">adi.masputra at sun.com</A>&gt;
++# Jan 24, 2000
++#
++
++#
++# You'd definitely want to change the following addresses to suit
++# your network configuration
++#
++LOC_IP=10.0.0.1
++REM_IP=10.0.0.2
++NETMASK=255.255.0.0
++
++export LOC_IP REM_IP
++
++#
++# This is the remote peer where in.rshd is running, either
++# its hostname or IP address
++#
++PPPD_RHOST=myremotehost
++
++#
++# For this example, we assume that pppd on both local and remote
++# machines reside in the same place, /usr/local/bin/pppd
++#
++PPPD_LOC=/usr/local/bin/pppd
++
++#
++# The location of local options file (where rsh client is running).
++# Note that the sample options file included in the distribution
++# may need further customizations, depending on your needs. The 'noauth'
++# option specified in the file is there to simplify the example. In
++# reality, you'd probably want to remove such option.
++#
++PPPD_LOC_OPT=/etc/ppp/options-rsh-loc
++
++#
++# The location of remote options file (where in.rshd daemon is running).
++# Note that the sample options file included in the distribution
++# may need further customizations, depending on your needs. The 'noauth'
++# option specified in the file is there to simplify the example. In
++# reality, you'd probably want to remove such option. Also note that
++# the remote options file need to include the 'notty' option for this
++# to work
++#
++PPPD_REM_OPT=/etc/ppp/options-rsh-rem
++
++#
++# The location of rsh client on the local machine
++#
++RSH_LOC=/bin/rsh
++
++export PPPD_LOC PPPD_LOC_OPT PPPD_REM_OPT PPPD_RHOST RSH_LOC
++
++#
++# Uncomment the following to enable IPv6, note that the IPv6 support
++# needs to be enabled during compilation
++#
++# PPPD_IPV6='+ipv6 ipv6cp-use-ipaddr'
++export PPPD_IPV6
++
++#
++# And execute pppd with the pty option, specifying rsh client as the
++# slave side of the pseduo-tty master/slave pair.
++#
++exec $PPPD_LOC \
++ pty '$RSH_LOC $PPPD_RHOST $PPPD_LOC $REM_IP:$LOC_IP $PPPD_IPV6 file $PPPD_REM_OPT' \
++ $LOC_IP:$REM_IP netmask $NETMASK $PPPD_IPV6 file $PPPD_LOC_OPT
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/scripts/ppp-on-rsh
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: drakx/trunk/mdk-stage1/ppp/scripts/ppp-on-ssh
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/scripts/ppp-on-ssh (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/scripts/ppp-on-ssh 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,76 @@
++#!/bin/sh
++#
++# A sample script to establish PPP session(s) via SSH 1.x
++#
++# Adi Masputra &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">adi.masputra at sun.com</A>&gt;
++# Jan 24, 2000
++#
++
++#
++# You'd definitely want to change the following addresses to suit
++# your network configuration
++#
++LOC_IP=10.0.0.1
++REM_IP=10.0.0.2
++NETMASK=255.255.0.0
++
++export LOC_IP REM_IP
++
++#
++# This is the remote peer where sshd is running, either
++# its hostname or IP address
++#
++PPPD_RHOST=myremotehost
++
++#
++# For this example, we assume that pppd on both local and remote
++# machines reside in the same place, /usr/local/bin/pppd
++#
++PPPD_LOC=/usr/local/bin/pppd
++
++#
++# The location of local options file (where ssh client is running).
++# Note that the sample options file included in the distribution
++# may need further customizations, depending on your needs. The 'noauth'
++# option specified in the file is there to simplify the example, although
++# some may choose to have it there and rely on ssh authentication
++# instead.
++#
++PPPD_LOC_OPT=/etc/ppp/options-ssh-loc
++
++#
++# The location of remote options file (where sshd daemon is running)
++# Note that the sample options file included in the distribution
++# may need further customizations, depending on your needs. The 'noauth'
++# option specified in the file is there to simplify the example, although
++# some may choose to have it there and rely on ssh authentication
++# instead. Also note that the remote options file need to include the 'notty'
++# options for this to work.
++#
++PPPD_REM_OPT=/etc/ppp/options-ssh-rem
++
++#
++# The location of ssh client on the local machine
++#
++SSH_LOC=/usr/local/bin/ssh
++
++export PPPD_LOC PPPD_LOC_OPT PPPD_REM_OPT PPPD_RHOST SSH_LOC
++
++#
++# Uncomment the following to enable IPv6, note that the IPv6 support
++# needs to be enabled during compilation
++#
++# PPPD_IPV6='+ipv6 ipv6cp-use-ipaddr'
++export PPPD_IPV6
++
++#
++# And execute pppd with the pty option, specifying ssh client as the
++# slave side of the pseudo-tty master/slave pair. Note that on this example,
++# ssh has been compiled to allow NULL encryption (thus the '-c none' option),
++# but in reality, you'd probably want to specify the encryption algorithm.
++# See the man page of ssh(1) for details.
++#
++exec $PPPD_LOC \
++ pty '$SSH_LOC -c none $PPPD_RHOST $PPPD_LOC $REM_IP:$LOC_IP $PPPD_IPV6 file $PPPD_REM_OPT' \
++ $LOC_IP:$REM_IP netmask $NETMASK $PPPD_IPV6 file $PPPD_LOC_OPT
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/scripts/ppp-on-ssh
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: drakx/trunk/mdk-stage1/ppp/scripts/redialer
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/scripts/redialer (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/scripts/redialer 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,96 @@
++#!/bin/sh
++###################################################################
++#
++# These parameters control the attack dialing sequence.
++#
++# Maximum number of attempts to reach the telephone number(s)
++MAX_ATTEMPTS=10
++
++# Delay between each of the attempts. This is a parameter to sleep
++# so use &quot;15s&quot; for 15 seconds, &quot;1m&quot; for 1 minute, etc.
++SLEEP_DELAY=15s
++
++###################################################################
++#
++# This is a list of telephone numbers. Add new numbers if you wish
++# and see the function 'callall' below for the dial process.
++PHONE1=555-1212
++PHONE2=411
++
++###################################################################
++#
++# If you use the ppp-on script, then these are passed to this routine
++# automatically. There is no need to define them here. If not, then
++# you will need to set the values.
++#
++ACCOUNT=my_account_name
++PASSWORD=my_password
++
++###################################################################
++#
++# Function to initialize the modem and ensure that it is in command
++# state. This may not be needed, but it doesn't hurt.
++#
++function initialize
++{
++ chat -v TIMEOUT 3 '' AT 'OK-+++\c-OK'
++ return
++}
++
++###################################################################
++#
++# Script to dial a telephone
++#
++function callnumber
++{
++chat -v \
++ ABORT '\nBUSY\r' \
++ ABORT '\nNO ANSWER\r' \
++ ABORT '\nRINGING\r\n\r\nRINGING\r' \
++ '' ATDT$1 \
++ CONNECT '' \
++ ogin:--ogin: $ACCOUNT \
++ assword: $PASSWORD
++#
++# If the connection was successful then end the whole script with a
++# success.
++#
++ if [ &quot;$?&quot; = &quot;0&quot; ]; then
++ exit 0
++ fi
++
++ return
++}
++
++###################################################################
++#
++# Script to dial any telephone number
++#
++function callall
++{
++# echo &quot;dialing attempt number: $1&quot; &gt;/dev/console
++ callnumber $PHONE1
++# callnumber $PHONE2
++}
++
++###################################################################
++#
++# Initialize the modem to ensure that it is in the command state
++#
++initialize
++if [ ! &quot;$?&quot; = &quot;0&quot; ]; then
++ exit 1
++fi
++
++#
++# Dial telephone numbers until one answers
++#
++attempt=0
++while : ; do
++ attempt=`expr $attempt + 1`
++ callall $attempt
++ if [ &quot;$attempt&quot; = &quot;$MAX_ATTEMPTS&quot; ]; then
++ exit 1
++ fi
++ sleep &quot;$SLEEP_DELAY&quot;
++done
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/scripts/redialer
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: drakx/trunk/mdk-stage1/ppp/scripts/secure-card
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/scripts/secure-card (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/scripts/secure-card 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,111 @@
++#!/usr/local/bin/expect -f
++#
++# This script was written by Jim Isaacson &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">jcisaac at crl.com</A>&gt;. It is
++# designed to work as a script to use the SecureCARD(tm) device. This
++# little device is mated with a central controller. The number displayed
++# on this card changes every so often and you need to enter the number
++# along with your user account name in order to gain access. Since chat
++# is based upon fixed strings this procedure will not work with chat.
++#
++# It is included by permission. An excellent reference for the expect
++# program used by this script is in the book:
++#
++# &quot;Exploring Expect&quot;
++# by Don Libes
++# Published by O'Rielly and Associates
++#
++
++send_user &quot;hello, starting ppp\n&quot;
++
++system &quot;stty 19200 -echoe -echo raw &lt; /dev/cua3 &gt; /dev/cua3&quot;
++
++#
++# These are the parameters for the program.
++#
++set user Pxxxxxx
++set password xxxxxxx
++set modem /dev/cua3
++set dialup &lt;put phone number here&gt;
++set timeout 60
++
++spawn -noecho -open [open $modem &quot;r+&quot;]
++
++send &quot;AT&amp;F\r&quot;
++expect &quot;OK&quot;
++
++send &quot;ATe0v1x4&amp;c1q0&amp;d2&amp;c1s2=128s0=0DT $dialup\r&quot;
++set timeout 15
++set counter 0
++
++set still_connecting 1
++
++expect {
++ -re &quot;.*CONNECT.*\n&quot; {
++ set timeout 5
++ set still_connecting 0
++ continue -expect
++ }
++ -re &quot;.*CONNECT.*\r&quot; {
++ set timeout 5
++ set still_connecting 0
++ continue -expect
++ }
++ -re &quot;.*NO.*CARRIER&quot; {
++ send_user &quot;Failed to Connect, exiting...\n&quot;
++ exit
++ }
++ -re &quot;.*NO.*DIAL.*TONE&quot; {
++ send_user &quot;Failed to Connect, exiting...\n&quot;
++ exit
++ }
++ -re &quot;.*VOICE&quot; {
++ send_user &quot;Failed to Connect, exiting...\n&quot;
++ exit
++ }
++ -re &quot;.*sscode:.*\n&quot; {
++ continue -expect
++ }
++ -re &quot;.*sscode:&quot; {
++ set timeout -1
++ expect_user -re &quot;(.*)\n&quot;
++ send &quot;$expect_out(1,string)\r&quot;
++ set timeout 30
++ continue -expect
++ }
++ -re &quot;.*Next.*:&quot; {
++ set timeout -1
++ expect_user -re &quot;(.*)\n&quot;
++ send &quot;$expect_out(1,string)\r&quot;
++ set timeout 30
++ continue -expect
++ }
++ -re &quot;Your.*&quot; {
++ send &quot;\r&quot;
++ continue -expect
++ }
++ -re &quot;.*in:&quot; {
++ send &quot;$user\r&quot;
++ continue -expect
++ }
++ -re &quot;.*word:&quot; {
++ send &quot;$password\r&quot;
++ }
++
++ timeout {
++ if { $still_connecting &gt; 0 } {
++ continue -expect
++ }
++ set timeout 15
++ send &quot;\r&quot;
++ incr counter
++ if { $counter &gt; 8 } {
++ send_user &quot;Cannot Connect\n&quot;
++ exit
++ } else {
++ continue -expect
++ }
++ }
++}
++
++overlay -0 $spawn_id -1 $spawn_id pppd /dev/cua3 19200 192.111.187.215: \
++ crtscts modem defaultroute debug
+
+Added: drakx/trunk/mdk-stage1/ppp/solaris/Makedefs
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/solaris/Makedefs (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/solaris/Makedefs 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,16 @@
++#
++# defines common to several Makefiles
++#
++
++INSTALL= /usr/sbin/install
++
++BINDIR = /usr/local/bin
++MANDIR = /usr/local/man
++ETCDIR = /etc/ppp
++
++COPTS = -O -Xa
++
++# For compiling with gcc, comment out the COPTS definition above and
++# uncomment the next 2 definitions.
++#CC = gcc
++#COPTS = -O2
+
+Added: drakx/trunk/mdk-stage1/ppp/solaris/Makedefs.sol2
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/solaris/Makedefs.sol2 (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/solaris/Makedefs.sol2 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,59 @@
++#
++# Generic make definitions for Solaris 2
++#
++# $Id: Makedefs.sol2 195720 2001-06-11 11:44:34Z gc $
++#
++
++include ../solaris/Makedefs
++
++CPPFLAGS = -D_KERNEL -DSVR4 -DSOL2 -DPRIOQ -DDEBUG -I../include
++CFLAGS = $(CPPFLAGS) $(COPTS)
++
++# lint-specific variables
++LINT = lint
++LINT_OPT_32 =
++LINT_OPT_64 = -Xarch=v9 -errchk=longptr64
++
++LINT_32 =
++LINT_32 += -erroff=E_BAD_PTR_CAST_ALIGN
++LINT_32 += -erroff=E_SUPPRESSION_DIRECTIVE_UNUSED
++LINT_32 += -erroff=E_SUSPICIOUS_COMPARISON
++LINT_32 += -erroff=E_CAST_UINT_TO_SIGNED_INT
++LINT_32 += -erroff=E_PASS_UINT_TO_SIGNED_INT
++LINT_32 += -erroff=E_INVALID_ANNOTATION_NAME
++LINT_32 += -erroff=E_FUNC_ARG_UNUSED
++# This might be needed, but zlib.c and vjcompress.c will squawk
++# when not ignored
++LINT_32 += -erroff=E_CASE_FALLTHRU
++LINT_32 += -erroff=E_RET_INT_IMPLICITLY
++LINT_32 += -erroff=E_FUNC_NO_RET_VAL
++# Some STREAMS macros will be noisy too when this isn't ignored
++LINT_32 += -erroff=E_CONSTANT_CONDITION
++LINT_32 += -erroff=E_CONST_EXPR
++
++# Extra noise suppressant for 64-bit
++EXTRA_OFF =
++EXTRA_OFF += -erroff=E_CAST_INT_TO_SMALL_INT
++EXTRA_OFF += -erroff=E_CAST_INT_CONST_TO_SMALL_INT
++EXTRA_OFF += -erroff=E_CAST_TO_PTR_FROM_INT
++EXTRA_OFF += -erroff=E_ASSIGN_INT_TO_SMALL_INT
++EXTRA_OFF += -erroff=E_ASSIGN_INT_FROM_BIG_CONST
++EXTRA_OFF += -erroff=E_CONST_PROMOTED_UNSIGNED_LL
++EXTRA_OFF += -erroff=E_CONST_PROMOTED_LONG_LONG
++EXTRA_OFF += -erroff=E_CONST_TRUNCATED_BY_ASSIGN
++EXTRA_OFF += -erroff=E_PASS_INT_FROM_BIG_CONST
++EXTRA_OFF += -erroff=E_COMP_INT_WITH_LARGE_INT
++EXTRA_OFF += -erroff=E_ASSIGN_UINT_TO_SIGNED_INT
++EXTRA_OFF += -erroff=E_ASSIGN_NARROW_CONV
++EXTRA_OFF += -erroff=E_PASS_INT_TO_SMALL_INT
++EXTRA_OFF += -erroff=E_PTR_CONV_LOSES_BITS
++
++LINT_64 = $(LINT_32)
++LINT_64 += $(EXTRA_OFF)
++
++LINTFLAGS64 = -Xa -nsxmuF -errtags=yes $(LINT_OPT_64) $(LINT_64)
++LINT64 = $(LINT) -c $(LINTFLAGS64) $(CPPFLAGS)
++
++LINTFLAGS32 = -Xa -nsxmuF -errtags=yes $(LINT_OPT_32) $(LINT_32)
++LINT32 = $(LINT) -c $(LINTFLAGS32) $(CPPFLAGS)
++
+
+Added: drakx/trunk/mdk-stage1/ppp/solaris/Makefile.sol2
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/solaris/Makefile.sol2 (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/solaris/Makefile.sol2 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,66 @@
++#
++# Makefile for STREAMS modules for Solaris 2.
++#
++# $Id: Makefile.sol2 195720 2001-06-11 11:44:34Z gc $
++#
++
++include Makedefs.sol2
++
++COPTS += -xO2 -xspace -W0,-Lt
++
++COMP_OBJS = ppp_comp.o bsd-comp.o deflate.o zlib.o vjcompress.o \
++ ppp_comp_mod.o
++
++all: ppp ppp_ahdl ppp_comp
++
++ppp: ppp.o ppp_mod.o
++ ld -r -o $@ ppp.o ppp_mod.o
++ chmod +x $@
++
++ppp_ahdl: ppp_ahdlc.o ppp_ahdlc_mod.o
++ ld -r -o $@ ppp_ahdlc.o ppp_ahdlc_mod.o
++ chmod +x $@
++
++ppp_comp: $(COMP_OBJS)
++ ld -r -o $@ $(COMP_OBJS)
++ chmod +x $@
++
++bsd-comp.o: ../modules/bsd-comp.c
++ $(CC) $(CFLAGS) -c $?
++deflate.o: ../modules/deflate.c
++ $(CC) $(CFLAGS) -c $?
++ppp.o: ppp.c
++ $(CC) $(CFLAGS) -c $?
++ppp_mod.o: ppp_mod.c
++ $(CC) $(CFLAGS) -c $?
++ppp_ahdlc_mod.o: ppp_ahdlc_mod.c
++ $(CC) $(CFLAGS) -c $?
++ppp_ahdlc.o: ppp_ahdlc.c
++ $(CC) $(CFLAGS) -c $?
++ppp_comp.o: ppp_comp.c
++ $(CC) $(CFLAGS) -c $?
++ppp_comp_mod.o: ppp_comp_mod.c
++ $(CC) $(CFLAGS) -c $?
++vjcompress.o: ../modules/vjcompress.c
++ $(CC) $(CFLAGS) -c $?
++zlib.o: ../common/zlib.c
++ $(CC) $(CFLAGS) -c $?
++
++install:
++ cp ppp ppp.conf /kernel/drv
++ cp ppp_comp ppp_ahdl /kernel/strmod
++ if grep clone:ppp /etc/minor_perm; then :; else \
++ echo clone:ppp 0644 root sys &gt;&gt;/etc/minor_perm; fi
++ /usr/sbin/rem_drv ppp 2&gt;/dev/null || true
++ /usr/sbin/add_drv ppp
++
++SRCS = ppp.c ppp_mod.c ppp_ahdlc.c ppp_ahdlc_mod.c \
++ ppp_comp.c ../modules/bsd-comp.c ../modules/deflate.c \
++ ../common/zlib.c ../modules/vjcompress.c ppp_comp_mod.c
++
++lint:
++ $(LINT32) $(SRCS)
++
++clean:
++ rm -f ppp ppp_comp ppp_ahdl *.o *~ core
++ rm -f *.ln
+
+Added: drakx/trunk/mdk-stage1/ppp/solaris/Makefile.sol2-64
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/solaris/Makefile.sol2-64 (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/solaris/Makefile.sol2-64 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,85 @@
++#
++# Makefile for 64-bit STREAMS modules for Solaris 2.
++#
++# $Id: Makefile.sol2-64 195720 2001-06-11 11:44:34Z gc $
++#
++
++include Makedefs.sol2
++
++# Sun's cc flag for LP64 compilation / linkage
++COPTS += -xchip=ultra -xarch=v9 -Wc,-xcode=abs32 -Wc,-Qiselect-regsym=0 -xO3 -xspace -W0,-Lt
++
++# subdirectory where 64-bit objects / binaries will be placed
++LP64DIR = sparcv9
++
++# Name of legacy Makefile (for 32-bit binaries)
++STD_MAKE = Makefile.sol2
++
++COMP_OBJS = $(LP64DIR)/ppp_comp.o $(LP64DIR)/bsd-comp.o \
++ $(LP64DIR)/deflate.o $(LP64DIR)/zlib.o $(LP64DIR)/vjcompress.o \
++ $(LP64DIR)/ppp_comp_mod.o
++
++all: std_objs $(LP64DIR) ppp ppp_ahdl ppp_comp
++
++std_objs:
++ $(MAKE) -f $(STD_MAKE) all
++
++ppp: $(LP64DIR)/ppp.o $(LP64DIR)/ppp_mod.o
++ ld -r -o $(LP64DIR)/$@ $(LP64DIR)/ppp.o $(LP64DIR)/ppp_mod.o
++ chmod +x $(LP64DIR)/$@
++
++ppp_ahdl: $(LP64DIR)/ppp_ahdlc.o $(LP64DIR)/ppp_ahdlc_mod.o
++ ld -r -o $(LP64DIR)/$@ $(LP64DIR)/ppp_ahdlc.o $(LP64DIR)/ppp_ahdlc_mod.o
++ chmod +x $(LP64DIR)/$@
++
++ppp_comp: $(COMP_OBJS)
++ ld -r -o $(LP64DIR)/$@ $(COMP_OBJS)
++ chmod +x $(LP64DIR)/$@
++
++$(LP64DIR)/bsd-comp.o: ../modules/bsd-comp.c
++ $(CC) $(CFLAGS) -c $? -o $@
++$(LP64DIR)/deflate.o: ../modules/deflate.c
++ $(CC) $(CFLAGS) -c $? -o $@
++$(LP64DIR)/ppp.o: ppp.c
++ $(CC) $(CFLAGS) -c $? -o $@
++$(LP64DIR)/ppp_mod.o: ppp_mod.c
++ $(CC) $(CFLAGS) -c $? -o $@
++$(LP64DIR)/ppp_ahdlc_mod.o: ppp_ahdlc_mod.c
++ $(CC) $(CFLAGS) -c $? -o $@
++$(LP64DIR)/ppp_ahdlc.o: ppp_ahdlc.c
++ $(CC) $(CFLAGS) -c $? -o $@
++$(LP64DIR)/ppp_comp.o: ppp_comp.c
++ $(CC) $(CFLAGS) -c $? -o $@
++$(LP64DIR)/ppp_comp_mod.o: ppp_comp_mod.c
++ $(CC) $(CFLAGS) -c $? -o $@
++$(LP64DIR)/vjcompress.o: ../modules/vjcompress.c
++ $(CC) $(CFLAGS) -c $? -o $@
++$(LP64DIR)/zlib.o: ../common/zlib.c
++ $(CC) $(CFLAGS) -c $? -o $@
++
++$(LP64DIR):
++ mkdir -m 755 -p $@
++
++install:
++ cp ppp ppp.conf /kernel/drv
++ cp ppp_comp ppp_ahdl /kernel/strmod
++ cp $(LP64DIR)/ppp /kernel/drv/$(LP64DIR)
++ cp $(LP64DIR)/ppp_comp $(LP64DIR)/ppp_ahdl /kernel/strmod/$(LP64DIR)
++ if grep clone:ppp /etc/minor_perm; then :; else \
++ echo clone:ppp 0644 root sys &gt;&gt;/etc/minor_perm; fi
++ /usr/sbin/rem_drv ppp 2&gt;/dev/null || true
++ /usr/sbin/add_drv ppp
++
++SRCS = ppp.c ppp_mod.c ppp_ahdlc.c ppp_ahdlc_mod.c \
++ ppp_comp.c ../modules/bsd-comp.c ../modules/deflate.c \
++ ../common/zlib.c ../modules/vjcompress.c ppp_comp_mod.c
++
++lint:
++ $(LINT64) $(SRCS)
++
++lint-32:
++ $(LINT32) $(SRCS)
++
++clean:
++ $(MAKE) -f $(STD_MAKE) clean
++ rm -f $(LP64DIR)/ppp $(LP64DIR)/ppp_comp $(LP64DIR)/ppp_ahdl $(LP64DIR)/*.o $(LP64DIR)/*~ $(LP64DIR)/core
+
+Added: drakx/trunk/mdk-stage1/ppp/solaris/Makefile.top
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/solaris/Makefile.top (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/solaris/Makefile.top 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,50 @@
++#
++# ppp top level makefile for SVR4 and Solaris 2
++#
++# $Id: Makefile.top 195720 2001-06-11 11:44:34Z gc $
++#
++
++include solaris/Makedefs
++
++all:
++ cd chat; $(MAKE) all
++ cd pppd; $(MAKE) all
++ cd pppstats; $(MAKE) all
++ cd pppdump; $(MAKE) all
++ cd solaris; $(MAKE) all
++
++install: $(BINDIR) $(MANDIR)/man8 install-progs install-etcppp
++
++install-progs:
++ cd chat; $(MAKE) install
++ cd pppd; $(MAKE) install
++ cd pppstats; $(MAKE) install
++ cd pppdump; $(MAKE) install
++ cd solaris; $(MAKE) install
++
++install-etcppp: $(ETCDIR) $(ETCDIR)/options $(ETCDIR)/pap-secrets \
++ $(ETCDIR)/chap-secrets
++
++$(ETCDIR)/options:
++ cp etc.ppp/options $@
++ chmod go-w $@
++$(ETCDIR)/pap-secrets:
++ $(INSTALL) -f $(ETCDIR) -m 600 etc.ppp/pap-secrets
++$(ETCDIR)/chap-secrets:
++ $(INSTALL) -f $(ETCDIR) -m 600 etc.ppp/chap-secrets
++
++$(BINDIR):
++ mkdir -m 755 -p $@
++$(MANDIR)/man8:
++ mkdir -m 755 -p $@
++$(ETCDIR):
++ mkdir -m 755 -p $@
++
++clean:
++ rm -f *~
++ cd chat; $(MAKE) clean
++ cd pppd; $(MAKE) clean
++ cd pppstats; $(MAKE) clean
++ cd pppdump; $(MAKE) clean
++ cd solaris; $(MAKE) clean
++
+
+Added: drakx/trunk/mdk-stage1/ppp/solaris/ppp.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/solaris/ppp.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/solaris/ppp.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,2486 @@
++/*
++ * ppp.c - STREAMS multiplexing pseudo-device driver for PPP.
++ *
++ * Copyright (c) 1994 The Australian National University.
++ * All rights reserved.
++ *
++ * Permission to use, copy, modify, and distribute this software and its
++ * documentation is hereby granted, provided that the above copyright
++ * notice appears in all copies. This software is provided without any
++ * warranty, express or implied. The Australian National University
++ * makes no representations about the suitability of this software for
++ * any purpose.
++ *
++ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
++ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
++ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
++ * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
++ * OF SUCH DAMAGE.
++ *
++ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
++ * ON AN &quot;AS IS&quot; BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
++ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
++ * OR MODIFICATIONS.
++ *
++ * $Id: ppp.c 195720 2001-06-11 11:44:34Z gc $
++ */
++
++/*
++ * This file is used under Solaris 2, SVR4, SunOS 4, and Digital UNIX.
++ */
++
++#include &lt;sys/types.h&gt;
++#include &lt;sys/param.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;sys/stream.h&gt;
++#include &lt;sys/stropts.h&gt;
++#include &lt;sys/errno.h&gt;
++#ifdef __osf__
++#include &lt;sys/ioctl.h&gt;
++#include &lt;sys/cmn_err.h&gt;
++#define queclass(mp) ((mp)-&gt;b_band &amp; QPCTL)
++#else
++#include &lt;sys/ioccom.h&gt;
++#endif
++#include &lt;sys/time.h&gt;
++#ifdef SVR4
++#include &lt;sys/cmn_err.h&gt;
++#include &lt;sys/conf.h&gt;
++#include &lt;sys/dlpi.h&gt;
++#include &lt;sys/ddi.h&gt;
++#ifdef SOL2
++#include &lt;sys/ksynch.h&gt;
++#include &lt;sys/kstat.h&gt;
++#include &lt;sys/sunddi.h&gt;
++#include &lt;sys/ethernet.h&gt;
++#else
++#include &lt;sys/socket.h&gt;
++#include &lt;sys/sockio.h&gt;
++#include &lt;net/if.h&gt;
++#include &lt;netinet/in.h&gt;
++#endif /* SOL2 */
++#else /* not SVR4 */
++#include &lt;sys/user.h&gt;
++#endif /* SVR4 */
++#include &lt;net/ppp_defs.h&gt;
++#include &lt;net/pppio.h&gt;
++#include &quot;ppp_mod.h&quot;
++
++/*
++ * Modifications marked with #ifdef PRIOQ are for priority queueing of
++ * interactive traffic, and are due to Marko Zec &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">zec at japa.tel.fer.hr</A>&gt;.
++ */
++#ifdef PRIOQ
++#endif /* PRIOQ */
++
++#include &lt;netinet/in.h&gt; /* leave this outside of PRIOQ for htons */
++
++#ifdef __STDC__
++#define __P(x) x
++#else
++#define __P(x) ()
++#endif
++
++/*
++ * The IP module may use this SAP value for IP packets.
++ */
++#ifndef ETHERTYPE_IP
++#define ETHERTYPE_IP 0x800
++#endif
++
++#if !defined(ETHERTYPE_IPV6)
++#define ETHERTYPE_IPV6 0x86dd
++#endif /* !defined(ETHERTYPE_IPV6) */
++
++#if !defined(ETHERTYPE_ALLSAP) &amp;&amp; defined(SOL2)
++#define ETHERTYPE_ALLSAP 0
++#endif /* !defined(ETHERTYPE_ALLSAP) &amp;&amp; defined(SOL2) */
++
++#if !defined(PPP_ALLSAP) &amp;&amp; defined(SOL2)
++#define PPP_ALLSAP PPP_ALLSTATIONS
++#endif /* !defined(PPP_ALLSAP) &amp;&amp; defined(SOL2) */
++
++extern time_t time;
++
++#ifdef SOL2
++/*
++ * We use this reader-writer lock to ensure that the lower streams
++ * stay connected to the upper streams while the lower-side put and
++ * service procedures are running. Essentially it is an existence
++ * lock for the upper stream associated with each lower stream.
++ */
++krwlock_t ppp_lower_lock;
++#define LOCK_LOWER_W rw_enter(&amp;ppp_lower_lock, RW_WRITER)
++#define LOCK_LOWER_R rw_enter(&amp;ppp_lower_lock, RW_READER)
++#define TRYLOCK_LOWER_R rw_tryenter(&amp;ppp_lower_lock, RW_READER)
++#define UNLOCK_LOWER rw_exit(&amp;ppp_lower_lock)
++
++#define MT_ENTER(x) mutex_enter(x)
++#define MT_EXIT(x) mutex_exit(x)
++
++/*
++ * Notes on multithreaded implementation for Solaris 2:
++ *
++ * We use an inner perimeter around each queue pair and an outer
++ * perimeter around the whole driver. The inner perimeter is
++ * entered exclusively for all entry points (open, close, put,
++ * service). The outer perimeter is entered exclusively for open
++ * and close and shared for put and service. This is all done for
++ * us by the streams framework.
++ *
++ * I used to think that the perimeters were entered for the lower
++ * streams' put and service routines as well as for the upper streams'.
++ * Because of problems experienced by people, and after reading the
++ * documentation more closely, I now don't think that is true. So we
++ * now use ppp_lower_lock to give us an existence guarantee on the
++ * upper stream controlling each lower stream.
++ *
++ * Shared entry to the outer perimeter protects the existence of all
++ * the upper streams and their upperstr_t structures, and guarantees
++ * that the following fields of any upperstr_t won't change:
++ * nextmn, next, nextppa. It guarantees that the lowerq field of an
++ * upperstr_t won't go from non-zero to zero, that the global `ppas'
++ * won't change and that the no lower stream will get unlinked.
++ *
++ * Shared (reader) access to ppa_lower_lock guarantees that no lower
++ * stream will be unlinked and that the lowerq field of all upperstr_t
++ * structures won't change.
++ */
++
++#else /* SOL2 */
++#define LOCK_LOWER_W 0
++#define LOCK_LOWER_R 0
++#define TRYLOCK_LOWER_R 1
++#define UNLOCK_LOWER 0
++#define MT_ENTER(x) 0
++#define MT_EXIT(x) 0
++
++#endif /* SOL2 */
++
++/*
++ * Private information; one per upper stream.
++ */
++typedef struct upperstr {
++ minor_t mn; /* minor device number */
++ struct upperstr *nextmn; /* next minor device */
++ queue_t *q; /* read q associated with this upper stream */
++ int flags; /* flag bits, see below */
++ int state; /* current DLPI state */
++ int sap; /* service access point */
++ int req_sap; /* which SAP the DLPI client requested */
++ struct upperstr *ppa; /* control stream for our ppa */
++ struct upperstr *next; /* next stream for this ppa */
++ uint ioc_id; /* last ioctl ID for this stream */
++ enum NPmode npmode; /* what to do with packets on this SAP */
++ unsigned char rblocked; /* flow control has blocked upper read strm */
++ /* N.B. rblocked is only changed by control stream's put/srv procs */
++ /*
++ * There is exactly one control stream for each PPA.
++ * The following fields are only used for control streams.
++ */
++ int ppa_id;
++ queue_t *lowerq; /* write queue attached below this PPA */
++ struct upperstr *nextppa; /* next control stream */
++ int mru;
++ int mtu;
++ struct pppstat stats; /* statistics */
++ time_t last_sent; /* time last NP packet sent */
++ time_t last_recv; /* time last NP packet rcvd */
++#ifdef SOL2
++ kmutex_t stats_lock; /* lock for stats updates */
++ kstat_t *kstats; /* stats for netstat */
++#endif /* SOL2 */
++#ifdef LACHTCP
++ int ifflags;
++ char ifname[IFNAMSIZ];
++ struct ifstats ifstats;
++#endif /* LACHTCP */
++} upperstr_t;
++
++/* Values for flags */
++#define US_PRIV 1 /* stream was opened by superuser */
++#define US_CONTROL 2 /* stream is a control stream */
++#define US_BLOCKED 4 /* flow ctrl has blocked lower write stream */
++#define US_LASTMOD 8 /* no PPP modules below us */
++#define US_DBGLOG 0x10 /* log various occurrences */
++#define US_RBLOCKED 0x20 /* flow ctrl has blocked upper read stream */
++
++#if defined(SOL2)
++#if DL_CURRENT_VERSION &gt;= 2
++#define US_PROMISC 0x40 /* stream is promiscuous */
++#endif /* DL_CURRENT_VERSION &gt;= 2 */
++#define US_RAWDATA 0x80 /* raw M_DATA, no DLPI header */
++#endif /* defined(SOL2) */
++
++#ifdef PRIOQ
++static u_char max_band=0;
++static u_char def_band=0;
++
++#define IPPORT_DEFAULT 65535
++
++/*
++ * Port priority table
++ * Highest priority ports are listed first, lowest are listed last.
++ * ICMP &amp; packets using unlisted ports will be treated as &quot;default&quot;.
++ * If IPPORT_DEFAULT is not listed here, &quot;default&quot; packets will be
++ * assigned lowest priority.
++ * Each line should be terminated with &quot;0&quot;.
++ * Line containing only &quot;0&quot; marks the end of the list.
++ */
++
++static u_short prioq_table[]= {
++ 113, 53, 0,
++ 22, 23, 513, 517, 518, 0,
++ 514, 21, 79, 111, 0,
++ 25, 109, 110, 0,
++ IPPORT_DEFAULT, 0,
++ 20, 70, 80, 8001, 8008, 8080, 0, /* 8001,8008,8080 - common proxy ports */
++0 };
++
++#endif /* PRIOQ */
++
++
++static upperstr_t *minor_devs = NULL;
++static upperstr_t *ppas = NULL;
++
++#ifdef SVR4
++static int pppopen __P((queue_t *, dev_t *, int, int, cred_t *));
++static int pppclose __P((queue_t *, int, cred_t *));
++#else
++static int pppopen __P((queue_t *, int, int, int));
++static int pppclose __P((queue_t *, int));
++#endif /* SVR4 */
++static int pppurput __P((queue_t *, mblk_t *));
++static int pppuwput __P((queue_t *, mblk_t *));
++static int pppursrv __P((queue_t *));
++static int pppuwsrv __P((queue_t *));
++static int ppplrput __P((queue_t *, mblk_t *));
++static int ppplwput __P((queue_t *, mblk_t *));
++static int ppplrsrv __P((queue_t *));
++static int ppplwsrv __P((queue_t *));
++#ifndef NO_DLPI
++static void dlpi_request __P((queue_t *, mblk_t *, upperstr_t *));
++static void dlpi_error __P((queue_t *, upperstr_t *, int, int, int));
++static void dlpi_ok __P((queue_t *, int));
++#endif
++static int send_data __P((mblk_t *, upperstr_t *));
++static void new_ppa __P((queue_t *, mblk_t *));
++static void attach_ppa __P((queue_t *, mblk_t *));
++static void detach_ppa __P((queue_t *, mblk_t *));
++static void detach_lower __P((queue_t *, mblk_t *));
++static void debug_dump __P((queue_t *, mblk_t *));
++static upperstr_t *find_dest __P((upperstr_t *, int));
++#if defined(SOL2)
++static upperstr_t *find_promisc __P((upperstr_t *, int));
++static mblk_t *prepend_ether __P((upperstr_t *, mblk_t *, int));
++static mblk_t *prepend_udind __P((upperstr_t *, mblk_t *, int));
++static void promisc_sendup __P((upperstr_t *, mblk_t *, int, int));
++#endif /* defined(SOL2) */
++static int putctl2 __P((queue_t *, int, int, int));
++static int putctl4 __P((queue_t *, int, int, int));
++static int pass_packet __P((upperstr_t *ppa, mblk_t *mp, int outbound));
++#ifdef FILTER_PACKETS
++static int ip_hard_filter __P((upperstr_t *ppa, mblk_t *mp, int outbound));
++#endif /* FILTER_PACKETS */
++
++#define PPP_ID 0xb1a6
++static struct module_info ppp_info = {
++#ifdef PRIOQ
++ PPP_ID, &quot;ppp&quot;, 0, 512, 512, 384
++#else
++ PPP_ID, &quot;ppp&quot;, 0, 512, 512, 128
++#endif /* PRIOQ */
++};
++
++static struct qinit pppurint = {
++ pppurput, pppursrv, pppopen, pppclose, NULL, &amp;ppp_info, NULL
++};
++
++static struct qinit pppuwint = {
++ pppuwput, pppuwsrv, NULL, NULL, NULL, &amp;ppp_info, NULL
++};
++
++static struct qinit ppplrint = {
++ ppplrput, ppplrsrv, NULL, NULL, NULL, &amp;ppp_info, NULL
++};
++
++static struct qinit ppplwint = {
++ ppplwput, ppplwsrv, NULL, NULL, NULL, &amp;ppp_info, NULL
++};
++
++#ifdef LACHTCP
++extern struct ifstats *ifstats;
++int pppdevflag = 0;
++#endif
++
++struct streamtab pppinfo = {
++ &amp;pppurint, &amp;pppuwint,
++ &amp;ppplrint, &amp;ppplwint
++};
++
++int ppp_count;
++
++/*
++ * How we maintain statistics.
++ */
++#ifdef SOL2
++#define INCR_IPACKETS(ppa) \
++ if (ppa-&gt;kstats != 0) { \
++ KSTAT_NAMED_PTR(ppa-&gt;kstats)[0].value.ul++; \
++ }
++#define INCR_IERRORS(ppa) \
++ if (ppa-&gt;kstats != 0) { \
++ KSTAT_NAMED_PTR(ppa-&gt;kstats)[1].value.ul++; \
++ }
++#define INCR_OPACKETS(ppa) \
++ if (ppa-&gt;kstats != 0) { \
++ KSTAT_NAMED_PTR(ppa-&gt;kstats)[2].value.ul++; \
++ }
++#define INCR_OERRORS(ppa) \
++ if (ppa-&gt;kstats != 0) { \
++ KSTAT_NAMED_PTR(ppa-&gt;kstats)[3].value.ul++; \
++ }
++#endif
++
++#ifdef LACHTCP
++#define INCR_IPACKETS(ppa) ppa-&gt;ifstats.ifs_ipackets++;
++#define INCR_IERRORS(ppa) ppa-&gt;ifstats.ifs_ierrors++;
++#define INCR_OPACKETS(ppa) ppa-&gt;ifstats.ifs_opackets++;
++#define INCR_OERRORS(ppa) ppa-&gt;ifstats.ifs_oerrors++;
++#endif
++
++/*
++ * STREAMS driver entry points.
++ */
++static int
++#ifdef SVR4
++pppopen(q, devp, oflag, sflag, credp)
++ queue_t *q;
++ dev_t *devp;
++ int oflag, sflag;
++ cred_t *credp;
++#else
++pppopen(q, dev, oflag, sflag)
++ queue_t *q;
++ int dev; /* really dev_t */
++ int oflag, sflag;
++#endif
++{
++ upperstr_t *up;
++ upperstr_t **prevp;
++ minor_t mn;
++#ifdef PRIOQ
++ u_short *ptr;
++ u_char new_band;
++#endif /* PRIOQ */
++
++ if (q-&gt;q_ptr)
++ DRV_OPEN_OK(dev); /* device is already open */
++
++#ifdef PRIOQ
++ /* Calculate max_bband &amp; def_band from definitions in prioq.h
++ This colud be done at some more approtiate time (less often)
++ but this way it works well so I'll just leave it here */
++
++ max_band = 1;
++ def_band = 0;
++ ptr = prioq_table;
++ while (*ptr) {
++ new_band = 1;
++ while (*ptr)
++ if (*ptr++ == IPPORT_DEFAULT) {
++ new_band = 0;
++ def_band = max_band;
++ }
++ max_band += new_band;
++ ptr++;
++ }
++ if (def_band)
++ def_band = max_band - def_band;
++ --max_band;
++#endif /* PRIOQ */
++
++ if (sflag == CLONEOPEN) {
++ mn = 0;
++ for (prevp = &amp;minor_devs; (up = *prevp) != 0; prevp = &amp;up-&gt;nextmn) {
++ if (up-&gt;mn != mn)
++ break;
++ ++mn;
++ }
++ } else {
++#ifdef SVR4
++ mn = getminor(*devp);
++#else
++ mn = minor(dev);
++#endif
++ for (prevp = &amp;minor_devs; (up = *prevp) != 0; prevp = &amp;up-&gt;nextmn) {
++ if (up-&gt;mn &gt;= mn)
++ break;
++ }
++ if (up-&gt;mn == mn) {
++ /* this can't happen */
++ q-&gt;q_ptr = WR(q)-&gt;q_ptr = (caddr_t) up;
++ DRV_OPEN_OK(dev);
++ }
++ }
++
++ /*
++ * Construct a new minor node.
++ */
++ up = (upperstr_t *) ALLOC_SLEEP(sizeof(upperstr_t));
++ bzero((caddr_t) up, sizeof(upperstr_t));
++ if (up == 0) {
++ DPRINT(&quot;pppopen: out of kernel memory\n&quot;);
++ OPEN_ERROR(ENXIO);
++ }
++ up-&gt;nextmn = *prevp;
++ *prevp = up;
++ up-&gt;mn = mn;
++#ifdef SVR4
++ *devp = makedevice(getmajor(*devp), mn);
++#endif
++ up-&gt;q = q;
++ if (NOTSUSER() == 0)
++ up-&gt;flags |= US_PRIV;
++#ifndef NO_DLPI
++ up-&gt;state = DL_UNATTACHED;
++#endif
++#ifdef LACHTCP
++ up-&gt;ifflags = IFF_UP | IFF_POINTOPOINT;
++#endif
++ up-&gt;sap = -1;
++ up-&gt;last_sent = up-&gt;last_recv = time;
++ up-&gt;npmode = NPMODE_DROP;
++ q-&gt;q_ptr = (caddr_t) up;
++ WR(q)-&gt;q_ptr = (caddr_t) up;
++ noenable(WR(q));
++#ifdef SOL2
++ mutex_init(&amp;up-&gt;stats_lock, NULL, MUTEX_DRIVER, NULL);
++#endif
++ ++ppp_count;
++
++ qprocson(q);
++ DRV_OPEN_OK(makedev(major(dev), mn));
++}
++
++static int
++#ifdef SVR4
++pppclose(q, flag, credp)
++ queue_t *q;
++ int flag;
++ cred_t *credp;
++#else
++pppclose(q, flag)
++ queue_t *q;
++ int flag;
++#endif
++{
++ upperstr_t *up, **upp;
++ upperstr_t *as, *asnext;
++ upperstr_t **prevp;
++
++ qprocsoff(q);
++
++ up = (upperstr_t *) q-&gt;q_ptr;
++ if (up == 0) {
++ DPRINT(&quot;pppclose: q_ptr = 0\n&quot;);
++ return 0;
++ }
++ if (up-&gt;flags &amp; US_DBGLOG)
++ DPRINT2(&quot;ppp/%d: close, flags=%x\n&quot;, up-&gt;mn, up-&gt;flags);
++ if (up-&gt;flags &amp; US_CONTROL) {
++#ifdef LACHTCP
++ struct ifstats *ifp, *pifp;
++#endif
++ if (up-&gt;lowerq != 0) {
++ /* Gack! the lower stream should have be unlinked earlier! */
++ DPRINT1(&quot;ppp%d: lower stream still connected on close?\n&quot;,
++ up-&gt;mn);
++ LOCK_LOWER_W;
++ up-&gt;lowerq-&gt;q_ptr = 0;
++ RD(up-&gt;lowerq)-&gt;q_ptr = 0;
++ up-&gt;lowerq = 0;
++ UNLOCK_LOWER;
++ }
++
++ /*
++ * This stream represents a PPA:
++ * For all streams attached to the PPA, clear their
++ * references to this PPA.
++ * Then remove this PPA from the list of PPAs.
++ */
++ for (as = up-&gt;next; as != 0; as = asnext) {
++ asnext = as-&gt;next;
++ as-&gt;next = 0;
++ as-&gt;ppa = 0;
++ if (as-&gt;flags &amp; US_BLOCKED) {
++ as-&gt;flags &amp;= ~US_BLOCKED;
++ flushq(WR(as-&gt;q), FLUSHDATA);
++ }
++ }
++ for (upp = &amp;ppas; *upp != 0; upp = &amp;(*upp)-&gt;nextppa)
++ if (*upp == up) {
++ *upp = up-&gt;nextppa;
++ break;
++ }
++#ifdef LACHTCP
++ /* Remove the statistics from the active list. */
++ for (ifp = ifstats, pifp = 0; ifp; ifp = ifp-&gt;ifs_next) {
++ if (ifp == &amp;up-&gt;ifstats) {
++ if (pifp)
++ pifp-&gt;ifs_next = ifp-&gt;ifs_next;
++ else
++ ifstats = ifp-&gt;ifs_next;
++ break;
++ }
++ pifp = ifp;
++ }
++#endif
++ } else {
++ /*
++ * If this stream is attached to a PPA,
++ * remove it from the PPA's list.
++ */
++ if ((as = up-&gt;ppa) != 0) {
++ for (; as-&gt;next != 0; as = as-&gt;next)
++ if (as-&gt;next == up) {
++ as-&gt;next = up-&gt;next;
++ break;
++ }
++ }
++ }
++
++#ifdef SOL2
++ if (up-&gt;kstats)
++ kstat_delete(up-&gt;kstats);
++ mutex_destroy(&amp;up-&gt;stats_lock);
++#endif
++
++ q-&gt;q_ptr = NULL;
++ WR(q)-&gt;q_ptr = NULL;
++
++ for (prevp = &amp;minor_devs; *prevp != 0; prevp = &amp;(*prevp)-&gt;nextmn) {
++ if (*prevp == up) {
++ *prevp = up-&gt;nextmn;
++ break;
++ }
++ }
++ FREE(up, sizeof(upperstr_t));
++ --ppp_count;
++
++ return 0;
++}
++
++/*
++ * A message from on high. We do one of three things:
++ * - qreply()
++ * - put the message on the lower write stream
++ * - queue it for our service routine
++ */
++static int
++pppuwput(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ upperstr_t *us, *ppa, *nps;
++ struct iocblk *iop;
++ struct linkblk *lb;
++#ifdef LACHTCP
++ struct ifreq *ifr;
++ int i;
++#endif
++ queue_t *lq;
++ int error, n, sap;
++ mblk_t *mq;
++ struct ppp_idle *pip;
++#ifdef PRIOQ
++ queue_t *tlq;
++#endif /* PRIOQ */
++#ifdef NO_DLPI
++ upperstr_t *os;
++#endif
++
++ us = (upperstr_t *) q-&gt;q_ptr;
++ if (us == 0) {
++ DPRINT(&quot;pppuwput: q_ptr = 0!\n&quot;);
++ return 0;
++ }
++ if (mp == 0) {
++ DPRINT1(&quot;pppuwput/%d: mp = 0!\n&quot;, us-&gt;mn);
++ return 0;
++ }
++ if (mp-&gt;b_datap == 0) {
++ DPRINT1(&quot;pppuwput/%d: mp-&gt;b_datap = 0!\n&quot;, us-&gt;mn);
++ return 0;
++ }
++ switch (mp-&gt;b_datap-&gt;db_type) {
++#ifndef NO_DLPI
++ case M_PCPROTO:
++ case M_PROTO:
++ dlpi_request(q, mp, us);
++ break;
++#endif /* NO_DLPI */
++
++ case M_DATA:
++ if (us-&gt;flags &amp; US_DBGLOG)
++ DPRINT3(&quot;ppp/%d: uwput M_DATA len=%d flags=%x\n&quot;,
++ us-&gt;mn, msgdsize(mp), us-&gt;flags);
++ if (us-&gt;ppa == 0 || msgdsize(mp) &gt; us-&gt;ppa-&gt;mtu + PPP_HDRLEN
++#ifndef NO_DLPI
++ || (us-&gt;flags &amp; US_CONTROL) == 0
++#endif /* NO_DLPI */
++ ) {
++ DPRINT1(&quot;pppuwput: junk data len=%d\n&quot;, msgdsize(mp));
++ freemsg(mp);
++ break;
++ }
++#ifdef NO_DLPI
++ if ((us-&gt;flags &amp; US_CONTROL) == 0 &amp;&amp; !pass_packet(us, mp, 1))
++ break;
++#endif
++ if (!send_data(mp, us))
++ putq(q, mp);
++ break;
++
++ case M_IOCTL:
++ iop = (struct iocblk *) mp-&gt;b_rptr;
++ error = EINVAL;
++ if (us-&gt;flags &amp; US_DBGLOG)
++ DPRINT3(&quot;ppp/%d: ioctl %x count=%d\n&quot;,
++ us-&gt;mn, iop-&gt;ioc_cmd, iop-&gt;ioc_count);
++ switch (iop-&gt;ioc_cmd) {
++#if defined(SOL2)
++ case DLIOCRAW: /* raw M_DATA mode */
++ us-&gt;flags |= US_RAWDATA;
++ error = 0;
++ break;
++#endif /* defined(SOL2) */
++ case I_LINK:
++ if ((us-&gt;flags &amp; US_CONTROL) == 0 || us-&gt;lowerq != 0)
++ break;
++ if (mp-&gt;b_cont == 0) {
++ DPRINT1(&quot;pppuwput/%d: ioctl I_LINK b_cont = 0!\n&quot;, us-&gt;mn);
++ break;
++ }
++ lb = (struct linkblk *) mp-&gt;b_cont-&gt;b_rptr;
++ lq = lb-&gt;l_qbot;
++ if (lq == 0) {
++ DPRINT1(&quot;pppuwput/%d: ioctl I_LINK l_qbot = 0!\n&quot;, us-&gt;mn);
++ break;
++ }
++ LOCK_LOWER_W;
++ us-&gt;lowerq = lq;
++ lq-&gt;q_ptr = (caddr_t) q;
++ RD(lq)-&gt;q_ptr = (caddr_t) us-&gt;q;
++ UNLOCK_LOWER;
++ iop-&gt;ioc_count = 0;
++ error = 0;
++ us-&gt;flags &amp;= ~US_LASTMOD;
++ /* Unblock upper streams which now feed this lower stream. */
++ qenable(q);
++ /* Send useful information down to the modules which
++ are now linked below us. */
++ putctl2(lq, M_CTL, PPPCTL_UNIT, us-&gt;ppa_id);
++ putctl4(lq, M_CTL, PPPCTL_MRU, us-&gt;mru);
++ putctl4(lq, M_CTL, PPPCTL_MTU, us-&gt;mtu);
++#ifdef PRIOQ
++ /* Lower tty driver's queue hiwat/lowat from default 4096/128
++ to 256/128 since we don't want queueing of data on
++ output to physical device */
++
++ freezestr(lq);
++ for (tlq = lq; tlq-&gt;q_next != NULL; tlq = tlq-&gt;q_next)
++ ;
++ strqset(tlq, QHIWAT, 0, 256);
++ strqset(tlq, QLOWAT, 0, 128);
++ unfreezestr(lq);
++#endif /* PRIOQ */
++ break;
++
++ case I_UNLINK:
++ if (mp-&gt;b_cont == 0) {
++ DPRINT1(&quot;pppuwput/%d: ioctl I_UNLINK b_cont = 0!\n&quot;, us-&gt;mn);
++ break;
++ }
++ lb = (struct linkblk *) mp-&gt;b_cont-&gt;b_rptr;
++#if DEBUG
++ if (us-&gt;lowerq != lb-&gt;l_qbot) {
++ DPRINT2(&quot;ppp unlink: lowerq=%x qbot=%x\n&quot;,
++ us-&gt;lowerq, lb-&gt;l_qbot);
++ break;
++ }
++#endif
++ iop-&gt;ioc_count = 0;
++ qwriter(q, mp, detach_lower, PERIM_OUTER);
++ error = -1;
++ break;
++
++ case PPPIO_NEWPPA:
++ if (us-&gt;flags &amp; US_CONTROL)
++ break;
++ if ((us-&gt;flags &amp; US_PRIV) == 0) {
++ error = EPERM;
++ break;
++ }
++ /* Arrange to return an int */
++ if ((mq = mp-&gt;b_cont) == 0
++ || mq-&gt;b_datap-&gt;db_lim - mq-&gt;b_rptr &lt; sizeof(int)) {
++ mq = allocb(sizeof(int), BPRI_HI);
++ if (mq == 0) {
++ error = ENOSR;
++ break;
++ }
++ if (mp-&gt;b_cont != 0)
++ freemsg(mp-&gt;b_cont);
++ mp-&gt;b_cont = mq;
++ mq-&gt;b_cont = 0;
++ }
++ iop-&gt;ioc_count = sizeof(int);
++ mq-&gt;b_wptr = mq-&gt;b_rptr + sizeof(int);
++ qwriter(q, mp, new_ppa, PERIM_OUTER);
++ error = -1;
++ break;
++
++ case PPPIO_ATTACH:
++ /* like dlpi_attach, for programs which can't write to
++ the stream (like pppstats) */
++ if (iop-&gt;ioc_count != sizeof(int) || us-&gt;ppa != 0)
++ break;
++ if (mp-&gt;b_cont == 0) {
++ DPRINT1(&quot;pppuwput/%d: ioctl PPPIO_ATTACH b_cont = 0!\n&quot;, us-&gt;mn);
++ break;
++ }
++ n = *(int *)mp-&gt;b_cont-&gt;b_rptr;
++ for (ppa = ppas; ppa != 0; ppa = ppa-&gt;nextppa)
++ if (ppa-&gt;ppa_id == n)
++ break;
++ if (ppa == 0)
++ break;
++ us-&gt;ppa = ppa;
++ iop-&gt;ioc_count = 0;
++ qwriter(q, mp, attach_ppa, PERIM_OUTER);
++ error = -1;
++ break;
++
++#ifdef NO_DLPI
++ case PPPIO_BIND:
++ /* Attach to a given SAP. */
++ if (iop-&gt;ioc_count != sizeof(int) || us-&gt;ppa == 0)
++ break;
++ if (mp-&gt;b_cont == 0) {
++ DPRINT1(&quot;pppuwput/%d: ioctl PPPIO_BIND b_cont = 0!\n&quot;, us-&gt;mn);
++ break;
++ }
++ n = *(int *)mp-&gt;b_cont-&gt;b_rptr;
++ /* n must be a valid PPP network protocol number. */
++ if (n &lt; 0x21 || n &gt; 0x3fff || (n &amp; 0x101) != 1)
++ break;
++ /* check that no other stream is bound to this sap already. */
++ for (os = us-&gt;ppa; os != 0; os = os-&gt;next)
++ if (os-&gt;sap == n)
++ break;
++ if (os != 0)
++ break;
++ us-&gt;sap = n;
++ iop-&gt;ioc_count = 0;
++ error = 0;
++ break;
++#endif /* NO_DLPI */
++
++ case PPPIO_MRU:
++ if (iop-&gt;ioc_count != sizeof(int) || (us-&gt;flags &amp; US_CONTROL) == 0)
++ break;
++ if (mp-&gt;b_cont == 0) {
++ DPRINT1(&quot;pppuwput/%d: ioctl PPPIO_MRU b_cont = 0!\n&quot;, us-&gt;mn);
++ break;
++ }
++ n = *(int *)mp-&gt;b_cont-&gt;b_rptr;
++ if (n &lt;= 0 || n &gt; PPP_MAXMRU)
++ break;
++ if (n &lt; PPP_MRU)
++ n = PPP_MRU;
++ us-&gt;mru = n;
++ if (us-&gt;lowerq)
++ putctl4(us-&gt;lowerq, M_CTL, PPPCTL_MRU, n);
++ error = 0;
++ iop-&gt;ioc_count = 0;
++ break;
++
++ case PPPIO_MTU:
++ if (iop-&gt;ioc_count != sizeof(int) || (us-&gt;flags &amp; US_CONTROL) == 0)
++ break;
++ if (mp-&gt;b_cont == 0) {
++ DPRINT1(&quot;pppuwput/%d: ioctl PPPIO_MTU b_cont = 0!\n&quot;, us-&gt;mn);
++ break;
++ }
++ n = *(int *)mp-&gt;b_cont-&gt;b_rptr;
++ if (n &lt;= 0 || n &gt; PPP_MAXMTU)
++ break;
++ us-&gt;mtu = n;
++#ifdef LACHTCP
++ /* The MTU reported in netstat, not used as IP max packet size! */
++ us-&gt;ifstats.ifs_mtu = n;
++#endif
++ if (us-&gt;lowerq)
++ putctl4(us-&gt;lowerq, M_CTL, PPPCTL_MTU, n);
++ error = 0;
++ iop-&gt;ioc_count = 0;
++ break;
++
++ case PPPIO_LASTMOD:
++ us-&gt;flags |= US_LASTMOD;
++ error = 0;
++ break;
++
++ case PPPIO_DEBUG:
++ if (iop-&gt;ioc_count != sizeof(int))
++ break;
++ if (mp-&gt;b_cont == 0) {
++ DPRINT1(&quot;pppuwput/%d: ioctl PPPIO_DEBUG b_cont = 0!\n&quot;, us-&gt;mn);
++ break;
++ }
++ n = *(int *)mp-&gt;b_cont-&gt;b_rptr;
++ if (n == PPPDBG_DUMP + PPPDBG_DRIVER) {
++ qwriter(q, NULL, debug_dump, PERIM_OUTER);
++ iop-&gt;ioc_count = 0;
++ error = -1;
++ } else if (n == PPPDBG_LOG + PPPDBG_DRIVER) {
++ DPRINT1(&quot;ppp/%d: debug log enabled\n&quot;, us-&gt;mn);
++ us-&gt;flags |= US_DBGLOG;
++ iop-&gt;ioc_count = 0;
++ error = 0;
++ } else {
++ if (us-&gt;ppa == 0 || us-&gt;ppa-&gt;lowerq == 0)
++ break;
++ putnext(us-&gt;ppa-&gt;lowerq, mp);
++ error = -1;
++ }
++ break;
++
++ case PPPIO_NPMODE:
++ if (iop-&gt;ioc_count != 2 * sizeof(int))
++ break;
++ if ((us-&gt;flags &amp; US_CONTROL) == 0)
++ break;
++ if (mp-&gt;b_cont == 0) {
++ DPRINT1(&quot;pppuwput/%d: ioctl PPPIO_NPMODE b_cont = 0!\n&quot;, us-&gt;mn);
++ break;
++ }
++ sap = ((int *)mp-&gt;b_cont-&gt;b_rptr)[0];
++ for (nps = us-&gt;next; nps != 0; nps = nps-&gt;next) {
++ if (us-&gt;flags &amp; US_DBGLOG)
++ DPRINT2(&quot;us = 0x%x, us-&gt;next-&gt;sap = 0x%x\n&quot;, nps, nps-&gt;sap);
++ if (nps-&gt;sap == sap)
++ break;
++ }
++ if (nps == 0) {
++ if (us-&gt;flags &amp; US_DBGLOG)
++ DPRINT2(&quot;ppp/%d: no stream for sap %x\n&quot;, us-&gt;mn, sap);
++ break;
++ }
++ /* XXX possibly should use qwriter here */
++ nps-&gt;npmode = (enum NPmode) ((int *)mp-&gt;b_cont-&gt;b_rptr)[1];
++ if (nps-&gt;npmode != NPMODE_QUEUE &amp;&amp; (nps-&gt;flags &amp; US_BLOCKED) != 0)
++ qenable(WR(nps-&gt;q));
++ iop-&gt;ioc_count = 0;
++ error = 0;
++ break;
++
++ case PPPIO_GIDLE:
++ if ((ppa = us-&gt;ppa) == 0)
++ break;
++ mq = allocb(sizeof(struct ppp_idle), BPRI_HI);
++ if (mq == 0) {
++ error = ENOSR;
++ break;
++ }
++ if (mp-&gt;b_cont != 0)
++ freemsg(mp-&gt;b_cont);
++ mp-&gt;b_cont = mq;
++ mq-&gt;b_cont = 0;
++ pip = (struct ppp_idle *) mq-&gt;b_wptr;
++ pip-&gt;xmit_idle = time - ppa-&gt;last_sent;
++ pip-&gt;recv_idle = time - ppa-&gt;last_recv;
++ mq-&gt;b_wptr += sizeof(struct ppp_idle);
++ iop-&gt;ioc_count = sizeof(struct ppp_idle);
++ error = 0;
++ break;
++
++#ifdef LACHTCP
++ case SIOCSIFNAME:
++ /* Sent from IP down to us. Attach the ifstats structure. */
++ if (iop-&gt;ioc_count != sizeof(struct ifreq) || us-&gt;ppa == 0)
++ break;
++ ifr = (struct ifreq *)mp-&gt;b_cont-&gt;b_rptr;
++ /* Find the unit number in the interface name. */
++ for (i = 0; i &lt; IFNAMSIZ; i++) {
++ if (ifr-&gt;ifr_name[i] == 0 ||
++ (ifr-&gt;ifr_name[i] &gt;= '0' &amp;&amp;
++ ifr-&gt;ifr_name[i] &lt;= '9'))
++ break;
++ else
++ us-&gt;ifname[i] = ifr-&gt;ifr_name[i];
++ }
++ us-&gt;ifname[i] = 0;
++
++ /* Convert the unit number to binary. */
++ for (n = 0; i &lt; IFNAMSIZ; i++) {
++ if (ifr-&gt;ifr_name[i] == 0) {
++ break;
++ }
++ else {
++ n = n * 10 + ifr-&gt;ifr_name[i] - '0';
++ }
++ }
++
++ /* Verify the ppa. */
++ if (us-&gt;ppa-&gt;ppa_id != n)
++ break;
++ ppa = us-&gt;ppa;
++
++ /* Set up the netstat block. */
++ strncpy (ppa-&gt;ifname, us-&gt;ifname, IFNAMSIZ);
++
++ ppa-&gt;ifstats.ifs_name = ppa-&gt;ifname;
++ ppa-&gt;ifstats.ifs_unit = n;
++ ppa-&gt;ifstats.ifs_active = us-&gt;state != DL_UNBOUND;
++ ppa-&gt;ifstats.ifs_mtu = ppa-&gt;mtu;
++
++ /* Link in statistics used by netstat. */
++ ppa-&gt;ifstats.ifs_next = ifstats;
++ ifstats = &amp;ppa-&gt;ifstats;
++
++ iop-&gt;ioc_count = 0;
++ error = 0;
++ break;
++
++ case SIOCGIFFLAGS:
++ if (!(us-&gt;flags &amp; US_CONTROL)) {
++ if (us-&gt;ppa)
++ us = us-&gt;ppa;
++ else
++ break;
++ }
++ ((struct iocblk_in *)iop)-&gt;ioc_ifflags = us-&gt;ifflags;
++ error = 0;
++ break;
++
++ case SIOCSIFFLAGS:
++ if (!(us-&gt;flags &amp; US_CONTROL)) {
++ if (us-&gt;ppa)
++ us = us-&gt;ppa;
++ else
++ break;
++ }
++ us-&gt;ifflags = ((struct iocblk_in *)iop)-&gt;ioc_ifflags;
++ error = 0;
++ break;
++
++ case SIOCSIFADDR:
++ if (!(us-&gt;flags &amp; US_CONTROL)) {
++ if (us-&gt;ppa)
++ us = us-&gt;ppa;
++ else
++ break;
++ }
++ us-&gt;ifflags |= IFF_RUNNING;
++ ((struct iocblk_in *)iop)-&gt;ioc_ifflags |= IFF_RUNNING;
++ error = 0;
++ break;
++
++ case SIOCSIFMTU:
++ /*
++ * Vanilla SVR4 systems don't handle SIOCSIFMTU, rather
++ * they take the MTU from the DL_INFO_ACK we sent in response
++ * to their DL_INFO_REQ. Fortunately, they will update the
++ * MTU if we send an unsolicited DL_INFO_ACK up.
++ */
++ if ((mq = allocb(sizeof(dl_info_req_t), BPRI_HI)) == 0)
++ break; /* should do bufcall */
++ ((union DL_primitives *)mq-&gt;b_rptr)-&gt;dl_primitive = DL_INFO_REQ;
++ mq-&gt;b_wptr = mq-&gt;b_rptr + sizeof(dl_info_req_t);
++ dlpi_request(q, mq, us);
++ error = 0;
++ break;
++
++ case SIOCGIFNETMASK:
++ case SIOCSIFNETMASK:
++ case SIOCGIFADDR:
++ case SIOCGIFDSTADDR:
++ case SIOCSIFDSTADDR:
++ case SIOCGIFMETRIC:
++ error = 0;
++ break;
++#endif /* LACHTCP */
++
++ default:
++ if (us-&gt;ppa == 0 || us-&gt;ppa-&gt;lowerq == 0)
++ break;
++ us-&gt;ioc_id = iop-&gt;ioc_id;
++ error = -1;
++ switch (iop-&gt;ioc_cmd) {
++ case PPPIO_GETSTAT:
++ case PPPIO_GETCSTAT:
++ if (us-&gt;flags &amp; US_LASTMOD) {
++ error = EINVAL;
++ break;
++ }
++ putnext(us-&gt;ppa-&gt;lowerq, mp);
++ break;
++ default:
++ if (us-&gt;flags &amp; US_PRIV)
++ putnext(us-&gt;ppa-&gt;lowerq, mp);
++ else {
++ DPRINT1(&quot;ppp ioctl %x rejected\n&quot;, iop-&gt;ioc_cmd);
++ error = EPERM;
++ }
++ break;
++ }
++ break;
++ }
++
++ if (error &gt; 0) {
++ iop-&gt;ioc_error = error;
++ mp-&gt;b_datap-&gt;db_type = M_IOCNAK;
++ qreply(q, mp);
++ } else if (error == 0) {
++ mp-&gt;b_datap-&gt;db_type = M_IOCACK;
++ qreply(q, mp);
++ }
++ break;
++
++ case M_FLUSH:
++ if (us-&gt;flags &amp; US_DBGLOG)
++ DPRINT2(&quot;ppp/%d: flush %x\n&quot;, us-&gt;mn, *mp-&gt;b_rptr);
++ if (*mp-&gt;b_rptr &amp; FLUSHW)
++ flushq(q, FLUSHDATA);
++ if (*mp-&gt;b_rptr &amp; FLUSHR) {
++ *mp-&gt;b_rptr &amp;= ~FLUSHW;
++ qreply(q, mp);
++ } else
++ freemsg(mp);
++ break;
++
++ default:
++ freemsg(mp);
++ break;
++ }
++ return 0;
++}
++
++#ifndef NO_DLPI
++static void
++dlpi_request(q, mp, us)
++ queue_t *q;
++ mblk_t *mp;
++ upperstr_t *us;
++{
++ union DL_primitives *d = (union DL_primitives *) mp-&gt;b_rptr;
++ int size = mp-&gt;b_wptr - mp-&gt;b_rptr;
++ mblk_t *reply, *np;
++ upperstr_t *ppa, *os;
++ int sap, len;
++ dl_info_ack_t *info;
++ dl_bind_ack_t *ackp;
++#if DL_CURRENT_VERSION &gt;= 2
++ dl_phys_addr_ack_t *paddrack;
++ static struct ether_addr eaddr = {0};
++#endif
++
++ if (us-&gt;flags &amp; US_DBGLOG)
++ DPRINT3(&quot;ppp/%d: dlpi prim %x len=%d\n&quot;, us-&gt;mn,
++ d-&gt;dl_primitive, size);
++ switch (d-&gt;dl_primitive) {
++ case DL_INFO_REQ:
++ if (size &lt; sizeof(dl_info_req_t))
++ goto badprim;
++ if ((reply = allocb(sizeof(dl_info_ack_t), BPRI_HI)) == 0)
++ break; /* should do bufcall */
++ reply-&gt;b_datap-&gt;db_type = M_PCPROTO;
++ info = (dl_info_ack_t *) reply-&gt;b_wptr;
++ reply-&gt;b_wptr += sizeof(dl_info_ack_t);
++ bzero((caddr_t) info, sizeof(dl_info_ack_t));
++ info-&gt;dl_primitive = DL_INFO_ACK;
++ info-&gt;dl_max_sdu = us-&gt;ppa? us-&gt;ppa-&gt;mtu: PPP_MAXMTU;
++ info-&gt;dl_min_sdu = 1;
++ info-&gt;dl_addr_length = sizeof(uint);
++ info-&gt;dl_mac_type = DL_ETHER; /* a bigger lie */
++ info-&gt;dl_current_state = us-&gt;state;
++ info-&gt;dl_service_mode = DL_CLDLS;
++ info-&gt;dl_provider_style = DL_STYLE2;
++#if DL_CURRENT_VERSION &gt;= 2
++ info-&gt;dl_sap_length = sizeof(uint);
++ info-&gt;dl_version = DL_CURRENT_VERSION;
++#endif
++ qreply(q, reply);
++ break;
++
++ case DL_ATTACH_REQ:
++ if (size &lt; sizeof(dl_attach_req_t))
++ goto badprim;
++ if (us-&gt;state != DL_UNATTACHED || us-&gt;ppa != 0) {
++ dlpi_error(q, us, DL_ATTACH_REQ, DL_OUTSTATE, 0);
++ break;
++ }
++ for (ppa = ppas; ppa != 0; ppa = ppa-&gt;nextppa)
++ if (ppa-&gt;ppa_id == d-&gt;attach_req.dl_ppa)
++ break;
++ if (ppa == 0) {
++ dlpi_error(q, us, DL_ATTACH_REQ, DL_BADPPA, 0);
++ break;
++ }
++ us-&gt;ppa = ppa;
++ qwriter(q, mp, attach_ppa, PERIM_OUTER);
++ return;
++
++ case DL_DETACH_REQ:
++ if (size &lt; sizeof(dl_detach_req_t))
++ goto badprim;
++ if (us-&gt;state != DL_UNBOUND || us-&gt;ppa == 0) {
++ dlpi_error(q, us, DL_DETACH_REQ, DL_OUTSTATE, 0);
++ break;
++ }
++ qwriter(q, mp, detach_ppa, PERIM_OUTER);
++ return;
++
++ case DL_BIND_REQ:
++ if (size &lt; sizeof(dl_bind_req_t))
++ goto badprim;
++ if (us-&gt;state != DL_UNBOUND || us-&gt;ppa == 0) {
++ dlpi_error(q, us, DL_BIND_REQ, DL_OUTSTATE, 0);
++ break;
++ }
++#if 0
++ /* apparently this test fails (unnecessarily?) on some systems */
++ if (d-&gt;bind_req.dl_service_mode != DL_CLDLS) {
++ dlpi_error(q, us, DL_BIND_REQ, DL_UNSUPPORTED, 0);
++ break;
++ }
++#endif
++
++ /* saps must be valid PPP network protocol numbers,
++ except that we accept ETHERTYPE_IP in place of PPP_IP. */
++ sap = d-&gt;bind_req.dl_sap;
++ us-&gt;req_sap = sap;
++
++#if defined(SOL2)
++ if (us-&gt;flags &amp; US_DBGLOG)
++ DPRINT2(&quot;DL_BIND_REQ: ip gives sap = 0x%x, us = 0x%x&quot;, sap, us);
++
++ if (sap == ETHERTYPE_IP) /* normal IFF_IPV4 */
++ sap = PPP_IP;
++ else if (sap == ETHERTYPE_IPV6) /* when IFF_IPV6 is set */
++ sap = PPP_IPV6;
++ else if (sap == ETHERTYPE_ALLSAP) /* snoop gives sap of 0 */
++ sap = PPP_ALLSAP;
++ else {
++ DPRINT2(&quot;DL_BIND_REQ: unrecognized sap = 0x%x, us = 0x%x&quot;, sap, us);
++ dlpi_error(q, us, DL_BIND_REQ, DL_BADADDR, 0);
++ break;
++ }
++#else
++ if (sap == ETHERTYPE_IP)
++ sap = PPP_IP;
++ if (sap &lt; 0x21 || sap &gt; 0x3fff || (sap &amp; 0x101) != 1) {
++ dlpi_error(q, us, DL_BIND_REQ, DL_BADADDR, 0);
++ break;
++ }
++#endif /* defined(SOL2) */
++
++ /* check that no other stream is bound to this sap already. */
++ for (os = us-&gt;ppa; os != 0; os = os-&gt;next)
++ if (os-&gt;sap == sap)
++ break;
++ if (os != 0) {
++ dlpi_error(q, us, DL_BIND_REQ, DL_NOADDR, 0);
++ break;
++ }
++
++ us-&gt;sap = sap;
++ us-&gt;state = DL_IDLE;
++
++ if ((reply = allocb(sizeof(dl_bind_ack_t) + sizeof(uint),
++ BPRI_HI)) == 0)
++ break; /* should do bufcall */
++ ackp = (dl_bind_ack_t *) reply-&gt;b_wptr;
++ reply-&gt;b_wptr += sizeof(dl_bind_ack_t) + sizeof(uint);
++ reply-&gt;b_datap-&gt;db_type = M_PCPROTO;
++ bzero((caddr_t) ackp, sizeof(dl_bind_ack_t));
++ ackp-&gt;dl_primitive = DL_BIND_ACK;
++ ackp-&gt;dl_sap = sap;
++ ackp-&gt;dl_addr_length = sizeof(uint);
++ ackp-&gt;dl_addr_offset = sizeof(dl_bind_ack_t);
++ *(uint *)(ackp+1) = sap;
++ qreply(q, reply);
++ break;
++
++ case DL_UNBIND_REQ:
++ if (size &lt; sizeof(dl_unbind_req_t))
++ goto badprim;
++ if (us-&gt;state != DL_IDLE) {
++ dlpi_error(q, us, DL_UNBIND_REQ, DL_OUTSTATE, 0);
++ break;
++ }
++ us-&gt;sap = -1;
++ us-&gt;state = DL_UNBOUND;
++#ifdef LACHTCP
++ us-&gt;ppa-&gt;ifstats.ifs_active = 0;
++#endif
++ dlpi_ok(q, DL_UNBIND_REQ);
++ break;
++
++ case DL_UNITDATA_REQ:
++ if (size &lt; sizeof(dl_unitdata_req_t))
++ goto badprim;
++ if (us-&gt;state != DL_IDLE) {
++ dlpi_error(q, us, DL_UNITDATA_REQ, DL_OUTSTATE, 0);
++ break;
++ }
++ if ((ppa = us-&gt;ppa) == 0) {
++ cmn_err(CE_CONT, &quot;ppp: in state dl_idle but ppa == 0?\n&quot;);
++ break;
++ }
++ len = mp-&gt;b_cont == 0? 0: msgdsize(mp-&gt;b_cont);
++ if (len &gt; ppa-&gt;mtu) {
++ DPRINT2(&quot;dlpi data too large (%d &gt; %d)\n&quot;, len, ppa-&gt;mtu);
++ break;
++ }
++
++#if defined(SOL2)
++ /*
++ * Should there be any promiscuous stream(s), send the data
++ * up for each promiscuous stream that we recognize.
++ */
++ if (mp-&gt;b_cont)
++ promisc_sendup(ppa, mp-&gt;b_cont, us-&gt;sap, 0);
++#endif /* defined(SOL2) */
++
++ mp-&gt;b_band = 0;
++#ifdef PRIOQ
++ /* Extract s_port &amp; d_port from IP-packet, the code is a bit
++ dirty here, but so am I, too... */
++ if (mp-&gt;b_datap-&gt;db_type == M_PROTO &amp;&amp; us-&gt;sap == PPP_IP
++ &amp;&amp; mp-&gt;b_cont != 0) {
++ u_char *bb, *tlh;
++ int iphlen, len;
++ u_short *ptr;
++ u_char band_unset, cur_band, syn;
++ u_short s_port, d_port;
++
++ bb = mp-&gt;b_cont-&gt;b_rptr; /* bb points to IP-header*/
++ len = mp-&gt;b_cont-&gt;b_wptr - mp-&gt;b_cont-&gt;b_rptr;
++ syn = 0;
++ s_port = IPPORT_DEFAULT;
++ d_port = IPPORT_DEFAULT;
++ if (len &gt;= 20) { /* 20 = minimum length of IP header */
++ iphlen = (bb[0] &amp; 0x0f) * 4;
++ tlh = bb + iphlen;
++ len -= iphlen;
++ switch (bb[9]) {
++ case IPPROTO_TCP:
++ if (len &gt;= 20) { /* min length of TCP header */
++ s_port = (tlh[0] &lt;&lt; 8) + tlh[1];
++ d_port = (tlh[2] &lt;&lt; 8) + tlh[3];
++ syn = tlh[13] &amp; 0x02;
++ }
++ break;
++ case IPPROTO_UDP:
++ if (len &gt;= 8) { /* min length of UDP header */
++ s_port = (tlh[0] &lt;&lt; 8) + tlh[1];
++ d_port = (tlh[2] &lt;&lt; 8) + tlh[3];
++ }
++ break;
++ }
++ }
++
++ /*
++ * Now calculate b_band for this packet from the
++ * port-priority table.
++ */
++ ptr = prioq_table;
++ cur_band = max_band;
++ band_unset = 1;
++ while (*ptr) {
++ while (*ptr &amp;&amp; band_unset)
++ if (s_port == *ptr || d_port == *ptr++) {
++ mp-&gt;b_band = cur_band;
++ band_unset = 0;
++ break;
++ }
++ ptr++;
++ cur_band--;
++ }
++ if (band_unset)
++ mp-&gt;b_band = def_band;
++ /* It may be usable to urge SYN packets a bit */
++ if (syn)
++ mp-&gt;b_band++;
++ }
++#endif /* PRIOQ */
++ /* this assumes PPP_HDRLEN &lt;= sizeof(dl_unitdata_req_t) */
++ if (mp-&gt;b_datap-&gt;db_ref &gt; 1) {
++ np = allocb(PPP_HDRLEN, BPRI_HI);
++ if (np == 0)
++ break; /* gak! */
++ np-&gt;b_cont = mp-&gt;b_cont;
++ mp-&gt;b_cont = 0;
++ freeb(mp);
++ mp = np;
++ } else
++ mp-&gt;b_datap-&gt;db_type = M_DATA;
++ /* XXX should use dl_dest_addr_offset/length here,
++ but we would have to translate ETHERTYPE_IP -&gt; PPP_IP */
++ mp-&gt;b_wptr = mp-&gt;b_rptr + PPP_HDRLEN;
++ mp-&gt;b_rptr[0] = PPP_ALLSTATIONS;
++ mp-&gt;b_rptr[1] = PPP_UI;
++ mp-&gt;b_rptr[2] = us-&gt;sap &gt;&gt; 8;
++ mp-&gt;b_rptr[3] = us-&gt;sap;
++ if (pass_packet(us, mp, 1)) {
++ if (!send_data(mp, us))
++ putq(q, mp);
++ }
++ return;
++
++#if DL_CURRENT_VERSION &gt;= 2
++ case DL_PHYS_ADDR_REQ:
++ if (size &lt; sizeof(dl_phys_addr_req_t))
++ goto badprim;
++
++ /*
++ * Don't check state because ifconfig sends this one down too
++ */
++
++ if ((reply = allocb(sizeof(dl_phys_addr_ack_t)+ETHERADDRL,
++ BPRI_HI)) == 0)
++ break; /* should do bufcall */
++ reply-&gt;b_datap-&gt;db_type = M_PCPROTO;
++ paddrack = (dl_phys_addr_ack_t *) reply-&gt;b_wptr;
++ reply-&gt;b_wptr += sizeof(dl_phys_addr_ack_t);
++ bzero((caddr_t) paddrack, sizeof(dl_phys_addr_ack_t)+ETHERADDRL);
++ paddrack-&gt;dl_primitive = DL_PHYS_ADDR_ACK;
++ paddrack-&gt;dl_addr_length = ETHERADDRL;
++ paddrack-&gt;dl_addr_offset = sizeof(dl_phys_addr_ack_t);
++ bcopy(&amp;eaddr, reply-&gt;b_wptr, ETHERADDRL);
++ reply-&gt;b_wptr += ETHERADDRL;
++ qreply(q, reply);
++ break;
++
++#if defined(SOL2)
++ case DL_PROMISCON_REQ:
++ if (size &lt; sizeof(dl_promiscon_req_t))
++ goto badprim;
++ us-&gt;flags |= US_PROMISC;
++ dlpi_ok(q, DL_PROMISCON_REQ);
++ break;
++
++ case DL_PROMISCOFF_REQ:
++ if (size &lt; sizeof(dl_promiscoff_req_t))
++ goto badprim;
++ us-&gt;flags &amp;= ~US_PROMISC;
++ dlpi_ok(q, DL_PROMISCOFF_REQ);
++ break;
++#else
++ case DL_PROMISCON_REQ: /* fall thru */
++ case DL_PROMISCOFF_REQ: /* fall thru */
++#endif /* defined(SOL2) */
++#endif /* DL_CURRENT_VERSION &gt;= 2 */
++
++#if DL_CURRENT_VERSION &gt;= 2
++ case DL_SET_PHYS_ADDR_REQ:
++ case DL_SUBS_BIND_REQ:
++ case DL_SUBS_UNBIND_REQ:
++ case DL_ENABMULTI_REQ:
++ case DL_DISABMULTI_REQ:
++ case DL_XID_REQ:
++ case DL_TEST_REQ:
++ case DL_REPLY_UPDATE_REQ:
++ case DL_REPLY_REQ:
++ case DL_DATA_ACK_REQ:
++#endif
++ case DL_CONNECT_REQ:
++ case DL_TOKEN_REQ:
++ dlpi_error(q, us, d-&gt;dl_primitive, DL_NOTSUPPORTED, 0);
++ break;
++
++ case DL_CONNECT_RES:
++ case DL_DISCONNECT_REQ:
++ case DL_RESET_REQ:
++ case DL_RESET_RES:
++ dlpi_error(q, us, d-&gt;dl_primitive, DL_OUTSTATE, 0);
++ break;
++
++ case DL_UDQOS_REQ:
++ dlpi_error(q, us, d-&gt;dl_primitive, DL_BADQOSTYPE, 0);
++ break;
++
++#if DL_CURRENT_VERSION &gt;= 2
++ case DL_TEST_RES:
++ case DL_XID_RES:
++ break;
++#endif
++
++ default:
++ cmn_err(CE_CONT, &quot;ppp: unknown dlpi prim 0x%x\n&quot;, d-&gt;dl_primitive);
++ /* fall through */
++ badprim:
++ dlpi_error(q, us, d-&gt;dl_primitive, DL_BADPRIM, 0);
++ break;
++ }
++ freemsg(mp);
++}
++
++static void
++dlpi_error(q, us, prim, err, uerr)
++ queue_t *q;
++ upperstr_t *us;
++ int prim, err, uerr;
++{
++ mblk_t *reply;
++ dl_error_ack_t *errp;
++
++ if (us-&gt;flags &amp; US_DBGLOG)
++ DPRINT3(&quot;ppp/%d: dlpi error, prim=%x, err=%x\n&quot;, us-&gt;mn, prim, err);
++ reply = allocb(sizeof(dl_error_ack_t), BPRI_HI);
++ if (reply == 0)
++ return; /* XXX should do bufcall */
++ reply-&gt;b_datap-&gt;db_type = M_PCPROTO;
++ errp = (dl_error_ack_t *) reply-&gt;b_wptr;
++ reply-&gt;b_wptr += sizeof(dl_error_ack_t);
++ errp-&gt;dl_primitive = DL_ERROR_ACK;
++ errp-&gt;dl_error_primitive = prim;
++ errp-&gt;dl_errno = err;
++ errp-&gt;dl_unix_errno = uerr;
++ qreply(q, reply);
++}
++
++static void
++dlpi_ok(q, prim)
++ queue_t *q;
++ int prim;
++{
++ mblk_t *reply;
++ dl_ok_ack_t *okp;
++
++ reply = allocb(sizeof(dl_ok_ack_t), BPRI_HI);
++ if (reply == 0)
++ return; /* XXX should do bufcall */
++ reply-&gt;b_datap-&gt;db_type = M_PCPROTO;
++ okp = (dl_ok_ack_t *) reply-&gt;b_wptr;
++ reply-&gt;b_wptr += sizeof(dl_ok_ack_t);
++ okp-&gt;dl_primitive = DL_OK_ACK;
++ okp-&gt;dl_correct_primitive = prim;
++ qreply(q, reply);
++}
++#endif /* NO_DLPI */
++
++static int
++pass_packet(us, mp, outbound)
++ upperstr_t *us;
++ mblk_t *mp;
++ int outbound;
++{
++ int pass;
++ upperstr_t *ppa;
++
++ if ((ppa = us-&gt;ppa) == 0) {
++ freemsg(mp);
++ return 0;
++ }
++
++#ifdef FILTER_PACKETS
++ pass = ip_hard_filter(us, mp, outbound);
++#else
++ /*
++ * Here is where we might, in future, decide whether to pass
++ * or drop the packet, and whether it counts as link activity.
++ */
++ pass = 1;
++#endif /* FILTER_PACKETS */
++
++ if (pass &lt; 0) {
++ /* pass only if link already up, and don't update time */
++ if (ppa-&gt;lowerq == 0) {
++ freemsg(mp);
++ return 0;
++ }
++ pass = 1;
++ } else if (pass) {
++ if (outbound)
++ ppa-&gt;last_sent = time;
++ else
++ ppa-&gt;last_recv = time;
++ }
++
++ return pass;
++}
++
++/*
++ * We have some data to send down to the lower stream (or up the
++ * control stream, if we don't have a lower stream attached).
++ * Returns 1 if the message was dealt with, 0 if it wasn't able
++ * to be sent on and should therefore be queued up.
++ */
++static int
++send_data(mp, us)
++ mblk_t *mp;
++ upperstr_t *us;
++{
++ upperstr_t *ppa;
++
++ if ((us-&gt;flags &amp; US_BLOCKED) || us-&gt;npmode == NPMODE_QUEUE)
++ return 0;
++ ppa = us-&gt;ppa;
++ if (ppa == 0 || us-&gt;npmode == NPMODE_DROP || us-&gt;npmode == NPMODE_ERROR) {
++ if (us-&gt;flags &amp; US_DBGLOG)
++ DPRINT2(&quot;ppp/%d: dropping pkt (npmode=%d)\n&quot;, us-&gt;mn, us-&gt;npmode);
++ freemsg(mp);
++ return 1;
++ }
++ if (ppa-&gt;lowerq == 0) {
++ /* try to send it up the control stream */
++ if (bcanputnext(ppa-&gt;q, mp-&gt;b_band)) {
++ /*
++ * The message seems to get corrupted for some reason if
++ * we just send the message up as it is, so we send a copy.
++ */
++ mblk_t *np = copymsg(mp);
++ freemsg(mp);
++ if (np != 0)
++ putnext(ppa-&gt;q, np);
++ return 1;
++ }
++ } else {
++ if (bcanputnext(ppa-&gt;lowerq, mp-&gt;b_band)) {
++ MT_ENTER(&amp;ppa-&gt;stats_lock);
++ ppa-&gt;stats.ppp_opackets++;
++ ppa-&gt;stats.ppp_obytes += msgdsize(mp);
++#ifdef INCR_OPACKETS
++ INCR_OPACKETS(ppa);
++#endif
++ MT_EXIT(&amp;ppa-&gt;stats_lock);
++ /*
++ * The lower queue is only ever detached while holding an
++ * exclusive lock on the whole driver. So we can be confident
++ * that the lower queue is still there.
++ */
++ putnext(ppa-&gt;lowerq, mp);
++ return 1;
++ }
++ }
++ us-&gt;flags |= US_BLOCKED;
++ return 0;
++}
++
++/*
++ * Allocate a new PPA id and link this stream into the list of PPAs.
++ * This procedure is called with an exclusive lock on all queues in
++ * this driver.
++ */
++static void
++new_ppa(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ upperstr_t *us, *up, **usp;
++ int ppa_id;
++
++ us = (upperstr_t *) q-&gt;q_ptr;
++ if (us == 0) {
++ DPRINT(&quot;new_ppa: q_ptr = 0!\n&quot;);
++ return;
++ }
++
++ usp = &amp;ppas;
++ ppa_id = 0;
++ while ((up = *usp) != 0 &amp;&amp; ppa_id == up-&gt;ppa_id) {
++ ++ppa_id;
++ usp = &amp;up-&gt;nextppa;
++ }
++ us-&gt;ppa_id = ppa_id;
++ us-&gt;ppa = us;
++ us-&gt;next = 0;
++ us-&gt;nextppa = *usp;
++ *usp = us;
++ us-&gt;flags |= US_CONTROL;
++ us-&gt;npmode = NPMODE_PASS;
++
++ us-&gt;mtu = PPP_MTU;
++ us-&gt;mru = PPP_MRU;
++
++#ifdef SOL2
++ /*
++ * Create a kstats record for our statistics, so netstat -i works.
++ */
++ if (us-&gt;kstats == 0) {
++ char unit[32];
++
++ sprintf(unit, &quot;ppp%d&quot;, us-&gt;ppa-&gt;ppa_id);
++ us-&gt;kstats = kstat_create(&quot;ppp&quot;, us-&gt;ppa-&gt;ppa_id, unit,
++ &quot;net&quot;, KSTAT_TYPE_NAMED, 4, 0);
++ if (us-&gt;kstats != 0) {
++ kstat_named_t *kn = KSTAT_NAMED_PTR(us-&gt;kstats);
++
++ strcpy(kn[0].name, &quot;ipackets&quot;);
++ kn[0].data_type = KSTAT_DATA_ULONG;
++ strcpy(kn[1].name, &quot;ierrors&quot;);
++ kn[1].data_type = KSTAT_DATA_ULONG;
++ strcpy(kn[2].name, &quot;opackets&quot;);
++ kn[2].data_type = KSTAT_DATA_ULONG;
++ strcpy(kn[3].name, &quot;oerrors&quot;);
++ kn[3].data_type = KSTAT_DATA_ULONG;
++ kstat_install(us-&gt;kstats);
++ }
++ }
++#endif /* SOL2 */
++
++ *(int *)mp-&gt;b_cont-&gt;b_rptr = ppa_id;
++ mp-&gt;b_datap-&gt;db_type = M_IOCACK;
++ qreply(q, mp);
++}
++
++static void
++attach_ppa(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ upperstr_t *us, *t;
++
++ us = (upperstr_t *) q-&gt;q_ptr;
++ if (us == 0) {
++ DPRINT(&quot;attach_ppa: q_ptr = 0!\n&quot;);
++ return;
++ }
++
++#ifndef NO_DLPI
++ us-&gt;state = DL_UNBOUND;
++#endif
++ for (t = us-&gt;ppa; t-&gt;next != 0; t = t-&gt;next)
++ ;
++ t-&gt;next = us;
++ us-&gt;next = 0;
++ if (mp-&gt;b_datap-&gt;db_type == M_IOCTL) {
++ mp-&gt;b_datap-&gt;db_type = M_IOCACK;
++ qreply(q, mp);
++ } else {
++#ifndef NO_DLPI
++ dlpi_ok(q, DL_ATTACH_REQ);
++#endif
++ }
++}
++
++static void
++detach_ppa(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ upperstr_t *us, *t;
++
++ us = (upperstr_t *) q-&gt;q_ptr;
++ if (us == 0) {
++ DPRINT(&quot;detach_ppa: q_ptr = 0!\n&quot;);
++ return;
++ }
++
++ for (t = us-&gt;ppa; t-&gt;next != 0; t = t-&gt;next)
++ if (t-&gt;next == us) {
++ t-&gt;next = us-&gt;next;
++ break;
++ }
++ us-&gt;next = 0;
++ us-&gt;ppa = 0;
++#ifndef NO_DLPI
++ us-&gt;state = DL_UNATTACHED;
++ dlpi_ok(q, DL_DETACH_REQ);
++#endif
++}
++
++/*
++ * We call this with qwriter in order to give the upper queue procedures
++ * the guarantee that the lower queue is not going to go away while
++ * they are executing.
++ */
++static void
++detach_lower(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ upperstr_t *us;
++
++ us = (upperstr_t *) q-&gt;q_ptr;
++ if (us == 0) {
++ DPRINT(&quot;detach_lower: q_ptr = 0!\n&quot;);
++ return;
++ }
++
++ LOCK_LOWER_W;
++ us-&gt;lowerq-&gt;q_ptr = 0;
++ RD(us-&gt;lowerq)-&gt;q_ptr = 0;
++ us-&gt;lowerq = 0;
++ UNLOCK_LOWER;
++
++ /* Unblock streams which now feed back up the control stream. */
++ qenable(us-&gt;q);
++
++ mp-&gt;b_datap-&gt;db_type = M_IOCACK;
++ qreply(q, mp);
++}
++
++static int
++pppuwsrv(q)
++ queue_t *q;
++{
++ upperstr_t *us, *as;
++ mblk_t *mp;
++
++ us = (upperstr_t *) q-&gt;q_ptr;
++ if (us == 0) {
++ DPRINT(&quot;pppuwsrv: q_ptr = 0!\n&quot;);
++ return 0;
++ }
++
++ /*
++ * If this is a control stream, then this service procedure
++ * probably got enabled because of flow control in the lower
++ * stream being enabled (or because of the lower stream going
++ * away). Therefore we enable the service procedure of all
++ * attached upper streams.
++ */
++ if (us-&gt;flags &amp; US_CONTROL) {
++ for (as = us-&gt;next; as != 0; as = as-&gt;next)
++ qenable(WR(as-&gt;q));
++ }
++
++ /* Try to send on any data queued here. */
++ us-&gt;flags &amp;= ~US_BLOCKED;
++ while ((mp = getq(q)) != 0) {
++ if (!send_data(mp, us)) {
++ putbq(q, mp);
++ break;
++ }
++ }
++
++ return 0;
++}
++
++/* should never get called... */
++static int
++ppplwput(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ putnext(q, mp);
++ return 0;
++}
++
++static int
++ppplwsrv(q)
++ queue_t *q;
++{
++ queue_t *uq;
++
++ /*
++ * Flow control has back-enabled this stream:
++ * enable the upper write service procedure for
++ * the upper control stream for this lower stream.
++ */
++ LOCK_LOWER_R;
++ uq = (queue_t *) q-&gt;q_ptr;
++ if (uq != 0)
++ qenable(uq);
++ UNLOCK_LOWER;
++ return 0;
++}
++
++/*
++ * This should only get called for control streams.
++ */
++static int
++pppurput(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ upperstr_t *ppa, *us;
++ int proto, len;
++ struct iocblk *iop;
++
++ ppa = (upperstr_t *) q-&gt;q_ptr;
++ if (ppa == 0) {
++ DPRINT(&quot;pppurput: q_ptr = 0!\n&quot;);
++ return 0;
++ }
++
++ switch (mp-&gt;b_datap-&gt;db_type) {
++ case M_CTL:
++ MT_ENTER(&amp;ppa-&gt;stats_lock);
++ switch (*mp-&gt;b_rptr) {
++ case PPPCTL_IERROR:
++#ifdef INCR_IERRORS
++ INCR_IERRORS(ppa);
++#endif
++ ppa-&gt;stats.ppp_ierrors++;
++ break;
++ case PPPCTL_OERROR:
++#ifdef INCR_OERRORS
++ INCR_OERRORS(ppa);
++#endif
++ ppa-&gt;stats.ppp_oerrors++;
++ break;
++ }
++ MT_EXIT(&amp;ppa-&gt;stats_lock);
++ freemsg(mp);
++ break;
++
++ case M_IOCACK:
++ case M_IOCNAK:
++ /*
++ * Attempt to match up the response with the stream
++ * that the request came from.
++ */
++ iop = (struct iocblk *) mp-&gt;b_rptr;
++ for (us = ppa; us != 0; us = us-&gt;next)
++ if (us-&gt;ioc_id == iop-&gt;ioc_id)
++ break;
++ if (us == 0)
++ freemsg(mp);
++ else
++ putnext(us-&gt;q, mp);
++ break;
++
++ case M_HANGUP:
++ /*
++ * The serial device has hung up. We don't want to send
++ * the M_HANGUP message up to pppd because that will stop
++ * us from using the control stream any more. Instead we
++ * send a zero-length message as an end-of-file indication.
++ */
++ freemsg(mp);
++ mp = allocb(1, BPRI_HI);
++ if (mp == 0) {
++ DPRINT1(&quot;ppp/%d: couldn't allocate eof message!\n&quot;, ppa-&gt;mn);
++ break;
++ }
++ putnext(ppa-&gt;q, mp);
++ break;
++
++ default:
++ if (mp-&gt;b_datap-&gt;db_type == M_DATA) {
++ len = msgdsize(mp);
++ if (mp-&gt;b_wptr - mp-&gt;b_rptr &lt; PPP_HDRLEN) {
++ PULLUP(mp, PPP_HDRLEN);
++ if (mp == 0) {
++ DPRINT1(&quot;ppp_urput: msgpullup failed (len=%d)\n&quot;, len);
++ break;
++ }
++ }
++ MT_ENTER(&amp;ppa-&gt;stats_lock);
++ ppa-&gt;stats.ppp_ipackets++;
++ ppa-&gt;stats.ppp_ibytes += len;
++#ifdef INCR_IPACKETS
++ INCR_IPACKETS(ppa);
++#endif
++ MT_EXIT(&amp;ppa-&gt;stats_lock);
++
++ proto = PPP_PROTOCOL(mp-&gt;b_rptr);
++
++#if defined(SOL2)
++ /*
++ * Should there be any promiscuous stream(s), send the data
++ * up for each promiscuous stream that we recognize.
++ */
++ promisc_sendup(ppa, mp, proto, 1);
++#endif /* defined(SOL2) */
++
++ if (proto &lt; 0x8000 &amp;&amp; (us = find_dest(ppa, proto)) != 0) {
++ /*
++ * A data packet for some network protocol.
++ * Queue it on the upper stream for that protocol.
++ * XXX could we just putnext it? (would require thought)
++ * The rblocked flag is there to ensure that we keep
++ * messages in order for each network protocol.
++ */
++ if (!pass_packet(us, mp, 0))
++ break;
++ if (!us-&gt;rblocked &amp;&amp; !canput(us-&gt;q))
++ us-&gt;rblocked = 1;
++ if (!us-&gt;rblocked)
++ putq(us-&gt;q, mp);
++ else
++ putq(q, mp);
++ break;
++ }
++ }
++ /*
++ * A control frame, a frame for an unknown protocol,
++ * or some other message type.
++ * Send it up to pppd via the control stream.
++ */
++ if (queclass(mp) == QPCTL || canputnext(ppa-&gt;q))
++ putnext(ppa-&gt;q, mp);
++ else
++ putq(q, mp);
++ break;
++ }
++
++ return 0;
++}
++
++static int
++pppursrv(q)
++ queue_t *q;
++{
++ upperstr_t *us, *as;
++ mblk_t *mp, *hdr;
++#ifndef NO_DLPI
++ dl_unitdata_ind_t *ud;
++#endif
++ int proto;
++
++ us = (upperstr_t *) q-&gt;q_ptr;
++ if (us == 0) {
++ DPRINT(&quot;pppursrv: q_ptr = 0!\n&quot;);
++ return 0;
++ }
++
++ if (us-&gt;flags &amp; US_CONTROL) {
++ /*
++ * A control stream.
++ * If there is no lower queue attached, run the write service
++ * routines of other upper streams attached to this PPA.
++ */
++ if (us-&gt;lowerq == 0) {
++ as = us;
++ do {
++ if (as-&gt;flags &amp; US_BLOCKED)
++ qenable(WR(as-&gt;q));
++ as = as-&gt;next;
++ } while (as != 0);
++ }
++
++ /*
++ * Messages get queued on this stream's read queue if they
++ * can't be queued on the read queue of the attached stream
++ * that they are destined for. This is for flow control -
++ * when this queue fills up, the lower read put procedure will
++ * queue messages there and the flow control will propagate
++ * down from there.
++ */
++ while ((mp = getq(q)) != 0) {
++ proto = PPP_PROTOCOL(mp-&gt;b_rptr);
++ if (proto &lt; 0x8000 &amp;&amp; (as = find_dest(us, proto)) != 0) {
++ if (!canput(as-&gt;q))
++ break;
++ putq(as-&gt;q, mp);
++ } else {
++ if (!canputnext(q))
++ break;
++ putnext(q, mp);
++ }
++ }
++ if (mp) {
++ putbq(q, mp);
++ } else {
++ /* can now put stuff directly on network protocol streams again */
++ for (as = us-&gt;next; as != 0; as = as-&gt;next)
++ as-&gt;rblocked = 0;
++ }
++
++ /*
++ * If this stream has a lower stream attached,
++ * enable the read queue's service routine.
++ * XXX we should really only do this if the queue length
++ * has dropped below the low-water mark.
++ */
++ if (us-&gt;lowerq != 0)
++ qenable(RD(us-&gt;lowerq));
++
++ } else {
++ /*
++ * A network protocol stream. Put a DLPI header on each
++ * packet and send it on.
++ * (Actually, it seems that the IP module will happily
++ * accept M_DATA messages without the DL_UNITDATA_IND header.)
++ */
++ while ((mp = getq(q)) != 0) {
++ if (!canputnext(q)) {
++ putbq(q, mp);
++ break;
++ }
++#ifndef NO_DLPI
++ proto = PPP_PROTOCOL(mp-&gt;b_rptr);
++ mp-&gt;b_rptr += PPP_HDRLEN;
++ hdr = allocb(sizeof(dl_unitdata_ind_t) + 2 * sizeof(uint),
++ BPRI_MED);
++ if (hdr == 0) {
++ /* XXX should put it back and use bufcall */
++ freemsg(mp);
++ continue;
++ }
++ hdr-&gt;b_datap-&gt;db_type = M_PROTO;
++ ud = (dl_unitdata_ind_t *) hdr-&gt;b_wptr;
++ hdr-&gt;b_wptr += sizeof(dl_unitdata_ind_t) + 2 * sizeof(uint);
++ hdr-&gt;b_cont = mp;
++ ud-&gt;dl_primitive = DL_UNITDATA_IND;
++ ud-&gt;dl_dest_addr_length = sizeof(uint);
++ ud-&gt;dl_dest_addr_offset = sizeof(dl_unitdata_ind_t);
++ ud-&gt;dl_src_addr_length = sizeof(uint);
++ ud-&gt;dl_src_addr_offset = ud-&gt;dl_dest_addr_offset + sizeof(uint);
++#if DL_CURRENT_VERSION &gt;= 2
++ ud-&gt;dl_group_address = 0;
++#endif
++ /* Send the DLPI client the data with the SAP they requested,
++ (e.g. ETHERTYPE_IP) rather than the PPP protocol number
++ (e.g. PPP_IP) */
++ ((uint *)(ud + 1))[0] = us-&gt;req_sap; /* dest SAP */
++ ((uint *)(ud + 1))[1] = us-&gt;req_sap; /* src SAP */
++ putnext(q, hdr);
++#else /* NO_DLPI */
++ putnext(q, mp);
++#endif /* NO_DLPI */
++ }
++ /*
++ * Now that we have consumed some packets from this queue,
++ * enable the control stream's read service routine so that we
++ * can process any packets for us that might have got queued
++ * there for flow control reasons.
++ */
++ if (us-&gt;ppa)
++ qenable(us-&gt;ppa-&gt;q);
++ }
++
++ return 0;
++}
++
++static upperstr_t *
++find_dest(ppa, proto)
++ upperstr_t *ppa;
++ int proto;
++{
++ upperstr_t *us;
++
++ for (us = ppa-&gt;next; us != 0; us = us-&gt;next)
++ if (proto == us-&gt;sap)
++ break;
++ return us;
++}
++
++#if defined (SOL2)
++/*
++ * Test upstream promiscuous conditions. As of now, only pass IPv4 and
++ * Ipv6 packets upstream (let PPP packets be decoded elsewhere).
++ */
++static upperstr_t *
++find_promisc(us, proto)
++ upperstr_t *us;
++ int proto;
++{
++
++ if ((proto != PPP_IP) &amp;&amp; (proto != PPP_IPV6))
++ return (upperstr_t *)0;
++
++ for ( ; us; us = us-&gt;next) {
++ if ((us-&gt;flags &amp; US_PROMISC) &amp;&amp; (us-&gt;state == DL_IDLE))
++ return us;
++ }
++
++ return (upperstr_t *)0;
++}
++
++/*
++ * Prepend an empty Ethernet header to msg for snoop, et al.
++ */
++static mblk_t *
++prepend_ether(us, mp, proto)
++ upperstr_t *us;
++ mblk_t *mp;
++ int proto;
++{
++ mblk_t *eh;
++ int type;
++
++ if ((eh = allocb(sizeof(struct ether_header), BPRI_HI)) == 0) {
++ freemsg(mp);
++ return (mblk_t *)0;
++ }
++
++ if (proto == PPP_IP)
++ type = ETHERTYPE_IP;
++ else if (proto == PPP_IPV6)
++ type = ETHERTYPE_IPV6;
++ else
++ type = proto; /* What else? Let decoder decide */
++
++ eh-&gt;b_wptr += sizeof(struct ether_header);
++ bzero((caddr_t)eh-&gt;b_rptr, sizeof(struct ether_header));
++ ((struct ether_header *)eh-&gt;b_rptr)-&gt;ether_type = htons((short)type);
++ eh-&gt;b_cont = mp;
++ return (eh);
++}
++
++/*
++ * Prepend DL_UNITDATA_IND mblk to msg
++ */
++static mblk_t *
++prepend_udind(us, mp, proto)
++ upperstr_t *us;
++ mblk_t *mp;
++ int proto;
++{
++ dl_unitdata_ind_t *dlu;
++ mblk_t *dh;
++ size_t size;
++
++ size = sizeof(dl_unitdata_ind_t);
++ if ((dh = allocb(size, BPRI_MED)) == 0) {
++ freemsg(mp);
++ return (mblk_t *)0;
++ }
++
++ dh-&gt;b_datap-&gt;db_type = M_PROTO;
++ dh-&gt;b_wptr = dh-&gt;b_datap-&gt;db_lim;
++ dh-&gt;b_rptr = dh-&gt;b_wptr - size;
++
++ dlu = (dl_unitdata_ind_t *)dh-&gt;b_rptr;
++ dlu-&gt;dl_primitive = DL_UNITDATA_IND;
++ dlu-&gt;dl_dest_addr_length = 0;
++ dlu-&gt;dl_dest_addr_offset = sizeof(dl_unitdata_ind_t);
++ dlu-&gt;dl_src_addr_length = 0;
++ dlu-&gt;dl_src_addr_offset = sizeof(dl_unitdata_ind_t);
++ dlu-&gt;dl_group_address = 0;
++
++ dh-&gt;b_cont = mp;
++ return (dh);
++}
++
++/*
++ * For any recognized promiscuous streams, send data upstream
++ */
++static void
++promisc_sendup(ppa, mp, proto, skip)
++ upperstr_t *ppa;
++ mblk_t *mp;
++ int proto, skip;
++{
++ mblk_t *dup_mp, *dup_dup_mp;
++ upperstr_t *prus, *nprus;
++
++ if ((prus = find_promisc(ppa, proto)) != 0) {
++ if (dup_mp = dupmsg(mp)) {
++
++ if (skip)
++ dup_mp-&gt;b_rptr += PPP_HDRLEN;
++
++ for ( ; nprus = find_promisc(prus-&gt;next, proto);
++ prus = nprus) {
++
++ if (dup_dup_mp = dupmsg(dup_mp)) {
++ if (canputnext(prus-&gt;q)) {
++ if (prus-&gt;flags &amp; US_RAWDATA) {
++ dup_dup_mp = prepend_ether(prus, dup_dup_mp, proto);
++ putnext(prus-&gt;q, dup_dup_mp);
++ } else {
++ dup_dup_mp = prepend_udind(prus, dup_dup_mp, proto);
++ putnext(prus-&gt;q, dup_dup_mp);
++ }
++ } else {
++ DPRINT(&quot;ppp_urput: data to promisc q dropped\n&quot;);
++ freemsg(dup_dup_mp);
++ }
++ }
++ }
++
++ if (canputnext(prus-&gt;q)) {
++ if (prus-&gt;flags &amp; US_RAWDATA) {
++ dup_mp = prepend_ether(prus, dup_mp, proto);
++ putnext(prus-&gt;q, dup_mp);
++ } else {
++ dup_mp = prepend_udind(prus, dup_mp, proto);
++ putnext(prus-&gt;q, dup_mp);
++ }
++ } else {
++ DPRINT(&quot;ppp_urput: data to promisc q dropped\n&quot;);
++ freemsg(dup_mp);
++ }
++ }
++ }
++}
++#endif /* defined(SOL2) */
++
++/*
++ * We simply put the message on to the associated upper control stream
++ * (either here or in ppplrsrv). That way we enter the perimeters
++ * before looking through the list of attached streams to decide which
++ * stream it should go up.
++ */
++static int
++ppplrput(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ queue_t *uq;
++ struct iocblk *iop;
++
++ switch (mp-&gt;b_datap-&gt;db_type) {
++ case M_IOCTL:
++ iop = (struct iocblk *) mp-&gt;b_rptr;
++ iop-&gt;ioc_error = EINVAL;
++ mp-&gt;b_datap-&gt;db_type = M_IOCNAK;
++ qreply(q, mp);
++ return 0;
++ case M_FLUSH:
++ if (*mp-&gt;b_rptr &amp; FLUSHR)
++ flushq(q, FLUSHDATA);
++ if (*mp-&gt;b_rptr &amp; FLUSHW) {
++ *mp-&gt;b_rptr &amp;= ~FLUSHR;
++ qreply(q, mp);
++ } else
++ freemsg(mp);
++ return 0;
++ }
++
++ /*
++ * If we can't get the lower lock straight away, queue this one
++ * rather than blocking, to avoid the possibility of deadlock.
++ */
++ if (!TRYLOCK_LOWER_R) {
++ putq(q, mp);
++ return 0;
++ }
++
++ /*
++ * Check that we're still connected to the driver.
++ */
++ uq = (queue_t *) q-&gt;q_ptr;
++ if (uq == 0) {
++ UNLOCK_LOWER;
++ DPRINT1(&quot;ppplrput: q = %x, uq = 0??\n&quot;, q);
++ freemsg(mp);
++ return 0;
++ }
++
++ /*
++ * Try to forward the message to the put routine for the upper
++ * control stream for this lower stream.
++ * If there are already messages queued here, queue this one so
++ * they don't get out of order.
++ */
++ if (queclass(mp) == QPCTL || (qsize(q) == 0 &amp;&amp; canput(uq)))
++ put(uq, mp);
++ else
++ putq(q, mp);
++
++ UNLOCK_LOWER;
++ return 0;
++}
++
++static int
++ppplrsrv(q)
++ queue_t *q;
++{
++ mblk_t *mp;
++ queue_t *uq;
++
++ /*
++ * Packets get queued here for flow control reasons
++ * or if the lrput routine couldn't get the lower lock
++ * without blocking.
++ */
++ LOCK_LOWER_R;
++ uq = (queue_t *) q-&gt;q_ptr;
++ if (uq == 0) {
++ UNLOCK_LOWER;
++ flushq(q, FLUSHALL);
++ DPRINT1(&quot;ppplrsrv: q = %x, uq = 0??\n&quot;, q);
++ return 0;
++ }
++ while ((mp = getq(q)) != 0) {
++ if (queclass(mp) == QPCTL || canput(uq))
++ put(uq, mp);
++ else {
++ putbq(q, mp);
++ break;
++ }
++ }
++ UNLOCK_LOWER;
++ return 0;
++}
++
++static int
++putctl2(q, type, code, val)
++ queue_t *q;
++ int type, code, val;
++{
++ mblk_t *mp;
++
++ mp = allocb(2, BPRI_HI);
++ if (mp == 0)
++ return 0;
++ mp-&gt;b_datap-&gt;db_type = type;
++ mp-&gt;b_wptr[0] = code;
++ mp-&gt;b_wptr[1] = val;
++ mp-&gt;b_wptr += 2;
++ putnext(q, mp);
++ return 1;
++}
++
++static int
++putctl4(q, type, code, val)
++ queue_t *q;
++ int type, code, val;
++{
++ mblk_t *mp;
++
++ mp = allocb(4, BPRI_HI);
++ if (mp == 0)
++ return 0;
++ mp-&gt;b_datap-&gt;db_type = type;
++ mp-&gt;b_wptr[0] = code;
++ ((short *)mp-&gt;b_wptr)[1] = val;
++ mp-&gt;b_wptr += 4;
++ putnext(q, mp);
++ return 1;
++}
++
++static void
++debug_dump(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ upperstr_t *us;
++ queue_t *uq, *lq;
++
++ DPRINT(&quot;ppp upper streams:\n&quot;);
++ for (us = minor_devs; us != 0; us = us-&gt;nextmn) {
++ uq = us-&gt;q;
++ DPRINT3(&quot; %d: q=%x rlev=%d&quot;,
++ us-&gt;mn, uq, (uq? qsize(uq): 0));
++ DPRINT3(&quot; wlev=%d flags=0x%b&quot;, (uq? qsize(WR(uq)): 0),
++ us-&gt;flags, &quot;\020\1priv\2control\3blocked\4last&quot;);
++ DPRINT3(&quot; state=%x sap=%x req_sap=%x&quot;, us-&gt;state, us-&gt;sap,
++ us-&gt;req_sap);
++ if (us-&gt;ppa == 0)
++ DPRINT(&quot; ppa=?\n&quot;);
++ else
++ DPRINT1(&quot; ppa=%d\n&quot;, us-&gt;ppa-&gt;ppa_id);
++ if (us-&gt;flags &amp; US_CONTROL) {
++ lq = us-&gt;lowerq;
++ DPRINT3(&quot; control for %d lq=%x rlev=%d&quot;,
++ us-&gt;ppa_id, lq, (lq? qsize(RD(lq)): 0));
++ DPRINT3(&quot; wlev=%d mru=%d mtu=%d\n&quot;,
++ (lq? qsize(lq): 0), us-&gt;mru, us-&gt;mtu);
++ }
++ }
++ mp-&gt;b_datap-&gt;db_type = M_IOCACK;
++ qreply(q, mp);
++}
++
++#ifdef FILTER_PACKETS
++#include &lt;netinet/in_systm.h&gt;
++#include &lt;netinet/ip.h&gt;
++#include &lt;netinet/udp.h&gt;
++#include &lt;netinet/tcp.h&gt;
++
++#define MAX_IPHDR 128 /* max TCP/IP header size */
++
++
++/* The following table contains a hard-coded list of protocol/port pairs.
++ * Any matching packets are either discarded unconditionally, or,
++ * if ok_if_link_up is non-zero when a connection does not currently exist
++ * (i.e., they go through if the connection is present, but never initiate
++ * a dial-out).
++ * This idea came from a post by <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dm at garage.uun.org</A> (David Mazieres)
++ */
++static struct pktfilt_tab {
++ int proto;
++ u_short port;
++ u_short ok_if_link_up;
++} pktfilt_tab[] = {
++ { IPPROTO_UDP, 520, 1 }, /* RIP, ok to pass if link is up */
++ { IPPROTO_UDP, 123, 1 }, /* NTP, don't keep up the link for it */
++ { -1, 0, 0 } /* terminator entry has port == -1 */
++};
++
++
++static int
++ip_hard_filter(us, mp, outbound)
++ upperstr_t *us;
++ mblk_t *mp;
++ int outbound;
++{
++ struct ip *ip;
++ struct pktfilt_tab *pft;
++ mblk_t *temp_mp;
++ int proto;
++ int len, hlen;
++
++
++ /* Note, the PPP header has already been pulled up in all cases */
++ proto = PPP_PROTOCOL(mp-&gt;b_rptr);
++ if (us-&gt;flags &amp; US_DBGLOG)
++ DPRINT3(&quot;ppp/%d: filter, proto=0x%x, out=%d\n&quot;, us-&gt;mn, proto, outbound);
++
++ switch (proto)
++ {
++ case PPP_IP:
++ if ((mp-&gt;b_wptr - mp-&gt;b_rptr) == PPP_HDRLEN &amp;&amp; mp-&gt;b_cont != 0) {
++ temp_mp = mp-&gt;b_cont;
++ len = msgdsize(temp_mp);
++ hlen = (len &lt; MAX_IPHDR) ? len : MAX_IPHDR;
++ PULLUP(temp_mp, hlen);
++ if (temp_mp == 0) {
++ DPRINT2(&quot;ppp/%d: filter, pullup next failed, len=%d\n&quot;,
++ us-&gt;mn, hlen);
++ mp-&gt;b_cont = 0; /* PULLUP() freed the rest */
++ freemsg(mp);
++ return 0;
++ }
++ ip = (struct ip *)mp-&gt;b_cont-&gt;b_rptr;
++ }
++ else {
++ len = msgdsize(mp);
++ hlen = (len &lt; (PPP_HDRLEN+MAX_IPHDR)) ? len : (PPP_HDRLEN+MAX_IPHDR);
++ PULLUP(mp, hlen);
++ if (mp == 0) {
++ DPRINT2(&quot;ppp/%d: filter, pullup failed, len=%d\n&quot;,
++ us-&gt;mn, hlen);
++ return 0;
++ }
++ ip = (struct ip *)(mp-&gt;b_rptr + PPP_HDRLEN);
++ }
++
++ /* For IP traffic, certain packets (e.g., RIP) may be either
++ * 1. ignored - dropped completely
++ * 2. will not initiate a connection, but
++ * will be passed if a connection is currently up.
++ */
++ for (pft=pktfilt_tab; pft-&gt;proto != -1; pft++) {
++ if (ip-&gt;ip_p == pft-&gt;proto) {
++ switch(pft-&gt;proto) {
++ case IPPROTO_UDP:
++ if (((struct udphdr *) &amp;((int *)ip)[ip-&gt;ip_hl])-&gt;uh_dport
++ == htons(pft-&gt;port)) goto endfor;
++ break;
++ case IPPROTO_TCP:
++ if (((struct tcphdr *) &amp;((int *)ip)[ip-&gt;ip_hl])-&gt;th_dport
++ == htons(pft-&gt;port)) goto endfor;
++ break;
++ }
++ }
++ }
++ endfor:
++ if (pft-&gt;proto != -1) {
++ if (us-&gt;flags &amp; US_DBGLOG)
++ DPRINT3(&quot;ppp/%d: found IP pkt, proto=0x%x (%d)\n&quot;,
++ us-&gt;mn, pft-&gt;proto, pft-&gt;port);
++ /* Discard if not connected, or if not pass_with_link_up */
++ /* else, if link is up let go by, but don't update time */
++ return pft-&gt;ok_if_link_up? -1: 0;
++ }
++ break;
++ } /* end switch (proto) */
++
++ return 1;
++}
++#endif /* FILTER_PACKETS */
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/solaris/ppp.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/solaris/ppp.conf
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/solaris/ppp.conf (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/solaris/ppp.conf 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1 @@
++name=&quot;ppp&quot; parent=&quot;pseudo&quot; instance=0;
+
+Added: drakx/trunk/mdk-stage1/ppp/solaris/ppp_ahdlc.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/solaris/ppp_ahdlc.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/solaris/ppp_ahdlc.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,878 @@
++/*
++ * ppp_ahdlc.c - STREAMS module for doing PPP asynchronous HDLC.
++ *
++ * Re-written by Adi Masputra &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">adi.masputra at sun.com</A>&gt;, based on
++ * the original ppp_ahdlc.c
++ *
++ * Copyright (c) 2000 by Sun Microsystems, Inc.
++ * All rights reserved.
++ *
++ * Permission to use, copy, modify, and distribute this software and its
++ * documentation is hereby granted, provided that the above copyright
++ * notice appears in all copies.
++ *
++ * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
++ * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
++ * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
++ * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
++ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
++ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
++ *
++ * Copyright (c) 1994 The Australian National University.
++ * All rights reserved.
++ *
++ * Permission to use, copy, modify, and distribute this software and its
++ * documentation is hereby granted, provided that the above copyright
++ * notice appears in all copies. This software is provided without any
++ * warranty, express or implied. The Australian National University
++ * makes no representations about the suitability of this software for
++ * any purpose.
++ *
++ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
++ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
++ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
++ * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
++ * OF SUCH DAMAGE.
++ *
++ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
++ * ON AN &quot;AS IS&quot; BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
++ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
++ * OR MODIFICATIONS.
++ *
++ * $Id: ppp_ahdlc.c 195720 2001-06-11 11:44:34Z gc $
++ */
++
++/*
++ * This file is used under Solaris 2, SVR4, SunOS 4, and Digital UNIX.
++ */
++#include &lt;sys/types.h&gt;
++#include &lt;sys/param.h&gt;
++#include &lt;sys/stream.h&gt;
++#include &lt;sys/errno.h&gt;
++
++#ifdef SVR4
++#include &lt;sys/conf.h&gt;
++#include &lt;sys/kmem.h&gt;
++#include &lt;sys/cmn_err.h&gt;
++#include &lt;sys/ddi.h&gt;
++#else
++#include &lt;sys/user.h&gt;
++#ifdef __osf__
++#include &lt;sys/cmn_err.h&gt;
++#endif
++#endif /* SVR4 */
++
++#include &lt;net/ppp_defs.h&gt;
++#include &lt;net/pppio.h&gt;
++#include &quot;ppp_mod.h&quot;
++
++/*
++ * Right now, mutex is only enabled for Solaris 2.x
++ */
++#if defined(SOL2)
++#define USE_MUTEX
++#endif /* SOL2 */
++
++/*
++ * intpointer_t and uintpointer_t are signed and unsigned integer types
++ * large enough to hold any data pointer; that is, data pointers can be
++ * assigned into or from these integer types without losing precision.
++ * On recent Solaris releases, these types are defined in sys/int_types.h,
++ * but not on SunOS 4.x or the earlier Solaris versions.
++ */
++#if defined(_LP64) || defined(_I32LPx)
++typedef long intpointer_t;
++typedef unsigned long uintpointer_t;
++#else
++typedef int intpointer_t;
++typedef unsigned int uintpointer_t;
++#endif
++
++MOD_OPEN_DECL(ahdlc_open);
++MOD_CLOSE_DECL(ahdlc_close);
++static int ahdlc_wput __P((queue_t *, mblk_t *));
++static int ahdlc_rput __P((queue_t *, mblk_t *));
++static void ahdlc_encode __P((queue_t *, mblk_t *));
++static void ahdlc_decode __P((queue_t *, mblk_t *));
++static int msg_byte __P((mblk_t *, unsigned int));
++
++#if defined(SOL2)
++/*
++ * Don't send HDLC start flag is last transmit is within 1.5 seconds -
++ * FLAG_TIME is defined is microseconds
++ */
++#define FLAG_TIME 1500
++#define ABS(x) (x &gt;= 0 ? x : (-x))
++#endif /* SOL2 */
++
++/*
++ * Extract byte i of message mp
++ */
++#define MSG_BYTE(mp, i) ((i) &lt; (mp)-&gt;b_wptr - (mp)-&gt;b_rptr? (mp)-&gt;b_rptr[i]: \
++ msg_byte((mp), (i)))
++
++/*
++ * Is this LCP packet one we have to transmit using LCP defaults?
++ */
++#define LCP_USE_DFLT(mp) (1 &lt;= (code = MSG_BYTE((mp), 4)) &amp;&amp; code &lt;= 7)
++
++/*
++ * Standard STREAMS declarations
++ */
++static struct module_info minfo = {
++ 0x7d23, &quot;ppp_ahdl&quot;, 0, INFPSZ, 32768, 512
++};
++
++static struct qinit rinit = {
++ ahdlc_rput, NULL, ahdlc_open, ahdlc_close, NULL, &amp;minfo, NULL
++};
++
++static struct qinit winit = {
++ ahdlc_wput, NULL, NULL, NULL, NULL, &amp;minfo, NULL
++};
++
++#if defined(SVR4) &amp;&amp; !defined(SOL2)
++int phdldevflag = 0;
++#define ppp_ahdlcinfo phdlinfo
++#endif /* defined(SVR4) &amp;&amp; !defined(SOL2) */
++
++struct streamtab ppp_ahdlcinfo = {
++ &amp;rinit, /* ptr to st_rdinit */
++ &amp;winit, /* ptr to st_wrinit */
++ NULL, /* ptr to st_muxrinit */
++ NULL, /* ptr to st_muxwinit */
++#if defined(SUNOS4)
++ NULL /* ptr to ptr to st_modlist */
++#endif /* SUNOS4 */
++};
++
++#if defined(SUNOS4)
++int ppp_ahdlc_count = 0; /* open counter */
++#endif /* SUNOS4 */
++
++/*
++ * Per-stream state structure
++ */
++typedef struct ahdlc_state {
++#if defined(USE_MUTEX)
++ kmutex_t lock; /* lock for this structure */
++#endif /* USE_MUTEX */
++ int flags; /* link flags */
++ mblk_t *rx_buf; /* ptr to receive buffer */
++ int rx_buf_size; /* receive buffer size */
++ ushort_t infcs; /* calculated rx HDLC FCS */
++ u_int32_t xaccm[8]; /* 256-bit xmit ACCM */
++ u_int32_t raccm; /* 32-bit rcv ACCM */
++ int mtu; /* interface MTU */
++ int mru; /* link MRU */
++ int unit; /* current PPP unit number */
++ struct pppstat stats; /* statistic structure */
++#if defined(SOL2)
++ clock_t flag_time; /* time in usec between flags */
++ clock_t lbolt; /* last updated lbolt */
++#endif /* SOL2 */
++} ahdlc_state_t;
++
++/*
++ * Values for flags
++ */
++#define ESCAPED 0x100 /* last saw escape char on input */
++#define IFLUSH 0x200 /* flushing input due to error */
++
++/*
++ * RCV_B7_1, etc., defined in net/pppio.h, are stored in flags also.
++ */
++#define RCV_FLAGS (RCV_B7_1|RCV_B7_0|RCV_ODDP|RCV_EVNP)
++
++/*
++ * FCS lookup table as calculated by genfcstab.
++ */
++static u_short fcstab[256] = {
++ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
++ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
++ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
++ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
++ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
++ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
++ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
++ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
++ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
++ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
++ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
++ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
++ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
++ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
++ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
++ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
++ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
++ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
++ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
++ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
++ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
++ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
++ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
++ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
++ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
++ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
++ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
++ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
++ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
++ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
++ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
++ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
++};
++
++static u_int32_t paritytab[8] =
++{
++ 0x96696996, 0x69969669, 0x69969669, 0x96696996,
++ 0x69969669, 0x96696996, 0x96696996, 0x69969669
++};
++
++/*
++ * STREAMS module open (entry) point
++ */
++MOD_OPEN(ahdlc_open)
++{
++ ahdlc_state_t *state;
++
++ /*
++ * Return if it's already opened
++ */
++ if (q-&gt;q_ptr) {
++ return 0;
++ }
++
++ /*
++ * This can only be opened as a module
++ */
++ if (sflag != MODOPEN) {
++ return 0;
++ }
++
++ state = (ahdlc_state_t *) ALLOC_NOSLEEP(sizeof(ahdlc_state_t));
++ if (state == 0)
++ OPEN_ERROR(ENOSR);
++ bzero((caddr_t) state, sizeof(ahdlc_state_t));
++
++ q-&gt;q_ptr = (caddr_t) state;
++ WR(q)-&gt;q_ptr = (caddr_t) state;
++
++#if defined(USE_MUTEX)
++ mutex_init(&amp;state-&gt;lock, NULL, MUTEX_DEFAULT, NULL);
++ mutex_enter(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++
++ state-&gt;xaccm[0] = ~0; /* escape 0x00 through 0x1f */
++ state-&gt;xaccm[3] = 0x60000000; /* escape 0x7d and 0x7e */
++ state-&gt;mru = PPP_MRU; /* default of 1500 bytes */
++#if defined(SOL2)
++ state-&gt;flag_time = drv_usectohz(FLAG_TIME);
++#endif /* SOL2 */
++
++#if defined(USE_MUTEX)
++ mutex_exit(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++
++#if defined(SUNOS4)
++ ppp_ahdlc_count++;
++#endif /* SUNOS4 */
++
++ qprocson(q);
++
++ return 0;
++}
++
++/*
++ * STREAMS module close (exit) point
++ */
++MOD_CLOSE(ahdlc_close)
++{
++ ahdlc_state_t *state;
++
++ qprocsoff(q);
++
++ state = (ahdlc_state_t *) q-&gt;q_ptr;
++
++ if (state == 0) {
++ DPRINT(&quot;state == 0 in ahdlc_close\n&quot;);
++ return 0;
++ }
++
++#if defined(USE_MUTEX)
++ mutex_enter(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++
++ if (state-&gt;rx_buf != 0) {
++ freemsg(state-&gt;rx_buf);
++ state-&gt;rx_buf = 0;
++ }
++
++#if defined(USE_MUTEX)
++ mutex_exit(&amp;state-&gt;lock);
++ mutex_destroy(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++
++ FREE(q-&gt;q_ptr, sizeof(ahdlc_state_t));
++ q-&gt;q_ptr = NULL;
++ OTHERQ(q)-&gt;q_ptr = NULL;
++
++#if defined(SUNOS4)
++ if (ppp_ahdlc_count)
++ ppp_ahdlc_count--;
++#endif /* SUNOS4 */
++
++ return 0;
++}
++
++/*
++ * Write side put routine
++ */
++static int
++ahdlc_wput(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ ahdlc_state_t *state;
++ struct iocblk *iop;
++ int error;
++ mblk_t *np;
++ struct ppp_stats *psp;
++
++ state = (ahdlc_state_t *) q-&gt;q_ptr;
++ if (state == 0) {
++ DPRINT(&quot;state == 0 in ahdlc_wput\n&quot;);
++ freemsg(mp);
++ return 0;
++ }
++
++ switch (mp-&gt;b_datap-&gt;db_type) {
++ case M_DATA:
++ /*
++ * A data packet - do character-stuffing and FCS, and
++ * send it onwards.
++ */
++ ahdlc_encode(q, mp);
++ freemsg(mp);
++ break;
++
++ case M_IOCTL:
++ iop = (struct iocblk *) mp-&gt;b_rptr;
++ error = EINVAL;
++ switch (iop-&gt;ioc_cmd) {
++ case PPPIO_XACCM:
++ if ((iop-&gt;ioc_count &lt; sizeof(u_int32_t)) ||
++ (iop-&gt;ioc_count &gt; sizeof(ext_accm))) {
++ break;
++ }
++ if (mp-&gt;b_cont == 0) {
++ DPRINT1(&quot;ahdlc_wput/%d: PPPIO_XACCM b_cont = 0!\n&quot;, state-&gt;unit);
++ break;
++ }
++#if defined(USE_MUTEX)
++ mutex_enter(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ bcopy((caddr_t)mp-&gt;b_cont-&gt;b_rptr, (caddr_t)state-&gt;xaccm,
++ iop-&gt;ioc_count);
++ state-&gt;xaccm[2] &amp;= ~0x40000000; /* don't escape 0x5e */
++ state-&gt;xaccm[3] |= 0x60000000; /* do escape 0x7d, 0x7e */
++#if defined(USE_MUTEX)
++ mutex_exit(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ iop-&gt;ioc_count = 0;
++ error = 0;
++ break;
++
++ case PPPIO_RACCM:
++ if (iop-&gt;ioc_count != sizeof(u_int32_t))
++ break;
++ if (mp-&gt;b_cont == 0) {
++ DPRINT1(&quot;ahdlc_wput/%d: PPPIO_RACCM b_cont = 0!\n&quot;, state-&gt;unit);
++ break;
++ }
++#if defined(USE_MUTEX)
++ mutex_enter(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ bcopy((caddr_t)mp-&gt;b_cont-&gt;b_rptr, (caddr_t)&amp;state-&gt;raccm,
++ sizeof(u_int32_t));
++#if defined(USE_MUTEX)
++ mutex_exit(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ iop-&gt;ioc_count = 0;
++ error = 0;
++ break;
++
++ case PPPIO_GCLEAN:
++ np = allocb(sizeof(int), BPRI_HI);
++ if (np == 0) {
++ error = ENOSR;
++ break;
++ }
++ if (mp-&gt;b_cont != 0)
++ freemsg(mp-&gt;b_cont);
++ mp-&gt;b_cont = np;
++#if defined(USE_MUTEX)
++ mutex_enter(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ *(int *)np-&gt;b_wptr = state-&gt;flags &amp; RCV_FLAGS;
++#if defined(USE_MUTEX)
++ mutex_exit(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ np-&gt;b_wptr += sizeof(int);
++ iop-&gt;ioc_count = sizeof(int);
++ error = 0;
++ break;
++
++ case PPPIO_GETSTAT:
++ np = allocb(sizeof(struct ppp_stats), BPRI_HI);
++ if (np == 0) {
++ error = ENOSR;
++ break;
++ }
++ if (mp-&gt;b_cont != 0)
++ freemsg(mp-&gt;b_cont);
++ mp-&gt;b_cont = np;
++ psp = (struct ppp_stats *) np-&gt;b_wptr;
++ np-&gt;b_wptr += sizeof(struct ppp_stats);
++ bzero((caddr_t)psp, sizeof(struct ppp_stats));
++ psp-&gt;p = state-&gt;stats;
++ iop-&gt;ioc_count = sizeof(struct ppp_stats);
++ error = 0;
++ break;
++
++ case PPPIO_LASTMOD:
++ /* we knew this anyway */
++ error = 0;
++ break;
++
++ default:
++ error = -1;
++ break;
++ }
++
++ if (error &lt; 0)
++ putnext(q, mp);
++ else if (error == 0) {
++ mp-&gt;b_datap-&gt;db_type = M_IOCACK;
++ qreply(q, mp);
++ } else {
++ mp-&gt;b_datap-&gt;db_type = M_IOCNAK;
++ iop-&gt;ioc_count = 0;
++ iop-&gt;ioc_error = error;
++ qreply(q, mp);
++ }
++ break;
++
++ case M_CTL:
++ switch (*mp-&gt;b_rptr) {
++ case PPPCTL_MTU:
++#if defined(USE_MUTEX)
++ mutex_enter(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ state-&gt;mtu = ((unsigned short *)mp-&gt;b_rptr)[1];
++#if defined(USE_MUTEX)
++ mutex_exit(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ freemsg(mp);
++ break;
++ case PPPCTL_MRU:
++#if defined(USE_MUTEX)
++ mutex_enter(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ state-&gt;mru = ((unsigned short *)mp-&gt;b_rptr)[1];
++#if defined(USE_MUTEX)
++ mutex_exit(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ freemsg(mp);
++ break;
++ case PPPCTL_UNIT:
++#if defined(USE_MUTEX)
++ mutex_enter(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ state-&gt;unit = mp-&gt;b_rptr[1];
++#if defined(USE_MUTEX)
++ mutex_exit(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ break;
++ default:
++ putnext(q, mp);
++ }
++ break;
++
++ default:
++ putnext(q, mp);
++ }
++
++ return 0;
++}
++
++/*
++ * Read side put routine
++ */
++static int
++ahdlc_rput(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ ahdlc_state_t *state;
++
++ state = (ahdlc_state_t *) q-&gt;q_ptr;
++ if (state == 0) {
++ DPRINT(&quot;state == 0 in ahdlc_rput\n&quot;);
++ freemsg(mp);
++ return 0;
++ }
++
++ switch (mp-&gt;b_datap-&gt;db_type) {
++ case M_DATA:
++ ahdlc_decode(q, mp);
++ freemsg(mp);
++ break;
++
++ case M_HANGUP:
++#if defined(USE_MUTEX)
++ mutex_enter(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ if (state-&gt;rx_buf != 0) {
++ /* XXX would like to send this up for debugging */
++ freemsg(state-&gt;rx_buf);
++ state-&gt;rx_buf = 0;
++ }
++ state-&gt;flags = IFLUSH;
++#if defined(USE_MUTEX)
++ mutex_exit(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ putnext(q, mp);
++ break;
++
++ default:
++ putnext(q, mp);
++ }
++ return 0;
++}
++
++/*
++ * Extract bit c from map m, to determine if c needs to be escaped
++ */
++#define IN_TX_MAP(c, m) ((m)[(c) &gt;&gt; 5] &amp; (1 &lt;&lt; ((c) &amp; 0x1f)))
++
++static void
++ahdlc_encode(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ ahdlc_state_t *state;
++ u_int32_t *xaccm, loc_xaccm[8];
++ ushort_t fcs;
++ size_t outmp_len;
++ mblk_t *outmp, *tmp;
++ uchar_t *dp, fcs_val;
++ int is_lcp, code;
++#if defined(SOL2)
++ clock_t lbolt;
++#endif /* SOL2 */
++
++ if (msgdsize(mp) &lt; 4) {
++ return;
++ }
++
++ state = (ahdlc_state_t *)q-&gt;q_ptr;
++#if defined(USE_MUTEX)
++ mutex_enter(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++
++ /*
++ * Allocate an output buffer large enough to handle a case where all
++ * characters need to be escaped
++ */
++ outmp_len = (msgdsize(mp) &lt;&lt; 1) + /* input block x 2 */
++ (sizeof(fcs) &lt;&lt; 2) + /* HDLC FCS x 4 */
++ (sizeof(uchar_t) &lt;&lt; 1); /* HDLC flags x 2 */
++
++ outmp = allocb(outmp_len, BPRI_MED);
++ if (outmp == NULL) {
++ state-&gt;stats.ppp_oerrors++;
++#if defined(USE_MUTEX)
++ mutex_exit(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++ putctl1(RD(q)-&gt;q_next, M_CTL, PPPCTL_OERROR);
++ return;
++ }
++
++#if defined(SOL2)
++ /*
++ * Check if our last transmit happenned within flag_time, using
++ * the system's LBOLT value in clock ticks
++ */
++ if (drv_getparm(LBOLT, &amp;lbolt) != -1) {
++ if (ABS((clock_t)lbolt - state-&gt;lbolt) &gt; state-&gt;flag_time) {
++ *outmp-&gt;b_wptr++ = PPP_FLAG;
++ }
++ state-&gt;lbolt = lbolt;
++ } else {
++ *outmp-&gt;b_wptr++ = PPP_FLAG;
++ }
++#else
++ /*
++ * If the driver below still has a message to process, skip the
++ * HDLC flag, otherwise, put one in the beginning
++ */
++ if (qsize(q-&gt;q_next) == 0) {
++ *outmp-&gt;b_wptr++ = PPP_FLAG;
++ }
++#endif
++
++ /*
++ * All control characters must be escaped for LCP packets with code
++ * values between 1 (Conf-Req) and 7 (Code-Rej).
++ */
++ is_lcp = ((MSG_BYTE(mp, 0) == PPP_ALLSTATIONS) &amp;&amp;
++ (MSG_BYTE(mp, 1) == PPP_UI) &amp;&amp;
++ (MSG_BYTE(mp, 2) == (PPP_LCP &gt;&gt; 8)) &amp;&amp;
++ (MSG_BYTE(mp, 3) == (PPP_LCP &amp; 0xff)) &amp;&amp;
++ LCP_USE_DFLT(mp));
++
++ xaccm = state-&gt;xaccm;
++ if (is_lcp) {
++ bcopy((caddr_t)state-&gt;xaccm, (caddr_t)loc_xaccm, sizeof(loc_xaccm));
++ loc_xaccm[0] = ~0; /* force escape on 0x00 through 0x1f */
++ xaccm = loc_xaccm;
++ }
++
++ fcs = PPP_INITFCS; /* Initial FCS is 0xffff */
++
++ /*
++ * Process this block and the rest (if any) attached to the this one
++ */
++ for (tmp = mp; tmp; tmp = tmp-&gt;b_cont) {
++ if (tmp-&gt;b_datap-&gt;db_type == M_DATA) {
++ for (dp = tmp-&gt;b_rptr; dp &lt; tmp-&gt;b_wptr; dp++) {
++ fcs = PPP_FCS(fcs, *dp);
++ if (IN_TX_MAP(*dp, xaccm)) {
++ *outmp-&gt;b_wptr++ = PPP_ESCAPE;
++ *outmp-&gt;b_wptr++ = *dp ^ PPP_TRANS;
++ } else {
++ *outmp-&gt;b_wptr++ = *dp;
++ }
++ }
++ } else {
++ continue; /* skip if db_type is something other than M_DATA */
++ }
++ }
++
++ /*
++ * Append the HDLC FCS, making sure that escaping is done on any
++ * necessary bytes
++ */
++ fcs_val = (fcs ^ 0xffff) &amp; 0xff;
++ if (IN_TX_MAP(fcs_val, xaccm)) {
++ *outmp-&gt;b_wptr++ = PPP_ESCAPE;
++ *outmp-&gt;b_wptr++ = fcs_val ^ PPP_TRANS;
++ } else {
++ *outmp-&gt;b_wptr++ = fcs_val;
++ }
++
++ fcs_val = ((fcs ^ 0xffff) &gt;&gt; 8) &amp; 0xff;
++ if (IN_TX_MAP(fcs_val, xaccm)) {
++ *outmp-&gt;b_wptr++ = PPP_ESCAPE;
++ *outmp-&gt;b_wptr++ = fcs_val ^ PPP_TRANS;
++ } else {
++ *outmp-&gt;b_wptr++ = fcs_val;
++ }
++
++ /*
++ * And finally, append the HDLC flag, and send it away
++ */
++ *outmp-&gt;b_wptr++ = PPP_FLAG;
++
++ state-&gt;stats.ppp_obytes += msgdsize(outmp);
++ state-&gt;stats.ppp_opackets++;
++
++#if defined(USE_MUTEX)
++ mutex_exit(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++
++ putnext(q, outmp);
++ return;
++}
++
++/*
++ * Checks the 32-bit receive ACCM to see if the byte needs un-escaping
++ */
++#define IN_RX_MAP(c, m) ((((unsigned int) (uchar_t) (c)) &lt; 0x20) &amp;&amp; \
++ (m) &amp; (1 &lt;&lt; (c)))
++
++
++/*
++ * Process received characters.
++ */
++static void
++ahdlc_decode(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ ahdlc_state_t *state;
++ mblk_t *om;
++ uchar_t *dp;
++ ushort_t fcs;
++#if defined(SOL2)
++ mblk_t *zmp;
++#endif /* SOL2 */
++
++#if defined(SOL2)
++ /*
++ * In case the driver (or something below) doesn't send
++ * data upstream in one message block, concatenate everything
++ */
++ if (!((mp-&gt;b_wptr - mp-&gt;b_rptr == msgdsize(mp)) &amp;&amp;
++ ((intpointer_t)mp-&gt;b_rptr % sizeof(intpointer_t) == 0))) {
++
++ zmp = msgpullup(mp, -1);
++ freemsg(mp);
++ mp = zmp;
++ if (mp == 0)
++ return;
++ }
++#endif /* SOL2 */
++
++ state = (ahdlc_state_t *) q-&gt;q_ptr;
++
++#if defined(USE_MUTEX)
++ mutex_enter(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++
++ state-&gt;stats.ppp_ibytes += msgdsize(mp);
++
++ for (dp = mp-&gt;b_rptr; dp &lt; mp-&gt;b_wptr; dp++) {
++
++ /*
++ * This should detect the lack of 8-bit communication channel
++ * which is necessary for PPP to work. In addition, it also
++ * checks on the parity.
++ */
++ if (*dp &amp; 0x80)
++ state-&gt;flags |= RCV_B7_1;
++ else
++ state-&gt;flags |= RCV_B7_0;
++
++ if (paritytab[*dp &gt;&gt; 5] &amp; (1 &lt;&lt; (*dp &amp; 0x1f)))
++ state-&gt;flags |= RCV_ODDP;
++ else
++ state-&gt;flags |= RCV_EVNP;
++
++ /*
++ * So we have a HDLC flag ...
++ */
++ if (*dp == PPP_FLAG) {
++
++ /*
++ * If we think that it marks the beginning of the frame,
++ * then continue to process the next octects
++ */
++ if ((state-&gt;flags &amp; IFLUSH) ||
++ (state-&gt;rx_buf == 0) ||
++ (msgdsize(state-&gt;rx_buf) == 0)) {
++
++ state-&gt;flags &amp;= ~IFLUSH;
++ continue;
++ }
++
++ /*
++ * We get here because the above condition isn't true,
++ * in which case the HDLC flag was there to mark the end
++ * of the frame (or so we think)
++ */
++ om = state-&gt;rx_buf;
++
++ if (state-&gt;infcs == PPP_GOODFCS) {
++ state-&gt;stats.ppp_ipackets++;
++ adjmsg(om, -PPP_FCSLEN);
++ putnext(q, om);
++ } else {
++ DPRINT2(&quot;ppp%d: bad fcs (len=%d)\n&quot;,
++ state-&gt;unit, msgdsize(state-&gt;rx_buf));
++ freemsg(state-&gt;rx_buf);
++ state-&gt;flags &amp;= ~(IFLUSH | ESCAPED);
++ state-&gt;stats.ppp_ierrors++;
++ putctl1(q-&gt;q_next, M_CTL, PPPCTL_IERROR);
++ }
++
++ state-&gt;rx_buf = 0;
++ continue;
++ }
++
++ if (state-&gt;flags &amp; IFLUSH) {
++ continue;
++ }
++
++ /*
++ * Allocate a receive buffer, large enough to store a frame (after
++ * un-escaping) of at least 1500 octets. If MRU is negotiated to
++ * be more than the default, then allocate that much. In addition,
++ * we add an extra 32-bytes for a fudge factor
++ */
++ if (state-&gt;rx_buf == 0) {
++ state-&gt;rx_buf_size = (state-&gt;mru &lt; PPP_MRU ? PPP_MRU : state-&gt;mru);
++ state-&gt;rx_buf_size += (sizeof(u_int32_t) &lt;&lt; 3);
++ state-&gt;rx_buf = allocb(state-&gt;rx_buf_size, BPRI_MED);
++
++ /*
++ * If allocation fails, try again on the next frame
++ */
++ if (state-&gt;rx_buf == 0) {
++ state-&gt;flags |= IFLUSH;
++ continue;
++ }
++ state-&gt;flags &amp;= ~(IFLUSH | ESCAPED);
++ state-&gt;infcs = PPP_INITFCS;
++ }
++
++ if (*dp == PPP_ESCAPE) {
++ state-&gt;flags |= ESCAPED;
++ continue;
++ }
++
++ /*
++ * Make sure we un-escape the necessary characters, as well as the
++ * ones in our receive async control character map
++ */
++ if (state-&gt;flags &amp; ESCAPED) {
++ *dp ^= PPP_TRANS;
++ state-&gt;flags &amp;= ~ESCAPED;
++ } else if (IN_RX_MAP(*dp, state-&gt;raccm))
++ continue;
++
++ /*
++ * Unless the peer lied to us about the negotiated MRU, we should
++ * never get a frame which is too long. If it happens, toss it away
++ * and grab the next incoming one
++ */
++ if (msgdsize(state-&gt;rx_buf) &lt; state-&gt;rx_buf_size) {
++ state-&gt;infcs = PPP_FCS(state-&gt;infcs, *dp);
++ *state-&gt;rx_buf-&gt;b_wptr++ = *dp;
++ } else {
++ DPRINT2(&quot;ppp%d: frame too long (%d)\n&quot;,
++ state-&gt;unit, msgdsize(state-&gt;rx_buf));
++ freemsg(state-&gt;rx_buf);
++ state-&gt;rx_buf = 0;
++ state-&gt;flags |= IFLUSH;
++ }
++ }
++
++#if defined(USE_MUTEX)
++ mutex_exit(&amp;state-&gt;lock);
++#endif /* USE_MUTEX */
++}
++
++static int
++msg_byte(mp, i)
++ mblk_t *mp;
++ unsigned int i;
++{
++ while (mp != 0 &amp;&amp; i &gt;= mp-&gt;b_wptr - mp-&gt;b_rptr)
++ mp = mp-&gt;b_cont;
++ if (mp == 0)
++ return -1;
++ return mp-&gt;b_rptr[i];
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/solaris/ppp_ahdlc.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/solaris/ppp_ahdlc_mod.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/solaris/ppp_ahdlc_mod.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/solaris/ppp_ahdlc_mod.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,49 @@
++#include &lt;sys/types.h&gt;
++#include &lt;sys/param.h&gt;
++#include &lt;sys/conf.h&gt;
++#include &lt;sys/modctl.h&gt;
++#include &lt;sys/sunddi.h&gt;
++
++extern struct streamtab ppp_ahdlcinfo;
++
++static struct fmodsw fsw = {
++ &quot;ppp_ahdl&quot;,
++ &amp;ppp_ahdlcinfo,
++ D_NEW | D_MP | D_MTQPAIR
++};
++
++extern struct mod_ops mod_strmodops;
++
++static struct modlstrmod modlstrmod = {
++ &amp;mod_strmodops,
++ &quot;PPP async HDLC module&quot;,
++ &amp;fsw
++};
++
++static struct modlinkage modlinkage = {
++ MODREV_1,
++ (void *) &amp;modlstrmod,
++ NULL
++};
++
++/*
++ * Entry points for modloading.
++ */
++int
++_init(void)
++{
++ return mod_install(&amp;modlinkage);
++}
++
++int
++_fini(void)
++{
++ return mod_remove(&amp;modlinkage);
++}
++
++int
++_info(mip)
++ struct modinfo *mip;
++{
++ return mod_info(&amp;modlinkage, mip);
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/solaris/ppp_ahdlc_mod.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/solaris/ppp_comp.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/solaris/ppp_comp.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/solaris/ppp_comp.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1126 @@
++/*
++ * ppp_comp.c - STREAMS module for kernel-level compression and CCP support.
++ *
++ * Copyright (c) 1994 The Australian National University.
++ * All rights reserved.
++ *
++ * Permission to use, copy, modify, and distribute this software and its
++ * documentation is hereby granted, provided that the above copyright
++ * notice appears in all copies. This software is provided without any
++ * warranty, express or implied. The Australian National University
++ * makes no representations about the suitability of this software for
++ * any purpose.
++ *
++ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
++ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
++ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
++ * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
++ * OF SUCH DAMAGE.
++ *
++ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
++ * ON AN &quot;AS IS&quot; BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
++ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
++ * OR MODIFICATIONS.
++ *
++ * $Id: ppp_comp.c 195720 2001-06-11 11:44:34Z gc $
++ */
++
++/*
++ * This file is used under SVR4, Solaris 2, SunOS 4, and Digital UNIX.
++ */
++
++#include &lt;sys/types.h&gt;
++#include &lt;sys/param.h&gt;
++#include &lt;sys/errno.h&gt;
++#include &lt;sys/stream.h&gt;
++
++#ifdef SVR4
++#include &lt;sys/conf.h&gt;
++#include &lt;sys/cmn_err.h&gt;
++#include &lt;sys/ddi.h&gt;
++#else
++#include &lt;sys/user.h&gt;
++#ifdef __osf__
++#include &lt;sys/cmn_err.h&gt;
++#endif
++#endif /* SVR4 */
++
++#include &lt;net/ppp_defs.h&gt;
++#include &lt;net/pppio.h&gt;
++#include &quot;ppp_mod.h&quot;
++
++#ifdef __osf__
++#include &lt;sys/mbuf.h&gt;
++#include &lt;sys/protosw.h&gt;
++#endif
++
++#include &lt;netinet/in.h&gt;
++#include &lt;netinet/in_systm.h&gt;
++#include &lt;netinet/ip.h&gt;
++#include &lt;net/vjcompress.h&gt;
++
++#define PACKETPTR mblk_t *
++#include &lt;net/ppp-comp.h&gt;
++
++MOD_OPEN_DECL(ppp_comp_open);
++MOD_CLOSE_DECL(ppp_comp_close);
++static int ppp_comp_rput __P((queue_t *, mblk_t *));
++static int ppp_comp_rsrv __P((queue_t *));
++static int ppp_comp_wput __P((queue_t *, mblk_t *));
++static int ppp_comp_wsrv __P((queue_t *));
++static void ppp_comp_ccp __P((queue_t *, mblk_t *, int));
++static int msg_byte __P((mblk_t *, unsigned int));
++
++/* Extract byte i of message mp. */
++#define MSG_BYTE(mp, i) ((i) &lt; (mp)-&gt;b_wptr - (mp)-&gt;b_rptr? (mp)-&gt;b_rptr[i]: \
++ msg_byte((mp), (i)))
++
++/* Is this LCP packet one we have to transmit using LCP defaults? */
++#define LCP_USE_DFLT(mp) (1 &lt;= (code = MSG_BYTE((mp), 4)) &amp;&amp; code &lt;= 7)
++
++#define PPP_COMP_ID 0xbadf
++static struct module_info minfo = {
++#ifdef PRIOQ
++ PPP_COMP_ID, &quot;ppp_comp&quot;, 0, INFPSZ, 16512, 16384,
++#else
++ PPP_COMP_ID, &quot;ppp_comp&quot;, 0, INFPSZ, 16384, 4096,
++#endif
++};
++
++static struct qinit r_init = {
++ ppp_comp_rput, ppp_comp_rsrv, ppp_comp_open, ppp_comp_close,
++ NULL, &amp;minfo, NULL
++};
++
++static struct qinit w_init = {
++ ppp_comp_wput, ppp_comp_wsrv, NULL, NULL, NULL, &amp;minfo, NULL
++};
++
++#if defined(SVR4) &amp;&amp; !defined(SOL2)
++int pcmpdevflag = 0;
++#define ppp_compinfo pcmpinfo
++#endif
++struct streamtab ppp_compinfo = {
++ &amp;r_init, &amp;w_init, NULL, NULL
++};
++
++int ppp_comp_count; /* number of module instances in use */
++
++#ifdef __osf__
++
++static void ppp_comp_alloc __P((comp_state_t *));
++typedef struct memreq {
++ unsigned char comp_opts[20];
++ int cmd;
++ int thread_status;
++ char *returned_mem;
++} memreq_t;
++
++#endif
++
++typedef struct comp_state {
++ int flags;
++ int mru;
++ int mtu;
++ int unit;
++ struct compressor *xcomp;
++ void *xstate;
++ struct compressor *rcomp;
++ void *rstate;
++ struct vjcompress vj_comp;
++ int vj_last_ierrors;
++ struct pppstat stats;
++#ifdef __osf__
++ memreq_t memreq;
++ thread_t thread;
++#endif
++} comp_state_t;
++
++
++#ifdef __osf__
++extern task_t first_task;
++#endif
++
++/* Bits in flags are as defined in pppio.h. */
++#define CCP_ERR (CCP_ERROR | CCP_FATALERROR)
++#define LAST_MOD 0x1000000 /* no ppp modules below us */
++#define DBGLOG 0x2000000 /* log debugging stuff */
++
++#define MAX_IPHDR 128 /* max TCP/IP header size */
++#define MAX_VJHDR 20 /* max VJ compressed header size (?) */
++
++#undef MIN /* just in case */
++#define MIN(a, b) ((a) &lt; (b)? (a): (b))
++
++/*
++ * List of compressors we know about.
++ */
++
++#if DO_BSD_COMPRESS
++extern struct compressor ppp_bsd_compress;
++#endif
++#if DO_DEFLATE
++extern struct compressor ppp_deflate, ppp_deflate_draft;
++#endif
++
++struct compressor *ppp_compressors[] = {
++#if DO_BSD_COMPRESS
++ &amp;ppp_bsd_compress,
++#endif
++#if DO_DEFLATE
++ &amp;ppp_deflate,
++ &amp;ppp_deflate_draft,
++#endif
++ NULL
++};
++
++/*
++ * STREAMS module entry points.
++ */
++MOD_OPEN(ppp_comp_open)
++{
++ comp_state_t *cp;
++#ifdef __osf__
++ thread_t thread;
++#endif
++
++ if (q-&gt;q_ptr == NULL) {
++ cp = (comp_state_t *) ALLOC_SLEEP(sizeof(comp_state_t));
++ if (cp == NULL)
++ OPEN_ERROR(ENOSR);
++ bzero((caddr_t)cp, sizeof(comp_state_t));
++ WR(q)-&gt;q_ptr = q-&gt;q_ptr = (caddr_t) cp;
++ cp-&gt;mru = PPP_MRU;
++ cp-&gt;mtu = PPP_MTU;
++ cp-&gt;xstate = NULL;
++ cp-&gt;rstate = NULL;
++ vj_compress_init(&amp;cp-&gt;vj_comp, -1);
++#ifdef __osf__
++ if (!(thread = kernel_thread_w_arg(first_task, ppp_comp_alloc, (void *)cp)))
++ OPEN_ERROR(ENOSR);
++ cp-&gt;thread = thread;
++#endif
++ ++ppp_comp_count;
++ qprocson(q);
++ }
++ return 0;
++}
++
++MOD_CLOSE(ppp_comp_close)
++{
++ comp_state_t *cp;
++
++ qprocsoff(q);
++ cp = (comp_state_t *) q-&gt;q_ptr;
++ if (cp != NULL) {
++ if (cp-&gt;xstate != NULL)
++ (*cp-&gt;xcomp-&gt;comp_free)(cp-&gt;xstate);
++ if (cp-&gt;rstate != NULL)
++ (*cp-&gt;rcomp-&gt;decomp_free)(cp-&gt;rstate);
++#ifdef __osf__
++ if (!cp-&gt;thread)
++ printf(&quot;ppp_comp_close: NULL thread!\n&quot;);
++ else
++ thread_terminate(cp-&gt;thread);
++#endif
++ FREE(cp, sizeof(comp_state_t));
++ q-&gt;q_ptr = NULL;
++ OTHERQ(q)-&gt;q_ptr = NULL;
++ --ppp_comp_count;
++ }
++ return 0;
++}
++
++#ifdef __osf__
++
++/* thread for calling back to a compressor's memory allocator
++ * Needed for Digital UNIX since it's VM can't handle requests
++ * for large amounts of memory without blocking. The thread
++ * provides a context in which we can call a memory allocator
++ * that may block.
++ */
++static void
++ppp_comp_alloc(comp_state_t *cp)
++{
++ int len, cmd;
++ unsigned char *compressor_options;
++ thread_t thread;
++ void *(*comp_allocator)();
++
++
++#if defined(MAJOR_VERSION) &amp;&amp; (MAJOR_VERSION &lt;= 2)
++
++ /* In 2.x and earlier the argument gets passed
++ * in the thread structure itself. Yuck.
++ */
++ thread = current_thread();
++ cp = thread-&gt;reply_port;
++ thread-&gt;reply_port = PORT_NULL;
++
++#endif
++
++ for (;;) {
++ assert_wait((vm_offset_t)&amp;cp-&gt;memreq.thread_status, TRUE);
++ thread_block();
++
++ if (thread_should_halt(current_thread()))
++ thread_halt_self();
++ cmd = cp-&gt;memreq.cmd;
++ compressor_options = &amp;cp-&gt;memreq.comp_opts[0];
++ len = compressor_options[1];
++ if (cmd == PPPIO_XCOMP) {
++ cp-&gt;memreq.returned_mem = cp-&gt;xcomp-&gt;comp_alloc(compressor_options, len);
++ if (!cp-&gt;memreq.returned_mem) {
++ cp-&gt;memreq.thread_status = ENOSR;
++ } else {
++ cp-&gt;memreq.thread_status = 0;
++ }
++ } else {
++ cp-&gt;memreq.returned_mem = cp-&gt;rcomp-&gt;decomp_alloc(compressor_options, len);
++ if (!cp-&gt;memreq.returned_mem) {
++ cp-&gt;memreq.thread_status = ENOSR;
++ } else {
++ cp-&gt;memreq.thread_status = 0;
++ }
++ }
++ }
++}
++
++#endif /* __osf__ */
++
++/* here's the deal with memory allocation under Digital UNIX.
++ * Some other may also benefit from this...
++ * We can't ask for huge chunks of memory in a context where
++ * the caller can't be put to sleep (like, here.) The alloc
++ * is likely to fail. Instead we do this: the first time we
++ * get called, kick off a thread to do the allocation. Return
++ * immediately to the caller with EAGAIN, as an indication that
++ * they should send down the ioctl again. By the time the
++ * second call comes in it's likely that the memory allocation
++ * thread will have returned with the requested memory. We will
++ * continue to return EAGAIN however until the thread has completed.
++ * When it has, we return zero (and the memory) if the allocator
++ * was successful and ENOSR otherwise.
++ *
++ * Callers of the RCOMP and XCOMP ioctls are encouraged (but not
++ * required) to loop for some number of iterations with a small
++ * delay in the loop body (for instance a 1/10-th second &quot;sleep&quot;
++ * via select.)
++ */
++static int
++ppp_comp_wput(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ struct iocblk *iop;
++ comp_state_t *cp;
++ int error, len, n;
++ int flags, mask;
++ mblk_t *np;
++ struct compressor **comp;
++ struct ppp_stats *psp;
++ struct ppp_comp_stats *csp;
++ unsigned char *opt_data;
++ int nxslots, nrslots;
++
++ cp = (comp_state_t *) q-&gt;q_ptr;
++ if (cp == 0) {
++ DPRINT(&quot;cp == 0 in ppp_comp_wput\n&quot;);
++ freemsg(mp);
++ return 0;
++ }
++
++ switch (mp-&gt;b_datap-&gt;db_type) {
++
++ case M_DATA:
++ putq(q, mp);
++ break;
++
++ case M_IOCTL:
++ iop = (struct iocblk *) mp-&gt;b_rptr;
++ error = EINVAL;
++ switch (iop-&gt;ioc_cmd) {
++
++ case PPPIO_CFLAGS:
++ /* set/get CCP state */
++ if (iop-&gt;ioc_count != 2 * sizeof(int))
++ break;
++ if (mp-&gt;b_cont == 0) {
++ DPRINT1(&quot;ppp_comp_wput/%d: PPPIO_CFLAGS b_cont = 0!\n&quot;, cp-&gt;unit);
++ break;
++ }
++ flags = ((int *) mp-&gt;b_cont-&gt;b_rptr)[0];
++ mask = ((int *) mp-&gt;b_cont-&gt;b_rptr)[1];
++ cp-&gt;flags = (cp-&gt;flags &amp; ~mask) | (flags &amp; mask);
++ if ((mask &amp; CCP_ISOPEN) &amp;&amp; (flags &amp; CCP_ISOPEN) == 0) {
++ if (cp-&gt;xstate != NULL) {
++ (*cp-&gt;xcomp-&gt;comp_free)(cp-&gt;xstate);
++ cp-&gt;xstate = NULL;
++ }
++ if (cp-&gt;rstate != NULL) {
++ (*cp-&gt;rcomp-&gt;decomp_free)(cp-&gt;rstate);
++ cp-&gt;rstate = NULL;
++ }
++ cp-&gt;flags &amp;= ~CCP_ISUP;
++ }
++ error = 0;
++ iop-&gt;ioc_count = sizeof(int);
++ ((int *) mp-&gt;b_cont-&gt;b_rptr)[0] = cp-&gt;flags;
++ mp-&gt;b_cont-&gt;b_wptr = mp-&gt;b_cont-&gt;b_rptr + sizeof(int);
++ break;
++
++ case PPPIO_VJINIT:
++ /*
++ * Initialize VJ compressor/decompressor
++ */
++ if (iop-&gt;ioc_count != 2)
++ break;
++ if (mp-&gt;b_cont == 0) {
++ DPRINT1(&quot;ppp_comp_wput/%d: PPPIO_VJINIT b_cont = 0!\n&quot;, cp-&gt;unit);
++ break;
++ }
++ nxslots = mp-&gt;b_cont-&gt;b_rptr[0] + 1;
++ nrslots = mp-&gt;b_cont-&gt;b_rptr[1] + 1;
++ if (nxslots &gt; MAX_STATES || nrslots &gt; MAX_STATES)
++ break;
++ vj_compress_init(&amp;cp-&gt;vj_comp, nxslots);
++ cp-&gt;vj_last_ierrors = cp-&gt;stats.ppp_ierrors;
++ error = 0;
++ iop-&gt;ioc_count = 0;
++ break;
++
++ case PPPIO_XCOMP:
++ case PPPIO_RCOMP:
++ if (iop-&gt;ioc_count &lt;= 0)
++ break;
++ if (mp-&gt;b_cont == 0) {
++ DPRINT1(&quot;ppp_comp_wput/%d: PPPIO_[XR]COMP b_cont = 0!\n&quot;, cp-&gt;unit);
++ break;
++ }
++ opt_data = mp-&gt;b_cont-&gt;b_rptr;
++ len = mp-&gt;b_cont-&gt;b_wptr - opt_data;
++ if (len &gt; iop-&gt;ioc_count)
++ len = iop-&gt;ioc_count;
++ if (opt_data[1] &lt; 2 || opt_data[1] &gt; len)
++ break;
++ for (comp = ppp_compressors; *comp != NULL; ++comp)
++ if ((*comp)-&gt;compress_proto == opt_data[0]) {
++ /* here's the handler! */
++ error = 0;
++#ifndef __osf__
++ if (iop-&gt;ioc_cmd == PPPIO_XCOMP) {
++ /* A previous call may have fetched memory for a compressor
++ * that's now being retired or reset. Free it using it's
++ * mechanism for freeing stuff.
++ */
++ if (cp-&gt;xstate != NULL) {
++ (*cp-&gt;xcomp-&gt;comp_free)(cp-&gt;xstate);
++ cp-&gt;xstate = NULL;
++ }
++ cp-&gt;xcomp = *comp;
++ cp-&gt;xstate = (*comp)-&gt;comp_alloc(opt_data, len);
++ if (cp-&gt;xstate == NULL)
++ error = ENOSR;
++ } else {
++ if (cp-&gt;rstate != NULL) {
++ (*cp-&gt;rcomp-&gt;decomp_free)(cp-&gt;rstate);
++ cp-&gt;rstate = NULL;
++ }
++ cp-&gt;rcomp = *comp;
++ cp-&gt;rstate = (*comp)-&gt;decomp_alloc(opt_data, len);
++ if (cp-&gt;rstate == NULL)
++ error = ENOSR;
++ }
++#else
++ if ((error = cp-&gt;memreq.thread_status) != EAGAIN)
++ if (iop-&gt;ioc_cmd == PPPIO_XCOMP) {
++ if (cp-&gt;xstate) {
++ (*cp-&gt;xcomp-&gt;comp_free)(cp-&gt;xstate);
++ cp-&gt;xstate = 0;
++ }
++ /* sanity check for compressor options
++ */
++ if (sizeof (cp-&gt;memreq.comp_opts) &lt; len) {
++ printf(&quot;can't handle options for compressor %d (%d)\n&quot;, opt_data[0],
++ opt_data[1]);
++ cp-&gt;memreq.thread_status = ENOSR;
++ cp-&gt;memreq.returned_mem = 0;
++ }
++ /* fill in request for the thread and kick it off
++ */
++ if (cp-&gt;memreq.thread_status == 0 &amp;&amp; !cp-&gt;memreq.returned_mem) {
++ bcopy(opt_data, cp-&gt;memreq.comp_opts, len);
++ cp-&gt;memreq.cmd = PPPIO_XCOMP;
++ cp-&gt;xcomp = *comp;
++ error = cp-&gt;memreq.thread_status = EAGAIN;
++ thread_wakeup((vm_offset_t)&amp;cp-&gt;memreq.thread_status);
++ } else {
++ cp-&gt;xstate = cp-&gt;memreq.returned_mem;
++ cp-&gt;memreq.returned_mem = 0;
++ cp-&gt;memreq.thread_status = 0;
++ }
++ } else {
++ if (cp-&gt;rstate) {
++ (*cp-&gt;rcomp-&gt;decomp_free)(cp-&gt;rstate);
++ cp-&gt;rstate = NULL;
++ }
++ if (sizeof (cp-&gt;memreq.comp_opts) &lt; len) {
++ printf(&quot;can't handle options for compressor %d (%d)\n&quot;, opt_data[0],
++ opt_data[1]);
++ cp-&gt;memreq.thread_status = ENOSR;
++ cp-&gt;memreq.returned_mem = 0;
++ }
++ if (cp-&gt;memreq.thread_status == 0 &amp;&amp; !cp-&gt;memreq.returned_mem) {
++ bcopy(opt_data, cp-&gt;memreq.comp_opts, len);
++ cp-&gt;memreq.cmd = PPPIO_RCOMP;
++ cp-&gt;rcomp = *comp;
++ error = cp-&gt;memreq.thread_status = EAGAIN;
++ thread_wakeup((vm_offset_t)&amp;cp-&gt;memreq.thread_status);
++ } else {
++ cp-&gt;rstate = cp-&gt;memreq.returned_mem;
++ cp-&gt;memreq.returned_mem = 0;
++ cp-&gt;memreq.thread_status = 0;
++ }
++ }
++#endif
++ break;
++ }
++ iop-&gt;ioc_count = 0;
++ break;
++
++ case PPPIO_GETSTAT:
++ if ((cp-&gt;flags &amp; LAST_MOD) == 0) {
++ error = -1; /* let the ppp_ahdl module handle it */
++ break;
++ }
++ np = allocb(sizeof(struct ppp_stats), BPRI_HI);
++ if (np == 0) {
++ error = ENOSR;
++ break;
++ }
++ if (mp-&gt;b_cont != 0)
++ freemsg(mp-&gt;b_cont);
++ mp-&gt;b_cont = np;
++ psp = (struct ppp_stats *) np-&gt;b_wptr;
++ np-&gt;b_wptr += sizeof(struct ppp_stats);
++ iop-&gt;ioc_count = sizeof(struct ppp_stats);
++ psp-&gt;p = cp-&gt;stats;
++ psp-&gt;vj = cp-&gt;vj_comp.stats;
++ error = 0;
++ break;
++
++ case PPPIO_GETCSTAT:
++ np = allocb(sizeof(struct ppp_comp_stats), BPRI_HI);
++ if (np == 0) {
++ error = ENOSR;
++ break;
++ }
++ if (mp-&gt;b_cont != 0)
++ freemsg(mp-&gt;b_cont);
++ mp-&gt;b_cont = np;
++ csp = (struct ppp_comp_stats *) np-&gt;b_wptr;
++ np-&gt;b_wptr += sizeof(struct ppp_comp_stats);
++ iop-&gt;ioc_count = sizeof(struct ppp_comp_stats);
++ bzero((caddr_t)csp, sizeof(struct ppp_comp_stats));
++ if (cp-&gt;xstate != 0)
++ (*cp-&gt;xcomp-&gt;comp_stat)(cp-&gt;xstate, &amp;csp-&gt;c);
++ if (cp-&gt;rstate != 0)
++ (*cp-&gt;rcomp-&gt;decomp_stat)(cp-&gt;rstate, &amp;csp-&gt;d);
++ error = 0;
++ break;
++
++ case PPPIO_DEBUG:
++ if (iop-&gt;ioc_count != sizeof(int))
++ break;
++ if (mp-&gt;b_cont == 0) {
++ DPRINT1(&quot;ppp_comp_wput/%d: PPPIO_DEBUG b_cont = 0!\n&quot;, cp-&gt;unit);
++ break;
++ }
++ n = *(int *)mp-&gt;b_cont-&gt;b_rptr;
++ if (n == PPPDBG_LOG + PPPDBG_COMP) {
++ DPRINT1(&quot;ppp_comp%d: debug log enabled\n&quot;, cp-&gt;unit);
++ cp-&gt;flags |= DBGLOG;
++ error = 0;
++ iop-&gt;ioc_count = 0;
++ } else {
++ error = -1;
++ }
++ break;
++
++ case PPPIO_LASTMOD:
++ cp-&gt;flags |= LAST_MOD;
++ error = 0;
++ break;
++
++ default:
++ error = -1;
++ break;
++ }
++
++ if (error &lt; 0)
++ putnext(q, mp);
++ else if (error == 0) {
++ mp-&gt;b_datap-&gt;db_type = M_IOCACK;
++ qreply(q, mp);
++ } else {
++ mp-&gt;b_datap-&gt;db_type = M_IOCNAK;
++ iop-&gt;ioc_error = error;
++ iop-&gt;ioc_count = 0;
++ qreply(q, mp);
++ }
++ break;
++
++ case M_CTL:
++ switch (*mp-&gt;b_rptr) {
++ case PPPCTL_MTU:
++ cp-&gt;mtu = ((unsigned short *)mp-&gt;b_rptr)[1];
++ break;
++ case PPPCTL_MRU:
++ cp-&gt;mru = ((unsigned short *)mp-&gt;b_rptr)[1];
++ break;
++ case PPPCTL_UNIT:
++ cp-&gt;unit = mp-&gt;b_rptr[1];
++ break;
++ }
++ putnext(q, mp);
++ break;
++
++ default:
++ putnext(q, mp);
++ }
++
++ return 0;
++}
++
++static int
++ppp_comp_wsrv(q)
++ queue_t *q;
++{
++ mblk_t *mp, *cmp = NULL;
++ comp_state_t *cp;
++ int len, proto, type, hlen, code;
++ struct ip *ip;
++ unsigned char *vjhdr, *dp;
++
++ cp = (comp_state_t *) q-&gt;q_ptr;
++ if (cp == 0) {
++ DPRINT(&quot;cp == 0 in ppp_comp_wsrv\n&quot;);
++ return 0;
++ }
++
++ while ((mp = getq(q)) != 0) {
++ /* assert(mp-&gt;b_datap-&gt;db_type == M_DATA) */
++#ifdef PRIOQ
++ if (!bcanputnext(q,mp-&gt;b_band))
++#else
++ if (!canputnext(q))
++#endif PRIOQ
++ {
++ putbq(q, mp);
++ break;
++ }
++
++ /*
++ * First check the packet length and work out what the protocol is.
++ */
++ len = msgdsize(mp);
++ if (len &lt; PPP_HDRLEN) {
++ DPRINT1(&quot;ppp_comp_wsrv: bogus short packet (%d)\n&quot;, len);
++ freemsg(mp);
++ cp-&gt;stats.ppp_oerrors++;
++ putctl1(RD(q)-&gt;q_next, M_CTL, PPPCTL_OERROR);
++ continue;
++ }
++ proto = (MSG_BYTE(mp, 2) &lt;&lt; 8) + MSG_BYTE(mp, 3);
++
++ /*
++ * Make sure we've got enough data in the first mblk
++ * and that we are its only user.
++ */
++ if (proto == PPP_CCP)
++ hlen = len;
++ else if (proto == PPP_IP)
++ hlen = PPP_HDRLEN + MAX_IPHDR;
++ else
++ hlen = PPP_HDRLEN;
++ if (hlen &gt; len)
++ hlen = len;
++ if (mp-&gt;b_wptr &lt; mp-&gt;b_rptr + hlen || mp-&gt;b_datap-&gt;db_ref &gt; 1) {
++ PULLUP(mp, hlen);
++ if (mp == 0) {
++ DPRINT1(&quot;ppp_comp_wsrv: pullup failed (%d)\n&quot;, hlen);
++ cp-&gt;stats.ppp_oerrors++;
++ putctl1(RD(q)-&gt;q_next, M_CTL, PPPCTL_OERROR);
++ continue;
++ }
++ }
++
++ /*
++ * Do VJ compression if requested.
++ */
++ if (proto == PPP_IP &amp;&amp; (cp-&gt;flags &amp; COMP_VJC)) {
++ ip = (struct ip *) (mp-&gt;b_rptr + PPP_HDRLEN);
++ if (ip-&gt;ip_p == IPPROTO_TCP) {
++ type = vj_compress_tcp(ip, len - PPP_HDRLEN, &amp;cp-&gt;vj_comp,
++ (cp-&gt;flags &amp; COMP_VJCCID), &amp;vjhdr);
++ switch (type) {
++ case TYPE_UNCOMPRESSED_TCP:
++ mp-&gt;b_rptr[3] = proto = PPP_VJC_UNCOMP;
++ break;
++ case TYPE_COMPRESSED_TCP:
++ dp = vjhdr - PPP_HDRLEN;
++ dp[1] = mp-&gt;b_rptr[1]; /* copy control field */
++ dp[0] = mp-&gt;b_rptr[0]; /* copy address field */
++ dp[2] = 0; /* set protocol field */
++ dp[3] = proto = PPP_VJC_COMP;
++ mp-&gt;b_rptr = dp;
++ break;
++ }
++ }
++ }
++
++ /*
++ * Do packet compression if enabled.
++ */
++ if (proto == PPP_CCP)
++ ppp_comp_ccp(q, mp, 0);
++ else if (proto != PPP_LCP &amp;&amp; (cp-&gt;flags &amp; CCP_COMP_RUN)
++ &amp;&amp; cp-&gt;xstate != NULL) {
++ len = msgdsize(mp);
++ (*cp-&gt;xcomp-&gt;compress)(cp-&gt;xstate, &amp;cmp, mp, len,
++ (cp-&gt;flags &amp; CCP_ISUP? cp-&gt;mtu + PPP_HDRLEN: 0));
++ if (cmp != NULL) {
++#ifdef PRIOQ
++ cmp-&gt;b_band=mp-&gt;b_band;
++#endif PRIOQ
++ freemsg(mp);
++ mp = cmp;
++ }
++ }
++
++ /*
++ * Do address/control and protocol compression if enabled.
++ */
++ if ((cp-&gt;flags &amp; COMP_AC)
++ &amp;&amp; !(proto == PPP_LCP &amp;&amp; LCP_USE_DFLT(mp))) {
++ mp-&gt;b_rptr += 2; /* drop the address &amp; ctrl fields */
++ if (proto &lt; 0x100 &amp;&amp; (cp-&gt;flags &amp; COMP_PROT))
++ ++mp-&gt;b_rptr; /* drop the high protocol byte */
++ } else if (proto &lt; 0x100 &amp;&amp; (cp-&gt;flags &amp; COMP_PROT)) {
++ /* shuffle up the address &amp; ctrl fields */
++ mp-&gt;b_rptr[2] = mp-&gt;b_rptr[1];
++ mp-&gt;b_rptr[1] = mp-&gt;b_rptr[0];
++ ++mp-&gt;b_rptr;
++ }
++
++ cp-&gt;stats.ppp_opackets++;
++ cp-&gt;stats.ppp_obytes += msgdsize(mp);
++ putnext(q, mp);
++ }
++
++ return 0;
++}
++
++static int
++ppp_comp_rput(q, mp)
++ queue_t *q;
++ mblk_t *mp;
++{
++ comp_state_t *cp;
++ struct iocblk *iop;
++ struct ppp_stats *psp;
++
++ cp = (comp_state_t *) q-&gt;q_ptr;
++ if (cp == 0) {
++ DPRINT(&quot;cp == 0 in ppp_comp_rput\n&quot;);
++ freemsg(mp);
++ return 0;
++ }
++
++ switch (mp-&gt;b_datap-&gt;db_type) {
++
++ case M_DATA:
++ putq(q, mp);
++ break;
++
++ case M_IOCACK:
++ iop = (struct iocblk *) mp-&gt;b_rptr;
++ switch (iop-&gt;ioc_cmd) {
++ case PPPIO_GETSTAT:
++ /*
++ * Catch this on the way back from the ppp_ahdl module
++ * so we can fill in the VJ stats.
++ */
++ if (mp-&gt;b_cont == 0 || iop-&gt;ioc_count != sizeof(struct ppp_stats))
++ break;
++ psp = (struct ppp_stats *) mp-&gt;b_cont-&gt;b_rptr;
++ psp-&gt;vj = cp-&gt;vj_comp.stats;
++ break;
++ }
++ putnext(q, mp);
++ break;
++
++ case M_CTL:
++ switch (mp-&gt;b_rptr[0]) {
++ case PPPCTL_IERROR:
++ ++cp-&gt;stats.ppp_ierrors;
++ break;
++ case PPPCTL_OERROR:
++ ++cp-&gt;stats.ppp_oerrors;
++ break;
++ }
++ putnext(q, mp);
++ break;
++
++ default:
++ putnext(q, mp);
++ }
++
++ return 0;
++}
++
++static int
++ppp_comp_rsrv(q)
++ queue_t *q;
++{
++ int proto, rv, i;
++ mblk_t *mp, *dmp = NULL, *np;
++ uchar_t *dp, *iphdr;
++ comp_state_t *cp;
++ int len, hlen, vjlen;
++ u_int iphlen;
++
++ cp = (comp_state_t *) q-&gt;q_ptr;
++ if (cp == 0) {
++ DPRINT(&quot;cp == 0 in ppp_comp_rsrv\n&quot;);
++ return 0;
++ }
++
++ while ((mp = getq(q)) != 0) {
++ /* assert(mp-&gt;b_datap-&gt;db_type == M_DATA) */
++ if (!canputnext(q)) {
++ putbq(q, mp);
++ break;
++ }
++
++ len = msgdsize(mp);
++ cp-&gt;stats.ppp_ibytes += len;
++ cp-&gt;stats.ppp_ipackets++;
++
++ /*
++ * First work out the protocol and where the PPP header ends.
++ */
++ i = 0;
++ proto = MSG_BYTE(mp, 0);
++ if (proto == PPP_ALLSTATIONS) {
++ i = 2;
++ proto = MSG_BYTE(mp, 2);
++ }
++ if ((proto &amp; 1) == 0) {
++ ++i;
++ proto = (proto &lt;&lt; 8) + MSG_BYTE(mp, i);
++ }
++ hlen = i + 1;
++
++ /*
++ * Now reconstruct a complete, contiguous PPP header at the
++ * start of the packet.
++ */
++ if (hlen &lt; ((cp-&gt;flags &amp; DECOMP_AC)? 0: 2)
++ + ((cp-&gt;flags &amp; DECOMP_PROT)? 1: 2)) {
++ /* count these? */
++ goto bad;
++ }
++ if (mp-&gt;b_rptr + hlen &gt; mp-&gt;b_wptr) {
++ adjmsg(mp, hlen); /* XXX check this call */
++ hlen = 0;
++ }
++ if (hlen != PPP_HDRLEN) {
++ /*
++ * We need to put some bytes on the front of the packet
++ * to make a full-length PPP header.
++ * If we can put them in *mp, we do, otherwise we
++ * tack another mblk on the front.
++ * XXX we really shouldn't need to carry around
++ * the address and control at this stage.
++ */
++ dp = mp-&gt;b_rptr + hlen - PPP_HDRLEN;
++ if (dp &lt; mp-&gt;b_datap-&gt;db_base || mp-&gt;b_datap-&gt;db_ref &gt; 1) {
++ np = allocb(PPP_HDRLEN, BPRI_MED);
++ if (np == 0)
++ goto bad;
++ np-&gt;b_cont = mp;
++ mp-&gt;b_rptr += hlen;
++ mp = np;
++ dp = mp-&gt;b_wptr;
++ mp-&gt;b_wptr += PPP_HDRLEN;
++ } else
++ mp-&gt;b_rptr = dp;
++
++ dp[0] = PPP_ALLSTATIONS;
++ dp[1] = PPP_UI;
++ dp[2] = proto &gt;&gt; 8;
++ dp[3] = proto;
++ }
++
++ /*
++ * Now see if we have a compressed packet to decompress,
++ * or a CCP packet to take notice of.
++ */
++ proto = PPP_PROTOCOL(mp-&gt;b_rptr);
++ if (proto == PPP_CCP) {
++ len = msgdsize(mp);
++ if (mp-&gt;b_wptr &lt; mp-&gt;b_rptr + len) {
++ PULLUP(mp, len);
++ if (mp == 0)
++ goto bad;
++ }
++ ppp_comp_ccp(q, mp, 1);
++ } else if (proto == PPP_COMP) {
++ if ((cp-&gt;flags &amp; CCP_ISUP)
++ &amp;&amp; (cp-&gt;flags &amp; CCP_DECOMP_RUN) &amp;&amp; cp-&gt;rstate
++ &amp;&amp; (cp-&gt;flags &amp; CCP_ERR) == 0) {
++ rv = (*cp-&gt;rcomp-&gt;decompress)(cp-&gt;rstate, mp, &amp;dmp);
++ switch (rv) {
++ case DECOMP_OK:
++ freemsg(mp);
++ mp = dmp;
++ if (mp == NULL) {
++ /* no error, but no packet returned either. */
++ continue;
++ }
++ break;
++ case DECOMP_ERROR:
++ cp-&gt;flags |= CCP_ERROR;
++ ++cp-&gt;stats.ppp_ierrors;
++ putctl1(q-&gt;q_next, M_CTL, PPPCTL_IERROR);
++ break;
++ case DECOMP_FATALERROR:
++ cp-&gt;flags |= CCP_FATALERROR;
++ ++cp-&gt;stats.ppp_ierrors;
++ putctl1(q-&gt;q_next, M_CTL, PPPCTL_IERROR);
++ break;
++ }
++ }
++ } else if (cp-&gt;rstate &amp;&amp; (cp-&gt;flags &amp; CCP_DECOMP_RUN)) {
++ (*cp-&gt;rcomp-&gt;incomp)(cp-&gt;rstate, mp);
++ }
++
++ /*
++ * Now do VJ decompression.
++ */
++ proto = PPP_PROTOCOL(mp-&gt;b_rptr);
++ if (proto == PPP_VJC_COMP || proto == PPP_VJC_UNCOMP) {
++ len = msgdsize(mp) - PPP_HDRLEN;
++ if ((cp-&gt;flags &amp; DECOMP_VJC) == 0 || len &lt;= 0)
++ goto bad;
++
++ /*
++ * Advance past the ppp header.
++ * Here we assume that the whole PPP header is in the first mblk.
++ */
++ np = mp;
++ dp = np-&gt;b_rptr + PPP_HDRLEN;
++ if (dp &gt;= mp-&gt;b_wptr) {
++ np = np-&gt;b_cont;
++ dp = np-&gt;b_rptr;
++ }
++
++ /*
++ * Make sure we have sufficient contiguous data at this point.
++ */
++ hlen = (proto == PPP_VJC_COMP)? MAX_VJHDR: MAX_IPHDR;
++ if (hlen &gt; len)
++ hlen = len;
++ if (np-&gt;b_wptr &lt; dp + hlen || np-&gt;b_datap-&gt;db_ref &gt; 1) {
++ PULLUP(mp, hlen + PPP_HDRLEN);
++ if (mp == 0)
++ goto bad;
++ np = mp;
++ dp = np-&gt;b_rptr + PPP_HDRLEN;
++ }
++
++ if (proto == PPP_VJC_COMP) {
++ /*
++ * Decompress VJ-compressed packet.
++ * First reset compressor if an input error has occurred.
++ */
++ if (cp-&gt;stats.ppp_ierrors != cp-&gt;vj_last_ierrors) {
++ if (cp-&gt;flags &amp; DBGLOG)
++ DPRINT1(&quot;ppp%d: resetting VJ\n&quot;, cp-&gt;unit);
++ vj_uncompress_err(&amp;cp-&gt;vj_comp);
++ cp-&gt;vj_last_ierrors = cp-&gt;stats.ppp_ierrors;
++ }
++
++ vjlen = vj_uncompress_tcp(dp, np-&gt;b_wptr - dp, len,
++ &amp;cp-&gt;vj_comp, &amp;iphdr, &amp;iphlen);
++ if (vjlen &lt; 0) {
++ if (cp-&gt;flags &amp; DBGLOG)
++ DPRINT2(&quot;ppp%d: vj_uncomp_tcp failed, pkt len %d\n&quot;,
++ cp-&gt;unit, len);
++ ++cp-&gt;vj_last_ierrors; /* so we don't reset next time */
++ goto bad;
++ }
++
++ /* drop ppp and vj headers off */
++ if (mp != np) {
++ freeb(mp);
++ mp = np;
++ }
++ mp-&gt;b_rptr = dp + vjlen;
++
++ /* allocate a new mblk for the ppp and ip headers */
++ if ((np = allocb(iphlen + PPP_HDRLEN + 4, BPRI_MED)) == 0)
++ goto bad;
++ dp = np-&gt;b_rptr; /* prepend mblk with TCP/IP hdr */
++ dp[0] = PPP_ALLSTATIONS; /* reconstruct PPP header */
++ dp[1] = PPP_UI;
++ dp[2] = PPP_IP &gt;&gt; 8;
++ dp[3] = PPP_IP;
++ bcopy((caddr_t)iphdr, (caddr_t)dp + PPP_HDRLEN, iphlen);
++ np-&gt;b_wptr = dp + iphlen + PPP_HDRLEN;
++ np-&gt;b_cont = mp;
++
++ /* XXX there seems to be a bug which causes panics in strread
++ if we make an mbuf with only the IP header in it :-( */
++ if (mp-&gt;b_wptr - mp-&gt;b_rptr &gt; 4) {
++ bcopy((caddr_t)mp-&gt;b_rptr, (caddr_t)np-&gt;b_wptr, 4);
++ mp-&gt;b_rptr += 4;
++ np-&gt;b_wptr += 4;
++ } else {
++ bcopy((caddr_t)mp-&gt;b_rptr, (caddr_t)np-&gt;b_wptr,
++ mp-&gt;b_wptr - mp-&gt;b_rptr);
++ np-&gt;b_wptr += mp-&gt;b_wptr - mp-&gt;b_rptr;
++ np-&gt;b_cont = mp-&gt;b_cont;
++ freeb(mp);
++ }
++
++ mp = np;
++
++ } else {
++ /*
++ * &quot;Decompress&quot; a VJ-uncompressed packet.
++ */
++ cp-&gt;vj_last_ierrors = cp-&gt;stats.ppp_ierrors;
++ if (!vj_uncompress_uncomp(dp, hlen, &amp;cp-&gt;vj_comp)) {
++ if (cp-&gt;flags &amp; DBGLOG)
++ DPRINT2(&quot;ppp%d: vj_uncomp_uncomp failed, pkt len %d\n&quot;,
++ cp-&gt;unit, len);
++ ++cp-&gt;vj_last_ierrors; /* don't need to reset next time */
++ goto bad;
++ }
++ mp-&gt;b_rptr[3] = PPP_IP; /* fix up the PPP protocol field */
++ }
++ }
++
++ putnext(q, mp);
++ continue;
++
++ bad:
++ if (mp != 0)
++ freemsg(mp);
++ cp-&gt;stats.ppp_ierrors++;
++ putctl1(q-&gt;q_next, M_CTL, PPPCTL_IERROR);
++ }
++
++ return 0;
++}
++
++/*
++ * Handle a CCP packet being sent or received.
++ * Here all the data in the packet is in a single mbuf.
++ */
++static void
++ppp_comp_ccp(q, mp, rcvd)
++ queue_t *q;
++ mblk_t *mp;
++ int rcvd;
++{
++ int len, clen;
++ comp_state_t *cp;
++ unsigned char *dp;
++
++ len = msgdsize(mp);
++ if (len &lt; PPP_HDRLEN + CCP_HDRLEN)
++ return;
++
++ cp = (comp_state_t *) q-&gt;q_ptr;
++ dp = mp-&gt;b_rptr + PPP_HDRLEN;
++ len -= PPP_HDRLEN;
++ clen = CCP_LENGTH(dp);
++ if (clen &gt; len)
++ return;
++
++ switch (CCP_CODE(dp)) {
++ case CCP_CONFREQ:
++ case CCP_TERMREQ:
++ case CCP_TERMACK:
++ cp-&gt;flags &amp;= ~CCP_ISUP;
++ break;
++
++ case CCP_CONFACK:
++ if ((cp-&gt;flags &amp; (CCP_ISOPEN | CCP_ISUP)) == CCP_ISOPEN
++ &amp;&amp; clen &gt;= CCP_HDRLEN + CCP_OPT_MINLEN
++ &amp;&amp; clen &gt;= CCP_HDRLEN + CCP_OPT_LENGTH(dp + CCP_HDRLEN)) {
++ if (!rcvd) {
++ if (cp-&gt;xstate != NULL
++ &amp;&amp; (*cp-&gt;xcomp-&gt;comp_init)
++ (cp-&gt;xstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN,
++ cp-&gt;unit, 0, ((cp-&gt;flags &amp; DBGLOG) != 0)))
++ cp-&gt;flags |= CCP_COMP_RUN;
++ } else {
++ if (cp-&gt;rstate != NULL
++ &amp;&amp; (*cp-&gt;rcomp-&gt;decomp_init)
++ (cp-&gt;rstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN,
++ cp-&gt;unit, 0, cp-&gt;mru, ((cp-&gt;flags &amp; DBGLOG) != 0)))
++ cp-&gt;flags = (cp-&gt;flags &amp; ~CCP_ERR) | CCP_DECOMP_RUN;
++ }
++ }
++ break;
++
++ case CCP_RESETACK:
++ if (cp-&gt;flags &amp; CCP_ISUP) {
++ if (!rcvd) {
++ if (cp-&gt;xstate &amp;&amp; (cp-&gt;flags &amp; CCP_COMP_RUN))
++ (*cp-&gt;xcomp-&gt;comp_reset)(cp-&gt;xstate);
++ } else {
++ if (cp-&gt;rstate &amp;&amp; (cp-&gt;flags &amp; CCP_DECOMP_RUN)) {
++ (*cp-&gt;rcomp-&gt;decomp_reset)(cp-&gt;rstate);
++ cp-&gt;flags &amp;= ~CCP_ERROR;
++ }
++ }
++ }
++ break;
++ }
++}
++
++#if 0
++dump_msg(mp)
++ mblk_t *mp;
++{
++ dblk_t *db;
++
++ while (mp != 0) {
++ db = mp-&gt;b_datap;
++ DPRINT2(&quot;mp=%x cont=%x &quot;, mp, mp-&gt;b_cont);
++ DPRINT3(&quot;rptr=%x wptr=%x datap=%x\n&quot;, mp-&gt;b_rptr, mp-&gt;b_wptr, db);
++ DPRINT2(&quot; base=%x lim=%x&quot;, db-&gt;db_base, db-&gt;db_lim);
++ DPRINT2(&quot; ref=%d type=%d\n&quot;, db-&gt;db_ref, db-&gt;db_type);
++ mp = mp-&gt;b_cont;
++ }
++}
++#endif
++
++static int
++msg_byte(mp, i)
++ mblk_t *mp;
++ unsigned int i;
++{
++ while (mp != 0 &amp;&amp; i &gt;= mp-&gt;b_wptr - mp-&gt;b_rptr)
++ mp = mp-&gt;b_cont;
++ if (mp == 0)
++ return -1;
++ return mp-&gt;b_rptr[i];
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/solaris/ppp_comp.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/solaris/ppp_comp_mod.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/solaris/ppp_comp_mod.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/solaris/ppp_comp_mod.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,81 @@
++/*
++ * ppp_comp_mod.c - modload support for PPP compression STREAMS module.
++ *
++ * Copyright (c) 1994 The Australian National University.
++ * All rights reserved.
++ *
++ * Permission to use, copy, modify, and distribute this software and its
++ * documentation is hereby granted, provided that the above copyright
++ * notice appears in all copies. This software is provided without any
++ * warranty, express or implied. The Australian National University
++ * makes no representations about the suitability of this software for
++ * any purpose.
++ *
++ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
++ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
++ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
++ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
++ * OF SUCH DAMAGE.
++ *
++ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
++ * ON AN &quot;AS IS&quot; BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
++ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
++ * OR MODIFICATIONS.
++ *
++ * $Id: ppp_comp_mod.c 195720 2001-06-11 11:44:34Z gc $
++ */
++
++/*
++ * This file is used under Solaris 2.
++ */
++#include &lt;sys/types.h&gt;
++#include &lt;sys/param.h&gt;
++#include &lt;sys/conf.h&gt;
++#include &lt;sys/modctl.h&gt;
++#include &lt;sys/sunddi.h&gt;
++
++extern struct streamtab ppp_compinfo;
++
++static struct fmodsw fsw = {
++ &quot;ppp_comp&quot;,
++ &amp;ppp_compinfo,
++ D_NEW | D_MP | D_MTQPAIR
++};
++
++extern struct mod_ops mod_strmodops;
++
++static struct modlstrmod modlstrmod = {
++ &amp;mod_strmodops,
++ &quot;PPP compression module&quot;,
++ &amp;fsw
++};
++
++static struct modlinkage modlinkage = {
++ MODREV_1,
++ (void *) &amp;modlstrmod,
++ NULL
++};
++
++/*
++ * Entry points for modloading.
++ */
++int
++_init(void)
++{
++ return mod_install(&amp;modlinkage);
++}
++
++int
++_fini(void)
++{
++ return mod_remove(&amp;modlinkage);
++}
++
++int
++_info(mip)
++ struct modinfo *mip;
++{
++ return mod_info(&amp;modlinkage, mip);
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/solaris/ppp_comp_mod.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/solaris/ppp_mod.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/solaris/ppp_mod.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/solaris/ppp_mod.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,174 @@
++/*
++ * ppp_mod.c - modload support for PPP pseudo-device driver.
++ *
++ * Copyright (c) 1994 The Australian National University.
++ * All rights reserved.
++ *
++ * Permission to use, copy, modify, and distribute this software and its
++ * documentation is hereby granted, provided that the above copyright
++ * notice appears in all copies. This software is provided without any
++ * warranty, express or implied. The Australian National University
++ * makes no representations about the suitability of this software for
++ * any purpose.
++ *
++ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
++ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
++ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
++ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
++ * OF SUCH DAMAGE.
++ *
++ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
++ * ON AN &quot;AS IS&quot; BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
++ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
++ * OR MODIFICATIONS.
++ *
++ * $Id: ppp_mod.c 195720 2001-06-11 11:44:34Z gc $
++ */
++
++/*
++ * This file is used under Solaris 2.
++ */
++
++#include &lt;sys/types.h&gt;
++#include &lt;sys/param.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;sys/conf.h&gt;
++#include &lt;sys/modctl.h&gt;
++#include &lt;sys/sunddi.h&gt;
++#include &lt;sys/ksynch.h&gt;
++
++#ifdef __STDC__
++#define __P(x) x
++#else
++#define __P(x) ()
++#endif
++
++static int ppp_identify __P((dev_info_t *));
++static int ppp_attach __P((dev_info_t *, ddi_attach_cmd_t));
++static int ppp_detach __P((dev_info_t *, ddi_detach_cmd_t));
++static int ppp_devinfo __P((dev_info_t *, ddi_info_cmd_t, void *, void **));
++
++extern struct streamtab pppinfo;
++extern krwlock_t ppp_lower_lock;
++
++static dev_info_t *ppp_dip;
++
++static struct cb_ops cb_ppp_ops = {
++ nulldev, nulldev, nodev, nodev, /* cb_open, ... */
++ nodev, nodev, nodev, nodev, /* cb_dump, ... */
++ nodev, nodev, nodev, nochpoll, /* cb_devmap, ... */
++ ddi_prop_op, /* cb_prop_op */
++ &amp;pppinfo, /* cb_stream */
++ D_NEW|D_MP|D_MTQPAIR|D_MTOUTPERIM|D_MTOCEXCL /* cb_flag */
++};
++
++static struct dev_ops ppp_ops = {
++ DEVO_REV, /* devo_rev */
++ 0, /* devo_refcnt */
++ ppp_devinfo, /* devo_getinfo */
++ ppp_identify, /* devo_identify */
++ nulldev, /* devo_probe */
++ ppp_attach, /* devo_attach */
++ ppp_detach, /* devo_detach */
++ nodev, /* devo_reset */
++ &amp;cb_ppp_ops, /* devo_cb_ops */
++ NULL /* devo_bus_ops */
++};
++
++/*
++ * Module linkage information
++ */
++
++static struct modldrv modldrv = {
++ &amp;mod_driverops, /* says this is a pseudo driver */
++ &quot;PPP-2.3 multiplexing driver&quot;,
++ &amp;ppp_ops /* driver ops */
++};
++
++static struct modlinkage modlinkage = {
++ MODREV_1,
++ (void *) &amp;modldrv,
++ NULL
++};
++
++int
++_init(void)
++{
++ return mod_install(&amp;modlinkage);
++}
++
++int
++_fini(void)
++{
++ return mod_remove(&amp;modlinkage);
++}
++
++int
++_info(mip)
++ struct modinfo *mip;
++{
++ return mod_info(&amp;modlinkage, mip);
++}
++
++static int
++ppp_identify(dip)
++ dev_info_t *dip;
++{
++ return strcmp(ddi_get_name(dip), &quot;ppp&quot;) == 0? DDI_IDENTIFIED:
++ DDI_NOT_IDENTIFIED;
++}
++
++static int
++ppp_attach(dip, cmd)
++ dev_info_t *dip;
++ ddi_attach_cmd_t cmd;
++{
++
++ if (cmd != DDI_ATTACH)
++ return DDI_FAILURE;
++ if (ddi_create_minor_node(dip, &quot;ppp&quot;, S_IFCHR, 0, DDI_PSEUDO, CLONE_DEV)
++ == DDI_FAILURE) {
++ ddi_remove_minor_node(dip, NULL);
++ return DDI_FAILURE;
++ }
++ rw_init(&amp;ppp_lower_lock, NULL, RW_DRIVER, NULL);
++ return DDI_SUCCESS;
++}
++
++static int
++ppp_detach(dip, cmd)
++ dev_info_t *dip;
++ ddi_detach_cmd_t cmd;
++{
++ rw_destroy(&amp;ppp_lower_lock);
++ ddi_remove_minor_node(dip, NULL);
++ return DDI_SUCCESS;
++}
++
++static int
++ppp_devinfo(dip, cmd, arg, result)
++ dev_info_t *dip;
++ ddi_info_cmd_t cmd;
++ void *arg;
++ void **result;
++{
++ int error;
++
++ error = DDI_SUCCESS;
++ switch (cmd) {
++ case DDI_INFO_DEVT2DEVINFO:
++ if (ppp_dip == NULL)
++ error = DDI_FAILURE;
++ else
++ *result = (void *) ppp_dip;
++ break;
++ case DDI_INFO_DEVT2INSTANCE:
++ *result = NULL;
++ break;
++ default:
++ error = DDI_FAILURE;
++ }
++ return error;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/solaris/ppp_mod.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/solaris/ppp_mod.h
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/solaris/ppp_mod.h (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/solaris/ppp_mod.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,190 @@
++/*
++ * Miscellaneous definitions for PPP STREAMS modules.
++ */
++
++/*
++ * Macros for allocating and freeing kernel memory.
++ */
++#ifdef SVR4 /* SVR4, including Solaris 2 */
++#include &lt;sys/kmem.h&gt;
++#define ALLOC_SLEEP(n) kmem_alloc((n), KM_SLEEP)
++#define ALLOC_NOSLEEP(n) kmem_alloc((n), KM_NOSLEEP)
++#define FREE(p, n) kmem_free((p), (n))
++#endif
++
++#ifdef SUNOS4
++#include &lt;sys/kmem_alloc.h&gt; /* SunOS 4.x */
++#define ALLOC_SLEEP(n) kmem_alloc((n), KMEM_SLEEP)
++#define ALLOC_NOSLEEP(n) kmem_alloc((n), KMEM_NOSLEEP)
++#define FREE(p, n) kmem_free((p), (n))
++#define NOTSUSER() (suser()? 0: EPERM)
++#define bcanputnext(q, band) canputnext((q))
++#endif /* SunOS 4 */
++
++#ifdef __osf__
++#include &lt;sys/malloc.h&gt;
++
++/* caution: this mirrors macros in sys/malloc.h, and uses interfaces
++ * which are subject to change.
++ * The problems are that:
++ * - the official MALLOC macro wants the lhs of the assignment as an argument,
++ * and it takes care of the assignment itself (yuck.)
++ * - PPP insists on using &quot;FREE&quot; which conflicts with a macro of the same name.
++ *
++ */
++#ifdef BUCKETINDX /* V2.0 */
++#define ALLOC_SLEEP(n) (void *)malloc((u_long)(n), BUCKETP(n), M_DEVBUF, M_WAITOK)
++#define ALLOC_NOSLEEP(n) (void *)malloc((u_long)(n), BUCKETP(n), M_DEVBUF, M_NOWAIT)
++#else
++#define ALLOC_SLEEP(n) (void *)malloc((u_long)(n), BUCKETINDEX(n), M_DEVBUF, M_WAITOK)
++#define ALLOC_NOSLEEP(n) (void *)malloc((u_long)(n), BUCKETINDEX(n), M_DEVBUF, M_NOWAIT)
++#endif
++
++#define bcanputnext(q, band) canputnext((q))
++
++#ifdef FREE
++#undef FREE
++#endif
++#define FREE(p, n) free((void *)(p), M_DEVBUF)
++
++#define NO_DLPI 1
++
++#ifndef IFT_PPP
++#define IFT_PPP 0x17
++#endif
++
++#include &lt;sys/proc.h&gt;
++#define NOTSUSER() (suser(u.u_procp-&gt;p_rcred, &amp;u.u_acflag) ? EPERM : 0)
++
++/* #include &quot;ppp_osf.h&quot; */
++
++#endif /* __osf__ */
++
++#ifdef AIX4
++#define ALLOC_SLEEP(n) xmalloc((n), 0, pinned_heap) /* AIX V4.x */
++#define ALLOC_NOSLEEP(n) xmalloc((n), 0, pinned_heap) /* AIX V4.x */
++#define FREE(p, n) xmfree((p), pinned_heap)
++#define NOTSUSER() (suser()? 0: EPERM)
++#endif /* AIX */
++
++/*
++ * Macros for printing debugging stuff.
++ */
++#ifdef DEBUG
++#if defined(SVR4) || defined(__osf__)
++#if defined(SNI)
++#include &lt;sys/strlog.h&gt;
++#define STRLOG_ID 4712
++#define DPRINT(f) strlog(STRLOG_ID, 0, 0, SL_TRACE, f)
++#define DPRINT1(f, a1) strlog(STRLOG_ID, 0, 0, SL_TRACE, f, a1)
++#define DPRINT2(f, a1, a2) strlog(STRLOG_ID, 0, 0, SL_TRACE, f, a1, a2)
++#define DPRINT3(f, a1, a2, a3) strlog(STRLOG_ID, 0, 0, SL_TRACE, f, a1, a2, a3)
++#else
++#define DPRINT(f) cmn_err(CE_CONT, f)
++#define DPRINT1(f, a1) cmn_err(CE_CONT, f, a1)
++#define DPRINT2(f, a1, a2) cmn_err(CE_CONT, f, a1, a2)
++#define DPRINT3(f, a1, a2, a3) cmn_err(CE_CONT, f, a1, a2, a3)
++#endif /* SNI */
++#else
++#define DPRINT(f) printf(f)
++#define DPRINT1(f, a1) printf(f, a1)
++#define DPRINT2(f, a1, a2) printf(f, a1, a2)
++#define DPRINT3(f, a1, a2, a3) printf(f, a1, a2, a3)
++#endif /* SVR4 or OSF */
++
++#else
++#define DPRINT(f) 0
++#define DPRINT1(f, a1) 0
++#define DPRINT2(f, a1, a2) 0
++#define DPRINT3(f, a1, a2, a3) 0
++#endif /* DEBUG */
++
++#ifndef SVR4
++typedef unsigned char uchar_t;
++typedef unsigned short ushort_t;
++#ifndef __osf__
++typedef int minor_t;
++#endif
++#endif
++
++/*
++ * If we don't have multithreading support, define substitutes.
++ */
++#ifndef D_MP
++# define qprocson(q)
++# define qprocsoff(q)
++# define put(q, mp) ((*(q)-&gt;q_qinfo-&gt;qi_putp)((q), (mp)))
++# define canputnext(q) canput((q)-&gt;q_next)
++# define qwriter(q, mp, func, scope) (func)((q), (mp))
++#endif
++
++#ifdef D_MP
++/* Use msgpullup if we have other multithreading support. */
++#define PULLUP(mp, len) \
++ do { \
++ mblk_t *np = msgpullup((mp), (len)); \
++ freemsg((mp)); \
++ mp = np; \
++ } while (0)
++
++#else
++/* Use pullupmsg if we don't have any multithreading support. */
++#define PULLUP(mp, len) \
++ do { \
++ if (!pullupmsg((mp), (len))) { \
++ freemsg((mp)); \
++ mp = 0; \
++ } \
++ } while (0)
++#endif
++
++/*
++ * How to declare the open and close procedures for a module.
++ */
++#ifdef SVR4
++#define MOD_OPEN_DECL(name) \
++static int name __P((queue_t *, dev_t *, int, int, cred_t *))
++
++#define MOD_CLOSE_DECL(name) \
++static int name __P((queue_t *, int, cred_t *))
++
++#define MOD_OPEN(name) \
++static int name(q, devp, flag, sflag, credp) \
++ queue_t *q; \
++ dev_t *devp; \
++ int flag, sflag; \
++ cred_t *credp;
++
++#define MOD_CLOSE(name) \
++static int name(q, flag, credp) \
++ queue_t *q; \
++ int flag; \
++ cred_t *credp;
++
++#define OPEN_ERROR(x) return (x)
++#define DRV_OPEN_OK(dev) return 0
++
++#define NOTSUSER() (drv_priv(credp))
++
++#else /* not SVR4 */
++#define MOD_OPEN_DECL(name) \
++static int name __P((queue_t *, int, int, int))
++
++#define MOD_CLOSE_DECL(name) \
++static int name __P((queue_t *, int))
++
++#define MOD_OPEN(name) \
++static int name(q, dev, flag, sflag) \
++ queue_t *q; \
++ int dev; \
++ int flag, sflag;
++
++#define MOD_CLOSE(name) \
++static int name(q, flag) \
++ queue_t *q; \
++ int flag;
++
++#define OPEN_ERROR(x) { u.u_error = (x); return OPENFAIL; }
++#define DRV_OPEN_OK(dev) return (dev)
++
++#endif /* SVR4 */
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/solaris/ppp_mod.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/sunos4/Makedefs
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/sunos4/Makedefs (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/sunos4/Makedefs 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,13 @@
++#
++# defines common to several Makefiles
++#
++
++INSTALL= install -o root -g daemon
++
++BINDIR = /usr/local/etc
++MANDIR = /usr/local/man
++ETCDIR = /etc/ppp
++
++# To use gcc, uncomment the next line.
++#CC = gcc
++COPTS = -O
+
+Added: drakx/trunk/mdk-stage1/ppp/sunos4/Makefile
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/sunos4/Makefile (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/sunos4/Makefile 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,57 @@
++#
++# Makefile for STREAMS modules for SunOS 4.
++#
++# $Id: Makefile 195720 2001-06-11 11:44:34Z gc $
++#
++
++include Makedefs
++
++LD = /usr/bin/ld # make sure we don't get gnu ld
++
++# Defining __$(ARCH)__ is for gcc's broken version of sun/vddrv.h.
++ARCH = `/bin/arch -k`
++DEFINES= -DKERNEL -D_KERNEL -DSUNOS4 -D$(ARCH) -D__$(ARCH)__ \
++ -DDEBUG -DNO_DLPI -DSNIT_SUPPORT
++CFLAGS= $(DEFINES) -I../include $(COPTS)
++
++MODULES= ppp_mod.o ppp_ahdl_mod.o ppp_comp_mod.o if_ppp_mod.o
++
++all: $(MODULES)
++
++ppp_mod.o: ppp.o ppp_vdcmd.o
++ $(LD) -r -o ppp_mod.o ppp.o ppp_vdcmd.o
++
++ppp_ahdl_mod.o: ppp_ahdlc.o ppp_ahdlc_vdcmd.o
++ $(LD) -r -o ppp_ahdl_mod.o ppp_ahdlc.o ppp_ahdlc_vdcmd.o
++
++COMP_OBJS = ppp_comp.o bsd-comp.o deflate.o zlib.o vjcompress.o \
++ ppp_comp_vdcmd.o
++ppp_comp_mod.o: $(COMP_OBJS)
++ $(LD) -r -o $@ $(COMP_OBJS)
++
++if_ppp.o: ../modules/if_ppp.c
++ $(CC) $(CFLAGS) -c $?
++bsd-comp.o: ../modules/bsd-comp.c
++ $(CC) $(CFLAGS) -c $?
++deflate.o: ../modules/deflate.c
++ $(CC) $(CFLAGS) -c $?
++ppp.o: ../modules/ppp.c
++ $(CC) $(CFLAGS) -c $?
++ppp_ahdlc.o: ../modules/ppp_ahdlc.c
++ $(CC) $(CFLAGS) -c $?
++ppp_comp.o: ../modules/ppp_comp.c
++ $(CC) $(CFLAGS) -c $?
++vjcompress.o: ../modules/vjcompress.c
++ $(CC) $(CFLAGS) -c $?
++zlib.o: ../common/zlib.c
++ $(CC) $(CFLAGS) -c $?
++
++if_ppp_mod.o: if_ppp.o if_ppp_vdcmd.o
++ $(LD) -r -o if_ppp_mod.o if_ppp.o if_ppp_vdcmd.o
++
++install: all
++ $(INSTALL) $(MODULES) $(BINDIR)
++ ./ppp.INSTALL
++
++clean:
++ rm -f ppp ppp_comp ppp_ahdl *.o *~ core
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/sunos4/Makefile
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/sunos4/Makefile.top
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/sunos4/Makefile.top (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/sunos4/Makefile.top 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,46 @@
++#
++# ppp top level makefile
++#
++
++include sunos4/Makedefs
++
++all:
++ cd chat; $(MAKE) all
++ cd pppd; $(MAKE) all
++ cd pppstats; $(MAKE) all
++ cd sunos4; $(MAKE) all
++ cd pppdump; $(MAKE) all
++
++install: $(BINDIR) $(MANDIR)/man8 install-progs install-etcppp
++
++install-progs:
++ cd chat; $(MAKE) install
++ cd pppd; $(MAKE) install
++ cd pppstats; $(MAKE) install
++ cd pppdump; $(MAKE) install
++ cd sunos4; $(MAKE) install
++
++install-etcppp: $(ETCDIR) $(ETCDIR)/options $(ETCDIR)/pap-secrets \
++ $(ETCDIR)/chap-secrets
++
++$(ETCDIR)/options:
++ $(INSTALL) -c -m 644 etc.ppp/options $@
++$(ETCDIR)/pap-secrets:
++ $(INSTALL) -c -m 600 etc.ppp/pap-secrets $@
++$(ETCDIR)/chap-secrets:
++ $(INSTALL) -c -m 600 etc.ppp/chap-secrets $@
++
++$(BINDIR):
++ $(INSTALL) -d -m 755 $@
++$(MANDIR)/man8:
++ $(INSTALL) -d -m 755 $@
++$(ETCDIR):
++ $(INSTALL) -d -m 755 $@
++
++clean:
++ rm -f *~
++ cd chat; $(MAKE) clean
++ cd pppd; $(MAKE) clean
++ cd pppstats; $(MAKE) clean
++ cd sunos4; $(MAKE) clean
++
+
+Added: drakx/trunk/mdk-stage1/ppp/sunos4/if_ppp_vdcmd.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/sunos4/if_ppp_vdcmd.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/sunos4/if_ppp_vdcmd.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,57 @@
++#include &lt;sys/types.h&gt;
++#include &lt;sys/errno.h&gt;
++#include &lt;sys/conf.h&gt;
++#include &lt;sun/vddrv.h&gt;
++
++extern struct streamtab if_pppinfo;
++
++static struct vdldrv vd = {
++ VDMAGIC_USER,
++ &quot;if_ppp&quot;
++};
++
++static int fmodsw_index = -1;
++
++int
++if_ppp_vdcmd(fun, vdp, vdi, vds)
++ unsigned int fun;
++ struct vddrv *vdp;
++ addr_t vdi;
++ struct vdstat *vds;
++{
++ int n, error;
++
++ switch (fun) {
++ case VDLOAD:
++ vdp-&gt;vdd_vdtab = (struct vdlinkage *) &amp;vd;
++ if (fmodsw_index &gt;= 0)
++ return EBUSY;
++ for (n = 0; n &lt; fmodcnt; ++n)
++ if (fmodsw[n].f_str == 0)
++ break;
++ if (n &gt;= fmodcnt)
++ return ENODEV;
++ strncpy(fmodsw[n].f_name, vd.Drv_name, FMNAMESZ+1);
++ fmodsw[n].f_str = &amp;if_pppinfo;
++ fmodsw_index = n;
++ break;
++
++ case VDUNLOAD:
++ if (fmodsw_index &lt;= 0)
++ return EINVAL;
++ error = if_ppp_unload();
++ if (error != 0)
++ return error;
++ fmodsw[fmodsw_index].f_name[0] = 0;
++ fmodsw[fmodsw_index].f_str = 0;
++ fmodsw_index = -1;
++ break;
++
++ case VDSTAT:
++ break;
++
++ default:
++ return EIO;
++ }
++ return 0;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/sunos4/if_ppp_vdcmd.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/sunos4/ppp.INSTALL
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/sunos4/ppp.INSTALL (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/sunos4/ppp.INSTALL 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,104 @@
++#!/bin/sh
++
++# Script for loading, unloading, etc. ppp modules.
++
++moddir=/usr/local/etc
++etcppp=/etc/ppp
++
++PATH=/usr/etc:/usr/bin
++
++# Check that we're superuser
++touch /tmp/su$$
++if chown root /tmp/su$$ &gt;/dev/null; then :
++else
++ echo &quot;$0: must be root.&quot;
++ rm -f /tmp/su$$
++ exit 1
++fi
++rm -f /tmp/su$$
++
++case &quot;$0&quot; in
++*ppp.INSTALL)
++ if [ ! -f ppp.INSTALL ]; then
++ echo &quot;ppp.INSTALL: not found&quot;
++ exit 1
++ fi
++ for n in INSTALL LOAD UNLOAD MKDEV RMDEV; do
++ if [ -h /dev/ppp.$n -o -f /dev/ppp.$n ]; then
++ rm /dev/ppp.$n
++ fi
++ done
++ cp ppp.INSTALL /dev
++ for n in LOAD UNLOAD MKDEV RMDEV; do
++ ln -s ppp.INSTALL /dev/ppp.$n
++ done
++ ;;
++
++*ppp.LOAD)
++ if modstat | grep -w ppp &gt;/dev/null; then
++ echo &quot;ppp driver is already loaded.&quot;
++ exit 1
++ fi
++ if modstat | grep -w if_ppp &gt;/dev/null; then
++ echo &quot;if_ppp module already loaded: not reloading.&quot;
++ else
++ echo -n &quot;if_ppp: &quot;
++ modload $moddir/if_ppp_mod.o -sym -entry _if_ppp_vdcmd \
++ -o $etcppp/if_ppp_mod
++ fi
++ echo -n &quot;ppp: &quot;
++ modload $moddir/ppp_mod.o -sym -entry _ppp_vdcmd -exec /dev/ppp.MKDEV \
++ -o $etcppp/ppp_mod
++ echo -n &quot;ppp_comp: &quot;
++ modload $moddir/ppp_comp_mod.o -sym -entry _ppp_comp_vdcmd \
++ -o $etcppp/ppp_comp
++ echo -n &quot;ppp_ahdl: &quot;
++ modload $moddir/ppp_ahdl_mod.o -sym -entry _ppp_ahdlc_vdcmd \
++ -o $etcppp/ppp_ahdl
++ exit 0
++ ;;
++
++*ppp.MKDEV)
++ # args: module number, type, b-major, c-major
++ if [ $# -ne 4 ]; then
++ echo &quot;Usage: $0 module-id module-type b-major c-major&quot;
++ exit 1
++ fi
++ if [ &quot;$2&quot; -ne &quot;12345607&quot; -a &quot;$2&quot; -ne &quot;12345600&quot; ]; then
++ echo &quot;$0: $2: bad module type&quot;
++ exit 1
++ fi
++ rm -f /dev/ppp
++ # we &quot;just know&quot; that 37 is the major number of the clone driver
++ mknod /dev/ppp c 37 $4
++ chmod 644 /dev/ppp
++ exit 0
++ ;;
++
++*ppp.UNLOAD)
++ stat=0
++ if modstat | grep -w if_ppp &gt;/dev/null; then
++ echo &quot;$0: not unloading if_ppp module.&quot;
++ fi
++ for mod in ppp ppp_comp ppp_ahdl; do
++ id=`modstat | grep -w $mod | awk '{print $1}'`
++ if [ x$id = x ]; then
++ echo &quot;$mod is not loaded.&quot;
++ stat=1
++ else
++ modunload -id $id
++ fi
++ done
++ exit $stat
++ ;;
++
++*ppp.RMDEV)
++ rm -f /dev/ppp
++ exit 0
++ ;;
++
++*)
++ echo &quot;Invocation names: ppp.INSTALL ppp.LOAD ppp.UNLOAD ppp.MKDEV ppp.RMDEV&quot;
++ exit 1
++ ;;
++esac
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/sunos4/ppp.INSTALL
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: drakx/trunk/mdk-stage1/ppp/sunos4/ppp_ahdlc_vdcmd.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/sunos4/ppp_ahdlc_vdcmd.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/sunos4/ppp_ahdlc_vdcmd.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,57 @@
++#include &lt;sys/types.h&gt;
++#include &lt;sys/errno.h&gt;
++#include &lt;sys/conf.h&gt;
++#include &lt;sun/vddrv.h&gt;
++
++extern struct streamtab ppp_ahdlcinfo;
++extern int ppp_ahdlc_count;
++
++static struct vdldrv vd = {
++ VDMAGIC_USER,
++ &quot;ppp_ahdl&quot;
++};
++
++static int fmodsw_index = -1;
++
++int
++ppp_ahdlc_vdcmd(fun, vdp, vdi, vds)
++ unsigned int fun;
++ struct vddrv *vdp;
++ addr_t vdi;
++ struct vdstat *vds;
++{
++ int n;
++
++ switch (fun) {
++ case VDLOAD:
++ vdp-&gt;vdd_vdtab = (struct vdlinkage *) &amp;vd;
++ if (fmodsw_index &gt;= 0)
++ return EBUSY;
++ for (n = 0; n &lt; fmodcnt; ++n)
++ if (fmodsw[n].f_str == 0)
++ break;
++ if (n &gt;= fmodcnt)
++ return ENODEV;
++ strncpy(fmodsw[n].f_name, vd.Drv_name, FMNAMESZ+1);
++ fmodsw[n].f_str = &amp;ppp_ahdlcinfo;
++ fmodsw_index = n;
++ break;
++
++ case VDUNLOAD:
++ if (ppp_ahdlc_count &gt; 0)
++ return EBUSY;
++ if (fmodsw_index &lt;= 0)
++ return EINVAL;
++ fmodsw[fmodsw_index].f_name[0] = 0;
++ fmodsw[fmodsw_index].f_str = 0;
++ fmodsw_index = -1;
++ break;
++
++ case VDSTAT:
++ break;
++
++ default:
++ return EIO;
++ }
++ return 0;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/sunos4/ppp_ahdlc_vdcmd.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/sunos4/ppp_comp_vdcmd.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/sunos4/ppp_comp_vdcmd.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/sunos4/ppp_comp_vdcmd.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,57 @@
++#include &lt;sys/types.h&gt;
++#include &lt;sys/errno.h&gt;
++#include &lt;sys/conf.h&gt;
++#include &lt;sun/vddrv.h&gt;
++
++extern struct streamtab ppp_compinfo;
++extern int ppp_comp_count;
++
++static struct vdldrv vd = {
++ VDMAGIC_USER,
++ &quot;ppp_comp&quot;
++};
++
++static int fmodsw_index = -1;
++
++int
++ppp_comp_vdcmd(fun, vdp, vdi, vds)
++ unsigned int fun;
++ struct vddrv *vdp;
++ addr_t vdi;
++ struct vdstat *vds;
++{
++ int n;
++
++ switch (fun) {
++ case VDLOAD:
++ vdp-&gt;vdd_vdtab = (struct vdlinkage *) &amp;vd;
++ if (fmodsw_index &gt;= 0)
++ return EBUSY;
++ for (n = 0; n &lt; fmodcnt; ++n)
++ if (fmodsw[n].f_str == 0)
++ break;
++ if (n &gt;= fmodcnt)
++ return ENODEV;
++ strncpy(fmodsw[n].f_name, vd.Drv_name, FMNAMESZ+1);
++ fmodsw[n].f_str = &amp;ppp_compinfo;
++ fmodsw_index = n;
++ break;
++
++ case VDUNLOAD:
++ if (ppp_comp_count &gt; 0)
++ return EBUSY;
++ if (fmodsw_index &lt;= 0)
++ return EINVAL;
++ fmodsw[fmodsw_index].f_name[0] = 0;
++ fmodsw[fmodsw_index].f_str = 0;
++ fmodsw_index = -1;
++ break;
++
++ case VDSTAT:
++ break;
++
++ default:
++ return EIO;
++ }
++ return 0;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/sunos4/ppp_comp_vdcmd.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/sunos4/ppp_vdcmd.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/sunos4/ppp_vdcmd.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/sunos4/ppp_vdcmd.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,81 @@
++#include &lt;sys/types.h&gt;
++#include &lt;sys/errno.h&gt;
++#include &lt;sys/conf.h&gt;
++#include &lt;sun/vddrv.h&gt;
++
++extern struct streamtab pppinfo;
++extern int ppp_count;
++extern int nchrdev;
++
++static struct vdldrv vd = {
++ VDMAGIC_PSEUDO,
++ &quot;ppp&quot;
++};
++
++extern int nodev();
++
++static struct cdevsw ppp_cdevsw = {
++ nodev, nodev, nodev, nodev, nodev, nodev, nodev, 0,
++ &amp;pppinfo
++};
++
++static struct cdevsw old_entry;
++
++int
++ppp_vdcmd(fun, vdp, vdi, vds)
++ unsigned int fun;
++ struct vddrv *vdp;
++ addr_t vdi;
++ struct vdstat *vds;
++{
++ static int majnum = -1;
++ int n, maj;
++
++ switch (fun) {
++ case VDLOAD:
++ /*
++ * It seems like modload doesn't install the cdevsw entry
++ * for us. Oh well...
++ */
++ for (maj = 1; maj &lt; nchrdev; ++maj)
++ if (cdevsw[maj].d_open == vd_unuseddev)
++ break;
++ if (maj &gt;= nchrdev)
++ return ENODEV;
++ vd.Drv_charmajor = maj;
++ old_entry = cdevsw[maj];
++ cdevsw[maj] = ppp_cdevsw;
++ vd.Drv_cdevsw = &amp;ppp_cdevsw;
++ vdp-&gt;vdd_vdtab = (struct vdlinkage *) &amp;vd;
++ majnum = maj;
++ break;
++
++ case VDUNLOAD:
++ if (ppp_count &gt; 0)
++ return EBUSY;
++ if (vd.Drv_charmajor &gt; 0)
++ cdevsw[vd.Drv_charmajor] = old_entry;
++ break;
++
++ case VDSTAT:
++ /*
++ * We have to fool the modstat command into thinking
++ * that this module is actually a driver! This is
++ * so that installation commands that use the -exec
++ * option of modload to run a shell script find out
++ * the block and/or char major numbers of the driver
++ * loaded (so that the shell script can go off to
++ * /dev and *MAKE* the bloody device nodes- remember
++ * they might change from one load to another if
++ * you don't hardwire the number!).
++ */
++ vds-&gt;vds_magic = VDMAGIC_DRV;
++ vds-&gt;vds_modinfo[0] = (char) 0;
++ vds-&gt;vds_modinfo[1] = (char) majnum;
++ break;
++
++ default:
++ return EIO;
++ }
++ return 0;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/sunos4/ppp_vdcmd.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/svr4/Makedefs
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/svr4/Makedefs (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/svr4/Makedefs 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,16 @@
++#
++# defines common to several Makefiles
++#
++
++INSTALL= /usr/sbin/install
++
++BINDIR = /usr/local/bin
++MANDIR = /usr/local/man
++ETCDIR = /etc/ppp
++
++COPTS = -O -Xa
++
++# For compiling with gcc, comment out the COPTS definition above and
++# uncomment the next 2 definitions.
++#CC = gcc
++#COPTS = -O2
+
+Added: drakx/trunk/mdk-stage1/ppp/svr4/Makedefs.sol2
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/svr4/Makedefs.sol2 (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/svr4/Makedefs.sol2 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,59 @@
++#
++# Generic make definitions for Solaris 2
++#
++# $Id: Makedefs.sol2 195720 2001-06-11 11:44:34Z gc $
++#
++
++include ../svr4/Makedefs
++
++CPPFLAGS = -D_KERNEL -DSVR4 -DSOL2 -DPRIOQ -DDEBUG -I../include
++CFLAGS = $(CPPFLAGS) $(COPTS)
++
++# lint-specific variables
++LINT = lint
++LINT_OPT_32 =
++LINT_OPT_64 = -Xarch=v9 -errchk=longptr64
++
++LINT_32 =
++LINT_32 += -erroff=E_BAD_PTR_CAST_ALIGN
++LINT_32 += -erroff=E_SUPPRESSION_DIRECTIVE_UNUSED
++LINT_32 += -erroff=E_SUSPICIOUS_COMPARISON
++LINT_32 += -erroff=E_CAST_UINT_TO_SIGNED_INT
++LINT_32 += -erroff=E_PASS_UINT_TO_SIGNED_INT
++LINT_32 += -erroff=E_INVALID_ANNOTATION_NAME
++LINT_32 += -erroff=E_FUNC_ARG_UNUSED
++# This might be needed, but zlib.c and vjcompress.c will squawk
++# when not ignored
++LINT_32 += -erroff=E_CASE_FALLTHRU
++LINT_32 += -erroff=E_RET_INT_IMPLICITLY
++LINT_32 += -erroff=E_FUNC_NO_RET_VAL
++# Some STREAMS macros will be noisy too when this isn't ignored
++LINT_32 += -erroff=E_CONSTANT_CONDITION
++LINT_32 += -erroff=E_CONST_EXPR
++
++# Extra noise suppressant for 64-bit
++EXTRA_OFF =
++EXTRA_OFF += -erroff=E_CAST_INT_TO_SMALL_INT
++EXTRA_OFF += -erroff=E_CAST_INT_CONST_TO_SMALL_INT
++EXTRA_OFF += -erroff=E_CAST_TO_PTR_FROM_INT
++EXTRA_OFF += -erroff=E_ASSIGN_INT_TO_SMALL_INT
++EXTRA_OFF += -erroff=E_ASSIGN_INT_FROM_BIG_CONST
++EXTRA_OFF += -erroff=E_CONST_PROMOTED_UNSIGNED_LL
++EXTRA_OFF += -erroff=E_CONST_PROMOTED_LONG_LONG
++EXTRA_OFF += -erroff=E_CONST_TRUNCATED_BY_ASSIGN
++EXTRA_OFF += -erroff=E_PASS_INT_FROM_BIG_CONST
++EXTRA_OFF += -erroff=E_COMP_INT_WITH_LARGE_INT
++EXTRA_OFF += -erroff=E_ASSIGN_UINT_TO_SIGNED_INT
++EXTRA_OFF += -erroff=E_ASSIGN_NARROW_CONV
++EXTRA_OFF += -erroff=E_PASS_INT_TO_SMALL_INT
++EXTRA_OFF += -erroff=E_PTR_CONV_LOSES_BITS
++
++LINT_64 = $(LINT_32)
++LINT_64 += $(EXTRA_OFF)
++
++LINTFLAGS64 = -Xa -nsxmuF -errtags=yes $(LINT_OPT_64) $(LINT_64)
++LINT64 = $(LINT) -c $(LINTFLAGS64) $(CPPFLAGS)
++
++LINTFLAGS32 = -Xa -nsxmuF -errtags=yes $(LINT_OPT_32) $(LINT_32)
++LINT32 = $(LINT) -c $(LINTFLAGS32) $(CPPFLAGS)
++
+
+Added: drakx/trunk/mdk-stage1/ppp/svr4/Makefile.sol2
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/svr4/Makefile.sol2 (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/svr4/Makefile.sol2 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,66 @@
++#
++# Makefile for STREAMS modules for Solaris 2.
++#
++# $Id: Makefile.sol2 195720 2001-06-11 11:44:34Z gc $
++#
++
++include Makedefs.sol2
++
++COPTS += -xO2 -xspace -W0,-Lt
++
++COMP_OBJS = ppp_comp.o bsd-comp.o deflate.o zlib.o vjcompress.o \
++ ppp_comp_mod.o
++
++all: ppp ppp_ahdl ppp_comp
++
++ppp: ppp.o ppp_mod.o
++ ld -r -o $@ ppp.o ppp_mod.o
++ chmod +x $@
++
++ppp_ahdl: ppp_ahdlc.o ppp_ahdlc_mod.o
++ ld -r -o $@ ppp_ahdlc.o ppp_ahdlc_mod.o
++ chmod +x $@
++
++ppp_comp: $(COMP_OBJS)
++ ld -r -o $@ $(COMP_OBJS)
++ chmod +x $@
++
++bsd-comp.o: ../modules/bsd-comp.c
++ $(CC) $(CFLAGS) -c $?
++deflate.o: ../modules/deflate.c
++ $(CC) $(CFLAGS) -c $?
++ppp.o: ../modules/ppp.c
++ $(CC) $(CFLAGS) -c $?
++ppp_mod.o: ppp_mod.c
++ $(CC) $(CFLAGS) -c $?
++ppp_ahdlc_mod.o: ppp_ahdlc_mod.c
++ $(CC) $(CFLAGS) -c $?
++ppp_ahdlc.o: ../modules/ppp_ahdlc.c
++ $(CC) $(CFLAGS) -c $?
++ppp_comp.o: ../modules/ppp_comp.c
++ $(CC) $(CFLAGS) -c $?
++ppp_comp_mod.o: ppp_comp_mod.c
++ $(CC) $(CFLAGS) -c $?
++vjcompress.o: ../modules/vjcompress.c
++ $(CC) $(CFLAGS) -c $?
++zlib.o: ../common/zlib.c
++ $(CC) $(CFLAGS) -c $?
++
++install:
++ cp ppp ppp.conf /kernel/drv
++ cp ppp_comp ppp_ahdl /kernel/strmod
++ if grep clone:ppp /etc/minor_perm; then :; else \
++ echo clone:ppp 0644 root sys &gt;&gt;/etc/minor_perm; fi
++ /usr/sbin/rem_drv ppp 2&gt;/dev/null || true
++ /usr/sbin/add_drv ppp
++
++SRCS = ../modules/ppp.c ppp_mod.c ../modules/ppp_ahdlc.c ppp_ahdlc_mod.c \
++ ../modules/ppp_comp.c ../modules/bsd-comp.c ../modules/deflate.c \
++ ../common/zlib.c ../modules/vjcompress.c ppp_comp_mod.c
++
++lint:
++ $(LINT32) $(SRCS)
++
++clean:
++ rm -f ppp ppp_comp ppp_ahdl *.o *~ core
++ rm -f *.ln
+
+Added: drakx/trunk/mdk-stage1/ppp/svr4/Makefile.sol2-64
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/svr4/Makefile.sol2-64 (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/svr4/Makefile.sol2-64 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,85 @@
++#
++# Makefile for 64-bit STREAMS modules for Solaris 2.
++#
++# $Id: Makefile.sol2-64 195720 2001-06-11 11:44:34Z gc $
++#
++
++include Makedefs.sol2
++
++# Sun's cc flag for LP64 compilation / linkage
++COPTS += -xchip=ultra -xarch=v9 -Wc,-xcode=abs32 -Wc,-Qiselect-regsym=0 -xO3 -xspace -W0,-Lt
++
++# subdirectory where 64-bit objects / binaries will be placed
++LP64DIR = sparcv9
++
++# Name of legacy Makefile (for 32-bit binaries)
++STD_MAKE = Makefile.sol2
++
++COMP_OBJS = $(LP64DIR)/ppp_comp.o $(LP64DIR)/bsd-comp.o \
++ $(LP64DIR)/deflate.o $(LP64DIR)/zlib.o $(LP64DIR)/vjcompress.o \
++ $(LP64DIR)/ppp_comp_mod.o
++
++all: std_objs $(LP64DIR) ppp ppp_ahdl ppp_comp
++
++std_objs:
++ $(MAKE) -f $(STD_MAKE) all
++
++ppp: $(LP64DIR)/ppp.o $(LP64DIR)/ppp_mod.o
++ ld -r -o $(LP64DIR)/$@ $(LP64DIR)/ppp.o $(LP64DIR)/ppp_mod.o
++ chmod +x $(LP64DIR)/$@
++
++ppp_ahdl: $(LP64DIR)/ppp_ahdlc.o $(LP64DIR)/ppp_ahdlc_mod.o
++ ld -r -o $(LP64DIR)/$@ $(LP64DIR)/ppp_ahdlc.o $(LP64DIR)/ppp_ahdlc_mod.o
++ chmod +x $(LP64DIR)/$@
++
++ppp_comp: $(COMP_OBJS)
++ ld -r -o $(LP64DIR)/$@ $(COMP_OBJS)
++ chmod +x $(LP64DIR)/$@
++
++$(LP64DIR)/bsd-comp.o: ../modules/bsd-comp.c
++ $(CC) $(CFLAGS) -c $? -o $@
++$(LP64DIR)/deflate.o: ../modules/deflate.c
++ $(CC) $(CFLAGS) -c $? -o $@
++$(LP64DIR)/ppp.o: ../modules/ppp.c
++ $(CC) $(CFLAGS) -c $? -o $@
++$(LP64DIR)/ppp_mod.o: ppp_mod.c
++ $(CC) $(CFLAGS) -c $? -o $@
++$(LP64DIR)/ppp_ahdlc_mod.o: ppp_ahdlc_mod.c
++ $(CC) $(CFLAGS) -c $? -o $@
++$(LP64DIR)/ppp_ahdlc.o: ../modules/ppp_ahdlc.c
++ $(CC) $(CFLAGS) -c $? -o $@
++$(LP64DIR)/ppp_comp.o: ../modules/ppp_comp.c
++ $(CC) $(CFLAGS) -c $? -o $@
++$(LP64DIR)/ppp_comp_mod.o: ppp_comp_mod.c
++ $(CC) $(CFLAGS) -c $? -o $@
++$(LP64DIR)/vjcompress.o: ../modules/vjcompress.c
++ $(CC) $(CFLAGS) -c $? -o $@
++$(LP64DIR)/zlib.o: ../common/zlib.c
++ $(CC) $(CFLAGS) -c $? -o $@
++
++$(LP64DIR):
++ mkdir -m 755 -p $@
++
++install:
++ cp ppp ppp.conf /kernel/drv
++ cp ppp_comp ppp_ahdl /kernel/strmod
++ cp $(LP64DIR)/ppp /kernel/drv/$(LP64DIR)
++ cp $(LP64DIR)/ppp_comp $(LP64DIR)/ppp_ahdl /kernel/strmod/$(LP64DIR)
++ if grep clone:ppp /etc/minor_perm; then :; else \
++ echo clone:ppp 0644 root sys &gt;&gt;/etc/minor_perm; fi
++ /usr/sbin/rem_drv ppp 2&gt;/dev/null || true
++ /usr/sbin/add_drv ppp
++
++SRCS = ../modules/ppp.c ppp_mod.c ../modules/ppp_ahdlc.c ppp_ahdlc_mod.c \
++ ../modules/ppp_comp.c ../modules/bsd-comp.c ../modules/deflate.c \
++ ../common/zlib.c ../modules/vjcompress.c ppp_comp_mod.c
++
++lint:
++ $(LINT64) $(SRCS)
++
++lint-32:
++ $(LINT32) $(SRCS)
++
++clean:
++ $(MAKE) -f $(STD_MAKE) clean
++ rm -f $(LP64DIR)/ppp $(LP64DIR)/ppp_comp $(LP64DIR)/ppp_ahdl $(LP64DIR)/*.o $(LP64DIR)/*~ $(LP64DIR)/core
+
+Added: drakx/trunk/mdk-stage1/ppp/svr4/Makefile.svr4
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/svr4/Makefile.svr4 (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/svr4/Makefile.svr4 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,60 @@
++#
++# Makefile for STREAMS modules for SVR4.
++#
++# $Id: Makefile.svr4 195720 2001-06-11 11:44:34Z gc $
++#
++
++COPTS = -O
++
++CFLAGS= -D_KERNEL -DSVR4 -DLACHTCP -I../include $(COPTS)
++
++all: ppp ppp_ahdl ppp_comp
++
++ppp: ppp.o
++ ld -r -o $@ ppp.o
++
++ppp_ahdl: ppp_ahdlc.o
++ ld -r -o $@ ppp_ahdlc.o
++
++ppp_comp: ppp_comp.o bsd-comp.o vjcompress.o deflate.o zlib.o
++ ld -r -o $@ ppp_comp.o bsd-comp.o vjcompress.o deflate.o zlib.o
++
++bsd-comp.o: ../modules/bsd-comp.c
++ $(CC) $(CFLAGS) -c $?
++deflate.o: ../modules/deflate.c
++ $(CC) $(CFLAGS) -c $?
++ppp.o: ../modules/ppp.c
++ $(CC) $(CFLAGS) -c $?
++ppp_ahdlc.o: ../modules/ppp_ahdlc.c
++ $(CC) $(CFLAGS) -c $?
++ppp_comp.o: ../modules/ppp_comp.c
++ $(CC) $(CFLAGS) -c $?
++vjcompress.o: ../modules/vjcompress.c
++ $(CC) $(CFLAGS) -c $?
++zlib.o: ../common/zlib.c
++ $(CC) $(CFLAGS) -c $?
++
++install: all
++ cp ppp Driver.o
++ cp ppp.Master Master
++ cp ppp.System System
++ cp ppp.Node Node
++ /etc/conf/bin/idinstall -d ppp
++ /etc/conf/bin/idinstall -a ppp
++ cp ppp_comp Driver.o
++ cp ppp_comp.Master Master
++ cp ppp_comp.System System
++ /etc/conf/bin/idinstall -d ppp_comp
++ /etc/conf/bin/idinstall -a ppp_comp
++ cp ppp_ahdl Driver.o
++ cp ppp_ahdl.Master Master
++ cp ppp_ahdl.System System
++ /etc/conf/bin/idinstall -d ppp_ahdl
++ /etc/conf/bin/idinstall -a ppp_ahdl
++ @echo
++ @echo 'NOTE: You must rebuild your kernel to incorporate the driver.'
++ @echo '(use /etc/conf/bin/idbuild)'
++ @echo
++
++clean:
++ rm -f ppp ppp_comp ppp_ahdl *.o *~ core
+
+Added: drakx/trunk/mdk-stage1/ppp/svr4/Makefile.top
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/svr4/Makefile.top (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/svr4/Makefile.top 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,50 @@
++#
++# ppp top level makefile for SVR4 and Solaris 2
++#
++# $Id: Makefile.top 195720 2001-06-11 11:44:34Z gc $
++#
++
++include svr4/Makedefs
++
++all:
++ cd chat; $(MAKE) all
++ cd pppd; $(MAKE) all
++ cd pppstats; $(MAKE) all
++ cd pppdump; $(MAKE) all
++ cd svr4; $(MAKE) all
++
++install: $(BINDIR) $(MANDIR)/man8 install-progs install-etcppp
++
++install-progs:
++ cd chat; $(MAKE) install
++ cd pppd; $(MAKE) install
++ cd pppstats; $(MAKE) install
++ cd pppdump; $(MAKE) install
++ cd svr4; $(MAKE) install
++
++install-etcppp: $(ETCDIR) $(ETCDIR)/options $(ETCDIR)/pap-secrets \
++ $(ETCDIR)/chap-secrets
++
++$(ETCDIR)/options:
++ cp etc.ppp/options $@
++ chmod go-w $@
++$(ETCDIR)/pap-secrets:
++ $(INSTALL) -f $(ETCDIR) -m 600 etc.ppp/pap-secrets
++$(ETCDIR)/chap-secrets:
++ $(INSTALL) -f $(ETCDIR) -m 600 etc.ppp/chap-secrets
++
++$(BINDIR):
++ mkdir -m 755 -p $@
++$(MANDIR)/man8:
++ mkdir -m 755 -p $@
++$(ETCDIR):
++ mkdir -m 755 -p $@
++
++clean:
++ rm -f *~
++ cd chat; $(MAKE) clean
++ cd pppd; $(MAKE) clean
++ cd pppstats; $(MAKE) clean
++ cd pppdump; $(MAKE) clean
++ cd svr4; $(MAKE) clean
++
+
+Added: drakx/trunk/mdk-stage1/ppp/svr4/ppp.Master
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/svr4/ppp.Master (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/svr4/ppp.Master 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1 @@
++ppp - Sciof ppp 0 0 1 128 -1
+
+Added: drakx/trunk/mdk-stage1/ppp/svr4/ppp.Node
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/svr4/ppp.Node (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/svr4/ppp.Node 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1 @@
++clone ppp c ppp
+
+Added: drakx/trunk/mdk-stage1/ppp/svr4/ppp.System
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/svr4/ppp.System (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/svr4/ppp.System 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1 @@
++ppp Y 1 0 0 0 0 0 0 0
+
+Added: drakx/trunk/mdk-stage1/ppp/svr4/ppp.conf
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/svr4/ppp.conf (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/svr4/ppp.conf 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1 @@
++name=&quot;ppp&quot; parent=&quot;pseudo&quot; instance=0;
+
+Added: drakx/trunk/mdk-stage1/ppp/svr4/ppp_ahdl.Master
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/svr4/ppp_ahdl.Master (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/svr4/ppp_ahdl.Master 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1 @@
++ppp_ahdl - iSf phdl 0 0 1 1 -1
+
+Added: drakx/trunk/mdk-stage1/ppp/svr4/ppp_ahdl.System
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/svr4/ppp_ahdl.System (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/svr4/ppp_ahdl.System 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1 @@
++ppp_ahdl Y 1 0 0 0 0 0 0 0
+
+Added: drakx/trunk/mdk-stage1/ppp/svr4/ppp_ahdlc_mod.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/svr4/ppp_ahdlc_mod.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/svr4/ppp_ahdlc_mod.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,49 @@
++#include &lt;sys/types.h&gt;
++#include &lt;sys/param.h&gt;
++#include &lt;sys/conf.h&gt;
++#include &lt;sys/modctl.h&gt;
++#include &lt;sys/sunddi.h&gt;
++
++extern struct streamtab ppp_ahdlcinfo;
++
++static struct fmodsw fsw = {
++ &quot;ppp_ahdl&quot;,
++ &amp;ppp_ahdlcinfo,
++ D_NEW | D_MP | D_MTQPAIR
++};
++
++extern struct mod_ops mod_strmodops;
++
++static struct modlstrmod modlstrmod = {
++ &amp;mod_strmodops,
++ &quot;PPP async HDLC module&quot;,
++ &amp;fsw
++};
++
++static struct modlinkage modlinkage = {
++ MODREV_1,
++ (void *) &amp;modlstrmod,
++ NULL
++};
++
++/*
++ * Entry points for modloading.
++ */
++int
++_init(void)
++{
++ return mod_install(&amp;modlinkage);
++}
++
++int
++_fini(void)
++{
++ return mod_remove(&amp;modlinkage);
++}
++
++int
++_info(mip)
++ struct modinfo *mip;
++{
++ return mod_info(&amp;modlinkage, mip);
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/svr4/ppp_ahdlc_mod.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/svr4/ppp_comp.Master
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/svr4/ppp_comp.Master (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/svr4/ppp_comp.Master 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1 @@
++ppp_comp - iSf pcmp 0 0 1 1 -1
+
+Added: drakx/trunk/mdk-stage1/ppp/svr4/ppp_comp.System
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/svr4/ppp_comp.System (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/svr4/ppp_comp.System 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1 @@
++ppp_comp Y 1 0 0 0 0 0 0 0
+
+Added: drakx/trunk/mdk-stage1/ppp/svr4/ppp_comp_mod.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/svr4/ppp_comp_mod.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/svr4/ppp_comp_mod.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,81 @@
++/*
++ * ppp_comp_mod.c - modload support for PPP compression STREAMS module.
++ *
++ * Copyright (c) 1994 The Australian National University.
++ * All rights reserved.
++ *
++ * Permission to use, copy, modify, and distribute this software and its
++ * documentation is hereby granted, provided that the above copyright
++ * notice appears in all copies. This software is provided without any
++ * warranty, express or implied. The Australian National University
++ * makes no representations about the suitability of this software for
++ * any purpose.
++ *
++ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
++ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
++ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
++ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
++ * OF SUCH DAMAGE.
++ *
++ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
++ * ON AN &quot;AS IS&quot; BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
++ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
++ * OR MODIFICATIONS.
++ *
++ * $Id: ppp_comp_mod.c 195720 2001-06-11 11:44:34Z gc $
++ */
++
++/*
++ * This file is used under Solaris 2.
++ */
++#include &lt;sys/types.h&gt;
++#include &lt;sys/param.h&gt;
++#include &lt;sys/conf.h&gt;
++#include &lt;sys/modctl.h&gt;
++#include &lt;sys/sunddi.h&gt;
++
++extern struct streamtab ppp_compinfo;
++
++static struct fmodsw fsw = {
++ &quot;ppp_comp&quot;,
++ &amp;ppp_compinfo,
++ D_NEW | D_MP | D_MTQPAIR
++};
++
++extern struct mod_ops mod_strmodops;
++
++static struct modlstrmod modlstrmod = {
++ &amp;mod_strmodops,
++ &quot;PPP compression module&quot;,
++ &amp;fsw
++};
++
++static struct modlinkage modlinkage = {
++ MODREV_1,
++ (void *) &amp;modlstrmod,
++ NULL
++};
++
++/*
++ * Entry points for modloading.
++ */
++int
++_init(void)
++{
++ return mod_install(&amp;modlinkage);
++}
++
++int
++_fini(void)
++{
++ return mod_remove(&amp;modlinkage);
++}
++
++int
++_info(mip)
++ struct modinfo *mip;
++{
++ return mod_info(&amp;modlinkage, mip);
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/svr4/ppp_comp_mod.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/ppp/svr4/ppp_mod.c
+===================================================================
+--- drakx/trunk/mdk-stage1/ppp/svr4/ppp_mod.c (rev 0)
++++ drakx/trunk/mdk-stage1/ppp/svr4/ppp_mod.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,174 @@
++/*
++ * ppp_mod.c - modload support for PPP pseudo-device driver.
++ *
++ * Copyright (c) 1994 The Australian National University.
++ * All rights reserved.
++ *
++ * Permission to use, copy, modify, and distribute this software and its
++ * documentation is hereby granted, provided that the above copyright
++ * notice appears in all copies. This software is provided without any
++ * warranty, express or implied. The Australian National University
++ * makes no representations about the suitability of this software for
++ * any purpose.
++ *
++ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
++ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
++ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
++ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
++ * OF SUCH DAMAGE.
++ *
++ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
++ * ON AN &quot;AS IS&quot; BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
++ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
++ * OR MODIFICATIONS.
++ *
++ * $Id: ppp_mod.c 195720 2001-06-11 11:44:34Z gc $
++ */
++
++/*
++ * This file is used under Solaris 2.
++ */
++
++#include &lt;sys/types.h&gt;
++#include &lt;sys/param.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;sys/conf.h&gt;
++#include &lt;sys/modctl.h&gt;
++#include &lt;sys/sunddi.h&gt;
++#include &lt;sys/ksynch.h&gt;
++
++#ifdef __STDC__
++#define __P(x) x
++#else
++#define __P(x) ()
++#endif
++
++static int ppp_identify __P((dev_info_t *));
++static int ppp_attach __P((dev_info_t *, ddi_attach_cmd_t));
++static int ppp_detach __P((dev_info_t *, ddi_detach_cmd_t));
++static int ppp_devinfo __P((dev_info_t *, ddi_info_cmd_t, void *, void **));
++
++extern struct streamtab pppinfo;
++extern krwlock_t ppp_lower_lock;
++
++static dev_info_t *ppp_dip;
++
++static struct cb_ops cb_ppp_ops = {
++ nulldev, nulldev, nodev, nodev, /* cb_open, ... */
++ nodev, nodev, nodev, nodev, /* cb_dump, ... */
++ nodev, nodev, nodev, nochpoll, /* cb_devmap, ... */
++ ddi_prop_op, /* cb_prop_op */
++ &amp;pppinfo, /* cb_stream */
++ D_NEW|D_MP|D_MTQPAIR|D_MTOUTPERIM|D_MTOCEXCL /* cb_flag */
++};
++
++static struct dev_ops ppp_ops = {
++ DEVO_REV, /* devo_rev */
++ 0, /* devo_refcnt */
++ ppp_devinfo, /* devo_getinfo */
++ ppp_identify, /* devo_identify */
++ nulldev, /* devo_probe */
++ ppp_attach, /* devo_attach */
++ ppp_detach, /* devo_detach */
++ nodev, /* devo_reset */
++ &amp;cb_ppp_ops, /* devo_cb_ops */
++ NULL /* devo_bus_ops */
++};
++
++/*
++ * Module linkage information
++ */
++
++static struct modldrv modldrv = {
++ &amp;mod_driverops, /* says this is a pseudo driver */
++ &quot;PPP-2.3 multiplexing driver&quot;,
++ &amp;ppp_ops /* driver ops */
++};
++
++static struct modlinkage modlinkage = {
++ MODREV_1,
++ (void *) &amp;modldrv,
++ NULL
++};
++
++int
++_init(void)
++{
++ return mod_install(&amp;modlinkage);
++}
++
++int
++_fini(void)
++{
++ return mod_remove(&amp;modlinkage);
++}
++
++int
++_info(mip)
++ struct modinfo *mip;
++{
++ return mod_info(&amp;modlinkage, mip);
++}
++
++static int
++ppp_identify(dip)
++ dev_info_t *dip;
++{
++ return strcmp(ddi_get_name(dip), &quot;ppp&quot;) == 0? DDI_IDENTIFIED:
++ DDI_NOT_IDENTIFIED;
++}
++
++static int
++ppp_attach(dip, cmd)
++ dev_info_t *dip;
++ ddi_attach_cmd_t cmd;
++{
++
++ if (cmd != DDI_ATTACH)
++ return DDI_FAILURE;
++ if (ddi_create_minor_node(dip, &quot;ppp&quot;, S_IFCHR, 0, DDI_PSEUDO, CLONE_DEV)
++ == DDI_FAILURE) {
++ ddi_remove_minor_node(dip, NULL);
++ return DDI_FAILURE;
++ }
++ rw_init(&amp;ppp_lower_lock, NULL, RW_DRIVER, NULL);
++ return DDI_SUCCESS;
++}
++
++static int
++ppp_detach(dip, cmd)
++ dev_info_t *dip;
++ ddi_detach_cmd_t cmd;
++{
++ rw_destroy(&amp;ppp_lower_lock);
++ ddi_remove_minor_node(dip, NULL);
++ return DDI_SUCCESS;
++}
++
++static int
++ppp_devinfo(dip, cmd, arg, result)
++ dev_info_t *dip;
++ ddi_info_cmd_t cmd;
++ void *arg;
++ void **result;
++{
++ int error;
++
++ error = DDI_SUCCESS;
++ switch (cmd) {
++ case DDI_INFO_DEVT2DEVINFO:
++ if (ppp_dip == NULL)
++ error = DDI_FAILURE;
++ else
++ *result = (void *) ppp_dip;
++ break;
++ case DDI_INFO_DEVT2INSTANCE:
++ *result = NULL;
++ break;
++ default:
++ error = DDI_FAILURE;
++ }
++ return error;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/ppp/svr4/ppp_mod.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/probe-modules.c
+===================================================================
+--- drakx/trunk/mdk-stage1/probe-modules.c (rev 0)
++++ drakx/trunk/mdk-stage1/probe-modules.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,70 @@
++/*
++ * Olivier Blin (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">blino at mandriva.com</A>)
++ *
++ * Copyright 2007-2004 Mandriva
++ *
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#include &quot;log.h&quot;
++#include &quot;modules.h&quot;
++#include &quot;probing.h&quot;
++#include &quot;frontend.h&quot;
++#include &lt;stdlib.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;string.h&gt;
++#include &quot;utils.h&quot;
++
++void exit_bootsplash(void) {}
++void stg1_error_message(char *msg, ...)
++{
++ va_list args;
++ va_start(args, msg);
++ verror_message(msg, args);
++ va_end(args);
++}
++void fatal_error(char *msg)
++{
++ log_message(&quot;FATAL ERROR IN MODULES LOADER: %s\n\nI can't recover from this.\nYou may reboot your system.\n&quot;, msg);
++ exit(EXIT_FAILURE);
++}
++
++int main(int argc, char **argv, char **env)
++{
++ enum media_bus bus = BUS_ANY;
++ char *module = NULL;
++ char options[500] = &quot;&quot;;
++
++ if (argc &gt; 1) {
++ if (streq(argv[1], &quot;--usb&quot;)) {
++ bus = BUS_USB;
++ } else if (!ptr_begins_static_str(argv[1], &quot;--&quot;)) {
++ int i;
++ module = argv[1];
++ for (i = 2; i &lt; argc; i++) {
++ strcat(options, argv[i]);
++ strcat(options, &quot; &quot;);
++ }
++ }
++ }
++
++ open_log();
++ init_modules_insmoding();
++
++ if (module) {
++ my_insmod(module, ANY_DRIVER_TYPE, options, 0);
++ } else {
++ find_media(bus);
++ }
++
++ close_log();
++
++ return 0;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/probe-modules.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/probing.c
+===================================================================
+--- drakx/trunk/mdk-stage1/probing.c (rev 0)
++++ drakx/trunk/mdk-stage1/probing.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,972 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Portions from Erik Troan (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ewt at redhat.com</A>)
++ *
++ * Copyright 1996 Red Hat Software
++ *
++ */
++
++
++/*
++ * This contains stuff related to probing:
++ * (1) any (actually only SCSI, NET, CPQ, USB Controllers) devices (autoprobe for PCI and USB)
++ * (2) IDE media
++ * (3) SCSI media
++ * (4) ETH devices
++ */
++
++
++#include &lt;stdlib.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;string.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;dirent.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;fnmatch.h&gt;
++#include &lt;sys/socket.h&gt;
++#include &lt;net/if.h&gt;
++#include &lt;sys/ioctl.h&gt;
++#include &lt;sys/mount.h&gt;
++#include &lt;pci/pci.h&gt;
++#include &lt;libldetect.h&gt;
++#include &quot;stage1.h&quot;
++
++#include &quot;log.h&quot;
++#include &quot;utils.h&quot;
++#include &quot;frontend.h&quot;
++#include &quot;modules.h&quot;
++#include &quot;pci-resource/pci-ids.h&quot;
++#ifdef ENABLE_USB
++#include &quot;usb-resource/usb-ids.h&quot;
++#endif
++#ifdef ENABLE_PCMCIA
++#include &quot;sysfs/libsysfs.h&quot;
++#include &quot;pcmcia-resource/pcmcia-ids.h&quot;
++#endif
++
++#include &quot;probing.h&quot;
++
++
++struct media_info {
++ char * name;
++ char * model;
++ enum media_type type;
++};
++
++
++static void warning_insmod_failed(enum insmod_return r)
++{
++ if (IS_AUTOMATIC &amp;&amp; r == INSMOD_FAILED_FILE_NOT_FOUND)
++ return;
++ if (r != INSMOD_OK) {
++ if (r == INSMOD_FAILED_FILE_NOT_FOUND)
++ stg1_error_message(&quot;This floppy doesn't contain the driver.&quot;);
++ else
++ stg1_error_message(&quot;Warning, installation of driver failed. (please include msg from &lt;Alt-F3&gt; for bugreports)&quot;);
++ }
++}
++
++#ifndef DISABLE_NETWORK
++struct net_description_elem
++{
++ char * intf_name;
++ char * intf_description;
++};
++static struct net_description_elem net_descriptions[50];
++static int net_descr_number = 0;
++static char * intf_descr_for_discover = NULL;
++static char * net_intf_too_early_name[50]; /* for modules providing more than one net intf */
++static int net_intf_too_early_number = 0;
++static int net_intf_too_early_ptr = 0;
++
++const char * safe_descr(const char * text) {
++ return text ? text : &quot;unknown&quot;;
++}
++
++void prepare_intf_descr(const char * intf_descr)
++{
++ intf_descr_for_discover = strdup(intf_descr);
++}
++
++void net_discovered_interface(char * intf_name)
++{
++ if (!intf_descr_for_discover) {
++ net_intf_too_early_name[net_intf_too_early_number++] = strdup(intf_name);
++ return;
++ }
++ if (!intf_name) {
++ if (net_intf_too_early_ptr &gt;= net_intf_too_early_number) {
++ log_message(&quot;NET: was expecting another network interface (broken net module?)&quot;);
++ return;
++ }
++ net_descriptions[net_descr_number].intf_name = net_intf_too_early_name[net_intf_too_early_ptr++];
++ }
++ else
++ net_descriptions[net_descr_number].intf_name = strdup(intf_name);
++ net_descriptions[net_descr_number].intf_description = strdup(intf_descr_for_discover);
++ intf_descr_for_discover = NULL;
++ net_descr_number++;
++}
++
++char * get_net_intf_description(char * intf_name)
++{
++ int i;
++ for (i = 0; i &lt; net_descr_number ; i++)
++ if (!strcmp(net_descriptions[i].intf_name, intf_name))
++ return net_descriptions[i].intf_description;
++ return strdup(&quot;unknown&quot;);
++}
++#endif
++
++static int device_match_modules_list(struct pciusb_entry *e, char **modules, unsigned int modules_len) {
++ int i;
++ if (!e-&gt;module)
++ return 0;
++ for (i = 0; i &lt; modules_len; i++)
++ if (!strcmp(modules[i], e-&gt;module))
++ return 1;
++ return 0;
++}
++
++struct pcitable_entry *detected_devices = NULL;
++int detected_devices_len = 0;
++
++static void detected_devices_destroy(void)
++{
++ if (detected_devices)
++ free(detected_devices);
++}
++
++static struct pcitable_entry *detected_device_new(void)
++{
++ static int detected_devices_maxlen = 0;
++ if (detected_devices_len &gt;= detected_devices_maxlen) {
++ detected_devices_maxlen += 32;
++ if (detected_devices == NULL)
++ detected_devices = malloc(detected_devices_maxlen * sizeof(*detected_devices));
++ else
++ detected_devices = realloc(detected_devices, detected_devices_maxlen * sizeof(*detected_devices));
++ if (detected_devices == NULL)
++ log_perror(&quot;detected_device_new: could not (re)allocate table. Let it crash, sorry&quot;);
++ }
++ return &amp;detected_devices[detected_devices_len++];
++}
++
++/* FIXME: factorize with probe_that_type() */
++
++static void add_detected_device(unsigned short vendor, unsigned short device, unsigned int subvendor, unsigned int subdevice, const char *name, const char *module)
++{
++ struct pcitable_entry *dev = detected_device_new();
++ dev-&gt;vendor = vendor;
++ dev-&gt;device = device;
++ dev-&gt;subvendor = subvendor;
++ dev-&gt;subdevice = subdevice;
++ strncpy(dev-&gt;module, module, sizeof(dev-&gt;module) - 1);
++ dev-&gt;module[sizeof(dev-&gt;module) - 1] = '\0';
++ strncpy(dev-&gt;description, safe_descr(name), sizeof(dev-&gt;description) - 1);
++ dev-&gt;description[sizeof(dev-&gt;description) - 1] = '\0';
++ log_message(&quot;detected device (%04x, %04x, %04x, %04x, %s, %s)&quot;, vendor, device, subvendor, subdevice, name, module);
++}
++
++static int add_detected_device_if_match(struct pciusb_entry *e, char **modules, unsigned int modules_len)
++{
++ int ret = device_match_modules_list(e, modules, modules_len);
++ if (ret)
++ add_detected_device(e-&gt;vendor, e-&gt;device, e-&gt;subvendor, e-&gt;subdevice,
++ e-&gt;text, e-&gt;module);
++ return ret;
++}
++
++void probing_detect_devices()
++{
++ static int already_detected_devices = 0;
++ struct pciusb_entries entries;
++ int i;
++
++ if (already_detected_devices)
++ return;
++
++ entries = pci_probe();
++ for (i = 0; i &lt; entries.nb; i++) {
++ struct pciusb_entry *e = &amp;entries.entries[i];
++#ifndef DISABLE_PCIADAPTERS
++#ifndef DISABLE_MEDIAS
++ if (add_detected_device_if_match(e, medias_ide_pci_modules, medias_ide_pci_modules_len))
++ continue;
++ if (add_detected_device_if_match(e, medias_other_pci_modules, medias_other_pci_modules_len))
++ continue;
++#endif
++
++#ifndef DISABLE_NETWORK
++ if (add_detected_device_if_match(e, network_pci_modules, network_pci_modules_len))
++ continue;
++#endif
++
++#ifdef ENABLE_USB
++ if (add_detected_device_if_match(e, usb_controller_modules, usb_controller_modules_len))
++ continue;
++#endif
++#endif
++ /* device can't be found in built-in pcitables, but keep it */
++ add_detected_device(e-&gt;vendor, e-&gt;device, e-&gt;subvendor, e-&gt;subdevice, e-&gt;text, e-&gt;module);
++ }
++ pciusb_free(&amp;entries);
++
++ already_detected_devices = 1;
++}
++
++void probing_destroy(void)
++{
++ detected_devices_destroy();
++}
++
++#ifndef DISABLE_MEDIAS
++static const char * get_alternate_module(const char * name)
++{
++ struct alternate_mapping {
++ const char * a;
++ const char * b;
++ };
++ static struct alternate_mapping mappings[] = {
++ { &quot;ahci&quot;, &quot;ata_piix&quot; },
++ };
++ int mappings_nb = sizeof(mappings) / sizeof(struct alternate_mapping);
++ int i;
++
++ for (i=0; i&lt;mappings_nb; i++) {
++ const char * alternate = NULL;
++ if (streq(name, mappings[i].a))
++ alternate = mappings[i].b;
++ else if (streq(name, mappings[i].b))
++ alternate = mappings[i].a;
++ if (alternate) {
++ log_message(&quot;found alternate module %s for driver %s&quot;, alternate, name);
++ return alternate;
++ }
++ }
++ return NULL;
++}
++#endif
++
++void discovered_device(enum driver_type type, const char * description, const char * driver)
++{
++ description = safe_descr(description);
++
++ enum insmod_return failed = INSMOD_FAILED;
++#ifndef DISABLE_MEDIAS
++ if (type == MEDIA_ADAPTERS) {
++ const char * alternate = NULL;
++ wait_message(&quot;Loading driver for media adapter:\n \n%s&quot;, description);
++ failed = my_insmod(driver, MEDIA_ADAPTERS, NULL, 1);
++ alternate = get_alternate_module(driver);
++ if (!IS_NOAUTO &amp;&amp; alternate) {
++ failed = failed || my_insmod(alternate, MEDIA_ADAPTERS, NULL, 1);
++ }
++ remove_wait_message();
++ warning_insmod_failed(failed);
++ }
++#endif
++#ifndef DISABLE_NETWORK
++ if (type == NETWORK_DEVICES) {
++ wait_message(&quot;Loading driver for network device:\n \n%s&quot;, description);
++ prepare_intf_descr(description);
++ failed = my_insmod(driver, NETWORK_DEVICES, NULL, 1);
++ warning_insmod_failed(failed);
++ remove_wait_message();
++ if (intf_descr_for_discover) /* for modules providing more than one net intf */
++ net_discovered_interface(NULL);
++ }
++#endif
++#ifdef ENABLE_USB
++ if (type == USB_CONTROLLERS)
++ /* we can't allow additional modules floppy since we need usbhid for keystrokes of usb keyboards */
++ failed = my_insmod(driver, USB_CONTROLLERS, NULL, 0);
++#endif
++}
++
++void probe_pci_modules(enum driver_type type, char **pci_modules, unsigned int pci_modules_len) {
++ struct pciusb_entries entries;
++ int i;
++
++ entries = pci_probe();
++ for (i = 0; i &lt; entries.nb; i++) {
++ struct pciusb_entry *e = &amp;entries.entries[i];
++ if (device_match_modules_list(e, pci_modules, pci_modules_len)) {
++ log_message(&quot;PCI: device %04x %04x %04x %04x is \&quot;%s\&quot;, driver is %s&quot;,
++ e-&gt;vendor, e-&gt;device, e-&gt;subvendor, e-&gt;subdevice, safe_descr(e-&gt;text), e-&gt;module);
++ discovered_device(type, e-&gt;text, e-&gt;module);
++ }
++ }
++ pciusb_free(&amp;entries);
++}
++
++/** Loads modules for known virtio devices
++ *
++ * virtio modules are not being loaded using the PCI probing mechanism
++ * because pcitable.gz does not have IDs for these devices.
++ *
++ * The possible correct solution for it is to fix the script which
++ * generates pcitable.gz to handle the virtio_device_id structure.
++ */
++void probe_virtio_modules(void)
++{
++ struct pciusb_entries entries;
++ int i;
++ char *name;
++ char *options;
++ int loaded_pci = 0;
++
++ entries = pci_probe();
++ for (i = 0; i &lt; entries.nb; i++) {
++ struct pciusb_entry *e = &amp;entries.entries[i];
++ if (e-&gt;vendor == VIRTIO_PCI_VENDOR) {
++ if (!loaded_pci) {
++ log_message(&quot;loading virtio-pci&quot;);
++ my_insmod(&quot;virtio_pci&quot;, ANY_DRIVER_TYPE, NULL, 0);
++ loaded_pci = 1;
++ }
++
++ name = NULL;
++ options = NULL;
++
++ switch (e-&gt;subdevice) {
++ case VIRTIO_ID_NET:
++ name = &quot;virtio_net&quot;;
++ options = &quot;csum=0&quot;;
++ break;
++ case VIRTIO_ID_BLOCK:
++ name = &quot;virtio_blk&quot;;
++ break;
++ case VIRTIO_ID_BALLOON:
++ name = &quot;virtio_balloon&quot;;
++ break;
++ default:
++ log_message(&quot;warning: unknown virtio device %04x&quot;, e-&gt;device);
++ }
++ if (name) {
++ log_message(&quot;virtio: loading %s&quot;, name);
++ my_insmod(name, ANY_DRIVER_TYPE, options, 0);
++ }
++ }
++ }
++ pciusb_free(&amp;entries);
++}
++
++#ifdef ENABLE_USB
++void probe_that_type(enum driver_type type, enum media_bus bus)
++#else
++void probe_that_type(enum driver_type type, enum media_bus bus __attribute__ ((unused)))
++#endif
++{
++ static int already_probed_usb_controllers = 0;
++ static int already_loaded_usb_scsi = 0;
++ static int already_probed_virtio_devices = 0;
++
++ /* ---- PCI probe ---------------------------------------------- */
++ if (bus != BUS_USB) {
++ switch (type) {
++#ifndef DISABLE_PCIADAPTERS
++#ifndef DISABLE_MEDIAS
++ static int already_probed_media_adapters = 0;
++ case MEDIA_ADAPTERS:
++ if (already_probed_media_adapters)
++ break;
++ already_probed_media_adapters = 1;
++ probe_pci_modules(type, medias_ide_pci_modules, medias_ide_pci_modules_len);
++ probe_pci_modules(type, medias_other_pci_modules, medias_other_pci_modules_len);
++ break;
++#endif
++#ifndef DISABLE_NETWORK
++ case NETWORK_DEVICES:
++ probe_pci_modules(type, network_pci_modules, network_pci_modules_len);
++ break;
++#endif
++#endif
++#ifdef ENABLE_USB
++ case USB_CONTROLLERS:
++ if (already_probed_usb_controllers || IS_NOAUTO)
++ break;
++ already_probed_usb_controllers = 1;
++ probe_pci_modules(type, usb_controller_modules, usb_controller_modules_len);
++ break;
++#endif
++ case VIRTIO_DEVICES:
++ if (already_probed_virtio_devices)
++ break;
++ probe_virtio_modules();
++ already_probed_virtio_devices = 1;
++ break;
++ default:
++ break;
++ }
++ }
++
++
++#ifdef ENABLE_USB
++ /* ---- USB probe ---------------------------------------------- */
++ if ((bus == BUS_USB || bus == BUS_ANY) &amp;&amp; !(IS_NOAUTO)) {
++ static int already_mounted_usbdev = 0;
++ struct pciusb_entries entries;
++ int i;
++
++ if (!already_probed_usb_controllers)
++ probe_that_type(USB_CONTROLLERS, BUS_ANY);
++
++ if (!already_mounted_usbdev) {
++ already_mounted_usbdev = 1;
++ if (mount(&quot;none&quot;, &quot;/proc/bus/usb&quot;, &quot;usbfs&quot;, 0, NULL) &amp;&amp;
++ mount(&quot;none&quot;, &quot;/proc/bus/usb&quot;, &quot;usbdevfs&quot;, 0, NULL)) {
++ log_message(&quot;USB: couldn't mount /proc/bus/usb&quot;);
++ goto end_usb_probe;
++ }
++ wait_message(&quot;Detecting USB devices.&quot;);
++ sleep(4); /* sucking background work */
++ my_insmod(&quot;usbhid&quot;, ANY_DRIVER_TYPE, NULL, 0);
++ remove_wait_message();
++ }
++
++ if (type != NETWORK_DEVICES)
++ goto end_usb_probe;
++
++ entries = usb_probe();
++ for (i = 0; i &lt; entries.nb; i++) {
++ struct pciusb_entry *e = &amp;entries.entries[i];
++ if (device_match_modules_list(e, usb_modules, usb_modules_len)) {
++ log_message(&quot;USB: device %04x %04x is \&quot;%s\&quot; (%s)&quot;, e-&gt;vendor, e-&gt;device, safe_descr(e-&gt;text), e-&gt;module);
++ discovered_device(type, e-&gt;text, e-&gt;module);
++ }
++ }
++ pciusb_free(&amp;entries);
++ end_usb_probe:;
++ }
++#endif
++
++#ifdef ENABLE_PCMCIA
++ /* ---- PCMCIA probe ---------------------------------------------- */
++ if ((bus == BUS_PCMCIA || bus == BUS_ANY) &amp;&amp; !(IS_NOAUTO)) {
++ struct pcmcia_alias * pcmciadb = NULL;
++ unsigned int len = 0;
++ char *base = &quot;/sys/bus/pcmcia/devices&quot;;
++ DIR *dir;
++ struct dirent *dent;
++
++ dir = opendir(base);
++ if (dir == NULL)
++ goto end_pcmcia_probe;
++
++ switch (type) {
++#ifndef DISABLE_MEDIAS
++ case MEDIA_ADAPTERS:
++ pcmciadb = medias_pcmcia_ids;
++ len = medias_pcmcia_num_ids;
++ break;
++#endif
++#ifndef DISABLE_NETWORK
++ case NETWORK_DEVICES:
++ pcmciadb = network_pcmcia_ids;
++ len = network_pcmcia_num_ids;
++ break;
++#endif
++ default:
++ goto end_pcmcia_probe;
++ }
++
++ for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
++ struct sysfs_attribute *modalias_attr;
++ char keyfile[256];
++ int i, id;
++
++ if (dent-&gt;d_name[0] == '.')
++ continue;
++
++ log_message(&quot;PCMCIA: device found %s&quot;, dent-&gt;d_name);
++
++ snprintf(keyfile, sizeof(keyfile)-1, &quot;%s/%s/modalias&quot;, base, dent-&gt;d_name);
++ modalias_attr = sysfs_open_attribute(keyfile);
++ if (!modalias_attr)
++ continue;
++ if (sysfs_read_attribute(modalias_attr) != 0 || !modalias_attr-&gt;value) {
++ sysfs_close_attribute(modalias_attr);
++ continue;
++ }
++
++ log_message(&quot;PCMCIA: device found %s&quot;, modalias_attr-&gt;value);
++
++ for (i = 0; i &lt; len; i++) {
++ if (!fnmatch(pcmciadb[i].modalias, modalias_attr-&gt;value, 0)) {
++ char product[256];
++
++ log_message(&quot;PCMCIA: device found %s (%s)&quot;, pcmciadb[i].modalias, pcmciadb[i].module);
++ strcpy(product, &quot;&quot;);
++ for (id = 1; id &lt;= 4; id++) {
++ struct sysfs_attribute *product_attr;
++ snprintf(keyfile, sizeof(keyfile)-1, &quot;%s/%s/prod_id%d&quot;, base, dent-&gt;d_name, id);
++ product_attr = sysfs_open_attribute(keyfile);
++ if (!product_attr)
++ continue;
++ if (sysfs_read_attribute(product_attr) || !product_attr-&gt;value) {
++ sysfs_close_attribute(product_attr);
++ continue;
++ }
++ snprintf(product + strlen(product), sizeof(product)-strlen(product)-1, &quot;%s%s&quot;, product[0] ? &quot; &quot; : &quot;&quot;, product_attr-&gt;value);
++ if (product[strlen(product)-1] == '\n')
++ product[strlen(product)-1] = '\0';
++ sysfs_close_attribute(product_attr);
++ }
++
++ if (!product[0])
++ strcpy(product, &quot;PCMCIA device&quot;);
++
++ log_message(&quot;PCMCIA: device found %s (%s)&quot;, product, pcmciadb[i].module);
++ discovered_device(type, product, pcmciadb[i].module);
++ }
++ }
++
++ sysfs_close_attribute(modalias_attr);
++ }
++ end_pcmcia_probe:;
++ if (dir)
++ closedir(dir);
++ }
++#endif
++
++ /* be sure to load usb-storage after media adapters, so that they are in
++ same order than reboot, so that naming is the same */
++ if (type == MEDIA_ADAPTERS &amp;&amp; (bus == BUS_USB || bus == BUS_SCSI || bus == BUS_ANY) &amp;&amp;
++ already_probed_usb_controllers &amp;&amp; !already_loaded_usb_scsi) {
++ already_loaded_usb_scsi = 1;
++ /* we can't allow additional modules floppy since we need usbkbd for keystrokes of usb keyboards */
++ my_insmod(&quot;usb_storage&quot;, MEDIA_ADAPTERS, NULL, 0);
++ if (module_already_present(&quot;ieee1394&quot;))
++ my_insmod(&quot;sbp2&quot;, MEDIA_ADAPTERS, NULL, 0);
++ wait_message(&quot;Detecting USB mass-storage devices.&quot;);
++ sleep(10); /* sucking background work */
++ remove_wait_message();
++ }
++}
++
++
++static struct media_info * medias = NULL;
++
++void find_media(enum media_bus bus)
++{
++ char b[50];
++ char buf[5000];
++ struct media_info tmp[50];
++ int count = 0;
++ int fd;
++
++ if (medias)
++ free(medias); /* that does not free the strings, by the way */
++
++ log_message(&quot;looking for media adapters&quot;);
++ probe_that_type(MEDIA_ADAPTERS, bus);
++
++ /* ----------------------------------------------- */
++ if (bus != BUS_IDE &amp;&amp; bus != BUS_ANY)
++ goto find_media_after_ide;
++ log_message(&quot;looking for ide media&quot;);
++
++ strcpy(b, &quot;/proc/ide/hd&quot;);
++ for (b[12] = 'a'; b[12] &lt;= 't'; b[12]++) {
++ int i;
++ char ide_disk[] = &quot;disk&quot;;
++ char ide_cdrom[] = &quot;cdrom&quot;;
++ char ide_tape[] = &quot;tape&quot;;
++ char ide_floppy[] = &quot;floppy&quot;;
++
++ /* first, test if file exists (will tell if attached medium exists) */
++ b[13] = '\0';
++ if (access(b, R_OK))
++ continue;
++
++ tmp[count].name = strdup(&quot;hda&quot;);
++ tmp[count].name[2] = b[12];
++
++ /* media type */
++ strcpy(b + 13, &quot;/media&quot;);
++ fd = open(b, O_RDONLY);
++ if (fd == -1) {
++ log_message(&quot;failed to open %s for reading&quot;, b);
++ continue;
++ }
++
++ i = read(fd, buf, sizeof(buf));
++ if (i == -1) {
++ log_message(&quot;failed to read %s&quot;, b);
++ continue;
++ }
++ buf[i] = '\0';
++ close(fd);
++
++ if (ptr_begins_static_str(buf, ide_disk))
++ tmp[count].type = DISK;
++ else if (ptr_begins_static_str(buf, ide_cdrom))
++ tmp[count].type = CDROM;
++ else if (ptr_begins_static_str(buf, ide_tape))
++ tmp[count].type = TAPE;
++ else if (ptr_begins_static_str(buf, ide_floppy))
++ tmp[count].type = FLOPPY;
++ else
++ tmp[count].type = UNKNOWN_MEDIA;
++
++ /* media model */
++ strcpy(b + 13, &quot;/model&quot;);
++ fd = open(b, O_RDONLY);
++ if (fd == -1) {
++ log_message(&quot;failed to open %s for reading&quot;, b);
++ continue;
++ }
++
++ i = read(fd, buf, sizeof(buf));
++ if (i &lt;= 0) {
++ log_message(&quot;failed to read %s&quot;, b);
++ tmp[count].model = strdup(&quot;(none)&quot;);
++ }
++ else {
++ buf[i-1] = '\0'; /* eat the \n */
++ tmp[count].model = strdup(buf);
++ }
++ close(fd);
++
++ log_message(&quot;IDE/%d: %s is a %s&quot;, tmp[count].type, tmp[count].name, tmp[count].model);
++ count++;
++ }
++
++ find_media_after_ide:
++ /* ----------------------------------------------- */
++ if (bus != BUS_SCSI &amp;&amp; bus != BUS_USB &amp;&amp; bus != BUS_PCMCIA &amp;&amp; bus != BUS_ANY)
++ goto find_media_after_scsi;
++ log_message(&quot;looking for scsi media&quot;);
++
++ fd = open(&quot;/proc/scsi/scsi&quot;, O_RDONLY);
++ if (fd != -1) {
++ FILE * f;
++
++ enum { SCSI_TOP, SCSI_HOST, SCSI_VENDOR, SCSI_TYPE } state = SCSI_TOP;
++ char * start, * chptr, * next, * end;
++ char scsi_disk_count = 'a';
++ char scsi_cdrom_count = '0';
++ char scsi_tape_count = '0';
++
++ char scsi_no_devices[] = &quot;Attached devices: none&quot;;
++ char scsi_some_devices[] = &quot;Attached devices:&quot;;
++ char scsi_host[] = &quot;Host: &quot;;
++ char scsi_vendor[] = &quot; Vendor: &quot;;
++
++ int i = read(fd, &amp;buf, sizeof(buf)-1);
++ if (i &lt; 1) {
++ close(fd);
++ goto end_scsi;
++ }
++ close(fd);
++ buf[i] = '\0';
++
++ if (ptr_begins_static_str(buf, scsi_no_devices))
++ goto end_scsi;
++
++ start = buf;
++ while (*start) {
++ char tmp_model[50];
++ char tmp_name[10];
++
++ chptr = start;
++ while (*chptr != '\n') chptr++;
++ *chptr = '\0';
++ next = chptr + 1;
++
++ switch (state) {
++ case SCSI_TOP:
++ if (!ptr_begins_static_str(start, scsi_some_devices))
++ goto end_scsi;
++ state = SCSI_HOST;
++ break;
++
++ case SCSI_HOST:
++ if (!ptr_begins_static_str(start, scsi_host))
++ goto end_scsi;
++ state = SCSI_VENDOR;
++ break;
++
++ case SCSI_VENDOR:
++ if (!ptr_begins_static_str(start, scsi_vendor))
++ goto end_scsi;
++
++ /* (1) Grab Vendor info */
++ start += 10;
++ end = chptr = strstr(start, &quot;Model:&quot;);
++ if (!chptr)
++ goto end_scsi;
++
++ chptr--;
++ while (*chptr == ' ')
++ chptr--;
++ if (*chptr == ':') {
++ chptr++;
++ *(chptr + 1) = '\0';
++ strcpy(tmp_model,&quot;(unknown)&quot;);
++ } else {
++ *(chptr + 1) = '\0';
++ strcpy(tmp_model, start);
++ }
++
++ /* (2) Grab Model info */
++ start = end;
++ start += 7;
++
++ chptr = strstr(start, &quot;Rev:&quot;);
++ if (!chptr)
++ goto end_scsi;
++
++ chptr--;
++ while (*chptr == ' ') chptr--;
++ *(chptr + 1) = '\0';
++
++ strcat(tmp_model, &quot; &quot;);
++ strcat(tmp_model, start);
++
++ tmp[count].model = strdup(tmp_model);
++
++ state = SCSI_TYPE;
++
++ break;
++
++ case SCSI_TYPE:
++ if (strncmp(&quot; Type:&quot;, start, 7))
++ goto end_scsi;
++ *tmp_name = '\0';
++
++ if (strstr(start, &quot;Direct-Access&quot;)) {
++ sprintf(tmp_name, &quot;sd%c&quot;, scsi_disk_count++);
++ tmp[count].type = DISK;
++ } else if (strstr(start, &quot;Sequential-Access&quot;)) {
++ sprintf(tmp_name, &quot;st%c&quot;, scsi_tape_count++);
++ tmp[count].type = TAPE;
++ } else if (strstr(start, &quot;CD-ROM&quot;)) {
++ sprintf(tmp_name, &quot;sr%c&quot;, scsi_cdrom_count++);
++ tmp[count].type = CDROM;
++ }
++
++ if (!(f = fopen(&quot;/proc/partitions&quot;, &quot;rb&quot;)) || !fgets(buf, sizeof(buf), f) || !fgets(buf, sizeof(buf), f)) {
++ log_message(&quot;Couldn't open /proc/partitions&quot;);
++ } else {
++ while (fgets(buf, sizeof(buf), f)) {
++ char name[100];
++ int major, minor, blocks;
++ struct stat statbuf;
++ char *ptr;
++ memset(name, 0, sizeof(name));
++ strcpy(name, &quot;/dev/&quot;);
++ sscanf(buf, &quot; %d %d %d %s&quot;, &amp;major, &amp;minor, &amp;blocks, &amp;name[5]);
++ if (streq(&amp;name[5], tmp_name) &amp;&amp; tmp[count].type == DISK &amp;&amp; ((blocks == 1048575) || (blocks == 1440)))
++ tmp[count].type = FLOPPY;
++ /* Try to create all devices while we have major/minor */
++ if ((ptr = strchr(&amp;name[5], '/'))) {
++ *ptr = '\0';
++ if (stat(name, &amp;statbuf))
++ mkdir(name, 0755);
++ *ptr = '/';
++ }
++ if (stat(name, &amp;statbuf) &amp;&amp; mknod(name, S_IFBLK | 0600, makedev(major, minor))) {
++ log_perror(name);
++ }
++ }
++ fclose(f);
++ }
++
++ if (*tmp_name) {
++ tmp[count].name = strdup(tmp_name);
++ log_message(&quot;SCSI/%d: %s is a %s&quot;, tmp[count].type, tmp[count].name, tmp[count].model);
++ count++;
++ }
++
++ state = SCSI_HOST;
++ }
++
++ start = next;
++ }
++
++ end_scsi:;
++ }
++
++ /* ----------------------------------------------- */
++ log_message(&quot;looking for Compaq Smart Array media&quot;);
++ {
++ char * procfiles[] = { &quot;/proc/driver/cpqarray/ida0&quot;, &quot;/proc/driver/cciss/cciss0&quot;, // 2.4 style
++ &quot;/proc/array/ida&quot;, &quot;/proc/cciss/cciss&quot;, // 2.2 style
++ NULL };
++ static char cpq_descr[] = &quot;Compaq RAID logical disk&quot;;
++ char ** procfile;
++ FILE * f;
++
++ for (procfile = procfiles; procfile &amp;&amp; *procfile; procfile++) {
++ if((f = fopen(*procfile, &quot;rb&quot;))) {
++ while (fgets(buf, sizeof(buf), f)) {
++ if (ptr_begins_static_str(buf, &quot;ida/&quot;) || ptr_begins_static_str(buf, &quot;cciss/&quot;)) {
++ char * end = strchr(buf, ':');
++ if (!end)
++ log_message(&quot;Inconsistency in %s, line:\n%s&quot;, *procfile, buf);
++ else {
++ *end = '\0';
++ tmp[count].name = strdup(buf);
++ tmp[count].type = DISK;
++ tmp[count].model = cpq_descr;
++ log_message(&quot;CPQ: found %s&quot;, tmp[count].name);
++ count++;
++ }
++ }
++ }
++ fclose(f);
++ }
++ }
++ }
++
++ /* ----------------------------------------------- */
++ log_message(&quot;looking for DAC960&quot;);
++ {
++ FILE * f;
++ if ((f = fopen(&quot;/tmp/syslog&quot;, &quot;rb&quot;))) {
++ while (fgets(buf, sizeof(buf), f)) {
++ char * start;
++ if ((start = strstr(buf, &quot;/dev/rd/&quot;))) {
++ char * end = strchr(start, ':');
++ if (!end)
++ log_message(&quot;Inconsistency in syslog, line:\n%s&quot;, buf);
++ else {
++ *end = '\0';
++ tmp[count].name = strdup(start+5);
++ tmp[count].type = DISK;
++ start = end + 2;
++ end = strchr(start, ',');
++ if (end) {
++ *end = '\0';
++ tmp[count].model = strdup(start);
++ } else
++ tmp[count].model = &quot;(unknown)&quot;;
++ log_message(&quot;DAC960: found %s (%s)&quot;, tmp[count].name, tmp[count].model);
++ count++;
++ }
++ }
++ }
++ fclose(f);
++ }
++ }
++ find_media_after_scsi:
++
++ /* ----------------------------------------------- */
++ tmp[count].name = NULL;
++ count++;
++
++ medias = memdup(tmp, sizeof(struct media_info) * count);
++}
++
++
++/* Finds by media */
++void get_medias(enum media_type media, char *** names, char *** models, enum media_bus bus)
++{
++ struct media_info * m;
++ char * tmp_names[50];
++ char * tmp_models[50];
++ int count;
++
++ find_media(bus);
++
++ m = medias;
++
++ count = 0;
++ while (m &amp;&amp; m-&gt;name) {
++ if (m-&gt;type == media) {
++ tmp_names[count] = strdup(m-&gt;name);
++ tmp_models[count++] = strdup(m-&gt;model);
++ }
++ m++;
++ }
++ tmp_names[count] = NULL;
++ tmp_models[count++] = NULL;
++
++ *names = memdup(tmp_names, sizeof(char *) * count);
++ *models = memdup(tmp_models, sizeof(char *) * count);
++}
++
++
++#ifndef DISABLE_NETWORK
++static int is_net_interface_blacklisted(char *intf)
++{
++ /* see detect_devicess::is_lan_interface() */
++ char * blacklist[] = { &quot;lo&quot;, &quot;ippp&quot;, &quot;isdn&quot;, &quot;plip&quot;, &quot;ppp&quot;, &quot;wifi&quot;, &quot;sit&quot;, NULL };
++ char ** ptr = blacklist;
++
++ while (ptr &amp;&amp; *ptr) {
++ if (!strncmp(intf, *ptr, strlen(*ptr)))
++ return 1;
++ ptr++;
++ }
++
++ return 0;
++}
++
++char ** get_net_devices(void)
++{
++ char * tmp[50];
++ static int already_probed = 0;
++ FILE * f;
++ int i = 0;
++
++ if (!already_probed) {
++ already_probed = 1; /* cut off loop brought by: probe_that_type =&gt; my_insmod =&gt; get_net_devices */
++ probe_that_type(NETWORK_DEVICES, BUS_ANY);
++ }
++
++ /* use /proc/net/dev since SIOCGIFCONF doesn't work with some drivers (rt2500) */
++ f = fopen(&quot;/proc/net/dev&quot;, &quot;rb&quot;);
++ if (f) {
++ char line[128];
++
++ /* skip the two first lines */
++ fgets(line, sizeof(line), f);
++ fgets(line, sizeof(line), f);
++
++ while (1) {
++ char *start, *end;
++ if (!fgets(line, sizeof(line), f))
++ break;
++ start = line;
++ while (*start == ' ')
++ start++;
++ end = strchr(start, ':');
++ if (end)
++ end[0] = '\0';
++ if (!is_net_interface_blacklisted(start)) {
++ log_message(&quot;found net interface %s&quot;, start);
++ tmp[i++] = strdup(start);
++ } else {
++ log_message(&quot;found net interface %s, but blacklisted&quot;, start);
++ }
++ }
++
++ fclose(f);
++ } else {
++ log_message(&quot;net: could not open devices file&quot;);
++ }
++
++ tmp[i++] = NULL;
++
++ return memdup(tmp, sizeof(char *) * i);
++
++}
++#endif /* DISABLE_NETWORK */
+
+
+Property changes on: drakx/trunk/mdk-stage1/probing.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/probing.h
+===================================================================
+--- drakx/trunk/mdk-stage1/probing.h (rev 0)
++++ drakx/trunk/mdk-stage1/probing.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,65 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Portions from Erik Troan (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ewt at redhat.com</A>)
++ *
++ * Copyright 1996 Red Hat Software
++ *
++ */
++
++#ifndef _PROBING_H_
++#define _PROBING_H_
++
++enum media_type { CDROM, DISK, FLOPPY, TAPE, UNKNOWN_MEDIA };
++
++enum driver_type { MEDIA_ADAPTERS, NETWORK_DEVICES, USB_CONTROLLERS,
++ VIRTIO_DEVICES, ANY_DRIVER_TYPE };
++
++enum media_bus { BUS_IDE, BUS_SCSI, BUS_USB, BUS_PCMCIA, BUS_ANY };
++
++#define VIRTIO_PCI_VENDOR 0x1af4
++#define VIRTIO_ID_NET 0x0001
++#define VIRTIO_ID_BLOCK 0x0002
++#define VIRTIO_ID_BALLOON 0x0005
++
++void find_media(enum media_bus bus);
++void get_medias(enum media_type media, char *** names, char *** models, enum media_bus bus);
++char ** get_net_devices(void);
++void net_discovered_interface(char * intf_name);
++char * get_net_intf_description(char * intf_name);
++void prepare_intf_descr(const char * intf_descr);
++void probe_that_type(enum driver_type type, enum media_bus bus);
++
++/* Make sure the MATCH_ALL value is greater than all possible values
++ for subvendor &amp; subdevice: this simplifies the orderer */
++#define PCITABLE_MATCH_ALL 0x10000
++
++struct pcitable_entry {
++ /* some bits stolen from pci-resource/pci-ids.h
++ * FIXME: split pci-ids.h into pci-ids.c and pci-ids.h so that the header can be re-used
++ */
++ unsigned short vendor; /* PCI vendor id */
++ unsigned short device; /* PCI device id */
++ unsigned int subvendor; /* PCI subvendor id */
++ unsigned int subdevice; /* PCI subdevice id */
++ char module[20]; /* module to load */
++ char description[100]; /* PCI human readable description */
++};
++extern struct pcitable_entry *detected_devices;
++extern int detected_devices_len;
++void probing_detect_devices();
++void probing_destroy(void);
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/probing.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/rescue-gui.c
+===================================================================
+--- drakx/trunk/mdk-stage1/rescue-gui.c (rev 0)
++++ drakx/trunk/mdk-stage1/rescue-gui.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,297 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2001 Mandriva
++ *
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#include &lt;stdlib.h&gt;
++#define _USE_BSD
++#include &lt;sys/types.h&gt;
++#include &lt;sys/time.h&gt;
++#include &lt;sys/resource.h&gt;
++#include &lt;sys/wait.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;string.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;sys/mount.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;sys/ioctl.h&gt;
++#include &lt;linux/unistd.h&gt;
++#include &lt;sys/select.h&gt;
++
++#include &quot;config-stage1.h&quot;
++#include &quot;frontend.h&quot;
++#include &quot;utils.h&quot;
++#include &quot;params.h&quot;
++
++#include &lt;sys/syscall.h&gt;
++#define reboot(...) syscall(__NR_reboot, __VA_ARGS__)
++
++#if defined(__i386__) || defined(__x86_64__)
++#define ENABLE_RESCUE_MS_BOOT 1
++#endif
++
++char * env[] = {
++ &quot;PATH=/usr/bin:/bin:/sbin:/usr/sbin:/mnt/sbin:/mnt/usr/sbin:/mnt/bin:/mnt/usr/bin&quot;,
++ &quot;LD_LIBRARY_PATH=/lib:/usr/lib:/mnt/lib:/mnt/usr/lib:/usr/X11R6/lib:/mnt/usr/X11R6/lib&quot;
++#if defined(__x86_64__) || defined(__ppc64__)
++ &quot;:/lib64:/usr/lib64:/usr/X11R6/lib64:/mnt/lib64:/mnt/usr/lib64:/mnt/usr/X11R6/lib64&quot;
++#endif
++ ,
++ &quot;HOME=/&quot;,
++ &quot;TERM=linux&quot;,
++ &quot;TERMINFO=/etc/terminfo&quot;,
++ NULL
++};
++
++/* pause() already exists and causes the invoking process to sleep
++ until a signal is received */
++static void PAUSE(void) {
++ unsigned char t;
++ fflush(stdout);
++ read(0, &amp;t, 1);
++}
++
++
++/* ------ UUURGH this is duplicated from `init.c', don't edit here........ */
++void fatal_error(char *msg)
++{
++ printf(&quot;FATAL ERROR IN RESCUE: %s\n\nI can't recover from this.\nYou may reboot your system.\n&quot;, msg);
++ while (1);
++}
++
++#define LOOP_CLR_FD 0x4C01
++void del_loop(char *device)
++{
++ int fd;
++ if ((fd = open(device, O_RDONLY, 0)) &lt; 0) {
++ printf(&quot;del_loop open failed\n&quot;);
++ return;
++ }
++
++ if (ioctl(fd, LOOP_CLR_FD, 0) &lt; 0) {
++ printf(&quot;del_loop ioctl failed&quot;);
++ return;
++ }
++
++ close(fd);
++}
++struct filesystem { char * dev; char * name; char * fs; int mounted; };
++void unmount_filesystems(void)
++{
++ int fd, size;
++ char buf[65535]; /* this should be big enough */
++ char *p;
++ struct filesystem fs[500];
++ int numfs = 0;
++ int i, nb;
++
++ printf(&quot;unmounting filesystems...\n&quot;);
++
++ fd = open(&quot;/proc/mounts&quot;, O_RDONLY, 0);
++ if (fd &lt; 1) {
++ printf(&quot;ERROR: failed to open /proc/mounts&quot;);
++ sleep(2);
++ return;
++ }
++
++ size = read(fd, buf, sizeof(buf) - 1);
++ buf[size] = '\0';
++
++ close(fd);
++
++ p = buf;
++ while (*p) {
++ fs[numfs].mounted = 1;
++ fs[numfs].dev = p;
++ while (*p != ' ') p++;
++ *p++ = '\0';
++ fs[numfs].name = p;
++ while (*p != ' ') p++;
++ *p++ = '\0';
++ fs[numfs].fs = p;
++ while (*p != ' ') p++;
++ *p++ = '\0';
++ while (*p != '\n') p++;
++ p++;
++ if (strcmp(fs[numfs].name, &quot;/&quot;) != 0) numfs++; /* skip if root, no need to take initrd root in account */
++ }
++
++ /* Pixel's ultra-optimized sorting algorithm:
++ multiple passes trying to umount everything until nothing moves
++ anymore (a.k.a holy shotgun method) */
++ do {
++ nb = 0;
++ for (i = 0; i &lt; numfs; i++) {
++ /*printf(&quot;trying with %s\n&quot;, fs[i].name);*/
++ if (fs[i].mounted &amp;&amp; umount(fs[i].name) == 0) {
++ if (strncmp(fs[i].dev + sizeof(&quot;/dev/&quot;) - 1, &quot;loop&quot;,
++ sizeof(&quot;loop&quot;) - 1) == 0)
++ del_loop(fs[i].dev);
++
++ printf(&quot;\t%s\n&quot;, fs[i].name);
++ fs[i].mounted = 0;
++ nb++;
++ }
++ }
++ } while (nb);
++
++ for (i = nb = 0; i &lt; numfs; i++)
++ if (fs[i].mounted) {
++ printf(&quot;\t%s umount failed\n&quot;, fs[i].name);
++ if (strcmp(fs[i].fs, &quot;ext2&quot;) == 0) nb++; /* don't count not-ext2 umount failed */
++ }
++
++ if (nb) {
++ printf(&quot;failed to umount some filesystems\n&quot;);
++ while (1);
++ }
++}
++/* ------ UUURGH -- end */
++
++
++/* ------ UUURGH -- this is dirrrrrttttyyyyyy */
++void probe_that_type(void) {}
++void exit_bootsplash(void) {}
++
++
++int main(int argc __attribute__ ((unused)), char **argv __attribute__ ((unused)))
++{
++ enum return_type results;
++
++ char install_bootloader[] = &quot;Re-install Boot Loader&quot;;
++#if ENABLE_RESCUE_MS_BOOT
++ char restore_ms_boot[] = &quot;Restore Windows Boot Loader&quot;;
++#endif
++ char mount_parts[] = &quot;Mount your partitions under /mnt&quot;;
++ char go_to_console[] = &quot;Go to console&quot;;
++ char reboot_[] = &quot;Reboot&quot;;
++ char doc[] = &quot;Doc: what's addressed by this Rescue?&quot;;
++
++ char upgrade[] = &quot;Upgrade to New Version&quot;;
++ char rootpass[] = &quot;Reset Root Password&quot;;
++ char userpass[] = &quot;Reset User Password&quot;;
++ char factory[] = &quot;Reset to Factory Defaults&quot;;
++ char backup[] = &quot;Backup User Files&quot;;
++ char restore[] = &quot;Restore User Files from Backup&quot;;
++ char badblocks[] = &quot;Test Key for Badblocks&quot;;
++
++ char * actions_default[] = { install_bootloader,
++#if ENABLE_RESCUE_MS_BOOT
++ restore_ms_boot,
++#endif
++ mount_parts, go_to_console, reboot_, doc, NULL };
++ char * actions_flash_rescue[] = { rootpass, userpass, factory, backup, restore,
++ badblocks, go_to_console, reboot_, NULL };
++ char * actions_flash_upgrade[] = { upgrade, go_to_console, reboot_, NULL };
++
++
++ char * flash_mode;
++ char ** actions;
++ char * choice;
++
++ process_cmdline();
++ flash_mode = get_param_valued(&quot;flash&quot;);
++ actions = !flash_mode ?
++ actions_default :
++ streq(flash_mode, &quot;upgrade&quot;) ? actions_flash_upgrade : actions_flash_rescue;
++
++ init_frontend(&quot;Welcome to &quot; DISTRIB_NAME &quot; Rescue (&quot; DISTRIB_VERSION &quot;) &quot; __DATE__ &quot; &quot; __TIME__);
++
++ do {
++ int pid;
++ char * binary = NULL;
++
++ choice = &quot;&quot;;
++ results = ask_from_list(&quot;Please choose the desired action.&quot;, actions, &amp;choice);
++
++ if (ptr_begins_static_str(choice, install_bootloader)) {
++ binary = &quot;/usr/bin/install_bootloader&quot;;
++ }
++#if ENABLE_RESCUE_MS_BOOT
++ if (ptr_begins_static_str(choice, restore_ms_boot)) {
++ binary = &quot;/usr/bin/restore_ms_boot&quot;;
++ }
++#endif
++ if (ptr_begins_static_str(choice, mount_parts)) {
++ binary = &quot;/usr/bin/guessmounts&quot;;
++ }
++ if (ptr_begins_static_str(choice, reboot_)) {
++ finish_frontend();
++ sync(); sync();
++ sleep(2);
++ unmount_filesystems();
++ sync(); sync();
++ printf(&quot;rebooting system\n&quot;);
++ sleep(2);
++ reboot(0xfee1dead, 672274793, 0x01234567);
++ }
++ if (ptr_begins_static_str(choice, doc)) {
++ binary = &quot;/usr/bin/rescue-doc&quot;;
++ }
++
++ /* Mandriva Flash entries */
++ if (ptr_begins_static_str(choice, rootpass)) {
++ binary = &quot;/usr/bin/reset_rootpass&quot;;
++ }
++ if (ptr_begins_static_str(choice, userpass)) {
++ binary = &quot;/usr/bin/reset_userpass&quot;;
++ }
++ if (ptr_begins_static_str(choice, factory)) {
++ binary = &quot;/usr/bin/clear_systemloop&quot;;
++ }
++ if (ptr_begins_static_str(choice, backup)) {
++ binary = &quot;/usr/bin/backup_systemloop&quot;;
++ }
++ if (ptr_begins_static_str(choice, restore)) {
++ binary = &quot;/usr/bin/restore_systemloop&quot;;
++ }
++ if (ptr_begins_static_str(choice, badblocks)) {
++ binary = &quot;/usr/bin/test_badblocks&quot;;
++ }
++ if (ptr_begins_static_str(choice, upgrade)) {
++ binary = &quot;/usr/bin/upgrade&quot;;
++ }
++
++ if (binary) {
++ int wait_status;
++ suspend_to_console();
++ if (!(pid = fork())) {
++
++ char * child_argv[2];
++ child_argv[0] = binary;
++ child_argv[1] = NULL;
++
++ execve(child_argv[0], child_argv, env);
++ printf(&quot;Can't execute binary (%s)\n&lt;press Enter&gt;\n&quot;, binary);
++ PAUSE();
++
++ return 33;
++ }
++ while (wait4(-1, &amp;wait_status, 0, NULL) != pid) {};
++ printf(&quot;&lt;press Enter to return to Rescue menu&gt;&quot;);
++ PAUSE();
++ resume_from_suspend();
++ if (!WIFEXITED(wait_status) || WEXITSTATUS(wait_status) != 0) {
++ error_message(&quot;Program exited abnormally (return code %d).&quot;, WEXITSTATUS(wait_status));
++ if (WIFSIGNALED(wait_status))
++ error_message(&quot;(received signal %d)&quot;, WTERMSIG(wait_status));
++ }
++ }
++
++ } while (results == RETURN_OK &amp;&amp; !ptr_begins_static_str(choice, go_to_console));
++
++ finish_frontend();
++ printf(&quot;Bye.\n&quot;);
++
++ return 0;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/rescue-gui.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/README
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/README (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/README 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,87 @@
++pppoe: a PPP-over-Ethernet redirector for pppd
++Copyright (C) 2001 Roaring Penguin Software Inc.
++
++Much inspiration from an earlier client by Luke Stras.
++
++The MSS clamping was inspired by mssclampfw by Marc Boucher &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">marc at mbsi.ca</A>&gt;
++with acknowledgements to Rebel.com (<A HREF="http://www.rebel.com">http://www.rebel.com</A>). However, the
++actual MSS clamping code is original and is licensed under the GPL, unlike
++the original mssclampfw.
++
++Introduction
++============
++
++pppoe is a user-space redirector which permits the use of PPPoE
++(Point-to-Point Over Ethernet) with Linux. PPPoE is used by many
++ADSL service providers.
++
++Installation
++============
++
++Requirements
++------------
++
++1) Linux 2.2.9 or later on Intel, Sparc or PowerPC. It may work on
++ Alpha, too -- anyone care to let me know?
++
++ OR
++
++ Linux 2.0.36 or later.
++
++ OR
++
++ FreeBSD, NetBSD or OpenBSD with BPF support. I have access only
++ to FreeBSD. In general, I can't answer questions about the *BSD's
++ as well as I can about Linux.
++
++
++2) pppd 2.3.10 or later. Versions 2.3.7 and later work unless you use
++ demand-dialling. For demand dialling, you *must* use 2.3.10 or later.
++
++QUICKSTART
++----------
++
++If you're lucky, the &quot;quickstart&quot; method will work. After unpacking
++the archive, become root and type:
++
++ ./go
++
++This should configure, compile and install the software and set up your
++ADSL connection. You'll have to answer a few questions along the way.
++
++If you want the GUI wrapper, type:
++
++ ./go-gui
++
++If ./go and ./go-gui didn't work, read the rest of this README.
++
++Compiling
++---------
++
++Compile and install pppd if you don't already have it. Then:
++
++1) Unpack:
++
++ $ tar xzvf rp-pppoe-xxx.tar.gz
++
++2) Change to source directory:
++
++ $ cd src
++
++3) Configure:
++
++ $ ./configure
++
++4) Compile:
++
++ $ make
++
++4) Install (this step must be done as root)
++
++ # make install
++
++5) Now read doc/HOW-TO-CONNECT
++
++--
++David F. Skoll &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dfs at roaringpenguin.com</A>&gt; | Roaring Penguin Software Inc.
++<A HREF="http://www.roaringpenguin.com">http://www.roaringpenguin.com</A> | Linux and UNIX Specialists
+\ No newline at end of file
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/configs/firewall-masq
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/configs/firewall-masq (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/configs/firewall-masq 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,35 @@
++#!/bin/sh
++#
++# firewall-masq This script sets up firewall rules for a machine
++# acting as a masquerading gateway
++#
++# Copyright (C) 2000 Roaring Penguin Software Inc. This software may
++# be distributed under the terms of the GNU General Public License, version
++# 2 or any later version.
++
++# Interface to Internet
++EXTIF=ppp+
++
++ANY=0.0.0.0/0
++
++ipchains -P input ACCEPT
++ipchains -P output ACCEPT
++ipchains -P forward DENY
++
++ipchains -F forward
++ipchains -F input
++ipchains -F output
++
++# Deny TCP and UDP packets to privileged ports
++ipchains -A input -l -i $EXTIF -d $ANY 0:1023 -p udp -j DENY
++ipchains -A input -l -i $EXTIF -d $ANY 0:1023 -p tcp -j DENY
++
++# Deny TCP connection attempts
++ipchains -A input -l -i $EXTIF -p tcp -y -j DENY
++
++# Deny ICMP echo-requests
++ipchains -A input -l -i $EXTIF -s $ANY echo-request -p icmp -j DENY
++
++# Do masquerading
++ipchains -A forward -j MASQ
++echo 1 &gt; /proc/sys/net/ipv4/ip_forward
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/configs/firewall-standalone
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/configs/firewall-standalone (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/configs/firewall-standalone 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,32 @@
++#!/bin/sh
++#
++# firewall-standalone This script sets up firewall rules for a standalone
++# machine
++#
++# Copyright (C) 2000 Roaring Penguin Software Inc. This software may
++# be distributed under the terms of the GNU General Public License, version
++# 2 or any later version.
++
++# Interface to Internet
++EXTIF=ppp+
++
++ANY=0.0.0.0/0
++
++ipchains -P input ACCEPT
++ipchains -P output ACCEPT
++ipchains -P forward DENY
++
++ipchains -F forward
++ipchains -F input
++ipchains -F output
++
++# Deny TCP and UDP packets to privileged ports
++ipchains -A input -l -i $EXTIF -d $ANY 0:1023 -p udp -j DENY
++ipchains -A input -l -i $EXTIF -d $ANY 0:1023 -p tcp -j DENY
++
++# Deny TCP connection attempts
++ipchains -A input -l -i $EXTIF -p tcp -y -j DENY
++
++# Deny ICMP echo-requests
++ipchains -A input -l -i $EXTIF -s $ANY echo-request -p icmp -j DENY
++
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/configs/pap-secrets
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/configs/pap-secrets (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/configs/pap-secrets 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,9 @@
++# Edit this file and place it in /etc/ppp/pap-secrets
++
++#User #Server #Password #IP
+<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">+bxxxxx at sympatico.ca</A> * my_password *
++
++# Replace <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">bxxxxx at sympatico.ca</A> with your Sympatico user-ID
++# Replace my_password with your Sympatico password
++
++# For Magma, use <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">xxyyzz at magma.ca</A>
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/configs/pppoe-server-options
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/configs/pppoe-server-options (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/configs/pppoe-server-options 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,5 @@
++# PPP options for the PPPoE server
++require-pap
++login
++lcp-echo-interval 10
++lcp-echo-failure 2
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/configs/pppoe.conf
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/configs/pppoe.conf (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/configs/pppoe.conf 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,126 @@
++#***********************************************************************
++#
++# pppoe.conf
++#
++# Configuration file for rp-pppoe. Edit as appropriate and install in
++# /etc/ppp/pppoe.conf
++#
++# NOTE: This file is used by the adsl-start, adsl-stop, adsl-connect and
++# adsl-status shell scripts. It is *not* used in any way by the
++# &quot;pppoe&quot; executable.
++#
++# Copyright (C) 2000 Roaring Penguin Software Inc.
++#
++# This file may be distributed under the terms of the GNU General
++# Public License.
++#
++# $Id: pppoe.conf 195724 2001-06-11 13:49:39Z gc $
++#***********************************************************************
++
++# When you configure a variable, DO NOT leave spaces around the &quot;=&quot; sign.
++
++# Ethernet card connected to ADSL modem
++ETH=eth1
++
++# ADSL user name. You may have to supply &quot;@provider.com&quot; Sympatico
++# users in Canada do need to include &quot;@sympatico.ca&quot;
++# Sympatico uses PAP authentication. Make sure /etc/ppp/pap-secrets
++# contains the right username/password combination.
++# For Magma, use <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">xxyyzz at magma.ca</A>
++USER=<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">bxxxnxnx at sympatico.ca</A>
++
++# Bring link up on demand? Default is to leave link up all the time.
++# If you want the link to come up on demand, set DEMAND to a number indicating
++# the idle time after which the link is brought down.
++DEMAND=no
++#DEMAND=300
++
++# DNS type: SERVER=obtain from server; SPECIFY=use DNS1 and DNS2;
++# NOCHANGE=do not adjust.
++DNSTYPE=SERVER
++
++# Obtain DNS server addresses from the peer (recent versions of pppd only)
++USEPEERDNS=yes
++
++DNS1=
++DNS2=
++
++### ONLY TOUCH THE FOLLOWING SETTINGS IF YOU'RE AN EXPERT
++
++# How long adsl-start waits for a new PPP interface to appear before
++# concluding something went wrong. If you use 0, then adsl-start
++# exits immediately with a successful status and does not wait for the
++# link to come up. Time is in seconds.
++#
++# WARNING WARNING WARNING:
++#
++# If you are using rp-pppoe on a physically-inaccessible host, set
++# CONNECT_TIMEOUT to 0. This makes SURE that the machine keeps trying
++# to connect forever after adsl-start is called. Otherwise, it will
++# give out after CONNECT_TIMEOUT seconds and will not attempt to
++# connect again, making it impossible to reach.
++CONNECT_TIMEOUT=30
++
++# How often in seconds adsl-start polls to check if link is up
++CONNECT_POLL=2
++
++# Specific desired AC Name
++ACNAME=
++
++# Specific desired service name
++SERVICENAME=
++
++# Character to echo at each poll. Use PING=&quot;&quot; if you don't want
++# anything echoed
++PING=&quot;.&quot;
++
++# File where the adsl-connect script writes its process-ID.
++# Three files are actually used:
++# $PIDFILE contains PID of adsl-connect script
++# $PIDFILE.pppoe contains PID of pppoe process
++# $PIDFILE.pppd contains PID of pppd process
++CF_BASE=`basename $CONFIG`
++PIDFILE=&quot;/var/run/$CF_BASE-adsl.pid&quot;
++
++# Do you want to use synchronous PPP? &quot;yes&quot; or &quot;no&quot;. &quot;yes&quot; is much
++# easier on CPU usage, but may not work for you. It is safer to use
++# &quot;no&quot;, but you may want to experiment with &quot;yes&quot;. &quot;yes&quot; is generally
++# safe on Linux machines with the n_hdlc line discipline; unsafe on others.
++SYNCHRONOUS=no
++
++# Do you want to clamp the MSS? Here's how to decide:
++# - If you have only a SINGLE computer connected to the ADSL modem, choose
++# &quot;no&quot;.
++# - If you have a computer acting as a gateway for a LAN, choose &quot;1412&quot;.
++# The setting of 1412 is safe for either setup, but uses slightly more
++# CPU power.
++CLAMPMSS=1412
++#CLAMPMSS=no
++
++# LCP echo interval and failure count.
++LCP_INTERVAL=20
++LCP_FAILURE=3
++
++# PPPOE_TIMEOUT should be about 4*LCP_INTERVAL
++PPPOE_TIMEOUT=80
++
++# Firewalling: One of NONE, STANDALONE or MASQUERADE
++FIREWALL=NONE
++
++# Linux kernel-mode plugin for pppd. If you want to try the kernel-mode
++# plugin, use LINUX_PLUGIN=/etc/ppp/plugins/rp-pppoe.so
++LINUX_PLUGIN=
++
++# Any extra arguments to pass to pppoe. Normally, use a blank string
++# like this:
++PPPOE_EXTRA=&quot;&quot;
++
++# Rumour has it that &quot;Citizen's Communications&quot; with a 3Com
++# HomeConnect ADSL Modem DualLink requires these extra options:
++# PPPOE_EXTRA=&quot;-f 3c12:3c13 -S ISP&quot;
++
++# Any extra arguments to pass to pppd. Normally, use a blank string
++# like this:
++PPPD_EXTRA=&quot;&quot;
++
++
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/doc/CHANGES
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/doc/CHANGES (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/doc/CHANGES 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,177 @@
++Changes from Version 2.8 to 3.0:
++
++- Many small improvements to server. Server now only makes one
++ discovery socket, systemwide, with addition of &quot;-n&quot; option to pppoe.
++
++- Fixes for compilation problems on BSD, Solaris and some Linux platforms.
++
++- Added &quot;-p&quot; option to pppoe-server to allow you to specify a pool of
++ IP addresses to assign to clients.
++
++- Added GUI system (tkpppoe). This work was funded by Iospan
++ Wireless, Inc. The GUI includes a Set-UID wrapper (pppoe-wrapper)
++ which allows ordinary users to control a link (if so authorized.)
++ I believe the wrapper script is secure, but please audit the
++ source code (gui/wrapper.c) if you have any concerns.
++
++- Changes to scripts and pppoe.conf. DNS setup is now dynamic (happens
++ each time adsl-connect runs.)
++
++- Made relay.c check packet lengths rigorously; made it throw out Ethernet
++ frame padding on session packets as well as discovery packets.
++
++Changes from Version 2.7 to 2.8:
++
++- Added init scripts for TurboLinux, courtesy of Yasuhiro Sumi.
++
++- Made relay.c check packet lengths rigorously; made it throw out Ethernet
++ frame padding on discovery packets.
++
++*** NOTE: 2.7 was not released publicly
++
++Changes from Version 2.6 to 2.7:
++
++- Completely restructured source file tree.
++
++- Much internal restructuring to eliminate a bunch of global variables.
++
++- adsl-connect now executes /etc/ppp/adsl-lost whenever connection is dropped
++ or cannot be established.
++
++- Split pppoe.c into pppoe.c and discovery.c.
++
++- Added relay agent (pppoe-relay).
++
++- Made adsl-connect script use the &quot;-U&quot; (host-unique) option to better support
++ multiple PPPoE links.
++
++- Added support for kernel-mode PPPoE (EXPERIMENTAL, UNSUPPORTED!)
++
++- Added &quot;-o&quot; option to PPPoE server; encoded server PID in pppoe-server
++ cookie.
++
++Changes from Version 2.5 to 2.6:
++
++- Code should now compile cleanly on Caldera and Slackware Linux
++
++- Fixed rp-pppoe.spec file to work on Mandrake and Red Hat.
++
++- Deleted some obsolete files
++
++- Fixed bug in Solaris/x86 port (thanks to Philippe Levan)
++
++- Made shell scripts nicer under Solaris (again, Philippe Levan)
++
++- Made adsl-status look under /var/run and /etc/ppp for PID files. Should
++ fix problems with NetBSD.
++
++- Added PPPD_EXTRA to pppoe.conf; made the PID file depend on the config
++ file name. This makes it easier to run multiple PPPoE sessions.
++
++Changes from Version 2.4 to 2.5:
++
++- Tested for zero-length TCP option-length field, and for reverse-packing
++ of type/code bitfields. Thanks to Robert Schlabbach for pointing out
++ these problems.
++
++- Set umask to 077 in adsl-setup.in to protect created files like
++ /etc/ppp/pap-secrets.
++
++Changes from Version 2.3 to 2.4:
++
++- Fixed spec file to automatically add .gz extension to man files as required
++
++- Tightened firewall rules.
++
++- Better check for /var/run in adsl-status; minor shell script fixes and
++ cleanups for NetBSD and Solaris.
++
++- Added FAQ to HOW-TO-CONNECT regarding running a script each time a
++ connection is made.
++
++Changes from Version 2.2 to 2.3:
++
++- Fixed the init script to create/remove /var/lock/subsys/adsl (patch
++ courtesy of Charley Carter.)
++
++- Added support (under Linux) for N_HDLC line discipline which should
++ greatly reduce CPU usage. My tests show it cuts CPU usage in half.
++ My 486 DX2/66 gets 800 kb/s at 22% CPU usage.
++
++- adsl-connect uses &quot;setsid&quot; (if available) so that adsl-stop doesn't kill
++ its caller. There is (IMO) a bug in pppd which kills all processes in
++ its process group if the &quot;pty&quot; option is used. The setsid program gets
++ around this bug, on Linux at least.
++
++- Port to Solaris, courtesy of David Holland.
++
++- Renamed spec file from &quot;spec&quot; to &quot;rp-pppoe.spec&quot; and made some cleanups.
++ NOTE: Red Hat, in their infinite wisdom, decided to make the new RPM
++ compress man pages automatically. You may have problems building RPM's
++ from source unless you get the latest rpm package and make sure it
++ compresses man pages.
++
++Changes from Version 2.1 to 2.2:
++
++- Added &quot;-f&quot; option to pppoe to allow use of any Ethernet frame type
++ for PPPoE. USE WITH CAUTION -- this is a workaround for broken DSL
++ providers, not something you should monkey with freely!
++
++- Added pppoe-sniff program to help expose non-standard PPPoE implementations.
++
++Changes from Version 2.0 to 2.1:
++
++- Fixed minor bugs in bounds-checking
++
++- Modified adsl-status to use output of &quot;netstat -r -n&quot; to determine whether
++ or not link is up. This should make it independent of locale, I hope!
++
++- Added &quot;-k&quot; and &quot;-d&quot; options to pppoe.
++
++Changes from Version 1.9 to 2.0:
++
++- Addition of pppoe-server
++
++- Massive internal code restructuring
++
++- Zealous bounds-checking everywhere.
++
++- adsl-setup now quotes user name and password in /etc/ppp/pap-secrets.
++
++- Ported to OpenBSD, FreeBSD and NetBSD, courtesy of Geoff Mottram
++ and Yannis Sismanis.
++
++- Rearranged adsl-* shell scripts, courtesy of Heiko Schlittermann.
++
++- Fixed bug in which Host-Uniq did not work if access concentrator sent
++ a cookie.
++
++- Addition of SuSE-specific &quot;init&quot; script, courtesy of Gary Cameron.
++
++Changes from Version 1.8 to 1.9:
++
++- Added some more documentation to HOW-TO-CONNECT
++
++- Demand-dialling option now works correctly
++
++- SIGHUP terminates pppoe after sending a PADT to the access concentrator
++
++- Minor cleanups to connection shell scripts
++
++Changes from Version 1.7 to 1.8:
++
++- Added demand-dialling option
++
++- Clarified HOW-TO-CONNECT
++
++- Added adsl-status script
++
++- Added &quot;restart&quot; and &quot;status&quot; options to Red Hat /etc/rc.d/init.d/adsl script
++
++- Made adsl-setup check for existence of pppd
++
++- Wildcarded external interface in firewall rules
++
++- Made pppoe send a PADT frame if connection is terminated
++
++$Id: CHANGES 195724 2001-06-11 13:49:39Z gc $
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/doc/HOW-TO-CONNECT
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/doc/HOW-TO-CONNECT (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/doc/HOW-TO-CONNECT 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,295 @@
++$Id: HOW-TO-CONNECT 195724 2001-06-11 13:49:39Z gc $
++
++This package lets you connect a Linux machine to Sympatico HSE or Magma's
++high-speed service using a Nortel 1-meg modem.
++
++Follow these steps and you should have your high-speed service up and running.
++
++0. Install the rp-pppoe-software
++--------------------------------
++
++You should have already done this by the time you're reading this. If not,
++go back and read README.
++
++1. Set up your Ethernet hardware
++--------------------------------
++
++First, make sure the Ethernet card you intend to use with the modem is
++visible to the Linux kernel. Just how to do this is beyond the scope
++of this document. However, if the card is the only Ethernet card in
++the system, executing:
++
++ ifconfig eth0
++
++should display something like this:
++
++ eth0 Link encap:Ethernet HWaddr 00:60:67:62:31:D4
++
++plust some more lines. Your HWaddr will be different. As long as you see
++the HWaddr line, your card should be working.
++
++DO NOT assign an IP address to the Ethernet card. DO NOT configure the
++card to come up at boot time.
++
++2. Configure various files
++--------------------------
++
++Several files need editing. The easiest way to do this is to run
++the following command as root:
++
++ adsl-setup
++
++Answer the questions and you should be all set. If you want to know what
++goes on behind the scenes, continue reading this document. If you don't
++care and your connection works, stop reading. :-)
++
++3. Edit pap-secrets
++-------------------
++
++Edit the &quot;pap-secrets&quot; file, inserting your proper user-ID and password.
++Install the file (or copy the relevant lines) to /etc/ppp/pap-secrets.
++Your ISP may use CHAP authentication. In this case, add the line to
++/etc/ppp/chap-secrets.
++
++4. Edit /etc/ppp/pppoe.conf
++-----------------------------
++
++The file /etc/ppp/pppoe.conf contains configuration information for the
++ADSL connection. You need to edit the following items:
++
++- Change ETH=eth1 to the correct Ethernet device for your modem.
++- Change USER=<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">bxxxnxnx at sympatico.ca</A> to your proper ADSL user-ID.
++
++Don't edit any of the other settings unless you're an expert.
++
++5. Set up DNS
++-------------
++
++If you are using DNS servers supplied by your ISP, edit the file
++/etc/resolv.conf to contain these lines:
++
++ nameserver ip_addr_of_first_dns_server
++ nameserver ip_addr_of_second_dns_server
++
++For example:
++
++ nameserver 204.101.251.1
++ nameserver 204.101.251.2
++
++
++6. Firewall your machine
++------------------------
++
++MAKE SURE YOU FIREWALL YOUR MACHINE. A sample firewall script is given
++in the shell script &quot;firewall&quot; To install the script:
++
++a) Copy it to /etc/rc.d/init.d/firewall
++b) Type: chkconfig firewall on
++c) Start the firewall: sh /etc/rc.d/init.d/firewall start
++
++(The above procedure works ONLY on Red Hat-like systems.)
++
++You may want to tweak the script somewhat.
++
++7. Bring up the connection at boot time
++---------------------------------------
++
++On a Red Hat system, the installation procedure should have installed
++a script called /etc/rc.d/init.d/adsl. To bring up the connection
++at boot time, just type this command as root:
++
++ chkconfig --add adsl
++
++On non-Red-Hat systems, add this line to the end
++of /etc/rc.d/rc.local:
++
++ /usr/sbin/adsl-start
++
++8. Configure LAN Hosts
++----------------------
++
++If you have a LAN behind the firewall, you have to lower the TCP
++maximum segment size from the normal 1460 to 1452 (or better, 1412.)
++You have two options: Either set the MTU of all the interfaces on
++other hosts on the LAN to 1452, or use the &quot;-m 1412&quot; option to pppoe.
++The &quot;-m&quot; option for pppoe is far simpler and makes it easier to add
++hosts to the LAN, but consumes some extra CPU time.
++
++If you want to manually configure the LAN hosts, here's how:
++
++In Linux, use: &quot;ifconfig eth0 mtu 1452&quot;. For best results, put this
++in an /etc/rc.d/rc.local script.
++
++For Windows, machines, see <A HREF="http://lan.cns.ksu.edu/OS/WIN95/slip95.htm.">http://lan.cns.ksu.edu/OS/WIN95/slip95.htm.</A>
++Set the MaxMTU to 1452.
++
++9. Commands to control the ADSL link
++------------------------------------
++
++As root, bring up the link by typing: adsl-start
++As root, bring down the link by typing: adsl-stop
++
++That's it!
++
++--
++David F. Skoll &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dfs at roaringpenguin.com</A>&gt; | Roaring Penguin Software Inc.
++<A HREF="http://www.roaringpenguin.com">http://www.roaringpenguin.com</A> | Linux and UNIX Specialists
++
++PROBLEMS! DAVE, IT DOESN'T WORK!
++---------------------------------
++
++Here are some problems PPPoE users have encountered.
++
++-----------------------------------------------------------------------------
++A) Can't see the Ethernet interface
++
++Well, I can't really help you here. To use these instructions, you must
++have Linux working to the point where it recognizes your Ethernet card.
++If you type &quot;ifconfig ethx&quot; and you get back a HWAddr value, your Ethernet
++card is probably OK. But I really can't help with hardware configuration
++issues.
++
++-----------------------------------------------------------------------------
++B) Connection seems to come up, but I can't browse the web or ping anything
++
++You probably don't have DNS set up. See step 6.
++
++-----------------------------------------------------------------------------
++C) Can't compile PPPoE
++
++I have only tested compilation on 2.2-kernel machines. Make sure you have
++&quot;make&quot;, the C compiler and all development header files installed.
++
++-----------------------------------------------------------------------------
++D) pppd complains about (i) &quot;unknown option pty&quot; or (ii) &quot;pty option precludes
++ specifying device name&quot;
++
++(i) Your pppd is too old. You need at least 2.3.7.
++(ii) Your /etc/ppp/options file is not empty. Empty it!
++
++-----------------------------------------------------------------------------
++E) pppoe dies with the log message &quot;Message too long&quot;
++
++You set the MTU of the Ethernet interface connected to the ADSL modem
++to less than 1500. Don't do that.
++
++-----------------------------------------------------------------------------
++F) Internal hosts can't see the Internet
++
++Do you have masquerading set up? I can't help you in great detail, but
++see the IPCHAINS-HOWTO and the IP-Masquerade mini-HOWTO.
++
++-----------------------------------------------------------------------------
++G) Authentication fails
++
++Make sure you have the right secret in /etc/ppp/pap-secrets. Your ISP
++may be using CHAP; it won't hurt to copy the line to /etc/ppp/chap-secrets.
++
++Also, MAKE SURE that /etc/ppp/options is EMPTY. The &quot;adsl-connect&quot; script
++supplies all required options on the command line; additional options
++in /etc/ppp/options may mess things up.
++
++-----------------------------------------------------------------------------
++H) VPN software does not work
++
++If you are using VPN software on a Windows or Linux machine with another
++Linux machine running PPPoE as the gateway, you MUST NOT use the &quot;-m&quot; option
++to pppoe. This alters IP packets, which will break any VPN which uses IPSec.
++In /etc/ppp/pppoe.conf, set CLAMPMSS to &quot;no&quot;. You'll also have to reduce
++the MTU on the hosts behind the gateway to 1452.
++
++-----------------------------------------------------------------------------
++I) I can browse some web sites just fine, but others stall forever.
++
++There is probably a buggy router or firewall between you and the Web server.
++One possible workaround: In /etc/ppp/pppoe.conf, find the line which reads:
++
++ CLAMPMSS=1412
++
++Try lowering the 1412 until it works (go down in steps of 100 or so.) Each
++time you lower the value, you have to restart your connection like this:
++
++ adsl-stop; adsl-start
++
++This should work around buggy routers which do not support Path MTU discovery.
++
++-----------------------------------------------------------------------------
++J) Whenever I connect using ADSL, my internal LAN no longer sees the gateway
++
++You are more than likely running a 2.0.X Linux kernel. To solve this
++problem, give the Ethernet card connected to the DSL modem a fake IP
++address. For example, if eth0 is your internal LAN card and eth1 goes to
++the DSL modem, do something like this:
++
++ ifconfig eth1 10.0.0.1 netmask 255.255.255.0
++
++(You may have to choose a different IP address; experiment.)
++-----------------------------------------------------------------------------
++K) How can I run a script every time I connect and get a new IP address?
++
++Put the script in /etc/ppp/ip-up. See the pppd(8) man page.
++-----------------------------------------------------------------------------
++L) Nothing works!
++
++You may need to put your Ethernet card in half-duplex, 10Mb/s mode to
++work with the DSL modem. You may have to run a DOS program to do this,
++or pass special parameters to the Linux driver.
++
++Some providers object to attempts to set the MRU or MTU. Try removing
++&quot;mtu 1492 mru 1492&quot; from PPP_STD_OPTIONS in the adsl-connect script.
++This problem has been seen with an ISP in Hong Kong.
++
++Your DSL provider may be using non-standard PPPoE frames or require
++something special in the Service-Name field. If you have two computers,
++you can try sniffing out these values with the &quot;pppoe-sniff&quot; program.
++Type &quot;man pppoe-sniff&quot; for details. If you don't have two computers,
++you'll have to ask your DSL provider if it uses non-standard PPPoE frames
++or special Service-Name fields. Good luck getting an answer...
++
++If pppoe-sniff indicates that nothing is amiss, make sure the Ethernet
++card associated with the ADSL modem does NOT have a valid IP address.
++(NOTE: For 2.0 kernels, you may have to give it a fake IP address
++which is not on your internal subnet. Something like 192.168.42.42
++might work if you are not using 192.168.42.*)
++
++If you are using synchronous PPP on a slow machine, try switching to
++asynchronous PPP.
++
++Make sure no entries in the routing table go through the Ethernet card
++connected to the ADSL modem. You might want to add these lines in
++adsl-connect:
++
++ ifconfig ethx down
++ ifconfig ethx up mtu 1500
++
++which should reset things to sane values.
++
++#######################################################################
++# WHEN ALL ELSE FAILS: #
++#######################################################################
++
++If you are completely unable to connect, run the adsl-start script in
++debugging mode. If you are using bash as your shell (if you don't
++know what your shell is, it's probably bash), type this:
++
++ DEBUG=1 adsl-start
++
++In tcsh or csh, use:
++
++ setenv DEBUG 1; adsl-start
++
++Then follow the instructions to mail the debugging file to me. PLEASE
++DON'T DO THIS until you have exhausted all other avenues; rp-pppoe is
++free software and it costs me time and money to help people with
++problems. While I don't mind doing this, I do mind it if you don't
++make an effort to fix the problem yourself first.
++
++WARNING: If you run adsl-start in debugging mode and you manage to
++connect, your connection will be extremely slow and huge amounts of
++data will quickly fill your /tmp directory. Do not use debugging mode
++unless you really cannot get your connection to work.
++
++Be aware that debugging mode produces hex dumps which potentially reveal
++your user name and password. If the debugging output includes packets
++labeled &quot;PPPOE Session&quot;, you may wish to remove these packets from the
++dump before mailing it to me.
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/doc/KERNEL-MODE-PPPOE
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/doc/KERNEL-MODE-PPPOE (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/doc/KERNEL-MODE-PPPOE 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,39 @@
++RP-PPPoE now supports kernel-mode PPPoE on Linux kernels 2.4.x. However,
++the default &quot;./go&quot; build procedure does not make kernel-mode support.
++
++Here's what you need to do:
++
++1) Download Michal Ostrowski's patched version of pppd which supports
++a PPPoE plugin. The latest version as of this writing is
++at <A HREF="http://www.math.uwaterloo.ca/~mostrows/">http://www.math.uwaterloo.ca/~mostrows/</A> in
++<A HREF="http://www.math.uwaterloo.ca/~mostrows/ppp-2.4.0-pppoe4.tgz.">http://www.math.uwaterloo.ca/~mostrows/ppp-2.4.0-pppoe4.tgz.</A> It is
++also mirrored at <A HREF="http://www.roaringpenguin.com/pppoe/">http://www.roaringpenguin.com/pppoe/</A>
++
++2) Unpack that version of pppd and build and install it.
++
++3) In the rp-pppoe directory, change to src/ and type:
++
++ ./configure --enable-plugin=/path/to/ppp-tree
++
++Here, /path/to/ppp-tree is where you unpacked the pppd software. It
++should be the directory named ppp-2.4.0.pppoe
++
++4) Type make; make install
++
++5) Edit /etc/ppp/pppoe.conf to include this line:
++
++ LINUX_PLUGIN=/etc/ppp/plugins/rp-pppoe.so
++
++6) Make sure your kernel was built with support for PPP, PPPOX and that
++all modules are locatable by modprobe. Make sure you have a /dev/ppp
++device:
++
++ mknod /dev/ppp c 108 0
++
++After that, adsl-start should use kernel-mode PPPoE.
++
++This code is experimental and unsupported. Use at your own risk.
++
++--
++David F. Skoll &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dfs at roaringpenguin.com</A>&gt;
++
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/doc/LICENSE
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/doc/LICENSE (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/doc/LICENSE 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,339 @@
++ GNU GENERAL PUBLIC LICENSE
++ Version 2, June 1991
++
++ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
++ 675 Mass Ave, Cambridge, MA 02139, USA
++ Everyone is permitted to copy and distribute verbatim copies
++ of this license document, but changing it is not allowed.
++
++ Preamble
++
++ The licenses for most software are designed to take away your
++freedom to share and change it. By contrast, the GNU General Public
++License is intended to guarantee your freedom to share and change free
++software--to make sure the software is free for all its users. This
++General Public License applies to most of the Free Software
++Foundation's software and to any other program whose authors commit to
++using it. (Some other Free Software Foundation software is covered by
++the GNU Library General Public License instead.) You can apply it to
++your programs, too.
++
++ When we speak of free software, we are referring to freedom, not
++price. Our General Public Licenses are designed to make sure that you
++have the freedom to distribute copies of free software (and charge for
++this service if you wish), that you receive source code or can get it
++if you want it, that you can change the software or use pieces of it
++in new free programs; and that you know you can do these things.
++
++ To protect your rights, we need to make restrictions that forbid
++anyone to deny you these rights or to ask you to surrender the rights.
++These restrictions translate to certain responsibilities for you if you
++distribute copies of the software, or if you modify it.
++
++ For example, if you distribute copies of such a program, whether
++gratis or for a fee, you must give the recipients all the rights that
++you have. You must make sure that they, too, receive or can get the
++source code. And you must show them these terms so they know their
++rights.
++
++ We protect your rights with two steps: (1) copyright the software, and
++(2) offer you this license which gives you legal permission to copy,
++distribute and/or modify the software.
++
++ Also, for each author's protection and ours, we want to make certain
++that everyone understands that there is no warranty for this free
++software. If the software is modified by someone else and passed on, we
++want its recipients to know that what they have is not the original, so
++that any problems introduced by others will not reflect on the original
++authors' reputations.
++
++ Finally, any free program is threatened constantly by software
++patents. We wish to avoid the danger that redistributors of a free
++program will individually obtain patent licenses, in effect making the
++program proprietary. To prevent this, we have made it clear that any
++patent must be licensed for everyone's free use or not licensed at all.
++
++ The precise terms and conditions for copying, distribution and
++modification follow.
++
++ GNU GENERAL PUBLIC LICENSE
++ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
++
++ 0. This License applies to any program or other work which contains
++a notice placed by the copyright holder saying it may be distributed
++under the terms of this General Public License. The &quot;Program&quot;, below,
++refers to any such program or work, and a &quot;work based on the Program&quot;
++means either the Program or any derivative work under copyright law:
++that is to say, a work containing the Program or a portion of it,
++either verbatim or with modifications and/or translated into another
++language. (Hereinafter, translation is included without limitation in
++the term &quot;modification&quot;.) Each licensee is addressed as &quot;you&quot;.
++
++Activities other than copying, distribution and modification are not
++covered by this License; they are outside its scope. The act of
++running the Program is not restricted, and the output from the Program
++is covered only if its contents constitute a work based on the
++Program (independent of having been made by running the Program).
++Whether that is true depends on what the Program does.
++
++ 1. You may copy and distribute verbatim copies of the Program's
++source code as you receive it, in any medium, provided that you
++conspicuously and appropriately publish on each copy an appropriate
++copyright notice and disclaimer of warranty; keep intact all the
++notices that refer to this License and to the absence of any warranty;
++and give any other recipients of the Program a copy of this License
++along with the Program.
++
++You may charge a fee for the physical act of transferring a copy, and
++you may at your option offer warranty protection in exchange for a fee.
++
++ 2. You may modify your copy or copies of the Program or any portion
++of it, thus forming a work based on the Program, and copy and
++distribute such modifications or work under the terms of Section 1
++above, provided that you also meet all of these conditions:
++
++ a) You must cause the modified files to carry prominent notices
++ stating that you changed the files and the date of any change.
++
++ b) You must cause any work that you distribute or publish, that in
++ whole or in part contains or is derived from the Program or any
++ part thereof, to be licensed as a whole at no charge to all third
++ parties under the terms of this License.
++
++ c) If the modified program normally reads commands interactively
++ when run, you must cause it, when started running for such
++ interactive use in the most ordinary way, to print or display an
++ announcement including an appropriate copyright notice and a
++ notice that there is no warranty (or else, saying that you provide
++ a warranty) and that users may redistribute the program under
++ these conditions, and telling the user how to view a copy of this
++ License. (Exception: if the Program itself is interactive but
++ does not normally print such an announcement, your work based on
++ the Program is not required to print an announcement.)
++
++These requirements apply to the modified work as a whole. If
++identifiable sections of that work are not derived from the Program,
++and can be reasonably considered independent and separate works in
++themselves, then this License, and its terms, do not apply to those
++sections when you distribute them as separate works. But when you
++distribute the same sections as part of a whole which is a work based
++on the Program, the distribution of the whole must be on the terms of
++this License, whose permissions for other licensees extend to the
++entire whole, and thus to each and every part regardless of who wrote it.
++
++Thus, it is not the intent of this section to claim rights or contest
++your rights to work written entirely by you; rather, the intent is to
++exercise the right to control the distribution of derivative or
++collective works based on the Program.
++
++In addition, mere aggregation of another work not based on the Program
++with the Program (or with a work based on the Program) on a volume of
++a storage or distribution medium does not bring the other work under
++the scope of this License.
++
++ 3. You may copy and distribute the Program (or a work based on it,
++under Section 2) in object code or executable form under the terms of
++Sections 1 and 2 above provided that you also do one of the following:
++
++ a) Accompany it with the complete corresponding machine-readable
++ source code, which must be distributed under the terms of Sections
++ 1 and 2 above on a medium customarily used for software interchange; or,
++
++ b) Accompany it with a written offer, valid for at least three
++ years, to give any third party, for a charge no more than your
++ cost of physically performing source distribution, a complete
++ machine-readable copy of the corresponding source code, to be
++ distributed under the terms of Sections 1 and 2 above on a medium
++ customarily used for software interchange; or,
++
++ c) Accompany it with the information you received as to the offer
++ to distribute corresponding source code. (This alternative is
++ allowed only for noncommercial distribution and only if you
++ received the program in object code or executable form with such
++ an offer, in accord with Subsection b above.)
++
++The source code for a work means the preferred form of the work for
++making modifications to it. For an executable work, complete source
++code means all the source code for all modules it contains, plus any
++associated interface definition files, plus the scripts used to
++control compilation and installation of the executable. However, as a
++special exception, the source code distributed need not include
++anything that is normally distributed (in either source or binary
++form) with the major components (compiler, kernel, and so on) of the
++operating system on which the executable runs, unless that component
++itself accompanies the executable.
++
++If distribution of executable or object code is made by offering
++access to copy from a designated place, then offering equivalent
++access to copy the source code from the same place counts as
++distribution of the source code, even though third parties are not
++compelled to copy the source along with the object code.
++
++ 4. You may not copy, modify, sublicense, or distribute the Program
++except as expressly provided under this License. Any attempt
++otherwise to copy, modify, sublicense or distribute the Program is
++void, and will automatically terminate your rights under this License.
++However, parties who have received copies, or rights, from you under
++this License will not have their licenses terminated so long as such
++parties remain in full compliance.
++
++ 5. You are not required to accept this License, since you have not
++signed it. However, nothing else grants you permission to modify or
++distribute the Program or its derivative works. These actions are
++prohibited by law if you do not accept this License. Therefore, by
++modifying or distributing the Program (or any work based on the
++Program), you indicate your acceptance of this License to do so, and
++all its terms and conditions for copying, distributing or modifying
++the Program or works based on it.
++
++ 6. Each time you redistribute the Program (or any work based on the
++Program), the recipient automatically receives a license from the
++original licensor to copy, distribute or modify the Program subject to
++these terms and conditions. You may not impose any further
++restrictions on the recipients' exercise of the rights granted herein.
++You are not responsible for enforcing compliance by third parties to
++this License.
++
++ 7. If, as a consequence of a court judgment or allegation of patent
++infringement or for any other reason (not limited to patent issues),
++conditions are imposed on you (whether by court order, agreement or
++otherwise) that contradict the conditions of this License, they do not
++excuse you from the conditions of this License. If you cannot
++distribute so as to satisfy simultaneously your obligations under this
++License and any other pertinent obligations, then as a consequence you
++may not distribute the Program at all. For example, if a patent
++license would not permit royalty-free redistribution of the Program by
++all those who receive copies directly or indirectly through you, then
++the only way you could satisfy both it and this License would be to
++refrain entirely from distribution of the Program.
++
++If any portion of this section is held invalid or unenforceable under
++any particular circumstance, the balance of the section is intended to
++apply and the section as a whole is intended to apply in other
++circumstances.
++
++It is not the purpose of this section to induce you to infringe any
++patents or other property right claims or to contest validity of any
++such claims; this section has the sole purpose of protecting the
++integrity of the free software distribution system, which is
++implemented by public license practices. Many people have made
++generous contributions to the wide range of software distributed
++through that system in reliance on consistent application of that
++system; it is up to the author/donor to decide if he or she is willing
++to distribute software through any other system and a licensee cannot
++impose that choice.
++
++This section is intended to make thoroughly clear what is believed to
++be a consequence of the rest of this License.
++
++ 8. If the distribution and/or use of the Program is restricted in
++certain countries either by patents or by copyrighted interfaces, the
++original copyright holder who places the Program under this License
++may add an explicit geographical distribution limitation excluding
++those countries, so that distribution is permitted only in or among
++countries not thus excluded. In such case, this License incorporates
++the limitation as if written in the body of this License.
++
++ 9. The Free Software Foundation may publish revised and/or new versions
++of the General Public License from time to time. Such new versions will
++be similar in spirit to the present version, but may differ in detail to
++address new problems or concerns.
++
++Each version is given a distinguishing version number. If the Program
++specifies a version number of this License which applies to it and &quot;any
++later version&quot;, you have the option of following the terms and conditions
++either of that version or of any later version published by the Free
++Software Foundation. If the Program does not specify a version number of
++this License, you may choose any version ever published by the Free Software
++Foundation.
++
++ 10. If you wish to incorporate parts of the Program into other free
++programs whose distribution conditions are different, write to the author
++to ask for permission. For software which is copyrighted by the Free
++Software Foundation, write to the Free Software Foundation; we sometimes
++make exceptions for this. Our decision will be guided by the two goals
++of preserving the free status of all derivatives of our free software and
++of promoting the sharing and reuse of software generally.
++
++ NO WARRANTY
++
++ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
++FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
++OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
++PROVIDE THE PROGRAM &quot;AS IS&quot; WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
++OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
++TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
++PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
++REPAIR OR CORRECTION.
++
++ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
++WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
++REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
++INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
++OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
++TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
++YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
++PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
++POSSIBILITY OF SUCH DAMAGES.
++
++ END OF TERMS AND CONDITIONS
++
++ Appendix: How to Apply These Terms to Your New Programs
++
++ If you develop a new program, and you want it to be of the greatest
++possible use to the public, the best way to achieve this is to make it
++free software which everyone can redistribute and change under these terms.
++
++ To do so, attach the following notices to the program. It is safest
++to attach them to the start of each source file to most effectively
++convey the exclusion of warranty; and each file should have at least
++the &quot;copyright&quot; line and a pointer to where the full notice is found.
++
++ &lt;one line to give the program's name and a brief idea of what it does.&gt;
++ Copyright (C) 19yy &lt;name of author&gt;
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++Also add information on how to contact you by electronic and paper mail.
++
++If the program is interactive, make it output a short notice like this
++when it starts in an interactive mode:
++
++ Gnomovision version 69, Copyright (C) 19yy name of author
++ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
++ This is free software, and you are welcome to redistribute it
++ under certain conditions; type `show c' for details.
++
++The hypothetical commands `show w' and `show c' should show the appropriate
++parts of the General Public License. Of course, the commands you use may
++be called something other than `show w' and `show c'; they could even be
++mouse-clicks or menu items--whatever suits your program.
++
++You should also get your employer (if you work as a programmer) or your
++school, if any, to sign a &quot;copyright disclaimer&quot; for the program, if
++necessary. Here is a sample; alter the names:
++
++ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
++ `Gnomovision' (which makes passes at compilers) written by James Hacker.
++
++ &lt;signature of Ty Coon&gt;, 1 April 1989
++ Ty Coon, President of Vice
++
++This General Public License does not permit incorporating your program into
++proprietary programs. If your program is a subroutine library, you may
++consider it more useful to permit linking proprietary applications with the
++library. If this is what you want to do, use the GNU Library General
++Public License instead of this License.
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/doc/PROBLEMS
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/doc/PROBLEMS (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/doc/PROBLEMS 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,3 @@
++Problems?
++
++See the last section of HOW-TO-CONNECT.
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/go
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/go (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/go 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,43 @@
++#!/bin/sh
++#***********************************************************************
++#
++# go
++#
++# Quick-start shell script to set up ADSL
++#
++# Copyright (C) 2000 Roaring Penguin Software Inc.
++#
++# $Id: go 195724 2001-06-11 13:49:39Z gc $
++#***********************************************************************
++
++# Figure out directory of script
++MYDIR=`dirname $0`
++cd $MYDIR/src
++
++echo &quot;Running ./configure...&quot;
++./configure
++if [ &quot;$?&quot; != 0 ] ; then
++ echo &quot;Oops! It looks like ./configure failed.&quot;
++ exit 1
++fi
++
++echo &quot;Running make...&quot;
++make
++if [ &quot;$?&quot; != 0 ] ; then
++ echo &quot;Oops! It looks like make failed.&quot;
++ exit 1
++fi
++
++echo &quot;Running make install...&quot;
++make install
++
++if [ &quot;$?&quot; != 0 ] ; then
++ echo &quot;Oops! It looks like make install failed.&quot;
++ exit 1
++fi
++
++for i in a a a a a a a a a a a a a a a a a a a a a a a a a a a a ; do
++ echo &quot;&quot;
++done
++
++sh ../scripts/adsl-setup
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/go
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/go-gui
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/go-gui (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/go-gui 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,92 @@
++#!/bin/sh
++#***********************************************************************
++#
++# go-gui
++#
++# Quick-start shell script to set up ADSL and GUI wrapper
++#
++# Copyright (C) 2000 Roaring Penguin Software Inc.
++#
++# $Id: go-gui 195724 2001-06-11 13:49:39Z gc $
++#***********************************************************************
++
++# GUI only works on Linux
++if test &quot;`uname`&quot; != &quot;Linux&quot; ; then
++ echo &quot;Sorry, the GUI only works on Linux.&quot;
++ exit 1
++fi
++
++# Figure out directory of script
++MYDIR=`dirname $0`
++cd $MYDIR/src
++
++echo &quot;Running ./configure...&quot;
++./configure
++if [ &quot;$?&quot; != 0 ] ; then
++ echo &quot;Oops! It looks like ./configure failed.&quot;
++ exit 1
++fi
++
++echo &quot;Running make...&quot;
++make
++if [ &quot;$?&quot; != 0 ] ; then
++ echo &quot;Oops! It looks like make failed.&quot;
++ exit 1
++fi
++
++echo &quot;Running make install...&quot;
++make install
++
++if [ &quot;$?&quot; != 0 ] ; then
++ echo &quot;Oops! It looks like make install failed.&quot;
++ exit 1
++fi
++
++echo &quot;Building GUI wrapper...&quot;
++cd ../gui
++make
++if [ &quot;$?&quot; != 0 ] ; then
++ echo &quot;Oops! It looks like make failed.&quot;
++ exit 1
++fi
++
++echo &quot;Installing GUI...&quot;
++make install
++
++if [ &quot;$?&quot; != 0 ] ; then
++ echo &quot;Oops! It looks like make install failed.&quot;
++ exit 1
++fi
++
++# Install entry in KDE menu
++if test -n &quot;$KDEDIR&quot; ; then
++ echo &quot;Installing KDE menu entry Internet : TkPPPoE...&quot;
++ mkdir -p &quot;$KDEDIR/share/applnk/Internet&quot;
++ cat &lt;&lt;EOF &gt; &quot;$KDEDIR/share/applnk/Internet/tkpppoe.kdelnk&quot;
++# KDE Config File
++[KDE Desktop Entry]
++Name=TkPPPoE
++Comment=Start/Stop ADSL connections
++Exec=tkpppoe
++Terminal=0
++Type=Application
++EOF
++fi
++
++# Install entry in GNOME menus
++GNOMEDIR=`gnome-config --datadir 2&gt;/dev/null`
++if test -n &quot;$GNOMEDIR&quot; ; then
++ echo &quot;Installing GNOME menu entry Internet : TkPPPoE...&quot;
++ mkdir -p &quot;$GNOMEDIR/gnome/apps/Internet&quot;
++cat &lt;&lt;EOF &gt; &quot;$GNOMEDIR/gnome/apps/Internet/tkpppoe.desktop&quot;
++[Desktop Entry]
++Name=TkPPPoE
++Comment=Start/Stop ADSL connections
++Exec=tkpppoe
++Terminal=0
++Type=Application
++EOF
++fi
++echo &quot;Running GUI configuration tool...&quot;
++tkpppoe &amp;
++exit 0
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/go-gui
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/gui/Makefile.in
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/gui/Makefile.in (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/gui/Makefile.in 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,64 @@
++# @configure_input@
++#***********************************************************************
++#
++# Makefile
++#
++# Makefile for GUI for Roaring Penguin's Linux user-space PPPoE client.
++#
++# Copyright (C) 2001 Roaring Penguin Software Inc.
++#
++# This program may be distributed according to the terms of the GNU
++# General Public License, version 2 or (at your option) any later version.
++#
++# $Id: Makefile.in 195724 2001-06-11 13:49:39Z gc $
++#***********************************************************************
++DEFINES=
++prefix=@prefix@
++exec_prefix=@exec_prefix@
++mandir=@mandir@
++install=@INSTALL@
++install_dir=@INSTALL@ -d
++sbindir=@sbindir@
++bindir=@bindir@
++
++ADSL_START_PATH=@sbindir@/adsl-start
++ADSL_STOP_PATH=@sbindir@/adsl-stop
++ADSL_STATUS_PATH=@sbindir@/adsl-status
++
++PATHS='-DADSL_START_PATH=&quot;$(ADSL_START_PATH)&quot;' '-DADSL_STOP_PATH=&quot;$(ADSL_STOP_PATH)&quot;' '-DADSL_STATUS_PATH=&quot;$(ADSL_STATUS_PATH)&quot;'
++
++CFLAGS= @CFLAGS@ $(DEFINES) $(PATHS)
++
++all: pppoe-wrapper
++ @echo &quot;&quot;
++ @echo &quot;Type 'make install' as root to install the software.&quot;
++
++pppoe-wrapper: wrapper.o
++ @CC@ -o pppoe-wrapper wrapper.o
++
++wrapper.o: wrapper.c
++ @CC@ $(CFLAGS) -c -o wrapper.o wrapper.c
++
++install: all
++ -mkdir -p $(RPM_INSTALL_ROOT)$(sbindir)
++ -mkdir -p $(RPM_INSTALL_ROOT)$(bindir)
++ -mkdir -p $(RPM_INSTALL_ROOT)/etc/ppp/rp-pppoe-gui
++ $(install) -m 4755 -s pppoe-wrapper $(RPM_INSTALL_ROOT)$(sbindir)
++ $(install) -m 755 tkpppoe $(RPM_INSTALL_ROOT)$(bindir)
++ -mkdir -p $(RPM_INSTALL_ROOT)$(mandir)/man1
++ $(install) -m 644 pppoe-wrapper.1 $(RPM_INSTALL_ROOT)$(mandir)/man1
++ $(install) -m 644 tkpppoe.1 $(RPM_INSTALL_ROOT)$(mandir)/man1
++ -mkdir -p $(RPM_INSTALL_ROOT)/usr/share/rp-pppoe-gui
++ for i in tkpppoe.html mainwin-busy.png mainwin-nonroot.png mainwin.png props-advanced.png props-basic.png props-nic.png props-options.png ; do \
++ $(install) -m 644 html/$$i $(RPM_INSTALL_ROOT)/usr/share/rp-pppoe-gui; \
++ done
++
++clean:
++ rm -f *.o *~ pppoe-wrapper
++
++distclean: clean
++ rm -f Makefile tkpppoe
++
++.PHONY: clean
++
++.PHONY: distclean
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/gui/html/tkpppoe.html
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/gui/html/tkpppoe.html (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/gui/html/tkpppoe.html 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,181 @@
++&lt;!doctype html public &quot;-//w3c//dtd html 4.0 transitional//en&quot;&gt;
++&lt;html&gt;
++&lt;head&gt;
++ &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=iso-8859-1&quot;&gt;
++ &lt;meta name=&quot;GENERATOR&quot; content=&quot;Mozilla/4.76 [en] (X11; U; Linux 2.2.14-5.0 i686) [Netscape]&quot;&gt;
++ &lt;title&gt;TkPPPoE Manual&lt;/title&gt;
++&lt;/head&gt;
++&lt;body text=&quot;#000000&quot; bgcolor=&quot;#FFFFFF&quot; link=&quot;#0000EF&quot; vlink=&quot;#59188E&quot; alink=&quot;#FF0000&quot;&gt;
++
++&lt;center&gt;
++&lt;h1&gt;tkpppoe - A GUI for managing PPPoE Connections&lt;/h1&gt;
++&lt;/center&gt;
++
++&lt;h1&gt;Introduction&lt;/h1&gt;
++
++TkPPPoE is a graphical user interface for managing PPPoE connections. It
++performs two different functions:
++&lt;ul&gt;
++&lt;li&gt;TkPPPoE lets you &lt;em&gt;define&lt;/em&gt; connection properties. This step must
++be done as root.
++&lt;li&gt;TkPPPoE lets you &lt;em&gt;start and stop&lt;/em&gt; PPPoE connections. This step
++may be done as a normal user, depending on how you configured the connection.
++&lt;/ul&gt;
++
++&lt;h1&gt;Defining Connections&lt;/h1&gt;
++
++To define connections, start TkPPPoE as root. You can do this from
++a terminal by typing &lt;code&gt;tkpppoe&lt;/code&gt;, or from the KDE or GNOME menus
++by selecting &lt;b&gt;Internet : TkPPPoE&lt;/b&gt;. The following window pops up:
++
++&lt;p&gt;
++&lt;center&gt;&lt;img src=&quot;mainwin.png&quot; width=&quot;361&quot; height=&quot;73&quot; alt=&quot;Main Window&quot;&gt;
++&lt;/center&gt;
++
++&lt;p&gt;
++Because you have not yet defined any connections, the connection property
++window also pops up:
++
++&lt;p&gt;
++&lt;center&gt;&lt;img src=&quot;props-basic.png&quot; width=&quot;440&quot; height=&quot;259&quot; alt=&quot;Connection Properties - Basic&quot;&gt;
++&lt;/center&gt;
++
++You can pop up the connection property window at any time by clicking
++&lt;b&gt;New Connection...&lt;/b&gt; You can edit the properties of an existing
++connection by selecting the connection's name and clicking
++&lt;b&gt;Properties...&lt;/b&gt;
++&lt;h4&gt;Basic Information&lt;/h4&gt;
++
++Let's fill in the basic information:
++&lt;ul&gt;
++&lt;li&gt;For &lt;b&gt;Connection Name&lt;/b&gt;, enter a unique name for this connection. It
++can be anything you like, but must contain only letters, numbers, underscores
++or dashes. In particular, it can't contain spaces. If you have only one
++PPPoE connection, a good name is &lt;b&gt;Default&lt;/b&gt;.
++&lt;li&gt;For &lt;b&gt;User Name&lt;/b&gt;, enter the user name supplied by your ISP. Enter
++only the user name; do not enter an &quot;@isp.com&quot; part.
++&lt;li&gt;For &lt;b&gt;Network&lt;/b&gt;, you may have to enter your ISP's domain name.
++(For example, &lt;b&gt;isp.com&lt;/b&gt;.) Some DSL providers add this to your user
++name; others do not. You may have to experiment a bit. The two most likely
++choices are your ISP's domain name, or blank. Try both.
++&lt;li&gt;For &lt;b&gt;Password&lt;/b&gt;, enter the password your ISP provided you with.
++&lt;/ul&gt;
++
++&lt;h4&gt;NIC and DNS&lt;/h4&gt;
++Click on the &lt;b&gt;NIC and DNS&lt;/b&gt; tab:
++
++&lt;p&gt;
++&lt;center&gt;&lt;img src=&quot;props-nic.png&quot; width=&quot;440&quot; height=&quot;259&quot; alt=&quot;Connection Properties - NIC and DNS&quot;&gt;&lt;/center&gt;
++&lt;p&gt;
++&lt;ul&gt;
++&lt;li&gt;For &lt;b&gt;Ethernet Interface&lt;/b&gt;, enter the Ethernet interface connected
++to the DSL modem. It is something like &lt;b&gt;eth0&lt;/b&gt; or &lt;b&gt;eth1&lt;/b&gt;. Click
++on &lt;b&gt;...&lt;/b&gt; to browse a list of detected Ethernet interfaces.
++&lt;li&gt;For &lt;b&gt;DNS Setup&lt;/b&gt;, you have three options:
++&lt;ol&gt;
++&lt;li&gt;&lt;b&gt;From Server&lt;/b&gt; means that the system will obtain DNS information from
++the PPPoE server. This is the correct choice for most ISPs.
++&lt;li&gt;&lt;b&gt;Specify&lt;/b&gt; means that you will enter the IP addresses of your DNS
++servers manually. In this case, enter the addresses in the &lt;b&gt;Primary DNS&lt;/b&gt;
++and &lt;b&gt;Secondary DNS&lt;/b&gt; entries.
++&lt;li&gt;&lt;b&gt;Do not Adjust&lt;/b&gt; means that you want RP-PPPoE to leave your
++DNS setup alone. Use this if you are running your own caching DNS server
++or know that you don't want the DNS setup touched.
++&lt;/ol&gt;
++&lt;/ul&gt;
++
++&lt;h4&gt;Options&lt;/h4&gt;
++Click on the &lt;b&gt;Options&lt;/b&gt; tab:
++
++&lt;p&gt;
++&lt;center&gt;&lt;img src=&quot;props-options.png&quot; width=&quot;440&quot; height=&quot;259&quot; alt=&quot;Connection Properties - Options&quot;&gt;&lt;/center&gt;
++&lt;p&gt;
++&lt;ul&gt;
++&lt;li&gt;If you want ordinary users to be able to start and stop this connection,
++enable &lt;b&gt;Allow use by non-root users&lt;/b&gt;. If you do not enable this,
++non-root users will be able to monitor the connection, but not control it.
++&lt;li&gt;If you want to use synchronous PPP, enable &lt;b&gt;Use synchronous PPP&lt;/b&gt;.
++This is recommended as it conserves CPU usage, but may not work on some
++(misconfigured) Linux kernels.
++&lt;li&gt;For &lt;b&gt;Firewalling&lt;/b&gt;, you have three options:
++&lt;ol&gt;
++&lt;li&gt;&lt;b&gt;Stand-Alone&lt;/b&gt; installs a simple firewall ruleset for stand-alone
++machines. Use this if you have only a single computer connected to the DSL
++modem.
++&lt;li&gt;&lt;b&gt;Masquerading&lt;/b&gt; installs a simple firewall ruleset for using
++your Linux computer as an Internet sharing device. If you have two Ethernet
++cards, you can connect one card to the DSL modem and the other to an
++internal LAN. The masquerading firewall ruleset lets internal machines
++share the DSL connection.
++&lt;li&gt;&lt;b&gt;None&lt;/b&gt;. If you already have your own firewall rules, or you wish
++to run servers on your machine, select None. This is &lt;em&gt;not recommended&lt;/em&gt;
++unless you take steps to secure your machine, and know what you are doing.
++&lt;/ol&gt;
++&lt;/ul&gt;
++
++&lt;h4&gt;Advanced&lt;/h4&gt;
++Click on the &lt;b&gt;Advanced&lt;/b&gt; tab:
++
++&lt;p&gt;
++&lt;center&gt;&lt;img src=&quot;props-advanced.png&quot; width=&quot;440&quot; height=&quot;259&quot; alt=&quot;Connection Properties - Advanced&quot;&gt;&lt;/center&gt;
++&lt;p&gt;
++
++In most cases, you can leave &lt;b&gt;AC-Name&lt;/b&gt; and &lt;b&gt;Service-Name&lt;/b&gt; blank.
++In some cases, your ISP may require you to enter information in these fields;
++contact your ISP for more information.
++
++&lt;h1&gt;Controlling Connections&lt;/h1&gt;
++For these examples, run &lt;code&gt;tkpppoe&lt;/code&gt; as a normal user (not root).
++The main window appears like this:
++
++&lt;p&gt;
++&lt;center&gt;&lt;img src=&quot;mainwin-nonroot.png&quot; width=&quot;206&quot; height=&quot;73&quot; alt=&quot;Main Window - Non-root&quot;&gt;
++&lt;/center&gt;
++&lt;p&gt;
++&lt;ul&gt;
++&lt;li&gt;To start a connection, press &lt;b&gt;Start&lt;/b&gt;. The two LEDs flash red
++and grey. If the connection is established, they turn green.
++&lt;li&gt;To stop a connection, press &lt;b&gt;Stop&lt;/b&gt;.
++&lt;/ul&gt;
++
++&lt;p&gt;The two rectangles to the right of the connection name are the
++&lt;em&gt;status LEDs&lt;/em&gt;. The top LED corresponds to transmitted data and
++the bottom to received. The LEDs are colored as follows:
++&lt;ul&gt;
++&lt;li&gt;Grey -- connection is not established.
++&lt;li&gt;Flashing red/grey -- connection is being started.
++&lt;li&gt;Green -- connection is up, but idle.
++&lt;li&gt;Yellow -- connection is up and data is being sent or received.
++&lt;li&gt;Red -- connection has been lost, but the system is trying to reestablish it.
++&lt;/ul&gt;
++
++&lt;p&gt;
++When a connection is established, two graphs appear:
++
++&lt;p&gt;
++&lt;center&gt;&lt;img src=&quot;mainwin-busy.png&quot; width=&quot;206&quot; height=&quot;73&quot; alt=&quot;Main Window - Established Connection&quot;&gt;
++&lt;/center&gt;
++&lt;p&gt;
++
++The left (red) graph shows transmitted packets and the average
++transmission speed (in bits per second) over the sample time. The
++right (green) graph shows received packets.
++
++&lt;h1&gt;Miscellaneous Information&lt;/h1&gt;
++&lt;ul&gt;
++&lt;li&gt;The connection menu has an entry called &lt;b&gt;User's Manual&lt;/b&gt; which
++will pop up this user manual (if you have Netscape installed.)
++&lt;li&gt;You can define multiple PPPoE connections, but you should not use
++more than one simultaneuously unless you feel comfortable editing scripts
++and setting up routing tables. By default, TkPPPoE tries to add a default
++route for connections. This does not work well with multiple simultaneous
++connections.
++&lt;li&gt;If you exit from TkPPPoE, connections which are up remain up. You
++have to explicitly stop connections if you want them terminated.
++&lt;/ul&gt;
++&lt;hr&gt;
++&lt;a href=&quot;<A HREF="http://www.roaringpenguin.com/pppoe/">http://www.roaringpenguin.com/pppoe/</A>&quot;&gt;TkPPPoE&lt;/a&gt; is Copyright 2001 by &lt;a href=&quot;<A HREF="http://www.roaringpenguin.com">http://www.roaringpenguin.com</A>&quot;&gt;Roaring Penguin Software Inc&lt;/a&gt; and
++is licensed under the GNU General Public License.
++&lt;p&gt;Screenshots show TkPPPoE running under the &lt;a href=&quot;<A HREF="http://www.xfce.org">http://www.xfce.org</A>&quot;&gt;XFCE&lt;/a&gt; desktop, a lightweight UNIX and Linux desktop.
++&lt;/body&gt;
++&lt;/html&gt;
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/gui/pppoe-wrapper.1
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/gui/pppoe-wrapper.1 (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/gui/pppoe-wrapper.1 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,45 @@
++.\&quot; $Id: pppoe-wrapper.1 195724 2001-06-11 13:49:39Z gc $
++.TH PPPOE-WRAPPER 1 &quot;26 February 2001&quot;
++.UC 4
++.SH NAME
++pppoe-wrapper \- SUID wrapper for starting and stopping PPPoE connections.
++.SH SYNOPSIS
++.B pppoe-wrapper start linkname
++.P
++.B pppoe-wrapper stop linkname
++.P
++.B pppoe-wrapper status linkname
++
++.SH DESCRIPTION
++\fBpppoe-wrapper\fR is a small SUID program which allows non-root users
++to start and stop PPPoE links. It operates as follows:
++
++.TP
++.B o
++First, \fIlinkname\fR is sanity-checked. Too-long names and names containing
++illegal characters are rejected.
++
++.TP
++.B o
++Second, \fBpppoe-wrapper\fR opens the file \fB/etc/ppp/rp-pppoe-gui/\fR\fIlinkname\fR for reading. If that file does not contain the line:
++.nf
++
++ NONROOT=OK
++
++.fi
++then \fBpppoe-wrapper\fR fails.
++
++.TP
++.B o
++Otherwise, \fBpppoe-wrapper\fR runs \fBadsl-start\fR, \fBadsl-stop\fR or
++\fBadsl-status\fR with the above filename as its single argument.
++
++.SH AUTHOR
++\fBpppoe-wrapper\fR was written by David F. Skoll &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dfs at roaringpenguin.com</A>&gt;.
++
++The \fBpppoe\fR home page is \<A HREF="fIhttp://www.roaringpenguin.com/pppoe/\fR.">fIhttp://www.roaringpenguin.com/pppoe/\fR.</A>
++
++.SH SEE ALSO
++adsl-start(8), adsl-stop(8), adsl-status(8), tkpppoe(1)
++
++
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/gui/tkpppoe.1
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/gui/tkpppoe.1 (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/gui/tkpppoe.1 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,36 @@
++.\&quot; $Id: tkpppoe.1 195724 2001-06-11 13:49:39Z gc $
++.TH TKPPPOE 1 &quot;26 February 2001&quot;
++.UC 4
++.SH NAME
++tkpppoe \- Graphical interface for controlling rp-pppoe
++.SH SYNOPSIS
++.B tkpppoe
++
++.SH DESCRIPTION
++\fBtkpppoe\fR is a graphical program for controlling PPPoE links.
++It works with the RP-PPPoE package and has its own HTML manual.
++
++.SH FILES
++
++.TP
++.B /etc/ppp/rp-pppoe-gui/connection-info
++Contains connection information. This file is not human-editable.
++
++.TP
++.B /etc/ppp/rp-pppoe-gui/passwd
++Contains passwords for each connection. This file is not human-editable.
++
++.TP
++.B /etc/ppp/rp-pppoe-gui/conf.*
++These configuration files are used by \fBadsl-start\fR. They are
++generated anew by \fBtkpppoe\fR each time a change is made to a
++connection's properties.
++
++.SH AUTHOR
++\fBtkpppoe\fR was written by David F. Skoll &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dfs at roaringpenguin.com</A>&gt;.
++
++The \fBpppoe\fR home page is \<A HREF="fIhttp://www.roaringpenguin.com/pppoe/\fR.">fIhttp://www.roaringpenguin.com/pppoe/\fR.</A>
++
++.SH SEE ALSO
++adsl-start(8), adsl-stop(8), pppoe-wrapper(8).
++
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/gui/tkpppoe.in
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/gui/tkpppoe.in (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/gui/tkpppoe.in 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,2891 @@
++#!/bin/sh
++# -*-Mode: TCL;-*-
++
++#--------------------------------------------------------------
++# tkpppoe
++#
++# A graphical front-end for configuring and using rp-pppoe.
++#
++# Copyright (C) 2001 by Roaring Penguin Software Inc.
++# This file may be distributed under the terms of the GNU General Public
++# License, Version 2, or (at your option) any later version.
++#
++# The &quot;Roaring Penguin&quot; logo is a trademark of Roaring Penguin Software Inc.
++#
++# <A HREF="http://www.roaringpenguin.com">http://www.roaringpenguin.com</A>
++#
++#--------------------------------------------------------------
++
++# $Id: tkpppoe.in 195724 2001-06-11 13:49:39Z gc $
++
++# the next line restarts using wish \
++umask 022; \
++exec wish &quot;$0&quot; &quot;$@&quot; || clear; echo &quot;*****&quot;; echo &quot;Cannot find 'wish' -- you need Tcl/Tk installed to run this program&quot;; exit 1
++
++# Set app name
++tk appname TkPPPoE
++
++# Set this to one if you want to allow multiple instances of TkPPPoE
++set AllowMultipleInstances 0
++
++# Check for other instances
++if {&quot;[tk appname]&quot; != &quot;TkPPPoE&quot;} {
++ # Must be another instance running...
++ if {!$AllowMultipleInstances} {
++ send TkPPPoE AnotherInstance
++ exit 0
++ }
++}
++
++# Location of config directory
++set ConfigDir /etc/ppp/rp-pppoe-gui
++
++# Are we running as root?
++set Admin 0
++
++# Location of connection info file
++set ConnectionInfoFile [file join $ConfigDir connection-info]
++
++# Location of password file
++set PasswordFile [file join $ConfigDir passwd]
++
++# Location of &quot;already run&quot; file
++set AlreadyRunFile [file join $ConfigDir gui-already-run]
++
++# Connection information
++set ConnectionInfo {}
++
++# Connection options
++set OPTS(nonroot) 0
++set OPTS(sync) 1
++
++# Location of wrapper
++set Wrapper &quot;@WRAPPER@&quot;
++
++# Timer token for UpdateConnectionState
++set UpdateToken {}
++
++# Update interval in milliseconds
++set UpdateInterval 500
++
++# Packet counters for signalling activity
++set Packets(in) 0
++set Packets(out) 0
++set Bytes(in) 0
++set Bytes(out) 0
++set MeasureTime 0
++
++# Set up some options to make it look better
++option add *Button.borderWidth 1
++option add *Button.Pad 1
++option add *Menubutton.borderWidth 1
++option add *Menubutton.Pad 1
++option add *Entry.Background white
++
++# Array holding help strings for windows
++array set HelpData {}
++
++bind HelpWin &lt;Enter&gt; &quot;HelpWindowEntered %W&quot;
++bind HelpWin &lt;Leave&gt; &quot;HelpWindowLeft %W&quot;
++
++proc AnotherInstance {} {
++ wm deiconify .
++ raise .
++}
++
++#***********************************************************************
++# %PROCEDURE: HelpWindowEntered
++# %ARGUMENTS:
++# w -- window
++# %RETURNS:
++# Nothing
++# %DESCRIPTION:
++# Looks for procedure in HelpData; evals it if found.
++#***********************************************************************
++proc HelpWindowEntered { w } {
++ global HelpData
++ if {[info exists HelpData($w)]} {
++ set cmd &quot;$HelpData($w) Enter&quot;
++ uplevel #0 $cmd
++ }
++}
++
++#***********************************************************************
++# %PROCEDURE: HelpWindowLeft
++# %ARGUMENTS:
++# w -- window
++# %RETURNS:
++# Nothing
++# %DESCRIPTION:
++# Looks for procedure in HelpData; evals it if found.
++#***********************************************************************
++proc HelpWindowLeft { w } {
++ global HelpData
++ if {[info exists HelpData($w)]} {
++ set cmd &quot;$HelpData($w) Leave&quot;
++ uplevel #0 $cmd
++ }
++}
++
++#***********************************************************************
++# %PROCEDURE: RegisterHelpWindow
++# %ARGUMENTS:
++# w -- window we need help about
++# helptext -- the help text
++# win -- window in which to put help messages
++# %RETURNS:
++# Nothing
++# %DESCRIPTION:
++# Sets things up so help text appears in &quot;$win&quot; when mouse enters &quot;$w&quot;
++#***********************************************************************
++proc RegisterHelpWindow {w helptext win} {
++ global HelpData
++ set tags [bindtags $w]
++ if {[lsearch -exact $tags HelpWin] &lt; 0} {
++ lappend tags HelpWin
++ bindtags $w $tags
++ }
++ set HelpData($w) [list HelpInTextWin $helptext $win]
++}
++
++#***********************************************************************
++# %PROCEDURE: HelpInTextWin
++# %ARGUMENTS:
++# text -- help text
++# tw -- window in which to write text
++# what -- one of &quot;Enter&quot; or &quot;Leave&quot;
++# %RETURNS:
++# Nothing
++# %DESCRIPTION:
++# Clears out $tw; if $what is &quot;Enter&quot;, puts $text in $tw.
++#***********************************************************************
++proc HelpInTextWin {text tw what} {
++ $tw configure -state normal
++ $tw delete 1.0 end
++ if {&quot;$what&quot; == &quot;Enter&quot;} {
++ $tw insert end $text
++ }
++ $tw configure -state disabled
++}
++
++
++#***********************************************************************
++# %PROCEDURE: drawLogo
++# %ARGUMENTS:
++# c -- canvas to draw logo in
++# bg -- background color of canvas
++# pencolor -- color of the word &quot;Penguin&quot;
++# %RETURNS:
++# Nothing
++# %DESCRIPTION:
++# Draws Roaring Penguin logo in a Tcl canvas
++#***********************************************************************
++proc drawLogo { c bg {pengcolor #6699cc} } {
++ $c create polygon 372.249 5.182 361.23 5.519 \
++ 346.164 8.892 316.482 20.023 305.463 17.774 296.468 \
++ 19.573 288.935 24.97 282.864 33.177 267.348 55.102 \
++ 254.531 77.814 236.204 125.26 225.635 174.844 \
++ 221.026 226.113 213.605 228.025 208.658 232.634 \
++ 225.523 240.28 250.708 243.316 282.752 242.416 \
++ 320.079 238.818 330.985 193.17 338.181 146.735 \
++ 338.743 99.963 335.483 76.577 329.524 53.191 345.602 \
++ 48.131 353.135 45.995 359.768 41.048 342.679 43.184 \
++ 324.689 40.036 334.583 28.905 348.3 18.674 372.249 \
++ 5.182 -fill #000000 -outline {} -width 1 -tags logo
++
++ $c create line 372.249 5.182 361.23 5.519 \
++ 346.164 8.892 316.482 20.023 305.463 17.774 296.468 \
++ 19.573 288.935 24.97 282.864 33.177 267.348 55.102 \
++ 254.531 77.814 236.204 125.26 225.635 174.844 \
++ 221.026 226.113 213.605 228.025 208.658 232.634 \
++ 225.523 240.28 250.708 243.316 282.752 242.416 \
++ 320.079 238.818 330.985 193.17 338.181 146.735 \
++ 338.743 99.963 335.483 76.577 329.524 53.191 345.602 \
++ 48.131 353.135 45.995 359.768 41.048 342.679 43.184 \
++ 324.689 40.036 334.583 28.905 348.3 18.674 372.249 \
++ 5.182 -tags logo
++
++ $c create polygon 298.605 109.632 290.734 \
++ 159.328 282.752 182.939 271.958 205.65 262.851 \
++ 171.133 263.75 138.752 264.537 164.5 271.958 192.833 \
++ 286.687 157.192 298.605 109.632 -fill #ffffff \
++ -outline {} -width 1 -tags logo
++
++ $c create line 298.605 109.632 290.734 159.328 \
++ 282.752 182.939 271.958 205.65 262.851 171.133 \
++ 263.75 138.752 264.537 164.5 271.958 192.833 286.687 \
++ 157.192 298.605 109.632 -tags logo
++
++ $c create polygon 312.546 30.592 315.132 35.876 \
++ 310.747 39.586 308.161 34.414 312.546 30.592 -fill \
++ #ffffff -outline {} -width 1 -tags logo
++
++ $c create line 312.546 30.592 315.132 35.876 \
++ 310.747 39.586 308.161 34.414 312.546 30.592 -tags logo
++
++ $c create polygon 328.624 54.427 322.665 58.7 \
++ 314.458 61.286 289.16 59.15 284.55 74.665 285.338 \
++ 90.181 303.214 98.951 308.499 106.259 310.523 \
++ 116.378 305.913 130.208 312.771 141.563 308.049 \
++ 167.76 299.729 192.158 279.041 238.593 313.558 \
++ 233.871 327.388 185.75 335.033 139.989 335.82 96.253 \
++ 328.624 54.427 -fill #ffffff -outline {} -width 1 -tags logo
++
++ $c create line 328.624 54.427 322.665 58.7 \
++ 314.458 61.286 289.16 59.15 284.55 74.665 285.338 \
++ 90.181 303.214 98.951 308.499 106.259 310.523 \
++ 116.378 305.913 130.208 312.771 141.563 308.049 \
++ 167.76 299.729 192.158 279.041 238.593 313.558 \
++ 233.871 327.388 185.75 335.033 139.989 335.82 96.253 \
++ 328.624 54.427 -tags logo
++
++ $c create polygon 53.837 185.412 54.399 185.862 \
++ 53.837 188.223 54.399 188.673 53.837 188.673 53.837 \
++ 189.572 53.837 190.472 53.387 191.034 52.938 192.833 \
++ 50.577 195.644 49.677 196.656 49.677 197.105 48.215 \
++ 198.455 47.316 198.904 46.866 198.904 44.505 200.816 \
++ 43.606 200.366 42.594 201.265 42.144 201.715 41.245 \
++ 202.277 40.795 202.727 40.345 202.277 39.783 202.277 \
++ 36.972 203.177 36.522 203.177 36.073 203.177 35.623 \
++ 203.627 34.723 203.627 34.161 203.627 34.161 204.076 \
++ 30.901 204.526 28.54 205.538 26.291 205.088 25.729 \
++ 205.088 24.829 205.088 24.38 204.526 23.93 204.526 \
++ 23.48 204.526 22.918 205.088 22.918 206.437 22.918 \
++ 206.887 22.918 207.337 22.468 207.337 22.468 208.798 \
++ 22.018 209.248 22.018 211.16 22.018 211.609 21.569 \
++ 213.521 21.119 215.769 21.569 216.781 20.669 218.13 \
++ 20.669 219.592 20.669 220.042 20.107 220.941 20.107 \
++ 221.953 20.107 223.752 19.657 225.664 19.208 226.113 \
++ 19.657 227.013 18.308 230.835 17.858 240.167 17.296 \
++ 248.15 17.296 249.05 16.846 250.062 15.947 250.062 \
++ 15.048 250.062 15.048 250.511 12.686 251.86 12.237 \
++ 251.86 11.675 251.411 11.675 250.511 11.675 246.689 \
++ 11.225 245.339 11.225 243.878 10.775 240.617 11.225 \
++ 239.268 11.225 238.818 10.775 238.256 10.325 237.357 \
++ 10.325 236.007 9.876 232.634 9.876 231.735 9.876 \
++ 231.285 9.876 230.835 9.876 230.386 9.876 229.824 \
++ 9.426 229.374 9.426 226.113 9.876 226.113 9.876 \
++ 225.664 9.426 224.202 9.426 223.752 9.426 223.302 \
++ 10.325 221.953 9.426 220.941 9.426 219.592 9.426 \
++ 219.142 9.426 218.58 9.426 217.681 9.426 217.231 \
++ 9.426 216.781 8.864 216.332 8.864 214.42 8.864 \
++ 213.97 8.414 213.521 8.414 210.148 8.414 209.248 \
++ 7.964 207.899 8.414 205.988 8.414 204.526 7.065 \
++ 201.265 7.515 200.816 9.426 201.715 10.325 201.265 \
++ 10.775 200.816 10.775 198.904 11.225 198.005 11.225 \
++ 197.555 10.775 197.555 9.876 196.094 9.426 194.744 \
++ 7.515 194.295 6.615 193.845 6.053 193.845 5.153 \
++ 193.283 3.804 191.484 3.804 190.022 3.804 189.572 \
++ 3.804 189.123 3.242 188.673 3.242 186.762 3.804 \
++ 185.412 4.254 184.85 4.704 184.4 7.964 180.24 10.325 \
++ 178.779 11.225 178.779 12.237 177.879 14.036 176.98 \
++ 15.497 175.968 21.569 173.607 22.918 173.157 23.48 \
++ 173.157 24.38 172.707 24.829 172.707 29.102 171.808 \
++ 29.551 171.808 30.001 171.358 31.35 170.796 31.913 \
++ 171.358 32.362 170.796 39.783 171.358 40.345 170.796 \
++ 42.144 171.358 47.766 174.619 48.778 176.418 49.227 \
++ 176.418 49.677 176.98 50.127 176.98 51.588 178.329 \
++ 52.038 179.228 52.488 180.69 52.038 181.14 52.038 \
++ 181.59 52.488 182.039 52.938 182.039 53.387 182.601 \
++ 53.837 183.051 53.837 183.501 53.837 185.412 -fill \
++ $pengcolor -outline {} -width 1 -tags logo
++
++ $c create polygon 42.594 222.853 43.156 221.953 \
++ 41.694 222.403 39.783 224.202 39.783 224.764 39.783 \
++ 225.214 40.345 225.214 41.245 224.202 41.694 223.752 \
++ 42.594 222.853 -fill $pengcolor -outline {} -width 1 -tags logo
++
++ $c create polygon 58.559 234.096 59.009 234.096 \
++ 59.009 234.546 58.559 234.995 58.559 235.445 57.21 \
++ 236.907 56.648 237.806 52.938 241.067 52.038 241.629 \
++ 52.038 242.079 51.026 242.529 50.577 242.978 50.127 \
++ 242.978 49.227 244.44 45.405 246.239 44.055 246.689 \
++ 43.606 246.689 43.606 247.251 42.144 247.251 41.694 \
++ 247.7 40.795 247.7 38.434 248.15 36.522 248.15 \
++ 35.173 247.7 34.161 246.689 33.711 246.239 32.812 \
++ 244.44 32.362 241.629 32.812 239.718 32.812 239.268 \
++ 33.711 234.995 36.522 229.824 35.623 228.474 35.623 \
++ 227.013 36.522 225.664 37.534 224.202 38.883 222.853 \
++ 41.694 220.492 42.594 219.592 43.156 219.592 43.606 \
++ 219.142 45.405 217.681 45.967 217.681 46.416 217.231 \
++ 48.778 215.769 52.038 214.87 53.387 214.42 54.849 \
++ 214.87 55.299 214.87 56.198 215.769 56.198 217.681 \
++ 56.198 218.58 54.399 221.953 53.837 222.853 53.837 \
++ 223.302 53.387 223.752 50.577 226.113 49.677 226.563 \
++ 47.316 228.474 43.156 230.386 41.245 230.835 40.795 \
++ 230.835 40.345 230.835 39.333 230.835 38.883 230.835 \
++ 38.883 229.824 39.783 229.374 40.795 228.474 41.694 \
++ 228.025 42.594 227.575 45.967 227.013 46.866 226.563 \
++ 50.127 224.764 51.588 223.302 52.488 221.953 52.488 \
++ 220.492 52.488 219.142 51.026 218.13 49.677 218.13 \
++ 48.778 218.13 47.766 219.142 47.316 219.142 47.316 \
++ 219.592 46.866 219.592 45.967 220.941 44.505 221.953 \
++ 44.055 222.403 43.606 222.853 42.594 223.752 41.694 \
++ 225.664 41.245 225.664 41.245 226.113 40.345 226.563 \
++ 39.333 227.575 39.333 228.474 38.434 229.374 36.522 \
++ 233.197 35.623 236.457 35.623 237.357 35.623 238.256 \
++ 35.173 241.067 35.623 242.079 36.522 243.428 37.534 \
++ 243.878 37.984 244.44 38.434 244.89 38.883 244.89 \
++ 39.783 245.339 43.156 245.339 45.967 244.44 49.227 \
++ 242.529 50.127 241.629 50.577 241.067 54.399 238.818 \
++ 54.399 238.256 54.399 237.806 56.198 236.907 58.559 \
++ 234.096 -fill $pengcolor -outline {} -width 1 -tags logo
++
++ $c create polygon 92.289 248.6 92.739 249.05 \
++ 92.289 249.05 91.84 249.05 90.94 248.6 90.378 248.6 \
++ 89.478 247.7 89.029 247.251 88.129 246.689 87.117 \
++ 245.789 85.768 244.89 85.318 244.44 85.768 244.44 \
++ 85.318 242.529 84.756 242.079 84.756 240.617 84.756 \
++ 240.167 84.756 239.718 84.756 239.268 83.857 236.457 \
++ 83.407 234.096 83.407 233.197 83.407 231.735 83.407 \
++ 223.302 83.407 221.391 82.957 220.941 82.508 221.953 \
++ 80.596 226.113 80.146 226.563 80.146 227.013 79.697 \
++ 228.025 79.135 228.474 79.697 228.474 76.324 234.096 \
++ 75.874 234.995 75.424 236.457 74.975 236.457 74.975 \
++ 236.907 74.975 237.357 74.075 239.268 73.513 239.718 \
++ 73.063 240.167 72.613 241.067 72.164 242.529 71.714 \
++ 242.529 71.714 243.878 70.252 245.789 69.803 246.689 \
++ 68.903 246.689 68.903 247.251 67.891 247.7 66.542 \
++ 247.7 66.092 247.7 65.643 247.7 65.08 247.251 65.08 \
++ 246.689 65.08 245.789 64.631 242.079 65.08 242.079 \
++ 64.631 241.629 65.08 241.067 65.08 238.818 64.631 \
++ 237.806 64.631 236.457 64.631 234.546 64.631 233.197 \
++ 64.631 232.634 64.631 232.185 64.631 231.735 64.631 \
++ 228.924 64.631 227.575 64.631 225.664 64.631 225.214 \
++ 64.631 224.764 64.631 223.302 64.631 217.231 65.08 \
++ 216.332 65.643 215.769 69.803 214.87 70.252 215.32 \
++ 70.252 216.332 70.252 217.681 70.252 218.58 69.803 \
++ 219.142 69.803 220.492 69.353 220.941 69.353 221.391 \
++ 68.903 221.953 68.903 225.664 68.453 226.563 68.453 \
++ 228.025 68.453 228.474 67.891 228.924 67.891 230.835 \
++ 68.453 236.457 68.453 237.806 68.453 238.818 68.453 \
++ 240.617 68.453 241.067 68.903 241.067 68.903 241.629 \
++ 69.353 241.629 70.702 241.067 70.702 240.617 71.264 \
++ 240.167 71.264 239.268 72.164 238.256 73.063 236.457 \
++ 74.525 234.546 74.975 233.197 76.324 230.835 77.336 \
++ 229.824 78.235 227.575 78.235 227.013 78.685 226.563 \
++ 78.685 225.664 79.135 225.214 79.697 224.764 79.697 \
++ 224.202 80.146 222.403 81.046 220.941 81.945 217.681 \
++ 82.957 215.769 85.318 214.87 85.768 214.87 87.567 \
++ 214.42 87.567 215.769 87.117 216.332 87.567 216.781 \
++ 88.129 219.592 87.567 219.592 87.567 220.492 87.567 \
++ 221.391 87.567 224.764 87.567 225.664 87.567 226.113 \
++ 87.117 226.113 87.117 227.575 87.567 229.374 88.579 \
++ 235.445 89.029 239.268 89.029 239.718 89.029 241.067 \
++ 89.478 242.529 89.478 242.978 89.928 243.878 89.928 \
++ 244.44 90.378 244.89 90.94 246.239 92.289 248.6 \
++ -fill $pengcolor -outline {} -width 1 -tags logo
++
++ $c create polygon 117.587 220.492 118.037 \
++ 222.403 117.587 222.853 117.587 224.764 116.687 \
++ 226.113 116.687 227.013 116.238 228.025 114.776 \
++ 229.374 113.877 231.285 112.865 231.735 109.154 \
++ 234.995 106.343 236.457 105.444 237.357 103.982 \
++ 237.806 103.083 238.256 102.633 238.818 102.183 \
++ 238.818 101.172 239.268 99.822 239.718 98.361 \
++ 239.268 97.461 239.718 96.562 239.268 96.0 238.818 \
++ 95.55 238.818 94.201 236.907 94.201 235.445 94.201 \
++ 233.646 94.65 233.197 94.65 232.634 95.1 232.185 \
++ 95.1 231.735 95.55 231.735 96.0 230.386 97.461 \
++ 228.025 97.461 227.575 98.361 226.563 99.822 224.764 \
++ 101.172 223.302 101.172 222.853 102.633 221.391 \
++ 103.083 220.941 104.432 219.592 103.982 218.58 \
++ 103.982 217.231 103.982 216.781 103.982 215.32 \
++ 104.432 214.42 103.982 210.148 103.982 209.698 \
++ 103.982 209.248 104.432 208.798 104.432 207.899 \
++ 104.432 205.988 104.432 205.538 104.994 203.177 \
++ 104.994 202.277 104.994 201.265 104.994 200.816 \
++ 104.994 200.366 104.994 199.916 105.894 199.467 \
++ 106.343 198.904 106.793 198.455 107.243 198.904 \
++ 108.255 198.904 108.255 199.467 108.705 199.467 \
++ 108.705 202.727 108.255 204.076 108.255 205.538 \
++ 108.255 205.988 107.805 205.988 107.805 206.887 \
++ 107.805 209.698 107.243 210.71 106.793 212.059 \
++ 106.343 214.87 106.343 215.32 106.343 215.769 \
++ 105.894 217.681 106.343 217.681 106.793 217.681 \
++ 107.243 217.231 108.705 215.32 109.604 215.32 \
++ 110.054 214.42 110.054 213.97 110.616 213.97 110.616 \
++ 214.42 111.965 214.87 112.415 214.87 112.865 215.32 \
++ 114.326 216.332 116.238 217.681 116.687 218.58 \
++ 117.137 219.592 117.587 220.042 117.587 220.492 \
++ -fill $pengcolor -outline {} -width 1 -tags logo
++
++ $c create polygon 123.658 258.944 123.658 \
++ 259.394 123.658 260.293 123.658 261.755 123.658 \
++ 262.654 123.658 263.104 123.209 266.364 123.209 \
++ 267.376 122.759 269.175 122.309 269.737 121.859 \
++ 271.087 121.859 271.536 121.859 271.986 121.297 \
++ 271.986 121.297 272.548 120.847 273.448 120.398 \
++ 273.448 120.398 273.897 118.486 276.259 118.037 \
++ 276.708 117.587 277.608 117.137 278.17 116.687 \
++ 278.17 115.675 278.62 115.675 279.069 113.427 \
++ 280.419 112.865 280.981 112.415 280.981 111.965 \
++ 281.43 110.054 282.33 109.154 282.33 108.705 282.78 \
++ 108.255 282.78 107.805 283.229 104.994 283.792 \
++ 104.432 283.792 103.982 283.792 103.533 283.792 \
++ 103.083 283.792 102.633 283.792 102.183 283.792 \
++ 101.172 283.792 100.722 283.792 99.822 283.792 98.81 \
++ 283.792 96.562 282.33 96.0 282.78 95.1 281.88 94.201 \
++ 281.43 91.84 279.969 92.289 279.519 92.289 278.62 \
++ 93.751 279.069 93.751 279.519 94.201 279.519 94.65 \
++ 279.969 95.1 279.969 96.0 280.981 98.81 281.88 \
++ 101.172 281.88 101.621 281.88 102.633 281.88 103.083 \
++ 281.88 103.533 281.88 104.432 281.43 104.994 281.88 \
++ 105.444 281.43 106.793 281.43 107.805 280.981 \
++ 108.705 280.419 109.154 280.419 109.604 279.969 \
++ 110.054 279.969 110.616 279.969 111.066 279.519 \
++ 112.865 278.17 113.427 277.608 113.877 277.608 \
++ 113.877 277.158 114.326 277.158 114.326 276.708 \
++ 114.776 276.259 115.226 276.259 116.238 274.347 \
++ 116.687 274.347 116.687 273.897 117.587 272.998 \
++ 117.587 272.548 118.037 271.986 119.498 267.826 \
++ 120.398 265.015 120.398 262.204 119.948 259.843 \
++ 119.948 259.394 119.948 258.944 119.498 257.482 \
++ 118.486 254.222 118.037 253.772 117.587 251.86 \
++ 115.675 249.05 115.226 248.6 114.776 248.15 113.877 \
++ 247.251 111.965 246.239 111.515 246.239 110.616 \
++ 246.239 110.054 246.239 109.154 246.239 107.243 \
++ 247.251 106.343 247.251 105.444 247.7 104.994 247.7 \
++ 103.083 248.15 102.183 248.6 101.621 248.6 101.172 \
++ 249.05 100.722 249.499 99.822 250.062 98.361 250.062 \
++ 97.461 249.499 97.012 249.499 96.562 249.05 96.562 \
++ 248.6 97.012 248.15 99.822 245.789 100.272 245.339 \
++ 101.621 244.44 101.621 243.878 102.183 243.428 \
++ 102.633 243.428 102.633 242.978 103.982 241.629 \
++ 103.982 241.067 103.982 240.617 103.982 240.167 \
++ 105.444 239.268 108.705 236.907 108.705 236.457 \
++ 109.154 236.457 110.054 235.445 111.066 234.546 \
++ 112.415 234.096 112.865 233.646 113.427 233.646 \
++ 113.877 233.646 113.877 234.096 114.326 234.995 \
++ 114.776 235.445 114.776 236.457 114.326 237.357 \
++ 113.427 238.818 112.415 239.268 112.415 240.167 \
++ 111.965 240.167 111.515 240.617 110.054 241.629 \
++ 110.054 242.079 109.604 242.529 108.705 242.978 \
++ 110.054 242.978 113.427 242.079 114.326 242.529 \
++ 115.226 242.978 116.687 244.44 119.048 246.689 \
++ 119.498 247.7 119.498 248.15 119.948 248.6 119.948 \
++ 249.05 120.398 249.05 120.398 249.499 120.847 \
++ 249.499 120.847 250.062 121.297 250.511 121.297 \
++ 251.411 121.859 252.31 122.759 252.872 122.759 \
++ 254.222 122.759 254.671 123.658 258.494 123.658 \
++ 258.944 -fill $pengcolor -outline {} -width 1 -tags logo
++
++ $c create polygon 147.607 215.769 148.506 215.32 \
++ 148.506 217.231 148.506 217.681 148.506 218.13 \
++ 148.956 218.58 148.506 220.492 148.506 220.941 \
++ 148.506 222.853 148.956 224.764 148.956 226.113 \
++ 148.506 226.563 148.956 226.563 148.506 228.924 \
++ 148.956 229.824 148.956 231.285 148.506 232.185 \
++ 148.956 232.634 148.956 233.646 149.405 234.995 \
++ 148.956 234.995 149.405 235.445 149.405 236.907 \
++ 149.405 237.357 149.968 238.818 150.867 240.167 \
++ 150.867 240.617 151.317 242.079 152.216 243.428 \
++ 153.228 245.339 154.128 245.789 155.027 246.239 \
++ 156.939 245.789 157.388 246.239 156.489 246.689 \
++ 155.027 247.7 154.128 247.7 153.228 247.7 152.216 \
++ 247.7 151.767 247.7 150.867 247.251 150.417 246.239 \
++ 149.405 246.239 148.056 245.339 147.607 244.44 \
++ 147.157 243.428 145.695 241.629 145.695 240.617 \
++ 145.245 240.167 145.245 239.718 144.796 238.256 \
++ 144.346 236.907 144.346 235.445 143.784 234.546 \
++ 143.784 233.197 143.784 232.185 143.784 230.835 \
++ 143.334 229.824 143.784 229.374 143.334 229.374 \
++ 143.334 228.474 142.884 230.386 141.985 231.735 \
++ 140.973 233.197 140.523 234.096 140.523 234.546 \
++ 140.523 234.995 139.624 236.457 139.174 237.806 \
++ 138.162 239.718 137.263 241.067 136.813 242.079 \
++ 135.913 242.978 134.452 244.89 134.002 245.789 \
++ 133.552 245.789 132.091 246.689 131.191 247.251 \
++ 129.73 248.15 129.28 248.15 128.38 247.7 128.38 \
++ 248.15 126.919 247.7 126.019 247.251 125.12 246.239 \
++ 125.12 245.339 124.67 244.89 124.67 244.44 124.67 \
++ 243.428 124.67 242.529 124.67 241.067 124.67 239.718 \
++ 125.12 239.268 124.67 239.268 124.67 238.256 125.12 \
++ 237.806 125.12 237.357 125.12 236.907 125.12 236.007 \
++ 125.12 234.096 125.57 233.197 125.57 232.185 126.019 \
++ 232.185 126.019 231.285 126.019 230.386 126.019 \
++ 229.374 126.469 228.474 126.469 227.013 126.469 \
++ 225.214 126.019 225.214 126.469 225.214 126.019 \
++ 223.302 126.019 221.953 126.019 220.492 125.57 \
++ 220.042 125.12 219.592 124.108 219.142 123.209 \
++ 219.142 121.859 220.042 121.297 220.042 120.398 \
++ 220.941 119.498 221.391 119.048 221.391 118.486 \
++ 221.953 118.037 221.953 118.037 221.391 118.486 \
++ 220.941 119.498 220.042 120.847 219.142 122.759 \
++ 217.681 124.108 216.781 125.12 215.769 126.469 \
++ 214.87 126.919 214.87 127.481 214.87 128.38 214.87 \
++ 128.83 214.87 129.73 214.87 129.73 215.769 130.292 \
++ 215.769 130.742 216.781 130.742 217.681 130.292 \
++ 219.142 130.292 221.953 130.292 223.302 130.292 \
++ 224.202 129.73 225.214 129.28 227.013 128.83 227.575 \
++ 129.28 227.575 129.28 228.474 128.83 229.374 129.28 \
++ 229.824 129.28 230.386 128.83 231.735 128.38 234.096 \
++ 128.38 234.995 127.931 236.457 127.931 239.268 \
++ 127.931 240.167 127.931 241.629 128.83 242.978 \
++ 129.28 243.878 129.73 244.44 130.742 244.44 131.191 \
++ 244.44 132.091 244.44 133.103 243.878 134.002 \
++ 242.978 134.902 242.079 135.351 241.067 135.913 \
++ 240.167 136.363 239.268 136.813 238.818 137.263 \
++ 237.806 137.712 236.907 138.162 235.445 138.724 \
++ 234.546 139.174 233.646 139.624 232.634 140.523 \
++ 230.835 140.973 228.924 141.535 227.013 142.435 \
++ 225.664 142.884 223.302 143.334 221.391 143.334 \
++ 220.941 143.334 219.142 144.346 217.681 144.796 \
++ 216.781 145.695 216.332 146.595 216.332 147.607 \
++ 215.769 -fill $pengcolor -outline {} -width 1 -tags logo
++
++ $c create polygon 165.371 241.067 165.371 \
++ 241.067 164.921 243.878 164.921 246.239 163.46 \
++ 246.689 161.211 247.251 160.649 247.251 160.199 \
++ 244.44 160.199 243.878 160.199 243.428 160.199 \
++ 242.079 160.199 240.167 160.199 239.718 159.749 \
++ 239.268 160.199 237.806 159.749 237.357 159.749 \
++ 236.007 159.749 230.835 159.749 229.824 159.749 \
++ 228.924 159.749 226.113 159.749 225.664 159.749 \
++ 223.752 159.749 222.853 159.749 218.58 159.749 \
++ 218.13 159.749 217.681 160.199 217.231 161.661 \
++ 216.781 162.11 216.781 162.56 216.781 163.46 216.781 \
++ 164.022 219.142 163.46 222.403 163.46 222.853 163.46 \
++ 224.202 163.46 225.664 163.46 226.563 163.46 227.013 \
++ 163.46 228.924 163.01 230.835 163.01 232.634 163.46 \
++ 233.197 164.022 232.634 164.472 232.634 164.921 \
++ 232.185 164.921 231.735 165.371 231.735 165.821 \
++ 232.185 165.371 233.646 165.821 236.007 165.371 \
++ 238.256 165.371 238.818 165.371 240.617 165.371 \
++ 241.067 -fill $pengcolor -outline {} -width 1 -tags logo
++
++ $c create polygon 165.821 214.42 166.833 215.32 \
++ 166.271 215.32 165.821 216.332 165.371 216.332 \
++ 165.371 216.781 165.821 217.681 165.821 218.13 \
++ 165.371 219.142 165.371 220.042 164.921 222.853 \
++ 165.371 224.764 164.921 225.664 165.371 227.575 \
++ 165.371 228.474 164.921 228.474 164.472 227.575 \
++ 164.472 226.113 164.022 224.764 164.472 224.202 \
++ 164.472 223.752 164.472 222.403 164.921 214.87 \
++ 164.472 213.521 164.472 212.959 164.472 212.509 \
++ 164.022 212.509 163.46 212.509 163.01 212.959 162.56 \
++ 212.959 161.661 212.959 161.211 212.059 161.211 \
++ 211.609 160.649 211.609 160.199 209.698 160.649 \
++ 208.349 163.46 206.437 164.472 206.437 165.821 \
++ 207.899 165.821 208.349 166.833 210.148 166.833 \
++ 210.71 165.821 211.609 165.371 212.059 165.371 \
++ 212.959 165.821 213.97 165.821 214.42 -fill $pengcolor \
++ -outline {} -width 1 -tags logo
++
++ $c create polygon 201.462 248.6 201.462 249.05 \
++ 201.012 249.05 200.563 249.05 200.001 248.6 199.551 \
++ 248.6 198.651 247.7 197.752 247.251 196.74 246.689 \
++ 196.29 245.789 194.379 244.89 194.379 244.44 194.379 \
++ 242.529 193.929 242.079 193.479 240.617 193.479 \
++ 240.167 193.929 239.718 193.479 239.268 193.03 \
++ 236.457 192.58 234.096 192.58 233.197 192.58 231.735 \
++ 192.58 223.302 192.58 221.391 192.13 220.941 191.568 \
++ 221.953 189.769 226.113 189.319 226.563 189.319 \
++ 227.013 188.757 228.025 188.307 228.474 188.757 \
++ 228.474 185.497 234.096 185.047 234.995 184.597 \
++ 236.457 184.147 236.457 184.147 236.907 184.147 \
++ 237.357 183.136 239.268 182.686 239.268 182.686 \
++ 239.718 182.236 240.167 181.786 241.067 181.337 \
++ 242.529 180.887 242.529 180.887 243.878 179.425 \
++ 245.789 178.975 246.689 178.076 246.689 178.076 \
++ 247.251 177.064 247.7 175.715 247.7 175.265 247.7 \
++ 174.703 247.7 174.253 247.251 174.253 246.689 \
++ 174.253 245.789 173.804 242.079 174.253 242.079 \
++ 173.804 241.629 173.804 241.067 173.804 238.818 \
++ 173.804 237.806 173.804 236.457 173.354 234.546 \
++ 173.354 233.197 173.804 232.634 173.804 232.185 \
++ 173.804 231.735 173.804 228.924 173.354 227.575 \
++ 173.804 227.575 173.804 225.664 173.804 225.214 \
++ 173.804 224.764 173.804 223.302 173.804 217.231 \
++ 174.253 216.332 174.703 215.769 178.526 214.87 \
++ 179.425 215.32 179.425 216.332 179.425 217.681 \
++ 179.425 218.58 178.975 219.142 178.526 220.492 \
++ 178.526 220.941 178.076 221.391 178.076 221.953 \
++ 178.076 225.664 177.514 226.563 177.514 228.025 \
++ 177.064 228.474 177.064 228.924 177.064 230.835 \
++ 177.514 236.457 177.064 237.806 177.514 237.806 \
++ 177.514 238.818 177.514 240.617 177.514 241.067 \
++ 178.076 241.629 178.526 241.629 179.425 241.067 \
++ 179.875 240.617 179.875 240.167 180.325 239.268 \
++ 181.337 238.256 182.236 236.457 183.698 234.546 \
++ 184.147 233.197 185.497 230.835 186.509 229.824 \
++ 187.408 227.575 187.408 227.013 187.408 226.563 \
++ 187.858 225.664 188.307 225.214 188.757 224.764 \
++ 188.757 224.202 189.319 222.403 190.219 220.941 \
++ 191.118 217.681 192.13 215.769 194.379 214.87 \
++ 194.941 214.87 196.74 214.42 196.74 215.769 196.29 \
++ 215.769 196.29 216.332 196.29 216.781 196.74 219.592 \
++ 196.74 220.492 196.29 221.391 196.74 224.764 196.29 \
++ 225.664 196.29 226.113 196.29 227.575 196.74 229.374 \
++ 197.19 235.445 198.202 239.268 198.202 239.718 \
++ 198.202 241.067 198.202 242.529 198.651 242.978 \
++ 199.101 243.878 199.101 244.44 199.551 244.89 \
++ 200.001 246.239 201.462 248.6 -fill $pengcolor -outline \
++ {} -width 1 -tags logo
++
++ $c create polygon 71.714 185.412 71.714 110.869 \
++ 81.496 110.869 82.845 110.981 83.969 111.431 85.094 \
++ 112.106 86.105 113.118 86.893 114.467 87.567 116.041 \
++ 88.017 117.39 88.242 118.065 88.467 118.852 88.579 \
++ 119.639 88.804 120.538 88.916 121.438 89.029 122.337 \
++ 89.141 123.349 89.254 124.361 89.366 125.485 89.366 \
++ 126.61 89.478 127.734 89.478 128.971 89.478 130.208 \
++ 89.478 131.444 89.478 132.456 89.478 133.468 89.478 \
++ 134.48 89.366 135.492 89.254 136.391 89.254 137.291 \
++ 89.141 138.19 89.029 139.09 88.916 139.877 88.804 \
++ 140.664 88.691 141.451 88.579 142.238 88.354 143.362 \
++ 88.129 144.374 87.904 145.386 87.567 146.398 87.342 \
++ 147.297 87.005 148.197 86.668 148.984 86.218 149.771 \
++ 87.005 151.233 87.342 152.02 87.68 152.919 87.904 \
++ 153.931 88.129 154.943 88.129 155.505 88.354 156.854 \
++ 88.354 157.641 88.354 158.428 88.467 159.328 88.467 \
++ 160.34 88.467 161.352 88.467 162.476 88.579 163.6 \
++ 88.579 164.837 88.579 166.186 88.579 166.973 88.691 \
++ 167.873 88.804 168.885 88.916 169.897 89.029 171.021 \
++ 89.029 172.258 89.029 173.719 89.029 175.068 89.029 \
++ 176.305 89.029 177.542 89.141 178.554 89.141 179.566 \
++ 89.141 180.353 89.141 181.14 89.254 181.814 89.366 \
++ 182.714 89.478 183.051 89.478 185.412 83.857 185.412 \
++ 83.857 184.738 83.744 183.951 83.744 183.276 83.744 \
++ 182.489 83.744 180.803 83.857 179.791 83.857 178.891 \
++ 83.857 177.879 83.857 176.867 83.857 175.743 83.857 \
++ 174.619 83.857 173.27 83.857 172.033 83.744 170.908 \
++ 83.744 170.009 83.632 169.109 83.632 168.322 83.52 \
++ 166.973 83.407 166.524 83.407 166.186 83.407 165.062 \
++ 83.407 164.05 83.295 163.151 83.295 162.251 83.295 \
++ 161.464 83.182 160.789 82.957 159.553 81.945 158.203 \
++ 80.596 157.754 76.886 157.754 76.886 185.412 71.714 \
++ 185.412 -fill #000000 -outline {} -width 1 -tags logo
++
++ $c create polygon 92.289 148.309 92.289 147.185 \
++ 92.289 146.061 92.289 145.049 92.402 143.924 92.402 \
++ 142.8 92.402 141.788 92.402 140.664 92.514 139.652 \
++ 92.514 138.64 92.627 137.628 92.627 136.616 92.739 \
++ 135.717 92.739 134.705 92.851 133.805 92.964 132.793 \
++ 92.964 131.894 93.076 130.995 93.301 129.196 93.414 \
++ 128.409 93.526 127.509 93.639 126.722 93.751 125.935 \
++ 93.863 125.148 93.976 124.361 94.313 122.787 94.426 \
++ 122.112 94.65 121.325 94.763 120.651 95.1 119.301 \
++ 95.55 117.615 96.112 116.041 96.674 114.692 97.236 \
++ 113.455 97.799 112.443 98.361 111.544 99.035 110.757 \
++ 99.71 110.082 100.385 109.632 101.059 109.295 \
++ 101.846 109.07 102.633 108.958 104.207 109.295 \
++ 104.882 109.632 105.556 110.082 106.231 110.757 \
++ 106.906 111.544 107.468 112.443 108.03 113.455 \
++ 108.592 114.692 109.154 116.041 109.604 117.615 \
++ 110.054 119.301 110.279 119.976 110.616 121.325 \
++ 110.841 122.112 110.953 122.787 111.178 123.574 \
++ 111.403 125.148 111.628 125.935 111.74 126.722 \
++ 111.853 127.622 111.965 128.409 112.078 129.308 \
++ 112.19 130.208 112.302 130.995 112.415 132.006 \
++ 112.64 133.805 112.752 134.817 112.865 135.717 \
++ 112.977 136.729 112.977 137.741 113.089 138.752 \
++ 113.089 139.764 113.202 140.776 113.202 141.788 \
++ 113.314 142.912 113.314 143.924 113.314 145.049 \
++ 113.427 146.061 113.427 147.185 113.427 148.309 \
++ 113.427 149.546 113.314 150.783 113.314 151.907 \
++ 113.314 153.032 113.314 154.156 113.202 155.28 \
++ 113.202 156.405 113.089 157.529 113.089 158.541 \
++ 112.977 159.553 112.865 160.565 112.752 161.576 \
++ 112.64 162.588 112.527 163.6 112.415 164.5 112.302 \
++ 165.512 112.19 166.411 112.078 167.311 111.965 \
++ 168.21 111.853 169.109 111.628 169.897 111.515 \
++ 170.796 111.403 171.583 111.178 172.37 111.066 \
++ 173.157 110.616 174.731 110.504 175.518 110.279 \
++ 176.193 110.054 176.98 109.604 178.666 109.154 \
++ 180.128 108.592 181.59 108.03 182.826 107.468 \
++ 183.951 106.906 184.963 106.231 185.75 105.556 \
++ 186.424 104.882 186.986 104.207 187.436 103.42 \
++ 187.661 102.633 187.661 101.846 187.661 101.059 \
++ 187.436 100.385 186.986 99.71 186.424 99.035 185.75 \
++ 98.361 184.963 97.799 183.951 97.236 182.826 96.674 \
++ 181.59 96.112 180.128 95.55 178.666 95.1 176.98 \
++ 94.988 176.193 94.763 175.518 94.538 174.731 94.426 \
++ 173.944 94.088 172.37 93.976 171.583 93.863 170.796 \
++ 93.639 169.897 93.526 169.109 93.414 168.21 93.301 \
++ 167.311 93.189 166.411 93.076 165.512 92.964 164.5 \
++ 92.964 163.6 92.851 162.588 92.739 161.576 92.627 \
++ 160.565 92.627 159.553 92.514 158.541 92.514 157.529 \
++ 92.514 156.405 92.402 155.28 92.402 154.156 92.402 \
++ 153.032 92.289 151.907 92.289 150.783 92.289 149.546 \
++ 92.289 148.309 -fill #000000 -outline {} -width 1 -tags logo
++
++ $c create polygon 121.859 110.869 127.481 \
++ 110.869 134.902 185.412 129.28 185.412 127.931 \
++ 171.808 120.847 171.808 119.948 185.412 114.326 \
++ 185.412 121.859 110.869 -fill #000000 -outline {} \
++ -width 1 -tags logo
++
++ $c create polygon 137.263 185.412 137.263 \
++ 110.869 147.157 110.869 148.394 110.981 149.518 \
++ 111.431 150.417 112.106 151.317 113.118 152.104 \
++ 114.467 152.778 116.041 153.228 117.39 153.341 \
++ 118.065 153.566 118.852 153.903 120.538 154.015 \
++ 121.438 154.128 122.337 154.24 123.349 154.353 \
++ 124.361 154.465 125.485 154.465 126.61 154.577 \
++ 127.734 154.577 128.971 154.577 130.208 154.577 \
++ 131.444 154.577 132.456 154.577 133.468 154.577 \
++ 134.48 154.577 135.492 154.577 136.391 154.577 \
++ 137.291 154.577 138.19 154.465 139.09 154.465 \
++ 139.877 154.353 140.664 154.24 141.451 154.128 \
++ 142.238 153.903 143.362 153.678 144.374 153.341 \
++ 145.386 153.003 146.398 152.554 147.297 152.216 \
++ 148.197 151.767 148.984 151.317 149.771 152.104 \
++ 151.233 152.441 152.02 152.778 152.919 153.003 \
++ 153.931 153.228 154.943 153.341 155.505 153.453 \
++ 156.854 153.566 157.641 153.678 158.428 153.79 \
++ 159.328 153.903 160.34 154.015 161.352 154.015 \
++ 162.476 154.128 163.6 154.128 164.837 154.128 \
++ 166.186 154.128 166.973 154.128 167.873 154.128 \
++ 168.885 154.128 169.897 154.128 171.021 154.128 \
++ 172.258 154.128 173.719 154.24 175.068 154.24 \
++ 176.305 154.353 177.542 154.353 178.554 154.465 \
++ 179.566 154.577 180.353 154.69 181.14 154.69 181.814 \
++ 154.915 182.714 155.027 183.051 155.027 185.412 \
++ 149.405 185.412 149.405 184.738 149.293 183.951 \
++ 149.293 183.276 149.181 182.489 149.181 180.803 \
++ 149.068 179.791 149.068 178.891 149.068 177.879 \
++ 149.068 176.867 148.956 175.743 148.956 174.619 \
++ 148.956 173.27 148.956 172.033 148.956 170.908 \
++ 148.956 170.009 148.956 169.109 148.956 168.322 \
++ 148.956 166.973 148.956 166.524 148.956 166.186 \
++ 148.956 165.062 148.843 164.05 148.731 163.151 \
++ 148.618 162.251 148.506 161.464 148.394 160.789 \
++ 148.056 159.553 147.269 158.203 146.145 157.754 \
++ 142.435 157.754 142.435 185.412 137.263 185.412 \
++ -fill #000000 -outline {} -width 1 -tags logo
++
++ $c create polygon 158.4 185.412 158.4 110.869 \
++ 164.022 110.869 164.022 185.412 158.4 185.412 -fill \
++ #000000 -outline {} -width 1 -tags logo
++
++ $c create polygon 168.182 185.412 168.182 \
++ 110.869 173.804 110.869 177.514 135.267 177.739 \
++ 136.054 177.851 136.954 177.964 137.853 178.076 \
++ 138.752 178.301 139.539 178.413 140.439 178.526 \
++ 141.338 178.751 143.137 178.975 144.037 179.088 \
++ 144.824 179.2 145.723 179.313 146.623 179.425 147.41 \
++ 179.538 148.422 179.763 149.321 179.875 150.333 \
++ 180.1 151.233 180.212 152.132 180.437 153.032 180.55 \
++ 154.043 180.774 154.943 180.887 155.842 180.999 \
++ 156.742 181.224 157.754 181.337 158.653 181.337 \
++ 157.641 181.224 156.629 181.224 155.617 181.224 \
++ 154.606 181.224 153.594 181.112 152.582 181.112 \
++ 151.682 181.112 150.67 180.999 149.771 180.999 \
++ 148.759 180.999 147.86 180.887 146.96 180.887 \
++ 145.948 180.887 145.049 180.887 144.149 180.887 \
++ 143.25 180.887 142.125 180.887 141.114 180.887 \
++ 140.102 180.887 139.09 180.887 138.078 180.887 \
++ 137.178 180.887 136.166 180.887 135.267 180.887 \
++ 134.368 180.887 133.468 180.887 132.569 180.887 \
++ 131.669 180.887 130.882 180.887 130.095 180.887 \
++ 110.869 185.946 110.869 185.946 185.412 180.325 \
++ 185.412 176.165 160.565 176.052 159.778 175.94 \
++ 158.99 175.827 158.203 175.602 156.517 175.49 \
++ 155.617 175.378 154.718 175.265 153.931 175.153 \
++ 153.032 175.04 152.02 174.928 151.12 174.703 150.221 \
++ 174.591 149.321 174.478 148.422 174.366 147.41 \
++ 174.141 146.51 174.028 145.611 173.804 144.599 \
++ 173.691 143.587 173.579 142.575 173.354 141.676 \
++ 173.241 140.551 173.017 139.539 172.904 138.528 \
++ 172.904 139.539 172.904 140.551 173.017 141.563 \
++ 173.017 142.575 173.017 143.587 173.129 144.599 \
++ 173.129 145.498 173.129 146.51 173.241 147.41 \
++ 173.241 148.422 173.241 149.321 173.354 150.221 \
++ 173.354 151.233 173.354 152.132 173.354 153.144 \
++ 173.354 154.156 173.354 155.055 173.354 156.067 \
++ 173.354 156.967 173.354 157.866 173.354 158.766 \
++ 173.354 159.553 173.354 160.452 173.354 161.239 \
++ 173.354 162.026 173.354 162.926 173.354 185.412 \
++ 168.182 185.412 -fill #000000 -outline {} -width 1 -tags logo
++
++ $c create polygon 206.184 185.412 205.622 \
++ 175.968 205.397 177.092 205.172 178.217 204.948 \
++ 179.228 204.61 180.128 204.385 181.027 204.048 \
++ 181.814 203.823 182.489 203.486 183.164 203.149 \
++ 183.838 202.811 184.4 202.024 185.75 201.125 186.762 \
++ 200.113 187.436 199.101 187.661 198.089 187.549 \
++ 197.19 186.986 196.29 186.087 195.391 184.85 194.941 \
++ 184.176 194.491 183.389 194.042 182.489 193.592 \
++ 181.477 193.255 180.465 192.805 179.341 192.467 \
++ 178.217 192.13 176.98 191.905 176.193 191.68 175.406 \
++ 191.568 174.619 191.456 173.832 191.231 172.932 \
++ 191.118 172.145 191.006 171.246 190.781 169.559 \
++ 190.669 168.66 190.556 167.648 190.444 166.748 \
++ 190.331 165.736 190.219 164.725 190.106 163.825 \
++ 189.994 162.926 189.994 162.026 189.882 161.127 \
++ 189.769 160.227 189.769 159.215 189.657 158.316 \
++ 189.544 157.304 189.544 156.405 189.432 155.393 \
++ 189.432 154.381 189.319 153.369 189.319 152.357 \
++ 189.319 151.345 189.319 150.333 189.319 149.321 \
++ 189.319 148.197 189.319 146.96 189.319 145.948 \
++ 189.319 144.824 189.319 143.7 189.319 142.688 \
++ 189.432 141.563 189.432 140.551 189.544 139.539 \
++ 189.544 138.528 189.544 137.516 189.657 136.504 \
++ 189.769 135.492 189.769 134.592 189.882 133.581 \
++ 189.994 132.681 189.994 131.782 190.106 130.882 \
++ 190.219 129.983 190.331 129.083 190.556 127.397 \
++ 190.669 126.61 190.781 125.823 191.006 124.923 \
++ 191.118 124.136 191.231 123.462 191.568 121.887 \
++ 191.793 121.213 191.905 120.426 192.13 119.751 \
++ 192.58 117.952 193.142 116.378 193.704 114.917 \
++ 194.266 113.567 194.941 112.443 195.616 111.431 \
++ 196.29 110.532 196.965 109.857 197.752 109.295 \
++ 198.426 108.845 199.214 108.62 200.001 108.508 \
++ 201.799 108.958 202.699 109.407 203.374 110.194 \
++ 204.161 111.094 204.835 112.218 205.51 113.567 \
++ 206.184 115.141 206.634 116.491 206.859 117.165 \
++ 206.971 117.952 207.421 119.526 207.534 120.426 \
++ 207.758 121.325 207.871 122.225 207.983 123.124 \
++ 208.096 124.136 208.208 125.036 208.321 126.047 \
++ 208.433 127.172 208.545 128.184 208.658 129.308 \
++ 208.77 130.32 208.77 131.557 208.883 132.681 208.995 \
++ 133.805 204.273 133.805 204.161 132.681 203.936 \
++ 131.557 203.711 130.432 203.486 129.533 203.261 \
++ 128.633 202.924 127.734 202.699 126.947 202.362 \
++ 126.385 201.35 124.586 200.001 124.024 199.438 \
++ 124.136 198.989 124.361 198.426 124.923 197.977 \
++ 125.598 197.527 126.497 197.077 127.622 196.628 \
++ 128.971 196.29 130.545 196.178 131.219 195.953 \
++ 132.681 195.84 133.356 195.728 134.143 195.616 \
++ 134.93 195.503 135.829 195.278 137.516 195.278 \
++ 138.303 195.166 139.315 195.166 140.214 195.053 \
++ 141.114 195.053 142.125 194.941 143.137 194.941 \
++ 144.149 194.941 145.161 194.941 146.173 194.941 \
++ 147.297 194.941 148.309 194.941 149.546 194.941 \
++ 150.67 194.941 151.907 194.941 152.919 195.053 \
++ 154.043 195.053 155.168 195.166 156.18 195.166 \
++ 157.192 195.278 158.091 195.391 159.103 195.391 \
++ 160.002 195.503 160.902 195.616 161.801 195.728 \
++ 162.588 195.84 163.375 196.065 164.162 196.178 \
++ 164.949 196.29 165.736 196.628 167.198 197.077 \
++ 168.547 197.527 169.672 197.977 170.571 198.426 \
++ 171.246 198.989 171.808 199.438 172.145 200.001 \
++ 172.258 200.9 171.92 201.575 171.246 202.249 170.009 \
++ 202.811 168.547 203.149 167.76 203.374 166.973 \
++ 203.598 166.186 203.823 165.399 204.048 164.5 \
++ 204.273 163.488 204.385 162.476 204.498 161.464 \
++ 204.61 160.34 204.723 159.103 200.001 159.103 \
++ 200.001 145.049 209.445 145.049 209.445 185.412 \
++ 206.184 185.412 -fill #000000 -outline {} -width 1 -tags logo
++
++ $c create polygon 148.506 261.305 148.506 \
++ 263.554 143.784 263.554 143.784 261.305 143.671 \
++ 260.068 143.334 259.394 142.772 259.056 141.985 \
++ 258.944 141.085 259.056 140.523 259.394 140.074 \
++ 261.755 140.074 263.104 140.523 264.678 141.085 \
++ 265.465 141.985 266.364 146.145 270.637 147.607 \
++ 271.874 148.506 272.998 148.843 274.01 148.956 \
++ 275.359 148.956 277.158 148.843 278.507 148.506 \
++ 279.632 147.944 280.643 147.157 281.43 146.482 \
++ 281.88 145.695 282.218 144.796 282.442 143.784 \
++ 282.667 142.659 282.78 141.535 282.78 140.298 282.78 \
++ 139.286 282.78 138.387 282.667 137.6 282.442 136.925 \
++ 282.218 136.363 281.88 135.576 281.093 135.014 \
++ 280.194 134.564 278.957 134.452 277.608 134.452 \
++ 275.359 139.624 275.359 139.624 277.608 139.736 \
++ 279.069 140.074 279.969 141.535 280.419 142.659 \
++ 280.081 143.334 279.519 143.671 278.62 143.784 \
++ 277.158 143.784 275.809 143.671 275.022 143.334 \
++ 274.235 142.772 273.448 141.985 272.548 137.263 \
++ 267.376 136.251 266.364 135.351 265.465 135.014 \
++ 264.565 134.902 263.554 134.902 261.755 135.014 \
++ 260.518 135.464 259.506 136.026 258.719 136.813 \
++ 257.932 137.488 257.595 138.275 257.145 139.174 \
++ 256.92 140.186 256.695 141.31 256.583 142.435 \
++ 256.583 143.447 256.583 144.458 256.583 145.245 \
++ 256.695 145.92 256.92 147.157 257.482 147.719 \
++ 258.157 148.169 258.944 148.394 260.068 148.506 \
++ 261.305 -fill #000000 -outline {} -width 1 -tags logo
++
++ $c create polygon 165.821 270.187 165.821 \
++ 276.708 165.821 277.833 165.708 278.957 165.483 \
++ 279.856 165.259 280.643 164.921 281.318 164.472 \
++ 281.88 163.909 282.218 163.235 282.555 162.448 \
++ 282.667 161.548 282.78 160.536 282.78 159.3 282.78 \
++ 158.175 282.78 157.051 282.78 156.151 282.667 \
++ 155.364 282.555 154.69 282.218 154.128 281.88 \
++ 153.678 281.318 153.341 280.643 153.116 279.856 \
++ 152.891 278.845 152.778 277.833 152.778 276.708 \
++ 152.778 270.187 152.778 269.063 152.891 268.051 \
++ 153.116 267.264 153.341 266.589 154.128 265.465 \
++ 155.364 264.678 156.151 264.453 157.051 264.228 \
++ 158.063 264.116 159.3 264.116 160.424 264.116 \
++ 161.548 264.228 162.448 264.453 163.235 264.678 \
++ 163.909 265.015 164.472 265.465 164.921 265.915 \
++ 165.483 267.264 165.708 268.051 165.821 269.063 \
++ 165.821 270.187 -fill #000000 -outline {} -width 1 -tags logo
++
++ $c create polygon 177.514 256.583 177.514 \
++ 258.494 177.064 258.494 176.165 258.606 175.715 \
++ 258.944 175.378 259.281 175.265 259.843 175.265 \
++ 264.565 177.514 264.565 177.514 266.927 175.265 \
++ 266.927 175.265 282.78 170.543 282.78 170.543 \
++ 266.927 168.632 266.927 168.632 264.565 170.543 \
++ 264.565 170.543 261.305 170.655 259.843 170.993 \
++ 258.606 171.442 257.707 171.892 257.032 173.579 \
++ 256.358 174.703 256.133 176.165 256.133 176.727 \
++ 256.133 177.064 256.133 177.514 256.583 -fill \
++ #000000 -outline {} -width 1 -tags logo
++
++ $c create polygon 185.946 259.843 185.946 \
++ 264.565 188.757 264.565 188.757 266.927 185.946 \
++ 266.927 185.946 278.62 186.171 279.407 186.509 \
++ 279.969 187.071 280.306 187.858 280.419 188.307 \
++ 280.419 188.757 280.419 188.757 282.78 188.645 \
++ 282.78 188.307 282.78 187.183 282.78 186.509 282.78 \
++ 185.159 282.78 183.923 282.555 182.911 282.33 \
++ 182.236 281.88 181.786 281.206 181.561 280.419 \
++ 181.337 279.407 181.337 278.17 181.337 266.927 \
++ 179.425 266.927 179.425 264.565 181.337 264.565 \
++ 181.337 261.305 185.946 259.843 -fill #000000 \
++ -outline {} -width 1 -tags logo
++
++ $c create polygon 190.219 264.565 194.379 \
++ 264.565 196.29 279.519 196.74 279.519 199.101 \
++ 264.565 204.723 264.565 207.084 279.519 207.534 \
++ 279.519 209.895 264.565 213.605 264.565 209.895 \
++ 282.78 204.723 282.78 201.912 267.376 201.462 \
++ 267.376 199.101 282.78 193.479 282.78 190.219 \
++ 264.565 -fill #000000 -outline {} -width 1 -tags logo
++
++ $c create polygon 229.121 269.175 229.121 282.78 \
++ 224.848 282.78 224.848 280.981 224.061 281.768 \
++ 223.049 282.33 221.925 282.667 220.688 282.78 \
++ 219.564 282.78 218.44 282.555 217.54 282.33 216.866 \
++ 281.88 216.528 281.318 216.191 280.531 216.079 \
++ 279.632 215.966 278.62 215.966 275.359 216.079 \
++ 274.347 216.978 272.998 217.877 272.548 218.44 \
++ 272.211 219.114 271.986 219.789 271.761 220.688 \
++ 271.536 221.588 271.424 222.6 271.311 223.724 \
++ 271.199 224.848 271.087 224.848 269.175 224.736 \
++ 267.826 224.399 266.927 223.612 266.477 222.487 \
++ 266.364 221.7 266.477 221.138 266.927 220.688 \
++ 268.726 220.688 269.175 216.416 269.175 216.528 \
++ 267.938 216.753 266.702 217.203 265.69 217.877 \
++ 265.015 218.44 264.678 219.114 264.453 219.901 \
++ 264.228 220.801 264.116 221.925 264.116 223.049 \
++ 264.116 224.061 264.116 225.073 264.116 225.86 \
++ 264.228 226.535 264.453 227.659 265.015 228.334 \
++ 265.69 228.783 266.702 229.008 267.938 229.121 \
++ 269.175 -fill #000000 -outline {} -width 1 -tags logo
++
++ $c create polygon 243.175 264.565 243.175 \
++ 266.927 242.725 266.927 241.601 266.927 240.701 \
++ 267.151 239.914 267.489 239.352 267.826 239.015 \
++ 268.276 238.678 268.95 238.565 269.737 238.453 \
++ 270.637 238.453 282.78 233.731 282.78 233.731 \
++ 264.565 238.453 264.565 238.453 265.915 239.352 \
++ 265.128 240.364 264.565 242.163 264.116 242.725 \
++ 264.565 243.175 264.565 -fill #000000 -outline {} \
++ -width 1 -tags logo
++
++ $c create polygon 258.129 270.187 258.129 \
++ 274.347 249.696 274.347 249.696 278.17 249.809 \
++ 279.294 250.146 279.969 250.708 280.643 251.607 \
++ 280.981 252.732 280.643 253.406 279.969 253.744 \
++ 279.294 253.969 278.17 253.969 276.708 258.129 \
++ 276.708 258.129 277.608 258.129 278.957 257.904 \
++ 280.081 257.454 281.093 256.779 281.88 256.217 \
++ 282.218 254.643 282.667 253.744 282.78 252.732 \
++ 282.78 251.607 282.78 250.371 282.78 249.359 282.78 \
++ 248.459 282.667 247.672 282.442 246.436 281.88 \
++ 245.986 281.318 245.649 280.643 245.424 279.856 \
++ 245.199 278.957 245.086 277.833 244.974 276.708 \
++ 244.974 270.187 245.086 269.063 245.199 268.051 \
++ 245.311 267.264 245.649 266.589 245.986 265.915 \
++ 246.436 265.465 246.998 265.015 247.672 264.678 \
++ 248.459 264.453 249.359 264.228 250.371 264.116 \
++ 251.607 264.116 252.732 264.116 253.744 264.228 \
++ 254.756 264.453 255.543 264.678 256.217 265.015 \
++ 256.779 265.465 257.229 265.915 257.566 266.589 \
++ 257.791 267.264 258.016 268.051 258.129 269.063 \
++ 258.129 270.187 -fill #000000 -outline {} -width 1 -tags logo
++
++ $c create polygon 272.183 256.583 277.355 \
++ 256.583 277.355 282.78 272.183 282.78 272.183 \
++ 256.583 -fill #000000 -outline {} -width 1 -tags logo
++
++ $c create polygon 295.569 268.726 295.569 282.78 \
++ 290.959 282.78 290.959 269.175 290.847 268.051 \
++ 290.509 267.376 289.947 266.702 289.048 266.364 \
++ 287.923 266.702 287.136 267.376 287.024 268.051 \
++ 287.136 269.175 287.136 282.78 282.527 282.78 \
++ 282.527 264.565 286.687 264.565 287.136 265.915 \
++ 288.036 265.128 289.048 264.565 290.172 264.228 \
++ 291.409 264.116 292.533 264.116 293.433 264.341 \
++ 294.107 264.565 294.669 265.015 295.344 266.477 \
++ 295.569 267.489 295.569 268.726 -fill #000000 \
++ -outline {} -width 1 -tags logo
++
++ $c create polygon 312.434 269.737 312.434 \
++ 270.637 308.274 270.637 308.274 269.175 308.161 \
++ 267.826 307.824 266.927 307.262 266.477 306.363 \
++ 266.364 305.576 266.477 305.013 266.927 304.676 \
++ 267.826 304.564 269.175 304.564 278.17 304.676 \
++ 279.294 305.013 279.969 306.363 280.981 307.262 \
++ 280.643 307.824 279.969 307.937 279.294 307.824 \
++ 278.17 307.824 276.259 312.434 276.259 312.434 \
++ 277.608 312.434 278.957 312.209 280.081 311.759 \
++ 281.093 311.085 281.88 310.523 282.218 309.173 \
++ 282.667 308.386 282.78 307.374 282.78 306.363 282.78 \
++ 305.238 282.78 304.226 282.78 303.327 282.667 \
++ 302.427 282.442 301.753 282.218 301.191 281.88 \
++ 300.853 281.318 300.516 280.643 300.179 279.856 \
++ 299.954 278.957 299.841 277.833 299.841 276.708 \
++ 299.841 270.187 299.841 269.063 299.954 268.051 \
++ 300.179 267.264 300.404 266.589 301.191 265.465 \
++ 302.427 264.678 303.327 264.453 304.226 264.228 \
++ 305.238 264.116 306.363 264.116 307.374 264.116 \
++ 308.386 264.228 309.173 264.453 309.96 264.678 \
++ 310.523 265.015 311.085 265.465 311.759 266.252 \
++ 312.209 267.264 312.434 268.388 312.434 269.737 \
++ -fill #000000 -outline {} -width 1 -tags logo
++
++ $c create polygon 316.706 279.069 320.866 \
++ 279.069 320.866 282.78 316.706 282.78 316.706 \
++ 279.069 -fill #000000 -outline {} -width 1 -tags logo
++
++ $c create polygon 48.215 186.312 48.215 185.412 \
++ 47.766 184.4 47.766 183.501 47.316 183.501 47.316 \
++ 182.601 46.416 181.59 46.416 181.14 45.967 180.24 \
++ 45.405 179.791 44.955 179.228 44.055 178.329 43.606 \
++ 177.879 43.156 177.43 42.144 176.98 41.694 176.418 \
++ 41.245 175.968 38.883 175.068 36.972 174.169 36.522 \
++ 174.169 35.173 173.607 34.723 174.169 31.913 173.607 \
++ 31.913 174.169 29.551 173.607 29.551 174.169 28.54 \
++ 174.169 28.09 174.619 27.19 174.169 27.19 174.619 \
++ 26.741 174.619 25.729 175.068 23.93 175.518 22.918 \
++ 175.068 22.468 175.518 20.669 176.418 19.657 176.418 \
++ 15.048 178.779 14.036 179.228 12.686 180.24 12.237 \
++ 180.69 11.225 181.59 10.775 182.039 10.325 182.601 \
++ 10.775 182.601 10.325 184.4 10.775 184.85 11.225 \
++ 186.312 14.036 188.223 14.485 188.673 16.846 190.022 \
++ 17.296 190.472 17.296 191.034 15.947 191.933 15.048 \
++ 192.383 14.485 192.833 14.036 193.283 13.136 193.845 \
++ 12.237 194.295 12.686 195.644 12.686 196.094 12.237 \
++ 197.555 12.237 198.005 11.675 198.904 12.237 200.816 \
++ 12.237 202.277 12.237 204.526 11.675 205.988 12.237 \
++ 205.988 12.237 206.437 12.237 207.337 12.686 208.349 \
++ 12.686 209.248 13.136 209.698 12.686 211.16 13.136 \
++ 212.509 13.136 213.521 13.586 215.32 13.586 216.781 \
++ 13.586 217.681 14.036 220.492 14.485 222.403 15.048 \
++ 222.853 15.947 222.853 15.947 222.403 16.397 221.953 \
++ 16.846 216.781 17.296 215.32 17.858 211.609 18.308 \
++ 210.71 18.308 210.148 18.308 209.248 17.858 208.798 \
++ 17.858 207.899 18.308 206.437 18.308 205.538 18.308 \
++ 205.088 18.308 203.627 16.846 203.627 15.947 203.177 \
++ 15.947 202.727 15.947 202.277 16.397 201.715 16.846 \
++ 201.715 17.858 201.715 18.308 201.715 18.758 201.265 \
++ 18.308 200.816 17.858 199.916 18.308 198.455 17.858 \
++ 198.455 17.858 193.283 19.208 192.383 20.107 191.933 \
++ 21.569 191.484 22.018 191.484 22.918 192.383 22.918 \
++ 192.833 23.48 192.833 23.93 198.005 23.48 199.467 \
++ 23.93 202.277 25.279 202.277 29.551 202.727 30.001 \
++ 202.277 30.901 202.277 31.913 202.277 35.623 201.265 \
++ 36.522 201.265 36.972 200.816 37.984 200.816 38.883 \
++ 200.816 39.333 200.366 40.345 199.916 40.795 199.916 \
++ 42.594 198.455 44.055 198.005 44.055 197.555 44.505 \
++ 197.105 46.416 195.644 46.416 194.744 46.866 194.295 \
++ 47.316 193.845 47.766 193.283 47.316 192.833 48.215 \
++ 190.472 48.215 190.022 48.215 189.572 48.215 188.673 \
++ 48.215 187.211 48.215 186.762 48.215 186.312 -fill \
++ $bg -outline {} -width 1 -tags logo
++
++ $c create polygon 76.886 142.688 81.046 142.688 \
++ 82.508 142.35 83.407 140.889 83.632 140.327 83.969 \
++ 138.865 84.082 137.965 84.194 137.066 84.307 136.054 \
++ 84.307 134.93 84.307 133.805 84.307 132.456 84.194 \
++ 131.332 84.082 130.208 83.857 129.308 83.632 128.409 \
++ 83.407 127.734 82.395 126.272 81.046 125.823 76.886 \
++ 125.823 76.886 142.688 -fill $bg -outline {} -width \
++ 1 -tags logo
++
++ $c create polygon 97.461 148.309 97.461 149.546 \
++ 97.461 150.783 97.461 152.02 97.574 153.144 97.574 \
++ 154.268 97.686 155.28 97.686 156.405 97.799 157.416 \
++ 97.799 158.316 97.911 159.328 98.023 160.227 98.136 \
++ 161.127 98.361 162.701 98.473 163.488 98.586 164.275 \
++ 98.698 164.949 98.81 165.736 99.373 167.535 99.822 \
++ 169.109 100.497 170.234 101.059 171.133 101.846 \
++ 171.583 102.633 171.808 104.095 171.133 104.769 \
++ 170.234 105.332 169.109 105.894 167.535 106.343 \
++ 165.736 106.456 164.949 106.681 164.275 106.793 \
++ 163.488 106.906 162.701 107.018 161.914 107.243 \
++ 160.227 107.355 159.328 107.355 158.316 107.468 \
++ 157.416 107.58 156.405 107.58 155.28 107.693 154.268 \
++ 107.693 153.144 107.693 152.02 107.693 150.783 \
++ 107.805 149.546 107.805 148.309 107.805 147.073 \
++ 107.693 145.836 107.693 144.711 107.693 143.587 \
++ 107.693 142.463 107.58 141.338 107.58 140.327 \
++ 107.468 139.315 107.355 138.303 107.355 137.403 \
++ 107.243 136.504 107.131 135.604 106.906 133.918 \
++ 106.793 133.131 106.681 132.456 106.456 131.669 \
++ 106.343 130.995 105.894 129.196 105.332 127.622 \
++ 104.769 126.497 104.095 125.598 103.42 125.148 \
++ 102.633 124.923 101.846 125.148 101.059 125.598 \
++ 100.497 126.497 99.822 127.622 99.373 129.196 98.81 \
++ 130.995 98.698 131.669 98.586 132.456 98.473 133.131 \
++ 98.361 133.918 98.248 134.817 98.023 136.504 97.911 \
++ 137.403 97.799 138.303 97.799 139.315 97.686 140.327 \
++ 97.686 141.338 97.574 142.463 97.574 143.587 97.461 \
++ 144.711 97.461 145.836 97.461 147.073 97.461 148.309 \
++ -fill $bg -outline {} -width 1 -tags logo
++
++ $c create polygon 122.309 156.292 126.919 \
++ 156.292 124.67 130.545 122.309 156.292 -fill $bg \
++ -outline {} -width 1 -tags logo
++
++ $c create polygon 142.435 142.688 146.145 \
++ 142.688 147.607 142.35 148.506 140.889 148.731 \
++ 140.327 149.068 138.865 149.181 137.965 149.293 \
++ 137.066 149.405 136.054 149.405 134.93 149.405 \
++ 133.805 149.405 132.456 149.405 131.332 149.405 \
++ 130.208 149.293 129.308 149.181 128.409 148.956 \
++ 127.734 148.056 126.272 146.595 125.823 142.435 \
++ 125.823 142.435 142.688 -fill $bg -outline {} -width \
++ 1 -tags logo
++
++ $c create polygon 111.515 228.924 111.515 \
++ 227.575 111.066 225.664 108.705 221.391 108.255 \
++ 220.042 108.255 219.142 108.255 218.58 108.255 \
++ 218.13 107.805 217.681 106.793 218.58 104.994 \
++ 220.941 104.432 221.953 102.633 224.202 102.183 \
++ 224.764 101.621 225.214 99.822 228.474 97.461 \
++ 233.197 97.461 234.096 97.461 234.995 97.911 235.445 \
++ 98.361 236.007 99.822 236.457 102.633 236.457 \
++ 104.432 235.445 105.894 234.995 106.343 234.546 \
++ 106.793 234.546 107.805 233.646 110.616 230.835 \
++ 111.515 229.824 111.515 229.374 111.515 228.924 \
++ -fill $bg -outline {} -width 1 -tags logo
++
++ $c create polygon 161.211 269.175 160.986 \
++ 267.826 160.649 266.927 160.199 266.477 159.3 \
++ 266.364 158.4 266.477 157.838 266.927 157.613 \
++ 267.826 157.388 269.175 157.388 278.17 157.613 \
++ 279.294 157.838 279.969 159.3 280.981 160.199 \
++ 280.643 160.649 279.969 160.986 279.294 161.211 \
++ 278.17 161.211 269.175 -fill $bg -outline {} -width \
++ 1 -tags logo
++
++ $c create polygon 224.848 273.448 223.836 \
++ 273.448 222.825 273.56 222.15 273.673 221.588 \
++ 273.897 220.913 274.684 220.688 275.809 220.688 \
++ 278.17 220.801 279.294 221.138 279.969 221.7 280.643 \
++ 222.487 280.981 223.612 280.643 224.399 279.969 \
++ 224.736 279.294 224.848 278.17 224.848 273.448 -fill \
++ $bg -outline {} -width 1 -tags logo
++
++ $c create polygon 253.969 269.175 253.744 \
++ 267.826 253.406 266.927 252.732 266.477 251.607 \
++ 266.364 250.708 266.477 250.146 266.927 249.696 \
++ 269.175 249.696 272.548 253.969 272.548 253.969 \
++ 269.175 -fill $bg -outline {} -width 1 -tags logo
++
++}
++
++#***********************************************************************
++# %PROCEDURE: LoadConnectionInfo
++# %ARGUMENTS:
++# None
++# %RETURNS:
++# Nothing
++# %DESCRIPTION:
++# Loads the connection information into the global ConnectionInfo variable
++#***********************************************************************
++proc LoadConnectionInfo {} {
++ global ConnectionInfoFile ConnectionInfo PasswordFile
++ set ConnectionInfo {}
++ if {![file exists $ConnectionInfoFile]} {
++ return
++ }
++ set problem [catch {
++ set fp [open $ConnectionInfoFile &quot;r&quot;]
++ while {1} {
++ if {[gets $fp line] &lt; 0} {
++ break
++ }
++ set line [string trim $line]
++ if {[string match &quot;#*&quot; $line]} {
++ continue
++ }
++ if {&quot;$line&quot; == &quot;&quot;} {
++ continue
++ }
++ set ConnectionInfo $line
++ break
++ }
++ close $fp
++ } err]
++ if {$problem} {
++ tk_dialog .err Error &quot;Error loading configuration file: $err&quot; error 0 OK
++ }
++ # Try loading and merging passwords if the password file is readable
++ if {![file readable $PasswordFile]} {
++ return
++ }
++
++ set fp [open $PasswordFile &quot;r&quot;]
++ while {1} {
++ if {[gets $fp line] &lt; 0} {
++ break
++ }
++ set line [string trim $line]
++ if {[string match &quot;#*&quot; $line]} {
++ continue
++ }
++ if {&quot;$line&quot; == &quot;&quot;} {
++ continue
++ }
++ set passwords $line
++ break
++ }
++ close $fp
++
++ # Merge passwords
++ foreach thing $passwords {
++ set name [value $thing ConnectionName]
++ set password [value $thing Password]
++ set conn [GetConnection $name]
++ if {&quot;$conn&quot; != &quot;&quot;} {
++ lappend conn Password $password
++ ReplaceConnection $conn
++ }
++ }
++}
++
++#***********************************************************************
++# %PROCEDURE: GetConnection
++# %ARGUMENTS:
++# name -- name of connection
++# %RETURNS:
++# key/value pair listing connection configuration, or &quot;&quot; if not found.
++#***********************************************************************
++proc GetConnection { name } {
++ global ConnectionInfo
++ foreach thing $ConnectionInfo {
++ if {[value $thing ConnectionName] == &quot;$name&quot;} {
++ return $thing
++ }
++ }
++ return &quot;&quot;
++}
++
++
++#***********************************************************************
++# %PROCEDURE: DeleteConnection
++# %ARGUMENTS:
++# name -- name of connection
++# %RETURNS:
++# Nothing, but deletes connection named &quot;$name&quot;
++#***********************************************************************
++proc DeleteConnection { name } {
++ global ConnectionInfo ConfigDir
++ set newInfo {}
++ set found 0
++ foreach thing $ConnectionInfo {
++ if {[value $thing ConnectionName] == &quot;$name&quot;} {
++ set found 1
++ } else {
++ lappend newInfo $thing
++ }
++ }
++ if {!$found} {
++ return
++ }
++ set ConnectionInfo $newInfo
++ SaveConnectionInfo
++
++ # Delete the config file
++ set fname [file join $ConfigDir conf.$name]
++ catch { file delete $fname }
++
++ BuildConnectionMenu
++ if {[GetCurrentConnection] == $name} {
++ if {[llength $ConnectionInfo] == 0} {
++ SwitchConnection &quot;&quot;
++ } else {
++ set name [value [lindex $ConnectionInfo 0] ConnectionName]
++ SwitchConnection $name
++ }
++ }
++}
++
++#***********************************************************************
++# %PROCEDURE: ReplaceConnection
++# %ARGUMENTS:
++# conn -- new name/value pairs
++# %RETURNS:
++# Nothing, but replaces connection in ConnectionInfo. If no such
++# connection exists, appends new connection.
++#***********************************************************************
++proc ReplaceConnection { conn } {
++ global ConnectionInfo
++ set name [value $conn ConnectionName]
++ set newInfo {}
++ set found 0
++ foreach thing $ConnectionInfo {
++ if {[value $thing ConnectionName] == &quot;$name&quot;} {
++ lappend newInfo $conn
++ set found 1
++ } else {
++ lappend newInfo $thing
++ }
++ }
++ if {!$found} {
++ lappend newInfo $conn
++ }
++ set ConnectionInfo $newInfo
++}
++
++proc DeletePPPoEConnection {} {
++ set conn [GetCurrentConnection]
++ if {&quot;$conn&quot; == &quot;&quot;} {
++ return
++ }
++ set ans [tk_dialog .confirm &quot;Confirm Deletion - RP-PPPoE&quot; &quot;Are you sure you wish to delete the connection `$conn'?&quot; warning 0 No Yes]
++ if {$ans} {
++ DeleteConnection $conn
++ }
++}
++
++#***********************************************************************
++# %PROCEDURE: CreateMainDialog
++# %ARGUMENTS:
++# None
++# %RETURNS:
++# Nothing
++# %DESCRIPTION:
++# Creates the main window
++#***********************************************************************
++proc CreateMainDialog {} {
++ global ConnectionInfoFile
++ global ConnectionInfo
++ global Admin
++ wm title . &quot;RP-PPPoE&quot;
++ wm iconname . &quot;PPPoE&quot;
++ frame .f1
++ label .l1 -text &quot;Connection: &quot;
++ menubutton .m1 -text &quot;&quot; -indicatoron 1 -menu .m1.menu -relief raised
++ menu .m1.menu -tearoff 0
++ pack .l1 .m1 -in .f1 -side left -expand 0 -fill x
++ canvas .c -width 40 -height 20
++ pack .c -in .f1 -side left -expand 0 -fill none
++
++ # Draw the LED's
++ .c create rectangle 10 1 30 8 -outline &quot;#808080&quot; -fill &quot;#A0A0A0&quot; -tags xmitrect
++ .c create rectangle 10 10 30 18 -outline &quot;#808080&quot; -fill &quot;#A0A0A0&quot; -tags recvrect
++
++ frame .buttons
++ button .start -text &quot;Start&quot; -command &quot;StartPPPoEConnection&quot;
++ button .stop -text &quot;Stop&quot; -command &quot;StopPPPoEConnection&quot;
++ button .exit -text &quot;Exit&quot; -command &quot;exit&quot;
++ canvas .graph -width 1 -height 1
++ if {[file writable $ConnectionInfoFile]} {
++ set Admin 1
++ pack .f1 -side top -expand 1 -fill both
++ pack .buttons -side top -expand 0 -fill x
++ button .delete -text &quot;Delete&quot; -command &quot;DeletePPPoEConnection&quot;
++ button .new -text &quot;New Connection...&quot; -command &quot;NewPPPoEConnection&quot;
++ button .props -text &quot;Properties...&quot; -command &quot;EditConnectionProps&quot;
++ pack .graph -in .f1 -side left -expand 1 -fill both
++ pack .start .stop .delete .props .new .exit -in .buttons -side left -expand 0 -fill none
++ } else {
++ set Admin 0
++ pack .f1 -side top -expand 0 -fill x
++ pack .buttons -side top -expand 1 -fill both
++ pack .start .stop .exit -in .buttons -side left -expand 0 -fill none
++ pack .graph -in .buttons -side left -expand 1 -fill both
++ }
++
++ LoadConnectionInfo
++ BuildConnectionMenu
++ # If no connections exist, pop up new connection dialog
++ if {[llength $ConnectionInfo] == 0} {
++ SwitchConnection &quot;&quot;
++ if {$Admin} {
++ update idletasks
++ NewPPPoEConnection
++ } else {
++ tk_dialog .note Note &quot;Note: There are no connections defined. You must run this program as root to define connections&quot; warning 0 OK
++ }
++ } else {
++ set con [lindex $ConnectionInfo 0]
++ set name [value $con ConnectionName]
++ SwitchConnection $name
++ }
++}
++
++#***********************************************************************
++# %PROCEDURE: GetCurrentConnection
++# %ARGUMENTS:
++# None
++# %RETURNS:
++# The name of the current connection in the GUI.
++#***********************************************************************
++proc GetCurrentConnection {} {
++ .m1 cget -text
++}
++
++#***********************************************************************
++# %PROCEDURE: value
++# %ARGUMENTS:
++# lst -- a list of key/value pairs
++# key -- key we're looking for
++# %RETURNS:
++# value corresponding to $key, or &quot;&quot; if not found.
++#***********************************************************************
++proc value { lst key } {
++ set idx [lsearch -exact $lst $key]
++ if {$idx &gt;= 0} {
++ return [lindex $lst [expr $idx+1]]
++ }
++ return &quot;&quot;
++}
++
++#***********************************************************************
++# %PROCEDURE: SwitchConnection
++# %ARGUMENTS:
++# name -- new connection name
++# %DESCRIPTION:
++# Makes $name the active connection
++#***********************************************************************
++proc SwitchConnection { name } {
++ .m1 configure -text $name
++ SetButtonStates
++ UpdateConnectionState 0
++}
++
++#***********************************************************************
++# %PROCEDURE: EditConnectionProps
++# %ARGUMENTS:
++# None
++# %DESCRIPTION:
++# Pops up edit window for current connection
++#***********************************************************************
++proc EditConnectionProps {} {
++ global ConnectionInfo
++ set conn [GetCurrentConnection]
++ NewPPPoEConnection $conn
++}
++
++#***********************************************************************
++# %PROCEDURE: FillConnectionGui
++# %ARGUMENTS:
++# w -- connection property GUI
++# name -- name of connection
++# %DESCRIPTION:
++# Fills GUI with values corresponding to $name.
++#***********************************************************************
++proc FillConnectionGui { w name } {
++ global ConnectionInfo
++ set found [GetConnection $name]
++ if {&quot;$found&quot; != &quot;&quot;} {
++ ListToSetupGui $w $found
++ }
++}
++
++#***********************************************************************
++# %PROCEDURE: BuildConnectionMenu
++# %ARGUMENTS:
++# None
++# %RETURNS:
++# Nothing
++# %DESCRIPTION:
++# Builds the connection menu
++#***********************************************************************
++proc BuildConnectionMenu {} {
++ global ConnectionInfo
++ .m1.menu delete 0 end
++ foreach connection $ConnectionInfo {
++ set name [value $connection ConnectionName]
++ .m1.menu add command -label $name -command [list SwitchConnection $name]
++ }
++ .m1.menu add separator
++ .m1.menu add command -label &quot;User's Manual&quot; -command Help
++}
++
++#***********************************************************************
++# %PROCEDURE: SetButtonStates
++# %ARGUMENTS:
++# None
++# %RETURNS:
++# Nothing
++# %DESCRIPTION:
++# Enables or disables buttons, as appropriate
++#***********************************************************************
++proc SetButtonStates {} {
++ global Admin
++ set conn [GetCurrentConnection]
++ if {&quot;$conn&quot; == &quot;&quot;} {
++ .start configure -state disabled
++ .stop configure -state disabled
++ catch {
++ .delete configure -state disabled
++ .props configure -state disabled
++ .new configure -state normal
++ }
++ } else {
++ foreach {startstop updown interface} [GetConnectionStatus $conn] {break}
++ if {&quot;$startstop&quot; == &quot;started&quot;} {
++ .start configure -state disabled
++ .stop configure -state normal
++ } else {
++ .start configure -state normal
++ .stop configure -state disabled
++ }
++ catch {
++ .delete configure -state normal
++ .props configure -state normal
++ .new configure -state normal
++ }
++ if {!$Admin} {
++ set ok [value [GetConnection $conn] NonrootOK]
++ if {!$ok} {
++ .start configure -state disabled
++ .stop configure -state disabled
++ }
++ }
++ }
++}
++
++#***********************************************************************
++# %PROCEDURE: GetEthernetInterfaces
++# %ARGUMENTS:
++# None
++# %RETURNS:
++# A list of Ethernet interfaces
++#***********************************************************************
++proc GetEthernetInterfaces {} {
++ set ifs {}
++ set fp [open &quot;|/sbin/ifconfig&quot; &quot;r&quot;]
++ while {[gets $fp line] &gt;= 0} {
++ if {[regexp {^eth[0-9]+} $line eth]} {
++ lappend ifs $eth
++ }
++ }
++ return $ifs
++}
++
++#***********************************************************************
++# %PROCEDURE: StartPPPoEConnection
++# %ARGUMENTS:
++# None
++# %RETURNS:
++# Nothing
++# %DESCRIPTION:
++# Starts currently-selected PPPoE connection.
++#***********************************************************************
++proc StartPPPoEConnection {} {
++ global Wrapper
++ global StartState
++ global UpdateToken
++
++ set conn [GetCurrentConnection]
++ if {&quot;$conn&quot; == &quot;&quot;} {
++ return
++ }
++
++ if {&quot;$UpdateToken&quot; != &quot;&quot;} {
++ after cancel $UpdateToken
++ set UpdateToken &quot;&quot;
++ }
++
++ catch { unset StartState }
++ set StartState(chars) &quot;&quot;
++ set StartState(status) &quot;&quot;
++ set StartState(msg) &quot;&quot;
++ set StartState(flip) 0
++
++ set fp [open &quot;|$Wrapper start $conn&quot; &quot;r&quot;]
++
++ # Set fileevent
++ fileevent $fp readable [list StartFPReadable $fp]
++
++ LockGui $fp
++ vwait StartState(status)
++ UnlockGui
++
++ if {$StartState(status) == &quot;failed&quot;} {
++ tk_dialog .err Error &quot;Error starting connection: $StartState(msg)&quot; error 0 OK
++ }
++ SetButtonStates
++ UpdateConnectionState 0
++}
++
++proc LockGui { fp } {
++ .start configure -state disabled
++ .stop configure -state normal -command [list AbortConnection $fp]
++ .exit configure -state disabled
++ .m1 configure -state disabled
++ grab set .stop
++}
++
++proc UnlockGui {} {
++ .start configure -state normal
++ .stop configure -state disabled -command StopPPPoEConnection
++ .exit configure -state normal
++ .m1 configure -state normal
++ grab release .stop
++}
++
++proc AbortConnection { fp } {
++ global StartState
++ catch { StopPPPoEConnection }
++ catch { close $fp }
++ set StartState(msg) &quot;Connection aborted by user&quot;
++ set StartState(status) &quot;failed&quot;
++}
++
++#***********************************************************************
++# %PROCEDURE: StartFPReadable
++# %ARGUMENTS:
++# fp -- file handle
++# %RETURNS:
++# Nothing
++# %DESCRIPTION:
++# Called when the &quot;adsl-start&quot; file handle is readable.
++#***********************************************************************
++proc StartFPReadable { fp } {
++ global StartState
++ set char [read $fp 1]
++ if {$char == &quot;&quot;} {
++ set uhoh [catch {close $fp} err]
++ if {$uhoh} {
++ set StartState(status) &quot;failed&quot;
++ set StartState(msg) $err
++ } else {
++ set StartState(status) &quot;succeeded&quot;
++ }
++ return
++ }
++ append StartState(chars) $char
++ if {$StartState(flip)} {
++ ConnectionStateDown
++ } else {
++ ConnectionStateOff
++ }
++ set StartState(flip) [expr 1 - $StartState(flip)]
++}
++
++#***********************************************************************
++# %PROCEDURE: StopPPPoEConnection
++# %ARGUMENTS:
++# None
++# %RETURNS:
++# Nothing
++# %DESCRIPTION:
++# Stops currently-selected PPPoE connection.
++#***********************************************************************
++proc StopPPPoEConnection {} {
++ global Wrapper
++ set conn [GetCurrentConnection]
++ if {&quot;$conn&quot; == &quot;&quot;} {
++ return
++ }
++ set fp [open &quot;|$Wrapper stop $conn&quot; &quot;r&quot;]
++ while {1} {
++ set char [read $fp 1]
++ if {&quot;$char&quot; == &quot;&quot;} {
++ break;
++ }
++ }
++ set uhoh [catch {close $fp} err]
++ if {$uhoh} {
++ # Ignore a common error
++ if {![string match &quot;*appears to have died*&quot; $err]} {
++ tk_dialog .err Error &quot;Error stopping connection: $err&quot; error 0 OK
++ }
++ }
++ SetButtonStates
++ UpdateConnectionState 0
++}
++
++#***********************************************************************
++# %PROCEDURE: NewPPPoEConnection
++# %ARGUMENTS:
++# name -- if supplied, we're editing the existing connection &quot;name&quot;
++# %RETURNS:
++# Nothing
++# %DESCRIPTION:
++# Creates a new PPPoE connection
++#***********************************************************************
++proc NewPPPoEConnection {{name &quot;&quot;}} {
++ set w .newcon
++ if {[winfo exists $w]} {
++ wm deiconify $w
++ raise $w
++ return
++ }
++
++ toplevel $w
++ if {&quot;$name&quot; == &quot;&quot;} {
++ wm title $w &quot;New Connection - RP-PPPoE&quot;
++ wm iconname $w &quot;New Connection&quot;
++ } else {
++ wm title $w &quot;Edit Connection - RP-PPPoE&quot;
++ wm iconname $w &quot;Edit Connection&quot;
++ }
++ wm withdraw $w
++
++ tabnotebook_create $w.tn
++ set basic [tabnotebook_page $w.tn &quot;Basic&quot;]
++ set interface [tabnotebook_page $w.tn &quot;NIC and DNS&quot;]
++ set opts [tabnotebook_page $w.tn &quot;Options&quot;]
++ set advanced [tabnotebook_page $w.tn &quot;Advanced&quot;]
++
++ # ----------- BASIC PAGE -------------
++ label $w.lconName -text &quot;Connection Name: &quot; -anchor e
++ if {&quot;$name&quot; != &quot;&quot;} {
++ label $w.conName -text $name -anchor w
++ } else {
++ entry $w.conName -width 15
++ RegisterHelpWindow $w.lconName &quot;Enter a name for this connection. It can contain letters, numbers, undescores and the minus-sign.&quot; $w.help
++ RegisterHelpWindow $w.conName &quot;Enter a name for this connection. It can contain letters, numbers, undescores and the minus-sign.&quot; $w.help
++ }
++
++ label $w.luser -text &quot;User Name: &quot; -anchor e
++ entry $w.user -width 15
++ RegisterHelpWindow $w.luser &quot;Enter your user name. Do not add a domain-name after the user name.&quot; $w.help
++ RegisterHelpWindow $w.user &quot;Enter your user name. Do not add a domain-name after the user name.&quot; $w.help
++
++ label $w.lnet -text &quot;Network: &quot; -anchor e
++ entry $w.network -width 15
++ RegisterHelpWindow $w.lnet &quot;Some ISP's require you to enter their domain-name here (e.g. \&quot;sympatico.ca\&quot;).&quot; $w.help
++ RegisterHelpWindow $w.network &quot;Some ISP's require you to enter their domain-name here (e.g. \&quot;sympatico.ca\&quot;).&quot; $w.help
++
++ label $w.lpass -text &quot;Password: &quot; -anchor e
++ entry $w.pass -width 15 -show &quot;*&quot;
++ RegisterHelpWindow $w.lpass &quot;Enter your password.&quot; $w.help
++ RegisterHelpWindow $w.pass &quot;Enter your password.&quot; $w.help
++
++ grid $w.lconName $w.conName -in $basic -sticky nsew
++ grid $w.luser $w.user -in $basic -sticky nsew
++ grid $w.lnet $w.network -in $basic -sticky nsew
++ grid $w.lpass $w.pass -in $basic -sticky nsew
++ grid columnconfigure $basic 1 -weight 1
++
++ # ----------- INTERFACES PAGE -------------
++ set ifs {}
++ catch {set ifs [GetEthernetInterfaces]}
++
++ label $w.lifname -text &quot;Ethernet Interface: &quot; -anchor e
++ entry $w.ifname -width 8
++ RegisterHelpWindow $w.lifname &quot;Enter Ethernet interface to which DSL modem is attached.&quot; $w.help
++ RegisterHelpWindow $w.ifname &quot;Enter Ethernet interface to which DSL modem is attached.&quot; $w.help
++
++ if {[llength $ifs] &gt; 0} {
++ menubutton $w.ifmb -relief raised -text &quot;...&quot; -menu $w.ifmb.menu
++ RegisterHelpWindow $w.ifmb &quot;Browse detected Ethernet interface names.&quot; $w.help
++ menu $w.ifmb.menu -tearoff 0
++ foreach if $ifs {
++ $w.ifmb.menu add command -label $if -command &quot;$w.ifname delete 0 end; $w.ifname insert end [list $if]&quot;
++ }
++ grid $w.lifname $w.ifname $w.ifmb -in $interface -sticky nsew
++ } else {
++ grid $w.lifname $w.ifname - -in $interface -sticky nsew
++ }
++
++ label $w.ldns -text &quot;DNS Setup: &quot; -anchor e
++ menubutton $w.dns -text &quot;From Server&quot; -menu $w.dns.menu -relief raised -indicatoron 1
++ menu $w.dns.menu -tearoff 0
++ foreach thing {&quot;From Server&quot; &quot;Specify&quot; &quot;Do not Adjust&quot;} {
++ $w.dns.menu add command -label $thing -command [list SetDNSOption $w $thing]
++ }
++ RegisterHelpWindow $w.ldns &quot;DNS server options:\n'From Server' - Let PPPoE server specify DNS servers\n'Specify' - Enter IP addresses of DNS servers yourself\n'Do not Adjust' - Leave your DNS setup alone.&quot; $w.help
++ RegisterHelpWindow $w.dns &quot;DNS server options:\n'From Server' - Let PPPoE server specify DNS servers\n'Specify' - Enter IP addresses of DNS servers yourself\n'Do not Adjust' - Leave your DNS setup alone.&quot; $w.help
++
++ label $w.ldns1 -text &quot;Primary DNS: &quot; -anchor e
++ entry $w.dns1 -width 16
++ RegisterHelpWindow $w.ldns1 &quot;Enter the IP address of the primary DNS server.&quot; $w.help
++ RegisterHelpWindow $w.dns1 &quot;Enter the IP address of the primary DNS server.&quot; $w.help
++ label $w.ldns2 -text &quot;Secondary DNS: &quot; -anchor e
++ entry $w.dns2 -width 16
++ RegisterHelpWindow $w.ldns2 &quot;Enter the IP address of the secondary DNS server.&quot; $w.help
++ RegisterHelpWindow $w.dns2 &quot;Enter the IP address of the secondary DNS server.&quot; $w.help
++
++ SetDNSOption $w &quot;From Server&quot;
++ grid $w.ldns $w.dns - -in $interface -sticky nsew
++ grid $w.ldns1 $w.dns1 - -in $interface -sticky nsew
++ grid $w.ldns2 $w.dns2 - -in $interface -sticky nsew
++
++ # If only one Ethernet interface, select it by default
++ if {[llength $ifs] == 1} {
++ $w.ifname insert end [lindex $ifs 0]
++ }
++
++ grid columnconfigure $interface 1 -weight 1
++ # ----------- OPTS PAGE -------------
++ checkbutton $w.nonroot -text &quot;Allow use by non-root users&quot; -variable OPTS(nonroot) -anchor w
++ RegisterHelpWindow $w.nonroot &quot;If enabled, ordinary users can start and stop this connection.&quot; $w.help
++ checkbutton $w.sync -text &quot;Use synchronous PPP&quot; -variable OPTS(sync) -anchor w
++ RegisterHelpWindow $w.sync &quot;Use synchronous PPP (recommended -- easier on the CPU.)&quot; $w.help
++ label $w.lfw -text &quot;Firewalling: &quot; -anchor e
++ if {[llength $ifs] == 1} {
++ set defaultFW &quot;Stand-Alone&quot;
++ } else {
++ set defaultFW &quot;Masquerading&quot;
++ }
++ menubutton $w.fw -text $defaultFW -menu $w.fw.menu -indicatoron 1 -relief raised
++ menu $w.fw.menu -tearoff 0
++ foreach type {Stand-Alone Masquerading None} {
++ $w.fw.menu add command -label $type -command [list $w.fw configure -text $type]
++ }
++
++ RegisterHelpWindow $w.lfw &quot;Firewalling options:\nStand-Alone - A stand-alone machine.\nMasquerading - A gateway machine used for Internet sharing.\nNone - Use if you already have your own firewall rules or want to run servers.&quot; $w.help
++ RegisterHelpWindow $w.fw &quot;Firewalling options:\nStand-Alone - A stand-alone machine.\nMasquerading - A gateway machine used for Internet sharing.\nNone - Use if you already have your own firewall rules or want to run servers.&quot; $w.help
++ grid $w.nonroot - -in $opts -sticky nsew
++ grid $w.sync - -in $opts -sticky nsew
++ grid $w.lfw $w.fw -in $opts -sticky nsw
++ grid columnconfigure $opts 1 -weight 1
++
++ # ----------- ADVANCED PAGE -------------
++ label $w.lsn -text &quot;Service-Name: &quot; -anchor e
++ entry $w.servicename -width 24
++
++ label $w.lac -text &quot;AC-Name: &quot; -anchor e
++ entry $w.acname -width 24
++
++ RegisterHelpWindow $w.lac &quot;Enter access concentrator name if required. Most ISPs do not require this; try leaving it blank.&quot; $w.help
++ RegisterHelpWindow $w.acname &quot;Enter access concentrator name if required. Most ISPs do not require this; try leaving it blank.&quot; $w.help
++ grid $w.lsn $w.servicename -in $advanced -sticky nsew
++ grid $w.lac $w.acname -in $advanced -sticky nsew
++ RegisterHelpWindow $w.lsn &quot;Enter service name if required. Most ISPs do not require this; try leaving it blank.&quot; $w.help
++ RegisterHelpWindow $w.servicename &quot;Enter service name if required. Most ISPs do not require this; try leaving it blank.&quot; $w.help
++
++ grid columnconfigure $advanced 1 -weight 1
++
++ # ----------- BUTTONS -------------
++ frame $w.buttons
++ button $w.ok -text &quot;OK&quot; -command [list NewPPPoEConnectionOK $name $w]
++ button $w.cancel -text &quot;Cancel&quot; -command [list destroy $w]
++ pack $w.ok $w.cancel -in $w.buttons -expand 0 -fill none -side left
++
++ pack $w.tn -side top -expand 1 -fill both
++
++ text $w.help -width 60 -wrap word -state disabled -height 6
++ pack $w.help -side top -expand 0 -fill both
++ pack $w.buttons -side top -expand 0 -fill x
++
++ # If we're editing existing connection, fill GUI with current values
++ if {&quot;$name&quot; != &quot;&quot;} {
++ FillConnectionGui $w $name
++ }
++ wm deiconify $w
++ update idletasks
++ raise $w
++}
++
++#***********************************************************************
++# %PROCEDURE: SetDNSOption
++# %ARGUMENTS:
++# w -- connection-editing window
++# opt -- value of DNS option
++# %RETURNS:
++# Nothing
++# %DESCRIPTION:
++# Adjusts GUI for specified option
++#***********************************************************************
++proc SetDNSOption { w opt } {
++ $w.dns configure -text $opt
++ if {&quot;$opt&quot; == &quot;Specify&quot;} {
++ $w.dns1 configure -state normal -background white
++ $w.dns2 configure -state normal -background white
++ } else {
++ $w.dns1 configure -state disabled -background &quot;#d9d9d9&quot;
++ $w.dns2 configure -state disabled -background &quot;#d9d9d9&quot;
++ }
++}
++
++# ----------------------------------------------------------------------
++# Tabbed notebook code from &quot;Effective Tcl/Tk Programming&quot;
++# ----------------------------------------------------------------------
++# EXAMPLE: tabnotebook that can dial up pages
++# ----------------------------------------------------------------------
++# Effective Tcl/Tk Programming
++# Mark Harrison, DSC Communications Corp.
++# Michael McLennan, Bell Labs Innovations for Lucent Technologies
++# Addison-Wesley Professional Computing Series
++# ======================================================================
++# Copyright (c) 1996-1997 Lucent Technologies Inc. and Mark Harrison
++# ======================================================================
++
++option add *Tabnotebook.tabs.background #666666 widgetDefault
++option add *Tabnotebook.margin 6 widgetDefault
++option add *Tabnotebook.tabColor #a6a6a6 widgetDefault
++option add *Tabnotebook.activeTabColor #d9d9d9 widgetDefault
++option add *Tabnotebook.tabFont \
++ -*-helvetica-bold-r-normal--*-120-* widgetDefault
++
++proc tabnotebook_create {win} {
++ global tnInfo
++
++ frame $win -class Tabnotebook
++ canvas $win.tabs -highlightthickness 0
++ pack $win.tabs -fill x
++
++ notebook_create $win.notebook
++ pack $win.notebook -expand yes -fill both
++
++ set tnInfo($win-tabs) &quot;&quot;
++ set tnInfo($win-current) &quot;&quot;
++ set tnInfo($win-pending) &quot;&quot;
++ return $win
++}
++
++proc tabnotebook_page {win name} {
++ global tnInfo
++
++ set page [notebook_page $win.notebook $name]
++ lappend tnInfo($win-tabs) $name
++
++ if {$tnInfo($win-pending) == &quot;&quot;} {
++ set id [after idle [list tabnotebook_refresh $win]]
++ set tnInfo($win-pending) $id
++ }
++ return $page
++}
++
++proc tabnotebook_refresh {win} {
++ global tnInfo
++
++ $win.tabs delete all
++
++ set margin [option get $win margin Margin]
++ set color [option get $win tabColor Color]
++ set font [option get $win tabFont Font]
++ set x 2
++ set maxh 0
++
++ foreach name $tnInfo($win-tabs) {
++ set id [$win.tabs create text \
++ [expr $x+$margin+2] [expr -0.5*$margin] \
++ -anchor sw -text $name -font $font \
++ -tags [list $name]]
++
++ set bbox [$win.tabs bbox $id]
++ set wd [expr [lindex $bbox 2]-[lindex $bbox 0]]
++ set ht [expr [lindex $bbox 3]-[lindex $bbox 1]]
++ if {$ht &gt; $maxh} {
++ set maxh $ht
++ }
++
++ $win.tabs create polygon 0 0 $x 0 \
++ [expr $x+$margin] [expr -$ht-$margin] \
++ [expr $x+$margin+$wd] [expr -$ht-$margin] \
++ [expr $x+$wd+2*$margin] 0 \
++ 2000 0 2000 10 0 10 \
++ -outline black -fill $color \
++ -tags [list $name tab tab-$name]
++
++ $win.tabs raise $id
++
++ $win.tabs bind $name &lt;ButtonPress-1&gt; \
++ [list tabnotebook_display $win $name]
++
++ set x [expr $x+$wd+2*$margin]
++ }
++ set height [expr $maxh+2*$margin]
++ $win.tabs move all 0 $height
++
++ $win.tabs configure -width $x -height [expr $height+4]
++
++ if {$tnInfo($win-current) != &quot;&quot;} {
++ tabnotebook_display $win $tnInfo($win-current)
++ } else {
++ tabnotebook_display $win [lindex $tnInfo($win-tabs) 0]
++ }
++ set tnInfo($win-pending) &quot;&quot;
++}
++
++proc tabnotebook_display {win name} {
++ global tnInfo
++
++ notebook_display $win.notebook $name
++
++ set normal [option get $win tabColor Color]
++ $win.tabs itemconfigure tab -fill $normal
++
++ set active [option get $win activeTabColor Color]
++ $win.tabs itemconfigure tab-$name -fill $active
++ $win.tabs raise $name
++
++ set tnInfo($win-current) $name
++}
++
++# ----------------------------------------------------------------------
++# EXAMPLE: simple notebook that can dial up pages
++# ----------------------------------------------------------------------
++# Effective Tcl/Tk Programming
++# Mark Harrison, DSC Communications Corp.
++# Michael McLennan, Bell Labs Innovations for Lucent Technologies
++# Addison-Wesley Professional Computing Series
++# ======================================================================
++# Copyright (c) 1996-1997 Lucent Technologies Inc. and Mark Harrison
++# ======================================================================
++
++option add *Notebook.borderWidth 2 widgetDefault
++option add *Notebook.relief sunken widgetDefault
++
++proc notebook_create {win} {
++ global nbInfo
++
++ frame $win -class Notebook
++ pack propagate $win 0
++
++ set nbInfo($win-count) 0
++ set nbInfo($win-pages) &quot;&quot;
++ set nbInfo($win-current) &quot;&quot;
++ return $win
++}
++
++proc notebook_page {win name} {
++ global nbInfo
++
++ set page &quot;$win.page[incr nbInfo($win-count)]&quot;
++ lappend nbInfo($win-pages) $page
++ set nbInfo($win-page-$name) $page
++
++ frame $page
++
++ if {$nbInfo($win-count) == 1} {
++ after idle [list notebook_display $win $name]
++ }
++ return $page
++}
++
++proc notebook_display {win name} {
++ global nbInfo
++
++ set page &quot;&quot;
++ if {[info exists nbInfo($win-page-$name)]} {
++ set page $nbInfo($win-page-$name)
++ } elseif {[winfo exists $win.page$name]} {
++ set page $win.page$name
++ }
++ if {$page == &quot;&quot;} {
++ error &quot;bad notebook page \&quot;$name\&quot;&quot;
++ }
++
++ notebook_fix_size $win
++
++ if {$nbInfo($win-current) != &quot;&quot;} {
++ pack forget $nbInfo($win-current)
++ }
++ pack $page -expand yes -fill both
++ set nbInfo($win-current) $page
++}
++
++proc notebook_fix_size {win} {
++ global nbInfo
++
++ update idletasks
++
++ set maxw 0
++ set maxh 0
++ foreach page $nbInfo($win-pages) {
++ set w [winfo reqwidth $page]
++ if {$w &gt; $maxw} {
++ set maxw $w
++ }
++ set h [winfo reqheight $page]
++ if {$h &gt; $maxh} {
++ set maxh $h
++ }
++ }
++ set bd [$win cget -borderwidth]
++ set maxw [expr $maxw+2*$bd]
++ set maxh [expr $maxh+2*$bd]
++ $win configure -width $maxw -height $maxh
++}
++
++#***********************************************************************
++# %PROCEDURE: SetupGuiToList
++# %ARGUMENTS:
++# w -- the PPPoE connection setup window
++# %RETURNS:
++# A list of (name value) pairs for the connection.
++# %DESCRIPTION:
++# Reads values from the GUI; makes a list.
++#***********************************************************************
++proc SetupGuiToList { w } {
++ global OPTS
++ set ans {}
++ if {[catch {lappend ans ConnectionName [$w.conName get]}]} {
++ lappend ans ConnectionName [$w.conName cget -text]
++ }
++ lappend ans UserName [$w.user get]
++ lappend ans NetworkName [$w.network get]
++ lappend ans Password [$w.pass get]
++ lappend ans Interface [$w.ifname get]
++ lappend ans DNSType [$w.dns cget -text]
++ lappend ans DNS1 [$w.dns1 get]
++ lappend ans DNS2 [$w.dns2 get]
++ lappend ans NonrootOK $OPTS(nonroot)
++ lappend ans Sync $OPTS(sync)
++ lappend ans FirewallType [$w.fw cget -text]
++ lappend ans ServiceName [$w.servicename get]
++ lappend ans ACName [$w.acname get]
++
++ # Validate
++ set name [value $ans ConnectionName]
++ if {![regexp -nocase {^[-a-z0-9_]+$} $name]} {
++ error &quot;Connection name must be non-blank and contain only letters, digits, `_' and `-'&quot;
++ }
++
++ # Check DNS
++ set type [value $ans DNSType]
++ if {&quot;$type&quot; == &quot;Specify&quot;} {
++ set dns [value $ans DNS1]
++ if {![regexp {[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+} &quot;$dns&quot;]} {
++ error &quot;Primary DNS entry must consist of four dot-separated decimal numbers&quot;
++ }
++ set dns [value $ans DNS2]
++ if {&quot;$dns&quot; != &quot;&quot; &amp;&amp; ![regexp {[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+} &quot;$dns&quot;]} {
++ error &quot;Secondary DNS entry must consist of four dot-separated decimal numbers&quot;
++ }
++ }
++ return $ans
++}
++
++#***********************************************************************
++# %PROCEDURE: ListToSetupGui
++# %ARGUMENTS:
++# w -- the PPPoE connection setup window
++# lst -- a list of name/value pairs
++# %RETURNS:
++# Nothing
++# %DESCRIPTION:
++# Updates GUI to reflect lst
++#***********************************************************************
++proc ListToSetupGui { w lst } {
++ global OPTS
++ foreach {key value} $lst {
++ switch -exact -- $key {
++ ConnectionName {
++ catch {
++ $w.conName delete 0 end
++ $w.conName insert end $value
++ }
++ catch {
++ $w.conName configure -text $value
++ }
++ }
++ UserName {
++ $w.user delete 0 end
++ $w.user insert end $value
++ }
++ NetworkName {
++ $w.network delete 0 end
++ $w.network insert end $value
++ }
++ Password {
++ $w.pass delete 0 end
++ $w.pass insert end $value
++ }
++ Interface {
++ $w.ifname delete 0 end
++ $w.ifname insert end $value
++ }
++ DNSType {
++ SetDNSOption $w $value
++ }
++ DNS1 {
++ set oldstate [$w.dns1 cget -state]
++ $w.dns1 configure -state normal
++ $w.dns1 delete 0 end
++ $w.dns1 insert end $value
++ $w.dns1 configure -state $oldstate
++ }
++ DNS2 {
++ set oldstate [$w.dns2 cget -state]
++ $w.dns2 configure -state normal
++ $w.dns2 delete 0 end
++ $w.dns2 insert end $value
++ $w.dns2 configure -state $oldstate
++ }
++ NonrootOK {
++ set OPTS(nonroot) $value
++ }
++ Sync {
++ set OPTS(sync) $value
++ }
++ FirewallType {
++ $w.fw configure -text $value
++ }
++ ServiceName {
++ $w.servicename delete 0 end
++ $w.servicename insert end $value
++ }
++ ACName {
++ $w.acname delete 0 end
++ $w.acname insert end $value
++ }
++ }
++ }
++}
++
++proc NewPPPoEConnectionOK { name w } {
++ if {[catch {set conn [SetupGuiToList $w]} err]} {
++ tk_dialog .err &quot;Invalid Parameters&quot; &quot;$err&quot; error 0 OK
++ return
++ }
++ if {&quot;$name&quot; == &quot;&quot;} {
++ set name [value $conn ConnectionName]
++ set tmp [GetConnection $name]
++ if {&quot;$tmp&quot; != &quot;&quot;} {
++ tk_dialog .err &quot;Connection Exists&quot; &quot;The connection `$name' already exists. Pick another name.&quot; error 0 OK
++ return
++ }
++ }
++ ReplaceConnection $conn
++ SaveConnectionInfo
++ BuildConnectionMenu
++ SwitchConnection $name
++ destroy $w
++}
++
++proc SaveConnectionInfo {} {
++ global ConnectionInfo ConnectionInfoFile PasswordFile
++ set fp [open &quot;$ConnectionInfoFile.new&quot; &quot;w&quot;]
++ puts $fp &quot;# RP-PPPoE GUI Configuration Information.&quot;
++ puts $fp &quot;# This file may *look* human-editable, but it is NOT.&quot;
++ puts $fp &quot;# So, you with the text editor: Keep away from this file.&quot;
++ puts $fp &quot;#&quot;
++ set expunged {}
++ set passwords {}
++ foreach thing $ConnectionInfo {
++ set name [value $thing ConnectionName]
++ set password [value $thing Password]
++ set pwindex [lsearch -exact $thing Password]
++ set safe [lreplace $thing $pwindex [expr $pwindex+1]]
++ set pwd [list ConnectionName $name Password $password]
++ lappend expunged $safe
++ lappend passwords $pwd
++ }
++ puts $fp $expunged
++ close $fp
++ set fp [open &quot;$PasswordFile.new&quot; &quot;w&quot;]
++ exec chmod 600 &quot;$PasswordFile.new&quot;
++ puts $fp &quot;# RP-PPPoE GUI Configuration Information.&quot;
++ puts $fp &quot;# This file may *look* human-editable, but it is NOT.&quot;
++ puts $fp &quot;# So, you with the text editor: Keep away from this file.&quot;
++ puts $fp &quot;#&quot;
++ puts $fp $passwords
++ close $fp
++ file rename -force &quot;$ConnectionInfoFile.new&quot; &quot;$ConnectionInfoFile&quot;
++ file rename -force &quot;$PasswordFile.new&quot; &quot;$PasswordFile&quot;
++
++ # Generate config files for adsl-start for each connection
++ foreach thing $ConnectionInfo {
++ GenerateConfigFile $thing
++ }
++
++ # Now update /etc/ppp/pap-secrets and /etc/ppp/chap-secrets
++ foreach thing $ConnectionInfo {
++ GenerateSecretsEntry $thing
++ }
++}
++
++#***********************************************************************
++# %PROCEDURE: ReadShellEscapedWord
++# %ARGUMENTS:
++# str -- a string
++# %RETURNS:
++# A two-element list -- the first element is a shell-escaped word
++# extracted from $str, just the way pppd parses /etc/ppp/pap-secrets.
++# The second element is the remaining portion of $str
++#***********************************************************************
++proc ReadShellEscapedWord { str } {
++ set ans {}
++ set rest $str
++
++ # Chew up leading spaces
++ set rest [string trimleft $rest]
++
++ # If first char is a quote, read until a quote
++ if {&quot;[string index $rest 0]&quot; == &quot;\&quot;&quot;} {
++ set rest [string range $rest 1 end]
++ set nextquote [string first &quot;\&quot;&quot; $rest]
++ # If no following quote, pretend we haven't seen a quote, I guess.
++ if {$nextquote &gt;= 0} {
++ set ans [string range $rest 0 [expr $nextquote-1]]
++ set rest [string range $rest [expr $nextquote+1] end]
++ return [list $ans $rest]
++ }
++ }
++
++ # Not a quote; chew through the string until an unescaped space
++ while {[string length $rest] &gt; 0} {
++ set char [string index $rest 0]
++ set rest [string range $rest 1 end]
++ # Sneaky test for whitespace in Tcl 8.0
++ if {&quot;[string trim $char]&quot; == &quot;&quot;} {
++ return [list $ans $rest]
++ }
++ if {&quot;$char&quot; == &quot;\\&quot;} {
++ set char [string index $rest 0]
++ set rest [string range $rest 1 end]
++ }
++ append ans $char
++ }
++ return [list $ans $rest]
++}
++
++
++#***********************************************************************
++# %PROCEDURE: GenerateSecretsEntry
++# %ARGUMENTS:
++# conn -- a connection key/value list
++# %RETURNS:
++# Nothing
++# %DESCRIPTION:
++# Adds entries to /etc/ppp/pap-secrets and /etc/ppp/chap-secrets.
++#***********************************************************************
++proc GenerateSecretsEntry { conn } {
++ set user [value $conn UserName]
++ set net [value $conn NetworkName]
++ set password [value $conn Password]
++ if {&quot;$net&quot; != &quot;&quot;} {
++ set user &quot;$user@$net&quot;
++ }
++ GenerateSecretsEntryForFile $user $password &quot;/etc/ppp/pap-secrets&quot;
++ GenerateSecretsEntryForFile $user $password &quot;/etc/ppp/chap-secrets&quot;
++}
++
++#***********************************************************************
++# %PROCEDURE: GenerateSecretsEntryForFile
++# %ARGUMENTS:
++# user -- user name
++# password -- password
++# fname -- file to add entry to.
++# %RETURNS:
++# Nothing
++# %DESCRIPTION:
++# Adds entries to /etc/ppp/pap-secrets or /etc/ppp/chap-secrets.
++#***********************************************************************
++proc GenerateSecretsEntryForFile { user password fname } {
++ # Copy $fname to $fname.new
++ set out [open &quot;$fname.new&quot; &quot;w&quot;]
++ exec chmod go-rwx &quot;$fname.new&quot;
++ if {[file exists $fname]} {
++ set in [open $fname &quot;r&quot;]
++ while {[gets $in line] &gt;= 0} {
++ set trimmed [string trim $line]
++ if {&quot;$trimmed&quot; == &quot;&quot;} {
++ puts $out $line
++ continue
++ }
++ if {[string match &quot;#*&quot; $trimmed]} {
++ puts $out $line
++ continue
++ }
++
++ # Read the user name off the line; copy it unless it's our
++ # user name.
++ foreach {word dummy} [ReadShellEscapedWord $line] {break}
++ if {$word != $user} {
++ puts $out $line
++ }
++ }
++ close $in
++ }
++
++ # Now add our line
++ set user [ShellEscape $user]
++ set password [ShellEscape $password]
++ puts $out &quot;$user\t*\t$password\t*&quot;
++ close $out
++ file rename -force $fname.new $fname
++}
++
++#***********************************************************************
++# %PROCEDURE: ShellEscape
++# %ARGUMENTS:
++# str
++# %RETURNS:
++# A version of $str with shell meta-characters escaped
++#***********************************************************************
++proc ShellEscape { str } {
++ set ans &quot;&quot;
++ foreach char [split $str &quot;&quot;] {
++ if {[string first $char &quot;01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_+=<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">- at .</A>/&quot;] &gt;= 0} {
++ append ans $char
++ } else {
++ append ans &quot;\\$char&quot;
++ }
++ }
++ return $ans
++}
++
++
++#***********************************************************************
++# %PROCEDURE: GenerateConfigFile
++# %ARGUMENTS:
++# conn -- a connection key/value list
++# %RETURNS:
++# Nothing
++# %DESCRIPTION:
++# Generates a configuration file for adsl-start and friends under
++# /etc/ppp/rp-pppoe-gui
++#***********************************************************************
++proc GenerateConfigFile { conn } {
++ global ConfigDir
++ set name [value $conn ConnectionName]
++ set fname [file join $ConfigDir conf.$name]
++ set fp [open &quot;$fname.new&quot; w]
++ puts $fp &quot;# Configuration file for connection `$name'.&quot;
++ puts $fp &quot;# Automatically generated. Do not edit by hand.&quot;
++ puts $fp &quot;&quot;
++ foreach {var val} $conn {
++ switch -exact $var {
++ UserName {
++ set net [value $conn NetworkName]
++ if {&quot;$net&quot; != &quot;&quot;} {
++ set user &quot;$val@$net&quot;
++ } else {
++ set user &quot;$val&quot;
++ }
++ puts $fp [ShellEscape &quot;USER=$user&quot;]
++ }
++ Interface {
++ puts $fp [ShellEscape &quot;ETH=$val&quot;]
++ }
++ DNSType {
++ if {&quot;$val&quot; == &quot;From Server&quot;} {
++ puts $fp &quot;DNSTYPE=SERVER&quot;
++ puts $fp &quot;USEPEERDNS=yes&quot;
++ } elseif {&quot;$val&quot; == &quot;Specify&quot;} {
++ puts $fp &quot;DNSTYPE=SPECIFY&quot;
++ puts $fp &quot;USEPEERDNS=no&quot;
++ } else {
++ puts $fp &quot;DNSTYPE=NOCHANGE&quot;
++ puts $fp &quot;USEPEERDNS=no&quot;
++ }
++ }
++ DNS1 {
++ puts $fp [ShellEscape &quot;DNS1=$val&quot;]
++ }
++ DNS2 {
++ puts $fp [ShellEscape &quot;DNS2=$val&quot;]
++ }
++ NonrootOK {
++ if {$val} {
++ puts $fp &quot;NONROOT=OK&quot;
++ }
++ }
++ ACName {
++ puts $fp [ShellEscape &quot;ACNAME=$val&quot;]
++ }
++ ServiceName {
++ puts $fp [ShellEscape &quot;SERVICENAME=$val&quot;]
++ }
++ FirewallType {
++ if {&quot;$val&quot; == &quot;None&quot;} {
++ puts $fp &quot;FIREWALL=NONE&quot;
++ } elseif {&quot;$val&quot; == &quot;Masquerading&quot;} {
++ puts $fp &quot;FIREWALL=MASQUERADE&quot;
++ } else {
++ puts $fp &quot;FIREWALL=STANDALONE&quot;
++ }
++ }
++ Sync {
++ if {$val} {
++ puts $fp &quot;SYNCHRONOUS=yes&quot;
++ } else {
++ puts $fp &quot;SYNCHRONOUS=no&quot;
++ }
++ }
++ }
++ }
++ puts $fp &quot;CONNECT_TIMEOUT=30&quot;
++ puts $fp &quot;CONNECT_POLL=1&quot;
++ puts $fp &quot;FORCEPING=\&quot;.\&quot;&quot;
++ puts $fp &quot;PIDFILE=/var/run/adsl-$name.pid&quot;
++ puts $fp &quot;CLAMPMSS=1412&quot;
++ puts $fp &quot;LCP_INTERVAL=20&quot;
++ puts $fp &quot;LCP_FAILURE=3&quot;
++ puts $fp &quot;PPPOE_TIMEOUT=80&quot;
++ puts $fp &quot;LINUX_PLUGIN=&quot;
++ puts $fp &quot;DEMAND=no&quot;
++ close $fp
++ file rename -force &quot;$fname.new&quot; &quot;$fname&quot;
++}
++
++#***********************************************************************
++# %PROCEDURE: GetConnectionStatus
++# %ARGUMENTS:
++# conn -- connection name
++# %RETURNS:
++# A three-element list:
++# {started/stopped up/down if}
++# If first element is &quot;started&quot;, then connection has been started.
++# If second element is &quot;up&quot;, then connection is up.
++# If connection is up, third element is PPP interface.
++#***********************************************************************
++proc GetConnectionStatus { conn } {
++ set pidfile &quot;/var/run/adsl-$conn.pid&quot;
++
++ # Check for PID file
++ if {![file readable $pidfile]} {
++ return {stopped down &quot;&quot;}
++ }
++ set fp [open $pidfile &quot;r&quot;]
++ gets $fp pid
++ close $fp
++
++ # Check if process is dead
++ if {![file exists &quot;/proc/$pid&quot;]} {
++ # The pppd might still be running... doh...
++ if {![file readable &quot;$pidfile.pppd&quot;]} {
++ return {stopped down &quot;&quot;}
++ }
++ set fp [open &quot;$pidfile.pppd&quot; &quot;r&quot;]
++ gets $fp pid
++ close $fp
++ if {![file exists &quot;/proc/$pid&quot;]} {
++ return {stopped down &quot;&quot;}
++ }
++ }
++
++ # Now get PID of pppd
++ if {![file readable &quot;$pidfile.pppd&quot;]} {
++ return {started down &quot;&quot;}
++ }
++ set fp [open &quot;$pidfile.pppd&quot; &quot;r&quot;]
++ gets $fp pid
++ close $fp
++
++ # Find interface to which it corresponds
++ set pppdfiles [glob -nocomplain &quot;/var/run/ppp*.pid&quot;]
++ set found {}
++ foreach file $pppdfiles {
++ set fp [open $file &quot;r&quot;]
++ gets $fp ifpid
++ close $fp
++ if {$ifpid == $pid} {
++ set found [file rootname [file tail $file]]
++ break
++ }
++ }
++ if {&quot;$found&quot; == &quot;&quot;} {
++ return {started down &quot;&quot;}
++ }
++ return [list started up $found]
++}
++
++#***********************************************************************
++# %PROCEDURE: UpdateConnectionState
++# %ARGUMENTS:
++# fromAfter -- if 1, was called from an &quot;after&quot; callback.
++# %RETURNS:
++# Nothing
++# %DESCRIPTION:
++# Updates the &quot;LED&quot; displays; periodically reschedules itself to keep
++# updating display.
++#***********************************************************************
++proc UpdateConnectionState {{fromAfter 1}} {
++ global UpdateToken
++ global Packets
++ global Bytes
++ global UpdateInterval
++ global MeasureTime
++ if {$fromAfter} {
++ set UpdateToken &quot;&quot;
++ }
++
++ set conn [GetCurrentConnection]
++ if {&quot;$conn&quot; == &quot;&quot;} {
++ ConnectionStateOff
++ ResetGraph
++ if {&quot;$UpdateToken&quot; != &quot;&quot;} {
++ after cancel $UpdateToken
++ set UpdateToken {}
++ }
++ return
++ }
++
++ foreach {startstop updown interface} [GetConnectionStatus $conn] {break}
++ if {&quot;$startstop&quot; == &quot;stopped&quot;} {
++ ConnectionStateOff
++ ResetGraph
++ } elseif {&quot;$updown&quot; == &quot;down&quot;} {
++ ConnectionStateDown
++ ResetGraph
++ } else {
++ # Get the packet counts
++ set found 0
++ set fp [open &quot;/proc/net/dev&quot; &quot;r&quot;]
++ while {[gets $fp line] &gt;= 0} {
++ if {![string match &quot;*$interface:*&quot; $line]} {
++ continue
++ }
++ set colon [string first &quot;:&quot; $line]
++ if {$colon &lt; 0} {
++ continue
++ }
++ set line [string range $line [expr $colon+1] end]
++ set found 1
++ set MeasureTime [clock seconds]
++ break
++ }
++ close $fp
++ if {$found} {
++ foreach {rbytes rpacks rerrs rdrop rfifo rframe rcomp rmulti tbytes tpacks} $line {break}
++ if {!$fromAfter} {
++ set Packets(in) $rpacks
++ set Packets(out) $tpacks
++ set Bytes(in) $rbytes
++ set Bytes(out) $tbytes
++ ConnectionStateUp
++ ResetGraph
++ } else {
++ if {$rpacks != $Packets(in)} {
++ ConnectionReceiveActive
++ } else {
++ ConnectionReceiveUp
++ }
++ if {$tpacks != $Packets(out)} {
++ ConnectionTransmitActive
++ } else {
++ ConnectionTransmitUp
++ }
++ set Packets(in) $rpacks
++ set Packets(out) $tpacks
++ set Bytes(in) $rbytes
++ set Bytes(out) $tbytes
++ UpdateGraph
++ }
++ } else {
++ ConnectionStateUp
++ ResetGraph
++ }
++ }
++ if {&quot;$UpdateToken&quot; == &quot;&quot;} {
++ set UpdateToken [after $UpdateInterval UpdateConnectionState]
++ }
++ if {$fromAfter} {
++ SetButtonStates
++ }
++}
++
++proc ConnectionStateOff {} {
++ .c itemconfigure xmitrect -fill &quot;#A0A0A0&quot;
++ .c itemconfigure recvrect -fill &quot;#A0A0A0&quot;
++}
++
++proc ConnectionStateDown {} {
++ .c itemconfigure xmitrect -fill &quot;#A00000&quot;
++ .c itemconfigure recvrect -fill &quot;#A00000&quot;
++}
++
++proc ConnectionStateUp {} {
++ .c itemconfigure xmitrect -fill &quot;#00D000&quot;
++ .c itemconfigure recvrect -fill &quot;#00D000&quot;
++}
++
++proc ConnectionTransmitActive {} {
++ .c itemconfigure xmitrect -fill &quot;#FFFF00&quot;
++}
++
++proc ConnectionTransmitUp {} {
++ .c itemconfigure xmitrect -fill &quot;#00D000&quot;
++}
++
++proc ConnectionReceiveActive {} {
++ .c itemconfigure recvrect -fill &quot;#FFFF00&quot;
++}
++
++proc ConnectionReceiveUp {} {
++ .c itemconfigure recvrect -fill &quot;#00D000&quot;
++}
++
++proc ResetGraph {} {
++ global GraphPoints
++ set GraphPoints(in) {}
++ set GraphPoints(out) {}
++ set GraphPoints(times) {}
++ .graph delete all
++ UpdateGraph
++}
++
++proc UpdateGraph {} {
++ global GraphPoints Bytes UpdateInterval MeasureTime
++ lappend GraphPoints(times) $MeasureTime
++ lappend GraphPoints(in) $Bytes(in)
++ lappend GraphPoints(out) $Bytes(out)
++
++ set w [winfo width .graph]
++ set w2 [expr $w/2]
++
++ set h [winfo height .graph]
++ set toChop [expr [llength $GraphPoints(in)] - $w2 - 1]
++ if {$toChop &gt; 0} {
++ set GraphPoints(in) [lrange $GraphPoints(in) $toChop end]
++ }
++ set toChop [expr [llength $GraphPoints(out)] - $w2 - 1]
++ if {$toChop &gt; 0} {
++ set GraphPoints(out) [lrange $GraphPoints(out) $toChop end]
++ }
++ set toChop [expr [llength $GraphPoints(times)] - $w2 - 1]
++ if {$toChop &gt; 0} {
++ set GraphPoints(times) [lrange $GraphPoints(times) $toChop end]
++ }
++
++ set prev [lindex $GraphPoints(in) 0]
++ set incoords {}
++ set outcoords {}
++ set inmax 0
++ set outmax 0
++ foreach thing [lrange $GraphPoints(in) 1 end] {
++ set diff [expr $thing - $prev]
++ set prev $thing
++ lappend incoords $diff
++ if {$diff &gt; $inmax} {
++ set inmax $diff
++ }
++ }
++
++ set prev [lindex $GraphPoints(out) 0]
++ foreach thing [lrange $GraphPoints(out) 1 end] {
++ set diff [expr $thing - $prev]
++ set prev $thing
++ lappend outcoords $diff
++ if {$diff &gt; $outmax} {
++ set outmax $diff
++ }
++ }
++
++ if {$inmax == 0} { set inmax 1 }
++ if {$outmax == 0} { set outmax 1 }
++ # Draw the transmit line
++ set x 0
++ set hh [expr $h-4]
++ set scaled {}
++ foreach thing $outcoords {
++ lappend scaled $x [expr double($h) - 2 - (double($hh) * double($thing) / double($outmax))]
++ incr x
++ }
++
++ .graph delete all
++ if {[llength $scaled] &gt;= 4} {
++ eval &quot;.graph create line $scaled -fill #A00000&quot;
++ set bits [expr 8.0 * ([lindex $GraphPoints(out) end] - [lindex $GraphPoints(out) 0])]
++ set timediff [expr [lindex $GraphPoints(times) end] - [lindex $GraphPoints(times) 0]]
++ if {$timediff != 0} {
++ set bps [Pretty [expr double($bits) / $timediff]]
++ .graph create text 2 2 -anchor nw -font fixed -text &quot;$bps&quot;
++ }
++ }
++
++ # Draw the receive line
++ set x $w2
++ set scaled {}
++ foreach thing $incoords {
++ lappend scaled $x [expr double($h) - 2 - (double($hh) * double($thing) / double($inmax))]
++ incr x
++ }
++
++ if {[llength $scaled] &gt;= 4} {
++ eval &quot;.graph create line $scaled -fill #00A000&quot;
++ set bits [expr 8.0 * ([lindex $GraphPoints(in) end] - [lindex $GraphPoints(in) 0])]
++ set timediff [expr [lindex $GraphPoints(times) end] - [lindex $GraphPoints(times) 0]]
++ if {$timediff != 0} {
++ set bps [Pretty [expr double($bits) / $timediff]]
++ .graph create text [expr $w2+2] 2 -anchor nw -font fixed -text &quot;$bps&quot;
++ }
++ }
++}
++
++proc Pretty { n } {
++ if {$n &lt; 0} {
++ return &quot;***&quot;
++ }
++ if {$n &lt; 1000} {
++ return [format &quot;%.1f&quot; $n]
++ }
++ set n [expr $n/1000.0]
++ if {$n &lt; 1000} {
++ return [format &quot;%.1fk&quot; $n]
++ }
++ set n [expr $n/1000.0]
++ if {$n &lt; 1000} {
++ return [format &quot;%.1fM&quot; $n]
++ }
++ set n [expr $n/1000.0]
++ return [format &quot;%.1fG&quot; $n]
++}
++
++#***********************************************************************
++# %PROCEDURE: Help
++# %ARGUMENTS:
++# None
++# %RETURNS:
++# Nothing
++# %DESCRIPTION:
++# Opens help page
++#***********************************************************************
++proc Help {} {
++ if {![file readable /usr/share/rp-pppoe-gui/tkpppoe.html]} {
++ tk_dialog .err Error &quot;Help file '/usr/share/rp-pppoe-gui/tkpppoe.html' is not installed&quot; error 0 OK
++ return
++ }
++ catch { exec /bin/sh -c &quot;netscape -remote 'openURL(/usr/share/rp-pppoe-gui/tkpppoe.html)' || netscape /usr/share/rp-pppoe-gui/tkpppoe.html&quot; &gt; /dev/null 2&gt;/dev/null &amp; }
++}
++
++
++
++#***********************************************************************
++# %PROCEDURE: doLogo
++# %ARGUMENTS:
++# None
++# %RETURNS:
++# Nothing
++# %DESCRIPTION:
++# Does the logo thing
++#***********************************************************************
++proc doLogo {} {
++ global AlreadyRunFile ConfigDir
++ if {[file exists $AlreadyRunFile]} {
++ return
++ }
++ catch { file mkdir $ConfigDir }
++ catch { close [open $AlreadyRunFile &quot;w&quot;] }
++ canvas .c -width 374 -height 286 -bg #FFFFCC
++ pack .c
++ drawLogo .c #FFFFCC
++
++ # Funky effect
++ .c create text 4 4 -anchor nw -text &quot;Welcome to RP-PPPoE&quot; \
++ -fill red -font {-family times -size -24 -weight bold} -tags pppoe
++ .c lower pppoe
++
++ .c move logo -300 0
++
++ update idletasks
++
++ for {set i 0} {$i &lt; 15} {incr i} {
++ .c move logo 20 0
++ update idletasks
++ after 25
++ }
++
++ .c create text 4 28 -anchor nw -text &quot;<A HREF="http://www.roaringpenguin.com">http://www.roaringpenguin.com</A>&quot; \
++ -fill red -font {-family courier -size -14 -weight bold}
++ update idletasks
++ after 2500
++}
++
++doLogo
++catch { destroy .c }
++
++# Try creating an empty config file if none exists
++if {![file readable $ConnectionInfoFile]} {
++ catch { file mkdir $ConfigDir }
++ catch {
++ set fp [open $ConnectionInfoFile &quot;w&quot;]
++ close $fp
++ }
++}
++
++CreateMainDialog
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/gui/tkpppoe.in
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/gui/wrapper.c
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/gui/wrapper.c (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/gui/wrapper.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,234 @@
++/* -*-Mode: C;-*- */
++
++/***********************************************************************
++*
++* wrapper.c
++*
++* C wrapper designed to run SUID root for controlling PPPoE connections.
++*
++* Copyright (C) 2001 by Roaring Penguin Software Inc.
++*
++***********************************************************************/
++
++static char const RCSID[] =
++&quot;$Id: wrapper.c 195724 2001-06-11 13:49:39Z gc $&quot;;
++
++#define _SVID_SOURCE 1 /* For putenv */
++#define _POSIX_SOURCE 1 /* For fileno */
++#define _BSD_SOURCE 1 /* For setreuid */
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;errno.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;unistd.h&gt;
++
++#define CONN_NAME_LEN 64
++#define LINELEN 512
++
++static char const *adsl_start = ADSL_START_PATH;
++static char const *adsl_stop = ADSL_STOP_PATH;
++static char const *adsl_status = ADSL_STATUS_PATH;
++
++/**********************************************************************
++ *%FUNCTION: PathOK
++ *%ARGUMENTS:
++ * fname -- a file name.
++ *%RETURNS:
++ * 1 if path to fname is secure; 0 otherwise.
++ *%DESCRIPTION:
++ * Makes sure ownership/permissions of file and parent directories
++ * are safe.
++ **********************************************************************/
++static int
++PathOK(char const *fname)
++{
++ char path[LINELEN];
++ struct stat buf;
++ char const *slash;
++
++ if (strlen(fname) &gt; LINELEN) {
++ fprintf(stderr, &quot;Pathname '%s' too long\n&quot;, fname);
++ return 0;
++ }
++
++ /* Must be absolute path */
++ if (*fname != '/') {
++ fprintf(stderr, &quot;Unsafe path '%s' not absolute\n&quot;, fname);
++ return 0;
++ }
++
++ /* Check root directory */
++ if (stat(&quot;/&quot;, &amp;buf) &lt; 0) {
++ perror(&quot;stat&quot;);
++ return 0;
++ }
++ if (buf.st_uid) {
++ fprintf(stderr, &quot;SECURITY ALERT: Root directory (/) not owned by root\n&quot;);
++ return 0;
++ }
++ if (buf.st_mode &amp; (S_IWGRP | S_IWOTH)) {
++ fprintf(stderr, &quot;SECURITY ALERT: Root directory (/) writable by group or other\n&quot;);
++ return 0;
++ }
++
++ /* Check each component */
++ slash = fname;
++
++ while(*slash) {
++ slash = strchr(slash+1, '/');
++ if (!slash) {
++ slash = fname + strlen(fname);
++ }
++ memcpy(path, fname, slash-fname);
++ path[slash-fname] = 0;
++ if (stat(path, &amp;buf) &lt; 0) {
++ perror(&quot;stat&quot;);
++ return 0;
++ }
++ if (buf.st_uid) {
++ fprintf(stderr, &quot;SECURITY ALERT: '%s' not owned by root\n&quot;, path);
++ return 0;
++ }
++
++ if (buf.st_mode &amp; (S_IWGRP | S_IWOTH)) {
++ fprintf(stderr, &quot;SECURITY ALERT: '%s' writable by group or other\n&quot;,
++ path);
++ return 0;
++ }
++ }
++ return 1;
++}
++
++/**********************************************************************
++ *%FUNCTION: CleanEnvironment
++ *%ARGUMENTS:
++ * envp -- environment passed to main
++ *%RETURNS:
++ * Nothing
++ *%DESCRIPTION:
++ * Deletes all environment variables; makes safe environment
++ **********************************************************************/
++static void
++CleanEnvironment(char *envp[])
++{
++ envp[0] = NULL;
++ putenv(&quot;PATH=/bin:/usr/bin:/sbin:/usr/sbin&quot;);
++}
++
++/**********************************************************************
++ *%FUNCTION: main
++ *%ARGUMENTS:
++ * argc, argv -- usual suspects
++ * Usage: pppoe-wrapper {start|stop|status} {connection_name}
++ *%RETURNS:
++ * Whatever adsl-start, adsl-stop or adsl-status returns.
++ *%DESCRIPTION:
++ * Runs adsl-start, adsl-stop or adsl-status on given connection if
++ * non-root users are allowed to do it.
++ **********************************************************************/
++int
++main(int argc, char *argv[])
++{
++ int amRoot;
++ char *cp;
++ char fname[64+CONN_NAME_LEN];
++ char line[LINELEN+1];
++ int allowed = 0;
++
++ FILE *fp;
++
++ extern char **environ;
++
++ /* Clean out environment */
++ CleanEnvironment(environ);
++
++ /* Are we root? */
++ amRoot = (getuid() == 0);
++
++ /* Validate arguments */
++ if (argc != 3) {
++ fprintf(stderr, &quot;Usage: %s {start|stop|status} connection_name\n&quot;,
++ argv[0]);
++ exit(1);
++ }
++
++ if (strcmp(argv[1], &quot;start&quot;) &amp;&amp;
++ strcmp(argv[1], &quot;stop&quot;) &amp;&amp;
++ strcmp(argv[1], &quot;status&quot;)) {
++ fprintf(stderr, &quot;Usage: %s {start|stop|status} connection_name\n&quot;,
++ argv[0]);
++ exit(1);
++ }
++
++ /* Connection name can be at most CONN_NAME_LEN chars; alpha, num, underscore */
++ if (strlen(argv[2]) &gt; CONN_NAME_LEN) {
++ fprintf(stderr, &quot;%s: Connection name '%s' too long.\n&quot;,
++ argv[0], argv[2]);
++ exit(1);
++ }
++
++ for (cp = argv[2]; *cp; cp++) {
++ if (!strchr(&quot;abcdefghijklmnopqrstuvwxyz&quot;
++ &quot;ABCDEFGHIJKLMNOPQRSTUVWXYZ&quot;
++ &quot;0123456789_-&quot;, *cp)) {
++ fprintf(stderr, &quot;%s: Connection name '%s' contains illegal character '%c'\n&quot;, argv[0], argv[2], *cp);
++ exit(1);
++ }
++ }
++
++ /* Open the connection file */
++ sprintf(fname, &quot;/etc/ppp/rp-pppoe-gui/conf.%s&quot;, argv[2]);
++ /* Check path sanity */
++ if (!PathOK(fname)) {
++ exit(1);
++ }
++
++ fp = fopen(fname, &quot;r&quot;);
++ if (!fp) {
++ fprintf(stderr, &quot;%s: Could not open '%s': %s\n&quot;,
++ argv[0], fname, strerror(errno));
++ exit(1);
++ }
++
++ /* Check if non-root users can control it */
++ if (amRoot) {
++ allowed = 1;
++ } else {
++ while (!feof(fp)) {
++ if (!fgets(line, LINELEN, fp)) {
++ break;
++ }
++ if (!strcmp(line, &quot;NONROOT=OK\n&quot;)) {
++ allowed = 1;
++ break;
++ }
++ }
++ }
++ fclose(fp);
++
++ if (!allowed) {
++ fprintf(stderr, &quot;%s: Non-root users are not permitted to control connection '%s'\n&quot;, argv[0], argv[2]);
++ exit(1);
++ }
++
++ /* Become root with setuid() to defeat is-root checks in shell scripts */
++ if (setreuid(0, 0) &lt; 0) {
++ perror(&quot;setreuid&quot;);
++ exit(1);
++ }
++
++ /* It's OK -- do it. */
++ if (!strcmp(argv[1], &quot;start&quot;)) {
++ if (!PathOK(adsl_start)) exit(1);
++ execl(adsl_start, &quot;adsl-start&quot;, fname, NULL);
++ } else if (!strcmp(argv[1], &quot;stop&quot;)) {
++ if (!PathOK(adsl_stop)) exit(1);
++ execl(adsl_stop, &quot;adsl-stop&quot;, fname, NULL);
++ } else {
++ if (!PathOK(adsl_status)) exit(1);
++ execl(adsl_status, &quot;adsl-status&quot;, fname, NULL);
++ }
++ fprintf(stderr, &quot;%s: execl: %s\n&quot;, argv[0], strerror(errno));
++ exit(1);
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/gui/wrapper.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/man/adsl-connect.8
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/man/adsl-connect.8 (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/man/adsl-connect.8 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,66 @@
++.\&quot; $Id: adsl-connect.8 195724 2001-06-11 13:49:39Z gc $
++.TH ADSL-CONNECT 8 &quot;21 February 2000&quot;
++.UC 4
++.SH NAME
++adsl-connect \- Shell script to manage a PPPoE link
++
++.SH SYNOPSIS
++.B adsl-connect \fR[\fIconfig_file\fR]
++.P
++.B adsl-connect \fR\fIinterface user\fR [\fIconfig_file\fR]
++
++
++.SH DESCRIPTION
++\fBadsl-connect\fR is a shell script which manages an ADSL connection
++using the Roaring Penguin user-space PPPoE client. If you omit
++\fIconfig_file\fR, the default file \fB/etc/ppp/pppoe.conf\fR is used.
++If you supply \fIinterface\fR and \fIuser\fR, then they override the
++Ethernet interface and user-name settings in the configuration file.
++.P
++Note that normally, you should \fInot\fR invoke \fBadsl-connect\fR
++directly. Instead, use \fBadsl-start\fR to bring up the ADSL connection.
++.P
++\fBadsl-connect\fR first reads a configuration file. It then brings
++up a PPPoE connection. If the connection ever drops, a message is logged
++to syslog, and \fBadsl-connect\fR re-establishes the connection. In addition,
++each time the connection is dropped or cannot be established,
++\fBadsl-connect\fR executes the script \fB/etc/ppp/adsl-lost\fR if it
++exists and is executable.
++
++.P
++The shell script \fBadsl-stop\fR causes \fBadsl-connect\fR to break out
++of its loop, bring the connection down, and exit.
++
++.SH TECHNICAL DETAILS
++\fBadsl-connect\fR uses the following shell variables from the
++configuration file:
++
++.TP
++.B ETH
++The Ethernet interface connected to the ADSL modem (for example, eth0).
++
++.TP
++.B USER
++The ADSL user-id (for example, <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">b1xxnxnx at sympatico.ca</A>).
++
++.TP
++.B PIDFILE
++A file in which to write the process-ID of the adsl-connect process
++(for example, \fB/var/run/pppoe.pid\fR). Two additional files
++($PIDFILE.pppd and $PIDFILE.pppoe) hold the process-ID's of the
++\fBpppd\fR and \fBpppoe\fR processes, respectively.
++
++.P
++By using different configuration files with different PIDFILE
++settings, you can manage multiple PPPoE connections. Just specify the
++configuration file as an argument to \fBadsl-start\fR and
++\fBadsl-stop\fR.
++
++.SH AUTHOR
++\fBadsl-connect\fR was written by David F. Skoll &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dfs at roaringpenguin.com</A>&gt;.
++
++The \fBpppoe\fR home page is \<A HREF="fIhttp://www.roaringpenguin.com/pppoe/\fR.">fIhttp://www.roaringpenguin.com/pppoe/\fR.</A>
++
++.SH SEE ALSO
++pppoe(8), adsl-start(8), adsl-stop(8), pppd(8), pppoe.conf(5), adsl-setup(8), adsl-status(8), pppoe-sniff(8), pppoe-server(8), pppoe-relay(8)
++
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/man/adsl-setup.8
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/man/adsl-setup.8 (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/man/adsl-setup.8 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,23 @@
++.\&quot; $Id: adsl-setup.8 195724 2001-06-11 13:49:39Z gc $
++.TH ADSL-SETUP 8 &quot;21 February 2000&quot;
++.UC 4
++.SH NAME
++adsl-setup \- Shell script to configure Roaring Penguin PPPoE client
++.SH SYNOPSIS
++.B adsl-setup
++
++.SH DESCRIPTION
++\fBadsl-setup\fR is a shell script which prompts you for various pieces
++of information and sets up an /etc/ppp/pppoe.conf configuration script
++for the \fBadsl-start\fR, \fBadsl-stop\fR and \fBadsl-connect\fR scripts.
++
++.SH AUTHOR
++\fBadsl-setup\fR was written by David F. Skoll &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dfs at roaringpenguin.com</A>&gt;.
++
++The \fBpppoe\fR home page is \<A HREF="fIhttp://www.roaringpenguin.com/pppoe/\fR.">fIhttp://www.roaringpenguin.com/pppoe/\fR.</A>
++
++.SH SEE ALSO
++pppoe(8), adsl-start(8), adsl-stop(8), adsl-connect(8), pppd(8),
++pppoe.conf(5), adsl-status(8), pppoe-sniff(8), pppoe-relay(8),
++pppoe-server(8)
++
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/man/adsl-start.8
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/man/adsl-start.8 (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/man/adsl-start.8 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,27 @@
++.\&quot; $Id: adsl-start.8 195724 2001-06-11 13:49:39Z gc $
++.TH ADSL-START 8 &quot;21 February 2000&quot;
++.UC 4
++.SH NAME
++adsl-start \- Shell script to bring up a PPPoE link
++.SH SYNOPSIS
++.B adsl-start \fR[\fIconfig_file\fR]
++.P
++.B adsl-start \fR\fIinterface user\fR [\fIconfig_file\fR]
++
++.SH DESCRIPTION
++\fBadsl-start\fR is a shell script which starts the Roaring Penguin
++user-space PPPoE client. If you omit \fIconfig_file\fR, the default
++file \fB/etc/ppp/pppoe.conf\fR is used. If you supply
++\fIinterface\fR and \fIuser\fR, then they override the Ethernet interface
++and user-name settings in the configuration file.
++
++.SH AUTHOR
++\fBadsl-start\fR was written by David F. Skoll &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dfs at roaringpenguin.com</A>&gt;.
++
++The \fBpppoe\fR home page is \<A HREF="fIhttp://www.roaringpenguin.com/pppoe/\fR.">fIhttp://www.roaringpenguin.com/pppoe/\fR.</A>
++
++.SH SEE ALSO
++pppoe(8), adsl-stop(8), adsl-connect(8), pppd(8), pppoe.conf(5),
++adsl-setup(8), adsl-status(8), pppoe-sniff(8), pppoe-relay(8),
++pppoe-server(8)
++
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/man/adsl-status.8
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/man/adsl-status.8 (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/man/adsl-status.8 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,25 @@
++.\&quot; $Id: adsl-status.8 195724 2001-06-11 13:49:39Z gc $
++.TH ADSL-STATUS 8 &quot;16 March 2000&quot;
++.UC 4
++.SH NAME
++adsl-status \- Shell script to report on status of PPPoE link
++.SH SYNOPSIS
++.B adsl-status \fR[\fIconfig_file\fR]
++
++.SH DESCRIPTION
++\fBadsl-status\fR is a shell script which checks the status of the
++PPPoE link established by the Roaring Penguin user-space PPPoE client.
++If you omit \fIconfig_file\fR, the default file
++\fB/etc/ppp/pppoe.conf\fR is used.
++
++.SH AUTHOR
++\fBadsl-status\fR was written by David F. Skoll &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dfs at roaringpenguin.com</A>&gt;.
++
++The \fBpppoe\fR home page is \<A HREF="fIhttp://www.roaringpenguin.com/pppoe/\fR.">fIhttp://www.roaringpenguin.com/pppoe/\fR.</A>
++
++.SH SEE ALSO
++pppoe(8), adsl-start(8), adsl-connect(8), pppd(8), pppoe.conf(5),
++adsl-setup(8), adsl-stop(8), pppoe-sniff(8), pppoe-relay(8),
++pppoe-server(8)
++
++
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/man/adsl-stop.8
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/man/adsl-stop.8 (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/man/adsl-stop.8 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,21 @@
++.\&quot; $Id: adsl-stop.8 195724 2001-06-11 13:49:39Z gc $
++.TH ADSL-STOP 8 &quot;21 February 2000&quot;
++.UC 4
++.SH NAME
++adsl-stop \- Shell script to shut down a PPPoE link
++.SH SYNOPSIS
++.B adsl-stop \fR[\fIconfig_file\fR]
++
++.SH DESCRIPTION
++\fBadsl-stop\fR is a shell script which stops the Roaring Penguin
++user-space PPPoE client. If you omit \fIconfig_file\fR, the default
++file \fB/etc/ppp/pppoe.conf\fR is used.
++
++.SH AUTHOR
++\fBadsl-stop\fR was written by David F. Skoll &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dfs at roaringpenguin.com</A>&gt;.
++
++The \fBpppoe\fR home page is \<A HREF="fIhttp://www.roaringpenguin.com/pppoe/\fR.">fIhttp://www.roaringpenguin.com/pppoe/\fR.</A>
++
++.SH SEE ALSO
++pppoe(8), adsl-start(8), adsl-connect(8), pppd(8), pppoe.conf(5), adsl-setup(8), adsl-status(8), pppoe-sniff(8), pppoe-relay(8), pppoe-server(8)
++
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/man/pppoe-relay.8
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/man/pppoe-relay.8 (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/man/pppoe-relay.8 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,124 @@
++.\&quot; $Id: pppoe-relay.8 195724 2001-06-11 13:49:39Z gc $
++.TH PPPOE-RELAY 8 &quot;26 January 2001&quot;
++.\&quot;&quot;
++.UC 4
++.SH NAME
++pppoe-relay \- user-space PPPoE relay agent.
++.SH SYNOPSIS
++.B pppoe-relay \fR[\fIoptions\fR]
++
++.SH DESCRIPTION
++\fBpppoe-relay\fR is a user-space relay agent for PPPoE
++(Point-to-Point Protocol over Ethernet) for Linux. \fBpppoe-relay\fR
++works in concert with the \fBpppoe\fR client and \fBpppoe-server\fR
++server. See the OPERATION section later in this manual for
++details on how \fBpppoe-relay\fR works.
++
++.SH OPTIONS
++.TP
++.B \-S \fIinterface\fR
++Adds the Ethernet interface \fIinterface\fR to the list of interfaces
++managed by \fBpppoe-relay\fR. Only PPPoE servers may be connected to
++this interface.
++
++.TP
++.B \-C \fIinterface\fR
++Adds the Ethernet interface \fIinterface\fR to the list of interfaces
++managed by \fBpppoe-relay\fR. Only PPPoE clients may be connected to
++this interface.
++
++.TP
++.B \-B \fIinterface\fR
++Adds the Ethernet interface \fIinterface\fR to the list of interfaces
++managed by \fBpppoe-relay\fR. Both PPPoE clients and servers may be
++connected to this interface.
++
++.TP
++.B \-n \fInum\fR
++Allows at most \fInum\fR concurrent PPPoE sessions. If not specified,
++the default is 5000. \fInum\fR can range from 1 to 65534.
++
++.TP
++.B \-i \fItimeout\fR
++Specifies the session idle timeout. If both peers in a session are idle
++for more than \fItimeout\fR seconds, the session is terminated.
++If \fItimeout\fR is specified as zero, sessions will never be terminated
++because of idleness.
++
++Note that the idle-session expiry routine is never run more frequently than
++every 30 seconds, so the timeout is approximate. The default value for
++\fItimeout\fR is 600 seconds (10 minutes.)
++
++.TP
++.B \-F
++The \fB\-F\fR option causes \fBpppoe-relay\fR \fInot\fR to fork into the
++background; instead, it remains in the foreground.
++
++.TP
++.B \-h
++The \fB\-h\fR option prints a brief usage message and exits.
++
++.SH OPERATION
++
++\fBpppoe-relay\fR listens for incoming PPPoE PADI frames on all interfaces
++specified with \fB-B\fR or \fB-C\fR options. When a PADI frame appears,
++\fBpppoe-relay\fR adds a Relay-Session-ID tag and broadcasts the PADI
++on all interfaces specified with \fB-B\fR or \fB-S\fR options (except the
++interface on which the frame arrived.)
++
++Any PADO frames received are relayed back to the client which sent the
++PADI (assuming they contain valid Relay-Session-ID tags.) Likewise,
++PADR frames from clients are relayed back to the matching access
++concentrator.
++
++When a PADS frame is received, \fBpppoe-relay\fR enters the two peers'
++MAC addresses and session-ID's into a hash table. (The session-ID seen
++by the access concentrator may be different from that seen by the client;
++\fBpppoe-relay\fR must renumber sessions to avoid the possibility of duplicate
++session-ID's.) Whenever either peer sends a session frame, \fBpppoe-relay\fR
++looks up the session entry in the hash table and relays the frame to
++the correct peer.
++
++When a PADT frame is received, \fBpppoe-relay\fR relays it to the peer
++and deletes the session entry from its hash table.
++
++If a client and server crash (or frames are lost), PADT frames may never
++be sent, and \fBpppoe-relay\fR's hash table can fill up with stale sessions.
++Therefore, a session-cleaning routine runs periodically, and removes old
++sessions from the hash table. A session is considered &quot;old&quot; if no traffic
++has been seen within \fItimeout\fR seconds. When a session is deleted because
++of a timeout, a PADT frame is sent to each peer to make certain that they
++are aware the session has been killed.
++
++.SH EXAMPLE INVOCATIONS
++
++.nf
++pppoe-relay -C eth0 -S eth1
++.fi
++
++The example above relays frames between PPPoE clients on the eth0 network
++and PPPoE servers on the eth1 network.
++
++.nf
++pppoe-relay -B eth0 -B eth1
++.fi
++
++This example is a transparent relay -- frames are relayed between any mix
++of clients and servers on the eth0 and eth1 networks.
++
++.nf
++pppoe-relay -S eth0 -C eth1 -C eth2 -C eth3
++.fi
++
++This example relays frames between servers on the eth0 network and
++clients on the eth1, eth2 and eth3 networks.
++
++.SH AUTHORS
++\fBpppoe-relay\fR was written by David F. Skoll &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dfs at roaringpenguin.com</A>&gt;.
++
++The \fBpppoe\fR home page is \<A HREF="fIhttp://www.roaringpenguin.com/pppoe/\fR.">fIhttp://www.roaringpenguin.com/pppoe/\fR.</A>
++
++.SH SEE ALSO
++adsl-start(8), adsl-stop(8), adsl-connect(8), pppd(8), pppoe.conf(5),
++pppoe(8), adsl-setup(8), adsl-status(8), pppoe-sniff(8), pppoe-server(8)
++
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/man/pppoe-server.8
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/man/pppoe-server.8 (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/man/pppoe-server.8 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,123 @@
++.\&quot; $Id: pppoe-server.8 195724 2001-06-11 13:49:39Z gc $
++.TH PPPOE-SERVER 8 &quot;3 July 2000&quot;
++.\&quot;&quot;
++.UC 4
++.SH NAME
++pppoe-server \- user-space PPPoE server
++.SH SYNOPSIS
++.B pppoe-server \fR[\fIoptions\fR]
++
++.SH DESCRIPTION
++\fBpppoe-server\fR is a user-space server for PPPoE (Point-to-Point Protocol
++over Ethernet) for Linux and other UNIX systems. \fBpppoe-server\fR works in
++concert with the \fBpppoe\fR client to respond to PPPoE discovery packets
++and set up PPPoE sessions.
++
++.SH OPTIONS
++.TP
++.B \-F
++The \fB\-F\fR option causes \fBpppoe-server\fR not to fork and become a
++daemon. The default is to fork and become a daemon.
++
++.TP
++.B \-I \fIinterface\fR
++The \fB\-I\fR option specifies the Ethernet interface to use. Under Linux,
++it is typically \fIeth0\fR or \fIeth1\fR. The interface should be &quot;up&quot;
++before you start \fBpppoe-server\fR, but should \fInot\fR be configured to have
++an IP address.
++
++.TP
++.B \-T \fItimeout\fR
++This option is passed directly to \fBpppoe\fR; see \fBpppoe\fR(8) for
++details.
++
++.TP
++.B \-C \fIac_name\fR
++Specifies which name to report as the access concentrator name. If not
++supplied, the host name is used.
++
++.TP
++.B \-m \fIMSS\fR
++This option is passed directly to \fBpppoe\fR; see \fBpppoe\fR(8) for
++details.
++
++.TP
++.B \-s
++This option is passed directly to \fBpppoe\fR; see \fBpppoe\fR(8) for
++details. In addition, it causes \fBpppd\fR to be invoked with the
++\fIsync\fR option.
++
++.TP
++.B \-L \fIip\fR
++Sets the local IP address. This is passed to spawned \fBpppd\fR processes.
++If not specified, the default is 10.0.0.1.
++
++.TP
++.B \-R \fIip\fR
++Sets the starting remote IP address. As sessions are established,
++IP addresses are assigned starting from \fIip\fR. \fBpppoe-server\fR
++automatically keeps track of the pool of addresses and passes a
++valid remote IP address to \fBpppd\fR. If not specified, a starting address
++of 10.67.15.1 is used.
++
++.TP
++.B \-N \fInum\fR
++Allows at most \fInum\fR concurrent PPPoE sessions. If not specified,
++the default is 64.
++
++.TP
++.B \-p \fIfname\fR
++Reads the specified file \fIfname\fR which is a text file consisting of
++one IP address per line. These IP addresses will be assigned to clients.
++The number of sessions allowed will equal the number of addresses found
++in the file. The \fB\-p\fR option overrides both \fB\-R\fR and \fB\-N\fR.
++
++.TP
++.B \-o \fIoffset\fR
++Instead of numbering PPPoE sessions starting at 1, they will be numbered
++starting at \fIoffset\fR+1. This allows you to run multiple servers on
++a given machine; just make sure that their session numbers do not
++overlap.
++
++.TP
++.B \-f disc:sess
++The \fB\-f\fR option sets the Ethernet frame types for PPPoE discovery
++and session frames. The types are specified as hexadecimal numbers
++separated by a colon. Standard PPPoE uses frame types 8863:8864.
++\fIYou should not use this option\fR unless you are absolutely sure
++the peer you are dealing with uses non-standard frame types.
++
++.TP
++.B \-h
++The \fB\-h\fR option prints a brief usage message and exits.
++
++.SH OPERATION
++
++\fBpppoe-server\fR listens for incoming PPPoE discovery packets. When
++a session is established, it spawns a \fBpppd\fR process. The following
++options are passed to \fBpppd\fR:
++
++.nf
++nodetach noaccomp nobsdcom nodeflate nopcomp novj novjccomp
++default-asyncmap
++.fi
++
++In addition, the local and remote IP address are set based on the
++\fB\-L\fR and \fB\-R\fR options. The \fBpty\fR option is supplied along
++with a \fBpppoe\fR command to initiate the PPPoE session. Finally,
++additional \fBpppd\fR options can be placed in the file
++\fB/etc/ppp/pppoe-server-options\fR (which must exist, even if it is just
++empty!)
++
++Note that \fBpppoe-server\fR is meant mainly for testing PPPoE clients.
++It is \fInot\fR a high-performance server meant for production use.
++
++.SH AUTHORS
++\fBpppoe-server\fR was written by David F. Skoll &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dfs at roaringpenguin.com</A>&gt;.
++
++The \fBpppoe\fR home page is \<A HREF="fIhttp://www.roaringpenguin.com/pppoe/\fR.">fIhttp://www.roaringpenguin.com/pppoe/\fR.</A>
++
++.SH SEE ALSO
++adsl-start(8), adsl-stop(8), adsl-connect(8), pppd(8), pppoe.conf(5),
++pppoe(8), adsl-setup(8), adsl-status(8), pppoe-sniff(8), pppoe-relay(8)
++
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/man/pppoe-sniff.8
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/man/pppoe-sniff.8 (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/man/pppoe-sniff.8 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,77 @@
++.\&quot; $Id: pppoe-sniff.8 195724 2001-06-11 13:49:39Z gc $
++.TH PPPOE-SNIFF 8 &quot;3 July 2000&quot;
++.\&quot;&quot;
++.UC 4
++.SH NAME
++pppoe-sniff \- examine network for non-standard PPPoE frames
++.SH SYNOPSIS
++.B pppoe-sniff \fR[\fIoptions\fR]
++
++.SH DESCRIPTION
++\fBpppoe-sniff\fR listens for likely-looking PPPoE PADR and session frames
++and deduces extra options required for \fBpppoe(8)\fR to work.
++
++Some DSL providers seem to use non-standard frame types for PPPoE frames,
++and/or require a certain value in the Service-Name field. It is often
++easier to sniff those values from a machine which can successfully connect
++rather than try to pry them out of the DSL provider.
++
++To use \fBpppoe-sniff\fR, you need two computers, a DSL modem and
++an Ethernet hub (\fInot\fR an Ethernet switch.)
++
++If the DSL modem normally connects directly to your computer's
++Ethernet card, connect it to the &quot;uplink&quot; port on the Ethernet hub.
++Plug two computers into normal ports on the hub. On one computer, run
++whatever software the DSL provider gave you on whatever operating
++system the DSL provider supports. On the other computer, run Linux and
++log in as root.
++
++On the Linux machine, put the Ethernet interface into promiscuous mode
++and start \fBpppoe-sniff\fR. If the ethernet interface is \fIeth0\fR,
++for example, type these commands:
++
++.nf
++ ifconfig eth0 promisc
++ pppoe-sniff -I eth0
++.fi
++
++On the other machine, start your DSL connection as usual. After a short
++time, \fBpppoe-sniff\fR should print recommendations for the value
++of \fBPPPOE_EXTRA\fR. Set this value in \fB/etc/ppp/pppoe.conf\fR.
++If \fBpppoe-sniff\fR indicates that something special is required in
++\fBPPPOE_EXTRA\fR, please e-mail this to \<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">fBpppoe at roaringpenguin.com</A>\fR
++along with the name of your ISP and the manufacturer and model number of
++your DSL modem. This information will be collated and provided on the
++PPPoE web page for users who do not have two computers.
++
++After \fBpppoe-sniff\fR finishes (or you stop it if it seems hung),
++remember to turn off promiscuous mode:
++
++.nf
++ ifconfig eth0 -promisc
++.fi
++
++.SH OPTIONS
++.TP
++.B \-I \fIinterface\fR
++The \fB\-I\fR option specifies the Ethernet interface to use. Under Linux,
++it is typically \fIeth0\fR or \fIeth1\fR. The interface should be &quot;up&quot;
++and in promiscuous mode before you start \fBpppoe-sniff\fR.
++
++.TP
++.B \-V
++The \fB\-V\fR option causes \fBpppoe-sniff\fR to print its version number and
++exit.
++
++.SH BUGS
++\fBpppoe-sniff\fR only works on Linux.
++
++.SH AUTHORS
++\fBpppoe-sniff\fR was written by David F. Skoll &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dfs at roaringpenguin.com</A>&gt;.
++
++The \fBpppoe\fR home page is \<A HREF="fIhttp://www.roaringpenguin.com/pppoe/\fR.">fIhttp://www.roaringpenguin.com/pppoe/\fR.</A>
++
++.SH SEE ALSO
++adsl-start(8), adsl-stop(8), adsl-connect(8), pppd(8), pppoe.conf(5),
++pppoe(8), adsl-setup(8), adsl-status(8), pppoe-server(8), pppoe-relay(8)
++
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/man/pppoe.8
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/man/pppoe.8 (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/man/pppoe.8 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,236 @@
++.\&quot; $Id: pppoe.8 195724 2001-06-11 13:49:39Z gc $
++.TH PPPOE 8 &quot;3 July 2000&quot;
++.UC 4
++.SH NAME
++pppoe \- user-space PPPoE client.
++.SH SYNOPSIS
++.B pppd pty 'pppoe \fR[\fIpppoe_options\fR]\fB' \fR[\fIpppd_options\fR]
++.P
++.B pppoe -A \fR[\fIpppoe_options\fR]
++.SH DESCRIPTION
++\fBpppoe\fR is a user-space client for PPPoE (Point-to-Point Protocol
++over Ethernet) for Linux and other UNIX systems. \fBpppoe\fR works in
++concert with the \fBpppd\fR PPP daemon to provide a PPP connection
++over Ethernet, as is used by many ADSL service providers.
++
++.SH OPTIONS
++.TP
++.B \-I \fIinterface\fR
++The \fB\-I\fR option specifies the Ethernet interface to use. Under Linux,
++it is typically \fIeth0\fR or \fIeth1\fR. The interface should be &quot;up&quot;
++before you start \fBpppoe\fR, but should \fInot\fR be configured to have
++an IP address.
++
++.TP
++.B \-T \fItimeout\fR
++The \fB\-T\fR option causes \fBpppoe\fR to exit if no session traffic
++is detected for \fItimeout\fR seconds. I recommend that you use this
++option as an extra safety measure, but if you do, you should make sure
++that PPP generates enough traffic so the timeout will normally not be
++triggered. The best way to do this is to use the
++\fIlcp-echo-interval\fR option to \fBpppd\fR. You should set the
++PPPoE timeout to be about four times the LCP echo interval.
++
++.TP
++.B \-D \fIfile_name\fR
++The \fB\-D\fR option causes every packet to be dumped to the specified
++\fIfile_name\fR. This is intended for debugging only; it produces huge
++amounts of output and greatly reduces performance.
++
++.TP
++.B \-V
++The \fB\-V\fR option causes \fBpppoe\fR to print its version number and
++exit.
++
++.TP
++.B \-A
++The \fB\-A\fR option causes \fBpppoe\fR to send a PADI packet and then print
++the names of access concentrators in each PADO packet it receives. Do not
++use this option in conjunction with \fBpppd\fR; the \fB\-A\fR option is
++meant to be used interactively to give interesting information about the
++access concentrator.
++
++.TP
++.B \-S \fIservice_name\fR
++Specifies the desired service name. \fBpppoe\fR will only initiate sessions
++with access concentrators which can provide the specified service. In
++most cases, you should \fInot\fR specify this option. Use it only if you
++know that there are multiple access concentrators or know that you need a
++specific service name.
++
++.TP
++.B \-C \fIac_name\fR
++Specifies the desired access concentrator name. \fBpppoe\fR will only
++initiate sessions with the specified access concentrator. In
++most cases, you should \fInot\fR specify this option. Use it only if you
++know that there are multiple access concentrators. If both the
++\fB\-S\fR and \fB\-C\fR options are specified, they must \fIboth\fR match
++for \fBpppoe\fR to initiate a session.
++
++.TP
++.B \-U
++Causes \fBpppoe\fR to use the Host-Uniq tag in its discovery packets. This
++lets you run multiple \fBpppoe\fR daemons without having their discovery
++packets interfere with one another. You must supply this option to
++\fIall\fR \fBpppoe\fR daemons if you intend to run multiple daemons
++simultaneously.
++
++.TP
++.B \-s
++Causes \fBpppoe\fR to use \fIsynchronous\fR PPP encapsulation. If you
++use this option, then you \fImust\fR use the \fBsync\fR option with
++\fBpppd\fR. You are encouraged to use this option if it works, because
++it greatly reduces the CPU overhead of \fBpppoe\fR. However, it
++MAY be unreliable on slow machines -- there is a race condition between
++pppd writing data and pppoe reading it. For this reason, the default
++setting is asynchronous. If you encounter bugs or crashes with Synchronous
++PPP, turn it off -- don't e-mail me for support!
++
++.TP
++.B \-m \fIMSS\fR
++Causes \fBpppoe\fR to \fIclamp\fR the TCP maximum segment size at the specified
++value. Because of PPPoE overhead, the maximum segment size for PPPoE is
++smaller than for normal Ethernet encapsulation. This could cause problems
++for machines on a LAN behind a gateway using PPPoE. If you have a LAN
++behind a gateway, and the gateway connects to the Internet using PPPoE,
++you are strongly recommended to use a \fB\-m 1412\fR option. This avoids
++having to set the MTU on all the hosts on the LAN.
++
++.TP
++.B \-p \fIfile\fR
++Causes \fBpppoe\fR to write its process-ID to the specified file. This
++can be used to locate and kill \fBpppoe\fR processes.
++
++.TP
++.B \-e \fIsess:mac\fR
++Causes \fBpppoe\fR to skip the discovery phase and move directly to the
++session phase. The session is given by \fIsess\fR and the MAC address of
++the peer by \fImac\fR. This mode is \fInot\fR meant for normal use; it
++is designed only for \fBpppoe-server\fR(8).
++
++.TP
++.B \-n
++Causes \fBpppoe\fR not to open a discovery socket. This mode is
++\fInot\fR meant for normal use; it is designed only for
++\fBpppoe-server\fR(8).
++
++.TP
++.B \-k
++Causes \fBpppoe\fR to terminate an existing session by sending a PADT frame,
++and then exit. You must use the \fB\-e\fR option in conjunction with this
++option to specify the session to kill. This may be useful for killing
++sessions when a buggy peer does not realize the session has ended.
++
++.TP
++.B \-d
++Causes \fBpppoe\fR to perform discovery and then exit, after printing
++session information to standard output. The session information is printed
++in exactly the format expected by the \fB\-e\fR option. This option lets
++you initiate a PPPoE discovery, perform some other work, and then start
++the actual PPP session. \fIBe careful\fR; if you use this option in a loop,
++you can create many sessions, which may annoy your peer.
++
++.TP
++.B \-f disc:sess
++The \fB\-f\fR option sets the Ethernet frame types for PPPoE discovery
++and session frames. The types are specified as hexadecimal numbers
++separated by a colon. Standard PPPoE uses frame types 8863:8864.
++\fIYou should not use this option\fR unless you are absolutely sure
++the peer you are dealing with uses non-standard frame types. If your
++ISP uses non-standard frame types, complain!
++
++.TP
++.B \-h
++The \fB\-h\fR option causes \fBpppoe\fR to print usage information and
++exit.
++
++.SH PPPOE BACKGROUND
++
++PPPoE (Point-to-Point Protocol over Ethernet) is described in RFC 2516
++and is a protocol which allows the session abstraction to be maintained
++over bridged Ethernet networks.
++
++PPPoE works by encapsulating PPP frames in Ethernet frames. The protocol
++has two distinct stages: The \fIdiscovery\fR and the \fIsession\fR stage.
++
++In the discovery stage, the host broadcasts a special PADI (PPPoE
++Active Discovery Initiation) frame to discover any \fIaccess
++concentrators\fR. The access concentrators (typically, only one
++access concentrator) reply with PADO (PPPoE Active Discovery Offer)
++packets, announcing their presence and the services they offer. The
++host picks one of the access concentrators and transmits a PADR (PPPoE
++Active Discovery Request) packet, asking for a session. The access
++concentrator replies with a PADS (PPPoE Active Discovery
++Session-Confirmation) packet. The protocol then moves to the session stage.
++
++In the session stage, the host and access concentrator exchange PPP frames
++embedded in Ethernet frames. The normal Ethernet MTU is 1500 bytes, but
++the PPPoE overhead plus two bytes of overhead for the encapsulated PPP
++frame mean that the MTU of the PPP interface is at most 1492 bytes.
++This causes \fIall kinds of problems\fR if you are using a Linux machine
++as a firewall and interfaces behind the firewall have an MTU greater than
++1492. In fact, to be safe, I recommend setting the MTU of machines
++behind the firewall to 1412, to allow for worst-case TCP and IP options
++in their respective headers.
++
++Normally, PPP uses the Link Control Protocol (LCP) to shut down a PPP
++link. However, the PPPoE specification allows the link to be shut down
++with a special PADT (PPPoE Active Discovery Terminate) packet. This client
++recognizes this packet and will correctly terminate if a terminate request
++is received for the PPP session.
++
++.SH DESIGN GOALS
++
++My design goals for this PPPoE client were as follows, in descending order
++of importance:
++
++.TP
++.B o
++It must work.
++
++.TP
++.B o
++It must be a user-space program and not a kernel patch.
++
++.TP
++.B o
++The code must be easy to read and maintain.
++
++.TP
++.B o
++It must be fully compliant with RFC 2516, the proposed PPPoE standard.
++
++.TP
++.B o
++It must never hang up forever -- if the connection is broken, it must
++detect this and exit, allowing a wrapper script to restart the connection.
++
++.TP
++.B o
++It must be fairly efficient.
++
++.P
++I believe I have achieved all of these goals, but (of course) am open
++to suggestions, patches and ideas. See my home page,
++<A HREF="http://www.roaringpenguin.com,">http://www.roaringpenguin.com,</A> for contact information.
++
++.SH NOTES
++
++For best results, you must give \fBpppd\fR an mtu option of
++1492. I have observed problems with excessively-large frames
++unless I set this option. Also, if \fBpppoe\fR is running on a firewall
++machine, all machines behind the firewall should have MTU's of 1412.
++
++If you have problems, check your system logs. \fBpppoe\fR logs interesting
++things to syslog. You may have to turn on logging of \fIdebug\fR-level
++messages for complete diagnosis.
++
++.SH AUTHORS
++\fBpppoe\fR was written by David F. Skoll &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dfs at roaringpenguin.com</A>&gt;,
++with much inspiration from an earlier version by Luke Stras.
++
++The \fBpppoe\fR home page is \<A HREF="fIhttp://www.roaringpenguin.com/pppoe/\fR.">fIhttp://www.roaringpenguin.com/pppoe/\fR.</A>
++
++.SH SEE ALSO
++adsl-start(8), adsl-stop(8), adsl-connect(8), pppd(8), pppoe.conf(5), adsl-setup(8), adsl-status(8), pppoe-sniff(8), pppoe-server(8), pppoe-relay(8)
++
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/man/pppoe.conf.5
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/man/pppoe.conf.5 (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/man/pppoe.conf.5 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,168 @@
++.\&quot; $Id: pppoe.conf.5 195724 2001-06-11 13:49:39Z gc $
++.\&quot;&quot;
++.TH PPPOE.CONF 5 &quot;21 February 2000&quot;
++.UC 4
++.SH NAME
++pppoe.conf \- Configuration file used by \fBadsl-start\fR(8),
++\fBadsl-stop\fR(8), \fBadsl-status(8)\fR and \fBadsl-connect\fR(8).
++
++.SH DESCRIPTION
++\fB/etc/ppp/pppoe.conf\fR is a shell script which contains configuration
++information for Roaring Penguin's ADSL scripts. Note that \fBpppoe.conf\fR
++is used only by the various adsl-* shell scripts, not by \fBpppoe\fR
++itself.
++
++\fBpppoe.conf\fR consists of a sequence of shell variable assignments.
++The variables and their meanings are:
++
++.TP
++.B ETH
++The Ethernet interface connected to the ADSL modem (for example, eth0).
++
++.TP
++.B USER
++The ADSL user-id (for example, <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">b1xxnxnx at sympatico.ca</A>).
++
++.TP
++.B SERVICENAME
++If this is not blank, then it is passed with the \fB\-S\fR option to
++\fBpppoe\fR. It specifies a service name to ask for. Usually, you
++should leave it blank.
++
++.TP
++.B ACNAME
++If this is not blank, then it is passed with the \fB\-C\fR option to
++\fBpppoe\fR. It specifies the name of the access concentrator to connect
++to. Usually, you should leave it blank.
++
++.TP
++.B DEMAND
++If set to a number, the link is activated on demand and brought down
++after after \fBDEMAND\fR seconds. If set to \fBno\fR, the link is kept
++up all the time rather than being activated on demand.
++
++.TP
++.B DNSTYPE
++One of \fBNOCHANGE\fR, \fBSPECIFY\fR or \fBSERVER\fR. If
++set to NOCHANGE, \fBadsl-connect\fR will not adjust the DNS setup in
++any way. If set to SPECIFY, it will re-write /etc/resolv.conf with
++the values of DNS1 and DNS2. If set to \fBSERVER\fR, it will
++supply the \fIusepeerdns\fR option to \fBpppd\fR, and make a symlink
++from /etc/resolv.conf to /etc/ppp/resolv.conf.
++
++.TP
++.B DNS1, DNS2
++IP addresses of DNS servers if you use DNSTYPE=SPECIFY.
++
++.TP
++.B NONROOT
++If the line \fBNONROOT=OK\fR (exactly like that; no whitespace or comments)
++appears in the configuration file, then \fBpppoe-wrapper\fR will allow
++non-root users to bring the conneciton up or down. The wrapper is installed
++only if you installed the rp-pppoe-gui package.
++
++.TP
++.B USEPEERDNS
++If set to &quot;yes&quot;, then \fBadsl-connect\fR will supply the \fIusepeerdns\fR
++option to \fBpppd\fR, which causes it to obtain DNS server addresses
++from the peer and create a new \fB/etc/resolv.conf\fR file. Otherwise,
++\fBadsl-connect\fR will not supply this option, and \fBpppd\fR will not
++modify \fB/etc/resolv.conf\fR.
++
++.TP
++.B CONNECT_POLL
++How often (in seconds) \fBadsl-start\fR should check to see if a new PPP
++interface has come up. If this is set to 0, the \fBadsl-start\fR simply
++initiates the PPP session, but does not wait to see if it comes up
++successfully.
++
++.TP
++.B CONNECT_TIMEOUT
++How long (in seconds) \fBadsl-start\fR should wait for a new PPP interface
++to come up before concluding that \fBadsl-connect\fR has failed and killing
++the session.
++
++.TP
++.B PING
++A character which is echoed every \fBCONNECT_POLL\fR seconds while
++\fBadsl-start\fR is waiting for the PPP interface to come up.
++
++.TP
++.B FORCEPING
++A character which is echoed every \fBCONNECT_POLL\fR seconds while
++\fBadsl-start\fR is waiting for the PPP interface to come up. Similar
++to \fBPING\fR, but the character is echoed even if \fBadsl-start\fR's
++standard output is not a tty.
++
++.TP
++.B PIDFILE
++A file in which to write the process-ID of the adsl-connect process
++(for example, \fB/var/run/pppoe.pid\fR). Two additional files
++($PIDFILE.pppd and $PIDFILE.pppoe) hold the process-ID's of the
++\fBpppd\fR and \fBpppoe\fR processes, respectively.
++
++.TP
++.B SYNCHRONOUS
++An indication of whether or not to use synchronous PPP (\fByes\fR or
++\fBno\fR). Synchronous PPP is safe on Linux machines with the n_hdlc
++line discipline. (If you have a file called &quot;n_hdlc.o&quot; in your
++modules directory, you have the line discipline.) It is \fInot
++recommended\fR on other machines or on Linux machines without the
++n_hdlc line discipline due to some known and unsolveable race
++conditions in a user-mode client.
++
++.TP
++.B CLAMPMSS
++The value at which to &quot;clamp&quot; the advertised MSS for TCP sessions. The
++default of 1412 should be fine.
++
++.TP
++.B LCP_INTERVAL
++How often (in seconds) \fBpppd\fR sends out LCP echo-request packets.
++
++.TP
++.B LCP_FAILURE
++How many unanswered LCP echo-requests must occur before \fBpppd\fR
++concludes the link is dead.
++
++.TP
++.B PPPOE_TIMEOUT
++If this many seconds elapse without any activity seen by \fBpppoe\fR,
++then \fBpppoe\fR exits.
++
++.TP
++.B FIREWALL
++One of NONE, STANDALONE or MASQUERADE. If NONE, then \fBadsl-connect\fR does
++not add any firewall rules. If STANDALONE, then it clears existing firewall
++rules and sets up basic rules for a standalone machine. If MASQUERADE, then
++it clears existing firewall rules and sets up basic rules for an Internet
++gateway. If you run services on your machine, these simple firewall scripts
++are inadequate; you'll have to make your own firewall rules and set FIREWALL
++to NONE.
++
++.TP
++.B PPPOE_EXTRA
++Any extra arguments to pass to \fBpppoe\fR
++
++.TP
++.B PPPD_EXTRA
++Any extra arguments to pass to \fBpppd\fR
++
++.TP
++.B LINUX_PLUGIN
++If non-blank, the full path of the Linux kernel-mode PPPoE plugin
++(typically \fB/etc/ppp/plugins/rp-pppoe.so\fR.) This forces
++\fBadsl-connect\fR to use kernel-mode PPPoE on Linux 2.4.x systems.
++This code is experimental and unsupported. Use of the plugin causes
++\fBadsl-connect\fR to ignore CLAMPMSS, PPPOE_EXTRA, SYNCHRONOUS and
++PPPOE_TIMEOUT.
++
++.P
++By using different configuration files with different PIDFILE
++settings, you can manage multiple PPPoE connections. Just specify the
++configuration file as an argument to \fBadsl-start\fR and \fBadsl-stop\fR.
++
++.SH SEE ALSO
++pppoe(8), adsl-connect(8), adsl-start(8), adsl-stop(8), pppd(8), adsl-setup(8),
++pppoe-wrapper(8)
++
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/rp-pppoe-gui.spec
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/rp-pppoe-gui.spec (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/rp-pppoe-gui.spec 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,98 @@
++Summary: PPP Over Ethernet (xDSL support)
++Name: rp-pppoe-gui
++Version: 3.0
++%if %(%{expand:test %{_vendor} != mandriva ; echo $?})
++Release: 1mdk
++%else
++Release: 1
++%endif
++Copyright: GPL
++Group: System Environment/Daemons
++Source: <A HREF="http://www.roaringpenguin.com/pppoe/rp-pppoe-3.0.tar.gz">http://www.roaringpenguin.com/pppoe/rp-pppoe-3.0.tar.gz</A>
++Url: <A HREF="http://www.roaringpenguin.com/pppoe/">http://www.roaringpenguin.com/pppoe/</A>
++Packager: David F. Skoll &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dfs at roaringpenguin.com</A>&gt;
++BuildRoot: /tmp/pppoe-build
++Vendor: Roaring Penguin Software Inc.
++Requires: ppp &gt;= 2.3.7
++Requires: rp-pppoe &gt;= 3.0
++
++%description
++This is a graphical wrapper around the rp-pppoe PPPoE client. PPPoE is
++a protocol used by many DSL Internet Service Providers.
++
++%prep
++umask 022
++mkdir -p $RPM_BUILD_ROOT
++cd $RPM_BUILD_ROOT
++rm -rf $RPM_BUILD_ROOT/rp-pppoe-%{version}
++zcat $RPM_SOURCE_DIR/rp-pppoe-%{version}.tar.gz | tar xvf -
++cd $RPM_BUILD_ROOT/rp-pppoe-%{version}/src
++./configure --mandir=%{_mandir}
++
++%build
++cd $RPM_BUILD_ROOT/rp-pppoe-%{version}/gui
++make
++
++%install
++cd $RPM_BUILD_ROOT/rp-pppoe-%{version}/gui
++make install RPM_INSTALL_ROOT=$RPM_BUILD_ROOT
++
++%clean
++rm -rf $RPM_BUILD_ROOT
++
++%post
++# Install entry in KDE menu
++if test -n &quot;$KDEDIR&quot; ; then
++ mkdir -p &quot;$KDEDIR/share/applnk/Internet&quot;
++ cat &lt;&lt;EOF &gt; &quot;$KDEDIR/share/applnk/Internet/tkpppoe.kdelnk&quot;
++# KDE Config File
++[KDE Desktop Entry]
++Name=TkPPPoE
++Comment=Start/Stop ADSL connections
++Exec=tkpppoe
++Terminal=0
++Type=Application
++EOF
++fi
++
++# Install entry in GNOME menus
++GNOMEDIR=`gnome-config --datadir 2&gt;/dev/null`
++if test -n &quot;$GNOMEDIR&quot; ; then
++ mkdir -p &quot;$GNOMEDIR/gnome/apps/Internet&quot;
++cat &lt;&lt;EOF &gt; &quot;$GNOMEDIR/gnome/apps/Internet/tkpppoe.desktop&quot;
++[Desktop Entry]
++Name=TkPPPoE
++Comment=Start/Stop ADSL connections
++Exec=tkpppoe
++Terminal=0
++Type=Application
++EOF
++fi
++
++%postun
++# Remove KDE menu entry
++if test -n &quot;$KDEDIR&quot; ; then
++ rm -f &quot;$KDEDIR/share/applnk/Internet/tkpppoe.kdelnk&quot;
++fi
++
++# Remove GNOME menu entry
++GNOMEDIR=`gnome-config --datadir 2&gt;/dev/null`
++if test -n &quot;$GNOMEDIR&quot; ; then
++ rm -f &quot;$GNOMEDIR/gnome/apps/Internet/tkpppoe.desktop&quot;
++fi
++
++%files
++%defattr(-,root,root)
++%dir /etc/ppp/rp-pppoe-gui
++/usr/sbin/pppoe-wrapper
++/usr/bin/tkpppoe
++%{_mandir}/man1/tkpppoe.1*
++%{_mandir}/man1/pppoe-wrapper.1*
++/usr/share/rp-pppoe-gui/tkpppoe.html
++/usr/share/rp-pppoe-gui/mainwin-busy.png
++/usr/share/rp-pppoe-gui/mainwin-nonroot.png
++/usr/share/rp-pppoe-gui/mainwin.png
++/usr/share/rp-pppoe-gui/props-advanced.png
++/usr/share/rp-pppoe-gui/props-basic.png
++/usr/share/rp-pppoe-gui/props-nic.png
++/usr/share/rp-pppoe-gui/props-options.png
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/rp-pppoe.spec
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/rp-pppoe.spec (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/rp-pppoe.spec 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,71 @@
++Summary: PPP Over Ethernet (xDSL support)
++Name: rp-pppoe
++Version: 3.0
++%if %(%{expand:test %{_vendor} != mandriva ; echo $?})
++Release: 1mdk
++%else
++Release: 1
++%endif
++Copyright: GPL
++Group: System Environment/Daemons
++Source: <A HREF="http://www.roaringpenguin.com/pppoe/rp-pppoe-3.0.tar.gz">http://www.roaringpenguin.com/pppoe/rp-pppoe-3.0.tar.gz</A>
++Url: <A HREF="http://www.roaringpenguin.com/pppoe/">http://www.roaringpenguin.com/pppoe/</A>
++Packager: David F. Skoll &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dfs at roaringpenguin.com</A>&gt;
++BuildRoot: /tmp/pppoe-build
++Vendor: Roaring Penguin Software Inc.
++Requires: ppp &gt;= 2.3.7
++
++%description
++PPPoE (Point-to-Point Protocol over Ethernet) is a protocol used by
++many ADSL Internet Service Providers. Roaring Penguin has a free
++client for Linux systems to connect to PPPoE service providers.
++
++The client is a user-mode program and does not require any kernel
++modifications. It is fully compliant with RFC 2516, the official PPPoE
++specification.
++
++%prep
++%setup
++cd src
++./configure --mandir=%{_mandir}
++
++%build
++cd src
++make
++
++%install
++cd src
++make install RPM_INSTALL_ROOT=$RPM_BUILD_ROOT
++
++%clean
++rm -rf $RPM_BUILD_ROOT
++
++%files
++%defattr(-,root,root)
++%doc doc/CHANGES doc/HOW-TO-CONNECT doc/LICENSE doc/KERNEL-MODE-PPPOE README
++%config /etc/ppp/pppoe.conf
++%config /etc/ppp/pppoe-server-options
++%config /etc/ppp/firewall-masq
++%config /etc/ppp/firewall-standalone
++/etc/ppp/plugins/*
++/usr/sbin/pppoe
++/usr/sbin/pppoe-server
++/usr/sbin/pppoe-sniff
++/usr/sbin/pppoe-relay
++/usr/sbin/adsl-connect
++/usr/sbin/adsl-start
++/usr/sbin/adsl-stop
++/usr/sbin/adsl-setup
++/usr/sbin/adsl-status
++%{_mandir}/man5/pppoe.conf.5*
++%{_mandir}/man8/pppoe.8*
++%{_mandir}/man8/pppoe-server.8*
++%{_mandir}/man8/pppoe-relay.8*
++%{_mandir}/man8/pppoe-sniff.8*
++%{_mandir}/man8/adsl-connect.8*
++%{_mandir}/man8/adsl-start.8*
++%{_mandir}/man8/adsl-stop.8*
++%{_mandir}/man8/adsl-status.8*
++%{_mandir}/man8/adsl-setup.8*
++/etc/rc.d/init.d/adsl
++
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-connect.in
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-connect.in (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-connect.in 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,278 @@
++#!/bin/sh
++# @configure_input@
++#***********************************************************************
++#
++# adsl-connect
++#
++# Shell script to connect to an ADSL provider using PPPoE
++#
++# Copyright (C) 2000 Roaring Penguin Software Inc.
++#
++# $Id: adsl-connect.in 195724 2001-06-11 13:49:39Z gc $
++#
++# This file may be distributed under the terms of the GNU General
++# Public License.
++#
++# Usage: adsl-connect [config_file]
++# adsl-connect interface user [config_file]
++# Second form overrides USER and ETH from config file.
++# If config_file is omitted, defaults to /etc//ppp/pppoe.conf
++#
++#***********************************************************************
++
++# From AUTOCONF
++prefix=@prefix@
++exec_prefix=@exec_prefix@
++localstatedir=/var
++
++# Paths to programs
++IFCONFIG=/sbin/ifconfig
++PPPD=@PPPD@
++SETSID=@SETSID@
++PPPOE=@sbindir@/pppoe
++LOGGER=&quot;/usr/bin/logger -t `basename $0`&quot;
++
++# Must be root
++if test &quot;`@ID@ -u`&quot; != 0 ; then
++ echo &quot;$0: You must be root to run this script&quot; &gt;&amp; 2
++ exit 1
++fi
++
++if test &quot;$SETSID&quot; != &quot;&quot; -a ! -x &quot;$SETSID&quot;; then
++ SETSID=&quot;&quot;
++fi
++
++CONFIG=/etc//ppp/pppoe.conf
++USER=&quot;&quot;
++ETH=&quot;&quot;
++
++# Sort out command-line arguments
++case &quot;$#&quot; in
++ 1)
++ CONFIG=&quot;$1&quot;
++ ;;
++ 3)
++ CONFIG=&quot;$3&quot;
++ ;;
++esac
++
++if test ! -f &quot;$CONFIG&quot; -o ! -r &quot;$CONFIG&quot; ; then
++ echo &quot;$0: Cannot read configuration file '$CONFIG'&quot; &gt;&amp; 2
++ exit 1
++fi
++
++. $CONFIG
++
++PPPOE_PIDFILE=&quot;$PIDFILE.pppoe&quot;
++PPPD_PIDFILE=&quot;$PIDFILE.pppd&quot;
++
++# Check for command-line overriding of ETH and USER
++case &quot;$#&quot; in
++ 2|3)
++ ETH=&quot;$1&quot;
++ USER=&quot;$2&quot;
++ ;;
++esac
++
++# Check that config file is sane
++if test &quot;$USER&quot; = &quot;&quot; ; then
++ echo &quot;$0: Check '$CONFIG' -- no setting for USER&quot; &gt;&amp; 2
++ exit 1
++fi
++if test &quot;$ETH&quot; = &quot;&quot; ; then
++ echo &quot;$0: Check '$CONFIG' -- no setting for ETH&quot; &gt;&amp; 2
++ exit 1
++fi
++
++PPPD_PID=0
++
++# Catch common error
++if test &quot;$DEBUG&quot; = &quot;1&quot; ; then
++ echo &quot;*** If you want to use DEBUG, invoke adsl-start, not adsl-connect.&quot;
++ exit 1
++fi
++
++if test &quot;$DEBUG&quot; != &quot;&quot; ; then
++ if test &quot;$LINUX_PLUGIN&quot; != &quot;&quot; ; then
++ echo &quot;Cannot use DEBUG mode and LINUX_PLUGIN at the same time.&quot;
++ echo &quot;Kernel-mode PPPoE is experimental and unsupported.&quot;
++ exit 1
++ fi
++ echo &quot;* The following section identifies your Ethernet interface&quot; &gt;&gt; $DEBUG
++ echo &quot;* and user name. Some ISP's need 'username'; others&quot; &gt;&gt; $DEBUG
++ echo &quot;* need '<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">username at isp.com</A>'. Try both&quot; &gt;&gt; $DEBUG
++ echo &quot;ETH=$ETH; USER=$USER&quot; &gt;&gt; $DEBUG
++ echo &quot;---------------------------------------------&quot; &gt;&gt; $DEBUG
++fi
++
++# MTU of Ethernet card attached to modem MUST be 1500. This apparently
++# fails on some *BSD's, so we'll only do it under Linux
++
++if test `uname -s` = Linux ; then
++ $IFCONFIG $ETH up mtu 1500
++ # For 2.4 kernels. Will fail on 2.2.x, but who cares?
++ modprobe ppp_generic &gt; /dev/null 2&gt;&amp;1
++ modprobe ppp_async &gt; /dev/null 2&gt;&amp;1
++ modprobe ppp_synctty &gt; /dev/null 2&gt;&amp;1
++ if test -n &quot;$LINUX_PLUGIN&quot; ; then
++ modprobe pppox &gt; /dev/null 2&gt;&amp;1
++ modprobe pppoe &gt; /dev/null 2&gt;&amp;1
++ fi
++fi
++
++if test &quot;$SYNCHRONOUS&quot; = &quot;yes&quot; ; then
++ PPPOE_SYNC=-s
++ PPPD_SYNC=sync
++ # Increase the chances of it working on Linux...
++ if test `uname -s` = Linux ; then
++ modprobe n_hdlc &gt; /dev/null 2&gt;&amp;1
++ fi
++else
++ PPPOE_SYNC=&quot;&quot;
++ PPPD_SYNC=&quot;&quot;
++fi
++
++if test -n &quot;$ACNAME&quot; ; then
++ ACNAME=&quot;-C $ACNAME&quot;
++fi
++
++if test -n &quot;$SERVICENAME&quot; ; then
++ SERVICENAME=&quot;-S $SERVICENAME&quot;
++fi
++
++if test &quot;$CLAMPMSS&quot; = &quot;no&quot; ; then
++ CLAMPMSS=&quot;&quot;
++else
++ CLAMPMSS=&quot;-m $CLAMPMSS&quot;
++fi
++
++# If DNSTYPE is SERVER, we must use &quot;usepeerdns&quot; option to pppd.
++if test &quot;$DNSTYPE&quot; = &quot;SERVER&quot; ; then
++ USEPEERDNS=yes
++fi
++
++if test &quot;$USEPEERDNS&quot; = &quot;yes&quot; ; then
++ USEPEERDNS=&quot;usepeerdns&quot;
++else
++ USEPEERDNS=&quot;&quot;
++fi
++
++# Backward config file compatibility
++if test &quot;$DEMAND&quot; = &quot;&quot; ; then
++ DEMAND=no
++fi
++
++if test &quot;$DEMAND&quot; = &quot;no&quot; ; then
++ DEMAND=&quot;&quot;
++else
++ DEMAND=&quot;demand persist idle $DEMAND 10.112.112.112:10.112.112.113 ipcp-accept-remote ipcp-accept-local connect true noipdefault ktune&quot;
++fi
++
++case &quot;$FIREWALL&quot; in
++ STANDALONE)
++ . /etc/ppp/firewall-standalone
++ ;;
++ MASQUERADE)
++ . /etc/ppp/firewall-masq
++ ;;
++esac
++
++# If we're using kernel-mode PPPoE on Linux...
++if test &quot;$LINUX_PLUGIN&quot; != &quot;&quot; ; then
++ PLUGIN_OPTS=&quot;plugin $LINUX_PLUGIN $ETH&quot;
++ modprobe pppoe &gt; /dev/null 2&gt;&amp;1
++fi
++
++# Standard PPP options we always use
++PPP_STD_OPTIONS=&quot;$PLUGIN_OPTS noipdefault noauth default-asyncmap defaultroute hide-password nodetach $USEPEERDNS local mtu 1492 mru 1492 noaccomp noccp nobsdcomp nodeflate nopcomp novj novjccomp user $USER lcp-echo-interval $LCP_INTERVAL lcp-echo-failure $LCP_FAILURE $PPPD_EXTRA&quot;
++
++# Jigger DNS if required...
++if test &quot;$DNSTYPE&quot; = &quot;SERVER&quot; ; then
++ # Sorry, dude...
++ rm -f /etc/resolv.conf
++ ln -s /etc/ppp/resolv.conf /etc/resolv.conf
++elif test &quot;$DNSTYPE&quot; = &quot;SPECIFY&quot; ; then
++ # Sorry, dude...
++ rm -f /etc/resolv.conf
++ echo &quot;nameserver $DNS1&quot; &gt; /etc/resolv.conf
++ if test -n &quot;$DNS2&quot; ; then
++ echo &quot;nameserver $DNS2&quot; &gt;&gt; /etc/resolv.conf
++ fi
++fi
++
++# PPPoE invocation
++PPPOE_CMD=&quot;$PPPOE -p $PPPOE_PIDFILE -I $ETH -T $PPPOE_TIMEOUT -U $PPPOE_SYNC $CLAMPMSS $ACNAME $SERVICENAME $PPPOE_EXTRA&quot;
++if test &quot;$DEBUG&quot; != &quot;&quot; ; then
++ if test &quot;$DEMAND&quot; != &quot;&quot; ; then
++ echo &quot;(Turning off DEMAND for debugging purposes)&quot;
++ DEMAND=&quot;&quot;
++ fi
++ echo &quot;* The following section shows the pppd command we will invoke&quot; &gt;&gt; $DEBUG
++ echo &quot;pppd invocation&quot; &gt;&gt; $DEBUG
++ echo &quot;$SETSID $PPPD pty '$PPPOE_CMD' $PPP_STD_OPTIONS $PPPD_SYNC debug&quot; &gt;&gt; $DEBUG
++ echo &quot;---------------------------------------------&quot; &gt;&gt; $DEBUG
++ $SETSID $PPPD pty &quot;$PPPOE_CMD -D $DEBUG-0&quot; \
++ $PPP_STD_OPTIONS \
++ $PPPD_SYNC \
++ debug &gt;&gt; $DEBUG 2&gt;&amp;1
++ echo &quot;---------------------------------------------&quot; &gt;&gt; $DEBUG
++ echo &quot;* The following section is an extract from your log.&quot; &gt;&gt; $DEBUG
++ echo &quot;* Look for error messages from pppd, such as&quot; &gt;&gt; $DEBUG
++ echo &quot;* a lack of kernel support for PPP, authentication failure&quot; &gt;&gt; $DEBUG
++ echo &quot;* etc.&quot; &gt;&gt; $DEBUG
++ echo &quot;Extract from /var/log/messages&quot; &gt;&gt; $DEBUG
++ grep 'ppp' /var/log/messages | tail -150 &gt;&gt; $DEBUG
++ date &gt;&gt; $DEBUG
++ echo &quot;---------------------------------------------&quot; &gt;&gt; $DEBUG
++ echo &quot;* The following section is a dump of the packets&quot; &gt;&gt; $DEBUG
++ echo &quot;* sent and received by rp-pppoe. If you don't see&quot; &gt;&gt; $DEBUG
++ echo &quot;* any output, it's an Ethernet driver problem. If you only&quot; &gt;&gt; $DEBUG
++ echo &quot;* see three PADI packets and nothing else, check your cables&quot; &gt;&gt; $DEBUG
++ echo &quot;* and modem. Make sure the modem lights flash when you try&quot; &gt;&gt; $DEBUG
++ echo &quot;* to connect. Check that your Ethernet card is in&quot; &gt;&gt; $DEBUG
++ echo &quot;* half-duplex, 10Mb/s mode. If all else fails,&quot; &gt;&gt; $DEBUG
++ echo &quot;* try using pppoe-sniff.&quot; &gt;&gt; $DEBUG
++ echo &quot;rp-pppoe debugging dump&quot; &gt;&gt; $DEBUG
++ cat $DEBUG-0 &gt;&gt; $DEBUG
++ rm -f $DEBUG-0
++ for i in 1 2 3 4 5 6 7 8 9 10 ; do
++ echo &quot;&quot;
++ echo &quot;&quot;
++ echo &quot;&quot;
++ done
++ echo &quot;*** Finished debugging run. Please review the file&quot;
++ echo &quot;*** '$DEBUG' and try to&quot;
++ echo &quot;*** figure out what is going on.&quot;
++ echo &quot;***&quot;
++ echo &quot;*** Unfortunately, we can NO LONGER accept debugging&quot;
++ echo &quot;*** output for analysis. Please do not send this to&quot;
++ echo &quot;*** Roaring Penguin; it is too time-consuming for&quot;
++ echo &quot;*** us to deal with all the analyses we have been sent.&quot;
++ exit 0
++fi
++
++echo $$ &gt; $PIDFILE
++
++while [ true ] ; do
++ if test &quot;$LINUX_PLUGIN&quot; != &quot;&quot; ; then
++ $SETSID $PPPD $PPP_STD_OPTIONS $DEMAND &amp;
++ echo &quot;$!&quot; &gt; $PPPD_PIDFILE
++ else
++ $SETSID $PPPD pty &quot;$PPPOE_CMD&quot; \
++ $PPP_STD_OPTIONS \
++ $DEMAND \
++ $PPPD_SYNC &amp;
++ echo &quot;$!&quot; &gt; $PPPD_PIDFILE
++ fi
++ wait
++
++ # Run /etc/ppp/adsl-lost if it exists
++ test -x /etc/ppp/adsl-lost &amp;&amp; /etc/ppp/adsl-lost
++
++ # Re-establish the connection
++ $LOGGER -p daemon.notice \
++ &quot;ADSL connection lost; attempting re-connection.&quot;
++
++ # Wait a bit in case a problem causes tons of log messages :-)
++ sleep 5
++done
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-connect.in
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-init-suse.in
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-init-suse.in (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-init-suse.in 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,62 @@
++#!/bin/sh
++#
++# adsl This script starts or stops an ADSL connection
++#
++# chkconfig: 2345 99 01
++# description: Connects to ADSL provider
++#
++# Copyright (C) 2000 Roaring Penguin Software Inc. This software may
++# be distributed under the terms of the GNU General Public License, version
++# 2 or any later version.
++# Modifed to work with SuSE 6.4 linux by Gary Cameron.
++#
++# Source function library.
++#. /etc/rc.d/init.d/functions # For red hat?
++. /etc/rc.config # For SuSE, enables setting from /etc/rc.config
++
++#Tweak this
++restart_time=120
++
++# From AUTOCONF
++prefix=@prefix@
++exec_prefix=@exec_prefix@
++
++# Paths to programs
++START=@sbindir@/adsl-start
++STOP=@sbindir@/adsl-stop
++STATUS=@sbindir@/adsl-status
++
++test &quot;$ADSL_START&quot; = &quot;yes&quot; || exit 0
++
++# The echo return value for success (defined in /etc/rc.config).
++return=$rc_done
++case &quot;$1&quot; in
++ start)
++ echo -n &quot;Bringing up ADSL link&quot;
++ $START &gt; /dev/null 2&gt;&amp;1 || return=$rc_failed
++ echo -e &quot;$return&quot;
++ ;;
++
++ stop)
++ echo -n &quot;Shutting down ADSL link&quot;
++ $STOP &gt; /dev/null 2&gt;&amp;1 || return=$rc_failed
++ echo -e &quot;$return&quot;
++ ;;
++
++ restart)
++ $0 stop
++ echo &quot;Waiting&quot; $restart_time &quot;seconds for the host to reset itself&quot;
++ sleep $restart_time #Note: Need time for host to reset itself
++ $0 start
++ ;;
++
++ status)
++ $STATUS
++ ;;
++
++ *)
++ echo &quot;Usage: adsl {start|stop|restart|status}&quot;
++ exit 1
++esac
++
++exit 0
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-init-suse.in
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-init-turbolinux.in
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-init-turbolinux.in (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-init-turbolinux.in 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,62 @@
++#!/bin/sh
++#
++# adsl This script starts or stops an ADSL connection
++#
++# chkconfig: 2345 99 01
++# description: Connects to ADSL provider
++#
++# Copyright (C) 2000 Roaring Penguin Software Inc. This software may
++# be distributed under the terms of the GNU General Public License, version
++# 2 or any later version.
++
++# Source function library if it exists
++test -r /etc/rc.d/init.d/functions &amp;&amp; . /etc/rc.d/init.d/functions
++
++# From AUTOCONF
++prefix=@prefix@
++exec_prefix=@exec_prefix@
++
++# Paths to programs
++START=@sbindir@/adsl-start
++STOP=@sbindir@/adsl-stop
++STATUS=@sbindir@/adsl-status
++case &quot;$1&quot; in
++ start)
++ echo -n &quot;Bringing up ADSL link: &quot;
++
++ $START
++ if [ $? = 0 ] ; then
++ echo success
++ touch /var/lock/subsys/adsl
++ else
++ echo failure
++ fi
++ ;;
++
++ stop)
++ echo -n &quot;Shutting down ADSL link: &quot;
++
++ $STOP &gt; /dev/null 2&gt;&amp;1
++ if [ $? = 0 ] ; then
++ echo success
++ rm -f /var/lock/subsys/adsl
++ else
++ echo failure
++ fi
++ ;;
++
++ restart)
++ $0 stop
++ $0 start
++ ;;
++
++ status)
++ $STATUS
++ ;;
++
++ *)
++ echo &quot;Usage: adsl {start|stop|restart|status}&quot;
++ exit 1
++esac
++
++exit 0
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-init-turbolinux.in
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-init.in
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-init.in (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-init.in 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,64 @@
++#!/bin/sh
++#
++# adsl This script starts or stops an ADSL connection
++#
++# chkconfig: 2345 99 01
++# description: Connects to ADSL provider
++#
++# Copyright (C) 2000 Roaring Penguin Software Inc. This software may
++# be distributed under the terms of the GNU General Public License, version
++# 2 or any later version.
++
++# Source function library if it exists
++test -r /etc/rc.d/init.d/functions &amp;&amp; . /etc/rc.d/init.d/functions
++
++# From AUTOCONF
++prefix=@prefix@
++exec_prefix=@exec_prefix@
++
++# Paths to programs
++START=@sbindir@/adsl-start
++STOP=@sbindir@/adsl-stop
++STATUS=@sbindir@/adsl-status
++case &quot;$1&quot; in
++ start)
++ echo -n &quot;Bringing up ADSL link&quot;
++
++ $START
++ if [ $? = 0 ] ; then
++ touch /var/lock/subsys/adsl
++ echo_success
++ else
++ echo_failure
++ fi
++ echo &quot;&quot;
++ ;;
++
++ stop)
++ echo -n &quot;Shutting down ADSL link&quot;
++
++ $STOP &gt; /dev/null 2&gt;&amp;1
++ if [ $? = 0 ] ; then
++ rm -f /var/lock/subsys/adsl
++ echo_success
++ else
++ echo_failure
++ fi
++ echo &quot;&quot;
++ ;;
++
++ restart)
++ $0 stop
++ $0 start
++ ;;
++
++ status)
++ $STATUS
++ ;;
++
++ *)
++ echo &quot;Usage: adsl {start|stop|restart|status}&quot;
++ exit 1
++esac
++
++exit 0
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-init.in
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-setup.in
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-setup.in (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-setup.in 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,346 @@
++#!/bin/sh
++#***********************************************************************
++#
++# adsl-setup
++#
++# All-purpose slicing/dicing shell script to configure rp-pppoe.
++#
++# Copyright (C) 2000 Roaring Penguin Software Inc.
++#
++# $Id: adsl-setup.in 195724 2001-06-11 13:49:39Z gc $
++#***********************************************************************
++
++# From AUTOCONF
++prefix=@prefix@
++exec_prefix=@exec_prefix@
++
++# Paths to programs
++IFCONFIG=/sbin/ifconfig
++PPPD=@PPPD@
++PPPOE=@sbindir@/pppoe
++ECHO=@ECHO@
++LOGGER=&quot;/usr/bin/logger -t `basename $0`&quot;
++
++CONFIG=/etc/ppp/pppoe.conf
++
++# Protect created files
++umask 077
++
++copy() {
++ cp $1 $2
++ if [ &quot;$?&quot; != 0 ] ; then
++ $ECHO &quot;*** Error copying $1 to $2&quot;
++ $ECHO &quot;*** Quitting.&quot;
++ exit 1
++ fi
++}
++
++$ECHO &quot;Welcome to the Roaring Penguin ADSL client setup. First, I will run&quot;
++$ECHO &quot;some checks on your system to make sure the PPPoE client is installed&quot;
++$ECHO &quot;properly...&quot;
++$ECHO &quot;&quot;
++
++# Must be root
++if [ &quot;`@ID@ -u`&quot; != 0 ] ; then
++ $ECHO &quot;$0: Sorry, you must be root to run this script&quot;
++ exit 1
++fi
++
++# Prototype config file must exist
++if [ ! -r &quot;$CONFIG&quot; ] ; then
++ $ECHO &quot;Oh, dear, I don't see the file '$CONFIG' anywhere. Please&quot;
++ $ECHO &quot;re-install the PPPoE client.&quot;
++ exit 1
++fi
++
++# Must have pppd
++if [ ! -x $PPPD ] ; then
++ $ECHO &quot;Oops, I can't execute the program '$PPPD'. You&quot;
++ $ECHO &quot;must install the PPP software suite, version 2.3.10 or later.&quot;
++ exit 1
++fi
++
++. $CONFIG
++
++if [ &quot;$DEMAND&quot; = &quot;&quot; ] ; then
++ DEMAND=no
++fi
++
++# pppoe must exist
++if [ ! -x &quot;$PPPOE&quot; ] ; then
++ $ECHO &quot;Oh, dear, I can't execute the program '$PPPOE'. Please&quot;
++ $ECHO &quot;re-install the rp-pppoe client.&quot;
++ exit 1
++fi
++
++$ECHO &quot;Looks good! Now, please enter some information:&quot;
++
++while [ true ] ; do
++ $ECHO &quot;&quot;
++ $ECHO &quot;USER NAME&quot;
++ $ECHO &quot;&quot;
++ $ECHO -n &quot;&gt;&gt;&gt; Enter your PPPoE user name (default $USER): &quot;
++ read U
++
++ if [ &quot;$U&quot; = &quot;&quot; ] ; then
++ U=&quot;$USER&quot;
++ fi
++
++ # Under Linux, &quot;fix&quot; the default interface if eth1 is not available
++ if test `uname -s` = &quot;Linux&quot; ; then
++ $IFCONFIG $ETH &gt; /dev/null 2&gt;&amp;1 || ETH=eth0
++ fi
++ $ECHO &quot;&quot;
++ $ECHO &quot;INTERFACE&quot;
++ $ECHO &quot;&quot;
++ $ECHO &quot;&gt;&gt;&gt; Enter the Ethernet interface connected to the ADSL modem&quot;
++ $ECHO &quot;For Solaris, this is likely to be something like /dev/hme0.&quot;
++ $ECHO &quot;For Linux, it will be ethn, where 'n' is a number.&quot;
++ $ECHO -n &quot;(default $ETH): &quot;
++ read E
++
++ if [ &quot;$E&quot; = &quot;&quot; ] ; then
++ E=&quot;$ETH&quot;
++ fi
++
++ $ECHO &quot;&quot;
++ $ECHO &quot;Do you want the link to come up on demand, or stay up continuously?&quot;
++ $ECHO &quot;If you want it to come up on demand, enter the idle time in seconds&quot;
++ $ECHO &quot;after which the link should be dropped. If you want the link to&quot;
++ $ECHO &quot;stay up permanently, enter 'no' (two letters, lower-case.)&quot;
++ $ECHO &quot;NOTE: Demand-activated links do not interact well with dynamic IP&quot;
++ $ECHO &quot;addresses. You may have some problems with demand-activated links.&quot;
++ $ECHO -n &quot;&gt;&gt;&gt; Enter the demand value (default $DEMAND): &quot;
++ read D
++ if [ &quot;$D&quot; = &quot;&quot; ] ; then
++ D=$DEMAND
++ fi
++
++ $ECHO &quot;&quot;
++ $ECHO &quot;DNS&quot;
++ $ECHO &quot;&quot;
++ $ECHO &quot;Please enter the IP address of your ISP's primary DNS server.&quot;
++ $ECHO &quot;If your ISP claims that 'the server will provide DNS addresses',&quot;
++ $ECHO &quot;enter 'server' (all lower-case) here.&quot;
++ $ECHO &quot;If you just press enter, I will assume you know what you are&quot;
++ $ECHO &quot;doing and not modify your DNS setup.&quot;
++ $ECHO -n &quot;&gt;&gt;&gt; Enter the DNS information here: &quot;
++
++ read DNS1
++
++
++ if [ &quot;$DNS1&quot; != &quot;&quot; ] ; then
++ if [ &quot;$DNS1&quot; != &quot;server&quot; ] ; then
++ $ECHO &quot;Please enter the IP address of your ISP's secondary DNS server.&quot;
++ $ECHO &quot;If you just press enter, I will assume there is only one DNS server.&quot;
++ $ECHO -n &quot;&gt;&gt;&gt; Enter the secondary DNS server address here: &quot;
++ read DNS2
++ fi
++ fi
++
++ while [ true ] ; do
++ $ECHO &quot;&quot;
++ $ECHO &quot;PASSWORD&quot;
++ $ECHO &quot;&quot;
++ stty -echo
++ $ECHO -n &quot;&gt;&gt;&gt; Please enter your PPPoE password: &quot;
++ read PWD1
++ $ECHO &quot;&quot;
++ $ECHO -n &quot;&gt;&gt;&gt; Please re-enter your PPPoE password: &quot;
++ read PWD2
++ $ECHO &quot;&quot;
++ stty echo
++ if [ &quot;$PWD1&quot; = &quot;$PWD2&quot; ] ; then
++ break
++ fi
++
++ $ECHO -n &quot;&gt;&gt;&gt; Sorry, the passwords do not match. Try again? (y/n)&quot;
++ read ANS
++ case &quot;$ANS&quot; in
++ N|No|NO|Non|n|no|non)
++ $ECHO &quot;OK, quitting. Bye.&quot;
++ exit 1
++ esac
++ done
++
++ # Firewalling
++ $ECHO &quot;&quot;
++ $ECHO &quot;FIREWALLING&quot;
++ $ECHO &quot;&quot;
++ if test `uname -s` != &quot;Linux&quot; ; then
++ $ECHO &quot;Sorry, firewalling is only supported under Linux. Consult&quot;
++ $ECHO &quot;your operating system manuals for details on setting up&quot;
++ $ECHO &quot;packet filters for your system.&quot;
++ FIREWALL=NONE
++ else
++ $ECHO &quot;Please choose the firewall rules to use. Note that these rules are&quot;
++ $ECHO &quot;very basic. You are strongly encouraged to use a more sophisticated&quot;
++ $ECHO &quot;firewall setup; however, these will provide basic security. If you&quot;
++ $ECHO &quot;are running any servers on your machine, you must choose 'NONE' and&quot;
++ $ECHO &quot;set up firewalling yourself. Otherwise, the firewall rules will deny&quot;
++ $ECHO &quot;access to all standard servers like Web, e-mail, ftp, etc. If you&quot;
++ $ECHO &quot;are using SSH, the rules will block outgoing SSH connections which&quot;
++ $ECHO &quot;allocate a privileged source port.&quot;
++ $ECHO &quot;&quot;
++ while [ true ] ; do
++ $ECHO &quot;The firewall choices are:&quot;
++ $ECHO &quot;0 - NONE: This script will not set any firewall rules. You are responsible&quot;
++ $ECHO &quot; for ensuring the security of your machine. You are STRONGLY&quot;
++ $ECHO &quot; recommended to use some kind of firewall rules.&quot;
++ $ECHO &quot;1 - STANDALONE: Appropriate for a basic stand-alone web-surfing workstation&quot;
++ $ECHO &quot;2 - MASQUERADE: Appropriate for a machine acting as an Internet gateway&quot;
++ $ECHO &quot; for a LAN&quot;
++ $ECHO -n &quot;&gt;&gt;&gt; Choose a type of firewall (0-2): &quot;
++ read a
++ if [ &quot;$a&quot; = 0 -o &quot;$a&quot; = 1 -o &quot;$a&quot; = 2 ] ; then
++ break
++ fi
++ $ECHO &quot;Please enter a number from 0 to 2&quot;
++ done
++
++ case &quot;$a&quot; in
++ 0)
++ FIREWALL=NONE
++ ;;
++ 1)
++ FIREWALL=STANDALONE
++ ;;
++ 2)
++ FIREWALL=MASQUERADE
++ ;;
++ esac
++ fi
++
++ $ECHO &quot;&quot;
++ $ECHO &quot;** Summary of what you entered **&quot;
++ $ECHO &quot;&quot;
++ $ECHO &quot;Ethernet Interface: $E&quot;
++ $ECHO &quot;User name: $U&quot;
++ if [ &quot;$D&quot; = &quot;no&quot; ] ; then
++ $ECHO &quot;Activate-on-demand: No&quot;
++ else
++ $ECHO &quot;Activate-on-demand: Yes; idle timeout = $D seconds&quot;
++ fi
++
++ if [ &quot;$DNS1&quot; != &quot;&quot; ] ; then
++ if [ &quot;$DNS1&quot; = &quot;server&quot; ] ; then
++ $ECHO &quot;DNS addresses: Supplied by ISP's server&quot;
++ else
++ $ECHO &quot;Primary DNS: $DNS1&quot;
++ if [ &quot;$DNS2&quot; != &quot;&quot; ] ; then
++ $ECHO &quot;Secondary DNS: $DNS2&quot;
++ fi
++ fi
++ else
++ $ECHO &quot;DNS: Do not adjust&quot;
++ fi
++ $ECHO &quot;Firewalling: $FIREWALL&quot;
++ $ECHO &quot;&quot;
++ while [ true ] ; do
++ $ECHO -n '&gt;&gt;&gt; Accept these settings and adjust configuration files (y/n)? '
++ read ANS
++ case &quot;ANS&quot; in
++ Y|y|yes|Yes|oui|Oui)
++ ANS=y
++ ;;
++ N|n|no|No|non|Non)
++ ANS=n
++ ;;
++ esac
++ if [ &quot;$ANS&quot; = &quot;y&quot; -o &quot;$ANS&quot; = &quot;n&quot; ] ; then
++ break
++ fi
++ done
++ if [ &quot;$ANS&quot; = &quot;y&quot; ] ; then
++ break
++ fi
++done
++
++# Adjust configuration files. First to $CONFIG
++
++$ECHO &quot;Adjusting $CONFIG&quot;
++
++copy $CONFIG $CONFIG-bak
++if [ &quot;$DNS1&quot; = &quot;server&quot; ] ; then
++ DNSTYPE=SERVER
++ DNS1=&quot;&quot;
++ USEPEERDNS=yes
++else
++ USEPEERDNS=no
++ if [ &quot;$DNS1&quot; = &quot;&quot; ] ; then
++ DNSTYPE=NOCHANGE
++ else
++ DNSTYPE=SPECIFY
++ fi
++fi
++
++# Where is pppd likely to put its pid?
++if [ -d /var/run ] ; then
++ VARRUN=/var/run
++else
++ VARRUN=/etc/ppp
++fi
++
++# Some #$(*&amp; ISP's use a slash in the user name...
++sed -e &quot;s&amp;^USER=.*&amp;USER='$U'&amp;&quot; \
++ -e &quot;s&amp;^ETH=.*&amp;ETH='$E'&amp;&quot; \
++ -e &quot;s&amp;^PIDFILE=.*&amp;PIDFILE=\&quot;$VARRUN/\$CF_BASE-adsl.pid\&quot;&amp;&quot; \
++ -e &quot;s/^FIREWALL=.*/FIREWALL=$FIREWALL/&quot; \
++ -e &quot;s/^DEMAND=.*/DEMAND=$D/&quot; \
++ -e &quot;s/^DNSTYPE=.*/DNSTYPE=$DNSTYPE/&quot; \
++ -e &quot;s/^DNS1=.*/DNS1=$DNS1/&quot; \
++ -e &quot;s/^DNS2=.*/DNS2=$DNS2/&quot; \
++ -e &quot;s/^USEPEERDNS=.*/USEPEERDNS=$USEPEERDNS/&quot; \
++ &lt; $CONFIG-bak &gt; $CONFIG
++
++if [ $? != 0 ] ; then
++ $ECHO &quot;** Error modifying $CONFIG&quot;
++ $ECHO &quot;** Quitting&quot;
++ exit 1
++fi
++
++if [ &quot;$DNS1&quot; != &quot;&quot; ] ; then
++ if [ &quot;$DNS1&quot; != &quot;server&quot; ] ; then
++ $ECHO &quot;Adjusting /etc/resolv.conf&quot;
++ if [ -r /etc/resolv.conf ] ; then
++ grep -s &quot;MADE-BY-RP-PPPOE&quot; /etc/resolv.conf &gt; /dev/null 2&gt;&amp;1
++ if [ &quot;$?&quot; != 0 ] ; then
++ $ECHO &quot; (But first backing it up to /etc/resolv.conf-bak)&quot;
++ copy /etc/resolv.conf /etc/resolv.conf-bak
++ fi
++ fi
++ $ECHO &quot;# MADE-BY-RP-PPPOE&quot; &gt; /etc/resolv.conf
++ $ECHO &quot;nameserver $DNS1&quot; &gt;&gt; /etc/resolv.conf
++ if [ &quot;$DNS2&quot; != &quot;&quot; ] ; then
++ $ECHO &quot;nameserver $DNS2&quot; &gt;&gt; /etc/resolv.conf
++ fi
++ fi
++fi
++
++$ECHO &quot;Adjusting /etc/ppp/pap-secrets and /etc/ppp/chap-secrets&quot;
++if [ -r /etc/ppp/pap-secrets ] ; then
++ $ECHO &quot; (But first backing it up to /etc/ppp/pap-secrets-bak)&quot;
++ copy /etc/ppp/pap-secrets /etc/ppp/pap-secrets-bak
++else
++ cp /dev/null /etc/ppp/pap-secrets-bak
++fi
++if [ -r /etc/ppp/chap-secrets ] ; then
++ $ECHO &quot; (But first backing it up to /etc/ppp/chap-secrets-bak)&quot;
++ copy /etc/ppp/chap-secrets /etc/ppp/chap-secrets-bak
++else
++ cp /dev/null /etc/ppp/chap-secrets-bak
++fi
++
++egrep -v &quot;^$U|^\&quot;$U\&quot;&quot; /etc/ppp/pap-secrets-bak &gt; /etc/ppp/pap-secrets
++$ECHO &quot;\&quot;$U\&quot; * \&quot;$PWD1\&quot;&quot; &gt;&gt; /etc/ppp/pap-secrets
++egrep -v &quot;^$U|^\&quot;$U\&quot;&quot; /etc/ppp/chap-secrets-bak &gt; /etc/ppp/chap-secrets
++$ECHO &quot;\&quot;$U\&quot; * \&quot;$PWD1\&quot;&quot; &gt;&gt; /etc/ppp/chap-secrets
++
++$ECHO &quot;&quot;
++$ECHO &quot;&quot;
++$ECHO &quot;&quot;
++$ECHO &quot;Congratulations, it should be all set up!&quot;
++$ECHO &quot;&quot;
++$ECHO &quot;Type 'adsl-start' to bring up your ADSL link and 'adsl-stop' to bring&quot;
++$ECHO &quot;it down. Type 'adsl-status' to see the link status.&quot;
++exit 0
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-setup.in
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-start.in
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-start.in (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-start.in 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,186 @@
++#!/bin/sh
++# @configure_input@
++#***********************************************************************
++#
++# adsl-start
++#
++# Shell script to bring up an ADSL connection
++#
++# Copyright (C) 2000 Roaring Penguin Software Inc.
++#
++# $Id: adsl-start.in 195724 2001-06-11 13:49:39Z gc $
++#
++# This file may be distributed under the terms of the GNU General
++# Public License.
++#
++# Usage: adsl-start [config_file]
++# adsl-start interface user [config_file]
++# Second form overrides USER and ETH from config file.
++# If config_file is omitted, defaults to /etc/ppp/pppoe.conf
++#
++#***********************************************************************
++
++# From AUTOCONF
++prefix=@prefix@
++exec_prefix=@exec_prefix@
++
++# Paths to programs
++CONNECT=@sbindir@/adsl-connect
++ECHO=@ECHO@
++IFCONFIG=/sbin/ifconfig
++
++# Defaults
++CONFIG=/etc/ppp/pppoe.conf
++USER=&quot;&quot;
++ETH=&quot;&quot;
++ME=`basename $0`
++# Must be root
++if [ &quot;`@ID@ -u`&quot; != 0 ] ; then
++ $ECHO &quot;$ME: You must be root to run this script&quot; &gt;&amp; 2
++ exit 1
++fi
++
++# Debugging
++if [ &quot;$DEBUG&quot; = &quot;1&quot; ] ; then
++ $ECHO &quot;*** Running in debug mode... please be patient...&quot;
++ DEBUG=/tmp/pppoe-debug-$$
++ export DEBUG
++ mkdir $DEBUG
++ if [ &quot;$?&quot; != 0 ] ; then
++ $ECHO &quot;Could not create directory $DEBUG... exiting&quot;
++ exit 1
++ fi
++ DEBUG=$DEBUG/pppoe-debug.txt
++
++ # Initial debug output
++ $ECHO &quot;---------------------------------------------&quot; &gt; $DEBUG
++ $ECHO &quot;* The following section contains information about your system&quot; &gt;&gt; $DEBUG
++ date &gt;&gt; $DEBUG
++ $ECHO &quot;Output of uname -a&quot; &gt;&gt; $DEBUG
++ uname -a &gt;&gt; $DEBUG
++ $ECHO &quot;---------------------------------------------&quot; &gt;&gt; $DEBUG
++ $ECHO &quot;* The following section contains information about your network&quot; &gt;&gt; $DEBUG
++ $ECHO &quot;* interfaces. The one you chose for PPPoE should contain the words:&quot; &gt;&gt; $DEBUG
++ $ECHO &quot;* 'UP' and 'RUNNING'. If it does not, you probably have an Ethernet&quot; &gt;&gt; $DEBUG
++ $ECHO &quot;* driver problem.&quot; &gt;&gt; $DEBUG
++ $ECHO &quot;Output of ifconfig -a&quot; &gt;&gt; $DEBUG
++ $IFCONFIG -a &gt;&gt; $DEBUG
++ $ECHO &quot;---------------------------------------------&quot; &gt;&gt; $DEBUG
++ if [ &quot;`uname -s`&quot; = &quot;Linux&quot; ] ; then
++ $ECHO &quot;* The following section contains information about kernel modules&quot; &gt;&gt; $DEBUG
++ $ECHO &quot;* If the module for your Ethernet card is 'tulip', you might&quot; &gt;&gt; $DEBUG
++ $ECHO &quot;* want to look for an updated version at <A HREF="http://www.scyld.com">http://www.scyld.com</A>&quot; &gt;&gt; $DEBUG
++ $ECHO &quot;Output of lsmod&quot; &gt;&gt; $DEBUG
++ lsmod &gt;&gt; $DEBUG
++ $ECHO &quot;---------------------------------------------&quot; &gt;&gt; $DEBUG
++ fi
++ $ECHO &quot;* The following section lists your routing table.&quot; &gt;&gt; $DEBUG
++ $ECHO &quot;* If you have an entry which starts with '0.0.0.0', you probably&quot; &gt;&gt; $DEBUG
++ $ECHO &quot;* have defined a default route and gateway, and pppd will&quot; &gt;&gt; $DEBUG
++ $ECHO &quot;* not create a default route using your ISP. Try getting&quot; &gt;&gt; $DEBUG
++ $ECHO &quot;* rid of this route.&quot; &gt;&gt; $DEBUG
++ $ECHO &quot;Output of netstat -n -r&quot; &gt;&gt; $DEBUG
++ netstat -n -r &gt;&gt; $DEBUG
++ $ECHO &quot;---------------------------------------------&quot; &gt;&gt; $DEBUG
++ $ECHO &quot;Contents of /etc/resolv.conf&quot; &gt;&gt; $DEBUG
++ $ECHO &quot;* The following section lists DNS setup.&quot; &gt;&gt; $DEBUG
++ $ECHO &quot;* If you can browse by IP address, but not name, suspect&quot; &gt;&gt; $DEBUG
++ $ECHO &quot;* a DNS problem.&quot; &gt;&gt; $DEBUG
++ cat /etc/resolv.conf &gt;&gt; $DEBUG
++ $ECHO &quot;---------------------------------------------&quot; &gt;&gt; $DEBUG
++ $ECHO &quot;* The following section lists /etc/ppp/options.&quot; &gt;&gt; $DEBUG
++ $ECHO &quot;* You should have NOTHING in that file.&quot; &gt;&gt; $DEBUG
++ $ECHO &quot;Contents of /etc/ppp/options&quot; &gt;&gt; $DEBUG
++ cat /etc/ppp/options &gt;&gt; $DEBUG 2&gt;/dev/null
++ $ECHO &quot;---------------------------------------------&quot; &gt;&gt; $DEBUG
++else
++ DEBUG=&quot;&quot;
++fi
++
++# Sort out command-line arguments
++case &quot;$#&quot; in
++ 1)
++ CONFIG=&quot;$1&quot;
++ ;;
++ 3)
++ CONFIG=&quot;$3&quot;
++ ;;
++esac
++
++if [ ! -f &quot;$CONFIG&quot; -o ! -r &quot;$CONFIG&quot; ] ; then
++ $ECHO &quot;$ME: Cannot read configuration file '$CONFIG'&quot; &gt;&amp; 2
++ exit 1
++fi
++
++. $CONFIG
++
++# Check for command-line overriding of ETH and USER
++case &quot;$#&quot; in
++ 2|3)
++ ETH=&quot;$1&quot;
++ USER=&quot;$2&quot;
++ ;;
++esac
++
++# Check for pidfile
++if [ -r &quot;$PIDFILE&quot; ] ; then
++ PID=`cat &quot;$PIDFILE&quot;`
++ # Check if still running
++ kill -0 $PID &gt; /dev/null 2&gt;&amp;1
++ if [ $? = 0 ] ; then
++ $ECHO &quot;$ME: There already seems to be an ADSL connection up (PID $PID)&quot; &gt;&amp; 2
++ exit 1
++ fi
++ # Delete bogus PIDFILE
++ rm -f &quot;$PIDFILE&quot; &quot;$PIDFILE.pppd&quot; &quot;$PIDFILE.pppoe&quot; &quot;$PIDFILE.start&quot;
++fi
++
++echo $$ &gt; $PIDFILE.start
++
++# Start the connection in the background unless we're debugging
++if [ &quot;$DEBUG&quot; != &quot;&quot; ] ; then
++ $CONNECT &quot;$@&quot;
++ exit 0
++fi
++
++$CONNECT &quot;$@&quot; &gt; /dev/null 2&gt;&amp;1 &amp;
++CONNECT_PID=$!
++
++if [ &quot;$CONNECT_TIMEOUT&quot; = &quot;&quot; -o &quot;$CONNECT_TIMEOUT&quot; = 0 ] ; then
++ exit 0
++fi
++
++# Don't monitor connection if dial-on-demand
++if [ &quot;$DEMAND&quot; != &quot;&quot; -a &quot;$DEMAND&quot; != &quot;no&quot; ] ; then
++ exit 0
++fi
++
++# Monitor connection
++TIME=0
++while [ true ] ; do
++ @sbindir@/adsl-status $CONFIG &gt; /dev/null 2&gt;&amp;1
++
++ # Looks like the interface came up
++ if [ $? = 0 ] ; then
++ # Print newline if standard input is a TTY
++ tty -s &amp;&amp; $ECHO &quot; Connected!&quot;
++ exit 0
++ fi
++
++ if test -n &quot;$FORCEPING&quot; ; then
++ $ECHO -n &quot;$FORCEPING&quot;
++ else
++ tty -s &amp;&amp; $ECHO -n &quot;$PING&quot;
++ fi
++ sleep $CONNECT_POLL
++ TIME=`expr $TIME + $CONNECT_POLL`
++ if [ $TIME -gt $CONNECT_TIMEOUT ] ; then
++ break
++ fi
++done
++
++$ECHO &quot;TIMED OUT&quot; &gt;&amp; 2
++# Timed out! Kill the adsl-connect process and quit
++kill $CONNECT_PID &gt; /dev/null 2&gt;&amp;1
++exit 1
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-start.in
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-status
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-status (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-status 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,82 @@
++#!/bin/sh
++#***********************************************************************
++#
++# adsl-status
++#
++# Shell script to report on status of ADSL connection
++#
++# Copyright (C) 2000-2001 Roaring Penguin Software Inc.
++#
++# $Id: adsl-status 195724 2001-06-11 13:49:39Z gc $
++#
++# This file may be distributed under the terms of the GNU General
++# Public License.
++#
++# Usage: adsl-status [config_file]
++# If config_file is omitted, defaults to /etc/ppp/pppoe.conf
++#
++#***********************************************************************
++
++# Defaults
++CONFIG=/etc/ppp/pppoe.conf
++
++case &quot;$#&quot; in
++ 1)
++ CONFIG=&quot;$1&quot;
++ ;;
++esac
++
++if [ ! -f &quot;$CONFIG&quot; -o ! -r &quot;$CONFIG&quot; ] ; then
++ echo &quot;$0: Cannot read configuration file '$CONFIG'&quot; &gt;&amp; 2
++ exit 1
++fi
++
++. $CONFIG
++
++PPPOE_PIDFILE=&quot;$PIDFILE.pppoe&quot;
++PPPD_PIDFILE=&quot;$PIDFILE.pppd&quot;
++
++if [ &quot;$DEMAND&quot; != &quot;no&quot; ] ; then
++ echo &quot;Note: You have enabled demand-connection; adsl-status may be inaccurate.&quot;
++fi
++
++# If no PPPOE_PIDFILE, connection is down, unless we're using the Linux plugin
++if [ &quot;$LINUX_PLUGIN&quot; = &quot;&quot; ] ; then
++ if [ ! -r &quot;$PPPOE_PIDFILE&quot; ] ; then
++ echo &quot;adsl-status: Link is down (can't read pppoe PID file $PPPOE_PIDFILE)&quot;
++ exit 1
++ fi
++fi
++
++# If no PPPD_PIDFILE, something fishy!
++if [ ! -r &quot;$PPPD_PIDFILE&quot; ] ; then
++ echo &quot;adsl-status: Link is down (can't read pppd PID file $PPPD_PIDFILE)&quot;
++ exit 1
++fi
++
++PPPD_PID=`cat &quot;$PPPD_PIDFILE&quot;`
++
++# Sigh. Some versions of pppd put PID files in /var/run; others put them
++# in /etc/ppp. Since it's too messy to figure out what pppd does, we
++# try both locations.
++for i in /etc/ppp/ppp*.pid /var/run/ppp*.pid ; do
++ if [ -r $i ] ; then
++ PID=`cat $i`
++ if [ &quot;$PID&quot; = &quot;$PPPD_PID&quot; ] ; then
++ IF=`basename $i .pid`
++ netstat -rn | grep &quot; ${IF}\$&quot; &gt; /dev/null
++ # /sbin/ifconfig $IF | grep &quot;UP.*POINTOPOINT&quot; &gt; /dev/null
++ if [ &quot;$?&quot; != &quot;0&quot; ] ; then
++ echo &quot;adsl-status: Link is attached to $IF, but $IF is down&quot;
++ exit 1
++ fi
++ echo &quot;adsl-status: Link is up and running on interface $IF&quot;
++ /sbin/ifconfig $IF
++ exit 0
++ fi
++ fi
++done
++
++echo &quot;adsl-status: Link is down -- could not find interface corresponding to&quot;
++echo &quot;pppd pid $PPPD_PID&quot;
++exit 1
+\ No newline at end of file
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-status
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-stop.in
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-stop.in (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-stop.in 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,84 @@
++#!/bin/sh
++# @configure_input@
++#***********************************************************************
++#
++# adsl-stop
++#
++# Shell script to bring down an ADSL connection
++#
++# Copyright (C) 2000 Roaring Penguin Software Inc.
++#
++# $Id: adsl-stop.in 195724 2001-06-11 13:49:39Z gc $
++#
++# This file may be distributed under the terms of the GNU General
++# Public License.
++#
++# Usage: adsl-stop [config_file]
++# If config_file is omitted, defaults to /etc/ppp/pppoe.conf
++#
++#***********************************************************************
++
++ME=&quot;`basename $0`&quot;
++LOGGER=&quot;/usr/bin/logger -t $ME&quot;
++CONFIG=&quot;$1&quot;
++if [ &quot;$CONFIG&quot; = &quot;&quot; ] ; then
++ CONFIG=/etc/ppp/pppoe.conf
++fi
++
++if [ ! -f &quot;$CONFIG&quot; -o ! -r &quot;$CONFIG&quot; ] ; then
++ echo &quot;$ME: Cannot read configuration file '$CONFIG'&quot; &gt;&amp; 2
++ exit 1
++fi
++
++. $CONFIG
++
++PPPOE_PIDFILE=&quot;$PIDFILE.pppoe&quot;
++PPPD_PIDFILE=&quot;$PIDFILE.pppd&quot;
++STARTPID=&quot;$PIDFILE.start&quot;
++
++# Backward config file compatibility
++if test &quot;$DEMAND&quot; = &quot;&quot; ; then
++ DEMAND=no
++fi
++
++# Ignore SIGTERM
++trap &quot;&quot; 15
++
++# Check for pidfile
++if [ -r &quot;$PIDFILE&quot; ] ; then
++ PID=`cat $PIDFILE`
++
++ # Check if still running
++ kill -0 $PID &gt; /dev/null 2&gt;&amp;1
++ if [ $? != 0 ] ; then
++ echo &quot;$ME: The adsl-connect script (PID $PID) appears to have died&quot; &gt;&amp; 2
++ fi
++
++ # Kill pppd, which should in turn kill pppoe
++ if [ -r &quot;$PPPD_PIDFILE&quot; ] ; then
++ PPPD_PID=`cat &quot;$PPPD_PIDFILE&quot;`
++ $LOGGER -p daemon.notice &quot;Killing pppd&quot;
++ echo &quot;Killing pppd ($PPPD_PID)&quot;
++ kill $PPPD_PID &gt; /dev/null 2&gt;&amp;1 || exit 1
++ fi
++
++ # Kill adsl-start
++ PIDS=`cat $STARTPID`
++ kill -0 $PIDS &gt; /dev/null 2&gt;&amp;1
++ if [ $? = 0 ] ; then
++ $LOGGER -p daemon.notice &quot;Killing adsl-connect&quot;
++ kill $PIDS &gt; /dev/null 2&gt;&amp;1
++ fi
++
++ # Kill adsl-connect
++ $LOGGER -p daemon.notice &quot;Killing adsl-connect&quot;
++ echo &quot;Killing adsl-connect ($PID)&quot;
++ kill $PID &gt; /dev/null 2&gt;&amp;1
++
++ rm -f &quot;$PIDFILE&quot; &quot;$PPPD_PIDFILE&quot; &quot;$PPPOE_PIDFILE&quot; &quot;$STARTPID&quot;
++else
++ echo &quot;$ME: No ADSL connection appears to be running&quot; &gt;&amp;2
++ exit 1
++fi
++
++exit 0
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/scripts/adsl-stop.in
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/src/Makefile
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/src/Makefile (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/src/Makefile 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,45 @@
++ #******************************************************************************
++ #
++ # Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ #
++ # Copyright 2000 Mandriva
++ #
++ # This software may be freely redistributed under the terms of the GNU
++ # public license.
++ #
++ # You should have received a copy of the GNU General Public License
++ # along with this program; if not, write to the Free Software
++ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ #
++ #*****************************************************************************
++
++top_dir = ../..
++
++include $(top_dir)/Makefile.common
++
++
++TARGETS = pppoe
++
++BINTARGET = ../../pppoe
++
++
++all: $(TARGETS)
++
++clean:
++ rm -f *.o *.a $(BINTARGET) pppoe
++
++FLAGS = -Wall -Werror -Os -fno-strict-aliasing -fomit-frame-pointer '-DPPPOE_PATH=&quot;/sbin/pppoe&quot;' '-DPPPD_PATH=&quot;/sbin/pppd&quot;' '-DVERSION=&quot;3.0-stg1&quot;'
++
++ifeq (GLIBC, $(L))
++EXTRA_LDFLAGS = -static
++endif
++
++OBJS = pppoe.o if.o debug.o common.o ppp.o discovery.o
++
++pppoe: $(OBJS)
++ $(DIET) gcc -o $@ $^ $(EXTRA_LDFLAGS)
++ $(STRIPCMD) $@
++ cp -f $@ $(BINTARGET)
++
++$(OBJS): %.o: %.c
++ $(DIET) gcc $(FLAGS) $(INCLUDES) $(INCS) -c $&lt; -o $@
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/src/Makefile
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/src/Makefile.in
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/src/Makefile.in (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/src/Makefile.in 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,257 @@
++# @configure_input@
++#***********************************************************************
++#
++# Makefile
++#
++# Makefile for Roaring Penguin's Linux user-space PPPoE client.
++#
++# Copyright (C) 2000 Roaring Penguin Software Inc.
++#
++# This program may be distributed according to the terms of the GNU
++# General Public License, version 2 or (at your option) any later version.
++#
++# $Id: Makefile.in 195724 2001-06-11 13:49:39Z gc $
++#***********************************************************************
++
++# Version is set ONLY IN THE MAKEFILE! Don't delete this!
++VERSION=3.0
++
++DEFINES=
++prefix=@prefix@
++exec_prefix=@exec_prefix@
++mandir=@mandir@
++docdir=@prefix@/doc/rp-pppoe-$(VERSION)
++install=@INSTALL@
++install_dir=@INSTALL@ -d
++sbindir=@sbindir@
++
++# Plugin for pppd on Linux
++LINUX_KERNELMODE_PLUGIN=@LINUX_KERNELMODE_PLUGIN@
++PPPD_INCDIR=@PPPD_INCDIR@
++
++# PPPoE relay -- currently only supported on Linux
++PPPOE_RELAY=@PPPOE_RELAY@
++
++# Program paths
++PPPOE_PATH=$(sbindir)/pppoe
++PPPD_PATH=@PPPD@
++
++# Kernel-mode plugin gets installed here.
++PLUGIN_DIR=/etc/ppp/plugins
++PLUGIN_PATH=$(PLUGIN_DIR)/rp-pppoe.so
++
++# Configuration file paths
++PPPOESERVER_PPPD_OPTIONS=/etc/ppp/pppoe-server-options
++
++PATHS='-DPPPOE_PATH=&quot;$(PPPOE_PATH)&quot;' '-DPPPD_PATH=&quot;$(PPPD_PATH)&quot;' \
++ '-DPLUGIN_PATH=&quot;$(PLUGIN_PATH)&quot;' \
++ '-DPPPOE_SERVER_OPTIONS=&quot;$(PPPOESERVER_PPPD_OPTIONS)&quot;'
++
++CFLAGS= @CFLAGS@ $(DEFINES) $(PATHS)
++TARGETS=@TARGETS@
++
++all: $(TARGETS)
++ @echo &quot;&quot;
++ @echo &quot;Type 'make install' as root to install the software.&quot;
++
++pppoe-sniff: pppoe-sniff.o if.o common.o debug.o
++ @CC@ -o pppoe-sniff pppoe-sniff.o if.o common.o debug.o $(LIBS)
++
++pppoe-server: pppoe-server.o if.o debug.o common.o md5.o
++ @CC@ -o pppoe-server pppoe-server.o if.o debug.o common.o md5.o $(LIBS)
++
++pppoe: pppoe.o if.o debug.o common.o ppp.o discovery.o
++ @CC@ -o pppoe pppoe.o if.o debug.o common.o ppp.o discovery.o $(LIBS)
++
++pppoe-relay: relay.o if.o debug.o common.o
++ @CC@ -o pppoe-relay relay.o if.o debug.o common.o $(LIBS)
++
++pppoe.o: pppoe.c pppoe.h
++ @CC@ $(CFLAGS) '-DVERSION=&quot;$(VERSION)&quot;' -c -o pppoe.o pppoe.c
++
++discovery.o: discovery.c pppoe.h
++ @CC@ $(CFLAGS) '-DVERSION=&quot;$(VERSION)&quot;' -c -o discovery.o discovery.c
++
++ppp.o: ppp.c pppoe.h
++ @CC@ $(CFLAGS) '-DVERSION=&quot;$(VERSION)&quot;' -c -o ppp.o ppp.c
++
++md5.o: md5.c md5.h
++ @CC@ $(CFLAGS) '-DVERSION=&quot;$(VERSION)&quot;' -c -o md5.o md5.c
++
++pppoe-server.o: pppoe-server.c pppoe.h
++ @CC@ $(CFLAGS) '-DVERSION=&quot;$(VERSION)&quot;' -c -o pppoe-server.o pppoe-server.c
++
++pppoe-sniff.o: pppoe-sniff.c pppoe.h
++ @CC@ $(CFLAGS) '-DVERSION=&quot;$(VERSION)&quot;' -c -o pppoe-sniff.o pppoe-sniff.c
++
++if.o: if.c pppoe.h
++ @CC@ $(CFLAGS) '-DVERSION=&quot;$(VERSION)&quot;' -c -o if.o if.c
++
++common.o: common.c pppoe.h
++ @CC@ $(CFLAGS) '-DVERSION=&quot;$(VERSION)&quot;' -c -o common.o common.c
++
++debug.o: debug.c pppoe.h
++ @CC@ $(CFLAGS) '-DVERSION=&quot;$(VERSION)&quot;' -c -o debug.o debug.c
++
++relay.o: relay.c relay.h pppoe.h
++ @CC@ $(CFLAGS) '-DVERSION=&quot;$(VERSION)&quot;' -c -o relay.o relay.c
++
++# Linux-specific plugin
++rp-pppoe.so: plugin/libplugin.a plugin/plugin.o
++ @CC@ -o rp-pppoe.so -shared plugin/plugin.o plugin/libplugin.a
++
++plugin/plugin.o: plugin.c
++ @CC@ '-DVERSION=&quot;$(VERSION)&quot;' -I$(PPPD_INCDIR) -c -o plugin/plugin.o -fPIC plugin.c
++
++plugin/libplugin.a: plugin/discovery.o plugin/if.o plugin/common.o plugin/debug.o
++ ar -rc $@ $^
++
++plugin/discovery.o: discovery.c
++ @CC@ $(CFLAGS) '-DVERSION=&quot;$(VERSION)&quot;' -c -o plugin/discovery.o -fPIC discovery.c
++
++plugin/if.o: if.c
++ @CC@ $(CFLAGS) '-DVERSION=&quot;$(VERSION)&quot;' -c -o plugin/if.o -fPIC if.c
++
++plugin/debug.o: debug.c
++ @CC@ $(CFLAGS) '-DVERSION=&quot;$(VERSION)&quot;' -c -o plugin/debug.o -fPIC debug.c
++
++plugin/common.o: common.c
++ @CC@ $(CFLAGS) '-DVERSION=&quot;$(VERSION)&quot;' -c -o plugin/common.o -fPIC common.c
++
++install: all
++ -mkdir -p $(RPM_INSTALL_ROOT)$(sbindir)
++ $(install) -m 755 -s pppoe $(RPM_INSTALL_ROOT)$(sbindir)
++ $(install) -m 755 -s pppoe-server $(RPM_INSTALL_ROOT)$(sbindir)
++ if test -x pppoe-relay ; then $(install) -m 755 -s pppoe-relay $(RPM_INSTALL_ROOT)$(sbindir); fi
++ $(install) -m 755 -s pppoe-sniff $(RPM_INSTALL_ROOT)$(sbindir)
++ $(install) -m 755 ../scripts/adsl-connect $(RPM_INSTALL_ROOT)$(sbindir)
++ $(install) -m 755 ../scripts/adsl-start $(RPM_INSTALL_ROOT)$(sbindir)
++ $(install) -m 755 ../scripts/adsl-status $(RPM_INSTALL_ROOT)$(sbindir)
++ $(install) -m 755 ../scripts/adsl-stop $(RPM_INSTALL_ROOT)$(sbindir)
++ $(install) -m 755 ../scripts/adsl-setup $(RPM_INSTALL_ROOT)$(sbindir)
++ -mkdir -p $(RPM_INSTALL_ROOT)$(docdir)
++ $(install) -m 644 ../doc/CHANGES $(RPM_INSTALL_ROOT)$(docdir)
++ $(install) -m 644 ../doc/KERNEL-MODE-PPPOE $(RPM_INSTALL_ROOT)$(docdir)
++ $(install) -m 644 ../doc/HOW-TO-CONNECT $(RPM_INSTALL_ROOT)$(docdir)
++ $(install) -m 644 ../doc/LICENSE $(RPM_INSTALL_ROOT)$(docdir)
++ $(install) -m 644 ../README $(RPM_INSTALL_ROOT)$(docdir)
++ $(install) -m 644 ../configs/pap-secrets $(RPM_INSTALL_ROOT)$(docdir)
++ -mkdir -p $(RPM_INSTALL_ROOT)$(mandir)/man8
++ for i in $(TARGETS) ; do \
++ if test -f ../man/$$i.8 ; then \
++ $(install) -m 644 ../man/$$i.8 $(RPM_INSTALL_ROOT)$(mandir)/man8 || exit 1; \
++ fi; \
++ done
++ $(install) -m 644 ../man/adsl-start.8 $(RPM_INSTALL_ROOT)$(mandir)/man8
++ $(install) -m 644 ../man/adsl-stop.8 $(RPM_INSTALL_ROOT)$(mandir)/man8
++ $(install) -m 644 ../man/adsl-status.8 $(RPM_INSTALL_ROOT)$(mandir)/man8
++ $(install) -m 644 ../man/adsl-connect.8 $(RPM_INSTALL_ROOT)$(mandir)/man8
++ $(install) -m 644 ../man/adsl-setup.8 $(RPM_INSTALL_ROOT)$(mandir)/man8
++ -mkdir -p $(RPM_INSTALL_ROOT)$(mandir)/man5
++ $(install) -m 644 ../man/pppoe.conf.5 $(RPM_INSTALL_ROOT)$(mandir)/man5
++ -mkdir -p $(RPM_INSTALL_ROOT)/etc/ppp
++ -mkdir -p $(RPM_INSTALL_ROOT)$(PLUGIN_DIR)
++ -echo &quot;# Directory created by rp-pppoe for kernel-mode plugin&quot; &gt; $(RPM_INSTALL_ROOT)$(PLUGIN_DIR)/README
++ @if test -r rp-pppoe.so; then $(install) -m 755 rp-pppoe.so $(RPM_INSTALL_ROOT)$(PLUGIN_DIR); fi
++ @for i in pppoe.conf firewall-standalone firewall-masq ; do \
++ if [ ! -f $(RPM_INSTALL_ROOT)/etc/ppp/$$i ] ; then \
++ $(install) -m 644 ../configs/$$i $(RPM_INSTALL_ROOT)/etc/ppp ; \
++ else \
++ echo &quot;NOT overwriting existing $(RPM_INSTALL_ROOT)/etc/ppp/$$i&quot; ;\
++ $(install) -m 644 ../configs/$$i $(RPM_INSTALL_ROOT)/etc/ppp/$$i-$(VERSION) ;\
++ fi ;\
++ done
++ @if [ ! -f $(RPM_INSTALL_ROOT)$(PPPOESERVER_PPPD_OPTIONS) ] ; then \
++ $(install) -m 644 ../configs/pppoe-server-options $(RPM_INSTALL_ROOT)$(PPPOESERVER_PPPD_OPTIONS) ; \
++ else \
++ echo &quot;NOT overwriting existing $(RPM_INSTALL_ROOT)$(PPPOESERVER_PPPD_OPTIONS)&quot;; \
++ $(install) -m 644 ../configs/pppoe-server-options $(RPM_INSTALL_ROOT)$(PPPOESERVER_PPPD_OPTIONS)-example ; \
++ fi
++ @if [ -f /etc/redhat-release ] ; then \
++ echo &quot;Looks like a Red Hat system; installing $(RPM_INSTALL_ROOT)/etc/rc.d/init.d/adsl&quot; ; \
++ mkdir -p $(RPM_INSTALL_ROOT)/etc/rc.d/init.d ;\
++ $(install) -m 755 ../scripts/adsl-init $(RPM_INSTALL_ROOT)/etc/rc.d/init.d/adsl ; \
++ fi
++ @if [ -f /etc/turbolinux-release ] ; then \
++ echo &quot;Looks like a TurboLinux system; installing $(RPM_INSTALL_ROOT)/etc/rc.d/init.d/adsl&quot; ; \
++ mkdir -p $(RPM_INSTALL_ROOT)/etc/rc.d/init.d ;\
++ $(install) -m 755 adsl-init-turbolinux $(RPM_INSTALL_ROOT)/etc/rc.d/init.d/adsl ; \
++ fi
++ @if [ -f /etc/SuSE-release ] ; then \
++ echo &quot;Looks like a SuSE Linux system; installing $(RPM_INSTALL_ROOT)/etc/rc.d/init.d/adsl&quot; ; \
++ mkdir -p $(RPM_INSTALL_ROOT)/etc/rc.d/init.d ;\
++ $(install) -m 755 ../scripts/adsl-init-suse $(RPM_INSTALL_ROOT)/etc/rc.d/init.d/adsl ; \
++ fi
++ @echo &quot;&quot;
++ @echo &quot;Type 'adsl-setup' to configure the software.&quot;
++
++distro:
++ cd ..; \
++ rm -rf rp-pppoe-$(VERSION) ; \
++ mkdir rp-pppoe-$(VERSION) || exit 1; \
++ for i in README go go-gui rp-pppoe.spec rp-pppoe-gui.spec; do \
++ cp $$i rp-pppoe-$(VERSION) || exit 1; \
++ done ; \
++ mkdir rp-pppoe-$(VERSION)/gui || exit 1; \
++ for i in Makefile.in tkpppoe.in wrapper.c tkpppoe.1 pppoe-wrapper.1 ; do \
++ cp gui/$$i rp-pppoe-$(VERSION)/gui || exit 1; \
++ done; \
++ mkdir rp-pppoe-$(VERSION)/gui/html || exit 1; \
++ for i in mainwin-busy.png mainwin-nonroot.png mainwin.png props-advanced.png props-basic.png props-nic.png props-options.png tkpppoe.html ; do \
++ cp gui/html/$$i rp-pppoe-$(VERSION)/gui/html || exit 1; \
++ done; \
++ mkdir rp-pppoe-$(VERSION)/configs || exit 1; \
++ for i in firewall-masq firewall-standalone pap-secrets pppoe-server-options pppoe.conf ; do \
++ cp configs/$$i rp-pppoe-$(VERSION)/configs || exit 1; \
++ done ; \
++ mkdir rp-pppoe-$(VERSION)/doc || exit 1; \
++ for i in CHANGES KERNEL-MODE-PPPOE HOW-TO-CONNECT LICENSE PROBLEMS ; do \
++ cp doc/$$i rp-pppoe-$(VERSION)/doc || exit 1; \
++ done; \
++ mkdir rp-pppoe-$(VERSION)/man || exit 1; \
++ for i in adsl-connect.8 adsl-setup.8 adsl-start.8 adsl-status.8 adsl-stop.8 pppoe-server.8 pppoe-sniff.8 pppoe.8 pppoe-relay.8 pppoe.conf.5 ; do \
++ cp man/$$i rp-pppoe-$(VERSION)/man || exit 1; \
++ done; \
++ mkdir rp-pppoe-$(VERSION)/scripts || exit 1; \
++ for i in adsl-connect.in adsl-init-suse.in adsl-init-turbolinux.in adsl-init.in adsl-setup.in adsl-start.in adsl-stop.in adsl-status ; do \
++ cp scripts/$$i rp-pppoe-$(VERSION)/scripts || exit 1; \
++ done; \
++ mkdir rp-pppoe-$(VERSION)/src || exit 1; \
++ for i in Makefile.in install-sh common.c config.h.in configure configure.in debug.c discovery.c if.c md5.c md5.h ppp.c pppoe-server.c pppoe-sniff.c pppoe.c pppoe.h plugin.c relay.c relay.h ; do \
++ cp src/$$i rp-pppoe-$(VERSION)/src || exit 1; \
++ done; \
++ mkdir rp-pppoe-$(VERSION)/src/plugin || exit 1; \
++ tar cvf rp-pppoe-$(VERSION).tar rp-pppoe-$(VERSION)/* ; \
++ gzip -f -v -9 rp-pppoe-$(VERSION).tar ; \
++
++rpms: distro
++ cp ../rp-pppoe-$(VERSION).tar.gz /usr/src/redhat/SOURCES
++ cd ..; \
++ rpm -ba rp-pppoe.spec; \
++ rpm -ba rp-pppoe-gui.spec
++
++clean:
++ rm -f *.o pppoe pppoe-sniff pppoe-server core rp-pppoe.so plugin/*.o plugin/libplugin.a *~
++
++distclean: clean
++ rm -f Makefile config.h config.cache config.log config.status
++ rm -f ../scripts/adsl-connect ../scripts/adsl-start ../scripts/adsl-stop ../scripts/adsl-init ../scripts/adsl-setup ../scripts/adsl-init-suse ../scripts/adsl-init-turbolinux
++
++update-version:
++ sed -e 's/^Version: .*$$/Version: $(VERSION)/' ../rp-pppoe.spec &gt; ../rp-pppoe.spec.new &amp;&amp; mv ../rp-pppoe.spec.new ../rp-pppoe.spec
++ sed -e 's+^Source: .*$$+Source: <A HREF="http://www.roaringpenguin.com/pppoe/rp-pppoe-$(VERSION">http://www.roaringpenguin.com/pppoe/rp-pppoe-$(VERSION</A>).tar.gz+' ../rp-pppoe.spec &gt; ../rp-pppoe.spec.new &amp;&amp; mv ../rp-pppoe.spec.new ../rp-pppoe.spec
++ sed -e 's/^Version: .*$$/Version: $(VERSION)/' ../rp-pppoe-gui.spec &gt; ../rp-pppoe-gui.spec.new &amp;&amp; mv ../rp-pppoe-gui.spec.new ../rp-pppoe-gui.spec
++ sed -e 's+^Source: .*$$+Source: <A HREF="http://www.roaringpenguin.com/pppoe/rp-pppoe-$(VERSION">http://www.roaringpenguin.com/pppoe/rp-pppoe-$(VERSION</A>).tar.gz+' ../rp-pppoe-gui.spec &gt; ../rp-pppoe-gui.spec.new &amp;&amp; mv ../rp-pppoe-gui.spec.new ../rp-pppoe-gui.spec
++ sed -e 's+^Requires: rp-pppoe &gt;=.*$$+Requires: rp-pppoe &gt;= $(VERSION)+' ../rp-pppoe-gui.spec &gt; ../rp-pppoe-gui.spec.new &amp;&amp; mv ../rp-pppoe-gui.spec.new ../rp-pppoe-gui.spec
++
++# Convenience target for David! Don't try to use this one.
++km:
++ ./configure --enable-plugin=/home/dfs/Archive/PPP/ppp-2.4.0.pppoe4-patched-dfs
++
++.PHONY: update-version
++
++.PHONY: clean
++
++.PHONY: distclean
++
++.PHONY: rpms
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/src/common.c
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/src/common.c (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/src/common.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,485 @@
++/***********************************************************************
++*
++* common.c
++*
++* Implementation of user-space PPPoE redirector for Linux.
++*
++* Common functions used by PPPoE client and server
++*
++* Copyright (C) 2000 by Roaring Penguin Software Inc.
++*
++* This program may be distributed according to the terms of the GNU
++* General Public License, version 2 or (at your option) any later version.
++*
++***********************************************************************/
++
++static char const RCSID[] =
++&quot;$Id: common.c 212191 2005-05-06 06:30:51Z rgarciasuarez $&quot;;
++
++#include &quot;pppoe.h&quot;
++
++#ifdef HAVE_SYSLOG_H
++#include &lt;syslog.h&gt;
++#endif
++
++#include &lt;string.h&gt;
++#include &lt;errno.h&gt;
++#include &lt;stdlib.h&gt;
++
++#ifdef HAVE_UNISTD_H
++#include &lt;unistd.h&gt;
++#endif
++
++/**********************************************************************
++*%FUNCTION: parsePacket
++*%ARGUMENTS:
++* packet -- the PPPoE discovery packet to parse
++* func -- function called for each tag in the packet
++* extra -- an opaque data pointer supplied to parsing function
++*%RETURNS:
++* 0 if everything went well; -1 if there was an error
++*%DESCRIPTION:
++* Parses a PPPoE discovery packet, calling &quot;func&quot; for each tag in the packet.
++* &quot;func&quot; is passed the additional argument &quot;extra&quot;.
++***********************************************************************/
++int
++parsePacket(PPPoEPacket *packet, ParseFunc *func, void *extra)
++{
++ UINT16_t len = ntohs(packet-&gt;length);
++ unsigned char *curTag;
++ UINT16_t tagType, tagLen;
++
++ if (packet-&gt;ver != 1) {
++ syslog(LOG_ERR, &quot;Invalid PPPoE version (%d)&quot;, (int) packet-&gt;ver);
++ return -1;
++ }
++ if (packet-&gt;type != 1) {
++ syslog(LOG_ERR, &quot;Invalid PPPoE type (%d)&quot;, (int) packet-&gt;type);
++ return -1;
++ }
++
++ /* Do some sanity checks on packet */
++ if (len &gt; ETH_DATA_LEN - 6) { /* 6-byte overhead for PPPoE header */
++ syslog(LOG_ERR, &quot;Invalid PPPoE packet length (%u)&quot;, len);
++ return -1;
++ }
++
++ /* Step through the tags */
++ curTag = packet-&gt;payload;
++ while(curTag - packet-&gt;payload &lt; len) {
++ /* Alignment is not guaranteed, so do this by hand... */
++ tagType = (((UINT16_t) curTag[0]) &lt;&lt; 8) +
++ (UINT16_t) curTag[1];
++ tagLen = (((UINT16_t) curTag[2]) &lt;&lt; 8) +
++ (UINT16_t) curTag[3];
++ if (tagType == TAG_END_OF_LIST) {
++ return 0;
++ }
++ if ((curTag - packet-&gt;payload) + tagLen + TAG_HDR_SIZE &gt; len) {
++ syslog(LOG_ERR, &quot;Invalid PPPoE tag length (%u)&quot;, tagLen);
++ return -1;
++ }
++ func(tagType, tagLen, curTag+TAG_HDR_SIZE, extra);
++ curTag = curTag + TAG_HDR_SIZE + tagLen;
++ }
++ return 0;
++}
++
++/**********************************************************************
++*%FUNCTION: findTag
++*%ARGUMENTS:
++* packet -- the PPPoE discovery packet to parse
++* type -- the type of the tag to look for
++* tag -- will be filled in with tag contents
++*%RETURNS:
++* A pointer to the tag if one of the specified type is found; NULL
++* otherwise.
++*%DESCRIPTION:
++* Looks for a specific tag type.
++***********************************************************************/
++unsigned char *
++findTag(PPPoEPacket *packet, UINT16_t type, PPPoETag *tag)
++{
++ UINT16_t len = ntohs(packet-&gt;length);
++ unsigned char *curTag;
++ UINT16_t tagType, tagLen;
++
++ if (packet-&gt;ver != 1) {
++ syslog(LOG_ERR, &quot;Invalid PPPoE version (%d)&quot;, (int) packet-&gt;ver);
++ return NULL;
++ }
++ if (packet-&gt;type != 1) {
++ syslog(LOG_ERR, &quot;Invalid PPPoE type (%d)&quot;, (int) packet-&gt;type);
++ return NULL;
++ }
++
++ /* Do some sanity checks on packet */
++ if (len &gt; ETH_DATA_LEN - 6) { /* 6-byte overhead for PPPoE header */
++ syslog(LOG_ERR, &quot;Invalid PPPoE packet length (%u)&quot;, len);
++ return NULL;
++ }
++
++ /* Step through the tags */
++ curTag = packet-&gt;payload;
++ while(curTag - packet-&gt;payload &lt; len) {
++ /* Alignment is not guaranteed, so do this by hand... */
++ tagType = (((UINT16_t) curTag[0]) &lt;&lt; 8) +
++ (UINT16_t) curTag[1];
++ tagLen = (((UINT16_t) curTag[2]) &lt;&lt; 8) +
++ (UINT16_t) curTag[3];
++ if (tagType == TAG_END_OF_LIST) {
++ return NULL;
++ }
++ if ((curTag - packet-&gt;payload) + tagLen + TAG_HDR_SIZE &gt; len) {
++ syslog(LOG_ERR, &quot;Invalid PPPoE tag length (%u)&quot;, tagLen);
++ return NULL;
++ }
++ if (tagType == type) {
++ memcpy(tag, curTag, tagLen + TAG_HDR_SIZE);
++ return curTag;
++ }
++ curTag = curTag + TAG_HDR_SIZE + tagLen;
++ }
++ return NULL;
++}
++
++/**********************************************************************
++*%FUNCTION: printErr
++*%ARGUMENTS:
++* str -- error message
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Prints a message to stderr and syslog.
++***********************************************************************/
++void
++printErr(char const *str)
++{
++ fprintf(stderr, &quot;pppoe: %s\n&quot;, str);
++ syslog(LOG_ERR, &quot;%s&quot;, str);
++}
++
++
++/**********************************************************************
++*%FUNCTION: strDup
++*%ARGUMENTS:
++* str -- string to copy
++*%RETURNS:
++* A malloc'd copy of str. Exits if malloc fails.
++***********************************************************************/
++char *
++strDup(char const *str)
++{
++ char *copy = malloc(strlen(str)+1);
++ if (!copy) {
++ rp_fatal(&quot;strdup failed&quot;);
++ }
++ strcpy(copy, str);
++ return copy;
++}
++
++/**********************************************************************
++*%FUNCTION: computeTCPChecksum
++*%ARGUMENTS:
++* ipHdr -- pointer to IP header
++* tcpHdr -- pointer to TCP header
++*%RETURNS:
++* The computed TCP checksum
++***********************************************************************/
++UINT16_t
++computeTCPChecksum(unsigned char *ipHdr, unsigned char *tcpHdr)
++{
++ UINT32_t sum = 0;
++ UINT16_t count = ipHdr[2] * 256 + ipHdr[3];
++ unsigned char *addr = tcpHdr;
++ unsigned char pseudoHeader[12];
++
++ /* Count number of bytes in TCP header and data */
++ count -= (ipHdr[0] &amp; 0x0F) * 4;
++
++ memcpy(pseudoHeader, ipHdr+12, 8);
++ pseudoHeader[8] = 0;
++ pseudoHeader[9] = ipHdr[9];
++ pseudoHeader[10] = (count &gt;&gt; 8) &amp; 0xFF;
++ pseudoHeader[11] = (count &amp; 0xFF);
++
++ /* Checksum the pseudo-header */
++ sum += * (UINT16_t *) pseudoHeader;
++ sum += * ((UINT16_t *) (pseudoHeader+2));
++ sum += * ((UINT16_t *) (pseudoHeader+4));
++ sum += * ((UINT16_t *) (pseudoHeader+6));
++ sum += * ((UINT16_t *) (pseudoHeader+8));
++ sum += * ((UINT16_t *) (pseudoHeader+10));
++
++ /* Checksum the TCP header and data */
++ while (count &gt; 1) {
++ sum += * (UINT16_t *) addr;
++ addr += 2;
++ count -= 2;
++ }
++ if (count &gt; 0) {
++ sum += *addr;
++ }
++
++ while(sum &gt;&gt; 16) {
++ sum = (sum &amp; 0xffff) + (sum &gt;&gt; 16);
++ }
++ return (UINT16_t) (~sum &amp; 0xFFFF);
++}
++
++/**********************************************************************
++*%FUNCTION: clampMSS
++*%ARGUMENTS:
++* packet -- PPPoE session packet
++* dir -- either &quot;incoming&quot; or &quot;outgoing&quot;
++* clampMss -- clamp value
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Clamps MSS option if TCP SYN flag is set.
++***********************************************************************/
++void
++clampMSS(PPPoEPacket *packet, char const *dir, int clampMss)
++{
++ unsigned char *tcpHdr;
++ unsigned char *ipHdr;
++ unsigned char *opt;
++ unsigned char *endHdr;
++ unsigned char *mssopt = NULL;
++ UINT16_t csum;
++
++ int len;
++
++ /* Is it IPv4? */
++ if (packet-&gt;payload[0] != 0x00 ||
++ packet-&gt;payload[1] != 0x21) {
++ /* Nope, ignore it */
++ return;
++ }
++
++ ipHdr = packet-&gt;payload + 2;
++
++ /* Is it too short? */
++ len = (int) ntohs(packet-&gt;length);
++ if (len &lt; 42) {
++ /* 20 byte IP header; 20 byte TCP header; 2 byte PPP protocol */
++ return;
++ }
++
++ /* Verify once more that it's IPv4 */
++ if ((ipHdr[0] &amp; 0xF0) != 0x40) {
++ return;
++ }
++
++ /* Is it a fragment that's not at the beginning of the packet? */
++ if ((ipHdr[6] &amp; 0x1F) || ipHdr[7]) {
++ /* Yup, don't touch! */
++ return;
++ }
++ /* Is it TCP? */
++ if (ipHdr[9] != 0x06) {
++ return;
++ }
++
++ /* Get start of TCP header */
++ tcpHdr = ipHdr + (ipHdr[0] &amp; 0x0F) * 4;
++
++ /* Is SYN set? */
++ if (!(tcpHdr[13] &amp; 0x02)) {
++ return;
++ }
++
++ /* Compute and verify TCP checksum -- do not touch a packet with a bad
++ checksum */
++ csum = computeTCPChecksum(ipHdr, tcpHdr);
++ if (csum) {
++ syslog(LOG_ERR, &quot;Bad TCP checksum %x&quot;, (unsigned int) csum);
++
++ /* Upper layers will drop it */
++ return;
++ }
++
++ /* Look for existing MSS option */
++ endHdr = tcpHdr + ((tcpHdr[12] &amp; 0xF0) &gt;&gt; 2);
++ opt = tcpHdr + 20;
++ while (opt &lt; endHdr) {
++ if (!*opt) break; /* End of options */
++ switch(*opt) {
++ case 1:
++ opt++;
++ break;
++
++ case 2:
++ if (opt[1] != 4) {
++ /* Something fishy about MSS option length. */
++ syslog(LOG_ERR,
++ &quot;Bogus length for MSS option (%u) from %u.%u.%u.%u&quot;,
++ (unsigned int) opt[1],
++ (unsigned int) ipHdr[12],
++ (unsigned int) ipHdr[13],
++ (unsigned int) ipHdr[14],
++ (unsigned int) ipHdr[15]);
++ return;
++ }
++ mssopt = opt;
++ break;
++ default:
++ if (opt[1] &lt; 2) {
++ /* Someone's trying to attack us? */
++ syslog(LOG_ERR,
++ &quot;Bogus TCP option length (%u) from %u.%u.%u.%u&quot;,
++ (unsigned int) opt[1],
++ (unsigned int) ipHdr[12],
++ (unsigned int) ipHdr[13],
++ (unsigned int) ipHdr[14],
++ (unsigned int) ipHdr[15]);
++ return;
++ }
++ opt += (opt[1]);
++ break;
++ }
++ /* Found existing MSS option? */
++ if (mssopt) break;
++ }
++
++ /* If MSS exists and it's low enough, do nothing */
++ if (mssopt) {
++ unsigned mss = mssopt[2] * 256 + mssopt[3];
++ if (mss &lt;= clampMss) {
++ return;
++ }
++
++ mssopt[2] = (((unsigned) clampMss) &gt;&gt; 8) &amp; 0xFF;
++ mssopt[3] = ((unsigned) clampMss) &amp; 0xFF;
++ } else {
++ /* No MSS option. Don't add one; we'll have to use 536. */
++ return;
++ }
++
++ /* Recompute TCP checksum */
++ tcpHdr[16] = 0;
++ tcpHdr[17] = 0;
++ csum = computeTCPChecksum(ipHdr, tcpHdr);
++ (* (UINT16_t *) (tcpHdr+16)) = csum;
++}
++
++/***********************************************************************
++*%FUNCTION: sendPADT
++*%ARGUMENTS:
++* conn -- PPPoE connection
++* msg -- if non-NULL, extra error message to include in PADT packet.
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Sends a PADT packet
++***********************************************************************/
++void
++sendPADT(PPPoEConnection *conn, char const *msg)
++{
++ PPPoEPacket packet;
++ unsigned char *cursor = packet.payload;
++
++ UINT16_t plen = 0;
++
++ /* Do nothing if no session established yet */
++ if (!conn-&gt;session) return;
++
++ /* Do nothing if no discovery socket */
++ if (conn-&gt;discoverySocket &lt; 0) return;
++
++ memcpy(packet.ethHdr.h_dest, conn-&gt;peerEth, ETH_ALEN);
++ memcpy(packet.ethHdr.h_source, conn-&gt;myEth, ETH_ALEN);
++
++ packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
++ packet.ver = 1;
++ packet.type = 1;
++ packet.code = CODE_PADT;
++ packet.session = conn-&gt;session;
++
++ /* Reset Session to zero so there is no possibility of
++ recursive calls to this function by any signal handler */
++ conn-&gt;session = 0;
++
++ /* If we're using Host-Uniq, copy it over */
++ if (conn-&gt;useHostUniq) {
++ PPPoETag hostUniq;
++ pid_t pid = getpid();
++ hostUniq.type = htons(TAG_HOST_UNIQ);
++ hostUniq.length = htons(sizeof(pid));
++ memcpy(hostUniq.payload, &amp;pid, sizeof(pid));
++ memcpy(cursor, &amp;hostUniq, sizeof(pid) + TAG_HDR_SIZE);
++ cursor += sizeof(pid) + TAG_HDR_SIZE;
++ plen += sizeof(pid) + TAG_HDR_SIZE;
++ }
++
++ /* Copy error message */
++ if (msg) {
++ PPPoETag err;
++ size_t elen = strlen(msg);
++ err.type = htons(TAG_GENERIC_ERROR);
++ err.length = htons(elen);
++ strcpy((char *)err.payload, msg);
++ memcpy(cursor, &amp;err, elen + TAG_HDR_SIZE);
++ cursor += elen + TAG_HDR_SIZE;
++ plen += elen + TAG_HDR_SIZE;
++ }
++
++ /* Copy cookie and relay-ID if needed */
++ if (conn-&gt;cookie.type) {
++ CHECK_ROOM(cursor, packet.payload,
++ ntohs(conn-&gt;cookie.length) + TAG_HDR_SIZE);
++ memcpy(cursor, &amp;conn-&gt;cookie, ntohs(conn-&gt;cookie.length) + TAG_HDR_SIZE);
++ cursor += ntohs(conn-&gt;cookie.length) + TAG_HDR_SIZE;
++ plen += ntohs(conn-&gt;cookie.length) + TAG_HDR_SIZE;
++ }
++
++ if (conn-&gt;relayId.type) {
++ CHECK_ROOM(cursor, packet.payload,
++ ntohs(conn-&gt;relayId.length) + TAG_HDR_SIZE);
++ memcpy(cursor, &amp;conn-&gt;relayId, ntohs(conn-&gt;relayId.length) + TAG_HDR_SIZE);
++ cursor += ntohs(conn-&gt;relayId.length) + TAG_HDR_SIZE;
++ plen += ntohs(conn-&gt;relayId.length) + TAG_HDR_SIZE;
++ }
++
++ packet.length = htons(plen);
++ sendPacket(conn, conn-&gt;discoverySocket, &amp;packet, (int) (plen + HDR_SIZE));
++ if (conn-&gt;debugFile) {
++ dumpPacket(conn-&gt;debugFile, &amp;packet, &quot;SENT&quot;);
++ fprintf(conn-&gt;debugFile, &quot;\n&quot;);
++ fflush(conn-&gt;debugFile);
++ }
++ syslog(LOG_INFO,&quot;Sent PADT&quot;);
++}
++
++/**********************************************************************
++*%FUNCTION: parseLogErrs
++*%ARGUMENTS:
++* type -- tag type
++* len -- tag length
++* data -- tag data
++* extra -- extra user data
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Picks error tags out of a packet and logs them.
++***********************************************************************/
++void
++parseLogErrs(UINT16_t type, UINT16_t len, unsigned char *data,
++ void *extra)
++{
++ switch(type) {
++ case TAG_SERVICE_NAME_ERROR:
++ syslog(LOG_ERR, &quot;PADT: Service-Name-Error: %.*s&quot;, (int) len, data);
++ fprintf(stderr, &quot;PADT: Service-Name-Error: %.*s\n&quot;, (int) len, data);
++ break;
++ case TAG_AC_SYSTEM_ERROR:
++ syslog(LOG_ERR, &quot;PADT: System-Error: %.*s&quot;, (int) len, data);
++ fprintf(stderr, &quot;PADT: System-Error: %.*s\n&quot;, (int) len, data);
++ break;
++ case TAG_GENERIC_ERROR:
++ syslog(LOG_ERR, &quot;PADT: Generic-Error: %.*s&quot;, (int) len, data);
++ fprintf(stderr, &quot;PADT: Generic-Error: %.*s\n&quot;, (int) len, data);
++ break;
++ }
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/src/common.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/src/config.h
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/src/config.h (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/src/config.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,135 @@
++/* config.h. Generated automatically by configure. */
++/* config.h.in. Generated automatically from configure.in by autoheader. */
++
++/* Define to empty if the keyword does not work. */
++/* #undef const */
++
++/* Define if you have &lt;sys/wait.h&gt; that is POSIX.1 compatible. */
++#define HAVE_SYS_WAIT_H 1
++
++/* Define to `int' if &lt;sys/types.h&gt; doesn't define. */
++/* #undef pid_t */
++
++/* Define as the return type of signal handlers (int or void). */
++#define RETSIGTYPE void
++
++/* Define if the setvbuf function takes the buffering type as its second
++ argument and the buffer pointer as the third, as on System V
++ before release 3. */
++/* #undef SETVBUF_REVERSED */
++
++/* Define if you have the ANSI C header files. */
++#define STDC_HEADERS 1
++
++/* Define if you can safely include both &lt;sys/time.h&gt; and &lt;time.h&gt;. */
++#define TIME_WITH_SYS_TIME 1
++
++/* Define if your &lt;sys/time.h&gt; declares struct tm. */
++/* #undef TM_IN_SYS_TIME */
++
++#define HAVE_STRUCT_SOCKADDR_LL 1
++
++/* The number of bytes in a unsigned int. */
++#define SIZEOF_UNSIGNED_INT 4
++
++/* The number of bytes in a unsigned long. */
++#define SIZEOF_UNSIGNED_LONG 4
++
++/* The number of bytes in a unsigned short. */
++#define SIZEOF_UNSIGNED_SHORT 2
++
++/* Define if you have the select function. */
++#define HAVE_SELECT 1
++
++/* Define if you have the socket function. */
++#define HAVE_SOCKET 1
++
++/* Define if you have the strerror function. */
++#define HAVE_STRERROR 1
++
++/* Define if you have the strtol function. */
++#define HAVE_STRTOL 1
++
++/* Define if you have the &lt;asm/types.h&gt; header file. */
++#define HAVE_ASM_TYPES_H 1
++
++/* Define if you have the &lt;fcntl.h&gt; header file. */
++#define HAVE_FCNTL_H 1
++
++/* Define if you have the &lt;getopt.h&gt; header file. */
++#define HAVE_GETOPT_H 1
++
++/* Define if you have the &lt;linux/if_ether.h&gt; header file. */
++#define HAVE_LINUX_IF_ETHER_H 1
++
++/* Define if you have kernel-mode PPPoE in Linux file. */
++/* #undef HAVE_LINUX_KERNEL_PPPOE */
++
++/* Define if you have the &lt;linux/if_packet.h&gt; header file. */
++#define HAVE_LINUX_IF_PACKET_H 1
++
++/* Define if you have the &lt;linux/if_pppox.h&gt; header file. */
++#define HAVE_LINUX_IF_PPPOX_H 1
++
++/* Define if you have the &lt;net/bpf.h&gt; header file. */
++#define HAVE_NET_BPF_H 1
++
++/* Define if you have the &lt;net/if_arp.h&gt; header file. */
++//#define HAVE_NET_IF_ARP_H 1
++
++/* Define if you have the &lt;net/ethernet.h&gt; header file. */
++#define HAVE_NET_ETHERNET_H 1
++
++/* Define if you have the &lt;net/if.h&gt; header file. */
++#define HAVE_NET_IF_H 1
++
++/* Define if you have the &lt;linux/if.h&gt; header file. */
++#define HAVE_LINUX_IF_H 1
++
++/* Define if you have the &lt;net/if_dl.h&gt; header file. */
++/* #undef HAVE_NET_IF_DL_H */
++
++/* Define if you have the &lt;net/if_ether.h&gt; header file. */
++/* #undef HAVE_NET_IF_ETHER_H */
++
++/* Define if you have the &lt;net/if_types.h&gt; header file. */
++/* #undef HAVE_NET_IF_TYPES_H */
++
++/* Define if you have the &lt;netinet/if_ether.h&gt; header file. */
++//#define HAVE_NETINET_IF_ETHER_H 1
++
++/* Define if you have the &lt;netpacket/packet.h&gt; header file. */
++#define HAVE_NETPACKET_PACKET_H 1
++
++/* Define if you have the &lt;sys/cdefs.h&gt; header file. */
++#define HAVE_SYS_CDEFS_H 1
++
++/* Define if you have the &lt;sys/dlpi.h&gt; header file. */
++/* #undef HAVE_SYS_DLPI_H */
++
++/* Define if you have the &lt;sys/ioctl.h&gt; header file. */
++#define HAVE_SYS_IOCTL_H 1
++
++/* Define if you have the &lt;sys/param.h&gt; header file. */
++#define HAVE_SYS_PARAM_H 1
++
++/* Define if you have the &lt;sys/socket.h&gt; header file. */
++#define HAVE_SYS_SOCKET_H 1
++
++/* Define if you have the &lt;sys/time.h&gt; header file. */
++#define HAVE_SYS_TIME_H 1
++
++/* Define if you have the &lt;sys/uio.h&gt; header file. */
++#define HAVE_SYS_UIO_H 1
++
++/* Define if you have the &lt;syslog.h&gt; header file. */
++#define HAVE_SYSLOG_H 1
++
++/* Define if you have the &lt;unistd.h&gt; header file. */
++#define HAVE_UNISTD_H 1
++
++/* Define if you have the N_HDLC line discipline in linux/termios.h */
++#define HAVE_N_HDLC 1
++
++/* Define if bitfields are packed in reverse order */
++#define PACK_BITFIELDS_REVERSED 1
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/src/config.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/src/config.h.in
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/src/config.h.in (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/src/config.h.in 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,134 @@
++/* config.h.in. Generated automatically from configure.in by autoheader. */
++
++/* Define to empty if the keyword does not work. */
++#undef const
++
++/* Define if you have &lt;sys/wait.h&gt; that is POSIX.1 compatible. */
++#undef HAVE_SYS_WAIT_H
++
++/* Define to `int' if &lt;sys/types.h&gt; doesn't define. */
++#undef pid_t
++
++/* Define as the return type of signal handlers (int or void). */
++#undef RETSIGTYPE
++
++/* Define if the setvbuf function takes the buffering type as its second
++ argument and the buffer pointer as the third, as on System V
++ before release 3. */
++#undef SETVBUF_REVERSED
++
++/* Define if you have the ANSI C header files. */
++#undef STDC_HEADERS
++
++/* Define if you can safely include both &lt;sys/time.h&gt; and &lt;time.h&gt;. */
++#undef TIME_WITH_SYS_TIME
++
++/* Define if your &lt;sys/time.h&gt; declares struct tm. */
++#undef TM_IN_SYS_TIME
++
++#undef HAVE_STRUCT_SOCKADDR_LL
++
++/* The number of bytes in a unsigned int. */
++#undef SIZEOF_UNSIGNED_INT
++
++/* The number of bytes in a unsigned long. */
++#undef SIZEOF_UNSIGNED_LONG
++
++/* The number of bytes in a unsigned short. */
++#undef SIZEOF_UNSIGNED_SHORT
++
++/* Define if you have the select function. */
++#undef HAVE_SELECT
++
++/* Define if you have the socket function. */
++#undef HAVE_SOCKET
++
++/* Define if you have the strerror function. */
++#undef HAVE_STRERROR
++
++/* Define if you have the strtol function. */
++#undef HAVE_STRTOL
++
++/* Define if you have the &lt;asm/types.h&gt; header file. */
++#undef HAVE_ASM_TYPES_H
++
++/* Define if you have the &lt;fcntl.h&gt; header file. */
++#undef HAVE_FCNTL_H
++
++/* Define if you have the &lt;getopt.h&gt; header file. */
++#undef HAVE_GETOPT_H
++
++/* Define if you have the &lt;linux/if_ether.h&gt; header file. */
++#undef HAVE_LINUX_IF_ETHER_H
++
++/* Define if you have kernel-mode PPPoE in Linux file. */
++#undef HAVE_LINUX_KERNEL_PPPOE
++
++/* Define if you have the &lt;linux/if_packet.h&gt; header file. */
++#undef HAVE_LINUX_IF_PACKET_H
++
++/* Define if you have the &lt;linux/if_pppox.h&gt; header file. */
++#undef HAVE_LINUX_IF_PPPOX_H
++
++/* Define if you have the &lt;net/bpf.h&gt; header file. */
++#undef HAVE_NET_BPF_H
++
++/* Define if you have the &lt;net/if_arp.h&gt; header file. */
++#undef HAVE_NET_IF_ARP_H
++
++/* Define if you have the &lt;net/ethernet.h&gt; header file. */
++#undef HAVE_NET_ETHERNET_H
++
++/* Define if you have the &lt;net/if.h&gt; header file. */
++#undef HAVE_NET_IF_H
++
++/* Define if you have the &lt;linux/if.h&gt; header file. */
++#undef HAVE_LINUX_IF_H
++
++/* Define if you have the &lt;net/if_dl.h&gt; header file. */
++#undef HAVE_NET_IF_DL_H
++
++/* Define if you have the &lt;net/if_ether.h&gt; header file. */
++#undef HAVE_NET_IF_ETHER_H
++
++/* Define if you have the &lt;net/if_types.h&gt; header file. */
++#undef HAVE_NET_IF_TYPES_H
++
++/* Define if you have the &lt;netinet/if_ether.h&gt; header file. */
++#undef HAVE_NETINET_IF_ETHER_H
++
++/* Define if you have the &lt;netpacket/packet.h&gt; header file. */
++#undef HAVE_NETPACKET_PACKET_H
++
++/* Define if you have the &lt;sys/cdefs.h&gt; header file. */
++#undef HAVE_SYS_CDEFS_H
++
++/* Define if you have the &lt;sys/dlpi.h&gt; header file. */
++#undef HAVE_SYS_DLPI_H
++
++/* Define if you have the &lt;sys/ioctl.h&gt; header file. */
++#undef HAVE_SYS_IOCTL_H
++
++/* Define if you have the &lt;sys/param.h&gt; header file. */
++#undef HAVE_SYS_PARAM_H
++
++/* Define if you have the &lt;sys/socket.h&gt; header file. */
++#undef HAVE_SYS_SOCKET_H
++
++/* Define if you have the &lt;sys/time.h&gt; header file. */
++#undef HAVE_SYS_TIME_H
++
++/* Define if you have the &lt;sys/uio.h&gt; header file. */
++#undef HAVE_SYS_UIO_H
++
++/* Define if you have the &lt;syslog.h&gt; header file. */
++#undef HAVE_SYSLOG_H
++
++/* Define if you have the &lt;unistd.h&gt; header file. */
++#undef HAVE_UNISTD_H
++
++/* Define if you have the N_HDLC line discipline in linux/termios.h */
++#undef HAVE_N_HDLC
++
++/* Define if bitfields are packed in reverse order */
++#undef PACK_BITFIELDS_REVERSED
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/src/configure
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/src/configure (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/src/configure 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,2356 @@
++#! /bin/sh
++
++# Guess values for system-dependent variables and create Makefiles.
++# Generated automatically using autoconf version 2.13
++# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
++#
++# This configure script is free software; the Free Software Foundation
++# gives unlimited permission to copy, distribute and modify it.
++
++# Defaults:
++ac_help=
++ac_default_prefix=/usr/local
++# Any additions from configure.in:
++ac_default_prefix=/usr
++ac_help=&quot;$ac_help
++ --enable-plugin=pppd_src_path build pppd plugin&quot;
++
++# Initialize some variables set by options.
++# The variables have the same names as the options, with
++# dashes changed to underlines.
++build=NONE
++cache_file=./config.cache
++exec_prefix=NONE
++host=NONE
++no_create=
++nonopt=NONE
++no_recursion=
++prefix=NONE
++program_prefix=NONE
++program_suffix=NONE
++program_transform_name=s,x,x,
++silent=
++site=
++srcdir=
++target=NONE
++verbose=
++x_includes=NONE
++x_libraries=NONE
++bindir='${exec_prefix}/bin'
++sbindir='${exec_prefix}/sbin'
++libexecdir='${exec_prefix}/libexec'
++datadir='${prefix}/share'
++sysconfdir='${prefix}/etc'
++sharedstatedir='${prefix}/com'
++localstatedir='${prefix}/var'
++libdir='${exec_prefix}/lib'
++includedir='${prefix}/include'
++oldincludedir='/usr/include'
++infodir='${prefix}/info'
++mandir='${prefix}/man'
++
++# Initialize some other variables.
++subdirs=
++MFLAGS= MAKEFLAGS=
++SHELL=${CONFIG_SHELL-/bin/sh}
++# Maximum number of lines to put in a shell here document.
++ac_max_here_lines=12
++
++ac_prev=
++for ac_option
++do
++
++ # If the previous option needs an argument, assign it.
++ if test -n &quot;$ac_prev&quot;; then
++ eval &quot;$ac_prev=\$ac_option&quot;
++ ac_prev=
++ continue
++ fi
++
++ case &quot;$ac_option&quot; in
++ -*=*) ac_optarg=`echo &quot;$ac_option&quot; | sed 's/[-_a-zA-Z0-9]*=//'` ;;
++ *) ac_optarg= ;;
++ esac
++
++ # Accept the important Cygnus configure options, so we can diagnose typos.
++
++ case &quot;$ac_option&quot; in
++
++ -bindir | --bindir | --bindi | --bind | --bin | --bi)
++ ac_prev=bindir ;;
++ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
++ bindir=&quot;$ac_optarg&quot; ;;
++
++ -build | --build | --buil | --bui | --bu)
++ ac_prev=build ;;
++ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
++ build=&quot;$ac_optarg&quot; ;;
++
++ -cache-file | --cache-file | --cache-fil | --cache-fi \
++ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
++ ac_prev=cache_file ;;
++ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
++ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
++ cache_file=&quot;$ac_optarg&quot; ;;
++
++ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
++ ac_prev=datadir ;;
++ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
++ | --da=*)
++ datadir=&quot;$ac_optarg&quot; ;;
++
++ -disable-* | --disable-*)
++ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
++ # Reject names that are not valid shell variable names.
++ if test -n &quot;`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`&quot;; then
++ { echo &quot;configure: error: $ac_feature: invalid feature name&quot; 1&gt;&amp;2; exit 1; }
++ fi
++ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
++ eval &quot;enable_${ac_feature}=no&quot; ;;
++
++ -enable-* | --enable-*)
++ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
++ # Reject names that are not valid shell variable names.
++ if test -n &quot;`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`&quot;; then
++ { echo &quot;configure: error: $ac_feature: invalid feature name&quot; 1&gt;&amp;2; exit 1; }
++ fi
++ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
++ case &quot;$ac_option&quot; in
++ *=*) ;;
++ *) ac_optarg=yes ;;
++ esac
++ eval &quot;enable_${ac_feature}='$ac_optarg'&quot; ;;
++
++ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
++ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
++ | --exec | --exe | --ex)
++ ac_prev=exec_prefix ;;
++ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
++ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
++ | --exec=* | --exe=* | --ex=*)
++ exec_prefix=&quot;$ac_optarg&quot; ;;
++
++ -gas | --gas | --ga | --g)
++ # Obsolete; use --with-gas.
++ with_gas=yes ;;
++
++ -help | --help | --hel | --he)
++ # Omit some internal or obsolete options to make the list less imposing.
++ # This message is too long to be a string in the A/UX 3.1 sh.
++ cat &lt;&lt; EOF
++Usage: configure [options] [host]
++Options: [defaults in brackets after descriptions]
++Configuration:
++ --cache-file=FILE cache test results in FILE
++ --help print this message
++ --no-create do not create output files
++ --quiet, --silent do not print \`checking...' messages
++ --version print the version of autoconf that created configure
++Directory and file names:
++ --prefix=PREFIX install architecture-independent files in PREFIX
++ [$ac_default_prefix]
++ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
++ [same as prefix]
++ --bindir=DIR user executables in DIR [EPREFIX/bin]
++ --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
++ --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
++ --datadir=DIR read-only architecture-independent data in DIR
++ [PREFIX/share]
++ --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
++ --sharedstatedir=DIR modifiable architecture-independent data in DIR
++ [PREFIX/com]
++ --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
++ --libdir=DIR object code libraries in DIR [EPREFIX/lib]
++ --includedir=DIR C header files in DIR [PREFIX/include]
++ --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
++ --infodir=DIR info documentation in DIR [PREFIX/info]
++ --mandir=DIR man documentation in DIR [PREFIX/man]
++ --srcdir=DIR find the sources in DIR [configure dir or ..]
++ --program-prefix=PREFIX prepend PREFIX to installed program names
++ --program-suffix=SUFFIX append SUFFIX to installed program names
++ --program-transform-name=PROGRAM
++ run sed PROGRAM on installed program names
++EOF
++ cat &lt;&lt; EOF
++Host type:
++ --build=BUILD configure for building on BUILD [BUILD=HOST]
++ --host=HOST configure for HOST [guessed]
++ --target=TARGET configure for TARGET [TARGET=HOST]
++Features and packages:
++ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
++ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
++ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
++ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
++ --x-includes=DIR X include files are in DIR
++ --x-libraries=DIR X library files are in DIR
++EOF
++ if test -n &quot;$ac_help&quot;; then
++ echo &quot;--enable and --with options recognized:$ac_help&quot;
++ fi
++ exit 0 ;;
++
++ -host | --host | --hos | --ho)
++ ac_prev=host ;;
++ -host=* | --host=* | --hos=* | --ho=*)
++ host=&quot;$ac_optarg&quot; ;;
++
++ -includedir | --includedir | --includedi | --included | --include \
++ | --includ | --inclu | --incl | --inc)
++ ac_prev=includedir ;;
++ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
++ | --includ=* | --inclu=* | --incl=* | --inc=*)
++ includedir=&quot;$ac_optarg&quot; ;;
++
++ -infodir | --infodir | --infodi | --infod | --info | --inf)
++ ac_prev=infodir ;;
++ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
++ infodir=&quot;$ac_optarg&quot; ;;
++
++ -libdir | --libdir | --libdi | --libd)
++ ac_prev=libdir ;;
++ -libdir=* | --libdir=* | --libdi=* | --libd=*)
++ libdir=&quot;$ac_optarg&quot; ;;
++
++ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
++ | --libexe | --libex | --libe)
++ ac_prev=libexecdir ;;
++ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
++ | --libexe=* | --libex=* | --libe=*)
++ libexecdir=&quot;$ac_optarg&quot; ;;
++
++ -localstatedir | --localstatedir | --localstatedi | --localstated \
++ | --localstate | --localstat | --localsta | --localst \
++ | --locals | --local | --loca | --loc | --lo)
++ ac_prev=localstatedir ;;
++ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
++ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
++ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
++ localstatedir=&quot;$ac_optarg&quot; ;;
++
++ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
++ ac_prev=mandir ;;
++ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
++ mandir=&quot;$ac_optarg&quot; ;;
++
++ -nfp | --nfp | --nf)
++ # Obsolete; use --without-fp.
++ with_fp=no ;;
++
++ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
++ | --no-cr | --no-c)
++ no_create=yes ;;
++
++ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
++ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
++ no_recursion=yes ;;
++
++ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
++ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
++ | --oldin | --oldi | --old | --ol | --o)
++ ac_prev=oldincludedir ;;
++ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
++ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
++ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
++ oldincludedir=&quot;$ac_optarg&quot; ;;
++
++ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
++ ac_prev=prefix ;;
++ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
++ prefix=&quot;$ac_optarg&quot; ;;
++
++ -program-prefix | --program-prefix | --program-prefi | --program-pref \
++ | --program-pre | --program-pr | --program-p)
++ ac_prev=program_prefix ;;
++ -program-prefix=* | --program-prefix=* | --program-prefi=* \
++ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
++ program_prefix=&quot;$ac_optarg&quot; ;;
++
++ -program-suffix | --program-suffix | --program-suffi | --program-suff \
++ | --program-suf | --program-su | --program-s)
++ ac_prev=program_suffix ;;
++ -program-suffix=* | --program-suffix=* | --program-suffi=* \
++ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
++ program_suffix=&quot;$ac_optarg&quot; ;;
++
++ -program-transform-name | --program-transform-name \
++ | --program-transform-nam | --program-transform-na \
++ | --program-transform-n | --program-transform- \
++ | --program-transform | --program-transfor \
++ | --program-transfo | --program-transf \
++ | --program-trans | --program-tran \
++ | --progr-tra | --program-tr | --program-t)
++ ac_prev=program_transform_name ;;
++ -program-transform-name=* | --program-transform-name=* \
++ | --program-transform-nam=* | --program-transform-na=* \
++ | --program-transform-n=* | --program-transform-=* \
++ | --program-transform=* | --program-transfor=* \
++ | --program-transfo=* | --program-transf=* \
++ | --program-trans=* | --program-tran=* \
++ | --progr-tra=* | --program-tr=* | --program-t=*)
++ program_transform_name=&quot;$ac_optarg&quot; ;;
++
++ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
++ | -silent | --silent | --silen | --sile | --sil)
++ silent=yes ;;
++
++ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
++ ac_prev=sbindir ;;
++ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
++ | --sbi=* | --sb=*)
++ sbindir=&quot;$ac_optarg&quot; ;;
++
++ -sharedstatedir | --sharedstatedir | --sharedstatedi \
++ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
++ | --sharedst | --shareds | --shared | --share | --shar \
++ | --sha | --sh)
++ ac_prev=sharedstatedir ;;
++ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
++ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
++ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
++ | --sha=* | --sh=*)
++ sharedstatedir=&quot;$ac_optarg&quot; ;;
++
++ -site | --site | --sit)
++ ac_prev=site ;;
++ -site=* | --site=* | --sit=*)
++ site=&quot;$ac_optarg&quot; ;;
++
++ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
++ ac_prev=srcdir ;;
++ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
++ srcdir=&quot;$ac_optarg&quot; ;;
++
++ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
++ | --syscon | --sysco | --sysc | --sys | --sy)
++ ac_prev=sysconfdir ;;
++ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
++ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
++ sysconfdir=&quot;$ac_optarg&quot; ;;
++
++ -target | --target | --targe | --targ | --tar | --ta | --t)
++ ac_prev=target ;;
++ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
++ target=&quot;$ac_optarg&quot; ;;
++
++ -v | -verbose | --verbose | --verbos | --verbo | --verb)
++ verbose=yes ;;
++
++ -version | --version | --versio | --versi | --vers)
++ echo &quot;configure generated by autoconf version 2.13&quot;
++ exit 0 ;;
++
++ -with-* | --with-*)
++ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
++ # Reject names that are not valid shell variable names.
++ if test -n &quot;`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`&quot;; then
++ { echo &quot;configure: error: $ac_package: invalid package name&quot; 1&gt;&amp;2; exit 1; }
++ fi
++ ac_package=`echo $ac_package| sed 's/-/_/g'`
++ case &quot;$ac_option&quot; in
++ *=*) ;;
++ *) ac_optarg=yes ;;
++ esac
++ eval &quot;with_${ac_package}='$ac_optarg'&quot; ;;
++
++ -without-* | --without-*)
++ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
++ # Reject names that are not valid shell variable names.
++ if test -n &quot;`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`&quot;; then
++ { echo &quot;configure: error: $ac_package: invalid package name&quot; 1&gt;&amp;2; exit 1; }
++ fi
++ ac_package=`echo $ac_package| sed 's/-/_/g'`
++ eval &quot;with_${ac_package}=no&quot; ;;
++
++ --x)
++ # Obsolete; use --with-x.
++ with_x=yes ;;
++
++ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
++ | --x-incl | --x-inc | --x-in | --x-i)
++ ac_prev=x_includes ;;
++ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
++ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
++ x_includes=&quot;$ac_optarg&quot; ;;
++
++ -x-libraries | --x-libraries | --x-librarie | --x-librari \
++ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
++ ac_prev=x_libraries ;;
++ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
++ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
++ x_libraries=&quot;$ac_optarg&quot; ;;
++
++ -*) { echo &quot;configure: error: $ac_option: invalid option; use --help to show usage&quot; 1&gt;&amp;2; exit 1; }
++ ;;
++
++ *)
++ if test -n &quot;`echo $ac_option| sed 's/[-a-z0-9.]//g'`&quot;; then
++ echo &quot;configure: warning: $ac_option: invalid host type&quot; 1&gt;&amp;2
++ fi
++ if test &quot;x$nonopt&quot; != xNONE; then
++ { echo &quot;configure: error: can only configure for one host and one target at a time&quot; 1&gt;&amp;2; exit 1; }
++ fi
++ nonopt=&quot;$ac_option&quot;
++ ;;
++
++ esac
++done
++
++if test -n &quot;$ac_prev&quot;; then
++ { echo &quot;configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`&quot; 1&gt;&amp;2; exit 1; }
++fi
++
++trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
++
++# File descriptor usage:
++# 0 standard input
++# 1 file creation
++# 2 errors and warnings
++# 3 some systems may open it to /dev/tty
++# 4 used on the Kubota Titan
++# 6 checking for... messages and results
++# 5 compiler messages saved in config.log
++if test &quot;$silent&quot; = yes; then
++ exec 6&gt;/dev/null
++else
++ exec 6&gt;&amp;1
++fi
++exec 5&gt;./config.log
++
++echo &quot;\
++This file contains any messages produced by compilers while
++running configure, to aid debugging if configure makes a mistake.
++&quot; 1&gt;&amp;5
++
++# Strip out --no-create and --no-recursion so they do not pile up.
++# Also quote any args containing shell metacharacters.
++ac_configure_args=
++for ac_arg
++do
++ case &quot;$ac_arg&quot; in
++ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
++ | --no-cr | --no-c) ;;
++ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
++ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
++ *&quot; &quot;*|*&quot; &quot;*|*[\[\]\~\#\$\^\&amp;\*\(\)\{\}\\\|\;\&lt;\&gt;\?]*)
++ ac_configure_args=&quot;$ac_configure_args '$ac_arg'&quot; ;;
++ *) ac_configure_args=&quot;$ac_configure_args $ac_arg&quot; ;;
++ esac
++done
++
++# NLS nuisances.
++# Only set these to C if already set. These must not be set unconditionally
++# because not all systems understand e.g. LANG=C (notably SCO).
++# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
++# Non-C LC_CTYPE values break the ctype check.
++if test &quot;${LANG+set}&quot; = set; then LANG=C; export LANG; fi
++if test &quot;${LC_ALL+set}&quot; = set; then LC_ALL=C; export LC_ALL; fi
++if test &quot;${LC_MESSAGES+set}&quot; = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
++if test &quot;${LC_CTYPE+set}&quot; = set; then LC_CTYPE=C; export LC_CTYPE; fi
++
++# confdefs.h avoids OS command line length limits that DEFS can exceed.
++rm -rf conftest* confdefs.h
++# AIX cpp loses on an empty file, so make sure it contains at least a newline.
++echo &gt; confdefs.h
++
++# A filename unique to this package, relative to the directory that
++# configure is in, which we can look for to find out if srcdir is correct.
++ac_unique_file=pppoe.c
++
++# Find the source files, if location was not specified.
++if test -z &quot;$srcdir&quot;; then
++ ac_srcdir_defaulted=yes
++ # Try the directory containing this script, then its parent.
++ ac_prog=$0
++ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
++ test &quot;x$ac_confdir&quot; = &quot;x$ac_prog&quot; &amp;&amp; ac_confdir=.
++ srcdir=$ac_confdir
++ if test ! -r $srcdir/$ac_unique_file; then
++ srcdir=..
++ fi
++else
++ ac_srcdir_defaulted=no
++fi
++if test ! -r $srcdir/$ac_unique_file; then
++ if test &quot;$ac_srcdir_defaulted&quot; = yes; then
++ { echo &quot;configure: error: can not find sources in $ac_confdir or ..&quot; 1&gt;&amp;2; exit 1; }
++ else
++ { echo &quot;configure: error: can not find sources in $srcdir&quot; 1&gt;&amp;2; exit 1; }
++ fi
++fi
++srcdir=`echo &quot;${srcdir}&quot; | sed 's%\([^/]\)/*$%\1%'`
++
++# Prefer explicitly selected file to automatically selected ones.
++if test -z &quot;$CONFIG_SITE&quot;; then
++ if test &quot;x$prefix&quot; != xNONE; then
++ CONFIG_SITE=&quot;$prefix/share/config.site $prefix/etc/config.site&quot;
++ else
++ CONFIG_SITE=&quot;$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site&quot;
++ fi
++fi
++for ac_site_file in $CONFIG_SITE; do
++ if test -r &quot;$ac_site_file&quot;; then
++ echo &quot;loading site script $ac_site_file&quot;
++ . &quot;$ac_site_file&quot;
++ fi
++done
++
++if test -r &quot;$cache_file&quot;; then
++ echo &quot;loading cache $cache_file&quot;
++ . $cache_file
++else
++ echo &quot;creating cache $cache_file&quot;
++ &gt; $cache_file
++fi
++
++ac_ext=c
++# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
++ac_cpp='$CPP $CPPFLAGS'
++ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1&gt;&amp;5'
++ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1&gt;&amp;5'
++cross_compiling=$ac_cv_prog_cc_cross
++
++ac_exeext=
++ac_objext=o
++if (echo &quot;testing\c&quot;; echo 1,2,3) | grep c &gt;/dev/null; then
++ # Stardent Vistra SVR4 grep lacks -e, says <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ghazi at caip.rutgers.edu.</A>
++ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn &gt;/dev/null; then
++ ac_n= ac_c='
++' ac_t=' '
++ else
++ ac_n=-n ac_c= ac_t=
++ fi
++else
++ ac_n= ac_c='\c' ac_t=
++fi
++
++
++
++
++
++
++
++# Extract the first word of &quot;gcc&quot;, so it can be a program name with args.
++set dummy gcc; ac_word=$2
++echo $ac_n &quot;checking for $ac_word&quot;&quot;... $ac_c&quot; 1&gt;&amp;6
++echo &quot;configure:536: checking for $ac_word&quot; &gt;&amp;5
++if eval &quot;test \&quot;`echo '$''{'ac_cv_prog_CC'+set}'`\&quot; = set&quot;; then
++ echo $ac_n &quot;(cached) $ac_c&quot; 1&gt;&amp;6
++else
++ if test -n &quot;$CC&quot;; then
++ ac_cv_prog_CC=&quot;$CC&quot; # Let the user override the test.
++else
++ IFS=&quot;${IFS= }&quot;; ac_save_ifs=&quot;$IFS&quot;; IFS=&quot;:&quot;
++ ac_dummy=&quot;$PATH&quot;
++ for ac_dir in $ac_dummy; do
++ test -z &quot;$ac_dir&quot; &amp;&amp; ac_dir=.
++ if test -f $ac_dir/$ac_word; then
++ ac_cv_prog_CC=&quot;gcc&quot;
++ break
++ fi
++ done
++ IFS=&quot;$ac_save_ifs&quot;
++fi
++fi
++CC=&quot;$ac_cv_prog_CC&quot;
++if test -n &quot;$CC&quot;; then
++ echo &quot;$ac_t&quot;&quot;$CC&quot; 1&gt;&amp;6
++else
++ echo &quot;$ac_t&quot;&quot;no&quot; 1&gt;&amp;6
++fi
++
++if test -z &quot;$CC&quot;; then
++ # Extract the first word of &quot;cc&quot;, so it can be a program name with args.
++set dummy cc; ac_word=$2
++echo $ac_n &quot;checking for $ac_word&quot;&quot;... $ac_c&quot; 1&gt;&amp;6
++echo &quot;configure:566: checking for $ac_word&quot; &gt;&amp;5
++if eval &quot;test \&quot;`echo '$''{'ac_cv_prog_CC'+set}'`\&quot; = set&quot;; then
++ echo $ac_n &quot;(cached) $ac_c&quot; 1&gt;&amp;6
++else
++ if test -n &quot;$CC&quot;; then
++ ac_cv_prog_CC=&quot;$CC&quot; # Let the user override the test.
++else
++ IFS=&quot;${IFS= }&quot;; ac_save_ifs=&quot;$IFS&quot;; IFS=&quot;:&quot;
++ ac_prog_rejected=no
++ ac_dummy=&quot;$PATH&quot;
++ for ac_dir in $ac_dummy; do
++ test -z &quot;$ac_dir&quot; &amp;&amp; ac_dir=.
++ if test -f $ac_dir/$ac_word; then
++ if test &quot;$ac_dir/$ac_word&quot; = &quot;/usr/ucb/cc&quot;; then
++ ac_prog_rejected=yes
++ continue
++ fi
++ ac_cv_prog_CC=&quot;cc&quot;
++ break
++ fi
++ done
++ IFS=&quot;$ac_save_ifs&quot;
++if test $ac_prog_rejected = yes; then
++ # We found a bogon in the path, so make sure we never use it.
++ set dummy $ac_cv_prog_CC
++ shift
++ if test $# -gt 0; then
++ # We chose a different compiler from the bogus one.
++ # However, it has the same basename, so the bogon will be chosen
++ # first if we set CC to just the basename; use the full file name.
++ shift
++ set dummy &quot;$ac_dir/$ac_word&quot; &quot;$@&quot;
++ shift
++ ac_cv_prog_CC=&quot;$@&quot;
++ fi
++fi
++fi
++fi
++CC=&quot;$ac_cv_prog_CC&quot;
++if test -n &quot;$CC&quot;; then
++ echo &quot;$ac_t&quot;&quot;$CC&quot; 1&gt;&amp;6
++else
++ echo &quot;$ac_t&quot;&quot;no&quot; 1&gt;&amp;6
++fi
++
++ if test -z &quot;$CC&quot;; then
++ case &quot;`uname -s`&quot; in
++ *win32* | *WIN32*)
++ # Extract the first word of &quot;cl&quot;, so it can be a program name with args.
++set dummy cl; ac_word=$2
++echo $ac_n &quot;checking for $ac_word&quot;&quot;... $ac_c&quot; 1&gt;&amp;6
++echo &quot;configure:617: checking for $ac_word&quot; &gt;&amp;5
++if eval &quot;test \&quot;`echo '$''{'ac_cv_prog_CC'+set}'`\&quot; = set&quot;; then
++ echo $ac_n &quot;(cached) $ac_c&quot; 1&gt;&amp;6
++else
++ if test -n &quot;$CC&quot;; then
++ ac_cv_prog_CC=&quot;$CC&quot; # Let the user override the test.
++else
++ IFS=&quot;${IFS= }&quot;; ac_save_ifs=&quot;$IFS&quot;; IFS=&quot;:&quot;
++ ac_dummy=&quot;$PATH&quot;
++ for ac_dir in $ac_dummy; do
++ test -z &quot;$ac_dir&quot; &amp;&amp; ac_dir=.
++ if test -f $ac_dir/$ac_word; then
++ ac_cv_prog_CC=&quot;cl&quot;
++ break
++ fi
++ done
++ IFS=&quot;$ac_save_ifs&quot;
++fi
++fi
++CC=&quot;$ac_cv_prog_CC&quot;
++if test -n &quot;$CC&quot;; then
++ echo &quot;$ac_t&quot;&quot;$CC&quot; 1&gt;&amp;6
++else
++ echo &quot;$ac_t&quot;&quot;no&quot; 1&gt;&amp;6
++fi
++ ;;
++ esac
++ fi
++ test -z &quot;$CC&quot; &amp;&amp; { echo &quot;configure: error: no acceptable cc found in \$PATH&quot; 1&gt;&amp;2; exit 1; }
++fi
++
++echo $ac_n &quot;checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works&quot;&quot;... $ac_c&quot; 1&gt;&amp;6
++echo &quot;configure:649: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works&quot; &gt;&amp;5
++
++ac_ext=c
++# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
++ac_cpp='$CPP $CPPFLAGS'
++ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1&gt;&amp;5'
++ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1&gt;&amp;5'
++cross_compiling=$ac_cv_prog_cc_cross
++
++cat &gt; conftest.$ac_ext &lt;&lt; EOF
++
++#line 660 &quot;configure&quot;
++#include &quot;confdefs.h&quot;
++
++main(){return(0);}
++EOF
++if { (eval echo configure:665: \&quot;$ac_link\&quot;) 1&gt;&amp;5; (eval $ac_link) 2&gt;&amp;5; } &amp;&amp; test -s conftest${ac_exeext}; then
++ ac_cv_prog_cc_works=yes
++ # If we can't run a trivial program, we are probably using a cross compiler.
++ if (./conftest; exit) 2&gt;/dev/null; then
++ ac_cv_prog_cc_cross=no
++ else
++ ac_cv_prog_cc_cross=yes
++ fi
++else
++ echo &quot;configure: failed program was:&quot; &gt;&amp;5
++ cat conftest.$ac_ext &gt;&amp;5
++ ac_cv_prog_cc_works=no
++fi
++rm -fr conftest*
++ac_ext=c
++# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
++ac_cpp='$CPP $CPPFLAGS'
++ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1&gt;&amp;5'
++ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1&gt;&amp;5'
++cross_compiling=$ac_cv_prog_cc_cross
++
++echo &quot;$ac_t&quot;&quot;$ac_cv_prog_cc_works&quot; 1&gt;&amp;6
++if test $ac_cv_prog_cc_works = no; then
++ { echo &quot;configure: error: installation or configuration problem: C compiler cannot create executables.&quot; 1&gt;&amp;2; exit 1; }
++fi
++echo $ac_n &quot;checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler&quot;&quot;... $ac_c&quot; 1&gt;&amp;6
++echo &quot;configure:691: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler&quot; &gt;&amp;5
++echo &quot;$ac_t&quot;&quot;$ac_cv_prog_cc_cross&quot; 1&gt;&amp;6
++cross_compiling=$ac_cv_prog_cc_cross
++
++echo $ac_n &quot;checking whether we are using GNU C&quot;&quot;... $ac_c&quot; 1&gt;&amp;6
++echo &quot;configure:696: checking whether we are using GNU C&quot; &gt;&amp;5
++if eval &quot;test \&quot;`echo '$''{'ac_cv_prog_gcc'+set}'`\&quot; = set&quot;; then
++ echo $ac_n &quot;(cached) $ac_c&quot; 1&gt;&amp;6
++else
++ cat &gt; conftest.c &lt;&lt;EOF
++#ifdef __GNUC__
++ yes;
++#endif
++EOF
++if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:705: \&quot;$ac_try\&quot;) 1&gt;&amp;5; (eval $ac_try) 2&gt;&amp;5; }; } | egrep yes &gt;/dev/null 2&gt;&amp;1; then
++ ac_cv_prog_gcc=yes
++else
++ ac_cv_prog_gcc=no
++fi
++fi
++
++echo &quot;$ac_t&quot;&quot;$ac_cv_prog_gcc&quot; 1&gt;&amp;6
++
++if test $ac_cv_prog_gcc = yes; then
++ GCC=yes
++else
++ GCC=
++fi
++
++ac_test_CFLAGS=&quot;${CFLAGS+set}&quot;
++ac_save_CFLAGS=&quot;$CFLAGS&quot;
++CFLAGS=
++echo $ac_n &quot;checking whether ${CC-cc} accepts -g&quot;&quot;... $ac_c&quot; 1&gt;&amp;6
++echo &quot;configure:724: checking whether ${CC-cc} accepts -g&quot; &gt;&amp;5
++if eval &quot;test \&quot;`echo '$''{'ac_cv_prog_cc_g'+set}'`\&quot; = set&quot;; then
++ echo $ac_n &quot;(cached) $ac_c&quot; 1&gt;&amp;6
++else
++ echo 'void f(){}' &gt; conftest.c
++if test -z &quot;`${CC-cc} -g -c conftest.c 2&gt;&amp;1`&quot;; then
++ ac_cv_prog_cc_g=yes
++else
++ ac_cv_prog_cc_g=no
++fi
++rm -f conftest*
++
++fi
++
++echo &quot;$ac_t&quot;&quot;$ac_cv_prog_cc_g&quot; 1&gt;&amp;6
++if test &quot;$ac_test_CFLAGS&quot; = set; then
++ CFLAGS=&quot;$ac_save_CFLAGS&quot;
++elif test $ac_cv_prog_cc_g = yes; then
++ if test &quot;$GCC&quot; = yes; then
++ CFLAGS=&quot;-g -O2&quot;
++ else
++ CFLAGS=&quot;-g&quot;
++ fi
++else
++ if test &quot;$GCC&quot; = yes; then
++ CFLAGS=&quot;-O2&quot;
++ else
++ CFLAGS=
++ fi
++fi
++
++
++
++echo $ac_n &quot;checking how to run the C preprocessor&quot;&quot;... $ac_c&quot; 1&gt;&amp;6
++echo &quot;configure:758: checking how to run the C preprocessor&quot; &gt;&amp;5
++# On Suns, sometimes $CPP names a directory.
++if test -n &quot;$CPP&quot; &amp;&amp; test -d &quot;$CPP&quot;; then
++ CPP=
++fi
++if test -z &quot;$CPP&quot;; then
++if eval &quot;test \&quot;`echo '$''{'ac_cv_prog_CPP'+set}'`\&quot; = set&quot;; then
++ echo $ac_n &quot;(cached) $ac_c&quot; 1&gt;&amp;6
++else
++ # This must be in double quotes, not single quotes, because CPP may get
++ # substituted into the Makefile and &quot;${CC-cc}&quot; will confuse make.
++ CPP=&quot;${CC-cc} -E&quot;
++ # On the NeXT, cc -E runs the code through the compiler's parser,
++ # not just through cpp.
++ cat &gt; conftest.$ac_ext &lt;&lt;EOF
++#line 773 &quot;configure&quot;
++#include &quot;confdefs.h&quot;
++#include &lt;assert.h&gt;
++Syntax Error
++EOF
++ac_try=&quot;$ac_cpp conftest.$ac_ext &gt;/dev/null 2&gt;conftest.out&quot;
++{ (eval echo configure:779: \&quot;$ac_try\&quot;) 1&gt;&amp;5; (eval $ac_try) 2&gt;&amp;5; }
++ac_err=`grep -v '^ *+' conftest.out | grep -v &quot;^conftest.${ac_ext}\$&quot;`
++if test -z &quot;$ac_err&quot;; then
++ :
++else
++ echo &quot;$ac_err&quot; &gt;&amp;5
++ echo &quot;configure: failed program was:&quot; &gt;&amp;5
++ cat conftest.$ac_ext &gt;&amp;5
++ rm -rf conftest*
++ CPP=&quot;${CC-cc} -E -traditional-cpp&quot;
++ cat &gt; conftest.$ac_ext &lt;&lt;EOF
++#line 790 &quot;configure&quot;
++#include &quot;confdefs.h&quot;
++#include &lt;assert.h&gt;
++Syntax Error
++EOF
++ac_try=&quot;$ac_cpp conftest.$ac_ext &gt;/dev/null 2&gt;conftest.out&quot;
++{ (eval echo configure:796: \&quot;$ac_try\&quot;) 1&gt;&amp;5; (eval $ac_try) 2&gt;&amp;5; }
++ac_err=`grep -v '^ *+' conftest.out | grep -v &quot;^conftest.${ac_ext}\$&quot;`
++if test -z &quot;$ac_err&quot;; then
++ :
++else
++ echo &quot;$ac_err&quot; &gt;&amp;5
++ echo &quot;configure: failed program was:&quot; &gt;&amp;5
++ cat conftest.$ac_ext &gt;&amp;5
++ rm -rf conftest*
++ CPP=&quot;${CC-cc} -nologo -E&quot;
++ cat &gt; conftest.$ac_ext &lt;&lt;EOF
++#line 807 &quot;configure&quot;
++#include &quot;confdefs.h&quot;
++#include &lt;assert.h&gt;
++Syntax Error
++EOF
++ac_try=&quot;$ac_cpp conftest.$ac_ext &gt;/dev/null 2&gt;conftest.out&quot;
++{ (eval echo configure:813: \&quot;$ac_try\&quot;) 1&gt;&amp;5; (eval $ac_try) 2&gt;&amp;5; }
++ac_err=`grep -v '^ *+' conftest.out | grep -v &quot;^conftest.${ac_ext}\$&quot;`
++if test -z &quot;$ac_err&quot;; then
++ :
++else
++ echo &quot;$ac_err&quot; &gt;&amp;5
++ echo &quot;configure: failed program was:&quot; &gt;&amp;5
++ cat conftest.$ac_ext &gt;&amp;5
++ rm -rf conftest*
++ CPP=/lib/cpp
++fi
++rm -f conftest*
++fi
++rm -f conftest*
++fi
++rm -f conftest*
++ ac_cv_prog_CPP=&quot;$CPP&quot;
++fi
++ CPP=&quot;$ac_cv_prog_CPP&quot;
++else
++ ac_cv_prog_CPP=&quot;$CPP&quot;
++fi
++echo &quot;$ac_t&quot;&quot;$CPP&quot; 1&gt;&amp;6
++
++echo $ac_n &quot;checking for ANSI C header files&quot;&quot;... $ac_c&quot; 1&gt;&amp;6
++echo &quot;configure:838: checking for ANSI C header files&quot; &gt;&amp;5
++if eval &quot;test \&quot;`echo '$''{'ac_cv_header_stdc'+set}'`\&quot; = set&quot;; then
++ echo $ac_n &quot;(cached) $ac_c&quot; 1&gt;&amp;6
++else
++ cat &gt; conftest.$ac_ext &lt;&lt;EOF
++#line 843 &quot;configure&quot;
++#include &quot;confdefs.h&quot;
++#include &lt;stdlib.h&gt;
++#include &lt;stdarg.h&gt;
++#include &lt;string.h&gt;
++#include &lt;float.h&gt;
++EOF
++ac_try=&quot;$ac_cpp conftest.$ac_ext &gt;/dev/null 2&gt;conftest.out&quot;
++{ (eval echo configure:851: \&quot;$ac_try\&quot;) 1&gt;&amp;5; (eval $ac_try) 2&gt;&amp;5; }
++ac_err=`grep -v '^ *+' conftest.out | grep -v &quot;^conftest.${ac_ext}\$&quot;`
++if test -z &quot;$ac_err&quot;; then
++ rm -rf conftest*
++ ac_cv_header_stdc=yes
++else
++ echo &quot;$ac_err&quot; &gt;&amp;5
++ echo &quot;configure: failed program was:&quot; &gt;&amp;5
++ cat conftest.$ac_ext &gt;&amp;5
++ rm -rf conftest*
++ ac_cv_header_stdc=no
++fi
++rm -f conftest*
++
++if test $ac_cv_header_stdc = yes; then
++ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
++cat &gt; conftest.$ac_ext &lt;&lt;EOF
++#line 868 &quot;configure&quot;
++#include &quot;confdefs.h&quot;
++#include &lt;string.h&gt;
++EOF
++if (eval &quot;$ac_cpp conftest.$ac_ext&quot;) 2&gt;&amp;5 |
++ egrep &quot;memchr&quot; &gt;/dev/null 2&gt;&amp;1; then
++ :
++else
++ rm -rf conftest*
++ ac_cv_header_stdc=no
++fi
++rm -f conftest*
++
++fi
++
++if test $ac_cv_header_stdc = yes; then
++ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
++cat &gt; conftest.$ac_ext &lt;&lt;EOF
++#line 886 &quot;configure&quot;
++#include &quot;confdefs.h&quot;
++#include &lt;stdlib.h&gt;
++EOF
++if (eval &quot;$ac_cpp conftest.$ac_ext&quot;) 2&gt;&amp;5 |
++ egrep &quot;free&quot; &gt;/dev/null 2&gt;&amp;1; then
++ :
++else
++ rm -rf conftest*
++ ac_cv_header_stdc=no
++fi
++rm -f conftest*
++
++fi
++
++if test $ac_cv_header_stdc = yes; then
++ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
++if test &quot;$cross_compiling&quot; = yes; then
++ :
++else
++ cat &gt; conftest.$ac_ext &lt;&lt;EOF
++#line 907 &quot;configure&quot;
++#include &quot;confdefs.h&quot;
++#include &lt;ctype.h&gt;
++#define ISLOWER(c) ('a' &lt;= (c) &amp;&amp; (c) &lt;= 'z')
++#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
++#define XOR(e, f) (((e) &amp;&amp; !(f)) || (!(e) &amp;&amp; (f)))
++int main () { int i; for (i = 0; i &lt; 256; i++)
++if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
++exit (0); }
++
++EOF
++if { (eval echo configure:918: \&quot;$ac_link\&quot;) 1&gt;&amp;5; (eval $ac_link) 2&gt;&amp;5; } &amp;&amp; test -s conftest${ac_exeext} &amp;&amp; (./conftest; exit) 2&gt;/dev/null
++then
++ :
++else
++ echo &quot;configure: failed program was:&quot; &gt;&amp;5
++ cat conftest.$ac_ext &gt;&amp;5
++ rm -fr conftest*
++ ac_cv_header_stdc=no
++fi
++rm -fr conftest*
++fi
++
++fi
++fi
++
++echo &quot;$ac_t&quot;&quot;$ac_cv_header_stdc&quot; 1&gt;&amp;6
++if test $ac_cv_header_stdc = yes; then
++ cat &gt;&gt; confdefs.h &lt;&lt;\EOF
++#define STDC_HEADERS 1
++EOF
++
++fi
++
++echo $ac_n &quot;checking for sys/wait.h that is POSIX.1 compatible&quot;&quot;... $ac_c&quot; 1&gt;&amp;6
++echo &quot;configure:942: checking for sys/wait.h that is POSIX.1 compatible&quot; &gt;&amp;5
++if eval &quot;test \&quot;`echo '$''{'ac_cv_header_sys_wait_h'+set}'`\&quot; = set&quot;; then
++ echo $ac_n &quot;(cached) $ac_c&quot; 1&gt;&amp;6
++else
++ cat &gt; conftest.$ac_ext &lt;&lt;EOF
++#line 947 &quot;configure&quot;
++#include &quot;confdefs.h&quot;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/wait.h&gt;
++#ifndef WEXITSTATUS
++#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) &gt;&gt; 8)
++#endif
++#ifndef WIFEXITED
++#define WIFEXITED(stat_val) (((stat_val) &amp; 255) == 0)
++#endif
++int main() {
++int s;
++wait (&amp;s);
++s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
++; return 0; }
++EOF
++if { (eval echo configure:963: \&quot;$ac_compile\&quot;) 1&gt;&amp;5; (eval $ac_compile) 2&gt;&amp;5; }; then
++ rm -rf conftest*
++ ac_cv_header_sys_wait_h=yes
++else
++ echo &quot;configure: failed program was:&quot; &gt;&amp;5
++ cat conftest.$ac_ext &gt;&amp;5
++ rm -rf conftest*
++ ac_cv_header_sys_wait_h=no
++fi
++rm -f conftest*
++fi
++
++echo &quot;$ac_t&quot;&quot;$ac_cv_header_sys_wait_h&quot; 1&gt;&amp;6
++if test $ac_cv_header_sys_wait_h = yes; then
++ cat &gt;&gt; confdefs.h &lt;&lt;\EOF
++#define HAVE_SYS_WAIT_H 1
++EOF
++
++fi
++
++for ac_hdr in fcntl.h sys/ioctl.h sys/time.h syslog.h unistd.h net/if_arp.h netinet/if_ether.h getopt.h sys/uio.h sys/param.h fcntl.h net/bpf.h netpacket/packet.h net/ethernet.h asm/types.h linux/if_packet.h linux/if_ether.h linux/if_pppox.h sys/socket.h sys/cdefs.h linux/if.h net/if.h net/if_dl.h net/if_ether.h net/if_types.h netinet/if_ether.h net/if_types.h net/if_dl.h sys/dlpi.h
++do
++ac_safe=`echo &quot;$ac_hdr&quot; | sed 'y%./+-%__p_%'`
++echo $ac_n &quot;checking for $ac_hdr&quot;&quot;... $ac_c&quot; 1&gt;&amp;6
++echo &quot;configure:987: checking for $ac_hdr&quot; &gt;&amp;5
++if eval &quot;test \&quot;`echo '$''{'ac_cv_header_$ac_safe'+set}'`\&quot; = set&quot;; then
++ echo $ac_n &quot;(cached) $ac_c&quot; 1&gt;&amp;6
++else
++ cat &gt; conftest.$ac_ext &lt;&lt;EOF
++#line 992 &quot;configure&quot;
++#include &quot;confdefs.h&quot;
++#include &lt;$ac_hdr&gt;
++EOF
++ac_try=&quot;$ac_cpp conftest.$ac_ext &gt;/dev/null 2&gt;conftest.out&quot;
++{ (eval echo configure:997: \&quot;$ac_try\&quot;) 1&gt;&amp;5; (eval $ac_try) 2&gt;&amp;5; }
++ac_err=`grep -v '^ *+' conftest.out | grep -v &quot;^conftest.${ac_ext}\$&quot;`
++if test -z &quot;$ac_err&quot;; then
++ rm -rf conftest*
++ eval &quot;ac_cv_header_$ac_safe=yes&quot;
++else
++ echo &quot;$ac_err&quot; &gt;&amp;5
++ echo &quot;configure: failed program was:&quot; &gt;&amp;5
++ cat conftest.$ac_ext &gt;&amp;5
++ rm -rf conftest*
++ eval &quot;ac_cv_header_$ac_safe=no&quot;
++fi
++rm -f conftest*
++fi
++if eval &quot;test \&quot;`echo '$ac_cv_header_'$ac_safe`\&quot; = yes&quot;; then
++ echo &quot;$ac_t&quot;&quot;yes&quot; 1&gt;&amp;6
++ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
++ cat &gt;&gt; confdefs.h &lt;&lt;EOF
++#define $ac_tr_hdr 1
++EOF
++
++else
++ echo &quot;$ac_t&quot;&quot;no&quot; 1&gt;&amp;6
++fi
++done
++
++
++echo $ac_n &quot;checking for working const&quot;&quot;... $ac_c&quot; 1&gt;&amp;6
++echo &quot;configure:1025: checking for working const&quot; &gt;&amp;5
++if eval &quot;test \&quot;`echo '$''{'ac_cv_c_const'+set}'`\&quot; = set&quot;; then
++ echo $ac_n &quot;(cached) $ac_c&quot; 1&gt;&amp;6
++else
++ cat &gt; conftest.$ac_ext &lt;&lt;EOF
++#line 1030 &quot;configure&quot;
++#include &quot;confdefs.h&quot;
++
++int main() {
++
++/* Ultrix mips cc rejects this. */
++typedef int charset[2]; const charset x;
++/* SunOS 4.1.1 cc rejects this. */
++char const *const *ccp;
++char **p;
++/* NEC SVR4.0.2 mips cc rejects this. */
++struct point {int x, y;};
++static struct point const zero = {0,0};
++/* AIX XL C 1.02.0.0 rejects this.
++ It does not let you subtract one const X* pointer from another in an arm
++ of an if-expression whose if-part is not a constant expression */
++const char *g = &quot;string&quot;;
++ccp = &amp;g + (g ? g-g : 0);
++/* HPUX 7.0 cc rejects these. */
++++ccp;
++p = (char**) ccp;
++ccp = (char const *const *) p;
++{ /* SCO 3.2v4 cc rejects this. */
++ char *t;
++ char const *s = 0 ? (char *) 0 : (char const *) 0;
++
++ *t++ = 0;
++}
++{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
++ int x[] = {25, 17};
++ const int *foo = &amp;x[0];
++ ++foo;
++}
++{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
++ typedef const int *iptr;
++ iptr p = 0;
++ ++p;
++}
++{ /* AIX XL C 1.02.0.0 rejects this saying
++ &quot;k.c&quot;, line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
++ struct s { int j; const int *ap[3]; };
++ struct s *b; b-&gt;j = 5;
++}
++{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
++ const int foo = 10;
++}
++
++; return 0; }
++EOF
++if { (eval echo configure:1079: \&quot;$ac_compile\&quot;) 1&gt;&amp;5; (eval $ac_compile) 2&gt;&amp;5; }; then
++ rm -rf conftest*
++ ac_cv_c_const=yes
++else
++ echo &quot;configure: failed program was:&quot; &gt;&amp;5
++ cat conftest.$ac_ext &gt;&amp;5
++ rm -rf conftest*
++ ac_cv_c_const=no
++fi
++rm -f conftest*
++fi
++
++echo &quot;$ac_t&quot;&quot;$ac_cv_c_const&quot; 1&gt;&amp;6
++if test $ac_cv_c_const = no; then
++ cat &gt;&gt; confdefs.h &lt;&lt;\EOF
++#define const
++EOF
++
++fi
++
++echo $ac_n &quot;checking for pid_t&quot;&quot;... $ac_c&quot; 1&gt;&amp;6
++echo &quot;configure:1100: checking for pid_t&quot; &gt;&amp;5
++if eval &quot;test \&quot;`echo '$''{'ac_cv_type_pid_t'+set}'`\&quot; = set&quot;; then
++ echo $ac_n &quot;(cached) $ac_c&quot; 1&gt;&amp;6
++else
++ cat &gt; conftest.$ac_ext &lt;&lt;EOF
++#line 1105 &quot;configure&quot;
++#include &quot;confdefs.h&quot;
++#include &lt;sys/types.h&gt;
++#if STDC_HEADERS
++#include &lt;stdlib.h&gt;
++#include &lt;stddef.h&gt;
++#endif
++EOF
++if (eval &quot;$ac_cpp conftest.$ac_ext&quot;) 2&gt;&amp;5 |
++ egrep &quot;(^|[^a-zA-Z_0-9])pid_t[^a-zA-Z_0-9]&quot; &gt;/dev/null 2&gt;&amp;1; then
++ rm -rf conftest*
++ ac_cv_type_pid_t=yes
++else
++ rm -rf conftest*
++ ac_cv_type_pid_t=no
++fi
++rm -f conftest*
++
++fi
++echo &quot;$ac_t&quot;&quot;$ac_cv_type_pid_t&quot; 1&gt;&amp;6
++if test $ac_cv_type_pid_t = no; then
++ cat &gt;&gt; confdefs.h &lt;&lt;\EOF
++#define pid_t int
++EOF
++
++fi
++
++echo $ac_n &quot;checking whether time.h and sys/time.h may both be included&quot;&quot;... $ac_c&quot; 1&gt;&amp;6
++echo &quot;configure:1133: checking whether time.h and sys/time.h may both be included&quot; &gt;&amp;5
++if eval &quot;test \&quot;`echo '$''{'ac_cv_header_time'+set}'`\&quot; = set&quot;; then
++ echo $ac_n &quot;(cached) $ac_c&quot; 1&gt;&amp;6
++else
++ cat &gt; conftest.$ac_ext &lt;&lt;EOF
++#line 1138 &quot;configure&quot;
++#include &quot;confdefs.h&quot;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/time.h&gt;
++#include &lt;time.h&gt;
++int main() {
++struct tm *tp;
++; return 0; }
++EOF
++if { (eval echo configure:1147: \&quot;$ac_compile\&quot;) 1&gt;&amp;5; (eval $ac_compile) 2&gt;&amp;5; }; then
++ rm -rf conftest*
++ ac_cv_header_time=yes
++else
++ echo &quot;configure: failed program was:&quot; &gt;&amp;5
++ cat conftest.$ac_ext &gt;&amp;5
++ rm -rf conftest*
++ ac_cv_header_time=no
++fi
++rm -f conftest*
++fi
++
++echo &quot;$ac_t&quot;&quot;$ac_cv_header_time&quot; 1&gt;&amp;6
++if test $ac_cv_header_time = yes; then
++ cat &gt;&gt; confdefs.h &lt;&lt;\EOF
++#define TIME_WITH_SYS_TIME 1
++EOF
++
++fi
++
++echo $ac_n &quot;checking whether struct tm is in sys/time.h or time.h&quot;&quot;... $ac_c&quot; 1&gt;&amp;6
++echo &quot;configure:1168: checking whether struct tm is in sys/time.h or time.h&quot; &gt;&amp;5
++if eval &quot;test \&quot;`echo '$''{'ac_cv_struct_tm'+set}'`\&quot; = set&quot;; then
++ echo $ac_n &quot;(cached) $ac_c&quot; 1&gt;&amp;6
++else
++ cat &gt; conftest.$ac_ext &lt;&lt;EOF
++#line 1173 &quot;configure&quot;
++#include &quot;confdefs.h&quot;
++#include &lt;sys/types.h&gt;
++#include &lt;time.h&gt;
++int main() {
++struct tm *tp; tp-&gt;tm_sec;
++; return 0; }
++EOF
++if { (eval echo configure:1181: \&quot;$ac_compile\&quot;) 1&gt;&amp;5; (eval $ac_compile) 2&gt;&amp;5; }; then
++ rm -rf conftest*
++ ac_cv_struct_tm=time.h
++else
++ echo &quot;configure: failed program was:&quot; &gt;&amp;5
++ cat conftest.$ac_ext &gt;&amp;5
++ rm -rf conftest*
++ ac_cv_struct_tm=sys/time.h
++fi
++rm -f conftest*
++fi
++
++echo &quot;$ac_t&quot;&quot;$ac_cv_struct_tm&quot; 1&gt;&amp;6
++if test $ac_cv_struct_tm = sys/time.h; then
++ cat &gt;&gt; confdefs.h &lt;&lt;\EOF
++#define TM_IN_SYS_TIME 1
++EOF
++
++fi
++
++
++# Extract the first word of &quot;echo&quot;, so it can be a program name with args.
++set dummy echo; ac_word=$2
++echo $ac_n &quot;checking for $ac_word&quot;&quot;... $ac_c&quot; 1&gt;&amp;6
++echo &quot;configure:1205: checking for $ac_word&quot; &gt;&amp;5
++if eval &quot;test \&quot;`echo '$''{'ac_cv_path_ECHO'+set}'`\&quot; = set&quot;; then
++ echo $ac_n &quot;(cached) $ac_c&quot; 1&gt;&amp;6
++else
++ case &quot;$ECHO&quot; in
++ /*)
++ ac_cv_path_ECHO=&quot;$ECHO&quot; # Let the user override the test with a path.
++ ;;
++ ?:/*)
++ ac_cv_path_ECHO=&quot;$ECHO&quot; # Let the user override the test with a dos path.
++ ;;
++ *)
++ IFS=&quot;${IFS= }&quot;; ac_save_ifs=&quot;$IFS&quot;; IFS=&quot;:&quot;
++ ac_dummy=&quot;/usr/ucb/bin:$PATH&quot;
++ for ac_dir in $ac_dummy; do
++ test -z &quot;$ac_dir&quot; &amp;&amp; ac_dir=.
++ if test -f $ac_dir/$ac_word; then
++ ac_cv_path_ECHO=&quot;$ac_dir/$ac_word&quot;
++ break
++ fi
++ done
++ IFS=&quot;$ac_save_ifs&quot;
++ test -z &quot;$ac_cv_path_ECHO&quot; &amp;&amp; ac_cv_path_ECHO=&quot;&quot;&quot;&quot;
++ ;;
++esac
++fi
++ECHO=&quot;$ac_cv_path_ECHO&quot;
++if test -n &quot;$ECHO&quot;; then
++ echo &quot;$ac_t&quot;&quot;$ECHO&quot; 1&gt;&amp;6
++else
++ echo &quot;$ac_t&quot;&quot;no&quot; 1&gt;&amp;6
++fi
++
++
++$ECHO -n &quot;checking for struct sockaddr_ll... &quot;
++cat &gt; conftest.$ac_ext &lt;&lt;EOF
++#line 1241 &quot;configure&quot;
++#include &quot;confdefs.h&quot;
++#include &lt;asm/types.h&gt;
++#include &lt;linux/if_packet.h&gt;
++#include &lt;linux/if_ether.h&gt;
++
++int main() {
++struct sockaddr_ll sa;
++; return 0; }
++EOF
++if { (eval echo configure:1251: \&quot;$ac_compile\&quot;) 1&gt;&amp;5; (eval $ac_compile) 2&gt;&amp;5; }; then
++ rm -rf conftest*
++ ac_cv_struct_sockaddr_ll=yes
++else
++ echo &quot;configure: failed program was:&quot; &gt;&amp;5
++ cat conftest.$ac_ext &gt;&amp;5
++ rm -rf conftest*
++ ac_cv_struct_sockaddr_ll=no
++fi
++rm -f conftest*
++$ECHO $ac_cv_struct_sockaddr_ll
++if test &quot;$ac_cv_struct_sockaddr_ll&quot; = yes ; then
++cat &gt;&gt; confdefs.h &lt;&lt;\EOF
++#define HAVE_STRUCT_SOCKADDR_LL 1
++EOF
++
++fi
++
++$ECHO -n &quot;checking for N_HDLC line discipline... &quot;
++cat &gt; conftest.$ac_ext &lt;&lt;EOF
++#line 1271 &quot;configure&quot;
++#include &quot;confdefs.h&quot;
++#include &lt;linux/termios.h&gt;
++int main() {
++int x = N_HDLC;
++; return 0; }
++EOF
++if { (eval echo configure:1278: \&quot;$ac_compile\&quot;) 1&gt;&amp;5; (eval $ac_compile) 2&gt;&amp;5; }; then
++ rm -rf conftest*
++ ac_cv_n_hdlc=yes
++else
++ echo &quot;configure: failed program was:&quot; &gt;&amp;5
++ cat conftest.$ac_ext &gt;&amp;5
++ rm -rf conftest*
++ ac_cv_n_hdlc=no
++fi
++rm -f conftest*
++$ECHO $ac_cv_n_hdlc
++if test &quot;$ac_cv_n_hdlc&quot; = yes ; then
++cat &gt;&gt; confdefs.h &lt;&lt;\EOF
++#define HAVE_N_HDLC 1
++EOF
++
++fi
++
++# Check whether --enable-plugin or --disable-plugin was given.
++if test &quot;${enable_plugin+set}&quot; = set; then
++ enableval=&quot;$enable_plugin&quot;
++ ac_cv_pluginpath=$enableval
++else
++ ac_cv_pluginpath=no
++fi
++
++
++LINUX_KERNELMODE_PLUGIN=&quot;&quot;
++PPPD_INCDIR=&quot;&quot;
++if test &quot;$ac_cv_header_linux_if_pppox_h&quot; = yes ; then
++ if test &quot;$ac_cv_pluginpath&quot; != no ; then
++ LINUX_KERNELMODE_PLUGIN=rp-pppoe.so
++ PPPD_INCDIR=$ac_cv_pluginpath
++ fi
++fi
++
++
++
++
++PPPOE_RELAY=&quot;&quot;
++if test &quot;`uname -s`&quot; = &quot;Linux&quot; ; then
++ PPPOE_RELAY=pppoe-relay
++fi
++
++
++echo $ac_n &quot;checking for 8-bit clean memcmp&quot;&quot;... $ac_c&quot; 1&gt;&amp;6
++echo &quot;configure:1324: checking for 8-bit clean memcmp&quot; &gt;&amp;5
++if eval &quot;test \&quot;`echo '$''{'ac_cv_func_memcmp_clean'+set}'`\&quot; = set&quot;; then
++ echo $ac_n &quot;(cached) $ac_c&quot; 1&gt;&amp;6
++else
++ if test &quot;$cross_compiling&quot; = yes; then
++ ac_cv_func_memcmp_clean=no
++else
++ cat &gt; conftest.$ac_ext &lt;&lt;EOF
++#line 1332 &quot;configure&quot;
++#include &quot;confdefs.h&quot;
++
++main()
++{
++ char c0 = 0x40, c1 = 0x80, c2 = 0x81;
++ exit(memcmp(&amp;c0, &amp;c2, 1) &lt; 0 &amp;&amp; memcmp(&amp;c1, &amp;c2, 1) &lt; 0 ? 0 : 1);
++}
++
++EOF
++if { (eval echo configure:1342: \&quot;$ac_link\&quot;) 1&gt;&amp;5; (eval $ac_link) 2&gt;&amp;5; } &amp;&amp; test -s conftest${ac_exeext} &amp;&amp; (./conftest; exit) 2&gt;/dev/null
++then
++ ac_cv_func_memcmp_clean=yes
++else
++ echo &quot;configure: failed program was:&quot; &gt;&amp;5
++ cat conftest.$ac_ext &gt;&amp;5
++ rm -fr conftest*
++ ac_cv_func_memcmp_clean=no
++fi
++rm -fr conftest*
++fi
++
++fi
++
++echo &quot;$ac_t&quot;&quot;$ac_cv_func_memcmp_clean&quot; 1&gt;&amp;6
++test $ac_cv_func_memcmp_clean = no &amp;&amp; LIBOBJS=&quot;$LIBOBJS memcmp.${ac_objext}&quot;
++
++echo $ac_n &quot;checking whether setvbuf arguments are reversed&quot;&quot;... $ac_c&quot; 1&gt;&amp;6
++echo &quot;configure:1360: checking whether setvbuf arguments are reversed&quot; &gt;&amp;5
++if eval &quot;test \&quot;`echo '$''{'ac_cv_func_setvbuf_reversed'+set}'`\&quot; = set&quot;; then
++ echo $ac_n &quot;(cached) $ac_c&quot; 1&gt;&amp;6
++else
++ if test &quot;$cross_compiling&quot; = yes; then
++ { echo &quot;configure: error: can not run test program while cross compiling&quot; 1&gt;&amp;2; exit 1; }
++else
++ cat &gt; conftest.$ac_ext &lt;&lt;EOF
++#line 1368 &quot;configure&quot;
++#include &quot;confdefs.h&quot;
++#include &lt;stdio.h&gt;
++/* If setvbuf has the reversed format, exit 0. */
++main () {
++ /* This call has the arguments reversed.
++ A reversed system may check and see that the address of main
++ is not _IOLBF, _IONBF, or _IOFBF, and return nonzero. */
++ if (setvbuf(stdout, _IOLBF, (char *) main, BUFSIZ) != 0)
++ exit(1);
++ putc('\r', stdout);
++ exit(0); /* Non-reversed systems segv here. */
++}
++EOF
++if { (eval echo configure:1382: \&quot;$ac_link\&quot;) 1&gt;&amp;5; (eval $ac_link) 2&gt;&amp;5; } &amp;&amp; test -s conftest${ac_exeext} &amp;&amp; (./conftest; exit) 2&gt;/dev/null
++then
++ ac_cv_func_setvbuf_reversed=yes
++else
++ echo &quot;configure: failed program was:&quot; &gt;&amp;5
++ cat conftest.$ac_ext &gt;&amp;5
++ rm -fr conftest*
++ ac_cv_func_setvbuf_reversed=no
++fi
++rm -fr conftest*
++fi
++
++rm -f core core.* *.core
++fi
++
++echo &quot;$ac_t&quot;&quot;$ac_cv_func_setvbuf_reversed&quot; 1&gt;&amp;6
++if test $ac_cv_func_setvbuf_reversed = yes; then
++ cat &gt;&gt; confdefs.h &lt;&lt;\EOF
++#define SETVBUF_REVERSED 1
++EOF
++
++fi
++
++echo $ac_n &quot;checking return type of signal handlers&quot;&quot;... $ac_c&quot; 1&gt;&amp;6
++echo &quot;configure:1406: checking return type of signal handlers&quot; &gt;&amp;5
++if eval &quot;test \&quot;`echo '$''{'ac_cv_type_signal'+set}'`\&quot; = set&quot;; then
++ echo $ac_n &quot;(cached) $ac_c&quot; 1&gt;&amp;6
++else
++ cat &gt; conftest.$ac_ext &lt;&lt;EOF
++#line 1411 &quot;configure&quot;
++#include &quot;confdefs.h&quot;
++#include &lt;sys/types.h&gt;
++#include &lt;signal.h&gt;
++#ifdef signal
++#undef signal
++#endif
++#ifdef __cplusplus
++extern &quot;C&quot; void (*signal (int, void (*)(int)))(int);
++#else
++void (*signal ()) ();
++#endif
++
++int main() {
++int i;
++; return 0; }
++EOF
++if { (eval echo configure:1428: \&quot;$ac_compile\&quot;) 1&gt;&amp;5; (eval $ac_compile) 2&gt;&amp;5; }; then
++ rm -rf conftest*
++ ac_cv_type_signal=void
++else
++ echo &quot;configure: failed program was:&quot; &gt;&amp;5
++ cat conftest.$ac_ext &gt;&amp;5
++ rm -rf conftest*
++ ac_cv_type_signal=int
++fi
++rm -f conftest*
++fi
++
++echo &quot;$ac_t&quot;&quot;$ac_cv_type_signal&quot; 1&gt;&amp;6
++cat &gt;&gt; confdefs.h &lt;&lt;EOF
++#define RETSIGTYPE $ac_cv_type_signal
++EOF
++
++
++for ac_func in select socket strerror strtol
++do
++echo $ac_n &quot;checking for $ac_func&quot;&quot;... $ac_c&quot; 1&gt;&amp;6
++echo &quot;configure:1449: checking for $ac_func&quot; &gt;&amp;5
++if eval &quot;test \&quot;`echo '$''{'ac_cv_func_$ac_func'+set}'`\&quot; = set&quot;; then
++ echo $ac_n &quot;(cached) $ac_c&quot; 1&gt;&amp;6
++else
++ cat &gt; conftest.$ac_ext &lt;&lt;EOF
++#line 1454 &quot;configure&quot;
++#include &quot;confdefs.h&quot;
++/* System header to define __stub macros and hopefully few prototypes,
++ which can conflict with char $ac_func(); below. */
++#include &lt;assert.h&gt;
++/* Override any gcc2 internal prototype to avoid an error. */
++/* We use char because int might match the return type of a gcc2
++ builtin and then its argument prototype would still apply. */
++char $ac_func();
++
++int main() {
++
++/* The GNU C library defines this for functions which it implements
++ to always fail with ENOSYS. Some functions are actually named
++ something starting with __ and the normal name is an alias. */
++#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
++choke me
++#else
++$ac_func();
++#endif
++
++; return 0; }
++EOF
++if { (eval echo configure:1477: \&quot;$ac_link\&quot;) 1&gt;&amp;5; (eval $ac_link) 2&gt;&amp;5; } &amp;&amp; test -s conftest${ac_exeext}; then
++ rm -rf conftest*
++ eval &quot;ac_cv_func_$ac_func=yes&quot;
++else
++ echo &quot;configure: failed program was:&quot; &gt;&amp;5
++ cat conftest.$ac_ext &gt;&amp;5
++ rm -rf conftest*
++ eval &quot;ac_cv_func_$ac_func=no&quot;
++fi
++rm -f conftest*
++fi
++
++if eval &quot;test \&quot;`echo '$ac_cv_func_'$ac_func`\&quot; = yes&quot;; then
++ echo &quot;$ac_t&quot;&quot;yes&quot; 1&gt;&amp;6
++ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
++ cat &gt;&gt; confdefs.h &lt;&lt;EOF
++#define $ac_tr_func 1
++EOF
++
++else
++ echo &quot;$ac_t&quot;&quot;no&quot; 1&gt;&amp;6
++fi
++done
++
++ac_aux_dir=
++for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
++ if test -f $ac_dir/install-sh; then
++ ac_aux_dir=$ac_dir
++ ac_install_sh=&quot;$ac_aux_dir/install-sh -c&quot;
++ break
++ elif test -f $ac_dir/install.sh; then
++ ac_aux_dir=$ac_dir
++ ac_install_sh=&quot;$ac_aux_dir/install.sh -c&quot;
++ break
++ fi
++done
++if test -z &quot;$ac_aux_dir&quot;; then
++ { echo &quot;configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../..&quot; 1&gt;&amp;2; exit 1; }
++fi
++ac_config_guess=$ac_aux_dir/config.guess
++ac_config_sub=$ac_aux_dir/config.sub
++ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
++
++# Find a good install program. We prefer a C program (faster),
++# so one script is as good as another. But avoid the broken or
++# incompatible versions:
++# SysV /etc/install, /usr/sbin/install
++# SunOS /usr/etc/install
++# IRIX /sbin/install
++# AIX /bin/install
++# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
++# AFS /usr/afsws/bin/install, which mishandles nonexistent args
++# SVR4 /usr/ucb/install, which tries to use the nonexistent group &quot;staff&quot;
++# ./install, which can be erroneously created by make from ./install.sh.
++echo $ac_n &quot;checking for a BSD compatible install&quot;&quot;... $ac_c&quot; 1&gt;&amp;6
++echo &quot;configure:1532: checking for a BSD compatible install&quot; &gt;&amp;5
++if test -z &quot;$INSTALL&quot;; then
++if eval &quot;test \&quot;`echo '$''{'ac_cv_path_install'+set}'`\&quot; = set&quot;; then
++ echo $ac_n &quot;(cached) $ac_c&quot; 1&gt;&amp;6
++else
++ IFS=&quot;${IFS= }&quot;; ac_save_IFS=&quot;$IFS&quot;; IFS=&quot;:&quot;
++ for ac_dir in $PATH; do
++ # Account for people who put trailing slashes in PATH elements.
++ case &quot;$ac_dir/&quot; in
++ /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
++ *)
++ # OSF1 and SCO ODT 3.0 have their own names for install.
++ # Don't use installbsd from OSF since it installs stuff as root
++ # by default.
++ for ac_prog in ginstall scoinst install; do
++ if test -f $ac_dir/$ac_prog; then
++ if test $ac_prog = install &amp;&amp;
++ grep dspmsg $ac_dir/$ac_prog &gt;/dev/null 2&gt;&amp;1; then
++ # AIX install. It has an incompatible calling convention.
++ :
++ else
++ ac_cv_path_install=&quot;$ac_dir/$ac_prog -c&quot;
++ break 2
++ fi
++ fi
++ done
++ ;;
++ esac
++ done
++ IFS=&quot;$ac_save_IFS&quot;
++
++fi
++ if test &quot;${ac_cv_path_install+set}&quot; = set; then
++ INSTALL=&quot;$ac_cv_path_install&quot;
++ else
++ # As a last resort, use the slow shell script. We don't cache a
++ # path for INSTALL within a source directory, because that will
++ # break other packages using the cache if that directory is
++ # removed, or if the path is relative.
++ INSTALL=&quot;$ac_install_sh&quot;
++ fi
++fi
++echo &quot;$ac_t&quot;&quot;$INSTALL&quot; 1&gt;&amp;6
++
++# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
++# It thinks the first close brace ends the variable substitution.
++test -z &quot;$INSTALL_PROGRAM&quot; &amp;&amp; INSTALL_PROGRAM='${INSTALL}'
++
++test -z &quot;$INSTALL_SCRIPT&quot; &amp;&amp; INSTALL_SCRIPT='${INSTALL_PROGRAM}'
++
++test -z &quot;$INSTALL_DATA&quot; &amp;&amp; INSTALL_DATA='${INSTALL} -m 644'
++
++
++echo $ac_n &quot;checking size of unsigned short&quot;&quot;... $ac_c&quot; 1&gt;&amp;6
++echo &quot;configure:1586: checking size of unsigned short&quot; &gt;&amp;5
++if eval &quot;test \&quot;`echo '$''{'ac_cv_sizeof_unsigned_short'+set}'`\&quot; = set&quot;; then
++ echo $ac_n &quot;(cached) $ac_c&quot; 1&gt;&amp;6
++else
++ if test &quot;$cross_compiling&quot; = yes; then
++ { echo &quot;configure: error: can not run test program while cross compiling&quot; 1&gt;&amp;2; exit 1; }
++else
++ cat &gt; conftest.$ac_ext &lt;&lt;EOF
++#line 1594 &quot;configure&quot;
++#include &quot;confdefs.h&quot;
++#include &lt;stdio.h&gt;
++main()
++{
++ FILE *f=fopen(&quot;conftestval&quot;, &quot;w&quot;);
++ if (!f) exit(1);
++ fprintf(f, &quot;%d\n&quot;, sizeof(unsigned short));
++ exit(0);
++}
++EOF
++if { (eval echo configure:1605: \&quot;$ac_link\&quot;) 1&gt;&amp;5; (eval $ac_link) 2&gt;&amp;5; } &amp;&amp; test -s conftest${ac_exeext} &amp;&amp; (./conftest; exit) 2&gt;/dev/null
++then
++ ac_cv_sizeof_unsigned_short=`cat conftestval`
++else
++ echo &quot;configure: failed program was:&quot; &gt;&amp;5
++ cat conftest.$ac_ext &gt;&amp;5
++ rm -fr conftest*
++ ac_cv_sizeof_unsigned_short=0
++fi
++rm -fr conftest*
++fi
++
++fi
++echo &quot;$ac_t&quot;&quot;$ac_cv_sizeof_unsigned_short&quot; 1&gt;&amp;6
++cat &gt;&gt; confdefs.h &lt;&lt;EOF
++#define SIZEOF_UNSIGNED_SHORT $ac_cv_sizeof_unsigned_short
++EOF
++
++
++echo $ac_n &quot;checking size of unsigned int&quot;&quot;... $ac_c&quot; 1&gt;&amp;6
++echo &quot;configure:1625: checking size of unsigned int&quot; &gt;&amp;5
++if eval &quot;test \&quot;`echo '$''{'ac_cv_sizeof_unsigned_int'+set}'`\&quot; = set&quot;; then
++ echo $ac_n &quot;(cached) $ac_c&quot; 1&gt;&amp;6
++else
++ if test &quot;$cross_compiling&quot; = yes; then
++ { echo &quot;configure: error: can not run test program while cross compiling&quot; 1&gt;&amp;2; exit 1; }
++else
++ cat &gt; conftest.$ac_ext &lt;&lt;EOF
++#line 1633 &quot;configure&quot;
++#include &quot;confdefs.h&quot;
++#include &lt;stdio.h&gt;
++main()
++{
++ FILE *f=fopen(&quot;conftestval&quot;, &quot;w&quot;);
++ if (!f) exit(1);
++ fprintf(f, &quot;%d\n&quot;, sizeof(unsigned int));
++ exit(0);
++}
++EOF
++if { (eval echo configure:1644: \&quot;$ac_link\&quot;) 1&gt;&amp;5; (eval $ac_link) 2&gt;&amp;5; } &amp;&amp; test -s conftest${ac_exeext} &amp;&amp; (./conftest; exit) 2&gt;/dev/null
++then
++ ac_cv_sizeof_unsigned_int=`cat conftestval`
++else
++ echo &quot;configure: failed program was:&quot; &gt;&amp;5
++ cat conftest.$ac_ext &gt;&amp;5
++ rm -fr conftest*
++ ac_cv_sizeof_unsigned_int=0
++fi
++rm -fr conftest*
++fi
++
++fi
++echo &quot;$ac_t&quot;&quot;$ac_cv_sizeof_unsigned_int&quot; 1&gt;&amp;6
++cat &gt;&gt; confdefs.h &lt;&lt;EOF
++#define SIZEOF_UNSIGNED_INT $ac_cv_sizeof_unsigned_int
++EOF
++
++
++echo $ac_n &quot;checking size of unsigned long&quot;&quot;... $ac_c&quot; 1&gt;&amp;6
++echo &quot;configure:1664: checking size of unsigned long&quot; &gt;&amp;5
++if eval &quot;test \&quot;`echo '$''{'ac_cv_sizeof_unsigned_long'+set}'`\&quot; = set&quot;; then
++ echo $ac_n &quot;(cached) $ac_c&quot; 1&gt;&amp;6
++else
++ if test &quot;$cross_compiling&quot; = yes; then
++ { echo &quot;configure: error: can not run test program while cross compiling&quot; 1&gt;&amp;2; exit 1; }
++else
++ cat &gt; conftest.$ac_ext &lt;&lt;EOF
++#line 1672 &quot;configure&quot;
++#include &quot;confdefs.h&quot;
++#include &lt;stdio.h&gt;
++main()
++{
++ FILE *f=fopen(&quot;conftestval&quot;, &quot;w&quot;);
++ if (!f) exit(1);
++ fprintf(f, &quot;%d\n&quot;, sizeof(unsigned long));
++ exit(0);
++}
++EOF
++if { (eval echo configure:1683: \&quot;$ac_link\&quot;) 1&gt;&amp;5; (eval $ac_link) 2&gt;&amp;5; } &amp;&amp; test -s conftest${ac_exeext} &amp;&amp; (./conftest; exit) 2&gt;/dev/null
++then
++ ac_cv_sizeof_unsigned_long=`cat conftestval`
++else
++ echo &quot;configure: failed program was:&quot; &gt;&amp;5
++ cat conftest.$ac_ext &gt;&amp;5
++ rm -fr conftest*
++ ac_cv_sizeof_unsigned_long=0
++fi
++rm -fr conftest*
++fi
++
++fi
++echo &quot;$ac_t&quot;&quot;$ac_cv_sizeof_unsigned_long&quot; 1&gt;&amp;6
++cat &gt;&gt; confdefs.h &lt;&lt;EOF
++#define SIZEOF_UNSIGNED_LONG $ac_cv_sizeof_unsigned_long
++EOF
++
++
++
++# Extract the first word of &quot;pppd&quot;, so it can be a program name with args.
++set dummy pppd; ac_word=$2
++echo $ac_n &quot;checking for $ac_word&quot;&quot;... $ac_c&quot; 1&gt;&amp;6
++echo &quot;configure:1706: checking for $ac_word&quot; &gt;&amp;5
++if eval &quot;test \&quot;`echo '$''{'ac_cv_path_PPPD'+set}'`\&quot; = set&quot;; then
++ echo $ac_n &quot;(cached) $ac_c&quot; 1&gt;&amp;6
++else
++ case &quot;$PPPD&quot; in
++ /*)
++ ac_cv_path_PPPD=&quot;$PPPD&quot; # Let the user override the test with a path.
++ ;;
++ ?:/*)
++ ac_cv_path_PPPD=&quot;$PPPD&quot; # Let the user override the test with a dos path.
++ ;;
++ *)
++ IFS=&quot;${IFS= }&quot;; ac_save_ifs=&quot;$IFS&quot;; IFS=&quot;:&quot;
++ ac_dummy=&quot;$PATH:/sbin:/usr/sbin:/usr/local/sbin&quot;
++ for ac_dir in $ac_dummy; do
++ test -z &quot;$ac_dir&quot; &amp;&amp; ac_dir=.
++ if test -f $ac_dir/$ac_word; then
++ ac_cv_path_PPPD=&quot;$ac_dir/$ac_word&quot;
++ break
++ fi
++ done
++ IFS=&quot;$ac_save_ifs&quot;
++ test -z &quot;$ac_cv_path_PPPD&quot; &amp;&amp; ac_cv_path_PPPD=&quot;NOTFOUND&quot;
++ ;;
++esac
++fi
++PPPD=&quot;$ac_cv_path_PPPD&quot;
++if test -n &quot;$PPPD&quot;; then
++ echo &quot;$ac_t&quot;&quot;$PPPD&quot; 1&gt;&amp;6
++else
++ echo &quot;$ac_t&quot;&quot;no&quot; 1&gt;&amp;6
++fi
++
++
++# Extract the first word of &quot;setsid&quot;, so it can be a program name with args.
++set dummy setsid; ac_word=$2
++echo $ac_n &quot;checking for $ac_word&quot;&quot;... $ac_c&quot; 1&gt;&amp;6
++echo &quot;configure:1743: checking for $ac_word&quot; &gt;&amp;5
++if eval &quot;test \&quot;`echo '$''{'ac_cv_path_SETSID'+set}'`\&quot; = set&quot;; then
++ echo $ac_n &quot;(cached) $ac_c&quot; 1&gt;&amp;6
++else
++ case &quot;$SETSID&quot; in
++ /*)
++ ac_cv_path_SETSID=&quot;$SETSID&quot; # Let the user override the test with a path.
++ ;;
++ ?:/*)
++ ac_cv_path_SETSID=&quot;$SETSID&quot; # Let the user override the test with a dos path.
++ ;;
++ *)
++ IFS=&quot;${IFS= }&quot;; ac_save_ifs=&quot;$IFS&quot;; IFS=&quot;:&quot;
++ ac_dummy=&quot;$PATH:/sbin:/usr/sbin:/usr/local/sbin&quot;
++ for ac_dir in $ac_dummy; do
++ test -z &quot;$ac_dir&quot; &amp;&amp; ac_dir=.
++ if test -f $ac_dir/$ac_word; then
++ ac_cv_path_SETSID=&quot;$ac_dir/$ac_word&quot;
++ break
++ fi
++ done
++ IFS=&quot;$ac_save_ifs&quot;
++ test -z &quot;$ac_cv_path_SETSID&quot; &amp;&amp; ac_cv_path_SETSID=&quot;&quot;&quot;&quot;
++ ;;
++esac
++fi
++SETSID=&quot;$ac_cv_path_SETSID&quot;
++if test -n &quot;$SETSID&quot;; then
++ echo &quot;$ac_t&quot;&quot;$SETSID&quot; 1&gt;&amp;6
++else
++ echo &quot;$ac_t&quot;&quot;no&quot; 1&gt;&amp;6
++fi
++
++
++# Extract the first word of &quot;id&quot;, so it can be a program name with args.
++set dummy id; ac_word=$2
++echo $ac_n &quot;checking for $ac_word&quot;&quot;... $ac_c&quot; 1&gt;&amp;6
++echo &quot;configure:1780: checking for $ac_word&quot; &gt;&amp;5
++if eval &quot;test \&quot;`echo '$''{'ac_cv_path_ID'+set}'`\&quot; = set&quot;; then
++ echo $ac_n &quot;(cached) $ac_c&quot; 1&gt;&amp;6
++else
++ case &quot;$ID&quot; in
++ /*)
++ ac_cv_path_ID=&quot;$ID&quot; # Let the user override the test with a path.
++ ;;
++ ?:/*)
++ ac_cv_path_ID=&quot;$ID&quot; # Let the user override the test with a dos path.
++ ;;
++ *)
++ IFS=&quot;${IFS= }&quot;; ac_save_ifs=&quot;$IFS&quot;; IFS=&quot;:&quot;
++ ac_dummy=&quot;/usr/xpg4/bin:$PATH&quot;
++ for ac_dir in $ac_dummy; do
++ test -z &quot;$ac_dir&quot; &amp;&amp; ac_dir=.
++ if test -f $ac_dir/$ac_word; then
++ ac_cv_path_ID=&quot;$ac_dir/$ac_word&quot;
++ break
++ fi
++ done
++ IFS=&quot;$ac_save_ifs&quot;
++ test -z &quot;$ac_cv_path_ID&quot; &amp;&amp; ac_cv_path_ID=&quot;&quot;&quot;&quot;
++ ;;
++esac
++fi
++ID=&quot;$ac_cv_path_ID&quot;
++if test -n &quot;$ID&quot;; then
++ echo &quot;$ac_t&quot;&quot;$ID&quot; 1&gt;&amp;6
++else
++ echo &quot;$ac_t&quot;&quot;no&quot; 1&gt;&amp;6
++fi
++
++
++$ECHO -n &quot;checking for Linux 2.4.X kernel-mode PPPoE support...&quot;
++if test &quot;`uname -s`&quot; = &quot;Linux&quot; ; then
++if test &quot;$cross_compiling&quot; = yes; then
++ { echo &quot;configure: error: can not run test program while cross compiling&quot; 1&gt;&amp;2; exit 1; }
++else
++ cat &gt; conftest.$ac_ext &lt;&lt;EOF
++#line 1820 &quot;configure&quot;
++#include &quot;confdefs.h&quot;
++#include &lt;sys/socket.h&gt;
++#include &lt;net/ethernet.h&gt;
++#include &lt;linux/if.h&gt;
++#include &lt;linux/if_pppox.h&gt;
++int main()
++{
++ if (socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OE) &gt;= 0) return 0; else return 1;
++}
++
++EOF
++if { (eval echo configure:1832: \&quot;$ac_link\&quot;) 1&gt;&amp;5; (eval $ac_link) 2&gt;&amp;5; } &amp;&amp; test -s conftest${ac_exeext} &amp;&amp; (./conftest; exit) 2&gt;/dev/null
++then
++ ac_cv_linux_kernel_pppoe=yes
++else
++ echo &quot;configure: failed program was:&quot; &gt;&amp;5
++ cat conftest.$ac_ext &gt;&amp;5
++ rm -fr conftest*
++ ac_cv_linux_kernel_pppoe=no
++fi
++rm -fr conftest*
++fi
++
++else
++ ac_cv_linux_kernel_pppoe=no
++fi
++
++$ECHO $ac_cv_linux_kernel_pppoe
++if test &quot;$ac_cv_linux_kernel_pppoe&quot; = yes ; then
++ cat &gt;&gt; confdefs.h &lt;&lt;\EOF
++#define HAVE_LINUX_KERNEL_PPPOE 1
++EOF
++
++fi
++
++if test &quot;$GCC&quot; = yes; then
++ CFLAGS=&quot;$CFLAGS -Wall -Wstrict-prototypes -ansi -pedantic&quot;
++fi
++
++if test &quot;$PPPD&quot; = &quot;NOTFOUND&quot;; then
++ $ECHO &quot;&quot;
++ $ECHO &quot;*** Oops! I couldn't find pppd, the PPP daemon anywhere.&quot;
++ $ECHO &quot;*** You must install pppd, version 2.3.10 or later.&quot;
++ $ECHO &quot;*** I will keep going, but it may not work.&quot;
++ $ECHO &quot;&quot;
++fi
++
++
++PPPD_VERSION=`$PPPD --version 2&gt;&amp;1 | awk '{print $NF}'`
++
++case &quot;$PPPD_VERSION&quot; in
++1.*|2.0.*|2.1.*|2.2.*|2.3.0|2.3.1|2.3.2|2.3.3|2.3.4|2.3.5|2.3.6)
++ $ECHO &quot;&quot;
++ $ECHO &quot;*** Oops! Your version of pppd is $PPPD_VERSION, which is too old.&quot;
++ $ECHO &quot;*** You need at least 2.3.7 (2.3.10 or newer recommended.)&quot;
++ $ECHO &quot;*** I will keep going, but it may not work.&quot;
++ $ECHO &quot;&quot;
++ ;;
++
++2.3.7|2.3.8|2.3.9)
++ $ECHO &quot;&quot;
++ $ECHO &quot;*** Warning. Your version of pppd is $PPPD_VERSION. You will&quot;
++ $ECHO &quot;*** not be able to use connect-on-demand. Upgrade to pppd&quot;
++ $ECHO &quot;*** 2.3.10 or newer if you need connect-on-demand.&quot;
++ $ECHO &quot;&quot;
++ ;;
++
++2*|3*|4*|5*|6*|7*|8*|9*)
++ ;;
++
++*)
++ $ECHO &quot;&quot;
++ $ECHO &quot;*** Oops. I cannot figure out what version of pppd you have.&quot;
++ $ECHO &quot;*** All I got back was '$PPPD_VERSION'&quot;
++ $ECHO &quot;*** I will keep going, but it may not work.&quot;
++ $ECHO &quot;&quot;
++ ;;
++esac
++
++$ECHO -n &quot;checking packing order of bit fields... &quot;
++if test &quot;$cross_compiling&quot; = yes; then
++ { echo &quot;configure: error: can not run test program while cross compiling&quot; 1&gt;&amp;2; exit 1; }
++else
++ cat &gt; conftest.$ac_ext &lt;&lt;EOF
++#line 1905 &quot;configure&quot;
++#include &quot;confdefs.h&quot;
++
++union foo {
++ struct bar {
++ unsigned int ver:4;
++ unsigned int type:4;
++ } bb;
++ unsigned char baz;
++};
++
++int
++main(void)
++{
++ union foo x;
++ x.bb.ver = 1;
++ x.bb.type = 2;
++ if (x.baz == 0x21) {
++ return 1;
++ } else if (x.baz == 0x12) {
++ return 0;
++ } else {
++ return 2;
++ }
++}
++EOF
++if { (eval echo configure:1931: \&quot;$ac_link\&quot;) 1&gt;&amp;5; (eval $ac_link) 2&gt;&amp;5; } &amp;&amp; test -s conftest${ac_exeext} &amp;&amp; (./conftest; exit) 2&gt;/dev/null
++then
++ PACK=normal
++else
++ echo &quot;configure: failed program was:&quot; &gt;&amp;5
++ cat conftest.$ac_ext &gt;&amp;5
++ rm -fr conftest*
++ PACK=rev
++fi
++rm -fr conftest*
++fi
++
++
++if test &quot;$PACK&quot; = &quot;rev&quot; ; then
++ $ECHO &quot;reversed&quot;
++ cat &gt;&gt; confdefs.h &lt;&lt;\EOF
++#define PACK_BITFIELDS_REVERSED 1
++EOF
++
++else
++ $ECHO &quot;normal&quot;
++fi
++
++# Sigh... got to fix this up for tcl
++test &quot;x$prefix&quot; = xNONE &amp;&amp; prefix=$ac_default_prefix
++# Let make expand exec_prefix.
++test &quot;x$exec_prefix&quot; = xNONE &amp;&amp; exec_prefix='${prefix}'
++
++# Fully resolve WRAPPER for Tcl script.
++WRAPPER=${sbindir}/pppoe-wrapper
++eval &quot;WRAPPER=${WRAPPER}&quot;
++eval &quot;WRAPPER=${WRAPPER}&quot;
++
++
++# Determine what targets to build
++TARGETS=&quot;pppoe pppoe-server&quot;
++
++# pppoe-sniff is built only on Linux and Solaris
++if test &quot;$ac_cv_header_linux_if_packet_h&quot; = &quot;yes&quot; -o &quot;$ac_cv_header_sys_dlpi_h&quot; = &quot;yes&quot; ; then
++ TARGETS=&quot;$TARGETS pppoe-sniff&quot;
++fi
++
++# pppoe-relay is built only on Linux
++if test &quot;$ac_cv_header_linux_if_packet_h&quot; = &quot;yes&quot; ; then
++ TARGETS=&quot;$TARGETS pppoe-relay&quot;
++fi
++
++# plugin is built only if we have kernel support
++if test -n &quot;$LINUX_KERNELMODE_PLUGIN&quot; ; then
++ TARGETS=&quot;$TARGETS $LINUX_KERNELMODE_PLUGIN&quot;
++fi
++
++
++
++trap '' 1 2 15
++cat &gt; confcache &lt;&lt;\EOF
++# This file is a shell script that caches the results of configure
++# tests run on this system so they can be shared between configure
++# scripts and configure runs. It is not useful on other systems.
++# If it contains results you don't want to keep, you may remove or edit it.
++#
++# By default, configure uses ./config.cache as the cache file,
++# creating it if it does not exist already. You can give configure
++# the --cache-file=FILE option to use a different cache file; that is
++# what configure does when it calls configure scripts in
++# subdirectories, so they share the cache.
++# Giving --cache-file=/dev/null disables caching, for debugging configure.
++# config.status only pays attention to the cache file if you give it the
++# --recheck option to rerun configure.
++#
++EOF
++# The following way of writing the cache mishandles newlines in values,
++# but we know of no workaround that is simple, portable, and efficient.
++# So, don't put newlines in cache variables' values.
++# Ultrix sh set writes to stderr and can't be redirected directly,
++# and sets the high bit in the cache file unless we assign to the vars.
++(set) 2&gt;&amp;1 |
++ case `(ac_space=' '; set | grep ac_space) 2&gt;&amp;1` in
++ *ac_space=\ *)
++ # `set' does not quote correctly, so add quotes (double-quote substitution
++ # turns \\\\ into \\, and sed turns \\ into \).
++ sed -n \
++ -e &quot;s/'/'\\\\''/g&quot; \
++ -e &quot;s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p&quot;
++ ;;
++ *)
++ # `set' quotes correctly as required by POSIX, so do not add quotes.
++ sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
++ ;;
++ esac &gt;&gt; confcache
++if cmp -s $cache_file confcache; then
++ :
++else
++ if test -w $cache_file; then
++ echo &quot;updating cache $cache_file&quot;
++ cat confcache &gt; $cache_file
++ else
++ echo &quot;not updating unwritable cache $cache_file&quot;
++ fi
++fi
++rm -f confcache
++
++trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
++
++test &quot;x$prefix&quot; = xNONE &amp;&amp; prefix=$ac_default_prefix
++# Let make expand exec_prefix.
++test &quot;x$exec_prefix&quot; = xNONE &amp;&amp; exec_prefix='${prefix}'
++
++# Any assignment to VPATH causes Sun make to only execute
++# the first set of double-colon rules, so remove it if not needed.
++# If there is a colon in the path, we need to keep it.
++if test &quot;x$srcdir&quot; = x.; then
++ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
++fi
++
++trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
++
++DEFS=-DHAVE_CONFIG_H
++
++# Without the &quot;./&quot;, some shells look in PATH for config.status.
++: ${CONFIG_STATUS=./config.status}
++
++echo creating $CONFIG_STATUS
++rm -f $CONFIG_STATUS
++cat &gt; $CONFIG_STATUS &lt;&lt;EOF
++#! /bin/sh
++# Generated automatically by configure.
++# Run this file to recreate the current configuration.
++# This directory was configured as follows,
++# on host `(hostname || uname -n) 2&gt;/dev/null | sed 1q`:
++#
++# $0 $ac_configure_args
++#
++# Compiler output produced by configure, useful for debugging
++# configure, is in ./config.log if it exists.
++
++ac_cs_usage=&quot;Usage: $CONFIG_STATUS [--recheck] [--version] [--help]&quot;
++for ac_option
++do
++ case &quot;\$ac_option&quot; in
++ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
++ echo &quot;running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion&quot;
++ exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
++ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
++ echo &quot;$CONFIG_STATUS generated by autoconf version 2.13&quot;
++ exit 0 ;;
++ -help | --help | --hel | --he | --h)
++ echo &quot;\$ac_cs_usage&quot;; exit 0 ;;
++ *) echo &quot;\$ac_cs_usage&quot;; exit 1 ;;
++ esac
++done
++
++ac_given_srcdir=$srcdir
++ac_given_INSTALL=&quot;$INSTALL&quot;
++
++trap 'rm -fr `echo &quot;Makefile ../scripts/adsl-connect ../scripts/adsl-start ../scripts/adsl-stop ../scripts/adsl-init ../scripts/adsl-init-suse ../scripts/adsl-init-turbolinux ../scripts/adsl-setup ../gui/Makefile ../gui/tkpppoe config.h&quot; | sed &quot;s/:[^ ]*//g&quot;` conftest*; exit 1' 1 2 15
++EOF
++cat &gt;&gt; $CONFIG_STATUS &lt;&lt;EOF
++
++# Protect against being on the right side of a sed subst in config.status.
++sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&amp;%]/\\\\&amp;/g;
++ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' &gt; conftest.subs &lt;&lt;\\CEOF
++$ac_vpsub
++$extrasub
++s%@SHELL@%$SHELL%g
++s%@CFLAGS@%$CFLAGS%g
++s%@CPPFLAGS@%$CPPFLAGS%g
++s%@CXXFLAGS@%$CXXFLAGS%g
++s%@FFLAGS@%$FFLAGS%g
++s%@DEFS@%$DEFS%g
++s%@LDFLAGS@%$LDFLAGS%g
++s%@LIBS@%$LIBS%g
++s%@exec_prefix@%$exec_prefix%g
++s%@prefix@%$prefix%g
++s%@program_transform_name@%$program_transform_name%g
++s%@bindir@%$bindir%g
++s%@sbindir@%$sbindir%g
++s%@libexecdir@%$libexecdir%g
++s%@datadir@%$datadir%g
++s%@sysconfdir@%$sysconfdir%g
++s%@sharedstatedir@%$sharedstatedir%g
++s%@localstatedir@%$localstatedir%g
++s%@libdir@%$libdir%g
++s%@includedir@%$includedir%g
++s%@oldincludedir@%$oldincludedir%g
++s%@infodir@%$infodir%g
++s%@mandir@%$mandir%g
++s%@CC@%$CC%g
++s%@CPP@%$CPP%g
++s%@ECHO@%$ECHO%g
++s%@LINUX_KERNELMODE_PLUGIN@%$LINUX_KERNELMODE_PLUGIN%g
++s%@PPPD_INCDIR@%$PPPD_INCDIR%g
++s%@PPPOE_RELAY@%$PPPOE_RELAY%g
++s%@LIBOBJS@%$LIBOBJS%g
++s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
++s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
++s%@INSTALL_DATA@%$INSTALL_DATA%g
++s%@PPPD@%$PPPD%g
++s%@SETSID@%$SETSID%g
++s%@ID@%$ID%g
++s%@WRAPPER@%$WRAPPER%g
++s%@TARGETS@%$TARGETS%g
++
++CEOF
++EOF
++
++cat &gt;&gt; $CONFIG_STATUS &lt;&lt;\EOF
++
++# Split the substitutions into bite-sized pieces for seds with
++# small command number limits, like on Digital OSF/1 and HP-UX.
++ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
++ac_file=1 # Number of current file.
++ac_beg=1 # First line for current file.
++ac_end=$ac_max_sed_cmds # Line after last line for current file.
++ac_more_lines=:
++ac_sed_cmds=&quot;&quot;
++while $ac_more_lines; do
++ if test $ac_beg -gt 1; then
++ sed &quot;1,${ac_beg}d; ${ac_end}q&quot; conftest.subs &gt; conftest.s$ac_file
++ else
++ sed &quot;${ac_end}q&quot; conftest.subs &gt; conftest.s$ac_file
++ fi
++ if test ! -s conftest.s$ac_file; then
++ ac_more_lines=false
++ rm -f conftest.s$ac_file
++ else
++ if test -z &quot;$ac_sed_cmds&quot;; then
++ ac_sed_cmds=&quot;sed -f conftest.s$ac_file&quot;
++ else
++ ac_sed_cmds=&quot;$ac_sed_cmds | sed -f conftest.s$ac_file&quot;
++ fi
++ ac_file=`expr $ac_file + 1`
++ ac_beg=$ac_end
++ ac_end=`expr $ac_end + $ac_max_sed_cmds`
++ fi
++done
++if test -z &quot;$ac_sed_cmds&quot;; then
++ ac_sed_cmds=cat
++fi
++EOF
++
++cat &gt;&gt; $CONFIG_STATUS &lt;&lt;EOF
++
++CONFIG_FILES=\${CONFIG_FILES-&quot;Makefile ../scripts/adsl-connect ../scripts/adsl-start ../scripts/adsl-stop ../scripts/adsl-init ../scripts/adsl-init-suse ../scripts/adsl-init-turbolinux ../scripts/adsl-setup ../gui/Makefile ../gui/tkpppoe&quot;}
++EOF
++cat &gt;&gt; $CONFIG_STATUS &lt;&lt;\EOF
++for ac_file in .. $CONFIG_FILES; do if test &quot;x$ac_file&quot; != x..; then
++ # Support &quot;outfile[:infile[:infile...]]&quot;, defaulting infile=&quot;outfile.in&quot;.
++ case &quot;$ac_file&quot; in
++ *:*) ac_file_in=`echo &quot;$ac_file&quot;|sed 's%[^:]*:%%'`
++ ac_file=`echo &quot;$ac_file&quot;|sed 's%:.*%%'` ;;
++ *) ac_file_in=&quot;${ac_file}.in&quot; ;;
++ esac
++
++ # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
++
++ # Remove last slash and all that follows it. Not all systems have dirname.
++ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
++ if test &quot;$ac_dir&quot; != &quot;$ac_file&quot; &amp;&amp; test &quot;$ac_dir&quot; != .; then
++ # The file is in a subdirectory.
++ test ! -d &quot;$ac_dir&quot; &amp;&amp; mkdir &quot;$ac_dir&quot;
++ ac_dir_suffix=&quot;/`echo $ac_dir|sed 's%^\./%%'`&quot;
++ # A &quot;../&quot; for each directory in $ac_dir_suffix.
++ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
++ else
++ ac_dir_suffix= ac_dots=
++ fi
++
++ case &quot;$ac_given_srcdir&quot; in
++ .) srcdir=.
++ if test -z &quot;$ac_dots&quot;; then top_srcdir=.
++ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
++ /*) srcdir=&quot;$ac_given_srcdir$ac_dir_suffix&quot;; top_srcdir=&quot;$ac_given_srcdir&quot; ;;
++ *) # Relative path.
++ srcdir=&quot;$ac_dots$ac_given_srcdir$ac_dir_suffix&quot;
++ top_srcdir=&quot;$ac_dots$ac_given_srcdir&quot; ;;
++ esac
++
++ case &quot;$ac_given_INSTALL&quot; in
++ [/$]*) INSTALL=&quot;$ac_given_INSTALL&quot; ;;
++ *) INSTALL=&quot;$ac_dots$ac_given_INSTALL&quot; ;;
++ esac
++
++ echo creating &quot;$ac_file&quot;
++ rm -f &quot;$ac_file&quot;
++ configure_input=&quot;Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure.&quot;
++ case &quot;$ac_file&quot; in
++ *Makefile*) ac_comsub=&quot;1i\\
++# $configure_input&quot; ;;
++ *) ac_comsub= ;;
++ esac
++
++ ac_file_inputs=`echo $ac_file_in|sed -e &quot;s%^%$ac_given_srcdir/%&quot; -e &quot;s%:% $ac_given_srcdir/%g&quot;`
++ sed -e &quot;$ac_comsub
++s%@configure_input@%$configure_input%g
++s%@srcdir@%$srcdir%g
++s%@top_srcdir@%$top_srcdir%g
++s%@INSTALL@%$INSTALL%g
++&quot; $ac_file_inputs | (eval &quot;$ac_sed_cmds&quot;) &gt; $ac_file
++fi; done
++rm -f conftest.s*
++
++# These sed commands are passed to sed as &quot;A NAME B NAME C VALUE D&quot;, where
++# NAME is the cpp macro being defined and VALUE is the value it is being given.
++#
++# ac_d sets the value in &quot;#define NAME VALUE&quot; lines.
++ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)'
++ac_dB='\([ ][ ]*\)[^ ]*%\1#\2'
++ac_dC='\3'
++ac_dD='%g'
++# ac_u turns &quot;#undef NAME&quot; with trailing blanks into &quot;#define NAME VALUE&quot;.
++ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
++ac_uB='\([ ]\)%\1#\2define\3'
++ac_uC=' '
++ac_uD='\4%g'
++# ac_e turns &quot;#undef NAME&quot; without trailing blanks into &quot;#define NAME VALUE&quot;.
++ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
++ac_eB='$%\1#\2define\3'
++ac_eC=' '
++ac_eD='%g'
++
++if test &quot;${CONFIG_HEADERS+set}&quot; != set; then
++EOF
++cat &gt;&gt; $CONFIG_STATUS &lt;&lt;EOF
++ CONFIG_HEADERS=&quot;config.h&quot;
++EOF
++cat &gt;&gt; $CONFIG_STATUS &lt;&lt;\EOF
++fi
++for ac_file in .. $CONFIG_HEADERS; do if test &quot;x$ac_file&quot; != x..; then
++ # Support &quot;outfile[:infile[:infile...]]&quot;, defaulting infile=&quot;outfile.in&quot;.
++ case &quot;$ac_file&quot; in
++ *:*) ac_file_in=`echo &quot;$ac_file&quot;|sed 's%[^:]*:%%'`
++ ac_file=`echo &quot;$ac_file&quot;|sed 's%:.*%%'` ;;
++ *) ac_file_in=&quot;${ac_file}.in&quot; ;;
++ esac
++
++ echo creating $ac_file
++
++ rm -f conftest.frag conftest.in conftest.out
++ ac_file_inputs=`echo $ac_file_in|sed -e &quot;s%^%$ac_given_srcdir/%&quot; -e &quot;s%:% $ac_given_srcdir/%g&quot;`
++ cat $ac_file_inputs &gt; conftest.in
++
++EOF
++
++# Transform confdefs.h into a sed script conftest.vals that substitutes
++# the proper values into config.h.in to produce config.h. And first:
++# Protect against being on the right side of a sed subst in config.status.
++# Protect against being in an unquoted here document in config.status.
++rm -f conftest.vals
++cat &gt; conftest.hdr &lt;&lt;\EOF
++s/[\\&amp;%]/\\&amp;/g
++s%[\\$`]%\\&amp;%g
++s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
++s%ac_d%ac_u%gp
++s%ac_u%ac_e%gp
++EOF
++sed -n -f conftest.hdr confdefs.h &gt; conftest.vals
++rm -f conftest.hdr
++
++# This sed command replaces #undef with comments. This is necessary, for
++# example, in the case of _POSIX_SOURCE, which is predefined and required
++# on some systems where configure will not decide to define it.
++cat &gt;&gt; conftest.vals &lt;&lt;\EOF
++s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* &amp; */%
++EOF
++
++# Break up conftest.vals because some shells have a limit on
++# the size of here documents, and old seds have small limits too.
++
++rm -f conftest.tail
++while :
++do
++ ac_lines=`grep -c . conftest.vals`
++ # grep -c gives empty output for an empty file on some AIX systems.
++ if test -z &quot;$ac_lines&quot; || test &quot;$ac_lines&quot; -eq 0; then break; fi
++ # Write a limited-size here document to conftest.frag.
++ echo ' cat &gt; conftest.frag &lt;&lt;CEOF' &gt;&gt; $CONFIG_STATUS
++ sed ${ac_max_here_lines}q conftest.vals &gt;&gt; $CONFIG_STATUS
++ echo 'CEOF
++ sed -f conftest.frag conftest.in &gt; conftest.out
++ rm -f conftest.in
++ mv conftest.out conftest.in
++' &gt;&gt; $CONFIG_STATUS
++ sed 1,${ac_max_here_lines}d conftest.vals &gt; conftest.tail
++ rm -f conftest.vals
++ mv conftest.tail conftest.vals
++done
++rm -f conftest.vals
++
++cat &gt;&gt; $CONFIG_STATUS &lt;&lt;\EOF
++ rm -f conftest.frag conftest.h
++ echo &quot;/* $ac_file. Generated automatically by configure. */&quot; &gt; conftest.h
++ cat conftest.in &gt;&gt; conftest.h
++ rm -f conftest.in
++ if cmp -s $ac_file conftest.h 2&gt;/dev/null; then
++ echo &quot;$ac_file is unchanged&quot;
++ rm -f conftest.h
++ else
++ # Remove last slash and all that follows it. Not all systems have dirname.
++ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
++ if test &quot;$ac_dir&quot; != &quot;$ac_file&quot; &amp;&amp; test &quot;$ac_dir&quot; != .; then
++ # The file is in a subdirectory.
++ test ! -d &quot;$ac_dir&quot; &amp;&amp; mkdir &quot;$ac_dir&quot;
++ fi
++ rm -f $ac_file
++ mv conftest.h $ac_file
++ fi
++fi; done
++
++EOF
++cat &gt;&gt; $CONFIG_STATUS &lt;&lt;EOF
++
++EOF
++cat &gt;&gt; $CONFIG_STATUS &lt;&lt;\EOF
++
++exit 0
++EOF
++chmod +x $CONFIG_STATUS
++rm -fr confdefs* $ac_clean_files
++test &quot;$no_create&quot; = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
++
++
++$ECHO &quot;&quot;
++$ECHO &quot;On this platform, the following targets will be built:&quot;
++$ECHO &quot; $TARGETS&quot;
++$ECHO &quot;&quot;
++$ECHO &quot;Type 'make' to compile the software.&quot;
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/src/configure
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/src/configure.in
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/src/configure.in (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/src/configure.in 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,231 @@
++dnl Process this file with autoconf to produce a configure script.
++AC_INIT(pppoe.c)
++
++AC_CONFIG_HEADER(config.h)
++
++AC_PREFIX_DEFAULT(/usr)
++
++dnl Checks for programs.
++AC_PROG_CC
++
++dnl Checks for libraries.
++
++dnl Checks for header files.
++AC_HEADER_STDC
++AC_HEADER_SYS_WAIT
++AC_CHECK_HEADERS(fcntl.h sys/ioctl.h sys/time.h syslog.h unistd.h net/if_arp.h netinet/if_ether.h getopt.h sys/uio.h sys/param.h fcntl.h net/bpf.h netpacket/packet.h net/ethernet.h asm/types.h linux/if_packet.h linux/if_ether.h linux/if_pppox.h sys/socket.h sys/cdefs.h linux/if.h net/if.h net/if_dl.h net/if_ether.h net/if_types.h netinet/if_ether.h net/if_types.h net/if_dl.h sys/dlpi.h )
++
++dnl Checks for typedefs, structures, and compiler characteristics.
++AC_C_CONST
++AC_TYPE_PID_T
++AC_HEADER_TIME
++AC_STRUCT_TM
++
++dnl Check for an echo which supports -n -- another hack for Solaris
++AC_PATH_PROG(ECHO, echo, &quot;&quot;, /usr/ucb/bin:$PATH)
++
++dnl Check for sockaddr_ll
++$ECHO -n &quot;checking for struct sockaddr_ll... &quot;
++AC_TRY_COMPILE([#include &lt;asm/types.h&gt;
++#include &lt;linux/if_packet.h&gt;
++#include &lt;linux/if_ether.h&gt;
++], [struct sockaddr_ll sa;],
++ac_cv_struct_sockaddr_ll=yes, ac_cv_struct_sockaddr_ll=no)
++$ECHO $ac_cv_struct_sockaddr_ll
++if test &quot;$ac_cv_struct_sockaddr_ll&quot; = yes ; then
++AC_DEFINE(HAVE_STRUCT_SOCKADDR_LL)
++fi
++
++dnl Check for N_HDLC line discipline
++$ECHO -n &quot;checking for N_HDLC line discipline... &quot;
++AC_TRY_COMPILE([#include &lt;linux/termios.h&gt;],
++ [int x = N_HDLC;],
++ ac_cv_n_hdlc=yes, ac_cv_n_hdlc=no)
++$ECHO $ac_cv_n_hdlc
++if test &quot;$ac_cv_n_hdlc&quot; = yes ; then
++AC_DEFINE(HAVE_N_HDLC)
++fi
++
++AC_ARG_ENABLE(plugin, [ --enable-plugin=pppd_src_path build pppd plugin], ac_cv_pluginpath=$enableval, ac_cv_pluginpath=no)
++
++dnl Determine whether or not to build Linux pppd plugin
++LINUX_KERNELMODE_PLUGIN=&quot;&quot;
++PPPD_INCDIR=&quot;&quot;
++if test &quot;$ac_cv_header_linux_if_pppox_h&quot; = yes ; then
++ if test &quot;$ac_cv_pluginpath&quot; != no ; then
++ LINUX_KERNELMODE_PLUGIN=rp-pppoe.so
++ PPPD_INCDIR=$ac_cv_pluginpath
++ fi
++fi
++
++AC_SUBST(LINUX_KERNELMODE_PLUGIN)
++AC_SUBST(PPPD_INCDIR)
++
++dnl Determine whether or not to build PPPoE relay
++PPPOE_RELAY=&quot;&quot;
++if test &quot;`uname -s`&quot; = &quot;Linux&quot; ; then
++ PPPOE_RELAY=pppoe-relay
++fi
++AC_SUBST(PPPOE_RELAY)
++
++dnl Checks for library functions.
++AC_FUNC_MEMCMP
++AC_FUNC_SETVBUF_REVERSED
++AC_TYPE_SIGNAL
++AC_CHECK_FUNCS(select socket strerror strtol)
++AC_PROG_INSTALL
++
++dnl Integer sizes
++AC_CHECK_SIZEOF(unsigned short)
++AC_CHECK_SIZEOF(unsigned int)
++AC_CHECK_SIZEOF(unsigned long)
++
++dnl Check for location of pppd
++AC_PATH_PROG(PPPD, pppd, NOTFOUND, $PATH:/sbin:/usr/sbin:/usr/local/sbin)
++
++dnl Check for setsid (probably Linux-specific)
++AC_PATH_PROG(SETSID, setsid, &quot;&quot;, $PATH:/sbin:/usr/sbin:/usr/local/sbin)
++
++dnl Check for an &quot;id&quot; which accepts &quot;-u&quot; option -- hack for Solaris.
++AC_PATH_PROG(ID, id, &quot;&quot;, /usr/xpg4/bin:$PATH)
++
++dnl Check for Linux-specific kernel support for PPPoE
++$ECHO -n &quot;checking for Linux 2.4.X kernel-mode PPPoE support...&quot;
++if test &quot;`uname -s`&quot; = &quot;Linux&quot; ; then
++AC_TRY_RUN([#include &lt;sys/socket.h&gt;
++#include &lt;net/ethernet.h&gt;
++#include &lt;linux/if.h&gt;
++#include &lt;linux/if_pppox.h&gt;
++int main()
++{
++ if (socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OE) &gt;= 0) return 0; else return 1;
++}
++], ac_cv_linux_kernel_pppoe=yes, ac_cv_linux_kernel_pppoe=no)
++else
++ ac_cv_linux_kernel_pppoe=no
++fi
++
++$ECHO $ac_cv_linux_kernel_pppoe
++if test &quot;$ac_cv_linux_kernel_pppoe&quot; = yes ; then
++ AC_DEFINE(HAVE_LINUX_KERNEL_PPPOE)
++fi
++
++dnl GCC warning level
++if test &quot;$GCC&quot; = yes; then
++ CFLAGS=&quot;$CFLAGS -Wall -Wstrict-prototypes&quot;
++fi
++
++dnl If we couldn't find pppd, die
++if test &quot;$PPPD&quot; = &quot;NOTFOUND&quot;; then
++ $ECHO &quot;&quot;
++ $ECHO &quot;*** Oops! I couldn't find pppd, the PPP daemon anywhere.&quot;
++ $ECHO &quot;*** You must install pppd, version 2.3.10 or later.&quot;
++ $ECHO &quot;*** I will keep going, but it may not work.&quot;
++ $ECHO &quot;&quot;
++fi
++
++dnl Figure out pppd version. 2.3.7 to 2.3.9 -- issue warning. Less than
++dnl 2.3.7 -- stop
++
++PPPD_VERSION=`$PPPD --version 2&gt;&amp;1 | awk '{print $NF}'`
++
++case &quot;$PPPD_VERSION&quot; in
++1.*|2.0.*|2.1.*|2.2.*|2.3.0|2.3.1|2.3.2|2.3.3|2.3.4|2.3.5|2.3.6)
++ $ECHO &quot;&quot;
++ $ECHO &quot;*** Oops! Your version of pppd is $PPPD_VERSION, which is too old.&quot;
++ $ECHO &quot;*** You need at least 2.3.7 (2.3.10 or newer recommended.)&quot;
++ $ECHO &quot;*** I will keep going, but it may not work.&quot;
++ $ECHO &quot;&quot;
++ ;;
++
++2.3.7|2.3.8|2.3.9)
++ $ECHO &quot;&quot;
++ $ECHO &quot;*** Warning. Your version of pppd is $PPPD_VERSION. You will&quot;
++ $ECHO &quot;*** not be able to use connect-on-demand. Upgrade to pppd&quot;
++ $ECHO &quot;*** 2.3.10 or newer if you need connect-on-demand.&quot;
++ $ECHO &quot;&quot;
++ ;;
++
++2*|3*|4*|5*|6*|7*|8*|9*)
++ ;;
++
++*)
++ $ECHO &quot;&quot;
++ $ECHO &quot;*** Oops. I cannot figure out what version of pppd you have.&quot;
++ $ECHO &quot;*** All I got back was '$PPPD_VERSION'&quot;
++ $ECHO &quot;*** I will keep going, but it may not work.&quot;
++ $ECHO &quot;&quot;
++ ;;
++esac
++
++dnl Figure out packing order of structures
++$ECHO -n &quot;checking packing order of bit fields... &quot;
++AC_TRY_RUN([
++union foo {
++ struct bar {
++ unsigned int ver:4;
++ unsigned int type:4;
++ } bb;
++ unsigned char baz;
++};
++
++int
++main(void)
++{
++ union foo x;
++ x.bb.ver = 1;
++ x.bb.type = 2;
++ if (x.baz == 0x21) {
++ return 1;
++ } else if (x.baz == 0x12) {
++ return 0;
++ } else {
++ return 2;
++ }
++}], PACK=normal, PACK=rev)
++
++if test &quot;$PACK&quot; = &quot;rev&quot; ; then
++ $ECHO &quot;reversed&quot;
++ AC_DEFINE(PACK_BITFIELDS_REVERSED)
++else
++ $ECHO &quot;normal&quot;
++fi
++
++# Sigh... got to fix this up for tcl
++test &quot;x$prefix&quot; = xNONE &amp;&amp; prefix=$ac_default_prefix
++# Let make expand exec_prefix.
++test &quot;x$exec_prefix&quot; = xNONE &amp;&amp; exec_prefix='${prefix}'
++
++# Fully resolve WRAPPER for Tcl script.
++WRAPPER=${sbindir}/pppoe-wrapper
++eval &quot;WRAPPER=${WRAPPER}&quot;
++eval &quot;WRAPPER=${WRAPPER}&quot;
++AC_SUBST(WRAPPER)
++
++# Determine what targets to build
++TARGETS=&quot;pppoe pppoe-server&quot;
++
++# pppoe-sniff is built only on Linux and Solaris
++if test &quot;$ac_cv_header_linux_if_packet_h&quot; = &quot;yes&quot; -o &quot;$ac_cv_header_sys_dlpi_h&quot; = &quot;yes&quot; ; then
++ TARGETS=&quot;$TARGETS pppoe-sniff&quot;
++fi
++
++# pppoe-relay is built only on Linux
++if test &quot;$ac_cv_header_linux_if_packet_h&quot; = &quot;yes&quot; ; then
++ TARGETS=&quot;$TARGETS pppoe-relay&quot;
++fi
++
++# plugin is built only if we have kernel support
++if test -n &quot;$LINUX_KERNELMODE_PLUGIN&quot; ; then
++ TARGETS=&quot;$TARGETS $LINUX_KERNELMODE_PLUGIN&quot;
++fi
++
++AC_SUBST(TARGETS)
++
++AC_OUTPUT(Makefile ../scripts/adsl-connect ../scripts/adsl-start ../scripts/adsl-stop ../scripts/adsl-init ../scripts/adsl-init-suse ../scripts/adsl-init-turbolinux ../scripts/adsl-setup ../gui/Makefile ../gui/tkpppoe)
++
++$ECHO &quot;&quot;
++$ECHO &quot;On this platform, the following targets will be built:&quot;
++$ECHO &quot; $TARGETS&quot;
++$ECHO &quot;&quot;
++$ECHO &quot;Type 'make' to compile the software.&quot;
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/src/debug.c
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/src/debug.c (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/src/debug.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,143 @@
++/***********************************************************************
++*
++* debug.c
++*
++* Implementation of user-space PPPoE redirector for Linux.
++*
++* Functions for printing debugging information
++*
++* Copyright (C) 2000 by Roaring Penguin Software Inc.
++*
++* This program may be distributed according to the terms of the GNU
++* General Public License, version 2 or (at your option) any later version.
++*
++***********************************************************************/
++
++static char const RCSID[] =
++&quot;$Id: debug.c 195724 2001-06-11 13:49:39Z gc $&quot;;
++
++#include &quot;pppoe.h&quot;
++#include &lt;sys/time.h&gt;
++#include &lt;time.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;ctype.h&gt;
++
++/**********************************************************************
++*%FUNCTION: dumpHex
++*%ARGUMENTS:
++* fp -- file to dump to
++* buf -- buffer to dump
++* len -- length of data
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Dumps buffer to fp in an easy-to-read format
++***********************************************************************/
++void
++dumpHex(FILE *fp, unsigned char const *buf, int len)
++{
++ int i;
++ int base;
++
++ if (!fp) return;
++
++ /* do NOT dump PAP packets */
++ if (len &gt;= 2 &amp;&amp; buf[0] == 0xC0 &amp;&amp; buf[1] == 0x23) {
++ fprintf(fp, &quot;(PAP Authentication Frame -- Contents not dumped)\n&quot;);
++ return;
++ }
++
++ for (base=0; base&lt;len; base += 16) {
++ for (i=base; i&lt;base+16; i++) {
++ if (i &lt; len) {
++ fprintf(fp, &quot;%02x &quot;, (unsigned) buf[i]);
++ } else {
++ fprintf(fp, &quot; &quot;);
++ }
++ }
++ fprintf(fp, &quot; &quot;);
++ for (i=base; i&lt;base+16; i++) {
++ if (i &lt; len) {
++ if (isprint(buf[i])) {
++ fprintf(fp, &quot;%c&quot;, buf[i]);
++ } else {
++ fprintf(fp, &quot;.&quot;);
++ }
++ } else {
++ break;
++ }
++ }
++ fprintf(fp, &quot;\n&quot;);
++ }
++}
++
++/**********************************************************************
++*%FUNCTION: dumpPacket
++*%ARGUMENTS:
++* fp -- file to dump to
++* packet -- a PPPoE packet
++* dir -- either SENT or RCVD
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Dumps the PPPoE packet to fp in an easy-to-read format
++***********************************************************************/
++void
++dumpPacket(FILE *fp, PPPoEPacket *packet, char const *dir)
++{
++ int len = ntohs(packet-&gt;length);
++
++ /* Sheesh... printing times is a pain... */
++ struct timeval tv;
++ time_t now;
++ int millisec;
++ struct tm *lt;
++ char timebuf[256];
++
++ UINT16_t type = etherType(packet);
++ if (!fp) return;
++ gettimeofday(&amp;tv, NULL);
++ now = (time_t) tv.tv_sec;
++ millisec = tv.tv_usec / 1000;
++ lt = localtime(&amp;now);
++ strftime(timebuf, 256, &quot;%H:%M:%S&quot;, lt);
++ fprintf(fp, &quot;%s.%03d %s PPPoE &quot;, timebuf, millisec, dir);
++ if (type == Eth_PPPOE_Discovery) {
++ fprintf(fp, &quot;Discovery (%x) &quot;, (unsigned) type);
++ } else if (type == Eth_PPPOE_Session) {
++ fprintf(fp, &quot;Session (%x) &quot;, (unsigned) type);
++ } else {
++ fprintf(fp, &quot;Unknown (%x) &quot;, (unsigned) type);
++ }
++
++ switch(packet-&gt;code) {
++ case CODE_PADI: fprintf(fp, &quot;PADI &quot;); break;
++ case CODE_PADO: fprintf(fp, &quot;PADO &quot;); break;
++ case CODE_PADR: fprintf(fp, &quot;PADR &quot;); break;
++ case CODE_PADS: fprintf(fp, &quot;PADS &quot;); break;
++ case CODE_PADT: fprintf(fp, &quot;PADT &quot;); break;
++ case CODE_SESS: fprintf(fp, &quot;SESS &quot;); break;
++ }
++
++ fprintf(fp, &quot;sess-id %d length %d\n&quot;,
++ (int) ntohs(packet-&gt;session),
++ len);
++
++ /* Ugly... I apologize... */
++ fprintf(fp,
++ &quot;SourceAddr %02x:%02x:%02x:%02x:%02x:%02x &quot;
++ &quot;DestAddr %02x:%02x:%02x:%02x:%02x:%02x\n&quot;,
++ (unsigned) packet-&gt;ethHdr.h_source[0],
++ (unsigned) packet-&gt;ethHdr.h_source[1],
++ (unsigned) packet-&gt;ethHdr.h_source[2],
++ (unsigned) packet-&gt;ethHdr.h_source[3],
++ (unsigned) packet-&gt;ethHdr.h_source[4],
++ (unsigned) packet-&gt;ethHdr.h_source[5],
++ (unsigned) packet-&gt;ethHdr.h_dest[0],
++ (unsigned) packet-&gt;ethHdr.h_dest[1],
++ (unsigned) packet-&gt;ethHdr.h_dest[2],
++ (unsigned) packet-&gt;ethHdr.h_dest[3],
++ (unsigned) packet-&gt;ethHdr.h_dest[4],
++ (unsigned) packet-&gt;ethHdr.h_dest[5]);
++ dumpHex(fp, packet-&gt;payload, ntohs(packet-&gt;length));
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/src/debug.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/src/discovery.c
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/src/discovery.c (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/src/discovery.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,629 @@
++/***********************************************************************
++*
++* discovery.c
++*
++* Perform PPPoE discovery
++*
++* Copyright (C) 1999 by Roaring Penguin Software Inc.
++*
++***********************************************************************/
++
++static char const RCSID[] =
++&quot;$Id: discovery.c 195724 2001-06-11 13:49:39Z gc $&quot;;
++
++#include &quot;pppoe.h&quot;
++
++#ifdef HAVE_SYSLOG_H
++#include &lt;syslog.h&gt;
++#endif
++
++#include &lt;string.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;errno.h&gt;
++
++#ifdef HAVE_SYS_TIME_H
++#include &lt;sys/time.h&gt;
++#endif
++
++#ifdef HAVE_SYS_UIO_H
++#include &lt;sys/uio.h&gt;
++#endif
++
++#ifdef HAVE_UNISTD_H
++#include &lt;unistd.h&gt;
++#endif
++
++#ifdef USE_LINUX_PACKET
++#include &lt;sys/ioctl.h&gt;
++#include &lt;fcntl.h&gt;
++#endif
++
++#include &lt;signal.h&gt;
++
++/**********************************************************************
++*%FUNCTION: parseForHostUniq
++*%ARGUMENTS:
++* type -- tag type
++* len -- tag length
++* data -- tag data.
++* extra -- user-supplied pointer. This is assumed to be a pointer to int.
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* If a HostUnique tag is found which matches our PID, sets *extra to 1.
++***********************************************************************/
++void
++parseForHostUniq(UINT16_t type, UINT16_t len, unsigned char *data,
++ void *extra)
++{
++ int *val = (int *) extra;
++ if (type == TAG_HOST_UNIQ &amp;&amp; len == sizeof(pid_t)) {
++ pid_t tmp;
++ memcpy(&amp;tmp, data, len);
++ if (tmp == getpid()) {
++ *val = 1;
++ }
++ }
++}
++
++/**********************************************************************
++*%FUNCTION: packetIsForMe
++*%ARGUMENTS:
++* conn -- PPPoE connection info
++* packet -- a received PPPoE packet
++*%RETURNS:
++* 1 if packet is for this PPPoE daemon; 0 otherwise.
++*%DESCRIPTION:
++* If we are using the Host-Unique tag, verifies that packet contains
++* our unique identifier.
++***********************************************************************/
++int
++packetIsForMe(PPPoEConnection *conn, PPPoEPacket *packet)
++{
++ int forMe = 0;
++
++ /* If we're not using the Host-Unique tag, then accept the packet */
++ if (!conn-&gt;useHostUniq) return 1;
++
++ parsePacket(packet, parseForHostUniq, &amp;forMe);
++ return forMe;
++}
++
++/**********************************************************************
++*%FUNCTION: parsePADOTags
++*%ARGUMENTS:
++* type -- tag type
++* len -- tag length
++* data -- tag data
++* extra -- extra user data. Should point to a PacketCriteria structure
++* which gets filled in according to selected AC name and service
++* name.
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Picks interesting tags out of a PADO packet
++***********************************************************************/
++void
++parsePADOTags(UINT16_t type, UINT16_t len, unsigned char *data,
++ void *extra)
++{
++ struct PacketCriteria *pc = (struct PacketCriteria *) extra;
++ PPPoEConnection *conn = pc-&gt;conn;
++ int i;
++
++ switch(type) {
++ case TAG_AC_NAME:
++ if (conn-&gt;printACNames) {
++ printf(&quot;Access-Concentrator: %.*s\n&quot;, (int) len, data);
++ }
++ if (conn-&gt;acName &amp;&amp; len == strlen(conn-&gt;acName) &amp;&amp;
++ !strncmp((char *) data, conn-&gt;acName, len)) {
++ pc-&gt;acNameOK = 1;
++ }
++ break;
++ case TAG_SERVICE_NAME:
++ if (conn-&gt;printACNames &amp;&amp; len &gt; 0) {
++ printf(&quot; Service-Name: %.*s\n&quot;, (int) len, data);
++ }
++ if (conn-&gt;serviceName &amp;&amp; len == strlen(conn-&gt;serviceName) &amp;&amp;
++ !strncmp((char *) data, conn-&gt;serviceName, len)) {
++ pc-&gt;serviceNameOK = 1;
++ }
++ break;
++ case TAG_AC_COOKIE:
++ if (conn-&gt;printACNames) {
++ printf(&quot;Got a cookie:&quot;);
++ /* Print first 20 bytes of cookie */
++ for (i=0; i&lt;len &amp;&amp; i &lt; 20; i++) {
++ printf(&quot; %02x&quot;, (unsigned) data[i]);
++ }
++ if (i &lt; len) printf(&quot;...&quot;);
++ printf(&quot;\n&quot;);
++ }
++ conn-&gt;cookie.type = htons(type);
++ conn-&gt;cookie.length = htons(len);
++ memcpy(conn-&gt;cookie.payload, data, len);
++ break;
++ case TAG_RELAY_SESSION_ID:
++ if (conn-&gt;printACNames) {
++ printf(&quot;Got a Relay-ID:&quot;);
++ /* Print first 20 bytes of relay ID */
++ for (i=0; i&lt;len &amp;&amp; i &lt; 20; i++) {
++ printf(&quot; %02x&quot;, (unsigned) data[i]);
++ }
++ if (i &lt; len) printf(&quot;...&quot;);
++ printf(&quot;\n&quot;);
++ }
++ conn-&gt;relayId.type = htons(type);
++ conn-&gt;relayId.length = htons(len);
++ memcpy(conn-&gt;relayId.payload, data, len);
++ break;
++ case TAG_SERVICE_NAME_ERROR:
++ if (conn-&gt;printACNames) {
++ printf(&quot;Got a Service-Name-Error tag: %.*s\n&quot;, (int) len, data);
++ } else {
++ syslog(LOG_ERR, &quot;PADO: Service-Name-Error: %.*s&quot;, (int) len, data);
++ exit(1);
++ }
++ break;
++ case TAG_AC_SYSTEM_ERROR:
++ if (conn-&gt;printACNames) {
++ printf(&quot;Got a System-Error tag: %.*s\n&quot;, (int) len, data);
++ } else {
++ syslog(LOG_ERR, &quot;PADO: System-Error: %.*s&quot;, (int) len, data);
++ exit(1);
++ }
++ break;
++ case TAG_GENERIC_ERROR:
++ if (conn-&gt;printACNames) {
++ printf(&quot;Got a Generic-Error tag: %.*s\n&quot;, (int) len, data);
++ } else {
++ syslog(LOG_ERR, &quot;PADO: Generic-Error: %.*s&quot;, (int) len, data);
++ exit(1);
++ }
++ break;
++ }
++}
++
++/**********************************************************************
++*%FUNCTION: parsePADSTags
++*%ARGUMENTS:
++* type -- tag type
++* len -- tag length
++* data -- tag data
++* extra -- extra user data (pointer to PPPoEConnection structure)
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Picks interesting tags out of a PADS packet
++***********************************************************************/
++void
++parsePADSTags(UINT16_t type, UINT16_t len, unsigned char *data,
++ void *extra)
++{
++ PPPoEConnection *conn = (PPPoEConnection *) extra;
++ switch(type) {
++ case TAG_SERVICE_NAME:
++ syslog(LOG_DEBUG, &quot;PADS: Service-Name: '%.*s'&quot;, (int) len, data);
++ break;
++ case TAG_SERVICE_NAME_ERROR:
++ syslog(LOG_ERR, &quot;PADS: Service-Name-Error: %.*s&quot;, (int) len, data);
++ fprintf(stderr, &quot;PADS: Service-Name-Error: %.*s\n&quot;, (int) len, data);
++ exit(1);
++ case TAG_AC_SYSTEM_ERROR:
++ syslog(LOG_ERR, &quot;PADS: System-Error: %.*s&quot;, (int) len, data);
++ fprintf(stderr, &quot;PADS: System-Error: %.*s\n&quot;, (int) len, data);
++ exit(1);
++ case TAG_GENERIC_ERROR:
++ syslog(LOG_ERR, &quot;PADS: Generic-Error: %.*s&quot;, (int) len, data);
++ fprintf(stderr, &quot;PADS: Generic-Error: %.*s\n&quot;, (int) len, data);
++ exit(1);
++ case TAG_RELAY_SESSION_ID:
++ conn-&gt;relayId.type = htons(type);
++ conn-&gt;relayId.length = htons(len);
++ memcpy(conn-&gt;relayId.payload, data, len);
++ break;
++ }
++}
++
++/***********************************************************************
++*%FUNCTION: sendPADI
++*%ARGUMENTS:
++* conn -- PPPoEConnection structure
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Sends a PADI packet
++***********************************************************************/
++void
++sendPADI(PPPoEConnection *conn)
++{
++ PPPoEPacket packet;
++ unsigned char *cursor = packet.payload;
++ PPPoETag *svc = (PPPoETag *) (&amp;packet.payload);
++ UINT16_t namelen = 0;
++ UINT16_t plen;
++
++ if (conn-&gt;serviceName) {
++ namelen = (UINT16_t) strlen(conn-&gt;serviceName);
++ }
++ plen = TAG_HDR_SIZE + namelen;
++ CHECK_ROOM(cursor, packet.payload, plen);
++
++ /* Set destination to Ethernet broadcast address */
++ memset(packet.ethHdr.h_dest, 0xFF, ETH_ALEN);
++ memcpy(packet.ethHdr.h_source, conn-&gt;myEth, ETH_ALEN);
++
++ packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
++ packet.ver = 1;
++ packet.type = 1;
++ packet.code = CODE_PADI;
++ packet.session = 0;
++
++ svc-&gt;type = TAG_SERVICE_NAME;
++ svc-&gt;length = htons(namelen);
++ CHECK_ROOM(cursor, packet.payload, namelen+TAG_HDR_SIZE);
++
++ if (conn-&gt;serviceName) {
++ memcpy(svc-&gt;payload, conn-&gt;serviceName, strlen(conn-&gt;serviceName));
++ }
++ cursor += namelen + TAG_HDR_SIZE;
++
++ /* If we're using Host-Uniq, copy it over */
++ if (conn-&gt;useHostUniq) {
++ PPPoETag hostUniq;
++ pid_t pid = getpid();
++ hostUniq.type = htons(TAG_HOST_UNIQ);
++ hostUniq.length = htons(sizeof(pid));
++ memcpy(hostUniq.payload, &amp;pid, sizeof(pid));
++ CHECK_ROOM(cursor, packet.payload, sizeof(pid) + TAG_HDR_SIZE);
++ memcpy(cursor, &amp;hostUniq, sizeof(pid) + TAG_HDR_SIZE);
++ cursor += sizeof(pid) + TAG_HDR_SIZE;
++ plen += sizeof(pid) + TAG_HDR_SIZE;
++ }
++
++ packet.length = htons(plen);
++
++ sendPacket(conn, conn-&gt;discoverySocket, &amp;packet, (int) (plen + HDR_SIZE));
++ if (conn-&gt;debugFile) {
++ dumpPacket(conn-&gt;debugFile, &amp;packet, &quot;SENT&quot;);
++ fprintf(conn-&gt;debugFile, &quot;\n&quot;);
++ fflush(conn-&gt;debugFile);
++ }
++}
++
++/**********************************************************************
++*%FUNCTION: waitForPADO
++*%ARGUMENTS:
++* conn -- PPPoEConnection structure
++* timeout -- how long to wait (in seconds)
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Waits for a PADO packet and copies useful information
++***********************************************************************/
++void
++waitForPADO(PPPoEConnection *conn, int timeout)
++{
++ fd_set readable;
++ int r;
++ struct timeval tv;
++ PPPoEPacket packet;
++ int len;
++
++ struct PacketCriteria pc;
++ pc.conn = conn;
++ pc.acNameOK = (conn-&gt;acName) ? 0 : 1;
++ pc.serviceNameOK = (conn-&gt;serviceName) ? 0 : 1;
++
++ do {
++ if (BPF_BUFFER_IS_EMPTY) {
++ tv.tv_sec = timeout;
++ tv.tv_usec = 0;
++
++ FD_ZERO(&amp;readable);
++ FD_SET(conn-&gt;discoverySocket, &amp;readable);
++
++ while(1) {
++ r = select(conn-&gt;discoverySocket+1, &amp;readable, NULL, NULL, &amp;tv);
++ if (r &gt;= 0 || errno != EINTR) break;
++ }
++ if (r &lt; 0) {
++ fatalSys(&quot;select (waitForPADO)&quot;);
++ }
++ if (r == 0) return; /* Timed out */
++ }
++
++ /* Get the packet */
++ receivePacket(conn-&gt;discoverySocket, &amp;packet, &amp;len);
++
++ /* Check length */
++ if (ntohs(packet.length) + HDR_SIZE &gt; len) {
++ syslog(LOG_ERR, &quot;Bogus PPPoE length field (%u)&quot;,
++ (unsigned int) ntohs(packet.length));
++ continue;
++ }
++
++#ifdef USE_BPF
++ /* If it's not a Discovery packet, loop again */
++ if (etherType(&amp;packet) != Eth_PPPOE_Discovery) continue;
++#endif
++
++ if (conn-&gt;debugFile) {
++ dumpPacket(conn-&gt;debugFile, &amp;packet, &quot;RCVD&quot;);
++ fprintf(conn-&gt;debugFile, &quot;\n&quot;);
++ fflush(conn-&gt;debugFile);
++ }
++ /* If it's not for us, loop again */
++ if (!packetIsForMe(conn, &amp;packet)) continue;
++
++ if (packet.code == CODE_PADO) {
++ if (NOT_UNICAST(packet.ethHdr.h_source)) {
++ printErr(&quot;Ignoring PADO packet from non-unicast MAC address&quot;);
++ continue;
++ }
++ conn-&gt;numPADOs++;
++ if (conn-&gt;printACNames) {
++ printf(&quot;--------------------------------------------------\n&quot;);
++ }
++ parsePacket(&amp;packet, parsePADOTags, &amp;pc);
++ if (pc.acNameOK &amp;&amp; pc.serviceNameOK) {
++ memcpy(conn-&gt;peerEth, packet.ethHdr.h_source, ETH_ALEN);
++ if (conn-&gt;printACNames) {
++ printf(&quot;AC-Ethernet-Address: %02x:%02x:%02x:%02x:%02x:%02x\n&quot;,
++ (unsigned) conn-&gt;peerEth[0],
++ (unsigned) conn-&gt;peerEth[1],
++ (unsigned) conn-&gt;peerEth[2],
++ (unsigned) conn-&gt;peerEth[3],
++ (unsigned) conn-&gt;peerEth[4],
++ (unsigned) conn-&gt;peerEth[5]);
++ continue;
++ }
++ conn-&gt;discoveryState = STATE_RECEIVED_PADO;
++ break;
++ }
++ }
++ } while (conn-&gt;discoveryState != STATE_RECEIVED_PADO);
++}
++
++/***********************************************************************
++*%FUNCTION: sendPADR
++*%ARGUMENTS:
++* conn -- PPPoE connection structur
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Sends a PADR packet
++***********************************************************************/
++void
++sendPADR(PPPoEConnection *conn)
++{
++ PPPoEPacket packet;
++ PPPoETag *svc = (PPPoETag *) packet.payload;
++ unsigned char *cursor = packet.payload;
++
++ UINT16_t namelen = 0;
++ UINT16_t plen;
++
++ if (conn-&gt;serviceName) {
++ namelen = (UINT16_t) strlen(conn-&gt;serviceName);
++ }
++ plen = TAG_HDR_SIZE + namelen;
++ CHECK_ROOM(cursor, packet.payload, plen);
++
++ memcpy(packet.ethHdr.h_dest, conn-&gt;peerEth, ETH_ALEN);
++ memcpy(packet.ethHdr.h_source, conn-&gt;myEth, ETH_ALEN);
++
++ packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
++ packet.ver = 1;
++ packet.type = 1;
++ packet.code = CODE_PADR;
++ packet.session = 0;
++
++ svc-&gt;type = TAG_SERVICE_NAME;
++ svc-&gt;length = htons(namelen);
++ if (conn-&gt;serviceName) {
++ memcpy(svc-&gt;payload, conn-&gt;serviceName, namelen);
++ }
++ cursor += namelen + TAG_HDR_SIZE;
++
++ /* If we're using Host-Uniq, copy it over */
++ if (conn-&gt;useHostUniq) {
++ PPPoETag hostUniq;
++ pid_t pid = getpid();
++ hostUniq.type = htons(TAG_HOST_UNIQ);
++ hostUniq.length = htons(sizeof(pid));
++ memcpy(hostUniq.payload, &amp;pid, sizeof(pid));
++ CHECK_ROOM(cursor, packet.payload, sizeof(pid)+TAG_HDR_SIZE);
++ memcpy(cursor, &amp;hostUniq, sizeof(pid) + TAG_HDR_SIZE);
++ cursor += sizeof(pid) + TAG_HDR_SIZE;
++ plen += sizeof(pid) + TAG_HDR_SIZE;
++ }
++
++ /* Copy cookie and relay-ID if needed */
++ if (conn-&gt;cookie.type) {
++ CHECK_ROOM(cursor, packet.payload,
++ ntohs(conn-&gt;cookie.length) + TAG_HDR_SIZE);
++ memcpy(cursor, &amp;conn-&gt;cookie, ntohs(conn-&gt;cookie.length) + TAG_HDR_SIZE);
++ cursor += ntohs(conn-&gt;cookie.length) + TAG_HDR_SIZE;
++ plen += ntohs(conn-&gt;cookie.length) + TAG_HDR_SIZE;
++ }
++
++ if (conn-&gt;relayId.type) {
++ CHECK_ROOM(cursor, packet.payload,
++ ntohs(conn-&gt;relayId.length) + TAG_HDR_SIZE);
++ memcpy(cursor, &amp;conn-&gt;relayId, ntohs(conn-&gt;relayId.length) + TAG_HDR_SIZE);
++ cursor += ntohs(conn-&gt;relayId.length) + TAG_HDR_SIZE;
++ plen += ntohs(conn-&gt;relayId.length) + TAG_HDR_SIZE;
++ }
++
++ packet.length = htons(plen);
++ sendPacket(conn, conn-&gt;discoverySocket, &amp;packet, (int) (plen + HDR_SIZE));
++ if (conn-&gt;debugFile) {
++ dumpPacket(conn-&gt;debugFile, &amp;packet, &quot;SENT&quot;);
++ fprintf(conn-&gt;debugFile, &quot;\n&quot;);
++ fflush(conn-&gt;debugFile);
++ }
++}
++
++/**********************************************************************
++*%FUNCTION: waitForPADS
++*%ARGUMENTS:
++* conn -- PPPoE connection info
++* timeout -- how long to wait (in seconds)
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Waits for a PADS packet and copies useful information
++***********************************************************************/
++void
++waitForPADS(PPPoEConnection *conn, int timeout)
++{
++ fd_set readable;
++ int r;
++ struct timeval tv;
++ PPPoEPacket packet;
++ int len;
++
++ do {
++ if (BPF_BUFFER_IS_EMPTY) {
++ tv.tv_sec = timeout;
++ tv.tv_usec = 0;
++
++ FD_ZERO(&amp;readable);
++ FD_SET(conn-&gt;discoverySocket, &amp;readable);
++
++ while(1) {
++ r = select(conn-&gt;discoverySocket+1, &amp;readable, NULL, NULL, &amp;tv);
++ if (r &gt;= 0 || errno != EINTR) break;
++ }
++ if (r &lt; 0) {
++ fatalSys(&quot;select (waitForPADS)&quot;);
++ }
++ if (r == 0) return;
++ }
++
++ /* Get the packet */
++ receivePacket(conn-&gt;discoverySocket, &amp;packet, &amp;len);
++
++ /* Check length */
++ if (ntohs(packet.length) + HDR_SIZE &gt; len) {
++ syslog(LOG_ERR, &quot;Bogus PPPoE length field (%u)&quot;,
++ (unsigned int) ntohs(packet.length));
++ continue;
++ }
++
++#ifdef USE_BPF
++ /* If it's not a Discovery packet, loop again */
++ if (etherType(&amp;packet) != Eth_PPPOE_Discovery) continue;
++#endif
++ if (conn-&gt;debugFile) {
++ dumpPacket(conn-&gt;debugFile, &amp;packet, &quot;RCVD&quot;);
++ fprintf(conn-&gt;debugFile, &quot;\n&quot;);
++ fflush(conn-&gt;debugFile);
++ }
++
++ /* If it's not from the AC, it's not for me */
++ if (memcmp(packet.ethHdr.h_source, conn-&gt;peerEth, ETH_ALEN)) continue;
++
++ /* If it's not for us, loop again */
++ if (!packetIsForMe(conn, &amp;packet)) continue;
++
++ /* Is it PADS? */
++ if (packet.code == CODE_PADS) {
++ /* Parse for goodies */
++ parsePacket(&amp;packet, parsePADSTags, conn);
++ conn-&gt;discoveryState = STATE_SESSION;
++ break;
++ }
++ } while (conn-&gt;discoveryState != STATE_SESSION);
++
++ /* Don't bother with ntohs; we'll just end up converting it back... */
++ conn-&gt;session = packet.session;
++
++ syslog(LOG_INFO, &quot;PPP session is %d&quot;, (int) ntohs(conn-&gt;session));
++
++ /* RFC 2516 says session id MUST NOT be zero or 0xFFFF */
++ if (ntohs(conn-&gt;session) == 0 || ntohs(conn-&gt;session) == 0xFFFF) {
++ syslog(LOG_ERR, &quot;Access concentrator used a session value of %x -- the AC is violating RFC 2516&quot;, (unsigned int) ntohs(conn-&gt;session));
++ }
++}
++
++/**********************************************************************
++*%FUNCTION: discovery
++*%ARGUMENTS:
++* conn -- PPPoE connection info structure
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Performs the PPPoE discovery phase
++***********************************************************************/
++void
++discovery(PPPoEConnection *conn)
++{
++ int padiAttempts = 0;
++ int padrAttempts = 0;
++ int timeout = PADI_TIMEOUT;
++
++ /* Skip discovery and don't open discovery socket? */
++ if (conn-&gt;skipDiscovery &amp;&amp; conn-&gt;noDiscoverySocket) {
++ conn-&gt;discoveryState = STATE_SESSION;
++ return;
++ }
++
++ conn-&gt;discoverySocket =
++ openInterface(conn-&gt;ifName, Eth_PPPOE_Discovery, conn-&gt;myEth);
++
++ /* Skip discovery? */
++ if (conn-&gt;skipDiscovery) {
++ conn-&gt;discoveryState = STATE_SESSION;
++ if (conn-&gt;killSession) {
++ sendPADT(conn, &quot;RP-PPPoE: Session killed manually&quot;);
++ exit(0);
++ }
++ return;
++ }
++
++ do {
++ padiAttempts++;
++ if (padiAttempts &gt; MAX_PADI_ATTEMPTS) {
++ rp_fatal(&quot;Timeout waiting for PADO packets&quot;);
++ }
++ sendPADI(conn);
++ conn-&gt;discoveryState = STATE_SENT_PADI;
++ waitForPADO(conn, timeout);
++
++ /* If we're just probing for access concentrators, don't do
++ exponential backoff. This reduces the time for an unsuccessful
++ probe to 15 seconds. */
++ if (!conn-&gt;printACNames) {
++ timeout *= 2;
++ }
++ if (conn-&gt;printACNames &amp;&amp; conn-&gt;numPADOs) {
++ break;
++ }
++ } while (conn-&gt;discoveryState == STATE_SENT_PADI);
++
++ /* If we're only printing access concentrator names, we're done */
++ if (conn-&gt;printACNames) {
++ printf(&quot;--------------------------------------------------\n&quot;);
++ exit(0);
++ }
++
++ timeout = PADI_TIMEOUT;
++ do {
++ padrAttempts++;
++ if (padrAttempts &gt; MAX_PADI_ATTEMPTS) {
++ rp_fatal(&quot;Timeout waiting for PADS packets&quot;);
++ }
++ sendPADR(conn);
++ conn-&gt;discoveryState = STATE_SENT_PADR;
++ waitForPADS(conn, timeout);
++ timeout *= 2;
++ } while (conn-&gt;discoveryState == STATE_SENT_PADR);
++
++ /* We're done. */
++ conn-&gt;discoveryState = STATE_SESSION;
++ return;
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/src/discovery.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/src/if.c
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/src/if.c (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/src/if.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1092 @@
++/***********************************************************************
++*
++* if.c
++*
++* Implementation of user-space PPPoE redirector for Linux.
++*
++* Functions for opening a raw socket and reading/writing raw Ethernet frames.
++*
++* Copyright (C) 2000 by Roaring Penguin Software Inc.
++*
++* This program may be distributed according to the terms of the GNU
++* General Public License, version 2 or (at your option) any later version.
++*
++***********************************************************************/
++
++static char const RCSID[] =
++&quot;$Id: if.c 195724 2001-06-11 13:49:39Z gc $&quot;;
++
++#include &quot;pppoe.h&quot;
++
++#ifdef HAVE_UNISTD_H
++#include &lt;unistd.h&gt;
++#endif
++
++#ifdef HAVE_NETPACKET_PACKET_H
++#include &lt;netpacket/packet.h&gt;
++#elif defined(HAVE_LINUX_IF_PACKET_H)
++#include &lt;linux/if_packet.h&gt;
++#endif
++
++#ifdef HAVE_NET_ETHERNET_H
++#include &lt;net/ethernet.h&gt;
++#endif
++
++#ifdef HAVE_ASM_TYPES_H
++#include &lt;asm/types.h&gt;
++#endif
++
++#ifdef HAVE_SYS_IOCTL_H
++#include &lt;sys/ioctl.h&gt;
++#endif
++
++#ifdef HAVE_SYSLOG_H
++#include &lt;syslog.h&gt;
++#endif
++
++#include &lt;errno.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++
++#ifdef HAVE_NET_IF_ARP_H
++#include &lt;net/if_arp.h&gt;
++#endif
++
++#ifdef USE_DLPI
++
++#include &lt;limits.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/time.h&gt;
++#include &lt;sys/stream.h&gt;
++#include &lt;sys/stropts.h&gt;
++#include &lt;sys/dlpi.h&gt;
++#include &lt;sys/bufmod.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;signal.h&gt;
++#include &lt;stropts.h&gt;
++
++/* function declarations */
++
++void dlpromisconreq( int fd, u_long level);
++void dlinforeq(int fd);
++void dlunitdatareq(int fd, u_char *addrp, int addrlen, u_long minpri, u_long maxpri, u_char *datap, int datalen);
++void dlinfoack(int fd, char *bufp);
++void dlbindreq(int fd, u_long sap, u_long max_conind, u_long service_mode, u_long conn_mgmt, u_long xidtest);
++void dlattachreq(int fd, u_long ppa);
++void dlokack(int fd, char *bufp);
++void dlbindack(int fd, char *bufp);
++int strioctl(int fd, int cmd, int timout, int len, char *dp);
++void strgetmsg(int fd, struct strbuf *ctlp, struct strbuf *datap, int *flagsp, char *caller);
++void sigalrm(int sig);
++void expecting(int prim, union DL_primitives *dlp);
++char *dlprim(u_long prim);
++
++/* #define DL_DEBUG */
++
++static int dl_abssaplen;
++static int dl_saplen;
++static int dl_addrlen;
++
++#endif
++
++#ifdef USE_BPF
++#include &lt;net/bpf.h&gt;
++#include &lt;fcntl.h&gt;
++
++unsigned char *bpfBuffer; /* Packet filter buffer */
++int bpfLength = 0; /* Packet filter buffer length */
++int bpfSize = 0; /* Number of unread bytes in buffer */
++int bpfOffset = 0; /* Current offset in bpfBuffer */
++#endif
++
++/* Initialize frame types to RFC 2516 values. Some broken peers apparently
++ use different frame types... sigh... */
++
++UINT16_t Eth_PPPOE_Discovery = ETH_PPPOE_DISCOVERY;
++UINT16_t Eth_PPPOE_Session = ETH_PPPOE_SESSION;
++
++/**********************************************************************
++*%FUNCTION: etherType
++*%ARGUMENTS:
++* packet -- a received PPPoE packet
++*%RETURNS:
++* ethernet packet type (see /usr/include/net/ethertypes.h)
++*%DESCRIPTION:
++* Checks the ethernet packet header to determine its type.
++* We should only be receveing DISCOVERY and SESSION types if the BPF
++* is set up correctly. Logs an error if an unexpected type is received.
++* Note that the ethernet type names come from &quot;pppoe.h&quot; and the packet
++* packet structure names use the LINUX dialect to maintain consistency
++* with the rest of this file. See the BSD section of &quot;pppoe.h&quot; for
++* translations of the data structure names.
++***********************************************************************/
++UINT16_t
++etherType(PPPoEPacket *packet)
++{
++ UINT16_t type = (UINT16_t) ntohs(packet-&gt;ethHdr.h_proto);
++ if (type != Eth_PPPOE_Discovery &amp;&amp; type != Eth_PPPOE_Session) {
++ syslog(LOG_ERR, &quot;Invalid ether type 0x%x&quot;, type);
++ }
++ return type;
++}
++
++#ifdef USE_BPF
++/**********************************************************************
++*%FUNCTION: getHWaddr
++*%ARGUMENTS:
++* ifname -- name of interface
++* hwaddr -- buffer for ehthernet address
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Locates the Ethernet hardware address for an interface.
++***********************************************************************/
++void
++getHWaddr(int sock, char const *ifname, unsigned char *hwaddr)
++{
++ char inbuf[8192];
++ const struct sockaddr_dl *sdl;
++ struct ifconf ifc;
++ struct ifreq ifreq, *ifr;
++ int i;
++ int found = 0;
++
++ ifc.ifc_len = sizeof(inbuf);
++ ifc.ifc_buf = inbuf;
++ if (ioctl(sock, SIOCGIFCONF, &amp;ifc) &lt; 0) {
++ fatalSys(&quot;SIOCGIFCONF&quot;);
++ }
++ ifr = ifc.ifc_req;
++ ifreq.ifr_name[0] = '\0';
++ for (i = 0; i &lt; ifc.ifc_len; ) {
++ ifr = (struct ifreq *)((caddr_t)ifc.ifc_req + i);
++ i += sizeof(ifr-&gt;ifr_name) +
++ (ifr-&gt;ifr_addr.sa_len &gt; sizeof(struct sockaddr)
++ ? ifr-&gt;ifr_addr.sa_len
++ : sizeof(struct sockaddr));
++ if (ifr-&gt;ifr_addr.sa_family == AF_LINK) {
++ sdl = (const struct sockaddr_dl *) &amp;ifr-&gt;ifr_addr;
++ if ((sdl-&gt;sdl_type == IFT_ETHER) &amp;&amp;
++ (sdl-&gt;sdl_alen == ETH_ALEN) &amp;&amp;
++ !strncmp(ifname, ifr-&gt;ifr_name, sizeof(ifr-&gt;ifr_name))) {
++ if (found) {
++ char buffer[256];
++ sprintf(buffer, &quot;interface %.16s has more than one ethernet address&quot;, ifname);
++ rp_fatal(buffer);
++ } else {
++ found = 1;
++ memcpy(hwaddr, LLADDR(sdl), ETH_ALEN);
++ }
++ }
++ }
++ }
++ if (!found) {
++ char buffer[256];
++ sprintf(buffer, &quot;interface %.16s has no ethernet address&quot;, ifname);
++ rp_fatal(buffer);
++ }
++}
++
++/**********************************************************************
++*%FUNCTION: initFilter
++*%ARGUMENTS:
++* fd -- file descriptor of BSD device
++* type -- Ethernet frame type (0 for watch mode)
++* hwaddr -- buffer with ehthernet address
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Initializes the packet filter rules.
++***********************************************************************/
++void
++initFilter(int fd, UINT16_t type, unsigned char *hwaddr)
++{
++ /* Packet Filter Instructions:
++ * Note that the ethernet type names come from &quot;pppoe.h&quot; and are
++ * used here to maintain consistency with the rest of this file. */
++ static struct bpf_insn bpfRun[] = { /* run PPPoE */
++ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12), /* ethernet type */
++ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_SESSION, 5, 0),
++ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_DISCOVERY, 0, 9),
++ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0), /* first word of dest. addr */
++#define PPPOE_BCAST_CMPW 4 /* offset of word compare */
++ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 2),
++ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4), /* next 1/2 word of dest. */
++#define PPPOE_BCAST_CMPH 6 /* offset of 1/2 word compare */
++ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 4, 0),
++ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0), /* first word of dest. addr */
++#define PPPOE_FILTER_CMPW 8 /* offset of word compare */
++ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 3),
++ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4), /* next 1/2 word of dest. */
++#define PPPOE_FILTER_CMPH 10 /* offset of 1/rd compare */
++ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 1),
++ BPF_STMT(BPF_RET+BPF_K, (u_int) -1), /* keep packet */
++ BPF_STMT(BPF_RET+BPF_K, 0), /* drop packet */
++ };
++
++ /* Fix the potentially varying parts */
++ bpfRun[1].code = (u_short) BPF_JMP+BPF_JEQ+BPF_K;
++ bpfRun[1].jt = 5;
++ bpfRun[1].jf = 0;
++ bpfRun[1].k = Eth_PPPOE_Session;
++
++ bpfRun[2].code = (u_short) BPF_JMP+BPF_JEQ+BPF_K;
++ bpfRun[2].jt = 0;
++ bpfRun[2].jf = 9;
++ bpfRun[2].k = Eth_PPPOE_Discovery;
++
++ {
++ struct bpf_insn bpfInsn[sizeof(bpfRun) / sizeof(bpfRun[0])];
++ struct bpf_program bpfProgram;
++ memcpy(bpfInsn, bpfRun, sizeof(bpfRun));
++ bpfInsn[PPPOE_BCAST_CMPW].k = ((0xff &lt;&lt; 24) | (0xff &lt;&lt; 16) |
++ (0xff &lt;&lt; 8) | 0xff);
++ bpfInsn[PPPOE_BCAST_CMPH].k = ((0xff &lt;&lt; 8) | 0xff);
++ bpfInsn[PPPOE_FILTER_CMPW].k = ((hwaddr[0] &lt;&lt; 24) | (hwaddr[1] &lt;&lt; 16) |
++ (hwaddr[2] &lt;&lt; 8) | hwaddr[3]);
++ bpfInsn[PPPOE_FILTER_CMPH].k = ((hwaddr[4] &lt;&lt; 8) | hwaddr[5]);
++ bpfProgram.bf_len = (sizeof(bpfInsn) / sizeof(bpfInsn[0]));
++ bpfProgram.bf_insns = &amp;bpfInsn[0];
++
++ /* Apply the filter */
++ if (ioctl(fd, BIOCSETF, &amp;bpfProgram) &lt; 0) {
++ fatalSys(&quot;ioctl(BIOCSETF)&quot;);
++ }
++ }
++}
++
++/**********************************************************************
++*%FUNCTION: openInterface
++*%ARGUMENTS:
++* ifname -- name of interface
++* type -- Ethernet frame type (0 for any frame type)
++* hwaddr -- if non-NULL, set to the hardware address
++*%RETURNS:
++* A file descriptor for talking with the Ethernet card. Exits on error.
++* Note that the Linux version of this routine returns a socket instead.
++*%DESCRIPTION:
++* Opens a BPF on an interface for all PPPoE traffic (discovery and
++* session). If 'type' is 0, uses promiscuous mode to watch any PPPoE
++* traffic on this network.
++***********************************************************************/
++int
++openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
++{
++ static int fd = -1;
++ char bpfName[32];
++ u_int optval;
++ struct bpf_version bpf_ver;
++ struct ifreq ifr;
++ int sock;
++ int i;
++
++ /* BSD only opens one socket for both Discovery and Session packets */
++ if (fd &gt;= 0) {
++ return fd;
++ }
++
++ /* Find a free BPF device */
++ for (i = 0; i &lt; 256; i++) {
++ sprintf(bpfName, &quot;/dev/bpf%d&quot;, i);
++ if (((fd = open(bpfName, O_RDWR, 0)) &gt;= 0) ||
++ (errno != EBUSY)) {
++ break;
++ }
++ }
++ if (fd &lt; 0) {
++ switch (errno) {
++ case EACCES: /* permission denied */
++ {
++ char buffer[256];
++ sprintf(buffer, &quot;Cannot open %.32s -- pppoe must be run as root.&quot;, bpfName);
++ rp_fatal(buffer);
++ }
++ break;
++ case EBUSY:
++ case ENOENT: /* no such file */
++ if (i == 0) {
++ rp_fatal(&quot;No /dev/bpf* devices (check your kernel configuration for BPF support)&quot;);
++ } else {
++ rp_fatal(&quot;All /dev/bpf* devices are in use&quot;);
++ }
++ break;
++ }
++ fatalSys(bpfName);
++ }
++
++ if ((sock = socket(AF_LOCAL, SOCK_DGRAM, 0)) &lt; 0) {
++ fatalSys(&quot;socket&quot;);
++ }
++
++ /* Check that the interface is up */
++ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
++ if (ioctl(sock, SIOCGIFFLAGS, &amp;ifr) &lt; 0) {
++ fatalSys(&quot;ioctl(SIOCGIFFLAGS)&quot;);
++ }
++ if ((ifr.ifr_flags &amp; IFF_UP) == 0) {
++ char buffer[256];
++ sprintf(buffer, &quot;Interface %.16s is not up\n&quot;, ifname);
++ rp_fatal(buffer);
++ }
++
++ /* Fill in hardware address and initialize the packet filter rules */
++ if (hwaddr == NULL) {
++ rp_fatal(&quot;openInterface: no hwaddr arg.&quot;);
++ }
++ getHWaddr(sock, ifname, hwaddr);
++ initFilter(fd, type, hwaddr);
++
++ /* Sanity check on MTU -- apparently does not work on OpenBSD */
++#if !defined(__OpenBSD__)
++ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
++ if (ioctl(sock, SIOCGIFMTU, &amp;ifr) &lt; 0) {
++ fatalSys(&quot;ioctl(SIOCGIFMTU)&quot;);
++ }
++ if (ifr.ifr_mtu &lt; ETH_DATA_LEN) {
++ char buffer[256];
++ sprintf(buffer, &quot;Interface %.16s has MTU of %d -- should be %d. You may have serious connection problems.&quot;,
++ ifname, ifr.ifr_mtu, ETH_DATA_LEN);
++ printErr(buffer);
++ }
++#endif
++
++ /* done with the socket */
++ if (close(sock) &lt; 0) {
++ fatalSys(&quot;close&quot;);
++ }
++
++ /* Check the BPF version number */
++ if (ioctl(fd, BIOCVERSION, &amp;bpf_ver) &lt; 0) {
++ fatalSys(&quot;ioctl(BIOCVERSION)&quot;);
++ }
++ if ((bpf_ver.bv_major != BPF_MAJOR_VERSION) ||
++ (bpf_ver.bv_minor &lt; BPF_MINOR_VERSION)) {
++ char buffer[256];
++ sprintf(buffer, &quot;Unsupported BPF version: %d.%d (kernel: %d.%d)&quot;,
++ BPF_MAJOR_VERSION, BPF_MINOR_VERSION,
++ bpf_ver.bv_major, bpf_ver.bv_minor);
++ rp_fatal(buffer);
++ }
++
++ /* allocate a receive packet buffer */
++ if (ioctl(fd, BIOCGBLEN, &amp;bpfLength) &lt; 0) {
++ fatalSys(&quot;ioctl(BIOCGBLEN)&quot;);
++ }
++ if (!(bpfBuffer = (unsigned char *) malloc(bpfLength))) {
++ rp_fatal(&quot;malloc&quot;);
++ }
++
++ /* reads should return as soon as there is a packet available */
++ optval = 1;
++ if (ioctl(fd, BIOCIMMEDIATE, &amp;optval) &lt; 0) {
++ fatalSys(&quot;ioctl(BIOCIMMEDIATE)&quot;);
++ }
++
++ /* Bind the interface to the filter */
++ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
++ if (ioctl(fd, BIOCSETIF, &amp;ifr) &lt; 0) {
++ char buffer[256];
++ sprintf(buffer, &quot;ioctl(BIOCSETIF) can't select interface %.16s&quot;,
++ ifname);
++ rp_fatal(buffer);
++ }
++
++ syslog(LOG_INFO, &quot;Interface=%.16s HWaddr=%02X:%02X:%02X:%02X:%02X:%02X Device=%.32s Buffer size=%d&quot;,
++ ifname,
++ hwaddr[0], hwaddr[1], hwaddr[2],
++ hwaddr[3], hwaddr[4], hwaddr[5],
++ bpfName, bpfLength);
++ return fd;
++}
++
++#endif /* USE_BPF */
++
++#ifdef USE_LINUX_PACKET
++/**********************************************************************
++*%FUNCTION: openInterface
++*%ARGUMENTS:
++* ifname -- name of interface
++* type -- Ethernet frame type
++* hwaddr -- if non-NULL, set to the hardware address
++*%RETURNS:
++* A raw socket for talking to the Ethernet card. Exits on error.
++*%DESCRIPTION:
++* Opens a raw Ethernet socket
++***********************************************************************/
++int
++openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
++{
++ int optval=1;
++ int fd;
++ struct ifreq ifr;
++ int domain, stype;
++
++#ifdef HAVE_STRUCT_SOCKADDR_LL
++ struct sockaddr_ll sa;
++#else
++ struct sockaddr sa;
++#endif
++
++ memset(&amp;sa, 0, sizeof(sa));
++
++#ifdef HAVE_STRUCT_SOCKADDR_LL
++ domain = PF_PACKET;
++ stype = SOCK_RAW;
++#else
++ domain = PF_INET;
++ stype = SOCK_PACKET;
++#endif
++
++ if ((fd = socket(domain, stype, htons(type))) &lt; 0) {
++ /* Give a more helpful message for the common error case */
++ if (errno == EPERM) {
++ rp_fatal(&quot;Cannot create raw socket -- pppoe must be run as root.&quot;);
++ }
++ fatalSys(&quot;socket&quot;);
++ }
++
++ if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &amp;optval, sizeof(optval)) &lt; 0) {
++ fatalSys(&quot;setsockopt&quot;);
++ }
++
++ /* Fill in hardware address */
++ if (hwaddr) {
++ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
++ if (ioctl(fd, SIOCGIFHWADDR, &amp;ifr) &lt; 0) {
++ fatalSys(&quot;ioctl(SIOCGIFHWADDR)&quot;);
++ }
++ memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
++#ifdef ARPHRD_ETHER
++ if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
++ char buffer[256];
++ sprintf(buffer, &quot;Interface %.16s is not Ethernet&quot;, ifname);
++ rp_fatal(buffer);
++ }
++#endif
++ if (NOT_UNICAST(hwaddr)) {
++ char buffer[256];
++ sprintf(buffer,
++ &quot;Interface %.16s has broadcast/multicast MAC address??&quot;,
++ ifname);
++ rp_fatal(buffer);
++ }
++ }
++
++ /* Sanity check on MTU */
++ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
++ if (ioctl(fd, SIOCGIFMTU, &amp;ifr) &lt; 0) {
++ fatalSys(&quot;ioctl(SIOCGIFMTU)&quot;);
++ }
++ if (ifr.ifr_mtu &lt; ETH_DATA_LEN) {
++ char buffer[256];
++ sprintf(buffer, &quot;Interface %.16s has MTU of %d -- should be %d. You may have serious connection problems.&quot;,
++ ifname, ifr.ifr_mtu, ETH_DATA_LEN);
++ printErr(buffer);
++ }
++
++#ifdef HAVE_STRUCT_SOCKADDR_LL
++ /* Get interface index */
++ sa.sll_family = AF_PACKET;
++ sa.sll_protocol = htons(type);
++
++ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
++ if (ioctl(fd, SIOCGIFINDEX, &amp;ifr) &lt; 0) {
++ fatalSys(&quot;ioctl(SIOCFIGINDEX): Could not get interface index&quot;);
++ }
++ sa.sll_ifindex = ifr.ifr_ifindex;
++
++#else
++ strcpy(sa.sa_data, ifname);
++#endif
++
++ /* We're only interested in packets on specified interface */
++ if (bind(fd, (struct sockaddr *) &amp;sa, sizeof(sa)) &lt; 0) {
++ fatalSys(&quot;bind&quot;);
++ }
++
++ return fd;
++}
++
++#endif /* USE_LINUX */
++
++/***********************************************************************
++*%FUNCTION: sendPacket
++*%ARGUMENTS:
++* sock -- socket to send to
++* pkt -- the packet to transmit
++* size -- size of packet (in bytes)
++*%RETURNS:
++* 0 on success; -1 on failure
++*%DESCRIPTION:
++* Transmits a packet
++***********************************************************************/
++int
++sendPacket(PPPoEConnection *conn, int sock, PPPoEPacket *pkt, int size)
++{
++#if defined(USE_BPF)
++ if (write(sock, pkt, size) &lt; 0) {
++ sysErr(&quot;write (sendPacket)&quot;);
++ return -1;
++ }
++#elif defined(HAVE_STRUCT_SOCKADDR_LL)
++ if (send(sock, pkt, size, 0) &lt; 0) {
++ sysErr(&quot;send (sendPacket)&quot;);
++ return -1;
++ }
++#else
++#ifdef USE_DLPI
++
++#define ABS(x) ((x) &lt; 0 ? -(x) : (x))
++
++ u_char addr[MAXDLADDR];
++ u_char phys[MAXDLADDR];
++ u_char sap[MAXDLADDR];
++ u_char xmitbuf[MAXDLBUF];
++ int data_size;
++
++ short tmp_sap;
++
++ tmp_sap = htons(pkt-&gt;ethHdr.h_proto);
++ data_size = size - sizeof(struct ethhdr);
++
++ memcpy((char *)phys, (char *)pkt-&gt;ethHdr.h_dest, ETHERADDRL);
++ memcpy((char *)sap, (char *)&amp;tmp_sap, sizeof(ushort_t));
++ memcpy((char *)xmitbuf, (char *)pkt + sizeof(struct ethhdr), data_size);
++
++ if (dl_saplen &gt; 0) { /* order is sap+phys */
++ (void) memcpy((char*)addr, (char*)&amp;sap, dl_abssaplen);
++ (void) memcpy((char*)addr+dl_abssaplen, (char*)phys, ETHERADDRL);
++ } else { /* order is phys+sap */
++ (void) memcpy((char*)addr, (char*)phys, ETHERADDRL);
++ (void) memcpy((char*)addr+ETHERADDRL, (char*)&amp;sap, dl_abssaplen);
++ }
++
++#ifdef DL_DEBUG
++ printf(&quot;%02x:%02x:%02x:%02x:%02x:%02x %02x:%02x\n&quot;,
++ addr[0],addr[1],addr[2],addr[3],addr[4],addr[5],
++ addr[6],addr[7]);
++#endif
++
++ dlunitdatareq(sock, addr, dl_addrlen, 0, 0, xmitbuf, data_size);
++
++
++
++#else
++ struct sockaddr sa;
++
++ if (!conn) {
++ rp_fatal(&quot;relay and server not supported on Linux 2.0 kernels&quot;);
++ }
++ strcpy(sa.sa_data, conn-&gt;ifName);
++ if (sendto(sock, pkt, size, 0, &amp;sa, sizeof(sa)) &lt; 0) {
++ sysErr(&quot;sendto (sendPacket)&quot;);
++ return -1;
++ }
++#endif
++#endif
++ return 0;
++}
++
++#ifdef USE_BPF
++/***********************************************************************
++*%FUNCTION: clearPacketHeader
++*%ARGUMENTS:
++* pkt -- packet that needs its head clearing
++*%RETURNS:
++* nothing
++*%DESCRIPTION:
++* Clears a PPPoE packet header after a truncated packet has been
++* received. Insures that the packet will fail any integrity tests
++* and will be discarded by upper level routines. Also resets the
++* bpfSize and bpfOffset variables to force a new read on the next
++* call to receivePacket().
++***********************************************************************/
++void
++clearPacketHeader(PPPoEPacket *pkt)
++{
++ bpfSize = bpfOffset = 0;
++ memset(pkt, 0, HDR_SIZE);
++}
++#endif
++
++/***********************************************************************
++*%FUNCTION: receivePacket
++*%ARGUMENTS:
++* sock -- socket to read from
++* pkt -- place to store the received packet
++* size -- set to size of packet in bytes
++*%RETURNS:
++* &gt;= 0 if all OK; &lt; 0 if error
++*%DESCRIPTION:
++* Receives a packet
++***********************************************************************/
++int
++receivePacket(int sock, PPPoEPacket *pkt, int *size)
++{
++#ifdef USE_BPF
++ struct bpf_hdr hdr;
++ int seglen, copylen;
++
++ if (bpfSize &lt;= 0) {
++ bpfOffset = 0;
++ if ((bpfSize = read(sock, bpfBuffer, bpfLength)) &lt; 0) {
++ sysErr(&quot;read (receivePacket)&quot;);
++ return -1;
++ }
++ }
++ if (bpfSize &lt; sizeof(hdr)) {
++ syslog(LOG_ERR, &quot;Truncated bpf packet header: len=%d&quot;, bpfSize);
++ clearPacketHeader(pkt); /* resets bpfSize and bpfOffset */
++ return 0;
++ }
++ memcpy(&amp;hdr, bpfBuffer + bpfOffset, sizeof(hdr));
++ if (hdr.bh_caplen != hdr.bh_datalen) {
++ syslog(LOG_ERR, &quot;Truncated bpf packet: caplen=%d, datalen=%d&quot;,
++ hdr.bh_caplen, hdr.bh_datalen);
++ clearPacketHeader(pkt); /* resets bpfSize and bpfOffset */
++ return 0;
++ }
++ seglen = hdr.bh_hdrlen + hdr.bh_caplen;
++ if (seglen &gt; bpfSize) {
++ syslog(LOG_ERR, &quot;Truncated bpf packet: seglen=%d, bpfSize=%d&quot;,
++ seglen, bpfSize);
++ clearPacketHeader(pkt); /* resets bpfSize and bpfOffset */
++ return 0;
++ }
++ seglen = BPF_WORDALIGN(seglen);
++ *size = copylen = ((hdr.bh_caplen &lt; sizeof(PPPoEPacket)) ?
++ hdr.bh_caplen : sizeof(PPPoEPacket));
++ memcpy(pkt, bpfBuffer + bpfOffset + hdr.bh_hdrlen, copylen);
++ if (seglen &gt;= bpfSize) {
++ bpfSize = bpfOffset = 0;
++ } else {
++ bpfSize -= seglen;
++ bpfOffset += seglen;
++ }
++#else
++#ifdef USE_DLPI
++ struct strbuf data;
++ int flags = 0;
++ int retval;
++
++ data.buf = (char *) pkt;
++ data.maxlen = MAXDLBUF;
++ data.len = 0;
++
++ if ((retval = getmsg(sock, NULL, &amp;data, &amp;flags)) &lt; 0) {
++ sysErr(&quot;read (receivePacket)&quot;);
++ return -1;
++ }
++
++ *size = data.len;
++
++#else
++ if ((*size = recv(sock, pkt, sizeof(PPPoEPacket), 0)) &lt; 0) {
++ sysErr(&quot;recv (receivePacket)&quot;);
++ return -1;
++ }
++#endif
++#endif
++ return 0;
++}
++
++#ifdef USE_DLPI
++/**********************************************************************
++*%FUNCTION: openInterface
++*%ARGUMENTS:
++* ifname -- name of interface
++* type -- Ethernet frame type
++* hwaddr -- if non-NULL, set to the hardware address
++*%RETURNS:
++* A raw socket for talking to the Ethernet card. Exits on error.
++*%DESCRIPTION:
++* Opens a raw Ethernet socket
++***********************************************************************/
++int
++openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
++{
++ int fd;
++ long buf[MAXDLBUF];
++
++ union DL_primitives *dlp;
++
++ char base_dev[PATH_MAX];
++ int ppa;
++
++ if(strlen(ifname) &gt; PATH_MAX) {
++ rp_fatal(&quot;socket: string to long&quot;);
++ }
++
++ ppa = atoi(&amp;ifname[strlen(ifname)-1]);
++ strncpy(base_dev, ifname, PATH_MAX);
++ base_dev[strlen(base_dev)-1] = '\0';
++
++ if (( fd = open(base_dev, O_RDWR)) &lt; 0) {
++ /* Give a more helpful message for the common error case */
++ if (errno == EPERM) {
++ rp_fatal(&quot;Cannot create raw socket -- pppoe must be run as root.&quot;);
++ }
++ fatalSys(&quot;socket&quot;);
++ }
++
++ dlinforeq(fd);
++ dlinfoack(fd, (char *)buf);
++
++ dlp = (union DL_primitives*) buf;
++
++ dl_abssaplen = ABS(dlp-&gt;info_ack.dl_sap_length);
++ dl_saplen = dlp-&gt;info_ack.dl_sap_length;
++ if (ETHERADDRL != (dlp-&gt;info_ack.dl_addr_length - dl_abssaplen))
++ fatalSys(&quot;invalid destination physical address length&quot;);
++ dl_addrlen = dl_abssaplen + ETHERADDRL;
++
++ dlattachreq(fd, ppa);
++ dlokack(fd, (char *)buf);
++
++ dlbindreq(fd, type, 0, DL_CLDLS, 0, 0);
++ dlbindack(fd, (char *)buf);
++
++ if ( strioctl(fd, DLIOCRAW, -1, 0, NULL) &lt; 0 ) {
++ fatalSys(&quot;DLIOCRAW&quot;);
++ }
++
++ if (ioctl(fd, I_FLUSH, FLUSHR) &lt; 0) fatalSys(&quot;I_FLUSH&quot;);
++
++ return fd;
++}
++
++/* cloned from dlcommon.c */
++
++void dlpromisconreq(int fd, u_long level)
++{
++ dl_promiscon_req_t promiscon_req;
++ struct strbuf ctl;
++ int flags;
++
++ promiscon_req.dl_primitive = DL_PROMISCON_REQ;
++ promiscon_req.dl_level = level;
++
++ ctl.maxlen = 0;
++ ctl.len = sizeof (promiscon_req);
++ ctl.buf = (char *) &amp;promiscon_req;
++
++ flags = 0;
++
++ if (putmsg(fd, &amp;ctl, (struct strbuf*) NULL, flags) &lt; 0)
++ fatalSys(&quot;dlpromiscon: putmsg&quot;);
++
++}
++
++void dlinforeq(int fd)
++{
++ dl_info_req_t info_req;
++ struct strbuf ctl;
++ int flags;
++
++ info_req.dl_primitive = DL_INFO_REQ;
++
++ ctl.maxlen = 0;
++ ctl.len = sizeof (info_req);
++ ctl.buf = (char *) &amp;info_req;
++
++ flags = RS_HIPRI;
++
++ if (putmsg(fd, &amp;ctl, (struct strbuf*) NULL, flags) &lt; 0)
++ fatalSys(&quot;dlinforeq: putmsg&quot;);
++}
++
++void dlunitdatareq(int fd, u_char *addrp, int addrlen, u_long minpri, u_long maxpri, u_char *datap, int datalen)
++{
++ long buf[MAXDLBUF];
++ union DL_primitives *dlp;
++ struct strbuf data, ctl;
++
++ dlp = (union DL_primitives*) buf;
++
++ dlp-&gt;unitdata_req.dl_primitive = DL_UNITDATA_REQ;
++ dlp-&gt;unitdata_req.dl_dest_addr_length = addrlen;
++ dlp-&gt;unitdata_req.dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
++ dlp-&gt;unitdata_req.dl_priority.dl_min = minpri;
++ dlp-&gt;unitdata_req.dl_priority.dl_max = maxpri;
++
++ (void) memcpy(OFFADDR(dlp, sizeof (dl_unitdata_req_t)), addrp, addrlen);
++
++ ctl.maxlen = 0;
++ ctl.len = sizeof (dl_unitdata_req_t) + addrlen;
++ ctl.buf = (char *) buf;
++
++ data.maxlen = 0;
++ data.len = datalen;
++ data.buf = (char *) datap;
++
++ if (putmsg(fd, &amp;ctl, &amp;data, 0) &lt; 0)
++ fatalSys(&quot;dlunitdatareq: putmsg&quot;);
++}
++
++void dlinfoack(int fd, char *bufp)
++{
++ union DL_primitives *dlp;
++ struct strbuf ctl;
++ int flags;
++
++ ctl.maxlen = MAXDLBUF;
++ ctl.len = 0;
++ ctl.buf = bufp;
++
++ strgetmsg(fd, &amp;ctl, (struct strbuf*)NULL, &amp;flags, &quot;dlinfoack&quot;);
++
++ dlp = (union DL_primitives *) ctl.buf;
++
++ expecting(DL_INFO_ACK, dlp);
++
++ if (ctl.len &lt; sizeof (dl_info_ack_t)) {
++ char buffer[256];
++ sprintf(buffer, &quot;dlinfoack: response ctl.len too short: %d&quot;, ctl.len);
++ rp_fatal(buffer);
++ }
++
++ if (flags != RS_HIPRI)
++ rp_fatal(&quot;dlinfoack: DL_INFO_ACK was not M_PCPROTO&quot;);
++
++ if (ctl.len &lt; sizeof (dl_info_ack_t)) {
++ char buffer[256];
++ sprintf(buffer, &quot;dlinfoack: short response ctl.len: %d&quot;, ctl.len);
++ rp_fatal(buffer);
++ }
++}
++
++void dlbindreq(int fd, u_long sap, u_long max_conind, u_long service_mode, u_long conn_mgmt, u_long xidtest)
++{
++ dl_bind_req_t bind_req;
++ struct strbuf ctl;
++ int flags;
++
++ bind_req.dl_primitive = DL_BIND_REQ;
++ bind_req.dl_sap = sap;
++ bind_req.dl_max_conind = max_conind;
++ bind_req.dl_service_mode = service_mode;
++ bind_req.dl_conn_mgmt = conn_mgmt;
++ bind_req.dl_xidtest_flg = xidtest;
++
++ ctl.maxlen = 0;
++ ctl.len = sizeof (bind_req);
++ ctl.buf = (char *) &amp;bind_req;
++
++ flags = 0;
++
++ if (putmsg(fd, &amp;ctl, (struct strbuf*) NULL, flags) &lt; 0)
++ fatalSys(&quot;dlbindreq: putmsg&quot;);
++}
++
++void dlattachreq(int fd, u_long ppa)
++{
++ dl_attach_req_t attach_req;
++ struct strbuf ctl;
++ int flags;
++
++ attach_req.dl_primitive = DL_ATTACH_REQ;
++ attach_req.dl_ppa = ppa;
++
++ ctl.maxlen = 0;
++ ctl.len = sizeof (attach_req);
++ ctl.buf = (char *) &amp;attach_req;
++
++ flags = 0;
++
++ if (putmsg(fd, &amp;ctl, (struct strbuf*) NULL, flags) &lt; 0)
++ fatalSys(&quot;dlattachreq: putmsg&quot;);
++}
++
++void dlokack(int fd, char *bufp)
++{
++ union DL_primitives *dlp;
++ struct strbuf ctl;
++ int flags;
++
++ ctl.maxlen = MAXDLBUF;
++ ctl.len = 0;
++ ctl.buf = bufp;
++
++ strgetmsg(fd, &amp;ctl, (struct strbuf*)NULL, &amp;flags, &quot;dlokack&quot;);
++
++ dlp = (union DL_primitives *) ctl.buf;
++
++ expecting(DL_OK_ACK, dlp);
++
++ if (ctl.len &lt; sizeof (dl_ok_ack_t)) {
++ char buffer[256];
++ sprintf(buffer, &quot;dlokack: response ctl.len too short: %d&quot;, ctl.len);
++ rp_fatal(buffer);
++ }
++
++ if (flags != RS_HIPRI)
++ rp_fatal(&quot;dlokack: DL_OK_ACK was not M_PCPROTO&quot;);
++
++ if (ctl.len &lt; sizeof (dl_ok_ack_t)) {
++ char buffer[256];
++ sprintf(buffer, &quot;dlokack: short response ctl.len: %d&quot;, ctl.len);
++ rp_fatal(buffer);
++ }
++}
++
++void dlbindack(int fd, char *bufp)
++{
++ union DL_primitives *dlp;
++ struct strbuf ctl;
++ int flags;
++
++ ctl.maxlen = MAXDLBUF;
++ ctl.len = 0;
++ ctl.buf = bufp;
++
++ strgetmsg(fd, &amp;ctl, (struct strbuf*)NULL, &amp;flags, &quot;dlbindack&quot;);
++
++ dlp = (union DL_primitives *) ctl.buf;
++
++ expecting(DL_BIND_ACK, dlp);
++
++ if (flags != RS_HIPRI)
++ rp_fatal(&quot;dlbindack: DL_OK_ACK was not M_PCPROTO&quot;);
++
++ if (ctl.len &lt; sizeof (dl_bind_ack_t)) {
++ char buffer[256];
++ sprintf(buffer, &quot;dlbindack: short response ctl.len: %d&quot;, ctl.len);
++ rp_fatal(buffer);
++ }
++}
++
++int strioctl(int fd, int cmd, int timout, int len, char *dp)
++{
++ struct strioctl sioc;
++ int rc;
++
++ sioc.ic_cmd = cmd;
++ sioc.ic_timout = timout;
++ sioc.ic_len = len;
++ sioc.ic_dp = dp;
++ rc = ioctl(fd, I_STR, &amp;sioc);
++
++ if (rc &lt; 0)
++ return (rc);
++ else
++ return (sioc.ic_len);
++}
++
++void strgetmsg(int fd, struct strbuf *ctlp, struct strbuf *datap, int *flagsp, char *caller)
++{
++ int rc;
++ static char errmsg[80];
++
++ /*
++ * Start timer.
++ */
++ (void) signal(SIGALRM, sigalrm);
++ if (alarm(MAXWAIT) &lt; 0) {
++ (void) sprintf(errmsg, &quot;%s: alarm&quot;, caller);
++ fatalSys(errmsg);
++ }
++
++ /*
++ * Set flags argument and issue getmsg().
++ */
++ *flagsp = 0;
++ if ((rc = getmsg(fd, ctlp, datap, flagsp)) &lt; 0) {
++ (void) sprintf(errmsg, &quot;%s: getmsg&quot;, caller);
++ fatalSys(errmsg);
++ }
++
++ /*
++ * Stop timer.
++ */
++ if (alarm(0) &lt; 0) {
++ (void) sprintf(errmsg, &quot;%s: alarm&quot;, caller);
++ fatalSys(errmsg);
++ }
++
++ /*
++ * Check for MOREDATA and/or MORECTL.
++ */
++ if ((rc &amp; (MORECTL | MOREDATA)) == (MORECTL | MOREDATA)) {
++ char buffer[256];
++ sprintf(buffer, &quot;%s: MORECTL|MOREDATA&quot;, caller);
++ rp_fatal(buffer);
++ }
++
++ if (rc &amp; MORECTL) {
++ char buffer[256];
++ sprintf(buffer, &quot;%s: MORECTL&quot;, caller);
++ rp_fatal(buffer);
++ }
++
++ if (rc &amp; MOREDATA) {
++ char buffer[256];
++ sprintf(buffer, &quot;%s: MOREDATA&quot;, caller);
++ rp_fatal(buffer);
++ }
++
++ /*
++ * Check for at least sizeof (long) control data portion.
++ */
++ if (ctlp-&gt;len &lt; sizeof (long)) {
++ char buffer[256];
++ sprintf(buffer, &quot;getmsg: control portion length &lt; sizeof (long): %d&quot;, ctlp-&gt;len);
++ rp_fatal(buffer);
++ }
++}
++
++void sigalrm(int sig)
++{
++ (void) rp_fatal(&quot;sigalrm: TIMEOUT&quot;);
++}
++
++void expecting(int prim, union DL_primitives *dlp)
++{
++ if (dlp-&gt;dl_primitive != (u_long)prim) {
++ char buffer[256];
++ sprintf(buffer, &quot;expected %s got %s&quot;, dlprim(prim), dlprim(dlp-&gt;dl_primitive));
++ rp_fatal(buffer);
++ exit(1);
++ }
++}
++
++char *dlprim(u_long prim)
++{
++ static char primbuf[80];
++
++ switch ((int)prim) {
++ CASERET(DL_INFO_REQ);
++ CASERET(DL_INFO_ACK);
++ CASERET(DL_ATTACH_REQ);
++ CASERET(DL_DETACH_REQ);
++ CASERET(DL_BIND_REQ);
++ CASERET(DL_BIND_ACK);
++ CASERET(DL_UNBIND_REQ);
++ CASERET(DL_OK_ACK);
++ CASERET(DL_ERROR_ACK);
++ CASERET(DL_SUBS_BIND_REQ);
++ CASERET(DL_SUBS_BIND_ACK);
++ CASERET(DL_UNITDATA_REQ);
++ CASERET(DL_UNITDATA_IND);
++ CASERET(DL_UDERROR_IND);
++ CASERET(DL_UDQOS_REQ);
++ CASERET(DL_CONNECT_REQ);
++ CASERET(DL_CONNECT_IND);
++ CASERET(DL_CONNECT_RES);
++ CASERET(DL_CONNECT_CON);
++ CASERET(DL_TOKEN_REQ);
++ CASERET(DL_TOKEN_ACK);
++ CASERET(DL_DISCONNECT_REQ);
++ CASERET(DL_DISCONNECT_IND);
++ CASERET(DL_RESET_REQ);
++ CASERET(DL_RESET_IND);
++ CASERET(DL_RESET_RES);
++ CASERET(DL_RESET_CON);
++ default:
++ (void) sprintf(primbuf, &quot;unknown primitive 0x%lx&quot;, prim);
++ return (primbuf);
++ }
++}
++
++#endif /* USE_DLPI */
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/src/if.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/src/install-sh
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/src/install-sh (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/src/install-sh 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,238 @@
++#! /bin/sh
++#
++# install - install a program, script, or datafile
++# This comes from X11R5.
++#
++# Calling this script install-sh is preferred over install.sh, to prevent
++# `make' implicit rules from creating a file called install from it
++# when there is no Makefile.
++#
++# This script is compatible with the BSD install script, but was written
++# from scratch.
++#
++
++
++# set DOITPROG to echo to test this script
++
++# Don't use :- since 4.3BSD and earlier shells don't like it.
++doit=&quot;${DOITPROG-}&quot;
++
++
++# put in absolute paths if you don't have them in your path; or use env. vars.
++
++mvprog=&quot;${MVPROG-mv}&quot;
++cpprog=&quot;${CPPROG-cp}&quot;
++chmodprog=&quot;${CHMODPROG-chmod}&quot;
++chownprog=&quot;${CHOWNPROG-chown}&quot;
++chgrpprog=&quot;${CHGRPPROG-chgrp}&quot;
++stripprog=&quot;${STRIPPROG-strip}&quot;
++rmprog=&quot;${RMPROG-rm}&quot;
++mkdirprog=&quot;${MKDIRPROG-mkdir}&quot;
++
++transformbasename=&quot;&quot;
++transform_arg=&quot;&quot;
++instcmd=&quot;$mvprog&quot;
++chmodcmd=&quot;$chmodprog 0755&quot;
++chowncmd=&quot;&quot;
++chgrpcmd=&quot;&quot;
++stripcmd=&quot;&quot;
++rmcmd=&quot;$rmprog -f&quot;
++mvcmd=&quot;$mvprog&quot;
++src=&quot;&quot;
++dst=&quot;&quot;
++dir_arg=&quot;&quot;
++
++while [ x&quot;$1&quot; != x ]; do
++ case $1 in
++ -c) instcmd=&quot;$cpprog&quot;
++ shift
++ continue;;
++
++ -d) dir_arg=true
++ shift
++ continue;;
++
++ -m) chmodcmd=&quot;$chmodprog $2&quot;
++ shift
++ shift
++ continue;;
++
++ -o) chowncmd=&quot;$chownprog $2&quot;
++ shift
++ shift
++ continue;;
++
++ -g) chgrpcmd=&quot;$chgrpprog $2&quot;
++ shift
++ shift
++ continue;;
++
++ -s) stripcmd=&quot;$stripprog&quot;
++ shift
++ continue;;
++
++ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
++ shift
++ continue;;
++
++ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
++ shift
++ continue;;
++
++ *) if [ x&quot;$src&quot; = x ]
++ then
++ src=$1
++ else
++ # this colon is to work around a 386BSD /bin/sh bug
++ :
++ dst=$1
++ fi
++ shift
++ continue;;
++ esac
++done
++
++if [ x&quot;$src&quot; = x ]
++then
++ echo &quot;install: no input file specified&quot;
++ exit 1
++else
++ true
++fi
++
++if [ x&quot;$dir_arg&quot; != x ]; then
++ dst=$src
++ src=&quot;&quot;
++
++ if [ -d $dst ]; then
++ instcmd=:
++ else
++ instcmd=mkdir
++ fi
++else
++
++# Waiting for this to be detected by the &quot;$instcmd $src $dsttmp&quot; command
++# might cause directories to be created, which would be especially bad
++# if $src (and thus $dsttmp) contains '*'.
++
++ if [ -f $src -o -d $src ]
++ then
++ true
++ else
++ echo &quot;install: $src does not exist&quot;
++ exit 1
++ fi
++
++ if [ x&quot;$dst&quot; = x ]
++ then
++ echo &quot;install: no destination specified&quot;
++ exit 1
++ else
++ true
++ fi
++
++# If destination is a directory, append the input filename; if your system
++# does not like double slashes in filenames, you may need to add some logic
++
++ if [ -d $dst ]
++ then
++ dst=&quot;$dst&quot;/`basename $src`
++ else
++ true
++ fi
++fi
++
++## this sed command emulates the dirname command
++dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
++
++# Make sure that the destination directory exists.
++# this part is taken from Noah Friedman's mkinstalldirs script
++
++# Skip lots of stat calls in the usual case.
++if [ ! -d &quot;$dstdir&quot; ]; then
++defaultIFS='
++'
++IFS=&quot;${IFS-${defaultIFS}}&quot;
++
++oIFS=&quot;${IFS}&quot;
++# Some sh's can't handle IFS=/ for some reason.
++IFS='%'
++set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
++IFS=&quot;${oIFS}&quot;
++
++pathcomp=''
++
++while [ $# -ne 0 ] ; do
++ pathcomp=&quot;${pathcomp}${1}&quot;
++ shift
++
++ if [ ! -d &quot;${pathcomp}&quot; ] ;
++ then
++ $mkdirprog &quot;${pathcomp}&quot;
++ else
++ true
++ fi
++
++ pathcomp=&quot;${pathcomp}/&quot;
++done
++fi
++
++if [ x&quot;$dir_arg&quot; != x ]
++then
++ $doit $instcmd $dst &amp;&amp;
++
++ if [ x&quot;$chowncmd&quot; != x ]; then $doit $chowncmd $dst; else true ; fi &amp;&amp;
++ if [ x&quot;$chgrpcmd&quot; != x ]; then $doit $chgrpcmd $dst; else true ; fi &amp;&amp;
++ if [ x&quot;$stripcmd&quot; != x ]; then $doit $stripcmd $dst; else true ; fi &amp;&amp;
++ if [ x&quot;$chmodcmd&quot; != x ]; then $doit $chmodcmd $dst; else true ; fi
++else
++
++# If we're going to rename the final executable, determine the name now.
++
++ if [ x&quot;$transformarg&quot; = x ]
++ then
++ dstfile=`basename $dst`
++ else
++ dstfile=`basename $dst $transformbasename |
++ sed $transformarg`$transformbasename
++ fi
++
++# don't allow the sed command to completely eliminate the filename
++
++ if [ x&quot;$dstfile&quot; = x ]
++ then
++ dstfile=`basename $dst`
++ else
++ true
++ fi
++
++# Make a temp file name in the proper directory.
++
++ dsttmp=$dstdir/#inst.$$#
++
++# Move or copy the file name to the temp name
++
++ $doit $instcmd $src $dsttmp &amp;&amp;
++
++ trap &quot;rm -f ${dsttmp}&quot; 0 &amp;&amp;
++
++# and set any options; do chmod last to preserve setuid bits
++
++# If any of these fail, we abort the whole thing. If we want to
++# ignore errors from any of these, just make sure not to ignore
++# errors from the above &quot;$doit $instcmd $src $dsttmp&quot; command.
++
++ if [ x&quot;$chowncmd&quot; != x ]; then $doit $chowncmd $dsttmp; else true;fi &amp;&amp;
++ if [ x&quot;$chgrpcmd&quot; != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &amp;&amp;
++ if [ x&quot;$stripcmd&quot; != x ]; then $doit $stripcmd $dsttmp; else true;fi &amp;&amp;
++ if [ x&quot;$chmodcmd&quot; != x ]; then $doit $chmodcmd $dsttmp; else true;fi &amp;&amp;
++
++# Now rename the file to the real destination.
++
++ $doit $rmcmd -f $dstdir/$dstfile &amp;&amp;
++ $doit $mvcmd $dsttmp $dstdir/$dstfile
++
++fi &amp;&amp;
++
++
++exit 0
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/src/install-sh
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/src/md5.c
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/src/md5.c (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/src/md5.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,246 @@
++/*
++ * This code implements the MD5 message-digest algorithm.
++ * The algorithm is due to Ron Rivest. This code was
++ * written by Colin Plumb in 1993, no copyright is claimed.
++ * This code is in the public domain; do with it what you wish.
++ *
++ * Equivalent code is available from RSA Data Security, Inc.
++ * This code has been tested against that, and is equivalent,
++ * except that you don't need to include two pages of legalese
++ * with every copy.
++ *
++ * To compute the message digest of a chunk of bytes, declare an
++ * MD5Context structure, pass it to MD5Init, call MD5Update as
++ * needed on buffers full of bytes, and then call MD5Final, which
++ * will fill a supplied 16-byte array with the digest.
++ */
++#include &lt;string.h&gt; /* for memcpy() */
++#include &quot;md5.h&quot;
++
++void byteReverse(unsigned char *buf, unsigned longs);
++
++/*
++ * Note: this code is harmless on little-endian machines.
++ */
++void byteReverse(unsigned char *buf, unsigned longs)
++{
++ uint32 t;
++ do {
++ t = (uint32) ((unsigned) buf[3] &lt;&lt; 8 | buf[2]) &lt;&lt; 16 |
++ ((unsigned) buf[1] &lt;&lt; 8 | buf[0]);
++ *(uint32 *) buf = t;
++ buf += 4;
++ } while (--longs);
++}
++
++/*
++ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
++ * initialization constants.
++ */
++void MD5Init(struct MD5Context *ctx)
++{
++ ctx-&gt;buf[0] = 0x67452301;
++ ctx-&gt;buf[1] = 0xefcdab89;
++ ctx-&gt;buf[2] = 0x98badcfe;
++ ctx-&gt;buf[3] = 0x10325476;
++
++ ctx-&gt;bits[0] = 0;
++ ctx-&gt;bits[1] = 0;
++}
++
++/*
++ * Update context to reflect the concatenation of another buffer full
++ * of bytes.
++ */
++void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
++{
++ uint32 t;
++
++ /* Update bitcount */
++
++ t = ctx-&gt;bits[0];
++ if ((ctx-&gt;bits[0] = t + ((uint32) len &lt;&lt; 3)) &lt; t)
++ ctx-&gt;bits[1]++; /* Carry from low to high */
++ ctx-&gt;bits[1] += len &gt;&gt; 29;
++
++ t = (t &gt;&gt; 3) &amp; 0x3f; /* Bytes already in shsInfo-&gt;data */
++
++ /* Handle any leading odd-sized chunks */
++
++ if (t) {
++ unsigned char *p = (unsigned char *) ctx-&gt;in + t;
++
++ t = 64 - t;
++ if (len &lt; t) {
++ memcpy(p, buf, len);
++ return;
++ }
++ memcpy(p, buf, t);
++ byteReverse(ctx-&gt;in, 16);
++ MD5Transform(ctx-&gt;buf, (uint32 *) ctx-&gt;in);
++ buf += t;
++ len -= t;
++ }
++ /* Process data in 64-byte chunks */
++
++ while (len &gt;= 64) {
++ memcpy(ctx-&gt;in, buf, 64);
++ byteReverse(ctx-&gt;in, 16);
++ MD5Transform(ctx-&gt;buf, (uint32 *) ctx-&gt;in);
++ buf += 64;
++ len -= 64;
++ }
++
++ /* Handle any remaining bytes of data. */
++
++ memcpy(ctx-&gt;in, buf, len);
++}
++
++/*
++ * Final wrapup - pad to 64-byte boundary with the bit pattern
++ * 1 0* (64-bit count of bits processed, MSB-first)
++ */
++void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
++{
++ unsigned count;
++ unsigned char *p;
++
++ /* Compute number of bytes mod 64 */
++ count = (ctx-&gt;bits[0] &gt;&gt; 3) &amp; 0x3F;
++
++ /* Set the first char of padding to 0x80. This is safe since there is
++ always at least one byte free */
++ p = ctx-&gt;in + count;
++ *p++ = 0x80;
++
++ /* Bytes of padding needed to make 64 bytes */
++ count = 64 - 1 - count;
++
++ /* Pad out to 56 mod 64 */
++ if (count &lt; 8) {
++ /* Two lots of padding: Pad the first block to 64 bytes */
++ memset(p, 0, count);
++ byteReverse(ctx-&gt;in, 16);
++ MD5Transform(ctx-&gt;buf, (uint32 *) ctx-&gt;in);
++
++ /* Now fill the next block with 56 bytes */
++ memset(ctx-&gt;in, 0, 56);
++ } else {
++ /* Pad block to 56 bytes */
++ memset(p, 0, count - 8);
++ }
++ byteReverse(ctx-&gt;in, 14);
++
++ /* Append length in bits and transform */
++ ((uint32 *) ctx-&gt;in)[14] = ctx-&gt;bits[0];
++ ((uint32 *) ctx-&gt;in)[15] = ctx-&gt;bits[1];
++
++ MD5Transform(ctx-&gt;buf, (uint32 *) ctx-&gt;in);
++ byteReverse((unsigned char *) ctx-&gt;buf, 4);
++ memcpy(digest, ctx-&gt;buf, 16);
++ memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
++}
++
++#ifndef ASM_MD5
++
++/* The four core functions - F1 is optimized somewhat */
++
++/* #define F1(x, y, z) (x &amp; y | ~x &amp; z) */
++#define F1(x, y, z) (z ^ (x &amp; (y ^ z)))
++#define F2(x, y, z) F1(z, x, y)
++#define F3(x, y, z) (x ^ y ^ z)
++#define F4(x, y, z) (y ^ (x | ~z))
++
++/* This is the central step in the MD5 algorithm. */
++#define MD5STEP(f, w, x, y, z, data, s) \
++ ( w += f(x, y, z) + data, w = w&lt;&lt;s | w&gt;&gt;(32-s), w += x )
++
++/*
++ * The core of the MD5 algorithm, this alters an existing MD5 hash to
++ * reflect the addition of 16 longwords of new data. MD5Update blocks
++ * the data and converts bytes into longwords for this routine.
++ */
++void MD5Transform(uint32 buf[4], uint32 const in[16])
++{
++ register uint32 a, b, c, d;
++
++ a = buf[0];
++ b = buf[1];
++ c = buf[2];
++ d = buf[3];
++
++ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
++ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
++ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
++ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
++ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
++ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
++ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
++ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
++ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
++ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
++ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
++ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
++ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
++ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
++ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
++ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
++
++ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
++ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
++ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
++ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
++ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
++ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
++ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
++ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
++ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
++ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
++ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
++ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
++ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
++ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
++ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
++ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
++
++ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
++ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
++ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
++ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
++ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
++ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
++ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
++ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
++ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
++ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
++ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
++ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
++ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
++ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
++ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
++ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
++
++ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
++ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
++ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
++ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
++ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
++ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
++ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
++ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
++ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
++ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
++ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
++ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
++ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
++ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
++ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
++ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
++
++ buf[0] += a;
++ buf[1] += b;
++ buf[2] += c;
++ buf[3] += d;
++}
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/src/md5.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/src/md5.h
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/src/md5.h (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/src/md5.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,27 @@
++#ifndef MD5_H
++#define MD5_H
++
++#ifdef __alpha
++typedef unsigned int uint32;
++#else
++typedef unsigned long uint32;
++#endif
++
++struct MD5Context {
++ uint32 buf[4];
++ uint32 bits[2];
++ unsigned char in[64];
++};
++
++void MD5Init(struct MD5Context *context);
++void MD5Update(struct MD5Context *context, unsigned char const *buf,
++ unsigned len);
++void MD5Final(unsigned char digest[16], struct MD5Context *context);
++void MD5Transform(uint32 buf[4], uint32 const in[16]);
++
++/*
++ * This is needed to make RSAREF happy on some MS-DOS compilers.
++ */
++typedef struct MD5Context MD5_CTX;
++
++#endif /* !MD5_H */
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/src/md5.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/src/plugin.c
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/src/plugin.c (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/src/plugin.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,397 @@
++/***********************************************************************
++*
++* plugin.c
++*
++* pppd plugin for kernel-mode PPPoE on Linux
++*
++* Copyright (C) 2001 by Roaring Penguin Software Inc., Michal Ostrowski
++* and Jamal Hadi Salim.
++*
++* Much code and many ideas derived from pppoe plugin by Michal
++* Ostrowski and Jamal Hadi Salim, which carries this copyright:
++*
++* Copyright 2000 Michal Ostrowski &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">mostrows at styx.uwaterloo.ca</A>&gt;,
++* Jamal Hadi Salim &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">hadi at cyberus.ca</A>&gt;
++* Borrows heavily from the PPPoATM plugin by Mitchell Blank Jr.,
++* which is based in part on work from Jens Axboe and Paul Mackerras.
++*
++* This program is free software; you can redistribute it and/or
++* modify it under the terms of the GNU General Public License
++* as published by the Free Software Foundation; either version
++* 2 of the License, or (at your option) any later version.
++***********************************************************************/
++
++static char const RCSID[] =
++&quot;$Id: plugin.c 195724 2001-06-11 13:49:39Z gc $&quot;;
++
++#define _GNU_SOURCE 1
++#include &quot;pppoe.h&quot;
++
++#include &quot;pppd/pppd.h&quot;
++#include &quot;pppd/fsm.h&quot;
++#include &quot;pppd/lcp.h&quot;
++#include &quot;pppd/ipcp.h&quot;
++#include &quot;pppd/ccp.h&quot;
++#include &quot;pppd/pathnames.h&quot;
++
++#include &lt;linux/types.h&gt;
++#include &lt;syslog.h&gt;
++#include &lt;sys/ioctl.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/socket.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;string.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;errno.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;signal.h&gt;
++#include &lt;net/ethernet.h&gt;
++#include &lt;net/if_arp.h&gt;
++#include &lt;linux/if_pppox.h&gt;
++
++/* From sys-linux.c in pppd -- MUST FIX THIS! */
++extern int new_style_driver;
++
++static char *service = NULL;
++static char *acName = NULL;
++static char *existingSession = NULL;
++
++static option_t Options[] = {
++ { &quot;rp_pppoe_service&quot;, o_string, &amp;service,
++ &quot;Desired PPPoE service name&quot; },
++ { &quot;rp_pppoe_ac&quot;, o_string, &amp;acName,
++ &quot;Desired PPPoE access concentrator name&quot; },
++ { &quot;rp_pppoe_sess&quot;, o_string, &amp;existingSession,
++ &quot;Attach to existing session (sessid:macaddr)&quot; },
++ { NULL }
++};
++int (*OldDevnameHook)(const char *name) = NULL;
++static PPPoEConnection *conn = NULL;
++
++/**********************************************************************
++ * %FUNCTION: PPPOEInitDevice
++ * %ARGUMENTS:
++ * None
++ * %RETURNS:
++ *
++ * %DESCRIPTION:
++ * Initializes PPPoE device.
++ ***********************************************************************/
++static int
++PPPOEInitDevice(void)
++{
++ conn = malloc(sizeof(PPPoEConnection));
++ if (!conn) {
++ fatal(&quot;Could not allocate memory for PPPoE session&quot;);
++ }
++ memset(conn, 0, sizeof(PPPoEConnection));
++ if (acName) {
++ SET_STRING(conn-&gt;acName, acName);
++ }
++ if (service) {
++ SET_STRING(conn-&gt;serviceName, acName);
++ }
++ SET_STRING(conn-&gt;ifName, devnam);
++ conn-&gt;discoverySocket = -1;
++ conn-&gt;sessionSocket = -1;
++ conn-&gt;useHostUniq = 1;
++ return 1;
++}
++
++/**********************************************************************
++ * %FUNCTION: PPPOEConnectDevice
++ * %ARGUMENTS:
++ * None
++ * %RETURNS:
++ * Non-negative if all goes well; -1 otherwise
++ * %DESCRIPTION:
++ * Connects PPPoE device.
++ ***********************************************************************/
++static int
++PPPOEConnectDevice(void)
++{
++ struct sockaddr_pppox sp;
++
++ strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam));
++ if (existingSession) {
++ unsigned int mac[ETH_ALEN];
++ int i, ses;
++ if (sscanf(existingSession, &quot;%d:%x:%x:%x:%x:%x:%x&quot;,
++ &amp;ses, &amp;mac[0], &amp;mac[1], &amp;mac[2],
++ &amp;mac[3], &amp;mac[4], &amp;mac[5]) != 7) {
++ fatal(&quot;Illegal value for rp_pppoe_sess option&quot;);
++ }
++ conn-&gt;session = htons(ses);
++ for (i=0; i&lt;ETH_ALEN; i++) {
++ conn-&gt;peerEth[i] = (unsigned char) mac[i];
++ }
++ } else {
++ discovery(conn);
++ if (conn-&gt;discoveryState != STATE_SESSION) {
++ fatal(&quot;Unable to complete PPPoE Discovery&quot;);
++ }
++ }
++
++ /* Make the session socket */
++ conn-&gt;sessionSocket = socket(AF_PPPOX, SOCK_STREAM, PX_PROTO_OE);
++ if (conn-&gt;sessionSocket &lt; 0) {
++ fatal(&quot;Failed to create PPPoE socket: %m&quot;);
++ }
++ sp.sa_family = AF_PPPOX;
++ sp.sa_protocol = PX_PROTO_OE;
++ sp.sa_addr.pppoe.sid = conn-&gt;session;
++ memcpy(sp.sa_addr.pppoe.dev, conn-&gt;ifName, IFNAMSIZ);
++ memcpy(sp.sa_addr.pppoe.remote, conn-&gt;peerEth, ETH_ALEN);
++ if (connect(conn-&gt;sessionSocket, (struct sockaddr *) &amp;sp,
++ sizeof(struct sockaddr_pppox)) &lt; 0) {
++ fatal(&quot;Failed to connect PPPoE socket: %d %m&quot;, errno);
++ return -1;
++ }
++ return conn-&gt;sessionSocket;
++}
++
++static void
++PPPOESendConfig(int unit,
++ int mtu,
++ u_int32_t asyncmap,
++ int pcomp,
++ int accomp)
++{
++ int sock;
++ struct ifreq ifr;
++
++ if (mtu &gt; MAX_PPPOE_MTU) {
++ warn(&quot;Couldn't increase MTU to %d&quot;, mtu);
++ }
++ sock = socket(AF_INET, SOCK_DGRAM, 0);
++ if (sock &lt; 0) {
++ fatal(&quot;Couldn't create IP socket: %m&quot;);
++ }
++ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
++ ifr.ifr_mtu = mtu;
++ if (ioctl(sock, SIOCSIFMTU, &amp;ifr) &lt; 0) {
++ fatal(&quot;ioctl(SIOCSIFMTU): %m&quot;);
++ }
++ (void) close (sock);
++}
++
++
++static void
++PPPOERecvConfig(int unit,
++ int mru,
++ u_int32_t asyncmap,
++ int pcomp,
++ int accomp)
++{
++ if (mru &gt; MAX_PPPOE_MTU) {
++ error(&quot;Couldn't increase MRU to %d&quot;, mru);
++ }
++}
++
++static void
++PPPOESetXaccm(int unit,
++ ext_accm accm)
++{
++ /* Do nothing */
++}
++
++/**********************************************************************
++ * %FUNCTION: PPPOEDisconnectDevice
++ * %ARGUMENTS:
++ * None
++ * %RETURNS:
++ * Nothing
++ * %DESCRIPTION:
++ * Disconnects PPPoE device
++ ***********************************************************************/
++static void
++PPPOEDisconnectDevice(void)
++{
++ struct sockaddr_pppox sp;
++
++ sp.sa_family = AF_PPPOX;
++ sp.sa_protocol = PX_PROTO_OE;
++ sp.sa_addr.pppoe.sid = 0;
++ memcpy(sp.sa_addr.pppoe.dev, conn-&gt;ifName, IFNAMSIZ);
++ memcpy(sp.sa_addr.pppoe.remote, conn-&gt;peerEth, ETH_ALEN);
++ if (connect(conn-&gt;sessionSocket, (struct sockaddr *) &amp;sp,
++ sizeof(struct sockaddr_pppox)) &lt; 0) {
++ fatal(&quot;Failed to disconnect PPPoE socket: %d %m&quot;, errno);
++ return;
++ }
++ close(conn-&gt;sessionSocket);
++}
++
++static int
++PPPOESetSpeed(const char *speed)
++{
++ return 0;
++}
++
++static void
++PPPOEDeviceCheckHook(void)
++{
++ if (!options_for_dev(_PATH_ETHOPT, devnam)) {
++ exit(EXIT_OPTION_ERROR);
++ }
++}
++
++/**********************************************************************
++ * %FUNCTION: PPPoEDevnameHook
++ * %ARGUMENTS:
++ * name -- name of device
++ * %RETURNS:
++ * 1 if we will handle this device; 0 otherwise.
++ * %DESCRIPTION:
++ * Checks if name is a valid interface name; if so, returns 1. Also
++ * sets up devnam (string representation of device) and sets devstat.st_mode
++ * so S_ISCHR(devstat.st_mode) != 1 for internal pppd consumption.
++ ***********************************************************************/
++static int
++PPPoEDevnameHook(const char *name)
++{
++ int r = 1;
++ int fd;
++ struct ifreq ifr;
++
++ /* Open a socket */
++ if ((fd = socket(PF_PACKET, SOCK_RAW, 0)) &lt; 0) {
++ r = 0;
++ }
++
++ /* Try getting interface index */
++ if (r) {
++ strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
++ if (ioctl(fd, SIOCGIFINDEX, &amp;ifr) &lt; 0) {
++ r = 0;
++ } else {
++ if (ioctl(fd, SIOCGIFHWADDR, &amp;ifr) &lt; 0) {
++ r = 0;
++ } else {
++ if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
++ error(&quot;Interface %s not Ethernet&quot;, name);
++ r=0;
++ }
++ }
++ }
++ }
++
++ /* Close socket */
++ close(fd);
++ if (r) {
++ strncpy(devnam, name, sizeof(devnam));
++ if (device_check_hook != PPPOEDeviceCheckHook) {
++ devstat.st_mode = S_IFSOCK;
++ device_init_hook = PPPOEInitDevice;
++ setspeed_hook = PPPOESetSpeed;
++ device_check_hook = PPPOEDeviceCheckHook;
++ connect_device_hook = PPPOEConnectDevice;
++ disconnect_device_hook = PPPOEDisconnectDevice;
++ send_config_hook = PPPOESendConfig;
++ recv_config_hook = PPPOERecvConfig;
++ set_xaccm_hook = PPPOESetXaccm;
++ modem = 0;
++
++ lcp_allowoptions[0].neg_accompression = 0;
++ lcp_wantoptions[0].neg_accompression = 0;
++
++ lcp_allowoptions[0].neg_asyncmap = 0;
++ lcp_wantoptions[0].neg_asyncmap = 0;
++
++ lcp_allowoptions[0].neg_pcompression = 0;
++ lcp_wantoptions[0].neg_pcompression = 0;
++
++ ccp_allowoptions[0].deflate = 0 ;
++ ccp_wantoptions[0].deflate = 0 ;
++
++ ipcp_allowoptions[0].neg_vj=0;
++ ipcp_wantoptions[0].neg_vj=0;
++
++ ccp_allowoptions[0].bsd_compress = 0;
++ ccp_wantoptions[0].bsd_compress = 0;
++
++ PPPOEInitDevice();
++ }
++ return 1;
++ }
++
++ if (OldDevnameHook) r = OldDevnameHook(name);
++ return r;
++}
++
++/**********************************************************************
++ * %FUNCTION: plugin_init
++ * %ARGUMENTS:
++ * None
++ * %RETURNS:
++ * Nothing
++ * %DESCRIPTION:
++ * Initializes hooks for pppd plugin
++ ***********************************************************************/
++void
++plugin_init(void)
++{
++ if (!new_style_driver) {
++ fatal(&quot;Linux kernel does not support PPPoE -- are you running 2.4.x?&quot;);
++ }
++ OldDevnameHook = setdevname_hook;
++ setdevname_hook = PPPoEDevnameHook;
++ add_options(Options);
++
++ info(&quot;Roaring Penguin PPPoE Plugin Initialized&quot;);
++}
++
++/**********************************************************************
++*%FUNCTION: fatalSys
++*%ARGUMENTS:
++* str -- error message
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Prints a message plus the errno value to stderr and syslog and exits.
++***********************************************************************/
++void
++fatalSys(char const *str)
++{
++ char buf[1024];
++ int i = errno;
++ sprintf(buf, &quot;%.256s: %.256s&quot;, str, strerror(i));
++ printErr(buf);
++ sprintf(buf, &quot;RP-PPPoE: %.256s: %.256s&quot;, str, strerror(i));
++ sendPADT(conn, buf);
++ exit(1);
++}
++
++/**********************************************************************
++*%FUNCTION: rp_fatal
++*%ARGUMENTS:
++* str -- error message
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Prints a message to stderr and syslog and exits.
++***********************************************************************/
++void
++rp_fatal(char const *str)
++{
++ char buf[1024];
++ printErr(str);
++ sprintf(buf, &quot;RP-PPPoE: %.256s&quot;, str);
++ sendPADT(conn, buf);
++ exit(1);
++}
++/**********************************************************************
++*%FUNCTION: sysErr
++*%ARGUMENTS:
++* str -- error message
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Prints a message plus the errno value to syslog.
++***********************************************************************/
++void
++sysErr(char const *str)
++{
++ rp_fatal(str);
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/src/plugin.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/src/ppp.c
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/src/ppp.c (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/src/ppp.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,258 @@
++/***********************************************************************
++*
++* ppp.c
++*
++* Implementation of user-space PPPoE redirector for Linux.
++*
++* Functions for talking to PPP daemon
++*
++* Copyright (C) 2000 by Roaring Penguin Software Inc.
++*
++* This program may be distributed according to the terms of the GNU
++* General Public License, version 2 or (at your option) any later version.
++*
++***********************************************************************/
++
++static char const RCSID[] =
++&quot;$Id: ppp.c 195724 2001-06-11 13:49:39Z gc $&quot;;
++
++#include &quot;pppoe.h&quot;
++
++#ifdef HAVE_SYSLOG_H
++#include &lt;syslog.h&gt;
++#endif
++
++#include &lt;string.h&gt;
++#include &lt;errno.h&gt;
++#include &lt;stdlib.h&gt;
++
++#ifdef HAVE_SYS_UIO_H
++#include &lt;sys/uio.h&gt;
++#endif
++
++#ifdef HAVE_UNISTD_H
++#include &lt;unistd.h&gt;
++#endif
++
++#ifdef HAVE_N_HDLC
++#ifndef N_HDLC
++#include &lt;linux/termios.h&gt;
++#endif
++#endif
++
++int PPPState;
++int PPPPacketSize;
++unsigned char PPPXorValue;
++
++UINT16_t fcstab[256] = {
++ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
++ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
++ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
++ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
++ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
++ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
++ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
++ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
++ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
++ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
++ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
++ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
++ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
++ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
++ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
++ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
++ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
++ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
++ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
++ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
++ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
++ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
++ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
++ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
++ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
++ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
++ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
++ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
++ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
++ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
++ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
++ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
++};
++
++/**********************************************************************
++*%FUNCTION: syncReadFromPPP
++*%ARGUMENTS:
++* conn -- PPPoEConnection structure
++* packet -- buffer in which to place PPPoE packet
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Reads from a synchronous PPP device and builds and transmits a PPPoE
++* packet
++***********************************************************************/
++void
++syncReadFromPPP(PPPoEConnection *conn, PPPoEPacket *packet)
++{
++ int r;
++#ifndef HAVE_N_HDLC
++ struct iovec vec[2];
++ unsigned char dummy[2];
++ vec[0].iov_base = (void *) dummy;
++ vec[0].iov_len = 2;
++ vec[1].iov_base = (void *) packet-&gt;payload;
++ vec[1].iov_len = ETH_DATA_LEN - PPPOE_OVERHEAD;
++
++ /* Use scatter-read to throw away the PPP frame address bytes */
++ r = readv(0, vec, 2);
++#else
++ /* Bloody hell... readv doesn't work with N_HDLC line discipline... GRR! */
++ unsigned char buf[ETH_DATA_LEN - PPPOE_OVERHEAD + 2];
++ r = read(0, buf, ETH_DATA_LEN - PPPOE_OVERHEAD + 2);
++ if (r &gt;= 2) {
++ memcpy(packet-&gt;payload, buf+2, r-2);
++ }
++#endif
++ if (r &lt; 0) {
++ /* Catch the Linux &quot;select&quot; bug */
++ if (errno == EAGAIN) {
++ rp_fatal(&quot;Linux select bug hit! This message is harmless, but please ask the Linux kernel developers to fix it.&quot;);
++ }
++ fatalSys(&quot;read (syncReadFromPPP)&quot;);
++ }
++ if (r == 0) {
++ syslog(LOG_INFO, &quot;end-of-file in syncReadFromPPP&quot;);
++ sendPADT(conn, &quot;RP-PPPoE: EOF in syncReadFromPPP&quot;);
++ exit(0);
++ }
++
++ if (r &lt; 2) {
++ rp_fatal(&quot;too few characters read from PPP (syncReadFromPPP)&quot;);
++ }
++
++ sendSessionPacket(conn, packet, r-2);
++}
++
++/**********************************************************************
++*%FUNCTION: initPPP
++*%ARGUMENTS:
++* None
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Initializes the PPP state machine
++***********************************************************************/
++void
++initPPP(void)
++{
++ PPPState = STATE_WAITFOR_FRAME_ADDR;
++ PPPPacketSize = 0;
++ PPPXorValue = 0;
++
++}
++/**********************************************************************
++*%FUNCTION: asyncReadFromPPP
++*%ARGUMENTS:
++* conn -- PPPoEConnection structure
++* packet -- buffer in which to place PPPoE packet
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Reads from an async PPP device and builds a PPPoE packet to transmit
++***********************************************************************/
++void
++asyncReadFromPPP(PPPoEConnection *conn, PPPoEPacket *packet)
++{
++ unsigned char buf[READ_CHUNK];
++ unsigned char *ptr = buf;
++ unsigned char c;
++
++ int r;
++
++ r = read(0, buf, READ_CHUNK);
++ if (r &lt; 0) {
++ fatalSys(&quot;read (asyncReadFromPPP)&quot;);
++ }
++
++ if (r == 0) {
++ syslog(LOG_INFO, &quot;end-of-file in asyncReadFromPPP&quot;);
++ sendPADT(conn, &quot;RP-PPPoE: EOF in asyncReadFromPPP&quot;);
++ exit(0);
++ }
++
++ while(r) {
++ if (PPPState == STATE_WAITFOR_FRAME_ADDR) {
++ while(r) {
++ --r;
++ if (*ptr++ == FRAME_ADDR) {
++ PPPState = STATE_DROP_PROTO;
++ break;
++ }
++ }
++ }
++
++ /* Still waiting... */
++ if (PPPState == STATE_WAITFOR_FRAME_ADDR) return;
++
++ while(r &amp;&amp; PPPState == STATE_DROP_PROTO) {
++ --r;
++ if (*ptr++ == (FRAME_CTRL ^ FRAME_ENC)) {
++ PPPState = STATE_BUILDING_PACKET;
++ }
++ }
++
++ if (PPPState == STATE_DROP_PROTO) return;
++
++ /* Start building frame */
++ while(r &amp;&amp; PPPState == STATE_BUILDING_PACKET) {
++ --r;
++ c = *ptr++;
++ switch(c) {
++ case FRAME_ESC:
++ PPPXorValue = FRAME_ENC;
++ break;
++ case FRAME_FLAG:
++ if (PPPPacketSize &lt; 2) {
++ rp_fatal(&quot;Packet too short from PPP (asyncReadFromPPP)&quot;);
++ }
++ sendSessionPacket(conn, packet, PPPPacketSize-2);
++ PPPPacketSize = 0;
++ PPPXorValue = 0;
++ PPPState = STATE_WAITFOR_FRAME_ADDR;
++ break;
++ default:
++ if (PPPPacketSize &gt;= ETH_DATA_LEN - 4) {
++ syslog(LOG_ERR, &quot;Packet too big! Check MTU on PPP interface&quot;);
++ PPPPacketSize = 0;
++ PPPXorValue = 0;
++ PPPState = STATE_WAITFOR_FRAME_ADDR;
++ } else {
++ packet-&gt;payload[PPPPacketSize++] = c ^ PPPXorValue;
++ PPPXorValue = 0;
++ }
++ }
++ }
++ }
++}
++
++/**********************************************************************
++*%FUNCTION: pppFCS16
++*%ARGUMENTS:
++* fcs -- current fcs
++* cp -- a buffer's worth of data
++* len -- length of buffer &quot;cp&quot;
++*%RETURNS:
++* A new FCS
++*%DESCRIPTION:
++* Updates the PPP FCS.
++***********************************************************************/
++UINT16_t
++pppFCS16(UINT16_t fcs,
++ unsigned char * cp,
++ int len)
++{
++ while (len--)
++ fcs = (fcs &gt;&gt; 8) ^ fcstab[(fcs ^ *cp++) &amp; 0xff];
++
++ return (fcs);
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/src/ppp.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/src/pppoe-server.c
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/src/pppoe-server.c (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/src/pppoe-server.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1247 @@
++/***********************************************************************
++*
++* pppoe.h
++*
++* Implementation of a user-space PPPoE server
++*
++* Copyright (C) 2000 Roaring Penguin Software Inc.
++*
++* This program may be distributed according to the terms of the GNU
++* General Public License, version 2 or (at your option) any later version.
++*
++* $Id: pppoe-server.c 195724 2001-06-11 13:49:39Z gc $
++*
++***********************************************************************/
++
++static char const RCSID[] =
++&quot;$Id: pppoe-server.c 195724 2001-06-11 13:49:39Z gc $&quot;;
++
++#include &quot;config.h&quot;
++
++#if defined(HAVE_NETPACKET_PACKET_H) || defined(HAVE_LINUX_IF_PACKET_H)
++#define _POSIX_SOURCE 1 /* For sigaction defines */
++#endif
++
++#define _BSD_SOURCE 1 /* for gethostname */
++
++#include &quot;pppoe.h&quot;
++#include &quot;md5.h&quot;
++
++#ifdef HAVE_SYSLOG_H
++#include &lt;syslog.h&gt;
++#endif
++
++#include &lt;errno.h&gt;
++#include &lt;string.h&gt;
++#include &lt;stdlib.h&gt;
++
++#ifdef HAVE_UNISTD_H
++#include &lt;unistd.h&gt;
++#endif
++
++#ifdef HAVE_GETOPT_H
++#include &lt;getopt.h&gt;
++#endif
++
++#ifdef HAVE_SYS_WAIT_H
++#include &lt;sys/wait.h&gt;
++#endif
++
++#ifdef HAVE_SYS_TIME_H
++#include &lt;sys/time.h&gt;
++#endif
++
++#include &lt;signal.h&gt;
++
++/* Hack for daemonizing */
++#define CLOSEFD 64
++
++/* Max. 64 sessions by default */
++#define DEFAULT_MAX_SESSIONS 64
++
++/* A list of client sessions */
++struct ClientSession *Sessions = NULL;
++
++/* The number of session slots */
++size_t NumSessionSlots;
++
++/* Offset of first session */
++size_t SessOffset = 0;
++
++/* Socket for client's discovery phases */
++int Socket = -1;
++
++/* Pipe written on reception of SIGCHLD */
++int Pipe[2] = {-1, -1};
++int ReapPending = 0;
++
++/* Synchronous mode */
++int Synchronous = 0;
++
++/* Random seed for cookie generation */
++#define SEED_LEN 16
++#define MD5_LEN 16
++#define COOKIE_LEN (MD5_LEN + sizeof(pid_t)) /* Cookie is 16-byte MD5 + PID of server */
++
++unsigned char CookieSeed[SEED_LEN];
++
++/* Default interface if no -I option given */
++#define DEFAULT_IF &quot;eth0&quot;
++char *IfName = NULL;
++
++/* Access concentrator name */
++char *ACName = NULL;
++
++/* Options to pass to pppoe process */
++char PppoeOptions[SMALLBUF] = &quot;&quot;;
++
++/* Our local IP address */
++unsigned char LocalIP[IPV4ALEN] = {10, 0, 0, 1};
++unsigned char RemoteIP[IPV4ALEN] = {10, 67, 15, 1}; /* Counter STARTS here */
++
++PPPoETag hostUniq;
++PPPoETag relayId;
++PPPoETag receivedCookie;
++PPPoETag requestedService;
++
++#define HOSTNAMELEN 256
++
++static void startPPPD(struct ClientSession *sess);
++static void sendErrorPADS(int sock, unsigned char *source, unsigned char *dest,
++ int errorTag, char *errorMsg);
++
++#define CHECK_ROOM(cursor, start, len) \
++do {\
++ if (((cursor)-(start))+(len) &gt; MAX_PPPOE_PAYLOAD) { \
++ syslog(LOG_ERR, &quot;Would create too-long packet&quot;); \
++ return; \
++ } \
++} while(0)
++
++/* Use Linux kernel-mode PPPoE? */
++int UseLinuxKernelModePPPoE = 0;
++
++/**********************************************************************
++*%FUNCTION: parseAddressPool
++*%ARGUMENTS:
++* fname -- name of file containing IP address pool.
++* install -- if true, install IP addresses in sessions.
++*%RETURNS:
++* Number of valid IP addresses found.
++*%DESCRIPTION:
++* Reads a list of IP addresses from a file.
++***********************************************************************/
++static int
++parseAddressPool(char const *fname, int install)
++{
++ FILE *fp = fopen(fname, &quot;r&quot;);
++ int numAddrs = 0;
++ unsigned int a, b, c, d;
++
++ if (!fp) {
++ sysErr(&quot;Cannot open address pool file&quot;);
++ }
++
++ while (!feof(fp)) {
++ if ((fscanf(fp, &quot;%u.%u.%u.%u&quot;, &amp;a, &amp;b, &amp;c, &amp;d) == 4) &amp;&amp;
++ a &lt; 256 &amp;&amp; b &lt; 256 &amp;&amp; c &lt; 256 &amp;&amp; d &lt; 256) {
++ if (install) {
++ Sessions[numAddrs].ip[0] = (unsigned char) a;
++ Sessions[numAddrs].ip[1] = (unsigned char) b;
++ Sessions[numAddrs].ip[2] = (unsigned char) c;
++ Sessions[numAddrs].ip[3] = (unsigned char) d;
++ }
++ numAddrs++;
++ }
++ }
++ if (!numAddrs) {
++ rp_fatal(&quot;No valid ip addresses found in pool file&quot;);
++ }
++ return numAddrs;
++}
++
++/**********************************************************************
++*%FUNCTION: parsePADITags
++*%ARGUMENTS:
++* type -- tag type
++* len -- tag length
++* data -- tag data
++* extra -- extra user data.
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Picks interesting tags out of a PADI packet
++***********************************************************************/
++void
++parsePADITags(UINT16_t type, UINT16_t len, unsigned char *data,
++ void *extra)
++{
++ switch(type) {
++ case TAG_SERVICE_NAME:
++ /* Should do something -- currently ignored */
++ break;
++ case TAG_RELAY_SESSION_ID:
++ relayId.type = htons(type);
++ relayId.length = htons(len);
++ memcpy(relayId.payload, data, len);
++ break;
++ case TAG_HOST_UNIQ:
++ hostUniq.type = htons(type);
++ hostUniq.length = htons(len);
++ memcpy(hostUniq.payload, data, len);
++ break;
++ }
++}
++
++/**********************************************************************
++*%FUNCTION: parsePADRTags
++*%ARGUMENTS:
++* type -- tag type
++* len -- tag length
++* data -- tag data
++* extra -- extra user data.
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Picks interesting tags out of a PADR packet
++***********************************************************************/
++void
++parsePADRTags(UINT16_t type, UINT16_t len, unsigned char *data,
++ void *extra)
++{
++ switch(type) {
++ case TAG_RELAY_SESSION_ID:
++ relayId.type = htons(type);
++ relayId.length = htons(len);
++ memcpy(relayId.payload, data, len);
++ break;
++ case TAG_HOST_UNIQ:
++ hostUniq.type = htons(type);
++ hostUniq.length = htons(len);
++ memcpy(hostUniq.payload, data, len);
++ break;
++ case TAG_AC_COOKIE:
++ receivedCookie.type = htons(type);
++ receivedCookie.length = htons(len);
++ memcpy(receivedCookie.payload, data, len);
++ break;
++ case TAG_SERVICE_NAME:
++ requestedService.type = htons(type);
++ requestedService.length = htons(len);
++ memcpy(requestedService.payload, data, len);
++ break;
++ }
++}
++
++/**********************************************************************
++*%FUNCTION: findSession
++*%ARGUMENTS:
++* pid -- PID of child which owns session. If PID is 0, searches for
++* empty session slots.
++*%RETURNS:
++* A pointer to the session, or NULL if no such session found.
++*%DESCRIPTION:
++* Searches for specified session.
++**********************************************************************/
++struct ClientSession *
++findSession(pid_t pid)
++{
++ size_t i;
++ for (i=0; i&lt;NumSessionSlots; i++) {
++ if (Sessions[i].pid == pid) {
++ return &amp;Sessions[i];
++ }
++ }
++ return NULL;
++}
++
++/**********************************************************************
++*%FUNCTION: reapSessions
++*%ARGUMENTS:
++* myAddr -- my Ethernet address
++* sock -- my discovery socket
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Reaps children which have exited and removes their sessions
++**********************************************************************/
++void
++reapSessions(unsigned char *myAddr, int sock)
++{
++ int status;
++ pid_t pid;
++ struct ClientSession *session;
++
++ /* Temporary structure for sending PADT's. */
++ PPPoEConnection conn;
++ memset(&amp;conn, 0, sizeof(conn));
++
++ /* Initialize fields of conn which do not depend on peer */
++ memcpy(conn.myEth, myAddr, ETH_ALEN);
++ conn.useHostUniq = 0;
++ conn.discoverySocket = sock;
++
++ while((pid = waitpid(-1, &amp;status, WNOHANG)) &gt; 0) {
++ session = findSession(pid);
++ if (!session) {
++ syslog(LOG_ERR, &quot;Child %d died but couldn't find session!&quot;,
++ (int) pid);
++ } else {
++ syslog(LOG_INFO,
++ &quot;Session %d closed for client %02x:%02x:%02x:%02x:%02x:%02x (%d.%d.%d.%d)&quot;,
++ ntohs(session-&gt;sess),
++ session-&gt;eth[0], session-&gt;eth[1], session-&gt;eth[2],
++ session-&gt;eth[3], session-&gt;eth[4], session-&gt;eth[5],
++ (int) session-&gt;ip[0], (int) session-&gt;ip[1],
++ (int) session-&gt;ip[2], (int) session-&gt;ip[3]);
++ conn.session = session-&gt;sess;
++ memcpy(conn.peerEth, session-&gt;eth, ETH_ALEN);
++ if (session-&gt;recvdPADT) {
++ sendPADT(&amp;conn, &quot;RP-PPPoE: Received PADT from peer&quot;);
++ } else {
++ sendPADT(&amp;conn, &quot;RP-PPPoE: Child pppd process terminated&quot;);
++ }
++ session-&gt;pid = 0;
++ }
++ }
++}
++
++/**********************************************************************
++*%FUNCTION: fatalSys
++*%ARGUMENTS:
++* str -- error message
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Prints a message plus the errno value to stderr and syslog and exits.
++***********************************************************************/
++void
++fatalSys(char const *str)
++{
++ char buf[SMALLBUF];
++ snprintf(buf, SMALLBUF, &quot;%s: %s&quot;, str, strerror(errno));
++ printErr(buf);
++ exit(EXIT_FAILURE);
++}
++
++/**********************************************************************
++*%FUNCTION: sysErr
++*%ARGUMENTS:
++* str -- error message
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Prints a message plus the errno value to syslog.
++***********************************************************************/
++void
++sysErr(char const *str)
++{
++ char buf[1024];
++ sprintf(buf, &quot;%.256s: %.256s&quot;, str, strerror(errno));
++ printErr(buf);
++}
++
++/**********************************************************************
++*%FUNCTION: rp_fatal
++*%ARGUMENTS:
++* str -- error message
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Prints a message to stderr and syslog and exits.
++***********************************************************************/
++void
++rp_fatal(char const *str)
++{
++ printErr(str);
++ exit(EXIT_FAILURE);
++}
++
++/**********************************************************************
++*%FUNCTION: genCookie
++*%ARGUMENTS:
++* peerEthAddr -- peer Ethernet address (6 bytes)
++* myEthAddr -- my Ethernet address (6 bytes)
++* seed -- random cookie seed to make things tasty (16 bytes)
++* cookie -- buffer which is filled with server PID and
++* md5 sum of previous items
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Forms the md5 sum of peer MAC address, our MAC address and seed, useful
++* in a PPPoE Cookie tag.
++***********************************************************************/
++void
++genCookie(unsigned char const *peerEthAddr,
++ unsigned char const *myEthAddr,
++ unsigned char const *seed,
++ unsigned char *cookie)
++{
++ struct MD5Context ctx;
++ pid_t pid = getpid();
++
++ MD5Init(&amp;ctx);
++ MD5Update(&amp;ctx, peerEthAddr, ETH_ALEN);
++ MD5Update(&amp;ctx, myEthAddr, ETH_ALEN);
++ MD5Update(&amp;ctx, seed, SEED_LEN);
++ MD5Final(cookie, &amp;ctx);
++ memcpy(cookie+MD5_LEN, &amp;pid, sizeof(pid));
++}
++
++/**********************************************************************
++*%FUNCTION: processPADI
++*%ARGUMENTS:
++* sock -- Ethernet socket
++* myAddr -- my Ethernet address
++* packet -- PPPoE PADI packet
++* len -- length of received packet
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Sends a PADO packet back to client
++***********************************************************************/
++void
++processPADI(int sock, unsigned char *myAddr,
++ PPPoEPacket *packet, int len)
++{
++ PPPoEPacket pado;
++ PPPoETag acname;
++ PPPoETag servname;
++ PPPoETag cookie;
++ size_t acname_len;
++ unsigned char *cursor = pado.payload;
++ UINT16_t plen;
++
++ /* Ignore PADI's which don't come from a unicast address */
++ if (NOT_UNICAST(packet-&gt;ethHdr.h_source)) {
++ syslog(LOG_ERR, &quot;PADI packet from non-unicast source address&quot;);
++ return;
++ }
++
++ acname.type = htons(TAG_AC_NAME);
++ acname_len = strlen(ACName);
++ acname.length = htons(acname_len);
++ memcpy(acname.payload, ACName, acname_len);
++
++ servname.type = htons(TAG_SERVICE_NAME);
++ servname.length = 0;
++
++ relayId.type = 0;
++ hostUniq.type = 0;
++ parsePacket(packet, parsePADITags, NULL);
++
++ /* Generate a cookie */
++ cookie.type = htons(TAG_AC_COOKIE);
++ cookie.length = htons(COOKIE_LEN);
++ genCookie(packet-&gt;ethHdr.h_source, myAddr, CookieSeed, cookie.payload);
++
++ /* Construct a PADO packet */
++ memcpy(pado.ethHdr.h_dest, packet-&gt;ethHdr.h_source, ETH_ALEN);
++ memcpy(pado.ethHdr.h_source, myAddr, ETH_ALEN);
++ pado.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
++ pado.ver = 1;
++ pado.type = 1;
++ pado.code = CODE_PADO;
++ pado.session = 0;
++ plen = TAG_HDR_SIZE + acname_len;
++
++ CHECK_ROOM(cursor, pado.payload, acname_len+TAG_HDR_SIZE);
++ memcpy(cursor, &amp;acname, acname_len + TAG_HDR_SIZE);
++ cursor += acname_len + TAG_HDR_SIZE;
++
++ CHECK_ROOM(cursor, pado.payload, TAG_HDR_SIZE);
++ memcpy(cursor, &amp;servname, TAG_HDR_SIZE);
++ cursor += TAG_HDR_SIZE;
++ plen += TAG_HDR_SIZE;
++
++ CHECK_ROOM(cursor, pado.payload, TAG_HDR_SIZE + COOKIE_LEN);
++ memcpy(cursor, &amp;cookie, TAG_HDR_SIZE + COOKIE_LEN);
++ cursor += TAG_HDR_SIZE + COOKIE_LEN;
++ plen += TAG_HDR_SIZE + COOKIE_LEN;
++
++ if (relayId.type) {
++ CHECK_ROOM(cursor, pado.payload, ntohs(relayId.length) + TAG_HDR_SIZE);
++ memcpy(cursor, &amp;relayId, ntohs(relayId.length) + TAG_HDR_SIZE);
++ cursor += ntohs(relayId.length) + TAG_HDR_SIZE;
++ plen += ntohs(relayId.length) + TAG_HDR_SIZE;
++ }
++ if (hostUniq.type) {
++ CHECK_ROOM(cursor, pado.payload, ntohs(hostUniq.length)+TAG_HDR_SIZE);
++ memcpy(cursor, &amp;hostUniq, ntohs(hostUniq.length) + TAG_HDR_SIZE);
++ cursor += ntohs(hostUniq.length) + TAG_HDR_SIZE;
++ plen += ntohs(hostUniq.length) + TAG_HDR_SIZE;
++ }
++ pado.length = htons(plen);
++ sendPacket(NULL, sock, &amp;pado, (int) (plen + HDR_SIZE));
++}
++
++/**********************************************************************
++*%FUNCTION: processPADT
++*%ARGUMENTS:
++* sock -- Ethernet socket
++* myAddr -- my Ethernet address
++* packet -- PPPoE PADT packet
++* len -- length of received packet
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Kills session whose session-ID is in PADT packet.
++***********************************************************************/
++void
++processPADT(int sock, unsigned char *myAddr,
++ PPPoEPacket *packet, int len)
++{
++ size_t i;
++
++ /* Ignore PADT's not directed at us */
++ if (memcmp(packet-&gt;ethHdr.h_dest, myAddr, ETH_ALEN)) return;
++
++ /* Get session's index */
++ i = ntohs(packet-&gt;session) - 1 - SessOffset;
++ if (i &gt;= NumSessionSlots) return;
++ if (Sessions[i].sess != packet-&gt;session) {
++ syslog(LOG_ERR, &quot;Session index %u doesn't match session number %u&quot;,
++ (unsigned int) i, (unsigned int) ntohs(packet-&gt;session));
++ return;
++ }
++ if (Sessions[i].pid) {
++ Sessions[i].recvdPADT = 1;
++ parsePacket(packet, parseLogErrs, NULL);
++ kill(Sessions[i].pid, SIGTERM);
++ }
++}
++
++/**********************************************************************
++*%FUNCTION: processPADR
++*%ARGUMENTS:
++* sock -- Ethernet socket
++* myAddr -- my Ethernet address
++* packet -- PPPoE PADR packet
++* len -- length of received packet
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Sends a PADS packet back to client and starts a PPP session if PADR
++* packet is OK.
++***********************************************************************/
++void
++processPADR(int sock, unsigned char *myAddr,
++ PPPoEPacket *packet, int len)
++{
++ unsigned char cookieBuffer[COOKIE_LEN];
++ struct ClientSession *cliSession;
++ pid_t child;
++ PPPoEPacket pads;
++ unsigned char *cursor = pads.payload;
++ UINT16_t plen;
++ PPPoETag servname;
++
++ /* Initialize some globals */
++ relayId.type = 0;
++ hostUniq.type = 0;
++ receivedCookie.type = 0;
++ requestedService.type = 0;
++
++ /* Ignore PADR's not directed at us */
++ if (memcmp(packet-&gt;ethHdr.h_dest, myAddr, ETH_ALEN)) return;
++
++ /* Ignore PADR's from non-unicast addresses */
++ if (NOT_UNICAST(packet-&gt;ethHdr.h_source)) {
++ syslog(LOG_ERR, &quot;PADR packet from non-unicast source address&quot;);
++ return;
++ }
++
++ parsePacket(packet, parsePADRTags, NULL);
++
++ /* Check that everything's cool */
++ if (!receivedCookie.type) {
++ /* Drop it -- do not send error PADS */
++ return;
++ }
++
++ /* Is cookie kosher? */
++ if (receivedCookie.length != htons(COOKIE_LEN)) {
++ /* Drop it -- do not send error PADS */
++ return;
++ }
++
++ genCookie(packet-&gt;ethHdr.h_source, myAddr, CookieSeed, cookieBuffer);
++ if (memcmp(receivedCookie.payload, cookieBuffer, COOKIE_LEN)) {
++ /* Drop it -- do not send error PADS */
++ return;
++ }
++
++ /* Check service name -- we only offer service &quot;&quot; */
++ if (!requestedService.type) {
++ syslog(LOG_ERR, &quot;Received PADR packet with no SERVICE_NAME tag&quot;);
++ sendErrorPADS(sock, myAddr, packet-&gt;ethHdr.h_source,
++ TAG_SERVICE_NAME_ERROR, &quot;RP-PPPoE: Server: No service name tag&quot;);
++ return;
++ }
++
++ if (requestedService.length) {
++ syslog(LOG_ERR, &quot;Received PADR packet asking for unsupported service %.*s&quot;, (int) ntohs(requestedService.length), requestedService.payload);
++ sendErrorPADS(sock, myAddr, packet-&gt;ethHdr.h_source,
++ TAG_SERVICE_NAME_ERROR, &quot;RP-PPPoE: Server: Invalid service name tag&quot;);
++ return;
++ }
++
++ /* Looks cool... find a slot for the session */
++ cliSession = findSession(0);
++ if (!cliSession) {
++ syslog(LOG_ERR, &quot;No client slots available (%02x:%02x:%02x:%02x:%02x:%02x)&quot;,
++ (unsigned int) packet-&gt;ethHdr.h_source[0],
++ (unsigned int) packet-&gt;ethHdr.h_source[1],
++ (unsigned int) packet-&gt;ethHdr.h_source[2],
++ (unsigned int) packet-&gt;ethHdr.h_source[3],
++ (unsigned int) packet-&gt;ethHdr.h_source[4],
++ (unsigned int) packet-&gt;ethHdr.h_source[5]);
++ sendErrorPADS(sock, myAddr, packet-&gt;ethHdr.h_source,
++ TAG_AC_SYSTEM_ERROR, &quot;RP-PPPoE: Server: No client slots available&quot;);
++ return;
++ }
++
++ /* Set up client session peer Ethernet address */
++ memcpy(cliSession-&gt;eth, packet-&gt;ethHdr.h_source, ETH_ALEN);
++ cliSession-&gt;recvdPADT = 0;
++
++ /* Create child process, send PADS packet back */
++ child = fork();
++ if (child &lt; 0) {
++ sendErrorPADS(sock, myAddr, packet-&gt;ethHdr.h_source,
++ TAG_AC_SYSTEM_ERROR, &quot;RP-PPPoE: Server: Unable to start session process&quot;);
++ return;
++ }
++ if (child != 0) {
++ /* In the parent process. Mark pid in session slot */
++ cliSession-&gt;pid = child;
++ return;
++ }
++
++ /* In the child process. */
++
++ /* pppd has a nasty habit of killing all processes in its process group.
++ Start a new session to stop pppd from killing us! */
++ setsid();
++
++ /* Send PADS and Start pppd */
++ memcpy(pads.ethHdr.h_dest, packet-&gt;ethHdr.h_source, ETH_ALEN);
++ memcpy(pads.ethHdr.h_source, myAddr, ETH_ALEN);
++ pads.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
++ pads.ver = 1;
++ pads.type = 1;
++ pads.code = CODE_PADS;
++
++ pads.session = cliSession-&gt;sess;
++ plen = 0;
++
++ servname.type = htons(TAG_SERVICE_NAME);
++ servname.length = 0;
++
++ memcpy(cursor, &amp;servname, TAG_HDR_SIZE);
++ cursor += TAG_HDR_SIZE;
++ plen += TAG_HDR_SIZE;
++
++ if (relayId.type) {
++ memcpy(cursor, &amp;relayId, ntohs(relayId.length) + TAG_HDR_SIZE);
++ cursor += ntohs(relayId.length) + TAG_HDR_SIZE;
++ plen += ntohs(relayId.length) + TAG_HDR_SIZE;
++ }
++ if (hostUniq.type) {
++ memcpy(cursor, &amp;hostUniq, ntohs(hostUniq.length) + TAG_HDR_SIZE);
++ cursor += ntohs(hostUniq.length) + TAG_HDR_SIZE;
++ plen += ntohs(hostUniq.length) + TAG_HDR_SIZE;
++ }
++ pads.length = htons(plen);
++ sendPacket(NULL, sock, &amp;pads, (int) (plen + HDR_SIZE));
++ startPPPD(cliSession);
++}
++
++/**********************************************************************
++*%FUNCTION: childHandler
++*%ARGUMENTS:
++* sig -- signal number
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Called by SIGCHLD. Writes one byte to Pipe to wake up the select
++* loop and cause reaping of dead sessions
++***********************************************************************/
++void
++childHandler(int sig)
++{
++ if (!ReapPending) {
++ ReapPending = 1;
++ write(Pipe[1], &amp;ReapPending, 1);
++ }
++}
++
++/**********************************************************************
++*%FUNCTION: usage
++*%ARGUMENTS:
++* argv0 -- argv[0] from main
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Prints usage instructions
++***********************************************************************/
++void
++usage(char const *argv0)
++{
++ fprintf(stderr, &quot;Usage: %s [options]\n&quot;, argv0);
++ fprintf(stderr, &quot;Options:\n&quot;);
++#ifdef USE_BPF
++ fprintf(stderr, &quot; -I if_name -- Specify interface (REQUIRED)\n&quot;);
++#else
++ fprintf(stderr, &quot; -I if_name -- Specify interface (default %s.)\n&quot;,
++ DEFAULT_IF);
++#endif
++ fprintf(stderr, &quot; -T timeout -- Specify inactivity timeout in seconds.\n&quot;);
++ fprintf(stderr, &quot; -C name -- Set access concentrator name.\n&quot;);
++ fprintf(stderr, &quot; -m MSS -- Clamp incoming and outgoing MSS options.\n&quot;);
++ fprintf(stderr, &quot; -L ip -- Set local IP address.\n&quot;);
++ fprintf(stderr, &quot; -R ip -- Set start address of remote IP pool.\n&quot;);
++ fprintf(stderr, &quot; -p fname -- Optain IP address pool from specified file.\n&quot;);
++ fprintf(stderr, &quot; -N num -- Allow 'num' concurrent sessions.\n&quot;);
++ fprintf(stderr, &quot; -o offset -- Assign session numbers starting at offset+1.\n&quot;);
++ fprintf(stderr, &quot; -f disc:sess -- Set Ethernet frame types (hex).\n&quot;);
++ fprintf(stderr, &quot; -s -- Use synchronous PPP mode.\n&quot;);
++#ifdef HAVE_LINUX_KERNEL_PPPOE
++ fprintf(stderr, &quot; -k -- Use kernel-mode PPPoE.\n&quot;);
++#endif
++ fprintf(stderr, &quot; -h -- Print usage information.\n\n&quot;);
++ fprintf(stderr, &quot;PPPoE-Server Version %s, Copyright (C) 2001 Roaring Penguin Software Inc.\n&quot;, VERSION);
++ fprintf(stderr, &quot;PPPoE-Server comes with ABSOLUTELY NO WARRANTY.\n&quot;);
++ fprintf(stderr, &quot;This is free software, and you are welcome to redistribute it\n&quot;);
++ fprintf(stderr, &quot;under the terms of the GNU General Public License, version 2\n&quot;);
++ fprintf(stderr, &quot;or (at your option) any later version.\n&quot;);
++ fprintf(stderr, &quot;<A HREF="http://www.roaringpenguin.com\n">http://www.roaringpenguin.com\n</A>&quot;);
++}
++
++/**********************************************************************
++*%FUNCTION: main
++*%ARGUMENTS:
++* argc, argv -- usual suspects
++*%RETURNS:
++* Exit status
++*%DESCRIPTION:
++* Main program of PPPoE server
++***********************************************************************/
++int
++main(int argc, char **argv)
++{
++
++ FILE *fp;
++ int i;
++ int opt;
++ unsigned char myAddr[ETH_ALEN];
++ PPPoEPacket packet;
++ int len;
++ int sock;
++ int d[IPV4ALEN];
++ int beDaemon = 1;
++ struct sigaction act;
++ int maxFD;
++ unsigned int discoveryType, sessionType;
++ char *addressPoolFname = NULL;
++
++#ifndef HAVE_LINUX_KERNEL_PPPOE
++ char *options = &quot;hI:C:L:R:T:m:FN:f:o:sp:&quot;;
++#else
++ char *options = &quot;hI:C:L:R:T:m:FN:f:o:skp:&quot;;
++#endif
++
++ /* Initialize syslog */
++ openlog(&quot;pppoe-server&quot;, LOG_PID, LOG_DAEMON);
++
++ /* Default number of session slots */
++ NumSessionSlots = DEFAULT_MAX_SESSIONS;
++
++ /* Parse command-line options */
++ while((opt = getopt(argc, argv, options)) != -1) {
++ switch(opt) {
++#ifdef HAVE_LINUX_KERNEL_PPPOE
++ case 'k':
++ UseLinuxKernelModePPPoE = 1;
++ break;
++#endif
++ case 'p':
++ addressPoolFname = optarg;
++ break;
++ case 's':
++ Synchronous = 1;
++ /* Pass the Synchronous option on to pppoe */
++ snprintf(PppoeOptions + strlen(PppoeOptions),
++ SMALLBUF-strlen(PppoeOptions),
++ &quot; -s&quot;);
++ break;
++ case 'f':
++ if (sscanf(optarg, &quot;%x:%x&quot;, &amp;discoveryType, &amp;sessionType) != 2) {
++ fprintf(stderr, &quot;Illegal argument to -f: Should be disc:sess in hex\n&quot;);
++ exit(EXIT_FAILURE);
++ }
++ Eth_PPPOE_Discovery = (UINT16_t) discoveryType;
++ Eth_PPPOE_Session = (UINT16_t) sessionType;
++ /* This option gets passed to pppoe */
++ snprintf(PppoeOptions + strlen(PppoeOptions),
++ SMALLBUF-strlen(PppoeOptions),
++ &quot; -%c %s&quot;, opt, optarg);
++ break;
++ case 'F':
++ beDaemon = 0;
++ break;
++ case 'N':
++ if (sscanf(optarg, &quot;%d&quot;, &amp;opt) != 1) {
++ usage(argv[0]);
++ exit(EXIT_FAILURE);
++ }
++ if (opt &lt;= 0) {
++ fprintf(stderr, &quot;-N: Value must be positive\n&quot;);
++ exit(EXIT_FAILURE);
++ }
++ NumSessionSlots = opt;
++ break;
++ case 'o':
++ if (sscanf(optarg, &quot;%d&quot;, &amp;opt) != 1) {
++ usage(argv[0]);
++ exit(EXIT_FAILURE);
++ }
++ if (opt &lt; 0) {
++ fprintf(stderr, &quot;-o: Value must be non-negative\n&quot;);
++ exit(EXIT_FAILURE);
++ }
++ SessOffset = (size_t) opt;
++ break;
++
++ case 'I':
++ SET_STRING(IfName, optarg);
++ break;
++ case 'C':
++ SET_STRING(ACName, optarg);
++ break;
++ case 'L':
++ case 'R':
++ /* Get local/remote IP address */
++ if (sscanf(optarg, &quot;%d.%d.%d.%d&quot;, &amp;d[0], &amp;d[1], &amp;d[2], &amp;d[3]) != 4) {
++ usage(argv[0]);
++ exit(EXIT_FAILURE);
++ }
++ for (i=0; i&lt;IPV4ALEN; i++) {
++ if (d[i] &lt; 0 || d[i] &gt; 255) {
++ usage(argv[0]);
++ exit(EXIT_FAILURE);
++ }
++ if (opt == 'L') {
++ LocalIP[i] = (unsigned char) d[i];
++ } else {
++ RemoteIP[i] = (unsigned char) d[i];
++ }
++ }
++ break;
++ case 'T':
++ case 'm':
++ /* These just get passed to pppoe */
++ snprintf(PppoeOptions + strlen(PppoeOptions),
++ SMALLBUF-strlen(PppoeOptions),
++ &quot; -%c %s&quot;, opt, optarg);
++ break;
++ case 'h':
++ usage(argv[0]);
++ exit(EXIT_SUCCESS);
++ }
++ }
++
++#ifdef USE_LINUX_PACKET
++#ifndef HAVE_STRUCT_SOCKADDR_LL
++ fprintf(stderr, &quot;The PPPoE relay does not work on Linux 2.0 kernels.\n&quot;);
++ exit(EXIT_FAILURE);
++#endif
++#endif
++
++ if (!IfName) {
++ IfName = DEFAULT_IF;
++ }
++
++ if (!ACName) {
++ ACName = malloc(HOSTNAMELEN);
++ if (gethostname(ACName, HOSTNAMELEN) &lt; 0) {
++ fatalSys(&quot;gethostname&quot;);
++ }
++ }
++
++ /* If address pool filename given, count number of addresses */
++ if (addressPoolFname) {
++ NumSessionSlots = parseAddressPool(addressPoolFname, 0);
++ }
++
++ /* Max 65534 - SessOffset sessions */
++ if (NumSessionSlots + SessOffset &gt; 65534) {
++ fprintf(stderr, &quot;-N and -o options must add up to at most 65534\n&quot;);
++ exit(EXIT_FAILURE);
++ }
++
++ /* Allocate memory for sessions */
++ Sessions = calloc(NumSessionSlots, sizeof(struct ClientSession));
++ if (!Sessions) {
++ rp_fatal(&quot;Cannot allocate memory for session slots&quot;);
++ }
++
++ /* Fill in remote IP addresses from pool */
++ if (addressPoolFname) {
++ (void) parseAddressPool(addressPoolFname, 1);
++ }
++
++ /* For testing -- generate sequential remote IP addresses */
++ for(i=0; i&lt;NumSessionSlots; i++) {
++ Sessions[i].pid = 0;
++ Sessions[i].sess = htons(i+1+SessOffset);
++
++ if (!addressPoolFname) {
++ memcpy(Sessions[i].ip, RemoteIP, sizeof(RemoteIP));
++
++ /* Increment IP */
++ RemoteIP[3]++;
++ if (!RemoteIP[3]) {
++ RemoteIP[3] = 0;
++ RemoteIP[2]++;
++ if (!RemoteIP[2]) {
++ RemoteIP[1]++;
++ if (!RemoteIP[1]) {
++ RemoteIP[0]++;
++ }
++ }
++ }
++ }
++ }
++
++ /* Daemonize -- UNIX Network Programming, Vol. 1, Stevens */
++ if (beDaemon) {
++ i = fork();
++ if (i &lt; 0) {
++ fatalSys(&quot;fork&quot;);
++ } else if (i != 0) {
++ /* parent */
++ exit(EXIT_SUCCESS);
++ }
++ setsid();
++ signal(SIGHUP, SIG_IGN);
++ i = fork();
++ if (i &lt; 0) {
++ fatalSys(&quot;fork&quot;);
++ } else if (i != 0) {
++ exit(EXIT_SUCCESS);
++ }
++
++ chdir(&quot;/&quot;);
++ closelog();
++ for (i=0; i&lt;CLOSEFD; i++) close(i);
++ /* We nuked our syslog descriptor... */
++ openlog(&quot;pppoe-server&quot;, LOG_PID, LOG_DAEMON);
++ }
++
++ /* Initialize our random cookie. Try /dev/urandom; if that fails,
++ use PID and rand() */
++ fp = fopen(&quot;/dev/urandom&quot;, &quot;r&quot;);
++ if (fp) {
++ fread(&amp;CookieSeed, 1, SEED_LEN, fp);
++ fclose(fp);
++ } else {
++ CookieSeed[0] = getpid() &amp; 0xFF;
++ CookieSeed[1] = (getpid() &gt;&gt; 8) &amp; 0xFF;
++ for (i=2; i&lt;SEED_LEN; i++) {
++ CookieSeed[i] = (rand() &gt;&gt; (i % 9)) &amp; 0xFF;
++ }
++ }
++
++ sock = openInterface(IfName, Eth_PPPOE_Discovery, myAddr);
++
++ /* Set signal handler for SIGCHLD */
++ act.sa_handler = childHandler;
++ sigemptyset(&amp;act.sa_mask);
++ act.sa_flags = SA_NOCLDSTOP | SA_RESTART;
++ if (sigaction(SIGCHLD, &amp;act, NULL) &lt; 0) {
++ fatalSys(&quot;sigaction&quot;);
++ }
++
++ /* Set up pipe for signal handler */
++ if (pipe(Pipe) &lt; 0) {
++ fatalSys(&quot;pipe&quot;);
++ }
++
++ /* Main server loop */
++ maxFD = sock;
++ if (Pipe[0] &gt; maxFD) maxFD = Pipe[0];
++ maxFD++;
++
++ for(;;) {
++ fd_set readable;
++ FD_ZERO(&amp;readable);
++ FD_SET(sock, &amp;readable);
++ FD_SET(Pipe[0], &amp;readable);
++
++ while(1) {
++ i = select(maxFD, &amp;readable, NULL, NULL, NULL);
++ if (i &gt;= 0 || errno != EINTR) break;
++ }
++ if (i &lt; 0) {
++ fatalSys(&quot;select&quot;);
++ }
++
++ if (FD_ISSET(Pipe[0], &amp;readable)) {
++ /* Clear pipe */
++ char buf[SMALLBUF];
++ read(Pipe[0], buf, SMALLBUF);
++ }
++
++ if (ReapPending) {
++ ReapPending = 0;
++ reapSessions(myAddr, sock);
++ }
++ if (!FD_ISSET(sock, &amp;readable)) {
++ continue;
++ }
++
++ if (receivePacket(sock, &amp;packet, &amp;len) &lt; 0) {
++ continue;
++ }
++
++ /* Check length */
++ if (ntohs(packet.length) + HDR_SIZE &gt; len) {
++ syslog(LOG_ERR, &quot;Bogus PPPoE length field (%u)&quot;,
++ (unsigned int) ntohs(packet.length));
++ continue;
++ }
++
++ /* Sanity check on packet */
++ if (packet.ver != 1 || packet.type != 1) {
++ /* Syslog an error */
++ continue;
++ }
++ switch(packet.code) {
++ case CODE_PADI:
++ processPADI(sock, myAddr, &amp;packet, len);
++ break;
++ case CODE_PADR:
++ processPADR(sock, myAddr, &amp;packet, len);
++ break;
++ case CODE_PADT:
++ /* Kill the child */
++ processPADT(sock, myAddr, &amp;packet, len);
++ break;
++ case CODE_SESS:
++ /* Ignore SESS -- children will handle them */
++ break;
++ case CODE_PADO:
++ case CODE_PADS:
++ /* Ignore PADO and PADS totally */
++ break;
++ default:
++ /* Syslog an error */
++ break;
++ }
++ }
++ return 0;
++}
++
++/**********************************************************************
++*%FUNCTION: sendErrorPADS
++*%ARGUMENTS:
++* sock -- socket to write to
++* source -- source Ethernet address
++* dest -- destination Ethernet address
++* errorTag -- error tag
++* errorMsg -- error message
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Sends a PADS packet with an error message
++***********************************************************************/
++void
++sendErrorPADS(int sock,
++ unsigned char *source,
++ unsigned char *dest,
++ int errorTag,
++ char *errorMsg)
++{
++ PPPoEPacket pads;
++ unsigned char *cursor = pads.payload;
++ UINT16_t plen;
++ PPPoETag err;
++ int elen = strlen(errorMsg);
++
++ memcpy(pads.ethHdr.h_dest, dest, ETH_ALEN);
++ memcpy(pads.ethHdr.h_source, source, ETH_ALEN);
++ pads.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
++ pads.ver = 1;
++ pads.type = 1;
++ pads.code = CODE_PADS;
++
++ pads.session = htons(0);
++ plen = 0;
++
++ err.type = htons(errorTag);
++ err.length = htons(elen);
++
++ memcpy(err.payload, errorMsg, elen);
++ memcpy(cursor, &amp;err, TAG_HDR_SIZE+elen);
++ cursor += TAG_HDR_SIZE + elen;
++ plen += TAG_HDR_SIZE + elen;
++
++ if (relayId.type) {
++ memcpy(cursor, &amp;relayId, ntohs(relayId.length) + TAG_HDR_SIZE);
++ cursor += ntohs(relayId.length) + TAG_HDR_SIZE;
++ plen += ntohs(relayId.length) + TAG_HDR_SIZE;
++ }
++ if (hostUniq.type) {
++ memcpy(cursor, &amp;hostUniq, ntohs(hostUniq.length) + TAG_HDR_SIZE);
++ cursor += ntohs(hostUniq.length) + TAG_HDR_SIZE;
++ plen += ntohs(hostUniq.length) + TAG_HDR_SIZE;
++ }
++ pads.length = htons(plen);
++ sendPacket(NULL, sock, &amp;pads, (int) (plen + HDR_SIZE));
++}
++
++
++/**********************************************************************
++*%FUNCTION: startPPPDUserMode
++*%ARGUMENTS:
++* session -- client session record
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Starts PPPD for user-mode PPPoE
++***********************************************************************/
++void
++startPPPDUserMode(struct ClientSession *session)
++{
++ /* Leave some room */
++ char *argv[20];
++
++ char buffer[SMALLBUF];
++
++ argv[0] = &quot;pppd&quot;;
++ argv[1] = &quot;pty&quot;;
++
++ snprintf(buffer, SMALLBUF, &quot;%s -n -I %s -e %d:%02x:%02x:%02x:%02x:%02x:%02x%s&quot;,
++ PPPOE_PATH, IfName,
++ ntohs(session-&gt;sess),
++ session-&gt;eth[0], session-&gt;eth[1], session-&gt;eth[2],
++ session-&gt;eth[3], session-&gt;eth[4], session-&gt;eth[5],
++ PppoeOptions);
++ argv[2] = strdup(buffer);
++ if (!argv[2]) {
++ /* TODO: Send a PADT */
++ exit(EXIT_FAILURE);
++ }
++
++ argv[3] = &quot;file&quot;;
++ argv[4] = PPPOE_SERVER_OPTIONS;
++
++ snprintf(buffer, SMALLBUF, &quot;%d.%d.%d.%d:%d.%d.%d.%d&quot;,
++ (int) LocalIP[0], (int) LocalIP[1],
++ (int) LocalIP[2], (int) LocalIP[3],
++ (int) session-&gt;ip[0], (int) session-&gt;ip[1],
++ (int) session-&gt;ip[2], (int) session-&gt;ip[3]);
++ syslog(LOG_INFO,
++ &quot;Session %d created for client %02x:%02x:%02x:%02x:%02x:%02x (%d.%d.%d.%d)&quot;,
++ ntohs(session-&gt;sess),
++ session-&gt;eth[0], session-&gt;eth[1], session-&gt;eth[2],
++ session-&gt;eth[3], session-&gt;eth[4], session-&gt;eth[5],
++ (int) session-&gt;ip[0], (int) session-&gt;ip[1],
++ (int) session-&gt;ip[2], (int) session-&gt;ip[3]);
++ argv[5] = buffer; /* No need for strdup -- about to execv! */
++ argv[6] = &quot;nodetach&quot;;
++ argv[7] = &quot;noaccomp&quot;;
++ argv[8] = &quot;nobsdcomp&quot;;
++ argv[9] = &quot;nodeflate&quot;;
++ argv[10] = &quot;nopcomp&quot;;
++ argv[11] = &quot;novj&quot;;
++ argv[12] = &quot;novjccomp&quot;;
++ argv[13] = &quot;default-asyncmap&quot;;
++ if (Synchronous) {
++ argv[14] = &quot;sync&quot;;
++ argv[15] = NULL;
++ } else {
++ argv[14] = NULL;
++ }
++
++ execv(PPPD_PATH, argv);
++ exit(EXIT_FAILURE);
++}
++
++/**********************************************************************
++*%FUNCTION: startPPPDLinuxKernelMode
++*%ARGUMENTS:
++* session -- client session record
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Starts PPPD for kernel-mode PPPoE on Linux
++***********************************************************************/
++void
++startPPPDLinuxKernelMode(struct ClientSession *session)
++{
++ /* Leave some room */
++ char *argv[20];
++
++ char buffer[SMALLBUF];
++
++ argv[0] = &quot;pppd&quot;;
++ argv[1] = &quot;plugin&quot;;
++ argv[2] = PLUGIN_PATH;
++ argv[3] = IfName;
++ snprintf(buffer, SMALLBUF, &quot;%d:%02x:%02x:%02x:%02x:%02x:%02x&quot;,
++ ntohs(session-&gt;sess),
++ session-&gt;eth[0], session-&gt;eth[1], session-&gt;eth[2],
++ session-&gt;eth[3], session-&gt;eth[4], session-&gt;eth[5]);
++ argv[4] = &quot;rp_pppoe_sess&quot;;
++ argv[5] = strdup(buffer);
++ if (!argv[5]) {
++ /* TODO: Send a PADT */
++ exit(EXIT_FAILURE);
++ }
++ argv[6] = &quot;file&quot;;
++ argv[7] = PPPOE_SERVER_OPTIONS;
++
++ snprintf(buffer, SMALLBUF, &quot;%d.%d.%d.%d:%d.%d.%d.%d&quot;,
++ (int) LocalIP[0], (int) LocalIP[1],
++ (int) LocalIP[2], (int) LocalIP[3],
++ (int) session-&gt;ip[0], (int) session-&gt;ip[1],
++ (int) session-&gt;ip[2], (int) session-&gt;ip[3]);
++ syslog(LOG_INFO,
++ &quot;Session %d created for client %02x:%02x:%02x:%02x:%02x:%02x (%d.%d.%d.%d)&quot;,
++ ntohs(session-&gt;sess),
++ session-&gt;eth[0], session-&gt;eth[1], session-&gt;eth[2],
++ session-&gt;eth[3], session-&gt;eth[4], session-&gt;eth[5],
++ (int) session-&gt;ip[0], (int) session-&gt;ip[1],
++ (int) session-&gt;ip[2], (int) session-&gt;ip[3]);
++ argv[8] = buffer;
++ argv[9] = &quot;nodetach&quot;;
++ argv[10] = &quot;noaccomp&quot;;
++ argv[11] = &quot;nobsdcomp&quot;;
++ argv[12] = &quot;nodeflate&quot;;
++ argv[13] = &quot;nopcomp&quot;;
++ argv[14] = &quot;novj&quot;;
++ argv[15] = &quot;novjccomp&quot;;
++ argv[16] = &quot;default-asyncmap&quot;;
++ argv[17] = NULL;
++ execv(PPPD_PATH, argv);
++ exit(EXIT_FAILURE);
++}
++
++/**********************************************************************
++*%FUNCTION: startPPPD
++*%ARGUMENTS:
++* session -- client session record
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Starts PPPD
++***********************************************************************/
++void
++startPPPD(struct ClientSession *session)
++{
++ if (UseLinuxKernelModePPPoE) startPPPDLinuxKernelMode(session);
++ else startPPPDUserMode(session);
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/src/pppoe-server.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/src/pppoe-sniff.c
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/src/pppoe-sniff.c (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/src/pppoe-sniff.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,258 @@
++/***********************************************************************
++*
++* pppoe-sniff.c
++*
++* Sniff a network for likely-looking PPPoE frames and deduce the value
++* to supply to PPPOE_EXTRA in /etc/ppp/pppoe.conf. USE AT YOUR OWN RISK.
++*
++* Copyright (C) 2000 by Roaring Penguin Software Inc.
++*
++* This program may be distributed according to the terms of the GNU
++* General Public License, version 2 or (at your option) any later version.
++*
++***********************************************************************/
++
++static char const RCSID[] =
++&quot;$Id: pppoe-sniff.c 195724 2001-06-11 13:49:39Z gc $&quot;;
++
++#include &quot;pppoe.h&quot;
++
++#ifdef HAVE_GETOPT_H
++#include &lt;getopt.h&gt;
++#endif
++
++#include &lt;errno.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;string.h&gt;
++#include &lt;stdlib.h&gt;
++
++#ifdef USE_DLPI
++#include &lt;sys/dlpi.h&gt;
++/* function declarations */
++void dlpromisconreq( int fd, u_long level);
++void dlokack(int fd, char *bufp);
++#endif
++
++/* Default interface if no -I option given */
++#define DEFAULT_IF &quot;eth0&quot;
++
++/* Global vars */
++int SeenPADR = 0;
++int SeenSess = 0;
++UINT16_t SessType, DiscType;
++
++char *IfName = NULL; /* Interface name */
++char *ServiceName = NULL; /* Service name */
++
++/**********************************************************************
++*%FUNCTION: parsePADRTags
++*%ARGUMENTS:
++* type -- tag type
++* len -- tag length
++* data -- tag data
++* extra -- extra user data.
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Picks interesting tags out of a PADR packet
++***********************************************************************/
++void
++parsePADRTags(UINT16_t type, UINT16_t len, unsigned char *data,
++ void *extra)
++{
++ switch(type) {
++ case TAG_SERVICE_NAME:
++ ServiceName = malloc(len+1);
++ if (ServiceName) {
++ memcpy(ServiceName, data, len);
++ ServiceName[len] = 0;
++ }
++ break;
++ }
++}
++
++/**********************************************************************
++*%FUNCTION: fatalSys
++*%ARGUMENTS:
++* str -- error message
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Prints a message plus the errno value to stderr and exits.
++***********************************************************************/
++void
++fatalSys(char const *str)
++{
++ char buf[1024];
++ sprintf(buf, &quot;%.256s: %.256s&quot;, str, strerror(errno));
++ printErr(buf);
++ exit(1);
++}
++
++/**********************************************************************
++*%FUNCTION: rp_fatal
++*%ARGUMENTS:
++* str -- error message
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Prints a message to stderr and syslog and exits.
++***********************************************************************/
++void
++rp_fatal(char const *str)
++{
++ printErr(str);
++ exit(1);
++}
++
++/**********************************************************************
++*%FUNCTION: usage
++*%ARGUMENTS:
++* argv0 -- program name
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Prints usage information and exits.
++***********************************************************************/
++void
++usage(char const *argv0)
++{
++ fprintf(stderr, &quot;Usage: %s [options]\n&quot;, argv0);
++ fprintf(stderr, &quot;Options:\n&quot;);
++ fprintf(stderr, &quot; -I if_name -- Specify interface (default %s.)\n&quot;,
++ DEFAULT_IF);
++ fprintf(stderr, &quot; -V -- Print version and exit.\n&quot;);
++ fprintf(stderr, &quot;\nPPPoE Version %s, Copyright (C) 2000 Roaring Penguin Software Inc.\n&quot;, VERSION);
++ fprintf(stderr, &quot;PPPoE comes with ABSOLUTELY NO WARRANTY.\n&quot;);
++ fprintf(stderr, &quot;This is free software, and you are welcome to redistribute it under the terms\n&quot;);
++ fprintf(stderr, &quot;of the GNU General Public License, version 2 or any later version.\n&quot;);
++ fprintf(stderr, &quot;<A HREF="http://www.roaringpenguin.com\n">http://www.roaringpenguin.com\n</A>&quot;);
++ exit(0);
++}
++
++#if !defined(USE_LINUX_PACKET) &amp;&amp; !defined(USE_DLPI)
++
++int
++main()
++{
++ fprintf(stderr, &quot;Sorry, pppoe-sniff works only on Linux.\n&quot;);
++ return 1;
++}
++
++#else
++
++/**********************************************************************
++*%FUNCTION: main
++*%ARGUMENTS:
++* argc, argv -- count and values of command-line arguments
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Main program
++***********************************************************************/
++int
++main(int argc, char *argv[])
++{
++ int opt;
++ int sock;
++ PPPoEPacket pkt;
++ int size;
++#ifdef USE_DLPI
++ long buf[MAXDLBUF];
++#endif
++
++ while((opt = getopt(argc, argv, &quot;I:V&quot;)) != -1) {
++ switch(opt) {
++ case 'I':
++ SET_STRING(IfName, optarg);
++ break;
++ case 'V':
++ printf(&quot;pppoe-sniff: Roaring Penguin PPPoE Version %s\n&quot;, VERSION);
++ exit(0);
++ default:
++ usage(argv[0]);
++ }
++ }
++
++ /* Pick a default interface name */
++ if (!IfName) {
++ IfName = DEFAULT_IF;
++ }
++
++ /* Open the interface */
++#ifdef USE_DLPI
++ sock = openInterface(IfName, Eth_PPPOE_Discovery, NULL);
++ dlpromisconreq(sock, DL_PROMISC_PHYS);
++ dlokack(sock, (char *)buf);
++ dlpromisconreq(sock, DL_PROMISC_SAP);
++ dlokack(sock, (char *)buf);
++#else
++
++ sock = openInterface(IfName, ETH_P_ALL, NULL);
++
++#endif
++
++ /* We assume interface is in promiscuous mode -- use ifconfig to
++ ensure this */
++ fprintf(stderr, &quot;Sniffing for PADR. Start your connection on another machine...\n&quot;);
++ while (!SeenPADR) {
++ if (receivePacket(sock, &amp;pkt, &amp;size) &lt; 0) continue;
++ if (ntohs(pkt.length) + HDR_SIZE &gt; size) continue;
++ if (pkt.ver != 1 || pkt.type != 1) continue;
++ if (pkt.code != CODE_PADR) continue;
++
++ /* Looks promising... parse it */
++ if (parsePacket(&amp;pkt, parsePADRTags, NULL) &lt; 0) {
++ continue;
++ }
++ DiscType = ntohs(pkt.ethHdr.h_proto);
++ fprintf(stderr, &quot;\nExcellent! Sniffed a likely-looking PADR.\n&quot;);
++ break;
++ }
++
++ while (!SeenSess) {
++ if (receivePacket(sock, &amp;pkt, &amp;size) &lt; 0) continue;
++ if (ntohs(pkt.length) + HDR_SIZE &gt; size) continue;
++ if (pkt.ver != 1 || pkt.type != 1) continue;
++ if (pkt.code != CODE_SESS) continue;
++
++ /* Cool! */
++ SessType = ntohs(pkt.ethHdr.h_proto);
++ break;
++ }
++
++ fprintf(stderr, &quot;Wonderful! Sniffed a likely-looking session packet.\n&quot;);
++ if ((ServiceName == NULL || *ServiceName == 0) &amp;&amp;
++ DiscType == ETH_PPPOE_DISCOVERY &amp;&amp;
++ SessType == ETH_PPPOE_SESSION) {
++ fprintf(stderr, &quot;\nGreat! It looks like a standard PPPoE service.\nYou should not need anything special in the configuration file.\n&quot;);
++ return 0;
++ }
++
++ fprintf(stderr, &quot;\nOK, looks like you need something special in the configuration file.\nTry this:\n\n&quot;);
++ if (ServiceName != NULL &amp;&amp; *ServiceName != 0) {
++ fprintf(stderr, &quot;SERVICENAME='%s'\n&quot;, ServiceName);
++ }
++ if (DiscType != ETH_PPPOE_DISCOVERY || SessType != ETH_PPPOE_SESSION) {
++ fprintf(stderr, &quot; PPPOE_EXTRA='-f %x:%x'\n&quot;, DiscType, SessType);
++ }
++ return 0;
++}
++
++#endif
++/**********************************************************************
++*%FUNCTION: sysErr
++*%ARGUMENTS:
++* str -- error message
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Prints a message plus the errno value to syslog.
++***********************************************************************/
++void
++sysErr(char const *str)
++{
++ char buf[1024];
++ sprintf(buf, &quot;%.256s: %.256s&quot;, str, strerror(errno));
++ printErr(buf);
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/src/pppoe-sniff.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/src/pppoe.c
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/src/pppoe.c (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/src/pppoe.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,834 @@
++/***********************************************************************
++*
++* pppoe.c
++*
++* Implementation of user-space PPPoE redirector for Linux.
++*
++* Copyright (C) 2000-2001 by Roaring Penguin Software Inc.
++*
++* This program may be distributed according to the terms of the GNU
++* General Public License, version 2 or (at your option) any later version.
++*
++***********************************************************************/
++
++static char const RCSID[] =
++&quot;$Id: pppoe.c 224882 2007-07-16 22:03:12Z blino $&quot;;
++
++#include &quot;pppoe.h&quot;
++
++#ifdef HAVE_SYSLOG_H
++#include &lt;syslog.h&gt;
++#endif
++
++#ifdef HAVE_GETOPT_H
++#include &lt;getopt.h&gt;
++#endif
++
++#include &lt;string.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;errno.h&gt;
++
++#ifdef HAVE_SYS_TIME_H
++#include &lt;sys/time.h&gt;
++#endif
++
++#ifdef HAVE_SYS_UIO_H
++#include &lt;sys/uio.h&gt;
++#endif
++
++#ifdef HAVE_UNISTD_H
++#include &lt;unistd.h&gt;
++#endif
++
++#ifdef USE_LINUX_PACKET
++#include &lt;sys/ioctl.h&gt;
++#include &lt;fcntl.h&gt;
++#endif
++
++#include &lt;signal.h&gt;
++
++#ifdef HAVE_N_HDLC
++#ifndef N_HDLC
++#include &lt;termios.h&gt;
++#endif
++#endif
++
++/* Default interface if no -I option given */
++#define DEFAULT_IF &quot;eth0&quot;
++
++/* Global variables -- options */
++int optInactivityTimeout = 0; /* Inactivity timeout */
++int optClampMSS = 0; /* Clamp MSS to this value */
++int optSkipSession = 0; /* Perform discovery, print session info
++ and exit */
++
++PPPoEConnection *Connection = NULL; /* Must be global -- used
++ in signal handler */
++/***********************************************************************
++*%FUNCTION: sendSessionPacket
++*%ARGUMENTS:
++* conn -- PPPoE connection
++* packet -- the packet to send
++* len -- length of data to send
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Transmits a session packet to the peer.
++***********************************************************************/
++void
++sendSessionPacket(PPPoEConnection *conn, PPPoEPacket *packet, int len)
++{
++ packet-&gt;length = htons(len);
++ if (optClampMSS) {
++ clampMSS(packet, &quot;outgoing&quot;, optClampMSS);
++ }
++ if (sendPacket(conn, conn-&gt;sessionSocket, packet, len + HDR_SIZE) &lt; 0) {
++ exit(EXIT_FAILURE);
++ }
++ if (conn-&gt;debugFile) {
++ dumpPacket(conn-&gt;debugFile, packet, &quot;SENT&quot;);
++ fprintf(conn-&gt;debugFile, &quot;\n&quot;);
++ fflush(conn-&gt;debugFile);
++ }
++}
++
++#ifdef USE_BPF
++/**********************************************************************
++*%FUNCTION: sessionDiscoveryPacket
++*%ARGUMENTS:
++* packet -- the discovery packet that was received
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* We got a discovery packet during the session stage. This most likely
++* means a PADT.
++*
++* The BSD version uses a single socket for both discovery and session
++* packets. When a packet comes in over the wire once we are in
++* session mode, either syncReadFromEth() or asyncReadFromEth() will
++* have already read the packet and determined it to be a discovery
++* packet before passing it here.
++***********************************************************************/
++void
++sessionDiscoveryPacket(PPPoEPacket *packet)
++{
++ /* Sanity check */
++ if (packet-&gt;code != CODE_PADT) {
++ return;
++ }
++
++ /* It's a PADT, all right. Is it for us? */
++ if (packet-&gt;session != Connection-&gt;session) {
++ /* Nope, ignore it */
++ return;
++ }
++
++ syslog(LOG_INFO,
++ &quot;Session terminated -- received PADT from access concentrator&quot;);
++ parsePacket(packet, parseLogErrs, NULL);
++ exit(EXIT_SUCCESS);
++}
++#else
++/**********************************************************************
++*%FUNCTION: sessionDiscoveryPacket
++*%ARGUMENTS:
++* conn -- PPPoE connection
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* We got a discovery packet during the session stage. This most likely
++* means a PADT.
++***********************************************************************/
++void
++sessionDiscoveryPacket(PPPoEConnection *conn)
++{
++ PPPoEPacket packet;
++ int len;
++
++ if (receivePacket(conn-&gt;discoverySocket, &amp;packet, &amp;len) &lt; 0) {
++ return;
++ }
++
++ /* Check length */
++ if (ntohs(packet.length) + HDR_SIZE &gt; len) {
++ syslog(LOG_ERR, &quot;Bogus PPPoE length field (%u)&quot;,
++ (unsigned int) ntohs(packet.length));
++ return;
++ }
++
++ if (conn-&gt;debugFile) {
++ dumpPacket(conn-&gt;debugFile, &amp;packet, &quot;RCVD&quot;);
++ fprintf(conn-&gt;debugFile, &quot;\n&quot;);
++ fflush(conn-&gt;debugFile);
++ }
++
++ if (packet.code != CODE_PADT) {
++ /* Not PADT; ignore it */
++ return;
++ }
++
++ /* It's a PADT, all right. Is it for us? */
++ if (packet.session != conn-&gt;session) {
++ /* Nope, ignore it */
++ return;
++ }
++
++ syslog(LOG_INFO,
++ &quot;Session terminated -- received PADT from peer&quot;);
++ parsePacket(&amp;packet, parseLogErrs, NULL);
++ exit(EXIT_SUCCESS);
++}
++#endif /* USE_BPF */
++
++/**********************************************************************
++*%FUNCTION: session
++*%ARGUMENTS:
++* conn -- PPPoE connection info
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Handles the &quot;session&quot; phase of PPPoE
++***********************************************************************/
++void
++session(PPPoEConnection *conn)
++{
++ fd_set readable;
++ PPPoEPacket packet;
++ struct timeval tv;
++ struct timeval *tvp = NULL;
++ int maxFD = 0;
++ int r;
++
++ /* Open a session socket */
++ conn-&gt;sessionSocket = openInterface(conn-&gt;ifName, Eth_PPPOE_Session, conn-&gt;myEth);
++
++ /* Prepare for select() */
++ if (conn-&gt;sessionSocket &gt; maxFD) maxFD = conn-&gt;sessionSocket;
++ if (conn-&gt;discoverySocket &gt; maxFD) maxFD = conn-&gt;discoverySocket;
++ maxFD++;
++
++ /* Fill in the constant fields of the packet to save time */
++ memcpy(packet.ethHdr.h_dest, conn-&gt;peerEth, ETH_ALEN);
++ memcpy(packet.ethHdr.h_source, conn-&gt;myEth, ETH_ALEN);
++ packet.ethHdr.h_proto = htons(Eth_PPPOE_Session);
++ packet.ver = 1;
++ packet.type = 1;
++ packet.code = CODE_SESS;
++ packet.session = conn-&gt;session;
++
++ initPPP();
++
++#ifdef USE_BPF
++ /* check for buffered session data */
++ while (BPF_BUFFER_HAS_DATA) {
++ if (conn-&gt;synchronous) {
++ syncReadFromEth(conn, conn-&gt;sessionSocket, optClampMSS);
++ } else {
++ asyncReadFromEth(conn, conn-&gt;sessionSocket, optClampMSS);
++ }
++ }
++#endif
++
++ for (;;) {
++ if (optInactivityTimeout &gt; 0) {
++ tv.tv_sec = optInactivityTimeout;
++ tv.tv_usec = 0;
++ tvp = &amp;tv;
++ }
++ FD_ZERO(&amp;readable);
++ FD_SET(0, &amp;readable); /* ppp packets come from stdin */
++ if (conn-&gt;discoverySocket &gt;= 0) {
++ FD_SET(conn-&gt;discoverySocket, &amp;readable);
++ }
++ FD_SET(conn-&gt;sessionSocket, &amp;readable);
++ while(1) {
++ r = select(maxFD, &amp;readable, NULL, NULL, tvp);
++ if (r &gt;= 0 || errno != EINTR) break;
++ }
++ if (r &lt; 0) {
++ fatalSys(&quot;select (session)&quot;);
++ }
++ if (r == 0) { /* Inactivity timeout */
++ syslog(LOG_ERR, &quot;Inactivity timeout... something wicked happened&quot;);
++ sendPADT(conn, &quot;RP-PPPoE: Inactivity timeout&quot;);
++ exit(EXIT_FAILURE);
++ }
++
++ /* Handle ready sockets */
++ if (FD_ISSET(0, &amp;readable)) {
++ if (conn-&gt;synchronous) {
++ syncReadFromPPP(conn, &amp;packet);
++ } else {
++ asyncReadFromPPP(conn, &amp;packet);
++ }
++ }
++
++ if (FD_ISSET(conn-&gt;sessionSocket, &amp;readable)) {
++ do {
++ if (conn-&gt;synchronous) {
++ syncReadFromEth(conn, conn-&gt;sessionSocket, optClampMSS);
++ } else {
++ asyncReadFromEth(conn, conn-&gt;sessionSocket, optClampMSS);
++ }
++ } while (BPF_BUFFER_HAS_DATA);
++ }
++
++#ifndef USE_BPF
++ /* BSD uses a single socket, see *syncReadFromEth() */
++ /* for calls to sessionDiscoveryPacket() */
++ if (conn-&gt;discoverySocket &gt;= 0) {
++ if (FD_ISSET(conn-&gt;discoverySocket, &amp;readable)) {
++ sessionDiscoveryPacket(conn);
++ }
++ }
++#endif
++
++ }
++}
++
++
++/***********************************************************************
++*%FUNCTION: sigPADT
++*%ARGUMENTS:
++* src -- signal received
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* If an established session exists send PADT to terminate from session
++* from our end
++***********************************************************************/
++void
++sigPADT(int src)
++{
++ syslog(LOG_DEBUG,&quot;Received signal %d.&quot;,(int)src);
++ sendPADT(Connection, &quot;RP-PPPoE: Received signal&quot;);
++ exit(EXIT_SUCCESS);
++}
++
++/**********************************************************************
++*%FUNCTION: usage
++*%ARGUMENTS:
++* argv0 -- program name
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Prints usage information and exits.
++***********************************************************************/
++void
++usage(char const *argv0)
++{
++ fprintf(stderr, &quot;Usage: %s [options]\n&quot;, argv0);
++ fprintf(stderr, &quot;Options:\n&quot;);
++#ifdef USE_BPF
++ fprintf(stderr, &quot; -I if_name -- Specify interface (REQUIRED)\n&quot;);
++#else
++ fprintf(stderr, &quot; -I if_name -- Specify interface (default %s.)\n&quot;,
++ DEFAULT_IF);
++#endif
++ fprintf(stderr, &quot; -T timeout -- Specify inactivity timeout in seconds.\n&quot;);
++ fprintf(stderr, &quot; -D filename -- Log debugging information in filename.\n&quot;);
++ fprintf(stderr, &quot; -V -- Print version and exit.\n&quot;);
++ fprintf(stderr, &quot; -A -- Print access concentrator names and exit.\n&quot;);
++ fprintf(stderr, &quot; -S name -- Set desired service name.\n&quot;);
++ fprintf(stderr, &quot; -C name -- Set desired access concentrator name.\n&quot;);
++ fprintf(stderr, &quot; -U -- Use Host-Unique to allow multiple PPPoE sessions.\n&quot;);
++ fprintf(stderr, &quot; -s -- Use synchronous PPP encapsulation.\n&quot;);
++ fprintf(stderr, &quot; -m MSS -- Clamp incoming and outgoing MSS options.\n&quot;);
++ fprintf(stderr, &quot; -p pidfile -- Write process-ID to pidfile.\n&quot;);
++ fprintf(stderr, &quot; -e sess:mac -- Skip discovery phase; use existing session.\n&quot;);
++ fprintf(stderr, &quot; -n -- Do not open discovery socket.\n&quot;);
++ fprintf(stderr, &quot; -k -- Kill a session with PADT (requires -e)\n&quot;);
++ fprintf(stderr, &quot; -d -- Perform discovery, print session info and exit.\n&quot;);
++ fprintf(stderr, &quot; -f disc:sess -- Set Ethernet frame types (hex).\n&quot;);
++ fprintf(stderr, &quot; -h -- Print usage information.\n\n&quot;);
++ fprintf(stderr, &quot;PPPoE Version %s, Copyright (C) 2001 Roaring Penguin Software Inc.\n&quot;, VERSION);
++ fprintf(stderr, &quot;PPPoE comes with ABSOLUTELY NO WARRANTY.\n&quot;);
++ fprintf(stderr, &quot;This is free software, and you are welcome to redistribute it under the terms\n&quot;);
++ fprintf(stderr, &quot;of the GNU General Public License, version 2 or any later version.\n&quot;);
++ fprintf(stderr, &quot;<A HREF="http://www.roaringpenguin.com\n">http://www.roaringpenguin.com\n</A>&quot;);
++ exit(EXIT_SUCCESS);
++}
++
++/**********************************************************************
++*%FUNCTION: main
++*%ARGUMENTS:
++* argc, argv -- count and values of command-line arguments
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Main program
++***********************************************************************/
++int
++main(int argc, char *argv[])
++{
++ int opt;
++ int n;
++ unsigned int m[6]; /* MAC address in -e option */
++ unsigned int s; /* Temporary to hold session */
++ FILE *pidfile;
++ unsigned int discoveryType, sessionType;
++
++ PPPoEConnection conn;
++
++#ifdef HAVE_N_HDLC
++ int disc = N_HDLC;
++ long flags;
++#endif
++
++ /* Initialize connection info */
++ memset(&amp;conn, 0, sizeof(conn));
++ conn.discoverySocket = -1;
++ conn.sessionSocket = -1;
++
++ /* For signal handler */
++ Connection = &amp;conn;
++
++ /* Initialize syslog */
++ openlog(&quot;pppoe&quot;, LOG_PID, LOG_DAEMON);
++
++ while((opt = getopt(argc, argv, &quot;I:VAT:D:hS:C:Usm:np:e:kdf:&quot;)) != -1) {
++ switch(opt) {
++ case 'f':
++ if (sscanf(optarg, &quot;%x:%x&quot;, &amp;discoveryType, &amp;sessionType) != 2) {
++ fprintf(stderr, &quot;Illegal argument to -f: Should be disc:sess in hex\n&quot;);
++ exit(EXIT_FAILURE);
++ }
++ Eth_PPPOE_Discovery = (UINT16_t) discoveryType;
++ Eth_PPPOE_Session = (UINT16_t) sessionType;
++ break;
++ case 'd':
++ optSkipSession = 1;
++ break;
++
++ case 'k':
++ conn.killSession = 1;
++ break;
++
++ case 'n':
++ /* Do not even open a discovery socket -- used when invoked
++ by pppoe-server */
++ conn.noDiscoverySocket = 1;
++ break;
++
++ case 'e':
++ /* Existing session: &quot;sess:xx:yy:zz:aa:bb:cc&quot; where &quot;sess&quot; is
++ session-ID, and xx:yy:zz:aa:bb:cc is MAC-address of peer */
++ n = sscanf(optarg, &quot;%u:%2x:%2x:%2x:%2x:%2x:%2x&quot;,
++ &amp;s, &amp;m[0], &amp;m[1], &amp;m[2], &amp;m[3], &amp;m[4], &amp;m[5]);
++ if (n != 7) {
++ fprintf(stderr, &quot;Illegal argument to -e: Should be sess:xx:yy:zz:aa:bb:cc\n&quot;);
++ exit(EXIT_FAILURE);
++ }
++
++ /* Copy MAC address of peer */
++ for (n=0; n&lt;6; n++) {
++ conn.peerEth[n] = (unsigned char) m[n];
++ }
++
++ /* Convert session */
++ conn.session = htons(s);
++
++ /* Skip discovery phase! */
++ conn.skipDiscovery = 1;
++ break;
++
++ case 'p':
++ pidfile = fopen(optarg, &quot;w&quot;);
++ if (pidfile) {
++ fprintf(pidfile, &quot;%lu\n&quot;, (unsigned long) getpid());
++ fclose(pidfile);
++ }
++ break;
++ case 'S':
++ SET_STRING(conn.serviceName, optarg);
++ break;
++ case 'C':
++ SET_STRING(conn.acName, optarg);
++ break;
++ case 's':
++ conn.synchronous = 1;
++ break;
++ case 'U':
++ conn.useHostUniq = 1;
++ break;
++ case 'D':
++ conn.debugFile = fopen(optarg, &quot;w&quot;);
++ if (!conn.debugFile) {
++ fprintf(stderr, &quot;Could not open %s: %s\n&quot;,
++ optarg, strerror(errno));
++ exit(EXIT_FAILURE);
++ }
++ fprintf(conn.debugFile, &quot;rp-pppoe-%s\n&quot;, VERSION);
++ fflush(conn.debugFile);
++ break;
++ case 'T':
++ optInactivityTimeout = (int) strtol(optarg, NULL, 10);
++ if (optInactivityTimeout &lt; 0) {
++ optInactivityTimeout = 0;
++ }
++ break;
++ case 'm':
++ optClampMSS = (int) strtol(optarg, NULL, 10);
++ if (optClampMSS &lt; 536) {
++ fprintf(stderr, &quot;-m: %d is too low (min 536)\n&quot;, optClampMSS);
++ exit(EXIT_FAILURE);
++ }
++ if (optClampMSS &gt; 1452) {
++ fprintf(stderr, &quot;-m: %d is too high (max 1452)\n&quot;, optClampMSS);
++ exit(EXIT_FAILURE);
++ }
++ break;
++ case 'I':
++ SET_STRING(conn.ifName, optarg);
++ break;
++ case 'V':
++ printf(&quot;Roaring Penguin PPPoE Version %s\n&quot;, VERSION);
++ exit(EXIT_SUCCESS);
++ case 'A':
++ conn.printACNames = 1;
++ break;
++ case 'h':
++ usage(argv[0]);
++ break;
++ default:
++ usage(argv[0]);
++ }
++ }
++
++ /* Pick a default interface name */
++ if (!conn.ifName) {
++#ifdef USE_BPF
++ fprintf(stderr, &quot;No interface specified (-I option)\n&quot;);
++ exit(EXIT_FAILURE);
++#else
++ SET_STRING(conn.ifName, DEFAULT_IF);
++#endif
++ }
++
++ /* Set signal handlers: send PADT on TERM, HUP and INT */
++ if (!conn.printACNames) {
++ signal(SIGTERM, sigPADT);
++ signal(SIGHUP, sigPADT);
++ signal(SIGINT, sigPADT);
++
++#ifdef HAVE_N_HDLC
++ if (conn.synchronous) {
++ if (ioctl(0, TIOCSETD, &amp;disc) &lt; 0) {
++ printErr(&quot;Unable to set line discipline to N_HDLC -- synchronous mode probably will fail&quot;);
++ } else {
++ syslog(LOG_INFO,
++ &quot;Changed pty line discipline to N_HDLC for synchronous mode&quot;);
++ }
++ /* There is a bug in Linux's select which returns a descriptor
++ * as readable if N_HDLC line discipline is on, even if
++ * it isn't really readable. This return happens only when
++ * select() times out. To avoid blocking forever in read(),
++ * make descriptor 0 non-blocking */
++ flags = fcntl(0, F_GETFL);
++ if (flags &lt; 0) fatalSys(&quot;fcntl(F_GETFL)&quot;);
++ if (fcntl(0, F_SETFL, (long) flags | O_NONBLOCK) &lt; 0) {
++ fatalSys(&quot;fcntl(F_SETFL)&quot;);
++ }
++ }
++#endif
++
++ }
++
++ discovery(&amp;conn);
++ if (optSkipSession) {
++ printf(&quot;%u:%02x:%02x:%02x:%02x:%02x:%02x\n&quot;,
++ ntohs(conn.session),
++ conn.peerEth[0],
++ conn.peerEth[1],
++ conn.peerEth[2],
++ conn.peerEth[3],
++ conn.peerEth[4],
++ conn.peerEth[5]);
++ exit(EXIT_SUCCESS);
++ }
++ session(&amp;conn);
++ return 0;
++}
++
++/**********************************************************************
++*%FUNCTION: fatalSys
++*%ARGUMENTS:
++* str -- error message
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Prints a message plus the errno value to stderr and syslog and exits.
++***********************************************************************/
++void
++fatalSys(char const *str)
++{
++ char buf[1024];
++ sprintf(buf, &quot;%.256s: %.256s&quot;, str, strerror(errno));
++ printErr(buf);
++ sendPADT(Connection, &quot;RP-PPPoE: System call error&quot;);
++ exit(EXIT_FAILURE);
++}
++
++/**********************************************************************
++*%FUNCTION: sysErr
++*%ARGUMENTS:
++* str -- error message
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Prints a message plus the errno value to syslog.
++***********************************************************************/
++void
++sysErr(char const *str)
++{
++ char buf[1024];
++ sprintf(buf, &quot;%.256s: %.256s&quot;, str, strerror(errno));
++ printErr(buf);
++}
++
++/**********************************************************************
++*%FUNCTION: rp_fatal
++*%ARGUMENTS:
++* str -- error message
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Prints a message to stderr and syslog and exits.
++***********************************************************************/
++void
++rp_fatal(char const *str)
++{
++ char buf[1024];
++ printErr(str);
++ sprintf(buf, &quot;RP-PPPoE: %.256s&quot;, str);
++ sendPADT(Connection, buf);
++ exit(EXIT_FAILURE);
++}
++
++/**********************************************************************
++*%FUNCTION: asyncReadFromEth
++*%ARGUMENTS:
++* conn -- PPPoE connection info
++* sock -- Ethernet socket
++* clampMss -- if non-zero, do MSS-clamping
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Reads a packet from the Ethernet interface and sends it to async PPP
++* device.
++***********************************************************************/
++void
++asyncReadFromEth(PPPoEConnection *conn, int sock, int clampMss)
++{
++ PPPoEPacket packet;
++ int len;
++ int plen;
++ int i;
++ unsigned char pppBuf[4096];
++ unsigned char *ptr = pppBuf;
++ unsigned char c;
++ UINT16_t fcs;
++ unsigned char header[2] = {FRAME_ADDR, FRAME_CTRL};
++ unsigned char tail[2];
++#ifdef USE_BPF
++ int type;
++#endif
++
++ if (receivePacket(sock, &amp;packet, &amp;len) &lt; 0) {
++ return;
++ }
++
++ /* Check length */
++ if (ntohs(packet.length) + HDR_SIZE &gt; len) {
++ syslog(LOG_ERR, &quot;Bogus PPPoE length field (%u)&quot;,
++ (unsigned int) ntohs(packet.length));
++ return;
++ }
++ if (conn-&gt;debugFile) {
++ dumpPacket(conn-&gt;debugFile, &amp;packet, &quot;RCVD&quot;);
++ fprintf(conn-&gt;debugFile, &quot;\n&quot;);
++ fflush(conn-&gt;debugFile);
++ }
++
++#ifdef USE_BPF
++ /* Make sure this is a session packet before processing further */
++ type = etherType(&amp;packet);
++ if (type == Eth_PPPOE_Discovery) {
++ sessionDiscoveryPacket(&amp;packet);
++ } else if (type != Eth_PPPOE_Session) {
++ return;
++ }
++#endif
++
++ /* Sanity check */
++ if (packet.code != CODE_SESS) {
++ syslog(LOG_ERR, &quot;Unexpected packet code %d&quot;, (int) packet.code);
++ return;
++ }
++ if (packet.ver != 1) {
++ syslog(LOG_ERR, &quot;Unexpected packet version %d&quot;, (int) packet.ver);
++ return;
++ }
++ if (packet.type != 1) {
++ syslog(LOG_ERR, &quot;Unexpected packet type %d&quot;, (int) packet.type);
++ return;
++ }
++ if (memcmp(packet.ethHdr.h_source, conn-&gt;peerEth, ETH_ALEN)) {
++ /* Not for us -- must be another session. This is not an error,
++ so don't log anything. */
++ return;
++ }
++
++ if (packet.session != conn-&gt;session) {
++ /* Not for us -- must be another session. This is not an error,
++ so don't log anything. */
++ return;
++ }
++ plen = ntohs(packet.length);
++ if (plen + HDR_SIZE &gt; len) {
++ syslog(LOG_ERR, &quot;Bogus length field in session packet %d (%d)&quot;,
++ (int) plen, (int) len);
++ return;
++ }
++
++ /* Clamp MSS */
++ if (clampMss) {
++ clampMSS(&amp;packet, &quot;incoming&quot;, clampMss);
++ }
++
++ /* Compute FCS */
++ fcs = pppFCS16(PPPINITFCS16, header, 2);
++ fcs = pppFCS16(fcs, packet.payload, plen) ^ 0xffff;
++ tail[0] = fcs &amp; 0x00ff;
++ tail[1] = (fcs &gt;&gt; 8) &amp; 0x00ff;
++
++ /* Build a buffer to send to PPP */
++ *ptr++ = FRAME_FLAG;
++ *ptr++ = FRAME_ADDR;
++ *ptr++ = FRAME_ESC;
++ *ptr++ = FRAME_CTRL ^ FRAME_ENC;
++
++ for (i=0; i&lt;plen; i++) {
++ c = packet.payload[i];
++ if (c == FRAME_FLAG || c == FRAME_ADDR || c == FRAME_ESC || c &lt; 0x20) {
++ *ptr++ = FRAME_ESC;
++ *ptr++ = c ^ FRAME_ENC;
++ } else {
++ *ptr++ = c;
++ }
++ }
++ for (i=0; i&lt;2; i++) {
++ c = tail[i];
++ if (c == FRAME_FLAG || c == FRAME_ADDR || c == FRAME_ESC || c &lt; 0x20) {
++ *ptr++ = FRAME_ESC;
++ *ptr++ = c ^ FRAME_ENC;
++ } else {
++ *ptr++ = c;
++ }
++ }
++ *ptr++ = FRAME_FLAG;
++
++ /* Ship it out */
++ if (write(1, pppBuf, (ptr-pppBuf)) &lt; 0) {
++ fatalSys(&quot;asyncReadFromEth: write&quot;);
++ }
++}
++
++/**********************************************************************
++*%FUNCTION: syncReadFromEth
++*%ARGUMENTS:
++* conn -- PPPoE connection info
++* sock -- Ethernet socket
++* clampMss -- if true, clamp MSS.
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Reads a packet from the Ethernet interface and sends it to sync PPP
++* device.
++***********************************************************************/
++void
++syncReadFromEth(PPPoEConnection *conn, int sock, int clampMss)
++{
++ PPPoEPacket packet;
++ int len;
++ int plen;
++ struct iovec vec[2];
++ unsigned char dummy[2];
++#ifdef USE_BPF
++ int type;
++#endif
++
++ if (receivePacket(sock, &amp;packet, &amp;len) &lt; 0) {
++ return;
++ }
++
++ /* Check length */
++ if (ntohs(packet.length) + HDR_SIZE &gt; len) {
++ syslog(LOG_ERR, &quot;Bogus PPPoE length field (%u)&quot;,
++ (unsigned int) ntohs(packet.length));
++ return;
++ }
++ if (conn-&gt;debugFile) {
++ dumpPacket(conn-&gt;debugFile, &amp;packet, &quot;RCVD&quot;);
++ fprintf(conn-&gt;debugFile, &quot;\n&quot;);
++ fflush(conn-&gt;debugFile);
++ }
++
++#ifdef USE_BPF
++ /* Make sure this is a session packet before processing further */
++ type = etherType(&amp;packet);
++ if (type == Eth_PPPOE_Discovery) {
++ sessionDiscoveryPacket(&amp;packet);
++ } else if (type != Eth_PPPOE_Session) {
++ return;
++ }
++#endif
++
++ /* Sanity check */
++ if (packet.code != CODE_SESS) {
++ syslog(LOG_ERR, &quot;Unexpected packet code %d&quot;, (int) packet.code);
++ return;
++ }
++ if (packet.ver != 1) {
++ syslog(LOG_ERR, &quot;Unexpected packet version %d&quot;, (int) packet.ver);
++ return;
++ }
++ if (packet.type != 1) {
++ syslog(LOG_ERR, &quot;Unexpected packet type %d&quot;, (int) packet.type);
++ return;
++ }
++ if (memcmp(packet.ethHdr.h_source, conn-&gt;peerEth, ETH_ALEN)) {
++ /* Not for us -- must be another session. This is not an error,
++ so don't log anything. */
++ return;
++ }
++ if (packet.session != conn-&gt;session) {
++ /* Not for us -- must be another session. This is not an error,
++ so don't log anything. */
++ return;
++ }
++ plen = ntohs(packet.length);
++ if (plen + HDR_SIZE &gt; len) {
++ syslog(LOG_ERR, &quot;Bogus length field in session packet %d (%d)&quot;,
++ (int) plen, (int) len);
++ return;
++ }
++
++ /* Clamp MSS */
++ if (clampMss) {
++ clampMSS(&amp;packet, &quot;incoming&quot;, clampMss);
++ }
++
++ /* Ship it out */
++ vec[0].iov_base = (void *) dummy;
++ dummy[0] = FRAME_ADDR;
++ dummy[1] = FRAME_CTRL;
++ vec[0].iov_len = 2;
++ vec[1].iov_base = (void *) packet.payload;
++ vec[1].iov_len = plen;
++
++ if (writev(1, vec, 2) &lt; 0) {
++ fatalSys(&quot;syncReadFromEth: write&quot;);
++ }
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/src/pppoe.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/src/pppoe.h
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/src/pppoe.h (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/src/pppoe.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,331 @@
++/***********************************************************************
++*
++* pppoe.h
++*
++* Declaration of various PPPoE constants
++*
++* Copyright (C) 2000 Roaring Penguin Software Inc.
++*
++* This program may be distributed according to the terms of the GNU
++* General Public License, version 2 or (at your option) any later version.
++*
++* $Id: pppoe.h 195724 2001-06-11 13:49:39Z gc $
++*
++***********************************************************************/
++
++#ifdef __sun__
++#define __EXTENSIONS__
++#endif
++
++#include &quot;config.h&quot;
++
++#if defined(HAVE_NETPACKET_PACKET_H) || defined(HAVE_LINUX_IF_PACKET_H)
++#define _POSIX_SOURCE 1 /* For sigaction defines */
++#endif
++
++#include &lt;stdio.h&gt; /* For FILE */
++#include &lt;sys/types.h&gt; /* For pid_t */
++
++/* How do we access raw Ethernet devices? */
++#undef USE_LINUX_PACKET
++#undef USE_BPF
++
++#if defined(HAVE_NETPACKET_PACKET_H) || defined(HAVE_LINUX_IF_PACKET_H)
++#define USE_LINUX_PACKET 1
++#elif defined(HAVE_NET_BPF_H)
++#define USE_BPF 1
++#elif defined(HAVE_SYS_DLPI_H)
++#define USE_DLPI
++#endif
++
++/* Sanity check */
++#if !defined(USE_BPF) &amp;&amp; !defined(USE_LINUX_PACKET) &amp;&amp; !defined(USE_DLPI)
++#error Unknown method for accessing raw Ethernet frames
++#endif
++
++#ifdef HAVE_SYS_CDEFS_H
++#include &lt;sys/cdefs.h&gt;
++#endif
++
++#ifdef HAVE_SYS_SOCKET_H
++#include &lt;sys/socket.h&gt;
++#endif
++
++/* Ugly header files on some Linux boxes... */
++#if defined(HAVE_LINUX_IF_H)
++#include &lt;linux/if.h&gt;
++#elif defined(HAVE_NET_IF_H)
++#include &lt;net/if.h&gt;
++#endif
++
++#ifdef HAVE_NET_IF_TYPES_H
++#include &lt;net/if_types.h&gt;
++#endif
++
++#ifdef HAVE_NET_IF_DL_H
++#include &lt;net/if_dl.h&gt;
++#endif
++
++/* I'm not sure why this is needed... I do not have OpenBSD */
++#if defined(__OpenBSD__)
++#include &lt;net/ppp_defs.h&gt;
++#include &lt;net/if_ppp.h&gt;
++#endif
++
++#ifdef USE_BPF
++extern int bpfSize;
++struct PPPoEPacketStruct;
++void sessionDiscoveryPacket(struct PPPoEPacketStruct *packet);
++#define BPF_BUFFER_IS_EMPTY (bpfSize &lt;= 0)
++#define BPF_BUFFER_HAS_DATA (bpfSize &gt; 0)
++#define ethhdr ether_header
++#define h_dest ether_dhost
++#define h_source ether_shost
++#define h_proto ether_type
++#define ETH_DATA_LEN ETHERMTU
++#define ETH_ALEN ETHER_ADDR_LEN
++#else
++#undef USE_BPF
++#define BPF_BUFFER_IS_EMPTY 1
++#define BPF_BUFFER_HAS_DATA 0
++#endif
++
++#ifdef USE_DLPI
++#include &lt;sys/ethernet.h&gt;
++#define ethhdr ether_header
++#define ETH_DATA_LEN ETHERMTU
++#define ETH_ALEN ETHERADDRL
++#define h_dest ether_dhost.ether_addr_octet
++#define h_source ether_shost.ether_addr_octet
++#define h_proto ether_type
++
++/* cloned from dltest.h */
++#define MAXDLBUF 8192
++#define MAXDLADDR 1024
++#define MAXWAIT 15
++#define OFFADDR(s, n) (u_char*)((char*)(s) + (int)(n))
++#define CASERET(s) case s: return (&quot;s&quot;)
++
++#endif
++
++/* Define various integer types -- assumes a char is 8 bits */
++#if SIZEOF_UNSIGNED_SHORT == 2
++typedef unsigned short UINT16_t;
++#elif SIZEOF_UNSIGNED_INT == 2
++typedef unsigned int UINT16_t;
++#else
++#error Could not find a 16-bit integer type
++#endif
++
++#if SIZEOF_UNSIGNED_SHORT == 4
++typedef unsigned short UINT32_t;
++#elif SIZEOF_UNSIGNED_INT == 4
++typedef unsigned int UINT32_t;
++#elif SIZEOF_UNSIGNED_LONG == 4
++typedef unsigned long UINT32_t;
++#else
++#error Could not find a 16-bit integer type
++#endif
++
++#ifdef HAVE_LINUX_IF_ETHER_H
++#include &lt;linux/if_ether.h&gt;
++#endif
++
++#include &lt;netinet/in.h&gt;
++
++#ifdef HAVE_NETINET_IF_ETHER_H
++#include &lt;sys/types.h&gt;
++
++#ifdef HAVE_SYS_SOCKET_H
++#include &lt;sys/socket.h&gt;
++#endif
++#ifndef HAVE_SYS_DLPI_H
++#include &lt;netinet/if_ether.h&gt;
++#endif
++#endif
++
++
++
++/* Ethernet frame types according to RFC 2516 */
++#define ETH_PPPOE_DISCOVERY 0x8863
++#define ETH_PPPOE_SESSION 0x8864
++
++/* But some brain-dead peers disobey the RFC, so frame types are variables */
++extern UINT16_t Eth_PPPOE_Discovery;
++extern UINT16_t Eth_PPPOE_Session;
++
++/* PPPoE codes */
++#define CODE_PADI 0x09
++#define CODE_PADO 0x07
++#define CODE_PADR 0x19
++#define CODE_PADS 0x65
++#define CODE_PADT 0xA7
++#define CODE_SESS 0x00
++
++/* PPPoE Tags */
++#define TAG_END_OF_LIST 0x0000
++#define TAG_SERVICE_NAME 0x0101
++#define TAG_AC_NAME 0x0102
++#define TAG_HOST_UNIQ 0x0103
++#define TAG_AC_COOKIE 0x0104
++#define TAG_VENDOR_SPECIFIC 0x0105
++#define TAG_RELAY_SESSION_ID 0x0110
++#define TAG_SERVICE_NAME_ERROR 0x0201
++#define TAG_AC_SYSTEM_ERROR 0x0202
++#define TAG_GENERIC_ERROR 0x0203
++
++/* Discovery phase states */
++#define STATE_SENT_PADI 0
++#define STATE_RECEIVED_PADO 1
++#define STATE_SENT_PADR 2
++#define STATE_SESSION 3
++#define STATE_TERMINATED 4
++
++/* How many PADI/PADS attempts? */
++#define MAX_PADI_ATTEMPTS 3
++
++/* Initial timeout for PADO/PADS */
++#define PADI_TIMEOUT 5
++
++/* States for scanning PPP frames */
++#define STATE_WAITFOR_FRAME_ADDR 0
++#define STATE_DROP_PROTO 1
++#define STATE_BUILDING_PACKET 2
++
++/* Special PPP frame characters */
++#define FRAME_ESC 0x7D
++#define FRAME_FLAG 0x7E
++#define FRAME_ADDR 0xFF
++#define FRAME_CTRL 0x03
++#define FRAME_ENC 0x20
++
++#define IPV4ALEN 4
++#define SMALLBUF 256
++
++/* A PPPoE Packet, including Ethernet headers */
++typedef struct PPPoEPacketStruct {
++ struct ethhdr ethHdr; /* Ethernet header */
++#ifdef PACK_BITFIELDS_REVERSED
++ unsigned int type:4; /* PPPoE Type (must be 1) */
++ unsigned int ver:4; /* PPPoE Version (must be 1) */
++#else
++ unsigned int ver:4; /* PPPoE Version (must be 1) */
++ unsigned int type:4; /* PPPoE Type (must be 1) */
++#endif
++ unsigned int code:8; /* PPPoE code */
++ unsigned int session:16; /* PPPoE session */
++ unsigned int length:16; /* Payload length */
++ unsigned char payload[ETH_DATA_LEN]; /* A bit of room to spare */
++} PPPoEPacket;
++
++/* Header size of a PPPoE packet */
++#define PPPOE_OVERHEAD 6 /* type, code, session, length */
++#define HDR_SIZE (sizeof(struct ethhdr) + PPPOE_OVERHEAD)
++#define MAX_PPPOE_PAYLOAD (ETH_DATA_LEN - PPPOE_OVERHEAD)
++#define MAX_PPPOE_MTU (MAX_PPPOE_PAYLOAD - 2)
++
++/* PPPoE Tag */
++
++typedef struct PPPoETagStruct {
++ unsigned int type:16; /* tag type */
++ unsigned int length:16; /* Length of payload */
++ unsigned char payload[ETH_DATA_LEN]; /* A LOT of room to spare */
++} PPPoETag;
++/* Header size of a PPPoE tag */
++#define TAG_HDR_SIZE 4
++
++/* Chunk to read from stdin */
++#define READ_CHUNK 4096
++
++/* Function passed to parsePacket */
++typedef void ParseFunc(UINT16_t type,
++ UINT16_t len,
++ unsigned char *data,
++ void *extra);
++
++/* Structures used by PPPoE server */
++struct ClientSession {
++ pid_t pid; /* PID of child handling session */
++ unsigned char ip[IPV4ALEN]; /* IP address of peer */
++ UINT16_t sess; /* Session number */
++ unsigned char eth[ETH_ALEN]; /* Peer's Ethernet address */
++ int recvdPADT; /* Peer sent a PADT */
++};
++
++#define PPPINITFCS16 0xffff /* Initial FCS value */
++
++/* Keep track of the state of a connection -- collect everything in
++ one spot */
++
++typedef struct PPPoEConnectionStruct {
++ int discoveryState; /* Where we are in discovery */
++ int discoverySocket; /* Raw socket for discovery frames */
++ int sessionSocket; /* Raw socket for session frames */
++ unsigned char myEth[ETH_ALEN]; /* My MAC address */
++ unsigned char peerEth[ETH_ALEN]; /* Peer's MAC address */
++ UINT16_t session; /* Session ID */
++ char *ifName; /* Interface name */
++ char *serviceName; /* Desired service name, if any */
++ char *acName; /* Desired AC name, if any */
++ int synchronous; /* Use synchronous PPP */
++ int useHostUniq; /* Use Host-Uniq tag */
++ int printACNames; /* Just print AC names */
++ int skipDiscovery; /* Skip discovery */
++ int noDiscoverySocket; /* Don't even open discovery socket */
++ int killSession; /* Kill session and exit */
++ FILE *debugFile; /* Debug file for dumping packets */
++ int numPADOs; /* Number of PADO packets received */
++ PPPoETag cookie; /* We have to send this if we get it */
++ PPPoETag relayId; /* Ditto */
++} PPPoEConnection;
++
++/* Structure used to determine acceptable PADO or PADS packet */
++struct PacketCriteria {
++ PPPoEConnection *conn;
++ int acNameOK;
++ int serviceNameOK;
++};
++
++/* Function Prototypes */
++UINT16_t etherType(PPPoEPacket *packet);
++int openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr);
++int sendPacket(PPPoEConnection *conn, int sock, PPPoEPacket *pkt, int size);
++int receivePacket(int sock, PPPoEPacket *pkt, int *size);
++void fatalSys(char const *str);
++void rp_fatal(char const *str);
++void printErr(char const *str);
++void sysErr(char const *str);
++void dumpPacket(FILE *fp, PPPoEPacket *packet, char const *dir);
++void dumpHex(FILE *fp, unsigned char const *buf, int len);
++int parsePacket(PPPoEPacket *packet, ParseFunc *func, void *extra);
++void parseLogErrs(UINT16_t typ, UINT16_t len, unsigned char *data, void *xtra);
++void syncReadFromPPP(PPPoEConnection *conn, PPPoEPacket *packet);
++void asyncReadFromPPP(PPPoEConnection *conn, PPPoEPacket *packet);
++void asyncReadFromEth(PPPoEConnection *conn, int sock, int clampMss);
++void syncReadFromEth(PPPoEConnection *conn, int sock, int clampMss);
++char *strDup(char const *str);
++void sendPADT(PPPoEConnection *conn, char const *msg);
++void sendSessionPacket(PPPoEConnection *conn,
++ PPPoEPacket *packet, int len);
++void initPPP(void);
++void clampMSS(PPPoEPacket *packet, char const *dir, int clampMss);
++UINT16_t computeTCPChecksum(unsigned char *ipHdr, unsigned char *tcpHdr);
++UINT16_t pppFCS16(UINT16_t fcs, unsigned char *cp, int len);
++void discovery(PPPoEConnection *conn);
++unsigned char *findTag(PPPoEPacket *packet, UINT16_t tagType,
++ PPPoETag *tag);
++
++#define SET_STRING(var, val) do { if (var) free(var); var = strDup(val); } while(0);
++
++#define CHECK_ROOM(cursor, start, len) \
++do {\
++ if (((cursor)-(start))+(len) &gt; MAX_PPPOE_PAYLOAD) { \
++ syslog(LOG_ERR, &quot;Would create too-long packet&quot;); \
++ return; \
++ } \
++} while(0)
++
++/* True if Ethernet address is broadcast or multicast */
++#define NOT_UNICAST(e) ((e[0] &amp; 0x01) != 0)
++#define BROADCAST(e) ((e[0] &amp; e[1] &amp; e[2] &amp; e[3] &amp; e[4] &amp; e[5]) == 0xFF)
++#define NOT_BROADCAST(e) ((e[0] &amp; e[1] &amp; e[2] &amp; e[3] &amp; e[4] &amp; e[5]) != 0xFF)
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/src/pppoe.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/src/relay.c
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/src/relay.c (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/src/relay.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1541 @@
++/***********************************************************************
++*
++* relay.c
++*
++* Implementation of PPPoE relay
++*
++* Copyright (C) 2001 Roaring Penguin Software Inc.
++*
++* This program may be distributed according to the terms of the GNU
++* General Public License, version 2 or (at your option) any later version.
++*
++* $Id: relay.c 195724 2001-06-11 13:49:39Z gc $
++*
++***********************************************************************/
++static char const RCSID[] =
++&quot;$Id: relay.c 195724 2001-06-11 13:49:39Z gc $&quot;;
++
++#define _GNU_SOURCE 1 /* For SA_RESTART */
++
++#include &quot;relay.h&quot;
++
++#include &lt;signal.h&gt;
++
++#ifdef HAVE_SYSLOG_H
++#include &lt;syslog.h&gt;
++#endif
++
++#ifdef HAVE_GETOPT_H
++#include &lt;getopt.h&gt;
++#endif
++
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++#include &lt;errno.h&gt;
++
++#ifdef HAVE_SYS_TIME_H
++#include &lt;sys/time.h&gt;
++#endif
++
++#ifdef HAVE_SYS_UIO_H
++#include &lt;sys/uio.h&gt;
++#endif
++
++#ifdef HAVE_UNISTD_H
++#include &lt;unistd.h&gt;
++#endif
++
++
++/* Interfaces (max MAX_INTERFACES) */
++PPPoEInterface Interfaces[MAX_INTERFACES];
++int NumInterfaces;
++
++/* Relay info */
++int NumSessions;
++int MaxSessions;
++PPPoESession *AllSessions;
++PPPoESession *FreeSessions;
++PPPoESession *ActiveSessions;
++
++SessionHash *AllHashes;
++SessionHash *FreeHashes;
++SessionHash *Buckets[HASHTAB_SIZE];
++
++volatile unsigned int Epoch = 0;
++volatile unsigned int CleanCounter = 0;
++
++/* How often to clean up stale sessions? */
++#define MIN_CLEAN_PERIOD 30 /* Minimum period to run cleaner */
++#define TIMEOUT_DIVISOR 20 /* How often to run cleaner per timeout period */
++unsigned int CleanPeriod = MIN_CLEAN_PERIOD;
++
++/* How long a session can be idle before it is cleaned up? */
++unsigned int IdleTimeout = MIN_CLEAN_PERIOD * TIMEOUT_DIVISOR;
++
++/* Pipe for breaking select() to initiate periodic cleaning */
++int CleanPipe[2];
++
++/* Our relay: if_index followed by peer_mac */
++#define MY_RELAY_TAG_LEN (sizeof(int) + ETH_ALEN)
++
++/* Hack for daemonizing */
++#define CLOSEFD 64
++
++/**********************************************************************
++*%FUNCTION: keepDescriptor
++*%ARGUMENTS:
++* fd -- a file descriptor
++*%RETURNS:
++* 1 if descriptor should NOT be closed during daemonizing; 0 otherwise.
++***********************************************************************/
++static int
++keepDescriptor(int fd)
++{
++ int i;
++ if (fd == CleanPipe[0] || fd == CleanPipe[1]) return 1;
++ for (i=0; i&lt;NumInterfaces; i++) {
++ if (fd == Interfaces[i].discoverySock ||
++ fd == Interfaces[i].sessionSock) return 1;
++ }
++ return 0;
++}
++
++/**********************************************************************
++*%FUNCTION: addTag
++*%ARGUMENTS:
++* packet -- a PPPoE packet
++* tag -- tag to add
++*%RETURNS:
++* -1 if no room in packet; number of bytes added otherwise.
++*%DESCRIPTION:
++* Inserts a tag as the first tag in a PPPoE packet.
++***********************************************************************/
++int
++addTag(PPPoEPacket *packet, PPPoETag const *tag)
++{
++ return insertBytes(packet, packet-&gt;payload, tag,
++ ntohs(tag-&gt;length) + TAG_HDR_SIZE);
++}
++
++/**********************************************************************
++*%FUNCTION: insertBytes
++*%ARGUMENTS:
++* packet -- a PPPoE packet
++* loc -- location at which to insert bytes of data
++* bytes -- the data to insert
++* len -- length of data to insert
++*%RETURNS:
++* -1 if no room in packet; len otherwise.
++*%DESCRIPTION:
++* Inserts &quot;len&quot; bytes of data at location &quot;loc&quot; in &quot;packet&quot;, moving all
++* other data up to make room.
++***********************************************************************/
++int
++insertBytes(PPPoEPacket *packet,
++ unsigned char *loc,
++ void const *bytes,
++ int len)
++{
++ int toMove;
++ int plen = ntohs(packet-&gt;length);
++ /* Sanity checks */
++ if (loc &lt; packet-&gt;payload ||
++ loc &gt; packet-&gt;payload + plen ||
++ len + plen &gt; MAX_PPPOE_PAYLOAD) {
++ return -1;
++ }
++
++ toMove = (packet-&gt;payload + plen) - loc;
++ memmove(loc+len, loc, toMove);
++ memcpy(loc, bytes, len);
++ packet-&gt;length = htons(plen + len);
++ return len;
++}
++
++/**********************************************************************
++*%FUNCTION: removeBytes
++*%ARGUMENTS:
++* packet -- a PPPoE packet
++* loc -- location at which to remove bytes of data
++* len -- length of data to remove
++*%RETURNS:
++* -1 if there was a problem, len otherwise
++*%DESCRIPTION:
++* Removes &quot;len&quot; bytes of data from location &quot;loc&quot; in &quot;packet&quot;, moving all
++* other data down to close the gap
++***********************************************************************/
++int
++removeBytes(PPPoEPacket *packet,
++ unsigned char *loc,
++ int len)
++{
++ int toMove;
++ int plen = ntohs(packet-&gt;length);
++ /* Sanity checks */
++ if (len &lt; 0 || len &gt; plen ||
++ loc &lt; packet-&gt;payload ||
++ loc + len &gt; packet-&gt;payload + plen) {
++ return -1;
++ }
++
++ toMove = ((packet-&gt;payload + plen) - loc) - len;
++ memmove(loc, loc+len, toMove);
++ packet-&gt;length = htons(plen - len);
++ return len;
++}
++
++/**********************************************************************
++*%FUNCTION: usage
++*%ARGUMENTS:
++* argv0 -- program name
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Prints usage information and exits.
++***********************************************************************/
++void
++usage(char const *argv0)
++{
++ fprintf(stderr, &quot;Usage: %s [options]\n&quot;, argv0);
++ fprintf(stderr, &quot;Options:\n&quot;);
++ fprintf(stderr, &quot; -S if_name -- Specify interface for PPPoE Server\n&quot;);
++ fprintf(stderr, &quot; -C if_name -- Specify interface for PPPoE Client\n&quot;);
++ fprintf(stderr, &quot; -B if_name -- Specify interface for both clients and server\n&quot;);
++ fprintf(stderr, &quot; -n nsess -- Maxmimum number of sessions to relay\n&quot;);
++ fprintf(stderr, &quot; -i timeout -- Idle timeout in seconds (0 = no timeout)\n&quot;);
++ fprintf(stderr, &quot; -F -- Do not fork into background\n&quot;);
++ fprintf(stderr, &quot; -h -- Print this help message\n&quot;);
++
++ fprintf(stderr, &quot;\nPPPoE Version %s, Copyright (C) 2001 Roaring Penguin Software Inc.\n&quot;, VERSION);
++ fprintf(stderr, &quot;PPPoE comes with ABSOLUTELY NO WARRANTY.\n&quot;);
++ fprintf(stderr, &quot;This is free software, and you are welcome to redistribute it under the terms\n&quot;);
++ fprintf(stderr, &quot;of the GNU General Public License, version 2 or any later version.\n&quot;);
++ fprintf(stderr, &quot;<A HREF="http://www.roaringpenguin.com\n">http://www.roaringpenguin.com\n</A>&quot;);
++ exit(EXIT_SUCCESS);
++}
++
++/**********************************************************************
++*%FUNCTION: main
++*%ARGUMENTS:
++* argc, argv -- usual suspects
++*%RETURNS:
++* EXIT_SUCCESS or EXIT_FAILURE
++*%DESCRIPTION:
++* Main program. Options:
++* -C ifname -- Use interface for PPPoE clients
++* -S ifname -- Use interface for PPPoE servers
++* -B ifname -- Use interface for both clients and servers
++* -n sessions -- Maximum of &quot;n&quot; sessions
++***********************************************************************/
++int
++main(int argc, char *argv[])
++{
++ int opt;
++ int nsess = DEFAULT_SESSIONS;
++ struct sigaction sa;
++ int beDaemon = 1;
++ openlog(&quot;pppoe-relay&quot;, LOG_PID, LOG_DAEMON);
++
++ while((opt = getopt(argc, argv, &quot;hC:S:B:n:i:F&quot;)) != -1) {
++ switch(opt) {
++ case 'h':
++ usage(argv[0]);
++ break;
++ case 'F':
++ beDaemon = 0;
++ break;
++ case 'C':
++ addInterface(optarg, 1, 0);
++ break;
++ case 'S':
++ addInterface(optarg, 0, 1);
++ break;
++ case 'B':
++ addInterface(optarg, 1, 1);
++ break;
++ case 'i':
++ if (sscanf(optarg, &quot;%u&quot;, &amp;IdleTimeout) != 1) {
++ fprintf(stderr, &quot;Illegal argument to -i: should be -i timeout\n&quot;);
++ exit(EXIT_FAILURE);
++ }
++ CleanPeriod = IdleTimeout / TIMEOUT_DIVISOR;
++ if (CleanPeriod &lt; MIN_CLEAN_PERIOD) CleanPeriod = MIN_CLEAN_PERIOD;
++ break;
++ case 'n':
++ if (sscanf(optarg, &quot;%d&quot;, &amp;nsess) != 1) {
++ fprintf(stderr, &quot;Illegal argument to -n: should be -n #sessions\n&quot;);
++ exit(EXIT_FAILURE);
++ }
++ if (nsess &lt; 1 || nsess &gt; 65534) {
++ fprintf(stderr, &quot;Illegal argument to -n: must range from 1 to 65534\n&quot;);
++ exit(EXIT_FAILURE);
++ }
++ break;
++ default:
++ usage(argv[0]);
++ }
++ }
++
++#ifdef USE_LINUX_PACKET
++#ifndef HAVE_STRUCT_SOCKADDR_LL
++ fprintf(stderr, &quot;The PPPoE relay does not work on Linux 2.0 kernels.\n&quot;);
++ exit(EXIT_FAILURE);
++#endif
++#endif
++
++ /* Check that at least two interfaces were defined */
++ if (NumInterfaces &lt; 2) {
++ fprintf(stderr, &quot;%s: Must define at least two interfaces\n&quot;,
++ argv[0]);
++ exit(EXIT_FAILURE);
++ }
++
++ /* Make a pipe for the cleaner */
++ if (pipe(CleanPipe) &lt; 0) {
++ fatalSys(&quot;pipe&quot;);
++ }
++
++ /* Set up alarm handler */
++ sa.sa_handler = alarmHandler;
++ sigemptyset(&amp;sa.sa_mask);
++ sa.sa_flags = SA_RESTART;
++ if (sigaction(SIGALRM, &amp;sa, NULL) &lt; 0) {
++ fatalSys(&quot;sigaction&quot;);
++ }
++
++ /* Allocate memory for sessions, etc. */
++ initRelay(nsess);
++
++ /* Daemonize -- UNIX Network Programming, Vol. 1, Stevens */
++ if (beDaemon) {
++ int i;
++ i = fork();
++ if (i &lt; 0) {
++ fatalSys(&quot;fork&quot;);
++ } else if (i != 0) {
++ /* parent */
++ exit(0);
++ }
++ setsid();
++ signal(SIGHUP, SIG_IGN);
++ i = fork();
++ if (i &lt; 0) {
++ fatalSys(&quot;fork&quot;);
++ } else if (i != 0) {
++ exit(0);
++ }
++
++ chdir(&quot;/&quot;);
++ closelog();
++ for (i=0; i&lt;CLOSEFD; i++) {
++ if (!keepDescriptor(i)) {
++ close(i);
++ }
++ }
++ /* We nuked our syslog descriptor... */
++ openlog(&quot;pppoe-relay&quot;, LOG_PID, LOG_DAEMON);
++ }
++
++ /* Kick off SIGALRM if there is an idle timeout */
++ if (IdleTimeout) alarm(1);
++
++ /* Enter the relay loop */
++ relayLoop();
++
++ /* Shouldn't ever get here... */
++ return EXIT_FAILURE;
++}
++
++/**********************************************************************
++*%FUNCTION: addInterface
++*%ARGUMENTS:
++* ifname -- interface name
++* clientOK -- true if this interface should relay PADI, PADR packets.
++* acOK -- true if this interface should relay PADO, PADS packets.
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Opens an interface; sets up discovery and session sockets.
++***********************************************************************/
++void
++addInterface(char const *ifname,
++ int clientOK,
++ int acOK)
++{
++ PPPoEInterface *i;
++ if (NumInterfaces &gt;= MAX_INTERFACES) {
++ fprintf(stderr, &quot;Too many interfaces (%d max)\n&quot;,
++ MAX_INTERFACES);
++ exit(EXIT_FAILURE);
++ }
++ i = &amp;Interfaces[NumInterfaces++];
++ strncpy(i-&gt;name, ifname, IFNAMSIZ);
++ i-&gt;name[IFNAMSIZ] = 0;
++
++ i-&gt;discoverySock = openInterface(ifname, Eth_PPPOE_Discovery, i-&gt;mac);
++ i-&gt;sessionSock = openInterface(ifname, Eth_PPPOE_Session, NULL);
++ i-&gt;clientOK = clientOK;
++ i-&gt;acOK = acOK;
++}
++
++/**********************************************************************
++*%FUNCTION: initRelay
++*%ARGUMENTS:
++* nsess -- maximum allowable number of sessions
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Initializes relay hash table and session tables.
++***********************************************************************/
++void
++initRelay(int nsess)
++{
++ int i;
++ NumSessions = 0;
++ MaxSessions = nsess;
++
++ AllSessions = calloc(MaxSessions, sizeof(PPPoESession));
++ if (!AllSessions) {
++ rp_fatal(&quot;Unable to allocate memory for PPPoE session table&quot;);
++ }
++ AllHashes = calloc(MaxSessions*2, sizeof(SessionHash));
++ if (!AllHashes) {
++ rp_fatal(&quot;Unable to allocate memory for PPPoE hash table&quot;);
++ }
++
++ /* Initialize sessions in a linked list */
++ AllSessions[0].prev = NULL;
++ if (MaxSessions &gt; 1) {
++ AllSessions[0].next = &amp;AllSessions[1];
++ } else {
++ AllSessions[0].next = NULL;
++ }
++ for (i=1; i&lt;MaxSessions-1; i++) {
++ AllSessions[i].prev = &amp;AllSessions[i-1];
++ AllSessions[i].next = &amp;AllSessions[i+1];
++ }
++ if (MaxSessions &gt; 1) {
++ AllSessions[MaxSessions-1].prev = &amp;AllSessions[MaxSessions-2];
++ AllSessions[MaxSessions-1].next = NULL;
++ }
++
++ FreeSessions = AllSessions;
++ ActiveSessions = NULL;
++
++ /* Initialize session numbers which we hand out */
++ for (i=0; i&lt;MaxSessions; i++) {
++ AllSessions[i].sesNum = htons((UINT16_t) i+1);
++ }
++
++ /* Initialize hashes in a linked list */
++ AllHashes[0].prev = NULL;
++ AllHashes[0].next = &amp;AllHashes[1];
++ for (i=1; i&lt;2*MaxSessions-1; i++) {
++ AllHashes[i].prev = &amp;AllHashes[i-1];
++ AllHashes[i].next = &amp;AllHashes[i+1];
++ }
++ AllHashes[2*MaxSessions-1].prev = &amp;AllHashes[2*MaxSessions-2];
++ AllHashes[2*MaxSessions-1].next = NULL;
++
++ FreeHashes = AllHashes;
++}
++
++/**********************************************************************
++*%FUNCTION: createSession
++*%ARGUMENTS:
++* ac -- Ethernet interface on access-concentrator side
++* cli -- Ethernet interface on client side
++* acMac -- Access concentrator's MAC address
++* cliMac -- Client's MAC address
++* acSess -- Access concentrator's session ID.
++*%RETURNS:
++* PPPoESession structure; NULL if one could not be allocated
++*%DESCRIPTION:
++* Initializes relay hash table and session tables.
++***********************************************************************/
++PPPoESession *
++createSession(PPPoEInterface const *ac,
++ PPPoEInterface const *cli,
++ unsigned char const *acMac,
++ unsigned char const *cliMac,
++ UINT16_t acSes)
++{
++ PPPoESession *sess;
++ SessionHash *acHash, *cliHash;
++
++ if (NumSessions &gt;= MaxSessions) {
++ printErr(&quot;Maximum number of sessions reached -- cannot create new session&quot;);
++ return NULL;
++ }
++
++ /* Grab a free session */
++ sess = FreeSessions;
++ FreeSessions = sess-&gt;next;
++ NumSessions++;
++
++ /* Link it to the active list */
++ sess-&gt;next = ActiveSessions;
++ if (sess-&gt;next) {
++ sess-&gt;next-&gt;prev = sess;
++ }
++ ActiveSessions = sess;
++ sess-&gt;prev = NULL;
++
++ sess-&gt;epoch = Epoch;
++
++ /* Get two hash entries */
++ acHash = FreeHashes;
++ cliHash = acHash-&gt;next;
++ FreeHashes = cliHash-&gt;next;
++
++ acHash-&gt;peer = cliHash;
++ cliHash-&gt;peer = acHash;
++
++ sess-&gt;acHash = acHash;
++ sess-&gt;clientHash = cliHash;
++
++ acHash-&gt;interface = ac;
++ cliHash-&gt;interface = cli;
++
++ memcpy(acHash-&gt;peerMac, acMac, ETH_ALEN);
++ acHash-&gt;sesNum = acSes;
++ acHash-&gt;ses = sess;
++
++ memcpy(cliHash-&gt;peerMac, cliMac, ETH_ALEN);
++ cliHash-&gt;sesNum = sess-&gt;sesNum;
++ cliHash-&gt;ses = sess;
++
++ addHash(acHash);
++ addHash(cliHash);
++
++ /* Log */
++ syslog(LOG_INFO,
++ &quot;Opened session: server=%02x:%02x:%02x:%02x:%02x:%02x(%s:%d), client=%02x:%02x:%02x:%02x:%02x:%02x(%s:%d)&quot;,
++ acHash-&gt;peerMac[0], acHash-&gt;peerMac[1],
++ acHash-&gt;peerMac[2], acHash-&gt;peerMac[3],
++ acHash-&gt;peerMac[4], acHash-&gt;peerMac[5],
++ acHash-&gt;interface-&gt;name,
++ ntohs(acHash-&gt;sesNum),
++ cliHash-&gt;peerMac[0], cliHash-&gt;peerMac[1],
++ cliHash-&gt;peerMac[2], cliHash-&gt;peerMac[3],
++ cliHash-&gt;peerMac[4], cliHash-&gt;peerMac[5],
++ cliHash-&gt;interface-&gt;name,
++ ntohs(cliHash-&gt;sesNum));
++
++ return sess;
++}
++
++/**********************************************************************
++*%FUNCTION: freeSession
++*%ARGUMENTS:
++* ses -- session to free
++* msg -- extra message to log on syslog.
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Frees data used by a PPPoE session -- adds hashes and session back
++* to the free list
++***********************************************************************/
++void
++freeSession(PPPoESession *ses, char const *msg)
++{
++ syslog(LOG_INFO,
++ &quot;Closed session: server=%02x:%02x:%02x:%02x:%02x:%02x(%s:%d), client=%02x:%02x:%02x:%02x:%02x:%02x(%s:%d): %s&quot;,
++ ses-&gt;acHash-&gt;peerMac[0], ses-&gt;acHash-&gt;peerMac[1],
++ ses-&gt;acHash-&gt;peerMac[2], ses-&gt;acHash-&gt;peerMac[3],
++ ses-&gt;acHash-&gt;peerMac[4], ses-&gt;acHash-&gt;peerMac[5],
++ ses-&gt;acHash-&gt;interface-&gt;name,
++ ntohs(ses-&gt;acHash-&gt;sesNum),
++ ses-&gt;clientHash-&gt;peerMac[0], ses-&gt;clientHash-&gt;peerMac[1],
++ ses-&gt;clientHash-&gt;peerMac[2], ses-&gt;clientHash-&gt;peerMac[3],
++ ses-&gt;clientHash-&gt;peerMac[4], ses-&gt;clientHash-&gt;peerMac[5],
++ ses-&gt;clientHash-&gt;interface-&gt;name,
++ ntohs(ses-&gt;clientHash-&gt;sesNum), msg);
++
++ /* Unlink from active sessions */
++ if (ses-&gt;prev) {
++ ses-&gt;prev-&gt;next = ses-&gt;next;
++ } else {
++ ActiveSessions = ses-&gt;next;
++ }
++ if (ses-&gt;next) {
++ ses-&gt;next-&gt;prev = ses-&gt;prev;
++ }
++
++ /* Link onto free list -- this is a singly-linked list, so
++ we do not care about prev */
++ ses-&gt;next = FreeSessions;
++ FreeSessions = ses;
++
++ unhash(ses-&gt;acHash);
++ unhash(ses-&gt;clientHash);
++ NumSessions--;
++}
++
++/**********************************************************************
++*%FUNCTION: unhash
++*%ARGUMENTS:
++* sh -- session hash to free
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Frees a session hash -- takes it out of hash table and puts it on
++* free list.
++***********************************************************************/
++void
++unhash(SessionHash *sh)
++{
++ unsigned int b = hash(sh-&gt;peerMac, sh-&gt;sesNum) % HASHTAB_SIZE;
++ if (sh-&gt;prev) {
++ sh-&gt;prev-&gt;next = sh-&gt;next;
++ } else {
++ Buckets[b] = sh-&gt;next;
++ }
++
++ if (sh-&gt;next) {
++ sh-&gt;next-&gt;prev = sh-&gt;prev;
++ }
++
++ /* Add to free list (singly-linked) */
++ sh-&gt;next = FreeHashes;
++ FreeHashes = sh;
++}
++
++/**********************************************************************
++*%FUNCTION: addHash
++*%ARGUMENTS:
++* sh -- a session hash
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Adds a SessionHash to the hash table
++***********************************************************************/
++void
++addHash(SessionHash *sh)
++{
++ unsigned int b = hash(sh-&gt;peerMac, sh-&gt;sesNum) % HASHTAB_SIZE;
++ sh-&gt;next = Buckets[b];
++ sh-&gt;prev = NULL;
++ if (sh-&gt;next) {
++ sh-&gt;next-&gt;prev = sh;
++ }
++ Buckets[b] = sh;
++}
++
++/**********************************************************************
++*%FUNCTION: hash
++*%ARGUMENTS:
++* mac -- an Ethernet address
++* sesNum -- a session number
++*%RETURNS:
++* A hash value combining Ethernet address with session number.
++* Currently very simplistic; we may need to experiment with different
++* hash values.
++***********************************************************************/
++unsigned int
++hash(unsigned char const *mac, UINT16_t sesNum)
++{
++ unsigned int ans1 =
++ ((unsigned int) mac[0]) |
++ (((unsigned int) mac[1]) &lt;&lt; 8) |
++ (((unsigned int) mac[2]) &lt;&lt; 16) |
++ (((unsigned int) mac[3]) &lt;&lt; 24);
++ unsigned int ans2 =
++ ((unsigned int) sesNum) |
++ (((unsigned int) mac[4]) &lt;&lt; 16) |
++ (((unsigned int) mac[5]) &lt;&lt; 24);
++ return ans1 ^ ans2;
++}
++
++/**********************************************************************
++*%FUNCTION: findSession
++*%ARGUMENTS:
++* mac -- an Ethernet address
++* sesNum -- a session number
++*%RETURNS:
++* The session hash for peer address &quot;mac&quot;, session number sesNum
++***********************************************************************/
++SessionHash *
++findSession(unsigned char const *mac, UINT16_t sesNum)
++{
++ unsigned int b = hash(mac, sesNum) % HASHTAB_SIZE;
++ SessionHash *sh = Buckets[b];
++ while(sh) {
++ if (!memcmp(mac, sh-&gt;peerMac, ETH_ALEN) &amp;&amp; sesNum == sh-&gt;sesNum) {
++ return sh;
++ }
++ sh = sh-&gt;next;
++ }
++ return NULL;
++}
++
++/**********************************************************************
++*%FUNCTION: fatalSys
++*%ARGUMENTS:
++* str -- error message
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Prints a message plus the errno value to stderr and syslog and exits.
++***********************************************************************/
++void
++fatalSys(char const *str)
++{
++ char buf[1024];
++ sprintf(buf, &quot;%.256s: %.256s&quot;, str, strerror(errno));
++ printErr(buf);
++ exit(EXIT_FAILURE);
++}
++
++/**********************************************************************
++*%FUNCTION: sysErr
++*%ARGUMENTS:
++* str -- error message
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Prints a message plus the errno value to syslog.
++***********************************************************************/
++void
++sysErr(char const *str)
++{
++ char buf[1024];
++ sprintf(buf, &quot;%.256s: %.256s&quot;, str, strerror(errno));
++ printErr(buf);
++}
++
++/**********************************************************************
++*%FUNCTION: rp_fatal
++*%ARGUMENTS:
++* str -- error message
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Prints a message to stderr and syslog and exits.
++***********************************************************************/
++void
++rp_fatal(char const *str)
++{
++ printErr(str);
++ exit(EXIT_FAILURE);
++}
++
++/**********************************************************************
++*%FUNCTION: relayLoop
++*%ARGUMENTS:
++* None
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Runs the relay loop. This function never returns
++***********************************************************************/
++void
++relayLoop()
++{
++ fd_set readable, readableCopy;
++ int maxFD;
++ int i, r;
++ int sock;
++
++ /* Build the select set */
++ FD_ZERO(&amp;readable);
++ maxFD = 0;
++ for (i=0; i&lt;NumInterfaces; i++) {
++ sock = Interfaces[i].discoverySock;
++ if (sock &gt; maxFD) maxFD = sock;
++ FD_SET(sock, &amp;readable);
++ sock = Interfaces[i].sessionSock;
++ if (sock &gt; maxFD) maxFD = sock;
++ FD_SET(sock, &amp;readable);
++ if (CleanPipe[0] &gt; maxFD) maxFD = CleanPipe[0];
++ FD_SET(CleanPipe[0], &amp;readable);
++ }
++ maxFD++;
++ for(;;) {
++ readableCopy = readable;
++ for(;;) {
++ r = select(maxFD, &amp;readableCopy, NULL, NULL, NULL);
++ if (r &gt;= 0 || errno != EINTR) break;
++ }
++ if (r &lt; 0) {
++ sysErr(&quot;select (relayLoop)&quot;);
++ continue;
++ }
++
++ /* Handle session packets first */
++ for (i=0; i&lt;NumInterfaces; i++) {
++ if (FD_ISSET(Interfaces[i].sessionSock, &amp;readableCopy)) {
++ relayGotSessionPacket(&amp;Interfaces[i]);
++ }
++ }
++
++ /* Now handle discovery packets */
++ for (i=0; i&lt;NumInterfaces; i++) {
++ if (FD_ISSET(Interfaces[i].discoverySock, &amp;readableCopy)) {
++ relayGotDiscoveryPacket(&amp;Interfaces[i]);
++ }
++ }
++
++ /* Handle the session-cleaning process */
++ if (FD_ISSET(CleanPipe[0], &amp;readableCopy)) {
++ char dummy;
++ CleanCounter = 0;
++ read(CleanPipe[0], &amp;dummy, 1);
++ if (IdleTimeout) cleanSessions();
++ }
++ }
++}
++
++/**********************************************************************
++*%FUNCTION: relayGotDiscoveryPacket
++*%ARGUMENTS:
++* iface -- interface on which packet is waiting
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Receives and processes a discovery packet.
++***********************************************************************/
++void
++relayGotDiscoveryPacket(PPPoEInterface const *iface)
++{
++ PPPoEPacket packet;
++ int size;
++
++ if (receivePacket(iface-&gt;discoverySock, &amp;packet, &amp;size) &lt; 0) {
++ return;
++ }
++ /* Ignore unknown code/version */
++ if (packet.ver != 1 || packet.type != 1) {
++ return;
++ }
++
++ /* Validate length */
++ if (ntohs(packet.length) + HDR_SIZE &gt; size) {
++ syslog(LOG_ERR, &quot;Bogus PPPoE length field (%u)&quot;,
++ (unsigned int) ntohs(packet.length));
++ return;
++ }
++
++ /* Drop Ethernet frame padding */
++ if (size &gt; ntohs(packet.length) + HDR_SIZE) {
++ size = ntohs(packet.length) + HDR_SIZE;
++ }
++
++ switch(packet.code) {
++ case CODE_PADT:
++ relayHandlePADT(iface, &amp;packet, size);
++ break;
++ case CODE_PADI:
++ relayHandlePADI(iface, &amp;packet, size);
++ break;
++ case CODE_PADO:
++ relayHandlePADO(iface, &amp;packet, size);
++ break;
++ case CODE_PADR:
++ relayHandlePADR(iface, &amp;packet, size);
++ break;
++ case CODE_PADS:
++ relayHandlePADS(iface, &amp;packet, size);
++ break;
++ default:
++ syslog(LOG_ERR, &quot;Discovery packet on %s with unknown code %d&quot;,
++ iface-&gt;name, (int) packet.code);
++ }
++}
++
++/**********************************************************************
++*%FUNCTION: relayGotSessionPacket
++*%ARGUMENTS:
++* iface -- interface on which packet is waiting
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Receives and processes a session packet.
++***********************************************************************/
++void
++relayGotSessionPacket(PPPoEInterface const *iface)
++{
++ PPPoEPacket packet;
++ int size;
++ SessionHash *sh;
++ PPPoESession *ses;
++
++ if (receivePacket(iface-&gt;sessionSock, &amp;packet, &amp;size) &lt; 0) {
++ return;
++ }
++
++ /* Ignore unknown code/version */
++ if (packet.ver != 1 || packet.type != 1) {
++ return;
++ }
++
++ /* Must be a session packet */
++ if (packet.code != CODE_SESS) {
++ syslog(LOG_ERR, &quot;Session packet with code %d&quot;, (int) packet.code);
++ return;
++ }
++
++ /* Ignore session packets whose destination address isn't ours */
++ if (memcmp(packet.ethHdr.h_dest, iface-&gt;mac, ETH_ALEN)) {
++ return;
++ }
++
++ /* Validate length */
++ if (ntohs(packet.length) + HDR_SIZE &gt; size) {
++ syslog(LOG_ERR, &quot;Bogus PPPoE length field (%u)&quot;,
++ (unsigned int) ntohs(packet.length));
++ return;
++ }
++
++ /* Drop Ethernet frame padding */
++ if (size &gt; ntohs(packet.length) + HDR_SIZE) {
++ size = ntohs(packet.length) + HDR_SIZE;
++ }
++
++ /* We're in business! Find the hash */
++ sh = findSession(packet.ethHdr.h_source, packet.session);
++ if (!sh) {
++ /* Don't log this. Someone could be running the client and the
++ relay on the same box. */
++ return;
++ }
++
++ /* Relay it */
++ ses = sh-&gt;ses;
++ ses-&gt;epoch = Epoch;
++ sh = sh-&gt;peer;
++ packet.session = sh-&gt;sesNum;
++ memcpy(packet.ethHdr.h_source, sh-&gt;interface-&gt;mac, ETH_ALEN);
++ memcpy(packet.ethHdr.h_dest, sh-&gt;peerMac, ETH_ALEN);
++#if 0
++ fprintf(stderr, &quot;Relaying %02x:%02x:%02x:%02x:%02x:%02x(%s:%d) to %02x:%02x:%02x:%02x:%02x:%02x(%s:%d)\n&quot;,
++ sh-&gt;peer-&gt;peerMac[0], sh-&gt;peer-&gt;peerMac[1], sh-&gt;peer-&gt;peerMac[2],
++ sh-&gt;peer-&gt;peerMac[3], sh-&gt;peer-&gt;peerMac[4], sh-&gt;peer-&gt;peerMac[5],
++ sh-&gt;peer-&gt;interface-&gt;name, ntohs(sh-&gt;peer-&gt;sesNum),
++ sh-&gt;peerMac[0], sh-&gt;peerMac[1], sh-&gt;peerMac[2],
++ sh-&gt;peerMac[3], sh-&gt;peerMac[4], sh-&gt;peerMac[5],
++ sh-&gt;interface-&gt;name, ntohs(sh-&gt;sesNum));
++#endif
++ sendPacket(NULL, sh-&gt;interface-&gt;sessionSock, &amp;packet, size);
++}
++
++/**********************************************************************
++*%FUNCTION: relayHandlePADT
++*%ARGUMENTS:
++* iface -- interface on which packet was received
++* packet -- the PADT packet
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Receives and processes a PADT packet.
++***********************************************************************/
++void
++relayHandlePADT(PPPoEInterface const *iface,
++ PPPoEPacket *packet,
++ int size)
++{
++ SessionHash *sh;
++ PPPoESession *ses;
++
++ sh = findSession(packet-&gt;ethHdr.h_source, packet-&gt;session);
++ if (!sh) {
++ return;
++ }
++ /* Relay the PADT to the peer */
++ sh = sh-&gt;peer;
++ ses = sh-&gt;ses;
++ packet-&gt;session = sh-&gt;sesNum;
++ memcpy(packet-&gt;ethHdr.h_source, sh-&gt;interface-&gt;mac, ETH_ALEN);
++ memcpy(packet-&gt;ethHdr.h_dest, sh-&gt;peerMac, ETH_ALEN);
++ sendPacket(NULL, sh-&gt;interface-&gt;sessionSock, packet, size);
++
++ /* Destroy the session */
++ freeSession(ses, &quot;Received PADT&quot;);
++}
++
++/**********************************************************************
++*%FUNCTION: relayHandlePADI
++*%ARGUMENTS:
++* iface -- interface on which packet was received
++* packet -- the PADI packet
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Receives and processes a PADI packet.
++***********************************************************************/
++void
++relayHandlePADI(PPPoEInterface const *iface,
++ PPPoEPacket *packet,
++ int size)
++{
++ PPPoETag tag;
++ unsigned char *loc;
++ int i, r;
++
++ int ifIndex;
++
++ /* Can a client legally be behind this interface? */
++ if (!iface-&gt;clientOK) {
++ syslog(LOG_ERR,
++ &quot;PADI packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not permitted&quot;,
++ packet-&gt;ethHdr.h_source[0],
++ packet-&gt;ethHdr.h_source[1],
++ packet-&gt;ethHdr.h_source[2],
++ packet-&gt;ethHdr.h_source[3],
++ packet-&gt;ethHdr.h_source[4],
++ packet-&gt;ethHdr.h_source[5],
++ iface-&gt;name);
++ return;
++ }
++
++ /* Source address must be unicast */
++ if (NOT_UNICAST(packet-&gt;ethHdr.h_source)) {
++ syslog(LOG_ERR,
++ &quot;PADI packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not from a unicast address&quot;,
++ packet-&gt;ethHdr.h_source[0],
++ packet-&gt;ethHdr.h_source[1],
++ packet-&gt;ethHdr.h_source[2],
++ packet-&gt;ethHdr.h_source[3],
++ packet-&gt;ethHdr.h_source[4],
++ packet-&gt;ethHdr.h_source[5],
++ iface-&gt;name);
++ return;
++ }
++
++ /* Destination address must be broadcast */
++ if (NOT_BROADCAST(packet-&gt;ethHdr.h_dest)) {
++ syslog(LOG_ERR,
++ &quot;PADI packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not to a broadcast address&quot;,
++ packet-&gt;ethHdr.h_source[0],
++ packet-&gt;ethHdr.h_source[1],
++ packet-&gt;ethHdr.h_source[2],
++ packet-&gt;ethHdr.h_source[3],
++ packet-&gt;ethHdr.h_source[4],
++ packet-&gt;ethHdr.h_source[5],
++ iface-&gt;name);
++ return;
++ }
++
++ /* Get array index of interface */
++ ifIndex = iface - Interfaces;
++
++ loc = findTag(packet, TAG_RELAY_SESSION_ID, &amp;tag);
++ if (!loc) {
++ tag.type = htons(TAG_RELAY_SESSION_ID);
++ tag.length = htons(MY_RELAY_TAG_LEN);
++ memcpy(tag.payload, &amp;ifIndex, sizeof(ifIndex));
++ memcpy(tag.payload+sizeof(ifIndex), packet-&gt;ethHdr.h_source, ETH_ALEN);
++ /* Add a relay tag if there's room */
++ r = addTag(packet, &amp;tag);
++ if (r &lt; 0) return;
++ size += r;
++ } else {
++ /* We do not re-use relay-id tags. Drop the frame. The RFC says the
++ relay agent SHOULD return a Generic-Error tag, but this does not
++ make sense for PADI packets. */
++ return;
++ }
++
++ /* Broadcast the PADI on all AC-capable interfaces except the interface
++ on which it came */
++ for (i=0; i &lt; NumInterfaces; i++) {
++ if (iface == &amp;Interfaces[i]) continue;
++ if (!Interfaces[i].acOK) continue;
++ memcpy(packet-&gt;ethHdr.h_source, Interfaces[i].mac, ETH_ALEN);
++ sendPacket(NULL, Interfaces[i].discoverySock, packet, size);
++ }
++
++}
++
++/**********************************************************************
++*%FUNCTION: relayHandlePADO
++*%ARGUMENTS:
++* iface -- interface on which packet was received
++* packet -- the PADO packet
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Receives and processes a PADO packet.
++***********************************************************************/
++void
++relayHandlePADO(PPPoEInterface const *iface,
++ PPPoEPacket *packet,
++ int size)
++{
++ PPPoETag tag;
++ unsigned char *loc;
++ int ifIndex;
++ int acIndex;
++
++ /* Can a server legally be behind this interface? */
++ if (!iface-&gt;acOK) {
++ syslog(LOG_ERR,
++ &quot;PADO packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not permitted&quot;,
++ packet-&gt;ethHdr.h_source[0],
++ packet-&gt;ethHdr.h_source[1],
++ packet-&gt;ethHdr.h_source[2],
++ packet-&gt;ethHdr.h_source[3],
++ packet-&gt;ethHdr.h_source[4],
++ packet-&gt;ethHdr.h_source[5],
++ iface-&gt;name);
++ return;
++ }
++
++ acIndex = iface - Interfaces;
++
++ /* Source address must be unicast */
++ if (NOT_UNICAST(packet-&gt;ethHdr.h_source)) {
++ syslog(LOG_ERR,
++ &quot;PADO packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not from a unicast address&quot;,
++ packet-&gt;ethHdr.h_source[0],
++ packet-&gt;ethHdr.h_source[1],
++ packet-&gt;ethHdr.h_source[2],
++ packet-&gt;ethHdr.h_source[3],
++ packet-&gt;ethHdr.h_source[4],
++ packet-&gt;ethHdr.h_source[5],
++ iface-&gt;name);
++ return;
++ }
++
++ /* Destination address must be interface's MAC address */
++ if (memcmp(packet-&gt;ethHdr.h_dest, iface-&gt;mac, ETH_ALEN)) {
++ return;
++ }
++
++ /* Find relay tag */
++ loc = findTag(packet, TAG_RELAY_SESSION_ID, &amp;tag);
++ if (!loc) {
++ syslog(LOG_ERR,
++ &quot;PADO packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have Relay-Session-Id tag&quot;,
++ packet-&gt;ethHdr.h_source[0],
++ packet-&gt;ethHdr.h_source[1],
++ packet-&gt;ethHdr.h_source[2],
++ packet-&gt;ethHdr.h_source[3],
++ packet-&gt;ethHdr.h_source[4],
++ packet-&gt;ethHdr.h_source[5],
++ iface-&gt;name);
++ return;
++ }
++
++ /* If it's the wrong length, ignore it */
++ if (ntohs(tag.length) != MY_RELAY_TAG_LEN) {
++ syslog(LOG_ERR,
++ &quot;PADO packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have correct length Relay-Session-Id tag&quot;,
++ packet-&gt;ethHdr.h_source[0],
++ packet-&gt;ethHdr.h_source[1],
++ packet-&gt;ethHdr.h_source[2],
++ packet-&gt;ethHdr.h_source[3],
++ packet-&gt;ethHdr.h_source[4],
++ packet-&gt;ethHdr.h_source[5],
++ iface-&gt;name);
++ return;
++ }
++
++ /* Extract interface index */
++ memcpy(&amp;ifIndex, tag.payload, sizeof(ifIndex));
++
++ if (ifIndex &lt; 0 || ifIndex &gt;= NumInterfaces ||
++ !Interfaces[ifIndex].clientOK ||
++ iface == &amp;Interfaces[ifIndex]) {
++ syslog(LOG_ERR,
++ &quot;PADO packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s has invalid interface in Relay-Session-Id tag&quot;,
++ packet-&gt;ethHdr.h_source[0],
++ packet-&gt;ethHdr.h_source[1],
++ packet-&gt;ethHdr.h_source[2],
++ packet-&gt;ethHdr.h_source[3],
++ packet-&gt;ethHdr.h_source[4],
++ packet-&gt;ethHdr.h_source[5],
++ iface-&gt;name);
++ return;
++ }
++
++ /* Replace Relay-ID tag with opposite-direction tag */
++ memcpy(loc+TAG_HDR_SIZE, &amp;acIndex, sizeof(acIndex));
++ memcpy(loc+TAG_HDR_SIZE+sizeof(ifIndex), packet-&gt;ethHdr.h_source, ETH_ALEN);
++
++ /* Set destination address to MAC address in relay ID */
++ memcpy(packet-&gt;ethHdr.h_dest, tag.payload + sizeof(ifIndex), ETH_ALEN);
++
++ /* Set source address to MAC address of interface */
++ memcpy(packet-&gt;ethHdr.h_source, Interfaces[ifIndex].mac, ETH_ALEN);
++
++ /* Send the PADO to the proper client */
++ sendPacket(NULL, Interfaces[ifIndex].discoverySock, packet, size);
++}
++
++/**********************************************************************
++*%FUNCTION: relayHandlePADR
++*%ARGUMENTS:
++* iface -- interface on which packet was received
++* packet -- the PADR packet
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Receives and processes a PADR packet.
++***********************************************************************/
++void
++relayHandlePADR(PPPoEInterface const *iface,
++ PPPoEPacket *packet,
++ int size)
++{
++ PPPoETag tag;
++ unsigned char *loc;
++ int ifIndex;
++ int cliIndex;
++
++ /* Can a client legally be behind this interface? */
++ if (!iface-&gt;clientOK) {
++ syslog(LOG_ERR,
++ &quot;PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not permitted&quot;,
++ packet-&gt;ethHdr.h_source[0],
++ packet-&gt;ethHdr.h_source[1],
++ packet-&gt;ethHdr.h_source[2],
++ packet-&gt;ethHdr.h_source[3],
++ packet-&gt;ethHdr.h_source[4],
++ packet-&gt;ethHdr.h_source[5],
++ iface-&gt;name);
++ return;
++ }
++
++ cliIndex = iface - Interfaces;
++
++ /* Source address must be unicast */
++ if (NOT_UNICAST(packet-&gt;ethHdr.h_source)) {
++ syslog(LOG_ERR,
++ &quot;PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not from a unicast address&quot;,
++ packet-&gt;ethHdr.h_source[0],
++ packet-&gt;ethHdr.h_source[1],
++ packet-&gt;ethHdr.h_source[2],
++ packet-&gt;ethHdr.h_source[3],
++ packet-&gt;ethHdr.h_source[4],
++ packet-&gt;ethHdr.h_source[5],
++ iface-&gt;name);
++ return;
++ }
++
++ /* Destination address must be interface's MAC address */
++ if (memcmp(packet-&gt;ethHdr.h_dest, iface-&gt;mac, ETH_ALEN)) {
++ return;
++ }
++
++ /* Find relay tag */
++ loc = findTag(packet, TAG_RELAY_SESSION_ID, &amp;tag);
++ if (!loc) {
++ syslog(LOG_ERR,
++ &quot;PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have Relay-Session-Id tag&quot;,
++ packet-&gt;ethHdr.h_source[0],
++ packet-&gt;ethHdr.h_source[1],
++ packet-&gt;ethHdr.h_source[2],
++ packet-&gt;ethHdr.h_source[3],
++ packet-&gt;ethHdr.h_source[4],
++ packet-&gt;ethHdr.h_source[5],
++ iface-&gt;name);
++ return;
++ }
++
++ /* If it's the wrong length, ignore it */
++ if (ntohs(tag.length) != MY_RELAY_TAG_LEN) {
++ syslog(LOG_ERR,
++ &quot;PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have correct length Relay-Session-Id tag&quot;,
++ packet-&gt;ethHdr.h_source[0],
++ packet-&gt;ethHdr.h_source[1],
++ packet-&gt;ethHdr.h_source[2],
++ packet-&gt;ethHdr.h_source[3],
++ packet-&gt;ethHdr.h_source[4],
++ packet-&gt;ethHdr.h_source[5],
++ iface-&gt;name);
++ return;
++ }
++
++ /* Extract interface index */
++ memcpy(&amp;ifIndex, tag.payload, sizeof(ifIndex));
++
++ if (ifIndex &lt; 0 || ifIndex &gt;= NumInterfaces ||
++ !Interfaces[ifIndex].acOK ||
++ iface == &amp;Interfaces[ifIndex]) {
++ syslog(LOG_ERR,
++ &quot;PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s has invalid interface in Relay-Session-Id tag&quot;,
++ packet-&gt;ethHdr.h_source[0],
++ packet-&gt;ethHdr.h_source[1],
++ packet-&gt;ethHdr.h_source[2],
++ packet-&gt;ethHdr.h_source[3],
++ packet-&gt;ethHdr.h_source[4],
++ packet-&gt;ethHdr.h_source[5],
++ iface-&gt;name);
++ return;
++ }
++
++ /* Replace Relay-ID tag with opposite-direction tag */
++ memcpy(loc+TAG_HDR_SIZE, &amp;cliIndex, sizeof(cliIndex));
++ memcpy(loc+TAG_HDR_SIZE+sizeof(ifIndex), packet-&gt;ethHdr.h_source, ETH_ALEN);
++
++ /* Set destination address to MAC address in relay ID */
++ memcpy(packet-&gt;ethHdr.h_dest, tag.payload + sizeof(ifIndex), ETH_ALEN);
++
++ /* Set source address to MAC address of interface */
++ memcpy(packet-&gt;ethHdr.h_source, Interfaces[ifIndex].mac, ETH_ALEN);
++
++ /* Send the PADR to the proper access concentrator */
++ sendPacket(NULL, Interfaces[ifIndex].discoverySock, packet, size);
++}
++
++/**********************************************************************
++*%FUNCTION: relayHandlePADS
++*%ARGUMENTS:
++* iface -- interface on which packet was received
++* packet -- the PADS packet
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Receives and processes a PADS packet.
++***********************************************************************/
++void
++relayHandlePADS(PPPoEInterface const *iface,
++ PPPoEPacket *packet,
++ int size)
++{
++ PPPoETag tag;
++ unsigned char *loc;
++ int ifIndex;
++ int acIndex;
++ PPPoESession *ses = NULL;
++ SessionHash *sh;
++
++ /* Can a server legally be behind this interface? */
++ if (!iface-&gt;acOK) {
++ syslog(LOG_ERR,
++ &quot;PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not permitted&quot;,
++ packet-&gt;ethHdr.h_source[0],
++ packet-&gt;ethHdr.h_source[1],
++ packet-&gt;ethHdr.h_source[2],
++ packet-&gt;ethHdr.h_source[3],
++ packet-&gt;ethHdr.h_source[4],
++ packet-&gt;ethHdr.h_source[5],
++ iface-&gt;name);
++ return;
++ }
++
++ acIndex = iface - Interfaces;
++
++ /* Source address must be unicast */
++ if (NOT_UNICAST(packet-&gt;ethHdr.h_source)) {
++ syslog(LOG_ERR,
++ &quot;PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not from a unicast address&quot;,
++ packet-&gt;ethHdr.h_source[0],
++ packet-&gt;ethHdr.h_source[1],
++ packet-&gt;ethHdr.h_source[2],
++ packet-&gt;ethHdr.h_source[3],
++ packet-&gt;ethHdr.h_source[4],
++ packet-&gt;ethHdr.h_source[5],
++ iface-&gt;name);
++ return;
++ }
++
++ /* Destination address must be interface's MAC address */
++ if (memcmp(packet-&gt;ethHdr.h_dest, iface-&gt;mac, ETH_ALEN)) {
++ return;
++ }
++
++ /* Find relay tag */
++ loc = findTag(packet, TAG_RELAY_SESSION_ID, &amp;tag);
++ if (!loc) {
++ syslog(LOG_ERR,
++ &quot;PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have Relay-Session-Id tag&quot;,
++ packet-&gt;ethHdr.h_source[0],
++ packet-&gt;ethHdr.h_source[1],
++ packet-&gt;ethHdr.h_source[2],
++ packet-&gt;ethHdr.h_source[3],
++ packet-&gt;ethHdr.h_source[4],
++ packet-&gt;ethHdr.h_source[5],
++ iface-&gt;name);
++ return;
++ }
++
++ /* If it's the wrong length, ignore it */
++ if (ntohs(tag.length) != MY_RELAY_TAG_LEN) {
++ syslog(LOG_ERR,
++ &quot;PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have correct length Relay-Session-Id tag&quot;,
++ packet-&gt;ethHdr.h_source[0],
++ packet-&gt;ethHdr.h_source[1],
++ packet-&gt;ethHdr.h_source[2],
++ packet-&gt;ethHdr.h_source[3],
++ packet-&gt;ethHdr.h_source[4],
++ packet-&gt;ethHdr.h_source[5],
++ iface-&gt;name);
++ return;
++ }
++
++ /* Extract interface index */
++ memcpy(&amp;ifIndex, tag.payload, sizeof(ifIndex));
++
++ if (ifIndex &lt; 0 || ifIndex &gt;= NumInterfaces ||
++ !Interfaces[ifIndex].clientOK ||
++ iface == &amp;Interfaces[ifIndex]) {
++ syslog(LOG_ERR,
++ &quot;PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s has invalid interface in Relay-Session-Id tag&quot;,
++ packet-&gt;ethHdr.h_source[0],
++ packet-&gt;ethHdr.h_source[1],
++ packet-&gt;ethHdr.h_source[2],
++ packet-&gt;ethHdr.h_source[3],
++ packet-&gt;ethHdr.h_source[4],
++ packet-&gt;ethHdr.h_source[5],
++ iface-&gt;name);
++ return;
++ }
++
++ /* If session ID is zero, it's the AC respoding with an error.
++ Just relay it; do not create a session */
++ if (packet-&gt;session != htons(0)) {
++ /* Check for existing session */
++ sh = findSession(packet-&gt;ethHdr.h_source, packet-&gt;session);
++ if (sh) ses = sh-&gt;ses;
++
++ /* If already an existing session, assume it's a duplicate PADS. Send
++ the frame, but do not create a new session. Is this the right
++ thing to do? Arguably, should send an error to the client and
++ a PADT to the server, because this could happen due to a
++ server crash and reboot. */
++
++ if (!ses) {
++ /* Create a new session */
++ ses = createSession(iface, &amp;Interfaces[ifIndex],
++ packet-&gt;ethHdr.h_source,
++ loc + TAG_HDR_SIZE + sizeof(ifIndex), packet-&gt;session);
++ if (!ses) {
++ /* Can't allocate session -- send error PADS to client and
++ PADT to server */
++ PPPoETag hostUniq, *hu;
++ if (findTag(packet, TAG_HOST_UNIQ, &amp;hostUniq)) {
++ hu = &amp;hostUniq;
++ } else {
++ hu = NULL;
++ }
++ relaySendError(CODE_PADS, htons(0), &amp;Interfaces[ifIndex],
++ loc + TAG_HDR_SIZE + sizeof(ifIndex),
++ hu, &quot;RP-PPPoE: Relay: Unable to allocate session&quot;);
++ relaySendError(CODE_PADT, packet-&gt;session, iface,
++ packet-&gt;ethHdr.h_source, NULL,
++ &quot;RP-PPPoE: Relay: Unable to allocate session&quot;);
++ return;
++ }
++ }
++ /* Replace session number */
++ packet-&gt;session = ses-&gt;sesNum;
++ }
++
++ /* Remove relay-ID tag */
++ removeBytes(packet, loc, MY_RELAY_TAG_LEN + TAG_HDR_SIZE);
++ size -= (MY_RELAY_TAG_LEN + TAG_HDR_SIZE);
++
++ /* Set destination address to MAC address in relay ID */
++ memcpy(packet-&gt;ethHdr.h_dest, tag.payload + sizeof(ifIndex), ETH_ALEN);
++
++ /* Set source address to MAC address of interface */
++ memcpy(packet-&gt;ethHdr.h_source, Interfaces[ifIndex].mac, ETH_ALEN);
++
++ /* Send the PADS to the proper client */
++ sendPacket(NULL, Interfaces[ifIndex].discoverySock, packet, size);
++}
++
++/**********************************************************************
++*%FUNCTION: relaySendError
++*%ARGUMENTS:
++* code -- PPPoE packet code (PADS or PADT, typically)
++* session -- PPPoE session number
++* iface -- interface on which to send frame
++* mac -- Ethernet address to which frame should be sent
++* hostUniq -- if non-NULL, a hostUniq tag to add to error frame
++* errMsg -- error message to insert into Generic-Error tag.
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Sends either a PADS or PADT packet with a Generic-Error tag and an
++* error message.
++***********************************************************************/
++void
++relaySendError(unsigned char code,
++ UINT16_t session,
++ PPPoEInterface const *iface,
++ unsigned char const *mac,
++ PPPoETag const *hostUniq,
++ char const *errMsg)
++{
++ PPPoEPacket packet;
++ PPPoETag errTag;
++ int size;
++
++ memcpy(packet.ethHdr.h_source, iface-&gt;mac, ETH_ALEN);
++ memcpy(packet.ethHdr.h_dest, mac, ETH_ALEN);
++ packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
++ packet.type = 1;
++ packet.ver = 1;
++ packet.code = code;
++ packet.session = session;
++ packet.length = htons(0);
++ if (hostUniq) {
++ if (addTag(&amp;packet, hostUniq) &lt; 0) return;
++ }
++ errTag.type = htons(TAG_GENERIC_ERROR);
++ errTag.length = htons(strlen(errMsg));
++ strcpy(errTag.payload, errMsg);
++ if (addTag(&amp;packet, &amp;errTag) &lt; 0) return;
++ size = ntohs(packet.length) + HDR_SIZE;
++ if (code == CODE_PADT) {
++ sendPacket(NULL, iface-&gt;discoverySock, &amp;packet, size);
++ } else {
++ sendPacket(NULL, iface-&gt;sessionSock, &amp;packet, size);
++ }
++}
++
++/**********************************************************************
++*%FUNCTION: alarmHandler
++*%ARGUMENTS:
++* sig -- signal number
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* SIGALRM handler. Increments Epoch; if necessary, writes a byte of
++* data to the alarm pipe to trigger the stale-session cleaner.
++***********************************************************************/
++void
++alarmHandler(int sig)
++{
++ alarm(1);
++ Epoch++;
++ CleanCounter++;
++ if (CleanCounter == CleanPeriod) {
++ write(CleanPipe[1], &quot;&quot;, 1);
++ }
++}
++
++/**********************************************************************
++*%FUNCTION: cleanSessions
++*%ARGUMENTS:
++* None
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Goes through active sessions and cleans sessions idle for longer
++* than IdleTimeout seconds.
++***********************************************************************/
++void cleanSessions(void)
++{
++ PPPoESession *cur, *next;
++ cur = ActiveSessions;
++ while(cur) {
++ next = cur-&gt;next;
++ if (Epoch - cur-&gt;epoch &gt; IdleTimeout) {
++ /* Send PADT to each peer */
++ relaySendError(CODE_PADT, cur-&gt;acHash-&gt;sesNum,
++ cur-&gt;acHash-&gt;interface,
++ cur-&gt;acHash-&gt;peerMac, NULL,
++ &quot;RP-PPPoE: Relay: Session exceeded idle timeout&quot;);
++ relaySendError(CODE_PADT, cur-&gt;clientHash-&gt;sesNum,
++ cur-&gt;clientHash-&gt;interface,
++ cur-&gt;clientHash-&gt;peerMac, NULL,
++ &quot;RP-PPPoE: Relay: Session exceeded idle timeout&quot;);
++ freeSession(cur, &quot;Idle Timeout&quot;);
++ }
++ cur = next;
++ }
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/src/relay.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/rp-pppoe/src/relay.h
+===================================================================
+--- drakx/trunk/mdk-stage1/rp-pppoe/src/relay.h (rev 0)
++++ drakx/trunk/mdk-stage1/rp-pppoe/src/relay.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,97 @@
++/**********************************************************************
++*
++* relay.h
++*
++* Definitions for PPPoE relay
++*
++* Copyright (C) 2001 Roaring Penguin Software Inc.
++*
++* This program may be distributed according to the terms of the GNU
++* General Public License, version 2 or (at your option) any later version.
++*
++* $Id: relay.h 195724 2001-06-11 13:49:39Z gc $
++*
++***********************************************************************/
++
++#include &quot;pppoe.h&quot;
++
++/* Description for each active Ethernet interface */
++typedef struct InterfaceStruct {
++ char name[IFNAMSIZ+1]; /* Interface name */
++ int discoverySock; /* Socket for discovery frames */
++ int sessionSock; /* Socket for session frames */
++ int clientOK; /* Client requests allowed (PADI, PADR) */
++ int acOK; /* AC replies allowed (PADO, PADS) */
++ unsigned char mac[ETH_ALEN]; /* MAC address */
++} PPPoEInterface;
++
++/* Session state for relay */
++struct SessionHashStruct;
++typedef struct SessionStruct {
++ struct SessionStruct *next; /* Free list link */
++ struct SessionStruct *prev; /* Free list link */
++ struct SessionHashStruct *acHash; /* Hash bucket for AC MAC/Session */
++ struct SessionHashStruct *clientHash; /* Hash bucket for client MAC/Session */
++ unsigned int epoch; /* Epoch when last activity was seen */
++ UINT16_t sesNum; /* Session number assigned by relay */
++} PPPoESession;
++
++/* Hash table entry to find sessions */
++typedef struct SessionHashStruct {
++ struct SessionHashStruct *next; /* Link in hash chain */
++ struct SessionHashStruct *prev; /* Link in hash chain */
++ struct SessionHashStruct *peer; /* Peer for this session */
++ PPPoEInterface const *interface; /* Interface */
++ unsigned char peerMac[ETH_ALEN]; /* Peer's MAC address */
++ UINT16_t sesNum; /* Session number */
++ PPPoESession *ses; /* Session data */
++} SessionHash;
++
++/* Function prototypes */
++
++void relayGotSessionPacket(PPPoEInterface const *i);
++void relayGotDiscoveryPacket(PPPoEInterface const *i);
++PPPoEInterface *findInterface(int sock);
++unsigned int hash(unsigned char const *mac, UINT16_t sesNum);
++SessionHash *findSession(unsigned char const *mac, UINT16_t sesNum);
++void deleteHash(SessionHash *hash);
++PPPoESession *createSession(PPPoEInterface const *ac,
++ PPPoEInterface const *cli,
++ unsigned char const *acMac,
++ unsigned char const *cliMac,
++ UINT16_t acSes);
++void freeSession(PPPoESession *ses, char const *msg);
++void addInterface(char const *ifname, int clientOK, int acOK);
++void usage(char const *progname);
++void initRelay(int nsess);
++void relayLoop(void);
++void addHash(SessionHash *sh);
++void unhash(SessionHash *sh);
++
++void relayHandlePADT(PPPoEInterface const *iface, PPPoEPacket *packet, int size);
++void relayHandlePADI(PPPoEInterface const *iface, PPPoEPacket *packet, int size);
++void relayHandlePADO(PPPoEInterface const *iface, PPPoEPacket *packet, int size);
++void relayHandlePADR(PPPoEInterface const *iface, PPPoEPacket *packet, int size);
++void relayHandlePADS(PPPoEInterface const *iface, PPPoEPacket *packet, int size);
++
++int addTag(PPPoEPacket *packet, PPPoETag const *tag);
++int insertBytes(PPPoEPacket *packet, unsigned char *loc,
++ void const *bytes, int length);
++int removeBytes(PPPoEPacket *packet, unsigned char *loc,
++ int length);
++void relaySendError(unsigned char code,
++ UINT16_t session,
++ PPPoEInterface const *iface,
++ unsigned char const *mac,
++ PPPoETag const *hostUniq,
++ char const *errMsg);
++
++void alarmHandler(int sig);
++void cleanSessions(void);
++
++#define MAX_INTERFACES 8
++#define DEFAULT_SESSIONS 5000
++
++/* Hash table size -- a prime number; gives load factor of around 6
++ for 65534 sessions */
++#define HASHTAB_SIZE 18917
+
+
+Property changes on: drakx/trunk/mdk-stage1/rp-pppoe/src/relay.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/Makefile
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/Makefile (rev 0)
++++ drakx/trunk/mdk-stage1/slang/Makefile 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,42 @@
++ #******************************************************************************
++ #
++ # Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ #
++ # Copyright 2000 Mandriva
++ #
++ # This software may be freely redistributed under the terms of the GNU
++ # public license.
++ #
++ # You should have received a copy of the GNU General Public License
++ # along with this program; if not, write to the Free Software
++ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ #
++ #*****************************************************************************
++
++top_dir = ..
++
++include $(top_dir)/Makefile.common
++
++
++LIBNAME = libslang
++
++OBJS = sltermin.o sldisply.o slutty.o slang.o slarray.o slclass.o slcmd.o slerr.o slgetkey.o slkeymap.o slmalloc.o slmath.o slmemchr.o slmemcmp.o slmemcpy.o slmemset.o slmisc.o slparse.o slprepr.o slregexp.o slrline.o slsearch.o slsmg.o slstd.o sltoken.o sltypes.o slxstrng.o slcurses.o slscroll.o slsignal.o slkeypad.o slerrno.o slstring.o slstruct.o slcmplex.o slarrfun.o slimport.o slpath.o slarith.o slassoc.o slcompat.o slposdir.o slstdio.o slproc.o sltime.o slstrops.o slbstr.o slpack.o slintall.o slistruc.o slposio.o slnspace.o slarrmis.o slospath.o slscanf.o
++
++DEFS = -Dunix -DSLANG
++
++INCS =
++
++
++TARGETS = $(LIBNAME).a
++
++all: $(TARGETS)
++
++clean:
++ rm -f *.o *.a
++
++$(LIBNAME).a: $(OBJS)
++ ar -cru $@ $^
++ ranlib $@
++
++$(OBJS): %.o: %.c
++ $(DIET) gcc $(CFLAGS) $(DEFS) $(INCS) $(INCLUDES) -c $&lt; -o $@
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/Makefile
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/_slang.h
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/_slang.h (rev 0)
++++ drakx/trunk/mdk-stage1/slang/_slang.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,743 @@
++#ifndef _PRIVATE_SLANG_H_
++#define _PRIVATE_SLANG_H_
++/* header file for S-Lang internal structures that users do not (should not)
++ need. Use slang.h for that purpose. */
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++/* #include &quot;config.h&quot; */
++#include &quot;jdmacros.h&quot;
++#include &quot;sllimits.h&quot;
++
++#ifdef VMS
++# define SLANG_SYSTEM_NAME &quot;_VMS&quot;
++#else
++# if defined (IBMPC_SYSTEM)
++# define SLANG_SYSTEM_NAME &quot;_IBMPC&quot;
++# else
++# define SLANG_SYSTEM_NAME &quot;_UNIX&quot;
++# endif
++#endif /* VMS */
++
++/* These quantities are main_types for byte-compiled code. They are used
++ * by the inner_interp routine. The _BC_ means byte-code.
++ */
++
++#define _SLANG_BC_LVARIABLE SLANG_LVARIABLE /* 0x01 */
++#define _SLANG_BC_GVARIABLE SLANG_GVARIABLE /* 0x02 */
++#define _SLANG_BC_IVARIABLE SLANG_IVARIABLE /* 0x03 */
++#define _SLANG_BC_RVARIABLE SLANG_RVARIABLE /* 0x04 */
++#define _SLANG_BC_INTRINSIC SLANG_INTRINSIC /* 0x05 */
++#define _SLANG_BC_FUNCTION SLANG_FUNCTION /* 0x06 */
++#define _SLANG_BC_MATH_UNARY SLANG_MATH_UNARY /* 0x07 */
++#define _SLANG_BC_APP_UNARY SLANG_APP_UNARY /* 0x08 */
++#define _SLANG_BC_ICONST SLANG_ICONSTANT /* 0x09 */
++#define _SLANG_BC_DCONST SLANG_DCONSTANT /* 0x0A */
++#define _SLANG_BC_PVARIABLE SLANG_PVARIABLE /* 0x0B */
++#define _SLANG_BC_PFUNCTION SLANG_PFUNCTION /* 0x0C */
++
++#define _SLANG_BC_BINARY 0x10
++#define _SLANG_BC_LITERAL 0x11 /* constant objects */
++#define _SLANG_BC_LITERAL_INT 0x12
++#define _SLANG_BC_LITERAL_STR 0x13
++#define _SLANG_BC_BLOCK 0x14
++
++/* These 3 MUST be in this order too ! */
++#define _SLANG_BC_RETURN 0x15
++#define _SLANG_BC_BREAK 0x16
++#define _SLANG_BC_CONTINUE 0x17
++
++#define _SLANG_BC_EXCH 0x18
++#define _SLANG_BC_LABEL 0x19
++#define _SLANG_BC_LOBJPTR 0x1A
++#define _SLANG_BC_GOBJPTR 0x1B
++#define _SLANG_BC_X_ERROR 0x1C
++/* These must be in this order */
++#define _SLANG_BC_X_USER0 0x1D
++#define _SLANG_BC_X_USER1 0x1E
++#define _SLANG_BC_X_USER2 0x1F
++#define _SLANG_BC_X_USER3 0x20
++#define _SLANG_BC_X_USER4 0x21
++
++#define _SLANG_BC_CALL_DIRECT 0x24
++#define _SLANG_BC_CALL_DIRECT_FRAME 0x25
++#define _SLANG_BC_UNARY 0x26
++#define _SLANG_BC_UNARY_FUNC 0x27
++
++#define _SLANG_BC_DEREF_ASSIGN 0x30
++#define _SLANG_BC_SET_LOCAL_LVALUE 0x31
++#define _SLANG_BC_SET_GLOBAL_LVALUE 0x32
++#define _SLANG_BC_SET_INTRIN_LVALUE 0x33
++#define _SLANG_BC_SET_STRUCT_LVALUE 0x34
++#define _SLANG_BC_FIELD 0x35
++#define _SLANG_BC_SET_ARRAY_LVALUE 0x36
++
++#define _SLANG_BC_LINE_NUM 0x40
++
++#define _SLANG_BC_TMP 0x50
++#define _SLANG_BC_LVARIABLE_AGET 0x60
++#define _SLANG_BC_LVARIABLE_APUT 0x61
++#define _SLANG_BC_INTEGER_PLUS 0x62
++#define _SLANG_BC_INTEGER_MINUS 0x63
++#define _SLANG_BC_ARG_LVARIABLE 0x64
++#define _SLANG_BC_EARG_LVARIABLE 0x65
++
++#define _SLANG_BC_CALL_DIRECT_INTRINSIC 0x80
++#define _SLANG_BC_INTRINSIC_CALL_DIRECT 0x81
++#define _SLANG_BC_CALL_DIRECT_LSTR 0x82
++#define _SLANG_BC_CALL_DIRECT_SLFUN 0x83
++#define _SLANG_BC_CALL_DIRECT_INTRSTOP 0x84
++#define _SLANG_BC_INTRINSIC_STOP 0x85
++#define _SLANG_BC_CALL_DIRECT_EARG_LVAR 0x86
++#define _SLANG_BC_CALL_DIRECT_LINT 0x87
++#define _SLANG_BC_CALL_DIRECT_LVAR 0x88
++
++
++/* Byte-Code Sub Types (_BCST_) */
++
++/* These are sub_types of _SLANG_BC_BLOCK */
++#define _SLANG_BCST_ERROR_BLOCK 0x01
++#define _SLANG_BCST_EXIT_BLOCK 0x02
++#define _SLANG_BCST_USER_BLOCK0 0x03
++#define _SLANG_BCST_USER_BLOCK1 0x04
++#define _SLANG_BCST_USER_BLOCK2 0x05
++#define _SLANG_BCST_USER_BLOCK3 0x06
++#define _SLANG_BCST_USER_BLOCK4 0x07
++/* The user blocks MUST be in the above order */
++#define _SLANG_BCST_LOOP 0x10
++#define _SLANG_BCST_WHILE 0x11
++#define _SLANG_BCST_FOR 0x12
++#define _SLANG_BCST_FOREVER 0x13
++#define _SLANG_BCST_CFOR 0x14
++#define _SLANG_BCST_DOWHILE 0x15
++#define _SLANG_BCST_FOREACH 0x16
++
++#define _SLANG_BCST_IF 0x20
++#define _SLANG_BCST_IFNOT 0x21
++#define _SLANG_BCST_ELSE 0x22
++#define _SLANG_BCST_ANDELSE 0x23
++#define _SLANG_BCST_ORELSE 0x24
++#define _SLANG_BCST_SWITCH 0x25
++#define _SLANG_BCST_NOTELSE 0x26
++
++/* assignment (_SLANG_BC_SET_*_LVALUE) subtypes. The order MUST correspond
++ * to the assignment token order with the ASSIGN_TOKEN as the first!
++ */
++#define _SLANG_BCST_ASSIGN 0x01
++#define _SLANG_BCST_PLUSEQS 0x02
++#define _SLANG_BCST_MINUSEQS 0x03
++#define _SLANG_BCST_TIMESEQS 0x04
++#define _SLANG_BCST_DIVEQS 0x05
++#define _SLANG_BCST_BOREQS 0x06
++#define _SLANG_BCST_BANDEQS 0x07
++#define _SLANG_BCST_PLUSPLUS 0x08
++#define _SLANG_BCST_POST_PLUSPLUS 0x09
++#define _SLANG_BCST_MINUSMINUS 0x0A
++#define _SLANG_BCST_POST_MINUSMINUS 0x0B
++
++/* These use SLANG_PLUS, SLANG_MINUS, SLANG_PLUSPLUS, etc... */
++
++typedef union
++{
++#if SLANG_HAS_FLOAT
++ double double_val;
++ float float_val;
++#endif
++ long long_val;
++ unsigned long ulong_val;
++ VOID_STAR ptr_val;
++ char *s_val;
++ int int_val;
++ unsigned int uint_val;
++ SLang_MMT_Type *ref;
++ SLang_Name_Type *n_val;
++ struct _SLang_Struct_Type *struct_val;
++ struct _SLang_Array_Type *array_val;
++ short short_val;
++ unsigned short ushort_val;
++ char char_val;
++ unsigned char uchar_val;
++}
++_SL_Object_Union_Type;
++
++typedef struct _SLang_Object_Type
++{
++ unsigned char data_type; /* SLANG_INT_TYPE, ... */
++ _SL_Object_Union_Type v;
++}
++SLang_Object_Type;
++
++struct _SLang_MMT_Type
++{
++ unsigned char data_type; /* int, string, etc... */
++ VOID_STAR user_data; /* address of user structure */
++ unsigned int count; /* number of references */
++};
++
++extern int _SLang_pop_object_of_type (unsigned char, SLang_Object_Type *, int);
++
++typedef struct
++{
++ char *name; /* slstring */
++ SLang_Object_Type obj;
++}
++_SLstruct_Field_Type;
++
++typedef struct _SLang_Struct_Type
++{
++ _SLstruct_Field_Type *fields;
++ unsigned int nfields; /* number used */
++ unsigned int num_refs;
++}
++_SLang_Struct_Type;
++
++extern void _SLstruct_delete_struct (_SLang_Struct_Type *);
++extern int _SLang_push_struct (_SLang_Struct_Type *);
++extern int _SLang_pop_struct (_SLang_Struct_Type **);
++extern int _SLstruct_init (void);
++/* extern int _SLstruct_get_field (char *); */
++extern int _SLstruct_define_struct (void);
++extern int _SLstruct_define_typedef (void);
++
++extern int _SLang_pop_datatype (unsigned char *);
++extern int _SLang_push_datatype (unsigned char);
++
++struct _SLang_Ref_Type
++{
++ int is_global;
++ union
++ {
++ SLang_Name_Type *nt;
++ SLang_Object_Type *local_obj;
++ }
++ v;
++};
++
++extern int _SLang_dereference_ref (SLang_Ref_Type *);
++extern int _SLang_deref_assign (SLang_Ref_Type *);
++extern int _SLang_push_ref (int, VOID_STAR);
++
++extern int _SL_increment_frame_pointer (void);
++extern int _SL_decrement_frame_pointer (void);
++
++extern int SLang_pop(SLang_Object_Type *);
++extern void SLang_free_object (SLang_Object_Type *);
++extern int _SLanytype_typecast (unsigned char, VOID_STAR, unsigned int,
++ unsigned char, VOID_STAR);
++extern void _SLstring_intrinsic (void);
++
++
++/* These functions are used to create slstrings of a fixed length. Be
++ * very careful how they are used. In particular, if len bytes are allocated,
++ * then the string must be len characters long, no more and no less.
++ */
++extern char *_SLallocate_slstring (unsigned int);
++extern char *_SLcreate_via_alloced_slstring (char *, unsigned int);
++extern void _SLunallocate_slstring (char *, unsigned int);
++extern int _SLpush_alloced_slstring (char *, unsigned int);
++
++typedef struct
++{
++ char **buf;
++ unsigned int max_num;
++ unsigned int num;
++ unsigned int delta_num;
++}
++_SLString_List_Type;
++extern int _SLstring_list_append (_SLString_List_Type *, char *);
++extern int _SLstring_list_init (_SLString_List_Type *, unsigned int, unsigned int);
++extern void _SLstring_list_delete (_SLString_List_Type *);
++extern int _SLstring_list_push (_SLString_List_Type *);
++
++/* This function assumes that s is an slstring. */
++extern char *_SLstring_dup_slstring (char *);
++extern int _SLang_dup_and_push_slstring (char *);
++
++
++extern int _SLang_init_import (void);
++
++/* This function checks to see if the referenced object is initialized */
++extern int _SLang_is_ref_initialized (SLang_Ref_Type *);
++extern int _SLcheck_identifier_syntax (char *);
++extern int _SLang_uninitialize_ref (SLang_Ref_Type *);
++
++extern int _SLpush_slang_obj (SLang_Object_Type *);
++
++extern char *_SLexpand_escaped_char(char *, char *);
++extern void _SLexpand_escaped_string (char *, char *, char *);
++
++/* returns a pointer to an SLstring string-- use SLang_free_slstring */
++extern char *_SLstringize_object (SLang_Object_Type *);
++extern int _SLdump_objects (char *, SLang_Object_Type *, unsigned int, int);
++
++extern SLang_Object_Type *_SLRun_Stack;
++extern SLang_Object_Type *_SLStack_Pointer;
++
++struct _SLang_NameSpace_Type
++{
++ struct _SLang_NameSpace_Type *next;
++ char *name; /* this is the load_type name */
++ char *namespace_name; /* this name is assigned by implements */
++ unsigned int table_size;
++ SLang_Name_Type **table;
++};
++extern SLang_NameSpace_Type *_SLns_allocate_namespace (char *, unsigned int);
++extern SLang_NameSpace_Type *_SLns_find_namespace (char *);
++extern int _SLns_set_namespace_name (SLang_NameSpace_Type *, char *);
++extern SLang_Array_Type *_SLnspace_apropos (SLang_NameSpace_Type *, char *, unsigned int);
++extern void _SLang_use_namespace_intrinsic (char *name);
++extern char *_SLang_cur_namespace_intrinsic (void);
++extern SLang_Array_Type *_SLang_apropos (char *, char *, unsigned int);
++extern void _SLang_implements_intrinsic (char *);
++
++extern int _SLang_Trace;
++extern int _SLstack_depth(void);
++extern char *_SLang_Current_Function_Name;
++
++extern int _SLang_trace_fun(char *);
++extern int _SLang_Compile_Line_Num_Info;
++
++extern char *_SLstring_dup_hashed_string (char *, unsigned long);
++extern unsigned long _SLcompute_string_hash (char *);
++extern char *_SLstring_make_hashed_string (char *, unsigned int, unsigned long *);
++extern void _SLfree_hashed_string (char *, unsigned int, unsigned long);
++unsigned long _SLstring_hash (unsigned char *, unsigned char *);
++extern int _SLinit_slcomplex (void);
++
++extern int _SLang_init_slstrops (void);
++extern int _SLstrops_do_sprintf_n (int);
++extern int _SLang_sscanf (void);
++extern double _SLang_atof (char *);
++extern int _SLang_init_bstring (void);
++extern int _SLang_init_sltime (void);
++extern void _SLpack (void);
++extern void _SLunpack (char *, SLang_BString_Type *);
++extern void _SLpack_pad_format (char *);
++extern unsigned int _SLpack_compute_size (char *);
++extern int _SLusleep (unsigned long);
++
++/* frees upon error. NULL __NOT__ ok. */
++extern int _SLang_push_slstring (char *);
++
++extern unsigned char _SLarith_promote_type (unsigned char);
++extern int _SLarith_get_precedence (unsigned char);
++extern int _SLarith_typecast (unsigned char, VOID_STAR, unsigned int,
++ unsigned char, VOID_STAR);
++
++extern int SLang_push(SLang_Object_Type *);
++extern int SLadd_global_variable (char *);
++extern void _SLang_clear_error (void);
++
++extern int _SLdo_pop (void);
++extern unsigned int _SLsys_getkey (void);
++extern int _SLsys_input_pending (int);
++#ifdef IBMPC_SYSTEM
++extern unsigned int _SLpc_convert_scancode (unsigned int, unsigned int, int);
++#define _SLTT_KEY_SHIFT 1
++#define _SLTT_KEY_CTRL 2
++#define _SLTT_KEY_ALT 4
++#endif
++
++typedef struct _SLterminfo_Type SLterminfo_Type;
++extern SLterminfo_Type *_SLtt_tigetent (char *);
++extern char *_SLtt_tigetstr (SLterminfo_Type *, char *);
++extern int _SLtt_tigetnum (SLterminfo_Type *, char *);
++extern int _SLtt_tigetflag (SLterminfo_Type *, char *);
++
++#if SLTT_HAS_NON_BCE_SUPPORT
++extern int _SLtt_get_bce_color_offset (void);
++#endif
++extern void (*_SLtt_color_changed_hook)(void);
++
++extern unsigned char SLang_Input_Buffer [SL_MAX_INPUT_BUFFER_LEN];
++
++extern int _SLregister_types (void);
++extern SLang_Class_Type *_SLclass_get_class (unsigned char);
++extern VOID_STAR _SLclass_get_ptr_to_value (SLang_Class_Type *, SLang_Object_Type *);
++extern void _SLclass_type_mismatch_error (unsigned char, unsigned char);
++extern int _SLclass_init (void);
++extern int _SLclass_copy_class (unsigned char, unsigned char);
++
++extern unsigned char _SLclass_Class_Type [256];
++
++extern int (*_SLclass_get_typecast (unsigned char, unsigned char, int))
++(unsigned char, VOID_STAR, unsigned int,
++ unsigned char, VOID_STAR);
++
++extern int (*_SLclass_get_binary_fun (int, SLang_Class_Type *, SLang_Class_Type *, SLang_Class_Type **, int))
++(int,
++ unsigned char, VOID_STAR, unsigned int,
++ unsigned char, VOID_STAR, unsigned int,
++ VOID_STAR);
++
++extern int (*_SLclass_get_unary_fun (int, SLang_Class_Type *, SLang_Class_Type **, int))
++(int, unsigned char, VOID_STAR, unsigned int, VOID_STAR);
++
++extern int _SLarith_register_types (void);
++extern unsigned char _SLarith_Arith_Types [];
++extern unsigned char _SLarith_Is_Arith_Type [256];
++extern int _SLarith_bin_op (SLang_Object_Type *, SLang_Object_Type *, int);
++
++extern int _SLarray_add_bin_op (unsigned char);
++
++extern int _SLang_call_funptr (SLang_Name_Type *);
++extern void _SLset_double_format (char *);
++extern SLang_Name_Type *_SLlocate_global_name (char *);
++extern SLang_Name_Type *_SLlocate_name (char *);
++
++extern char *_SLdefines[];
++
++#define SL_ERRNO_NOT_IMPLEMENTED 0x7FFF
++extern int _SLerrno_errno;
++extern int _SLerrno_init (void);
++
++extern int _SLstdio_fdopen (char *, int, char *);
++
++extern void _SLstruct_pop_args (int *);
++extern void _SLstruct_push_args (SLang_Array_Type *);
++
++extern int _SLarray_aput (void);
++extern int _SLarray_aget (void);
++extern int _SLarray_inline_implicit_array (void);
++extern int _SLarray_inline_array (void);
++extern int _SLarray_wildcard_array (void);
++
++extern int
++_SLarray_typecast (unsigned char, VOID_STAR, unsigned int,
++ unsigned char, VOID_STAR, int);
++
++extern int _SLarray_aput_transfer_elem (SLang_Array_Type *, int *,
++ VOID_STAR, unsigned int, int);
++extern int _SLarray_aget_transfer_elem (SLang_Array_Type *, int *,
++ VOID_STAR, unsigned int, int);
++extern void _SLarray_free_array_elements (SLang_Class_Type *, VOID_STAR, unsigned int);
++
++extern SLang_Foreach_Context_Type *
++_SLarray_cl_foreach_open (unsigned char, unsigned int);
++extern void _SLarray_cl_foreach_close (unsigned char, SLang_Foreach_Context_Type *);
++extern int _SLarray_cl_foreach (unsigned char, SLang_Foreach_Context_Type *);
++
++extern int _SLarray_matrix_multiply (void);
++extern void (*_SLang_Matrix_Multiply)(void);
++
++extern int _SLarray_init_slarray (void);
++extern SLang_Array_Type *
++SLang_create_array1 (unsigned char, int, VOID_STAR, int *, unsigned int, int);
++
++extern int _SLcompile_push_context (SLang_Load_Type *);
++extern int _SLcompile_pop_context (void);
++extern int _SLang_Auto_Declare_Globals;
++
++typedef struct
++{
++ union
++ {
++ long long_val;
++ char *s_val; /* Used for IDENT_TOKEN, FLOAT, etc... */
++ SLang_BString_Type *b_val;
++ } v;
++ int free_sval_flag;
++ unsigned int num_refs;
++ unsigned long hash;
++#if _SLANG_HAS_DEBUG_CODE
++ int line_number;
++#endif
++ unsigned char type;
++}
++_SLang_Token_Type;
++
++extern void _SLcompile (_SLang_Token_Type *);
++extern void (*_SLcompile_ptr)(_SLang_Token_Type *);
++
++/* *** TOKENS *** */
++
++/* Note that that tokens corresponding to ^J, ^M, and ^Z should not be used.
++ * This is because a file that contains any of these characters will
++ * have an OS dependent interpretation, e.g., ^Z is EOF on MSDOS.
++ */
++
++/* Special tokens */
++#define EOF_TOKEN 0x01
++#define RPN_TOKEN 0x02
++#define NL_TOKEN 0x03
++#define NOP_TOKEN 0x05
++#define FARG_TOKEN 0x06
++#define TMP_TOKEN 0x07
++
++#define RESERVED1_TOKEN 0x0A /* \n */
++#define RESERVED2_TOKEN 0x0D /* \r */
++
++/* Literal tokens */
++#define CHAR_TOKEN 0x10
++#define UCHAR_TOKEN 0x11
++#define SHORT_TOKEN 0x12
++#define USHORT_TOKEN 0x13
++#define INT_TOKEN 0x14
++#define UINT_TOKEN 0x15
++#define LONG_TOKEN 0x16
++#define ULONG_TOKEN 0x17
++#define IS_INTEGER_TOKEN(x) ((x &gt;= CHAR_TOKEN) &amp;&amp; (x &lt;= ULONG_TOKEN))
++#define FLOAT_TOKEN 0x18
++#define DOUBLE_TOKEN 0x19
++#define RESERVED3_TOKEN 0x1A /* ^Z */
++#define COMPLEX_TOKEN 0x1B
++#define STRING_TOKEN 0x1C
++#define BSTRING_TOKEN 0x1D
++#define _BSTRING_TOKEN 0x1E /* byte-compiled BSTRING */
++#define ESC_STRING_TOKEN 0x1F
++
++/* Tokens that can be LVALUES */
++#define IDENT_TOKEN 0x20
++#define ARRAY_TOKEN 0x21
++#define DOT_TOKEN 0x22
++#define IS_LVALUE_TOKEN (((t) &lt;= DOT_TOKEN) &amp;&amp; ((t) &gt;= IDENT_TOKEN))
++
++/* do not use these values */
++#define RESERVED4_TOKEN 0x23 /* # */
++#define RESERVED5_TOKEN 0x25 /* % */
++
++/* Flags for struct fields */
++#define STATIC_TOKEN 0x26
++#define READONLY_TOKEN 0x27
++#define PRIVATE_TOKEN 0x28
++#define PUBLIC_TOKEN 0x29
++
++/* Punctuation tokens */
++#define OBRACKET_TOKEN 0x2a
++#define CBRACKET_TOKEN 0x2b
++#define OPAREN_TOKEN 0x2c
++#define CPAREN_TOKEN 0x2d
++#define OBRACE_TOKEN 0x2e
++#define CBRACE_TOKEN 0x2f
++
++#define COMMA_TOKEN 0x31
++#define SEMICOLON_TOKEN 0x32
++#define COLON_TOKEN 0x33
++#define NAMESPACE_TOKEN 0x34
++
++/* Operators */
++#define POW_TOKEN 0x38
++
++/* The order here must match the order in the Binop_Level table in slparse.c */
++#define FIRST_BINARY_OP 0x39
++#define ADD_TOKEN 0x39
++#define SUB_TOKEN 0x3a
++#define TIMES_TOKEN 0x3b
++#define DIV_TOKEN 0x3c
++#define LT_TOKEN 0x3d
++#define LE_TOKEN 0x3e
++#define GT_TOKEN 0x3f
++#define GE_TOKEN 0x40
++#define EQ_TOKEN 0x41
++#define NE_TOKEN 0x42
++#define AND_TOKEN 0x43
++#define OR_TOKEN 0x44
++#define MOD_TOKEN 0x45
++#define BAND_TOKEN 0x46
++#define SHL_TOKEN 0x47
++#define SHR_TOKEN 0x48
++#define BXOR_TOKEN 0x49
++#define BOR_TOKEN 0x4a
++#define POUND_TOKEN 0x4b /* matrix multiplication */
++
++#define LAST_BINARY_OP 0x4b
++#define IS_BINARY_OP(t) ((t &gt;= FIRST_BINARY_OP) &amp;&amp; (t &lt;= LAST_BINARY_OP))
++
++/* unary tokens -- but not all of them (see grammar) */
++#define DEREF_TOKEN 0x4d
++#define NOT_TOKEN 0x4e
++#define BNOT_TOKEN 0x4f
++
++#define IS_INTERNAL_FUNC(t) ((t &gt;= 0x50) &amp;&amp; (t &lt;= 0x56))
++#define POP_TOKEN 0x50
++#define CHS_TOKEN 0x51
++#define SIGN_TOKEN 0x52
++#define ABS_TOKEN 0x53
++#define SQR_TOKEN 0x54
++#define MUL2_TOKEN 0x55
++#define EXCH_TOKEN 0x56
++
++/* Assignment tokens. Note: these must appear with sequential values.
++ * The order here must match the specific lvalue assignments below.
++ * These tokens are used by rpn routines in slang.c. slparse.c maps them
++ * onto the specific lvalue tokens while parsing infix.
++ * Also the assignment _SLANG_BCST_ assumes this order
++ */
++#define ASSIGN_TOKEN 0x57
++#define PLUSEQS_TOKEN 0x58
++#define MINUSEQS_TOKEN 0x59
++#define TIMESEQS_TOKEN 0x5A
++#define DIVEQS_TOKEN 0x5B
++#define BOREQS_TOKEN 0x5C
++#define BANDEQS_TOKEN 0x5D
++#define PLUSPLUS_TOKEN 0x5E
++#define POST_PLUSPLUS_TOKEN 0x5F
++#define MINUSMINUS_TOKEN 0x60
++#define POST_MINUSMINUS_TOKEN 0x61
++
++/* Directives */
++#define FIRST_DIRECTIVE_TOKEN 0x62
++#define IFNOT_TOKEN 0x62
++#define IF_TOKEN 0x63
++#define ELSE_TOKEN 0x64
++#define FOREVER_TOKEN 0x65
++#define WHILE_TOKEN 0x66
++#define FOR_TOKEN 0x67
++#define _FOR_TOKEN 0x68
++#define LOOP_TOKEN 0x69
++#define SWITCH_TOKEN 0x6A
++#define DOWHILE_TOKEN 0x6B
++#define ANDELSE_TOKEN 0x6C
++#define ORELSE_TOKEN 0x6D
++#define ERRBLK_TOKEN 0x6E
++#define EXITBLK_TOKEN 0x6F
++/* These must be sequential */
++#define USRBLK0_TOKEN 0x70
++#define USRBLK1_TOKEN 0x71
++#define USRBLK2_TOKEN 0x72
++#define USRBLK3_TOKEN 0x73
++#define USRBLK4_TOKEN 0x74
++
++#define CONT_TOKEN 0x75
++#define BREAK_TOKEN 0x76
++#define RETURN_TOKEN 0x77
++
++#define CASE_TOKEN 0x78
++#define DEFINE_TOKEN 0x79
++#define DO_TOKEN 0x7a
++#define VARIABLE_TOKEN 0x7b
++#define GVARIABLE_TOKEN 0x7c
++#define _REF_TOKEN 0x7d
++#define PUSH_TOKEN 0x7e
++#define STRUCT_TOKEN 0x7f
++#define TYPEDEF_TOKEN 0x80
++#define NOTELSE_TOKEN 0x81
++#define DEFINE_STATIC_TOKEN 0x82
++#define FOREACH_TOKEN 0x83
++#define USING_TOKEN 0x84
++#define DEFINE_PRIVATE_TOKEN 0x85
++#define DEFINE_PUBLIC_TOKEN 0x86
++
++/* Note: the order here must match the order of the generic assignment tokens.
++ * Also, the first token of each group must be the ?_ASSIGN_TOKEN.
++ * slparse.c exploits this order, as well as slang.h.
++ */
++#define FIRST_ASSIGN_TOKEN 0x90
++#define _STRUCT_ASSIGN_TOKEN 0x90
++#define _STRUCT_PLUSEQS_TOKEN 0x91
++#define _STRUCT_MINUSEQS_TOKEN 0x92
++#define _STRUCT_TIMESEQS_TOKEN 0x93
++#define _STRUCT_DIVEQS_TOKEN 0x94
++#define _STRUCT_BOREQS_TOKEN 0x95
++#define _STRUCT_BANDEQS_TOKEN 0x96
++#define _STRUCT_PLUSPLUS_TOKEN 0x97
++#define _STRUCT_POST_PLUSPLUS_TOKEN 0x98
++#define _STRUCT_MINUSMINUS_TOKEN 0x99
++#define _STRUCT_POST_MINUSMINUS_TOKEN 0x9A
++
++#define _ARRAY_ASSIGN_TOKEN 0xA0
++#define _ARRAY_PLUSEQS_TOKEN 0xA1
++#define _ARRAY_MINUSEQS_TOKEN 0xA2
++#define _ARRAY_TIMESEQS_TOKEN 0xA3
++#define _ARRAY_DIVEQS_TOKEN 0xA4
++#define _ARRAY_BOREQS_TOKEN 0xA5
++#define _ARRAY_BANDEQS_TOKEN 0xA6
++#define _ARRAY_PLUSPLUS_TOKEN 0xA7
++#define _ARRAY_POST_PLUSPLUS_TOKEN 0xA8
++#define _ARRAY_MINUSMINUS_TOKEN 0xA9
++#define _ARRAY_POST_MINUSMINUS_TOKEN 0xAA
++
++#define _SCALAR_ASSIGN_TOKEN 0xB0
++#define _SCALAR_PLUSEQS_TOKEN 0xB1
++#define _SCALAR_MINUSEQS_TOKEN 0xB2
++#define _SCALAR_TIMESEQS_TOKEN 0xB3
++#define _SCALAR_DIVEQS_TOKEN 0xB4
++#define _SCALAR_BOREQS_TOKEN 0xB5
++#define _SCALAR_BANDEQS_TOKEN 0xB6
++#define _SCALAR_PLUSPLUS_TOKEN 0xB7
++#define _SCALAR_POST_PLUSPLUS_TOKEN 0xB8
++#define _SCALAR_MINUSMINUS_TOKEN 0xB9
++#define _SCALAR_POST_MINUSMINUS_TOKEN 0xBA
++
++#define _DEREF_ASSIGN_TOKEN 0xC0
++#define _DEREF_PLUSEQS_TOKEN 0xC1
++#define _DEREF_MINUSEQS_TOKEN 0xC2
++#define _DEREF_TIMESEQS_TOKEN 0xC3
++#define _DEREF_DIVEQS_TOKEN 0xC4
++#define _DEREF_BOREQS_TOKEN 0xC5
++#define _DEREF_BANDEQS_TOKEN 0xC6
++#define _DEREF_PLUSPLUS_TOKEN 0xC7
++#define _DEREF_POST_PLUSPLUS_TOKEN 0xC8
++#define _DEREF_MINUSMINUS_TOKEN 0xC9
++#define _DEREF_POST_MINUSMINUS_TOKEN 0xCA
++
++#define LAST_ASSIGN_TOKEN 0xCA
++#define IS_ASSIGN_TOKEN(t) (((t)&gt;=FIRST_ASSIGN_TOKEN)&amp;&amp;((t)&lt;=LAST_ASSIGN_TOKEN))
++
++#define _INLINE_ARRAY_TOKEN 0xE0
++#define _INLINE_IMPLICIT_ARRAY_TOKEN 0xE1
++#define _NULL_TOKEN 0xE2
++#define _INLINE_WILDCARD_ARRAY_TOKEN 0xE3
++
++#define LINE_NUM_TOKEN 0xFC
++#define ARG_TOKEN 0xFD
++#define EARG_TOKEN 0xFE
++#define NO_OP_LITERAL 0xFF
++
++typedef struct
++{
++ /* sltoken.c */
++ /* SLang_eval_object */
++ SLang_Load_Type *llt;
++ SLPreprocess_Type *this_slpp;
++ /* prep_get_char() */
++ char *input_line;
++ char cchar;
++ /* get_token() */
++ int want_nl_token;
++
++ /* slparse.c */
++ _SLang_Token_Type ctok;
++ int block_depth;
++ int assignment_expression;
++
++ /* slang.c : SLcompile() */
++ _SLang_Token_Type save_token;
++ _SLang_Token_Type next_token;
++ void (*slcompile_ptr)(_SLang_Token_Type *);
++}
++_SLEval_Context;
++
++extern int _SLget_token (_SLang_Token_Type *);
++extern void _SLparse_error (char *, _SLang_Token_Type *, int);
++extern void _SLparse_start (SLang_Load_Type *);
++extern int _SLget_rpn_token (_SLang_Token_Type *);
++extern void _SLcompile_byte_compiled (void);
++
++extern int (*_SLprep_eval_hook) (char *);
++
++#ifdef HAVE_VSNPRINTF
++#define _SLvsnprintf vsnprintf
++#else
++extern int _SLvsnprintf (char *, unsigned int, char *, va_list);
++#endif
++
++#ifdef HAVE_SNPRINTF
++# define _SLsnprintf snprintf
++#else
++extern int _SLsnprintf (char *, unsigned int, char *, ...);
++#endif
++
++#undef _INLINE_
++#if defined(__GNUC__) &amp;&amp; _SLANG_USE_INLINE_CODE
++# define _INLINE_ __inline__
++#else
++# define _INLINE_
++#endif
++
++
++#endif /* _PRIVATE_SLANG_H_ */
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/_slang.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/config.h
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/config.h (rev 0)
++++ drakx/trunk/mdk-stage1/slang/config.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,163 @@
++/* src/sysconf.h. Generated automatically by configure. */
++/* -*- c -*- */
++/* Note: this is for unix only. */
++
++#ifndef SL_CONFIG_H
++#define SL_CONFIG_H
++
++/* define if you have stdlib.h */
++#define HAVE_STDLIB_H 1
++
++/* define if you have unistd.h */
++#define HAVE_UNISTD_H 1
++
++/* define if you have termios.h */
++#define HAVE_TERMIOS_H 1
++
++/* define if you have memory.h */
++#define HAVE_MEMORY_H 1
++
++/* define if you have malloc.h */
++#define HAVE_MALLOC_H 1
++
++/* define if you have memset */
++#define HAVE_MEMSET 1
++
++/* define if you have memcpy */
++#define HAVE_MEMCPY 1
++
++//#define HAVE_SETLOCALE 1
++//#define HAVE_LOCALE_H 1
++
++#define HAVE_VFSCANF 1
++
++/* define if you have fcntl.h */
++#define HAVE_FCNTL_H 1
++
++/* Define if you have the vsnprintf, snprintf functions and they return
++ * EOF upon failure.
++ */
++#define HAVE_VSNPRINTF 1
++#define HAVE_SNPRINTF 1
++
++/* define if you have sys/fcntl.h */
++#define HAVE_SYS_FCNTL_H 1
++
++#define HAVE_SYS_TYPES_H 1
++#define HAVE_SYS_WAIT_H 1
++#define HAVE_SYS_TIMES_H 1
++
++/* Set these to the appropriate values */
++#define SIZEOF_SHORT 2
++#define SIZEOF_INT 4
++#define SIZEOF_LONG 4
++#define SIZEOF_FLOAT 4
++#define SIZEOF_DOUBLE 8
++
++/* define if you have these. */
++#define HAVE_ATEXIT 1
++#define HAVE_ON_EXIT 1
++#define HAVE_PUTENV 1
++#define HAVE_GETCWD 1
++#define HAVE_TCGETATTR 1
++#define HAVE_TCSETATTR 1
++#define HAVE_CFGETOSPEED 1
++#define HAVE_LSTAT 1
++#define HAVE_KILL 1
++#define HAVE_CHOWN 1
++#define HAVE_VSNPRINTF 1
++#define HAVE_POPEN 1
++#define HAVE_UMASK 1
++#define HAVE_READLINK 1
++#define HAVE_TIMES 1
++#define HAVE_GMTIME 1
++#define HAVE_MKFIFO 1
++
++#define HAVE_GETPPID 1
++#define HAVE_GETGID 1
++#define HAVE_GETEGID 1
++#define HAVE_GETEUID 1
++/* #undef HAVE_GETUID */
++
++#define HAVE_SETGID 1
++#define HAVE_SETPGID 1
++#define HAVE_SETUID 1
++
++#define HAVE_ACOSH 1
++#define HAVE_ASINH 1
++#define HAVE_ATANH 1
++
++#define HAVE_DIRENT_H 1
++/* #undef HAVE_SYS_NDIR_H */
++/* #undef HAVE_SYS_DIR_H */
++/* #undef HAVE_NDIR_H */
++
++#define HAVE_DLFCN_H 1
++
++#define HAVE_SYS_UTSNAME_H 1
++#define HAVE_UNAME 1
++
++/* These two are needed on DOS-like systems. Unix does not require them.
++ * They are included here for consistency.
++ *
++#define HAVE_IO_H
++#define HAVE_PROCESS_H
++ */
++
++/* #undef USE_TERMCAP */
++
++/* #undef mode_t */
++/* #undef uid_t */
++/* #undef pid_t */
++/* #undef gid_t */
++
++/* Do we have posix signals? */
++#define HAVE_SIGACTION 1
++#define HAVE_SIGPROCMASK 1
++#define HAVE_SIGEMPTYSET 1
++#define HAVE_SIGADDSET 1
++
++#if defined(HAVE_SIGADDSET) &amp;&amp; defined(HAVE_SIGEMPTYSET)
++# if defined(HAVE_SIGACTION) &amp;&amp; defined(HAVE_SIGPROCMASK)
++# define SLANG_POSIX_SIGNALS
++# endif
++#endif
++
++/* Define if you need to in order for stat and other things to work. */
++/* #undef _POSIX_SOURCE */
++
++#ifdef _AIX
++# ifndef _POSIX_SOURCE
++# define _POSIX_SOURCE 1
++# endif
++# ifndef _ALL_SOURCE
++# define _ALL_SOURCE
++# endif
++/* This may generate warnings but the fact is that without it, xlc will
++ * INCORRECTLY inline many str* functions. */
++/* # undef __STR__ */
++#endif
++
++/* define USE_TERMCAP if you want to use it instead of terminfo. */
++#if defined(sequent) || defined(NeXT)
++# ifndef USE_TERMCAP
++# define USE_TERMCAP
++# endif
++#endif
++
++#if defined(ultrix) &amp;&amp; !defined(__GNUC__)
++# ifndef NO_PROTOTYPES
++# define NO_PROTOTYPES
++# endif
++#endif
++
++#ifndef unix
++# define unix 1
++#endif
++
++#ifndef __unix__
++# define __unix__ 1
++#endif
++
++#define _SLANG_SOURCE_ 1
++#endif /* SL_CONFIG_H */
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/config.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/jdmacros.h
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/jdmacros.h (rev 0)
++++ drakx/trunk/mdk-stage1/slang/jdmacros.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,53 @@
++#ifndef _JD_MACROS_H_
++#define _JD_MACROS_H_
++
++#ifndef SLMEMSET
++# ifdef HAVE_MEMSET
++# define SLMEMSET memset
++# else
++# define SLMEMSET SLmemset
++# endif
++#endif
++
++#ifndef SLMEMCHR
++# ifdef HAVE_MEMCHR
++# define SLMEMCHR memchr
++# else
++# define SLMEMCHR SLmemchr
++# endif
++#endif
++
++#ifndef SLMEMCPY
++# ifdef HAVE_MEMCPY
++# define SLMEMCPY memcpy
++# else
++# define SLMEMCPY SLmemcpy
++# endif
++#endif
++
++/* Note: HAVE_MEMCMP requires an unsigned memory comparison!!! */
++#ifndef SLMEMCMP
++# ifdef HAVE_MEMCMP
++# define SLMEMCMP memcmp
++# else
++# define SLMEMCMP SLmemcmp
++# endif
++#endif
++
++#ifndef SLFREE
++# define SLFREE free
++#endif
++
++#ifndef SLMALLOC
++# define SLMALLOC malloc
++#endif
++
++#ifndef SLCALLOC
++# define SLCALLOC calloc
++#endif
++
++#ifndef SLREALLOC
++# define SLREALLOC realloc
++#endif
++
++#endif /* _JD_MACROS_H_ */
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/jdmacros.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/keywhash.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/keywhash.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/keywhash.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,190 @@
++/* Perfect hash generated by command line:
++ * ./a.out 1
++ */
++#define MIN_HASH_VALUE 2
++#define MAX_HASH_VALUE 118
++#define MIN_KEYWORD_LEN 2
++#define MAX_KEYWORD_LEN 11
++
++static unsigned char Keyword_Hash_Table [256] =
++{
++ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
++ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
++ 119, 1, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
++ 9, 7, 1, 8, 2, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
++ 119, 119, 0, 0, 119, 0, 119, 119, 119, 7, 119, 0, 0, 119, 119, 0,
++ 119, 119, 0, 0, 0, 0, 119, 119, 0, 119, 119, 119, 119, 119, 119, 2,
++ 119, 41, 1, 1, 9, 0, 55, 8, 0, 0, 119, 0, 27, 0, 0, 0,
++ 7, 2, 0, 21, 0, 0, 0, 3, 2, 0, 119, 119, 119, 119, 119, 119,
++ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
++ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
++ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
++ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
++ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
++ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
++ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
++ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119
++};
++
++static unsigned char keyword_hash (char *s, unsigned int len)
++{
++ unsigned int sum;
++
++ sum = len;
++ while (len)
++ {
++ len--;
++ sum += (unsigned int) Keyword_Hash_Table [(unsigned char)s[len]];
++ }
++ return sum;
++}
++
++typedef struct
++{
++ char *name;
++ unsigned int type;
++}
++Keyword_Table_Type;
++
++static Keyword_Table_Type Keyword_Table [/* 117 */] =
++{
++ {&quot;or&quot;, OR_TOKEN},
++ {&quot;not&quot;, NOT_TOKEN},
++ {NULL,0},
++ {&quot;xor&quot;, BXOR_TOKEN},
++ {&quot;return&quot;, RETURN_TOKEN},
++ {&quot;exch&quot;, EXCH_TOKEN},
++ {NULL,0},
++ {&quot;continue&quot;, CONT_TOKEN},
++ {NULL,0},
++ {&quot;do&quot;, DO_TOKEN},
++ {&quot;mod&quot;, MOD_TOKEN},
++ {&quot;ERROR_BLOCK&quot;, ERRBLK_TOKEN},
++ {&quot;USER_BLOCK2&quot;, USRBLK2_TOKEN},
++ {&quot;USER_BLOCK4&quot;, USRBLK4_TOKEN},
++ {&quot;__tmp&quot;, TMP_TOKEN},
++ {&quot;pop&quot;, POP_TOKEN},
++ {NULL,0},
++ {&quot;EXIT_BLOCK&quot;, EXITBLK_TOKEN},
++ {&quot;USER_BLOCK1&quot;, USRBLK1_TOKEN},
++ {&quot;USER_BLOCK3&quot;, USRBLK3_TOKEN},
++ {&quot;USER_BLOCK0&quot;, USRBLK0_TOKEN},
++ {NULL,0},
++ {&quot;shr&quot;, SHR_TOKEN},
++ {&quot;chs&quot;, CHS_TOKEN},
++ {&quot;sqr&quot;, SQR_TOKEN},
++ {NULL,0},
++ {&quot;struct&quot;, STRUCT_TOKEN},
++ {NULL,0},
++ {NULL,0},
++ {&quot;switch&quot;, SWITCH_TOKEN},
++ {&quot;mul2&quot;, MUL2_TOKEN},
++ {&quot;sign&quot;, SIGN_TOKEN},
++ {&quot;using&quot;, USING_TOKEN},
++ {&quot;while&quot;, WHILE_TOKEN},
++ {NULL,0},
++ {NULL,0},
++ {&quot;loop&quot;, LOOP_TOKEN},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {&quot;public&quot;, PUBLIC_TOKEN},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {&quot;break&quot;, BREAK_TOKEN},
++ {NULL,0},
++ {&quot;do_while&quot;, DOWHILE_TOKEN},
++ {NULL,0},
++ {&quot;shl&quot;, SHL_TOKEN},
++ {&quot;else&quot;, ELSE_TOKEN},
++ {&quot;and&quot;, AND_TOKEN},
++ {&quot;orelse&quot;, ORELSE_TOKEN},
++ {&quot;private&quot;, PRIVATE_TOKEN},
++ {NULL,0},
++ {&quot;if&quot;, IF_TOKEN},
++ {&quot;for&quot;, FOR_TOKEN},
++ {&quot;!if&quot;, IFNOT_TOKEN},
++ {NULL,0},
++ {&quot;_for&quot;, _FOR_TOKEN},
++ {&quot;forever&quot;, FOREVER_TOKEN},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {&quot;abs&quot;, ABS_TOKEN},
++ {&quot;case&quot;, CASE_TOKEN},
++ {NULL,0},
++ {&quot;static&quot;, STATIC_TOKEN},
++ {&quot;define&quot;, DEFINE_TOKEN},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {&quot;typedef&quot;, TYPEDEF_TOKEN},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {&quot;foreach&quot;, FOREACH_TOKEN},
++ {&quot;andelse&quot;, ANDELSE_TOKEN},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {NULL,0},
++ {&quot;variable&quot;, VARIABLE_TOKEN},
++};
++
++static Keyword_Table_Type *is_keyword (char *str, unsigned int len)
++{
++ unsigned int hash;
++ char *name;
++ Keyword_Table_Type *kw;
++
++ if ((len &lt; MIN_KEYWORD_LEN)
++ || (len &gt; MAX_KEYWORD_LEN))
++ return NULL;
++
++ hash = keyword_hash (str, len);
++ if ((hash &gt; MAX_HASH_VALUE) || (hash &lt; MIN_HASH_VALUE))
++ return NULL;
++
++ kw = &amp;Keyword_Table[hash - MIN_HASH_VALUE];
++ if ((NULL != (name = kw-&gt;name))
++ &amp;&amp; (*str == *name)
++ &amp;&amp; (0 == strcmp (str, name)))
++ return kw;
++ return NULL;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/keywhash.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/sl-feat.h
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/sl-feat.h (rev 0)
++++ drakx/trunk/mdk-stage1/slang/sl-feat.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,60 @@
++/* Setting this to 1 enables automatic support for associative arrays.
++ * If this is set to 0, an application must explicitly enable associative
++ * array support via SLang_init_slassoc.
++ */
++#define SLANG_HAS_ASSOC_ARRAYS 1
++
++#define SLANG_HAS_COMPLEX 1
++#define SLANG_HAS_FLOAT 1
++
++/* This is the old space-speed trade off. To reduce memory usage and code
++ * size, set this to zero.
++ */
++#define _SLANG_OPTIMIZE_FOR_SPEED 2
++
++#define _SLANG_USE_INLINE_CODE 1
++
++/* This is experimental. It adds extra information for tracking down
++ * errors.
++ */
++#define _SLANG_HAS_DEBUG_CODE 1
++
++/* Allow optimizations based upon the __tmp operator. */
++#define _SLANG_USE_TMP_OPTIMIZATION 1
++
++/* Setting this to one will map 8 bit vtxxx terminals to 7 bit. Terminals
++ * such as the vt320 can be set up to output the two-character escape sequence
++ * encoded as 'ESC [' as single character. Setting this variable to 1 will
++ * insert code to map such characters to the 7 bit equivalent.
++ * This affects just input characters in the range 128-160 on non PC
++ * systems.
++ */
++#if defined(VMS) || defined(AMIGA)
++# define _SLANG_MAP_VTXXX_8BIT 1
++#else
++# define _SLANG_MAP_VTXXX_8BIT 0
++#endif
++
++/* Add support for color terminals that cannot do background color erases
++ * Such terminals are poorly designed and are slowly disappearing but they
++ * are still quite common. For example, screen is one of them!
++ *
++ * This is experimental. In particular, it is not known to work if
++ * KANJI suupport is enabled.
++ */
++#if !defined(IBMPC_SYSTEM)
++# define SLTT_HAS_NON_BCE_SUPPORT 1
++#else
++# define SLTT_HAS_NON_BCE_SUPPORT 0
++#endif
++
++/* If you want slang to assume that an xterm always has the background color
++ * erase feature, then set this to 1. Otherwise, it will check the terminfo
++ * database. This may or may not be a good idea since most good color xterms
++ * support bce but many terminfo systems do not support it.
++ */
++#define SLTT_XTERM_ALWAYS_BCE 0
++
++/* Set this to 1 to enable Kanji support. See above comment. */
++#define SLANG_HAS_KANJI_SUPPORT 0
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/sl-feat.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slang.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slang.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slang.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,5547 @@
++/* -*- mode: C; mode: fold; -*- */
++/* slang.c --- guts of S-Lang interpreter */
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++
++#if SLANG_HAS_FLOAT
++# include &lt;math.h&gt;
++#endif
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++#define USE_COMBINED_BYTECODES 0
++
++struct _SLBlock_Type;
++
++typedef struct
++{
++ struct _SLBlock_Type *body;
++ unsigned int num_refs;
++}
++_SLBlock_Header_Type;
++
++typedef struct
++{
++ char *name;
++ SLang_Name_Type *next;
++ char name_type;
++
++ union
++ {
++ _SLBlock_Header_Type *header; /* body of function */
++ char *autoload_filename;
++ }
++ v;
++#if _SLANG_HAS_DEBUG_CODE
++ char *file;
++#endif
++#define SLANG_MAX_LOCAL_VARIABLES 254
++#define AUTOLOAD_NUM_LOCALS (SLANG_MAX_LOCAL_VARIABLES + 1)
++ unsigned char nlocals; /* number of local variables */
++ unsigned char nargs; /* number of arguments */
++}
++_SLang_Function_Type;
++
++typedef struct
++{
++ char *name;
++ SLang_Name_Type *next;
++ char name_type;
++
++ SLang_Object_Type obj;
++}
++SLang_Global_Var_Type;
++
++typedef struct
++{
++ char *name;
++ SLang_Name_Type *next;
++ char name_type;
++
++ int local_var_number;
++}
++SLang_Local_Var_Type;
++
++typedef struct _SLBlock_Type
++{
++ unsigned char bc_main_type;
++ unsigned char bc_sub_type;
++ union
++ {
++ struct _SLBlock_Type *blk;
++ int i_blk;
++
++ SLang_Name_Type *nt_blk;
++ SLang_App_Unary_Type *nt_unary_blk;
++ SLang_Intrin_Var_Type *nt_ivar_blk;
++ SLang_Intrin_Fun_Type *nt_ifun_blk;
++ SLang_Global_Var_Type *nt_gvar_blk;
++ SLang_IConstant_Type *iconst_blk;
++ SLang_DConstant_Type *dconst_blk;
++ _SLang_Function_Type *nt_fun_blk;
++
++ VOID_STAR ptr_blk;
++ char *s_blk;
++ SLang_BString_Type *bs_blk;
++
++#if SLANG_HAS_FLOAT
++ double *double_blk; /*literal double is a pointer */
++#endif
++ float float_blk;
++ long l_blk;
++ struct _SLang_Struct_Type *struct_blk;
++ int (*call_function)(void);
++ }
++ b;
++}
++SLBlock_Type;
++
++/* Debugging and tracing variables */
++
++void (*SLang_Enter_Function)(char *) = NULL;
++void (*SLang_Exit_Function)(char *) = NULL;
++/* If non null, these call C functions before and after a slang function. */
++
++int _SLang_Trace = 0;
++/* If _SLang_Trace = -1, do not trace intrinsics */
++static int Trace_Mode = 0;
++
++static char *Trace_Function; /* function to be traced */
++int SLang_Traceback = 0;
++/* non zero means do traceback. If less than 0, do not show local variables */
++
++/* These variables handle _NARGS processing by the parser */
++int SLang_Num_Function_Args;
++static int *Num_Args_Stack;
++static unsigned int Recursion_Depth;
++static SLang_Object_Type *Frame_Pointer;
++static int Next_Function_Num_Args;
++static unsigned int Frame_Pointer_Depth;
++static unsigned int *Frame_Pointer_Stack;
++
++static int Lang_Break_Condition = 0;
++/* true if any one below is true. This keeps us from testing 3 variables.
++ * I know this can be perfomed with a bitmapped variable, but...
++ */
++static int Lang_Break = 0;
++static int Lang_Return = 0;
++/* static int Lang_Continue = 0; */
++
++SLang_Object_Type *_SLRun_Stack;
++SLang_Object_Type *_SLStack_Pointer;
++static SLang_Object_Type *_SLStack_Pointer_Max;
++
++/* Might want to increase this. */
++static SLang_Object_Type Local_Variable_Stack[SLANG_MAX_LOCAL_STACK];
++static SLang_Object_Type *Local_Variable_Frame = Local_Variable_Stack;
++
++static void free_function_header (_SLBlock_Header_Type *);
++
++void (*SLang_Dump_Routine)(char *);
++
++static void call_dump_routine (char *fmt, ...)
++{
++ char buf[1024];
++ va_list ap;
++
++ va_start (ap, fmt);
++ if (SLang_Dump_Routine != NULL)
++ {
++ (void) _SLvsnprintf (buf, sizeof (buf), fmt, ap);
++ (*SLang_Dump_Routine) (buf);
++ }
++ else
++ {
++ vfprintf (stderr, fmt, ap);
++ fflush (stderr);
++ }
++ va_end (ap);
++}
++
++static void do_traceback (char *, unsigned int, char *);
++static int init_interpreter (void);
++
++/*{{{ push/pop/etc stack manipulation functions */
++
++/* This routine is assumed to work even in the presence of a SLang_Error. */
++_INLINE_
++int SLang_pop (SLang_Object_Type *x)
++{
++ register SLang_Object_Type *y;
++
++ y = _SLStack_Pointer;
++ if (y == _SLRun_Stack)
++ {
++ if (SLang_Error == 0) SLang_Error = SL_STACK_UNDERFLOW;
++ x-&gt;data_type = 0;
++ return -1;
++ }
++ y--;
++ *x = *y;
++
++ _SLStack_Pointer = y;
++ return 0;
++}
++
++static int pop_ctrl_integer (int *i)
++{
++ int type;
++ SLang_Class_Type *cl;
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ register SLang_Object_Type *y;
++
++ /* Most of the time, either an integer or a char will be on the stack.
++ * Optimize these cases.
++ */
++ y = _SLStack_Pointer;
++ if (y == _SLRun_Stack)
++ {
++ if (SLang_Error == 0) SLang_Error = SL_STACK_UNDERFLOW;
++ return -1;
++ }
++ y--;
++
++ type = y-&gt;data_type;
++ if (type == SLANG_INT_TYPE)
++ {
++ _SLStack_Pointer = y;
++ *i = y-&gt;v.int_val;
++ return 0;
++ }
++ if (type == SLANG_CHAR_TYPE)
++ {
++ _SLStack_Pointer = y;
++ *i = y-&gt;v.char_val;
++ return 0;
++ }
++#else
++ if (-1 == (type = SLang_peek_at_stack ()))
++ return -1;
++#endif
++
++ cl = _SLclass_get_class ((unsigned char) type);
++ if (cl-&gt;cl_to_bool == NULL)
++ {
++ SLang_verror (SL_TYPE_MISMATCH,
++ &quot;%s cannot be used in a boolean context&quot;,
++ cl-&gt;cl_name);
++ return -1;
++ }
++ return cl-&gt;cl_to_bool ((unsigned char) type, i);
++}
++
++_INLINE_
++int SLang_peek_at_stack (void)
++{
++ if (_SLStack_Pointer == _SLRun_Stack)
++ {
++ if (SLang_Error == 0)
++ SLang_Error = SL_STACK_UNDERFLOW;
++ return -1;
++ }
++
++ return (_SLStack_Pointer - 1)-&gt;data_type;
++}
++
++int SLang_peek_at_stack1 (void)
++{
++ int type;
++
++ type = SLang_peek_at_stack ();
++ if (type == SLANG_ARRAY_TYPE)
++ type = (_SLStack_Pointer - 1)-&gt;v.array_val-&gt;data_type;
++
++ return type;
++}
++
++_INLINE_
++void SLang_free_object (SLang_Object_Type *obj)
++{
++ unsigned char data_type;
++ SLang_Class_Type *cl;
++
++ if (obj == NULL) return;
++ data_type = obj-&gt;data_type;
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ if (SLANG_CLASS_TYPE_SCALAR == _SLclass_Class_Type [data_type])
++ return;
++ if (data_type == SLANG_STRING_TYPE)
++ {
++ SLang_free_slstring (obj-&gt;v.s_val);
++ return;
++ }
++#endif
++ cl = _SLclass_get_class (data_type);
++#if !_SLANG_OPTIMIZE_FOR_SPEED
++ if (cl-&gt;cl_class_type != SLANG_CLASS_TYPE_SCALAR)
++#endif
++ (*cl-&gt;cl_destroy) (data_type, (VOID_STAR) &amp;obj-&gt;v);
++}
++
++_INLINE_
++int SLang_push (SLang_Object_Type *x)
++{
++ register SLang_Object_Type *y;
++ y = _SLStack_Pointer;
++
++ /* if there is a SLang_Error, probably not much harm will be done
++ if it is ignored here */
++ /* if (SLang_Error) return; */
++
++ /* flag it now */
++ if (y &gt;= _SLStack_Pointer_Max)
++ {
++ if (!SLang_Error) SLang_Error = SL_STACK_OVERFLOW;
++ return -1;
++ }
++
++ *y = *x;
++ _SLStack_Pointer = y + 1;
++ return 0;
++}
++
++/* _INLINE_ */
++int SLclass_push_ptr_obj (unsigned char type, VOID_STAR pval)
++{
++ register SLang_Object_Type *y;
++ y = _SLStack_Pointer;
++
++ if (y &gt;= _SLStack_Pointer_Max)
++ {
++ if (!SLang_Error) SLang_Error = SL_STACK_OVERFLOW;
++ return -1;
++ }
++
++ y-&gt;data_type = type;
++ y-&gt;v.ptr_val = pval;
++
++ _SLStack_Pointer = y + 1;
++ return 0;
++}
++
++_INLINE_
++int SLclass_push_int_obj (unsigned char type, int x)
++{
++ register SLang_Object_Type *y;
++ y = _SLStack_Pointer;
++
++ if (y &gt;= _SLStack_Pointer_Max)
++ {
++ if (!SLang_Error) SLang_Error = SL_STACK_OVERFLOW;
++ return -1;
++ }
++
++ y-&gt;data_type = type;
++ y-&gt;v.int_val = x;
++
++ _SLStack_Pointer = y + 1;
++ return 0;
++}
++
++_INLINE_
++int _SLang_pop_object_of_type (unsigned char type, SLang_Object_Type *obj,
++ int allow_arrays)
++{
++ register SLang_Object_Type *y;
++
++ y = _SLStack_Pointer;
++ if (y == _SLRun_Stack)
++ return SLang_pop (obj);
++ y--;
++ if (y-&gt;data_type != type)
++ {
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ /* This is an implicit typecast. We do not want to typecast
++ * floats to ints implicitly.
++ */
++ if (_SLarith_Is_Arith_Type [type]
++ &amp;&amp; _SLarith_Is_Arith_Type [y-&gt;data_type]
++ &amp;&amp; (_SLarith_Is_Arith_Type [type] &gt;= _SLarith_Is_Arith_Type[y-&gt;data_type]))
++ {
++ /* This should not fail */
++ (void) _SLarith_typecast (y-&gt;data_type, (VOID_STAR)&amp;y-&gt;v, 1,
++ type, (VOID_STAR)&amp;obj-&gt;v);
++ obj-&gt;data_type = type;
++ _SLStack_Pointer = y;
++ return 0;
++ }
++#endif
++
++ if ((allow_arrays == 0)
++ || (y-&gt;data_type != SLANG_ARRAY_TYPE)
++ || (y-&gt;v.array_val-&gt;data_type != type))
++ if (-1 == SLclass_typecast (type, 1, 0))
++ return -1;
++ }
++ *obj = *y;
++ _SLStack_Pointer = y;
++ return 0;
++}
++
++/* This function reverses the top n items on the stack and returns a
++ * an offset from the start of the stack to the last item.
++ */
++int SLreverse_stack (int n)
++{
++ SLang_Object_Type *otop, *obot, tmp;
++
++ otop = _SLStack_Pointer;
++ if ((n &gt; otop - _SLRun_Stack) || (n &lt; 0))
++ {
++ SLang_Error = SL_STACK_UNDERFLOW;
++ return -1;
++ }
++ obot = otop - n;
++ otop--;
++ while (otop &gt; obot)
++ {
++ tmp = *obot;
++ *obot = *otop;
++ *otop = tmp;
++ otop--;
++ obot++;
++ }
++ return (int) ((_SLStack_Pointer - n) - _SLRun_Stack);
++}
++
++_INLINE_
++int SLroll_stack (int np)
++{
++ int n, i;
++ SLang_Object_Type *otop, *obot, tmp;
++
++ if ((n = abs(np)) &lt;= 1) return 0; /* identity */
++
++ obot = otop = _SLStack_Pointer;
++ i = n;
++ while (i != 0)
++ {
++ if (obot &lt;= _SLRun_Stack)
++ {
++ SLang_Error = SL_STACK_UNDERFLOW;
++ return -1;
++ }
++ obot--;
++ i--;
++ }
++ otop--;
++
++ if (np &gt; 0)
++ {
++ /* Put top on bottom and roll rest up. */
++ tmp = *otop;
++ while (otop &gt; obot)
++ {
++ *otop = *(otop - 1);
++ otop--;
++ }
++ *otop = tmp;
++ }
++ else
++ {
++ /* Put bottom on top and roll rest down. */
++ tmp = *obot;
++ while (obot &lt; otop)
++ {
++ *obot = *(obot + 1);
++ obot++;
++ }
++ *obot = tmp;
++ }
++ return 0;
++}
++
++int _SLstack_depth (void)
++{
++ return (int) (_SLStack_Pointer - _SLRun_Stack);
++}
++
++int SLdup_n (int n)
++{
++ SLang_Object_Type *bot, *top;
++
++ if (n &lt;= 0)
++ return 0;
++
++ top = _SLStack_Pointer;
++ if (top &lt; _SLRun_Stack + n)
++ {
++ if (SLang_Error == 0)
++ SLang_Error = SL_STACK_UNDERFLOW;
++ return -1;
++ }
++ if (top + n &gt; _SLStack_Pointer_Max)
++ {
++ if (SLang_Error == 0)
++ SLang_Error = SL_STACK_OVERFLOW;
++ return -1;
++ }
++ bot = top - n;
++
++ while (bot &lt; top)
++ {
++ SLang_Class_Type *cl;
++ unsigned char data_type = bot-&gt;data_type;
++
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ if (SLANG_CLASS_TYPE_SCALAR == _SLclass_Class_Type [data_type])
++ {
++ *_SLStack_Pointer++ = *bot++;
++ continue;
++ }
++#endif
++ cl = _SLclass_get_class (data_type);
++ if (-1 == (*cl-&gt;cl_push) (data_type, (VOID_STAR) &amp;bot-&gt;v))
++ return -1;
++ bot++;
++ }
++ return 0;
++}
++
++/*}}}*/
++
++/*{{{ inner interpreter and support functions */
++
++_INLINE_
++int _SL_increment_frame_pointer (void)
++{
++ if (Recursion_Depth &gt;= SLANG_MAX_RECURSIVE_DEPTH)
++ {
++ SLang_verror (SL_STACK_OVERFLOW, &quot;Num Args Stack Overflow&quot;);
++ return -1;
++ }
++ Num_Args_Stack [Recursion_Depth] = SLang_Num_Function_Args;
++
++ SLang_Num_Function_Args = Next_Function_Num_Args;
++ Next_Function_Num_Args = 0;
++ Recursion_Depth++;
++ return 0;
++}
++
++_INLINE_
++int _SL_decrement_frame_pointer (void)
++{
++ if (Recursion_Depth == 0)
++ {
++ SLang_verror (SL_STACK_UNDERFLOW, &quot;Num Args Stack Underflow&quot;);
++ return -1;
++ }
++
++ Recursion_Depth--;
++ if (Recursion_Depth &lt; SLANG_MAX_RECURSIVE_DEPTH)
++ SLang_Num_Function_Args = Num_Args_Stack [Recursion_Depth];
++
++ return 0;
++}
++
++_INLINE_
++int SLang_start_arg_list (void)
++{
++ if (Frame_Pointer_Depth &lt; SLANG_MAX_RECURSIVE_DEPTH)
++ {
++ Frame_Pointer_Stack [Frame_Pointer_Depth] = (unsigned int) (Frame_Pointer - _SLRun_Stack);
++ Frame_Pointer = _SLStack_Pointer;
++ Frame_Pointer_Depth++;
++ Next_Function_Num_Args = 0;
++ return 0;
++ }
++
++ SLang_verror (SL_STACK_OVERFLOW, &quot;Frame Stack Overflow&quot;);
++ return -1;
++}
++
++_INLINE_
++int SLang_end_arg_list (void)
++{
++ if (Frame_Pointer_Depth == 0)
++ {
++ SLang_verror (SL_STACK_UNDERFLOW, &quot;Frame Stack Underflow&quot;);
++ return -1;
++ }
++ Frame_Pointer_Depth--;
++ if (Frame_Pointer_Depth &lt; SLANG_MAX_RECURSIVE_DEPTH)
++ {
++ Next_Function_Num_Args = (int) (_SLStack_Pointer - Frame_Pointer);
++ Frame_Pointer = _SLRun_Stack + Frame_Pointer_Stack [Frame_Pointer_Depth];
++ }
++ return 0;
++}
++
++_INLINE_
++static int do_bc_call_direct_frame (int (*f)(void))
++{
++ if ((0 == SLang_end_arg_list ())
++ &amp;&amp; (0 == _SL_increment_frame_pointer ()))
++ {
++ (void) (*f) ();
++ _SL_decrement_frame_pointer ();
++ }
++ if (SLang_Error)
++ return -1;
++ return 0;
++}
++
++static int do_name_type_error (SLang_Name_Type *nt)
++{
++ char buf[256];
++ if (nt != NULL)
++ {
++ (void) _SLsnprintf (buf, sizeof (buf), &quot;(Error occurred processing %s)&quot;, nt-&gt;name);
++ do_traceback (buf, 0, NULL);
++ }
++ return -1;
++}
++
++/* local and global variable assignments */
++
++static int do_binary_ab (int op, SLang_Object_Type *obja, SLang_Object_Type *objb)
++{
++ SLang_Class_Type *a_cl, *b_cl, *c_cl;
++ unsigned char b_data_type, a_data_type, c_data_type;
++ int (*binary_fun) (int,
++ unsigned char, VOID_STAR, unsigned int,
++ unsigned char, VOID_STAR, unsigned int,
++ VOID_STAR);
++ VOID_STAR pa;
++ VOID_STAR pb;
++ VOID_STAR pc;
++ int ret;
++
++ b_data_type = objb-&gt;data_type;
++ a_data_type = obja-&gt;data_type;
++
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ if (_SLarith_Is_Arith_Type[a_data_type]
++ &amp;&amp; _SLarith_Is_Arith_Type[b_data_type])
++ {
++ int status;
++ status = _SLarith_bin_op (obja, objb, op);
++ if (status != 1)
++ return status;
++ /* drop and try it the hard way */
++ }
++#endif
++
++ a_cl = _SLclass_get_class (a_data_type);
++ if (a_data_type == b_data_type)
++ b_cl = a_cl;
++ else
++ b_cl = _SLclass_get_class (b_data_type);
++
++ if (NULL == (binary_fun = _SLclass_get_binary_fun (op, a_cl, b_cl, &amp;c_cl, 1)))
++ return -1;
++
++ c_data_type = c_cl-&gt;cl_data_type;
++
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ if (SLANG_CLASS_TYPE_SCALAR == _SLclass_Class_Type [a_data_type])
++ pa = (VOID_STAR) &amp;obja-&gt;v;
++ else
++#endif
++ pa = _SLclass_get_ptr_to_value (a_cl, obja);
++
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ if (SLANG_CLASS_TYPE_SCALAR == _SLclass_Class_Type [b_data_type])
++ pb = (VOID_STAR) &amp;objb-&gt;v;
++ else
++#endif
++ pb = _SLclass_get_ptr_to_value (b_cl, objb);
++
++ pc = c_cl-&gt;cl_transfer_buf;
++
++ if (1 != (*binary_fun) (op,
++ a_data_type, pa, 1,
++ b_data_type, pb, 1,
++ pc))
++ {
++ SLang_verror (SL_NOT_IMPLEMENTED,
++ &quot;Binary operation between %s and %s failed&quot;,
++ a_cl-&gt;cl_name, b_cl-&gt;cl_name);
++
++ return -1;
++ }
++
++ /* apush will create a copy, so make sure we free after the push */
++ ret = (*c_cl-&gt;cl_apush)(c_data_type, pc);
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [c_data_type])
++#endif
++ (*c_cl-&gt;cl_adestroy)(c_data_type, pc);
++
++ return ret;
++}
++
++_INLINE_
++static void do_binary (int op)
++{
++ SLang_Object_Type obja, objb;
++
++ if (SLang_pop (&amp;objb)) return;
++ if (0 == SLang_pop (&amp;obja))
++ {
++ (void) do_binary_ab (op, &amp;obja, &amp;objb);
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [obja.data_type])
++#endif
++ SLang_free_object (&amp;obja);
++ }
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [objb.data_type])
++#endif
++ SLang_free_object (&amp;objb);
++}
++
++static int do_unary_op (int op, SLang_Object_Type *obj, int unary_type)
++{
++ int (*f) (int, unsigned char, VOID_STAR, unsigned int, VOID_STAR);
++ VOID_STAR pa;
++ VOID_STAR pb;
++ SLang_Class_Type *a_cl, *b_cl;
++ unsigned char a_type, b_type;
++ int ret;
++
++ a_type = obj-&gt;data_type;
++ a_cl = _SLclass_get_class (a_type);
++
++ if (NULL == (f = _SLclass_get_unary_fun (op, a_cl, &amp;b_cl, unary_type)))
++ return -1;
++
++ b_type = b_cl-&gt;cl_data_type;
++
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ if (SLANG_CLASS_TYPE_SCALAR == _SLclass_Class_Type [a_type])
++ pa = (VOID_STAR) &amp;obj-&gt;v;
++ else
++#endif
++ pa = _SLclass_get_ptr_to_value (a_cl, obj);
++
++ pb = b_cl-&gt;cl_transfer_buf;
++
++ if (1 != (*f) (op, a_type, pa, 1, pb))
++ {
++ SLang_verror (SL_NOT_IMPLEMENTED,
++ &quot;Unary operation for %s failed&quot;, a_cl-&gt;cl_name);
++ return -1;
++ }
++
++ ret = (*b_cl-&gt;cl_apush)(b_type, pb);
++ /* cl_apush creates a copy, so make sure we call cl_adestroy */
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [b_type])
++#endif
++ (*b_cl-&gt;cl_adestroy)(b_type, pb);
++
++ return ret;
++}
++
++_INLINE_
++static int do_unary (int op, int unary_type)
++{
++ SLang_Object_Type obj;
++ int ret;
++
++ if (-1 == SLang_pop (&amp;obj)) return -1;
++ ret = do_unary_op (op, &amp;obj, unary_type);
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [obj.data_type])
++#endif
++ SLang_free_object (&amp;obj);
++ return ret;
++}
++
++static int do_assignment_binary (int op, SLang_Object_Type *obja_ptr)
++{
++ SLang_Object_Type objb;
++ int ret;
++
++ if (SLang_pop (&amp;objb))
++ return -1;
++
++ ret = do_binary_ab (op, obja_ptr, &amp;objb);
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [objb.data_type])
++#endif
++ SLang_free_object (&amp;objb);
++ return ret;
++}
++
++/* The order of these is assumed to match the binary operators
++ * defined in slang.h
++ */
++static int
++map_assignment_op_to_binary (unsigned char op_type, int *op, int *is_unary)
++{
++ *is_unary = 0;
++ switch (op_type)
++ {
++ case _SLANG_BCST_PLUSEQS:
++ case _SLANG_BCST_MINUSEQS:
++ case _SLANG_BCST_TIMESEQS:
++ case _SLANG_BCST_DIVEQS:
++ *op = SLANG_PLUS + (op_type - _SLANG_BCST_PLUSEQS);
++ break;
++
++ case _SLANG_BCST_BOREQS:
++ *op = SLANG_BOR;
++ break;
++
++ case _SLANG_BCST_BANDEQS:
++ *op = SLANG_BAND;
++ break;
++
++ case _SLANG_BCST_POST_MINUSMINUS:
++ case _SLANG_BCST_MINUSMINUS:
++ *op = SLANG_MINUS;
++ *is_unary = 1;
++ break;
++
++ case _SLANG_BCST_PLUSPLUS:
++ case _SLANG_BCST_POST_PLUSPLUS:
++ *op = SLANG_PLUS;
++ *is_unary = 1;
++ break;
++
++ default:
++ SLang_verror (SL_NOT_IMPLEMENTED, &quot;Assignment operator not implemented&quot;);
++ return -1;
++ }
++ return 0;
++}
++
++static int
++perform_lvalue_operation (unsigned char op_type, SLang_Object_Type *obja_ptr)
++{
++ switch (op_type)
++ {
++ case _SLANG_BCST_ASSIGN:
++ break;
++
++ /* The order of these is assumed to match the binary operators
++ * defined in slang.h
++ */
++ case _SLANG_BCST_PLUSEQS:
++ case _SLANG_BCST_MINUSEQS:
++ case _SLANG_BCST_TIMESEQS:
++ case _SLANG_BCST_DIVEQS:
++ if (-1 == do_assignment_binary (SLANG_PLUS + (op_type - _SLANG_BCST_PLUSEQS), obja_ptr))
++ return -1;
++ break;
++
++ case _SLANG_BCST_BOREQS:
++ if (-1 == do_assignment_binary (SLANG_BOR, obja_ptr))
++ return -1;
++ break;
++
++ case _SLANG_BCST_BANDEQS:
++ if (-1 == do_assignment_binary (SLANG_BAND, obja_ptr))
++ return -1;
++ break;
++
++ case _SLANG_BCST_PLUSPLUS:
++ case _SLANG_BCST_POST_PLUSPLUS:
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ if (obja_ptr-&gt;data_type == SLANG_INT_TYPE)
++ return SLclass_push_int_obj (SLANG_INT_TYPE, obja_ptr-&gt;v.int_val + 1);
++#endif
++ if (-1 == do_unary_op (SLANG_PLUSPLUS, obja_ptr, _SLANG_BC_UNARY))
++ return -1;
++ break;
++
++ case _SLANG_BCST_MINUSMINUS:
++ case _SLANG_BCST_POST_MINUSMINUS:
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ if (obja_ptr-&gt;data_type == SLANG_INT_TYPE)
++ return SLclass_push_int_obj (SLANG_INT_TYPE, obja_ptr-&gt;v.int_val - 1);
++#endif
++ if (-1 == do_unary_op (SLANG_MINUSMINUS, obja_ptr, _SLANG_BC_UNARY))
++ return -1;
++ break;
++
++ default:
++ SLang_Error = SL_INTERNAL_ERROR;
++ return -1;
++ }
++ return 0;
++}
++
++_INLINE_
++static int
++set_lvalue_obj (unsigned char op_type, SLang_Object_Type *obja_ptr)
++{
++ if (op_type != _SLANG_BCST_ASSIGN)
++ {
++ if (-1 == perform_lvalue_operation (op_type, obja_ptr))
++ return -1;
++ }
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [obja_ptr-&gt;data_type])
++#endif
++ SLang_free_object (obja_ptr);
++
++ return SLang_pop(obja_ptr);
++}
++
++static int
++set_struct_lvalue (SLBlock_Type *bc_blk)
++{
++ int type;
++ SLang_Class_Type *cl;
++ char *name;
++ int op;
++
++ if (-1 == (type = SLang_peek_at_stack ()))
++ return -1;
++
++ cl = _SLclass_get_class (type);
++ if ((cl-&gt;cl_sput == NULL)
++ || (cl-&gt;cl_sget == NULL))
++ {
++ SLang_verror (SL_NOT_IMPLEMENTED,
++ &quot;%s does not support structure access&quot;,
++ cl-&gt;cl_name);
++ SLdo_pop_n (2); /* object plus what was to be assigned */
++ return -1;
++ }
++ name = bc_blk-&gt;b.s_blk;
++ op = bc_blk-&gt;bc_sub_type;
++
++ if (op != _SLANG_BCST_ASSIGN)
++ {
++ /* We have something like (A.x += b) or (A.x++). In either case,
++ * we need A.x.
++ */
++ SLang_Object_Type obj_A;
++ SLang_Object_Type obj;
++
++ if (-1 == SLang_pop (&amp;obj_A))
++ return -1;
++
++ if ((-1 == _SLpush_slang_obj (&amp;obj_A))
++ || (-1 == cl-&gt;cl_sget ((unsigned char) type, name))
++ || (-1 == SLang_pop (&amp;obj)))
++ {
++ SLang_free_object (&amp;obj_A);
++ return -1;
++ }
++ /* Now the value of A.x is in obj. */
++ if (-1 == perform_lvalue_operation (op, &amp;obj))
++ {
++ SLang_free_object (&amp;obj);
++ SLang_free_object (&amp;obj_A);
++ return -1;
++ }
++ SLang_free_object (&amp;obj);
++ /* The result of the operation is now on the stack.
++ * Perform assignment */
++ if (-1 == SLang_push (&amp;obj_A))
++ {
++ SLang_free_object (&amp;obj_A);
++ return -1;
++ }
++ }
++
++ return (*cl-&gt;cl_sput) ((unsigned char) type, name);
++}
++
++static int make_unit_object (SLang_Object_Type *a, SLang_Object_Type *u)
++{
++ unsigned char type;
++
++ type = a-&gt;data_type;
++ if (type == SLANG_ARRAY_TYPE)
++ type = a-&gt;v.array_val-&gt;data_type;
++
++ u-&gt;data_type = type;
++ switch (type)
++ {
++ case SLANG_UCHAR_TYPE:
++ case SLANG_CHAR_TYPE:
++ u-&gt;v.char_val = 1;
++ break;
++
++ case SLANG_SHORT_TYPE:
++ case SLANG_USHORT_TYPE:
++ u-&gt;v.short_val = 1;
++ break;
++
++ case SLANG_LONG_TYPE:
++ case SLANG_ULONG_TYPE:
++ u-&gt;v.long_val = 1;
++ break;
++
++#if SLANG_HAS_FLOAT
++ case SLANG_FLOAT_TYPE:
++ u-&gt;v.float_val = 1;
++ break;
++
++ case SLANG_COMPLEX_TYPE:
++ u-&gt;data_type = SLANG_DOUBLE_TYPE;
++ case SLANG_DOUBLE_TYPE:
++ u-&gt;v.double_val = 1;
++ break;
++#endif
++ default:
++ u-&gt;data_type = SLANG_INT_TYPE;
++ u-&gt;v.int_val = 1;
++ }
++ return 0;
++}
++
++
++/* We want to convert 'A[i] op X' to 'A[i] = A[i] op X'. The code that
++ * has been generated is: X __args i A __aput-op
++ * where __aput-op represents this function. We need to generate:
++ * __args i A __eargs __aget X op __args i A __eargs __aput
++ * Here, __eargs implies a call to do_bc_call_direct_frame with either
++ * the aput or aget function. In addition, __args represents a call to
++ * SLang_start_arg_list. Of course, i represents a set of indices.
++ *
++ * Note: If op is an unary operation (e.g., ++ or --), then X will not
++ * b present an will have to be taken to be 1.
++ *
++ * Implementation note: For efficiency, calls to setup the frame, start
++ * arg list will be omitted and SLang_Num_Function_Args will be set.
++ * This is ugly but the alternative is much less efficient rendering these
++ * assignment operators useless. So, the plan is to roll the stack to get X,
++ * then duplicate the next N values, call __aget followed by op X, finally
++ * calling __aput. Hence, the sequence is:
++ *
++ * start: X i .. j A
++ * dupN: X i .. j A i .. j A
++ * __aget: X i .. j A Y
++ * roll: i .. j A Y X
++ * op: i .. j A Z
++ * roll: Z i .. j A
++ * __aput:
++ */
++static int
++set_array_lvalue (int op)
++{
++ SLang_Object_Type x, y;
++ int num_args, is_unary;
++
++ if (-1 == map_assignment_op_to_binary (op, &amp;op, &amp;is_unary))
++ return -1;
++
++ /* Grab the indices and the array. Do not start a new frame. */
++ if (-1 == SLang_end_arg_list ())
++ return -1;
++ num_args = Next_Function_Num_Args;
++ Next_Function_Num_Args = 0;
++
++ if (-1 == SLdup_n (num_args))
++ return -1;
++
++ SLang_Num_Function_Args = num_args;
++ if (-1 == _SLarray_aget ())
++ return -1;
++
++ if (-1 == SLang_pop (&amp;y))
++ return -1;
++
++ if (is_unary == 0)
++ {
++ if ((-1 == SLroll_stack (-(num_args + 1)))
++ || (-1 == SLang_pop (&amp;x)))
++ {
++ SLang_free_object (&amp;y);
++ return -1;
++ }
++ }
++ else if (-1 == make_unit_object (&amp;y, &amp;x))
++ {
++ SLang_free_object (&amp;y);
++ return -1;
++ }
++
++ if (-1 == do_binary_ab (op, &amp;y, &amp;x))
++ {
++ SLang_free_object (&amp;y);
++ SLang_free_object (&amp;x);
++ return -1;
++ }
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [y.data_type])
++#endif
++ SLang_free_object (&amp;y);
++
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [x.data_type])
++#endif
++ SLang_free_object (&amp;x);
++
++ if (-1 == SLroll_stack (num_args + 1))
++ return -1;
++
++ SLang_Num_Function_Args = num_args;
++ return _SLarray_aput ();
++}
++
++
++static int
++set_intrin_lvalue (SLBlock_Type *bc_blk)
++{
++ unsigned char op_type;
++ SLang_Object_Type obja;
++ SLang_Class_Type *cl;
++ SLang_Intrin_Var_Type *ivar;
++ VOID_STAR intrinsic_addr;
++ unsigned char intrinsic_type;
++
++ ivar = bc_blk-&gt;b.nt_ivar_blk;
++
++ intrinsic_type = ivar-&gt;type;
++ intrinsic_addr = ivar-&gt;addr;
++
++ op_type = bc_blk-&gt;bc_sub_type;
++
++ cl = _SLclass_get_class (intrinsic_type);
++
++ if (op_type != _SLANG_BCST_ASSIGN)
++ {
++ /* We want to get the current value into obja. This is the
++ * easiest way.
++ */
++ if ((-1 == (*cl-&gt;cl_push) (intrinsic_type, intrinsic_addr))
++ || (-1 == SLang_pop (&amp;obja)))
++ return -1;
++
++ (void) perform_lvalue_operation (op_type, &amp;obja);
++ SLang_free_object (&amp;obja);
++
++ if (SLang_Error)
++ return -1;
++ }
++
++ return (*cl-&gt;cl_pop) (intrinsic_type, intrinsic_addr);
++}
++
++int _SLang_deref_assign (SLang_Ref_Type *ref)
++{
++ SLang_Object_Type *objp;
++ SLang_Name_Type *nt;
++ SLBlock_Type blk;
++
++ if (ref-&gt;is_global == 0)
++ {
++ objp = ref-&gt;v.local_obj;
++ if (objp &gt; Local_Variable_Frame)
++ {
++ SLang_verror (SL_UNDEFINED_NAME, &quot;Local variable reference is out of scope&quot;);
++ return -1;
++ }
++ return set_lvalue_obj (_SLANG_BCST_ASSIGN, objp);
++ }
++
++ nt = ref-&gt;v.nt;
++ switch (nt-&gt;name_type)
++ {
++ case SLANG_GVARIABLE:
++ case SLANG_PVARIABLE:
++ if (-1 == set_lvalue_obj (_SLANG_BCST_ASSIGN,
++ &amp;((SLang_Global_Var_Type *)nt)-&gt;obj))
++ {
++ do_name_type_error (nt);
++ return -1;
++ }
++ break;
++
++ case SLANG_IVARIABLE:
++ blk.b.nt_blk = nt;
++ blk.bc_sub_type = _SLANG_BCST_ASSIGN;
++ if (-1 == set_intrin_lvalue (&amp;blk))
++ {
++ do_name_type_error (nt);
++ return -1;
++ }
++ break;
++
++ case SLANG_LVARIABLE:
++ SLang_Error = SL_INTERNAL_ERROR;
++ /* set_intrin_lvalue (&amp;blk); */
++ return -1;
++
++ case SLANG_RVARIABLE:
++ default:
++ SLang_verror (SL_READONLY_ERROR, &quot;deref assignment to %s not allowed&quot;, nt-&gt;name);
++ return -1;
++ }
++
++ return 0;
++}
++
++static void set_deref_lvalue (SLBlock_Type *bc_blk)
++{
++ SLang_Object_Type *objp;
++ SLang_Ref_Type *ref;
++
++ switch (bc_blk-&gt;bc_sub_type)
++ {
++ case SLANG_LVARIABLE:
++ objp = (Local_Variable_Frame - bc_blk-&gt;b.i_blk);
++ break;
++ case SLANG_GVARIABLE:
++ case SLANG_PVARIABLE:
++ objp = &amp;bc_blk-&gt;b.nt_gvar_blk-&gt;obj;
++ break;
++ default:
++ SLang_Error = SL_INTERNAL_ERROR;
++ return;
++ }
++
++ if (-1 == _SLpush_slang_obj (objp))
++ return;
++
++ if (-1 == SLang_pop_ref (&amp;ref))
++ return;
++ (void) _SLang_deref_assign (ref);
++ SLang_free_ref (ref);
++}
++
++static int push_struct_field (char *name)
++{
++ int type;
++ SLang_Class_Type *cl;
++
++ if (-1 == (type = SLang_peek_at_stack ()))
++ return -1;
++
++ cl = _SLclass_get_class ((unsigned char) type);
++ if (cl-&gt;cl_sget == NULL)
++ {
++ SLang_verror (SL_NOT_IMPLEMENTED,
++ &quot;%s does not permit structure access&quot;,
++ cl-&gt;cl_name);
++ SLdo_pop_n (2);
++ return -1;
++ }
++
++ return (*cl-&gt;cl_sget) ((unsigned char) type, name);
++}
++
++static void trace_dump (char *format, char *name, SLang_Object_Type *objs, int n, int dir)
++{
++ unsigned int len;
++ char prefix [52];
++
++ len = Trace_Mode - 1;
++ if (len + 2 &gt;= sizeof (prefix))
++ len = sizeof (prefix) - 2;
++
++ SLMEMSET (prefix, ' ', len);
++ prefix[len] = 0;
++
++ call_dump_routine (prefix);
++ call_dump_routine (format, name, n);
++
++ if (n &gt; 0)
++ {
++ prefix[len] = ' ';
++ len++;
++ prefix[len] = 0;
++
++ _SLdump_objects (prefix, objs, n, dir);
++ }
++}
++
++/* Pop a data item from the stack and return a pointer to it.
++ * Strings are not freed from stack so use another routine to do it.
++ */
++static VOID_STAR pop_pointer (SLang_Object_Type *obj, unsigned char type)
++{
++#ifndef _SLANG_OPTIMIZE_FOR_SPEED
++ SLang_Class_Type *cl;
++#endif
++
++ SLang_Array_Type *at;
++
++ /* Arrays are special. Allow scalars to automatically convert to arrays.
++ */
++ if (type == SLANG_ARRAY_TYPE)
++ {
++ if (-1 == SLang_pop_array (&amp;at, 1))
++ return NULL;
++ obj-&gt;data_type = SLANG_ARRAY_TYPE;
++ return obj-&gt;v.ptr_val = (VOID_STAR) at;
++ }
++
++ if (type == 0)
++ {
++ /* This happens when an intrinsic is declared without any information
++ * regarding parameter types.
++ */
++ if (-1 == SLang_pop (obj))
++ return NULL;
++ type = obj-&gt;data_type;
++ }
++ else if (-1 == _SLang_pop_object_of_type (type, obj, 0))
++ return NULL;
++
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ type = _SLclass_Class_Type [type];
++#else
++ type = _SLclass_get_class (type)-&gt;cl_class_type;
++#endif
++
++ if (type == SLANG_CLASS_TYPE_SCALAR)
++ return (VOID_STAR) &amp;obj-&gt;v;
++ else if (type == SLANG_CLASS_TYPE_MMT)
++ return SLang_object_from_mmt (obj-&gt;v.ref);
++ else
++ return obj-&gt;v.ptr_val;
++}
++
++/* This is ugly. Does anyone have a advice for a cleaner way of doing
++ * this??
++ */
++typedef void (*VF0_Type)(void);
++typedef void (*VF1_Type)(VOID_STAR);
++typedef void (*VF2_Type)(VOID_STAR, VOID_STAR);
++typedef void (*VF3_Type)(VOID_STAR, VOID_STAR, VOID_STAR);
++typedef void (*VF4_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
++typedef void (*VF5_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
++typedef void (*VF6_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
++typedef void (*VF7_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
++typedef long (*LF0_Type)(void);
++typedef long (*LF1_Type)(VOID_STAR);
++typedef long (*LF2_Type)(VOID_STAR, VOID_STAR);
++typedef long (*LF3_Type)(VOID_STAR, VOID_STAR, VOID_STAR);
++typedef long (*LF4_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
++typedef long (*LF5_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
++typedef long (*LF6_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
++typedef long (*LF7_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
++#if SLANG_HAS_FLOAT
++typedef double (*FF0_Type)(void);
++typedef double (*FF1_Type)(VOID_STAR);
++typedef double (*FF2_Type)(VOID_STAR, VOID_STAR);
++typedef double (*FF3_Type)(VOID_STAR, VOID_STAR, VOID_STAR);
++typedef double (*FF4_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
++typedef double (*FF5_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
++typedef double (*FF6_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
++typedef double (*FF7_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
++#endif
++
++static int execute_intrinsic_fun (SLang_Intrin_Fun_Type *objf)
++{
++#if SLANG_HAS_FLOAT
++ double xf;
++#endif
++ VOID_STAR p[SLANG_MAX_INTRIN_ARGS];
++ SLang_Object_Type objs[SLANG_MAX_INTRIN_ARGS];
++ long ret;
++ unsigned char type;
++ unsigned int argc;
++ unsigned int i;
++ FVOID_STAR fptr;
++ unsigned char *arg_types;
++ int stk_depth;
++
++ fptr = objf-&gt;i_fun;
++ argc = objf-&gt;num_args;
++ type = objf-&gt;return_type;
++ arg_types = objf-&gt;arg_types;
++
++ if (argc &gt; SLANG_MAX_INTRIN_ARGS)
++ {
++ SLang_verror(SL_APPLICATION_ERROR,
++ &quot;Intrinsic function %s requires too many parameters&quot;, objf-&gt;name);
++ return -1;
++ }
++
++ if (-1 == _SL_increment_frame_pointer ())
++ return -1;
++
++ stk_depth = -1;
++ if (Trace_Mode &amp;&amp; (_SLang_Trace &gt; 0))
++ {
++ int nargs;
++
++ stk_depth = _SLstack_depth ();
++
++ nargs = SLang_Num_Function_Args;
++ if (nargs == 0)
++ nargs = (int)argc;
++
++ stk_depth -= nargs;
++
++ if (stk_depth &gt;= 0)
++ trace_dump (&quot;&gt;&gt;%s (%d args)\n&quot;,
++ objf-&gt;name,
++ _SLStack_Pointer - nargs,
++ nargs,
++ 1);
++ }
++
++ i = argc;
++ while (i != 0)
++ {
++ i--;
++ if (NULL == (p[i] = pop_pointer (objs + i, arg_types[i])))
++ {
++ i++;
++ goto free_and_return;
++ }
++ }
++
++ ret = 0;
++#if SLANG_HAS_FLOAT
++ xf = 0.0;
++#endif
++
++ switch (argc)
++ {
++ case 0:
++ if (type == SLANG_VOID_TYPE) ((VF0_Type) fptr) ();
++#if SLANG_HAS_FLOAT
++ else if (type == SLANG_DOUBLE_TYPE) xf = ((FF0_Type) fptr)();
++#endif
++ else ret = ((LF0_Type) fptr)();
++ break;
++
++ case 1:
++ if (type == SLANG_VOID_TYPE) ((VF1_Type) fptr)(p[0]);
++#if SLANG_HAS_FLOAT
++ else if (type == SLANG_DOUBLE_TYPE) xf = ((FF1_Type) fptr)(p[0]);
++#endif
++ else ret = ((LF1_Type) fptr)(p[0]);
++ break;
++
++ case 2:
++ if (type == SLANG_VOID_TYPE) ((VF2_Type) fptr)(p[0], p[1]);
++#if SLANG_HAS_FLOAT
++ else if (type == SLANG_DOUBLE_TYPE) xf = ((FF2_Type) fptr)(p[0], p[1]);
++#endif
++ else ret = ((LF2_Type) fptr)(p[0], p[1]);
++ break;
++
++ case 3:
++ if (type == SLANG_VOID_TYPE) ((VF3_Type) fptr)(p[0], p[1], p[2]);
++#if SLANG_HAS_FLOAT
++ else if (type == SLANG_DOUBLE_TYPE) xf = ((FF3_Type) fptr)(p[0], p[1], p[2]);
++#endif
++ else ret = ((LF3_Type) fptr)(p[0], p[1], p[2]);
++ break;
++
++ case 4:
++ if (type == SLANG_VOID_TYPE) ((VF4_Type) fptr)(p[0], p[1], p[2], p[3]);
++#if SLANG_HAS_FLOAT
++ else if (type == SLANG_DOUBLE_TYPE) xf = ((FF4_Type) fptr)(p[0], p[1], p[2], p[3]);
++#endif
++ else ret = ((LF4_Type) fptr)(p[0], p[1], p[2], p[3]);
++ break;
++
++ case 5:
++ if (type == SLANG_VOID_TYPE) ((VF5_Type) fptr)(p[0], p[1], p[2], p[3], p[4]);
++#if SLANG_HAS_FLOAT
++ else if (type == SLANG_DOUBLE_TYPE) xf = ((FF5_Type) fptr)(p[0], p[1], p[2], p[3], p[4]);
++#endif
++ else ret = ((LF5_Type) fptr)(p[0], p[1], p[2], p[3], p[4]);
++ break;
++
++ case 6:
++ if (type == SLANG_VOID_TYPE) ((VF6_Type) fptr)(p[0], p[1], p[2], p[3], p[4], p[5]);
++#if SLANG_HAS_FLOAT
++ else if (type == SLANG_DOUBLE_TYPE) xf = ((FF6_Type) fptr)(p[0], p[1], p[2], p[3], p[4], p[5]);
++#endif
++ else ret = ((LF6_Type) fptr)(p[0], p[1], p[2], p[3], p[4], p[5]);
++ break;
++
++ case 7:
++ if (type == SLANG_VOID_TYPE) ((VF7_Type) fptr)(p[0], p[1], p[2], p[3], p[4], p[5], p[6]);
++#if SLANG_HAS_FLOAT
++ else if (type == SLANG_DOUBLE_TYPE) xf = ((FF7_Type) fptr)(p[0], p[1], p[2], p[3], p[4], p[5], p[6]);
++#endif
++ else ret = ((LF7_Type) fptr)(p[0], p[1], p[2], p[3], p[4], p[5], p[6]);
++ break;
++ }
++
++ switch (type)
++ {
++ case SLANG_VOID_TYPE:
++ break;
++
++#if SLANG_HAS_FLOAT
++ case SLANG_DOUBLE_TYPE:
++ (void) SLang_push_double (xf);
++ break;
++#endif
++ case SLANG_UINT_TYPE:
++ case SLANG_INT_TYPE: (void) SLclass_push_int_obj (type, (int) ret);
++ break;
++
++ case SLANG_CHAR_TYPE:
++ case SLANG_UCHAR_TYPE: (void) SLclass_push_char_obj (type, (char) ret);
++ break;
++
++ case SLANG_SHORT_TYPE:
++ case SLANG_USHORT_TYPE: (void) SLclass_push_short_obj (type, (short) ret);
++ break;
++
++ case SLANG_LONG_TYPE:
++ case SLANG_ULONG_TYPE: (void) SLclass_push_long_obj (type, ret);
++ break;
++
++ case SLANG_STRING_TYPE:
++ if (NULL == (char *)ret)
++ {
++ if (SLang_Error == 0) SLang_Error = SL_INTRINSIC_ERROR;
++ }
++ else (void) SLang_push_string ((char *)ret);
++ break;
++
++ default:
++ SLang_verror (SL_NOT_IMPLEMENTED,
++ &quot;Support for intrinsic functions returning %s is not provided&quot;,
++ SLclass_get_datatype_name (type));
++ }
++
++ if (stk_depth &gt;= 0)
++ {
++ stk_depth = _SLstack_depth () - stk_depth;
++
++ trace_dump (&quot;&lt;&lt;%s (returning %d values)\n&quot;,
++ objf-&gt;name,
++ _SLStack_Pointer - stk_depth,
++ stk_depth,
++ 1);
++ }
++
++ free_and_return:
++ while (i &lt; argc)
++ {
++ SLang_free_object (objs + i);
++ i++;
++ }
++
++ return _SL_decrement_frame_pointer ();
++}
++
++static int inner_interp(register SLBlock_Type *);
++
++/* Switch_Obj_Ptr points to the NEXT available free switch object */
++static SLang_Object_Type Switch_Objects[SLANG_MAX_NESTED_SWITCH];
++static SLang_Object_Type *Switch_Obj_Ptr = Switch_Objects;
++static SLang_Object_Type *Switch_Obj_Max = Switch_Objects + SLANG_MAX_NESTED_SWITCH;
++
++static void
++lang_do_loops (unsigned char stype, SLBlock_Type *block, unsigned int num_blocks)
++{
++ int i, ctrl;
++ int first, last;
++ SLBlock_Type *blks[4];
++ char *loop_name;
++ SLang_Foreach_Context_Type *foreach_context;
++ SLang_Class_Type *cl;
++ int type;
++ unsigned int j;
++
++ j = 0;
++ for (i = 0; i &lt; (int) num_blocks; i++)
++ {
++ if (block[i].bc_main_type != _SLANG_BC_BLOCK)
++ {
++ if (block[i].bc_main_type == _SLANG_BC_LINE_NUM)
++ continue;
++
++ SLang_verror (SL_SYNTAX_ERROR, &quot;Bytecode is not a looping block&quot;);
++ return;
++ }
++ blks[j] = block[i].b.blk;
++ j++;
++ }
++
++ num_blocks = j;
++ block = blks[0];
++
++ switch (stype)
++ {
++ case _SLANG_BCST_FOREACH:
++ loop_name = &quot;foreach&quot;;
++ if (num_blocks != 1)
++ goto wrong_num_blocks_error;
++
++ /* We should find Next_Function_Num_Args + 1 items on the stack.
++ * The first Next_Function_Num_Args items represent the arguments to
++ * to USING. The last item (deepest in stack) is the object to loop
++ * over. So, roll the stack up and grab it.
++ */
++ if ((-1 == SLroll_stack (-(Next_Function_Num_Args + 1)))
++ || (-1 == (type = SLang_peek_at_stack ())))
++ goto return_error;
++
++ cl = _SLclass_get_class ((unsigned char) type);
++ if ((cl-&gt;cl_foreach == NULL)
++ || (cl-&gt;cl_foreach_open == NULL)
++ || (cl-&gt;cl_foreach_close == NULL))
++ {
++ SLang_verror (SL_NOT_IMPLEMENTED, &quot;%s does not permit foreach&quot;, cl-&gt;cl_name);
++ SLdo_pop_n (Next_Function_Num_Args + 1);
++ goto return_error;
++ }
++
++ if (NULL == (foreach_context = (*cl-&gt;cl_foreach_open) ((unsigned char)type, Next_Function_Num_Args)))
++ goto return_error;
++
++ while (1)
++ {
++ int status;
++
++ if (SLang_Error)
++ {
++ (*cl-&gt;cl_foreach_close) ((unsigned char) type, foreach_context);
++ goto return_error;
++ }
++
++ status = (*cl-&gt;cl_foreach) ((unsigned char) type, foreach_context);
++ if (status &lt;= 0)
++ {
++ if (status == 0)
++ break;
++
++ (*cl-&gt;cl_foreach_close) ((unsigned char) type, foreach_context);
++ goto return_error;
++ }
++
++ inner_interp (block);
++ if (Lang_Break) break;
++ Lang_Break_Condition = /* Lang_Continue = */ 0;
++ }
++ (*cl-&gt;cl_foreach_close) ((unsigned char) type, foreach_context);
++ break;
++
++ case _SLANG_BCST_WHILE:
++ loop_name = &quot;while&quot;;
++
++ if (num_blocks != 2)
++ goto wrong_num_blocks_error;
++
++ type = blks[1]-&gt;bc_main_type;
++ while (1)
++ {
++ if (SLang_Error)
++ goto return_error;
++
++ inner_interp (block);
++ if (Lang_Break) break;
++
++ if (-1 == pop_ctrl_integer (&amp;ctrl))
++ goto return_error;
++
++ if (ctrl == 0) break;
++
++ if (type)
++ {
++ inner_interp (blks[1]);
++ if (Lang_Break) break;
++ Lang_Break_Condition = /* Lang_Continue = */ 0;
++ }
++ }
++ break;
++
++ case _SLANG_BCST_DOWHILE:
++ loop_name = &quot;do...while&quot;;
++
++ if (num_blocks != 2)
++ goto wrong_num_blocks_error;
++
++ while (1)
++ {
++ if (SLang_Error)
++ goto return_error;
++
++ Lang_Break_Condition = /* Lang_Continue = */ 0;
++ inner_interp (block);
++ if (Lang_Break) break;
++ Lang_Break_Condition = /* Lang_Continue = */ 0;
++ inner_interp (blks[1]);
++ if (-1 == pop_ctrl_integer (&amp;ctrl))
++ goto return_error;
++
++ if (ctrl == 0) break;
++ }
++ break;
++
++ case _SLANG_BCST_CFOR:
++ loop_name = &quot;for&quot;;
++
++ /* we need 4 blocks: first 3 control, the last is code */
++ if (num_blocks != 4) goto wrong_num_blocks_error;
++
++ inner_interp (block);
++ while (1)
++ {
++ if (SLang_Error)
++ goto return_error;
++
++ inner_interp(blks[1]); /* test */
++ if (-1 == pop_ctrl_integer (&amp;ctrl))
++ goto return_error;
++
++ if (ctrl == 0) break;
++ inner_interp(blks[3]); /* code */
++ if (Lang_Break) break;
++ inner_interp(blks[2]); /* bump */
++ Lang_Break_Condition = /* Lang_Continue = */ 0;
++ }
++ break;
++
++ case _SLANG_BCST_FOR:
++ loop_name = &quot;_for&quot;;
++
++ if (num_blocks != 1)
++ goto wrong_num_blocks_error;
++
++ /* 3 elements: first, last, step */
++ if ((-1 == SLang_pop_integer (&amp;ctrl))
++ || (-1 == SLang_pop_integer (&amp;last))
++ || (-1 == SLang_pop_integer (&amp;first)))
++ goto return_error;
++
++ i = first;
++ while (1)
++ {
++ /* It is ugly to have this test here but I do not know of a
++ * simple way to do this without using two while loops.
++ */
++ if (ctrl &gt;= 0)
++ {
++ if (i &gt; last) break;
++ }
++ else if (i &lt; last) break;
++
++ if (SLang_Error) goto return_error;
++
++ SLclass_push_int_obj (SLANG_INT_TYPE, i);
++ inner_interp (block);
++ if (Lang_Break) break;
++ Lang_Break_Condition = /* Lang_Continue = */ 0;
++
++ i += ctrl;
++ }
++ break;
++
++ case _SLANG_BCST_LOOP:
++ loop_name = &quot;loop&quot;;
++ if (num_blocks != 1)
++ goto wrong_num_blocks_error;
++
++ if (-1 == SLang_pop_integer (&amp;ctrl))
++ goto return_error;
++ while (ctrl &gt; 0)
++ {
++ ctrl--;
++
++ if (SLang_Error)
++ goto return_error;
++
++ inner_interp (block);
++ if (Lang_Break) break;
++ Lang_Break_Condition = /* Lang_Continue = */ 0;
++ }
++ break;
++
++ case _SLANG_BCST_FOREVER:
++ loop_name = &quot;forever&quot;;
++
++ if (num_blocks != 1)
++ goto wrong_num_blocks_error;
++
++ while (1)
++ {
++ if (SLang_Error)
++ goto return_error;
++
++ inner_interp (block);
++ if (Lang_Break) break;
++ Lang_Break_Condition = /* Lang_Continue = */ 0;
++ }
++ break;
++
++ default: SLang_verror(SL_INTERNAL_ERROR, &quot;Unknown loop type&quot;);
++ return;
++ }
++ Lang_Break = /* Lang_Continue = */ 0;
++ Lang_Break_Condition = Lang_Return;
++ return;
++
++ wrong_num_blocks_error:
++ SLang_verror (SL_SYNTAX_ERROR, &quot;Wrong number of blocks for '%s' construct&quot;, loop_name);
++
++ /* drop */
++ return_error:
++ do_traceback (loop_name, 0, NULL);
++}
++
++static void lang_do_and_orelse (unsigned char stype, SLBlock_Type *addr, SLBlock_Type *addr_max)
++{
++ int test = 0;
++ int is_or;
++
++ is_or = (stype == _SLANG_BCST_ORELSE);
++
++ while (addr &lt;= addr_max)
++ {
++ if (addr-&gt;bc_main_type == _SLANG_BC_LINE_NUM)
++ {
++ addr++;
++ continue;
++ }
++
++ inner_interp (addr-&gt;b.blk);
++ if (SLang_Error
++ || Lang_Break_Condition
++ || (-1 == pop_ctrl_integer (&amp;test)))
++ return;
++
++ if (is_or == (test != 0))
++ break;
++
++ /* if (((stype == _SLANG_BCST_ANDELSE) &amp;&amp; (test == 0))
++ * || ((stype == _SLANG_BCST_ORELSE) &amp;&amp; test))
++ * break;
++ */
++
++ addr++;
++ }
++ SLclass_push_int_obj (SLANG_INT_TYPE, test);
++}
++
++static void do_else_if (SLBlock_Type *zero_block, SLBlock_Type *non_zero_block)
++{
++ int test;
++
++ if (-1 == pop_ctrl_integer (&amp;test))
++ return;
++
++ if (test == 0)
++ non_zero_block = zero_block;
++
++ if (non_zero_block != NULL)
++ inner_interp (non_zero_block-&gt;b.blk);
++}
++
++int _SLang_trace_fun (char *f)
++{
++ if (NULL == (f = SLang_create_slstring (f)))
++ return -1;
++
++ SLang_free_slstring (Trace_Function);
++ Trace_Function = f;
++ _SLang_Trace = 1;
++ return 0;
++}
++
++int _SLdump_objects (char *prefix, SLang_Object_Type *x, unsigned int n, int dir)
++{
++ char *s;
++ SLang_Class_Type *cl;
++
++ while (n)
++ {
++ cl = _SLclass_get_class (x-&gt;data_type);
++
++ if (NULL == (s = _SLstringize_object (x)))
++ s = &quot;??&quot;;
++
++ call_dump_routine (&quot;%s[%s]:%s\n&quot;, prefix, cl-&gt;cl_name, s);
++
++ SLang_free_slstring (s);
++
++ x += dir;
++ n--;
++ }
++ return 0;
++}
++
++static SLBlock_Type *Exit_Block_Ptr;
++static SLBlock_Type *Global_User_Block[5];
++static SLBlock_Type **User_Block_Ptr = Global_User_Block;
++char *_SLang_Current_Function_Name = NULL;
++
++static int execute_slang_fun (_SLang_Function_Type *fun)
++{
++ register unsigned int i;
++ register SLang_Object_Type *frame, *lvf;
++ register unsigned int n_locals;
++ _SLBlock_Header_Type *header;
++ /* SLBlock_Type *val; */
++ SLBlock_Type *exit_block_save;
++ SLBlock_Type **user_block_save;
++ SLBlock_Type *user_blocks[5];
++ char *save_fname;
++
++ exit_block_save = Exit_Block_Ptr;
++ user_block_save = User_Block_Ptr;
++ User_Block_Ptr = user_blocks;
++ *(user_blocks) = NULL;
++ *(user_blocks + 1) = NULL;
++ *(user_blocks + 2) = NULL;
++ *(user_blocks + 3) = NULL;
++ *(user_blocks + 4) = NULL;
++
++ Exit_Block_Ptr = NULL;
++
++ save_fname = _SLang_Current_Function_Name;
++ _SLang_Current_Function_Name = fun-&gt;name;
++
++ _SL_increment_frame_pointer ();
++
++ /* need loaded? */
++ if (fun-&gt;nlocals == AUTOLOAD_NUM_LOCALS)
++ {
++ header = NULL;
++ if (-1 == SLang_load_file(fun-&gt;v.autoload_filename))
++ goto the_return;
++
++ if (fun-&gt;nlocals == AUTOLOAD_NUM_LOCALS)
++ {
++ SLang_verror (SL_UNDEFINED_NAME, &quot;%s: Function did not autoload&quot;,
++ _SLang_Current_Function_Name);
++ goto the_return;
++ }
++ }
++
++ n_locals = fun-&gt;nlocals;
++
++ /* let the error propagate through since it will do no harm
++ and allow us to restore stack. */
++
++ /* set new stack frame */
++ lvf = frame = Local_Variable_Frame;
++ i = n_locals;
++ if ((lvf + i) &gt; Local_Variable_Stack + SLANG_MAX_LOCAL_STACK)
++ {
++ SLang_verror(SL_STACK_OVERFLOW, &quot;%s: Local Variable Stack Overflow&quot;,
++ _SLang_Current_Function_Name);
++ goto the_return;
++ }
++
++ /* Make sure we do not allow this header to get destroyed by something
++ * like: define crash () { eval (&quot;define crash ();&quot;) }
++ */
++ header = fun-&gt;v.header;
++ header-&gt;num_refs++;
++
++ while (i--)
++ {
++ lvf++;
++ lvf-&gt;data_type = SLANG_UNDEFINED_TYPE;
++ }
++ Local_Variable_Frame = lvf;
++
++ /* read values of function arguments */
++ i = fun-&gt;nargs;
++ while (i &gt; 0)
++ {
++ i--;
++ (void) SLang_pop (Local_Variable_Frame - i);
++ }
++
++ if (SLang_Enter_Function != NULL) (*SLang_Enter_Function)(_SLang_Current_Function_Name);
++
++ if (_SLang_Trace)
++ {
++ int stack_depth;
++
++ stack_depth = _SLstack_depth ();
++
++ if ((Trace_Function != NULL)
++ &amp;&amp; (0 == strcmp (Trace_Function, _SLang_Current_Function_Name))
++ &amp;&amp; (Trace_Mode == 0))
++ Trace_Mode = 1;
++
++ if (Trace_Mode)
++ {
++ /* The local variable frame grows backwards */
++ trace_dump (&quot;&gt;&gt;%s (%d args)\n&quot;,
++ _SLang_Current_Function_Name,
++ Local_Variable_Frame,
++ (int) fun-&gt;nargs,
++ -1);
++ Trace_Mode++;
++ }
++
++ inner_interp (header-&gt;body);
++ Lang_Break_Condition = Lang_Return = Lang_Break = 0;
++ if (Exit_Block_Ptr != NULL) inner_interp(Exit_Block_Ptr);
++
++ if (Trace_Mode)
++ {
++ Trace_Mode--;
++ stack_depth = _SLstack_depth () - stack_depth;
++
++ trace_dump (&quot;&lt;&lt;%s (returning %d values)\n&quot;,
++ _SLang_Current_Function_Name,
++ _SLStack_Pointer - stack_depth,
++ stack_depth,
++ 1);
++
++ if (Trace_Mode == 1)
++ Trace_Mode = 0;
++ }
++ }
++ else
++ {
++ inner_interp (header-&gt;body);
++ Lang_Break_Condition = Lang_Return = Lang_Break = 0;
++ if (Exit_Block_Ptr != NULL) inner_interp(Exit_Block_Ptr);
++ }
++
++ if (SLang_Exit_Function != NULL) (*SLang_Exit_Function)(_SLang_Current_Function_Name);
++
++ if (SLang_Error)
++ do_traceback(fun-&gt;name, n_locals,
++#if _SLANG_HAS_DEBUG_CODE
++ fun-&gt;file
++#else
++ NULL
++#endif
++ );
++
++ /* free local variables.... */
++ lvf = Local_Variable_Frame;
++ while (lvf &gt; frame)
++ {
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [lvf-&gt;data_type])
++#endif
++ SLang_free_object (lvf);
++ lvf--;
++ }
++ Local_Variable_Frame = lvf;
++
++ if (header-&gt;num_refs == 1)
++ free_function_header (header);
++ else
++ header-&gt;num_refs--;
++
++ the_return:
++
++ Lang_Break_Condition = Lang_Return = Lang_Break = 0;
++ Exit_Block_Ptr = exit_block_save;
++ User_Block_Ptr = user_block_save;
++ _SLang_Current_Function_Name = save_fname;
++ _SL_decrement_frame_pointer ();
++
++ if (SLang_Error)
++ return -1;
++
++ return 0;
++}
++
++static void do_traceback (char *name, unsigned int locals, char *file)
++{
++ char *s;
++ unsigned int i;
++ SLang_Object_Type *objp;
++ unsigned short stype;
++
++ /* FIXME: Priority=low
++ * I need to make this configurable!!! That is, let the
++ * application decide whether or not a usage error should result in a
++ * traceback.
++ */
++ if (SLang_Error == SL_USAGE_ERROR)
++ return;
++
++ if (SLang_Traceback == 0)
++ return;
++
++ call_dump_routine (&quot;S-Lang Traceback: %s\n&quot;, name);
++ if (SLang_Traceback &lt; 0)
++ return;
++
++ if (file != NULL)
++ call_dump_routine (&quot;File: %s\n&quot;, file);
++
++ if (locals == 0)
++ return;
++
++ call_dump_routine (&quot; Local Variables:\n&quot;);
++
++ for (i = 0; i &lt; locals; i++)
++ {
++ SLang_Class_Type *cl;
++ char *class_name;
++
++ objp = Local_Variable_Frame - i;
++ stype = objp-&gt;data_type;
++
++ s = _SLstringize_object (objp);
++ cl = _SLclass_get_class (stype);
++ class_name = cl-&gt;cl_name;
++
++ call_dump_routine (&quot;\t$%d: Type: %s,\tValue:\t&quot;, i, class_name);
++
++ if (s == NULL) call_dump_routine(&quot;??\n&quot;);
++ else
++ {
++ char *q = &quot;&quot;;
++#ifndef HAVE_VSNPRINTF
++ char buf[256];
++ if (strlen (s) &gt;= sizeof (buf))
++ {
++ strncpy (buf, s, sizeof(buf));
++ s = buf;
++ s[sizeof(buf) - 1] = 0;
++ }
++#endif
++ if (SLANG_STRING_TYPE == stype) q = &quot;\&quot;&quot;;
++ call_dump_routine (&quot;%s%s%s\n&quot;, q, s, q);
++ }
++ }
++}
++
++static void do_app_unary (SLang_App_Unary_Type *nt)
++{
++ if (-1 == do_unary (nt-&gt;unary_op, nt-&gt;name_type))
++ do_traceback (nt-&gt;name, 0, NULL);
++}
++
++static int inner_interp_nametype (SLang_Name_Type *nt)
++{
++ SLBlock_Type bc_blks[2];
++
++ bc_blks[0].b.nt_blk = nt;
++ bc_blks[0].bc_main_type = nt-&gt;name_type;
++ bc_blks[1].bc_main_type = 0;
++ return inner_interp(bc_blks);
++}
++
++int _SLang_dereference_ref (SLang_Ref_Type *ref)
++{
++ if (ref == NULL)
++ {
++ SLang_Error = SL_INTERNAL_ERROR;
++ return -1;
++ }
++
++ if (ref-&gt;is_global == 0)
++ {
++ SLang_Object_Type *obj = ref-&gt;v.local_obj;
++ if (obj &gt; Local_Variable_Frame)
++ {
++ SLang_verror (SL_UNDEFINED_NAME, &quot;Local variable deref is out of scope&quot;);
++ return -1;
++ }
++ return _SLpush_slang_obj (ref-&gt;v.local_obj);
++ }
++
++ (void) inner_interp_nametype (ref-&gt;v.nt);
++ return 0;
++}
++
++int _SLang_is_ref_initialized (SLang_Ref_Type *ref)
++{
++ unsigned char type;
++
++ if (ref == NULL)
++ {
++ SLang_Error = SL_INTERNAL_ERROR;
++ return -1;
++ }
++
++ if (ref-&gt;is_global == 0)
++ {
++ SLang_Object_Type *obj = ref-&gt;v.local_obj;
++ if (obj &gt; Local_Variable_Frame)
++ {
++ SLang_verror (SL_UNDEFINED_NAME, &quot;Local variable deref is out of scope&quot;);
++ return -1;
++ }
++ type = ref-&gt;v.local_obj-&gt;data_type;
++ }
++ else
++ {
++ SLang_Name_Type *nt = ref-&gt;v.nt;
++ if ((nt-&gt;name_type != SLANG_GVARIABLE)
++ &amp;&amp; (nt-&gt;name_type != SLANG_PVARIABLE))
++ return 1;
++ type = ((SLang_Global_Var_Type *)nt)-&gt;obj.data_type;
++ }
++ return type != SLANG_UNDEFINED_TYPE;
++}
++
++int _SLang_uninitialize_ref (SLang_Ref_Type *ref)
++{
++ SLang_Object_Type *obj;
++
++ if (ref == NULL)
++ {
++ SLang_Error = SL_INTERNAL_ERROR;
++ return -1;
++ }
++
++ if (ref-&gt;is_global == 0)
++ {
++ obj = ref-&gt;v.local_obj;
++ if (obj &gt; Local_Variable_Frame)
++ {
++ SLang_verror (SL_UNDEFINED_NAME, &quot;Local variable deref is out of scope&quot;);
++ return -1;
++ }
++ obj = ref-&gt;v.local_obj;
++ }
++ else
++ {
++ SLang_Name_Type *nt = ref-&gt;v.nt;
++ if ((nt-&gt;name_type != SLANG_GVARIABLE)
++ &amp;&amp; (nt-&gt;name_type != SLANG_PVARIABLE))
++ return -1;
++ obj = &amp;((SLang_Global_Var_Type *)nt)-&gt;obj;
++ }
++ SLang_free_object (obj);
++ obj-&gt;data_type = SLANG_UNDEFINED_TYPE;
++ obj-&gt;v.ptr_val = NULL;
++ return 0;
++}
++
++void (*SLang_Interrupt)(void);
++static int Last_Error;
++void (*SLang_User_Clear_Error)(void);
++void _SLang_clear_error (void)
++{
++ if (Last_Error &lt;= 0)
++ {
++ Last_Error = 0;
++ return;
++ }
++ Last_Error--;
++ if (SLang_User_Clear_Error != NULL) (*SLang_User_Clear_Error)();
++}
++
++int _SLpush_slang_obj (SLang_Object_Type *obj)
++{
++ unsigned char subtype;
++ SLang_Class_Type *cl;
++
++ if (obj == NULL) return SLang_push_null ();
++
++ subtype = obj-&gt;data_type;
++
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ if (SLANG_CLASS_TYPE_SCALAR == _SLclass_Class_Type[subtype])
++ return SLang_push (obj);
++#endif
++
++ cl = _SLclass_get_class (subtype);
++ return (*cl-&gt;cl_push) (subtype, (VOID_STAR) &amp;obj-&gt;v);
++}
++
++_INLINE_
++static int push_local_variable (int i)
++{
++ SLang_Class_Type *cl;
++ SLang_Object_Type *obj;
++ unsigned char subtype;
++
++ obj = Local_Variable_Frame - i;
++ subtype = obj-&gt;data_type;
++
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ if (SLANG_CLASS_TYPE_SCALAR == _SLclass_Class_Type[subtype])
++ return SLang_push (obj);
++ if (subtype == SLANG_STRING_TYPE)
++ return _SLang_dup_and_push_slstring (obj-&gt;v.s_val);
++#endif
++
++ cl = _SLclass_get_class (subtype);
++ return (*cl-&gt;cl_push) (subtype, (VOID_STAR) &amp;obj-&gt;v);
++}
++
++static int push_intrinsic_variable (SLang_Intrin_Var_Type *ivar)
++{
++ SLang_Class_Type *cl;
++ unsigned char stype;
++
++ stype = ivar-&gt;type;
++ cl = _SLclass_get_class (stype);
++
++ if (-1 == (*cl-&gt;cl_push_intrinsic) (stype, ivar-&gt;addr))
++ {
++ do_name_type_error ((SLang_Name_Type *) ivar);
++ return -1;
++ }
++ return 0;
++}
++
++static int dereference_object (void)
++{
++ SLang_Object_Type obj;
++ SLang_Class_Type *cl;
++ unsigned char type;
++ int ret;
++
++ if (-1 == SLang_pop (&amp;obj))
++ return -1;
++
++ type = obj.data_type;
++
++ cl = _SLclass_get_class (type);
++ ret = (*cl-&gt;cl_dereference)(type, (VOID_STAR) &amp;obj.v);
++
++ SLang_free_object (&amp;obj);
++ return ret;
++}
++
++static int case_function (void)
++{
++ unsigned char type;
++ SLang_Object_Type obj;
++ SLang_Object_Type *swobjptr;
++
++ swobjptr = Switch_Obj_Ptr - 1;
++
++ if ((swobjptr &lt; Switch_Objects)
++ || (0 == (type = swobjptr-&gt;data_type)))
++ {
++ SLang_verror (SL_SYNTAX_ERROR, &quot;Misplaced 'case' keyword&quot;);
++ return -1;
++ }
++
++ if (-1 == SLang_pop (&amp;obj))
++ return -1;
++
++ if (obj.data_type != type)
++ {
++ SLang_Class_Type *a_cl, *b_cl;
++
++ a_cl = _SLclass_get_class (obj.data_type);
++ b_cl = _SLclass_get_class (type);
++
++ if (NULL == _SLclass_get_binary_fun (SLANG_EQ, a_cl, b_cl, &amp;a_cl, 0))
++ {
++ (void) SLclass_push_int_obj (SLANG_INT_TYPE, 0);
++ SLang_free_object (&amp;obj);
++ return 0;
++ }
++ }
++
++ (void) do_binary_ab (SLANG_EQ, swobjptr, &amp;obj);
++ SLang_free_object (&amp;obj);
++ return 0;
++}
++
++static void tmp_variable_function (SLBlock_Type *addr)
++{
++ SLang_Object_Type *obj;
++
++ switch (addr-&gt;bc_sub_type)
++ {
++ case SLANG_GVARIABLE:
++ case SLANG_PVARIABLE:
++ obj = &amp;addr-&gt;b.nt_gvar_blk-&gt;obj;
++ break;
++
++ case SLANG_LVARIABLE:
++ obj = Local_Variable_Frame - addr-&gt;b.i_blk;
++ break;
++
++ default:
++ SLang_Error = SL_INTERNAL_ERROR;
++ return;
++ }
++
++ /* There is no need to go through higher level routines since we are
++ * not creating or destroying extra copies.
++ */
++ if (-1 == SLang_push (obj))
++ return;
++
++ obj-&gt;data_type = SLANG_UNDEFINED_TYPE;
++ obj-&gt;v.ptr_val = NULL;
++}
++
++
++static int
++do_inner_interp_error (SLBlock_Type *err_block,
++ SLBlock_Type *addr_start,
++ SLBlock_Type *addr)
++{
++ int save_err, slerr;
++
++ /* Someday I can use the these variable to provide extra information
++ * about what went wrong.
++ */
++ (void) addr_start;
++ (void) addr;
++
++ if (err_block == NULL)
++ goto return_error;
++
++ if (SLang_Error &lt; 0) /* errors less than 0 are severe */
++ goto return_error;
++
++ save_err = Last_Error++;
++ slerr = SLang_Error;
++ SLang_Error = 0;
++ inner_interp (err_block-&gt;b.blk);
++
++ if (Last_Error &lt;= save_err)
++ {
++ /* Caught error and cleared it */
++ Last_Error = save_err;
++ if ((Lang_Break_Condition == 0)
++ /* An error may have cleared the error and then caused the
++ * function to return. We will allow that but let's not allow
++ * 'break' nor 'continue' statements until later.
++ */
++ || Lang_Return)
++ return 0;
++
++ /* drop--- either a break or continue was called */
++ }
++
++ Last_Error = save_err;
++ SLang_Error = slerr;
++
++ return_error:
++#if _SLANG_HAS_DEBUG_CODE
++ while (addr &gt;= addr_start)
++ {
++ if (addr-&gt;bc_main_type == _SLANG_BC_LINE_NUM)
++ {
++ char buf[256];
++ sprintf (buf, &quot;(Error occurred on line %lu)&quot;, addr-&gt;b.l_blk);
++ do_traceback (buf, 0, NULL);
++ break;
++ }
++ /* Special hack for 16 bit systems to prevent pointer wrapping. */
++#if defined(__16_BIT_SYSTEM__)
++ if (addr == addr_start)
++ break;
++#endif
++ addr--;
++ }
++#endif
++ return -1;
++}
++
++
++#define GATHER_STATISTICS 0
++#if GATHER_STATISTICS
++static unsigned int Bytecodes[0xFFFF];
++
++static void print_stats (void)
++{
++ unsigned int i;
++ unsigned long total;
++ FILE *fp = fopen (&quot;stats.txt&quot;, &quot;w&quot;);
++ if (fp == NULL)
++ return;
++
++ total = 0;
++ for (i = 0; i &lt; 0xFFFF; i++)
++ total += Bytecodes[i];
++
++ if (total == 0)
++ total = 1;
++
++ for (i = 0; i &lt; 0xFFFF; i++)
++ {
++ if (Bytecodes[i])
++ fprintf (fp, &quot;0x%04X %9u %e\n&quot;, i, Bytecodes[i], Bytecodes[i]/(double) total);
++ }
++ fclose (fp);
++}
++
++static void add_to_statistics (SLBlock_Type *b)
++{
++ unsigned short x, y;
++
++ x = b-&gt;bc_main_type;
++ if (x == 0)
++ {
++ Bytecodes[0] += 1;
++ return;
++ }
++ b++;
++ y = b-&gt;bc_main_type;
++
++ Bytecodes[(x &lt;&lt; 8) | y] += 1;
++}
++
++#endif
++
++/* inner interpreter */
++/* The return value from this function is only meaningful when it is used
++ * to process blocks for the switch statement. If it returns 0, the calling
++ * routine should pass the next block to it. Otherwise it will
++ * return non-zero, with or without error.
++ */
++static int inner_interp (SLBlock_Type *addr_start)
++{
++ SLBlock_Type *block, *err_block, *addr;
++#if GATHER_STATISTICS
++ static int inited = 0;
++
++ if (inited == 0)
++ {
++ (void) SLang_add_cleanup_function (print_stats);
++ inited = 1;
++ }
++#endif
++
++ /* for systems that have no real interrupt facility (e.g. go32 on dos) */
++ if (SLang_Interrupt != NULL) (*SLang_Interrupt)();
++
++ block = err_block = NULL;
++ addr = addr_start;
++
++#if GATHER_STATISTICS
++ add_to_statistics (addr);
++#endif
++ while (1)
++ {
++ switch (addr-&gt;bc_main_type)
++ {
++ case 0:
++ return 1;
++ case _SLANG_BC_LVARIABLE:
++ push_local_variable (addr-&gt;b.i_blk);
++ break;
++ case _SLANG_BC_GVARIABLE:
++ if (-1 == _SLpush_slang_obj (&amp;addr-&gt;b.nt_gvar_blk-&gt;obj))
++ do_name_type_error (addr-&gt;b.nt_blk);
++ break;
++
++ case _SLANG_BC_IVARIABLE:
++ case _SLANG_BC_RVARIABLE:
++ push_intrinsic_variable (addr-&gt;b.nt_ivar_blk);
++ break;
++
++ case _SLANG_BC_INTRINSIC:
++ execute_intrinsic_fun (addr-&gt;b.nt_ifun_blk);
++ if (SLang_Error)
++ do_traceback(addr-&gt;b.nt_ifun_blk-&gt;name, 0, NULL);
++ break;
++
++ case _SLANG_BC_FUNCTION:
++ execute_slang_fun (addr-&gt;b.nt_fun_blk);
++ if (Lang_Break_Condition) goto handle_break_condition;
++ break;
++
++ case _SLANG_BC_MATH_UNARY:
++ case _SLANG_BC_APP_UNARY:
++ /* Make sure we treat these like function calls since the
++ * parser took sin(x) to be a function call.
++ */
++ if (0 == _SL_increment_frame_pointer ())
++ {
++ do_app_unary (addr-&gt;b.nt_unary_blk);
++ (void) _SL_decrement_frame_pointer ();
++ }
++ break;
++
++ case _SLANG_BC_ICONST:
++ SLclass_push_int_obj (SLANG_INT_TYPE, addr-&gt;b.iconst_blk-&gt;i);
++ break;
++
++#if SLANG_HAS_FLOAT
++ case _SLANG_BC_DCONST:
++ SLang_push_double (addr-&gt;b.dconst_blk-&gt;d);
++ break;
++#endif
++
++ case _SLANG_BC_PVARIABLE:
++ if (-1 == _SLpush_slang_obj (&amp;addr-&gt;b.nt_gvar_blk-&gt;obj))
++ do_name_type_error (addr-&gt;b.nt_blk);
++ break;
++
++ case _SLANG_BC_PFUNCTION:
++ execute_slang_fun (addr-&gt;b.nt_fun_blk);
++ if (Lang_Break_Condition) goto handle_break_condition;
++ break;
++
++ case _SLANG_BC_BINARY:
++ do_binary (addr-&gt;b.i_blk);
++ break;
++
++ case _SLANG_BC_LITERAL:
++#if !_SLANG_OPTIMIZE_FOR_SPEED
++ case _SLANG_BC_LITERAL_INT:
++ case _SLANG_BC_LITERAL_STR:
++#endif
++ {
++ SLang_Class_Type *cl = _SLclass_get_class (addr-&gt;bc_sub_type);
++ (*cl-&gt;cl_push_literal) (addr-&gt;bc_sub_type, (VOID_STAR) &amp;addr-&gt;b.ptr_blk);
++ }
++ break;
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ case _SLANG_BC_LITERAL_INT:
++ SLclass_push_int_obj (addr-&gt;bc_sub_type, (int) addr-&gt;b.l_blk);
++ break;
++
++ case _SLANG_BC_LITERAL_STR:
++ _SLang_dup_and_push_slstring (addr-&gt;b.s_blk);
++ break;
++#endif
++ case _SLANG_BC_BLOCK:
++ switch (addr-&gt;bc_sub_type)
++ {
++ case _SLANG_BCST_ERROR_BLOCK:
++ err_block = addr;
++ break;
++
++ case _SLANG_BCST_EXIT_BLOCK:
++ Exit_Block_Ptr = addr-&gt;b.blk;
++ break;
++
++ case _SLANG_BCST_USER_BLOCK0:
++ case _SLANG_BCST_USER_BLOCK1:
++ case _SLANG_BCST_USER_BLOCK2:
++ case _SLANG_BCST_USER_BLOCK3:
++ case _SLANG_BCST_USER_BLOCK4:
++ User_Block_Ptr[addr-&gt;bc_sub_type - _SLANG_BCST_USER_BLOCK0] = addr-&gt;b.blk;
++ break;
++
++ case _SLANG_BCST_LOOP:
++ case _SLANG_BCST_WHILE:
++ case _SLANG_BCST_FOR:
++ case _SLANG_BCST_FOREVER:
++ case _SLANG_BCST_CFOR:
++ case _SLANG_BCST_DOWHILE:
++ case _SLANG_BCST_FOREACH:
++ if (block == NULL) block = addr;
++ lang_do_loops(addr-&gt;bc_sub_type, block, 1 + (unsigned int) (addr - block));
++ block = NULL;
++ break;
++
++ case _SLANG_BCST_IFNOT:
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ {
++ int i;
++
++ if ((0 == pop_ctrl_integer (&amp;i)) &amp;&amp; (i == 0))
++ inner_interp (addr-&gt;b.blk);
++ }
++#else
++ do_else_if (addr, NULL);
++#endif
++ break;
++
++ case _SLANG_BCST_IF:
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ {
++ int i;
++
++ if ((0 == pop_ctrl_integer (&amp;i)) &amp;&amp; i)
++ inner_interp (addr-&gt;b.blk);
++ }
++#else
++ do_else_if (NULL, addr);
++#endif
++ break;
++
++ case _SLANG_BCST_NOTELSE:
++ do_else_if (block, addr);
++ block = NULL;
++ break;
++
++ case _SLANG_BCST_ELSE:
++ do_else_if (addr, block);
++ block = NULL;
++ break;
++
++ case _SLANG_BCST_SWITCH:
++ if (Switch_Obj_Ptr == Switch_Obj_Max)
++ {
++ SLang_doerror(&quot;switch nesting too deep&quot;);
++ break;
++ }
++ (void) SLang_pop (Switch_Obj_Ptr);
++ Switch_Obj_Ptr++;
++
++ if (block == NULL) block = addr;
++ while ((SLang_Error == 0)
++ &amp;&amp; (block &lt;= addr)
++ &amp;&amp; (Lang_Break_Condition == 0)
++ &amp;&amp; (0 == inner_interp (block-&gt;b.blk)))
++ block++;
++ Switch_Obj_Ptr--;
++ SLang_free_object (Switch_Obj_Ptr);
++ Switch_Obj_Ptr-&gt;data_type = 0;
++ block = NULL;
++ break;
++
++ case _SLANG_BCST_ANDELSE:
++ case _SLANG_BCST_ORELSE:
++ if (block == NULL) block = addr;
++ lang_do_and_orelse (addr-&gt;bc_sub_type, block, addr);
++ block = NULL;
++ break;
++
++ default:
++ if (block == NULL) block = addr;
++ break;
++ }
++ if (Lang_Break_Condition) goto handle_break_condition;
++ break;
++
++ case _SLANG_BC_RETURN:
++ Lang_Break_Condition = Lang_Return = Lang_Break = 1; return 1;
++ case _SLANG_BC_BREAK:
++ Lang_Break_Condition = Lang_Break = 1; return 1;
++ case _SLANG_BC_CONTINUE:
++ Lang_Break_Condition = /* Lang_Continue = */ 1; return 1;
++
++ case _SLANG_BC_EXCH:
++ (void) SLreverse_stack (2);
++ break;
++
++ case _SLANG_BC_LABEL:
++ {
++ int test;
++ if ((0 == SLang_pop_integer (&amp;test))
++ &amp;&amp; (test == 0))
++ return 0;
++ }
++ break;
++
++ case _SLANG_BC_LOBJPTR:
++ (void)_SLang_push_ref (0, (VOID_STAR)(Local_Variable_Frame - addr-&gt;b.i_blk));
++ break;
++
++ case _SLANG_BC_GOBJPTR:
++ (void)_SLang_push_ref (1, (VOID_STAR)addr-&gt;b.nt_blk);
++ break;
++
++ case _SLANG_BC_X_ERROR:
++ if (err_block != NULL)
++ {
++ inner_interp(err_block-&gt;b.blk);
++ if (SLang_Error) err_block = NULL;
++ }
++ else SLang_verror(SL_SYNTAX_ERROR, &quot;No ERROR_BLOCK&quot;);
++ if (Lang_Break_Condition) goto handle_break_condition;
++ break;
++
++ case _SLANG_BC_X_USER0:
++ case _SLANG_BC_X_USER1:
++ case _SLANG_BC_X_USER2:
++ case _SLANG_BC_X_USER3:
++ case _SLANG_BC_X_USER4:
++ if (User_Block_Ptr[addr-&gt;bc_main_type - _SLANG_BC_X_USER0] != NULL)
++ {
++ inner_interp(User_Block_Ptr[addr-&gt;bc_main_type - _SLANG_BC_X_USER0]);
++ }
++ else SLang_verror(SL_SYNTAX_ERROR, &quot;No block for X_USERBLOCK&quot;);
++ if (Lang_Break_Condition) goto handle_break_condition;
++ break;
++
++ case _SLANG_BC_CALL_DIRECT:
++ (*addr-&gt;b.call_function) ();
++ break;
++
++ case _SLANG_BC_CALL_DIRECT_FRAME:
++ do_bc_call_direct_frame (addr-&gt;b.call_function);
++ break;
++
++ case _SLANG_BC_UNARY:
++ do_unary (addr-&gt;b.i_blk, _SLANG_BC_UNARY);
++ break;
++
++ case _SLANG_BC_UNARY_FUNC:
++ /* Make sure we treat these like function calls since the
++ * parser took abs(x) to be a function call.
++ */
++ if (0 == _SL_increment_frame_pointer ())
++ {
++ do_unary (addr-&gt;b.i_blk, _SLANG_BC_UNARY);
++ (void) _SL_decrement_frame_pointer ();
++ }
++ break;
++
++ case _SLANG_BC_DEREF_ASSIGN:
++ set_deref_lvalue (addr);
++ break;
++ case _SLANG_BC_SET_LOCAL_LVALUE:
++ set_lvalue_obj (addr-&gt;bc_sub_type, Local_Variable_Frame - addr-&gt;b.i_blk);
++ break;
++ case _SLANG_BC_SET_GLOBAL_LVALUE:
++ if (-1 == set_lvalue_obj (addr-&gt;bc_sub_type, &amp;addr-&gt;b.nt_gvar_blk-&gt;obj))
++ do_name_type_error (addr-&gt;b.nt_blk);
++ break;
++ case _SLANG_BC_SET_INTRIN_LVALUE:
++ set_intrin_lvalue (addr);
++ break;
++ case _SLANG_BC_SET_STRUCT_LVALUE:
++ set_struct_lvalue (addr);
++ break;
++
++ case _SLANG_BC_FIELD:
++ (void) push_struct_field (addr-&gt;b.s_blk);
++ break;
++
++ case _SLANG_BC_SET_ARRAY_LVALUE:
++ set_array_lvalue (addr-&gt;bc_sub_type);
++ break;
++
++#if _SLANG_HAS_DEBUG_CODE
++ case _SLANG_BC_LINE_NUM:
++ break;
++#endif
++
++ case _SLANG_BC_TMP:
++ tmp_variable_function (addr);
++ break;
++
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ case _SLANG_BC_LVARIABLE_AGET:
++ if (0 == push_local_variable (addr-&gt;b.i_blk))
++ do_bc_call_direct_frame (_SLarray_aget);
++ break;
++
++ case _SLANG_BC_LVARIABLE_APUT:
++ if (0 == push_local_variable (addr-&gt;b.i_blk))
++ do_bc_call_direct_frame (_SLarray_aput);
++ break;
++ case _SLANG_BC_INTEGER_PLUS:
++ if (0 == SLclass_push_int_obj (addr-&gt;bc_sub_type, (int) addr-&gt;b.l_blk))
++ do_binary (SLANG_PLUS);
++ break;
++
++ case _SLANG_BC_INTEGER_MINUS:
++ if (0 == SLclass_push_int_obj (addr-&gt;bc_sub_type, (int) addr-&gt;b.l_blk))
++ do_binary (SLANG_MINUS);
++ break;
++#endif
++#if 0
++ case _SLANG_BC_ARG_LVARIABLE:
++ (void) SLang_start_arg_list ();
++ push_local_variable (addr-&gt;b.i_blk);
++ break;
++#endif
++ case _SLANG_BC_EARG_LVARIABLE:
++ push_local_variable (addr-&gt;b.i_blk);
++ (void) SLang_end_arg_list ();
++ break;
++
++#if USE_COMBINED_BYTECODES
++ case _SLANG_BC_CALL_DIRECT_INTRINSIC:
++ (*addr-&gt;b.call_function) ();
++ addr++;
++ execute_intrinsic_fun (addr-&gt;b.nt_ifun_blk);
++ if (SLang_Error)
++ do_traceback(addr-&gt;b.nt_ifun_blk-&gt;name, 0, NULL);
++ break;
++
++ case _SLANG_BC_INTRINSIC_CALL_DIRECT:
++ execute_intrinsic_fun (addr-&gt;b.nt_ifun_blk);
++ if (SLang_Error)
++ {
++ do_traceback(addr-&gt;b.nt_ifun_blk-&gt;name, 0, NULL);
++ break;
++ }
++ addr++;
++ (*addr-&gt;b.call_function) ();
++ break;
++
++ case _SLANG_BC_CALL_DIRECT_LSTR:
++ (*addr-&gt;b.call_function) ();
++ addr++;
++ _SLang_dup_and_push_slstring (addr-&gt;b.s_blk);
++ break;
++
++ case _SLANG_BC_CALL_DIRECT_SLFUN:
++ (*addr-&gt;b.call_function) ();
++ addr++;
++ execute_slang_fun (addr-&gt;b.nt_fun_blk);
++ if (Lang_Break_Condition) goto handle_break_condition;
++ break;
++
++ case _SLANG_BC_CALL_DIRECT_INTRSTOP:
++ (*addr-&gt;b.call_function) ();
++ addr++;
++ /* drop */
++ case _SLANG_BC_INTRINSIC_STOP:
++ execute_intrinsic_fun (addr-&gt;b.nt_ifun_blk);
++ if (SLang_Error == 0)
++ return 1;
++ do_traceback(addr-&gt;b.nt_ifun_blk-&gt;name, 0, NULL);
++ break;
++
++ case _SLANG_BC_CALL_DIRECT_EARG_LVAR:
++ (*addr-&gt;b.call_function) ();
++ addr++;
++ push_local_variable (addr-&gt;b.i_blk);
++ (void) SLang_end_arg_list ();
++ break;
++
++ case _SLANG_BC_CALL_DIRECT_LINT:
++ (*addr-&gt;b.call_function) ();
++ addr++;
++ SLclass_push_int_obj (addr-&gt;bc_sub_type, (int) addr-&gt;b.l_blk);
++ break;
++
++ case _SLANG_BC_CALL_DIRECT_LVAR:
++ (*addr-&gt;b.call_function) ();
++ addr++;
++ push_local_variable (addr-&gt;b.i_blk);
++ break;
++#endif /* USE_COMBINED_BYTECODES */
++
++ default:
++ SLang_verror (SL_INTERNAL_ERROR, &quot;Byte-Code 0x%X is not valid&quot;, addr-&gt;bc_main_type);
++ }
++
++ /* Someday I plan to add a 'signal' intrinsic function. Then when a
++ * signal is caught, a variable will be set to one and that value of
++ * that variable will need to be monitored here, e.g.,
++ * if (Handle_Signal) handle_signal ();
++ * It would be nice to check only one variable instead of Handle_Signal
++ * and SLang_Error. Perhaps I should phase out SLang_Error = xxx
++ * and used something like: SLang_set_error (code); Then, I could
++ * use:
++ * if (Handle_Condition)
++ * {
++ * Handle_Condition = 0;
++ * if (SLang_Error) ....
++ * else if (Handle_Signal) handle_signal ();
++ * else....
++ * }
++ */
++ if (SLang_Error)
++ {
++ if (-1 == do_inner_interp_error (err_block, addr_start, addr))
++ return 1;
++ if (SLang_Error)
++ return 1;
++
++ /* Otherwise, error cleared. Continue onto next bytecode.
++ * Someday I need to add something to indicate where the
++ * next statement begins since continuing on the next
++ * bytecode is not really what is desired.
++ */
++ if (Lang_Break_Condition) goto handle_break_condition;
++ }
++ addr++;
++ }
++
++ handle_break_condition:
++ /* Get here if Lang_Break_Condition != 0, which implies that either
++ * Lang_Return, Lang_Break, or Lang_Continue is non zero
++ */
++ if (Lang_Return)
++ Lang_Break = 1;
++
++ return 1;
++}
++
++/*}}}*/
++
++/* The functions below this point are used to implement the parsed token
++ * to byte-compiled code.
++ */
++/* static SLang_Name_Type **Static_Hash_Table; */
++
++static SLang_Name_Type **Locals_Hash_Table;
++static int Local_Variable_Number;
++static unsigned int Function_Args_Number;
++int _SLang_Auto_Declare_Globals = 0;
++int (*SLang_Auto_Declare_Var_Hook) (char *);
++
++static SLang_NameSpace_Type *This_Static_NameSpace;
++static SLang_NameSpace_Type *Global_NameSpace;
++
++#if _SLANG_HAS_DEBUG_CODE
++static char *This_Compile_Filename;
++#endif
++static SLBlock_Type SLShort_Blocks[6];
++/* These are initialized in add_table below. I cannot init a Union!! */
++
++static int Lang_Defining_Function;
++static void (*Default_Variable_Mode) (_SLang_Token_Type *);
++static void (*Default_Define_Function) (char *, unsigned long);
++
++static int push_compile_context (char *);
++static int pop_compile_context (void);
++
++typedef struct
++{
++ int block_type;
++ SLBlock_Type *block; /* beginning of block definition */
++ SLBlock_Type *block_ptr; /* current location */
++ SLBlock_Type *block_max; /* end of definition */
++ SLang_NameSpace_Type *static_namespace;
++}
++Block_Context_Type;
++
++static Block_Context_Type Block_Context_Stack [SLANG_MAX_BLOCK_STACK_LEN];
++static unsigned int Block_Context_Stack_Len;
++
++static SLBlock_Type *Compile_ByteCode_Ptr;
++static SLBlock_Type *This_Compile_Block;
++static SLBlock_Type *This_Compile_Block_Max;
++static int This_Compile_Block_Type;
++#define COMPILE_BLOCK_TYPE_FUNCTION 1
++#define COMPILE_BLOCK_TYPE_BLOCK 2
++#define COMPILE_BLOCK_TYPE_TOP_LEVEL 3
++
++/* If it returns 0, DO NOT FREE p */
++static int lang_free_branch (SLBlock_Type *p)
++{
++ /* Note: we look at 0,2,4, since these blocks are 0 terminated */
++ if ((p == SLShort_Blocks)
++ || (p == SLShort_Blocks + 2)
++ || (p == SLShort_Blocks + 4)
++ )
++ return 0;
++
++ while (1)
++ {
++ SLang_Class_Type *cl;
++
++ switch (p-&gt;bc_main_type)
++ {
++ case _SLANG_BC_BLOCK:
++ if (lang_free_branch(p-&gt;b.blk))
++ SLfree((char *)p-&gt;b.blk);
++ break;
++
++ case _SLANG_BC_LITERAL:
++ case _SLANG_BC_LITERAL_STR:
++ /* No user types should be here. */
++ cl = _SLclass_get_class (p-&gt;bc_sub_type);
++ (*cl-&gt;cl_byte_code_destroy) (p-&gt;bc_sub_type, (VOID_STAR) &amp;p-&gt;b.ptr_blk);
++ break;
++
++ case _SLANG_BC_FIELD:
++ case _SLANG_BC_SET_STRUCT_LVALUE:
++ SLang_free_slstring (p-&gt;b.s_blk);
++ break;
++
++ default:
++ break;
++
++ case 0:
++ return 1;
++ }
++ p++;
++ }
++}
++
++static void free_function_header (_SLBlock_Header_Type *h)
++{
++ if (h-&gt;num_refs &gt; 1)
++ {
++ h-&gt;num_refs--;
++ return;
++ }
++
++ if (h-&gt;body != NULL)
++ {
++ if (lang_free_branch (h-&gt;body))
++ SLfree ((char *) h-&gt;body);
++ }
++
++ SLfree ((char *) h);
++}
++
++static int push_block_context (int type)
++{
++ Block_Context_Type *c;
++ unsigned int num;
++ SLBlock_Type *b;
++
++ if (Block_Context_Stack_Len == SLANG_MAX_BLOCK_STACK_LEN)
++ {
++ SLang_verror (SL_STACK_OVERFLOW, &quot;Block stack overflow&quot;);
++ return -1;
++ }
++
++ num = 5; /* 40 bytes */
++ if (NULL == (b = (SLBlock_Type *) SLcalloc (num, sizeof (SLBlock_Type))))
++ return -1;
++
++ c = Block_Context_Stack + Block_Context_Stack_Len;
++ c-&gt;block = This_Compile_Block;
++ c-&gt;block_ptr = Compile_ByteCode_Ptr;
++ c-&gt;block_max = This_Compile_Block_Max;
++ c-&gt;block_type = This_Compile_Block_Type;
++ c-&gt;static_namespace = This_Static_NameSpace;
++
++ Compile_ByteCode_Ptr = This_Compile_Block = b;
++ This_Compile_Block_Max = b + num;
++ This_Compile_Block_Type = type;
++
++ Block_Context_Stack_Len += 1;
++ return 0;
++}
++
++static int pop_block_context (void)
++{
++ Block_Context_Type *c;
++
++ if (Block_Context_Stack_Len == 0)
++ return -1;
++
++ Block_Context_Stack_Len -= 1;
++ c = Block_Context_Stack + Block_Context_Stack_Len;
++
++ This_Compile_Block = c-&gt;block;
++ This_Compile_Block_Max = c-&gt;block_max;
++ This_Compile_Block_Type = c-&gt;block_type;
++ Compile_ByteCode_Ptr = c-&gt;block_ptr;
++ This_Static_NameSpace = c-&gt;static_namespace;
++
++ return 0;
++}
++
++int _SLcompile_push_context (SLang_Load_Type *load_object)
++{
++ if (-1 == push_compile_context (load_object-&gt;name))
++ return -1;
++
++ if (NULL == (This_Static_NameSpace = _SLns_allocate_namespace (load_object-&gt;name, SLSTATIC_HASH_TABLE_SIZE)))
++ {
++ pop_compile_context ();
++ return -1;
++ }
++
++ if (-1 == push_block_context (COMPILE_BLOCK_TYPE_TOP_LEVEL))
++ {
++ pop_compile_context ();
++ return -1;
++ }
++
++ return 0;
++}
++
++int _SLcompile_pop_context (void)
++{
++ if (This_Compile_Block_Type == COMPILE_BLOCK_TYPE_TOP_LEVEL)
++ {
++ Compile_ByteCode_Ptr-&gt;bc_main_type = 0;
++ if (lang_free_branch (This_Compile_Block))
++ SLfree ((char *) This_Compile_Block);
++ }
++
++ (void) pop_block_context ();
++ (void) pop_compile_context ();
++
++ if (This_Compile_Block == NULL)
++ return 0;
++
++#if 0
++ if (This_Compile_Block_Type != COMPILE_BLOCK_TYPE_TOP_LEVEL)
++ {
++ SLang_verror (SL_INTERNAL_ERROR, &quot;Not at top-level&quot;);
++ return -1;
++ }
++#endif
++
++ return 0;
++}
++
++/*{{{ Hash and Name Table Functions */
++
++static SLang_Name_Type *locate_name_in_table (char *name, unsigned long hash,
++ SLang_Name_Type **table, unsigned int table_size)
++{
++ SLang_Name_Type *t;
++ char ch;
++
++ t = table [(unsigned int) (hash % table_size)];
++ ch = *name++;
++
++ while (t != NULL)
++ {
++ if ((ch == t-&gt;name[0])
++ &amp;&amp; (0 == strcmp (t-&gt;name + 1, name)))
++ break;
++
++ t = t-&gt;next;
++ }
++
++ return t;
++}
++
++static SLang_Name_Type *locate_namespace_encoded_name (char *name, int err_on_bad_ns)
++{
++ char *ns, *ns1;
++ SLang_NameSpace_Type *table;
++ SLang_Name_Type *nt;
++
++ ns = name;
++ name = strchr (name, '-');
++ if ((name == NULL) || (name [1] != '&gt;'))
++ name = ns;
++
++ ns1 = SLang_create_nslstring (ns, (unsigned int) (name - ns));
++ if (ns1 == NULL)
++ return NULL;
++ if (ns != name)
++ name += 2;
++ ns = ns1;
++
++ if (*ns == 0)
++ {
++ /* Use Global Namespace */
++ SLang_free_slstring (ns);
++ return locate_name_in_table (name, _SLcompute_string_hash (name),
++ Global_NameSpace-&gt;table, Global_NameSpace-&gt;table_size);
++ }
++
++ if (NULL == (table = _SLns_find_namespace (ns)))
++ {
++ if (err_on_bad_ns)
++ SLang_verror (SL_SYNTAX_ERROR, &quot;Unable to find namespace called %s&quot;, ns);
++ SLang_free_slstring (ns);
++ return NULL;
++ }
++ SLang_free_slstring (ns);
++
++ /* FIXME: the hash table size should be stored in the hash table itself */
++ nt = locate_name_in_table (name, _SLcompute_string_hash (name),
++ table-&gt;table, table-&gt;table_size);
++ if (nt == NULL)
++ return NULL;
++
++ switch (nt-&gt;name_type)
++ {
++ /* These are private and cannot be accessed through the namespace. */
++ case SLANG_PVARIABLE:
++ case SLANG_PFUNCTION:
++ return NULL;
++ }
++ return nt;
++}
++
++static SLang_Name_Type *locate_hashed_name (char *name, unsigned long hash)
++{
++ SLang_Name_Type *t;
++
++ if (Lang_Defining_Function)
++ {
++ t = locate_name_in_table (name, hash, Locals_Hash_Table, SLLOCALS_HASH_TABLE_SIZE);
++ if (t != NULL)
++ return t;
++ }
++
++ if ((This_Static_NameSpace != NULL)
++ &amp;&amp; (NULL != (t = locate_name_in_table (name, hash, This_Static_NameSpace-&gt;table, This_Static_NameSpace-&gt;table_size))))
++ return t;
++
++ t = locate_name_in_table (name, hash, Global_NameSpace-&gt;table, Global_NameSpace-&gt;table_size);
++ if (NULL != t)
++ return t;
++
++ return locate_namespace_encoded_name (name, 1);
++}
++
++SLang_Name_Type *_SLlocate_name (char *name)
++{
++ return locate_hashed_name (name, _SLcompute_string_hash (name));
++}
++
++static SLang_Name_Type *
++add_name_to_hash_table (char *name, unsigned long hash,
++ unsigned int sizeof_obj, unsigned char name_type,
++ SLang_Name_Type **table, unsigned int table_size,
++ int check_existing)
++{
++ SLang_Name_Type *t;
++
++ if (check_existing)
++ {
++ t = locate_name_in_table (name, hash, table, table_size);
++ if (t != NULL)
++ return t;
++ }
++
++ if (-1 == _SLcheck_identifier_syntax (name))
++ return NULL;
++
++ t = (SLang_Name_Type *) SLmalloc (sizeof_obj);
++ if (t == NULL)
++ return t;
++
++ memset ((char *) t, 0, sizeof_obj);
++ if (NULL == (t-&gt;name = _SLstring_dup_hashed_string (name, hash)))
++ {
++ SLfree ((char *) t);
++ return NULL;
++ }
++ t-&gt;name_type = name_type;
++
++ hash = hash % table_size;
++ t-&gt;next = table [(unsigned int)hash];
++ table [(unsigned int) hash] = t;
++
++ return t;
++}
++
++static SLang_Name_Type *
++add_global_name (char *name, unsigned long hash,
++ unsigned char name_type, unsigned int sizeof_obj,
++ SLang_NameSpace_Type *ns)
++{
++ SLang_Name_Type *nt;
++ SLang_Name_Type **table;
++ unsigned int table_size;
++
++ table = ns-&gt;table;
++ table_size = ns-&gt;table_size;
++
++ nt = locate_name_in_table (name, hash, table, table_size);
++ if (nt != NULL)
++ {
++ if (nt-&gt;name_type == name_type)
++ return nt;
++
++ SLang_verror (SL_DUPLICATE_DEFINITION, &quot;%s cannot be re-defined&quot;, name);
++ return NULL;
++ }
++
++ return add_name_to_hash_table (name, hash, sizeof_obj, name_type,
++ table, table_size, 0);
++}
++
++static int add_intrinsic_function (SLang_NameSpace_Type *ns,
++ char *name, FVOID_STAR addr, unsigned char ret_type,
++ unsigned int nargs, va_list ap)
++{
++ SLang_Intrin_Fun_Type *f;
++ unsigned int i;
++
++ if (-1 == init_interpreter ())
++ return -1;
++
++ if (ns == NULL) ns = Global_NameSpace;
++
++ if (nargs &gt; SLANG_MAX_INTRIN_ARGS)
++ {
++ SLang_verror (SL_APPLICATION_ERROR, &quot;Function %s requires too many arguments&quot;, name);
++ return -1;
++ }
++
++ if (ret_type == SLANG_FLOAT_TYPE)
++ {
++ SLang_verror (SL_NOT_IMPLEMENTED, &quot;Function %s is not permitted to return float&quot;, name);
++ return -1;
++ }
++
++ f = (SLang_Intrin_Fun_Type *) add_global_name (name, _SLcompute_string_hash (name),
++ SLANG_INTRINSIC, sizeof (SLang_Intrin_Fun_Type),
++ ns);
++
++ if (f == NULL)
++ return -1;
++
++ f-&gt;i_fun = addr;
++ f-&gt;num_args = nargs;
++ f-&gt;return_type = ret_type;
++
++ for (i = 0; i &lt; nargs; i++)
++ f-&gt;arg_types [i] = va_arg (ap, unsigned int);
++
++ return 0;
++}
++
++int SLadd_intrinsic_function (char *name, FVOID_STAR addr, unsigned char ret_type,
++ unsigned int nargs, ...)
++{
++ va_list ap;
++ int status;
++
++ va_start (ap, nargs);
++ status = add_intrinsic_function (NULL, name, addr, ret_type, nargs, ap);
++ va_end (ap);
++
++ return status;
++}
++
++int SLns_add_intrinsic_function (SLang_NameSpace_Type *ns,
++ char *name, FVOID_STAR addr, unsigned char ret_type,
++ unsigned int nargs, ...)
++{
++ va_list ap;
++ int status;
++
++ va_start (ap, nargs);
++ status = add_intrinsic_function (ns, name, addr, ret_type, nargs, ap);
++ va_end (ap);
++
++ return status;
++}
++
++int SLns_add_intrinsic_variable (SLang_NameSpace_Type *ns,
++ char *name, VOID_STAR addr, unsigned char data_type, int ro)
++{
++ SLang_Intrin_Var_Type *v;
++
++ if (-1 == init_interpreter ())
++ return -1;
++
++ if (ns == NULL) ns = Global_NameSpace;
++
++ v = (SLang_Intrin_Var_Type *)add_global_name (name,
++ _SLcompute_string_hash (name),
++ (ro ? SLANG_RVARIABLE : SLANG_IVARIABLE),
++ sizeof (SLang_Intrin_Var_Type),
++ ns);
++ if (v == NULL)
++ return -1;
++
++ v-&gt;addr = addr;
++ v-&gt;type = data_type;
++ return 0;
++}
++
++int SLadd_intrinsic_variable (char *name, VOID_STAR addr, unsigned char data_type, int ro)
++{
++ return SLns_add_intrinsic_variable (NULL, name, addr, data_type, ro);
++}
++
++static int
++add_slang_function (char *name, unsigned char type, unsigned long hash,
++ unsigned int num_args, unsigned int num_locals,
++#if _SLANG_HAS_DEBUG_CODE
++ char *file,
++#endif
++ _SLBlock_Header_Type *h,
++ SLang_NameSpace_Type *ns)
++{
++ _SLang_Function_Type *f;
++
++#if _SLANG_HAS_DEBUG_CODE
++ if ((file != NULL)
++ &amp;&amp; (NULL == (file = SLang_create_slstring (file))))
++ return -1;
++#endif
++
++ f = (_SLang_Function_Type *)add_global_name (name, hash,
++ type,
++ sizeof (_SLang_Function_Type),
++ ns);
++ if (f == NULL)
++ {
++#if _SLANG_HAS_DEBUG_CODE
++ SLang_free_slstring (file); /* NULL ok */
++#endif
++ return -1;
++ }
++
++ if (f-&gt;v.header != NULL)
++ {
++ if (f-&gt;nlocals == AUTOLOAD_NUM_LOCALS)
++ SLang_free_slstring ((char *)f-&gt;v.autoload_filename); /* autoloaded filename */
++ else
++ free_function_header (f-&gt;v.header);
++ }
++
++#if _SLANG_HAS_DEBUG_CODE
++ if (f-&gt;file != NULL) SLang_free_slstring (f-&gt;file);
++ f-&gt;file = file;
++#endif
++ f-&gt;v.header = h;
++ f-&gt;nlocals = num_locals;
++ f-&gt;nargs = num_args;
++
++ return 0;
++}
++
++int SLang_autoload (char *name, char *file)
++{
++ _SLang_Function_Type *f;
++ unsigned long hash;
++
++ hash = _SLcompute_string_hash (name);
++ f = (_SLang_Function_Type *)locate_name_in_table (name, hash, Global_NameSpace-&gt;table, Global_NameSpace-&gt;table_size);
++
++ if ((f != NULL)
++ &amp;&amp; (f-&gt;name_type == SLANG_FUNCTION)
++ &amp;&amp; (f-&gt;v.header != NULL)
++ &amp;&amp; (f-&gt;nlocals != AUTOLOAD_NUM_LOCALS))
++ {
++ /* already loaded */
++ return 0;
++ }
++
++ file = SLang_create_slstring (file);
++ if (-1 == add_slang_function (name, SLANG_FUNCTION, hash, 0, AUTOLOAD_NUM_LOCALS,
++#if _SLANG_HAS_DEBUG_CODE
++ file,
++#endif
++ (_SLBlock_Header_Type *) file,
++ Global_NameSpace))
++ {
++ SLang_free_slstring (file);
++ return -1;
++ }
++
++ return 0;
++}
++
++SLang_Name_Type *_SLlocate_global_name (char *name)
++{
++ unsigned long hash;
++
++ hash = _SLcompute_string_hash (name);
++ return locate_name_in_table (name, hash, Global_NameSpace-&gt;table,
++ Global_NameSpace-&gt;table_size);
++}
++
++/*}}}*/
++
++static void free_local_variable_table (void)
++{
++ unsigned int i;
++ SLang_Name_Type *t, *t1;
++
++ for (i = 0; i &lt; SLLOCALS_HASH_TABLE_SIZE; i++)
++ {
++ t = Locals_Hash_Table [i];
++ while (t != NULL)
++ {
++ SLang_free_slstring (t-&gt;name);
++ t1 = t-&gt;next;
++ SLfree ((char *) t);
++ t = t1;
++ }
++ Locals_Hash_Table [i] = NULL;
++ }
++ Local_Variable_Number = 0;
++}
++
++/* call inner interpreter or return for more */
++static void lang_try_now(void)
++{
++ Compile_ByteCode_Ptr++;
++ if (This_Compile_Block_Type != COMPILE_BLOCK_TYPE_TOP_LEVEL)
++ return;
++
++ Compile_ByteCode_Ptr-&gt;bc_main_type = 0; /* so next command stops after this */
++
++ /* now do it */
++ inner_interp (This_Compile_Block);
++ (void) lang_free_branch (This_Compile_Block);
++ Compile_ByteCode_Ptr = This_Compile_Block;
++}
++
++SLang_Name_Type *SLang_get_fun_from_ref (SLang_Ref_Type *ref)
++{
++ if (ref-&gt;is_global)
++ {
++ SLang_Name_Type *nt = ref-&gt;v.nt;
++
++ switch (nt-&gt;name_type)
++ {
++ case SLANG_PFUNCTION:
++ case SLANG_FUNCTION:
++ case SLANG_INTRINSIC:
++ case SLANG_MATH_UNARY:
++ case SLANG_APP_UNARY:
++ return nt;
++ }
++ SLang_verror (SL_TYPE_MISMATCH,
++ &quot;Reference to a function expected. Found &amp;%s&quot;,
++ nt-&gt;name);
++ }
++
++ SLang_verror (SL_TYPE_MISMATCH,
++ &quot;Reference to a function expected&quot;);
++ return NULL;
++}
++
++int SLexecute_function (SLang_Name_Type *nt)
++{
++ unsigned char type;
++ char *name;
++
++ if (SLang_Error)
++ return -1;
++
++ type = nt-&gt;name_type;
++ name = nt-&gt;name;
++
++ switch (type)
++ {
++ case SLANG_PFUNCTION:
++ case SLANG_FUNCTION:
++ execute_slang_fun ((_SLang_Function_Type *) nt);
++ break;
++
++ case SLANG_INTRINSIC:
++ execute_intrinsic_fun ((SLang_Intrin_Fun_Type *) nt);
++ break;
++
++ case SLANG_MATH_UNARY:
++ case SLANG_APP_UNARY:
++ inner_interp_nametype (nt);
++ break;
++
++ default:
++ SLang_verror (SL_TYPE_MISMATCH, &quot;%s is not a function&quot;, name);
++ return -1;
++ }
++
++ if (SLang_Error)
++ {
++ SLang_verror (SLang_Error, &quot;Error while executing %s&quot;, name);
++ return -1;
++ }
++
++ return 1;
++}
++
++int SLang_execute_function (char *name)
++{
++ SLang_Name_Type *entry;
++
++ if (NULL == (entry = SLang_get_function (name)))
++ return 0;
++
++ return SLexecute_function (entry);
++}
++
++/* return S-Lang function or NULL */
++SLang_Name_Type *SLang_get_function (char *name)
++{
++ SLang_Name_Type *entry;
++
++ if (NULL == (entry = locate_namespace_encoded_name (name, 0)))
++ return NULL;
++
++ if ((entry-&gt;name_type == SLANG_FUNCTION)
++ || (entry-&gt;name_type == SLANG_INTRINSIC))
++ return entry;
++
++ return NULL;
++}
++
++static void lang_begin_function (void)
++{
++ if (This_Compile_Block_Type != COMPILE_BLOCK_TYPE_TOP_LEVEL)
++ {
++ SLang_verror (SL_SYNTAX_ERROR, &quot;Function nesting is illegal&quot;);
++ return;
++ }
++ Lang_Defining_Function = 1;
++ (void) push_block_context (COMPILE_BLOCK_TYPE_FUNCTION);
++}
++
++#if USE_COMBINED_BYTECODES
++static void optimize_block (SLBlock_Type *b)
++{
++ while (1)
++ {
++ switch (b-&gt;bc_main_type)
++ {
++ case 0:
++ return;
++
++ default:
++ b++;
++ break;
++
++ case _SLANG_BC_CALL_DIRECT:
++ b++;
++ switch (b-&gt;bc_main_type)
++ {
++ case 0:
++ return;
++ case _SLANG_BC_INTRINSIC:
++ if ((b+1)-&gt;bc_main_type == 0)
++ {
++ (b-1)-&gt;bc_main_type = _SLANG_BC_CALL_DIRECT_INTRSTOP;
++ return;
++ }
++ (b-1)-&gt;bc_main_type = _SLANG_BC_CALL_DIRECT_INTRINSIC;
++ b++;
++ break;
++ case _SLANG_BC_LITERAL_STR:
++ (b-1)-&gt;bc_main_type = _SLANG_BC_CALL_DIRECT_LSTR;
++ b++;
++ break;
++ case _SLANG_BC_FUNCTION:
++ case _SLANG_BC_PFUNCTION:
++ (b-1)-&gt;bc_main_type = _SLANG_BC_CALL_DIRECT_SLFUN;
++ b++;
++ break;
++ case _SLANG_BC_EARG_LVARIABLE:
++ (b-1)-&gt;bc_main_type = _SLANG_BC_CALL_DIRECT_EARG_LVAR;
++ b++;
++ break;
++ case _SLANG_BC_LITERAL_INT:
++ (b-1)-&gt;bc_main_type = _SLANG_BC_CALL_DIRECT_LINT;
++ b++;
++ break;
++ case _SLANG_BC_LVARIABLE:
++ (b-1)-&gt;bc_main_type = _SLANG_BC_CALL_DIRECT_LVAR;
++ b++;
++ break;
++ }
++ break;
++
++ case _SLANG_BC_INTRINSIC:
++ b++;
++ switch (b-&gt;bc_main_type)
++ {
++ case _SLANG_BC_CALL_DIRECT:
++ (b-1)-&gt;bc_main_type = _SLANG_BC_INTRINSIC_CALL_DIRECT;
++ b++;
++ break;
++#if 0
++ case _SLANG_BC_BLOCK:
++ (b-1)-&gt;bc_main_type = _SLANG_BC_INTRINSIC_BLOCK;
++ b++;
++ break;
++#endif
++
++ case 0:
++ (b-1)-&gt;bc_main_type = _SLANG_BC_INTRINSIC_STOP;
++ return;
++ }
++ break;
++ }
++ }
++}
++
++#endif
++
++
++/* name will be NULL if the object is to simply terminate the function
++ * definition. See SLang_restart.
++ */
++static int lang_define_function (char *name, unsigned char type, unsigned long hash,
++ SLang_NameSpace_Type *ns)
++{
++ if (This_Compile_Block_Type != COMPILE_BLOCK_TYPE_FUNCTION)
++ {
++ SLang_verror (SL_SYNTAX_ERROR, &quot;Premature end of function&quot;);
++ return -1;
++ }
++
++ /* terminate function */
++ Compile_ByteCode_Ptr-&gt;bc_main_type = 0;
++
++ if (name != NULL)
++ {
++ _SLBlock_Header_Type *h;
++
++ h = (_SLBlock_Header_Type *)SLmalloc (sizeof (_SLBlock_Header_Type));
++ if (h != NULL)
++ {
++ h-&gt;num_refs = 1;
++ h-&gt;body = This_Compile_Block;
++
++#if USE_COMBINED_BYTECODES
++ optimize_block (h-&gt;body);
++#endif
++
++ if (-1 == add_slang_function (name, type, hash,
++ Function_Args_Number,
++ Local_Variable_Number,
++#if _SLANG_HAS_DEBUG_CODE
++ This_Compile_Filename,
++#endif
++ h, ns))
++ SLfree ((char *) h);
++ }
++ /* Drop through for clean-up */
++ }
++
++ free_local_variable_table ();
++
++ Function_Args_Number = 0;
++ Lang_Defining_Function = 0;
++
++ if (SLang_Error) return -1;
++ /* SLang_restart will finish this if there is a slang error. */
++
++ pop_block_context ();
++
++ /* A function is only defined at top-level */
++ if (This_Compile_Block_Type != COMPILE_BLOCK_TYPE_TOP_LEVEL)
++ {
++ SLang_verror (SL_INTERNAL_ERROR, &quot;Not at top-level&quot;);
++ return -1;
++ }
++ Compile_ByteCode_Ptr = This_Compile_Block;
++ return 0;
++}
++
++static void define_static_function (char *name, unsigned long hash)
++{
++ (void) lang_define_function (name, SLANG_FUNCTION, hash, This_Static_NameSpace);
++}
++
++static void define_private_function (char *name, unsigned long hash)
++{
++ (void) lang_define_function (name, SLANG_PFUNCTION, hash, This_Static_NameSpace);
++}
++
++static void define_public_function (char *name, unsigned long hash)
++{
++ (void) lang_define_function (name, SLANG_FUNCTION, hash, Global_NameSpace);
++}
++
++static void lang_end_block (void)
++{
++ SLBlock_Type *node, *branch;
++ unsigned char mtype;
++
++ if (This_Compile_Block_Type != COMPILE_BLOCK_TYPE_BLOCK)
++ {
++ SLang_verror (SL_SYNTAX_ERROR, &quot;Not defining a block&quot;);
++ return;
++ }
++
++ /* terminate the block */
++ Compile_ByteCode_Ptr-&gt;bc_main_type = 0;
++ branch = This_Compile_Block;
++
++ /* Try to save some space by using the cached blocks. */
++ if (Compile_ByteCode_Ptr == branch + 1)
++ {
++ mtype = branch-&gt;bc_main_type;
++ if (((mtype == _SLANG_BC_BREAK)
++ || (mtype == _SLANG_BC_CONTINUE)
++ || (mtype == _SLANG_BC_RETURN))
++ &amp;&amp; (SLang_Error == 0))
++ {
++ SLfree ((char *)branch);
++ branch = SLShort_Blocks + 2 * (int) (mtype - _SLANG_BC_RETURN);
++ }
++ }
++
++#if USE_COMBINED_BYTECODES
++ optimize_block (branch);
++#endif
++
++ pop_block_context ();
++ node = Compile_ByteCode_Ptr++;
++
++ node-&gt;bc_main_type = _SLANG_BC_BLOCK;
++ node-&gt;bc_sub_type = 0;
++ node-&gt;b.blk = branch;
++}
++
++static int lang_begin_block (void)
++{
++ return push_block_context (COMPILE_BLOCK_TYPE_BLOCK);
++}
++
++static int lang_check_space (void)
++{
++ unsigned int n;
++ SLBlock_Type *p;
++
++ if (NULL == (p = This_Compile_Block))
++ {
++ SLang_verror (SL_INTERNAL_ERROR, &quot;Top-level block not present&quot;);
++ return -1;
++ }
++
++ /* Allow 1 extra for terminator */
++ if (Compile_ByteCode_Ptr + 1 &lt; This_Compile_Block_Max)
++ return 0;
++
++ n = (unsigned int) (This_Compile_Block_Max - p);
++
++ /* enlarge the space by 2 objects */
++ n += 2;
++
++ if (NULL == (p = (SLBlock_Type *) SLrealloc((char *)p, n * sizeof(SLBlock_Type))))
++ return -1;
++
++ This_Compile_Block_Max = p + n;
++ n = (unsigned int) (Compile_ByteCode_Ptr - This_Compile_Block);
++ This_Compile_Block = p;
++ Compile_ByteCode_Ptr = p + n;
++
++ return 0;
++}
++
++/* returns positive number if name is a function or negative number if it
++ is a variable. If it is intrinsic, it returns magnitude of 1, else 2 */
++int SLang_is_defined(char *name)
++{
++ SLang_Name_Type *t;
++
++ if (-1 == init_interpreter ())
++ return -1;
++
++ t = locate_namespace_encoded_name (name, 0);
++ if (t == NULL)
++ return 0;
++
++ switch (t-&gt;name_type)
++ {
++ case SLANG_FUNCTION:
++ /* case SLANG_PFUNCTION: */
++ return 2;
++ case SLANG_GVARIABLE:
++ /* case SLANG_PVARIABLE: */
++ return -2;
++
++ case SLANG_ICONSTANT:
++ case SLANG_DCONSTANT:
++ case SLANG_RVARIABLE:
++ case SLANG_IVARIABLE:
++ return -1;
++
++ case SLANG_INTRINSIC:
++ default:
++ return 1;
++ }
++}
++
++static int add_global_variable (char *name, char name_type, unsigned long hash,
++ SLang_NameSpace_Type *ns)
++{
++ SLang_Name_Type *g;
++
++ /* Note the importance of checking if it is already defined or not. For example,
++ * suppose X is defined as an intrinsic variable. Then S-Lang code like:
++ * !if (is_defined(&quot;X&quot;)) { variable X; }
++ * will not result in a global variable X. On the other hand, this would
++ * not be an issue if 'variable' statements always were not processed
++ * immediately. That is, as it is now, 'if (0) {variable ZZZZ;}' will result
++ * in the variable ZZZZ being defined because of the immediate processing.
++ * The current solution is to do: if (0) { eval(&quot;variable ZZZZ;&quot;); }
++ */
++ /* hash = _SLcompute_string_hash (name); */
++ g = locate_name_in_table (name, hash, ns-&gt;table, ns-&gt;table_size);
++
++ if (g != NULL)
++ {
++ if (g-&gt;name_type == name_type)
++ return 0;
++ }
++
++ if (NULL == add_global_name (name, hash, name_type,
++ sizeof (SLang_Global_Var_Type), ns))
++ return -1;
++
++ return 0;
++}
++
++int SLadd_global_variable (char *name)
++{
++ if (-1 == init_interpreter ())
++ return -1;
++
++ return add_global_variable (name, SLANG_GVARIABLE,
++ _SLcompute_string_hash (name),
++ Global_NameSpace);
++}
++
++static int add_local_variable (char *name, unsigned long hash)
++{
++ SLang_Local_Var_Type *t;
++
++ /* local variable */
++ if (Local_Variable_Number &gt;= SLANG_MAX_LOCAL_VARIABLES)
++ {
++ SLang_verror (SL_SYNTAX_ERROR, &quot;Too many local variables&quot;);
++ return -1;
++ }
++
++ if (NULL != locate_name_in_table (name, hash, Locals_Hash_Table, SLLOCALS_HASH_TABLE_SIZE))
++ {
++ SLang_verror (SL_SYNTAX_ERROR, &quot;Local variable %s has already been defined&quot;, name);
++ return -1;
++ }
++
++ t = (SLang_Local_Var_Type *)
++ add_name_to_hash_table (name, hash,
++ sizeof (SLang_Local_Var_Type), SLANG_LVARIABLE,
++ Locals_Hash_Table, SLLOCALS_HASH_TABLE_SIZE, 0);
++ if (t == NULL)
++ return -1;
++
++ t-&gt;local_var_number = Local_Variable_Number;
++ Local_Variable_Number++;
++ return 0;
++}
++
++static void (*Compile_Mode_Function) (_SLang_Token_Type *);
++static void compile_basic_token_mode (_SLang_Token_Type *);
++
++/* if an error occurs, discard current object, block, function, etc... */
++void SLang_restart (int localv)
++{
++ int save = SLang_Error;
++
++ SLang_Error = SL_UNKNOWN_ERROR;
++
++ _SLcompile_ptr = _SLcompile;
++ Compile_Mode_Function = compile_basic_token_mode;
++
++ Lang_Break = /* Lang_Continue = */ Lang_Return = 0;
++ Trace_Mode = 0;
++
++ while (This_Compile_Block_Type == COMPILE_BLOCK_TYPE_BLOCK)
++ lang_end_block();
++
++ if (This_Compile_Block_Type == COMPILE_BLOCK_TYPE_FUNCTION)
++ {
++ /* Terminate function definition and free variables */
++ lang_define_function (NULL, SLANG_FUNCTION, 0, Global_NameSpace);
++ if (lang_free_branch (This_Compile_Block))
++ SLfree((char *)This_Compile_Block);
++ }
++ Lang_Defining_Function = 0;
++
++ SLang_Error = save;
++
++ if (SLang_Error == SL_STACK_OVERFLOW)
++ {
++ /* This loop guarantees that the stack is properly cleaned. */
++ while (_SLStack_Pointer != _SLRun_Stack)
++ {
++ SLdo_pop ();
++ }
++ }
++
++ while ((This_Compile_Block_Type != COMPILE_BLOCK_TYPE_TOP_LEVEL)
++ &amp;&amp; (0 == pop_block_context ()))
++ ;
++
++ if (localv)
++ {
++ Next_Function_Num_Args = SLang_Num_Function_Args = 0;
++ Local_Variable_Frame = Local_Variable_Stack;
++ Recursion_Depth = 0;
++ Frame_Pointer = _SLStack_Pointer;
++ Frame_Pointer_Depth = 0;
++ Switch_Obj_Ptr = Switch_Objects;
++ while (Switch_Obj_Ptr &lt; Switch_Obj_Max)
++ {
++ SLang_free_object (Switch_Obj_Ptr);
++ Switch_Obj_Ptr++;
++ }
++ Switch_Obj_Ptr = Switch_Objects;
++ }
++}
++
++static void compile_directive (unsigned char sub_type)
++{
++ /* This function is called only from compile_directive_mode which is
++ * only possible when a block is available.
++ */
++
++ /* use BLOCK */
++ Compile_ByteCode_Ptr--;
++ Compile_ByteCode_Ptr-&gt;bc_sub_type = sub_type;
++
++ lang_try_now ();
++}
++
++static void compile_unary (int op, unsigned char mt)
++{
++ Compile_ByteCode_Ptr-&gt;bc_main_type = mt;
++ Compile_ByteCode_Ptr-&gt;b.i_blk = op;
++ Compile_ByteCode_Ptr-&gt;bc_sub_type = 0;
++
++ lang_try_now ();
++}
++
++
++static void compile_binary (int op)
++{
++ Compile_ByteCode_Ptr-&gt;bc_main_type = _SLANG_BC_BINARY;
++ Compile_ByteCode_Ptr-&gt;b.i_blk = op;
++ Compile_ByteCode_Ptr-&gt;bc_sub_type = 0;
++
++ lang_try_now ();
++}
++
++#if _SLANG_OPTIMIZE_FOR_SPEED
++static int try_compressed_bytecode (unsigned char last_bc, unsigned char bc)
++{
++ if (Compile_ByteCode_Ptr != This_Compile_Block)
++ {
++ SLBlock_Type *b;
++ b = Compile_ByteCode_Ptr - 1;
++ if (b-&gt;bc_main_type == last_bc)
++ {
++ Compile_ByteCode_Ptr = b;
++ b-&gt;bc_main_type = bc;
++ lang_try_now ();
++ return 0;
++ }
++ }
++ return -1;
++}
++#endif
++
++static void compile_fast_binary (int op, unsigned char bc)
++{
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ if (0 == try_compressed_bytecode (_SLANG_BC_LITERAL_INT, bc))
++ return;
++#else
++ (void) bc;
++#endif
++ compile_binary (op);
++}
++
++/* This is a hack */
++typedef struct _Special_NameTable_Type
++{
++ char *name;
++ int (*fun) (struct _Special_NameTable_Type *, _SLang_Token_Type *);
++ VOID_STAR blk_data;
++ unsigned char main_type;
++}
++Special_NameTable_Type;
++
++static int handle_special (Special_NameTable_Type *nt, _SLang_Token_Type *tok)
++{
++ (void) tok;
++ Compile_ByteCode_Ptr-&gt;bc_main_type = nt-&gt;main_type;
++ Compile_ByteCode_Ptr-&gt;b.ptr_blk = nt-&gt;blk_data;
++ return 0;
++}
++
++static int handle_special_file (Special_NameTable_Type *nt, _SLang_Token_Type *tok)
++{
++ char *name;
++
++ (void) nt; (void) tok;
++
++ if (This_Static_NameSpace == NULL) name = &quot;***Unknown***&quot;;
++ else
++ name = This_Static_NameSpace-&gt;name;
++
++ name = SLang_create_slstring (name);
++ if (name == NULL)
++ return -1;
++
++ Compile_ByteCode_Ptr-&gt;b.s_blk = name;
++ Compile_ByteCode_Ptr-&gt;bc_main_type = _SLANG_BC_LITERAL_STR;
++ Compile_ByteCode_Ptr-&gt;bc_sub_type = SLANG_STRING_TYPE;
++ return 0;
++}
++
++static int handle_special_line (Special_NameTable_Type *nt, _SLang_Token_Type *tok)
++{
++ (void) nt;
++
++#if _SLANG_HAS_DEBUG_CODE
++ Compile_ByteCode_Ptr-&gt;b.l_blk = (long) tok-&gt;line_number;
++#endif
++ Compile_ByteCode_Ptr-&gt;bc_main_type = _SLANG_BC_LITERAL;
++ Compile_ByteCode_Ptr-&gt;bc_sub_type = SLANG_UINT_TYPE;
++
++ return 0;
++}
++
++static Special_NameTable_Type Special_Name_Table [] =
++{
++ {&quot;EXECUTE_ERROR_BLOCK&quot;, handle_special, NULL, _SLANG_BC_X_ERROR},
++ {&quot;X_USER_BLOCK0&quot;, handle_special, NULL, _SLANG_BC_X_USER0},
++ {&quot;X_USER_BLOCK1&quot;, handle_special, NULL, _SLANG_BC_X_USER1},
++ {&quot;X_USER_BLOCK2&quot;, handle_special, NULL, _SLANG_BC_X_USER2},
++ {&quot;X_USER_BLOCK3&quot;, handle_special, NULL, _SLANG_BC_X_USER3},
++ {&quot;X_USER_BLOCK4&quot;, handle_special, NULL, _SLANG_BC_X_USER4},
++ {&quot;__FILE__&quot;, handle_special_file, NULL, 0},
++ {&quot;__LINE__&quot;, handle_special_line, NULL, 0},
++#if 0
++ {&quot;__NAMESPACE__&quot;, handle_special_namespace, NULL, 0},
++#endif
++ {NULL, NULL, NULL, 0}
++};
++
++static void compile_hashed_identifier (char *name, unsigned long hash, _SLang_Token_Type *tok)
++{
++ SLang_Name_Type *entry;
++ unsigned char name_type;
++
++ entry = locate_hashed_name (name, hash);
++
++ if (entry == NULL)
++ {
++ Special_NameTable_Type *nt = Special_Name_Table;
++
++ while (nt-&gt;name != NULL)
++ {
++ if (strcmp (name, nt-&gt;name))
++ {
++ nt++;
++ continue;
++ }
++
++ if (0 == (*nt-&gt;fun)(nt, tok))
++ lang_try_now ();
++ return;
++ }
++
++ SLang_verror (SL_UNDEFINED_NAME, &quot;%s is undefined&quot;, name);
++ return;
++ }
++
++ name_type = entry-&gt;name_type;
++ Compile_ByteCode_Ptr-&gt;bc_main_type = name_type;
++
++ if (name_type == SLANG_LVARIABLE)
++ Compile_ByteCode_Ptr-&gt;b.i_blk = ((SLang_Local_Var_Type *) entry)-&gt;local_var_number;
++ else
++ Compile_ByteCode_Ptr-&gt;b.nt_blk = entry;
++
++ lang_try_now ();
++}
++
++static void compile_tmp_variable (char *name, unsigned long hash)
++{
++ SLang_Name_Type *entry;
++ unsigned char name_type;
++
++ if (NULL == (entry = locate_hashed_name (name, hash)))
++ {
++ SLang_verror (SL_UNDEFINED_NAME, &quot;%s is undefined&quot;, name);
++ return;
++ }
++
++ name_type = entry-&gt;name_type;
++ switch (name_type)
++ {
++ case SLANG_LVARIABLE:
++ Compile_ByteCode_Ptr-&gt;b.i_blk = ((SLang_Local_Var_Type *) entry)-&gt;local_var_number;
++ break;
++
++ case SLANG_GVARIABLE:
++ case SLANG_PVARIABLE:
++ Compile_ByteCode_Ptr-&gt;b.nt_blk = entry;
++ break;
++
++ default:
++ SLang_verror (SL_SYNTAX_ERROR, &quot;__tmp(%s) does not specifiy a variable&quot;, name);
++ return;
++ }
++
++ Compile_ByteCode_Ptr-&gt;bc_main_type = _SLANG_BC_TMP;
++ Compile_ByteCode_Ptr-&gt;bc_sub_type = name_type;
++
++ lang_try_now ();
++}
++
++static void compile_simple (unsigned char main_type)
++{
++ Compile_ByteCode_Ptr-&gt;bc_main_type = main_type;
++ Compile_ByteCode_Ptr-&gt;bc_sub_type = 0;
++ Compile_ByteCode_Ptr-&gt;b.blk = NULL;
++ lang_try_now ();
++}
++
++static void compile_identifier (char *name, _SLang_Token_Type *tok)
++{
++ compile_hashed_identifier (name, _SLcompute_string_hash (name), tok);
++}
++
++static void compile_call_direct (int (*f) (void), unsigned char byte_code)
++{
++ Compile_ByteCode_Ptr-&gt;b.call_function = f;
++ Compile_ByteCode_Ptr-&gt;bc_main_type = byte_code;
++ Compile_ByteCode_Ptr-&gt;bc_sub_type = 0;
++ lang_try_now ();
++}
++
++static void compile_lvar_call_direct (int (*f)(void), unsigned char bc,
++ unsigned char frame_op)
++{
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ if (0 == try_compressed_bytecode (_SLANG_BC_LVARIABLE, bc))
++ return;
++#else
++ (void) bc;
++#endif
++
++ compile_call_direct (f, frame_op);
++}
++
++static void compile_integer (long i, unsigned char bc_main_type, unsigned char bc_sub_type)
++{
++ Compile_ByteCode_Ptr-&gt;b.l_blk = i;
++ Compile_ByteCode_Ptr-&gt;bc_main_type = bc_main_type;
++ Compile_ByteCode_Ptr-&gt;bc_sub_type = bc_sub_type;
++
++ lang_try_now ();
++}
++
++#if SLANG_HAS_FLOAT
++static void compile_double (char *str, unsigned char type)
++{
++ double d;
++ unsigned int factor = 1;
++ double *ptr;
++
++#if 1
++ d = _SLang_atof (str);
++#else
++ if (1 != sscanf (str, &quot;%lf&quot;, &amp;d))
++ {
++ SLang_verror (SL_SYNTAX_ERROR, &quot;Unable to convert %s to double&quot;, str);
++ return;
++ }
++#endif
++
++#if SLANG_HAS_COMPLEX
++ if (type == SLANG_COMPLEX_TYPE) factor = 2;
++#endif
++ if (NULL == (ptr = (double *) SLmalloc(factor * sizeof(double))))
++ return;
++
++ Compile_ByteCode_Ptr-&gt;b.double_blk = ptr;
++#if SLANG_HAS_COMPLEX
++ if (type == SLANG_COMPLEX_TYPE)
++ *ptr++ = 0;
++#endif
++ *ptr = d;
++
++ Compile_ByteCode_Ptr-&gt;bc_main_type = _SLANG_BC_LITERAL;
++ Compile_ByteCode_Ptr-&gt;bc_sub_type = type;
++ lang_try_now ();
++}
++
++static void compile_float (char *s)
++{
++ float x;
++
++#if 1
++ x = (float) _SLang_atof (s);
++#else
++ if (1 != sscanf (s, &quot;%f&quot;, &amp;x))
++ {
++ SLang_verror (SL_SYNTAX_ERROR, &quot;Unable to convert %s to float&quot;, s);
++ return;
++ }
++#endif
++ Compile_ByteCode_Ptr-&gt;b.float_blk = x;
++ Compile_ByteCode_Ptr-&gt;bc_main_type = _SLANG_BC_LITERAL;
++ Compile_ByteCode_Ptr-&gt;bc_sub_type = SLANG_FLOAT_TYPE;
++ lang_try_now ();
++}
++
++#endif
++
++static void compile_string (char *s, unsigned long hash)
++{
++ if (NULL == (Compile_ByteCode_Ptr-&gt;b.s_blk = _SLstring_dup_hashed_string (s, hash)))
++ return;
++
++ Compile_ByteCode_Ptr-&gt;bc_main_type = _SLANG_BC_LITERAL_STR;
++ Compile_ByteCode_Ptr-&gt;bc_sub_type = SLANG_STRING_TYPE;
++
++ lang_try_now ();
++}
++
++static void compile_bstring (SLang_BString_Type *s)
++{
++ if (NULL == (Compile_ByteCode_Ptr-&gt;b.bs_blk = SLbstring_dup (s)))
++ return;
++
++ Compile_ByteCode_Ptr-&gt;bc_main_type = _SLANG_BC_LITERAL;
++ Compile_ByteCode_Ptr-&gt;bc_sub_type = SLANG_BSTRING_TYPE;
++
++ lang_try_now ();
++}
++
++/* assign_type is one of _SLANG_BCST_ASSIGN, ... values */
++static void compile_assign (unsigned char assign_type,
++ char *name, unsigned long hash)
++{
++ SLang_Name_Type *v;
++ unsigned char main_type;
++ SLang_Class_Type *cl;
++
++ v = locate_hashed_name (name, hash);
++ if (v == NULL)
++ {
++ if ((_SLang_Auto_Declare_Globals == 0)
++ || (NULL != strchr (name, '-')) /* namespace-&gt;name form */
++ || Lang_Defining_Function
++ || (assign_type != _SLANG_BCST_ASSIGN)
++ || (This_Static_NameSpace == NULL))
++ {
++ SLang_verror (SL_UNDEFINED_NAME, &quot;%s is undefined&quot;, name);
++ return;
++ }
++ /* Note that function local variables are not at top level */
++
++ /* Variables that are automatically declared are given static
++ * scope.
++ */
++ if ((NULL != SLang_Auto_Declare_Var_Hook)
++ &amp;&amp; (-1 == (*SLang_Auto_Declare_Var_Hook) (name)))
++ return;
++
++ if ((-1 == add_global_variable (name, SLANG_GVARIABLE, hash, This_Static_NameSpace))
++ || (NULL == (v = locate_hashed_name (name, hash))))
++ return;
++ }
++
++ switch (v-&gt;name_type)
++ {
++ case SLANG_LVARIABLE:
++ main_type = _SLANG_BC_SET_LOCAL_LVALUE;
++ Compile_ByteCode_Ptr-&gt;b.i_blk = ((SLang_Local_Var_Type *) v)-&gt;local_var_number;
++ break;
++
++ case SLANG_GVARIABLE:
++ case SLANG_PVARIABLE:
++ main_type = _SLANG_BC_SET_GLOBAL_LVALUE;
++ Compile_ByteCode_Ptr-&gt;b.nt_blk = v;
++ break;
++
++ case SLANG_IVARIABLE:
++ cl = _SLclass_get_class (((SLang_Intrin_Var_Type *)v)-&gt;type);
++ if (cl-&gt;cl_class_type != SLANG_CLASS_TYPE_SCALAR)
++ {
++ SLang_verror (SL_SYNTAX_ERROR, &quot;Assignment to %s is not allowed&quot;, name);
++ return;
++ }
++ main_type = _SLANG_BC_SET_INTRIN_LVALUE;
++ Compile_ByteCode_Ptr-&gt;b.nt_blk = v;
++ break;
++
++ case SLANG_RVARIABLE:
++ SLang_verror (SL_READONLY_ERROR, &quot;%s is read-only&quot;, name);
++ return;
++
++ default:
++ SLang_verror (SL_DUPLICATE_DEFINITION, &quot;%s may not be used as an lvalue&quot;, name);
++ return;
++ }
++
++ Compile_ByteCode_Ptr-&gt;bc_sub_type = assign_type;
++ Compile_ByteCode_Ptr-&gt;bc_main_type = main_type;
++
++ lang_try_now ();
++}
++
++static void compile_deref_assign (char *name, unsigned long hash)
++{
++ SLang_Name_Type *v;
++
++ v = locate_hashed_name (name, hash);
++
++ if (v == NULL)
++ {
++ SLang_verror (SL_UNDEFINED_NAME, &quot;%s is undefined&quot;, name);
++ return;
++ }
++
++ switch (v-&gt;name_type)
++ {
++ case SLANG_LVARIABLE:
++ Compile_ByteCode_Ptr-&gt;b.i_blk = ((SLang_Local_Var_Type *) v)-&gt;local_var_number;
++ break;
++
++ case SLANG_GVARIABLE:
++ case SLANG_PVARIABLE:
++ Compile_ByteCode_Ptr-&gt;b.nt_blk = v;
++ break;
++
++ default:
++ /* FIXME: Priority=low
++ * This could be made to work. It is not a priority because
++ * I cannot imagine application intrinsics which are references.
++ */
++ SLang_verror (SL_NOT_IMPLEMENTED, &quot;Deref assignment to %s is not allowed&quot;, name);
++ return;
++ }
++
++ Compile_ByteCode_Ptr-&gt;bc_sub_type = v-&gt;name_type;
++ Compile_ByteCode_Ptr-&gt;bc_main_type = _SLANG_BC_DEREF_ASSIGN;
++
++ lang_try_now ();
++}
++
++static void
++compile_struct_assign (_SLang_Token_Type *t)
++{
++ Compile_ByteCode_Ptr-&gt;bc_sub_type = _SLANG_BCST_ASSIGN + (t-&gt;type - _STRUCT_ASSIGN_TOKEN);
++ Compile_ByteCode_Ptr-&gt;bc_main_type = _SLANG_BC_SET_STRUCT_LVALUE;
++ Compile_ByteCode_Ptr-&gt;b.s_blk = _SLstring_dup_hashed_string (t-&gt;v.s_val, t-&gt;hash);
++ lang_try_now ();
++}
++
++static void
++compile_array_assign (_SLang_Token_Type *t)
++{
++ Compile_ByteCode_Ptr-&gt;bc_sub_type = _SLANG_BCST_ASSIGN + (t-&gt;type - _ARRAY_ASSIGN_TOKEN);
++ Compile_ByteCode_Ptr-&gt;bc_main_type = _SLANG_BC_SET_ARRAY_LVALUE;
++ Compile_ByteCode_Ptr-&gt;b.s_blk = NULL;
++ lang_try_now ();
++}
++
++static void compile_dot(_SLang_Token_Type *t)
++{
++ Compile_ByteCode_Ptr-&gt;bc_main_type = _SLANG_BC_FIELD;
++ Compile_ByteCode_Ptr-&gt;b.s_blk = _SLstring_dup_hashed_string(t-&gt;v.s_val, t-&gt;hash);
++ lang_try_now ();
++}
++
++static void compile_ref (char *name, unsigned long hash)
++{
++ SLang_Name_Type *entry;
++ unsigned char main_type;
++
++ if (NULL == (entry = locate_hashed_name (name, hash)))
++ {
++ SLang_verror (SL_UNDEFINED_NAME, &quot;%s is undefined&quot;, name);
++ return;
++ }
++
++ main_type = entry-&gt;name_type;
++
++ if (main_type == SLANG_LVARIABLE)
++ {
++ main_type = _SLANG_BC_LOBJPTR;
++ Compile_ByteCode_Ptr-&gt;b.i_blk = ((SLang_Local_Var_Type *)entry)-&gt;local_var_number;
++ }
++ else
++ {
++ main_type = _SLANG_BC_GOBJPTR;
++ Compile_ByteCode_Ptr-&gt;b.nt_blk = entry;
++ }
++
++ Compile_ByteCode_Ptr-&gt;bc_main_type = main_type;
++ lang_try_now ();
++}
++
++static void compile_break (unsigned char break_type,
++ int requires_block, int requires_fun,
++ char *str)
++{
++ if ((requires_fun
++ &amp;&amp; (Lang_Defining_Function == 0))
++ || (requires_block
++ &amp;&amp; (This_Compile_Block_Type != COMPILE_BLOCK_TYPE_BLOCK)))
++ {
++ SLang_verror (SL_SYNTAX_ERROR, &quot;misplaced %s&quot;, str);
++ return;
++ }
++
++ Compile_ByteCode_Ptr-&gt;bc_main_type = break_type;
++ Compile_ByteCode_Ptr-&gt;bc_sub_type = 0;
++
++ lang_try_now ();
++}
++
++static void compile_public_variable_mode (_SLang_Token_Type *t)
++{
++ if (t-&gt;type == IDENT_TOKEN)
++ {
++ /* If the variable is already defined in the static hash table,
++ * generate an error.
++ */
++ if ((This_Static_NameSpace != NULL)
++ &amp;&amp; (NULL != locate_name_in_table (t-&gt;v.s_val, t-&gt;hash, This_Static_NameSpace-&gt;table, This_Static_NameSpace-&gt;table_size)))
++ {
++ SLang_verror (SL_DUPLICATE_DEFINITION,
++ &quot;%s already has static or private linkage in this unit&quot;,
++ t-&gt;v.s_val);
++ return;
++ }
++ add_global_variable (t-&gt;v.s_val, SLANG_GVARIABLE, t-&gt;hash, Global_NameSpace);
++ }
++ else if (t-&gt;type == CBRACKET_TOKEN)
++ Compile_Mode_Function = compile_basic_token_mode;
++ else
++ SLang_verror (SL_SYNTAX_ERROR, &quot;Misplaced token in variable list&quot;);
++}
++
++static void compile_local_variable_mode (_SLang_Token_Type *t)
++{
++ if (t-&gt;type == IDENT_TOKEN)
++ add_local_variable (t-&gt;v.s_val, t-&gt;hash);
++ else if (t-&gt;type == CBRACKET_TOKEN)
++ Compile_Mode_Function = compile_basic_token_mode;
++ else
++ SLang_verror (SL_SYNTAX_ERROR, &quot;Misplaced token in variable list&quot;);
++}
++
++static void compile_static_variable_mode (_SLang_Token_Type *t)
++{
++ if (t-&gt;type == IDENT_TOKEN)
++ add_global_variable (t-&gt;v.s_val, SLANG_GVARIABLE, t-&gt;hash, This_Static_NameSpace);
++ else if (t-&gt;type == CBRACKET_TOKEN)
++ Compile_Mode_Function = compile_basic_token_mode;
++ else
++ SLang_verror (SL_SYNTAX_ERROR, &quot;Misplaced token in variable list&quot;);
++}
++
++static void compile_private_variable_mode (_SLang_Token_Type *t)
++{
++ if (t-&gt;type == IDENT_TOKEN)
++ add_global_variable (t-&gt;v.s_val, SLANG_PVARIABLE, t-&gt;hash, This_Static_NameSpace);
++ else if (t-&gt;type == CBRACKET_TOKEN)
++ Compile_Mode_Function = compile_basic_token_mode;
++ else
++ SLang_verror (SL_SYNTAX_ERROR, &quot;Misplaced token in variable list&quot;);
++}
++
++static void compile_function_mode (_SLang_Token_Type *t)
++{
++ if (-1 == lang_check_space ())
++ return;
++
++ if (t-&gt;type != IDENT_TOKEN)
++ SLang_verror (SL_SYNTAX_ERROR, &quot;Expecting function name&quot;);
++ else
++ lang_define_function (t-&gt;v.s_val, SLANG_FUNCTION, t-&gt;hash, Global_NameSpace);
++
++ Compile_Mode_Function = compile_basic_token_mode;
++}
++
++/* An error block is not permitted to contain continue or break statements.
++ * This restriction may be removed later but for now reject them.
++ */
++static int check_error_block (void)
++{
++ SLBlock_Type *p;
++ unsigned char t;
++
++ /* Back up to the block and then scan it. */
++ p = (Compile_ByteCode_Ptr - 1)-&gt;b.blk;
++
++ while (0 != (t = p-&gt;bc_main_type))
++ {
++ if ((t == _SLANG_BC_BREAK)
++ || (t == _SLANG_BC_CONTINUE))
++ {
++ SLang_verror (SL_SYNTAX_ERROR,
++ &quot;An ERROR_BLOCK is not permitted to contain continue or break statements&quot;);
++ return -1;
++ }
++ p++;
++ }
++ return 0;
++}
++
++/* The only allowed tokens are the directives and another block start.
++ * The mode is only active if a block is available. The inner_interp routine
++ * expects such safety checks.
++ */
++static void compile_directive_mode (_SLang_Token_Type *t)
++{
++ int bc_sub_type;
++
++ if (-1 == lang_check_space ())
++ return;
++
++ bc_sub_type = -1;
++
++ switch (t-&gt;type)
++ {
++ case FOREVER_TOKEN:
++ bc_sub_type = _SLANG_BCST_FOREVER;
++ break;
++
++ case IFNOT_TOKEN:
++ bc_sub_type = _SLANG_BCST_IFNOT;
++ break;
++
++ case IF_TOKEN:
++ bc_sub_type = _SLANG_BCST_IF;
++ break;
++
++ case ANDELSE_TOKEN:
++ bc_sub_type = _SLANG_BCST_ANDELSE;
++ break;
++
++ case SWITCH_TOKEN:
++ bc_sub_type = _SLANG_BCST_SWITCH;
++ break;
++
++ case EXITBLK_TOKEN:
++ if (Lang_Defining_Function == 0)
++ {
++ SLang_verror (SL_SYNTAX_ERROR, &quot;misplaced EXIT_BLOCK&quot;);
++ break;
++ }
++ bc_sub_type = _SLANG_BCST_EXIT_BLOCK;
++ break;
++
++ case ERRBLK_TOKEN:
++ if (This_Compile_Block_Type == COMPILE_BLOCK_TYPE_TOP_LEVEL)
++ {
++ SLang_verror (SL_SYNTAX_ERROR, &quot;misplaced ERROR_BLOCK&quot;);
++ break;
++ }
++ if (0 == check_error_block ())
++ bc_sub_type = _SLANG_BCST_ERROR_BLOCK;
++ break;
++
++ case USRBLK0_TOKEN:
++ case USRBLK1_TOKEN:
++ case USRBLK2_TOKEN:
++ case USRBLK3_TOKEN:
++ case USRBLK4_TOKEN:
++ if (This_Compile_Block_Type == COMPILE_BLOCK_TYPE_TOP_LEVEL)
++ {
++ SLang_verror (SL_SYNTAX_ERROR, &quot;misplaced USER_BLOCK&quot;);
++ break;
++ }
++ bc_sub_type = _SLANG_BCST_USER_BLOCK0 + (t-&gt;type - USRBLK0_TOKEN);
++ break;
++
++ case NOTELSE_TOKEN:
++ bc_sub_type = _SLANG_BCST_NOTELSE;
++ break;
++
++ case ELSE_TOKEN:
++ bc_sub_type = _SLANG_BCST_ELSE;
++ break;
++
++ case LOOP_TOKEN:
++ bc_sub_type = _SLANG_BCST_LOOP;
++ break;
++
++ case DOWHILE_TOKEN:
++ bc_sub_type = _SLANG_BCST_DOWHILE;
++ break;
++
++ case WHILE_TOKEN:
++ bc_sub_type = _SLANG_BCST_WHILE;
++ break;
++
++ case ORELSE_TOKEN:
++ bc_sub_type = _SLANG_BCST_ORELSE;
++ break;
++
++ case _FOR_TOKEN:
++ bc_sub_type = _SLANG_BCST_FOR;
++ break;
++
++ case FOR_TOKEN:
++ bc_sub_type = _SLANG_BCST_CFOR;
++ break;
++
++ case FOREACH_TOKEN:
++ bc_sub_type = _SLANG_BCST_FOREACH;
++ break;
++
++ case OBRACE_TOKEN:
++ lang_begin_block ();
++ break;
++
++ default:
++ SLang_verror (SL_SYNTAX_ERROR, &quot;Expecting directive token. Found 0x%X&quot;, t-&gt;type);
++ break;
++ }
++
++ /* Reset this pointer first because compile_directive may cause a
++ * file to be loaded.
++ */
++ Compile_Mode_Function = compile_basic_token_mode;
++
++ if (bc_sub_type != -1)
++ compile_directive (bc_sub_type);
++}
++
++static unsigned int Assign_Mode_Type;
++static void compile_assign_mode (_SLang_Token_Type *t)
++{
++ if (t-&gt;type != IDENT_TOKEN)
++ {
++ SLang_verror (SL_SYNTAX_ERROR, &quot;Expecting identifier for assignment&quot;);
++ return;
++ }
++
++ compile_assign (Assign_Mode_Type, t-&gt;v.s_val, t-&gt;hash);
++ Compile_Mode_Function = compile_basic_token_mode;
++}
++
++static void compile_basic_token_mode (_SLang_Token_Type *t)
++{
++ if (-1 == lang_check_space ())
++ return;
++
++ switch (t-&gt;type)
++ {
++ case PUSH_TOKEN:
++ case NOP_TOKEN:
++ case EOF_TOKEN:
++ case READONLY_TOKEN:
++ case DO_TOKEN:
++ case VARIABLE_TOKEN:
++ case SEMICOLON_TOKEN:
++ default:
++ SLang_verror (SL_SYNTAX_ERROR, &quot;Unknown or unsupported token type 0x%X&quot;, t-&gt;type);
++ break;
++
++ case DEREF_TOKEN:
++ compile_call_direct (dereference_object, _SLANG_BC_CALL_DIRECT);
++ break;
++
++ case STRUCT_TOKEN:
++ compile_call_direct (_SLstruct_define_struct, _SLANG_BC_CALL_DIRECT);
++ break;
++
++ case TYPEDEF_TOKEN:
++ compile_call_direct (_SLstruct_define_typedef, _SLANG_BC_CALL_DIRECT);
++ break;
++
++ case TMP_TOKEN:
++ compile_tmp_variable (t-&gt;v.s_val, t-&gt;hash);
++ break;
++
++ case DOT_TOKEN: /* X . field */
++ compile_dot (t);
++ break;
++
++ case COMMA_TOKEN:
++ break; /* do nothing */
++
++ case IDENT_TOKEN:
++ compile_hashed_identifier (t-&gt;v.s_val, t-&gt;hash, t);
++ break;
++
++ case _REF_TOKEN:
++ compile_ref (t-&gt;v.s_val, t-&gt;hash);
++ break;
++
++ case ARG_TOKEN:
++ compile_call_direct (SLang_start_arg_list, _SLANG_BC_CALL_DIRECT);
++ break;
++
++ case EARG_TOKEN:
++ compile_lvar_call_direct (SLang_end_arg_list, _SLANG_BC_EARG_LVARIABLE, _SLANG_BC_CALL_DIRECT);
++ break;
++
++ case COLON_TOKEN:
++ if (This_Compile_Block_Type == COMPILE_BLOCK_TYPE_BLOCK)
++ compile_simple (_SLANG_BC_LABEL);
++ else SLang_Error = SL_SYNTAX_ERROR;
++ break;
++
++ case POP_TOKEN:
++ compile_call_direct (SLdo_pop, _SLANG_BC_CALL_DIRECT);
++ break;
++
++ case CASE_TOKEN:
++ if (This_Compile_Block_Type != COMPILE_BLOCK_TYPE_BLOCK)
++ SLang_verror (SL_SYNTAX_ERROR, &quot;Misplaced 'case'&quot;);
++ else
++ compile_call_direct (case_function, _SLANG_BC_CALL_DIRECT);
++ break;
++
++ case CHAR_TOKEN:
++ compile_integer (t-&gt;v.long_val, _SLANG_BC_LITERAL, SLANG_CHAR_TYPE);
++ break;
++ case SHORT_TOKEN:
++ compile_integer (t-&gt;v.long_val, _SLANG_BC_LITERAL, SLANG_SHORT_TYPE);
++ break;
++ case INT_TOKEN:
++ compile_integer (t-&gt;v.long_val, _SLANG_BC_LITERAL_INT, SLANG_INT_TYPE);
++ break;
++ case UCHAR_TOKEN:
++ compile_integer (t-&gt;v.long_val, _SLANG_BC_LITERAL, SLANG_UCHAR_TYPE);
++ break;
++ case USHORT_TOKEN:
++ compile_integer (t-&gt;v.long_val, _SLANG_BC_LITERAL, SLANG_USHORT_TYPE);
++ break;
++ case UINT_TOKEN:
++ compile_integer (t-&gt;v.long_val, _SLANG_BC_LITERAL_INT, SLANG_UINT_TYPE);
++ break;
++ case LONG_TOKEN:
++ compile_integer (t-&gt;v.long_val, _SLANG_BC_LITERAL, SLANG_LONG_TYPE);
++ break;
++ case ULONG_TOKEN:
++ compile_integer (t-&gt;v.long_val, _SLANG_BC_LITERAL, SLANG_ULONG_TYPE);
++ break;
++
++#if SLANG_HAS_FLOAT
++ case FLOAT_TOKEN:
++ compile_float (t-&gt;v.s_val);
++ break;
++
++ case DOUBLE_TOKEN:
++ compile_double (t-&gt;v.s_val, SLANG_DOUBLE_TYPE);
++ break;
++#endif
++#if SLANG_HAS_COMPLEX
++ case COMPLEX_TOKEN:
++ compile_double (t-&gt;v.s_val, SLANG_COMPLEX_TYPE);
++ break;
++#endif
++
++ case STRING_TOKEN:
++ compile_string (t-&gt;v.s_val, t-&gt;hash);
++ break;
++
++ case _BSTRING_TOKEN:
++ compile_bstring (SLbstring_create ((unsigned char *)t-&gt;v.s_val, (unsigned int) t-&gt;hash));
++ break;
++
++ case BSTRING_TOKEN:
++ compile_bstring (t-&gt;v.b_val);
++ break;
++
++ case _NULL_TOKEN:
++ compile_identifier (&quot;NULL&quot;, t);
++ break;
++
++ case _INLINE_WILDCARD_ARRAY_TOKEN:
++ compile_call_direct (_SLarray_wildcard_array, _SLANG_BC_CALL_DIRECT);
++ break;
++
++ case _INLINE_ARRAY_TOKEN:
++ compile_call_direct (_SLarray_inline_array, _SLANG_BC_CALL_DIRECT_FRAME);
++ break;
++
++ case _INLINE_IMPLICIT_ARRAY_TOKEN:
++ compile_call_direct (_SLarray_inline_implicit_array, _SLANG_BC_CALL_DIRECT_FRAME);
++ break;
++
++ case ARRAY_TOKEN:
++ compile_lvar_call_direct (_SLarray_aget, _SLANG_BC_LVARIABLE_AGET, _SLANG_BC_CALL_DIRECT_FRAME);
++ break;
++
++ /* Note: I need to add the other _ARRAY assign tokens. */
++ case _ARRAY_PLUSEQS_TOKEN:
++ case _ARRAY_MINUSEQS_TOKEN:
++ case _ARRAY_TIMESEQS_TOKEN:
++ case _ARRAY_DIVEQS_TOKEN:
++ case _ARRAY_BOREQS_TOKEN:
++ case _ARRAY_BANDEQS_TOKEN:
++ case _ARRAY_POST_MINUSMINUS_TOKEN:
++ case _ARRAY_MINUSMINUS_TOKEN:
++ case _ARRAY_POST_PLUSPLUS_TOKEN:
++ case _ARRAY_PLUSPLUS_TOKEN:
++ compile_array_assign (t);
++ break;
++
++ case _ARRAY_ASSIGN_TOKEN:
++ compile_lvar_call_direct (_SLarray_aput, _SLANG_BC_LVARIABLE_APUT, _SLANG_BC_CALL_DIRECT_FRAME);
++ break;
++
++ case _STRUCT_ASSIGN_TOKEN:
++ case _STRUCT_PLUSEQS_TOKEN:
++ case _STRUCT_MINUSEQS_TOKEN:
++ case _STRUCT_TIMESEQS_TOKEN:
++ case _STRUCT_DIVEQS_TOKEN:
++ case _STRUCT_BOREQS_TOKEN:
++ case _STRUCT_BANDEQS_TOKEN:
++ case _STRUCT_POST_MINUSMINUS_TOKEN:
++ case _STRUCT_MINUSMINUS_TOKEN:
++ case _STRUCT_POST_PLUSPLUS_TOKEN:
++ case _STRUCT_PLUSPLUS_TOKEN:
++ compile_struct_assign (t);
++ break;
++
++ case _SCALAR_ASSIGN_TOKEN:
++ case _SCALAR_PLUSEQS_TOKEN:
++ case _SCALAR_MINUSEQS_TOKEN:
++ case _SCALAR_TIMESEQS_TOKEN:
++ case _SCALAR_DIVEQS_TOKEN:
++ case _SCALAR_BOREQS_TOKEN:
++ case _SCALAR_BANDEQS_TOKEN:
++ case _SCALAR_POST_MINUSMINUS_TOKEN:
++ case _SCALAR_MINUSMINUS_TOKEN:
++ case _SCALAR_POST_PLUSPLUS_TOKEN:
++ case _SCALAR_PLUSPLUS_TOKEN:
++ compile_assign (_SLANG_BCST_ASSIGN + (t-&gt;type - _SCALAR_ASSIGN_TOKEN),
++ t-&gt;v.s_val, t-&gt;hash);
++ break;
++
++ case _DEREF_ASSIGN_TOKEN:
++ compile_deref_assign (t-&gt;v.s_val, t-&gt;hash);
++ break;
++
++ /* For processing RPN tokens */
++ case ASSIGN_TOKEN:
++ case PLUSEQS_TOKEN:
++ case MINUSEQS_TOKEN:
++ case TIMESEQS_TOKEN:
++ case DIVEQS_TOKEN:
++ case BOREQS_TOKEN:
++ case BANDEQS_TOKEN:
++ case POST_MINUSMINUS_TOKEN:
++ case MINUSMINUS_TOKEN:
++ case POST_PLUSPLUS_TOKEN:
++ case PLUSPLUS_TOKEN:
++ Compile_Mode_Function = compile_assign_mode;
++ Assign_Mode_Type = _SLANG_BCST_ASSIGN + (t-&gt;type - ASSIGN_TOKEN);
++ break;
++
++ case LT_TOKEN:
++ compile_binary (SLANG_LT);
++ break;
++
++ case LE_TOKEN:
++ compile_binary (SLANG_LE);
++ break;
++
++ case GT_TOKEN:
++ compile_binary (SLANG_GT);
++ break;
++
++ case GE_TOKEN:
++ compile_binary (SLANG_GE);
++ break;
++
++ case EQ_TOKEN:
++ compile_binary (SLANG_EQ);
++ break;
++
++ case NE_TOKEN:
++ compile_binary (SLANG_NE);
++ break;
++
++ case AND_TOKEN:
++ compile_binary (SLANG_AND);
++ break;
++
++ case ADD_TOKEN:
++ compile_fast_binary (SLANG_PLUS, _SLANG_BC_INTEGER_PLUS);
++ break;
++
++ case SUB_TOKEN:
++ compile_fast_binary (SLANG_MINUS, _SLANG_BC_INTEGER_MINUS);
++ break;
++
++ case TIMES_TOKEN:
++ compile_binary (SLANG_TIMES);
++ break;
++
++ case DIV_TOKEN:
++ compile_binary (SLANG_DIVIDE);
++ break;
++
++ case POW_TOKEN:
++ compile_binary (SLANG_POW);
++ break;
++
++ case BXOR_TOKEN:
++ compile_binary (SLANG_BXOR);
++ break;
++
++ case BAND_TOKEN:
++ compile_binary (SLANG_BAND);
++ break;
++
++ case BOR_TOKEN:
++ compile_binary (SLANG_BOR);
++ break;
++
++ case SHR_TOKEN:
++ compile_binary (SLANG_SHR);
++ break;
++
++ case SHL_TOKEN:
++ compile_binary (SLANG_SHL);
++ break;
++
++ case MOD_TOKEN:
++ compile_binary (SLANG_MOD);
++ break;
++
++ case OR_TOKEN:
++ compile_binary (SLANG_OR);
++ break;
++
++ case NOT_TOKEN:
++ compile_unary (SLANG_NOT, _SLANG_BC_UNARY);
++ break;
++
++ case BNOT_TOKEN:
++ compile_unary (SLANG_BNOT, _SLANG_BC_UNARY);
++ break;
++
++ case MUL2_TOKEN:
++ compile_unary (SLANG_MUL2, _SLANG_BC_UNARY_FUNC);
++ break;
++
++ case CHS_TOKEN:
++ compile_unary (SLANG_CHS, _SLANG_BC_UNARY_FUNC);
++ break;
++
++ case ABS_TOKEN:
++ compile_unary (SLANG_ABS, _SLANG_BC_UNARY_FUNC);
++ break;
++
++ case SQR_TOKEN:
++ compile_unary (SLANG_SQR, _SLANG_BC_UNARY_FUNC);
++ break;
++
++ case SIGN_TOKEN:
++ compile_unary (SLANG_SIGN, _SLANG_BC_UNARY_FUNC);
++ break;
++
++ case BREAK_TOKEN:
++ compile_break (_SLANG_BC_BREAK, 1, 0, &quot;break&quot;);
++ break;
++
++ case RETURN_TOKEN:
++ compile_break (_SLANG_BC_RETURN, 0, 1, &quot;return&quot;);
++ break;
++
++ case CONT_TOKEN:
++ compile_break (_SLANG_BC_CONTINUE, 1, 0, &quot;continue&quot;);
++ break;
++
++ case EXCH_TOKEN:
++ compile_break (_SLANG_BC_EXCH, 0, 0, &quot;&quot;); /* FIXME: Priority=low */
++ break;
++
++ case STATIC_TOKEN:
++ if (Lang_Defining_Function == 0)
++ Compile_Mode_Function = compile_static_variable_mode;
++ else
++ SLang_verror (SL_NOT_IMPLEMENTED, &quot;static variables not permitted in functions&quot;);
++ break;
++
++ case PRIVATE_TOKEN:
++ if (Lang_Defining_Function == 0)
++ Compile_Mode_Function = compile_private_variable_mode;
++ else
++ SLang_verror (SL_NOT_IMPLEMENTED, &quot;private variables not permitted in functions&quot;);
++ break;
++
++ case PUBLIC_TOKEN:
++ if (Lang_Defining_Function == 0)
++ Compile_Mode_Function = compile_public_variable_mode;
++ else
++ SLang_verror (SL_NOT_IMPLEMENTED, &quot;public variables not permitted in functions&quot;);
++ break;
++
++ case OBRACKET_TOKEN:
++ if (Lang_Defining_Function == 0)
++ Compile_Mode_Function = Default_Variable_Mode;
++ else
++ Compile_Mode_Function = compile_local_variable_mode;
++ break;
++
++ case OPAREN_TOKEN:
++ lang_begin_function ();
++ break;
++
++ case DEFINE_STATIC_TOKEN:
++ if (Lang_Defining_Function)
++ define_static_function (t-&gt;v.s_val, t-&gt;hash);
++ else SLang_Error = SL_SYNTAX_ERROR;
++ break;
++
++ case DEFINE_PRIVATE_TOKEN:
++ if (Lang_Defining_Function)
++ define_private_function (t-&gt;v.s_val, t-&gt;hash);
++ else SLang_Error = SL_SYNTAX_ERROR;
++ break;
++
++ case DEFINE_PUBLIC_TOKEN:
++ if (Lang_Defining_Function)
++ define_public_function (t-&gt;v.s_val, t-&gt;hash);
++ else SLang_Error = SL_SYNTAX_ERROR;
++ break;
++
++ case DEFINE_TOKEN:
++ if (Lang_Defining_Function)
++ (*Default_Define_Function) (t-&gt;v.s_val, t-&gt;hash);
++ else
++ SLang_Error = SL_SYNTAX_ERROR;
++ break;
++
++ case CPAREN_TOKEN:
++ if (Lang_Defining_Function)
++ Compile_Mode_Function = compile_function_mode;
++ else SLang_Error = SL_SYNTAX_ERROR;
++ break;
++
++ case CBRACE_TOKEN:
++ lang_end_block ();
++ Compile_Mode_Function = compile_directive_mode;
++ break;
++
++ case OBRACE_TOKEN:
++ lang_begin_block ();
++ break;
++
++ case FARG_TOKEN:
++ Function_Args_Number = Local_Variable_Number;
++ break;
++
++#if _SLANG_HAS_DEBUG_CODE
++ case LINE_NUM_TOKEN:
++ Compile_ByteCode_Ptr-&gt;bc_main_type = _SLANG_BC_LINE_NUM;
++ Compile_ByteCode_Ptr-&gt;b.l_blk = t-&gt;v.long_val;
++ lang_try_now ();
++ break;
++#endif
++ case POUND_TOKEN:
++ compile_call_direct (_SLarray_matrix_multiply, _SLANG_BC_CALL_DIRECT);
++ break;
++ }
++}
++
++void _SLcompile (_SLang_Token_Type *t)
++{
++ if (SLang_Error == 0)
++ {
++ if (Compile_Mode_Function != compile_basic_token_mode)
++ {
++ if (Compile_Mode_Function == NULL)
++ Compile_Mode_Function = compile_basic_token_mode;
++#if _SLANG_HAS_DEBUG_CODE
++ if (t-&gt;type == LINE_NUM_TOKEN)
++ {
++ compile_basic_token_mode (t);
++ return;
++ }
++#endif
++ }
++
++ (*Compile_Mode_Function) (t);
++ }
++
++ if (SLang_Error)
++ {
++ Compile_Mode_Function = compile_basic_token_mode;
++ SLang_restart (0);
++ }
++}
++
++void (*_SLcompile_ptr)(_SLang_Token_Type *) = _SLcompile;
++
++typedef struct _Compile_Context_Type
++{
++ struct _Compile_Context_Type *next;
++ SLang_NameSpace_Type *static_namespace;
++ void (*compile_variable_mode) (_SLang_Token_Type *);
++ void (*define_function) (char *, unsigned long);
++ int lang_defining_function;
++ int local_variable_number;
++ unsigned int function_args_number;
++ SLang_Name_Type **locals_hash_table;
++ void (*compile_mode_function)(_SLang_Token_Type *);
++#if _SLANG_HAS_DEBUG_CODE
++ char *compile_filename;
++#endif
++}
++Compile_Context_Type;
++
++static Compile_Context_Type *Compile_Context_Stack;
++
++/* The only way the push/pop_context functions can get called is via
++ * an eval type function. That can only happen when executed from a
++ * top level block. This means that Compile_ByteCode_Ptr can always be
++ * rest back to the beginning of a block.
++ */
++
++static int pop_compile_context (void)
++{
++ Compile_Context_Type *cc;
++
++ if (NULL == (cc = Compile_Context_Stack))
++ return -1;
++
++ This_Static_NameSpace = cc-&gt;static_namespace;
++ Compile_Context_Stack = cc-&gt;next;
++ Default_Variable_Mode = cc-&gt;compile_variable_mode;
++ Default_Define_Function = cc-&gt;define_function;
++ Compile_Mode_Function = cc-&gt;compile_mode_function;
++
++ Lang_Defining_Function = cc-&gt;lang_defining_function;
++ Local_Variable_Number = cc-&gt;local_variable_number;
++ Function_Args_Number = cc-&gt;function_args_number;
++
++#if _SLANG_HAS_DEBUG_CODE
++ SLang_free_slstring (This_Compile_Filename);
++ This_Compile_Filename = cc-&gt;compile_filename;
++#endif
++
++ SLfree ((char *) Locals_Hash_Table);
++ Locals_Hash_Table = cc-&gt;locals_hash_table;
++
++ SLfree ((char *) cc);
++
++ return 0;
++}
++
++static int push_compile_context (char *name)
++{
++ Compile_Context_Type *cc;
++ SLang_Name_Type **lns;
++
++ cc = (Compile_Context_Type *)SLmalloc (sizeof (Compile_Context_Type));
++ if (cc == NULL)
++ return -1;
++ memset ((char *) cc, 0, sizeof (Compile_Context_Type));
++
++ lns = (SLang_Name_Type **) SLcalloc (sizeof (SLang_Name_Type *), SLLOCALS_HASH_TABLE_SIZE);
++ if (lns == NULL)
++ {
++ SLfree ((char *) cc);
++ return -1;
++ }
++
++#if _SLANG_HAS_DEBUG_CODE
++ if ((name != NULL)
++ &amp;&amp; (NULL == (name = SLang_create_slstring (name))))
++ {
++ SLfree ((char *) cc);
++ SLfree ((char *) lns);
++ return -1;
++ }
++
++ cc-&gt;compile_filename = This_Compile_Filename;
++ This_Compile_Filename = name;
++#endif
++
++ cc-&gt;static_namespace = This_Static_NameSpace;
++ cc-&gt;compile_variable_mode = Default_Variable_Mode;
++ cc-&gt;define_function = Default_Define_Function;
++ cc-&gt;locals_hash_table = Locals_Hash_Table;
++
++ cc-&gt;lang_defining_function = Lang_Defining_Function;
++ cc-&gt;local_variable_number = Local_Variable_Number;
++ cc-&gt;function_args_number = Function_Args_Number;
++ cc-&gt;locals_hash_table = Locals_Hash_Table;
++ cc-&gt;compile_mode_function = Compile_Mode_Function;
++
++ cc-&gt;next = Compile_Context_Stack;
++ Compile_Context_Stack = cc;
++
++ Compile_Mode_Function = compile_basic_token_mode;
++ Default_Variable_Mode = compile_public_variable_mode;
++ Default_Define_Function = define_public_function;
++ Lang_Defining_Function = 0;
++ Local_Variable_Number = 0;
++ Function_Args_Number = 0;
++ Locals_Hash_Table = lns;
++ return 0;
++}
++
++static int init_interpreter (void)
++{
++ SLang_NameSpace_Type *ns;
++
++ if (Global_NameSpace != NULL)
++ return 0;
++
++ if (NULL == (ns = _SLns_allocate_namespace (&quot;***GLOBAL***&quot;, SLGLOBALS_HASH_TABLE_SIZE)))
++ return -1;
++ if (-1 == _SLns_set_namespace_name (ns, &quot;Global&quot;))
++ return -1;
++ Global_NameSpace = ns;
++
++ _SLRun_Stack = (SLang_Object_Type *) SLcalloc (SLANG_MAX_STACK_LEN,
++ sizeof (SLang_Object_Type));
++ if (_SLRun_Stack == NULL)
++ return -1;
++
++ _SLStack_Pointer = _SLRun_Stack;
++ _SLStack_Pointer_Max = _SLRun_Stack + SLANG_MAX_STACK_LEN;
++
++ SLShort_Blocks[0].bc_main_type = _SLANG_BC_RETURN;
++ SLShort_Blocks[2].bc_main_type = _SLANG_BC_BREAK;
++ SLShort_Blocks[4].bc_main_type = _SLANG_BC_CONTINUE;
++
++ Num_Args_Stack = (int *) SLmalloc (sizeof (int) * SLANG_MAX_RECURSIVE_DEPTH);
++ if (Num_Args_Stack == NULL)
++ {
++ SLfree ((char *) _SLRun_Stack);
++ return -1;
++ }
++ Recursion_Depth = 0;
++ Frame_Pointer_Stack = (unsigned int *) SLmalloc (sizeof (unsigned int) * SLANG_MAX_RECURSIVE_DEPTH);
++ if (Frame_Pointer_Stack == NULL)
++ {
++ SLfree ((char *) _SLRun_Stack);
++ SLfree ((char *)Num_Args_Stack);
++ return -1;
++ }
++ Frame_Pointer_Depth = 0;
++ Frame_Pointer = _SLRun_Stack;
++
++ Default_Variable_Mode = compile_public_variable_mode;
++ Default_Define_Function = define_public_function;
++ return 0;
++}
++
++static int add_generic_table (SLang_NameSpace_Type *ns,
++ SLang_Name_Type *table, char *pp_name,
++ unsigned int entry_len)
++{
++ SLang_Name_Type *t, **ns_table;
++ char *name;
++ unsigned int table_size;
++
++ if (-1 == init_interpreter ())
++ return -1;
++
++ if (ns == NULL)
++ ns = Global_NameSpace;
++
++ ns_table = ns-&gt;table;
++ table_size = ns-&gt;table_size;
++
++ if ((pp_name != NULL)
++ &amp;&amp; (-1 == SLdefine_for_ifdef (pp_name)))
++ return -1;
++
++ t = table;
++ while (NULL != (name = t-&gt;name))
++ {
++ unsigned long hash;
++
++ /* Backward compatibility: '.' WAS used as hash marker */
++ if (*name == '.')
++ {
++ name++;
++ t-&gt;name = name;
++ }
++
++ if (NULL == (name = SLang_create_slstring (name)))
++ return -1;
++
++ t-&gt;name = name;
++
++ hash = _SLcompute_string_hash (name);
++ hash = hash % table_size;
++
++ t-&gt;next = ns_table [(unsigned int) hash];
++ ns_table [(unsigned int) hash] = t;
++
++ t = (SLang_Name_Type *) ((char *)t + entry_len);
++ }
++
++ return 0;
++}
++
++int SLadd_intrin_fun_table (SLang_Intrin_Fun_Type *tbl, char *pp)
++{
++ return add_generic_table (NULL, (SLang_Name_Type *) tbl, pp, sizeof (SLang_Intrin_Fun_Type));
++}
++
++int SLadd_intrin_var_table (SLang_Intrin_Var_Type *tbl, char *pp)
++{
++ return add_generic_table (NULL, (SLang_Name_Type *) tbl, pp, sizeof (SLang_Intrin_Var_Type));
++}
++
++int SLadd_app_unary_table (SLang_App_Unary_Type *tbl, char *pp)
++{
++ return add_generic_table (NULL, (SLang_Name_Type *) tbl, pp, sizeof (SLang_App_Unary_Type));
++}
++
++int SLadd_math_unary_table (SLang_Math_Unary_Type *tbl, char *pp)
++{
++ return add_generic_table (NULL, (SLang_Name_Type *) tbl, pp, sizeof (SLang_Math_Unary_Type));
++}
++
++int SLadd_iconstant_table (SLang_IConstant_Type *tbl, char *pp)
++{
++ return add_generic_table (NULL, (SLang_Name_Type *) tbl, pp, sizeof (SLang_IConstant_Type));
++}
++
++#if SLANG_HAS_FLOAT
++int SLadd_dconstant_table (SLang_DConstant_Type *tbl, char *pp)
++{
++ return add_generic_table (NULL, (SLang_Name_Type *) tbl, pp, sizeof (SLang_DConstant_Type));
++}
++#endif
++
++/* ----------- */
++int SLns_add_intrin_fun_table (SLang_NameSpace_Type *ns, SLang_Intrin_Fun_Type *tbl, char *pp)
++{
++ return add_generic_table (ns, (SLang_Name_Type *) tbl, pp, sizeof (SLang_Intrin_Fun_Type));
++}
++
++int SLns_add_intrin_var_table (SLang_NameSpace_Type *ns, SLang_Intrin_Var_Type *tbl, char *pp)
++{
++ return add_generic_table (ns, (SLang_Name_Type *) tbl, pp, sizeof (SLang_Intrin_Var_Type));
++}
++
++int SLns_add_app_unary_table (SLang_NameSpace_Type *ns, SLang_App_Unary_Type *tbl, char *pp)
++{
++ return add_generic_table (ns, (SLang_Name_Type *) tbl, pp, sizeof (SLang_App_Unary_Type));
++}
++
++int SLns_add_math_unary_table (SLang_NameSpace_Type *ns, SLang_Math_Unary_Type *tbl, char *pp)
++{
++ return add_generic_table (ns, (SLang_Name_Type *) tbl, pp, sizeof (SLang_Math_Unary_Type));
++}
++
++int SLns_add_iconstant_table (SLang_NameSpace_Type *ns, SLang_IConstant_Type *tbl, char *pp)
++{
++ return add_generic_table (ns, (SLang_Name_Type *) tbl, pp, sizeof (SLang_IConstant_Type));
++}
++
++#if SLANG_HAS_FLOAT
++int SLns_add_dconstant_table (SLang_NameSpace_Type *ns, SLang_DConstant_Type *tbl, char *pp)
++{
++ return add_generic_table (ns, (SLang_Name_Type *) tbl, pp, sizeof (SLang_DConstant_Type));
++}
++#endif
++
++/* what is a bitmapped value:
++ * 1 intrin fun
++ * 2 user fun
++ * 4 intrin var
++ * 8 user defined var
++ */
++SLang_Array_Type *_SLang_apropos (char *namespace_name, char *pat, unsigned int what)
++{
++ SLang_NameSpace_Type *ns;
++
++ if (namespace_name == NULL)
++ namespace_name = &quot;Global&quot;;
++
++ if (*namespace_name == 0)
++ ns = This_Static_NameSpace;
++ else ns = _SLns_find_namespace (namespace_name);
++
++ return _SLnspace_apropos (ns, pat, what);
++}
++
++void _SLang_implements_intrinsic (char *name)
++{
++ if (This_Static_NameSpace == NULL)
++ {
++ SLang_verror (SL_INTRINSIC_ERROR, &quot;No namespace available&quot;);
++ return;
++ }
++
++ (void) _SLns_set_namespace_name (This_Static_NameSpace, name);
++
++ Default_Define_Function = define_static_function;
++ Default_Variable_Mode = compile_static_variable_mode;
++}
++
++void _SLang_use_namespace_intrinsic (char *name)
++{
++ SLang_NameSpace_Type *ns;
++
++ if (NULL == (ns = _SLns_find_namespace (name)))
++ {
++ SLang_verror (SL_INTRINSIC_ERROR, &quot;Namespace %s does not exist&quot;, name);
++ return;
++ }
++ This_Static_NameSpace = ns;
++ if (Global_NameSpace == ns)
++ {
++ Default_Define_Function = define_public_function;
++ Default_Variable_Mode = compile_public_variable_mode;
++ }
++ else
++ {
++ Default_Define_Function = define_static_function;
++ Default_Variable_Mode = compile_static_variable_mode;
++ }
++}
++
++
++char *_SLang_cur_namespace_intrinsic (void)
++{
++ if (This_Static_NameSpace == NULL)
++ return &quot;Global&quot;;
++
++ if (This_Static_NameSpace-&gt;namespace_name == NULL)
++ return &quot;&quot;;
++
++ return This_Static_NameSpace-&gt;namespace_name;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slang.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slang.h
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slang.h (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slang.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1930 @@
++#ifndef DAVIS_SLANG_H_
++#define DAVIS_SLANG_H_
++/* -*- mode: C; mode: fold; -*- */
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++#define SLANG_VERSION 10404
++#define SLANG_VERSION_STRING &quot;1.4.4&quot;
++
++/*{{{ System Dependent Macros and Typedefs */
++
++#if defined(__WATCOMC__) &amp;&amp; defined(DOS)
++# ifndef __MSDOS__
++# define __MSDOS__
++# endif
++# ifndef DOS386
++# define DOS386
++# endif
++# ifndef IBMPC_SYSTEM
++# define IBMPC_SYSTEM
++# endif
++#endif /* __watcomc__ */
++
++#if defined(unix) || defined(__unix)
++# ifndef __unix__
++# define __unix__ 1
++# endif
++#endif
++
++#if !defined(__GO32__)
++# ifdef __unix__
++# define REAL_UNIX_SYSTEM
++# endif
++#endif
++
++/* Set of the various defines for pc systems. This includes OS/2 */
++#ifdef __GO32__
++# ifndef __DJGPP__
++# define __DJGPP__ 1
++# endif
++# ifndef IBMPC_SYSTEM
++# define IBMPC_SYSTEM
++# endif
++#endif
++
++#ifdef __BORLANDC__
++# ifndef IBMPC_SYSTEM
++# define IBMPC_SYSTEM
++# endif
++#endif
++
++#ifdef __MSDOS__
++# ifndef IBMPC_SYSTEM
++# define IBMPC_SYSTEM
++# endif
++#endif
++
++#if defined(OS2) || defined(__os2__)
++# ifndef IBMPC_SYSTEM
++# define IBMPC_SYSTEM
++# endif
++# ifndef __os2__
++# define __os2__
++# endif
++#endif
++
++#if defined(__NT__) || defined(__MINGW32__) || defined(__CYGWIN32__)
++# ifndef IBMPC_SYSTEM
++# define IBMPC_SYSTEM
++# endif
++#endif
++
++#if defined(IBMPC_SYSTEM) || defined(VMS)
++# ifdef REAL_UNIX_SYSTEM
++# undef REAL_UNIX_SYSTEM
++# endif
++#endif
++
++#ifdef __cplusplus
++extern &quot;C&quot; {
++#endif
++#if 0
++}
++#endif
++
++#include &lt;stdio.h&gt;
++#include &lt;stdarg.h&gt;
++#if defined(__STDC__) || defined(__BORLANDC__) || defined(__cplusplus)
++# include &lt;stddef.h&gt; /* for offsetof */
++#endif
++
++/* ---------------------------- Generic Macros ----------------------------- */
++
++/* __SC__ is defined for Symantec C++
++ DOS386 is defined for -mx memory model, 32 bit DOS extender. */
++
++#if defined(__SC__) &amp;&amp; !defined(DOS386)
++# include &lt;dos.h&gt;
++#endif
++
++#if defined(__BORLANDC__)
++# include &lt;alloc.h&gt;
++#endif
++
++#if defined (__cplusplus) || defined(__STDC__) || defined(IBMPC_SYSTEM)
++ typedef void *VOID_STAR;
++#else
++ typedef unsigned char *VOID_STAR;
++#endif
++
++typedef int (*FVOID_STAR)(void);
++
++#if defined(__MSDOS_) &amp;&amp; defined(__BORLANDC__)
++# define SLFREE(buf) farfree((void far *)(buf))
++# define SLMALLOC(x) farmalloc((unsigned long) (x))
++# define SLREALLOC(buf, n) farrealloc((void far *) (buf), (unsigned long) (n))
++# define SLCALLOC(n, m) farcalloc((unsigned long) (n), (unsigned long) (m))
++#else
++# if defined(VMS) &amp;&amp; !defined(__DECC)
++# define SLFREE VAXC$FREE_OPT
++# define SLMALLOC VAXC$MALLOC_OPT
++# define SLREALLOC VAXC$REALLOC_OPT
++# define SLCALLOC VAXC$CALLOC_OPT
++# else
++# define SLFREE(x) free((char *)(x))
++# define SLMALLOC malloc
++# define SLREALLOC realloc
++# define SLCALLOC calloc
++# endif
++#endif
++
++ extern char *SLdebug_malloc (unsigned long);
++ extern char *SLdebug_calloc (unsigned long, unsigned long);
++ extern char *SLdebug_realloc (char *, unsigned long);
++ extern void SLdebug_free (char *);
++ extern void SLmalloc_dump_statistics (void);
++ extern char *SLstrcpy(register char *, register char *);
++ extern int SLstrcmp(register char *, register char *);
++ extern char *SLstrncpy(char *, register char *, register int);
++
++ extern void SLmemset (char *, char, int);
++ extern char *SLmemchr (register char *, register char, register int);
++ extern char *SLmemcpy (char *, char *, int);
++ extern int SLmemcmp (char *, char *, int);
++
++/*}}}*/
++
++/*{{{ Interpreter Typedefs */
++
++typedef struct _SLang_Name_Type
++{
++ char *name;
++ struct _SLang_Name_Type *next;
++ char name_type;
++ /* These values must be less than 0x10 because they map directly
++ * to byte codes. See _slang.h.
++ */
++#define SLANG_LVARIABLE 0x01
++#define SLANG_GVARIABLE 0x02
++#define SLANG_IVARIABLE 0x03 /* intrinsic variables */
++ /* Note!!! For Macro MAKE_VARIABLE below to work, SLANG_IVARIABLE Must
++ be 1 less than SLANG_RVARIABLE!!! */
++#define SLANG_RVARIABLE 0x04 /* read only variable */
++#define SLANG_INTRINSIC 0x05
++#define SLANG_FUNCTION 0x06
++#define SLANG_MATH_UNARY 0x07
++#define SLANG_APP_UNARY 0x08
++#define SLANG_ICONSTANT 0x09
++#define SLANG_DCONSTANT 0x0A
++#define SLANG_PVARIABLE 0x0B /* private */
++#define SLANG_PFUNCTION 0x0C /* private */
++
++ /* Rest of fields depend on name type */
++}
++SLang_Name_Type;
++
++typedef struct
++{
++ char *name;
++ struct _SLang_Name_Type *next; /* this is for the hash table */
++ char name_type;
++
++ FVOID_STAR i_fun; /* address of object */
++
++ /* Do not change this without modifying slang.c:execute_intrinsic_fun */
++#define SLANG_MAX_INTRIN_ARGS 7
++ unsigned char arg_types [SLANG_MAX_INTRIN_ARGS];
++ unsigned char num_args;
++ unsigned char return_type;
++}
++SLang_Intrin_Fun_Type;
++
++typedef struct
++{
++ char *name;
++ SLang_Name_Type *next;
++ char name_type;
++
++ VOID_STAR addr;
++ unsigned char type;
++}
++SLang_Intrin_Var_Type;
++
++typedef struct
++{
++ char *name;
++ SLang_Name_Type *next;
++ char name_type;
++
++ int unary_op;
++}
++SLang_App_Unary_Type;
++
++typedef struct
++{
++ char *name;
++ SLang_Name_Type *next;
++ char name_type;
++
++ int unary_op;
++}
++SLang_Math_Unary_Type;
++
++typedef struct
++{
++ char *name;
++ SLang_Name_Type *next;
++ char name_type;
++ int i;
++}
++SLang_IConstant_Type;
++
++typedef struct
++{
++ char *name;
++ SLang_Name_Type *next;
++ char name_type;
++ double d;
++}
++SLang_DConstant_Type;
++
++typedef struct
++{
++ char *field_name;
++ unsigned int offset;
++ unsigned char type;
++ unsigned char read_only;
++}
++SLang_IStruct_Field_Type;
++
++extern int SLadd_intrin_fun_table (SLang_Intrin_Fun_Type *, char *);
++extern int SLadd_intrin_var_table (SLang_Intrin_Var_Type *, char *);
++extern int SLadd_app_unary_table (SLang_App_Unary_Type *, char *);
++extern int SLadd_math_unary_table (SLang_Math_Unary_Type *, char *);
++extern int SLadd_iconstant_table (SLang_IConstant_Type *, char *);
++extern int SLadd_dconstant_table (SLang_DConstant_Type *, char *);
++extern int SLadd_istruct_table (SLang_IStruct_Field_Type *, VOID_STAR, char *);
++
++typedef struct _SLang_NameSpace_Type SLang_NameSpace_Type;
++
++extern int SLns_add_intrin_fun_table (SLang_NameSpace_Type *, SLang_Intrin_Fun_Type *, char *);
++extern int SLns_add_intrin_var_table (SLang_NameSpace_Type *, SLang_Intrin_Var_Type *, char *);
++extern int SLns_add_app_unary_table (SLang_NameSpace_Type *, SLang_App_Unary_Type *, char *);
++extern int SLns_add_math_unary_table (SLang_NameSpace_Type *, SLang_Math_Unary_Type *, char *);
++extern int SLns_add_iconstant_table (SLang_NameSpace_Type *, SLang_IConstant_Type *, char *);
++extern int SLns_add_dconstant_table (SLang_NameSpace_Type *, SLang_DConstant_Type *, char *);
++extern int SLns_add_istruct_table (SLang_NameSpace_Type *, SLang_IStruct_Field_Type *, VOID_STAR, char *);
++
++extern SLang_NameSpace_Type *SLns_create_namespace (char *);
++extern void SLns_delete_namespace (SLang_NameSpace_Type *);
++
++typedef struct SLang_Load_Type
++{
++ int type;
++
++ VOID_STAR client_data;
++ /* Pointer to data that client needs for loading */
++
++ int auto_declare_globals;
++ /* if non-zero, undefined global variables are declared as static */
++
++ char *(*read)(struct SLang_Load_Type *);
++ /* function to call to read next line from obj. */
++
++ unsigned int line_num;
++ /* Number of lines read, used for error reporting */
++
++ int parse_level;
++ /* 0 if at top level of parsing */
++
++ char *name;
++ /* Name of this object, e.g., filename. This name should be unique because
++ * it alone determines the name space for static objects associated with
++ * the compilable unit.
++ */
++
++ unsigned long reserved[4];
++ /* For future expansion */
++} SLang_Load_Type;
++
++extern SLang_Load_Type *SLallocate_load_type (char *);
++extern void SLdeallocate_load_type (SLang_Load_Type *);
++
++/* Returns SLang_Error upon failure */
++extern int SLang_load_object (SLang_Load_Type *);
++extern int (*SLang_Load_File_Hook)(char *);
++extern int (*SLang_Auto_Declare_Var_Hook) (char *);
++
++extern int SLang_generate_debug_info (int);
++
++
++#if defined(ultrix) &amp;&amp; !defined(__GNUC__)
++# ifndef NO_PROTOTYPES
++# define NO_PROTOTYPES
++# endif
++#endif
++
++#ifndef NO_PROTOTYPES
++# define _PROTO(x) x
++#else
++# define _PROTO(x) ()
++#endif
++
++typedef struct SL_OOBinary_Type
++{
++ unsigned char data_type; /* partner type for binary op */
++
++ int (*binary_function)_PROTO((int,
++ unsigned char, VOID_STAR, unsigned int,
++ unsigned char, VOID_STAR, unsigned int,
++ VOID_STAR));
++
++ int (*binary_result) _PROTO((int, unsigned char, unsigned char, unsigned char *));
++ struct SL_OOBinary_Type *next;
++}
++SL_OOBinary_Type;
++
++typedef struct _SL_Typecast_Type
++{
++ unsigned char data_type; /* to_type */
++ int allow_implicit;
++
++ int (*typecast)_PROTO((unsigned char, VOID_STAR, unsigned int,
++ unsigned char, VOID_STAR));
++ struct _SL_Typecast_Type *next;
++}
++SL_Typecast_Type;
++
++typedef struct _SLang_Struct_Type SLang_Struct_Type;
++
++#if defined(SL_APP_WANTS_FOREACH)
++/* It is up to the application to define struct _SLang_Foreach_Context_Type */
++typedef struct _SLang_Foreach_Context_Type SLang_Foreach_Context_Type;
++#else
++typedef int SLang_Foreach_Context_Type;
++#endif
++
++typedef struct
++{
++ unsigned char cl_class_type;
++#define SLANG_CLASS_TYPE_MMT 0
++#define SLANG_CLASS_TYPE_SCALAR 1
++#define SLANG_CLASS_TYPE_VECTOR 2
++#define SLANG_CLASS_TYPE_PTR 3
++
++ unsigned int cl_data_type; /* SLANG_INTEGER_TYPE, etc... */
++ char *cl_name; /* slstring type */
++
++ unsigned int cl_sizeof_type;
++ VOID_STAR cl_transfer_buf; /* cl_sizeof_type bytes*/
++
++ /* Methods */
++
++ /* Most of the method functions are prototyped:
++ * int method (unsigned char type, VOID_STAR addr);
++ * Here, @type@ represents the type of object that the method is asked
++ * to deal with. The second parameter @addr@ will contain the ADDRESS of
++ * the object. For example, if type is SLANG_INT_TYPE, then @addr@ will
++ * actually be int *. Similary, if type is SLANG_STRING_TYPE,
++ * then @addr@ will contain the address of the string, i.e., char **.
++ */
++
++ void (*cl_destroy)_PROTO((unsigned char, VOID_STAR));
++ /* Prototype: void destroy(unsigned type, VOID_STAR val)
++ * Called to delete/free the object */
++
++ char *(*cl_string)_PROTO((unsigned char, VOID_STAR));
++ /* Prototype: char *to_string (unsigned char t, VOID_STAR p);
++ * Here p is a pointer to the object for which a string representation
++ * is to be returned. The returned pointer is to be a MALLOCED string.
++ */
++
++ /* Prototype: void push(unsigned char type, VOID_STAR v);
++ * Push a copy of the object of type @type@ at address @v@ onto the
++ * stack.
++ */
++ int (*cl_push)_PROTO((unsigned char, VOID_STAR));
++
++ /* Prototype: int pop(unsigned char type, VOID_STAR v);
++ * Pops value from stack and assign it to object, whose address is @<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">v at .</A>
++ */
++ int (*cl_pop)_PROTO((unsigned char, VOID_STAR));
++
++ int (*cl_unary_op_result_type)_PROTO((int, unsigned char, unsigned char *));
++ int (*cl_unary_op)_PROTO((int, unsigned char, VOID_STAR, unsigned int, VOID_STAR));
++
++ int (*cl_app_unary_op_result_type)_PROTO((int, unsigned char, unsigned char *));
++ int (*cl_app_unary_op)_PROTO((int, unsigned char, VOID_STAR, unsigned int, VOID_STAR));
++
++ /* If this function is non-NULL, it will be called for sin, cos, etc... */
++#define SLMATH_SIN 1
++#define SLMATH_COS 2
++#define SLMATH_TAN 3
++#define SLMATH_ATAN 4
++#define SLMATH_ASIN 5
++#define SLMATH_ACOS 6
++#define SLMATH_EXP 7
++#define SLMATH_LOG 8
++#define SLMATH_SQRT 9
++#define SLMATH_LOG10 10
++#define SLMATH_REAL 11
++#define SLMATH_IMAG 12
++#define SLMATH_SINH 13
++#define SLMATH_COSH 14
++#define SLMATH_TANH 15
++#define SLMATH_ATANH 16
++#define SLMATH_ASINH 17
++#define SLMATH_ACOSH 18
++#define SLMATH_TODOUBLE 19
++#define SLMATH_CONJ 20
++
++ int (*cl_math_op)_PROTO((int, unsigned char, VOID_STAR, unsigned int, VOID_STAR));
++ int (*cl_math_op_result_type)_PROTO((int, unsigned char, unsigned char *));
++
++ SL_OOBinary_Type *cl_binary_ops;
++ SL_Typecast_Type *cl_typecast_funs;
++
++ void (*cl_byte_code_destroy)_PROTO((unsigned char, VOID_STAR));
++ void (*cl_user_destroy_fun)_PROTO((unsigned char, VOID_STAR));
++ int (*cl_init_array_object)_PROTO((unsigned char, VOID_STAR));
++ int (*cl_datatype_deref)_PROTO((unsigned char));
++ SLang_Struct_Type *cl_struct_def;
++ int (*cl_dereference) _PROTO((unsigned char, VOID_STAR));
++ int (*cl_acopy) (unsigned char, VOID_STAR, VOID_STAR);
++ int (*cl_apop) _PROTO((unsigned char, VOID_STAR));
++ int (*cl_apush) _PROTO((unsigned char, VOID_STAR));
++ int (*cl_push_literal) _PROTO((unsigned char, VOID_STAR));
++ void (*cl_adestroy)_PROTO((unsigned char, VOID_STAR));
++ int (*cl_push_intrinsic)_PROTO((unsigned char, VOID_STAR));
++ int (*cl_void_typecast)_PROTO((unsigned char, VOID_STAR, unsigned int, unsigned char, VOID_STAR));
++
++ int (*cl_anytype_typecast)_PROTO((unsigned char, VOID_STAR, unsigned int, unsigned char, VOID_STAR));
++
++ /* Array access functions */
++ int (*cl_aput) (unsigned char, unsigned int);
++ int (*cl_aget) (unsigned char, unsigned int);
++ int (*cl_anew) (unsigned char, unsigned int);
++
++ /* length method */
++ int (*cl_length) (unsigned char, VOID_STAR, unsigned int *);
++
++ /* foreach */
++ SLang_Foreach_Context_Type *(*cl_foreach_open) (unsigned char, unsigned int);
++ void (*cl_foreach_close) (unsigned char, SLang_Foreach_Context_Type *);
++ int (*cl_foreach) (unsigned char, SLang_Foreach_Context_Type *);
++
++ /* Structure access: get and put (assign to) fields */
++ int (*cl_sput) (unsigned char, char *);
++ int (*cl_sget) (unsigned char, char *);
++
++ /* File I/O */
++ int (*cl_fread) (unsigned char, FILE *, VOID_STAR, unsigned int, unsigned int *);
++ int (*cl_fwrite) (unsigned char, FILE *, VOID_STAR, unsigned int, unsigned int *);
++ int (*cl_fdread) (unsigned char, int, VOID_STAR, unsigned int, unsigned int *);
++ int (*cl_fdwrite) (unsigned char, int, VOID_STAR, unsigned int, unsigned int *);
++
++ int (*cl_to_bool) (unsigned char, int *);
++
++ int (*cl_cmp)(unsigned char, VOID_STAR, VOID_STAR, int *);
++
++} SLang_Class_Type;
++
++/* These are the low-level functions for building push/pop methods. They
++ * know nothing about memory management. For SLANG_CLASS_TYPE_MMT, use the
++ * MMT push/pop functions instead.
++ */
++extern int SLclass_push_double_obj (unsigned char, double);
++extern int SLclass_push_float_obj (unsigned char, float);
++extern int SLclass_push_long_obj (unsigned char, long);
++extern int SLclass_push_int_obj (unsigned char, int);
++extern int SLclass_push_short_obj (unsigned char, short);
++extern int SLclass_push_char_obj (unsigned char, char);
++extern int SLclass_push_ptr_obj (unsigned char, VOID_STAR);
++extern int SLclass_pop_double_obj (unsigned char, double *);
++extern int SLclass_pop_float_obj (unsigned char, float *);
++extern int SLclass_pop_long_obj (unsigned char, long *);
++extern int SLclass_pop_int_obj (unsigned char, int *);
++extern int SLclass_pop_short_obj (unsigned char, short *);
++extern int SLclass_pop_char_obj (unsigned char, char *);
++extern int SLclass_pop_ptr_obj (unsigned char, VOID_STAR *);
++
++extern SLang_Class_Type *SLclass_allocate_class (char *);
++extern int SLclass_get_class_id (SLang_Class_Type *cl);
++extern int SLclass_create_synonym (char *, unsigned char);
++extern int SLclass_is_class_defined (unsigned char);
++
++extern int SLclass_register_class (SLang_Class_Type *, unsigned char, unsigned int, unsigned char);
++extern int SLclass_set_string_function (SLang_Class_Type *, char *(*)(unsigned char, VOID_STAR));
++extern int SLclass_set_destroy_function (SLang_Class_Type *, void (*)(unsigned char, VOID_STAR));
++extern int SLclass_set_push_function (SLang_Class_Type *, int (*)(unsigned char, VOID_STAR));
++extern int SLclass_set_pop_function (SLang_Class_Type *, int (*)(unsigned char, VOID_STAR));
++
++extern int SLclass_set_aget_function (SLang_Class_Type *, int (*)(unsigned char, unsigned int));
++extern int SLclass_set_aput_function (SLang_Class_Type *, int (*)(unsigned char, unsigned int));
++extern int SLclass_set_anew_function (SLang_Class_Type *, int (*)(unsigned char, unsigned int));
++
++extern int SLclass_set_sget_function (SLang_Class_Type *, int (*)(unsigned char, char *));
++extern int SLclass_set_sput_function (SLang_Class_Type *, int (*)(unsigned char, char *));
++
++/* Typecast object on the stack to type p1. p2 and p3 should be set to 1 */
++extern int SLclass_typecast (unsigned char, int, int);
++
++extern int SLclass_add_unary_op (unsigned char,
++ int (*) (int,
++ unsigned char, VOID_STAR, unsigned int,
++ VOID_STAR),
++ int (*) (int, unsigned char, unsigned char *));
++
++extern int
++SLclass_add_app_unary_op (unsigned char,
++ int (*) (int,
++ unsigned char, VOID_STAR, unsigned int,
++ VOID_STAR),
++ int (*) (int, unsigned char, unsigned char *));
++
++extern int
++SLclass_add_binary_op (unsigned char, unsigned char,
++ int (*) (int,
++ unsigned char, VOID_STAR, unsigned int,
++ unsigned char, VOID_STAR, unsigned int,
++ VOID_STAR),
++ int (*) (int, unsigned char, unsigned char, unsigned char *));
++
++extern int
++SLclass_add_math_op (unsigned char,
++ int (*)(int,
++ unsigned char, VOID_STAR, unsigned int,
++ VOID_STAR),
++ int (*)(int, unsigned char, unsigned char *));
++
++extern int
++SLclass_add_typecast (unsigned char /* from */, unsigned char /* to */,
++ int (*)_PROTO((unsigned char, VOID_STAR, unsigned int,
++ unsigned char, VOID_STAR)),
++ int /* allow implicit typecasts */
++ );
++
++extern char *SLclass_get_datatype_name (unsigned char);
++
++extern double SLcomplex_abs (double *);
++extern double *SLcomplex_times (double *, double *, double *);
++extern double *SLcomplex_divide (double *, double *, double *);
++extern double *SLcomplex_sin (double *, double *);
++extern double *SLcomplex_cos (double *, double *);
++extern double *SLcomplex_tan (double *, double *);
++extern double *SLcomplex_asin (double *, double *);
++extern double *SLcomplex_acos (double *, double *);
++extern double *SLcomplex_atan (double *, double *);
++extern double *SLcomplex_exp (double *, double *);
++extern double *SLcomplex_log (double *, double *);
++extern double *SLcomplex_log10 (double *, double *);
++extern double *SLcomplex_sqrt (double *, double *);
++extern double *SLcomplex_sinh (double *, double *);
++extern double *SLcomplex_cosh (double *, double *);
++extern double *SLcomplex_tanh (double *, double *);
++extern double *SLcomplex_pow (double *, double *, double *);
++extern double SLmath_hypot (double x, double y);
++
++/* Not implemented yet */
++extern double *SLcomplex_asinh (double *, double *);
++extern double *SLcomplex_acosh (double *, double *);
++extern double *SLcomplex_atanh (double *, double *);
++
++#ifdef _SLANG_SOURCE_
++typedef struct _SLang_MMT_Type SLang_MMT_Type;
++#else
++typedef int SLang_MMT_Type;
++#endif
++
++extern void SLang_free_mmt (SLang_MMT_Type *);
++extern VOID_STAR SLang_object_from_mmt (SLang_MMT_Type *);
++extern SLang_MMT_Type *SLang_create_mmt (unsigned char, VOID_STAR);
++extern int SLang_push_mmt (SLang_MMT_Type *);
++extern SLang_MMT_Type *SLang_pop_mmt (unsigned char);
++extern void SLang_inc_mmt (SLang_MMT_Type *);
++
++/* Maximum number of dimensions of an array. */
++#define SLARRAY_MAX_DIMS 7
++typedef struct _SLang_Array_Type
++{
++ unsigned char data_type;
++ unsigned int sizeof_type;
++ VOID_STAR data;
++ unsigned int num_elements;
++ unsigned int num_dims;
++ int dims [SLARRAY_MAX_DIMS];
++ VOID_STAR (*index_fun)_PROTO((struct _SLang_Array_Type *, int *));
++ /* This function is designed to allow a type to store an array in
++ * any manner it chooses. This function returns the address of the data
++ * value at the specified index location.
++ */
++ unsigned int flags;
++#define SLARR_DATA_VALUE_IS_READ_ONLY 1
++#define SLARR_DATA_VALUE_IS_POINTER 2
++#define SLARR_DATA_VALUE_IS_RANGE 4
++#define SLARR_DATA_VALUE_IS_INTRINSIC 8
++ SLang_Class_Type *cl;
++ unsigned int num_refs;
++}
++SLang_Array_Type;
++
++extern int SLang_pop_array_of_type (SLang_Array_Type **, unsigned char);
++extern int SLang_pop_array (SLang_Array_Type **, int);
++extern int SLang_push_array (SLang_Array_Type *, int);
++extern void SLang_free_array (SLang_Array_Type *);
++extern SLang_Array_Type *SLang_create_array (unsigned char, int, VOID_STAR, int *, unsigned int);
++extern SLang_Array_Type *SLang_duplicate_array (SLang_Array_Type *);
++extern int SLang_get_array_element (SLang_Array_Type *, int *, VOID_STAR);
++extern int SLang_set_array_element (SLang_Array_Type *, int *, VOID_STAR);
++
++
++/*}}}*/
++
++/*{{{ Interpreter Function Prototypes */
++
++ extern volatile int SLang_Error;
++/* Non zero if error occurs. Must be reset to zero to continue. */
++/* error codes, severe errors are less than 0 */
++#define SL_APPLICATION_ERROR -2
++#define SL_VARIABLE_UNINITIALIZED -3
++#define SL_INTERNAL_ERROR -5
++#define SL_STACK_OVERFLOW -6
++#define SL_STACK_UNDERFLOW -7
++#define SL_UNDEFINED_NAME -8
++#define SL_SYNTAX_ERROR -9
++#define SL_DUPLICATE_DEFINITION -10
++#define SL_TYPE_MISMATCH -11
++#define SL_OBJ_UNKNOWN -13
++#define SL_UNKNOWN_ERROR -14
++#define SL_TYPE_UNDEFINED_OP_ERROR -16
++
++#define SL_INTRINSIC_ERROR 1
++/* Intrinsic error is an error generated by intrinsic functions */
++#define SL_USER_BREAK 2
++#define SL_DIVIDE_ERROR 3
++#define SL_OBJ_NOPEN 4
++#define SL_USER_ERROR 5
++#define SL_USAGE_ERROR 6
++#define SL_READONLY_ERROR 7
++#define SL_INVALID_PARM 8
++#define SL_NOT_IMPLEMENTED 9
++#define SL_MALLOC_ERROR 10
++#define SL_OVERFLOW 11
++#define SL_FLOATING_EXCEPTION 12
++
++/* Compatibility */
++#define USER_BREAK SL_USER_BREAK
++#define INTRINSIC_ERROR SL_INTRINSIC_ERROR
++
++ extern int SLang_Traceback;
++ /* If non-zero, dump an S-Lang traceback upon error. Available as
++ _traceback in S-Lang. */
++
++ extern char *SLang_User_Prompt;
++ /* Prompt to use when reading from stdin */
++ extern int SLang_Version;
++ extern char *SLang_Version_String;
++extern char *SLang_Doc_Dir;
++
++extern void (*SLang_VMessage_Hook) (char *, va_list);
++extern void SLang_vmessage (char *, ...);
++
++ extern void (*SLang_Error_Hook)(char *);
++ /* Pointer to application dependent error messaging routine. By default,
++ messages are displayed on stderr. */
++
++ extern void (*SLang_Exit_Error_Hook)(char *, va_list);
++ extern void SLang_exit_error (char *, ...);
++ extern void (*SLang_Dump_Routine)(char *);
++ /* Called if S-Lang traceback is enabled as well as other debugging
++ routines (e.g., trace). By default, these messages go to stderr. */
++
++ extern void (*SLang_Interrupt)(void);
++ /* function to call whenever inner interpreter is entered. This is
++ a good place to set SLang_Error to USER_BREAK. */
++
++ extern void (*SLang_User_Clear_Error)(void);
++ /* function that gets called when '_clear_error' is called. */
++
++ /* If non null, these call C functions before and after a slang function. */
++ extern void (*SLang_Enter_Function)(char *);
++extern void (*SLang_Exit_Function)(char *);
++
++extern int SLang_Num_Function_Args;
++
++/* Functions: */
++
++extern int SLang_init_all (void);
++/* Initializes interpreter and all modules */
++
++extern int SLang_init_slang (void);
++/* This function is mandatory and must be called by all applications that
++ * use the interpreter
++ */
++extern int SLang_init_posix_process (void); /* process specific intrinsics */
++extern int SLang_init_stdio (void); /* fgets, etc. stdio functions */
++extern int SLang_init_posix_dir (void);
++extern int SLang_init_ospath (void);
++
++extern int SLang_init_slmath (void);
++/* called if math functions sin, cos, etc... are needed. */
++
++ extern int SLang_init_slfile (void);
++ extern int SLang_init_slunix (void);
++ /* These functions are obsolte. Use init_stdio, posix_process, etc. */
++
++extern int SLang_init_slassoc (void);
++/* Assoc Arrays (Hashes) */
++
++extern int SLang_init_array (void);
++/* Additional arrays functions: transpose, etc... */
++
++/* Dynamic linking facility */
++extern int SLang_init_import (void);
++
++ extern int SLang_load_file (char *);
++ /* Load a file of S-Lang code for interpreting. If the parameter is
++ * NULL, input comes from stdin. */
++
++ extern void SLang_restart(int);
++ /* should be called if an error occurs. If the passed integer is
++ * non-zero, items are popped off the stack; otherwise, the stack is
++ * left intact. Any time the stack is believed to be trashed, this routine
++ * should be called with a non-zero argument (e.g., if setjmp/longjmp is
++ * called). */
++
++ extern int SLang_byte_compile_file(char *, int);
++ /* takes a file of S-Lang code and ``byte-compiles'' it for faster
++ * loading. The new filename is equivalent to the old except that a `c' is
++ * appended to the name. (e.g., init.sl --&gt; init.slc). The second
++ * specified the method; currently, it is not used.
++ */
++
++ extern int SLang_autoload(char *, char *);
++ /* Automatically load S-Lang function p1 from file p2. This function
++ is also available via S-Lang */
++
++ extern int SLang_load_string(char *);
++ /* Like SLang_load_file except input is from a null terminated string. */
++
++ extern int SLdo_pop(void);
++ /* pops item off stack and frees any memory associated with it */
++ extern int SLdo_pop_n(unsigned int);
++ /* pops n items off stack and frees any memory associated with them */
++
++extern int SLang_pop_integer(int *);
++extern int SLang_pop_uinteger(unsigned int *);
++ /* pops integer *p0 from the stack. Returns 0 upon success and non-zero
++ * if the stack is empty or a type mismatch occurs, setting SLang_Error.
++ */
++extern int SLang_pop_char (char *);
++extern int SLang_pop_uchar (unsigned char *);
++extern int SLang_pop_short(short *);
++extern int SLang_pop_ushort(unsigned short *);
++extern int SLang_pop_long(long *);
++extern int SLang_pop_ulong(unsigned long *);
++
++extern int SLang_pop_float(float *);
++extern int SLang_pop_double(double *, int *, int *);
++ /* Pops double *p1 from stack. If *p3 is non-zero, *p1 was derived
++ from the integer *p2. Returns zero upon success. */
++
++ extern int SLang_pop_complex (double *, double *);
++
++ extern int SLpop_string (char **);
++ extern int SLang_pop_string(char **, int *);
++ /* pops string *p0 from stack. If *p1 is non-zero, the string must be
++ * freed after its use. DO NOT FREE p0 if *p1 IS ZERO! Returns 0 upon
++ * success */
++
++ extern int SLang_push_complex (double, double);
++
++ extern int SLang_push_char (char);
++ extern int SLang_push_uchar (unsigned char);
++
++ extern int SLang_push_integer(int);
++ extern int SLang_push_uinteger(unsigned int);
++ /* push integer p1 on stack */
++
++ extern int SLang_push_short(short);
++ extern int SLang_push_ushort(unsigned short);
++ extern int SLang_push_long(long);
++ extern int SLang_push_ulong(unsigned long);
++ extern int SLang_push_float(float);
++ extern int SLang_push_double(double);
++ /* Push double onto stack */
++
++ extern int SLang_push_string(char *);
++ /* Push string p1 onto stack */
++
++ extern int SLang_push_malloced_string(char *);
++ /* The normal SLang_push_string pushes an slstring. This one converts
++ * a normally malloced string to an slstring, and then frees the
++ * malloced string. So, do NOT use the malloced string after calling
++ * this routine because it will be freed! The routine returns -1 upon
++ * error, but the string will be freed.
++ */
++
++extern int SLang_push_null (void);
++extern int SLang_pop_null (void);
++
++extern int SLang_push_value (unsigned char type, VOID_STAR);
++extern int SLang_pop_value (unsigned char type, VOID_STAR);
++extern void SLang_free_value (unsigned char type, VOID_STAR);
++
++typedef struct _SLang_Object_Type SLang_Any_Type;
++
++extern int SLang_pop_anytype (SLang_Any_Type **);
++extern int SLang_push_anytype (SLang_Any_Type *);
++extern void SLang_free_anytype (SLang_Any_Type *);
++
++#ifdef _SLANG_SOURCE_
++typedef struct _SLang_Ref_Type SLang_Ref_Type;
++#else
++typedef int SLang_Ref_Type;
++#endif
++
++extern int SLang_pop_ref (SLang_Ref_Type **);
++extern void SLang_free_ref (SLang_Ref_Type *);
++extern int SLang_assign_to_ref (SLang_Ref_Type *, unsigned char, VOID_STAR);
++extern SLang_Name_Type *SLang_pop_function (void);
++extern SLang_Name_Type *SLang_get_fun_from_ref (SLang_Ref_Type *);
++extern void SLang_free_function (SLang_Name_Type *f);
++
++ extern int SLang_is_defined(char *);
++ /* Return non-zero is p1 is defined otherwise returns 0. */
++
++ extern int SLang_run_hooks(char *, unsigned int, ...);
++ /* calls S-Lang function p1 pushing p2 strings in the variable argument
++ * list onto the stack first.
++ * Returns -1 upon error, 1 if hooks exists and it ran,
++ * or 0 if hook does not exist. Thus it returns non-zero is hook was called.
++ */
++
++/* These functions return 1 if the indicated function exists and the function
++ * runs without error. If the function does not exist, the function returns
++ * 0. Otherwise -1 is returned with SLang_Error set appropriately.
++ */
++extern int SLexecute_function (SLang_Name_Type *);
++extern int SLang_execute_function(char *);
++
++
++extern int SLang_end_arg_list (void);
++extern int SLang_start_arg_list (void);
++
++extern void SLang_verror (int, char *, ...);
++
++extern void SLang_doerror(char *);
++ /* set SLang_Error and display p1 as error message */
++
++extern int SLang_add_intrinsic_array (char *, /* name */
++ unsigned char, /* type */
++ int, /* readonly */
++ VOID_STAR, /* data */
++ unsigned int, ...); /* num dims */
++
++extern int SLextract_list_element (char *, unsigned int, char,
++ char *, unsigned int);
++
++extern void SLexpand_escaped_string (register char *, register char *,
++ register char *);
++
++extern SLang_Name_Type *SLang_get_function (char *);
++extern void SLang_release_function (SLang_Name_Type *);
++
++extern int SLreverse_stack (int);
++extern int SLroll_stack (int);
++/* If argument p is positive, the top p objects on the stack are rolled
++ * up. If negative, the stack is rolled down.
++ */
++extern int SLdup_n (int n);
++/* Duplicate top n elements of stack */
++
++extern int SLang_peek_at_stack1 (void);
++extern int SLang_peek_at_stack (void);
++/* Returns type of next object on stack-- -1 upon stack underflow. */
++extern void SLmake_lut (unsigned char *, unsigned char *, unsigned char);
++
++ extern int SLang_guess_type (char *);
++
++extern int SLstruct_create_struct (unsigned int,
++ char **,
++ unsigned char *,
++ VOID_STAR *);
++
++/*}}}*/
++
++/*{{{ Misc Functions */
++
++/* This is an interface to atexit */
++extern int SLang_add_cleanup_function (void (*)(void));
++
++extern char *SLmake_string (char *);
++extern char *SLmake_nstring (char *, unsigned int);
++/* Returns a null terminated string made from the first n characters of the
++ * string.
++ */
++
++/* The string created by this routine must be freed by SLang_free_slstring
++ * and nothing else!! Also these strings must not be modified. Use
++ * SLmake_string if you intend to modify them!!
++ */
++extern char *SLang_create_nslstring (char *, unsigned int);
++extern char *SLang_create_slstring (char *);
++extern void SLang_free_slstring (char *); /* handles NULL */
++extern int SLang_pop_slstring (char **); /* free with SLang_free_slstring */
++extern char *SLang_concat_slstrings (char *a, char *b);
++extern char *SLang_create_static_slstring (char *); /* adds a string that will not get deleted */
++extern void SLstring_dump_stats (void);
++
++/* Binary strings */
++/* The binary string is an opaque type. Use the SLbstring_get_pointer function
++ * to get a pointer and length.
++ */
++typedef struct _SLang_BString_Type SLang_BString_Type;
++extern unsigned char *SLbstring_get_pointer (SLang_BString_Type *, unsigned int *);
++
++extern SLang_BString_Type *SLbstring_dup (SLang_BString_Type *);
++extern SLang_BString_Type *SLbstring_create (unsigned char *, unsigned int);
++
++/* The create_malloced function used the first argument which is assumed
++ * to be a pointer to a len + 1 malloced string. The extra byte is for
++ * \0 termination.
++ */
++extern SLang_BString_Type *SLbstring_create_malloced (unsigned char *, unsigned int, int);
++
++/* Create a bstring from an slstring */
++extern SLang_BString_Type *SLbstring_create_slstring (char *);
++
++extern void SLbstring_free (SLang_BString_Type *);
++extern int SLang_pop_bstring (SLang_BString_Type **);
++extern int SLang_push_bstring (SLang_BString_Type *);
++
++extern char *SLmalloc (unsigned int);
++extern char *SLcalloc (unsigned int, unsigned int);
++extern void SLfree(char *); /* This function handles NULL */
++extern char *SLrealloc (char *, unsigned int);
++
++extern char *SLcurrent_time_string (void);
++
++extern int SLatoi(unsigned char *);
++extern long SLatol (unsigned char *);
++extern unsigned long SLatoul (unsigned char *);
++
++extern int SLang_pop_fileptr (SLang_MMT_Type **, FILE **);
++extern char *SLang_get_name_from_fileptr (SLang_MMT_Type *);
++
++typedef struct _SLFile_FD_Type SLFile_FD_Type;
++extern SLFile_FD_Type *SLfile_create_fd (char *, int);
++extern void SLfile_free_fd (SLFile_FD_Type *);
++extern int SLfile_push_fd (SLFile_FD_Type *);
++extern int SLfile_pop_fd (SLFile_FD_Type **);
++extern int SLfile_get_fd (SLFile_FD_Type *, int *);
++extern SLFile_FD_Type *SLfile_dup_fd (SLFile_FD_Type *f0);
++extern int SLang_init_posix_io (void);
++
++typedef double (*SLang_To_Double_Fun_Type)(VOID_STAR);
++extern SLang_To_Double_Fun_Type SLarith_get_to_double_fun (unsigned char, unsigned int *);
++
++extern int SLang_set_argc_argv (int, char **);
++
++/*}}}*/
++
++/*{{{ SLang getkey interface Functions */
++
++#ifdef REAL_UNIX_SYSTEM
++extern int SLang_TT_Baud_Rate;
++extern int SLang_TT_Read_FD;
++#endif
++
++extern int SLang_init_tty (int, int, int);
++/* Initializes the tty for single character input. If the first parameter *p1
++ * is in the range 0-255, it will be used for the abort character;
++ * otherwise, (unix only) if it is -1, the abort character will be the one
++ * used by the terminal. If the second parameter p2 is non-zero, flow
++ * control is enabled. If the last parmeter p3 is zero, output processing
++ * is NOT turned on. A value of zero is required for the screen management
++ * routines. Returns 0 upon success. In addition, if SLang_TT_Baud_Rate ==
++ * 0 when this function is called, SLang will attempt to determine the
++ * terminals baud rate. As far as the SLang library is concerned, if
++ * SLang_TT_Baud_Rate is less than or equal to zero, the baud rate is
++ * effectively infinite.
++ */
++
++extern void SLang_reset_tty (void);
++/* Resets tty to what it was prior to a call to SLang_init_tty */
++#ifdef REAL_UNIX_SYSTEM
++extern void SLtty_set_suspend_state (int);
++ /* If non-zero argument, terminal driver will be told to react to the
++ * suspend character. If 0, it will not.
++ */
++extern int (*SLang_getkey_intr_hook) (void);
++#endif
++
++#define SLANG_GETKEY_ERROR 0xFFFF
++extern unsigned int SLang_getkey (void);
++/* reads a single key from the tty. If the read fails, 0xFFFF is returned. */
++
++#ifdef IBMPC_SYSTEM
++extern int SLgetkey_map_to_ansi (int);
++#endif
++
++extern int SLang_ungetkey_string (unsigned char *, unsigned int);
++extern int SLang_buffer_keystring (unsigned char *, unsigned int);
++extern int SLang_ungetkey (unsigned char);
++extern void SLang_flush_input (void);
++extern int SLang_input_pending (int);
++extern int SLang_Abort_Char;
++/* The value of the character (0-255) used to trigger SIGINT */
++extern int SLang_Ignore_User_Abort;
++/* If non-zero, pressing the abort character will not result in USER_BREAK
++ * SLang_Error. */
++
++extern int SLang_set_abort_signal (void (*)(int));
++/* If SIGINT is generated, the function p1 will be called. If p1 is NULL
++ * the SLang_default signal handler is called. This sets SLang_Error to
++ * USER_BREAK. I suspect most users will simply want to pass NULL.
++ */
++extern unsigned int SLang_Input_Buffer_Len;
++
++extern volatile int SLKeyBoard_Quit;
++
++#ifdef VMS
++/* If this function returns -1, ^Y will be added to input buffer. */
++extern int (*SLtty_VMS_Ctrl_Y_Hook) (void);
++#endif
++/*}}}*/
++
++/*{{{ SLang Keymap routines */
++
++typedef struct SLKeymap_Function_Type
++{
++ char *name;
++ int (*f)(void);
++}
++SLKeymap_Function_Type;
++
++#define SLANG_MAX_KEYMAP_KEY_SEQ 14
++typedef struct SLang_Key_Type
++{
++ struct SLang_Key_Type *next;
++ union
++ {
++ char *s;
++ FVOID_STAR f;
++ unsigned int keysym;
++ }
++ f;
++ unsigned char type; /* type of function */
++#define SLKEY_F_INTERPRET 0x01
++#define SLKEY_F_INTRINSIC 0x02
++#define SLKEY_F_KEYSYM 0x03
++ unsigned char str[SLANG_MAX_KEYMAP_KEY_SEQ + 1];/* key sequence */
++}
++SLang_Key_Type;
++
++typedef struct SLKeyMap_List_Type
++{
++ char *name; /* hashed string */
++ SLang_Key_Type *keymap;
++ SLKeymap_Function_Type *functions; /* intrinsic functions */
++}
++SLKeyMap_List_Type;
++
++/* This is arbitrary but I have got to start somewhere */
++#define SLANG_MAX_KEYMAPS 30
++extern SLKeyMap_List_Type SLKeyMap_List[SLANG_MAX_KEYMAPS];
++
++extern char *SLang_process_keystring(char *);
++
++extern int SLkm_define_key (char *, FVOID_STAR, SLKeyMap_List_Type *);
++
++extern int SLang_define_key(char *, char *, SLKeyMap_List_Type *);
++/* Like define_key1 except that p2 is a string that is to be associated with
++ * a function in the functions field of p3. This routine calls define_key1.
++ */
++
++extern int SLkm_define_keysym (char *, unsigned int, SLKeyMap_List_Type *);
++
++extern void SLang_undefine_key(char *, SLKeyMap_List_Type *);
++
++extern SLKeyMap_List_Type *SLang_create_keymap(char *, SLKeyMap_List_Type *);
++/* create and returns a pointer to a new keymap named p1 created by copying
++ * keymap p2. If p2 is NULL, it is up to the calling routine to initialize
++ * the keymap.
++ */
++
++extern char *SLang_make_keystring(unsigned char *);
++
++extern SLang_Key_Type *SLang_do_key(SLKeyMap_List_Type *, int (*)(void));
++/* read a key using keymap p1 with getkey function p2 */
++
++extern
++ FVOID_STAR
++ SLang_find_key_function(char *, SLKeyMap_List_Type *);
++
++extern SLKeyMap_List_Type *SLang_find_keymap(char *);
++
++extern int SLang_Last_Key_Char;
++extern int SLang_Key_TimeOut_Flag;
++
++/*}}}*/
++
++/*{{{ SLang Readline Interface */
++
++typedef struct SLang_Read_Line_Type
++{
++ struct SLang_Read_Line_Type *prev, *next;
++ unsigned char *buf;
++ int buf_len; /* number of chars in the buffer */
++ int num; /* num and misc are application specific*/
++ int misc;
++} SLang_Read_Line_Type;
++
++/* Maximum size of display */
++#define SLRL_DISPLAY_BUFFER_SIZE 256
++
++typedef struct
++{
++ SLang_Read_Line_Type *root, *tail, *last;
++ unsigned char *buf; /* edit buffer */
++ int buf_len; /* sizeof buffer */
++ int point; /* current editing point */
++ int tab; /* tab width */
++ int len; /* current line size */
++
++ /* display variables */
++ int edit_width; /* length of display field */
++ int curs_pos; /* current column */
++ int start_column; /* column offset of display */
++ int dhscroll; /* amount to use for horiz scroll */
++ char *prompt;
++
++ FVOID_STAR last_fun; /* last function executed by rl */
++
++ /* These two contain an image of what is on the display */
++ unsigned char upd_buf1[SLRL_DISPLAY_BUFFER_SIZE];
++ unsigned char upd_buf2[SLRL_DISPLAY_BUFFER_SIZE];
++ unsigned char *old_upd, *new_upd; /* pointers to previous two buffers */
++ int new_upd_len, old_upd_len; /* length of output buffers */
++
++ SLKeyMap_List_Type *keymap;
++
++ /* tty variables */
++ unsigned int flags; /* */
++#define SL_RLINE_NO_ECHO 1
++#define SL_RLINE_USE_ANSI 2
++#define SL_RLINE_BLINK_MATCH 4
++ unsigned int (*getkey)(void); /* getkey function -- required */
++ void (*tt_goto_column)(int);
++ void (*tt_insert)(char);
++ void (*update_hook)(unsigned char *, int, int);
++ /* The update hook is called with a pointer to a buffer p1 that contains
++ * an image of what the update hook is suppoed to produce. The length
++ * of the buffer is p2 and after the update, the cursor is to be placed
++ * in column p3.
++ */
++ /* This function is only called when blinking matches */
++ int (*input_pending)(int);
++ unsigned long reserved[4];
++} SLang_RLine_Info_Type;
++
++extern int SLang_RL_EOF_Char;
++
++extern SLang_Read_Line_Type * SLang_rline_save_line (SLang_RLine_Info_Type *);
++extern int SLang_init_readline (SLang_RLine_Info_Type *);
++extern int SLang_read_line (SLang_RLine_Info_Type *);
++extern int SLang_rline_insert (char *);
++extern void SLrline_redraw (SLang_RLine_Info_Type *);
++extern int SLang_Rline_Quit;
++
++/*}}}*/
++
++/*{{{ Low Level Screen Output Interface */
++
++extern unsigned long SLtt_Num_Chars_Output;
++extern int SLtt_Baud_Rate;
++
++typedef unsigned long SLtt_Char_Type;
++
++#define SLTT_BOLD_MASK 0x01000000UL
++#define SLTT_BLINK_MASK 0x02000000UL
++#define SLTT_ULINE_MASK 0x04000000UL
++#define SLTT_REV_MASK 0x08000000UL
++#define SLTT_ALTC_MASK 0x10000000UL
++
++extern int SLtt_Screen_Rows;
++extern int SLtt_Screen_Cols;
++extern int SLtt_Term_Cannot_Insert;
++extern int SLtt_Term_Cannot_Scroll;
++extern int SLtt_Use_Ansi_Colors;
++extern int SLtt_Ignore_Beep;
++#if defined(REAL_UNIX_SYSTEM)
++extern int SLtt_Force_Keypad_Init;
++extern int SLang_TT_Write_FD;
++#endif
++
++#ifndef IBMPC_SYSTEM
++extern char *SLtt_Graphics_Char_Pairs;
++#endif
++
++#ifndef __GO32__
++#if defined(VMS) || defined(REAL_UNIX_SYSTEM)
++extern int SLtt_Blink_Mode;
++extern int SLtt_Use_Blink_For_ACS;
++extern int SLtt_Newline_Ok;
++extern int SLtt_Has_Alt_Charset;
++extern int SLtt_Has_Status_Line; /* if 0, NO. If &gt; 0, YES, IF -1, ?? */
++# ifndef VMS
++extern int SLtt_Try_Termcap;
++# endif
++#endif
++#endif
++
++#if defined(IBMPC_SYSTEM)
++extern int SLtt_Msdos_Cheap_Video;
++#endif
++
++typedef unsigned short SLsmg_Char_Type;
++#define SLSMG_EXTRACT_CHAR(x) ((x) &amp; 0xFF)
++#define SLSMG_EXTRACT_COLOR(x) (((x)&gt;&gt;8)&amp;0xFF)
++#define SLSMG_BUILD_CHAR(ch,color) (((SLsmg_Char_Type)(unsigned char)(ch))|((color)&lt;&lt;8))
++
++extern int SLtt_flush_output (void);
++extern void SLtt_set_scroll_region(int, int);
++extern void SLtt_reset_scroll_region(void);
++extern void SLtt_reverse_video (int);
++extern void SLtt_bold_video (void);
++extern void SLtt_begin_insert(void);
++extern void SLtt_end_insert(void);
++extern void SLtt_del_eol(void);
++extern void SLtt_goto_rc (int, int);
++extern void SLtt_delete_nlines(int);
++extern void SLtt_delete_char(void);
++extern void SLtt_erase_line(void);
++extern void SLtt_normal_video(void);
++extern void SLtt_cls(void);
++extern void SLtt_beep(void);
++extern void SLtt_reverse_index(int);
++extern void SLtt_smart_puts(SLsmg_Char_Type *, SLsmg_Char_Type *, int, int);
++extern void SLtt_write_string (char *);
++extern void SLtt_putchar(char);
++extern int SLtt_init_video (void);
++extern int SLtt_reset_video (void);
++extern void SLtt_get_terminfo(void);
++extern void SLtt_get_screen_size (void);
++extern int SLtt_set_cursor_visibility (int);
++
++extern int SLtt_set_mouse_mode (int, int);
++
++#if defined(VMS) || defined(REAL_UNIX_SYSTEM)
++extern int SLtt_initialize (char *);
++extern void SLtt_enable_cursor_keys(void);
++extern void SLtt_set_term_vtxxx(int *);
++extern void SLtt_set_color_esc (int, char *);
++extern void SLtt_wide_width(void);
++extern void SLtt_narrow_width(void);
++extern void SLtt_set_alt_char_set (int);
++extern int SLtt_write_to_status_line (char *, int);
++extern void SLtt_disable_status_line (void);
++# ifdef REAL_UNIX_SYSTEM
++/* These are termcap/terminfo routines that assume SLtt_initialize has
++ * been called.
++ */
++extern char *SLtt_tgetstr (char *);
++extern int SLtt_tgetnum (char *);
++extern int SLtt_tgetflag (char *);
++
++/* The following are terminfo-only routines -- these prototypes will change
++ * in V2.x.
++ */
++extern char *SLtt_tigetent (char *);
++extern char *SLtt_tigetstr (char *, char **);
++extern int SLtt_tigetnum (char *, char **);
++# endif
++#endif
++
++extern SLtt_Char_Type SLtt_get_color_object (int);
++extern void SLtt_set_color_object (int, SLtt_Char_Type);
++extern void SLtt_set_color (int, char *, char *, char *);
++extern void SLtt_set_mono (int, char *, SLtt_Char_Type);
++extern void SLtt_add_color_attribute (int, SLtt_Char_Type);
++extern void SLtt_set_color_fgbg (int, SLtt_Char_Type, SLtt_Char_Type);
++
++/*}}}*/
++
++/*{{{ SLang Preprocessor Interface */
++
++typedef struct
++{
++ int this_level;
++ int exec_level;
++ int prev_exec_level;
++ char preprocess_char;
++ char comment_char;
++ unsigned char flags;
++#define SLPREP_BLANK_LINES_OK 1
++#define SLPREP_COMMENT_LINES_OK 2
++}
++SLPreprocess_Type;
++
++extern int SLprep_open_prep (SLPreprocess_Type *);
++extern void SLprep_close_prep (SLPreprocess_Type *);
++extern int SLprep_line_ok (char *, SLPreprocess_Type *);
++ extern int SLdefine_for_ifdef (char *);
++ /* Adds a string to the SLang #ifdef preparsing defines. SLang already
++ defines MSDOS, UNIX, and VMS on the appropriate system. */
++extern int (*SLprep_exists_hook) (char *, char);
++
++/*}}}*/
++
++/*{{{ SLsmg Screen Management Functions */
++
++extern void SLsmg_fill_region (int, int, unsigned int, unsigned int, unsigned char);
++extern void SLsmg_set_char_set (int);
++#ifndef IBMPC_SYSTEM
++extern int SLsmg_Scroll_Hash_Border;
++#endif
++extern int SLsmg_suspend_smg (void);
++extern int SLsmg_resume_smg (void);
++extern void SLsmg_erase_eol (void);
++extern void SLsmg_gotorc (int, int);
++extern void SLsmg_erase_eos (void);
++extern void SLsmg_reverse_video (void);
++extern void SLsmg_set_color (int);
++extern void SLsmg_normal_video (void);
++extern void SLsmg_printf (char *, ...);
++extern void SLsmg_vprintf (char *, va_list);
++extern void SLsmg_write_string (char *);
++extern void SLsmg_write_nstring (char *, unsigned int);
++extern void SLsmg_write_char (char);
++extern void SLsmg_write_nchars (char *, unsigned int);
++extern void SLsmg_write_wrapped_string (char *, int, int, unsigned int, unsigned int, int);
++extern void SLsmg_cls (void);
++extern void SLsmg_refresh (void);
++extern void SLsmg_touch_lines (int, unsigned int);
++extern void SLsmg_touch_screen (void);
++extern int SLsmg_init_smg (void);
++extern int SLsmg_reinit_smg (void);
++extern void SLsmg_reset_smg (void);
++extern SLsmg_Char_Type SLsmg_char_at(void);
++extern void SLsmg_set_screen_start (int *, int *);
++extern void SLsmg_draw_hline (unsigned int);
++extern void SLsmg_draw_vline (int);
++extern void SLsmg_draw_object (int, int, unsigned char);
++extern void SLsmg_draw_box (int, int, unsigned int, unsigned int);
++extern int SLsmg_get_column(void);
++extern int SLsmg_get_row(void);
++extern void SLsmg_forward (int);
++extern void SLsmg_write_color_chars (SLsmg_Char_Type *, unsigned int);
++extern unsigned int SLsmg_read_raw (SLsmg_Char_Type *, unsigned int);
++extern unsigned int SLsmg_write_raw (SLsmg_Char_Type *, unsigned int);
++extern void SLsmg_set_color_in_region (int, int, int, unsigned int, unsigned int);
++extern int SLsmg_Display_Eight_Bit;
++extern int SLsmg_Tab_Width;
++
++#define SLSMG_NEWLINE_IGNORED 0 /* default */
++#define SLSMG_NEWLINE_MOVES 1 /* moves to next line, column 0 */
++#define SLSMG_NEWLINE_SCROLLS 2 /* moves but scrolls at bottom of screen */
++#define SLSMG_NEWLINE_PRINTABLE 3 /* prints as ^J */
++extern int SLsmg_Newline_Behavior;
++
++extern int SLsmg_Backspace_Moves;
++
++#ifdef IBMPC_SYSTEM
++# define SLSMG_HLINE_CHAR 0xC4
++# define SLSMG_VLINE_CHAR 0xB3
++# define SLSMG_ULCORN_CHAR 0xDA
++# define SLSMG_URCORN_CHAR 0xBF
++# define SLSMG_LLCORN_CHAR 0xC0
++# define SLSMG_LRCORN_CHAR 0xD9
++# define SLSMG_RTEE_CHAR 0xB4
++# define SLSMG_LTEE_CHAR 0xC3
++# define SLSMG_UTEE_CHAR 0xC2
++# define SLSMG_DTEE_CHAR 0xC1
++# define SLSMG_PLUS_CHAR 0xC5
++/* There are several to choose from: 0xB0, 0xB1, and 0xB2 */
++# define SLSMG_CKBRD_CHAR 0xB0
++# define SLSMG_DIAMOND_CHAR 0x04
++# define SLSMG_DEGREE_CHAR 0xF8
++# define SLSMG_PLMINUS_CHAR 0xF1
++# define SLSMG_BULLET_CHAR 0xF9
++# define SLSMG_LARROW_CHAR 0x1B
++# define SLSMG_RARROW_CHAR 0x1A
++# define SLSMG_DARROW_CHAR 0x19
++# define SLSMG_UARROW_CHAR 0x18
++# define SLSMG_BOARD_CHAR 0xB2
++# define SLSMG_BLOCK_CHAR 0xDB
++#else
++# if defined(AMIGA)
++# define SLSMG_HLINE_CHAR '-'
++# define SLSMG_VLINE_CHAR '|'
++# define SLSMG_ULCORN_CHAR '+'
++# define SLSMG_URCORN_CHAR '+'
++# define SLSMG_LLCORN_CHAR '+'
++# define SLSMG_LRCORN_CHAR '+'
++# define SLSMG_CKBRD_CHAR '#'
++# define SLSMG_RTEE_CHAR '+'
++# define SLSMG_LTEE_CHAR '+'
++# define SLSMG_UTEE_CHAR '+'
++# define SLSMG_DTEE_CHAR '+'
++# define SLSMG_PLUS_CHAR '+'
++# define SLSMG_DIAMOND_CHAR '+'
++# define SLSMG_DEGREE_CHAR '\\'
++# define SLSMG_PLMINUS_CHAR '#'
++# define SLSMG_BULLET_CHAR 'o'
++# define SLSMG_LARROW_CHAR '&lt;'
++# define SLSMG_RARROW_CHAR '&gt;'
++# define SLSMG_DARROW_CHAR 'v'
++# define SLSMG_UARROW_CHAR '^'
++# define SLSMG_BOARD_CHAR '#'
++# define SLSMG_BLOCK_CHAR '#'
++# else
++# define SLSMG_HLINE_CHAR 'q'
++# define SLSMG_VLINE_CHAR 'x'
++# define SLSMG_ULCORN_CHAR 'l'
++# define SLSMG_URCORN_CHAR 'k'
++# define SLSMG_LLCORN_CHAR 'm'
++# define SLSMG_LRCORN_CHAR 'j'
++# define SLSMG_CKBRD_CHAR 'a'
++# define SLSMG_RTEE_CHAR 'u'
++# define SLSMG_LTEE_CHAR 't'
++# define SLSMG_UTEE_CHAR 'w'
++# define SLSMG_DTEE_CHAR 'v'
++# define SLSMG_PLUS_CHAR 'n'
++# define SLSMG_DIAMOND_CHAR '`'
++# define SLSMG_DEGREE_CHAR 'f'
++# define SLSMG_PLMINUS_CHAR 'g'
++# define SLSMG_BULLET_CHAR '~'
++# define SLSMG_LARROW_CHAR ','
++# define SLSMG_RARROW_CHAR '+'
++# define SLSMG_DARROW_CHAR '.'
++# define SLSMG_UARROW_CHAR '-'
++# define SLSMG_BOARD_CHAR 'h'
++# define SLSMG_BLOCK_CHAR '0'
++# endif /* AMIGA */
++#endif /* IBMPC_SYSTEM */
++
++#ifndef IBMPC_SYSTEM
++# define SLSMG_COLOR_BLACK 0x000000
++# define SLSMG_COLOR_RED 0x000001
++# define SLSMG_COLOR_GREEN 0x000002
++# define SLSMG_COLOR_BROWN 0x000003
++# define SLSMG_COLOR_BLUE 0x000004
++# define SLSMG_COLOR_MAGENTA 0x000005
++# define SLSMG_COLOR_CYAN 0x000006
++# define SLSMG_COLOR_LGRAY 0x000007
++# define SLSMG_COLOR_GRAY 0x000008
++# define SLSMG_COLOR_BRIGHT_RED 0x000009
++# define SLSMG_COLOR_BRIGHT_GREEN 0x00000A
++# define SLSMG_COLOR_BRIGHT_BROWN 0x00000B
++# define SLSMG_COLOR_BRIGHT_BLUE 0x00000C
++# define SLSMG_COLOR_BRIGHT_CYAN 0x00000D
++# define SLSMG_COLOR_BRIGHT_MAGENTA 0x00000E
++# define SLSMG_COLOR_BRIGHT_WHITE 0x00000F
++#endif
++
++typedef struct
++{
++ void (*tt_normal_video)(void);
++ void (*tt_set_scroll_region)(int, int);
++ void (*tt_goto_rc)(int, int);
++ void (*tt_reverse_index)(int);
++ void (*tt_reset_scroll_region)(void);
++ void (*tt_delete_nlines)(int);
++ void (*tt_cls) (void);
++ void (*tt_del_eol) (void);
++ void (*tt_smart_puts) (SLsmg_Char_Type *, SLsmg_Char_Type *, int, int);
++ int (*tt_flush_output) (void);
++ int (*tt_reset_video) (void);
++ int (*tt_init_video) (void);
++
++ int *tt_screen_rows;
++ int *tt_screen_cols;
++
++ int *tt_term_cannot_scroll;
++ int *tt_has_alt_charset;
++ int *tt_use_blink_for_acs;
++ char **tt_graphic_char_pairs;
++
++ long reserved[4];
++}
++SLsmg_Term_Type;
++extern void SLsmg_set_terminal_info (SLsmg_Term_Type *);
++
++/*}}}*/
++
++/*{{{ SLang Keypad Interface */
++
++#define SL_KEY_ERR 0xFFFF
++
++#define SL_KEY_UP 0x101
++#define SL_KEY_DOWN 0x102
++#define SL_KEY_LEFT 0x103
++#define SL_KEY_RIGHT 0x104
++#define SL_KEY_PPAGE 0x105
++#define SL_KEY_NPAGE 0x106
++#define SL_KEY_HOME 0x107
++#define SL_KEY_END 0x108
++#define SL_KEY_A1 0x109
++#define SL_KEY_A3 0x10A
++#define SL_KEY_B2 0x10B
++#define SL_KEY_C1 0x10C
++#define SL_KEY_C3 0x10D
++#define SL_KEY_REDO 0x10E
++#define SL_KEY_UNDO 0x10F
++#define SL_KEY_BACKSPACE 0x110
++#define SL_KEY_ENTER 0x111
++#define SL_KEY_IC 0x112
++#define SL_KEY_DELETE 0x113
++
++#define SL_KEY_F0 0x200
++#define SL_KEY_F(X) (SL_KEY_F0 + X)
++
++/* I do not intend to use keysymps &gt; 0x1000. Applications can use those. */
++/* Returns 0 upon success or -1 upon error. */
++extern int SLkp_define_keysym (char *, unsigned int);
++
++/* This function must be called AFTER SLtt_get_terminfo and not before. */
++extern int SLkp_init (void);
++
++/* This function uses SLang_getkey and assumes that what ever initialization
++ * is required for SLang_getkey has been performed.
++ */
++extern int SLkp_getkey (void);
++
++/*}}}*/
++
++/*{{{ SLang Scroll Interface */
++
++typedef struct _SLscroll_Type
++{
++ struct _SLscroll_Type *next;
++ struct _SLscroll_Type *prev;
++ unsigned int flags;
++}
++SLscroll_Type;
++
++typedef struct
++{
++ unsigned int flags;
++ SLscroll_Type *top_window_line; /* list element at top of window */
++ SLscroll_Type *bot_window_line; /* list element at bottom of window */
++ SLscroll_Type *current_line; /* current list element */
++ SLscroll_Type *lines; /* first list element */
++ unsigned int nrows; /* number of rows in window */
++ unsigned int hidden_mask; /* applied to flags in SLscroll_Type */
++ unsigned int line_num; /* current line number (visible) */
++ unsigned int num_lines; /* total number of lines (visible) */
++ unsigned int window_row; /* row of current_line in window */
++ unsigned int border; /* number of rows that form scroll border */
++ int cannot_scroll; /* should window scroll or recenter */
++}
++SLscroll_Window_Type;
++
++extern int SLscroll_find_top (SLscroll_Window_Type *);
++extern int SLscroll_find_line_num (SLscroll_Window_Type *);
++extern unsigned int SLscroll_next_n (SLscroll_Window_Type *, unsigned int);
++extern unsigned int SLscroll_prev_n (SLscroll_Window_Type *, unsigned int);
++extern int SLscroll_pageup (SLscroll_Window_Type *);
++extern int SLscroll_pagedown (SLscroll_Window_Type *);
++
++/*}}}*/
++
++/*{{{ Signal Routines */
++
++typedef void SLSig_Fun_Type (int);
++extern SLSig_Fun_Type *SLsignal (int, SLSig_Fun_Type *);
++extern SLSig_Fun_Type *SLsignal_intr (int, SLSig_Fun_Type *);
++extern int SLsig_block_signals (void);
++extern int SLsig_unblock_signals (void);
++extern int SLsystem (char *);
++
++extern char *SLerrno_strerror (int);
++extern int SLerrno_set_errno (int);
++
++/*}}}*/
++
++/*{{{ Interpreter Macro Definitions */
++
++/* The definitions here are for objects that may be on the run-time stack.
++ * They are actually sub_types of literal and data main_types. The actual
++ * numbers are historical.
++ */
++#define SLANG_UNDEFINED_TYPE 0x00 /* MUST be 0 */
++#define SLANG_VOID_TYPE 0x01 /* also matches ANY type */
++#define SLANG_INT_TYPE 0x02
++#define SLANG_DOUBLE_TYPE 0x03
++#define SLANG_CHAR_TYPE 0x04
++#define SLANG_INTP_TYPE 0x05
++/* An object of SLANG_INTP_TYPE should never really occur on the stack. Rather,
++ * the integer to which it refers will be there instead. It is defined here
++ * because it is a valid type for MAKE_VARIABLE.
++ */
++#define SLANG_REF_TYPE 0x06
++/* SLANG_REF_TYPE refers to an object on the stack that is a pointer (reference)
++ * to some other object.
++ */
++#define SLANG_COMPLEX_TYPE 0x07
++#define SLANG_NULL_TYPE 0x08
++#define SLANG_UCHAR_TYPE 0x09
++#define SLANG_SHORT_TYPE 0x0A
++#define SLANG_USHORT_TYPE 0x0B
++#define SLANG_UINT_TYPE 0x0C
++#define SLANG_LONG_TYPE 0x0D
++#define SLANG_ULONG_TYPE 0x0E
++#define SLANG_STRING_TYPE 0x0F
++#define SLANG_FLOAT_TYPE 0x10
++#define SLANG_STRUCT_TYPE 0x11
++#define SLANG_ISTRUCT_TYPE 0x12
++#define SLANG_ARRAY_TYPE 0x20
++#define SLANG_DATATYPE_TYPE 0x21
++#define SLANG_FILE_PTR_TYPE 0x22
++#define SLANG_ASSOC_TYPE 0x23
++#define SLANG_ANY_TYPE 0x24
++#define SLANG_BSTRING_TYPE 0x25
++#define SLANG_FILE_FD_TYPE 0x26
++
++/* Compatibility */
++#ifdef FLOAT_TYPE
++# undef FLOAT_TYPE
++#endif
++#define VOID_TYPE SLANG_VOID_TYPE
++#define INT_TYPE SLANG_INT_TYPE
++#define INTP_TYPE SLANG_INTP_TYPE
++#define FLOAT_TYPE SLANG_DOUBLE_TYPE
++#define ARRAY_TYPE SLANG_ARRAY_TYPE
++#define CHAR_TYPE SLANG_CHAR_TYPE
++#define STRING_TYPE SLANG_STRING_TYPE
++
++/* I am reserving values greater than or equal to 128 for user applications.
++ * The first 127 are reserved for S-Lang.
++ */
++
++/* Binary and Unary Subtypes */
++/* Since the application can define new types and can overload the binary
++ * and unary operators, these definitions must be present in this file.
++ * The current implementation assumes both unary and binary are distinct.
++ */
++#define SLANG_PLUS 0x01
++#define SLANG_MINUS 0x02
++#define SLANG_TIMES 0x03
++#define SLANG_DIVIDE 0x04
++#define SLANG_EQ 0x05
++#define SLANG_NE 0x06
++#define SLANG_GT 0x07
++#define SLANG_GE 0x08
++#define SLANG_LT 0x09
++#define SLANG_LE 0x0A
++#define SLANG_POW 0x0B
++#define SLANG_OR 0x0C
++#define SLANG_AND 0x0D
++#define SLANG_BAND 0x0E
++#define SLANG_BOR 0x0F
++#define SLANG_BXOR 0x10
++#define SLANG_SHL 0x11
++#define SLANG_SHR 0x12
++#define SLANG_MOD 0x13
++
++/* UNARY subtypes (may be overloaded) */
++#define SLANG_PLUSPLUS 0x20
++#define SLANG_MINUSMINUS 0x21
++#define SLANG_ABS 0x22
++#define SLANG_SIGN 0x23
++#define SLANG_SQR 0x24
++#define SLANG_MUL2 0x25
++#define SLANG_CHS 0x26
++#define SLANG_NOT 0x27
++#define SLANG_BNOT 0x28
++
++extern char *SLang_Error_Message;
++
++int SLadd_intrinsic_variable (char *, VOID_STAR, unsigned char, int);
++int SLadd_intrinsic_function (char *, FVOID_STAR, unsigned char, unsigned int,...);
++
++int SLns_add_intrinsic_variable (SLang_NameSpace_Type *, char *, VOID_STAR, unsigned char, int);
++int SLns_add_intrinsic_function (SLang_NameSpace_Type *, char *, FVOID_STAR, unsigned char, unsigned int,...);
++
++extern void SLadd_at_handler (long *, char *);
++
++#define MAKE_INTRINSIC_N(n,f,out,in,a1,a2,a3,a4,a5,a6,a7) \
++ {(n), NULL, SLANG_INTRINSIC, (FVOID_STAR) (f), \
++ {a1,a2,a3,a4,a5,a6,a7}, (in), (out)}
++
++#define MAKE_INTRINSIC_7(n,f,out,a1,a2,a3,a4,a5,a6,a7) \
++ MAKE_INTRINSIC_N(n,f,out,7,a1,a2,a3,a4,a5,a6,a7)
++#define MAKE_INTRINSIC_6(n,f,out,a1,a2,a3,a4,a5,a6) \
++ MAKE_INTRINSIC_N(n,f,out,6,a1,a2,a3,a4,a5,a6,0)
++#define MAKE_INTRINSIC_5(n,f,out,a1,a2,a3,a4,a5) \
++ MAKE_INTRINSIC_N(n,f,out,5,a1,a2,a3,a4,a5,0,0)
++#define MAKE_INTRINSIC_4(n,f,out,a1,a2,a3,a4) \
++ MAKE_INTRINSIC_N(n,f,out,4,a1,a2,a3,a4,0,0,0)
++#define MAKE_INTRINSIC_3(n,f,out,a1,a2,a3) \
++ MAKE_INTRINSIC_N(n,f,out,3,a1,a2,a3,0,0,0,0)
++#define MAKE_INTRINSIC_2(n,f,out,a1,a2) \
++ MAKE_INTRINSIC_N(n,f,out,2,a1,a2,0,0,0,0,0)
++#define MAKE_INTRINSIC_1(n,f,out,a1) \
++ MAKE_INTRINSIC_N(n,f,out,1,a1,0,0,0,0,0,0)
++#define MAKE_INTRINSIC_0(n,f,out) \
++ MAKE_INTRINSIC_N(n,f,out,0,0,0,0,0,0,0,0)
++
++#define MAKE_INTRINSIC_S(n,f,r) \
++ MAKE_INTRINSIC_1(n,f,r,SLANG_STRING_TYPE)
++#define MAKE_INTRINSIC_I(n,f,r) \
++ MAKE_INTRINSIC_1(n,f,r,SLANG_INT_TYPE)
++
++#define MAKE_INTRINSIC_SS(n,f,r) \
++ MAKE_INTRINSIC_2(n,f,r,SLANG_STRING_TYPE,SLANG_STRING_TYPE)
++#define MAKE_INTRINSIC_SI(n,f,r) \
++ MAKE_INTRINSIC_2(n,f,r,SLANG_STRING_TYPE,SLANG_INT_TYPE)
++#define MAKE_INTRINSIC_IS(n,f,r) \
++ MAKE_INTRINSIC_2(n,f,r,SLANG_INT_TYPE,SLANG_STRING_TYPE)
++#define MAKE_INTRINSIC_II(n,f,r) \
++ MAKE_INTRINSIC_2(n,f,r,SLANG_INT_TYPE,SLANG_INT_TYPE)
++
++#define MAKE_INTRINSIC_SSS(n,f,r) \
++ MAKE_INTRINSIC_3(n,f,r,SLANG_STRING_TYPE,SLANG_STRING_TYPE,SLANG_STRING_TYPE)
++#define MAKE_INTRINSIC_SSI(n,f,r) \
++ MAKE_INTRINSIC_3(n,f,r,SLANG_STRING_TYPE,SLANG_STRING_TYPE,SLANG_INT_TYPE)
++#define MAKE_INTRINSIC_SIS(n,f,r) \
++ MAKE_INTRINSIC_3(n,f,r,SLANG_STRING_TYPE,SLANG_INT_TYPE,SLANG_STRING_TYPE)
++#define MAKE_INTRINSIC_SII(n,f,r) \
++ MAKE_INTRINSIC_3(n,f,r,SLANG_STRING_TYPE,SLANG_INT_TYPE,SLANG_INT_TYPE)
++#define MAKE_INTRINSIC_ISS(n,f,r) \
++ MAKE_INTRINSIC_3(n,f,r,SLANG_INT_TYPE,SLANG_STRING_TYPE,SLANG_STRING_TYPE)
++#define MAKE_INTRINSIC_ISI(n,f,r) \
++ MAKE_INTRINSIC_3(n,f,r,SLANG_INT_TYPE,SLANG_STRING_TYPE,SLANG_INT_TYPE)
++#define MAKE_INTRINSIC_IIS(n,f,r) \
++ MAKE_INTRINSIC_3(n,f,r,SLANG_INT_TYPE,SLANG_INT_TYPE,SLANG_STRING_TYPE)
++#define MAKE_INTRINSIC_III(n,f,r) \
++ MAKE_INTRINSIC_3(n,f,r,SLANG_INT_TYPE,SLANG_INT_TYPE,SLANG_INT_TYPE)
++
++#define MAKE_INTRINSIC(n, f, out, in) \
++ MAKE_INTRINSIC_N(n,f,out,in,0,0,0,0,0,0,0)
++
++#define MAKE_VARIABLE(n, v, t, r) \
++ {n, NULL, SLANG_IVARIABLE + (r), (VOID_STAR)(v), (t)}
++
++#define MAKE_APP_UNARY(n,op) \
++ {(n), NULL, SLANG_APP_UNARY, (op)}
++
++#define MAKE_MATH_UNARY(n,op) \
++ {(n), NULL, SLANG_MATH_UNARY, (op)}
++
++#define MAKE_ICONSTANT(n,val) \
++ {(n),NULL, SLANG_ICONSTANT, (val)}
++
++#define MAKE_DCONSTANT(n,val) \
++ {(n),NULL, SLANG_DCONSTANT, (val)}
++
++#ifndef offsetof
++# define offsetof(T,F) ((unsigned int)((char *)&amp;((T *)0L)-&gt;F - (char *)0L))
++#endif
++#define MAKE_ISTRUCT_FIELD(s,f,n,t,r) {(n), offsetof(s,f), (t), (r)}
++
++#define SLANG_END_TABLE {NULL}
++#define SLANG_END_INTRIN_FUN_TABLE MAKE_INTRINSIC_0(NULL,NULL,0)
++#define SLANG_END_DCONST_TABLE MAKE_DCONSTANT(NULL,0)
++#define SLANG_END_MATH_UNARY_TABLE MAKE_MATH_UNARY(NULL,0)
++#define SLANG_END_INTRIN_VAR_TABLE MAKE_VARIABLE(NULL,NULL,0,0)
++#define SLANG_END_ICONST_TABLE MAKE_ICONSTANT(NULL,0)
++#define SLANG_END_ISTRUCT_TABLE {NULL, 0, 0, 0}
++
++
++
++/*}}}*/
++
++/*{{{ Upper/Lowercase Functions */
++
++extern void SLang_define_case(int *, int *);
++extern void SLang_init_case_tables (void);
++
++extern unsigned char _SLChg_UCase_Lut[256];
++extern unsigned char _SLChg_LCase_Lut[256];
++#define UPPER_CASE(x) (_SLChg_UCase_Lut[(unsigned char) (x)])
++#define LOWER_CASE(x) (_SLChg_LCase_Lut[(unsigned char) (x)])
++#define CHANGE_CASE(x) (((x) == _SLChg_LCase_Lut[(unsigned char) (x)]) ?\
++ _SLChg_UCase_Lut[(unsigned char) (x)] : _SLChg_LCase_Lut[(unsigned char) (x)])
++
++/*}}}*/
++
++/*{{{ Regular Expression Interface */
++
++typedef struct
++{
++ /* These must be set by calling routine. */
++ unsigned char *pat; /* regular expression pattern */
++ unsigned char *buf; /* buffer for compiled regexp */
++ unsigned int buf_len; /* length of buffer */
++ int case_sensitive; /* 1 if match is case sensitive */
++
++ /* The rest are set by SLang_regexp_compile */
++
++ int must_match; /* 1 if line must contain substring */
++ int must_match_bol; /* true if it must match beginning of line */
++ unsigned char must_match_str[16]; /* 15 char null term substring */
++ int osearch; /* 1 if ordinary search suffices */
++ unsigned int min_length; /* minimum length the match must be */
++ int beg_matches[10]; /* offset of start of \( */
++ unsigned int end_matches[10]; /* length of nth submatch
++ * Note that the entire match corresponds
++ * to \0
++ */
++ int offset; /* offset to be added to beg_matches */
++ int reserved[10];
++} SLRegexp_Type;
++
++extern unsigned char *SLang_regexp_match(unsigned char *,
++ unsigned int,
++ SLRegexp_Type *);
++
++/* Returns 0 upon success. If failure, the offset into the
++ * pattern is returned (start = 1).
++ */
++extern int SLang_regexp_compile (SLRegexp_Type *);
++extern char *SLregexp_quote_string (char *, char *, unsigned int);
++
++/*}}}*/
++
++/*{{{ SLang Command Interface */
++
++struct _SLcmd_Cmd_Type; /* Pre-declaration is needed below */
++typedef struct
++{
++ struct _SLcmd_Cmd_Type *table;
++ int argc;
++ /* Version 2.0 needs to use a union!! */
++ char **string_args;
++ int *int_args;
++ double *double_args;
++ unsigned char *arg_type;
++ unsigned long reserved[4];
++} SLcmd_Cmd_Table_Type;
++
++typedef struct _SLcmd_Cmd_Type
++{
++ int (*cmdfun)(int, SLcmd_Cmd_Table_Type *);
++ char *cmd;
++ char *arg_type;
++} SLcmd_Cmd_Type;
++
++extern int SLcmd_execute_string (char *, SLcmd_Cmd_Table_Type *);
++
++/*}}}*/
++
++/*{{{ SLang Search Interface */
++
++typedef struct
++{
++ int cs; /* case sensitive */
++ unsigned char key[256];
++ int ind[256];
++ int key_len;
++ int dir;
++} SLsearch_Type;
++
++extern int SLsearch_init (char *, int, int, SLsearch_Type *);
++/* This routine must first be called before any search can take place.
++ * The second parameter specifies the direction of the search: greater than
++ * zero for a forwrd search and less than zero for a backward search. The
++ * third parameter specifies whether the search is case sensitive or not.
++ * The last parameter is a pointer to a structure that is filled by this
++ * function and it is this structure that must be passed to SLsearch.
++ */
++
++extern unsigned char *SLsearch (unsigned char *, unsigned char *, SLsearch_Type *);
++/* To use this routine, you must first call 'SLsearch_init'. Then the first
++ * two parameters p1 and p2 serve to define the region over which the search
++ * is to take place. The third parameter is the structure that was previously
++ * initialized by SLsearch_init.
++ *
++ * The routine returns a pointer to the match if found otherwise it returns
++ * NULL.
++ */
++
++/*}}}*/
++
++/*{{{ SLang Pathname Interface */
++
++/* These function return pointers to the original space */
++extern char *SLpath_basename (char *);
++extern char *SLpath_extname (char *);
++extern int SLpath_is_absolute_path (char *);
++
++/* These return malloced strings--- NOT slstrings */
++extern char *SLpath_dircat (char *, char *);
++extern char *SLpath_find_file_in_path (char *, char *);
++extern char *SLpath_dirname (char *);
++extern int SLpath_file_exists (char *);
++extern char *SLpath_pathname_sans_extname (char *);
++
++/*}}}*/
++
++extern int SLang_set_module_load_path (char *);
++
++#define SLANG_MODULE(name) \
++ extern int init_##name##_module_ns (char *); \
++ extern void deinit_##name##_module (void)
++
++#if 0
++{
++#endif
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _DAVIS_SLANG_H_ */
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slang.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slarith.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slarith.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slarith.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1656 @@
++
++/* Copyright (c) 1998, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++
++#include &lt;math.h&gt;
++
++#ifdef HAVE_LOCALE_H
++# include &lt;locale.h&gt;
++#endif
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++/*
++ * This file defines binary and unary operations on all integer types.
++ * Supported types include:
++ *
++ * SLANG_CHAR_TYPE (char)
++ * SLANG_SHORT_TYPE (short)
++ * SLANG_INT_TYPE (int)
++ * SLANG_LONG_TYPE (long)
++ * SLANG_FLOAT_TYPE (float)
++ * SLANG_DOUBLE_TYPE (double)
++ *
++ * as well as unsigned types. The result-type of an arithmentic operation
++ * will depend upon the data types involved. I am going to distinguish
++ * between the boolean operations such as `and' and `or' from the arithmetic
++ * operations such as `plus'. Since the result of a boolean operation is
++ * either 1 or 0, a boolean result will be represented by SLANG_CHAR_TYPE.
++ * Ordinarily I would use an integer but for arrays it makes more sense to
++ * use a character data type.
++ *
++ * So, the following will be assumed (`+' is any arithmetic operator)
++ *
++ * char + char = int
++ * char|short + short = int
++ * char|short|int + int = int
++ * char|short|int|long + long = long
++ * char|short|int|long|float + float = float
++ * char|short|int|long|float|double + double = double
++ *
++ * In the actual implementation, a brute force approach is avoided. Such
++ * an approach would mean defining different functions for all possible
++ * combinations of types. Including the unsigned types, and not including
++ * the complex number type, there are 10 arithmetic types and 10*10=100
++ * different combinations of types. Clearly this would be too much.
++ *
++ * One approach would be to define binary functions only between operands of
++ * the same type and then convert types as appropriate. This would require
++ * just 6 such functions (int, uint, long, ulong, float, double).
++ * However, many conversion functions are going to be required, particularly
++ * since we are going to allow typecasting from one arithmetic to another.
++ * Since the bit pattern of signed and unsigned types are the same, and only
++ * the interpretation differs, there will be no functions to convert between
++ * signed and unsigned forms of a given type.
++ */
++
++#define MAX_ARITHMETIC_TYPES 10
++
++unsigned char _SLarith_Is_Arith_Type [256];
++
++unsigned char _SLarith_Arith_Types[] =
++{
++ SLANG_CHAR_TYPE,
++ SLANG_UCHAR_TYPE,
++ SLANG_SHORT_TYPE,
++ SLANG_USHORT_TYPE,
++ SLANG_INT_TYPE,
++ SLANG_UINT_TYPE,
++ SLANG_LONG_TYPE,
++ SLANG_ULONG_TYPE,
++ SLANG_FLOAT_TYPE,
++ SLANG_DOUBLE_TYPE,
++ 0
++};
++
++/* Here are a bunch of functions to convert from one type to another. To
++ * facilitate the process, a macros will be used.
++ */
++
++#define DEFUN_1(f,from_type,to_type) \
++static void f (to_type *y, from_type *x, unsigned int n) \
++{ \
++ unsigned int i; \
++ for (i = 0; i &lt; n; i++) y[i] = (to_type) x[i]; \
++}
++
++#define DEFUN_2(f,from_type,to_type,copy_fun) \
++static VOID_STAR f (VOID_STAR xp, unsigned int n) \
++{ \
++ from_type *x; \
++ to_type *y; \
++ x = (from_type *) xp; \
++ if (NULL == (y = (to_type *) SLmalloc (sizeof (to_type) * n))) return NULL; \
++ copy_fun (y, x, n); \
++ return (VOID_STAR) y; \
++}
++typedef VOID_STAR (*Convert_Fun_Type)(VOID_STAR, unsigned int);
++
++DEFUN_1(copy_char_to_char,char,char)
++#if SIZEOF_INT != SIZEOF_SHORT
++DEFUN_1(copy_char_to_short,char,short)
++DEFUN_1(copy_char_to_ushort,char,unsigned short)
++#else
++# define copy_char_to_short copy_char_to_int
++# define copy_char_to_ushort copy_char_to_uint
++#endif
++DEFUN_1(copy_char_to_int,char,int)
++DEFUN_1(copy_char_to_uint,char,unsigned int)
++#if SIZEOF_INT != SIZEOF_LONG
++DEFUN_1(copy_char_to_long,char,long)
++DEFUN_1(copy_char_to_ulong,char,unsigned long)
++#else
++# define copy_char_to_long copy_char_to_int
++# define copy_char_to_ulong copy_char_to_uint
++#endif
++DEFUN_1(copy_char_to_float,char,float)
++DEFUN_1(copy_char_to_double,char,double)
++
++#if SIZEOF_INT != SIZEOF_SHORT
++DEFUN_1(copy_uchar_to_short,unsigned char,short)
++DEFUN_1(copy_uchar_to_ushort,unsigned char,unsigned short)
++#else
++# define copy_uchar_to_short copy_uchar_to_int
++# define copy_uchar_to_ushort copy_uchar_to_uint
++#endif
++DEFUN_1(copy_uchar_to_int,unsigned char,int)
++DEFUN_1(copy_uchar_to_uint,unsigned char,unsigned int)
++#if SIZEOF_INT != SIZEOF_LONG
++DEFUN_1(copy_uchar_to_long,unsigned char,long)
++DEFUN_1(copy_uchar_to_ulong,unsigned char,unsigned long)
++#else
++# define copy_uchar_to_long copy_uchar_to_int
++# define copy_uchar_to_ulong copy_uchar_to_uint
++#endif
++DEFUN_1(copy_uchar_to_float,unsigned char,float)
++DEFUN_1(copy_uchar_to_double,unsigned char,double)
++
++#if SIZEOF_INT != SIZEOF_SHORT
++DEFUN_1(copy_short_to_char,short,char)
++DEFUN_1(copy_short_to_uchar,short,unsigned char)
++DEFUN_1(copy_short_to_short,short,short)
++DEFUN_1(copy_short_to_int,short,int)
++DEFUN_1(copy_short_to_uint,short,unsigned int)
++DEFUN_1(copy_short_to_long,short,long)
++DEFUN_1(copy_short_to_ulong,short,unsigned long)
++DEFUN_1(copy_short_to_float,short,float)
++DEFUN_1(copy_short_to_double,short,double)
++DEFUN_1(copy_ushort_to_char,unsigned short,char)
++DEFUN_1(copy_ushort_to_uchar,unsigned short,unsigned char)
++DEFUN_1(copy_ushort_to_int,unsigned short,int)
++DEFUN_1(copy_ushort_to_uint,unsigned short,unsigned int)
++DEFUN_1(copy_ushort_to_long,unsigned short,long)
++DEFUN_1(copy_ushort_to_ulong,unsigned short,unsigned long)
++DEFUN_1(copy_ushort_to_float,unsigned short,float)
++DEFUN_1(copy_ushort_to_double,unsigned short,double)
++#else
++# define copy_short_to_char copy_int_to_char
++# define copy_short_to_uchar copy_int_to_uchar
++# define copy_short_to_short copy_int_to_int
++# define copy_short_to_int copy_int_to_int
++# define copy_short_to_uint copy_int_to_int
++# define copy_short_to_long copy_int_to_long
++# define copy_short_to_ulong copy_int_to_ulong
++# define copy_short_to_float copy_int_to_float
++# define copy_short_to_double copy_int_to_double
++# define copy_ushort_to_char copy_uint_to_char
++# define copy_ushort_to_uchar copy_uint_to_uchar
++# define copy_ushort_to_int copy_int_to_int
++# define copy_ushort_to_uint copy_int_to_int
++# define copy_ushort_to_long copy_uint_to_long
++# define copy_ushort_to_ulong copy_uint_to_ulong
++# define copy_ushort_to_float copy_uint_to_float
++# define copy_ushort_to_double copy_uint_to_double
++#endif
++
++DEFUN_1(copy_int_to_char,int,char)
++DEFUN_1(copy_int_to_uchar,int,unsigned char)
++DEFUN_1(copy_uint_to_char,unsigned int,char)
++DEFUN_1(copy_uint_to_uchar,unsigned int,unsigned char)
++#if SIZEOF_INT != SIZEOF_SHORT
++DEFUN_1(copy_int_to_short,int,short)
++DEFUN_1(copy_int_to_ushort,int,unsigned short)
++DEFUN_1(copy_uint_to_short,unsigned int,short)
++DEFUN_1(copy_uint_to_ushort,unsigned int,unsigned short)
++#else
++# define copy_int_to_short copy_int_to_int
++# define copy_int_to_ushort copy_int_to_int
++# define copy_uint_to_short copy_int_to_int
++# define copy_uint_to_ushort copy_int_to_int
++#endif
++DEFUN_1(copy_int_to_int,int,int)
++#if SIZEOF_INT != SIZEOF_LONG
++DEFUN_1(copy_int_to_long,int,long)
++DEFUN_1(copy_int_to_ulong,int,unsigned long)
++DEFUN_1(copy_uint_to_long,unsigned int,long)
++DEFUN_1(copy_uint_to_ulong,unsigned int,unsigned long)
++#else
++# define copy_int_to_long copy_int_to_int
++# define copy_int_to_ulong copy_int_to_int
++# define copy_uint_to_long copy_int_to_int
++# define copy_uint_to_ulong copy_int_to_int
++#endif
++DEFUN_1(copy_int_to_float,int,float)
++DEFUN_1(copy_int_to_double,int,double)
++DEFUN_1(copy_uint_to_float,unsigned int,float)
++DEFUN_1(copy_uint_to_double,unsigned int,double)
++
++#if SIZEOF_INT != SIZEOF_LONG
++DEFUN_1(copy_long_to_char,long,char)
++DEFUN_1(copy_long_to_uchar,long,unsigned char)
++DEFUN_1(copy_long_to_short,long,short)
++DEFUN_1(copy_long_to_ushort,long,unsigned short)
++DEFUN_1(copy_long_to_int,long,int)
++DEFUN_1(copy_long_to_uint,long,unsigned int)
++DEFUN_1(copy_long_to_long,long,long)
++DEFUN_1(copy_long_to_float,long,float)
++DEFUN_1(copy_long_to_double,long,double)
++DEFUN_1(copy_ulong_to_char,unsigned long,char)
++DEFUN_1(copy_ulong_to_uchar,unsigned long,unsigned char)
++DEFUN_1(copy_ulong_to_short,unsigned long,short)
++DEFUN_1(copy_ulong_to_ushort,unsigned long,unsigned short)
++DEFUN_1(copy_ulong_to_int,unsigned long,int)
++DEFUN_1(copy_ulong_to_uint,unsigned long,unsigned int)
++DEFUN_1(copy_ulong_to_float,unsigned long,float)
++DEFUN_1(copy_ulong_to_double,unsigned long,double)
++#else
++#define copy_long_to_char copy_int_to_char
++#define copy_long_to_uchar copy_int_to_uchar
++#define copy_long_to_short copy_int_to_short
++#define copy_long_to_ushort copy_int_to_ushort
++#define copy_long_to_int copy_int_to_int
++#define copy_long_to_uint copy_int_to_int
++#define copy_long_to_long copy_int_to_int
++#define copy_long_to_float copy_int_to_float
++#define copy_long_to_double copy_int_to_double
++#define copy_ulong_to_char copy_uint_to_char
++#define copy_ulong_to_uchar copy_uint_to_uchar
++#define copy_ulong_to_short copy_uint_to_short
++#define copy_ulong_to_ushort copy_uint_to_ushort
++#define copy_ulong_to_int copy_int_to_int
++#define copy_ulong_to_uint copy_int_to_int
++#define copy_ulong_to_float copy_uint_to_float
++#define copy_ulong_to_double copy_uint_to_double
++#endif
++
++DEFUN_1(copy_float_to_char,float,char)
++DEFUN_1(copy_float_to_uchar,float,unsigned char)
++#if SIZEOF_INT != SIZEOF_SHORT
++DEFUN_1(copy_float_to_short,float,short)
++DEFUN_1(copy_float_to_ushort,float,unsigned short)
++#else
++# define copy_float_to_short copy_float_to_int
++# define copy_float_to_ushort copy_float_to_uint
++#endif
++DEFUN_1(copy_float_to_int,float,int)
++DEFUN_1(copy_float_to_uint,float,unsigned int)
++#if SIZEOF_INT != SIZEOF_LONG
++DEFUN_1(copy_float_to_long,float,long)
++DEFUN_1(copy_float_to_ulong,float,unsigned long)
++#else
++# define copy_float_to_long copy_float_to_int
++# define copy_float_to_ulong copy_float_to_uint
++#endif
++DEFUN_1(copy_float_to_float,float,float)
++DEFUN_1(copy_float_to_double,float,double)
++
++DEFUN_1(copy_double_to_char,double,char)
++DEFUN_1(copy_double_to_uchar,double,unsigned char)
++#if SIZEOF_INT != SIZEOF_SHORT
++DEFUN_1(copy_double_to_short,double,short)
++DEFUN_1(copy_double_to_ushort,double,unsigned short)
++#else
++# define copy_double_to_short copy_double_to_int
++# define copy_double_to_ushort copy_double_to_uint
++#endif
++DEFUN_1(copy_double_to_int,double,int)
++DEFUN_1(copy_double_to_uint,double,unsigned int)
++#if SIZEOF_INT != SIZEOF_LONG
++DEFUN_1(copy_double_to_long,double,long)
++DEFUN_1(copy_double_to_ulong,double,unsigned long)
++#else
++# define copy_double_to_long copy_double_to_int
++# define copy_double_to_ulong copy_double_to_uint
++#endif
++DEFUN_1(copy_double_to_float,double,float)
++DEFUN_1(copy_double_to_double,double,double)
++
++DEFUN_2(char_to_int,char,int,copy_char_to_int)
++DEFUN_2(char_to_uint,char,unsigned int,copy_char_to_uint)
++#if SIZEOF_INT != SIZEOF_LONG
++DEFUN_2(char_to_long,char,long,copy_char_to_long)
++DEFUN_2(char_to_ulong,char,unsigned long,copy_char_to_ulong)
++#else
++# define char_to_long char_to_int
++# define char_to_ulong char_to_uint
++#endif
++DEFUN_2(char_to_float,char,float,copy_char_to_float)
++DEFUN_2(char_to_double,char,double,copy_char_to_double)
++
++DEFUN_2(uchar_to_int,unsigned char,int,copy_uchar_to_int)
++DEFUN_2(uchar_to_uint,unsigned char,unsigned int,copy_uchar_to_uint)
++#if SIZEOF_INT != SIZEOF_LONG
++DEFUN_2(uchar_to_long,unsigned char,long,copy_uchar_to_long)
++DEFUN_2(uchar_to_ulong,unsigned char,unsigned long,copy_uchar_to_ulong)
++#else
++# define uchar_to_long uchar_to_int
++# define uchar_to_ulong uchar_to_uint
++#endif
++DEFUN_2(uchar_to_float,unsigned char,float,copy_uchar_to_float)
++DEFUN_2(uchar_to_double,unsigned char,double,copy_uchar_to_double)
++
++#if SIZEOF_INT != SIZEOF_SHORT
++DEFUN_2(short_to_int,short,int,copy_short_to_int)
++DEFUN_2(short_to_uint,short,unsigned int,copy_short_to_uint)
++DEFUN_2(short_to_long,short,long,copy_short_to_long)
++DEFUN_2(short_to_ulong,short,unsigned long,copy_short_to_ulong)
++DEFUN_2(short_to_float,short,float,copy_short_to_float)
++DEFUN_2(short_to_double,short,double,copy_short_to_double)
++DEFUN_2(ushort_to_int,unsigned short,int,copy_ushort_to_int)
++DEFUN_2(ushort_to_uint,unsigned short,unsigned int,copy_ushort_to_uint)
++DEFUN_2(ushort_to_long,unsigned short,long,copy_ushort_to_long)
++DEFUN_2(ushort_to_ulong,unsigned short,unsigned long,copy_ushort_to_ulong)
++DEFUN_2(ushort_to_float,unsigned short,float,copy_ushort_to_float)
++DEFUN_2(ushort_to_double,unsigned short,double,copy_ushort_to_double)
++#else
++# define short_to_int NULL
++# define short_to_uint NULL
++# define short_to_long int_to_long
++# define short_to_ulong int_to_ulong
++# define short_to_float int_to_float
++# define short_to_double int_to_double
++# define ushort_to_int NULL
++# define ushort_to_uint NULL
++# define ushort_to_long uint_to_long
++# define ushort_to_ulong uint_to_ulong
++# define ushort_to_float uint_to_float
++# define ushort_to_double uint_to_double
++#endif
++
++#if SIZEOF_INT != SIZEOF_LONG
++DEFUN_2(int_to_long,int,long,copy_int_to_long)
++DEFUN_2(int_to_ulong,int,unsigned long,copy_int_to_ulong)
++#else
++# define int_to_long NULL
++# define int_to_ulong NULL
++#endif
++DEFUN_2(int_to_float,int,float,copy_int_to_float)
++DEFUN_2(int_to_double,int,double,copy_int_to_double)
++
++#if SIZEOF_INT != SIZEOF_LONG
++DEFUN_2(uint_to_long,unsigned int,long,copy_uint_to_long)
++DEFUN_2(uint_to_ulong,unsigned int,unsigned long,copy_uint_to_ulong)
++#else
++# define uint_to_long NULL
++# define uint_to_ulong NULL
++#endif
++DEFUN_2(uint_to_float,unsigned int,float,copy_uint_to_float)
++DEFUN_2(uint_to_double,unsigned int,double,copy_uint_to_double)
++
++#if SIZEOF_INT != SIZEOF_LONG
++DEFUN_2(long_to_float,long,float,copy_long_to_float)
++DEFUN_2(long_to_double,long,double,copy_long_to_double)
++DEFUN_2(ulong_to_float,unsigned long,float,copy_ulong_to_float)
++DEFUN_2(ulong_to_double,unsigned long,double,copy_ulong_to_double)
++#else
++# define long_to_float int_to_float
++# define long_to_double int_to_double
++# define ulong_to_float uint_to_float
++# define ulong_to_double uint_to_double
++#endif
++
++DEFUN_2(float_to_double,float,double,copy_float_to_double)
++
++#define TO_DOUBLE_FUN(name,type) \
++static double name (VOID_STAR x) { return (double) *(type *) x; }
++TO_DOUBLE_FUN(char_to_one_double,char)
++TO_DOUBLE_FUN(uchar_to_one_double,unsigned char)
++#if SIZEOF_INT != SIZEOF_SHORT
++TO_DOUBLE_FUN(short_to_one_double,short)
++TO_DOUBLE_FUN(ushort_to_one_double,unsigned short)
++#else
++# define short_to_one_double int_to_one_double
++# define ushort_to_one_double uint_to_one_double
++#endif
++TO_DOUBLE_FUN(int_to_one_double,int)
++TO_DOUBLE_FUN(uint_to_one_double,unsigned int)
++#if SIZEOF_INT != SIZEOF_LONG
++TO_DOUBLE_FUN(long_to_one_double,long)
++TO_DOUBLE_FUN(ulong_to_one_double,unsigned long)
++#else
++# define long_to_one_double int_to_one_double
++# define ulong_to_one_double uint_to_one_double
++#endif
++TO_DOUBLE_FUN(float_to_one_double,float)
++TO_DOUBLE_FUN(double_to_one_double,double)
++
++SLang_To_Double_Fun_Type
++SLarith_get_to_double_fun (unsigned char type, unsigned int *sizeof_type)
++{
++ unsigned int da;
++ SLang_To_Double_Fun_Type to_double;
++
++ switch (type)
++ {
++ default:
++ return NULL;
++
++ case SLANG_CHAR_TYPE:
++ da = sizeof (char); to_double = char_to_one_double;
++ break;
++ case SLANG_UCHAR_TYPE:
++ da = sizeof (unsigned char); to_double = uchar_to_one_double;
++ break;
++ case SLANG_SHORT_TYPE:
++ da = sizeof (short); to_double = short_to_one_double;
++ break;
++ case SLANG_USHORT_TYPE:
++ da = sizeof (unsigned short); to_double = ushort_to_one_double;
++ break;
++ case SLANG_INT_TYPE:
++ da = sizeof (int); to_double = int_to_one_double;
++ break;
++ case SLANG_UINT_TYPE:
++ da = sizeof (unsigned int); to_double = uint_to_one_double;
++ break;
++ case SLANG_LONG_TYPE:
++ da = sizeof (long); to_double = long_to_one_double;
++ break;
++ case SLANG_ULONG_TYPE:
++ da = sizeof (unsigned long); to_double = ulong_to_one_double;
++ break;
++ case SLANG_FLOAT_TYPE:
++ da = sizeof (float); to_double = float_to_one_double;
++ break;
++ case SLANG_DOUBLE_TYPE:
++ da = sizeof (double); to_double = double_to_one_double;
++ break;
++ }
++
++ if (sizeof_type != NULL) *sizeof_type = da;
++ return to_double;
++}
++
++/* Each element of the matrix determines how the row maps onto the column.
++ * That is, let the matrix be B_ij. Where the i,j indices refer to
++ * precedence of the type. Then,
++ * B_ij-&gt;copy_function copies type i to type j. Similarly,
++ * B_ij-&gt;convert_function mallocs a new array of type j and copies i to it.
++ *
++ * Since types are always converted to higher levels of precedence for binary
++ * operations, many of the elements are NULL.
++ *
++ * Is the idea clear?
++ */
++typedef struct
++{
++ FVOID_STAR copy_function;
++ Convert_Fun_Type convert_function;
++}
++Binary_Matrix_Type;
++
++static Binary_Matrix_Type Binary_Matrix [MAX_ARITHMETIC_TYPES][MAX_ARITHMETIC_TYPES] =
++{
++ {
++ {(FVOID_STAR)copy_char_to_char, NULL},
++ {(FVOID_STAR)copy_char_to_char, NULL},
++ {(FVOID_STAR) copy_char_to_short, NULL},
++ {(FVOID_STAR) copy_char_to_ushort, NULL},
++ {(FVOID_STAR) copy_char_to_int, char_to_int},
++ {(FVOID_STAR) copy_char_to_uint, char_to_uint},
++ {(FVOID_STAR) copy_char_to_long, char_to_long},
++ {(FVOID_STAR) copy_char_to_ulong, char_to_ulong},
++ {(FVOID_STAR) copy_char_to_float, char_to_float},
++ {(FVOID_STAR) copy_char_to_double, char_to_double},
++ },
++
++ {
++ {(FVOID_STAR)copy_char_to_char, NULL},
++ {(FVOID_STAR)copy_char_to_char, NULL},
++ {(FVOID_STAR) copy_uchar_to_short, NULL},
++ {(FVOID_STAR) copy_uchar_to_ushort, NULL},
++ {(FVOID_STAR) copy_uchar_to_int, uchar_to_int},
++ {(FVOID_STAR) copy_uchar_to_uint, uchar_to_uint},
++ {(FVOID_STAR) copy_uchar_to_long, uchar_to_long},
++ {(FVOID_STAR) copy_uchar_to_ulong, uchar_to_ulong},
++ {(FVOID_STAR) copy_uchar_to_float, uchar_to_float},
++ {(FVOID_STAR) copy_uchar_to_double, uchar_to_double},
++ },
++
++ {
++ {(FVOID_STAR) copy_short_to_char, NULL},
++ {(FVOID_STAR) copy_short_to_uchar, NULL},
++ {(FVOID_STAR) copy_short_to_short, NULL},
++ {(FVOID_STAR) copy_short_to_short, NULL},
++ {(FVOID_STAR) copy_short_to_int, short_to_int},
++ {(FVOID_STAR) copy_short_to_uint, short_to_uint},
++ {(FVOID_STAR) copy_short_to_long, short_to_long},
++ {(FVOID_STAR) copy_short_to_ulong, short_to_ulong},
++ {(FVOID_STAR) copy_short_to_float, short_to_float},
++ {(FVOID_STAR) copy_short_to_double, short_to_double},
++ },
++
++ {
++ {(FVOID_STAR) copy_ushort_to_char, NULL},
++ {(FVOID_STAR) copy_ushort_to_uchar, NULL},
++ {(FVOID_STAR) copy_short_to_short, NULL},
++ {(FVOID_STAR) copy_short_to_short, NULL},
++ {(FVOID_STAR) copy_ushort_to_int, ushort_to_int},
++ {(FVOID_STAR) copy_ushort_to_uint, ushort_to_uint},
++ {(FVOID_STAR) copy_ushort_to_long, ushort_to_long},
++ {(FVOID_STAR) copy_ushort_to_ulong, ushort_to_ulong},
++ {(FVOID_STAR) copy_ushort_to_float, ushort_to_float},
++ {(FVOID_STAR) copy_ushort_to_double, ushort_to_double},
++ },
++
++ {
++ {(FVOID_STAR) copy_int_to_char, NULL},
++ {(FVOID_STAR) copy_int_to_uchar, NULL},
++ {(FVOID_STAR) copy_int_to_short, NULL},
++ {(FVOID_STAR) copy_int_to_ushort, NULL},
++ {(FVOID_STAR) copy_int_to_int, NULL},
++ {(FVOID_STAR) copy_int_to_int, NULL},
++ {(FVOID_STAR) copy_int_to_long, int_to_long},
++ {(FVOID_STAR) copy_int_to_ulong, int_to_ulong},
++ {(FVOID_STAR) copy_int_to_float, int_to_float},
++ {(FVOID_STAR) copy_int_to_double, int_to_double},
++ },
++
++ {
++ {(FVOID_STAR) copy_uint_to_char, NULL},
++ {(FVOID_STAR) copy_uint_to_uchar, NULL},
++ {(FVOID_STAR) copy_uint_to_short, NULL},
++ {(FVOID_STAR) copy_uint_to_ushort, NULL},
++ {(FVOID_STAR) copy_int_to_int, NULL},
++ {(FVOID_STAR) copy_int_to_int, NULL},
++ {(FVOID_STAR) copy_uint_to_long, uint_to_long},
++ {(FVOID_STAR) copy_uint_to_ulong, uint_to_ulong},
++ {(FVOID_STAR) copy_uint_to_float, uint_to_float},
++ {(FVOID_STAR) copy_uint_to_double, uint_to_double},
++ },
++
++ {
++ {(FVOID_STAR) copy_long_to_char, NULL},
++ {(FVOID_STAR) copy_long_to_uchar, NULL},
++ {(FVOID_STAR) copy_long_to_short, NULL},
++ {(FVOID_STAR) copy_long_to_ushort, NULL},
++ {(FVOID_STAR) copy_long_to_int, NULL},
++ {(FVOID_STAR) copy_long_to_uint, NULL},
++ {(FVOID_STAR) copy_long_to_long, NULL},
++ {(FVOID_STAR) copy_long_to_long, NULL},
++ {(FVOID_STAR) copy_long_to_float, long_to_float},
++ {(FVOID_STAR) copy_long_to_double, long_to_double},
++ },
++
++ {
++ {(FVOID_STAR) copy_ulong_to_char, NULL},
++ {(FVOID_STAR) copy_ulong_to_uchar, NULL},
++ {(FVOID_STAR) copy_ulong_to_short, NULL},
++ {(FVOID_STAR) copy_ulong_to_ushort, NULL},
++ {(FVOID_STAR) copy_ulong_to_int, NULL},
++ {(FVOID_STAR) copy_ulong_to_uint, NULL},
++ {(FVOID_STAR) copy_long_to_long, NULL},
++ {(FVOID_STAR) copy_long_to_long, NULL},
++ {(FVOID_STAR) copy_ulong_to_float, ulong_to_float},
++ {(FVOID_STAR) copy_ulong_to_double, ulong_to_double},
++ },
++
++ {
++ {(FVOID_STAR) copy_float_to_char, NULL},
++ {(FVOID_STAR) copy_float_to_uchar, NULL},
++ {(FVOID_STAR) copy_float_to_short, NULL},
++ {(FVOID_STAR) copy_float_to_ushort, NULL},
++ {(FVOID_STAR) copy_float_to_int, NULL},
++ {(FVOID_STAR) copy_float_to_uint, NULL},
++ {(FVOID_STAR) copy_float_to_long, NULL},
++ {(FVOID_STAR) copy_float_to_ulong, NULL},
++ {(FVOID_STAR) copy_float_to_float, NULL},
++ {(FVOID_STAR) copy_float_to_double, float_to_double},
++ },
++
++ {
++ {(FVOID_STAR) copy_double_to_char, NULL},
++ {(FVOID_STAR) copy_double_to_uchar, NULL},
++ {(FVOID_STAR) copy_double_to_short, NULL},
++ {(FVOID_STAR) copy_double_to_ushort, NULL},
++ {(FVOID_STAR) copy_double_to_int, NULL},
++ {(FVOID_STAR) copy_double_to_uint, NULL},
++ {(FVOID_STAR) copy_double_to_long, NULL},
++ {(FVOID_STAR) copy_double_to_ulong, NULL},
++ {(FVOID_STAR) copy_double_to_float, NULL},
++ {(FVOID_STAR) copy_double_to_double, NULL},
++ }
++};
++
++#define GENERIC_BINARY_FUNCTION int_int_bin_op
++#define GENERIC_BIT_OPERATIONS
++#define GENERIC_TYPE int
++#define POW_FUNCTION(a,b) pow((double)(a),(double)(b))
++#define POW_RESULT_TYPE double
++#define ABS_FUNCTION abs
++#define MOD_FUNCTION(a,b) ((a) % (b))
++#define GENERIC_UNARY_FUNCTION int_unary_op
++#define SIGN_FUNCTION(x) (((x) &gt; 0) ? 1 : (((x) &lt; 0) ? -1 : 0))
++#define SCALAR_BINARY_FUNCTION int_int_scalar_bin_op
++#define PUSH_SCALAR_OBJ_FUN(x) SLclass_push_int_obj(SLANG_INT_TYPE,(x))
++#define PUSH_POW_OBJ_FUN(x) SLclass_push_double_obj(SLANG_DOUBLE_TYPE, (x))
++#define CMP_FUNCTION int_cmp_function
++#include &quot;slarith.inc&quot;
++
++#define GENERIC_BINARY_FUNCTION uint_uint_bin_op
++#define GENERIC_BIT_OPERATIONS
++#define GENERIC_TYPE unsigned int
++#define POW_FUNCTION(a,b) pow((double)(a),(double)(b))
++#define POW_RESULT_TYPE double
++#define MOD_FUNCTION(a,b) ((a) % (b))
++#define GENERIC_UNARY_FUNCTION uint_unary_op
++#define ABS_FUNCTION(a) (a)
++#define SIGN_FUNCTION(x) (((x) &gt; 0) ? 1 : 0)
++#define SCALAR_BINARY_FUNCTION uint_uint_scalar_bin_op
++#define PUSH_SCALAR_OBJ_FUN(x) SLclass_push_int_obj(SLANG_UINT_TYPE,(int)(x))
++#define PUSH_POW_OBJ_FUN(x) SLclass_push_double_obj(SLANG_DOUBLE_TYPE, (x))
++#define CMP_FUNCTION uint_cmp_function
++#include &quot;slarith.inc&quot;
++
++#if SIZEOF_LONG != SIZEOF_INT
++#define GENERIC_BINARY_FUNCTION long_long_bin_op
++#define GENERIC_BIT_OPERATIONS
++#define GENERIC_TYPE long
++#define POW_FUNCTION(a,b) pow((double)(a),(double)(b))
++#define POW_RESULT_TYPE double
++#define MOD_FUNCTION(a,b) ((a) % (b))
++#define GENERIC_UNARY_FUNCTION long_unary_op
++#define ABS_FUNCTION(a) (((a) &gt;= 0) ? (a) : -(a))
++#define SIGN_FUNCTION(x) (((x) &gt; 0) ? 1 : (((x) &lt; 0) ? -1 : 0))
++#define SCALAR_BINARY_FUNCTION long_long_scalar_bin_op
++#define PUSH_SCALAR_OBJ_FUN(x) SLclass_push_long_obj(SLANG_LONG_TYPE,(x))
++#define PUSH_POW_OBJ_FUN(x) SLclass_push_double_obj(SLANG_DOUBLE_TYPE, (x))
++#define CMP_FUNCTION long_cmp_function
++#include &quot;slarith.inc&quot;
++
++#define GENERIC_BINARY_FUNCTION ulong_ulong_bin_op
++#define GENERIC_BIT_OPERATIONS
++#define GENERIC_TYPE unsigned long
++#define POW_FUNCTION(a,b) pow((double)(a),(double)(b))
++#define POW_RESULT_TYPE double
++#define MOD_FUNCTION(a,b) ((a) % (b))
++#define GENERIC_UNARY_FUNCTION ulong_unary_op
++#define ABS_FUNCTION(a) (a)
++#define SIGN_FUNCTION(x) (((x) &gt; 0) ? 1 : 0)
++#define SCALAR_BINARY_FUNCTION ulong_ulong_scalar_bin_op
++#define PUSH_SCALAR_OBJ_FUN(x) SLclass_push_long_obj(SLANG_ULONG_TYPE,(long)(x))
++#define PUSH_POW_OBJ_FUN(x) SLclass_push_double_obj(SLANG_DOUBLE_TYPE, (x))
++#define CMP_FUNCTION ulong_cmp_function
++#include &quot;slarith.inc&quot;
++#else
++#define long_long_bin_op int_int_bin_op
++#define ulong_ulong_bin_op uint_uint_bin_op
++#define long_unary_op int_unary_op
++#define ulong_unary_op uint_unary_op
++#define long_cmp_function int_cmp_function
++#define ulong_cmp_function uint_cmp_function
++#endif /* SIZEOF_INT != SIZEOF_LONG */
++
++#define GENERIC_BINARY_FUNCTION float_float_bin_op
++#define GENERIC_TYPE float
++#define POW_FUNCTION(a,b) (float)pow((double)(a),(double)(b))
++#define POW_RESULT_TYPE float
++#define MOD_FUNCTION(a,b) (float)fmod((a),(b))
++#define GENERIC_UNARY_FUNCTION float_unary_op
++#define ABS_FUNCTION(a) (float)fabs((double) a)
++#define SIGN_FUNCTION(x) (((x) &gt; 0) ? 1 : (((x) &lt; 0) ? -1 : 0))
++#define SCALAR_BINARY_FUNCTION float_float_scalar_bin_op
++#define PUSH_SCALAR_OBJ_FUN(x) SLclass_push_float_obj(SLANG_FLOAT_TYPE,(x))
++#define PUSH_POW_OBJ_FUN(x) SLclass_push_float_obj(SLANG_FLOAT_TYPE, (x))
++#define CMP_FUNCTION float_cmp_function
++#include &quot;slarith.inc&quot;
++
++#define GENERIC_BINARY_FUNCTION double_double_bin_op
++#define GENERIC_TYPE double
++#define POW_FUNCTION(a,b) pow((double)(a),(double)(b))
++#define POW_RESULT_TYPE double
++#define MOD_FUNCTION(a,b) (float)fmod((a),(b))
++#define GENERIC_UNARY_FUNCTION double_unary_op
++#define ABS_FUNCTION(a) fabs(a)
++#define SIGN_FUNCTION(x) (((x) &gt; 0) ? 1 : (((x) &lt; 0) ? -1 : 0))
++#define SCALAR_BINARY_FUNCTION double_double_scalar_bin_op
++#define PUSH_SCALAR_OBJ_FUN(x) SLclass_push_double_obj(SLANG_DOUBLE_TYPE,(x))
++#define PUSH_POW_OBJ_FUN(x) SLclass_push_double_obj(SLANG_DOUBLE_TYPE, (x))
++#define CMP_FUNCTION double_cmp_function
++#include &quot;slarith.inc&quot;
++
++#define GENERIC_UNARY_FUNCTION char_unary_op
++#define GENERIC_BIT_OPERATIONS
++#define GENERIC_TYPE signed char
++#define ABS_FUNCTION abs
++#define SIGN_FUNCTION(x) (((x) &gt; 0) ? 1 : (((x) &lt; 0) ? -1 : 0))
++#define CMP_FUNCTION char_cmp_function
++#include &quot;slarith.inc&quot;
++
++#define GENERIC_UNARY_FUNCTION uchar_unary_op
++#define GENERIC_BIT_OPERATIONS
++#define GENERIC_TYPE unsigned char
++#define ABS_FUNCTION(x) (x)
++#define SIGN_FUNCTION(x) (((x) &gt; 0) ? 1 : 0)
++#define CMP_FUNCTION uchar_cmp_function
++#include &quot;slarith.inc&quot;
++
++#if SIZEOF_SHORT != SIZEOF_INT
++#define GENERIC_UNARY_FUNCTION short_unary_op
++#define GENERIC_BIT_OPERATIONS
++#define GENERIC_TYPE short
++#define ABS_FUNCTION abs
++#define SIGN_FUNCTION(x) (((x) &gt; 0) ? 1 : (((x) &lt; 0) ? -1 : 0))
++#define CMP_FUNCTION short_cmp_function
++#include &quot;slarith.inc&quot;
++
++#define GENERIC_UNARY_FUNCTION ushort_unary_op
++#define GENERIC_BIT_OPERATIONS
++#define GENERIC_TYPE unsigned short
++#define ABS_FUNCTION(x) (x)
++#define SIGN_FUNCTION(x) (((x) &gt; 0) ? 1 : 0)
++#define CMP_FUNCTION ushort_cmp_function
++#include &quot;slarith.inc&quot;
++#endif /* SIZEOF_INT != SIZEOF_SHORT */
++
++/* Unfortunately, the numbers that were assigned to the data-types were
++ * not well thought out. So, I need to use the following table.
++ */
++#define MAXIMUM_ARITH_TYPE_VALUE SLANG_FLOAT_TYPE
++#define IS_INTEGER_TYPE(x) \
++ (((x) &lt;= MAXIMUM_ARITH_TYPE_VALUE) \
++ &amp;&amp; (Type_Precedence_Table[x] &lt; 8) &amp;&amp; (Type_Precedence_Table[x] != -1))
++#define IS_ARITHMETIC_TYPE(x) \
++ (((x) &lt;= MAXIMUM_ARITH_TYPE_VALUE) &amp;&amp; (Type_Precedence_Table[x] != -1))
++
++#define LONG_PRECEDENCE_VALUE 6
++#define FLOAT_PRECEDENCE_VALUE 8
++
++static signed char Type_Precedence_Table [MAXIMUM_ARITH_TYPE_VALUE + 1] =
++{
++ -1, /* SLANG_UNDEFINED_TYPE */
++ -1, /* SLANG_VOID_TYPE */
++ 4, /* SLANG_INT_TYPE */
++ 9, /* SLANG_DOUBLE_TYPE */
++ 0, /* SLANG_CHAR_TYPE */
++ -1, /* SLANG_INTP_TYPE */
++ -1, /* SLANG_REF_TYPE */
++ -1, /* SLANG_COMPLEX_TYPE */
++ -1, /* SLANG_NULL_TYPE */
++ 1, /* SLANG_UCHAR_TYPE */
++ 2, /* SLANG_SHORT_TYPE */
++ 3, /* SLANG_USHORT_TYPE */
++ 5, /* SLANG_UINT_TYPE */
++ 6, /* SLANG_LONG_TYPE */
++ 7, /* SLANG_ULONG_TYPE */
++ -1, /* SLANG_STRING_TYPE */
++ 8 /* SLANG_FLOAT_TYPE */
++};
++
++int _SLarith_get_precedence (unsigned char type)
++{
++ if (type &gt; MAXIMUM_ARITH_TYPE_VALUE)
++ return -1;
++
++ return Type_Precedence_Table[type];
++}
++
++unsigned char _SLarith_promote_type (unsigned char t)
++{
++ switch (t)
++ {
++ case SLANG_FLOAT_TYPE:
++ case SLANG_DOUBLE_TYPE:
++ case SLANG_LONG_TYPE:
++ case SLANG_ULONG_TYPE:
++ case SLANG_INT_TYPE:
++ case SLANG_UINT_TYPE:
++ break;
++
++ case SLANG_USHORT_TYPE:
++#if SIZEOF_INT == SIZEOF_SHORT
++ t = SLANG_UINT_TYPE;
++ break;
++#endif
++ /* drop */
++ case SLANG_CHAR_TYPE:
++ case SLANG_UCHAR_TYPE:
++ case SLANG_SHORT_TYPE:
++ default:
++ t = SLANG_INT_TYPE;
++ }
++
++ return t;
++}
++
++static unsigned char promote_to_common_type (unsigned char a, unsigned char b)
++{
++ a = _SLarith_promote_type (a);
++ b = _SLarith_promote_type (b);
++
++ return (Type_Precedence_Table[a] &gt; Type_Precedence_Table[b]) ? a : b;
++}
++
++static int arith_bin_op_result (int op, unsigned char a_type, unsigned char b_type,
++ unsigned char *c_type)
++{
++ switch (op)
++ {
++ case SLANG_EQ:
++ case SLANG_NE:
++ case SLANG_GT:
++ case SLANG_GE:
++ case SLANG_LT:
++ case SLANG_LE:
++ case SLANG_OR:
++ case SLANG_AND:
++ *c_type = SLANG_CHAR_TYPE;
++ return 1;
++
++ case SLANG_POW:
++ if (SLANG_FLOAT_TYPE == promote_to_common_type (a_type, b_type))
++ *c_type = SLANG_FLOAT_TYPE;
++ else
++ *c_type = SLANG_DOUBLE_TYPE;
++ return 1;
++
++ case SLANG_BAND:
++ case SLANG_BXOR:
++ case SLANG_BOR:
++ case SLANG_SHL:
++ case SLANG_SHR:
++ /* The bit-level operations are defined just for integer types */
++ if ((0 == IS_INTEGER_TYPE (a_type))
++ || (0 == IS_INTEGER_TYPE(b_type)))
++ return 0;
++ break;
++
++ default:
++ break;
++ }
++
++ *c_type = promote_to_common_type (a_type, b_type);
++ return 1;
++}
++
++typedef int (*Bin_Fun_Type) (int,
++ unsigned char, VOID_STAR, unsigned int,
++ unsigned char, VOID_STAR, unsigned int,
++ VOID_STAR);
++
++/* This array of functions must be indexed by precedence after arithmetic
++ * promotions.
++ */
++static Bin_Fun_Type Bin_Fun_Map [MAX_ARITHMETIC_TYPES] =
++{
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ int_int_bin_op,
++ uint_uint_bin_op,
++ long_long_bin_op,
++ ulong_ulong_bin_op,
++ float_float_bin_op,
++ double_double_bin_op
++};
++
++static int arith_bin_op (int op,
++ unsigned char a_type, VOID_STAR ap, unsigned int na,
++ unsigned char b_type, VOID_STAR bp, unsigned int nb,
++ VOID_STAR cp)
++{
++ Convert_Fun_Type af, bf;
++ Bin_Fun_Type binfun;
++ int a_indx, b_indx, c_indx;
++ unsigned char c_type;
++ int ret;
++
++ c_type = promote_to_common_type (a_type, b_type);
++
++ a_indx = Type_Precedence_Table [a_type];
++ b_indx = Type_Precedence_Table [b_type];
++ c_indx = Type_Precedence_Table [c_type];
++
++ af = Binary_Matrix[a_indx][c_indx].convert_function;
++ bf = Binary_Matrix[b_indx][c_indx].convert_function;
++ binfun = Bin_Fun_Map[c_indx];
++
++ if ((af != NULL)
++ &amp;&amp; (NULL == (ap = (VOID_STAR) (*af) (ap, na))))
++ return -1;
++
++ if ((bf != NULL)
++ &amp;&amp; (NULL == (bp = (VOID_STAR) (*bf) (bp, nb))))
++ {
++ if (af != NULL) SLfree ((char *) ap);
++ return -1;
++ }
++
++ ret = (*binfun) (op, a_type, ap, na, b_type, bp, nb, cp);
++ if (af != NULL) SLfree ((char *) ap);
++ if (bf != NULL) SLfree ((char *) bp);
++
++ return ret;
++}
++
++static int arith_unary_op_result (int op, unsigned char a, unsigned char *b)
++{
++ (void) a;
++ switch (op)
++ {
++ default:
++ return 0;
++
++ case SLANG_SQR:
++ case SLANG_MUL2:
++ case SLANG_PLUSPLUS:
++ case SLANG_MINUSMINUS:
++ case SLANG_CHS:
++ case SLANG_ABS:
++ *b = a;
++ break;
++
++ case SLANG_NOT:
++ case SLANG_BNOT:
++ if (0 == IS_INTEGER_TYPE(a))
++ return 0;
++ *b = a;
++ break;
++
++ case SLANG_SIGN:
++ *b = SLANG_INT_TYPE;
++ break;
++ }
++ return 1;
++}
++
++static int integer_pop (unsigned char type, VOID_STAR ptr)
++{
++ SLang_Object_Type obj;
++ int i, j;
++ void (*f)(VOID_STAR, VOID_STAR, unsigned int);
++
++ if (-1 == SLang_pop (&amp;obj))
++ return -1;
++
++ if ((obj.data_type &gt; MAXIMUM_ARITH_TYPE_VALUE)
++ || ((j = Type_Precedence_Table[obj.data_type]) == -1)
++ || (j &gt;= FLOAT_PRECEDENCE_VALUE))
++ {
++ _SLclass_type_mismatch_error (type, obj.data_type);
++ SLang_free_object (&amp;obj);
++ return -1;
++ }
++
++ i = Type_Precedence_Table[type];
++ f = (void (*)(VOID_STAR, VOID_STAR, unsigned int))
++ Binary_Matrix[j][i].copy_function;
++
++ (*f) (ptr, (VOID_STAR)&amp;obj.v, 1);
++
++ return 0;
++}
++
++static int integer_push (unsigned char type, VOID_STAR ptr)
++{
++ SLang_Object_Type obj;
++ int i;
++ void (*f)(VOID_STAR, VOID_STAR, unsigned int);
++
++ i = Type_Precedence_Table[type];
++ f = (void (*)(VOID_STAR, VOID_STAR, unsigned int))
++ Binary_Matrix[i][i].copy_function;
++
++ obj.data_type = type;
++
++ (*f) ((VOID_STAR)&amp;obj.v, ptr, 1);
++
++ return SLang_push (&amp;obj);
++}
++
++int SLang_pop_char (char *i)
++{
++ return integer_pop (SLANG_CHAR_TYPE, (VOID_STAR) i);
++}
++
++int SLang_pop_uchar (unsigned char *i)
++{
++ return integer_pop (SLANG_UCHAR_TYPE, (VOID_STAR) i);
++}
++
++int SLang_pop_short (short *i)
++{
++ return integer_pop (SLANG_SHORT_TYPE, (VOID_STAR) i);
++}
++
++int SLang_pop_ushort (unsigned short *i)
++{
++ return integer_pop (SLANG_USHORT_TYPE, (VOID_STAR) i);
++}
++
++int SLang_pop_long (long *i)
++{
++ return integer_pop (SLANG_LONG_TYPE, (VOID_STAR) i);
++}
++
++int SLang_pop_ulong (unsigned long *i)
++{
++ return integer_pop (SLANG_ULONG_TYPE, (VOID_STAR) i);
++}
++
++int SLang_pop_integer (int *i)
++{
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ SLang_Object_Type obj;
++
++ if (-1 == _SLang_pop_object_of_type (SLANG_INT_TYPE, &amp;obj, 0))
++ return -1;
++ *i = obj.v.int_val;
++ return 0;
++#else
++ return integer_pop (SLANG_INT_TYPE, (VOID_STAR) i);
++#endif
++}
++
++int SLang_pop_uinteger (unsigned int *i)
++{
++ return integer_pop (SLANG_UINT_TYPE, (VOID_STAR) i);
++}
++
++int SLang_push_integer (int i)
++{
++ return SLclass_push_int_obj (SLANG_INT_TYPE, i);
++}
++int SLang_push_uinteger (unsigned int i)
++{
++ return SLclass_push_int_obj (SLANG_UINT_TYPE, (int) i);
++}
++int SLang_push_char (char i)
++{
++ return SLclass_push_char_obj (SLANG_CHAR_TYPE, i);
++}
++int SLang_push_uchar (unsigned char i)
++{
++ return SLclass_push_char_obj (SLANG_UCHAR_TYPE, (char) i);
++}
++int SLang_push_short (short i)
++{
++ return SLclass_push_short_obj (SLANG_SHORT_TYPE, i);
++}
++int SLang_push_ushort (unsigned short i)
++{
++ return SLclass_push_short_obj (SLANG_USHORT_TYPE, (unsigned short) i);
++}
++int SLang_push_long (long i)
++{
++ return SLclass_push_long_obj (SLANG_LONG_TYPE, i);
++}
++int SLang_push_ulong (unsigned long i)
++{
++ return SLclass_push_long_obj (SLANG_ULONG_TYPE, (long) i);
++}
++
++_INLINE_
++int _SLarith_typecast (unsigned char a_type, VOID_STAR ap, unsigned int na,
++ unsigned char b_type, VOID_STAR bp)
++{
++ int i, j;
++
++ void (*copy)(VOID_STAR, VOID_STAR, unsigned int);
++
++ i = Type_Precedence_Table[a_type];
++ j = Type_Precedence_Table[b_type];
++
++ copy = (void (*)(VOID_STAR, VOID_STAR, unsigned int))
++ Binary_Matrix[i][j].copy_function;
++
++ (*copy) (bp, ap, na);
++ return 1;
++}
++
++#if SLANG_HAS_FLOAT
++
++int SLang_pop_double(double *x, int *convertp, int *ip)
++{
++ SLang_Object_Type obj;
++ int i, convert;
++
++ if (0 != SLang_pop (&amp;obj))
++ return -1;
++
++ i = 0;
++ convert = 0;
++
++ switch (obj.data_type)
++ {
++ case SLANG_FLOAT_TYPE:
++ *x = (double) obj.v.float_val;
++ break;
++
++ case SLANG_DOUBLE_TYPE:
++ *x = obj.v.double_val;
++ break;
++
++ case SLANG_INT_TYPE:
++ i = (int) obj.v.long_val;
++ *x = (double) i;
++ convert = 1;
++ break;
++
++ case SLANG_CHAR_TYPE: *x = (double) obj.v.char_val; break;
++ case SLANG_UCHAR_TYPE: *x = (double) obj.v.uchar_val; break;
++ case SLANG_SHORT_TYPE: *x = (double) obj.v.short_val; break;
++ case SLANG_USHORT_TYPE: *x = (double) obj.v.ushort_val; break;
++ case SLANG_UINT_TYPE: *x = (double) obj.v.uint_val; break;
++ case SLANG_LONG_TYPE: *x = (double) obj.v.long_val; break;
++ case SLANG_ULONG_TYPE: *x = (double) obj.v.ulong_val; break;
++
++ default:
++ _SLclass_type_mismatch_error (SLANG_DOUBLE_TYPE, obj.data_type);
++ SLang_free_object (&amp;obj);
++ return -1;
++ }
++
++ if (convertp != NULL) *convertp = convert;
++ if (ip != NULL) *ip = i;
++
++ return 0;
++}
++
++int SLang_push_double (double x)
++{
++ return SLclass_push_double_obj (SLANG_DOUBLE_TYPE, x);
++}
++
++int SLang_pop_float (float *x)
++{
++ double d;
++
++ /* Pop it as a double and let the double function do all the typcasting */
++ if (-1 == SLang_pop_double (&amp;d, NULL, NULL))
++ return -1;
++
++ *x = (float) d;
++ return 0;
++}
++
++int SLang_push_float (float f)
++{
++ return SLclass_push_float_obj (SLANG_FLOAT_TYPE, (double) f);
++}
++
++/* Double */
++static int double_push (unsigned char unused, VOID_STAR ptr)
++{
++ (void) unused;
++ SLang_push_double (*(double *) ptr);
++ return 0;
++}
++
++static int double_push_literal (unsigned char type, VOID_STAR ptr)
++{
++ (void) type;
++ return SLang_push_double (**(double **)ptr);
++}
++
++static int double_pop (unsigned char unused, VOID_STAR ptr)
++{
++ (void) unused;
++ return SLang_pop_double ((double *) ptr, NULL, NULL);
++}
++
++static void double_byte_code_destroy (unsigned char unused, VOID_STAR ptr)
++{
++ (void) unused;
++ SLfree (*(char **) ptr);
++}
++
++static int float_push (unsigned char unused, VOID_STAR ptr)
++{
++ (void) unused;
++ SLang_push_float (*(float *) ptr);
++ return 0;
++}
++
++static int float_pop (unsigned char unused, VOID_STAR ptr)
++{
++ (void) unused;
++ return SLang_pop_float ((float *) ptr);
++}
++
++#endif /* SLANG_HAS_FLOAT */
++
++#if SLANG_HAS_FLOAT
++static char Double_Format[16] = &quot;%g&quot;;
++
++void _SLset_double_format (char *s)
++{
++ strncpy (Double_Format, s, 15);
++ Double_Format[15] = 0;
++}
++#endif
++
++static char *arith_string (unsigned char type, VOID_STAR v)
++{
++ char buf [256];
++ char *s;
++
++ s = buf;
++
++ switch (type)
++ {
++ default:
++ s = SLclass_get_datatype_name (type);
++ break;
++
++ case SLANG_CHAR_TYPE:
++ sprintf (s, &quot;%d&quot;, *(char *) v);
++ break;
++ case SLANG_UCHAR_TYPE:
++ sprintf (s, &quot;%u&quot;, *(unsigned char *) v);
++ break;
++ case SLANG_SHORT_TYPE:
++ sprintf (s, &quot;%d&quot;, *(short *) v);
++ break;
++ case SLANG_USHORT_TYPE:
++ sprintf (s, &quot;%u&quot;, *(unsigned short *) v);
++ break;
++ case SLANG_INT_TYPE:
++ sprintf (s, &quot;%d&quot;, *(int *) v);
++ break;
++ case SLANG_UINT_TYPE:
++ sprintf (s, &quot;%u&quot;, *(unsigned int *) v);
++ break;
++ case SLANG_LONG_TYPE:
++ sprintf (s, &quot;%ld&quot;, *(long *) v);
++ break;
++ case SLANG_ULONG_TYPE:
++ sprintf (s, &quot;%lu&quot;, *(unsigned long *) v);
++ break;
++#if SLANG_HAS_FLOAT
++ case SLANG_FLOAT_TYPE:
++ if (EOF == _SLsnprintf (buf, sizeof (buf), Double_Format, *(float *) v))
++ sprintf (s, &quot;%e&quot;, *(float *) v);
++ break;
++ case SLANG_DOUBLE_TYPE:
++ if (EOF == _SLsnprintf (buf, sizeof (buf), Double_Format, *(double *) v))
++ sprintf (s, &quot;%e&quot;, *(double *) v);
++ break;
++#endif
++ }
++
++ return SLmake_string (s);
++}
++
++static int integer_to_bool (unsigned char type, int *t)
++{
++ (void) type;
++ return SLang_pop_integer (t);
++}
++
++static int push_int_literal (unsigned char type, VOID_STAR ptr)
++{
++ return SLclass_push_int_obj (type, (int) *(long *) ptr);
++}
++
++static int push_char_literal (unsigned char type, VOID_STAR ptr)
++{
++ return SLclass_push_char_obj (type, (char) *(long *) ptr);
++}
++
++#if SIZEOF_SHORT != SIZEOF_INT
++static int push_short_literal (unsigned char type, VOID_STAR ptr)
++{
++ return SLclass_push_short_obj (type, (short) *(long *) ptr);
++}
++#endif
++
++#if SIZEOF_INT != SIZEOF_LONG
++static int push_long_literal (unsigned char type, VOID_STAR ptr)
++{
++ return SLclass_push_long_obj (type, *(long *) ptr);
++}
++#endif
++
++typedef struct
++{
++ char *name;
++ unsigned char data_type;
++ unsigned int sizeof_type;
++ int (*unary_fun)(int, unsigned char, VOID_STAR, unsigned int, VOID_STAR);
++ int (*push_literal) (unsigned char, VOID_STAR);
++ int (*cmp_fun) (unsigned char, VOID_STAR, VOID_STAR, int *);
++}
++Integer_Info_Type;
++
++static Integer_Info_Type Integer_Types [8] =
++{
++ {&quot;Char_Type&quot;, SLANG_CHAR_TYPE, sizeof (char), char_unary_op, push_char_literal, char_cmp_function},
++ {&quot;UChar_Type&quot;, SLANG_UCHAR_TYPE, sizeof (unsigned char), uchar_unary_op, push_char_literal, uchar_cmp_function},
++#if SIZEOF_INT != SIZEOF_SHORT
++ {&quot;Short_Type&quot;, SLANG_SHORT_TYPE, sizeof (short), short_unary_op, push_short_literal, short_cmp_function},
++ {&quot;UShort_Type&quot;, SLANG_USHORT_TYPE, sizeof (unsigned short), ushort_unary_op, push_short_literal, ushort_cmp_function},
++#else
++ {NULL, SLANG_SHORT_TYPE},
++ {NULL, SLANG_USHORT_TYPE},
++#endif
++
++ {&quot;Integer_Type&quot;, SLANG_INT_TYPE, sizeof (int), int_unary_op, push_int_literal, int_cmp_function},
++ {&quot;UInteger_Type&quot;, SLANG_UINT_TYPE, sizeof (unsigned int), uint_unary_op, push_int_literal, uint_cmp_function},
++
++#if SIZEOF_INT != SIZEOF_LONG
++ {&quot;Long_Type&quot;, SLANG_LONG_TYPE, sizeof (long), long_unary_op, push_long_literal, long_cmp_function},
++ {&quot;ULong_Type&quot;, SLANG_ULONG_TYPE, sizeof (unsigned long), ulong_unary_op, push_long_literal, ulong_cmp_function}
++#else
++ {NULL, SLANG_LONG_TYPE, 0, NULL, NULL, NULL},
++ {NULL, SLANG_ULONG_TYPE, 0, NULL, NULL, NULL}
++#endif
++};
++
++static int create_synonyms (void)
++{
++ static char *names[8] =
++ {
++ &quot;Int16_Type&quot;, &quot;UInt16_Type&quot;, &quot;Int32_Type&quot;, &quot;UInt32_Type&quot;,
++ &quot;Int64_Type&quot;, &quot;UInt64_Type&quot;,
++ &quot;Float32_Type&quot;, &quot;Float64_Type&quot;
++ };
++ int types[8];
++ unsigned int i;
++
++ memset ((char *) types, 0, sizeof (types));
++
++ /* The assumption is that sizeof(unsigned X) == sizeof (X) */
++#if SIZEOF_INT == 2
++ types[0] = SLANG_INT_TYPE;
++ types[1] = SLANG_UINT_TYPE;
++#else
++# if SIZEOF_SHORT == 2
++ types[0] = SLANG_SHORT_TYPE;
++ types[1] = SLANG_USHORT_TYPE;
++# else
++# if SIZEOF_LONG == 2
++ types[0] = SLANG_LONG_TYPE;
++ types[1] = SLANG_ULONG_TYPE;
++# endif
++# endif
++#endif
++
++#if SIZEOF_INT == 4
++ types[2] = SLANG_INT_TYPE;
++ types[3] = SLANG_UINT_TYPE;
++#else
++# if SIZEOF_SHORT == 4
++ types[2] = SLANG_SHORT_TYPE;
++ types[3] = SLANG_USHORT_TYPE;
++# else
++# if SIZEOF_LONG == 4
++ types[2] = SLANG_LONG_TYPE;
++ types[3] = SLANG_ULONG_TYPE;
++# endif
++# endif
++#endif
++
++#if SIZEOF_INT == 8
++ types[4] = SLANG_INT_TYPE;
++ types[5] = SLANG_UINT_TYPE;
++#else
++# if SIZEOF_SHORT == 8
++ types[4] = SLANG_SHORT_TYPE;
++ types[5] = SLANG_USHORT_TYPE;
++# else
++# if SIZEOF_LONG == 8
++ types[4] = SLANG_LONG_TYPE;
++ types[5] = SLANG_ULONG_TYPE;
++# endif
++# endif
++#endif
++
++#if SLANG_HAS_FLOAT
++
++#if SIZEOF_FLOAT == 4
++ types[6] = SLANG_FLOAT_TYPE;
++#else
++# if SIZEOF_DOUBLE == 4
++ types[6] = SLANG_DOUBLE_TYPE;
++# endif
++#endif
++#if SIZEOF_FLOAT == 8
++ types[7] = SLANG_FLOAT_TYPE;
++#else
++# if SIZEOF_DOUBLE == 8
++ types[7] = SLANG_DOUBLE_TYPE;
++# endif
++#endif
++
++#endif
++
++ if ((-1 == SLclass_create_synonym (&quot;Int_Type&quot;, SLANG_INT_TYPE))
++ || (-1 == SLclass_create_synonym (&quot;UInt_Type&quot;, SLANG_UINT_TYPE)))
++ return -1;
++
++ for (i = 0; i &lt; 8; i++)
++ {
++ if (types[i] == 0) continue;
++
++ if (-1 == SLclass_create_synonym (names[i], types[i]))
++ return -1;
++ }
++
++#if SIZEOF_INT == SIZEOF_SHORT
++ if ((-1 == SLclass_create_synonym (&quot;Short_Type&quot;, SLANG_INT_TYPE))
++ || (-1 == SLclass_create_synonym (&quot;UShort_Type&quot;, SLANG_UINT_TYPE))
++ || (-1 == _SLclass_copy_class (SLANG_SHORT_TYPE, SLANG_INT_TYPE))
++ || (-1 == _SLclass_copy_class (SLANG_USHORT_TYPE, SLANG_UINT_TYPE)))
++ return -1;
++#endif
++#if SIZEOF_INT == SIZEOF_LONG
++ if ((-1 == SLclass_create_synonym (&quot;Long_Type&quot;, SLANG_INT_TYPE))
++ || (-1 == SLclass_create_synonym (&quot;ULong_Type&quot;, SLANG_UINT_TYPE))
++ || (-1 == _SLclass_copy_class (SLANG_LONG_TYPE, SLANG_INT_TYPE))
++ || (-1 == _SLclass_copy_class (SLANG_ULONG_TYPE, SLANG_UINT_TYPE)))
++ return -1;
++#endif
++ return 0;
++}
++
++int _SLarith_register_types (void)
++{
++ SLang_Class_Type *cl;
++ int a_type, b_type;
++ int i, j;
++
++#if defined(HAVE_SETLOCALE) &amp;&amp; defined(LC_NUMERIC)
++ /* make sure decimal point it used --- the parser requires it */
++ (void) setlocale (LC_NUMERIC, &quot;C&quot;);
++#endif
++
++ for (i = 0; i &lt; 8; i++)
++ {
++ Integer_Info_Type *info;
++
++ info = Integer_Types + i;
++
++ if (info-&gt;name == NULL)
++ {
++ /* This happens when the object is the same size as an integer
++ * For this case, we really want to copy the integer class.
++ * We will handle that when the synonym is created.
++ */
++ continue;
++ }
++
++ if (NULL == (cl = SLclass_allocate_class (info-&gt;name)))
++ return -1;
++
++ (void) SLclass_set_string_function (cl, arith_string);
++ (void) SLclass_set_push_function (cl, integer_push);
++ (void) SLclass_set_pop_function (cl, integer_pop);
++ cl-&gt;cl_push_literal = info-&gt;push_literal;
++ cl-&gt;cl_to_bool = integer_to_bool;
++
++ cl-&gt;cl_cmp = info-&gt;cmp_fun;
++
++ if (-1 == SLclass_register_class (cl, info-&gt;data_type, info-&gt;sizeof_type,
++ SLANG_CLASS_TYPE_SCALAR))
++ return -1;
++ if (-1 == SLclass_add_unary_op (info-&gt;data_type, info-&gt;unary_fun, arith_unary_op_result))
++ return -1;
++
++ _SLarith_Is_Arith_Type [info-&gt;data_type] = 1;
++ }
++
++#if SLANG_HAS_FLOAT
++ if (NULL == (cl = SLclass_allocate_class (&quot;Double_Type&quot;)))
++ return -1;
++ (void) SLclass_set_push_function (cl, double_push);
++ (void) SLclass_set_pop_function (cl, double_pop);
++ (void) SLclass_set_string_function (cl, arith_string);
++ cl-&gt;cl_byte_code_destroy = double_byte_code_destroy;
++ cl-&gt;cl_push_literal = double_push_literal;
++ cl-&gt;cl_cmp = double_cmp_function;
++
++ if (-1 == SLclass_register_class (cl, SLANG_DOUBLE_TYPE, sizeof (double),
++ SLANG_CLASS_TYPE_SCALAR))
++ return -1;
++ if (-1 == SLclass_add_unary_op (SLANG_DOUBLE_TYPE, double_unary_op, arith_unary_op_result))
++ return -1;
++ _SLarith_Is_Arith_Type [SLANG_DOUBLE_TYPE] = 2;
++
++ if (NULL == (cl = SLclass_allocate_class (&quot;Float_Type&quot;)))
++ return -1;
++ (void) SLclass_set_string_function (cl, arith_string);
++ (void) SLclass_set_push_function (cl, float_push);
++ (void) SLclass_set_pop_function (cl, float_pop);
++ cl-&gt;cl_cmp = float_cmp_function;
++
++ if (-1 == SLclass_register_class (cl, SLANG_FLOAT_TYPE, sizeof (float),
++ SLANG_CLASS_TYPE_SCALAR))
++ return -1;
++ if (-1 == SLclass_add_unary_op (SLANG_FLOAT_TYPE, float_unary_op, arith_unary_op_result))
++ return -1;
++ _SLarith_Is_Arith_Type [SLANG_FLOAT_TYPE] = 2;
++#endif
++
++ if (-1 == create_synonyms ())
++ return -1;
++
++ for (a_type = 0; a_type &lt;= MAXIMUM_ARITH_TYPE_VALUE; a_type++)
++ {
++ if (-1 == (i = Type_Precedence_Table [a_type]))
++ continue;
++
++ for (b_type = 0; b_type &lt;= MAXIMUM_ARITH_TYPE_VALUE; b_type++)
++ {
++ int implicit_ok;
++
++ if (-1 == (j = Type_Precedence_Table [b_type]))
++ continue;
++
++ /* Allow implicit typecast, except from into to float */
++ implicit_ok = ((j &gt;= FLOAT_PRECEDENCE_VALUE)
++ || (i &lt; FLOAT_PRECEDENCE_VALUE));
++
++ if (-1 == SLclass_add_binary_op (a_type, b_type, arith_bin_op, arith_bin_op_result))
++ return -1;
++
++ if (i != j)
++ if (-1 == SLclass_add_typecast (a_type, b_type, _SLarith_typecast, implicit_ok))
++ return -1;
++ }
++ }
++
++ return 0;
++}
++
++#if _SLANG_OPTIMIZE_FOR_SPEED
++
++static void promote_objs (SLang_Object_Type *a, SLang_Object_Type *b,
++ SLang_Object_Type *c, SLang_Object_Type *d)
++{
++ unsigned char ia, ib, ic, id;
++ int i, j;
++ void (*copy)(VOID_STAR, VOID_STAR, unsigned int);
++
++ ia = a-&gt;data_type;
++ ib = b-&gt;data_type;
++
++ ic = _SLarith_promote_type (ia);
++
++ if (ic == ib) id = ic; /* already promoted */
++ else id = _SLarith_promote_type (ib);
++
++ i = Type_Precedence_Table[ic];
++ j = Type_Precedence_Table[id];
++ if (i &gt; j)
++ {
++ id = ic;
++ j = i;
++ }
++
++ c-&gt;data_type = d-&gt;data_type = id;
++
++ i = Type_Precedence_Table[ia];
++ copy = (void (*)(VOID_STAR, VOID_STAR, unsigned int))
++ Binary_Matrix[i][j].copy_function;
++ (*copy) ((VOID_STAR) &amp;c-&gt;v, (VOID_STAR)&amp;a-&gt;v, 1);
++
++ i = Type_Precedence_Table[ib];
++ copy = (void (*)(VOID_STAR, VOID_STAR, unsigned int))
++ Binary_Matrix[i][j].copy_function;
++ (*copy) ((VOID_STAR) &amp;d-&gt;v, (VOID_STAR)&amp;b-&gt;v, 1);
++}
++
++int _SLarith_bin_op (SLang_Object_Type *oa, SLang_Object_Type *ob, int op)
++{
++ unsigned char a_type, b_type;
++
++ a_type = oa-&gt;data_type;
++ b_type = ob-&gt;data_type;
++
++ if (a_type != b_type)
++ {
++ SLang_Object_Type obj_a, obj_b;
++
++ /* Handle common cases */
++ if ((a_type == SLANG_INT_TYPE)
++ &amp;&amp; (b_type == SLANG_DOUBLE_TYPE))
++ return double_double_scalar_bin_op (oa-&gt;v.int_val, ob-&gt;v.double_val, op);
++
++ if ((a_type == SLANG_DOUBLE_TYPE)
++ &amp;&amp; (b_type == SLANG_INT_TYPE))
++ return double_double_scalar_bin_op (oa-&gt;v.double_val, ob-&gt;v.int_val, op);
++
++ /* Otherwise do it the hard way */
++ promote_objs (oa, ob, &amp;obj_a, &amp;obj_b);
++ oa = &amp;obj_a;
++ ob = &amp;obj_b;
++
++ a_type = oa-&gt;data_type;
++ b_type = ob-&gt;data_type;
++ }
++
++
++ switch (a_type)
++ {
++ case SLANG_CHAR_TYPE:
++ return int_int_scalar_bin_op (oa-&gt;v.char_val, ob-&gt;v.char_val, op);
++
++ case SLANG_UCHAR_TYPE:
++ return int_int_scalar_bin_op (oa-&gt;v.uchar_val, ob-&gt;v.uchar_val, op);
++
++ case SLANG_SHORT_TYPE:
++ return int_int_scalar_bin_op (oa-&gt;v.short_val, ob-&gt;v.short_val, op);
++
++ case SLANG_USHORT_TYPE:
++# if SIZEOF_INT == SIZEOF_SHORT
++ return uint_uint_scalar_bin_op (oa-&gt;v.ushort_val, ob-&gt;v.ushort_val, op);
++# else
++ return int_int_scalar_bin_op ((int)oa-&gt;v.ushort_val, (int)ob-&gt;v.ushort_val, op);
++# endif
++
++#if SIZEOF_LONG == SIZEOF_INT
++ case SLANG_LONG_TYPE:
++#endif
++ case SLANG_INT_TYPE:
++ return int_int_scalar_bin_op (oa-&gt;v.int_val, ob-&gt;v.int_val, op);
++
++#if SIZEOF_LONG == SIZEOF_INT
++ case SLANG_ULONG_TYPE:
++#endif
++ case SLANG_UINT_TYPE:
++ return uint_uint_scalar_bin_op (oa-&gt;v.uint_val, ob-&gt;v.uint_val, op);
++
++#if SIZEOF_LONG != SIZEOF_INT
++ case SLANG_LONG_TYPE:
++ return long_long_scalar_bin_op (oa-&gt;v.long_val, ob-&gt;v.long_val, op);
++ case SLANG_ULONG_TYPE:
++ return ulong_ulong_scalar_bin_op (oa-&gt;v.ulong_val, ob-&gt;v.ulong_val, op);
++#endif
++ case SLANG_FLOAT_TYPE:
++ return float_float_scalar_bin_op (oa-&gt;v.float_val, ob-&gt;v.float_val, op);
++ case SLANG_DOUBLE_TYPE:
++ return double_double_scalar_bin_op (oa-&gt;v.double_val, ob-&gt;v.double_val, op);
++ }
++
++ return 1;
++}
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slarith.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slarith.inc
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slarith.inc (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slarith.inc 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,783 @@
++/* -*- c -*- */
++
++/* This include file is a template for defining arithmetic binary operations
++ * on arithmetic types. I realize that doing it this way is not very
++ * elegant but it minimizes the number of lines of code and I believe it
++ * promotes clarity.
++ */
++
++/* The following macros should be properly defined before including this file:
++ *
++ * GENERIC_BINARY_FUNCTION: The name of the binary function
++ * GENERIC_TYPE: The class data type
++ * MOD_FUNCTION: The function to use for mod
++ * ABS_FUNCTION: Name of the abs function
++ * SIGN_FUNCTION: Name of the sign function
++ * GENERIC_UNARY_FUNCTION Name of the unary function
++ *
++ * If GENERIC_BIT_OPERATIONS is defined, the bit-level binary operators
++ * will get included. If the data type has a power operation (SLANG_POW),
++ * then POW_FUNCTION should be defined to return POW_RESULT_TYPE.
++ */
++#ifdef GENERIC_BINARY_FUNCTION
++
++static int GENERIC_BINARY_FUNCTION
++(int op,
++ unsigned char a_type, VOID_STAR ap, unsigned int na,
++ unsigned char b_type, VOID_STAR bp, unsigned int nb,
++ VOID_STAR cp)
++{
++ GENERIC_TYPE *c, *a, *b;
++#ifdef POW_FUNCTION
++ POW_RESULT_TYPE *d;
++#endif
++ unsigned int n;
++#if _SLANG_OPTIMIZE_FOR_SPEED &lt; 2
++ unsigned int n_max, da, db;
++#endif
++ char *cc;
++
++ (void) a_type; /* Both SLANG_INT_TYPE */
++ (void) b_type;
++
++ a = (GENERIC_TYPE *) ap;
++ b = (GENERIC_TYPE *) bp;
++ c = (GENERIC_TYPE *) cp;
++ cc = (char *) cp;
++
++#if _SLANG_OPTIMIZE_FOR_SPEED &lt; 2
++ if (na == 1) da = 0; else da = 1;
++ if (nb == 1) db = 0; else db = 1;
++
++ if (na &gt; nb) n_max = na; else n_max = nb;
++#endif
++
++ switch (op)
++ {
++ default:
++ return 0;
++#ifdef POW_FUNCTION
++ case SLANG_POW:
++ d = (POW_RESULT_TYPE *) cp;
++#if _SLANG_OPTIMIZE_FOR_SPEED &lt; 2
++ for (n = 0; n &lt; n_max; n++)
++ {
++ d[n] = POW_FUNCTION(*a, *b);
++ a += da; b += db;
++ }
++#else
++ if (na == nb)
++ {
++ for (n = 0; n &lt; na; n++)
++ d[n] = POW_FUNCTION(a[n],b[n]);
++ }
++ else if (nb == 1)
++ {
++ GENERIC_TYPE xb = *b;
++ if (xb == 2)
++ for (n = 0; n &lt; na; n++)
++ d[n] = a[n] * a[n];
++ else
++ for (n = 0; n &lt; na; n++)
++ d[n] = POW_FUNCTION(a[n], xb);
++ }
++ else /* if (na == 1) */
++ {
++ GENERIC_TYPE xa = *a;
++ for (n = 0; n &lt; nb; n++)
++ d[n] = POW_FUNCTION(xa, b[n]);
++ }
++#endif
++ break;
++#endif
++ case SLANG_PLUS:
++#if _SLANG_OPTIMIZE_FOR_SPEED &lt; 2
++ for (n = 0; n &lt; n_max; n++)
++ {
++ c[n] = (*a + *b); a += da; b += db;
++ }
++#else
++ if (na == nb)
++ {
++ for (n = 0; n &lt; na; n++)
++ c[n] = a[n] + b[n];
++ }
++ else if (nb == 1)
++ {
++ GENERIC_TYPE xb = *b;
++ for (n = 0; n &lt; na; n++)
++ c[n] = a[n] + xb;
++ }
++ else /* if (na == 1) */
++ {
++ GENERIC_TYPE xa = *a;
++ for (n = 0; n &lt; nb; n++)
++ c[n] = xa + b[n];
++ }
++#endif
++ break;
++
++ case SLANG_MINUS:
++#if _SLANG_OPTIMIZE_FOR_SPEED &lt; 2
++ for (n = 0; n &lt; n_max; n++)
++ {
++ c[n] = (*a - *b); a += da; b += db;
++ }
++#else
++ if (na == nb)
++ {
++ for (n = 0; n &lt; na; n++)
++ c[n] = a[n] - b[n];
++ }
++ else if (nb == 1)
++ {
++ GENERIC_TYPE xb = *b;
++ for (n = 0; n &lt; na; n++)
++ c[n] = a[n] - xb;
++ }
++ else /* if (na == 1) */
++ {
++ GENERIC_TYPE xa = *a;
++ for (n = 0; n &lt; nb; n++)
++ c[n] = xa - b[n];
++ }
++#endif
++ break;
++
++ case SLANG_TIMES:
++#if _SLANG_OPTIMIZE_FOR_SPEED &lt; 2
++ for (n = 0; n &lt; n_max; n++)
++ {
++ c[n] = (*a * *b); a += da; b += db;
++ }
++#else
++ if (na == nb)
++ {
++ for (n = 0; n &lt; na; n++)
++ c[n] = a[n] * b[n];
++ }
++ else if (nb == 1)
++ {
++ GENERIC_TYPE xb = *b;
++ for (n = 0; n &lt; na; n++)
++ c[n] = a[n] * xb;
++ }
++ else /* if (na == 1) */
++ {
++ GENERIC_TYPE xa = *a;
++ for (n = 0; n &lt; nb; n++)
++ c[n] = xa * b[n];
++ }
++#endif
++ break;
++
++ case SLANG_DIVIDE:
++#if _SLANG_OPTIMIZE_FOR_SPEED &lt; 2
++ for (n = 0; n &lt; n_max; n++)
++ {
++ if (*b == 0)
++ {
++ SLang_Error = SL_DIVIDE_ERROR;
++ return -1;
++ }
++ c[n] = (*a / *b); a += da; b += db;
++ }
++#else
++ if (na == nb)
++ {
++ for (n = 0; n &lt; na; n++)
++ {
++ if (b[n] == 0)
++ {
++ SLang_Error = SL_DIVIDE_ERROR;
++ return -1;
++ }
++ c[n] = a[n] / b[n];
++ }
++ }
++ else if (nb == 1)
++ {
++ GENERIC_TYPE xb = *b;
++
++ if (xb == 0)
++ {
++ SLang_Error = SL_DIVIDE_ERROR;
++ return -1;
++ }
++ for (n = 0; n &lt; na; n++)
++ c[n] = a[n] / xb;
++ }
++ else /* if (na == 1) */
++ {
++ GENERIC_TYPE xa = *a;
++ for (n = 0; n &lt; nb; n++)
++ {
++ if (b[n] == 0)
++ {
++ SLang_Error = SL_DIVIDE_ERROR;
++ return -1;
++ }
++ c[n] = xa / b[n];
++ }
++ }
++#endif
++ break;
++
++ case SLANG_MOD:
++#if _SLANG_OPTIMIZE_FOR_SPEED &lt; 2
++ for (n = 0; n &lt; n_max; n++)
++ {
++ if (*b == 0)
++ {
++ SLang_Error = SL_DIVIDE_ERROR;
++ return -1;
++ }
++ c[n] = MOD_FUNCTION(*a, *b); a += da; b += db;
++ }
++#else
++ if (na == nb)
++ {
++ for (n = 0; n &lt; na; n++)
++ {
++ if (b[n] == 0)
++ {
++ SLang_Error = SL_DIVIDE_ERROR;
++ return -1;
++ }
++ c[n] = MOD_FUNCTION(a[n],b[n]);
++ }
++ }
++ else if (nb == 1)
++ {
++ GENERIC_TYPE xb = *b;
++ if (xb == 0)
++ {
++ SLang_Error = SL_DIVIDE_ERROR;
++ return -1;
++ }
++ for (n = 0; n &lt; na; n++)
++ c[n] = MOD_FUNCTION(a[n],xb);
++ }
++ else /* if (na == 1) */
++ {
++ GENERIC_TYPE xa = *a;
++ for (n = 0; n &lt; nb; n++)
++ {
++ if (b[n] == 0)
++ {
++ SLang_Error = SL_DIVIDE_ERROR;
++ return -1;
++ }
++ c[n] = MOD_FUNCTION(xa,b[n]);
++ }
++ }
++#endif
++ break;
++
++#ifdef GENERIC_BIT_OPERATIONS
++ case SLANG_BAND:
++#if _SLANG_OPTIMIZE_FOR_SPEED &lt; 2
++ for (n = 0; n &lt; n_max; n++)
++ {
++ c[n] = (*a &amp; *b); a += da; b += db;
++ }
++#else
++ if (na == nb)
++ {
++ for (n = 0; n &lt; na; n++)
++ c[n] = a[n] &amp; b[n];
++ }
++ else if (nb == 1)
++ {
++ GENERIC_TYPE xb = *b;
++ for (n = 0; n &lt; na; n++)
++ c[n] = a[n] &amp; xb;
++ }
++ else /* if (na == 1) */
++ {
++ GENERIC_TYPE xa = *a;
++ for (n = 0; n &lt; nb; n++)
++ c[n] = xa &amp; b[n];
++ }
++#endif
++ break;
++
++ case SLANG_BXOR:
++#if _SLANG_OPTIMIZE_FOR_SPEED &lt; 2
++ for (n = 0; n &lt; n_max; n++)
++ {
++ c[n] = (*a ^ *b); a += da; b += db;
++ }
++#else
++ if (na == nb)
++ {
++ for (n = 0; n &lt; na; n++)
++ c[n] = a[n] ^ b[n];
++ }
++ else if (nb == 1)
++ {
++ GENERIC_TYPE xb = *b;
++ for (n = 0; n &lt; na; n++)
++ c[n] = a[n] ^ xb;
++ }
++ else /* if (na == 1) */
++ {
++ GENERIC_TYPE xa = *a;
++ for (n = 0; n &lt; nb; n++)
++ c[n] = xa ^ b[n];
++ }
++#endif
++ break;
++
++ case SLANG_BOR:
++#if _SLANG_OPTIMIZE_FOR_SPEED &lt; 2
++ for (n = 0; n &lt; n_max; n++)
++ {
++ c[n] = (*a | *b); a += da; b += db;
++ }
++#else
++ if (na == nb)
++ {
++ for (n = 0; n &lt; na; n++)
++ c[n] = a[n] | b[n];
++ }
++ else if (nb == 1)
++ {
++ GENERIC_TYPE xb = *b;
++ for (n = 0; n &lt; na; n++)
++ c[n] = a[n] | xb;
++ }
++ else /* if (na == 1) */
++ {
++ GENERIC_TYPE xa = *a;
++ for (n = 0; n &lt; nb; n++)
++ c[n] = xa | b[n];
++ }
++#endif
++ break;
++
++ case SLANG_SHL:
++#if _SLANG_OPTIMIZE_FOR_SPEED &lt; 2
++ for (n = 0; n &lt; n_max; n++)
++ {
++ c[n] = (*a &lt;&lt; *b); a += da; b += db;
++ }
++#else
++ if (na == nb)
++ {
++ for (n = 0; n &lt; na; n++)
++ c[n] = a[n] &lt;&lt; b[n];
++ }
++ else if (nb == 1)
++ {
++ GENERIC_TYPE xb = *b;
++ for (n = 0; n &lt; na; n++)
++ c[n] = a[n] &lt;&lt; xb;
++ }
++ else /* if (na == 1) */
++ {
++ GENERIC_TYPE xa = *a;
++ for (n = 0; n &lt; nb; n++)
++ c[n] = xa &lt;&lt; b[n];
++ }
++#endif
++ break;
++
++ case SLANG_SHR:
++#if _SLANG_OPTIMIZE_FOR_SPEED &lt; 2
++ for (n = 0; n &lt; n_max; n++)
++ {
++ c[n] = (*a &gt;&gt; *b); a += da; b += db;
++ }
++#else
++ if (na == nb)
++ {
++ for (n = 0; n &lt; na; n++)
++ c[n] = a[n] &gt;&gt; b[n];
++ }
++ else if (nb == 1)
++ {
++ GENERIC_TYPE xb = *b;
++ for (n = 0; n &lt; na; n++)
++ c[n] = a[n] &gt;&gt; xb;
++ }
++ else /* if (na == 1) */
++ {
++ GENERIC_TYPE xa = *a;
++ for (n = 0; n &lt; nb; n++)
++ c[n] = xa &gt;&gt; b[n];
++ }
++#endif
++ break;
++#endif /* GENERIC_BIT_OPERATIONS */
++ case SLANG_EQ:
++#if _SLANG_OPTIMIZE_FOR_SPEED &lt; 2
++ for (n = 0; n &lt; n_max; n++)
++ {
++ cc[n] = (*a == *b); a += da; b += db;
++ }
++#else
++ if (na == nb)
++ {
++ for (n = 0; n &lt; na; n++)
++ cc[n] = (a[n] == b[n]);
++ }
++ else if (nb == 1)
++ {
++ GENERIC_TYPE xb = *b;
++ for (n = 0; n &lt; na; n++)
++ cc[n] = (a[n] == xb);
++ }
++ else /* if (na == 1) */
++ {
++ GENERIC_TYPE xa = *a;
++ for (n = 0; n &lt; nb; n++)
++ cc[n] = (xa == b[n]);
++ }
++#endif
++ break;
++
++ case SLANG_NE:
++#if _SLANG_OPTIMIZE_FOR_SPEED &lt; 2
++ for (n = 0; n &lt; n_max; n++)
++ {
++ cc[n] = (*a != *b); a += da; b += db;
++ }
++#else
++ if (na == nb)
++ {
++ for (n = 0; n &lt; na; n++)
++ cc[n] = (a[n] != b[n]);
++ }
++ else if (nb == 1)
++ {
++ GENERIC_TYPE xb = *b;
++ for (n = 0; n &lt; na; n++)
++ cc[n] = (a[n] != xb);
++ }
++ else /* if (na == 1) */
++ {
++ GENERIC_TYPE xa = *a;
++ for (n = 0; n &lt; nb; n++)
++ cc[n] = (xa != b[n]);
++ }
++#endif
++ break;
++
++ case SLANG_GT:
++#if _SLANG_OPTIMIZE_FOR_SPEED &lt; 2
++ for (n = 0; n &lt; n_max; n++)
++ {
++ cc[n] = (*a &gt; *b); a += da; b += db;
++ }
++#else
++ if (na == nb)
++ {
++ for (n = 0; n &lt; na; n++)
++ cc[n] = (a[n] &gt; b[n]);
++ }
++ else if (nb == 1)
++ {
++ GENERIC_TYPE xb = *b;
++ for (n = 0; n &lt; na; n++)
++ cc[n] = (a[n] &gt; xb);
++ }
++ else /* if (na == 1) */
++ {
++ GENERIC_TYPE xa = *a;
++ for (n = 0; n &lt; nb; n++)
++ cc[n] = (xa &gt; b[n]);
++ }
++#endif
++ break;
++
++ case SLANG_GE:
++#if _SLANG_OPTIMIZE_FOR_SPEED &lt; 2
++ for (n = 0; n &lt; n_max; n++)
++ {
++ cc[n] = (*a &gt;= *b); a += da; b += db;
++ }
++#else
++ if (na == nb)
++ {
++ for (n = 0; n &lt; na; n++)
++ cc[n] = (a[n] &gt;= b[n]);
++ }
++ else if (nb == 1)
++ {
++ GENERIC_TYPE xb = *b;
++ for (n = 0; n &lt; na; n++)
++ cc[n] = (a[n] &gt;= xb);
++ }
++ else /* if (na == 1) */
++ {
++ GENERIC_TYPE xa = *a;
++ for (n = 0; n &lt; nb; n++)
++ cc[n] = (xa &gt;= b[n]);
++ }
++#endif
++ break;
++
++ case SLANG_LT:
++#if _SLANG_OPTIMIZE_FOR_SPEED &lt; 2
++ for (n = 0; n &lt; n_max; n++)
++ {
++ cc[n] = (*a &lt; *b); a += da; b += db;
++ }
++#else
++ if (na == nb)
++ {
++ for (n = 0; n &lt; na; n++)
++ cc[n] = (a[n] &lt; b[n]);
++ }
++ else if (nb == 1)
++ {
++ GENERIC_TYPE xb = *b;
++ for (n = 0; n &lt; na; n++)
++ cc[n] = (a[n] &lt; xb);
++ }
++ else /* if (na == 1) */
++ {
++ GENERIC_TYPE xa = *a;
++ for (n = 0; n &lt; nb; n++)
++ cc[n] = (xa &lt; b[n]);
++ }
++#endif
++ break;
++
++ case SLANG_LE:
++#if _SLANG_OPTIMIZE_FOR_SPEED &lt; 2
++ for (n = 0; n &lt; n_max; n++)
++ {
++ cc[n] = (*a &lt;= *b); a += da; b += db;
++ }
++#else
++ if (na == nb)
++ {
++ for (n = 0; n &lt; na; n++)
++ cc[n] = (a[n] &lt;= b[n]);
++ }
++ else if (nb == 1)
++ {
++ GENERIC_TYPE xb = *b;
++ for (n = 0; n &lt; na; n++)
++ cc[n] = (a[n] &lt;= xb);
++ }
++ else /* if (na == 1) */
++ {
++ GENERIC_TYPE xa = *a;
++ for (n = 0; n &lt; nb; n++)
++ cc[n] = (xa &lt;= b[n]);
++ }
++#endif
++ break;
++
++ case SLANG_OR:
++#if _SLANG_OPTIMIZE_FOR_SPEED &lt; 2
++ for (n = 0; n &lt; n_max; n++)
++ {
++ cc[n] = (*a || *b); a += da; b += db;
++ }
++#else
++ if (na == nb)
++ {
++ for (n = 0; n &lt; na; n++)
++ cc[n] = (a[n] || b[n]);
++ }
++ else if (nb == 1)
++ {
++ GENERIC_TYPE xb = *b;
++ for (n = 0; n &lt; na; n++)
++ cc[n] = (a[n] || xb);
++ }
++ else /* if (na == 1) */
++ {
++ GENERIC_TYPE xa = *a;
++ for (n = 0; n &lt; nb; n++)
++ cc[n] = (xa || b[n]);
++ }
++#endif
++ break;
++
++ case SLANG_AND:
++#if _SLANG_OPTIMIZE_FOR_SPEED &lt; 2
++ for (n = 0; n &lt; n_max; n++)
++ {
++ cc[n] = (*a &amp;&amp; *b); a += da; b += db;
++ }
++#else
++ if (na == nb)
++ {
++ for (n = 0; n &lt; na; n++)
++ cc[n] = (a[n] &amp;&amp; b[n]);
++ }
++ else if (nb == 1)
++ {
++ GENERIC_TYPE xb = *b;
++ for (n = 0; n &lt; na; n++)
++ cc[n] = (a[n] &amp;&amp; xb);
++ }
++ else /* if (na == 1) */
++ {
++ GENERIC_TYPE xa = *a;
++ for (n = 0; n &lt; nb; n++)
++ cc[n] = (xa &amp;&amp; b[n]);
++ }
++#endif
++ break;
++ }
++ return 1;
++}
++
++#endif /* GENERIC_BINARY_FUNCTION */
++
++
++#ifdef GENERIC_UNARY_FUNCTION
++
++static int GENERIC_UNARY_FUNCTION
++(int op,
++ unsigned char a_type, VOID_STAR ap, unsigned int na,
++ VOID_STAR bp
++ )
++{
++ GENERIC_TYPE *a, *b;
++ unsigned int n;
++ int *ib;
++
++ (void) a_type;
++
++ a = (GENERIC_TYPE *) ap;
++ b = (GENERIC_TYPE *) bp;
++
++ switch (op)
++ {
++ default:
++ return 0;
++
++ case SLANG_PLUSPLUS:
++ for (n = 0; n &lt; na; n++) b[n] = (a[n] + 1);
++ break;
++ case SLANG_MINUSMINUS:
++ for (n = 0; n &lt; na; n++) b[n] = (a[n] - 1);
++ break;
++ case SLANG_CHS:
++ for (n = 0; n &lt; na; n++) b[n] = (GENERIC_TYPE) -(a[n]);
++ break;
++ case SLANG_SQR:
++ for (n = 0; n &lt; na; n++) b[n] = (a[n] * a[n]);
++ break;
++ case SLANG_MUL2:
++ for (n = 0; n &lt; na; n++) b[n] = (2 * a[n]);
++ break;
++ case SLANG_ABS:
++ for (n = 0; n &lt; na; n++) b[n] = ABS_FUNCTION (a[n]);
++ break;
++ case SLANG_SIGN:
++ ib = (int *) bp;
++ for (n = 0; n &lt; na; n++)
++ ib[n] = SIGN_FUNCTION(a[n]);
++ break;
++
++#ifdef GENERIC_BIT_OPERATIONS
++ case SLANG_NOT:
++ for (n = 0; n &lt; na; n++) b[n] = !(a[n]);
++ break;
++ case SLANG_BNOT:
++ for (n = 0; n &lt; na; n++) b[n] = ~(a[n]);
++ break;
++#endif
++ }
++
++ return 1;
++}
++#endif /* GENERIC_UNARY_FUNCTION */
++
++
++#ifdef SCALAR_BINARY_FUNCTION
++
++static int SCALAR_BINARY_FUNCTION (GENERIC_TYPE a, GENERIC_TYPE b, int op)
++{
++ switch (op)
++ {
++ default:
++ return 1;
++
++#ifdef POW_FUNCTION
++ case SLANG_POW:
++ return PUSH_POW_OBJ_FUN(POW_FUNCTION(a, b));
++#endif
++ case SLANG_PLUS:
++ return PUSH_SCALAR_OBJ_FUN (a + b);
++ case SLANG_MINUS:
++ return PUSH_SCALAR_OBJ_FUN (a - b);
++ case SLANG_TIMES:
++ return PUSH_SCALAR_OBJ_FUN (a * b);
++ case SLANG_DIVIDE:
++ if (b == 0)
++ {
++ SLang_Error = SL_DIVIDE_ERROR;
++ return -1;
++ }
++ return PUSH_SCALAR_OBJ_FUN (a / b);
++ case SLANG_MOD:
++ if (b == 0)
++ {
++ SLang_Error = SL_DIVIDE_ERROR;
++ return -1;
++ }
++ return PUSH_SCALAR_OBJ_FUN (MOD_FUNCTION(a,b));
++#ifdef GENERIC_BIT_OPERATIONS
++ case SLANG_BAND:
++ return PUSH_SCALAR_OBJ_FUN (a &amp; b);
++ case SLANG_BXOR:
++ return PUSH_SCALAR_OBJ_FUN (a ^ b);
++ case SLANG_BOR:
++ return PUSH_SCALAR_OBJ_FUN (a | b);
++ case SLANG_SHL:
++ return PUSH_SCALAR_OBJ_FUN (a &lt;&lt; b);
++ case SLANG_SHR:
++ return PUSH_SCALAR_OBJ_FUN (a &gt;&gt; b);
++#endif
++ case SLANG_GT: return SLclass_push_char_obj (SLANG_CHAR_TYPE, (char)(a &gt; b));
++ case SLANG_LT: return SLclass_push_char_obj (SLANG_CHAR_TYPE, (char)(a &lt; b));
++ case SLANG_GE: return SLclass_push_char_obj (SLANG_CHAR_TYPE, (char)(a &gt;= b));
++ case SLANG_LE: return SLclass_push_char_obj (SLANG_CHAR_TYPE, (char)(a &lt;= b));
++ case SLANG_EQ: return SLclass_push_char_obj (SLANG_CHAR_TYPE, (char)(a == b));
++ case SLANG_NE: return SLclass_push_char_obj (SLANG_CHAR_TYPE, (char)(a != b));
++ case SLANG_OR: return SLclass_push_char_obj (SLANG_CHAR_TYPE, (char)(a || b));
++ case SLANG_AND: return SLclass_push_char_obj (SLANG_CHAR_TYPE, (char)(a &amp;&amp; b));
++ }
++}
++
++#endif /* SCALAR_BINARY_FUNCTION */
++
++#ifdef CMP_FUNCTION
++static int CMP_FUNCTION (unsigned char unused, VOID_STAR a, VOID_STAR b, int *c)
++{
++ GENERIC_TYPE x, y;
++
++ (void) unused;
++ x = *(GENERIC_TYPE *) a;
++ y = *(GENERIC_TYPE *) b;
++
++ if (x &gt; y) *c = 1;
++ else if (x == y) *c = 0;
++ else *c = -1;
++
++ return 0;
++}
++#endif
++
++#undef CMP_FUNCTION
++#undef SCALAR_BINARY_FUNCTION
++#undef PUSH_POW_OBJ_FUN
++#undef PUSH_SCALAR_OBJ_FUN
++#undef GENERIC_BINARY_FUNCTION
++#undef GENERIC_UNARY_FUNCTION
++#undef GENERIC_BIT_OPERATIONS
++#undef GENERIC_TYPE
++#undef POW_FUNCTION
++#undef POW_RESULT_TYPE
++#undef MOD_FUNCTION
++#undef ABS_FUNCTION
++#undef SIGN_FUNCTION
+
+Added: drakx/trunk/mdk-stage1/slang/slarray.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slarray.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slarray.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,3139 @@
++/* Array manipulation routines for S-Lang */
++/* Copyright (c) 1997, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++
++#define SL_APP_WANTS_FOREACH
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++typedef struct
++{
++ int first_index;
++ int last_index;
++ int delta;
++}
++SLarray_Range_Array_Type;
++
++/* Use SLang_pop_array when a linear array is required. */
++static int pop_array (SLang_Array_Type **at_ptr, int convert_scalar)
++{
++ SLang_Array_Type *at;
++ int one = 1;
++ int type;
++
++ *at_ptr = NULL;
++ type = SLang_peek_at_stack ();
++
++ switch (type)
++ {
++ case -1:
++ return -1;
++
++ case SLANG_ARRAY_TYPE:
++ return SLclass_pop_ptr_obj (SLANG_ARRAY_TYPE, (VOID_STAR *) at_ptr);
++
++ case SLANG_NULL_TYPE:
++ convert_scalar = 0;
++ /* drop */
++ default:
++ if (convert_scalar == 0)
++ {
++ SLdo_pop ();
++ SLang_verror (SL_TYPE_MISMATCH, &quot;Context requires an array. Scalar not converted&quot;);
++ return -1;
++ }
++ break;
++ }
++
++ if (NULL == (at = SLang_create_array ((unsigned char) type, 0, NULL, &amp;one, 1)))
++ return -1;
++
++ if (-1 == at-&gt;cl-&gt;cl_apop ((unsigned char) type, at-&gt;data))
++ {
++ SLang_free_array (at);
++ return -1;
++ }
++
++ *at_ptr = at;
++
++ return 0;
++}
++
++static VOID_STAR linear_get_data_addr (SLang_Array_Type *at, int *dims)
++{
++ unsigned int num_dims;
++ unsigned int ofs;
++ unsigned int i;
++ int *max_dims;
++
++ ofs = 0;
++ max_dims = at-&gt;dims;
++ num_dims = at-&gt;num_dims;
++
++ for (i = 0; i &lt; num_dims; i++)
++ {
++ int d = dims[i];
++
++ if (d &lt; 0)
++ d = d + max_dims[i];
++
++ ofs = ofs * (unsigned int)max_dims [i] + (unsigned int) d;
++ }
++
++ return (VOID_STAR) ((char *)at-&gt;data + (ofs * at-&gt;sizeof_type));
++}
++
++static VOID_STAR get_data_addr (SLang_Array_Type *at, int *dims)
++{
++ VOID_STAR data;
++
++ data = at-&gt;data;
++ if (data == NULL)
++ {
++ SLang_verror (SL_UNKNOWN_ERROR, &quot;Array has no data&quot;);
++ return NULL;
++ }
++
++ data = (*at-&gt;index_fun) (at, dims);
++
++ if (data == NULL)
++ {
++ SLang_verror (SL_UNKNOWN_ERROR, &quot;Unable to access array element&quot;);
++ return NULL;
++ }
++
++ return data;
++}
++
++void _SLarray_free_array_elements (SLang_Class_Type *cl, VOID_STAR s, unsigned int num)
++{
++ unsigned int sizeof_type;
++ void (*f) (unsigned char, VOID_STAR);
++ char *p;
++ unsigned char type;
++
++ if ((cl-&gt;cl_class_type == SLANG_CLASS_TYPE_SCALAR)
++ || (cl-&gt;cl_class_type == SLANG_CLASS_TYPE_VECTOR))
++ return;
++
++ f = cl-&gt;cl_destroy;
++ sizeof_type = cl-&gt;cl_sizeof_type;
++ type = cl-&gt;cl_data_type;
++
++ p = (char *) s;
++ while (num != 0)
++ {
++ if (NULL != *(VOID_STAR *)p)
++ {
++ (*f) (type, (VOID_STAR)p);
++ *(VOID_STAR *) p = NULL;
++ }
++ p += sizeof_type;
++ num--;
++ }
++}
++
++static int destroy_element (SLang_Array_Type *at,
++ int *dims,
++ VOID_STAR data)
++{
++ data = get_data_addr (at, dims);
++ if (data == NULL)
++ return -1;
++
++ /* This function should only get called for arrays that have
++ * pointer elements. Do not call the destroy method if the element
++ * is NULL.
++ */
++ if (NULL != *(VOID_STAR *)data)
++ {
++ (*at-&gt;cl-&gt;cl_destroy) (at-&gt;data_type, data);
++ *(VOID_STAR *) data = NULL;
++ }
++ return 0;
++}
++
++/* This function only gets called when a new array is created. Thus there
++ * is no need to destroy the object first.
++ */
++static int new_object_element (SLang_Array_Type *at,
++ int *dims,
++ VOID_STAR data)
++{
++ data = get_data_addr (at, dims);
++ if (data == NULL)
++ return -1;
++
++ return (*at-&gt;cl-&gt;cl_init_array_object) (at-&gt;data_type, data);
++}
++
++static int next_index (int *dims, int *max_dims, unsigned int num_dims)
++{
++ while (num_dims)
++ {
++ int dims_i;
++
++ num_dims--;
++
++ dims_i = dims [num_dims] + 1;
++ if (dims_i != (int) max_dims [num_dims])
++ {
++ dims [num_dims] = dims_i;
++ return 0;
++ }
++ dims [num_dims] = 0;
++ }
++
++ return -1;
++}
++
++static int do_method_for_all_elements (SLang_Array_Type *at,
++ int (*method)(SLang_Array_Type *,
++ int *,
++ VOID_STAR),
++ VOID_STAR client_data)
++{
++ int dims [SLARRAY_MAX_DIMS];
++ int *max_dims;
++ unsigned int num_dims;
++
++ if (at-&gt;num_elements == 0)
++ return 0;
++
++ max_dims = at-&gt;dims;
++ num_dims = at-&gt;num_dims;
++
++ SLMEMSET((char *)dims, 0, sizeof(dims));
++
++ do
++ {
++ if (-1 == (*method) (at, dims, client_data))
++ return -1;
++ }
++ while (0 == next_index (dims, max_dims, num_dims));
++
++ return 0;
++}
++
++void SLang_free_array (SLang_Array_Type *at)
++{
++ VOID_STAR data;
++ unsigned int flags;
++
++ if (at == NULL) return;
++
++ if (at-&gt;num_refs &gt; 1)
++ {
++ at-&gt;num_refs -= 1;
++ return;
++ }
++
++ data = at-&gt;data;
++ flags = at-&gt;flags;
++
++ if (flags &amp; SLARR_DATA_VALUE_IS_INTRINSIC)
++ return; /* not to be freed */
++
++ if (flags &amp; SLARR_DATA_VALUE_IS_POINTER)
++ (void) do_method_for_all_elements (at, destroy_element, NULL);
++
++ SLfree ((char *) data);
++ SLfree ((char *) at);
++}
++
++SLang_Array_Type *
++SLang_create_array1 (unsigned char type, int read_only, VOID_STAR data,
++ int *dims, unsigned int num_dims, int no_init)
++{
++ SLang_Class_Type *cl;
++ unsigned int i;
++ SLang_Array_Type *at;
++ unsigned int num_elements;
++ unsigned int sizeof_type;
++ unsigned int size;
++
++ if (num_dims &gt; SLARRAY_MAX_DIMS)
++ {
++ SLang_verror (SL_NOT_IMPLEMENTED, &quot;%u dimensional arrays are not supported&quot;, num_dims);
++ return NULL;
++ }
++
++ for (i = 0; i &lt; num_dims; i++)
++ {
++ if (dims[i] &lt; 0)
++ {
++ SLang_verror (SL_INVALID_PARM, &quot;Size of array dim %u is less than 0&quot;, i);
++ return NULL;
++ }
++ }
++
++ cl = _SLclass_get_class (type);
++
++ at = (SLang_Array_Type *) SLmalloc (sizeof(SLang_Array_Type));
++ if (at == NULL)
++ return NULL;
++
++ SLMEMSET ((char*) at, 0, sizeof(SLang_Array_Type));
++
++ at-&gt;data_type = type;
++ at-&gt;cl = cl;
++ at-&gt;num_dims = num_dims;
++ at-&gt;num_refs = 1;
++
++ if (read_only) at-&gt;flags = SLARR_DATA_VALUE_IS_READ_ONLY;
++ switch (cl-&gt;cl_class_type)
++ {
++ case SLANG_CLASS_TYPE_VECTOR:
++ case SLANG_CLASS_TYPE_SCALAR:
++ break;
++
++ default:
++ at-&gt;flags |= SLARR_DATA_VALUE_IS_POINTER;
++ }
++
++ num_elements = 1;
++ for (i = 0; i &lt; num_dims; i++)
++ {
++ at-&gt;dims [i] = dims[i];
++ num_elements = dims [i] * num_elements;
++ }
++
++ /* Now set the rest of the unused dimensions to 1. This makes it easier
++ * when transposing arrays.
++ */
++ while (i &lt; SLARRAY_MAX_DIMS)
++ at-&gt;dims[i++] = 1;
++
++ at-&gt;num_elements = num_elements;
++ at-&gt;index_fun = linear_get_data_addr;
++ at-&gt;sizeof_type = sizeof_type = cl-&gt;cl_sizeof_type;
++
++ if (data != NULL)
++ {
++ at-&gt;data = data;
++ return at;
++ }
++
++ size = num_elements * sizeof_type;
++
++ if (size == 0) size = 1;
++
++ if (NULL == (data = (VOID_STAR) SLmalloc (size)))
++ {
++ SLang_free_array (at);
++ return NULL;
++ }
++
++ if (no_init == 0)
++ SLMEMSET ((char *) data, 0, size);
++
++ at-&gt;data = data;
++
++ if ((cl-&gt;cl_init_array_object != NULL)
++ &amp;&amp; (-1 == do_method_for_all_elements (at, new_object_element, NULL)))
++ {
++ SLang_free_array (at);
++ return NULL;
++ }
++ return at;
++}
++
++SLang_Array_Type *
++SLang_create_array (unsigned char type, int read_only, VOID_STAR data,
++ int *dims, unsigned int num_dims)
++{
++ return SLang_create_array1 (type, read_only, data, dims, num_dims, 0);
++}
++
++int SLang_add_intrinsic_array (char *name,
++ unsigned char type,
++ int read_only,
++ VOID_STAR data,
++ unsigned int num_dims, ...)
++{
++ va_list ap;
++ unsigned int i;
++ int dims[SLARRAY_MAX_DIMS];
++ SLang_Array_Type *at;
++
++ if ((num_dims &gt; SLARRAY_MAX_DIMS)
++ || (name == NULL)
++ || (data == NULL))
++ {
++ SLang_verror (SL_INVALID_PARM, &quot;Unable to create intrinsic array&quot;);
++ return -1;
++ }
++
++ va_start (ap, num_dims);
++ for (i = 0; i &lt; num_dims; i++)
++ dims [i] = va_arg (ap, int);
++ va_end (ap);
++
++ at = SLang_create_array (type, read_only, data, dims, num_dims);
++ if (at == NULL)
++ return -1;
++ at-&gt;flags |= SLARR_DATA_VALUE_IS_INTRINSIC;
++
++ /* Note: The variable that refers to the intrinsic array is regarded as
++ * read-only. That way, Array_Name = another_array; will fail.
++ */
++ if (-1 == SLadd_intrinsic_variable (name, (VOID_STAR) at, SLANG_ARRAY_TYPE, 1))
++ {
++ SLang_free_array (at);
++ return -1;
++ }
++ return 0;
++}
++
++static int pop_array_indices (int *dims, unsigned int num_dims)
++{
++ unsigned int n;
++ int i;
++
++ if (num_dims &gt; SLARRAY_MAX_DIMS)
++ {
++ SLang_verror (SL_INVALID_PARM, &quot;Array size not supported&quot;);
++ return -1;
++ }
++
++ n = num_dims;
++ while (n != 0)
++ {
++ n--;
++ if (-1 == SLang_pop_integer (&amp;i))
++ return -1;
++
++ dims[n] = i;
++ }
++
++ return 0;
++}
++
++int SLang_push_array (SLang_Array_Type *at, int free_flag)
++{
++ if (at == NULL)
++ return SLang_push_null ();
++
++ at-&gt;num_refs += 1;
++
++ if (0 == SLclass_push_ptr_obj (SLANG_ARRAY_TYPE, (VOID_STAR) at))
++ {
++ if (free_flag)
++ SLang_free_array (at);
++ return 0;
++ }
++
++ at-&gt;num_refs -= 1;
++
++ if (free_flag) SLang_free_array (at);
++ return -1;
++}
++
++/* This function gets called via expressions such as Double_Type[10, 20];
++ */
++static int push_create_new_array (void)
++{
++ unsigned int num_dims;
++ SLang_Array_Type *at;
++ unsigned char type;
++ int dims [SLARRAY_MAX_DIMS];
++ int (*anew) (unsigned char, unsigned int);
++
++ num_dims = (SLang_Num_Function_Args - 1);
++
++ if (-1 == _SLang_pop_datatype (&amp;type))
++ return -1;
++
++ anew = (_SLclass_get_class (type))-&gt;cl_anew;
++ if (anew != NULL)
++ return (*anew) (type, num_dims);
++
++ if (-1 == pop_array_indices (dims, num_dims))
++ return -1;
++
++ if (NULL == (at = SLang_create_array (type, 0, NULL, dims, num_dims)))
++ return -1;
++
++ return SLang_push_array (at, 1);
++}
++
++static int push_element_at_addr (SLang_Array_Type *at,
++ VOID_STAR data, int allow_null)
++{
++ SLang_Class_Type *cl;
++
++ cl = at-&gt;cl;
++ if ((at-&gt;flags &amp; SLARR_DATA_VALUE_IS_POINTER)
++ &amp;&amp; (*(VOID_STAR *) data == NULL))
++ {
++ if (allow_null)
++ return SLang_push_null ();
++
++ SLang_verror (SL_VARIABLE_UNINITIALIZED,
++ &quot;%s array has unitialized element&quot;, cl-&gt;cl_name);
++ return -1;
++ }
++
++ return (*cl-&gt;cl_apush)(at-&gt;data_type, data);
++}
++
++static int coerse_array_to_linear (SLang_Array_Type *at)
++{
++ SLarray_Range_Array_Type *range;
++ int *data;
++ int xmin, dx;
++ unsigned int i, imax;
++
++ /* FIXME: Priority = low. This assumes that if an array is not linear, then
++ * it is a range.
++ */
++ if (0 == (at-&gt;flags &amp; SLARR_DATA_VALUE_IS_RANGE))
++ return 0;
++
++ range = (SLarray_Range_Array_Type *) at-&gt;data;
++ xmin = range-&gt;first_index;
++ dx = range-&gt;delta;
++
++ imax = at-&gt;num_elements;
++ data = (int *) SLmalloc ((imax + 1) * sizeof (int));
++ if (data == NULL)
++ return -1;
++
++ for (i = 0; i &lt; imax; i++)
++ {
++ data [i] = xmin;
++ xmin += dx;
++ }
++
++ SLfree ((char *) range);
++ at-&gt;data = (VOID_STAR) data;
++ at-&gt;flags &amp;= ~SLARR_DATA_VALUE_IS_RANGE;
++ at-&gt;index_fun = linear_get_data_addr;
++ return 0;
++}
++
++static void
++free_index_objects (SLang_Object_Type *index_objs, unsigned int num_indices)
++{
++ unsigned int i;
++ SLang_Object_Type *obj;
++
++ for (i = 0; i &lt; num_indices; i++)
++ {
++ obj = index_objs + i;
++ if (obj-&gt;data_type != 0)
++ SLang_free_object (obj);
++ }
++}
++
++static int
++pop_indices (SLang_Object_Type *index_objs, unsigned int num_indices,
++ int *is_index_array)
++{
++ unsigned int i;
++
++ SLMEMSET((char *) index_objs, 0, num_indices * sizeof (SLang_Object_Type));
++
++ *is_index_array = 0;
++
++ if (num_indices &gt;= SLARRAY_MAX_DIMS)
++ {
++ SLang_verror (SL_INVALID_PARM, &quot;too many indices for array&quot;);
++ return -1;
++ }
++
++ i = num_indices;
++ while (i != 0)
++ {
++ SLang_Object_Type *obj;
++
++ i--;
++ obj = index_objs + i;
++ if (-1 == _SLang_pop_object_of_type (SLANG_INT_TYPE, obj, 1))
++ goto return_error;
++
++ if (obj-&gt;data_type == SLANG_ARRAY_TYPE)
++ {
++ SLang_Array_Type *at = obj-&gt;v.array_val;
++
++ if (at-&gt;num_dims == 1)
++ {
++ if ((num_indices == 1)
++ &amp;&amp; (0 == (at-&gt;flags &amp; SLARR_DATA_VALUE_IS_RANGE)))
++ *is_index_array = 1;
++ }
++ else
++ {
++ SLang_verror (SL_INVALID_PARM, &quot;expecting a 1-d index array&quot;);
++ goto return_error;
++ }
++ }
++ }
++
++ return 0;
++
++ return_error:
++ free_index_objects (index_objs, num_indices);
++ return -1;
++}
++
++/* Here ind_at is a linear 1-d array of indices */
++static int
++check_index_array_ranges (SLang_Array_Type *at, SLang_Array_Type *ind_at)
++{
++ int *indices, *indices_max;
++ unsigned int num_elements;
++
++ num_elements = at-&gt;num_elements;
++ indices = (int *) ind_at-&gt;data;
++ indices_max = indices + ind_at-&gt;num_elements;
++
++ while (indices &lt; indices_max)
++ {
++ unsigned int d;
++
++ d = (unsigned int) *indices++;
++ if (d &gt;= num_elements)
++ {
++ SLang_verror (SL_INVALID_PARM,
++ &quot;index-array is out of range&quot;);
++ return -1;
++ }
++ }
++ return 0;
++}
++
++static int
++transfer_n_elements (SLang_Array_Type *at, VOID_STAR dest_data, VOID_STAR src_data,
++ unsigned int sizeof_type, unsigned int n, int is_ptr)
++{
++ unsigned char data_type;
++ SLang_Class_Type *cl;
++
++ if (is_ptr == 0)
++ {
++ SLMEMCPY ((char *) dest_data, (char *)src_data, n * sizeof_type);
++ return 0;
++ }
++
++ data_type = at-&gt;data_type;
++ cl = at-&gt;cl;
++
++ while (n != 0)
++ {
++ if (*(VOID_STAR *)dest_data != NULL)
++ {
++ (*cl-&gt;cl_destroy) (data_type, dest_data);
++ *(VOID_STAR *) dest_data = NULL;
++ }
++
++ if (*(VOID_STAR *) src_data == NULL)
++ *(VOID_STAR *) dest_data = NULL;
++ else
++ {
++ if (-1 == (*cl-&gt;cl_acopy) (data_type, src_data, dest_data))
++ /* No need to destroy anything */
++ return -1;
++ }
++
++ src_data = (VOID_STAR) ((char *)src_data + sizeof_type);
++ dest_data = (VOID_STAR) ((char *)dest_data + sizeof_type);
++
++ n--;
++ }
++
++ return 0;
++}
++
++int
++_SLarray_aget_transfer_elem (SLang_Array_Type *at, int *indices,
++ VOID_STAR new_data, unsigned int sizeof_type, int is_ptr)
++{
++ VOID_STAR at_data;
++
++ /* Since 1 element is being transferred, there is not need to coerse
++ * the array to linear.
++ */
++ if (NULL == (at_data = get_data_addr (at, indices)))
++ return -1;
++
++ return transfer_n_elements (at, new_data, at_data, sizeof_type, 1, is_ptr);
++}
++
++/* Here the ind_at index-array is a 1-d array of indices. This function
++ * creates a 1-d array of made up of values of 'at' at the locations
++ * specified by the indices. The result is pushed.
++ */
++static int
++aget_from_index_array (SLang_Array_Type *at,
++ SLang_Array_Type *ind_at)
++{
++ SLang_Array_Type *new_at;
++ int *indices, *indices_max;
++ unsigned char *new_data, *src_data;
++ unsigned int sizeof_type;
++ int is_ptr;
++
++ if (-1 == coerse_array_to_linear (at))
++ return -1;
++
++ if (-1 == coerse_array_to_linear (ind_at))
++ return -1;
++
++ if (-1 == check_index_array_ranges (at, ind_at))
++ return -1;
++
++ if (NULL == (new_at = SLang_create_array (at-&gt;data_type, 0, NULL, ind_at-&gt;dims, 1)))
++ return -1;
++
++ /* Since the index array is linear, I can address it directly */
++ indices = (int *) ind_at-&gt;data;
++ indices_max = indices + ind_at-&gt;num_elements;
++
++ src_data = (unsigned char *) at-&gt;data;
++ new_data = (unsigned char *) new_at-&gt;data;
++ sizeof_type = new_at-&gt;sizeof_type;
++ is_ptr = (new_at-&gt;flags &amp; SLARR_DATA_VALUE_IS_POINTER);
++
++ while (indices &lt; indices_max)
++ {
++ unsigned int offset;
++
++ offset = sizeof_type * (unsigned int)*indices;
++ if (-1 == transfer_n_elements (at, (VOID_STAR) new_data,
++ (VOID_STAR) (src_data + offset),
++ sizeof_type, 1, is_ptr))
++ {
++ SLang_free_array (new_at);
++ return -1;
++ }
++
++ new_data += sizeof_type;
++ indices++;
++ }
++
++ return SLang_push_array (new_at, 1);
++}
++
++/* This is extremely ugly. It is due to the fact that the index_objects
++ * may contain ranges. This is a utility function for the aget/aput
++ * routines
++ */
++static int
++convert_nasty_index_objs (SLang_Array_Type *at,
++ SLang_Object_Type *index_objs,
++ unsigned int num_indices,
++ int **index_data,
++ int *range_buf, int *range_delta_buf,
++ int *max_dims,
++ unsigned int *num_elements,
++ int *is_array, int is_dim_array[SLARRAY_MAX_DIMS])
++{
++ unsigned int i, total_num_elements;
++ SLang_Array_Type *ind_at;
++
++ if (num_indices != at-&gt;num_dims)
++ {
++ SLang_verror (SL_INVALID_PARM, &quot;Array requires %u indices&quot;, at-&gt;num_dims);
++ return -1;
++ }
++
++ *is_array = 0;
++ total_num_elements = 1;
++ for (i = 0; i &lt; num_indices; i++)
++ {
++ int max_index, min_index;
++ SLang_Object_Type *obj;
++ int at_dims_i;
++
++ at_dims_i = at-&gt;dims[i];
++ obj = index_objs + i;
++ range_delta_buf [i] = 0;
++
++ if (obj-&gt;data_type == SLANG_INT_TYPE)
++ {
++ range_buf [i] = min_index = max_index = obj-&gt;v.int_val;
++ max_dims [i] = 1;
++ index_data[i] = range_buf + i;
++ is_dim_array[i] = 0;
++ }
++ else
++ {
++ *is_array = 1;
++ is_dim_array[i] = 1;
++ ind_at = obj-&gt;v.array_val;
++
++ if (ind_at-&gt;flags &amp; SLARR_DATA_VALUE_IS_RANGE)
++ {
++ SLarray_Range_Array_Type *r;
++ int delta;
++ int first_index, last_index;
++
++ r = (SLarray_Range_Array_Type *) ind_at-&gt;data;
++
++ /* In an array indexing context, range arrays have different
++ * semantics. Consider a[[0:10]]. Clearly this means elements
++ * 0-10 of a. But what does a[[0:-1]] mean? By itself,
++ * [0:-1] is a null matrix []. But, it is useful in an
++ * indexing context to allow -1 to refer to the last element
++ * of the array. Similarly, [-3:-1] refers to the last 3
++ * elements.
++ *
++ * However, [-1:-3] does not refer to any of the elements.
++ */
++ if ((first_index = r-&gt;first_index) &lt; 0)
++ {
++ if (at_dims_i != 0)
++ first_index = (at_dims_i + first_index) % at_dims_i;
++ }
++
++ if ((last_index = r-&gt;last_index) &lt; 0)
++ {
++ if (at_dims_i != 0)
++ last_index = (at_dims_i + last_index) % at_dims_i;
++ }
++
++ delta = r-&gt;delta;
++
++ range_delta_buf [i] = delta;
++ range_buf[i] = first_index;
++
++ if (delta &gt; 0)
++ {
++ if (first_index &gt; last_index)
++ max_dims[i] = min_index = max_index = 0;
++ else
++ {
++ max_index = min_index = first_index;
++ while (max_index + delta &lt;= last_index)
++ max_index += delta;
++ max_dims [i] = 1 + (max_index - min_index) / delta;
++ }
++ }
++ else
++ {
++ if (first_index &lt; last_index)
++ max_dims[i] = min_index = max_index = 0;
++ else
++ {
++ min_index = max_index = first_index;
++ while (min_index + delta &gt;= last_index)
++ min_index += delta;
++ max_dims [i] = 1 + (max_index - min_index) / (-delta);
++ }
++ }
++ }
++ else
++ {
++ int *tmp, *tmp_max;
++
++ if (0 == (max_dims[i] = ind_at-&gt;num_elements))
++ {
++ total_num_elements = 0;
++ break;
++ }
++
++ tmp = (int *) ind_at-&gt;data;
++ tmp_max = tmp + ind_at-&gt;num_elements;
++ index_data [i] = tmp;
++
++ min_index = max_index = *tmp;
++ while (tmp &lt; tmp_max)
++ {
++ if (max_index &gt; *tmp)
++ max_index = *tmp;
++ if (min_index &lt; *tmp)
++ min_index = *tmp;
++
++ tmp++;
++ }
++ }
++ }
++
++ if ((at_dims_i == 0) &amp;&amp; (max_dims[i] == 0))
++ {
++ total_num_elements = 0;
++ continue;
++ }
++
++ if (max_index &lt; 0)
++ max_index += at_dims_i;
++ if (min_index &lt; 0)
++ min_index += at_dims_i;
++
++ if ((min_index &lt; 0) || (min_index &gt;= at_dims_i)
++ || (max_index &lt; 0) || (max_index &gt;= at_dims_i))
++ {
++ SLang_verror (SL_INVALID_PARM, &quot;Array index %u ([%d:%d]) out of allowed range [0-&gt;%d]&quot;,
++ i, min_index, max_index, at_dims_i);
++ return -1;
++ }
++
++ total_num_elements = total_num_elements * max_dims[i];
++ }
++
++ *num_elements = total_num_elements;
++ return 0;
++}
++
++/* This routine pushes a 1-d vector of values from 'at' indexed by
++ * the objects 'index_objs'. These objects can either be integers or
++ * 1-d integer arrays. The fact that the 1-d arrays can be ranges
++ * makes this look ugly.
++ */
++static int
++aget_from_indices (SLang_Array_Type *at,
++ SLang_Object_Type *index_objs, unsigned int num_indices)
++{
++ int *index_data [SLARRAY_MAX_DIMS];
++ int range_buf [SLARRAY_MAX_DIMS];
++ int range_delta_buf [SLARRAY_MAX_DIMS];
++ int max_dims [SLARRAY_MAX_DIMS];
++ unsigned int i, num_elements;
++ SLang_Array_Type *new_at;
++ int map_indices[SLARRAY_MAX_DIMS];
++ int indices [SLARRAY_MAX_DIMS];
++ unsigned int sizeof_type;
++ int is_ptr, ret, is_array;
++ char *new_data;
++ SLang_Class_Type *cl;
++ int is_dim_array[SLARRAY_MAX_DIMS];
++
++ if (-1 == convert_nasty_index_objs (at, index_objs, num_indices,
++ index_data, range_buf, range_delta_buf,
++ max_dims, &amp;num_elements, &amp;is_array,
++ is_dim_array))
++ return -1;
++
++ is_ptr = (at-&gt;flags &amp; SLARR_DATA_VALUE_IS_POINTER);
++ sizeof_type = at-&gt;sizeof_type;
++
++ cl = _SLclass_get_class (at-&gt;data_type);
++
++ if ((is_array == 0) &amp;&amp; (num_elements == 1))
++ {
++ new_data = (char *)cl-&gt;cl_transfer_buf;
++ memset (new_data, 0, sizeof_type);
++ new_at = NULL;
++ }
++ else
++ {
++ int i_num_elements = (int)num_elements;
++
++ new_at = SLang_create_array (at-&gt;data_type, 0, NULL, &amp;i_num_elements, 1);
++ if (NULL == new_at)
++ return -1;
++ if (num_elements == 0)
++ return SLang_push_array (new_at, 1);
++
++ new_data = (char *)new_at-&gt;data;
++ }
++
++ SLMEMSET((char *) map_indices, 0, sizeof(map_indices));
++ do
++ {
++ for (i = 0; i &lt; num_indices; i++)
++ {
++ int j;
++
++ j = map_indices[i];
++
++ if (0 != range_delta_buf[i])
++ indices[i] = range_buf[i] + j * range_delta_buf[i];
++ else
++ indices[i] = index_data [i][j];
++ }
++
++ if (-1 == _SLarray_aget_transfer_elem (at, indices, (VOID_STAR)new_data, sizeof_type, is_ptr))
++ {
++ SLang_free_array (new_at);
++ return -1;
++ }
++ new_data += sizeof_type;
++ }
++ while (0 == next_index (map_indices, max_dims, num_indices));
++
++ if (new_at != NULL)
++ {
++ int num_dims = 0;
++ /* Fixup dimensions on array */
++ for (i = 0; i &lt; num_indices; i++)
++ {
++ if (is_dim_array[i]) /* was: (max_dims[i] &gt; 1) */
++ {
++ new_at-&gt;dims[num_dims] = max_dims[i];
++ num_dims++;
++ }
++ }
++
++ if (num_dims != 0) new_at-&gt;num_dims = num_dims;
++ return SLang_push_array (new_at, 1);
++ }
++
++ /* Here new_data is a whole new copy, so free it after the push */
++ new_data -= sizeof_type;
++ if (is_ptr &amp;&amp; (*(VOID_STAR *)new_data == NULL))
++ ret = SLang_push_null ();
++ else
++ {
++ ret = (*cl-&gt;cl_apush) (at-&gt;data_type, (VOID_STAR)new_data);
++ (*cl-&gt;cl_adestroy) (at-&gt;data_type, (VOID_STAR)new_data);
++ }
++
++ return ret;
++}
++
++static int push_string_as_array (unsigned char *s, unsigned int len)
++{
++ int ilen;
++ SLang_Array_Type *at;
++
++ ilen = (int) len;
++
++ at = SLang_create_array (SLANG_UCHAR_TYPE, 0, NULL, &amp;ilen, 1);
++ if (at == NULL)
++ return -1;
++
++ memcpy ((char *)at-&gt;data, (char *)s, len);
++ return SLang_push_array (at, 1);
++}
++
++static int pop_array_as_string (char **sp)
++{
++ SLang_Array_Type *at;
++ int ret;
++
++ *sp = NULL;
++
++ if (-1 == SLang_pop_array_of_type (&amp;at, SLANG_UCHAR_TYPE))
++ return -1;
++
++ ret = 0;
++
++ if (NULL == (*sp = SLang_create_nslstring ((char *) at-&gt;data, at-&gt;num_elements)))
++ ret = -1;
++
++ SLang_free_array (at);
++ return ret;
++}
++
++static int pop_array_as_bstring (SLang_BString_Type **bs)
++{
++ SLang_Array_Type *at;
++ int ret;
++
++ *bs = NULL;
++
++ if (-1 == SLang_pop_array_of_type (&amp;at, SLANG_UCHAR_TYPE))
++ return -1;
++
++ ret = 0;
++
++ if (NULL == (*bs = SLbstring_create ((unsigned char *) at-&gt;data, at-&gt;num_elements)))
++ ret = -1;
++
++ SLang_free_array (at);
++ return ret;
++}
++
++static int aget_from_array (unsigned int num_indices)
++{
++ SLang_Array_Type *at;
++ SLang_Object_Type index_objs [SLARRAY_MAX_DIMS];
++ int ret;
++ int is_index_array;
++ unsigned int i;
++
++ if (num_indices &gt; SLARRAY_MAX_DIMS)
++ {
++ SLang_verror (SL_INVALID_PARM, &quot;Number of dims must be less than %d&quot;, SLARRAY_MAX_DIMS);
++ return -1;
++ }
++
++ if (-1 == pop_array (&amp;at, 1))
++ return -1;
++
++ if (-1 == pop_indices (index_objs, num_indices, &amp;is_index_array))
++ {
++ SLang_free_array (at);
++ return -1;
++ }
++
++ if (is_index_array == 0)
++ ret = aget_from_indices (at, index_objs, num_indices);
++ else
++ ret = aget_from_index_array (at, index_objs[0].v.array_val);
++
++ SLang_free_array (at);
++ for (i = 0; i &lt; num_indices; i++)
++ SLang_free_object (index_objs + i);
++
++ return ret;
++}
++
++static int push_string_element (unsigned char type, unsigned char *s, unsigned int len)
++{
++ int i;
++
++ if (SLang_peek_at_stack () == SLANG_ARRAY_TYPE)
++ {
++ char *str;
++
++ /* The indices are array values. So, do this: */
++ if (-1 == push_string_as_array (s, len))
++ return -1;
++
++ if (-1 == aget_from_array (1))
++ return -1;
++
++ if (type == SLANG_BSTRING_TYPE)
++ {
++ SLang_BString_Type *bs;
++ int ret;
++
++ if (-1 == pop_array_as_bstring (&amp;bs))
++ return -1;
++
++ ret = SLang_push_bstring (bs);
++ SLbstring_free (bs);
++ return ret;
++ }
++
++ if (-1 == pop_array_as_string (&amp;str))
++ return -1;
++ return _SLang_push_slstring (str); /* frees s upon error */
++ }
++
++ if (-1 == SLang_pop_integer (&amp;i))
++ return -1;
++
++ if (i &lt; 0) i = i + (int)len;
++ if ((unsigned int) i &gt; len)
++ i = len; /* get \0 character --- bstrings include it as well */
++
++ i = s[(unsigned int) i];
++
++ return SLang_push_integer (i);
++}
++
++/* ARRAY[i, j, k] generates code: __args i j ...k ARRAY __aput/__aget
++ * Here i, j, ... k may be a mixture of integers and 1-d arrays, or
++ * a single 2-d array of indices. The 2-d index array is generated by the
++ * 'where' function.
++ *
++ * If ARRAY is of type DataType, then this function will create an array of
++ * the appropriate type. In that case, the indices i, j, ..., k must be
++ * integers.
++ */
++int _SLarray_aget (void)
++{
++ unsigned int num_indices;
++ int type;
++ int (*aget_fun) (unsigned char, unsigned int);
++
++ num_indices = (SLang_Num_Function_Args - 1);
++
++ type = SLang_peek_at_stack ();
++ switch (type)
++ {
++ case -1:
++ return -1; /* stack underflow */
++
++ case SLANG_DATATYPE_TYPE:
++ return push_create_new_array ();
++
++ case SLANG_BSTRING_TYPE:
++ if (1 == num_indices)
++ {
++ SLang_BString_Type *bs;
++ int ret;
++ unsigned int len;
++ unsigned char *s;
++
++ if (-1 == SLang_pop_bstring (&amp;bs))
++ return -1;
++
++ if (NULL == (s = SLbstring_get_pointer (bs, &amp;len)))
++ ret = -1;
++ else
++ ret = push_string_element (type, s, len);
++
++ SLbstring_free (bs);
++ return ret;
++ }
++ break;
++
++ case SLANG_STRING_TYPE:
++ if (1 == num_indices)
++ {
++ char *s;
++ int ret;
++
++ if (-1 == SLang_pop_slstring (&amp;s))
++ return -1;
++
++ ret = push_string_element (type, (unsigned char *)s, strlen (s));
++ SLang_free_slstring (s);
++ return ret;
++ }
++ break;
++
++ case SLANG_ARRAY_TYPE:
++ break;
++
++ default:
++ aget_fun = _SLclass_get_class (type)-&gt;cl_aget;
++ if (NULL != aget_fun)
++ return (*aget_fun) (type, num_indices);
++ }
++
++ return aget_from_array (num_indices);
++}
++
++int
++_SLarray_aput_transfer_elem (SLang_Array_Type *at, int *indices,
++ VOID_STAR data_to_put, unsigned int sizeof_type, int is_ptr)
++{
++ VOID_STAR at_data;
++
++ /* Since 1 element is being transferred, there is no need to coerse
++ * the array to linear.
++ */
++ if (NULL == (at_data = get_data_addr (at, indices)))
++ return -1;
++
++ return transfer_n_elements (at, at_data, data_to_put, sizeof_type, 1, is_ptr);
++}
++
++static int
++aput_get_array_to_put (SLang_Class_Type *cl, unsigned int num_elements, int allow_array,
++ SLang_Array_Type **at_ptr, char **data_to_put, unsigned int *data_increment)
++{
++ unsigned char data_type;
++ SLang_Array_Type *at;
++
++ *at_ptr = NULL;
++
++ data_type = cl-&gt;cl_data_type;
++ if (-1 == SLclass_typecast (data_type, 1, allow_array))
++ return -1;
++
++ if ((data_type != SLANG_ARRAY_TYPE)
++ &amp;&amp; (data_type != SLANG_ANY_TYPE)
++ &amp;&amp; (SLANG_ARRAY_TYPE == SLang_peek_at_stack ()))
++ {
++ if (-1 == SLang_pop_array (&amp;at, 0))
++ return -1;
++
++ if ((at-&gt;num_elements != num_elements)
++#if 0
++ || (at-&gt;num_dims != 1)
++#endif
++ )
++ {
++ SLang_verror (SL_TYPE_MISMATCH, &quot;Array size is inappropriate for use with index-array&quot;);
++ SLang_free_array (at);
++ return -1;
++ }
++
++ *data_to_put = (char *) at-&gt;data;
++ *data_increment = at-&gt;sizeof_type;
++ *at_ptr = at;
++ return 0;
++ }
++
++ *data_increment = 0;
++ *data_to_put = (char *) cl-&gt;cl_transfer_buf;
++
++ if (-1 == (*cl-&gt;cl_apop)(data_type, (VOID_STAR) *data_to_put))
++ return -1;
++
++ return 0;
++}
++
++static int
++aput_from_indices (SLang_Array_Type *at,
++ SLang_Object_Type *index_objs, unsigned int num_indices)
++{
++ int *index_data [SLARRAY_MAX_DIMS];
++ int range_buf [SLARRAY_MAX_DIMS];
++ int range_delta_buf [SLARRAY_MAX_DIMS];
++ int max_dims [SLARRAY_MAX_DIMS];
++ unsigned int i, num_elements;
++ SLang_Array_Type *bt;
++ int map_indices[SLARRAY_MAX_DIMS];
++ int indices [SLARRAY_MAX_DIMS];
++ unsigned int sizeof_type;
++ int is_ptr, is_array, ret;
++ char *data_to_put;
++ unsigned int data_increment;
++ SLang_Class_Type *cl;
++ int is_dim_array [SLARRAY_MAX_DIMS];
++
++ if (-1 == convert_nasty_index_objs (at, index_objs, num_indices,
++ index_data, range_buf, range_delta_buf,
++ max_dims, &amp;num_elements, &amp;is_array,
++ is_dim_array))
++ return -1;
++
++ cl = at-&gt;cl;
++
++ if (-1 == aput_get_array_to_put (cl, num_elements, is_array,
++ &amp;bt, &amp;data_to_put, &amp;data_increment))
++ return -1;
++
++ sizeof_type = at-&gt;sizeof_type;
++ is_ptr = (at-&gt;flags &amp; SLARR_DATA_VALUE_IS_POINTER);
++
++ ret = -1;
++
++ SLMEMSET((char *) map_indices, 0, sizeof(map_indices));
++ if (num_elements) do
++ {
++ for (i = 0; i &lt; num_indices; i++)
++ {
++ int j;
++
++ j = map_indices[i];
++
++ if (0 != range_delta_buf[i])
++ indices[i] = range_buf[i] + j * range_delta_buf[i];
++ else
++ indices[i] = index_data [i][j];
++ }
++
++ if (-1 == _SLarray_aput_transfer_elem (at, indices, (VOID_STAR)data_to_put, sizeof_type, is_ptr))
++ goto return_error;
++
++ data_to_put += data_increment;
++ }
++ while (0 == next_index (map_indices, max_dims, num_indices));
++
++ ret = 0;
++
++ /* drop */
++
++ return_error:
++ if (bt == NULL)
++ {
++ if (is_ptr)
++ (*cl-&gt;cl_destroy) (cl-&gt;cl_data_type, (VOID_STAR) data_to_put);
++ }
++ else SLang_free_array (bt);
++
++ return ret;
++}
++
++static int
++aput_from_index_array (SLang_Array_Type *at, SLang_Array_Type *ind_at)
++{
++ int *indices, *indices_max;
++ unsigned int sizeof_type;
++ char *data_to_put, *dest_data;
++ unsigned int data_increment;
++ int is_ptr;
++ SLang_Array_Type *bt;
++ SLang_Class_Type *cl;
++ int ret;
++
++ if (-1 == coerse_array_to_linear (at))
++ return -1;
++
++ if (-1 == coerse_array_to_linear (ind_at))
++ return -1;
++
++ if (-1 == check_index_array_ranges (at, ind_at))
++ return -1;
++
++ sizeof_type = at-&gt;sizeof_type;
++
++ cl = at-&gt;cl;
++
++ /* Note that if bt is returned as non NULL, then the array is a linear
++ * one.
++ */
++ if (-1 == aput_get_array_to_put (cl, ind_at-&gt;num_elements, 1,
++ &amp;bt, &amp;data_to_put, &amp;data_increment))
++ return -1;
++
++ /* Since the index array is linear, I can address it directly */
++ indices = (int *) ind_at-&gt;data;
++ indices_max = indices + ind_at-&gt;num_elements;
++
++ is_ptr = (at-&gt;flags &amp; SLARR_DATA_VALUE_IS_POINTER);
++ dest_data = (char *) at-&gt;data;
++
++ ret = -1;
++ while (indices &lt; indices_max)
++ {
++ unsigned int offset;
++
++ offset = sizeof_type * (unsigned int)*indices;
++
++ if (-1 == transfer_n_elements (at, (VOID_STAR) (dest_data + offset),
++ (VOID_STAR) data_to_put, sizeof_type, 1,
++ is_ptr))
++ goto return_error;
++
++ indices++;
++ data_to_put += data_increment;
++ }
++
++ ret = 0;
++ /* Drop */
++
++ return_error:
++
++ if (bt == NULL)
++ {
++ if (is_ptr)
++ (*cl-&gt;cl_destroy) (cl-&gt;cl_data_type, (VOID_STAR)data_to_put);
++ }
++ else SLang_free_array (bt);
++
++ return ret;
++}
++
++/* ARRAY[i, j, k] = generates code: __args i j k ARRAY __aput
++ */
++int _SLarray_aput (void)
++{
++ unsigned int num_indices;
++ SLang_Array_Type *at;
++ SLang_Object_Type index_objs [SLARRAY_MAX_DIMS];
++ int ret;
++ int is_index_array;
++ int (*aput_fun) (unsigned char, unsigned int);
++ int type;
++
++ ret = -1;
++ num_indices = (SLang_Num_Function_Args - 1);
++
++ type = SLang_peek_at_stack ();
++ switch (type)
++ {
++ case -1:
++ return -1;
++
++ case SLANG_ARRAY_TYPE:
++ break;
++
++ default:
++ if (NULL != (aput_fun = _SLclass_get_class (type)-&gt;cl_aput))
++ return (*aput_fun) (type, num_indices);
++ break;
++ }
++
++ if (-1 == SLang_pop_array (&amp;at, 0))
++ return -1;
++
++ if (at-&gt;flags &amp; SLARR_DATA_VALUE_IS_READ_ONLY)
++ {
++ SLang_verror (SL_READONLY_ERROR, &quot;%s Array is read-only&quot;,
++ SLclass_get_datatype_name (at-&gt;data_type));
++ SLang_free_array (at);
++ return -1;
++ }
++
++ if (-1 == pop_indices (index_objs, num_indices, &amp;is_index_array))
++ {
++ SLang_free_array (at);
++ return -1;
++ }
++
++ if (is_index_array == 0)
++ ret = aput_from_indices (at, index_objs, num_indices);
++ else
++ ret = aput_from_index_array (at, index_objs[0].v.array_val);
++
++ SLang_free_array (at);
++ free_index_objects (index_objs, num_indices);
++ return ret;
++}
++
++/* This is for 1-d matrices only. It is used by the sort function */
++static int push_element_at_index (SLang_Array_Type *at, int indx)
++{
++ VOID_STAR data;
++
++ if (NULL == (data = get_data_addr (at, &amp;indx)))
++ return -1;
++
++ return push_element_at_addr (at, (VOID_STAR) data, 1);
++}
++
++static SLang_Name_Type *Sort_Function;
++static SLang_Array_Type *Sort_Array;
++
++static int sort_cmp_fun (int *a, int *b)
++{
++ int cmp;
++
++ if (SLang_Error
++ || (-1 == push_element_at_index (Sort_Array, *a))
++ || (-1 == push_element_at_index (Sort_Array, *b))
++ || (-1 == SLexecute_function (Sort_Function))
++ || (-1 == SLang_pop_integer (&amp;cmp)))
++ {
++ /* DO not allow qsort to loop forever. Return something meaningful */
++ if (*a &gt; *b) return 1;
++ if (*a &lt; *b) return -1;
++ return 0;
++ }
++
++ return cmp;
++}
++
++static int builtin_sort_cmp_fun (int *a, int *b)
++{
++ VOID_STAR a_data;
++ VOID_STAR b_data;
++ SLang_Class_Type *cl;
++
++ cl = Sort_Array-&gt;cl;
++
++ if ((SLang_Error == 0)
++ &amp;&amp; (NULL != (a_data = get_data_addr (Sort_Array, a)))
++ &amp;&amp; (NULL != (b_data = get_data_addr (Sort_Array, b))))
++ {
++ int cmp;
++
++ if ((Sort_Array-&gt;flags &amp; SLARR_DATA_VALUE_IS_POINTER)
++ &amp;&amp; ((*(VOID_STAR *) a_data == NULL) || (*(VOID_STAR *) a_data == NULL)))
++ {
++ SLang_verror (SL_VARIABLE_UNINITIALIZED,
++ &quot;%s array has unitialized element&quot;, cl-&gt;cl_name);
++ }
++ else if (0 == (*cl-&gt;cl_cmp)(Sort_Array-&gt;data_type, a_data, b_data, &amp;cmp))
++ return cmp;
++ }
++
++
++ if (*a &gt; *b) return 1;
++ if (*a == *b) return 0;
++ return -1;
++}
++
++static void sort_array_internal (SLang_Array_Type *at_str,
++ SLang_Name_Type *entry,
++ int (*sort_fun)(int *, int *))
++{
++ SLang_Array_Type *ind_at;
++ /* This is a silly hack to make up for braindead compilers and the lack of
++ * uniformity in prototypes for qsort.
++ */
++ void (*qsort_fun) (char *, unsigned int, int, int (*)(int *, int *));
++ int *indx;
++ int i, n;
++ int dims[1];
++
++ if (Sort_Array != NULL)
++ {
++ SLang_verror (SL_NOT_IMPLEMENTED, &quot;array_sort is not recursive&quot;);
++ return;
++ }
++
++ n = at_str-&gt;num_elements;
++
++ if (at_str-&gt;num_dims != 1)
++ {
++ SLang_verror (SL_INVALID_PARM, &quot;sort is restricted to 1 dim arrays&quot;);
++ return;
++ }
++
++ dims [0] = n;
++
++ if (NULL == (ind_at = SLang_create_array (SLANG_INT_TYPE, 0, NULL, dims, 1)))
++ return;
++
++ indx = (int *) ind_at-&gt;data;
++ for (i = 0; i &lt; n; i++) indx[i] = i;
++
++ if (n &gt; 1)
++ {
++ qsort_fun = (void (*)(char *, unsigned int, int, int (*)(int *,
++ int *)))
++ qsort;
++
++ Sort_Array = at_str;
++ Sort_Function = entry;
++ (*qsort_fun) ((char *) indx, n, sizeof (int), sort_fun);
++ }
++
++ Sort_Array = NULL;
++ (void) SLang_push_array (ind_at, 1);
++}
++
++static void sort_array (void)
++{
++ SLang_Name_Type *entry;
++ SLang_Array_Type *at;
++ int (*sort_fun) (int *, int *);
++
++ if (SLang_Num_Function_Args != 1)
++ {
++ sort_fun = sort_cmp_fun;
++
++ if (NULL == (entry = SLang_pop_function ()))
++ return;
++
++ if (-1 == SLang_pop_array (&amp;at, 1))
++ return;
++ }
++ else
++ {
++ sort_fun = builtin_sort_cmp_fun;
++ if (-1 == SLang_pop_array (&amp;at, 1))
++ return;
++ if (at-&gt;cl-&gt;cl_cmp == NULL)
++ {
++ SLang_verror (SL_NOT_IMPLEMENTED,
++ &quot;%s does not have a predefined sorting method&quot;,
++ at-&gt;cl-&gt;cl_name);
++ SLang_free_array (at);
++ return;
++ }
++ entry = NULL;
++ }
++
++ sort_array_internal (at, entry, sort_fun);
++ SLang_free_array (at);
++ SLang_free_function (entry);
++}
++
++static void bstring_to_array (SLang_BString_Type *bs)
++{
++ unsigned char *s;
++ unsigned int len;
++
++ if (NULL == (s = SLbstring_get_pointer (bs, &amp;len)))
++ (void) SLang_push_null ();
++ else
++ (void) push_string_as_array (s, len);
++}
++
++static void array_to_bstring (SLang_Array_Type *at)
++{
++ unsigned int nbytes;
++ SLang_BString_Type *bs;
++
++ nbytes = at-&gt;num_elements * at-&gt;sizeof_type;
++ bs = SLbstring_create ((unsigned char *)at-&gt;data, nbytes);
++ (void) SLang_push_bstring (bs);
++ SLbstring_free (bs);
++}
++
++static void init_char_array (void)
++{
++ SLang_Array_Type *at;
++ char *s;
++ unsigned int n, ndim;
++
++ if (SLang_pop_slstring (&amp;s)) return;
++
++ if (-1 == SLang_pop_array (&amp;at, 0))
++ goto free_and_return;
++
++ if (at-&gt;data_type != SLANG_CHAR_TYPE)
++ {
++ SLang_doerror(&quot;Operation requires character array&quot;);
++ goto free_and_return;
++ }
++
++ n = strlen (s);
++ ndim = at-&gt;num_elements;
++ if (n &gt; ndim)
++ {
++ SLang_doerror(&quot;String too big to init array&quot;);
++ goto free_and_return;
++ }
++
++ strncpy((char *) at-&gt;data, s, ndim);
++ /* drop */
++
++ free_and_return:
++ SLang_free_array (at);
++ SLang_free_slstring (s);
++}
++
++static void array_info (void)
++{
++ SLang_Array_Type *at, *bt;
++ int num_dims;
++
++ if (-1 == pop_array (&amp;at, 1))
++ return;
++
++ num_dims = (int)at-&gt;num_dims;
++
++ if (NULL != (bt = SLang_create_array (SLANG_INT_TYPE, 0, NULL, &amp;num_dims, 1)))
++ {
++ int *bdata;
++ int i;
++ int *a_dims;
++
++ a_dims = at-&gt;dims;
++ bdata = (int *) bt-&gt;data;
++ for (i = 0; i &lt; num_dims; i++) bdata [i] = a_dims [i];
++
++ if (0 == SLang_push_array (bt, 1))
++ {
++ (void) SLang_push_integer ((int) at-&gt;num_dims);
++ (void) _SLang_push_datatype (at-&gt;data_type);
++ }
++ }
++
++ SLang_free_array (at);
++}
++
++static VOID_STAR range_get_data_addr (SLang_Array_Type *at, int *dims)
++{
++ static int value;
++ SLarray_Range_Array_Type *r;
++ int d;
++
++ d = *dims;
++ r = (SLarray_Range_Array_Type *)at-&gt;data;
++
++ if (d &lt; 0)
++ d += at-&gt;dims[0];
++
++ value = r-&gt;first_index + d * r-&gt;delta;
++ return (VOID_STAR) &amp;value;
++}
++
++static SLang_Array_Type *inline_implicit_int_array (int *xminptr, int *xmaxptr, int *dxptr)
++{
++ int delta;
++ SLang_Array_Type *at;
++ int dims, idims;
++ SLarray_Range_Array_Type *data;
++
++ if (dxptr == NULL) delta = 1;
++ else delta = *dxptr;
++
++ if (delta == 0)
++ {
++ SLang_verror (SL_INVALID_PARM, &quot;range-array increment must be non-zero&quot;);
++ return NULL;
++ }
++
++ data = (SLarray_Range_Array_Type *) SLmalloc (sizeof (SLarray_Range_Array_Type));
++ if (data == NULL)
++ return NULL;
++
++ SLMEMSET((char *) data, 0, sizeof (SLarray_Range_Array_Type));
++ data-&gt;delta = delta;
++ dims = 0;
++
++ if (xminptr != NULL)
++ data-&gt;first_index = *xminptr;
++ else
++ data-&gt;first_index = 0;
++
++ if (xmaxptr != NULL)
++ data-&gt;last_index = *xmaxptr;
++ else
++ data-&gt;last_index = -1;
++
++/* if ((xminptr != NULL) &amp;&amp; (xmaxptr != NULL))
++ { */
++ idims = 1 + (data-&gt;last_index - data-&gt;first_index) / delta;
++ if (idims &gt; 0)
++ dims = idims;
++ /* } */
++
++ if (NULL == (at = SLang_create_array (SLANG_INT_TYPE, 0, (VOID_STAR) data, &amp;dims, 1)))
++ return NULL;
++
++ at-&gt;index_fun = range_get_data_addr;
++ at-&gt;flags |= SLARR_DATA_VALUE_IS_RANGE;
++
++ return at;
++}
++
++#if SLANG_HAS_FLOAT
++static SLang_Array_Type *inline_implicit_floating_array (unsigned char type,
++ double *xminptr, double *xmaxptr, double *dxptr)
++{
++ int n, i;
++ SLang_Array_Type *at;
++ int dims;
++ double xmin, xmax, dx;
++
++ if ((xminptr == NULL) || (xmaxptr == NULL))
++ {
++ SLang_verror (SL_INVALID_PARM, &quot;range-array has unknown size&quot;);
++ return NULL;
++ }
++ xmin = *xminptr;
++ xmax = *xmaxptr;
++ if (dxptr == NULL) dx = 1.0;
++ else dx = *dxptr;
++
++ if (dx == 0.0)
++ {
++ SLang_doerror (&quot;range-array increment must be non-zero&quot;);
++ return NULL;
++ }
++
++ /* I have convinced myself that it is better to use semi-open intervals
++ * because of less ambiguities. So, [a:b:c] will represent the set of
++ * values a, a + c, a + 2c ... a + nc
++ * such that a + nc &lt; b. That is, b lies outside the interval.
++ */
++
++ /* Allow for roundoff by adding 0.5 before truncation */
++ n = (int)(1.5 + ((xmax - xmin) / dx));
++ if (n &lt;= 0)
++ n = 0;
++ else
++ {
++ double last = xmin + (n-1) * dx;
++
++ if (dx &gt; 0.0)
++ {
++ if (last &gt;= xmax)
++ n -= 1;
++ }
++ else if (last &lt;= xmax)
++ n -= 1;
++ }
++
++ dims = n;
++ if (NULL == (at = SLang_create_array1 (type, 0, NULL, &amp;dims, 1, 1)))
++ return NULL;
++
++ if (type == SLANG_DOUBLE_TYPE)
++ {
++ double *ptr;
++
++ ptr = (double *) at-&gt;data;
++
++ for (i = 0; i &lt; n; i++)
++ ptr[i] = xmin + i * dx;
++ }
++ else
++ {
++ float *ptr;
++
++ ptr = (float *) at-&gt;data;
++
++ for (i = 0; i &lt; n; i++)
++ ptr[i] = (float) (xmin + i * dx);
++ }
++ return at;
++}
++#endif
++
++/* FIXME: Priority=medium
++ * This needs to be updated to work with all integer types.
++ */
++int _SLarray_inline_implicit_array (void)
++{
++ int int_vals[3];
++#if SLANG_HAS_FLOAT
++ double double_vals[3];
++#endif
++ int has_vals[3];
++ unsigned int i, count;
++ SLang_Array_Type *at;
++ int precedence;
++ unsigned char type;
++ int is_int;
++
++ count = SLang_Num_Function_Args;
++
++ if (count == 2)
++ has_vals [2] = 0;
++ else if (count != 3)
++ {
++ SLang_doerror (&quot;wrong number of arguments to __implicit_inline_array&quot;);
++ return -1;
++ }
++
++#if SLANG_HAS_FLOAT
++ is_int = 1;
++#endif
++
++ type = 0;
++ precedence = 0;
++
++ i = count;
++ while (i--)
++ {
++ int this_type, this_precedence;
++
++ if (-1 == (this_type = SLang_peek_at_stack ()))
++ return -1;
++
++ this_precedence = _SLarith_get_precedence ((unsigned char) this_type);
++ if (precedence &lt; this_precedence)
++ {
++ type = (unsigned char) this_type;
++ precedence = this_precedence;
++ }
++
++ has_vals [i] = 1;
++
++ switch (this_type)
++ {
++ case SLANG_NULL_TYPE:
++ has_vals[i] = 0;
++ (void) SLdo_pop ();
++ break;
++
++#if SLANG_HAS_FLOAT
++ case SLANG_DOUBLE_TYPE:
++ case SLANG_FLOAT_TYPE:
++ if (-1 == SLang_pop_double (double_vals + i, NULL, NULL))
++ return -1;
++ is_int = 0;
++ break;
++#endif
++ default:
++ if (-1 == SLang_pop_integer (int_vals + i))
++ return -1;
++ double_vals[i] = (double) int_vals[i];
++ }
++ }
++
++#if SLANG_HAS_FLOAT
++ if (is_int == 0)
++ at = inline_implicit_floating_array (type,
++ (has_vals[0] ? &amp;double_vals[0] : NULL),
++ (has_vals[1] ? &amp;double_vals[1] : NULL),
++ (has_vals[2] ? &amp;double_vals[2] : NULL));
++ else
++#endif
++ at = inline_implicit_int_array ((has_vals[0] ? &amp;int_vals[0] : NULL),
++ (has_vals[1] ? &amp;int_vals[1] : NULL),
++ (has_vals[2] ? &amp;int_vals[2] : NULL));
++
++ if (at == NULL)
++ return -1;
++
++ return SLang_push_array (at, 1);
++}
++
++int _SLarray_wildcard_array (void)
++{
++ SLang_Array_Type *at;
++
++ if (NULL == (at = inline_implicit_int_array (NULL, NULL, NULL)))
++ return -1;
++
++ return SLang_push_array (at, 1);
++}
++
++static SLang_Array_Type *concat_arrays (unsigned int count)
++{
++ SLang_Array_Type **arrays;
++ SLang_Array_Type *at, *bt;
++ unsigned int i;
++ int num_elements;
++ unsigned char type;
++ char *src_data, *dest_data;
++ int is_ptr;
++ unsigned int sizeof_type;
++ int max_dims, min_dims, max_rows, min_rows;
++
++ arrays = (SLang_Array_Type **)SLmalloc (count * sizeof (SLang_Array_Type *));
++ if (arrays == NULL)
++ {
++ SLdo_pop_n (count);
++ return NULL;
++ }
++ SLMEMSET((char *) arrays, 0, count * sizeof(SLang_Array_Type *));
++
++ at = NULL;
++
++ num_elements = 0;
++ i = count;
++
++ while (i != 0)
++ {
++ i--;
++
++ if (-1 == SLang_pop_array (&amp;bt, 1))
++ goto free_and_return;
++
++ arrays[i] = bt;
++ num_elements += (int)bt-&gt;num_elements;
++ }
++
++ type = arrays[0]-&gt;data_type;
++ max_dims = min_dims = arrays[0]-&gt;num_dims;
++ min_rows = max_rows = arrays[0]-&gt;dims[0];
++
++ for (i = 1; i &lt; count; i++)
++ {
++ SLang_Array_Type *ct;
++ int num;
++
++ bt = arrays[i];
++
++ num = bt-&gt;num_dims;
++ if (num &gt; max_dims) max_dims = num;
++ if (num &lt; min_dims) min_dims = num;
++
++ num = bt-&gt;dims[0];
++ if (num &gt; max_rows) max_rows = num;
++ if (num &lt; min_rows) min_rows = num;
++
++ if (type == bt-&gt;data_type)
++ continue;
++
++ if (1 != _SLarray_typecast (bt-&gt;data_type, (VOID_STAR) &amp;bt, 1,
++ type, (VOID_STAR) &amp;ct, 1))
++ goto free_and_return;
++
++ SLang_free_array (bt);
++ arrays [i] = ct;
++ }
++
++ if (NULL == (at = SLang_create_array (type, 0, NULL, &amp;num_elements, 1)))
++ goto free_and_return;
++
++ is_ptr = (at-&gt;flags &amp; SLARR_DATA_VALUE_IS_POINTER);
++ sizeof_type = at-&gt;sizeof_type;
++ dest_data = (char *) at-&gt;data;
++
++ for (i = 0; i &lt; count; i++)
++ {
++ bt = arrays[i];
++
++ src_data = (char *) bt-&gt;data;
++ num_elements = bt-&gt;num_elements;
++
++ if (-1 == transfer_n_elements (bt, (VOID_STAR)dest_data, (VOID_STAR)src_data, sizeof_type,
++ num_elements, is_ptr))
++ {
++ SLang_free_array (at);
++ at = NULL;
++ goto free_and_return;
++ }
++
++ dest_data += num_elements * sizeof_type;
++ }
++
++ /* If the arrays are all 1-d, and all the same size, then reshape to a
++ * 2-d array. This will allow us to do, e.g.
++ * a = [[1,2], [3,4]]
++ * to specifiy a 2-d.
++ * Someday I will generalize this.
++ */
++ if ((max_dims == min_dims) &amp;&amp; (max_dims == 1) &amp;&amp; (min_rows == max_rows))
++ {
++ at-&gt;num_dims = 2;
++ at-&gt;dims[0] = count;
++ at-&gt;dims[1] = min_rows;
++ }
++
++ free_and_return:
++
++ for (i = 0; i &lt; count; i++)
++ SLang_free_array (arrays[i]);
++ SLfree ((char *) arrays);
++
++ return at;
++}
++
++int _SLarray_inline_array (void)
++{
++ SLang_Object_Type *obj;
++ unsigned char type, this_type;
++ unsigned int count;
++ SLang_Array_Type *at;
++
++ obj = _SLStack_Pointer;
++
++ count = SLang_Num_Function_Args;
++ type = 0;
++
++ while ((count &gt; 0) &amp;&amp; (--obj &gt;= _SLRun_Stack))
++ {
++ this_type = obj-&gt;data_type;
++
++ if (type == 0)
++ type = this_type;
++
++ if ((type == this_type) || (type == SLANG_ARRAY_TYPE))
++ {
++ count--;
++ continue;
++ }
++
++ switch (this_type)
++ {
++ case SLANG_ARRAY_TYPE:
++ type = SLANG_ARRAY_TYPE;
++ break;
++
++ case SLANG_INT_TYPE:
++ switch (type)
++ {
++#if SLANG_HAS_FLOAT
++ case SLANG_DOUBLE_TYPE:
++ break;
++#endif
++#if SLANG_HAS_COMPLEX
++ case SLANG_COMPLEX_TYPE:
++ break;
++#endif
++ default:
++ goto type_mismatch;
++ }
++ break;
++#if SLANG_HAS_FLOAT
++ case SLANG_DOUBLE_TYPE:
++ switch (type)
++ {
++ case SLANG_INT_TYPE:
++ type = SLANG_DOUBLE_TYPE;
++ break;
++# if SLANG_HAS_COMPLEX
++ case SLANG_COMPLEX_TYPE:
++ break;
++# endif
++ default:
++ goto type_mismatch;
++ }
++ break;
++#endif
++#if SLANG_HAS_COMPLEX
++ case SLANG_COMPLEX_TYPE:
++ switch (type)
++ {
++ case SLANG_INT_TYPE:
++ case SLANG_DOUBLE_TYPE:
++ type = SLANG_COMPLEX_TYPE;
++ break;
++
++ default:
++ goto type_mismatch;
++ }
++ break;
++#endif
++ default:
++ type_mismatch:
++ _SLclass_type_mismatch_error (type, this_type);
++ return -1;
++ }
++ count--;
++ }
++
++ if (count != 0)
++ {
++ SLang_Error = SL_STACK_UNDERFLOW;
++ return -1;
++ }
++
++ count = SLang_Num_Function_Args;
++
++ if (count == 0)
++ {
++ SLang_verror (SL_NOT_IMPLEMENTED, &quot;Empty inline-arrays not supported&quot;);
++ return -1;
++ }
++
++ if (type == SLANG_ARRAY_TYPE)
++ {
++ if (NULL == (at = concat_arrays (count)))
++ return -1;
++ }
++ else
++ {
++ SLang_Object_Type index_obj;
++ int icount = (int) count;
++
++ if (NULL == (at = SLang_create_array (type, 0, NULL, &amp;icount, 1)))
++ return -1;
++
++ index_obj.data_type = SLANG_INT_TYPE;
++ while (count != 0)
++ {
++ count--;
++ index_obj.v.int_val = (int) count;
++ if (-1 == aput_from_indices (at, &amp;index_obj, 1))
++ {
++ SLang_free_array (at);
++ SLdo_pop_n (count);
++ return -1;
++ }
++ }
++ }
++
++ return SLang_push_array (at, 1);
++}
++
++static int array_binary_op_result (int op, unsigned char a, unsigned char b,
++ unsigned char *c)
++{
++ (void) op;
++ (void) a;
++ (void) b;
++ *c = SLANG_ARRAY_TYPE;
++ return 1;
++}
++
++static int array_binary_op (int op,
++ unsigned char a_type, VOID_STAR ap, unsigned int na,
++ unsigned char b_type, VOID_STAR bp, unsigned int nb,
++ VOID_STAR cp)
++{
++ SLang_Array_Type *at, *bt, *ct;
++ unsigned int i, num_dims;
++ int (*binary_fun) (int,
++ unsigned char, VOID_STAR, unsigned int,
++ unsigned char, VOID_STAR, unsigned int,
++ VOID_STAR);
++ SLang_Class_Type *a_cl, *b_cl, *c_cl;
++ int no_init;
++
++ if (a_type == SLANG_ARRAY_TYPE)
++ {
++ if (na != 1)
++ {
++ SLang_verror (SL_NOT_IMPLEMENTED, &quot;Binary operation on multiple arrays not implemented&quot;);
++ return -1;
++ }
++
++ at = *(SLang_Array_Type **) ap;
++ if (-1 == coerse_array_to_linear (at))
++ return -1;
++ ap = at-&gt;data;
++ a_type = at-&gt;data_type;
++ na = at-&gt;num_elements;
++ }
++ else
++ {
++ at = NULL;
++ }
++
++ if (b_type == SLANG_ARRAY_TYPE)
++ {
++ if (nb != 1)
++ {
++ SLang_verror (SL_NOT_IMPLEMENTED, &quot;Binary operation on multiple arrays not implemented&quot;);
++ return -1;
++ }
++
++ bt = *(SLang_Array_Type **) bp;
++ if (-1 == coerse_array_to_linear (bt))
++ return -1;
++ bp = bt-&gt;data;
++ b_type = bt-&gt;data_type;
++ nb = bt-&gt;num_elements;
++ }
++ else
++ {
++ bt = NULL;
++ }
++
++ if ((at != NULL) &amp;&amp; (bt != NULL))
++ {
++ num_dims = at-&gt;num_dims;
++
++ if (num_dims != bt-&gt;num_dims)
++ {
++ SLang_verror (SL_TYPE_MISMATCH, &quot;Arrays must have same dim for binary operation&quot;);
++ return -1;
++ }
++
++ for (i = 0; i &lt; num_dims; i++)
++ {
++ if (at-&gt;dims[i] != bt-&gt;dims[i])
++ {
++ SLang_verror (SL_TYPE_MISMATCH, &quot;Arrays must be the same for binary operation&quot;);
++ return -1;
++ }
++ }
++ }
++
++ a_cl = _SLclass_get_class (a_type);
++ b_cl = _SLclass_get_class (b_type);
++
++ if (NULL == (binary_fun = _SLclass_get_binary_fun (op, a_cl, b_cl, &amp;c_cl, 1)))
++ return -1;
++
++ no_init = ((c_cl-&gt;cl_class_type == SLANG_CLASS_TYPE_SCALAR)
++ || (c_cl-&gt;cl_class_type == SLANG_CLASS_TYPE_VECTOR));
++
++ ct = NULL;
++#if _SLANG_USE_TMP_OPTIMIZATION
++ /* If we are dealing with scalar (or vector) objects, and if the object
++ * appears to be owned by the stack, then use it instead of creating a
++ * new version. This can happen with code such as:
++ * @ x = [1,2,3,4];
++ * @ x = __tmp(x) + 1;
++ */
++ if (no_init)
++ {
++ if ((at != NULL)
++ &amp;&amp; (at-&gt;num_refs == 1)
++ &amp;&amp; (at-&gt;data_type == c_cl-&gt;cl_data_type))
++ {
++ ct = at;
++ ct-&gt;num_refs = 2;
++ }
++ else if ((bt != NULL)
++ &amp;&amp; (bt-&gt;num_refs == 1)
++ &amp;&amp; (bt-&gt;data_type == c_cl-&gt;cl_data_type))
++ {
++ ct = bt;
++ ct-&gt;num_refs = 2;
++ }
++ }
++#endif /* _SLANG_USE_TMP_OPTIMIZATION */
++
++ if (ct == NULL)
++ {
++ if (at != NULL) ct = at; else ct = bt;
++ ct = SLang_create_array1 (c_cl-&gt;cl_data_type, 0, NULL, ct-&gt;dims, ct-&gt;num_dims, no_init);
++ if (ct == NULL)
++ return -1;
++ }
++
++
++ if ((na == 0) || (nb == 0) /* allow empty arrays */
++ || (1 == (*binary_fun) (op, a_type, ap, na, b_type, bp, nb, ct-&gt;data)))
++ {
++ *(SLang_Array_Type **) cp = ct;
++ return 1;
++ }
++
++ SLang_free_array (ct);
++ return -1;
++}
++
++static void array_where (void)
++{
++ SLang_Array_Type *at, *bt;
++ char *a_data;
++ int *b_data;
++ unsigned int i, num_elements;
++ int b_num;
++
++ if (-1 == SLang_pop_array (&amp;at, 1))
++ return;
++
++ bt = NULL;
++
++ if (at-&gt;data_type != SLANG_CHAR_TYPE)
++ {
++ int zero;
++ SLang_Array_Type *tmp_at;
++
++ tmp_at = at;
++ zero = 0;
++ if (1 != array_binary_op (SLANG_NE,
++ SLANG_ARRAY_TYPE, (VOID_STAR) &amp;at, 1,
++ SLANG_CHAR_TYPE, (VOID_STAR) &amp;zero, 1,
++ (VOID_STAR) &amp;tmp_at))
++ goto return_error;
++
++ SLang_free_array (at);
++ at = tmp_at;
++ if (at-&gt;data_type != SLANG_CHAR_TYPE)
++ {
++ SLang_Error = SL_TYPE_MISMATCH;
++ goto return_error;
++ }
++ }
++
++ a_data = (char *) at-&gt;data;
++ num_elements = at-&gt;num_elements;
++
++ b_num = 0;
++ for (i = 0; i &lt; num_elements; i++)
++ if (a_data[i] != 0) b_num++;
++
++ if (NULL == (bt = SLang_create_array1 (SLANG_INT_TYPE, 0, NULL, &amp;b_num, 1, 1)))
++ goto return_error;
++
++ b_data = (int *) bt-&gt;data;
++
++ i = 0;
++ while (b_num)
++ {
++ if (a_data[i] != 0)
++ {
++ *b_data++ = i;
++ b_num--;
++ }
++
++ i++;
++ }
++
++ (void) SLang_push_array (bt, 0);
++ /* drop */
++
++ return_error:
++ SLang_free_array (at);
++ SLang_free_array (bt);
++}
++
++static int do_array_reshape (SLang_Array_Type *at, SLang_Array_Type *ind_at)
++{
++ int *dims;
++ unsigned int i, num_dims;
++ unsigned int num_elements;
++
++ if ((ind_at-&gt;data_type != SLANG_INT_TYPE)
++ || (ind_at-&gt;num_dims != 1))
++ {
++ SLang_verror (SL_TYPE_MISMATCH, &quot;Expecting 1-d integer array&quot;);
++ return -1;
++ }
++
++ num_dims = ind_at-&gt;num_elements;
++ dims = (int *) ind_at-&gt;data;
++
++ num_elements = 1;
++ for (i = 0; i &lt; num_dims; i++)
++ {
++ int d = dims[i];
++ if (d &lt; 0)
++ {
++ SLang_verror (SL_INVALID_PARM, &quot;reshape: dimension is less then 0&quot;);
++ return -1;
++ }
++
++ num_elements = (unsigned int) d * num_elements;
++ }
++
++ if ((num_elements != at-&gt;num_elements)
++ || (num_dims &gt; SLARRAY_MAX_DIMS))
++ {
++ SLang_verror (SL_INVALID_PARM, &quot;Unable to reshape array to specified size&quot;);
++ return -1;
++ }
++
++ for (i = 0; i &lt; num_dims; i++)
++ at-&gt;dims [i] = dims[i];
++
++ while (i &lt; SLARRAY_MAX_DIMS)
++ {
++ at-&gt;dims [i] = 1;
++ i++;
++ }
++
++ at-&gt;num_dims = num_dims;
++ return 0;
++}
++
++static void array_reshape (SLang_Array_Type *at, SLang_Array_Type *ind_at)
++{
++ (void) do_array_reshape (at, ind_at);
++}
++
++static void _array_reshape (SLang_Array_Type *ind_at)
++{
++ SLang_Array_Type *at;
++ SLang_Array_Type *new_at;
++
++ if (-1 == SLang_pop_array (&amp;at, 1))
++ return;
++
++ /* FIXME: Priority=low: duplicate_array could me modified to look at num_refs */
++
++ /* Now try to avoid the overhead of creating a new array if possible */
++ if (at-&gt;num_refs == 1)
++ {
++ /* Great, we are the sole owner of this array. */
++ if ((-1 == do_array_reshape (at, ind_at))
++ || (-1 == SLclass_push_ptr_obj (SLANG_ARRAY_TYPE, (VOID_STAR)at)))
++ SLang_free_array (at);
++ return;
++ }
++
++ new_at = SLang_duplicate_array (at);
++ if (new_at != NULL)
++ {
++ if (0 == do_array_reshape (new_at, ind_at))
++ (void) SLang_push_array (new_at, 0);
++
++ SLang_free_array (new_at);
++ }
++ SLang_free_array (at);
++}
++
++typedef struct
++{
++ SLang_Array_Type *at;
++ unsigned int increment;
++ char *addr;
++}
++Map_Arg_Type;
++/* Usage: array_map (Return-Type, func, args,....); */
++static void array_map (void)
++{
++ Map_Arg_Type *args;
++ unsigned int num_args;
++ unsigned int i, i_control;
++ SLang_Name_Type *nt;
++ unsigned int num_elements;
++ SLang_Array_Type *at;
++ char *addr;
++ unsigned char type;
++
++ at = NULL;
++ args = NULL;
++ nt = NULL;
++
++ if (SLang_Num_Function_Args &lt; 3)
++ {
++ SLang_verror (SL_INVALID_PARM,
++ &quot;Usage: array_map (Return-Type, &amp;func, args...)&quot;);
++ SLdo_pop_n (SLang_Num_Function_Args);
++ return;
++ }
++
++ num_args = (unsigned int)SLang_Num_Function_Args - 2;
++ args = (Map_Arg_Type *) SLmalloc (num_args * sizeof (Map_Arg_Type));
++ if (args == NULL)
++ {
++ SLdo_pop_n (SLang_Num_Function_Args);
++ return;
++ }
++ memset ((char *) args, 0, num_args * sizeof (Map_Arg_Type));
++ i = num_args;
++ i_control = 0;
++ while (i &gt; 0)
++ {
++ i--;
++ if (-1 == SLang_pop_array (&amp;args[i].at, 1))
++ {
++ SLdo_pop_n (i + 2);
++ goto return_error;
++ }
++ if (args[i].at-&gt;num_elements &gt; 1)
++ i_control = i;
++ }
++
++ if (NULL == (nt = SLang_pop_function ()))
++ {
++ SLdo_pop_n (1);
++ goto return_error;
++ }
++
++ num_elements = args[i_control].at-&gt;num_elements;
++
++ if (-1 == _SLang_pop_datatype (&amp;type))
++ goto return_error;
++
++ if (type == SLANG_UNDEFINED_TYPE) /* Void_Type */
++ at = NULL;
++ else
++ {
++ at = args[i_control].at;
++
++ if (NULL == (at = SLang_create_array (type, 0, NULL, at-&gt;dims, at-&gt;num_dims)))
++ goto return_error;
++ }
++
++
++ for (i = 0; i &lt; num_args; i++)
++ {
++ SLang_Array_Type *ati = args[i].at;
++ /* FIXME: Priority = low: The actual dimensions should be compared. */
++ if (ati-&gt;num_elements == num_elements)
++ args[i].increment = ati-&gt;sizeof_type;
++ /* memset already guarantees increment to be zero */
++
++ if (ati-&gt;num_elements == 0)
++ {
++ SLang_verror (0, &quot;array_map: function argument %d of %d is an empty array&quot;,
++ i+1, num_args);
++ goto return_error;
++ }
++
++ args[i].addr = (char *) ati-&gt;data;
++ }
++
++ if (at == NULL)
++ addr = NULL;
++ else
++ addr = (char *)at-&gt;data;
++
++ for (i = 0; i &lt; num_elements; i++)
++ {
++ unsigned int j;
++
++ if (-1 == SLang_start_arg_list ())
++ goto return_error;
++
++ for (j = 0; j &lt; num_args; j++)
++ {
++ if (-1 == push_element_at_addr (args[j].at,
++ (VOID_STAR) args[j].addr,
++ 1))
++ {
++ SLdo_pop_n (j);
++ goto return_error;
++ }
++
++ args[j].addr += args[j].increment;
++ }
++
++ if (-1 == SLang_end_arg_list ())
++ {
++ SLdo_pop_n (num_args);
++ goto return_error;
++ }
++
++ if (-1 == SLexecute_function (nt))
++ goto return_error;
++
++ if (at == NULL)
++ continue;
++
++ if (-1 == at-&gt;cl-&gt;cl_apop (type, (VOID_STAR) addr))
++ goto return_error;
++
++ addr += at-&gt;sizeof_type;
++ }
++
++ if (at != NULL)
++ (void) SLang_push_array (at, 0);
++
++ /* drop */
++
++ return_error:
++ SLang_free_array (at);
++ SLang_free_function (nt);
++ if (args != NULL)
++ {
++ for (i = 0; i &lt; num_args; i++)
++ SLang_free_array (args[i].at);
++
++ SLfree ((char *) args);
++ }
++}
++
++static SLang_Intrin_Fun_Type Array_Table [] =
++{
++ MAKE_INTRINSIC_0(&quot;array_map&quot;, array_map, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_0(&quot;array_sort&quot;, sort_array, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_1(&quot;array_to_bstring&quot;, array_to_bstring, SLANG_VOID_TYPE, SLANG_ARRAY_TYPE),
++ MAKE_INTRINSIC_1(&quot;bstring_to_array&quot;, bstring_to_array, SLANG_VOID_TYPE, SLANG_BSTRING_TYPE),
++ MAKE_INTRINSIC(&quot;init_char_array&quot;, init_char_array, SLANG_VOID_TYPE, 0),
++ MAKE_INTRINSIC(&quot;array_info&quot;, array_info, SLANG_VOID_TYPE, 0),
++ MAKE_INTRINSIC(&quot;where&quot;, array_where, SLANG_VOID_TYPE, 0),
++ MAKE_INTRINSIC_2(&quot;reshape&quot;, array_reshape, SLANG_VOID_TYPE, SLANG_ARRAY_TYPE, SLANG_ARRAY_TYPE),
++ MAKE_INTRINSIC_1(&quot;_reshape&quot;, _array_reshape, SLANG_VOID_TYPE, SLANG_ARRAY_TYPE),
++ SLANG_END_INTRIN_FUN_TABLE
++};
++
++static char *array_string (unsigned char type, VOID_STAR v)
++{
++ SLang_Array_Type *at;
++ char buf[512];
++ unsigned int i, num_dims;
++ int *dims;
++
++ at = *(SLang_Array_Type **) v;
++ type = at-&gt;data_type;
++ num_dims = at-&gt;num_dims;
++ dims = at-&gt;dims;
++
++ sprintf (buf, &quot;%s[%d&quot;, SLclass_get_datatype_name (type), at-&gt;dims[0]);
++
++ for (i = 1; i &lt; num_dims; i++)
++ sprintf (buf + strlen(buf), &quot;,%d&quot;, dims[i]);
++ strcat (buf, &quot;]&quot;);
++
++ return SLmake_string (buf);
++}
++
++static void array_destroy (unsigned char type, VOID_STAR v)
++{
++ (void) type;
++ SLang_free_array (*(SLang_Array_Type **) v);
++}
++
++static int array_push (unsigned char type, VOID_STAR v)
++{
++ SLang_Array_Type *at;
++
++ (void) type;
++ at = *(SLang_Array_Type **) v;
++ return SLang_push_array (at, 0);
++}
++
++/* Intrinsic arrays are not stored in a variable. So, the address that
++ * would contain the variable holds the array address.
++ */
++static int array_push_intrinsic (unsigned char type, VOID_STAR v)
++{
++ (void) type;
++ return SLang_push_array ((SLang_Array_Type *) v, 0);
++}
++
++int _SLarray_add_bin_op (unsigned char type)
++{
++ SL_OOBinary_Type *ab;
++ SLang_Class_Type *cl;
++
++ cl = _SLclass_get_class (type);
++ ab = cl-&gt;cl_binary_ops;
++
++ while (ab != NULL)
++ {
++ if (ab-&gt;data_type == SLANG_ARRAY_TYPE)
++ return 0;
++ ab = ab-&gt;next;
++ }
++
++ if ((-1 == SLclass_add_binary_op (SLANG_ARRAY_TYPE, type, array_binary_op, array_binary_op_result))
++ || (-1 == SLclass_add_binary_op (type, SLANG_ARRAY_TYPE, array_binary_op, array_binary_op_result)))
++ return -1;
++
++ return 0;
++}
++
++static SLang_Array_Type *
++do_array_math_op (int op, int unary_type,
++ SLang_Array_Type *at, unsigned int na)
++{
++ unsigned char a_type, b_type;
++ int (*f) (int, unsigned char, VOID_STAR, unsigned int, VOID_STAR);
++ SLang_Array_Type *bt;
++ SLang_Class_Type *b_cl;
++ int no_init;
++
++ if (na != 1)
++ {
++ SLang_verror (SL_NOT_IMPLEMENTED, &quot;Operation restricted to 1 array&quot;);
++ return NULL;
++ }
++
++ a_type = at-&gt;data_type;
++ if (NULL == (f = _SLclass_get_unary_fun (op, at-&gt;cl, &amp;b_cl, unary_type)))
++ return NULL;
++ b_type = b_cl-&gt;cl_data_type;
++
++ if (-1 == coerse_array_to_linear (at))
++ return NULL;
++
++ no_init = ((b_cl-&gt;cl_class_type == SLANG_CLASS_TYPE_SCALAR)
++ || (b_cl-&gt;cl_class_type == SLANG_CLASS_TYPE_VECTOR));
++
++#if _SLANG_USE_TMP_OPTIMIZATION
++ /* If we are dealing with scalar (or vector) objects, and if the object
++ * appears to be owned by the stack, then use it instead of creating a
++ * new version. This can happen with code such as:
++ * @ x = [1,2,3,4];
++ * @ x = UNARY_OP(__tmp(x));
++ */
++ if (no_init
++ &amp;&amp; (at-&gt;num_refs == 1)
++ &amp;&amp; (at-&gt;data_type == b_cl-&gt;cl_data_type))
++ {
++ bt = at;
++ bt-&gt;num_refs = 2;
++ }
++ else
++#endif /* _SLANG_USE_TMP_OPTIMIZATION */
++ if (NULL == (bt = SLang_create_array1 (b_type, 0, NULL, at-&gt;dims, at-&gt;num_dims, no_init)))
++ return NULL;
++
++ if (1 != (*f)(op, a_type, at-&gt;data, at-&gt;num_elements, bt-&gt;data))
++ {
++ SLang_free_array (bt);
++ return NULL;
++ }
++ return bt;
++}
++
++static int
++array_unary_op_result (int op, unsigned char a, unsigned char *b)
++{
++ (void) op;
++ (void) a;
++ *b = SLANG_ARRAY_TYPE;
++ return 1;
++}
++
++static int
++array_unary_op (int op,
++ unsigned char a, VOID_STAR ap, unsigned int na,
++ VOID_STAR bp)
++{
++ SLang_Array_Type *at;
++
++ (void) a;
++ at = *(SLang_Array_Type **) ap;
++ if (NULL == (at = do_array_math_op (op, _SLANG_BC_UNARY, at, na)))
++ {
++ if (SLang_Error) return -1;
++ return 0;
++ }
++ *(SLang_Array_Type **) bp = at;
++ return 1;
++}
++
++static int
++array_math_op (int op,
++ unsigned char a, VOID_STAR ap, unsigned int na,
++ VOID_STAR bp)
++{
++ SLang_Array_Type *at;
++
++ (void) a;
++ at = *(SLang_Array_Type **) ap;
++ if (NULL == (at = do_array_math_op (op, _SLANG_BC_MATH_UNARY, at, na)))
++ {
++ if (SLang_Error) return -1;
++ return 0;
++ }
++ *(SLang_Array_Type **) bp = at;
++ return 1;
++}
++
++static int
++array_app_op (int op,
++ unsigned char a, VOID_STAR ap, unsigned int na,
++ VOID_STAR bp)
++{
++ SLang_Array_Type *at;
++
++ (void) a;
++ at = *(SLang_Array_Type **) ap;
++ if (NULL == (at = do_array_math_op (op, _SLANG_BC_APP_UNARY, at, na)))
++ {
++ if (SLang_Error) return -1;
++ return 0;
++ }
++ *(SLang_Array_Type **) bp = at;
++ return 1;
++}
++
++int
++_SLarray_typecast (unsigned char a_type, VOID_STAR ap, unsigned int na,
++ unsigned char b_type, VOID_STAR bp,
++ int is_implicit)
++{
++ SLang_Array_Type *at, *bt;
++ SLang_Class_Type *b_cl;
++ int no_init;
++ int (*t) (unsigned char, VOID_STAR, unsigned int, unsigned char, VOID_STAR);
++
++ if (na != 1)
++ {
++ SLang_verror (SL_NOT_IMPLEMENTED, &quot;typecast of multiple arrays not implemented&quot;);
++ return -1;
++ }
++
++ at = *(SLang_Array_Type **) ap;
++ a_type = at-&gt;data_type;
++
++ if (a_type == b_type)
++ {
++ at-&gt;num_refs += 1;
++ *(SLang_Array_Type **) bp = at;
++ return 1;
++ }
++
++ if (NULL == (t = _SLclass_get_typecast (a_type, b_type, is_implicit)))
++ return -1;
++
++ if (-1 == coerse_array_to_linear (at))
++ return -1;
++
++ b_cl = _SLclass_get_class (b_type);
++
++ no_init = ((b_cl-&gt;cl_class_type == SLANG_CLASS_TYPE_SCALAR)
++ || (b_cl-&gt;cl_class_type == SLANG_CLASS_TYPE_VECTOR));
++
++ if (NULL == (bt = SLang_create_array1 (b_type, 0, NULL, at-&gt;dims, at-&gt;num_dims, no_init)))
++ return -1;
++
++ if (1 == (*t) (a_type, at-&gt;data, at-&gt;num_elements, b_type, bt-&gt;data))
++ {
++ *(SLang_Array_Type **) bp = bt;
++ return 1;
++ }
++
++ SLang_free_array (bt);
++ return 0;
++}
++
++SLang_Array_Type *SLang_duplicate_array (SLang_Array_Type *at)
++{
++ SLang_Array_Type *bt;
++ char *data, *a_data;
++ unsigned int i, num_elements, sizeof_type;
++ unsigned int size;
++ int (*cl_acopy) (unsigned char, VOID_STAR, VOID_STAR);
++ unsigned char type;
++
++ if (-1 == coerse_array_to_linear (at))
++ return NULL;
++
++ type = at-&gt;data_type;
++ num_elements = at-&gt;num_elements;
++ sizeof_type = at-&gt;sizeof_type;
++ size = num_elements * sizeof_type;
++
++ if (NULL == (data = SLmalloc (size)))
++ return NULL;
++
++ if (NULL == (bt = SLang_create_array (type, 0, (VOID_STAR)data, at-&gt;dims, at-&gt;num_dims)))
++ {
++ SLfree (data);
++ return NULL;
++ }
++
++ a_data = (char *) at-&gt;data;
++ if (0 == (at-&gt;flags &amp; SLARR_DATA_VALUE_IS_POINTER))
++ {
++ SLMEMCPY (data, a_data, size);
++ return bt;
++ }
++
++ SLMEMSET (data, 0, size);
++
++ cl_acopy = at-&gt;cl-&gt;cl_acopy;
++ for (i = 0; i &lt; num_elements; i++)
++ {
++ if (NULL != *(VOID_STAR *) a_data)
++ {
++ if (-1 == (*cl_acopy) (type, (VOID_STAR) a_data, (VOID_STAR) data))
++ {
++ SLang_free_array (bt);
++ return NULL;
++ }
++ }
++
++ data += sizeof_type;
++ a_data += sizeof_type;
++ }
++
++ return bt;
++}
++
++static int array_dereference (unsigned char type, VOID_STAR addr)
++{
++ SLang_Array_Type *at;
++
++ (void) type;
++ at = SLang_duplicate_array (*(SLang_Array_Type **) addr);
++ if (at == NULL) return -1;
++ return SLang_push_array (at, 1);
++}
++
++/* This function gets called via, e.g., @Array_Type (Double_Type, [10,20]);
++ */
++static int
++array_datatype_deref (unsigned char type)
++{
++ SLang_Array_Type *ind_at;
++ SLang_Array_Type *at;
++
++#if 0
++ /* The parser generated code for this as if a function call were to be
++ * made. However, the interpreter simply called the deref object routine
++ * instead of the function call. So, I must simulate the function call.
++ * This needs to be formalized to hide this detail from applications
++ * who wish to do the same. So...
++ * FIXME: Priority=medium
++ */
++ if (0 == _SL_increment_frame_pointer ())
++ (void) _SL_decrement_frame_pointer ();
++#endif
++
++ if (-1 == SLang_pop_array (&amp;ind_at, 1))
++ return -1;
++
++ if ((ind_at-&gt;data_type != SLANG_INT_TYPE)
++ || (ind_at-&gt;num_dims != 1))
++ {
++ SLang_verror (SL_TYPE_MISMATCH, &quot;Expecting 1-d integer array&quot;);
++ goto return_error;
++ }
++
++ if (-1 == _SLang_pop_datatype (&amp;type))
++ goto return_error;
++
++ if (NULL == (at = SLang_create_array (type, 0, NULL,
++ (int *) ind_at-&gt;data,
++ ind_at-&gt;num_elements)))
++ goto return_error;
++
++ SLang_free_array (ind_at);
++ return SLang_push_array (at, 1);
++
++ return_error:
++ SLang_free_array (ind_at);
++ return -1;
++}
++
++static int array_length (unsigned char type, VOID_STAR v, unsigned int *len)
++{
++ SLang_Array_Type *at;
++
++ (void) type;
++ at = *(SLang_Array_Type **) v;
++ *len = at-&gt;num_elements;
++ return 0;
++}
++
++int
++_SLarray_init_slarray (void)
++{
++ SLang_Class_Type *cl;
++
++ if (-1 == SLadd_intrin_fun_table (Array_Table, NULL))
++ return -1;
++
++ if (NULL == (cl = SLclass_allocate_class (&quot;Array_Type&quot;)))
++ return -1;
++
++ (void) SLclass_set_string_function (cl, array_string);
++ (void) SLclass_set_destroy_function (cl, array_destroy);
++ (void) SLclass_set_push_function (cl, array_push);
++ cl-&gt;cl_push_intrinsic = array_push_intrinsic;
++ cl-&gt;cl_dereference = array_dereference;
++ cl-&gt;cl_datatype_deref = array_datatype_deref;
++ cl-&gt;cl_length = array_length;
++
++ if (-1 == SLclass_register_class (cl, SLANG_ARRAY_TYPE, sizeof (VOID_STAR),
++ SLANG_CLASS_TYPE_PTR))
++ return -1;
++
++ if ((-1 == SLclass_add_binary_op (SLANG_ARRAY_TYPE, SLANG_ARRAY_TYPE, array_binary_op, array_binary_op_result))
++ || (-1 == SLclass_add_unary_op (SLANG_ARRAY_TYPE, array_unary_op, array_unary_op_result))
++ || (-1 == SLclass_add_app_unary_op (SLANG_ARRAY_TYPE, array_app_op, array_unary_op_result))
++ || (-1 == SLclass_add_math_op (SLANG_ARRAY_TYPE, array_math_op, array_unary_op_result))
++ || (-1 == SLclass_add_math_op (SLANG_ARRAY_TYPE, array_math_op, array_unary_op_result)))
++ return -1;
++
++ return 0;
++}
++
++int SLang_pop_array (SLang_Array_Type **at_ptr, int convert_scalar)
++{
++ if (-1 == pop_array (at_ptr, convert_scalar))
++ return -1;
++
++ if (-1 == coerse_array_to_linear (*at_ptr))
++ {
++ SLang_free_array (*at_ptr);
++ return -1;
++ }
++ return 0;
++}
++
++int SLang_pop_array_of_type (SLang_Array_Type **at, unsigned char type)
++{
++ if (-1 == SLclass_typecast (type, 1, 1))
++ return -1;
++
++ return SLang_pop_array (at, 1);
++}
++
++void (*_SLang_Matrix_Multiply)(void);
++
++int _SLarray_matrix_multiply (void)
++{
++ if (_SLang_Matrix_Multiply != NULL)
++ {
++ (*_SLang_Matrix_Multiply)();
++ return 0;
++ }
++ SLang_verror (SL_NOT_IMPLEMENTED, &quot;Matrix multiplication not available&quot;);
++ return -1;
++}
++
++struct _SLang_Foreach_Context_Type
++{
++ SLang_Array_Type *at;
++ unsigned int next_element_index;
++};
++
++SLang_Foreach_Context_Type *
++_SLarray_cl_foreach_open (unsigned char type, unsigned int num)
++{
++ SLang_Foreach_Context_Type *c;
++
++ if (num != 0)
++ {
++ SLdo_pop_n (num + 1);
++ SLang_verror (SL_NOT_IMPLEMENTED,
++ &quot;%s does not support 'foreach using' form&quot;,
++ SLclass_get_datatype_name (type));
++ return NULL;
++ }
++
++ if (NULL == (c = (SLang_Foreach_Context_Type *) SLmalloc (sizeof (SLang_Foreach_Context_Type))))
++ return NULL;
++
++ memset ((char *) c, 0, sizeof (SLang_Foreach_Context_Type));
++
++ if (-1 == pop_array (&amp;c-&gt;at, 1))
++ {
++ SLfree ((char *) c);
++ return NULL;
++ }
++
++ return c;
++}
++
++void _SLarray_cl_foreach_close (unsigned char type, SLang_Foreach_Context_Type *c)
++{
++ (void) type;
++ if (c == NULL) return;
++ SLang_free_array (c-&gt;at);
++ SLfree ((char *) c);
++}
++
++int _SLarray_cl_foreach (unsigned char type, SLang_Foreach_Context_Type *c)
++{
++ SLang_Array_Type *at;
++ VOID_STAR data;
++
++ (void) type;
++
++ if (c == NULL)
++ return -1;
++
++ at = c-&gt;at;
++ if (at-&gt;num_elements == c-&gt;next_element_index)
++ return 0;
++
++ /* FIXME: Priority = low. The following assumes linear arrays
++ * or Integer range arrays. Fixing it right requires a method to get the
++ * nth element of a multidimensional array.
++ */
++
++ if (at-&gt;flags &amp; SLARR_DATA_VALUE_IS_RANGE)
++ {
++ int d = (int) c-&gt;next_element_index;
++ data = range_get_data_addr (at, &amp;d);
++ }
++ else
++ data = (VOID_STAR) ((char *)at-&gt;data + (c-&gt;next_element_index * at-&gt;sizeof_type));
++
++ c-&gt;next_element_index += 1;
++
++ if ((at-&gt;flags &amp; SLARR_DATA_VALUE_IS_POINTER)
++ &amp;&amp; (*(VOID_STAR *) data == NULL))
++ {
++ if (-1 == SLang_push_null ())
++ return -1;
++ }
++ else if (-1 == (*at-&gt;cl-&gt;cl_apush)(at-&gt;data_type, data))
++ return -1;
++
++ /* keep going */
++ return 1;
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slarray.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slarrfun.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slarrfun.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slarrfun.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,464 @@
++/* Advanced array manipulation routines for S-Lang */
++/* Copyright (c) 1998, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++static int next_transposed_index (int *dims, int *max_dims, unsigned int num_dims)
++{
++ int i;
++
++ for (i = 0; i &lt; (int) num_dims; i++)
++ {
++ int dims_i;
++
++ dims_i = dims [i] + 1;
++ if (dims_i != (int) max_dims [i])
++ {
++ dims [i] = dims_i;
++ return 0;
++ }
++ dims [i] = 0;
++ }
++
++ return -1;
++}
++
++static SLang_Array_Type *allocate_transposed_array (SLang_Array_Type *at)
++{
++ unsigned int num_elements;
++ SLang_Array_Type *bt;
++ VOID_STAR b_data;
++
++ num_elements = at-&gt;num_elements;
++ b_data = (VOID_STAR) SLmalloc (at-&gt;sizeof_type * num_elements);
++ if (b_data == NULL)
++ return NULL;
++
++ bt = SLang_create_array (at-&gt;data_type, 0, b_data, at-&gt;dims, 2);
++ if (bt == NULL)
++ {
++ SLfree ((char *)b_data);
++ return NULL;
++ }
++
++ bt-&gt;dims[1] = at-&gt;dims[0];
++ bt-&gt;dims[0] = at-&gt;dims[1];
++
++ return bt;
++}
++
++#define GENERIC_TYPE float
++#define TRANSPOSE_2D_ARRAY transpose_floats
++#define GENERIC_TYPE_A float
++#define GENERIC_TYPE_B float
++#define GENERIC_TYPE_C float
++#define INNERPROD_FUNCTION innerprod_float_float
++#if SLANG_HAS_COMPLEX
++# define INNERPROD_COMPLEX_A innerprod_complex_float
++# define INNERPROD_A_COMPLEX innerprod_float_complex
++#endif
++#include &quot;slarrfun.inc&quot;
++
++#define GENERIC_TYPE double
++#define TRANSPOSE_2D_ARRAY transpose_doubles
++#define GENERIC_TYPE_A double
++#define GENERIC_TYPE_B double
++#define GENERIC_TYPE_C double
++#define INNERPROD_FUNCTION innerprod_double_double
++#if SLANG_HAS_COMPLEX
++# define INNERPROD_COMPLEX_A innerprod_complex_double
++# define INNERPROD_A_COMPLEX innerprod_double_complex
++#endif
++#include &quot;slarrfun.inc&quot;
++
++#define GENERIC_TYPE_A double
++#define GENERIC_TYPE_B float
++#define GENERIC_TYPE_C double
++#define INNERPROD_FUNCTION innerprod_double_float
++#include &quot;slarrfun.inc&quot;
++
++#define GENERIC_TYPE_A float
++#define GENERIC_TYPE_B double
++#define GENERIC_TYPE_C double
++#define INNERPROD_FUNCTION innerprod_float_double
++#include &quot;slarrfun.inc&quot;
++
++/* Finally pick up the complex_complex multiplication
++ * and do the integers
++ */
++#if SLANG_HAS_COMPLEX
++# define INNERPROD_COMPLEX_COMPLEX innerprod_complex_complex
++#endif
++#define GENERIC_TYPE int
++#define TRANSPOSE_2D_ARRAY transpose_ints
++#include &quot;slarrfun.inc&quot;
++
++#if SIZEOF_LONG != SIZEOF_INT
++# define GENERIC_TYPE long
++# define TRANSPOSE_2D_ARRAY transpose_longs
++# include &quot;slarrfun.inc&quot;
++#else
++# define transpose_longs transpose_ints
++#endif
++
++#if SIZEOF_SHORT != SIZEOF_INT
++# define GENERIC_TYPE short
++# define TRANSPOSE_2D_ARRAY transpose_shorts
++# include &quot;slarrfun.inc&quot;
++#else
++# define transpose_shorts transpose_ints
++#endif
++
++#define GENERIC_TYPE char
++#define TRANSPOSE_2D_ARRAY transpose_chars
++#include &quot;slarrfun.inc&quot;
++
++/* This routine works only with linear arrays */
++static SLang_Array_Type *transpose (SLang_Array_Type *at)
++{
++ int dims [SLARRAY_MAX_DIMS];
++ int *max_dims;
++ unsigned int num_dims;
++ SLang_Array_Type *bt;
++ int i;
++ unsigned int sizeof_type;
++ int is_ptr;
++ char *b_data;
++
++ max_dims = at-&gt;dims;
++ num_dims = at-&gt;num_dims;
++
++ if ((at-&gt;num_elements == 0)
++ || (num_dims == 1))
++ {
++ bt = SLang_duplicate_array (at);
++ if (num_dims == 1) bt-&gt;num_dims = 2;
++ goto transpose_dims;
++ }
++
++ /* For numeric arrays skip the overhead below */
++ if (num_dims == 2)
++ {
++ bt = allocate_transposed_array (at);
++ if (bt == NULL) return NULL;
++
++ switch (at-&gt;data_type)
++ {
++ case SLANG_INT_TYPE:
++ case SLANG_UINT_TYPE:
++ return transpose_ints (at, bt);
++ case SLANG_DOUBLE_TYPE:
++ return transpose_doubles (at, bt);
++ case SLANG_FLOAT_TYPE:
++ return transpose_floats (at, bt);
++ case SLANG_CHAR_TYPE:
++ case SLANG_UCHAR_TYPE:
++ return transpose_chars (at, bt);
++ case SLANG_LONG_TYPE:
++ case SLANG_ULONG_TYPE:
++ return transpose_longs (at, bt);
++ case SLANG_SHORT_TYPE:
++ case SLANG_USHORT_TYPE:
++ return transpose_shorts (at, bt);
++ }
++ }
++ else
++ {
++ bt = SLang_create_array (at-&gt;data_type, 0, NULL, max_dims, num_dims);
++ if (bt == NULL) return NULL;
++ }
++
++ sizeof_type = at-&gt;sizeof_type;
++ is_ptr = (at-&gt;flags &amp; SLARR_DATA_VALUE_IS_POINTER);
++
++ memset ((char *)dims, 0, sizeof(dims));
++
++ b_data = (char *) bt-&gt;data;
++
++ do
++ {
++ if (-1 == _SLarray_aget_transfer_elem (at, dims, (VOID_STAR) b_data,
++ sizeof_type, is_ptr))
++ {
++ SLang_free_array (bt);
++ return NULL;
++ }
++ b_data += sizeof_type;
++ }
++ while (0 == next_transposed_index (dims, max_dims, num_dims));
++
++ transpose_dims:
++
++ num_dims = bt-&gt;num_dims;
++ for (i = 0; i &lt; (int) num_dims; i++)
++ bt-&gt;dims[i] = max_dims [num_dims - i - 1];
++
++ return bt;
++}
++
++static void array_transpose (SLang_Array_Type *at)
++{
++ if (NULL != (at = transpose (at)))
++ (void) SLang_push_array (at, 1);
++}
++
++static int get_inner_product_parms (SLang_Array_Type *a, int *dp,
++ unsigned int *loops, unsigned int *other)
++{
++ int num_dims;
++ int d;
++
++ d = *dp;
++
++ num_dims = (int)a-&gt;num_dims;
++ if (num_dims == 0)
++ {
++ SLang_verror (SL_INVALID_PARM, &quot;Inner-product operation requires an array of at least 1 dimension.&quot;);
++ return -1;
++ }
++
++ /* An index of -1 refers to last dimension */
++ if (d == -1)
++ d += num_dims;
++ *dp = d;
++
++ if (a-&gt;num_elements == 0)
++ { /* [] # [] ==&gt; [] */
++ *loops = *other = 0;
++ return 0;
++ }
++
++ *loops = a-&gt;num_elements / a-&gt;dims[d];
++
++ if (d == 0)
++ {
++ *other = *loops; /* a-&gt;num_elements / a-&gt;dims[0]; */
++ return 0;
++ }
++
++ *other = a-&gt;dims[d];
++ return 0;
++}
++
++/* This routines takes two arrays A_i..j and B_j..k and produces a third
++ * via C_i..k = A_i..j B_j..k.
++ *
++ * If A is a vector, and B is a 2-d matrix, then regard A as a 2-d matrix
++ * with 1-column.
++ */
++static void do_inner_product (void)
++{
++ SLang_Array_Type *a, *b, *c;
++ void (*fun)(SLang_Array_Type *, SLang_Array_Type *, SLang_Array_Type *,
++ unsigned int, unsigned int, unsigned int, unsigned int,
++ unsigned int);
++ unsigned char c_type;
++ int dims[SLARRAY_MAX_DIMS];
++ int status;
++ unsigned int a_loops, b_loops, b_inc, a_stride;
++ int ai_dims, i, j;
++ unsigned int num_dims, a_num_dims, b_num_dims;
++ int ai, bi;
++
++ /* The result of a inner_product will be either a float, double, or
++ * a complex number.
++ *
++ * If an integer array is used, it will be promoted to a float.
++ */
++
++ switch (SLang_peek_at_stack1 ())
++ {
++ case SLANG_DOUBLE_TYPE:
++ if (-1 == SLang_pop_array_of_type (&amp;b, SLANG_DOUBLE_TYPE))
++ return;
++ break;
++
++#if SLANG_HAS_COMPLEX
++ case SLANG_COMPLEX_TYPE:
++ if (-1 == SLang_pop_array_of_type (&amp;b, SLANG_COMPLEX_TYPE))
++ return;
++ break;
++#endif
++ case SLANG_FLOAT_TYPE:
++ default:
++ if (-1 == SLang_pop_array_of_type (&amp;b, SLANG_FLOAT_TYPE))
++ return;
++ break;
++ }
++
++ switch (SLang_peek_at_stack1 ())
++ {
++ case SLANG_DOUBLE_TYPE:
++ status = SLang_pop_array_of_type (&amp;a, SLANG_DOUBLE_TYPE);
++ break;
++
++#if SLANG_HAS_COMPLEX
++ case SLANG_COMPLEX_TYPE:
++ status = SLang_pop_array_of_type (&amp;a, SLANG_COMPLEX_TYPE);
++ break;
++#endif
++ case SLANG_FLOAT_TYPE:
++ default:
++ status = SLang_pop_array_of_type (&amp;a, SLANG_FLOAT_TYPE);
++ break;
++ }
++
++ if (status == -1)
++ {
++ SLang_free_array (b);
++ return;
++ }
++
++ ai = -1; /* last index of a */
++ bi = 0; /* first index of b */
++ if ((-1 == get_inner_product_parms (a, &amp;ai, &amp;a_loops, &amp;a_stride))
++ || (-1 == get_inner_product_parms (b, &amp;bi, &amp;b_loops, &amp;b_inc)))
++ {
++ SLang_verror (SL_TYPE_MISMATCH, &quot;Array dimensions are not compatible for inner-product&quot;);
++ goto free_and_return;
++ }
++
++ a_num_dims = a-&gt;num_dims;
++ b_num_dims = b-&gt;num_dims;
++
++ /* Coerse a 1-d vector to 2-d */
++ if ((a_num_dims == 1)
++ &amp;&amp; (b_num_dims == 2)
++ &amp;&amp; (a-&gt;num_elements))
++ {
++ a_num_dims = 2;
++ ai = 1;
++ a_loops = a-&gt;num_elements;
++ a_stride = 1;
++ }
++
++ if ((ai_dims = a-&gt;dims[ai]) != b-&gt;dims[bi])
++ {
++ SLang_verror (SL_TYPE_MISMATCH, &quot;Array dimensions are not compatible for inner-product&quot;);
++ goto free_and_return;
++ }
++
++ num_dims = a_num_dims + b_num_dims - 2;
++ if (num_dims &gt; SLARRAY_MAX_DIMS)
++ {
++ SLang_verror (SL_NOT_IMPLEMENTED,
++ &quot;Inner-product result exceed max allowed dimensions&quot;);
++ goto free_and_return;
++ }
++
++ if (num_dims)
++ {
++ j = 0;
++ for (i = 0; i &lt; (int)a_num_dims; i++)
++ if (i != ai) dims [j++] = a-&gt;dims[i];
++ for (i = 0; i &lt; (int)b_num_dims; i++)
++ if (i != bi) dims [j++] = b-&gt;dims[i];
++ }
++ else
++ {
++ /* a scalar */
++ num_dims = 1;
++ dims[0] = 1;
++ }
++
++ c_type = 0; fun = NULL;
++ switch (a-&gt;data_type)
++ {
++ case SLANG_FLOAT_TYPE:
++ switch (b-&gt;data_type)
++ {
++ case SLANG_FLOAT_TYPE:
++ c_type = SLANG_FLOAT_TYPE;
++ fun = innerprod_float_float;
++ break;
++ case SLANG_DOUBLE_TYPE:
++ c_type = SLANG_DOUBLE_TYPE;
++ fun = innerprod_float_double;
++ break;
++#if SLANG_HAS_COMPLEX
++ case SLANG_COMPLEX_TYPE:
++ c_type = SLANG_COMPLEX_TYPE;
++ fun = innerprod_float_complex;
++ break;
++#endif
++ }
++ break;
++ case SLANG_DOUBLE_TYPE:
++ switch (b-&gt;data_type)
++ {
++ case SLANG_FLOAT_TYPE:
++ c_type = SLANG_DOUBLE_TYPE;
++ fun = innerprod_double_float;
++ break;
++ case SLANG_DOUBLE_TYPE:
++ c_type = SLANG_DOUBLE_TYPE;
++ fun = innerprod_double_double;
++ break;
++#if SLANG_HAS_COMPLEX
++ case SLANG_COMPLEX_TYPE:
++ c_type = SLANG_COMPLEX_TYPE;
++ fun = innerprod_double_complex;
++ break;
++#endif
++ }
++ break;
++#if SLANG_HAS_COMPLEX
++ case SLANG_COMPLEX_TYPE:
++ c_type = SLANG_COMPLEX_TYPE;
++ switch (b-&gt;data_type)
++ {
++ case SLANG_FLOAT_TYPE:
++ fun = innerprod_complex_float;
++ break;
++ case SLANG_DOUBLE_TYPE:
++ fun = innerprod_complex_double;
++ break;
++ case SLANG_COMPLEX_TYPE:
++ fun = innerprod_complex_complex;
++ break;
++ }
++ break;
++#endif
++ default:
++ break;
++ }
++
++ if (NULL == (c = SLang_create_array (c_type, 0, NULL, dims, num_dims)))
++ goto free_and_return;
++
++ (*fun)(a, b, c, a_loops, a_stride, b_loops, b_inc, ai_dims);
++
++ (void) SLang_push_array (c, 1);
++ /* drop */
++
++ free_and_return:
++ SLang_free_array (a);
++ SLang_free_array (b);
++}
++
++
++
++static SLang_Intrin_Fun_Type Array_Fun_Table [] =
++{
++ MAKE_INTRINSIC_1(&quot;transpose&quot;, array_transpose, SLANG_VOID_TYPE, SLANG_ARRAY_TYPE),
++ SLANG_END_INTRIN_FUN_TABLE
++};
++
++int SLang_init_array (void)
++{
++ if (-1 == SLadd_intrin_fun_table (Array_Fun_Table, &quot;__SLARRAY__&quot;))
++ return -1;
++#if SLANG_HAS_FLOAT
++ _SLang_Matrix_Multiply = do_inner_product;
++#endif
++ return 0;
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slarrfun.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slarrfun.inc
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slarrfun.inc (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slarrfun.inc 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,257 @@
++/* -*- mode: C -*- */
++
++/* Some &quot;inline&quot; functions for generic scalar types */
++
++#ifdef TRANSPOSE_2D_ARRAY
++static SLang_Array_Type *TRANSPOSE_2D_ARRAY (SLang_Array_Type *at, SLang_Array_Type *bt)
++{
++ GENERIC_TYPE *a_data, *b_data;
++ int nr, nc, i;
++
++ nr = at-&gt;dims[0];
++ nc = at-&gt;dims[1];
++
++ a_data = (GENERIC_TYPE *) at-&gt;data;
++ b_data = (GENERIC_TYPE *) bt-&gt;data;
++
++ for (i = 0; i &lt; nr; i++)
++ {
++ GENERIC_TYPE *offset = b_data + i;
++ int j;
++ for (j = 0; j &lt; nc; j++)
++ {
++ *offset = *a_data++;
++ offset += nr;
++ }
++ }
++ return bt;
++}
++#undef TRANSPOSE_2D_ARRAY
++#endif
++
++
++#ifdef INNERPROD_FUNCTION
++
++static void INNERPROD_FUNCTION
++ (SLang_Array_Type *at, SLang_Array_Type *bt, SLang_Array_Type *ct,
++ unsigned int a_loops, unsigned int a_stride,
++ unsigned int b_loops, unsigned int b_inc,
++ unsigned int inner_loops)
++{
++ GENERIC_TYPE_A *a;
++ GENERIC_TYPE_B *b;
++ GENERIC_TYPE_C *c;
++
++ c = (GENERIC_TYPE_C *) ct-&gt;data;
++ b = (GENERIC_TYPE_B *) bt-&gt;data;
++ a = (GENERIC_TYPE_A *) at-&gt;data;
++
++ while (a_loops--)
++ {
++ GENERIC_TYPE_B *bb;
++ unsigned int j;
++
++ bb = b;
++
++ for (j = 0; j &lt; inner_loops; j++)
++ {
++ double x = (double) a[j];
++
++ if (x != 0.0)
++ {
++ unsigned int k;
++
++ for (k = 0; k &lt; b_loops; k++)
++ c[k] += x * bb[k];
++ }
++ bb += b_inc;
++ }
++ c += b_loops;
++ a += a_stride;
++ }
++}
++#undef INNERPROD_FUNCTION
++
++#undef GENERIC_TYPE_A
++#undef GENERIC_TYPE_B
++#undef GENERIC_TYPE_C
++#endif
++
++#ifdef INNERPROD_COMPLEX_A
++static void INNERPROD_COMPLEX_A
++ (SLang_Array_Type *at, SLang_Array_Type *bt, SLang_Array_Type *ct,
++ unsigned int a_loops, unsigned int a_stride,
++ unsigned int b_loops, unsigned int b_inc,
++ unsigned int inner_loops)
++{
++ double *a;
++ GENERIC_TYPE *b;
++ double *c;
++
++ c = (double *) ct-&gt;data;
++ b = (GENERIC_TYPE *) bt-&gt;data;
++ a = (double *) at-&gt;data;
++
++ a_stride *= 2;
++
++ while (a_loops--)
++ {
++ GENERIC_TYPE *bb;
++ unsigned int bb_loops;
++
++ bb = b;
++ bb_loops = b_loops;
++
++ while (bb_loops--)
++ {
++ double real_sum;
++ double imag_sum;
++ unsigned int iloops;
++ double *aa;
++ GENERIC_TYPE *bbb;
++
++ aa = a;
++ bbb = bb;
++ iloops = inner_loops;
++
++ real_sum = 0.0;
++ imag_sum = 0.0;
++ while (iloops--)
++ {
++ real_sum += aa[0] * (double)bbb[0];
++ imag_sum += aa[1] * (double)bbb[0];
++ aa += 2;
++ bbb += b_inc;
++ }
++
++ *c++ = real_sum;
++ *c++ = imag_sum;
++ bb++;
++ }
++
++ a += a_stride;
++ }
++}
++
++static void INNERPROD_A_COMPLEX
++ (SLang_Array_Type *at, SLang_Array_Type *bt, SLang_Array_Type *ct,
++ unsigned int a_loops, unsigned int a_stride,
++ unsigned int b_loops, unsigned int b_inc,
++ unsigned int inner_loops)
++{
++ GENERIC_TYPE *a;
++ double *b;
++ double *c;
++
++ c = (double *) ct-&gt;data;
++ b = (double *) bt-&gt;data;
++ a = (GENERIC_TYPE *) at-&gt;data;
++
++ b_inc *= 2;
++
++ while (a_loops--)
++ {
++ double *bb;
++ unsigned int bb_loops;
++
++ bb = b;
++ bb_loops = b_loops;
++
++ while (bb_loops--)
++ {
++ double real_sum;
++ double imag_sum;
++ unsigned int iloops;
++ GENERIC_TYPE *aa;
++ double *bbb;
++
++ aa = a;
++ bbb = bb;
++ iloops = inner_loops;
++
++ real_sum = 0.0;
++ imag_sum = 0.0;
++ while (iloops--)
++ {
++ real_sum += (double)aa[0] * bbb[0];
++ imag_sum += (double)aa[0] * bbb[1];
++ aa += 1;
++ bbb += b_inc;
++ }
++
++ *c++ = real_sum;
++ *c++ = imag_sum;
++ bb += 2;
++ }
++
++ a += a_stride;
++ }
++}
++
++#undef INNERPROD_A_COMPLEX
++#undef INNERPROD_COMPLEX_A
++#endif /* INNERPROD_COMPLEX_A */
++
++
++#ifdef INNERPROD_COMPLEX_COMPLEX
++static void INNERPROD_COMPLEX_COMPLEX
++ (SLang_Array_Type *at, SLang_Array_Type *bt, SLang_Array_Type *ct,
++ unsigned int a_loops, unsigned int a_stride,
++ unsigned int b_loops, unsigned int b_inc,
++ unsigned int inner_loops)
++{
++ double *a;
++ double *b;
++ double *c;
++
++ c = (double *) ct-&gt;data;
++ b = (double *) bt-&gt;data;
++ a = (double *) at-&gt;data;
++
++ a_stride *= 2;
++ b_inc *= 2;
++
++ while (a_loops--)
++ {
++ double *bb;
++ unsigned int bb_loops;
++
++ bb = b;
++ bb_loops = b_loops;
++
++ while (bb_loops--)
++ {
++ double real_sum;
++ double imag_sum;
++ unsigned int iloops;
++ double *aa;
++ double *bbb;
++
++ aa = a;
++ bbb = bb;
++ iloops = inner_loops;
++
++ real_sum = 0.0;
++ imag_sum = 0.0;
++ while (iloops--)
++ {
++ real_sum += aa[0]*bbb[0] - aa[1]*bbb[1];
++ imag_sum += aa[0]*bbb[1] + aa[1]*bbb[0];
++ aa += 2;
++ bbb += b_inc;
++ }
++
++ *c++ = real_sum;
++ *c++ = imag_sum;
++ bb += 2;
++ }
++
++ a += a_stride;
++ }
++}
++#undef INNERPROD_COMPLEX_COMPLEX
++#endif
++
++#ifdef GENERIC_TYPE
++# undef GENERIC_TYPE
++#endif
+
+Added: drakx/trunk/mdk-stage1/slang/slarrmis.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slarrmis.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slarrmis.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,38 @@
++/* Misc Array Functions */
++/* Copyright (c) 1997, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++int SLang_get_array_element (SLang_Array_Type *at, int *indices, VOID_STAR data)
++{
++ int is_ptr;
++
++ if ((at == NULL)
++ || (indices == NULL)
++ || (data == NULL))
++ return -1;
++
++ is_ptr = (at-&gt;flags &amp; SLARR_DATA_VALUE_IS_POINTER);
++ if (is_ptr) *(VOID_STAR *) data = NULL;
++ return _SLarray_aget_transfer_elem (at, indices, data, at-&gt;sizeof_type, is_ptr);
++}
++
++int SLang_set_array_element (SLang_Array_Type *at, int *indices, VOID_STAR data)
++{
++ if ((at == NULL)
++ || (indices == NULL)
++ || (data == NULL))
++ return -1;
++
++ return _SLarray_aput_transfer_elem (at, indices, data, at-&gt;sizeof_type,
++ at-&gt;flags &amp; SLARR_DATA_VALUE_IS_POINTER);
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slarrmis.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slassoc.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slassoc.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slassoc.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,713 @@
++/* Copyright (c) 1998, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++#include &quot;slinclud.h&quot;
++
++#define SL_APP_WANTS_FOREACH
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++#define USE_NEW_ANYTYPE_CODE 1
++
++typedef struct _SLAssoc_Array_Element_Type
++{
++ char *key; /* slstring */
++ struct _SLAssoc_Array_Element_Type *next;
++ SLang_Object_Type value;
++}
++_SLAssoc_Array_Element_Type;
++
++typedef struct
++{
++ _SLAssoc_Array_Element_Type *elements[SLASSOC_HASH_TABLE_SIZE];
++ SLang_Object_Type default_value;
++ unsigned int num_elements;
++#define HAS_DEFAULT_VALUE 1
++ unsigned int flags;
++ unsigned char type;
++}
++SLang_Assoc_Array_Type;
++
++#define USE_CACHED_STRING 1
++
++#if USE_CACHED_STRING
++static char *Cached_String;
++static SLang_Object_Type *Cached_Obj;
++static SLang_Assoc_Array_Type *Cached_Array;
++#endif
++
++static SLang_Assoc_Array_Type *alloc_assoc_array (unsigned char type, int has_default_value)
++{
++ SLang_Assoc_Array_Type *a;
++
++ a = (SLang_Assoc_Array_Type *)SLmalloc (sizeof (SLang_Assoc_Array_Type));
++ if (a == NULL)
++ {
++ if (has_default_value)
++ SLdo_pop_n (1);
++ return NULL;
++ }
++
++ memset ((char *) a, 0, sizeof (SLang_Assoc_Array_Type));
++ a-&gt;type = type;
++
++ if (has_default_value)
++ {
++ if (
++#if USE_NEW_ANYTYPE_CODE
++ ((type != SLANG_ANY_TYPE) &amp;&amp; (-1 == SLclass_typecast (type, 1, 1)))
++#else
++ (-1 == SLclass_typecast (type, 1, 1))
++#endif
++ || (-1 == SLang_pop (&amp;a-&gt;default_value)))
++ {
++ SLfree ((char *) a);
++ return NULL;
++ }
++
++ a-&gt;flags |= HAS_DEFAULT_VALUE;
++ }
++ return a;
++}
++
++static void free_element (_SLAssoc_Array_Element_Type *e)
++{
++ if (e == NULL)
++ return;
++
++ SLang_free_object (&amp;e-&gt;value);
++ SLang_free_slstring (e-&gt;key);
++#if USE_CACHED_STRING
++ if (e-&gt;key == Cached_String)
++ Cached_String = NULL;
++#endif
++ SLfree ((char *)e);
++}
++
++static void delete_assoc_array (SLang_Assoc_Array_Type *a)
++{
++ unsigned int i;
++
++ if (a == NULL) return;
++
++ for (i = 0; i &lt; SLASSOC_HASH_TABLE_SIZE; i++)
++ {
++ _SLAssoc_Array_Element_Type *e;
++
++ e = a-&gt;elements[i];
++ while (e != NULL)
++ {
++ _SLAssoc_Array_Element_Type *next_e;
++
++ next_e = e-&gt;next;
++ free_element (e);
++ e = next_e;
++ }
++ }
++ if (a-&gt;flags &amp; HAS_DEFAULT_VALUE)
++ SLang_free_object (&amp;a-&gt;default_value);
++
++ SLfree ((char *) a);
++}
++
++_INLINE_
++static SLang_Object_Type *
++find_element (SLang_Assoc_Array_Type *a, char *str, unsigned long hash)
++{
++ unsigned int h;
++ _SLAssoc_Array_Element_Type *e;
++
++ h = (unsigned int) (hash % SLASSOC_HASH_TABLE_SIZE);
++ e = a-&gt;elements[h];
++
++ while (e != NULL)
++ {
++ if (str == e-&gt;key) /* slstrings can be compared this way */
++ {
++#if USE_CACHED_STRING
++ Cached_String = str;
++ Cached_Obj = &amp;e-&gt;value;
++ Cached_Array = a;
++#endif
++ return &amp;e-&gt;value;
++ }
++
++ e = e-&gt;next;
++ }
++
++ return NULL;
++}
++
++static _SLAssoc_Array_Element_Type *
++create_element (SLang_Assoc_Array_Type *a, char *str, unsigned long hash)
++{
++ unsigned int h;
++ _SLAssoc_Array_Element_Type *e;
++
++ e = (_SLAssoc_Array_Element_Type *) SLmalloc (sizeof (_SLAssoc_Array_Element_Type));
++ if (e == NULL)
++ return NULL;
++
++ memset ((char *) e, 0, sizeof (_SLAssoc_Array_Element_Type));
++ h = (unsigned int) (hash % SLASSOC_HASH_TABLE_SIZE);
++
++ if (NULL == (str = _SLstring_dup_hashed_string (str, hash)))
++ {
++ SLfree ((char *) e);
++ return NULL;
++ }
++
++ e-&gt;key = str;
++ e-&gt;next = a-&gt;elements[h];
++ a-&gt;elements[h] = e;
++
++ a-&gt;num_elements += 1;
++#if USE_CACHED_STRING
++ Cached_String = str;
++ Cached_Obj = &amp;e-&gt;value;
++ Cached_Array = a;
++#endif
++ return e;
++}
++
++static int store_object (SLang_Assoc_Array_Type *a, char *s, SLang_Object_Type *obj)
++{
++ unsigned long hash;
++ SLang_Object_Type *v;
++
++#if USE_CACHED_STRING
++ if ((s == Cached_String) &amp;&amp; (a == Cached_Array))
++ {
++ v = Cached_Obj;
++ SLang_free_object (v);
++ }
++ else
++ {
++#endif
++ hash = _SLcompute_string_hash (s);
++ if (NULL != (v = find_element (a, s, hash)))
++ SLang_free_object (v);
++ else
++ {
++ _SLAssoc_Array_Element_Type *e;
++
++ e = create_element (a, s, hash);
++ if (e == NULL)
++ return -1;
++
++ v = &amp;e-&gt;value;
++ }
++#if USE_CACHED_STRING
++ }
++#endif
++
++ *v = *obj;
++
++ return 0;
++}
++
++static void assoc_destroy (unsigned char type, VOID_STAR ptr)
++{
++ (void) type;
++ delete_assoc_array ((SLang_Assoc_Array_Type *) ptr);
++}
++
++static int pop_index (unsigned int num_indices,
++ SLang_MMT_Type **mmt,
++ SLang_Assoc_Array_Type **a,
++ char **str)
++{
++ if (NULL == (*mmt = SLang_pop_mmt (SLANG_ASSOC_TYPE)))
++ {
++ *a = NULL;
++ *str = NULL;
++ return -1;
++ }
++
++ if ((num_indices != 1)
++ || (-1 == SLang_pop_slstring (str)))
++ {
++ SLang_verror (SL_NOT_IMPLEMENTED,
++ &quot;Assoc_Type arrays require a single string index&quot;);
++ SLang_free_mmt (*mmt);
++ *mmt = NULL;
++ *a = NULL;
++ *str = NULL;
++ return -1;
++ }
++
++ *a = (SLang_Assoc_Array_Type *) SLang_object_from_mmt (*mmt);
++ return 0;
++}
++
++static int assoc_aget (unsigned char type, unsigned int num_indices)
++{
++ SLang_MMT_Type *mmt;
++ char *str;
++ SLang_Assoc_Array_Type *a;
++ SLang_Object_Type *obj;
++ int ret;
++
++ (void) type;
++
++ if (-1 == pop_index (num_indices, &amp;mmt, &amp;a, &amp;str))
++ return -1;
++
++#if USE_CACHED_STRING
++ if ((str == Cached_String) &amp;&amp; (a == Cached_Array))
++ obj = Cached_Obj;
++ else
++#endif
++ obj = find_element (a, str, _SLcompute_string_hash (str));
++
++ if ((obj == NULL)
++ &amp;&amp; (a-&gt;flags &amp; HAS_DEFAULT_VALUE))
++ obj = &amp;a-&gt;default_value;
++
++ if (obj == NULL)
++ {
++ SLang_verror (SL_INTRINSIC_ERROR,
++ &quot;No such element in Assoc Array: %s&quot;, str);
++ ret = -1;
++ }
++ else
++ {
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ if (SLANG_CLASS_TYPE_SCALAR == _SLclass_Class_Type[obj-&gt;data_type])
++ ret = SLang_push (obj);
++#endif
++ else
++ ret = _SLpush_slang_obj (obj);
++ }
++
++ SLang_free_slstring (str);
++ SLang_free_mmt (mmt);
++ return ret;
++}
++
++static int assoc_aput (unsigned char type, unsigned int num_indices)
++{
++ SLang_MMT_Type *mmt;
++ char *str;
++ SLang_Assoc_Array_Type *a;
++ SLang_Object_Type obj;
++ int ret;
++
++ (void) type;
++
++ if (-1 == pop_index (num_indices, &amp;mmt, &amp;a, &amp;str))
++ return -1;
++
++ ret = -1;
++
++ if (0 == SLang_pop (&amp;obj))
++ {
++ if ((obj.data_type != a-&gt;type)
++#if USE_NEW_ANYTYPE_CODE
++ &amp;&amp; (a-&gt;type != SLANG_ANY_TYPE)
++#endif
++ )
++ {
++ (void) SLang_push (&amp;obj);
++ if ((-1 == SLclass_typecast (a-&gt;type, 1, 1))
++ || (-1 == SLang_pop (&amp;obj)))
++ goto the_return;
++ }
++
++ if (-1 == store_object (a, str, &amp;obj))
++ SLang_free_object (&amp;obj);
++ else
++ ret = 0;
++ }
++
++ the_return:
++ SLang_free_slstring (str);
++ SLang_free_mmt (mmt);
++ return ret;
++}
++
++static int assoc_anew (unsigned char type, unsigned int num_dims)
++{
++ SLang_MMT_Type *mmt;
++ SLang_Assoc_Array_Type *a;
++ int has_default_value;
++
++ has_default_value = 0;
++ switch (num_dims)
++ {
++ case 0:
++ type = SLANG_ANY_TYPE;
++ break;
++ case 2:
++ (void) SLreverse_stack (2);
++ has_default_value = 1;
++ /* drop */
++ case 1:
++ if (0 == _SLang_pop_datatype (&amp;type))
++ break;
++ num_dims--;
++ /* drop */
++ default:
++ SLdo_pop_n (num_dims);
++ SLang_verror (SL_SYNTAX_ERROR, &quot;Usage: Assoc_Type [DataType_Type]&quot;);
++ return -1;
++ }
++
++ a = alloc_assoc_array (type, has_default_value);
++ if (a == NULL)
++ return -1;
++
++ if (NULL == (mmt = SLang_create_mmt (SLANG_ASSOC_TYPE, (VOID_STAR) a)))
++ {
++ delete_assoc_array (a);
++ return -1;
++ }
++
++ if (-1 == SLang_push_mmt (mmt))
++ {
++ SLang_free_mmt (mmt);
++ return -1;
++ }
++
++ return 0;
++}
++
++static void assoc_get_keys (SLang_Assoc_Array_Type *a)
++{
++ SLang_Array_Type *at;
++ int num;
++ unsigned int i, j;
++ char **data;
++
++ /* Note: If support for threads is added, then we need to modify this
++ * algorithm to prevent another thread from modifying the array.
++ * However, that should be handled in inner_interp.
++ */
++ num = a-&gt;num_elements;
++
++ if (NULL == (at = SLang_create_array (SLANG_STRING_TYPE, 0, NULL, &amp;num, 1)))
++ return;
++
++ data = (char **)at-&gt;data;
++
++ i = 0;
++ for (j = 0; j &lt; SLASSOC_HASH_TABLE_SIZE; j++)
++ {
++ _SLAssoc_Array_Element_Type *e;
++
++ e = a-&gt;elements[j];
++ while (e != NULL)
++ {
++ /* Next cannot fail because it is an slstring */
++ data [i] = SLang_create_slstring (e-&gt;key);
++ e = e-&gt;next;
++ i++;
++ }
++ }
++ (void) SLang_push_array (at, 1);
++}
++
++static int
++transfer_element (SLang_Class_Type *cl, VOID_STAR dest_data,
++ SLang_Object_Type *obj)
++{
++ unsigned int sizeof_type;
++ VOID_STAR src_data;
++
++#if USE_NEW_ANYTYPE_CODE
++ if (cl-&gt;cl_data_type == SLANG_ANY_TYPE)
++ {
++ SLang_Any_Type *any;
++
++ if ((-1 == _SLpush_slang_obj (obj))
++ || (-1 == SLang_pop_anytype (&amp;any)))
++ return -1;
++
++ *(SLang_Any_Type **)dest_data = any;
++ return 0;
++ }
++#endif
++ /* Optimize for scalar */
++ if (cl-&gt;cl_class_type == SLANG_CLASS_TYPE_SCALAR)
++ {
++ sizeof_type = cl-&gt;cl_sizeof_type;
++ memcpy ((char *) dest_data, (char *)&amp;obj-&gt;v, sizeof_type);
++ return 0;
++ }
++
++ src_data = _SLclass_get_ptr_to_value (cl, obj);
++
++ if (-1 == (*cl-&gt;cl_acopy) (cl-&gt;cl_data_type, src_data, dest_data))
++ return -1;
++
++ return 0;
++}
++
++static void assoc_get_values (SLang_Assoc_Array_Type *a)
++{
++ SLang_Array_Type *at;
++ int num;
++ unsigned int i, j;
++ char *dest_data;
++ unsigned char type;
++ SLang_Class_Type *cl;
++ unsigned int sizeof_type;
++
++ /* Note: If support for threads is added, then we need to modify this
++ * algorithm to prevent another thread from modifying the array.
++ * However, that should be handled in inner_interp.
++ */
++ num = a-&gt;num_elements;
++ type = a-&gt;type;
++
++ cl = _SLclass_get_class (type);
++ sizeof_type = cl-&gt;cl_sizeof_type;
++
++ if (NULL == (at = SLang_create_array (type, 0, NULL, &amp;num, 1)))
++ return;
++
++ dest_data = (char *)at-&gt;data;
++
++ i = 0;
++ for (j = 0; j &lt; SLASSOC_HASH_TABLE_SIZE; j++)
++ {
++ _SLAssoc_Array_Element_Type *e;
++
++ e = a-&gt;elements[j];
++ while (e != NULL)
++ {
++ if (-1 == transfer_element (cl, (VOID_STAR) dest_data, &amp;e-&gt;value))
++ {
++ SLang_free_array (at);
++ return;
++ }
++
++ dest_data += sizeof_type;
++ e = e-&gt;next;
++ i++;
++ }
++ }
++ (void) SLang_push_array (at, 1);
++}
++
++static int assoc_key_exists (SLang_Assoc_Array_Type *a, char *key)
++{
++ return (NULL != find_element (a, key, _SLcompute_string_hash (key)));
++}
++
++static void assoc_delete_key (SLang_Assoc_Array_Type *a, char *key)
++{
++ unsigned int h;
++ _SLAssoc_Array_Element_Type *v, *v0;
++
++ h = (unsigned int) (_SLcompute_string_hash (key) % SLASSOC_HASH_TABLE_SIZE);
++
++ v0 = NULL;
++ v = a-&gt;elements[h];
++ while (v != NULL)
++ {
++ if (v-&gt;key == key)
++ {
++ if (v0 != NULL)
++ v0-&gt;next = v-&gt;next;
++ else
++ a-&gt;elements[h] = v-&gt;next;
++
++ free_element (v);
++ a-&gt;num_elements -= 1;
++ return;
++ }
++ v0 = v;
++ v = v-&gt;next;
++ }
++
++ /* No such element. Let it pass with no error. */
++}
++
++#define A SLANG_ASSOC_TYPE
++#define S SLANG_STRING_TYPE
++static SLang_Intrin_Fun_Type Assoc_Table [] =
++{
++ MAKE_INTRINSIC_1(&quot;assoc_get_keys&quot;, assoc_get_keys, SLANG_VOID_TYPE, A),
++ MAKE_INTRINSIC_1(&quot;assoc_get_values&quot;, assoc_get_values, SLANG_VOID_TYPE, A),
++ MAKE_INTRINSIC_2(&quot;assoc_key_exists&quot;, assoc_key_exists, SLANG_INT_TYPE, A, S),
++ MAKE_INTRINSIC_2(&quot;assoc_delete_key&quot;, assoc_delete_key, SLANG_VOID_TYPE, A, S),
++
++ SLANG_END_INTRIN_FUN_TABLE
++};
++#undef A
++#undef S
++
++static int assoc_length (unsigned char type, VOID_STAR v, unsigned int *len)
++{
++ SLang_Assoc_Array_Type *a;
++
++ (void) type;
++ a = (SLang_Assoc_Array_Type *) SLang_object_from_mmt (*(SLang_MMT_Type **)v);
++ *len = a-&gt;num_elements;
++ return 0;
++}
++
++struct _SLang_Foreach_Context_Type
++{
++ SLang_MMT_Type *mmt;
++ SLang_Assoc_Array_Type *a;
++ unsigned int this_hash_index;
++ unsigned int next_same_hash_index;
++#define CTX_WRITE_KEYS 1
++#define CTX_WRITE_VALUES 2
++ unsigned char flags;
++};
++
++static SLang_Foreach_Context_Type *
++cl_foreach_open (unsigned char type, unsigned int num)
++{
++ SLang_Foreach_Context_Type *c;
++ unsigned char flags;
++ SLang_MMT_Type *mmt;
++
++ (void) type;
++
++ if (NULL == (mmt = SLang_pop_mmt (SLANG_ASSOC_TYPE)))
++ return NULL;
++
++ flags = 0;
++
++ while (num--)
++ {
++ char *s;
++
++ if (-1 == SLang_pop_slstring (&amp;s))
++ {
++ SLang_free_mmt (mmt);
++ return NULL;
++ }
++
++ if (0 == strcmp (s, &quot;keys&quot;))
++ flags |= CTX_WRITE_KEYS;
++ else if (0 == strcmp (s, &quot;values&quot;))
++ flags |= CTX_WRITE_VALUES;
++ else
++ {
++ SLang_verror (SL_NOT_IMPLEMENTED,
++ &quot;using '%s' not supported by SLassoc_Type&quot;,
++ s);
++ SLang_free_slstring (s);
++ SLang_free_mmt (mmt);
++ return NULL;
++ }
++
++ SLang_free_slstring (s);
++ }
++
++ if (NULL == (c = (SLang_Foreach_Context_Type *) SLmalloc (sizeof (SLang_Foreach_Context_Type))))
++ {
++ SLang_free_mmt (mmt);
++ return NULL;
++ }
++
++ memset ((char *) c, 0, sizeof (SLang_Foreach_Context_Type));
++
++ if (flags == 0) flags = CTX_WRITE_VALUES|CTX_WRITE_KEYS;
++
++ c-&gt;flags = flags;
++ c-&gt;mmt = mmt;
++ c-&gt;a = (SLang_Assoc_Array_Type *) SLang_object_from_mmt (mmt);
++
++ return c;
++}
++
++static void cl_foreach_close (unsigned char type, SLang_Foreach_Context_Type *c)
++{
++ (void) type;
++ if (c == NULL) return;
++ SLang_free_mmt (c-&gt;mmt);
++ SLfree ((char *) c);
++}
++
++static int cl_foreach (unsigned char type, SLang_Foreach_Context_Type *c)
++{
++ SLang_Assoc_Array_Type *a;
++ _SLAssoc_Array_Element_Type *e;
++ unsigned int i, j;
++
++ (void) type;
++
++ if (c == NULL)
++ return -1;
++
++ a = c-&gt;a;
++
++ i = c-&gt;this_hash_index;
++ if (i &gt;= SLASSOC_HASH_TABLE_SIZE)
++ return 0;
++
++ e = a-&gt;elements[i];
++
++ j = c-&gt;next_same_hash_index;
++ c-&gt;next_same_hash_index = j + 1;
++
++ while ((j &gt; 0) &amp;&amp; (e != NULL))
++ {
++ j--;
++ e = e-&gt;next;
++ }
++
++ if (e == NULL)
++ {
++ do
++ {
++ i++;
++ if (i &gt;= SLASSOC_HASH_TABLE_SIZE)
++ return 0; /* no more */
++ }
++ while (a-&gt;elements [i] == NULL);
++
++ e = a-&gt;elements[i];
++ c-&gt;this_hash_index = i;
++ c-&gt;next_same_hash_index = 1;
++ }
++
++ if ((c-&gt;flags &amp; CTX_WRITE_KEYS)
++ &amp;&amp; (-1 == SLang_push_string (e-&gt;key)))
++ return -1;
++
++ if ((c-&gt;flags &amp; CTX_WRITE_VALUES)
++ &amp;&amp; (-1 == _SLpush_slang_obj (&amp;e-&gt;value)))
++ return -1;
++
++ /* keep going */
++ return 1;
++}
++
++int SLang_init_slassoc (void)
++{
++ SLang_Class_Type *cl;
++
++ if (SLclass_is_class_defined (SLANG_ASSOC_TYPE))
++ return 0;
++
++ if (NULL == (cl = SLclass_allocate_class (&quot;Assoc_Type&quot;)))
++ return -1;
++
++ (void) SLclass_set_destroy_function (cl, assoc_destroy);
++ (void) SLclass_set_aput_function (cl, assoc_aput);
++ (void) SLclass_set_aget_function (cl, assoc_aget);
++ (void) SLclass_set_anew_function (cl, assoc_anew);
++ cl-&gt;cl_length = assoc_length;
++ cl-&gt;cl_foreach_open = cl_foreach_open;
++ cl-&gt;cl_foreach_close = cl_foreach_close;
++ cl-&gt;cl_foreach = cl_foreach;
++
++ if (-1 == SLclass_register_class (cl, SLANG_ASSOC_TYPE, sizeof (SLang_Assoc_Array_Type), SLANG_CLASS_TYPE_MMT))
++ return -1;
++
++ if (-1 == SLadd_intrin_fun_table (Assoc_Table, &quot;__SLASSOC__&quot;))
++ return -1;
++
++ return 0;
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slassoc.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slbstr.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slbstr.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slbstr.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,615 @@
++/* Copyright (c) 1998, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++struct _SLang_BString_Type
++{
++ unsigned int num_refs;
++ unsigned int len;
++ int ptr_type;
++#define IS_SLSTRING 1
++#define IS_MALLOCED 2
++#define IS_NOT_TO_BE_FREED 3
++ union
++ {
++ unsigned char bytes[1];
++ unsigned char *ptr;
++ }
++ v;
++};
++
++#define BS_GET_POINTER(b) ((b)-&gt;ptr_type ? (b)-&gt;v.ptr : (b)-&gt;v.bytes)
++
++static SLang_BString_Type *create_bstring_of_type (char *bytes, unsigned int len, int type)
++{
++ SLang_BString_Type *b;
++ unsigned int size;
++
++ size = sizeof(SLang_BString_Type);
++ if (type == 0)
++ size += len;
++
++ if (NULL == (b = (SLang_BString_Type *)SLmalloc (size)))
++ return NULL;
++
++ b-&gt;len = len;
++ b-&gt;num_refs = 1;
++ b-&gt;ptr_type = type;
++
++ switch (type)
++ {
++ case 0:
++ if (bytes != NULL) memcpy ((char *) b-&gt;v.bytes, bytes, len);
++ /* Now \0 terminate it because we want to also use it as a C string
++ * whenever possible. Note that sizeof(SLang_BString_Type) includes
++ * space for 1 character and we allocated len extra bytes. Thus, it is
++ * ok to add a \0 to the end.
++ */
++ b-&gt;v.bytes[len] = 0;
++ break;
++
++ case IS_SLSTRING:
++ if (NULL == (b-&gt;v.ptr = (unsigned char *)SLang_create_nslstring (bytes, len)))
++ {
++ SLfree ((char *) b);
++ return NULL;
++ }
++ break;
++
++ case IS_MALLOCED:
++ case IS_NOT_TO_BE_FREED:
++ b-&gt;v.ptr = (unsigned char *)bytes;
++ bytes [len] = 0; /* NULL terminate */
++ break;
++ }
++
++ return b;
++}
++
++SLang_BString_Type *
++SLbstring_create (unsigned char *bytes, unsigned int len)
++{
++ return create_bstring_of_type ((char *)bytes, len, 0);
++}
++
++/* Note that ptr must be len + 1 bytes long for \0 termination */
++SLang_BString_Type *
++SLbstring_create_malloced (unsigned char *ptr, unsigned int len, int free_on_error)
++{
++ SLang_BString_Type *b;
++
++ if (ptr == NULL)
++ return NULL;
++
++ if (NULL == (b = create_bstring_of_type ((char *)ptr, len, IS_MALLOCED)))
++ {
++ if (free_on_error)
++ SLfree ((char *) ptr);
++ }
++ return b;
++}
++
++SLang_BString_Type *SLbstring_create_slstring (char *s)
++{
++ if (s == NULL)
++ return NULL;
++
++ return create_bstring_of_type (s, strlen (s), IS_SLSTRING);
++}
++
++SLang_BString_Type *SLbstring_dup (SLang_BString_Type *b)
++{
++ if (b != NULL)
++ b-&gt;num_refs += 1;
++
++ return b;
++}
++
++unsigned char *SLbstring_get_pointer (SLang_BString_Type *b, unsigned int *len)
++{
++ if (b == NULL)
++ {
++ *len = 0;
++ return NULL;
++ }
++ *len = b-&gt;len;
++ return BS_GET_POINTER(b);
++}
++
++void SLbstring_free (SLang_BString_Type *b)
++{
++ if (b == NULL)
++ return;
++
++ if (b-&gt;num_refs &gt; 1)
++ {
++ b-&gt;num_refs -= 1;
++ return;
++ }
++
++ switch (b-&gt;ptr_type)
++ {
++ case 0:
++ case IS_NOT_TO_BE_FREED:
++ default:
++ break;
++
++ case IS_SLSTRING:
++ SLang_free_slstring ((char *)b-&gt;v.ptr);
++ break;
++
++ case IS_MALLOCED:
++ SLfree ((char *)b-&gt;v.ptr);
++ break;
++ }
++
++ SLfree ((char *) b);
++}
++
++int SLang_pop_bstring (SLang_BString_Type **b)
++{
++ return SLclass_pop_ptr_obj (SLANG_BSTRING_TYPE, (VOID_STAR *)b);
++}
++
++int SLang_push_bstring (SLang_BString_Type *b)
++{
++ if (b == NULL)
++ return SLang_push_null ();
++
++ b-&gt;num_refs += 1;
++
++ if (0 == SLclass_push_ptr_obj (SLANG_BSTRING_TYPE, (VOID_STAR)b))
++ return 0;
++
++ b-&gt;num_refs -= 1;
++ return -1;
++}
++
++static int
++bstring_bstring_bin_op_result (int op, unsigned char a, unsigned char b,
++ unsigned char *c)
++{
++ (void) a;
++ (void) b;
++ switch (op)
++ {
++ default:
++ return 0;
++
++ case SLANG_PLUS:
++ *c = SLANG_BSTRING_TYPE;
++ break;
++
++ case SLANG_GT:
++ case SLANG_GE:
++ case SLANG_LT:
++ case SLANG_LE:
++ case SLANG_EQ:
++ case SLANG_NE:
++ *c = SLANG_CHAR_TYPE;
++ break;
++ }
++ return 1;
++}
++
++static int compare_bstrings (SLang_BString_Type *a, SLang_BString_Type *b)
++{
++ unsigned int len;
++ int ret;
++
++ len = a-&gt;len;
++ if (b-&gt;len &lt; len) len = b-&gt;len;
++
++ ret = memcmp ((char *)BS_GET_POINTER(b), (char *)BS_GET_POINTER(a), len);
++ if (ret != 0)
++ return ret;
++
++ if (a-&gt;len &gt; b-&gt;len)
++ return 1;
++ if (a-&gt;len == b-&gt;len)
++ return 0;
++
++ return -1;
++}
++
++static SLang_BString_Type *
++concat_bstrings (SLang_BString_Type *a, SLang_BString_Type *b)
++{
++ unsigned int len;
++ SLang_BString_Type *c;
++ char *bytes;
++
++ len = a-&gt;len + b-&gt;len;
++
++ if (NULL == (c = SLbstring_create (NULL, len)))
++ return NULL;
++
++ bytes = (char *)BS_GET_POINTER(c);
++
++ memcpy (bytes, (char *)BS_GET_POINTER(a), a-&gt;len);
++ memcpy (bytes + a-&gt;len, (char *)BS_GET_POINTER(b), b-&gt;len);
++
++ return c;
++}
++
++static void free_n_bstrings (SLang_BString_Type **a, unsigned int n)
++{
++ unsigned int i;
++
++ if (a == NULL) return;
++
++ for (i = 0; i &lt; n; i++)
++ {
++ SLbstring_free (a[i]);
++ a[i] = NULL;
++ }
++}
++
++static int
++bstring_bstring_bin_op (int op,
++ unsigned char a_type, VOID_STAR ap, unsigned int na,
++ unsigned char b_type, VOID_STAR bp, unsigned int nb,
++ VOID_STAR cp)
++{
++ char *ic;
++ SLang_BString_Type **a, **b, **c;
++ unsigned int n, n_max;
++ unsigned int da, db;
++
++ (void) a_type;
++ (void) b_type;
++
++ if (na == 1) da = 0; else da = 1;
++ if (nb == 1) db = 0; else db = 1;
++
++ if (na &gt; nb) n_max = na; else n_max = nb;
++
++ a = (SLang_BString_Type **) ap;
++ b = (SLang_BString_Type **) bp;
++ for (n = 0; n &lt; n_max; n++)
++ {
++ if ((*a == NULL) || (*b == NULL))
++ {
++ SLang_verror (SL_VARIABLE_UNINITIALIZED,
++ &quot;Binary string element[%u] not initialized for binary operation&quot;, n);
++ return -1;
++ }
++ a += da; b += db;
++ }
++
++ a = (SLang_BString_Type **) ap;
++ b = (SLang_BString_Type **) bp;
++ ic = (char *) cp;
++ c = NULL;
++
++ switch (op)
++ {
++ case SLANG_PLUS:
++ /* Concat */
++ c = (SLang_BString_Type **) cp;
++ for (n = 0; n &lt; n_max; n++)
++ {
++ if (NULL == (c[n] = concat_bstrings (*a, *b)))
++ goto return_error;
++
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_NE:
++ for (n = 0; n &lt; n_max; n++)
++ {
++ ic [n] = (0 != compare_bstrings (*a, *b));
++ a += da;
++ b += db;
++ }
++ break;
++ case SLANG_GT:
++ for (n = 0; n &lt; n_max; n++)
++ {
++ ic [n] = (compare_bstrings (*a, *b) &gt; 0);
++ a += da;
++ b += db;
++ }
++ break;
++ case SLANG_GE:
++ for (n = 0; n &lt; n_max; n++)
++ {
++ ic [n] = (compare_bstrings (*a, *b) &gt;= 0);
++ a += da;
++ b += db;
++ }
++ break;
++ case SLANG_LT:
++ for (n = 0; n &lt; n_max; n++)
++ {
++ ic [n] = (compare_bstrings (*a, *b) &lt; 0);
++ a += da;
++ b += db;
++ }
++ break;
++ case SLANG_LE:
++ for (n = 0; n &lt; n_max; n++)
++ {
++ ic [n] = (compare_bstrings (*a, *b) &lt;= 0);
++ a += da;
++ b += db;
++ }
++ break;
++ case SLANG_EQ:
++ for (n = 0; n &lt; n_max; n++)
++ {
++ ic [n] = (compare_bstrings (*a, *b) == 0);
++ a += da;
++ b += db;
++ }
++ break;
++ }
++ return 1;
++
++ return_error:
++ if (c != NULL)
++ {
++ free_n_bstrings (c, n);
++ while (n &lt; n_max)
++ {
++ c[n] = NULL;
++ n++;
++ }
++ }
++ return -1;
++}
++
++/* If preserve_ptr, then use a[i] as the bstring data. See how this function
++ * is called by the binary op routines for why.
++ */
++static SLang_BString_Type **
++make_n_bstrings (SLang_BString_Type **b, char **a, unsigned int n, int ptr_type)
++{
++ unsigned int i;
++ int malloc_flag;
++
++ malloc_flag = 0;
++ if (b == NULL)
++ {
++ b = (SLang_BString_Type **) SLmalloc ((n + 1) * sizeof (SLang_BString_Type *));
++ if (b == NULL)
++ return NULL;
++ malloc_flag = 1;
++ }
++
++ for (i = 0; i &lt; n; i++)
++ {
++ char *s = a[i];
++
++ if (s == NULL)
++ {
++ b[i] = NULL;
++ continue;
++ }
++
++ if (NULL == (b[i] = create_bstring_of_type (s, strlen(s), ptr_type)))
++ {
++ free_n_bstrings (b, i);
++ if (malloc_flag) SLfree ((char *) b);
++ return NULL;
++ }
++ }
++
++ return b;
++}
++
++static int
++bstring_string_bin_op (int op,
++ unsigned char a_type, VOID_STAR ap, unsigned int na,
++ unsigned char b_type, VOID_STAR bp, unsigned int nb,
++ VOID_STAR cp)
++{
++ SLang_BString_Type **b;
++ int ret;
++
++ if (NULL == (b = make_n_bstrings (NULL, (char **)bp, nb, IS_NOT_TO_BE_FREED)))
++ return -1;
++
++ b_type = SLANG_BSTRING_TYPE;
++ ret = bstring_bstring_bin_op (op,
++ a_type, ap, na,
++ b_type, (VOID_STAR) b, nb,
++ cp);
++ free_n_bstrings (b, nb);
++ SLfree ((char *) b);
++ return ret;
++}
++
++static int
++string_bstring_bin_op (int op,
++ unsigned char a_type, VOID_STAR ap, unsigned int na,
++ unsigned char b_type, VOID_STAR bp, unsigned int nb,
++ VOID_STAR cp)
++{
++ SLang_BString_Type **a;
++ int ret;
++
++ if (NULL == (a = make_n_bstrings (NULL, (char **)ap, na, IS_NOT_TO_BE_FREED)))
++ return -1;
++
++ a_type = SLANG_BSTRING_TYPE;
++ ret = bstring_bstring_bin_op (op,
++ a_type, (VOID_STAR) a, na,
++ b_type, bp, nb,
++ cp);
++ free_n_bstrings (a, na);
++ SLfree ((char *) a);
++
++ return ret;
++}
++
++static void bstring_destroy (unsigned char unused, VOID_STAR s)
++{
++ (void) unused;
++ SLbstring_free (*(SLang_BString_Type **) s);
++}
++
++static int bstring_push (unsigned char unused, VOID_STAR sptr)
++{
++ (void) unused;
++
++ return SLang_push_bstring (*(SLang_BString_Type **) sptr);
++}
++
++static int string_to_bstring (unsigned char a_type, VOID_STAR ap, unsigned int na,
++ unsigned char b_type, VOID_STAR bp)
++{
++ char **s;
++ SLang_BString_Type **b;
++
++ (void) a_type;
++ (void) b_type;
++
++ s = (char **) ap;
++ b = (SLang_BString_Type **) bp;
++
++ if (NULL == make_n_bstrings (b, s, na, IS_SLSTRING))
++ return -1;
++
++ return 1;
++}
++
++static int bstring_to_string (unsigned char a_type, VOID_STAR ap, unsigned int na,
++ unsigned char b_type, VOID_STAR bp)
++{
++ char **s;
++ unsigned int i;
++ SLang_BString_Type **a;
++
++ (void) a_type;
++ (void) b_type;
++
++ s = (char **) bp;
++ a = (SLang_BString_Type **) ap;
++
++ for (i = 0; i &lt; na; i++)
++ {
++ SLang_BString_Type *ai = a[i];
++
++ if (ai == NULL)
++ {
++ s[i] = NULL;
++ continue;
++ }
++
++ if (NULL == (s[i] = SLang_create_slstring ((char *)BS_GET_POINTER(ai))))
++ {
++ while (i != 0)
++ {
++ i--;
++ SLang_free_slstring (s[i]);
++ s[i] = NULL;
++ }
++ return -1;
++ }
++ }
++
++ return 1;
++}
++
++static char *bstring_string (unsigned char type, VOID_STAR v)
++{
++ SLang_BString_Type *s;
++ unsigned char buf[128];
++ unsigned char *bytes, *bytes_max;
++ unsigned char *b, *bmax;
++
++ (void) type;
++
++ s = *(SLang_BString_Type **) v;
++ bytes = BS_GET_POINTER(s);
++ bytes_max = bytes + s-&gt;len;
++
++ b = buf;
++ bmax = buf + (sizeof (buf) - 4);
++
++ while (bytes &lt; bytes_max)
++ {
++ unsigned char ch = *bytes;
++
++ if ((ch &lt; 32) || (ch &gt;= 127) || (ch == '\\'))
++ {
++ if (b + 4 &gt; bmax)
++ break;
++
++ sprintf ((char *) b, &quot;\\%03o&quot;, ch);
++ b += 4;
++ }
++ else
++ {
++ if (b == bmax)
++ break;
++
++ *b++ = ch;
++ }
++
++ bytes++;
++ }
++
++ if (bytes &lt; bytes_max)
++ {
++ *b++ = '.';
++ *b++ = '.';
++ *b++ = '.';
++ }
++ *b = 0;
++
++ return SLmake_string ((char *)buf);
++}
++
++static unsigned int bstrlen_cmd (SLang_BString_Type *b)
++{
++ return b-&gt;len;
++}
++
++static SLang_Intrin_Fun_Type BString_Table [] = /*{{{*/
++{
++ MAKE_INTRINSIC_1(&quot;bstrlen&quot;, bstrlen_cmd, SLANG_UINT_TYPE, SLANG_BSTRING_TYPE),
++ MAKE_INTRINSIC_0(&quot;pack&quot;, _SLpack, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_2(&quot;unpack&quot;, _SLunpack, SLANG_VOID_TYPE, SLANG_STRING_TYPE, SLANG_BSTRING_TYPE),
++ MAKE_INTRINSIC_1(&quot;pad_pack_format&quot;, _SLpack_pad_format, SLANG_VOID_TYPE, SLANG_STRING_TYPE),
++ MAKE_INTRINSIC_1(&quot;sizeof_pack&quot;, _SLpack_compute_size, SLANG_UINT_TYPE, SLANG_STRING_TYPE),
++ SLANG_END_INTRIN_FUN_TABLE
++};
++
++int _SLang_init_bstring (void)
++{
++ SLang_Class_Type *cl;
++
++ if (NULL == (cl = SLclass_allocate_class (&quot;BString_Type&quot;)))
++ return -1;
++ (void) SLclass_set_destroy_function (cl, bstring_destroy);
++ (void) SLclass_set_push_function (cl, bstring_push);
++ (void) SLclass_set_string_function (cl, bstring_string);
++
++ if (-1 == SLclass_register_class (cl, SLANG_BSTRING_TYPE, sizeof (char *),
++ SLANG_CLASS_TYPE_PTR))
++ return -1;
++
++ if ((-1 == SLclass_add_typecast (SLANG_BSTRING_TYPE, SLANG_STRING_TYPE, bstring_to_string, 1))
++ || (-1 == SLclass_add_typecast (SLANG_STRING_TYPE, SLANG_BSTRING_TYPE, string_to_bstring, 1))
++ || (-1 == SLclass_add_binary_op (SLANG_BSTRING_TYPE, SLANG_BSTRING_TYPE, bstring_bstring_bin_op, bstring_bstring_bin_op_result))
++ || (-1 == SLclass_add_binary_op (SLANG_STRING_TYPE, SLANG_BSTRING_TYPE, string_bstring_bin_op, bstring_bstring_bin_op_result))
++ || (-1 == SLclass_add_binary_op (SLANG_BSTRING_TYPE, SLANG_STRING_TYPE, bstring_string_bin_op, bstring_bstring_bin_op_result)))
++
++ return -1;
++
++ if (-1 == SLadd_intrin_fun_table (BString_Table, NULL))
++ return -1;
++
++ return 0;
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slbstr.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slclass.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slclass.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slclass.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1391 @@
++/* User defined objects */
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++#if _SLANG_OPTIMIZE_FOR_SPEED
++unsigned char _SLclass_Class_Type [256];
++#endif
++
++static SLang_Class_Type *Registered_Types[256];
++SLang_Class_Type *_SLclass_get_class (unsigned char type)
++{
++ SLang_Class_Type *cl;
++
++ cl = Registered_Types [type];
++ if (cl == NULL)
++ SLang_exit_error (&quot;Application error: Type %d not registered&quot;, (int) type);
++
++ return cl;
++}
++
++int SLclass_is_class_defined (unsigned char type)
++{
++ return (NULL != Registered_Types[type]);
++}
++
++VOID_STAR _SLclass_get_ptr_to_value (SLang_Class_Type *cl,
++ SLang_Object_Type *obj)
++{
++ VOID_STAR p;
++
++ switch (cl-&gt;cl_class_type)
++ {
++ case SLANG_CLASS_TYPE_MMT:
++ case SLANG_CLASS_TYPE_PTR:
++ case SLANG_CLASS_TYPE_SCALAR:
++ p = (VOID_STAR) &amp;obj-&gt;v;
++ break;
++
++ case SLANG_CLASS_TYPE_VECTOR:
++ p = obj-&gt;v.ptr_val;
++ break;
++
++ default:
++ p = NULL;
++ }
++ return p;
++}
++
++char *SLclass_get_datatype_name (unsigned char stype)
++{
++ SLang_Class_Type *cl;
++
++ cl = _SLclass_get_class (stype);
++ return cl-&gt;cl_name;
++}
++
++static int method_undefined_error (unsigned char type, char *method, char *name)
++{
++ if (name == NULL) name = SLclass_get_datatype_name (type);
++
++ SLang_verror (SL_TYPE_MISMATCH, &quot;%s method not defined for %s&quot;,
++ method, name);
++ return -1;
++}
++
++static int
++scalar_vector_bin_op_result (int op, unsigned char a, unsigned char b,
++ unsigned char *c)
++{
++ (void) a; (void) b;
++ switch (op)
++ {
++ case SLANG_NE:
++ case SLANG_EQ:
++ *c = SLANG_INT_TYPE;
++ return 1;
++ }
++ return 0;
++}
++
++static int
++scalar_vector_bin_op (int op,
++ unsigned char a_type, VOID_STAR ap, unsigned int na,
++ unsigned char b_type, VOID_STAR bp, unsigned int nb,
++ VOID_STAR cp)
++{
++ int *c;
++ char *a, *b;
++ unsigned int da, db;
++ unsigned int n, n_max;
++ unsigned int data_type_len;
++ SLang_Class_Type *cl;
++
++ (void) b_type;
++ cl = _SLclass_get_class (a_type);
++
++ data_type_len = cl-&gt;cl_sizeof_type;
++
++ a = (char *) ap;
++ b = (char *) bp;
++ c = (int *) cp;
++
++ if (na == 1) da = 0; else da = data_type_len;
++ if (nb == 1) db = 0; else db = data_type_len;
++ if (na &gt; nb) n_max = na; else n_max = nb;
++
++ switch (op)
++ {
++ default:
++ return 0;
++
++ case SLANG_NE:
++ for (n = 0; n &lt; n_max; n++)
++ {
++ c[n] = (0 != SLMEMCMP(a, b, data_type_len));
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_EQ:
++ for (n = 0; n &lt; n_max; n++)
++ {
++ c[n] = (0 == SLMEMCMP(a, b, data_type_len));
++ a += da; b += db;
++ }
++ break;
++ }
++ return 1;
++}
++
++static int scalar_fread (unsigned char type, FILE *fp, VOID_STAR ptr,
++ unsigned int desired, unsigned int *actual)
++{
++ unsigned int n;
++
++ n = fread ((char *) ptr, _SLclass_get_class (type)-&gt;cl_sizeof_type,
++ desired, fp);
++ *actual = n;
++ return 0;
++}
++
++static int scalar_fwrite (unsigned char type, FILE *fp, VOID_STAR ptr,
++ unsigned int desired, unsigned int *actual)
++{
++ unsigned int n;
++
++ n = fwrite ((char *) ptr, _SLclass_get_class (type)-&gt;cl_sizeof_type,
++ desired, fp);
++ *actual = n;
++ return 0;
++}
++
++static int vector_apush (unsigned char type, VOID_STAR ptr)
++{
++ SLang_Class_Type *cl;
++
++ cl = _SLclass_get_class (type);
++ return (*cl-&gt;cl_push)(type, (VOID_STAR) &amp;ptr);
++}
++
++static int vector_apop (unsigned char type, VOID_STAR ptr)
++{
++ SLang_Class_Type *cl;
++
++ cl = _SLclass_get_class (type);
++ return (*cl-&gt;cl_pop)(type, (VOID_STAR) &amp;ptr);
++}
++
++static int default_push_mmt (unsigned char type_unused, VOID_STAR ptr)
++{
++ SLang_MMT_Type *ref;
++
++ (void) type_unused;
++ ref = *(SLang_MMT_Type **) ptr;
++ return SLang_push_mmt (ref);
++}
++
++static void default_destroy_simple (unsigned char type_unused, VOID_STAR ptr_unused)
++{
++ (void) type_unused;
++ (void) ptr_unused;
++}
++
++static void default_destroy_user (unsigned char type, VOID_STAR ptr)
++{
++ (void) type;
++ SLang_free_mmt (*(SLang_MMT_Type **) ptr);
++}
++
++static int default_pop (unsigned char type, VOID_STAR ptr)
++{
++ return SLclass_pop_ptr_obj (type, (VOID_STAR *) ptr);
++}
++
++static int default_datatype_deref (unsigned char type)
++{
++ return method_undefined_error (type, &quot;datatype_deref&quot;, NULL);
++}
++
++static int default_acopy (unsigned char type, VOID_STAR from, VOID_STAR to)
++{
++ SLang_Class_Type *cl;
++
++ cl = _SLclass_get_class (type);
++ if (-1 == (*cl-&gt;cl_apush) (type, from))
++ return -1;
++ return (*cl-&gt;cl_apop) (type, to);
++}
++
++static int default_dereference_object (unsigned char type, VOID_STAR ptr)
++{
++ (void) ptr;
++ return method_undefined_error (type, &quot;dereference&quot;, NULL);
++}
++
++static char *default_string (unsigned char stype, VOID_STAR v)
++{
++ char buf [256];
++ char *s;
++#if SLANG_HAS_COMPLEX
++ double *cplx;
++#endif
++ s = buf;
++
++ switch (stype)
++ {
++ case SLANG_STRING_TYPE:
++ s = *(char **) v;
++ break;
++
++ case SLANG_NULL_TYPE:
++ s = &quot;NULL&quot;;
++ break;
++
++ case SLANG_DATATYPE_TYPE:
++ s = SLclass_get_datatype_name ((unsigned char) *(int *)v);
++ break;
++
++#if SLANG_HAS_COMPLEX
++ case SLANG_COMPLEX_TYPE:
++ cplx = *(double **) v;
++ if (cplx[1] &lt; 0)
++ sprintf (s, &quot;(%g - %gi)&quot;, cplx [0], -cplx [1]);
++ else
++ sprintf (s, &quot;(%g + %gi)&quot;, cplx [0], cplx [1]);
++ break;
++#endif
++ default:
++ s = SLclass_get_datatype_name (stype);
++ }
++
++ return SLmake_string (s);
++}
++
++static int
++use_cmp_bin_op_result (int op, unsigned char a, unsigned char b,
++ unsigned char *c)
++{
++ if (a != b)
++ return 0;
++ switch (op)
++ {
++ case SLANG_NE:
++ case SLANG_EQ:
++ case SLANG_LT:
++ case SLANG_LE:
++ case SLANG_GT:
++ case SLANG_GE:
++ *c = SLANG_INT_TYPE;
++ return 1;
++ }
++ return 0;
++}
++
++static int
++use_cmp_bin_op (int op,
++ unsigned char a_type, VOID_STAR ap, unsigned int na,
++ unsigned char b_type, VOID_STAR bp, unsigned int nb,
++ VOID_STAR cp)
++{
++ int *c;
++ char *a, *b;
++ unsigned int da, db;
++ unsigned int n, n_max;
++ unsigned int data_type_len;
++ SLang_Class_Type *cl;
++ int (*cmp)(unsigned char, VOID_STAR, VOID_STAR, int *);
++
++ (void) b_type;
++ cl = _SLclass_get_class (a_type);
++ cmp = cl-&gt;cl_cmp;
++ data_type_len = cl-&gt;cl_sizeof_type;
++
++ a = (char *) ap;
++ b = (char *) bp;
++ c = (int *) cp;
++
++ if (na == 1) da = 0; else da = data_type_len;
++ if (nb == 1) db = 0; else db = data_type_len;
++ if (na &gt; nb) n_max = na; else n_max = nb;
++
++ switch (op)
++ {
++ int result;
++
++ default:
++ return 0;
++
++ case SLANG_NE:
++ for (n = 0; n &lt; n_max; n++)
++ {
++ if (-1 == (*cmp) (a_type, (VOID_STAR)a, (VOID_STAR)b, &amp;result))
++ return -1;
++ c[n] = (result != 0);
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_EQ:
++ for (n = 0; n &lt; n_max; n++)
++ {
++ if (-1 == (*cmp) (a_type, (VOID_STAR)a, (VOID_STAR)b, &amp;result))
++ return -1;
++ c[n] = (result == 0);
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_GT:
++ for (n = 0; n &lt; n_max; n++)
++ {
++ if (-1 == (*cmp) (a_type, (VOID_STAR)a, (VOID_STAR)b, &amp;result))
++ return -1;
++ c[n] = (result &gt; 0);
++ a += da; b += db;
++ }
++ break;
++ case SLANG_GE:
++ for (n = 0; n &lt; n_max; n++)
++ {
++ if (-1 == (*cmp) (a_type, (VOID_STAR)a, (VOID_STAR)b, &amp;result))
++ return -1;
++ c[n] = (result &gt;= 0);
++ a += da; b += db;
++ }
++ break;
++ case SLANG_LT:
++ for (n = 0; n &lt; n_max; n++)
++ {
++ if (-1 == (*cmp) (a_type, (VOID_STAR)a, (VOID_STAR)b, &amp;result))
++ return -1;
++ c[n] = (result &lt; 0);
++ a += da; b += db;
++ }
++ break;
++ case SLANG_LE:
++ for (n = 0; n &lt; n_max; n++)
++ {
++ if (-1 == (*cmp) (a_type, (VOID_STAR)a, (VOID_STAR)b, &amp;result))
++ return -1;
++ c[n] = (result &lt;= 0);
++ a += da; b += db;
++ }
++ break;
++ }
++ return 1;
++}
++
++
++int SLclass_get_class_id (SLang_Class_Type *cl)
++{
++ if (cl == NULL)
++ return -1;
++ return (int) cl-&gt;cl_data_type;
++}
++
++SLang_Class_Type *SLclass_allocate_class (char *name)
++{
++ SLang_Class_Type *cl;
++ unsigned int i;
++
++ for (i = 0; i &lt; 256; i++)
++ {
++ cl = Registered_Types [i];
++ if ((cl != NULL)
++ &amp;&amp; (0 == strcmp (cl-&gt;cl_name, name)))
++ {
++ SLang_verror (SL_DUPLICATE_DEFINITION, &quot;Type name %s already exists&quot;, name);
++ return NULL;
++ }
++ }
++
++ cl = (SLang_Class_Type *) SLmalloc (sizeof (SLang_Class_Type));
++ if (cl == NULL) return NULL;
++
++ SLMEMSET ((char *) cl, 0, sizeof (SLang_Class_Type));
++
++ if (NULL == (cl-&gt;cl_name = SLang_create_slstring (name)))
++ {
++ SLfree ((char *) cl);
++ return NULL;
++ }
++
++ return cl;
++}
++
++static int DataType_Ids [256];
++
++int _SLang_push_datatype (unsigned char data_type)
++{
++ /* This data type could be a copy of another type, e.g., short and
++ * int if they are the same size (Int16 == Short). So, make sure
++ * we push the original and not the copy.
++ */
++ data_type = _SLclass_get_class (data_type)-&gt;cl_data_type;
++ return SLclass_push_int_obj (SLANG_DATATYPE_TYPE, (int) data_type);
++}
++
++static int datatype_deref (unsigned char type, VOID_STAR ptr)
++{
++ SLang_Class_Type *cl;
++ int status;
++
++ /* The parser generated code for this as if a function call were to be
++ * made. However, we are calling the deref object routine
++ * instead of the function call. So, I must simulate the function call.
++ */
++ if (-1 == _SL_increment_frame_pointer ())
++ return -1;
++
++ type = (unsigned char) *(int *) ptr;
++ cl = _SLclass_get_class (type);
++ status = (*cl-&gt;cl_datatype_deref) (type);
++
++ (void) _SL_decrement_frame_pointer ();
++ return status;
++}
++
++static int datatype_push (unsigned char type_unused, VOID_STAR ptr)
++{
++ (void) type_unused;
++ return _SLang_push_datatype (*(int *) ptr);
++}
++
++int _SLang_pop_datatype (unsigned char *type)
++{
++ int i;
++
++ if (-1 == SLclass_pop_int_obj (SLANG_DATATYPE_TYPE, &amp;i))
++ return -1;
++
++ *type = (unsigned char) i;
++ return 0;
++}
++
++static int datatype_pop (unsigned char type, VOID_STAR ptr)
++{
++ if (-1 == _SLang_pop_datatype (&amp;type))
++ return -1;
++
++ *(int *) ptr = type;
++ return 0;
++}
++
++int _SLclass_init (void)
++{
++ SLang_Class_Type *cl;
++
++ /* First initialize the container classes. This is so binary operations
++ * added later will work with them.
++ */
++ if (-1 == _SLarray_init_slarray ())
++ return -1;
++
++ /* DataType_Type */
++ if (NULL == (cl = SLclass_allocate_class (&quot;DataType_Type&quot;)))
++ return -1;
++ cl-&gt;cl_pop = datatype_pop;
++ cl-&gt;cl_push = datatype_push;
++ cl-&gt;cl_dereference = datatype_deref;
++ if (-1 == SLclass_register_class (cl, SLANG_DATATYPE_TYPE, sizeof(int),
++ SLANG_CLASS_TYPE_SCALAR))
++ return -1;
++
++ return 0;
++}
++
++static int register_new_datatype (char *name, unsigned char type)
++{
++ DataType_Ids [type] = type;
++ return SLadd_intrinsic_variable (name, (VOID_STAR) (DataType_Ids + type),
++ SLANG_DATATYPE_TYPE, 1);
++}
++
++int SLclass_create_synonym (char *name, unsigned char type)
++{
++ if (NULL == _SLclass_get_class (type))
++ return -1;
++
++ return register_new_datatype (name, type);
++}
++
++int _SLclass_copy_class (unsigned char to, unsigned char from)
++{
++ SLang_Class_Type *cl = _SLclass_get_class (from);
++
++ if (Registered_Types[to] != NULL)
++ SLang_exit_error (&quot;Application error: Class already exists&quot;);
++
++ Registered_Types[to] = cl;
++
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ if (to != SLANG_UNDEFINED_TYPE)
++ _SLclass_Class_Type [to] = cl-&gt;cl_class_type;
++#endif
++ return 0;
++}
++
++int SLclass_register_class (SLang_Class_Type *cl, unsigned char type, unsigned int type_size, unsigned char class_type)
++{
++ char *name;
++ unsigned int i;
++ int can_binop = 1; /* scalar_vector_bin_op should work
++ * for all data types.
++ */
++
++ if (type == SLANG_VOID_TYPE) for (i = 0; i &lt; 256; i++)
++ {
++ if ((Registered_Types[i] == NULL)
++ &amp;&amp; (i != SLANG_VOID_TYPE))
++ {
++ type = (unsigned char) i;
++ break;
++ }
++ }
++
++ if ((NULL != Registered_Types [type])
++ || (type == SLANG_VOID_TYPE))
++ {
++ SLang_verror (SL_APPLICATION_ERROR, &quot;Class type %d already in use&quot;, (int) type);
++ return -1;
++ }
++
++ cl-&gt;cl_data_type = type;
++ cl-&gt;cl_class_type = class_type;
++ name = cl-&gt;cl_name;
++
++ switch (class_type)
++ {
++ case SLANG_CLASS_TYPE_MMT:
++ if (cl-&gt;cl_push == NULL) cl-&gt;cl_push = default_push_mmt;
++ if (cl-&gt;cl_destroy == NULL)
++ return method_undefined_error (type, &quot;destroy&quot;, name);
++ cl-&gt;cl_user_destroy_fun = cl-&gt;cl_destroy;
++ cl-&gt;cl_destroy = default_destroy_user;
++ type_size = sizeof (VOID_STAR);
++ break;
++
++ case SLANG_CLASS_TYPE_SCALAR:
++ if (cl-&gt;cl_destroy == NULL) cl-&gt;cl_destroy = default_destroy_simple;
++ if ((type_size == 0)
++ || (type_size &gt; sizeof (_SL_Object_Union_Type)))
++ {
++ SLang_verror (SL_INVALID_PARM,
++ &quot;Type size for %s not appropriate for SCALAR type&quot;,
++ name);
++ return -1;
++ }
++ if (cl-&gt;cl_pop == NULL)
++ return method_undefined_error (type, &quot;pop&quot;, name);
++ if (cl-&gt;cl_fread == NULL) cl-&gt;cl_fread = scalar_fread;
++ if (cl-&gt;cl_fwrite == NULL) cl-&gt;cl_fwrite = scalar_fwrite;
++
++ can_binop = 1;
++ break;
++
++ case SLANG_CLASS_TYPE_PTR:
++ if (cl-&gt;cl_destroy == NULL)
++ return method_undefined_error (type, &quot;destroy&quot;, name);
++ type_size = sizeof (VOID_STAR);
++ break;
++
++ case SLANG_CLASS_TYPE_VECTOR:
++ if (cl-&gt;cl_destroy == NULL)
++ return method_undefined_error (type, &quot;destroy&quot;, name);
++ if (cl-&gt;cl_pop == NULL)
++ return method_undefined_error (type, &quot;pop&quot;, name);
++ cl-&gt;cl_apop = vector_apop;
++ cl-&gt;cl_apush = vector_apush;
++ cl-&gt;cl_adestroy = default_destroy_simple;
++ if (cl-&gt;cl_fread == NULL) cl-&gt;cl_fread = scalar_fread;
++ if (cl-&gt;cl_fwrite == NULL) cl-&gt;cl_fwrite = scalar_fwrite;
++ can_binop = 1;
++ break;
++
++ default:
++ SLang_verror (SL_INVALID_PARM, &quot;%s: unknown class type (%d)&quot;, name, class_type);
++ return -1;
++ }
++
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ if (type != SLANG_UNDEFINED_TYPE)
++ _SLclass_Class_Type [type] = class_type;
++#endif
++
++ if (type_size == 0)
++ {
++ SLang_verror (SL_INVALID_PARM, &quot;type size must be non-zero for %s&quot;, name);
++ return -1;
++ }
++
++ if (cl-&gt;cl_string == NULL) cl-&gt;cl_string = default_string;
++ if (cl-&gt;cl_acopy == NULL) cl-&gt;cl_acopy = default_acopy;
++ if (cl-&gt;cl_datatype_deref == NULL) cl-&gt;cl_datatype_deref = default_datatype_deref;
++
++ if (cl-&gt;cl_pop == NULL) cl-&gt;cl_pop = default_pop;
++
++ if (cl-&gt;cl_push == NULL)
++ return method_undefined_error (type, &quot;push&quot;, name);
++
++ if (cl-&gt;cl_byte_code_destroy == NULL)
++ cl-&gt;cl_byte_code_destroy = cl-&gt;cl_destroy;
++ if (cl-&gt;cl_push_literal == NULL)
++ cl-&gt;cl_push_literal = cl-&gt;cl_push;
++
++ if (cl-&gt;cl_dereference == NULL)
++ cl-&gt;cl_dereference = default_dereference_object;
++
++ if (cl-&gt;cl_apop == NULL) cl-&gt;cl_apop = cl-&gt;cl_pop;
++ if (cl-&gt;cl_apush == NULL) cl-&gt;cl_apush = cl-&gt;cl_push;
++ if (cl-&gt;cl_adestroy == NULL) cl-&gt;cl_adestroy = cl-&gt;cl_destroy;
++ if (cl-&gt;cl_push_intrinsic == NULL) cl-&gt;cl_push_intrinsic = cl-&gt;cl_push;
++
++ if ((cl-&gt;cl_foreach == NULL)
++ || (cl-&gt;cl_foreach_open == NULL)
++ || (cl-&gt;cl_foreach_close == NULL))
++ {
++ cl-&gt;cl_foreach = _SLarray_cl_foreach;
++ cl-&gt;cl_foreach_open = _SLarray_cl_foreach_open;
++ cl-&gt;cl_foreach_close = _SLarray_cl_foreach_close;
++ }
++
++ cl-&gt;cl_sizeof_type = type_size;
++
++ if (NULL == (cl-&gt;cl_transfer_buf = (VOID_STAR) SLmalloc (type_size)))
++ return -1;
++
++ Registered_Types[type] = cl;
++
++ if (-1 == register_new_datatype (name, type))
++ return -1;
++
++ if (cl-&gt;cl_cmp != NULL)
++ {
++ if (-1 == SLclass_add_binary_op (type, type, use_cmp_bin_op, use_cmp_bin_op_result))
++ return -1;
++ }
++ else if (can_binop
++ &amp;&amp; (-1 == SLclass_add_binary_op (type, type, scalar_vector_bin_op, scalar_vector_bin_op_result)))
++ return -1;
++
++ cl-&gt;cl_anytype_typecast = _SLanytype_typecast;
++
++ return 0;
++}
++
++int SLclass_add_math_op (unsigned char type,
++ int (*handler)(int,
++ unsigned char, VOID_STAR, unsigned int,
++ VOID_STAR),
++ int (*result) (int, unsigned char, unsigned char *))
++{
++ SLang_Class_Type *cl = _SLclass_get_class (type);
++
++ cl-&gt;cl_math_op = handler;
++ cl-&gt;cl_math_op_result_type = result;
++ return 0;
++}
++
++int SLclass_add_binary_op (unsigned char a, unsigned char b,
++ int (*f) (int,
++ unsigned char, VOID_STAR, unsigned int,
++ unsigned char, VOID_STAR, unsigned int,
++ VOID_STAR),
++ int (*r) (int, unsigned char, unsigned char, unsigned char *))
++{
++ SLang_Class_Type *cl;
++ SL_OOBinary_Type *ab;
++
++ if ((f == NULL) || (r == NULL))
++ {
++ SLang_verror (SL_INVALID_PARM, &quot;SLclass_add_binary_op&quot;);
++ return -1;
++ }
++
++ cl = _SLclass_get_class (a);
++ (void) _SLclass_get_class (b);
++
++ if (NULL == (ab = (SL_OOBinary_Type *) SLmalloc (sizeof(SL_OOBinary_Type))))
++ return -1;
++
++ ab-&gt;data_type = b;
++ ab-&gt;binary_function = f;
++ ab-&gt;binary_result = r;
++ ab-&gt;next = cl-&gt;cl_binary_ops;
++ cl-&gt;cl_binary_ops = ab;
++
++ if ((a != SLANG_ARRAY_TYPE)
++ &amp;&amp; (b != SLANG_ARRAY_TYPE))
++ {
++ if ((-1 == _SLarray_add_bin_op (a))
++ || (-1 == _SLarray_add_bin_op (b)))
++ return -1;
++ }
++
++ return 0;
++}
++
++int SLclass_add_unary_op (unsigned char type,
++ int (*f)(int,
++ unsigned char, VOID_STAR, unsigned int,
++ VOID_STAR),
++ int (*r)(int, unsigned char, unsigned char *))
++{
++ SLang_Class_Type *cl;
++
++ cl = _SLclass_get_class (type);
++ if ((f == NULL) || (r == NULL))
++ {
++ SLang_verror (SL_INVALID_PARM, &quot;SLclass_add_unary_op&quot;);
++ return -1;
++ }
++
++ cl-&gt;cl_unary_op = f;
++ cl-&gt;cl_unary_op_result_type = r;
++
++ return 0;
++}
++
++int SLclass_add_app_unary_op (unsigned char type,
++ int (*f)(int,
++ unsigned char, VOID_STAR, unsigned int,
++ VOID_STAR),
++ int (*r)(int, unsigned char, unsigned char *))
++{
++ SLang_Class_Type *cl;
++
++ cl = _SLclass_get_class (type);
++ if ((f == NULL) || (r == NULL))
++ {
++ SLang_verror (SL_INVALID_PARM, &quot;SLclass_add_app_unary_op&quot;);
++ return -1;
++ }
++
++ cl-&gt;cl_app_unary_op = f;
++ cl-&gt;cl_app_unary_op_result_type = r;
++
++ return 0;
++}
++
++int SLclass_set_pop_function (SLang_Class_Type *cl, int (*f)(unsigned char, VOID_STAR))
++{
++ if (cl == NULL) return -1;
++ cl-&gt;cl_pop = f;
++
++ return 0;
++}
++
++int SLclass_set_push_function (SLang_Class_Type *cl, int (*f)(unsigned char, VOID_STAR))
++{
++ if (cl == NULL) return -1;
++ cl-&gt;cl_push = f;
++
++ return 0;
++}
++
++int SLclass_set_string_function (SLang_Class_Type *cl, char *(*f)(unsigned char, VOID_STAR))
++{
++ if (cl == NULL) return -1;
++
++ cl-&gt;cl_string = f;
++ return 0;
++}
++
++int SLclass_set_destroy_function (SLang_Class_Type *cl, void (*f)(unsigned char, VOID_STAR))
++{
++ if (cl == NULL) return -1;
++
++ cl-&gt;cl_destroy = f;
++ return 0;
++}
++
++int SLclass_set_sget_function (SLang_Class_Type *cl, int (*f)(unsigned char, char *))
++{
++ if (cl == NULL) return -1;
++ cl-&gt;cl_sget = f;
++ return 0;
++}
++
++int SLclass_set_sput_function (SLang_Class_Type *cl, int (*f)(unsigned char, char *))
++{
++ if (cl == NULL) return -1;
++ cl-&gt;cl_sput = f;
++ return 0;
++}
++
++int SLclass_set_aget_function (SLang_Class_Type *cl, int (*f)(unsigned char, unsigned int))
++{
++ if (cl == NULL) return -1;
++ cl-&gt;cl_aget = f;
++ return 0;
++}
++
++int SLclass_set_aput_function (SLang_Class_Type *cl, int (*f)(unsigned char, unsigned int))
++{
++ if (cl == NULL) return -1;
++ cl-&gt;cl_aput = f;
++ return 0;
++}
++
++int SLclass_set_anew_function (SLang_Class_Type *cl, int (*f)(unsigned char, unsigned int))
++{
++ if (cl == NULL) return -1;
++ cl-&gt;cl_anew = f;
++ return 0;
++}
++
++/* Misc */
++void _SLclass_type_mismatch_error (unsigned char a, unsigned char b)
++{
++ SLang_verror (SL_TYPE_MISMATCH, &quot;Expecting %s, found %s&quot;,
++ SLclass_get_datatype_name (a),
++ SLclass_get_datatype_name (b));
++}
++
++/* */
++
++static int null_binary_fun (int op,
++ unsigned char a, VOID_STAR ap, unsigned int na,
++ unsigned char b, VOID_STAR bp, unsigned int nb,
++ VOID_STAR cp)
++{
++ int *ic;
++ unsigned int i;
++ int c;
++
++ (void) ap; (void) bp;
++
++ switch (op)
++ {
++ case SLANG_EQ:
++ c = (a == b);
++ break;
++
++ case SLANG_NE:
++ c = (a != b);
++ break;
++
++ default:
++ return 0;
++ }
++
++ if (na &gt; nb) nb = na;
++ ic = (int *) cp;
++ for (i = 0; i &lt; nb; i++)
++ ic[i] = c;
++
++ return 1;
++}
++
++static char *get_binary_op_string (int op)
++{
++ static char *ops[SLANG_MOD] =
++ {
++ &quot;+&quot;, &quot;=&quot;, &quot;*&quot;, &quot;/&quot;, &quot;==&quot;, &quot;!=&quot;, &quot;&gt;&quot;, &quot;&gt;=&quot;, &quot;&lt;&quot;, &quot;&lt;=&quot;, &quot;^&quot;,
++ &quot;or&quot;, &quot;and&quot;, &quot;&amp;&quot;, &quot;|&quot;, &quot;xor&quot;, &quot;shl&quot;, &quot;shr&quot;, &quot;mod&quot;
++ };
++
++ if ((op &gt; SLANG_MOD) || (op &lt;= 0))
++ return &quot;??&quot;;
++ return ops[op - 1];
++}
++
++int (*_SLclass_get_binary_fun (int op,
++ SLang_Class_Type *a_cl, SLang_Class_Type *b_cl,
++ SLang_Class_Type **c_cl, int do_error))
++(int,
++ unsigned char, VOID_STAR, unsigned int,
++ unsigned char, VOID_STAR, unsigned int,
++ VOID_STAR)
++{
++ SL_OOBinary_Type *bt;
++ unsigned char a, b, c;
++
++ a = a_cl-&gt;cl_data_type;
++ b = b_cl-&gt;cl_data_type;
++
++ if ((a == SLANG_NULL_TYPE) || (b == SLANG_NULL_TYPE))
++ {
++ *c_cl = _SLclass_get_class (SLANG_INT_TYPE);
++ return null_binary_fun;
++ }
++
++ bt = a_cl-&gt;cl_binary_ops;
++
++ while (bt != NULL)
++ {
++ if (bt-&gt;data_type == b)
++ {
++ if (1 != (*bt-&gt;binary_result)(op, a, b, &amp;c))
++ break;
++
++ if (c == a) *c_cl = a_cl;
++ else if (c == b) *c_cl = b_cl;
++ else *c_cl = _SLclass_get_class (c);
++
++ return bt-&gt;binary_function;
++ }
++
++ bt = bt-&gt;next;
++ }
++
++ if (do_error)
++ SLang_verror (SL_TYPE_MISMATCH, &quot;%s %s %s is not possible&quot;,
++ a_cl-&gt;cl_name, get_binary_op_string (op), b_cl-&gt;cl_name);
++
++ *c_cl = NULL;
++ return NULL;
++}
++
++int (*_SLclass_get_unary_fun (int op,
++ SLang_Class_Type *a_cl,
++ SLang_Class_Type **b_cl,
++ int utype))
++(int, unsigned char, VOID_STAR, unsigned int, VOID_STAR)
++{
++ int (*f)(int, unsigned char, VOID_STAR, unsigned int, VOID_STAR);
++ int (*r)(int, unsigned char, unsigned char *);
++ unsigned char a;
++ unsigned char b;
++
++ switch (utype)
++ {
++ case _SLANG_BC_UNARY:
++ f = a_cl-&gt;cl_unary_op;
++ r = a_cl-&gt;cl_unary_op_result_type;
++ break;
++
++ case _SLANG_BC_MATH_UNARY:
++ f = a_cl-&gt;cl_math_op;
++ r = a_cl-&gt;cl_math_op_result_type;
++ break;
++
++ case _SLANG_BC_APP_UNARY:
++ f = a_cl-&gt;cl_app_unary_op;
++ r = a_cl-&gt;cl_app_unary_op_result_type;
++ break;
++
++ default:
++ f = NULL;
++ r = NULL;
++ }
++
++ a = a_cl-&gt;cl_data_type;
++ if ((f != NULL) &amp;&amp; (r != NULL) &amp;&amp; (1 == (*r) (op, a, &amp;b)))
++ {
++ if (a == b)
++ *b_cl = a_cl;
++ else
++ *b_cl = _SLclass_get_class (b);
++ return f;
++ }
++
++ SLang_verror (SL_TYPE_MISMATCH, &quot;undefined unary operation/function on %s&quot;,
++ a_cl-&gt;cl_name);
++
++ *b_cl = NULL;
++
++ return NULL;
++}
++
++int
++SLclass_typecast (unsigned char to_type, int is_implicit, int allow_array)
++{
++ unsigned char from_type;
++ SLang_Class_Type *cl_to, *cl_from;
++ SLang_Object_Type obj;
++ VOID_STAR ap;
++ VOID_STAR bp;
++ int status;
++
++ if (-1 == SLang_pop (&amp;obj))
++ return -1;
++
++ from_type = obj.data_type;
++ if (from_type == to_type)
++ {
++ SLang_push (&amp;obj);
++ return 0;
++ }
++
++ cl_from = _SLclass_get_class (from_type);
++
++ /* Since the typecast functions are designed to work on arrays,
++ * get the pointer to the value instead of just &amp;obj.v.
++ */
++ ap = _SLclass_get_ptr_to_value (cl_from, &amp;obj);
++
++ if ((from_type == SLANG_ARRAY_TYPE)
++ &amp;&amp; (allow_array || (to_type != SLANG_ANY_TYPE)))
++ {
++ if (allow_array == 0)
++ goto return_error;
++
++ cl_to = _SLclass_get_class (SLANG_ARRAY_TYPE);
++ bp = cl_to-&gt;cl_transfer_buf;
++ status = _SLarray_typecast (from_type, ap, 1, to_type, bp, is_implicit);
++ }
++ else
++ {
++ int (*t) (unsigned char, VOID_STAR, unsigned int, unsigned char, VOID_STAR);
++
++ if (NULL == (t = _SLclass_get_typecast (from_type, to_type, is_implicit)))
++ {
++ SLang_free_object (&amp;obj);
++ return -1;
++ }
++
++ cl_to = _SLclass_get_class (to_type);
++ bp = cl_to-&gt;cl_transfer_buf;
++ status = (*t) (from_type, ap, 1, to_type, bp);
++ }
++
++ if (1 == status)
++ {
++ if (-1 == (*cl_to-&gt;cl_apush)(to_type, bp))
++ {
++ (*cl_to-&gt;cl_adestroy) (to_type, bp);
++ SLang_free_object (&amp;obj);
++ return -1;
++ }
++
++ /* cl_apush will push a copy, so destry this one */
++ (*cl_to-&gt;cl_adestroy) (to_type, bp);
++ SLang_free_object (&amp;obj);
++ return 0;
++ }
++
++ return_error:
++
++ SLang_verror (SL_TYPE_MISMATCH, &quot;Unable to typecast %s to %s&quot;,
++ cl_from-&gt;cl_name,
++ SLclass_get_datatype_name (to_type));
++ SLang_free_object (&amp;obj);
++ return -1;
++}
++
++int (*_SLclass_get_typecast (unsigned char from, unsigned char to, int is_implicit))
++(unsigned char, VOID_STAR, unsigned int,
++ unsigned char, VOID_STAR)
++{
++ SL_Typecast_Type *t;
++ SLang_Class_Type *cl_from;
++
++ cl_from = _SLclass_get_class (from);
++
++ t = cl_from-&gt;cl_typecast_funs;
++ while (t != NULL)
++ {
++ if (t-&gt;data_type != to)
++ {
++ t = t-&gt;next;
++ continue;
++ }
++
++ if (is_implicit &amp;&amp; (t-&gt;allow_implicit == 0))
++ break;
++
++ return t-&gt;typecast;
++ }
++
++ if (to == SLANG_ANY_TYPE)
++ return _SLanytype_typecast;
++
++ if ((is_implicit == 0)
++ &amp;&amp; (cl_from-&gt;cl_void_typecast != NULL))
++ return cl_from-&gt;cl_void_typecast;
++
++ SLang_verror (SL_TYPE_MISMATCH, &quot;Unable to typecast %s to %s&quot;,
++ cl_from-&gt;cl_name,
++ SLclass_get_datatype_name (to));
++
++ return NULL;
++}
++
++int
++SLclass_add_typecast (unsigned char from, unsigned char to,
++ int (*f)_PROTO((unsigned char, VOID_STAR, unsigned int,
++ unsigned char, VOID_STAR)),
++ int allow_implicit)
++{
++ SL_Typecast_Type *t;
++ SLang_Class_Type *cl;
++
++ cl = _SLclass_get_class (from);
++ if (to == SLANG_VOID_TYPE)
++ {
++ cl-&gt;cl_void_typecast = f;
++ return 0;
++ }
++
++ (void) _SLclass_get_class (to);
++
++ if (NULL == (t = (SL_Typecast_Type *) SLmalloc (sizeof (SL_Typecast_Type))))
++ return -1;
++
++ SLMEMSET((char *) t, 0, sizeof(SL_Typecast_Type));
++ t-&gt;data_type = to;
++ t-&gt;next = cl-&gt;cl_typecast_funs;
++ t-&gt;typecast = f;
++ t-&gt;allow_implicit = allow_implicit;
++
++ cl-&gt;cl_typecast_funs = t;
++
++ return 0;
++}
++
++SLang_MMT_Type *SLang_pop_mmt (unsigned char type) /*{{{*/
++{
++ SLang_MMT_Type *mmt;
++
++ if (-1 == SLclass_pop_ptr_obj (type, (VOID_STAR *) &amp;mmt))
++ mmt = NULL;
++ return mmt;
++
++#if 0
++ SLang_Object_Type obj;
++ SLang_Class_Type *cl;
++
++ if (_SLang_pop_object_of_type (type, &amp;obj))
++ return NULL;
++
++ cl = _SLclass_get_class (type);
++ if ((cl-&gt;cl_class_type == SLANG_CLASS_TYPE_MMT)
++ &amp;&amp; (obj.data_type == type))
++ {
++ return obj.v.ref;
++ }
++
++ _SLclass_type_mismatch_error (type, obj.data_type);
++ SLang_free_object (&amp;obj);
++ return NULL;
++#endif
++}
++
++/*}}}*/
++
++int SLang_push_mmt (SLang_MMT_Type *ref) /*{{{*/
++{
++ if (ref == NULL)
++ return SLang_push_null ();
++
++ ref-&gt;count += 1;
++
++ if (0 == SLclass_push_ptr_obj (ref-&gt;data_type, (VOID_STAR) ref))
++ return 0;
++
++ ref-&gt;count -= 1;
++ return -1;
++}
++
++/*}}}*/
++
++void SLang_inc_mmt (SLang_MMT_Type *ref)
++{
++ if (ref != NULL)
++ ref-&gt;count += 1;
++}
++
++VOID_STAR SLang_object_from_mmt (SLang_MMT_Type *ref)
++{
++ if (ref == NULL)
++ return NULL;
++
++ return ref-&gt;user_data;
++}
++
++SLang_MMT_Type *SLang_create_mmt (unsigned char t, VOID_STAR p)
++{
++ SLang_MMT_Type *ref;
++
++ (void) _SLclass_get_class (t); /* check to see if it is registered */
++
++ if (NULL == (ref = (SLang_MMT_Type *) SLmalloc (sizeof (SLang_MMT_Type))))
++ return NULL;
++
++ SLMEMSET ((char *) ref, 0, sizeof (SLang_MMT_Type));
++
++ ref-&gt;data_type = t;
++ ref-&gt;user_data = p;
++ /* FIXME!! To be consistent with other types, the reference count should
++ * be set to 1 here. However, doing so will require other code changes
++ * involving the use of MMTs. For instance, SLang_free_mmt would have
++ * to be called after every push of the MMT.
++ */
++ return ref;
++}
++
++void SLang_free_mmt (SLang_MMT_Type *ref)
++{
++ unsigned char type;
++ SLang_Class_Type *cl;
++
++ if (ref == NULL)
++ return;
++
++ /* This can be zero if SLang_create_mmt is called followed
++ * by this routine before anything gets a chance to attach itself
++ * to it.
++ */
++ if (ref-&gt;count &gt; 1)
++ {
++ ref-&gt;count -= 1;
++ return;
++ }
++
++ type = ref-&gt;data_type;
++ cl = _SLclass_get_class (type);
++ (*cl-&gt;cl_user_destroy_fun) (type, ref-&gt;user_data);
++ SLfree ((char *)ref);
++}
++
++int SLang_push_value (unsigned char type, VOID_STAR v)
++{
++ SLang_Class_Type *cl;
++
++ cl = _SLclass_get_class (type);
++ return (*cl-&gt;cl_apush)(type, v);
++}
++
++int SLang_pop_value (unsigned char type, VOID_STAR v)
++{
++ SLang_Class_Type *cl;
++
++ cl = _SLclass_get_class (type);
++ return (*cl-&gt;cl_apop)(type, v);
++}
++
++void SLang_free_value (unsigned char type, VOID_STAR v)
++{
++ SLang_Class_Type *cl;
++
++ cl = _SLclass_get_class (type);
++ (*cl-&gt;cl_adestroy) (type, v);
++}
++
++/* These routines are very low-level and are designed for application data
++ * types to access the stack from their push/pop methods. The int and
++ * pointer versions are in slang.c
++ */
++#if SLANG_HAS_FLOAT
++int SLclass_push_double_obj (unsigned char type, double x)
++{
++ SLang_Object_Type obj;
++ obj.data_type = type;
++ obj.v.double_val = x;
++ return SLang_push (&amp;obj);
++}
++int SLclass_push_float_obj (unsigned char type, float x)
++{
++ SLang_Object_Type obj;
++ obj.data_type = type;
++ obj.v.float_val = x;
++ return SLang_push (&amp;obj);
++}
++
++#endif
++
++int SLclass_push_long_obj (unsigned char type, long x)
++{
++ SLang_Object_Type obj;
++ obj.data_type = type;
++ obj.v.long_val = x;
++ return SLang_push (&amp;obj);
++}
++
++int SLclass_push_short_obj (unsigned char type, short x)
++{
++ SLang_Object_Type obj;
++ obj.data_type = type;
++ obj.v.short_val = x;
++ return SLang_push (&amp;obj);
++}
++
++int SLclass_push_char_obj (unsigned char type, char x)
++{
++ SLang_Object_Type obj;
++ obj.data_type = type;
++ obj.v.char_val = x;
++ return SLang_push (&amp;obj);
++}
++
++#if SLANG_HAS_FLOAT
++int SLclass_pop_double_obj (unsigned char type, double *x)
++{
++ SLang_Object_Type obj;
++
++ if (-1 == _SLang_pop_object_of_type (type, &amp;obj, 0))
++ return -1;
++
++ *x = obj.v.double_val;
++ return 0;
++}
++
++int SLclass_pop_float_obj (unsigned char type, float *x)
++{
++ SLang_Object_Type obj;
++
++ if (-1 == _SLang_pop_object_of_type (type, &amp;obj, 0))
++ return -1;
++
++ *x = obj.v.float_val;
++ return 0;
++}
++#endif
++
++int SLclass_pop_long_obj (unsigned char type, long *x)
++{
++ SLang_Object_Type obj;
++
++ if (-1 == _SLang_pop_object_of_type (type, &amp;obj, 0))
++ return -1;
++
++ *x = obj.v.long_val;
++ return 0;
++}
++
++int SLclass_pop_int_obj (unsigned char type, int *x)
++{
++ SLang_Object_Type obj;
++
++ if (-1 == _SLang_pop_object_of_type (type, &amp;obj, 0))
++ return -1;
++
++ *x = obj.v.int_val;
++ return 0;
++}
++
++int SLclass_pop_short_obj (unsigned char type, short *x)
++{
++ SLang_Object_Type obj;
++
++ if (-1 == _SLang_pop_object_of_type (type, &amp;obj, 0))
++ return -1;
++
++ *x = obj.v.short_val;
++ return 0;
++}
++
++int SLclass_pop_char_obj (unsigned char type, char *x)
++{
++ SLang_Object_Type obj;
++
++ if (-1 == _SLang_pop_object_of_type (type, &amp;obj, 0))
++ return -1;
++
++ *x = obj.v.char_val;
++ return 0;
++}
++
++int SLclass_pop_ptr_obj (unsigned char type, VOID_STAR *s)
++{
++ SLang_Object_Type obj;
++
++ if (-1 == _SLang_pop_object_of_type (type, &amp;obj, 0))
++ {
++ *s = (VOID_STAR) NULL;
++ return -1;
++ }
++ *s = obj.v.ptr_val;
++ return 0;
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slclass.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slcmd.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slcmd.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slcmd.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,351 @@
++/* cmd line facility for slang */
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++#include &quot;slinclud.h&quot;
++
++#if SLANG_HAS_FLOAT
++# include &lt;math.h&gt;
++#endif
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++#ifndef HAVE_STDLIB_H
++/* Oh dear. Where is the prototype for atof? If not in stdlib, then
++ * I do not know where. Not in math.h onsome systems either.
++ */
++extern double atof ();
++#endif
++
++static SLcmd_Cmd_Type *SLcmd_find_command (char *s, SLcmd_Cmd_Type *cmd)
++{
++ char *cmdstr;
++ char chs = *s++, ch;
++
++ while ((cmd-&gt;cmdfun != NULL)
++ &amp;&amp; (NULL != (cmdstr = cmd-&gt;cmd))
++ &amp;&amp; (0 != (ch = *cmdstr++)))
++ {
++ if ((ch == chs) &amp;&amp; !strcmp (s, cmdstr)) return cmd;
++ cmd++;
++ }
++ return NULL;
++}
++
++static int extract_token (char **strptr, char *buf)
++{
++ char *s, *b;
++ char ch, quote;
++
++ *buf = 0;
++
++ s = *strptr;
++ while (((ch = *s) != 0)
++ &amp;&amp; ((ch == ' ') || (ch == '\t') || (ch == '\n')))
++ s++;
++
++ *strptr = s;
++
++ if (ch == 0) return 0;
++ if (ch == '%') return 0;
++
++ b = buf;
++
++ *b++ = ch;
++ s++;
++
++ if ((ch == '\'') || (ch == '&quot;'))
++ {
++ quote = ch;
++ while ((ch = *s) != 0)
++ {
++ s++;
++ *b++ = ch;
++ if (ch == quote)
++ break;
++
++ if (ch == '\\')
++ {
++ if (0 == (ch = *s))
++ break;
++ *b++ = ch;
++ s++;
++ }
++ }
++ *strptr = s;
++ *b = 0;
++ return 1;
++ }
++
++ while (((ch = *s) != 0)
++ &amp;&amp; (ch != ' ')
++ &amp;&amp; (ch != '\t')
++ &amp;&amp; (ch != '\n')
++ &amp;&amp; (ch != '%'))
++ *b++ = *s++;
++
++ *strptr = s;
++ *b = 0;
++ return 1;
++}
++
++static int allocate_arg_space (SLcmd_Cmd_Table_Type *table, int argc, unsigned int *space_ptr)
++{
++ unsigned int space = *space_ptr;
++ char *p;
++
++ if (argc + 1 &lt; (int) space)
++ return 0;
++
++ if (space &gt; 128)
++ {
++ if (space &gt; 1024) space += 1024;
++ else space += 128;
++ }
++ else space += 32;
++
++ if (NULL == (p = SLrealloc ((char *)table-&gt;string_args, space * sizeof (char *))))
++ return -1;
++ table-&gt;string_args = (char **)p;
++ table-&gt;string_args [argc] = NULL;
++
++ if (NULL == (p = SLrealloc ((char *)table-&gt;int_args, space * sizeof (int))))
++ return -1;
++ table-&gt;int_args = (int *)p;
++
++ if (NULL == (p = SLrealloc ((char *)table-&gt;double_args, space * sizeof (double))))
++ return -1;
++ table-&gt;double_args = (double *)p;
++
++ if (NULL == (p = SLrealloc ((char *)table-&gt;arg_type, space * sizeof (unsigned char))))
++ return -1;
++ table-&gt;arg_type = (unsigned char *)p;
++
++ *space_ptr = space;
++ return 0;
++}
++
++int SLcmd_execute_string (char *str, SLcmd_Cmd_Table_Type *table)
++{
++ char *s, *b = NULL, *arg_type, *last_str, *cmd_name;
++ SLcmd_Cmd_Type *cmd;
++ char *buf;
++ int token_present;
++ int i;
++ int status;
++ unsigned int len;
++ int argc;
++ unsigned int space;
++
++ table-&gt;argc = 0;
++ table-&gt;string_args = NULL;
++ table-&gt;int_args = NULL;
++ table-&gt;double_args = NULL;
++ table-&gt;arg_type = NULL;
++
++ buf = SLmake_string (str);
++ if (buf == NULL)
++ return -1;
++
++ status = extract_token (&amp;str, buf);
++ if (status &lt;= 0)
++ {
++ SLfree (buf);
++ return status;
++ }
++
++ if (((len = strlen (buf)) &gt;= 32)
++ || (NULL == (cmd = SLcmd_find_command (buf, table-&gt;table))))
++ {
++ SLang_verror (SL_UNDEFINED_NAME,&quot;%s: invalid command&quot;, buf);
++ SLfree (buf);
++ return -1;
++ }
++
++ if (NULL == (cmd_name = SLmake_string (buf)))
++ {
++ SLfree (buf);
++ return -1;
++ }
++
++ space = 0;
++ argc = 0;
++ if (-1 == allocate_arg_space (table, argc, &amp;space))
++ {
++ SLfree (buf);
++ return -1;
++ }
++ table-&gt;arg_type[argc] = SLANG_STRING_TYPE;
++ table-&gt;string_args[argc++] = cmd_name;
++
++ arg_type = cmd-&gt;arg_type;
++ status = -1;
++ while (*arg_type)
++ {
++ int guess_type = 0;
++
++ last_str = str;
++
++ if (-1 == allocate_arg_space (table, argc, &amp;space))
++ goto error;
++
++ if (-1 == (token_present = extract_token (&amp;str, buf)))
++ goto error;
++
++ table-&gt;string_args[argc] = NULL;
++
++ if (token_present)
++ {
++ b = buf;
++ len = strlen (b);
++
++ if ((*b == '&quot;') &amp;&amp; (len &gt; 1))
++ {
++ b++;
++ len -= 2;
++ b[len] = 0;
++ guess_type = SLANG_STRING_TYPE;
++ SLexpand_escaped_string (buf, b, b + len);
++ len = strlen (buf);
++ }
++ else if ((*b == '\'') &amp;&amp; (len &gt; 1))
++ {
++ char ch;
++ b++;
++ len -= 2;
++ b[len] = 0;
++ guess_type = SLANG_INT_TYPE;
++ ch = *b;
++ if (ch == '\\')
++ (void) _SLexpand_escaped_char (b, &amp;ch);
++ sprintf (buf, &quot;%d&quot;, (unsigned char) ch);
++ len = strlen (buf);
++ }
++ else guess_type = SLang_guess_type (buf);
++ }
++
++ switch (*arg_type++)
++ {
++ /* variable argument number */
++ case 'v':
++ if (token_present == 0) break;
++ case 'V':
++ if (token_present == 0)
++ {
++ SLang_verror (SL_INVALID_PARM, &quot;%s: Expecting argument&quot;, cmd_name);
++ goto error;
++ }
++
++ while (*last_str == ' ') last_str++;
++ len = strlen (last_str);
++ str = last_str + len;
++
++ s = SLmake_nstring (last_str, len);
++ if (s == NULL) goto error;
++
++ table-&gt;arg_type[argc] = SLANG_STRING_TYPE;
++ table-&gt;string_args[argc++] = s;
++ break;
++
++ case 's':
++ if (token_present == 0) break;
++ case 'S':
++ if (token_present == 0)
++ {
++ SLang_verror (SL_TYPE_MISMATCH, &quot;%s: Expecting string argument&quot;, cmd_name);
++ goto error;
++ }
++
++ s = SLmake_nstring (buf, len);
++ if (s == NULL) goto error;
++ table-&gt;arg_type[argc] = SLANG_STRING_TYPE;
++ table-&gt;string_args[argc++] = s;
++ break;
++
++ /* integer argument */
++ case 'i':
++ if (token_present == 0) break;
++ case 'I':
++ if ((token_present == 0) || (SLANG_INT_TYPE != guess_type))
++ {
++ SLang_verror (SL_TYPE_MISMATCH, &quot;%s: Expecting integer argument&quot;, cmd_name);
++ goto error;
++ }
++
++ table-&gt;arg_type[argc] = SLANG_INT_TYPE;
++ table-&gt;int_args[argc++] = SLatoi((unsigned char *) buf);
++ break;
++
++ /* floating point arg */
++#if SLANG_HAS_FLOAT
++ case 'f':
++ if (token_present == 0) break;
++ case 'F':
++ if ((token_present == 0) || (SLANG_STRING_TYPE == guess_type))
++ {
++ SLang_verror (SL_TYPE_MISMATCH, &quot;%s: Expecting double argument&quot;, cmd_name);
++ goto error;
++ }
++ table-&gt;arg_type[argc] = SLANG_DOUBLE_TYPE;
++ table-&gt;double_args[argc++] = atof(buf);
++ break;
++#endif
++ /* Generic type */
++ case 'g':
++ if (token_present == 0) break;
++ case 'G':
++ if (token_present == 0)
++ {
++ SLang_verror (SL_TYPE_MISMATCH, &quot;%s: Expecting argument&quot;, cmd_name);
++ goto error;
++ }
++
++ switch (guess_type)
++ {
++ case SLANG_INT_TYPE:
++ table-&gt;arg_type[argc] = SLANG_INT_TYPE;
++ table-&gt;int_args[argc++] = SLatoi((unsigned char *) buf);
++ break;
++
++ case SLANG_STRING_TYPE:
++ s = SLmake_nstring (buf, len);
++ if (s == NULL) goto error;
++
++ table-&gt;arg_type[argc] = SLANG_STRING_TYPE;
++ table-&gt;string_args[argc++] = s;
++ break;
++#if SLANG_HAS_FLOAT
++ case SLANG_DOUBLE_TYPE:
++ table-&gt;arg_type[argc] = SLANG_DOUBLE_TYPE;
++ table-&gt;double_args[argc++] = atof(buf);
++#endif
++ }
++ break;
++ }
++ }
++
++ /* call function */
++ status = (*cmd-&gt;cmdfun)(argc, table);
++
++ error:
++ if (table-&gt;string_args != NULL) for (i = 0; i &lt; argc; i++)
++ {
++ if (NULL != table-&gt;string_args[i])
++ {
++ SLfree (table-&gt;string_args[i]);
++ table-&gt;string_args[i] = NULL;
++ }
++ }
++ SLfree ((char *)table-&gt;string_args); table-&gt;string_args = NULL;
++ SLfree ((char *)table-&gt;double_args); table-&gt;double_args = NULL;
++ SLfree ((char *)table-&gt;int_args); table-&gt;int_args = NULL;
++ SLfree ((char *)table-&gt;arg_type); table-&gt;arg_type = NULL;
++
++ SLfree (buf);
++ return status;
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slcmd.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slcmplex.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slcmplex.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slcmplex.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1142 @@
++/* Complex Data Type definition for S-Lang */
++/* Copyright (c) 1997, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++/* The rest of the file is enclosed in this #if */
++#if SLANG_HAS_COMPLEX
++
++#if SLANG_HAS_FLOAT
++# include &lt;math.h&gt;
++#endif
++
++#ifdef PI
++# undef PI
++#endif
++#define PI 3.14159265358979323846
++
++int SLang_pop_complex (double *r, double *i)
++{
++ double *c;
++
++ switch (SLang_peek_at_stack ())
++ {
++ case SLANG_COMPLEX_TYPE:
++ if (-1 == SLclass_pop_ptr_obj (SLANG_COMPLEX_TYPE, (VOID_STAR *)&amp;c))
++ return -1;
++ *r = c[0];
++ *i = c[1];
++ SLfree ((char *) c);
++ break;
++
++ default:
++ *i = 0.0;
++ if (-1 == SLang_pop_double (r, NULL, NULL))
++ return -1;
++ break;
++
++ case -1:
++ return -1;
++ }
++ return 0;
++}
++
++int SLang_push_complex (double r, double i)
++{
++ double *c;
++
++ c = (double *) SLmalloc (2 * sizeof (double));
++ if (c == NULL)
++ return -1;
++
++ c[0] = r;
++ c[1] = i;
++
++ if (-1 == SLclass_push_ptr_obj (SLANG_COMPLEX_TYPE, (VOID_STAR) c))
++ {
++ SLfree ((char *) c);
++ return -1;
++ }
++ return 0;
++}
++
++double *SLcomplex_times (double *c, double *a, double *b)
++{
++ double a_real, b_real, a_imag, b_imag;
++
++ a_real = a[0];
++ b_real = b[0];
++ a_imag = a[1];
++ b_imag = b[1];
++
++ c[0] = a_real * b_real - a_imag * b_imag;
++ c[1] = a_imag * b_real + a_real * b_imag;
++
++ return c;
++}
++
++double *SLcomplex_divide (double *c, double *a, double *b)
++{
++ double a_real, b_real, a_imag, b_imag;
++ double ratio, invden;
++
++ a_real = a[0];
++ b_real = b[0];
++ a_imag = a[1];
++ b_imag = b[1];
++
++ /* Do it this way to avoid overflow in the denom */
++ if (fabs(b_real) &gt; fabs(b_imag))
++ {
++ ratio = b_imag / b_real;
++ invden = 1.0 / (b_real + b_imag * ratio);
++ c[0] = (a_real + ratio * a_imag) * invden;
++ c[1] = (a_imag - a_real * ratio) * invden;
++ }
++ else
++ {
++ ratio = b_real / b_imag;
++ invden = 1.0 / (b_real * ratio + b_imag);
++ c[0] = (a_real * ratio + a_imag) * invden;
++ c[1] = (a_imag * ratio - a_real) * invden;
++ }
++ return c;
++}
++
++/* a^b = exp (b log a); */
++double *SLcomplex_pow (double *c, double *a, double *b)
++{
++ return SLcomplex_exp (c, SLcomplex_times (c, b, SLcomplex_log (c, a)));
++}
++
++static double *complex_dpow (double *c, double *a, double b)
++{
++ SLcomplex_log (c, a);
++ c[0] *= b;
++ c[1] *= b;
++ return SLcomplex_exp (c, c);
++}
++
++static double *dcomplex_pow (double *c, double a, double *b)
++{
++ a = log (a);
++ c[0] = a * b[0];
++ c[1] = a * b[1];
++ return SLcomplex_exp (c, c);
++}
++
++double SLcomplex_abs (double *z)
++{
++ return SLmath_hypot (z[0], z[1]);
++}
++
++/* It appears that FORTRAN assumes that the branch cut for the log function
++ * is along the -x axis. So, use this for atan2:
++ */
++static double my_atan2 (double y, double x)
++{
++ double val;
++
++ val = atan (y/x);
++
++ if (x &gt;= 0)
++ return val; /* I, IV */
++
++ if (y &lt;= 0) /* III */
++ return val - PI;
++
++ return PI + val; /* II */
++}
++
++static void polar_form (double *r, double *theta, double *z)
++{
++ double x, y;
++
++ *r = SLcomplex_abs (z);
++
++ x = z[0];
++ y = z[1];
++
++ if (x == 0.0)
++ {
++ if (y &gt;= 0)
++ *theta = 0.5 * PI;
++ else
++ *theta = 1.5 * PI;
++ }
++ else *theta = my_atan2 (y, x);
++}
++
++double *SLcomplex_sin (double *sinz, double *z)
++{
++ double x, y;
++
++ x = z[0]; y = z[1];
++ sinz[0] = sin (x) * cosh (y);
++ sinz[1] = cos (x) * sinh (y);
++ return sinz;
++}
++
++double *SLcomplex_cos (double *cosz, double *z)
++{
++ double x, y;
++
++ x = z[0]; y = z[1];
++ cosz[0] = cos (x) * cosh (y);
++ cosz[1] = -sin (x) * sinh (y);
++ return cosz;
++}
++
++double *SLcomplex_exp (double *expz, double *z)
++{
++ double r, i;
++
++ r = exp (z[0]);
++ i = z[1];
++ expz[0] = r * cos (i);
++ expz[1] = r * sin (i);
++ return expz;
++}
++
++double *SLcomplex_log (double *logz, double *z)
++{
++ double r, theta;
++
++ polar_form (&amp;r, &amp;theta, z); /* log R.e^(ix) = log R + ix */
++ logz[0] = log(r);
++ logz[1] = theta;
++ return logz;
++}
++
++double *SLcomplex_log10 (double *log10z, double *z)
++{
++ double l10 = log (10.0);
++ (void) SLcomplex_log (log10z, z);
++ log10z[0] = log10z[0] / l10;
++ log10z[1] = log10z[1] / l10;
++ return log10z;
++}
++
++double *SLcomplex_sqrt (double *sqrtz, double *z)
++{
++ double r, x, y;
++
++ x = z[0];
++ y = z[1];
++
++ r = SLmath_hypot (x, y);
++
++ if (r == 0.0)
++ {
++ sqrtz [0] = sqrtz [1] = 0.0;
++ return sqrtz;
++ }
++
++ if (x &gt;= 0.0)
++ {
++ x = sqrt (0.5 * (r + x));
++ y = 0.5 * y / x;
++ }
++ else
++ {
++ r = sqrt (0.5 * (r - x));
++ x = 0.5 * y / r;
++ y = r;
++
++ if (x &lt; 0.0)
++ {
++ x = -x;
++ y = -y;
++ }
++ }
++
++ sqrtz[0] = x;
++ sqrtz[1] = y;
++
++ return sqrtz;
++}
++
++double *SLcomplex_tan (double *tanz, double *z)
++{
++ double x, y, invden;
++
++ x = 2 * z[0];
++ y = 2 * z[1];
++ invden = 1.0 / (cos (x) + cosh (y));
++ tanz[0] = invden * sin (x);
++ tanz[1] = invden * sinh (y);
++ return tanz;
++}
++
++/* Utility Function */
++static void compute_alpha_beta (double *z, double *alpha, double *beta)
++{
++ double x, y, a, b;
++
++ x = z[0];
++ y = z[1];
++ a = 0.5 * SLmath_hypot (x + 1, y);
++ b = 0.5 * SLmath_hypot (x - 1, y);
++
++ *alpha = a + b;
++ *beta = a - b;
++}
++
++double *SLcomplex_asin (double *asinz, double *z)
++{
++ double alpha, beta;
++
++ compute_alpha_beta (z, &amp;alpha, &amp;beta);
++ asinz[0] = asin (beta);
++ asinz[1] = log (alpha + sqrt (alpha * alpha - 1));
++ return asinz;
++}
++
++double *SLcomplex_acos (double *acosz, double *z)
++{
++ double alpha, beta;
++
++ compute_alpha_beta (z, &amp;alpha, &amp;beta);
++ acosz[0] = acos (beta);
++ acosz[1] = -log (alpha + sqrt (alpha * alpha - 1));
++ return acosz;
++}
++
++double *SLcomplex_atan (double *atanz, double *z)
++{
++ double x, y;
++ double z1[2], z2[2];
++
++ x = z[0]; y = z[1];
++ z1[0] = x;
++ z1[1] = 1 + y;
++ z2[0] = -x;
++ z2[1] = 1 - y;
++
++ SLcomplex_log (z1, SLcomplex_divide (z2, z1, z2));
++ atanz[0] = -0.5 * z1[1];
++ atanz[1] = 0.5 * z1[0];
++
++ return atanz;
++}
++
++double *SLcomplex_sinh (double *sinhz, double *z)
++{
++ double x, y;
++ x = z[0]; y = z[1];
++ sinhz[0] = sinh (x) * cos (y);
++ sinhz[1] = cosh (x) * sin (y);
++ return sinhz;
++}
++
++double *SLcomplex_cosh (double *coshz, double *z)
++{
++ double x, y;
++ x = z[0]; y = z[1];
++ coshz[0] = cosh (x) * cos (y);
++ coshz[1] = sinh (x) * sin (y);
++ return coshz;
++}
++
++double *SLcomplex_tanh (double *tanhz, double *z)
++{
++ double x, y, invden;
++ x = 2 * z[0];
++ y = 2 * z[1];
++ invden = 1.0 / (cosh (x) + cos (y));
++ tanhz[0] = invden * sinh (x);
++ tanhz[1] = invden * sin (y);
++ return tanhz;
++}
++#if 0
++static double *not_implemented (char *fun, double *p)
++{
++ SLang_verror (SL_NOT_IMPLEMENTED, &quot;%s for complex numbers has not been implemented&quot;,
++ fun);
++ *p = -1.0;
++ return p;
++}
++#endif
++/* Use: asinh(z) = -i asin(iz) */
++double *SLcomplex_asinh (double *asinhz, double *z)
++{
++ double iz[2];
++
++ iz[0] = -z[1];
++ iz[1] = z[0];
++
++ (void) SLcomplex_asin (iz, iz);
++ asinhz[0] = iz[1];
++ asinhz[1] = -iz[0];
++
++ return asinhz;
++}
++
++/* Use: acosh (z) = i acos(z) */
++double *SLcomplex_acosh (double *acoshz, double *z)
++{
++ double iz[2];
++
++ (void) SLcomplex_acos (iz, z);
++ acoshz[0] = -iz[1];
++ acoshz[1] = iz[0];
++
++ return acoshz;
++}
++
++/* Use: atanh(z) = -i atan(iz) */
++double *SLcomplex_atanh (double *atanhz, double *z)
++{
++ double iz[2];
++
++ iz[0] = -z[1];
++ iz[1] = z[0];
++
++ (void) SLcomplex_atan (iz, iz);
++ atanhz[0] = iz[1];
++ atanhz[1] = -iz[0];
++
++ return atanhz;
++}
++
++static int complex_binary_result (int op, unsigned char a, unsigned char b,
++ unsigned char *c)
++{
++ (void) a; (void) b;
++
++ switch (op)
++ {
++ default:
++ case SLANG_POW:
++ case SLANG_PLUS:
++ case SLANG_MINUS:
++ case SLANG_TIMES:
++ case SLANG_DIVIDE:
++ *c = SLANG_COMPLEX_TYPE;
++ break;
++
++ case SLANG_EQ:
++ case SLANG_NE:
++ *c = SLANG_CHAR_TYPE;
++ break;
++ }
++ return 1;
++}
++
++static int complex_complex_binary (int op,
++ unsigned char a_type, VOID_STAR ap, unsigned int na,
++ unsigned char b_type, VOID_STAR bp, unsigned int nb,
++ VOID_STAR cp)
++{
++ char *ic;
++ double *a, *b, *c;
++ unsigned int n, n_max;
++ unsigned int da, db;
++
++ (void) a_type;
++ (void) b_type;
++
++ a = (double *) ap;
++ b = (double *) bp;
++ c = (double *) cp;
++ ic = (char *) cp;
++
++ if (na == 1) da = 0; else da = 2;
++ if (nb == 1) db = 0; else db = 2;
++
++ if (na &gt; nb) n_max = na; else n_max = nb;
++ n_max = 2 * n_max;
++
++ switch (op)
++ {
++ default:
++ return 0;
++
++ case SLANG_PLUS:
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ c[n] = a[0] + b[0];
++ c[n + 1] = a[1] + b[1];
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_MINUS:
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ c[n] = a[0] - b[0];
++ c[n + 1] = a[1] - b[1];
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_TIMES:
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ SLcomplex_times (c + n, a, b);
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_DIVIDE: /* / */
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ if ((b[0] == 0.0) &amp;&amp; (b[1] == 0.0))
++ {
++ SLang_Error = SL_DIVIDE_ERROR;
++ return -1;
++ }
++ SLcomplex_divide (c + n, a, b);
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_EQ: /* == */
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ ic[n/2] = ((a[0] == b[0]) &amp;&amp; (a[1] == b[1]));
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_NE: /* != */
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ ic[n/2] = ((a[0] != b[0]) || (a[1] != b[1]));
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_POW:
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ SLcomplex_pow (c + n, a, b);
++ a += da; b += db;
++ }
++ break;
++
++ }
++
++ return 1;
++}
++
++static int complex_double_binary (int op,
++ unsigned char a_type, VOID_STAR ap, unsigned int na,
++ unsigned char b_type, VOID_STAR bp, unsigned int nb,
++ VOID_STAR cp)
++{
++ char *ic;
++ double *a, *b, *c;
++ unsigned int n, n_max;
++ unsigned int da, db;
++
++ (void) a_type;
++ (void) b_type;
++
++ a = (double *) ap;
++ b = (double *) bp;
++ c = (double *) cp;
++ ic = (char *) cp;
++
++ if (na == 1) da = 0; else da = 2;
++ if (nb == 1) db = 0; else db = 1;
++
++ if (na &gt; nb) n_max = na; else n_max = nb;
++ n_max = 2 * n_max;
++
++ switch (op)
++ {
++ default:
++ return 0;
++
++ case SLANG_PLUS:
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ c[n] = a[0] + b[0];
++ c[n + 1] = a[1];
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_MINUS:
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ c[n] = a[0] - b[0];
++ c[n + 1] = a[1];
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_TIMES:
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ double b0 = b[0];
++ c[n] = a[0] * b0;
++ c[n + 1] = a[1] * b0;
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_DIVIDE: /* / */
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ double b0 = b[0];
++ if (b0 == 0.0)
++ {
++ SLang_Error = SL_DIVIDE_ERROR;
++ return -1;
++ }
++ c[n] = a[0] / b0;
++ c[n + 1] = a[1] / b0;
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_EQ: /* == */
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ ic[n/2] = ((a[0] == b[0]) &amp;&amp; (a[1] == 0.0));
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_NE: /* != */
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ ic[n/2] = ((a[0] != b[0]) || (a[1] != 0.0));
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_POW:
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ complex_dpow (c + n, a, b[0]);
++ a += da; b += db;
++ }
++ break;
++ }
++
++ return 1;
++}
++
++static int double_complex_binary (int op,
++ unsigned char a_type, VOID_STAR ap, unsigned int na,
++ unsigned char b_type, VOID_STAR bp, unsigned int nb,
++ VOID_STAR cp)
++{
++ char *ic;
++ double *a, *b, *c;
++ unsigned int n, n_max;
++ unsigned int da, db;
++
++ (void) a_type;
++ (void) b_type;
++
++ a = (double *) ap;
++ b = (double *) bp;
++ c = (double *) cp;
++ ic = (char *) cp;
++
++ if (na == 1) da = 0; else da = 1;
++ if (nb == 1) db = 0; else db = 2;
++
++ if (na &gt; nb) n_max = na; else n_max = nb;
++ n_max = 2 * n_max;
++
++ switch (op)
++ {
++ default:
++ return 0;
++
++ case SLANG_PLUS:
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ c[n] = a[0] + b[0];
++ c[n + 1] = b[1];
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_MINUS:
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ c[n] = a[0] - b[0];
++ c[n + 1] = -b[1];
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_TIMES:
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ double a0 = a[0];
++ c[n] = a0 * b[0];
++ c[n + 1] = a0 * b[1];
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_DIVIDE: /* / */
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ double z[2];
++ if ((b[0] == 0.0) &amp;&amp; (b[1] == 0.0))
++ {
++ SLang_Error = SL_DIVIDE_ERROR;
++ return -1;
++ }
++ z[0] = a[0];
++ z[1] = 0.0;
++ SLcomplex_divide (c + n, z, b);
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_EQ: /* == */
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ ic[n/2] = ((a[0] == b[0]) &amp;&amp; (0.0 == b[1]));
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_NE: /* != */
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ ic[n/2] = ((a[0] != b[0]) || (0.0 != b[1]));
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_POW:
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ dcomplex_pow (c + n, a[0], b);
++ a += da; b += db;
++ }
++ break;
++ }
++
++ return 1;
++}
++
++static int complex_generic_binary (int op,
++ unsigned char a_type, VOID_STAR ap, unsigned int na,
++ unsigned char b_type, VOID_STAR bp, unsigned int nb,
++ VOID_STAR cp)
++{
++ char *ic;
++ char *b;
++ double *a, *c;
++ unsigned int n, n_max;
++ unsigned int da, db;
++ unsigned int sizeof_b;
++ SLang_To_Double_Fun_Type to_double;
++
++ if (NULL == (to_double = SLarith_get_to_double_fun (b_type, &amp;sizeof_b)))
++ return 0;
++
++ (void) a_type;
++
++ a = (double *) ap;
++ b = (char *) bp;
++ c = (double *) cp;
++ ic = (char *) cp;
++
++ if (na == 1) da = 0; else da = 2;
++ if (nb == 1) db = 0; else db = sizeof_b;
++
++ if (na &gt; nb) n_max = na; else n_max = nb;
++ n_max = 2 * n_max;
++
++ switch (op)
++ {
++ default:
++ return 0;
++
++ case SLANG_POW:
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ complex_dpow (c + n, a, to_double((VOID_STAR)b));
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_PLUS:
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ c[n] = a[0] + to_double((VOID_STAR)b);
++ c[n + 1] = a[1];
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_MINUS:
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ c[n] = a[0] - to_double((VOID_STAR)b);
++ c[n + 1] = a[1];
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_TIMES:
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ double b0 = to_double((VOID_STAR)b);
++ c[n] = a[0] * b0;
++ c[n + 1] = a[1] * b0;
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_DIVIDE: /* / */
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ double b0 = to_double((VOID_STAR)b);
++ if (b0 == 0)
++ {
++ SLang_Error = SL_DIVIDE_ERROR;
++ return -1;
++ }
++ c[n] = a[0] / b0;
++ c[n + 1] = a[1] / b0;
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_EQ: /* == */
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ ic[n/2] = ((a[0] == to_double((VOID_STAR)b)) &amp;&amp; (a[1] == 0.0));
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_NE: /* != */
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ ic[n/2] = ((a[0] != to_double((VOID_STAR)b)) || (a[1] != 0.0));
++ a += da; b += db;
++ }
++ break;
++ }
++
++ return 1;
++}
++
++static int generic_complex_binary (int op,
++ unsigned char a_type, VOID_STAR ap, unsigned int na,
++ unsigned char b_type, VOID_STAR bp, unsigned int nb,
++ VOID_STAR cp)
++{
++ double *b, *c;
++ char *a, *ic;
++ unsigned int n, n_max;
++ unsigned int da, db;
++ unsigned int sizeof_a;
++ SLang_To_Double_Fun_Type to_double;
++
++ if (NULL == (to_double = SLarith_get_to_double_fun (a_type, &amp;sizeof_a)))
++ return 0;
++
++ (void) b_type;
++
++ a = (char *) ap;
++ b = (double *) bp;
++ c = (double *) cp;
++ ic = (char *) cp;
++
++ if (na == 1) da = 0; else da = sizeof_a;
++ if (nb == 1) db = 0; else db = 2;
++
++ if (na &gt; nb) n_max = na; else n_max = nb;
++ n_max = 2 * n_max;
++
++ switch (op)
++ {
++ default:
++ return 0;
++ case SLANG_POW:
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ dcomplex_pow (c + n, to_double((VOID_STAR)a), b);
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_PLUS:
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ c[n] = to_double((VOID_STAR)a) + b[0];
++ c[n + 1] = b[1];
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_MINUS:
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ c[n] = to_double((VOID_STAR)a) - b[0];
++ c[n + 1] = -b[1];
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_TIMES:
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ double a0 = to_double((VOID_STAR)a);
++ c[n] = a0 * b[0];
++ c[n + 1] = a0 * b[1];
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_DIVIDE: /* / */
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ double z[2];
++ if ((b[0] == 0.0) &amp;&amp; (b[1] == 0.0))
++ {
++ SLang_Error = SL_DIVIDE_ERROR;
++ return -1;
++ }
++ z[0] = to_double((VOID_STAR)a);
++ z[1] = 0.0;
++ SLcomplex_divide (c + n, z, b);
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_EQ: /* == */
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ ic[n/2] = ((to_double((VOID_STAR)a) == b[0]) &amp;&amp; (0.0 == b[1]));
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_NE: /* != */
++ for (n = 0; n &lt; n_max; n += 2)
++ {
++ ic[n/2] = ((to_double((VOID_STAR)a) != b[0]) || (0.0 != b[1]));
++ a += da; b += db;
++ }
++ break;
++ }
++
++ return 1;
++}
++
++static int complex_unary_result (int op, unsigned char a, unsigned char *b)
++{
++ (void) a;
++
++ switch (op)
++ {
++ default:
++ return 0;
++
++ case SLANG_PLUSPLUS:
++ case SLANG_MINUSMINUS:
++ case SLANG_CHS:
++ case SLANG_MUL2:
++ *b = SLANG_COMPLEX_TYPE;
++ break;
++
++ case SLANG_SQR: /* |Real|^2 + |Imag|^2 ==&gt; double */
++ case SLANG_ABS: /* |z| ==&gt; double */
++ *b = SLANG_DOUBLE_TYPE;
++ break;
++
++ case SLANG_SIGN:
++ *b = SLANG_INT_TYPE;
++ break;
++ }
++ return 1;
++}
++
++static int complex_unary (int op,
++ unsigned char a_type, VOID_STAR ap, unsigned int na,
++ VOID_STAR bp)
++{
++ unsigned int n;
++ double *a, *b;
++ int *ic;
++
++ (void) a_type;
++
++ a = (double *) ap;
++ b = (double *) bp;
++ ic = (int *) bp;
++
++ na = 2 * na;
++
++ switch (op)
++ {
++ default:
++ return 0;
++
++ case SLANG_PLUSPLUS:
++ for (n = 0; n &lt; na; n += 2) b[n] = (a[n] + 1);
++ break;
++ case SLANG_MINUSMINUS:
++ for (n = 0; n &lt; na; n += 2) b[n] = (a[n] - 1);
++ break;
++ case SLANG_CHS:
++ for (n = 0; n &lt; na; n += 2)
++ {
++ b[n] = -(a[n]);
++ b[n + 1] = -(a[n + 1]);
++ }
++ break;
++ case SLANG_SQR: /* |Real|^2 + |Imag|^2 ==&gt; double */
++ for (n = 0; n &lt; na; n += 2)
++ b[n/2] = (a[n] * a[n] + a[n + 1] * a[n + 1]);
++ break;
++
++ case SLANG_MUL2:
++ for (n = 0; n &lt; na; n += 2)
++ {
++ b[n] = (2 * a[n]);
++ b[n + 1] = (2 * a[n + 1]);
++ }
++ break;
++
++ case SLANG_ABS: /* |z| ==&gt; double */
++ for (n = 0; n &lt; na; n += 2)
++ b[n/2] = SLcomplex_abs (a + n);
++ break;
++
++ case SLANG_SIGN:
++ /* Another creative extension. Lets return an integer which indicates
++ * whether the complex number is in the upperhalf plane or not.
++ */
++ for (n = 0; n &lt; na; n += 2)
++ {
++ if (a[n + 1] &lt; 0.0) ic[n/2] = -1;
++ else if (a[n + 1] &gt; 0.0) ic[n/2] = 1;
++ else ic[n/2] = 0;
++ }
++ break;
++ }
++
++ return 1;
++}
++
++static int
++complex_typecast (unsigned char from_type, VOID_STAR from, unsigned int num,
++ unsigned char to_type, VOID_STAR to)
++{
++ double *z;
++ double *d;
++ char *i;
++ unsigned int n;
++ unsigned int sizeof_i;
++ SLang_To_Double_Fun_Type to_double;
++
++ (void) to_type;
++
++ z = (double *) to;
++
++ switch (from_type)
++ {
++ default:
++ if (NULL == (to_double = SLarith_get_to_double_fun (from_type, &amp;sizeof_i)))
++ return 0;
++ i = (char *) from;
++ for (n = 0; n &lt; num; n++)
++ {
++ *z++ = to_double ((VOID_STAR) i);
++ *z++ = 0.0;
++
++ i += sizeof_i;
++ }
++ break;
++
++ case SLANG_DOUBLE_TYPE:
++ d = (double *) from;
++ for (n = 0; n &lt; num; n++)
++ {
++ *z++ = d[n];
++ *z++ = 0.0;
++ }
++ break;
++ }
++
++ return 1;
++}
++
++static void complex_destroy (unsigned char type, VOID_STAR ptr)
++{
++ (void) type;
++ SLfree ((char *)*(double **) ptr);
++}
++
++static int complex_push (unsigned char type, VOID_STAR ptr)
++{
++ double *z;
++
++ (void) type;
++ z = *(double **) ptr;
++ return SLang_push_complex (z[0], z[1]);
++}
++
++static int complex_pop (unsigned char type, VOID_STAR ptr)
++{
++ double *z;
++
++ (void) type;
++ z = *(double **) ptr;
++ return SLang_pop_complex (&amp;z[0], &amp;z[1]);
++}
++
++int _SLinit_slcomplex (void)
++{
++ SLang_Class_Type *cl;
++ unsigned char *types;
++
++ if (NULL == (cl = SLclass_allocate_class (&quot;Complex_Type&quot;)))
++ return -1;
++
++ (void) SLclass_set_destroy_function (cl, complex_destroy);
++ (void) SLclass_set_push_function (cl, complex_push);
++ (void) SLclass_set_pop_function (cl, complex_pop);
++
++ if (-1 == SLclass_register_class (cl, SLANG_COMPLEX_TYPE, 2 * sizeof (double),
++ SLANG_CLASS_TYPE_VECTOR))
++ return -1;
++
++ types = _SLarith_Arith_Types;
++ while (*types != SLANG_DOUBLE_TYPE)
++ {
++ unsigned char t = *types++;
++
++ if ((-1 == SLclass_add_binary_op (t, SLANG_COMPLEX_TYPE, generic_complex_binary, complex_binary_result))
++ || (-1 == SLclass_add_binary_op (SLANG_COMPLEX_TYPE, t, complex_generic_binary, complex_binary_result))
++ || (-1 == (SLclass_add_typecast (t, SLANG_COMPLEX_TYPE, complex_typecast, 1))))
++ return -1;
++ }
++
++ if ((-1 == (SLclass_add_binary_op (SLANG_COMPLEX_TYPE, SLANG_COMPLEX_TYPE, complex_complex_binary, complex_binary_result)))
++ || (-1 == (SLclass_add_binary_op (SLANG_COMPLEX_TYPE, SLANG_DOUBLE_TYPE, complex_double_binary, complex_binary_result)))
++ || (-1 == (SLclass_add_binary_op (SLANG_DOUBLE_TYPE, SLANG_COMPLEX_TYPE, double_complex_binary, complex_binary_result)))
++ || (-1 == (SLclass_add_unary_op (SLANG_COMPLEX_TYPE, complex_unary, complex_unary_result)))
++ || (-1 == (SLclass_add_typecast (SLANG_DOUBLE_TYPE, SLANG_COMPLEX_TYPE, complex_typecast, 1))))
++ return -1;
++
++ return 0;
++}
++
++#endif /* if SLANG_HAS_COMPLEX */
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slcmplex.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slcompat.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slcompat.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slcompat.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,34 @@
++/* These functions are provided for backward compatibility and are obsolete.
++ * Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++/* Compatibility */
++int SLang_init_slunix (void)
++{
++ if ((-1 == SLang_init_posix_dir ())
++ || (-1 == SLang_init_posix_process ())
++ || (-1 == SLdefine_for_ifdef (&quot;__SLUNIX__&quot;)))
++ return -1;
++
++ return 0;
++}
++
++int SLang_init_slfile (void)
++{
++ if ((-1 == SLang_init_stdio ())
++ || (-1 == SLang_init_posix_dir ())
++ || (-1 == SLdefine_for_ifdef(&quot;__SLFILE__&quot;)))
++ return -1;
++
++ return 0;
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slcompat.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slcurses.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slcurses.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slcurses.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,972 @@
++/* Copyright (c) 1998, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++#include &quot;slinclud.h&quot;
++
++#include &lt;signal.h&gt;
++#include &lt;errno.h&gt;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++#include &quot;slcurses.h&quot;
++
++/* This file is meant to implement a primitive curses implementation in
++ * terms of SLsmg calls. The fact is that the interfaces are sufficiently
++ * different that a 100% emulation is not possible.
++ */
++
++SLcurses_Window_Type *SLcurses_Stdscr;
++int SLcurses_Esc_Delay = 150; /* 0.15 seconds */
++SLtt_Char_Type SLcurses_Acs_Map [128];
++int SLcurses_Is_Endwin = 1;
++int SLcurses_Num_Colors = 8;
++
++static void blank_line (SLsmg_Char_Type *b, unsigned int len, SLsmg_Char_Type color)
++{
++ SLsmg_Char_Type *bmax;
++
++ bmax = b + len;
++ color = SLSMG_BUILD_CHAR(' ', color);
++
++ while (b &lt; bmax) *b++ = color;
++}
++
++static int va_mvprintw (SLcurses_Window_Type *w, int r, int c, int do_move,
++ char *fmt, va_list ap)
++{
++ char buf[1024];
++
++ if (do_move) SLcurses_wmove (w, r, c);
++
++ (void) _SLvsnprintf (buf, sizeof(buf), fmt, ap);
++
++ SLcurses_waddnstr (w, buf, -1);
++ return 0;
++}
++
++int SLcurses_mvprintw (int r, int c, char *fmt, ...)
++{
++ va_list ap;
++
++ va_start(ap, fmt);
++ va_mvprintw (SLcurses_Stdscr, r, c, 1, fmt, ap);
++ va_end(ap);
++
++ return 0;
++}
++
++int SLcurses_mvwprintw (SLcurses_Window_Type *w, int r, int c, char *fmt, ...)
++{
++ va_list ap;
++
++ va_start(ap, fmt);
++ va_mvprintw (w, r, c, 1, fmt, ap);
++ va_end(ap);
++
++ return 0;
++}
++
++int SLcurses_wprintw (SLcurses_Window_Type *w, char *fmt, ...)
++{
++ va_list ap;
++
++ va_start(ap, fmt);
++ va_mvprintw (w, 0, 0, 0, fmt, ap);
++ va_end(ap);
++
++ return 0;
++}
++
++int SLcurses_printw (char *fmt, ...)
++{
++ va_list ap;
++
++ va_start(ap, fmt);
++ va_mvprintw (SLcurses_Stdscr, 0, 0, 0, fmt, ap);
++ va_end(ap);
++
++ return 0;
++}
++
++int SLcurses_nil (void)
++{
++ return 0;
++}
++
++int SLcurses_has_colors(void)
++{
++ return SLtt_Use_Ansi_Colors;
++}
++
++int SLcurses_nodelay (SLcurses_Window_Type *w, int onoff)
++{
++ w-&gt;delay_off = (onoff ? 0 : -1);
++ return 0;
++}
++
++int SLcurses_wgetch (SLcurses_Window_Type *w)
++{
++ if (w == NULL)
++ return ERR;
++
++ SLcurses_wrefresh (w);
++
++ if ((w-&gt;delay_off == -1) ||
++ SLang_input_pending (w-&gt;delay_off))
++ {
++ if (w-&gt;use_keypad)
++ {
++ int ch = SLang_getkey ();
++ if (ch == '\033')
++ {
++ if (0 == SLang_input_pending (ESCDELAY / 100))
++ return ch;
++ }
++ else if (ch == 0xFFFF) return ERR;
++ SLang_ungetkey (ch);
++ return SLkp_getkey ();
++ }
++ return SLang_getkey ();
++ }
++
++ return ERR;
++}
++
++int SLcurses_getch (void)
++{
++ return SLcurses_wgetch (SLcurses_Stdscr);
++}
++
++/* This is a super hack. That fact is that SLsmg and curses
++ * are incompatible.
++ */
++static unsigned char Color_Objects[256];
++
++static unsigned int map_attr_to_object (SLtt_Char_Type attr)
++{
++ unsigned int obj;
++ SLtt_Char_Type at;
++
++ obj = (attr &gt;&gt; 8) &amp; 0xFF;
++
++ if (SLtt_Use_Ansi_Colors)
++ {
++ if (Color_Objects[obj] != 0) return obj;
++
++ at = SLtt_get_color_object (obj &amp; 0xF);
++
++ if (attr &amp; A_BOLD) at |= SLTT_BOLD_MASK;
++ if (attr &amp; A_UNDERLINE) at |= SLTT_ULINE_MASK;
++ if (attr &amp; A_REVERSE) at |= SLTT_REV_MASK;
++
++ SLtt_set_color_object (obj, at);
++
++ Color_Objects[obj] = 1;
++ }
++ else obj = obj &amp; 0xF0;
++
++ return obj;
++
++}
++
++int SLcurses_start_color (void)
++{
++ int f, b;
++ int obj;
++
++ if (SLtt_Use_Ansi_Colors == 0) return -1;
++
++ obj = 0;
++ for (f = 0; f &lt; 16; f++)
++ {
++ for (b = 0; b &lt; 16; b++)
++ {
++ obj++;
++ SLtt_set_color_fgbg (obj, f, b);
++ }
++ }
++ return 0;
++}
++
++#ifdef SIGINT
++static void sigint_handler (int sig)
++{
++ SLang_reset_tty ();
++ SLsmg_reset_smg ();
++ exit (sig);
++}
++#endif
++
++/* Values are assumed to be 0, 1, 2. This fact is exploited */
++static int TTY_State;
++
++static int init_tty (int suspend_ok)
++{
++ if (-1 == SLang_init_tty (-1, 1, 0))
++ return -1;
++
++#ifdef REAL_UNIX_SYSTEM
++ if (suspend_ok) SLtty_set_suspend_state (1);
++#endif
++ return 0;
++}
++
++int SLcurses_raw (void)
++{
++ TTY_State = 1;
++ return init_tty (0);
++}
++
++int SLcurses_cbreak (void)
++{
++ TTY_State = 2;
++ return init_tty (1);
++}
++
++#if defined(SIGTSTP) &amp;&amp; defined(SIGSTOP)
++static void sigtstp_handler (int sig)
++{
++ sig = errno;
++
++ SLsmg_suspend_smg ();
++
++ if (TTY_State)
++ SLang_reset_tty ();
++
++ kill(getpid(),SIGSTOP);
++
++ SLsmg_resume_smg ();
++
++ if (TTY_State) init_tty (TTY_State - 1);
++
++ signal (SIGTSTP, sigtstp_handler);
++ errno = sig;
++}
++#endif
++
++SLcurses_Window_Type *SLcurses_initscr (void)
++{
++ SLcurses_Is_Endwin = 0;
++ SLsmg_Newline_Behavior = SLSMG_NEWLINE_MOVES;
++ SLtt_get_terminfo ();
++
++#if !defined(IBMPC_SYSTEM) &amp;&amp; !defined(VMS)
++ if (-1 == (SLcurses_Num_Colors = SLtt_tgetnum (&quot;Co&quot;)))
++#endif
++ SLcurses_Num_Colors = 8;
++
++ if ((-1 == SLkp_init ())
++ || (-1 == SLcurses_cbreak ())
++ || (NULL == (SLcurses_Stdscr = SLcurses_newwin (0, 0, 0, 0)))
++ || (-1 == SLsmg_init_smg ()))
++ {
++ SLang_doerror (NULL);
++ SLang_exit_error (&quot;SLcurses_initscr: init failed\n&quot;);
++ return NULL;
++ }
++
++#ifdef SIGINT
++ signal (SIGINT, sigint_handler);
++#endif
++
++#if defined(SIGTSTP) &amp;&amp; defined(SIGSTOP)
++ signal (SIGTSTP, sigtstp_handler);
++#endif
++
++ SLtt_set_mono (A_BOLD &gt;&gt; 8, NULL, SLTT_BOLD_MASK);
++ SLtt_set_mono (A_UNDERLINE &gt;&gt; 8, NULL, SLTT_ULINE_MASK);
++ SLtt_set_mono (A_REVERSE &gt;&gt; 8, NULL, SLTT_REV_MASK);
++ /* SLtt_set_mono (A_BLINK &gt;&gt; 8, NULL, SLTT_BLINK_MASK); */
++ SLtt_set_mono ((A_BOLD|A_UNDERLINE) &gt;&gt; 8, NULL, SLTT_ULINE_MASK|SLTT_BOLD_MASK);
++ SLtt_set_mono ((A_REVERSE|A_UNDERLINE) &gt;&gt; 8, NULL, SLTT_ULINE_MASK|SLTT_REV_MASK);
++
++ if (SLtt_Has_Alt_Charset)
++ {
++ SLcurses_Acs_Map[SLSMG_ULCORN_CHAR] = SLSMG_ULCORN_CHAR | A_ALTCHARSET;
++ SLcurses_Acs_Map[SLSMG_URCORN_CHAR] = SLSMG_URCORN_CHAR | A_ALTCHARSET;
++ SLcurses_Acs_Map[SLSMG_LLCORN_CHAR] = SLSMG_LLCORN_CHAR | A_ALTCHARSET;
++ SLcurses_Acs_Map[SLSMG_LRCORN_CHAR] = SLSMG_LRCORN_CHAR | A_ALTCHARSET;
++ SLcurses_Acs_Map[SLSMG_UTEE_CHAR] = SLSMG_UTEE_CHAR | A_ALTCHARSET;
++ SLcurses_Acs_Map[SLSMG_DTEE_CHAR] = SLSMG_DTEE_CHAR | A_ALTCHARSET;
++ SLcurses_Acs_Map[SLSMG_LTEE_CHAR] = SLSMG_LTEE_CHAR | A_ALTCHARSET;
++ SLcurses_Acs_Map[SLSMG_RTEE_CHAR] = SLSMG_RTEE_CHAR | A_ALTCHARSET;
++ SLcurses_Acs_Map[SLSMG_VLINE_CHAR] = SLSMG_VLINE_CHAR | A_ALTCHARSET;
++ SLcurses_Acs_Map[SLSMG_HLINE_CHAR] = SLSMG_HLINE_CHAR | A_ALTCHARSET;
++ SLcurses_Acs_Map[SLSMG_PLUS_CHAR] = SLSMG_PLUS_CHAR | A_ALTCHARSET;
++ SLcurses_Acs_Map[SLSMG_CKBRD_CHAR] = SLSMG_CKBRD_CHAR | A_ALTCHARSET;
++ }
++ else
++ {
++ /* ugly defaults to use on terminals which don't support graphics */
++ SLcurses_Acs_Map[SLSMG_ULCORN_CHAR] = '+';
++ SLcurses_Acs_Map[SLSMG_URCORN_CHAR] = '+';
++ SLcurses_Acs_Map[SLSMG_LLCORN_CHAR] = '+';
++ SLcurses_Acs_Map[SLSMG_LRCORN_CHAR] = '+';
++ SLcurses_Acs_Map[SLSMG_UTEE_CHAR] = '+';
++ SLcurses_Acs_Map[SLSMG_DTEE_CHAR] = '+';
++ SLcurses_Acs_Map[SLSMG_LTEE_CHAR] = '+';
++ SLcurses_Acs_Map[SLSMG_RTEE_CHAR] = '+';
++ SLcurses_Acs_Map[SLSMG_VLINE_CHAR] = '|';
++ SLcurses_Acs_Map[SLSMG_HLINE_CHAR] = '-';
++ SLcurses_Acs_Map[SLSMG_PLUS_CHAR] = '+';
++ SLcurses_Acs_Map[SLSMG_CKBRD_CHAR] = '#';
++ }
++
++ return SLcurses_Stdscr;
++}
++
++int SLcurses_wattrset (SLcurses_Window_Type *w, SLtt_Char_Type ch)
++{
++ unsigned int obj;
++
++ obj = map_attr_to_object (ch);
++ w-&gt;color = obj;
++ w-&gt;attr = ch;
++ return 0;
++}
++
++int SLcurses_wattroff (SLcurses_Window_Type *w, SLtt_Char_Type ch)
++{
++ if (SLtt_Use_Ansi_Colors)
++ return SLcurses_wattrset (w, 0);
++
++ w-&gt;attr &amp;= ~ch;
++ return SLcurses_wattrset (w, w-&gt;attr);
++}
++
++int SLcurses_wattron (SLcurses_Window_Type *w, SLtt_Char_Type ch)
++{
++ if (SLtt_Use_Ansi_Colors)
++ return SLcurses_wattrset (w, ch);
++
++ w-&gt;attr |= ch;
++ return SLcurses_wattrset (w, w-&gt;attr);
++}
++
++int SLcurses_delwin (SLcurses_Window_Type *w)
++{
++ if (w == NULL) return 0;
++ if (w-&gt;lines != NULL)
++ {
++ SLsmg_Char_Type **lines = w-&gt;lines;
++ if (w-&gt;is_subwin == 0)
++ {
++ unsigned int r, rmax;
++
++ rmax = w-&gt;nrows;
++ for (r = 0; r &lt; rmax; r++)
++ {
++ SLfree ((char *)lines[r]);
++ }
++ }
++
++ SLfree ((char *)lines);
++ }
++
++ SLfree ((char *)w);
++ if (w == SLcurses_Stdscr)
++ SLcurses_Stdscr = NULL;
++ return 0;
++}
++
++SLcurses_Window_Type *SLcurses_newwin (unsigned int nrows, unsigned int ncols,
++ unsigned int r, unsigned int c)
++{
++ SLcurses_Window_Type *win;
++ SLsmg_Char_Type **lines;
++
++ if (r &gt;= (unsigned int) SLtt_Screen_Rows)
++ return NULL;
++ if (c &gt;= (unsigned int) SLtt_Screen_Cols)
++ return NULL;
++
++ if (NULL == (win = (SLcurses_Window_Type *) SLmalloc (sizeof (SLcurses_Window_Type))))
++ return NULL;
++
++ SLMEMSET ((char *) win, 0, sizeof (SLcurses_Window_Type));
++
++ if (nrows == 0)
++ nrows = (unsigned int) SLtt_Screen_Rows - r;
++ if (ncols == 0)
++ ncols = (unsigned int) SLtt_Screen_Cols - c;
++
++ lines = (SLsmg_Char_Type **) SLmalloc (nrows * sizeof (SLsmg_Char_Type *));
++ if (lines == NULL)
++ {
++ SLcurses_delwin (win);
++ return NULL;
++ }
++
++ SLMEMSET ((char *) lines, 0, nrows * sizeof (SLsmg_Char_Type *));
++
++ win-&gt;lines = lines;
++ win-&gt;scroll_max = win-&gt;nrows = nrows;
++ win-&gt;ncols = ncols;
++ win-&gt;_begy = r;
++ win-&gt;_begx = c;
++ win-&gt;_maxx = (c + ncols) - 1;
++ win-&gt;_maxy = (r + nrows) - 1;
++ win-&gt;modified = 1;
++ win-&gt;delay_off = -1;
++
++ for (r = 0; r &lt; nrows; r++)
++ {
++ SLsmg_Char_Type *b;
++
++ b = (SLsmg_Char_Type *) SLmalloc (ncols * sizeof (SLsmg_Char_Type));
++ if (b == NULL)
++ {
++ SLcurses_delwin (win);
++ return NULL;
++ }
++ lines [r] = b;
++ blank_line (b, ncols, 0);
++ }
++
++ return win;
++}
++
++int SLcurses_wmove (SLcurses_Window_Type *win, unsigned int r, unsigned int c)
++{
++ if (win == NULL) return -1;
++ win-&gt;_cury = r;
++ win-&gt;_curx = c;
++ win-&gt;modified = 1;
++ return 0;
++}
++
++static int do_newline (SLcurses_Window_Type *w)
++{
++ w-&gt;_curx = 0;
++ w-&gt;_cury += 1;
++ if (w-&gt;_cury &gt;= w-&gt;scroll_max)
++ {
++ w-&gt;_cury = w-&gt;scroll_max - 1;
++ if (w-&gt;scroll_ok)
++ SLcurses_wscrl (w, 1);
++ }
++
++ return 0;
++}
++
++int SLcurses_waddch (SLcurses_Window_Type *win, SLtt_Char_Type attr)
++{
++ SLsmg_Char_Type *b, ch;
++ SLsmg_Char_Type color;
++
++ if (win == NULL) return -1;
++
++ if (win-&gt;_cury &gt;= win-&gt;nrows)
++ {
++ /* Curses seems to move current postion to top of window. */
++ win-&gt;_cury = win-&gt;_curx = 0;
++ return -1;
++ }
++
++ win-&gt;modified = 1;
++
++ ch = SLSMG_EXTRACT_CHAR(attr);
++
++ if (attr == ch)
++ color = win-&gt;color;
++ else
++ {
++ /* hack to pick up the default color for graphics chars */
++ if (((attr &amp; A_COLOR) == 0) &amp;&amp; ((attr &amp; A_ALTCHARSET) != 0))
++ {
++ /* FIXME: priority=medium: Use SLSMG_?? instead of &lt;&lt; */
++ attr |= win-&gt;color &lt;&lt; 8;
++ }
++ color = map_attr_to_object (attr);
++ }
++
++ if (ch &lt; ' ')
++ {
++ if (ch == '\n')
++ {
++ SLcurses_wclrtoeol (win);
++ return do_newline (win);
++ }
++
++ if (ch == '\r')
++ {
++ win-&gt;_curx = 0;
++ return 0;
++ }
++
++ if (ch == '\b')
++ {
++ if (win-&gt;_curx &gt; 0)
++ win-&gt;_curx--;
++
++ return 0;
++ }
++
++ /* HACK HACK!!!! */
++ if (ch == '\t') ch = ' ';
++ }
++
++ if (win-&gt;_curx &gt;= win-&gt;ncols)
++ do_newline (win);
++
++ b = win-&gt;lines[win-&gt;_cury] + win-&gt;_curx;
++ *b = SLSMG_BUILD_CHAR(ch,color);
++ win-&gt;_curx++;
++
++ return 0;
++}
++
++int SLcurses_wnoutrefresh (SLcurses_Window_Type *w)
++{
++ unsigned int len;
++ unsigned int r, c;
++ unsigned int i, imax;
++
++ if (SLcurses_Is_Endwin)
++ {
++ if (TTY_State) init_tty (TTY_State - 1);
++ SLsmg_resume_smg ();
++ SLcurses_Is_Endwin = 0;
++ }
++
++ if (w == NULL)
++ {
++ SLsmg_refresh ();
++ return -1;
++ }
++
++ if (w-&gt;modified == 0)
++ return 0;
++
++ r = w-&gt;_begy;
++ c = w-&gt;_begx;
++
++ len = w-&gt;ncols;
++ imax = w-&gt;nrows;
++
++ for (i = 0; i &lt; imax; i++)
++ {
++ SLsmg_gotorc (r, c);
++ SLsmg_write_color_chars (w-&gt;lines[i], len);
++ r++;
++ }
++
++ if (w-&gt;has_box)
++ SLsmg_draw_box(w-&gt;_begy, w-&gt;_begx, w-&gt;nrows, w-&gt;ncols);
++
++ SLsmg_gotorc (w-&gt;_begy + w-&gt;_cury, w-&gt;_begx + w-&gt;_curx);
++ w-&gt;modified = 0;
++ return 0;
++}
++
++int SLcurses_wrefresh (SLcurses_Window_Type *w)
++{
++ if (w == NULL)
++ return -1;
++
++ if (w-&gt;modified == 0)
++ return 0;
++
++ SLcurses_wnoutrefresh (w);
++ SLsmg_refresh ();
++ return 0;
++}
++
++int SLcurses_wclrtoeol (SLcurses_Window_Type *w)
++{
++ SLsmg_Char_Type *b, *bmax;
++ SLsmg_Char_Type blank;
++
++ if (w == NULL) return -1;
++ if (w-&gt;_cury &gt;= w-&gt;nrows)
++ return 0;
++
++ w-&gt;modified = 1;
++
++ blank = SLSMG_BUILD_CHAR(' ',w-&gt;color);
++
++ b = w-&gt;lines[w-&gt;_cury];
++ bmax = b + w-&gt;ncols;
++ b += w-&gt;_curx;
++
++ while (b &lt; bmax) *b++ = blank;
++ return 0;
++}
++
++int SLcurses_wclrtobot (SLcurses_Window_Type *w)
++{
++ SLsmg_Char_Type *b, *bmax;
++ SLsmg_Char_Type blank;
++ unsigned int r;
++
++ if (w == NULL) return -1;
++
++ w-&gt;modified = 1;
++ blank = SLSMG_BUILD_CHAR(' ',w-&gt;color);
++ SLcurses_wclrtoeol (w);
++ for (r = w-&gt;_cury + 1; r &lt; w-&gt;nrows; r++)
++ {
++ b = w-&gt;lines [r];
++ bmax = b + w-&gt;ncols;
++
++ while (b &lt; bmax) *b++ = blank;
++ }
++
++ return 0;
++}
++
++int SLcurses_wscrl (SLcurses_Window_Type *w, int n)
++{
++ SLsmg_Char_Type **lines;
++ unsigned int r, rmax, rmin, ncols;
++ SLsmg_Char_Type color;
++
++ if ((w == NULL) || (w-&gt;scroll_ok == 0))
++ return -1;
++
++ w-&gt;modified = 1;
++#if 0
++ if (w-&gt;is_subwin)
++ {
++ SLang_reset_tty ();
++ SLsmg_reset_smg ();
++ fprintf (stderr, &quot;\rAttempt to scroll a subwindow\n&quot;);
++ exit (1);
++ }
++#endif
++
++ color = w-&gt;color;
++ ncols = w-&gt;ncols;
++ lines = w-&gt;lines;
++ rmax = w-&gt;scroll_max;
++ rmin = w-&gt;scroll_min;
++ if (rmax &gt; w-&gt;nrows)
++ rmax = w-&gt;nrows;
++ if (rmin &gt;= rmax)
++ return 0;
++
++ while (n &gt; 0)
++ {
++ for (r = rmin + 1; r &lt; rmax; r++)
++ {
++ /* lines[r - 1] = lines[r]; */
++ memcpy ((char *)lines[r - 1], (char *)lines[r],
++ sizeof (SLsmg_Char_Type) * ncols);
++ }
++ blank_line (lines[rmax - 1], ncols, color);
++ n--;
++ }
++
++ rmax--;
++ while (n &lt; 0)
++ {
++ for (r = rmax; r &gt; rmin; r--)
++ {
++ memcpy ((char *)lines[r], (char *)lines[r - 1],
++ sizeof (SLsmg_Char_Type) * ncols);
++ }
++ blank_line (lines[rmin], ncols, color);
++ n++;
++ }
++
++ /* wmove (w, w-&gt;nrows - 1, 0); */
++ /* wclrtobot (w); */
++ return 0;
++}
++
++/* Note: if len is &lt; 0, entire string will be used.
++ */
++int SLcurses_waddnstr (SLcurses_Window_Type *w, char *str, int len)
++{
++ SLsmg_Char_Type *b;
++ SLsmg_Char_Type color;
++ unsigned char ch;
++ unsigned int nrows, ncols, crow, ccol;
++
++ if ((w == NULL)
++ || (str == NULL))
++ return -1;
++
++ w-&gt;modified = 1;
++ nrows = w-&gt;nrows;
++ ncols = w-&gt;ncols;
++ crow = w-&gt;_cury;
++ ccol = w-&gt;_curx;
++ color = w-&gt;color;
++
++ if (w-&gt;scroll_max &lt;= nrows)
++ nrows = w-&gt;scroll_max;
++
++ if (crow &gt;= nrows)
++ crow = 0; /* wrap back to top */
++
++ b = w-&gt;lines [crow] + ccol;
++
++ while (len &amp;&amp; ((ch = (unsigned char) *str++) != 0))
++ {
++ len--;
++
++ if (ch == '\n')
++ {
++ w-&gt;_cury = crow;
++ w-&gt;_curx = ccol;
++ SLcurses_wclrtoeol (w);
++ do_newline (w);
++ crow = w-&gt;_cury;
++ ccol = w-&gt;_curx;
++ b = w-&gt;lines[crow];
++ continue;
++ }
++
++ if (ccol &gt;= ncols)
++ {
++ ccol = 0;
++ crow++;
++ if (crow &gt;= nrows)
++ {
++ w-&gt;_curx = 0;
++ w-&gt;_cury = crow;
++ do_newline (w);
++ crow = w-&gt;_cury;
++ ccol = w-&gt;_curx;
++ }
++
++ b = w-&gt;lines [crow];
++ }
++
++ if (ch == '\t')
++ {
++ unsigned int n = ccol;
++ n += SLsmg_Tab_Width;
++ n = SLsmg_Tab_Width - (n % SLsmg_Tab_Width);
++ if (ccol + n &gt; ncols) n = ncols - len;
++ ccol += n;
++ while (n--)
++ *b++ = SLSMG_BUILD_CHAR(' ',color);
++ continue;
++ }
++
++ *b++ = SLSMG_BUILD_CHAR(ch, color);
++ ccol++;
++ }
++
++ w-&gt;_curx = ccol;
++ w-&gt;_cury = crow;
++
++ return 0;
++}
++
++/* This routine IS NOT CORRECT. It needs to compute the proper overlap
++ * and copy accordingly. Here, I just assume windows are same size.
++ */
++#if 0
++int SLcurses_overlay (SLcurses_Window_Type *swin, SLcurses_Window_Type *dwin)
++{
++ SLsmg_Char_Type *s, *smax, *d, *dmax;
++
++ if ((swin == NULL) || (dwin == NULL))
++ return -1;
++
++ s = swin-&gt;buf;
++ smax = swin-&gt;bufmax;
++ d = dwin-&gt;buf;
++ dmax = dwin-&gt;bufmax;
++
++ while ((s &lt; smax) &amp;&amp; (d &lt; dmax))
++ {
++ SLsmg_Char_Type ch = *s++;
++ if (SLSMG_EXTRACT_CHAR(ch) != ' ')
++ *d = ch;
++ d++;
++ }
++
++ return -1; /* not implemented */
++}
++
++#endif
++
++SLcurses_Window_Type *SLcurses_subwin (SLcurses_Window_Type *orig,
++ unsigned int nlines, unsigned int ncols,
++ unsigned int begin_y, unsigned int begin_x)
++{
++ SLcurses_Window_Type *sw;
++ int r, c;
++ unsigned int i;
++
++ if (orig == NULL)
++ return NULL;
++
++ sw = (SLcurses_Window_Type *) SLmalloc (sizeof (SLcurses_Window_Type));
++ if (sw == NULL)
++ return NULL;
++
++ SLMEMSET ((char *)sw, 0, sizeof (SLcurses_Window_Type));
++#if 1
++ r = begin_y - orig-&gt;_begy;
++#else
++ r = 1 + ((int)orig-&gt;nrows - (int)nlines) / 2;
++#endif
++ if (r &lt; 0) r = 0;
++ if (r + nlines &gt; orig-&gt;nrows) nlines = orig-&gt;nrows - r;
++
++ c = ((int)orig-&gt;ncols - (int)ncols) / 2;
++ if (c &lt; 0) c = 0;
++ if (c + ncols &gt; orig-&gt;ncols) ncols = orig-&gt;ncols - c;
++
++ sw-&gt;scroll_min = 0;
++ sw-&gt;scroll_max = sw-&gt;nrows = nlines;
++ sw-&gt;ncols = ncols;
++ sw-&gt;_begy = begin_y;
++ sw-&gt;_begx = begin_x;
++ sw-&gt;_maxx = (begin_x + ncols) - 1;
++ sw-&gt;_maxy = (begin_y + nlines) - 1;
++
++ sw-&gt;lines = (SLsmg_Char_Type **) SLmalloc (nlines * sizeof (SLsmg_Char_Type *));
++ if (sw-&gt;lines == NULL)
++ {
++ SLcurses_delwin (sw);
++ return NULL;
++ }
++
++ for (i = 0; i &lt; nlines; i++)
++ {
++ sw-&gt;lines [i] = orig-&gt;lines [r + i] + c;
++ }
++
++ sw-&gt;is_subwin = 1;
++ return sw;
++}
++
++int SLcurses_wclear (SLcurses_Window_Type *w)
++{
++ unsigned int i;
++
++ if (w != NULL) w-&gt;modified = 1;
++ for (i=0; i &lt; w-&gt;nrows; i++)
++ blank_line (w-&gt;lines[i], w-&gt;ncols, w-&gt;color);
++ return 0;
++}
++
++int SLcurses_wdelch (SLcurses_Window_Type *w)
++{
++ SLsmg_Char_Type *p, *p1, *pmax;
++
++ p = w-&gt;lines[w-&gt;_cury];
++ pmax = p + w-&gt;ncols;
++ p += w-&gt;_curx;
++ p1 = p + 1;
++
++ while (p1 &lt; pmax)
++ {
++ *p = *p1;
++ p = p1;
++ p1++;
++ }
++
++ if (p &lt; pmax)
++ *p = SLSMG_BUILD_CHAR(' ',w-&gt;color);
++
++ w-&gt;modified = 1;
++ return 0;
++}
++
++int SLcurses_winsch (SLcurses_Window_Type *w, int ch)
++{
++ SLsmg_Char_Type *p, *p1, *pmax;
++
++ p = w-&gt;lines[w-&gt;_cury];
++ pmax = p + w-&gt;ncols;
++ p += w-&gt;_curx;
++ p1 = pmax - 1;
++
++ while (pmax &gt; p)
++ {
++ *pmax = *p1;
++ pmax = p1;
++ p1--;
++ }
++
++ if (p &lt; pmax)
++ *p = SLSMG_BUILD_CHAR(ch, w-&gt;color);
++
++ w-&gt;modified = 1;
++ return 0;
++}
++
++int SLcurses_endwin (void)
++{
++ SLcurses_Is_Endwin = 1;
++ SLsmg_suspend_smg ();
++ SLang_reset_tty ();
++ return 0;
++}
++
++#if 0
++int SLcurses_mvwscanw (SLcurses_Window_Type *w, unsigned int r, unsigned int c,
++ char *fmt, ...)
++{
++#if HAVE_VFSCANF
++ int ret;
++ va_list ap;
++
++ SLcurses_wmove (w, r, c);
++ SLcurses_wrefresh (w);
++
++ va_start(ap, fmt);
++ ret = vfscanf (stdin, fmt, ap);
++ va_end(ap);
++ return ret;
++#else
++ return 0;
++#endif
++}
++
++int SLcurses_wscanw (SLcurses_Window_Type *w, char *fmt, ...)
++{
++#if HAVE_VFSCANF
++ va_list ap;
++ int ret;
++
++ SLcurses_wrefresh (w);
++
++ va_start(ap, fmt);
++ ret = vfscanf (stdin, fmt, ap);
++ va_end(ap);
++
++ return ret;
++#else
++ return 0;
++#endif
++}
++
++int SLcurses_scanw (char *fmt, ...)
++{
++#ifdef HAVE_VFSCANF
++ va_list ap;
++ int ret;
++
++ SLcurses_wrefresh (SLcurses_Stdscr);
++
++ va_start(ap, fmt);
++ ret = vfscanf (stdin, fmt, ap);
++ va_end(ap);
++
++ return ret;
++#else
++ return 0;
++#endif
++}
++#endif
++
++int SLcurses_clearok (SLcurses_Window_Type *w, int bf)
++{
++ if (bf)
++ {
++ SLsmg_cls ();
++ w-&gt;modified = 1;
++ }
++ return 0;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slcurses.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slcurses.h
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slcurses.h (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slcurses.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,353 @@
++/* Copyright (c) 1998, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++#include &lt;stdio.h&gt;
++
++#ifndef SLANG_VERSION
++# include &lt;slang.h&gt;
++#endif
++
++/* This is a temporary hack until lynx is fixed to not include this file. */
++#ifndef LYCURSES_H
++
++typedef struct
++{
++ unsigned int _begy, _begx, _maxy, _maxx;
++ unsigned int _curx, _cury;
++ unsigned int nrows, ncols;
++ unsigned int scroll_min, scroll_max;
++ SLsmg_Char_Type **lines;
++ SLsmg_Char_Type color;
++ int is_subwin;
++ SLtt_Char_Type attr;
++ int delay_off;
++ int scroll_ok;
++ int modified;
++ int has_box;
++ int use_keypad;
++}
++SLcurses_Window_Type;
++
++extern int SLcurses_wclrtobot (SLcurses_Window_Type *);
++extern int SLcurses_wscrl (SLcurses_Window_Type *, int);
++extern int SLcurses_wrefresh (SLcurses_Window_Type *);
++extern int SLcurses_delwin (SLcurses_Window_Type *);
++extern int SLcurses_wprintw (SLcurses_Window_Type *, char *, ...);
++extern SLcurses_Window_Type *SLcurses_newwin (unsigned int, unsigned int,
++ unsigned int, unsigned int);
++
++extern SLcurses_Window_Type *SLcurses_subwin (SLcurses_Window_Type *,
++ unsigned int, unsigned int,
++ unsigned int, unsigned int);
++
++extern int SLcurses_wnoutrefresh (SLcurses_Window_Type *);
++extern int SLcurses_wclrtoeol (SLcurses_Window_Type *);
++
++extern int SLcurses_wmove (SLcurses_Window_Type *, unsigned int, unsigned int);
++extern int SLcurses_waddch (SLcurses_Window_Type *, SLtt_Char_Type);
++extern int SLcurses_waddnstr (SLcurses_Window_Type *, char *, int);
++
++#define waddnstr SLcurses_waddnstr
++#define waddch SLcurses_waddch
++#define waddstr(w,s) waddnstr((w),(s),-1)
++#define addstr(x) waddstr(stdscr, (x))
++#define addnstr(s,n) waddnstr(stdscr,(s),(n))
++#define addch(ch) waddch(stdscr,(ch))
++
++#define mvwaddnstr(w,y,x,s,n) \
++ (-1 == wmove((w),(y),(x)) ? -1 : waddnstr((w),(s),(n)))
++#define mvwaddstr(w,y,x,s) \
++ (-1 == wmove((w),(y),(x)) ? -1 : waddnstr((w),(s), -1))
++#define mvaddnstr(y,x,s,n) mvwaddnstr(stdscr,(y),(x),(s),(n))
++#define mvaddstr(y,x,s) mvwaddstr(stdscr,(y),(x),(s))
++#define mvwaddch(w,y,x,c) \
++ ((-1 == wmove((w),(y),(x))) ? -1 : waddch((w),(c)))
++#define mvaddch(y,x,c) mvwaddch(stdscr,(y),(x),(c))
++
++extern int SLcurses_wclear (SLcurses_Window_Type *w);
++extern int SLcurses_printw (char *, ...);
++
++#if 0
++/* Why are these functions part of curses??? */
++extern int SLcurses_mvwscanw (SLcurses_Window_Type *, unsigned int, unsigned int,
++ char *, ...);
++extern int SLcurses_wscanw (SLcurses_Window_Type *, char *, ...);
++extern int SLcurses_scanw (char *, ...);
++#define mvwscanw SLcurses_mvwscanw
++#define wscanw SLcurses_wscanw
++#define scanw SLcurses_scanw
++#endif
++
++extern SLcurses_Window_Type *SLcurses_Stdscr;
++#define WINDOW SLcurses_Window_Type
++#define stdscr SLcurses_Stdscr
++
++#define subwin SLcurses_subwin
++#define wclrtobot SLcurses_wclrtobot
++#define wscrl SLcurses_wscrl
++#define scrl(n) wscrl(stdscr,(n))
++#define scroll(w) wscrl((w),1)
++#define wrefresh SLcurses_wrefresh
++#define delwin SLcurses_delwin
++#define wmove SLcurses_wmove
++#define newwin SLcurses_newwin
++#define wnoutrefresh SLcurses_wnoutrefresh
++#define werase(w) SLcurses_wmove((w),0,0); SLcurses_wclrtobot(w)
++#define wclear(w) SLcurses_wmove((w),0,0); SLcurses_wclrtobot(w)
++#define wprintw SLcurses_wprintw
++#define mvwprintw SLcurses_mvwprintw
++
++#define winch(w) \
++ ((((w)-&gt;_cury &lt; (w)-&gt;nrows) &amp;&amp; ((w)-&gt;_curx &lt; (w)-&gt;ncols)) \
++ ? ((w)-&gt;lines[(w)-&gt;_cury][(w)-&gt;_curx]) : 0)
++
++#define inch() winch(stdscr)
++#define mvwinch(w,x,y) \
++ ((-1 != wmove((w),(x),(y))) ? winch(w) : (-1))
++#define doupdate SLsmg_refresh
++
++#define mvwin(w,a,b) ((w)-&gt;_begy = (a), (w)-&gt;_begx = (b))
++
++extern int SLcurses_mvprintw (int, int, char *, ...);
++extern int SLcurses_mvwprintw (SLcurses_Window_Type *, int, int, char *, ...);
++extern int SLcurses_has_colors(void);
++extern int SLcurses_nil (void);
++extern int SLcurses_wgetch (SLcurses_Window_Type *);
++extern int SLcurses_getch (void);
++
++extern int SLcurses_wattrset (SLcurses_Window_Type *, SLtt_Char_Type);
++extern int SLcurses_wattron (SLcurses_Window_Type *, SLtt_Char_Type);
++extern int SLcurses_wattroff (SLcurses_Window_Type *, SLtt_Char_Type);
++#define attrset(x) SLcurses_wattrset(stdscr, (x))
++#define attron(x) SLcurses_wattron(stdscr, (x))
++#define attroff(x) SLcurses_wattroff(stdscr, (x))
++#define wattrset(w, x) SLcurses_wattrset((w), (x))
++#define wattron(w, x) SLcurses_wattron((w), (x))
++#define wattroff(w, x) SLcurses_wattroff((w), (x))
++#define wattr_get(w) ((w)-&gt;color &lt;&lt; 8)
++#define attr_get() wattr_get(stdscr)
++
++#define COLOR_PAIR(x) ((x) &lt;&lt; 8)
++
++extern int SLcurses_start_color (void);
++#define start_color SLcurses_start_color
++
++#define ERR 0xFFFF
++#define wgetch SLcurses_wgetch
++#define getch SLcurses_getch
++
++extern int SLcurses_nodelay (SLcurses_Window_Type *, int);
++extern SLcurses_Window_Type *SLcurses_initscr (void);
++#define initscr SLcurses_initscr
++
++extern int SLcurses_cbreak (void);
++extern int SLcurses_raw (void);
++#define cbreak SLcurses_cbreak
++#define crmode SLcurses_cbreak
++#define raw SLcurses_raw
++#define noraw SLang_reset_tty
++#define nocbreak SLang_reset_tty
++
++#define mvprintw SLcurses_mvprintw
++#define has_colors SLcurses_has_colors
++#define nodelay SLcurses_nodelay
++
++#define ungetch SLang_ungetkey
++
++#define COLS SLtt_Screen_Cols
++#define LINES SLtt_Screen_Rows
++
++#define move(x,y) SLcurses_wmove(stdscr, (x), (y))
++#define wclrtoeol SLcurses_wclrtoeol
++#define clrtoeol() SLcurses_wclrtoeol(stdscr)
++#define clrtobot() SLcurses_wclrtobot(stdscr)
++
++#define printw SLcurses_printw
++#define mvprintw SLcurses_mvprintw
++#define wstandout(w) SLcurses_wattrset((w),A_STANDOUT)
++#define wstandend(w) SLcurses_wattrset((w),A_NORMAL)
++#define standout() SLcurses_wattrset(stdscr,A_STANDOUT)
++#define standend() SLcurses_wattrset(stdscr,A_NORMAL)
++
++#define refresh() SLcurses_wrefresh(stdscr)
++#define clear() SLcurses_wclear(stdscr)
++#define erase() werase(stdscr)
++#define touchline SLsmg_touch_lines
++#define resetterm SLang_reset_tty
++
++extern int SLcurses_endwin (void);
++#define endwin SLcurses_endwin
++extern int SLcurses_Is_Endwin;
++#define isendwin() SLcurses_Is_Endwin
++
++#define keypad(w,x) ((w)-&gt;use_keypad = (x))
++
++#define KEY_MIN SL_KEY_UP
++#define KEY_DOWN SL_KEY_DOWN
++#define KEY_UP SL_KEY_UP
++#define KEY_LEFT SL_KEY_LEFT
++#define KEY_RIGHT SL_KEY_RIGHT
++#define KEY_A1 SL_KEY_A1
++#define KEY_B1 SL_KEY_B1
++#define KEY_C1 SL_KEY_C1
++#define KEY_A2 SL_KEY_A2
++#define KEY_B2 SL_KEY_B2
++#define KEY_C2 SL_KEY_C2
++#define KEY_A3 SL_KEY_A3
++#define KEY_B3 SL_KEY_B3
++#define KEY_C3 SL_KEY_C3
++#define KEY_REDO SL_KEY_REDO
++#define KEY_UNDO SL_KEY_UNDO
++#define KEY_BACKSPACE SL_KEY_BACKSPACE
++#define KEY_PPAGE SL_KEY_PPAGE
++#define KEY_NPAGE SL_KEY_NPAGE
++#define KEY_HOME SL_KEY_HOME
++#define KEY_END SL_KEY_END
++#define KEY_F0 SL_KEY_F0
++#define KEY_F SL_KEY_F
++#define KEY_ENTER SL_KEY_ENTER
++#define KEY_MAX 0xFFFF
++
++/* Ugly Hacks that may not work */
++#define flushinp SLcurses_nil
++#define winsertln(w) \
++ ((w)-&gt;scroll_min=(w)-&gt;_cury, \
++ (w)-&gt;scroll_max=(w)-&gt;nrows, \
++ wscrl((w), -1))
++
++extern SLtt_Char_Type SLcurses_Acs_Map [128];
++#define acs_map SLcurses_Acs_Map
++
++#define ACS_ULCORNER (acs_map[SLSMG_ULCORN_CHAR])
++#define ACS_URCORNER (acs_map[SLSMG_URCORN_CHAR])
++#define ACS_LRCORNER (acs_map[SLSMG_LRCORN_CHAR])
++#define ACS_LLCORNER (acs_map[SLSMG_LLCORN_CHAR])
++#define ACS_TTEE (acs_map[SLSMG_UTEE_CHAR])
++#define ACS_LTEE (acs_map[SLSMG_LTEE_CHAR])
++#define ACS_RTEE (acs_map[SLSMG_RTEE_CHAR])
++#define ACS_BTEE (acs_map[SLSMG_DTEE_CHAR])
++#define ACS_PLUS (acs_map[SLSMG_PLUS_CHAR])
++#define ACS_VLINE (acs_map[SLSMG_VLINE_CHAR])
++#define ACS_HLINE (acs_map[SLSMG_HLINE_CHAR])
++#define ACS_S1 '-'
++#define ACS_S9 '-'
++#define ACS_DIAMOND '&amp;'
++#define ACS_CKBOARD (acs_map[SLSMG_CKBRD_CHAR])
++#define ACS_DEGREE 'o'
++#define ACS_PLMINUS '+'
++#define ACS_BULLET '*'
++#define ACS_LARROW '&lt;'
++#define ACS_RARROW '&gt;'
++#define ACS_DARROW 'v'
++#define ACS_UARROW '^'
++#define ACS_BOARD '#'
++#define ACS_LANTERN '#'
++#define ACS_BLOCK '#'
++
++#if 1
++#define hline(x,y) SLcurses_nil ()
++#define vline(x,y) SLcurses_nil ()
++#endif
++
++#define A_CHARTEXT 0x00FF
++#define A_NORMAL 0
++#define A_BOLD 0x1000
++#define A_REVERSE 0x2000
++#define A_STANDOUT A_REVERSE
++#define A_UNDERLINE 0x4000
++#define A_BLINK 0
++#define A_COLOR 0x0700
++#define A_ALTCHARSET 0x8000
++#define A_DIM 0
++#define A_PROTECT 0
++#define A_INVIS 0
++
++#define COLOR_BLACK SLSMG_COLOR_BLACK
++#define COLOR_RED SLSMG_COLOR_RED
++#define COLOR_GREEN SLSMG_COLOR_GREEN
++#define COLOR_YELLOW SLSMG_COLOR_BROWN
++#define COLOR_BLUE SLSMG_COLOR_BLUE
++#define COLOR_MAGENTA SLSMG_COLOR_MAGENTA
++#define COLOR_CYAN SLSMG_COLOR_CYAN
++#define COLOR_WHITE SLSMG_COLOR_LGRAY
++
++extern int SLcurses_Num_Colors;
++#define COLORS SLcurses_Num_Colors
++#define COLOR_PAIRS (SLcurses_Num_Colors*SLcurses_Num_Colors)
++
++#define init_pair(_x,_f,_b) \
++ SLtt_set_color_object((_x), ((_f) == (_b) ? 0x0700 : ((_f) | ((_b) &lt;&lt; 8)) &lt;&lt; 8))
++
++#define scrollok(a,b) ((a)-&gt;scroll_ok = (b))
++#define getyx(a,y,x) (y=(a)-&gt;_cury, x=(a)-&gt;_curx)
++#define getmaxyx(a,y,x) (y=(a)-&gt;nrows, x=(a)-&gt;ncols)
++#define napms(x) usleep(1000 * (x))
++typedef SLtt_Char_Type chtype;
++#define beep SLtt_beep
++#define curs_set(x) SLtt_set_cursor_visibility(x)
++#define touchwin(x) SLsmg_touch_lines((x)-&gt;_begy, (x)-&gt;nrows)
++#define flash SLtt_beep
++
++#define wsetscrreg(w,a,b) ((w)-&gt;scroll_min = (a), (w)-&gt;scroll_max = (b))
++
++#define wtimeout(a,b) (a)-&gt;delay_off = ((b &gt;= 0) ? (b) / 100 : -1)
++#define timeout(a) wtimeout(stdscr, a)
++extern int SLcurses_wdelch (SLcurses_Window_Type *);
++#define wdelch SLcurses_wdelch
++#define delch() wdelch(stdscr)
++
++extern int SLcurses_winsch (SLcurses_Window_Type *, int);
++#define winsch SLcurses_winsch
++
++extern int SLcurses_Esc_Delay;/* ESC expire time in milliseconds (ncurses compatible) */
++#define ESCDELAY SLcurses_Esc_Delay
++
++extern int SLcurses_clearok (SLcurses_Window_Type *, int);
++#define clearok SLcurses_clearok
++
++/* Functions that have not been implemented. */
++#define copywin(w,v,a,b,c,d,e,f,g) SLcurses_nil()
++#define wdeleteln(win) SLcurses_nil()
++#define resetty SLcurses_nil
++#define savetty SLcurses_nil
++#define overlay(u,v) SLcurses_nil()
++
++/* These functions do nothing */
++#define savetty SLcurses_nil
++#define nonl SLcurses_nil
++#define echo SLcurses_nil
++#define noecho SLcurses_nil
++#define saveterm SLcurses_nil
++#define box(w,y,z) ((w)-&gt;has_box = 1, (w)-&gt;modified = 1)
++#define leaveok(a,b) SLcurses_nil()
++#define nl() SLcurses_nil()
++#define trace(x) SLcurses_nil()
++#define tigetstr(x) NULL
++
++/* These have no place in C */
++#define TRUE 1
++#define FALSE 0
++#define bool int
++
++/* Lynx compatability */
++#else
++
++#define stdscr NULL
++#define COLS SLtt_Screen_Cols
++#define LINES SLtt_Screen_Rows
++#define move SLsmg_gotorc
++#define addstr SLsmg_write_string
++#define clear SLsmg_cls
++#define standout SLsmg_reverse_video
++#define standend SLsmg_normal_video
++#define clrtoeol SLsmg_erase_eol
++#define scrollok(a,b) SLsmg_Newline_Moves = ((b) ? 1 : -1)
++#define addch SLsmg_write_char
++#define echo()
++#define printw SLsmg_printf
++#define endwin SLsmg_reset_smg(),SLang_reset_tty
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slcurses.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/sldisply.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/sldisply.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/sldisply.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,2596 @@
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++#include &quot;slinclud.h&quot;
++
++#include &lt;time.h&gt;
++#include &lt;ctype.h&gt;
++
++#if !defined(VMS) || (__VMS_VER &gt;= 70000000)
++# include &lt;sys/time.h&gt;
++# ifdef __QNX__
++# include &lt;sys/select.h&gt;
++# endif
++# include &lt;sys/types.h&gt;
++#endif
++
++#ifdef __BEOS__
++/* Prototype for select */
++# include &lt;net/socket.h&gt;
++#endif
++
++#ifdef HAVE_TERMIOS_H
++# include &lt;termios.h&gt;
++#endif
++
++#ifdef VMS
++# include &lt;unixlib.h&gt;
++# include &lt;unixio.h&gt;
++# include &lt;dvidef.h&gt;
++# include &lt;descrip.h&gt;
++# include &lt;lib$routines.h&gt;
++# include &lt;starlet.h&gt;
++#else
++# if !defined(sun)
++# include &lt;sys/ioctl.h&gt;
++# endif
++#endif
++
++#ifdef SYSV
++# include &lt;sys/termio.h&gt;
++# include &lt;sys/stream.h&gt;
++# include &lt;sys/ptem.h&gt;
++# include &lt;sys/tty.h&gt;
++#endif
++
++#if defined (_AIX) &amp;&amp; !defined (FD_SET)
++# include &lt;sys/select.h&gt; /* for FD_ISSET, FD_SET, FD_ZERO */
++#endif
++
++#include &lt;errno.h&gt;
++
++#if defined(__DECC) &amp;&amp; defined(VMS)
++/* These get prototypes for write an sleep */
++# include &lt;unixio.h&gt;
++#endif
++#include &lt;signal.h&gt;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++/* Colors: These definitions are used for the display. However, the
++ * application only uses object handles which get mapped to this
++ * internal representation. The mapping is performed by the Color_Map
++ * structure below. */
++
++#define CHAR_MASK 0x000000FF
++#define FG_MASK 0x0000FF00
++#define BG_MASK 0x00FF0000
++#define ATTR_MASK 0x1F000000
++#define BGALL_MASK 0x0FFF0000
++
++/* The 0x10000000 bit represents the alternate character set. BGALL_MASK does
++ * not include this attribute.
++ */
++
++#define GET_FG(color) ((color &amp; FG_MASK) &gt;&gt; 8)
++#define GET_BG(color) ((color &amp; BG_MASK) &gt;&gt; 16)
++#define MAKE_COLOR(fg, bg) (((fg) | ((bg) &lt;&lt; 8)) &lt;&lt; 8)
++
++int SLtt_Screen_Cols;
++int SLtt_Screen_Rows;
++int SLtt_Term_Cannot_Insert;
++int SLtt_Term_Cannot_Scroll;
++int SLtt_Use_Ansi_Colors;
++int SLtt_Blink_Mode = 1;
++int SLtt_Use_Blink_For_ACS = 0;
++int SLtt_Newline_Ok = 0;
++int SLtt_Has_Alt_Charset = 0;
++int SLtt_Force_Keypad_Init = 0;
++
++void (*_SLtt_color_changed_hook)(void);
++
++#if SLTT_HAS_NON_BCE_SUPPORT
++static int Bce_Color_Offset = 0;
++#endif
++static int Can_Background_Color_Erase = 1;
++
++/* -1 means unknown */
++int SLtt_Has_Status_Line = -1; /* hs */
++int SLang_TT_Write_FD = -1;
++
++static int Automatic_Margins;
++/* static int No_Move_In_Standout; */
++static int Worthless_Highlight;
++#define HP_GLITCH_CODE
++#ifdef HP_GLITCH_CODE
++/* This glitch is exclusive to HP term. Basically it means that to clear
++ * attributes, one has to erase to the end of the line.
++ */
++static int Has_HP_Glitch;
++#endif
++
++static char *Reset_Color_String;
++static int Is_Color_Terminal = 0;
++
++static int Linux_Console;
++
++/* It is crucial that JMAX_COLORS must be less than 128 since the high bit
++ * is used to indicate a character from the ACS (alt char set). The exception
++ * to this rule is if SLtt_Use_Blink_For_ACS is true. This means that of
++ * the highbit is set, we interpret that as a blink character. This is
++ * exploited by DOSemu.
++ */
++#define JMAX_COLORS 256
++#define JNORMAL_COLOR 0
++
++typedef struct
++{
++ SLtt_Char_Type fgbg;
++ SLtt_Char_Type mono;
++ char *custom_esc;
++}
++Ansi_Color_Type;
++
++#define RGB1(r, g, b) ((r) | ((g) &lt;&lt; 1) | ((b) &lt;&lt; 2))
++#define RGB(r, g, b, br, bg, bb) ((RGB1(r, g, b) &lt;&lt; 8) | (RGB1(br, bg, bb) &lt;&lt; 16))
++
++static Ansi_Color_Type Ansi_Color_Map[JMAX_COLORS] =
++{
++ {RGB(1, 1, 1, 0, 0, 0), 0x00000000, NULL}, /* white/black */
++ {RGB(0, 1, 0, 0, 0, 0), SLTT_REV_MASK, NULL}, /* green/black */
++ {RGB(1, 0, 1, 0, 0, 0), SLTT_REV_MASK, NULL}, /* magenta/black */
++ {RGB(0, 1, 1, 0, 0, 0), SLTT_REV_MASK, NULL}, /* cyan/black */
++ {RGB(1, 0, 0, 0, 0, 0), SLTT_REV_MASK, NULL},
++ {RGB(0, 1, 0, 0, 0, 1), SLTT_REV_MASK, NULL},
++ {RGB(1, 0, 0, 0, 0, 1), SLTT_REV_MASK, NULL},
++ {RGB(1, 0, 0, 0, 1, 0), SLTT_REV_MASK, NULL},
++ {RGB(0, 0, 1, 1, 0, 0), SLTT_REV_MASK, NULL},
++ {RGB(0, 1, 0, 1, 0, 0), SLTT_REV_MASK, NULL},
++ {RGB(0, 1, 1, 1, 1, 1), SLTT_REV_MASK, NULL},
++ {RGB(1, 1, 0, 1, 1, 1), SLTT_REV_MASK, NULL},
++ {RGB(1, 0, 1, 1, 1, 1), SLTT_REV_MASK, NULL},
++ {RGB(0, 0, 0, 0, 1, 1), SLTT_REV_MASK, NULL},
++ {RGB(0, 1, 0, 1, 1, 1), SLTT_REV_MASK, NULL},
++ {RGB(0, 1, 0, 1, 1, 1), SLTT_REV_MASK, NULL},
++ {RGB(0, 1, 0, 1, 1, 1), SLTT_REV_MASK, NULL},
++ {RGB(0, 1, 0, 1, 1, 1), SLTT_REV_MASK, NULL}
++};
++
++static char *Color_Fg_Str = &quot;\033[3%dm&quot;;
++static char *Color_Bg_Str = &quot;\033[4%dm&quot;;
++static char *Default_Color_Fg_Str = &quot;\033[39m&quot;;
++static char *Default_Color_Bg_Str = &quot;\033[49m&quot;;
++
++static int Max_Terminfo_Colors = 8; /* termcap Co */
++
++char *SLtt_Graphics_Char_Pairs; /* ac termcap string -- def is vt100 */
++
++/* 1 if terminal lacks the ability to go into insert mode or into delete
++ mode. Currently controlled by S-Lang but later perhaps termcap. */
++
++static char *UnderLine_Vid_Str;
++static char *Blink_Vid_Str;
++static char *Bold_Vid_Str;
++static char *Ins_Mode_Str; /* = &quot;\033[4h&quot;; */ /* ins mode (im) */
++static char *Eins_Mode_Str; /* = &quot;\033[4l&quot;; */ /* end ins mode (ei) */
++static char *Scroll_R_Str; /* = &quot;\033[%d;%dr&quot;; */ /* scroll region */
++static char *Cls_Str; /* = &quot;\033[2J\033[H&quot;; */ /* cl termcap STR for ansi terminals */
++static char *Rev_Vid_Str; /* = &quot;\033[7m&quot;; */ /* mr,so termcap string */
++static char *Norm_Vid_Str; /* = &quot;\033[m&quot;; */ /* me,se termcap string */
++static char *Del_Eol_Str; /* = &quot;\033[K&quot;; */ /* ce */
++static char *Del_Bol_Str; /* = &quot;\033[1K&quot;; */ /* cb */
++static char *Del_Char_Str; /* = &quot;\033[P&quot;; */ /* dc */
++static char *Del_N_Lines_Str; /* = &quot;\033[%dM&quot;; */ /* DL */
++static char *Add_N_Lines_Str; /* = &quot;\033[%dL&quot;; */ /* AL */
++static char *Rev_Scroll_Str;
++static char *Curs_Up_Str;
++static char *Curs_F_Str; /* RI termcap string */
++static char *Cursor_Visible_Str; /* ve termcap string */
++static char *Cursor_Invisible_Str; /* vi termcap string */
++#if 0
++static char *Start_Mouse_Rpt_Str; /* Start mouse reporting mode */
++static char *End_Mouse_Rpt_Str; /* End mouse reporting mode */
++#endif
++static char *Start_Alt_Chars_Str; /* as */
++static char *End_Alt_Chars_Str; /* ae */
++static char *Enable_Alt_Char_Set; /* eA */
++
++static char *Term_Init_Str;
++static char *Keypad_Init_Str;
++static char *Term_Reset_Str;
++static char *Keypad_Reset_Str;
++
++/* status line functions */
++static char *Disable_Status_line_Str; /* ds */
++static char *Return_From_Status_Line_Str; /* fs */
++static char *Goto_Status_Line_Str; /* ts */
++static int Num_Status_Line_Columns; /* ws */
++/* static int Status_Line_Esc_Ok; */ /* es */
++
++/* static int Len_Curs_F_Str = 5; */
++
++/* cm string has %i%d since termcap numbers columns from 0 */
++/* char *CURS_POS_STR = &quot;\033[%d;%df&quot;; ansi-- hor and vert pos */
++static char *Curs_Pos_Str; /* = &quot;\033[%i%d;%dH&quot;;*/ /* cm termcap string */
++
++/* scrolling region */
++static int Scroll_r1 = 0, Scroll_r2 = 23;
++static int Cursor_r, Cursor_c; /* 0 based */
++
++/* current attributes --- initialized to impossible value */
++static SLtt_Char_Type Current_Fgbg = 0xFFFFFFFFU;
++
++static int Cursor_Set; /* 1 if cursor position known, 0
++ * if not. -1 if only row is known
++ */
++
++#define MAX_OUTPUT_BUFFER_SIZE 4096
++
++static unsigned char Output_Buffer[MAX_OUTPUT_BUFFER_SIZE];
++static unsigned char *Output_Bufferp = Output_Buffer;
++
++unsigned long SLtt_Num_Chars_Output;
++
++int _SLusleep (unsigned long usecs)
++{
++#if !defined(VMS) || (__VMS_VER &gt;= 70000000)
++ struct timeval tv;
++ tv.tv_sec = usecs / 1000000;
++ tv.tv_usec = usecs % 1000000;
++ return select(0, NULL, NULL, NULL, &amp;tv);
++#else
++ return 0;
++#endif
++}
++
++int SLtt_flush_output (void)
++{
++ int nwrite = 0;
++ unsigned int total;
++ int n = (int) (Output_Bufferp - Output_Buffer);
++
++ SLtt_Num_Chars_Output += n;
++
++ total = 0;
++ while (n &gt; 0)
++ {
++ nwrite = write (SLang_TT_Write_FD, (char *) Output_Buffer + total, n);
++ if (nwrite == -1)
++ {
++ nwrite = 0;
++#ifdef EAGAIN
++ if (errno == EAGAIN)
++ {
++ _SLusleep (100000); /* 1/10 sec */
++ continue;
++ }
++#endif
++#ifdef EWOULDBLOCK
++ if (errno == EWOULDBLOCK)
++ {
++ _SLusleep (100000);
++ continue;
++ }
++#endif
++#ifdef EINTR
++ if (errno == EINTR) continue;
++#endif
++ break;
++ }
++ n -= nwrite;
++ total += nwrite;
++ }
++ Output_Bufferp = Output_Buffer;
++ return n;
++}
++
++int SLtt_Baud_Rate;
++static void tt_write(char *str, unsigned int n)
++{
++ static unsigned long last_time;
++ static int total;
++ unsigned long now;
++ unsigned int ndiff;
++
++ if ((str == NULL) || (n == 0)) return;
++ total += n;
++
++ while (1)
++ {
++ ndiff = MAX_OUTPUT_BUFFER_SIZE - (int) (Output_Bufferp - Output_Buffer);
++ if (ndiff &lt; n)
++ {
++ SLMEMCPY ((char *) Output_Bufferp, (char *) str, ndiff);
++ Output_Bufferp += ndiff;
++ SLtt_flush_output ();
++ n -= ndiff;
++ str += ndiff;
++ }
++ else
++ {
++ SLMEMCPY ((char *) Output_Bufferp, str, n);
++ Output_Bufferp += n;
++ break;
++ }
++ }
++
++ if (((SLtt_Baud_Rate &gt; 150) &amp;&amp; (SLtt_Baud_Rate &lt;= 9600))
++ &amp;&amp; (10 * total &gt; SLtt_Baud_Rate))
++ {
++ total = 0;
++ if ((now = (unsigned long) time(NULL)) - last_time &lt;= 1)
++ {
++ SLtt_flush_output ();
++ sleep((unsigned) 1);
++ }
++ last_time = now;
++ }
++}
++
++static void tt_write_string (char *str)
++{
++ if (str != NULL) tt_write(str, strlen(str));
++}
++
++void SLtt_write_string (char *str)
++{
++ tt_write_string (str);
++ Cursor_Set = 0;
++}
++
++void SLtt_putchar (char ch)
++{
++ SLtt_normal_video ();
++ if (Cursor_Set == 1)
++ {
++ if (ch &gt;= ' ') Cursor_c++;
++ else if (ch == '\b') Cursor_c--;
++ else if (ch == '\r') Cursor_c = 0;
++ else Cursor_Set = 0;
++
++ if ((Cursor_c + 1 == SLtt_Screen_Cols)
++ &amp;&amp; Automatic_Margins) Cursor_Set = 0;
++ }
++
++ if (Output_Bufferp &lt; Output_Buffer + MAX_OUTPUT_BUFFER_SIZE)
++ {
++ *Output_Bufferp++ = (unsigned char) ch;
++ }
++ else tt_write (&amp;ch, 1);
++}
++
++static unsigned int tt_sprintf(char *buf, char *fmt, int x, int y)
++{
++ char *fmt_max;
++ register unsigned char *b, ch;
++ int offset;
++ int z, z1, parse_level;
++ int zero_pad;
++ int field_width;
++ int variables [26];
++ int stack [64];
++ unsigned int stack_len;
++ int parms [10];
++#define STACK_POP (stack_len ? stack[--stack_len] : 0)
++
++ if (fmt == NULL)
++ {
++ *buf = 0;
++ return 0;
++ }
++
++ stack [0] = y; /* pushed for termcap */
++ stack [1] = x;
++ stack_len = 2;
++
++ parms [1] = x; /* p1 */
++ parms [2] = y; /* p2 */
++
++ offset = 0;
++ zero_pad = 0;
++ field_width = 0;
++
++ b = (unsigned char *) buf;
++ fmt_max = fmt + strlen (fmt);
++
++ while (fmt &lt; fmt_max)
++ {
++ ch = *fmt++;
++
++ if (ch != '%')
++ {
++ *b++ = ch;
++ continue;
++ }
++
++ if (fmt == fmt_max) break;
++ ch = *fmt++;
++
++ switch (ch)
++ {
++ default:
++ *b++ = ch;
++ break;
++
++ case 'p':
++
++ if (fmt == fmt_max) break;
++ ch = *fmt++;
++ if ((ch &gt;= '0') &amp;&amp; (ch &lt;= '9'))
++ stack [stack_len++] = parms [ch - '0'];
++ break;
++
++ case '\'': /* 'x' */
++ if (fmt == fmt_max) break;
++ stack [stack_len++] = *fmt++;
++ if (fmt &lt; fmt_max) fmt++; /* skip ' */
++ break;
++
++ case '{': /* literal constant, e.g. {30} */
++ z = 0;
++ while ((fmt &lt; fmt_max) &amp;&amp; ((ch = *fmt) &lt;= '9') &amp;&amp; (ch &gt;= '0'))
++ {
++ z = z * 10 + (ch - '0');
++ fmt++;
++ }
++ stack [stack_len++] = z;
++ if ((ch == '}') &amp;&amp; (fmt &lt; fmt_max)) fmt++;
++ break;
++
++ case '0':
++ if (fmt == fmt_max) break;
++ ch = *fmt;
++ if ((ch != '2') &amp;&amp; (ch != '3'))
++ break;
++ zero_pad = 1;
++ fmt++;
++ /* drop */
++
++ case '2':
++ case '3':
++ if (fmt == fmt_max)
++ if (*fmt == 'x')
++ {
++ char x_fmt_buf [4];
++ char *x_fmt_buf_ptr;
++
++ x_fmt_buf_ptr = x_fmt_buf;
++ if (zero_pad) *x_fmt_buf_ptr++ = '0';
++ *x_fmt_buf_ptr++ = ch;
++ *x_fmt_buf_ptr++ = 'X';
++ *x_fmt_buf_ptr = 0;
++
++ z = STACK_POP;
++ z += offset;
++
++ sprintf ((char *)b, x_fmt_buf, z);
++ b += strlen ((char *)b);
++ zero_pad = 0;
++ break;
++ }
++
++ field_width = (ch - '0');
++ /* drop */
++
++ case 'd':
++ z = STACK_POP;
++ z += offset;
++ if (z &gt;= 100)
++ {
++ *b++ = z / 100 + '0';
++ z = z % 100;
++ zero_pad = 1;
++ field_width = 2;
++ }
++ else if (zero_pad &amp;&amp; (field_width == 3))
++ *b++ = '0';
++
++ if (z &gt;= 10)
++ {
++ *b++ = z / 10 + '0';
++ z = z % 10;
++ }
++ else if (zero_pad &amp;&amp; (field_width &gt;= 2))
++ *b++ = '0';
++
++ *b++ = z + '0';
++ field_width = zero_pad = 0;
++ break;
++
++ case 'x':
++ z = STACK_POP;
++ z += offset;
++ sprintf ((char *) b, &quot;%X&quot;, z);
++ b += strlen ((char *)b);
++ break;
++
++ case 'i':
++ offset = 1;
++ break;
++
++ case '+':
++ /* Handling this depends upon whether or not we are parsing
++ * terminfo. Terminfo requires the stack so use it as an
++ * indicator.
++ */
++ if (stack_len &gt; 2)
++ {
++ z = STACK_POP;
++ stack [stack_len - 1] += z;
++ }
++ else if (fmt &lt; fmt_max)
++ {
++ ch = *fmt++;
++ if ((unsigned char) ch == 128) ch = 0;
++ ch = ch + (unsigned char) STACK_POP;
++ if (ch == '\n') ch++;
++ *b++ = ch;
++ }
++ break;
++
++ /* Binary operators */
++ case '-':
++ case '*':
++ case '/':
++ case 'm':
++ case '&amp;':
++ case '|':
++ case '^':
++ case '=':
++ case '&gt;':
++ case '&lt;':
++ case 'A':
++ case 'O':
++ z1 = STACK_POP;
++ z = STACK_POP;
++ switch (ch)
++ {
++ case '-': z = (z - z1); break;
++ case '*': z = (z * z1); break;
++ case '/': z = (z / z1); break;
++ case 'm': z = (z % z1); break;
++ case '&amp;': z = (z &amp; z1); break;
++ case '|': z = (z | z1); break;
++ case '^': z = (z ^ z1); break;
++ case '=': z = (z == z1); break;
++ case '&gt;': z = (z &gt; z1); break;
++ case '&lt;': z = (z &lt; z1); break;
++ case 'A': z = (z &amp;&amp; z1); break;
++ case 'O': z = (z || z1); break;
++ }
++ stack [stack_len++] = z;
++ break;
++
++ /* unary */
++ case '!':
++ z = STACK_POP;
++ stack [stack_len++] = !z;
++ break;
++
++ case '~':
++ z = STACK_POP;
++ stack [stack_len++] = ~z;
++ break;
++
++ case 'r': /* termcap -- swap parameters */
++ z = stack [0];
++ stack [0] = stack [1];
++ stack [1] = z;
++ break;
++
++ case '.': /* termcap */
++ case 'c':
++ ch = (unsigned char) STACK_POP;
++ if (ch == '\n') ch++;
++ *b++ = ch;
++ break;
++
++ case 'g':
++ if (fmt == fmt_max) break;
++ ch = *fmt++;
++ if ((ch &gt;= 'a') &amp;&amp; (ch &lt;= 'z'))
++ stack [stack_len++] = variables [ch - 'a'];
++ break;
++
++ case 'P':
++ if (fmt == fmt_max) break;
++ ch = *fmt++;
++ if ((ch &gt;= 'a') &amp;&amp; (ch &lt;= 'z'))
++ variables [ch - 'a'] = STACK_POP;
++ break;
++
++ /* If then else parsing. Actually, this is rather easy. The
++ * key is to notice that 'then' does all the work. 'if' simply
++ * there to indicate the start of a test and endif indicates
++ * the end of tests. If 'else' is seen, then skip to
++ * endif.
++ */
++ case '?': /* if */
++ case ';': /* endif */
++ break;
++
++ case 't': /* then */
++ z = STACK_POP;
++ if (z != 0)
++ break; /* good. Continue parsing. */
++
++ /* z == 0 and test has failed. So, skip past this entire if
++ * expression to the matching else or matching endif.
++ */
++ /* drop */
++ case 'e': /* else */
++
++ parse_level = 0;
++ while (fmt &lt; fmt_max)
++ {
++ unsigned char ch1;
++
++ ch1 = *fmt++;
++ if ((ch1 != '%') || (fmt == fmt_max))
++ continue;
++
++ ch1 = *fmt++;
++
++ if (ch1 == '?') parse_level++; /* new if */
++ else if (ch1 == 'e')
++ {
++ if ((ch != 'e') &amp;&amp; (parse_level == 0))
++ break;
++ }
++ else if (ch1 == ';')
++ {
++ if (parse_level == 0)
++ break;
++ parse_level--;
++ }
++ }
++ break;
++ }
++ }
++ *b = 0;
++ return (unsigned int) (b - (unsigned char *) buf);
++}
++
++static void tt_printf(char *fmt, int x, int y)
++{
++ char buf[1024];
++ unsigned int n;
++ if (fmt == NULL) return;
++ n = tt_sprintf(buf, fmt, x, y);
++ tt_write(buf, n);
++}
++
++void SLtt_set_scroll_region (int r1, int r2)
++{
++ Scroll_r1 = r1;
++ Scroll_r2 = r2;
++ tt_printf (Scroll_R_Str, Scroll_r1, Scroll_r2);
++ Cursor_Set = 0;
++}
++
++void SLtt_reset_scroll_region (void)
++{
++ SLtt_set_scroll_region(0, SLtt_Screen_Rows - 1);
++}
++
++int SLtt_set_cursor_visibility (int show)
++{
++ if ((Cursor_Visible_Str == NULL) || (Cursor_Invisible_Str == NULL))
++ return -1;
++
++ tt_write_string (show ? Cursor_Visible_Str : Cursor_Invisible_Str);
++ return 0;
++}
++
++/* the goto_rc function moves to row relative to scrolling region */
++void SLtt_goto_rc(int r, int c)
++{
++ char *s = NULL;
++ int n;
++ char buf[6];
++
++ if ((c &lt; 0) || (r &lt; 0))
++ {
++ Cursor_Set = 0;
++ return;
++ }
++
++ /* if (No_Move_In_Standout &amp;&amp; Current_Fgbg) SLtt_normal_video (); */
++ r += Scroll_r1;
++
++ if ((Cursor_Set &gt; 0) || ((Cursor_Set &lt; 0) &amp;&amp; !Automatic_Margins))
++ {
++ n = r - Cursor_r;
++ if ((n == -1) &amp;&amp; (Cursor_Set &gt; 0) &amp;&amp; (Cursor_c == c)
++ &amp;&amp; (Curs_Up_Str != NULL))
++ {
++ s = Curs_Up_Str;
++ }
++ else if ((n &gt;= 0) &amp;&amp; (n &lt;= 4))
++ {
++ if ((n == 0) &amp;&amp; (Cursor_Set == 1)
++ &amp;&amp; ((c &gt; 1) || (c == Cursor_c)))
++ {
++ if (Cursor_c == c) return;
++ if (Cursor_c == c + 1)
++ {
++ s = buf;
++ *s++ = '\b'; *s = 0;
++ s = buf;
++ }
++ }
++ else if (c == 0)
++ {
++ s = buf;
++ if ((Cursor_Set != 1) || (Cursor_c != 0)) *s++ = '\r';
++ while (n--) *s++ = '\n';
++#ifdef VMS
++ /* Need to add this after \n to start a new record. Sheesh. */
++ *s++ = '\r';
++#endif
++ *s = 0;
++ s = buf;
++ }
++ /* Will fail on VMS */
++#ifndef VMS
++ else if (SLtt_Newline_Ok &amp;&amp; (Cursor_Set == 1) &amp;&amp;
++ (Cursor_c &gt;= c) &amp;&amp; (c + 3 &gt; Cursor_c))
++ {
++ s = buf;
++ while (n--) *s++ = '\n';
++ n = Cursor_c - c;
++ while (n--) *s++ = '\b';
++ *s = 0;
++ s = buf;
++ }
++#endif
++ }
++ }
++ if (s != NULL) tt_write_string(s);
++ else tt_printf(Curs_Pos_Str, r, c);
++ Cursor_c = c; Cursor_r = r;
++ Cursor_Set = 1;
++}
++
++void SLtt_begin_insert (void)
++{
++ tt_write_string(Ins_Mode_Str);
++}
++
++void SLtt_end_insert (void)
++{
++ tt_write_string(Eins_Mode_Str);
++}
++
++void SLtt_delete_char (void)
++{
++ SLtt_normal_video ();
++ tt_write_string(Del_Char_Str);
++}
++
++void SLtt_erase_line (void)
++{
++ tt_write_string(&quot;\r&quot;);
++ Cursor_Set = 1; Cursor_c = 0;
++ SLtt_del_eol();
++}
++
++/* It appears that the Linux console, and most likely others do not
++ * like scrolling regions that consist of one line. So I have to
++ * resort to this stupidity to make up for that stupidity.
++ */
++static void delete_line_in_scroll_region (void)
++{
++ SLtt_goto_rc (Cursor_r - Scroll_r1, 0);
++ SLtt_del_eol ();
++}
++
++void SLtt_delete_nlines (int n)
++{
++ int r1, curs;
++ char buf[132];
++
++ if (n &lt;= 0) return;
++ SLtt_normal_video ();
++
++ if (Scroll_r1 == Scroll_r2)
++ {
++ delete_line_in_scroll_region ();
++ return;
++ }
++
++ if (Del_N_Lines_Str != NULL) tt_printf(Del_N_Lines_Str,n, 0);
++ else
++ /* get a new terminal */
++ {
++ r1 = Scroll_r1;
++ curs = Cursor_r;
++ SLtt_set_scroll_region(curs, Scroll_r2);
++ SLtt_goto_rc(Scroll_r2 - Scroll_r1, 0);
++ SLMEMSET(buf, '\n', (unsigned int) n);
++ tt_write(buf, (unsigned int) n);
++ /* while (n--) tt_putchar('\n'); */
++ SLtt_set_scroll_region(r1, Scroll_r2);
++ SLtt_goto_rc(curs, 0);
++ }
++}
++
++void SLtt_cls (void)
++{
++ /* If the terminal is a color terminal but the user wants black and
++ * white, then make sure that the colors are reset. This appears to be
++ * necessary.
++ */
++ if ((SLtt_Use_Ansi_Colors == 0) &amp;&amp; Is_Color_Terminal)
++ {
++ if (Reset_Color_String != NULL)
++ tt_write_string (Reset_Color_String);
++ else
++ tt_write_string (&quot;\033[0m\033[m&quot;);
++ }
++
++ SLtt_normal_video();
++ SLtt_reset_scroll_region ();
++ tt_write_string(Cls_Str);
++}
++
++void SLtt_reverse_index (int n)
++{
++ if (!n) return;
++
++ SLtt_normal_video();
++
++ if (Scroll_r1 == Scroll_r2)
++ {
++ delete_line_in_scroll_region ();
++ return;
++ }
++
++ if (Add_N_Lines_Str != NULL) tt_printf(Add_N_Lines_Str,n, 0);
++ else
++ {
++ while(n--) tt_write_string(Rev_Scroll_Str);
++ }
++}
++
++int SLtt_Ignore_Beep = 1;
++static char *Visible_Bell_Str;
++
++void SLtt_beep (void)
++{
++ if (SLtt_Ignore_Beep &amp; 0x1) SLtt_putchar('\007');
++
++ if (SLtt_Ignore_Beep &amp; 0x2)
++ {
++ if (Visible_Bell_Str != NULL) tt_write_string (Visible_Bell_Str);
++#ifdef __linux__
++ else if (Linux_Console)
++ {
++ tt_write_string (&quot;\033[?5h&quot;);
++ SLtt_flush_output ();
++ _SLusleep (50000);
++ tt_write_string (&quot;\033[?5l&quot;);
++ }
++#endif
++ }
++ SLtt_flush_output ();
++}
++
++static void del_eol (void)
++{
++ int c;
++
++ if (Del_Eol_Str != NULL)
++ {
++ tt_write_string(Del_Eol_Str);
++ return;
++ }
++
++ c = Cursor_c;
++ /* Avoid writing to the lower right corner. If the terminal does not
++ * have Del_Eol_Str, then it probably does not have what it takes to play
++ * games with insert for for a space into that corner.
++ */
++ if (Cursor_r + 1 &lt; SLtt_Screen_Rows)
++ c++;
++
++ while (c &lt; SLtt_Screen_Cols)
++ {
++ tt_write (&quot; &quot;, 1);
++ c++;
++ }
++}
++
++void SLtt_del_eol (void)
++{
++ if (Current_Fgbg != 0xFFFFFFFFU) SLtt_normal_video ();
++ del_eol ();
++}
++
++typedef struct
++{
++ char *name;
++ SLtt_Char_Type color;
++}
++Color_Def_Type;
++
++#define MAX_COLOR_NAMES 17
++static Color_Def_Type Color_Defs [MAX_COLOR_NAMES] =
++{
++ {&quot;black&quot;, SLSMG_COLOR_BLACK},
++ {&quot;red&quot;, SLSMG_COLOR_RED},
++ {&quot;green&quot;, SLSMG_COLOR_GREEN},
++ {&quot;brown&quot;, SLSMG_COLOR_BROWN},
++ {&quot;blue&quot;, SLSMG_COLOR_BLUE},
++ {&quot;magenta&quot;, SLSMG_COLOR_MAGENTA},
++ {&quot;cyan&quot;, SLSMG_COLOR_CYAN},
++ {&quot;lightgray&quot;, SLSMG_COLOR_LGRAY},
++ {&quot;gray&quot;, SLSMG_COLOR_GRAY},
++ {&quot;brightred&quot;, SLSMG_COLOR_BRIGHT_RED},
++ {&quot;brightgreen&quot;, SLSMG_COLOR_BRIGHT_GREEN},
++ {&quot;yellow&quot;, SLSMG_COLOR_BRIGHT_BROWN},
++ {&quot;brightblue&quot;, SLSMG_COLOR_BRIGHT_BLUE},
++ {&quot;brightmagenta&quot;, SLSMG_COLOR_BRIGHT_CYAN},
++ {&quot;brightcyan&quot;, SLSMG_COLOR_BRIGHT_MAGENTA},
++ {&quot;white&quot;, SLSMG_COLOR_BRIGHT_WHITE},
++#define SLSMG_COLOR_DEFAULT 0xFF
++ {&quot;default&quot;, SLSMG_COLOR_DEFAULT}
++};
++
++void SLtt_set_mono (int obj, char *what, SLtt_Char_Type mask)
++{
++ (void) what;
++ if ((obj &lt; 0) || (obj &gt;= JMAX_COLORS))
++ {
++ return;
++ }
++ Ansi_Color_Map[obj].mono = mask &amp; ATTR_MASK;
++}
++
++static char *check_color_for_digit_form (char *color)
++{
++ unsigned int i, ich;
++ char *s = color;
++
++ i = 0;
++ while ((ich = (int) *s) != 0)
++ {
++ if ((ich &lt; '0') || (ich &gt; '9'))
++ return color;
++
++ i = i * 10 + (ich - '0');
++ s++;
++ }
++
++ if (i &lt; MAX_COLOR_NAMES)
++ color = Color_Defs[i].name;
++
++ return color;
++}
++
++static int get_default_colors (char **fgp, char **bgp)
++{
++ static char fg_buf[16], bg_buf[16], *bg, *fg;
++ static int already_parsed;
++ char *p, *pmax;
++
++ if (already_parsed == -1)
++ return -1;
++
++ if (already_parsed)
++ {
++ *fgp = fg;
++ *bgp = bg;
++ return 0;
++ }
++
++ already_parsed = -1;
++
++ bg = getenv (&quot;COLORFGBG&quot;);
++
++ if (bg == NULL)
++ {
++ bg = getenv (&quot;DEFAULT_COLORS&quot;);
++ if (bg == NULL)
++ return -1;
++ }
++
++ p = fg_buf;
++ pmax = p + (sizeof (fg_buf) - 1);
++
++ while ((*bg != 0) &amp;&amp; (*bg != ';'))
++ {
++ if (p &lt; pmax) *p++ = *bg;
++ bg++;
++ }
++ *p = 0;
++
++ if (*bg) bg++;
++
++ p = bg_buf;
++ pmax = p + (sizeof (bg_buf) - 1);
++
++ /* Mark suggested allowing for extra spplication specific stuff following
++ * the background color. That is what the check for the semi-colon is for.
++ */
++ while ((*bg != 0) &amp;&amp; (*bg != ';'))
++ {
++ if (p &lt; pmax) *p++ = *bg;
++ bg++;
++ }
++ *p = 0;
++
++ if (!strcmp (fg_buf, &quot;default&quot;) || !strcmp(bg_buf, &quot;default&quot;))
++ {
++ *fgp = *bgp = fg = bg = &quot;default&quot;;
++ }
++ else
++ {
++ *fgp = fg = check_color_for_digit_form (fg_buf);
++ *bgp = bg = check_color_for_digit_form (bg_buf);
++ }
++ already_parsed = 1;
++ return 0;
++}
++
++static unsigned char FgBg_Stats[JMAX_COLORS];
++
++static int Color_0_Modified = 0;
++
++void SLtt_set_color_object (int obj, SLtt_Char_Type attr)
++{
++ char *cust_esc;
++
++ if ((obj &lt; 0) || (obj &gt;= JMAX_COLORS)) return;
++
++ cust_esc = Ansi_Color_Map[obj].custom_esc;
++ if (cust_esc != NULL)
++ {
++ SLfree (cust_esc);
++ FgBg_Stats[(Ansi_Color_Map[obj].fgbg &gt;&gt; 8) &amp; 0x7F] -= 1;
++ Ansi_Color_Map[obj].custom_esc = NULL;
++ }
++
++ Ansi_Color_Map[obj].fgbg = attr;
++ if (obj == 0) Color_0_Modified = 1;
++
++ if (_SLtt_color_changed_hook != NULL)
++ (*_SLtt_color_changed_hook)();
++}
++
++SLtt_Char_Type SLtt_get_color_object (int obj)
++{
++ if ((obj &lt; 0) || (obj &gt;= JMAX_COLORS)) return 0;
++ return Ansi_Color_Map[obj].fgbg;
++}
++
++void SLtt_add_color_attribute (int obj, SLtt_Char_Type attr)
++{
++ if ((obj &lt; 0) || (obj &gt;= JMAX_COLORS)) return;
++
++ Ansi_Color_Map[obj].fgbg |= (attr &amp; ATTR_MASK);
++ if (obj == 0) Color_0_Modified = 1;
++ if (_SLtt_color_changed_hook != NULL)
++ (*_SLtt_color_changed_hook)();
++}
++
++static SLtt_Char_Type fb_to_fgbg (SLtt_Char_Type f, SLtt_Char_Type b)
++{
++ SLtt_Char_Type attr;
++
++ if (Max_Terminfo_Colors != 8)
++ {
++ if (f != SLSMG_COLOR_DEFAULT) f %= Max_Terminfo_Colors;
++ if (b != SLSMG_COLOR_DEFAULT) b %= Max_Terminfo_Colors;
++ return ((f &lt;&lt; 8) | (b &lt;&lt; 16));
++ }
++
++ /* Otherwise we have 8 ansi colors. Try to get bright versions
++ * by using the BOLD and BLINK attributes.
++ */
++
++ attr = 0;
++
++ /* Note: If f represents default, it will have the value 0xFF */
++ if (f != SLSMG_COLOR_DEFAULT)
++ {
++ if (f &amp; 0x8) attr = SLTT_BOLD_MASK;
++ f &amp;= 0x7;
++ }
++
++ if (b != SLSMG_COLOR_DEFAULT)
++ {
++ if (b &amp; 0x8) attr |= SLTT_BLINK_MASK;
++ b &amp;= 0x7;
++ }
++
++ return ((f &lt;&lt; 8) | (b &lt;&lt; 16) | attr);
++}
++
++/* This looks for colors with name form 'colorN'. If color is of this
++ * form, N is passed back via paramter list.
++ */
++static int parse_color_digit_name (char *color, SLtt_Char_Type *f)
++{
++ unsigned int i;
++ unsigned char ch;
++
++ if (strncmp (color, &quot;color&quot;, 5))
++ return -1;
++
++ color += 5;
++ if (*color == 0)
++ return -1;
++
++ i = 0;
++ while (1)
++ {
++ ch = (unsigned char) *color++;
++ if (ch == 0)
++ break;
++ if ((ch &gt; '9') || (ch &lt; '0'))
++ return -1;
++ i = 10 * i + (ch - '0');
++ }
++
++ *f = (SLtt_Char_Type) i;
++ return 0;
++}
++
++static int make_color_fgbg (char *fg, char *bg, SLtt_Char_Type *fgbg)
++{
++ SLtt_Char_Type f = 0xFFFFFFFFU, b = 0xFFFFFFFFU;
++ char *dfg, *dbg;
++ unsigned int i;
++
++ if ((fg != NULL) &amp;&amp; (*fg == 0)) fg = NULL;
++ if ((bg != NULL) &amp;&amp; (*bg == 0)) bg = NULL;
++
++ if ((fg == NULL) || (bg == NULL))
++ {
++ if (-1 == get_default_colors (&amp;dfg, &amp;dbg))
++ return -1;
++
++ if (fg == NULL) fg = dfg;
++ if (bg == NULL) bg = dbg;
++ }
++
++ if (-1 == parse_color_digit_name (fg, &amp;f))
++ {
++ for (i = 0; i &lt; MAX_COLOR_NAMES; i++)
++ {
++ if (strcmp(fg, Color_Defs[i].name)) continue;
++ f = Color_Defs[i].color;
++ break;
++ }
++ }
++
++ if (-1 == parse_color_digit_name (bg, &amp;b))
++ {
++ for (i = 0; i &lt; MAX_COLOR_NAMES; i++)
++ {
++ if (strcmp(bg, Color_Defs[i].name)) continue;
++ b = Color_Defs[i].color;
++ break;
++ }
++ }
++
++ if ((f == 0xFFFFFFFFU) || (b == 0xFFFFFFFFU))
++ return -1;
++
++ *fgbg = fb_to_fgbg (f, b);
++ return 0;
++}
++
++void SLtt_set_color (int obj, char *what, char *fg, char *bg)
++{
++ SLtt_Char_Type fgbg;
++
++ (void) what;
++ if ((obj &lt; 0) || (obj &gt;= JMAX_COLORS))
++ return;
++
++ if (-1 != make_color_fgbg (fg, bg, &amp;fgbg))
++ SLtt_set_color_object (obj, fgbg);
++}
++
++void SLtt_set_color_fgbg (int obj, SLtt_Char_Type f, SLtt_Char_Type b)
++{
++ SLtt_set_color_object (obj, fb_to_fgbg (f, b));
++}
++
++void SLtt_set_color_esc (int obj, char *esc)
++{
++ char *cust_esc;
++ SLtt_Char_Type fgbg = 0;
++ int i;
++
++ if ((obj &lt; 0) || (obj &gt;= JMAX_COLORS))
++ {
++ return;
++ }
++
++ cust_esc = Ansi_Color_Map[obj].custom_esc;
++ if (cust_esc != NULL)
++ {
++ SLfree (cust_esc);
++ FgBg_Stats[(Ansi_Color_Map[obj].fgbg &gt;&gt; 8) &amp; 0x7F] -= 1;
++ }
++
++ cust_esc = (char *) SLmalloc (strlen(esc) + 1);
++ if (cust_esc != NULL) strcpy (cust_esc, esc);
++
++ Ansi_Color_Map[obj].custom_esc = cust_esc;
++ if (cust_esc == NULL) fgbg = 0;
++ else
++ {
++ /* The whole point of this is to generate a unique fgbg */
++ for (i = 0; i &lt; JMAX_COLORS; i++)
++ {
++ if (FgBg_Stats[i] == 0) fgbg = i;
++
++ if (obj == i) continue;
++ if ((Ansi_Color_Map[i].custom_esc) == NULL) continue;
++ if (!strcmp (Ansi_Color_Map[i].custom_esc, cust_esc))
++ {
++ fgbg = (Ansi_Color_Map[i].fgbg &gt;&gt; 8) &amp; 0x7F;
++ break;
++ }
++ }
++ FgBg_Stats[fgbg] += 1;
++ }
++
++ fgbg |= 0x80;
++ Ansi_Color_Map[obj].fgbg = (fgbg | (fgbg &lt;&lt; 8)) &lt;&lt; 8;
++ if (obj == 0) Color_0_Modified = 1;
++ if (_SLtt_color_changed_hook != NULL)
++ (*_SLtt_color_changed_hook)();
++}
++
++void SLtt_set_alt_char_set (int i)
++{
++ static int last_i;
++ if (SLtt_Has_Alt_Charset == 0) return;
++ if (i == last_i) return;
++ tt_write_string (i ? Start_Alt_Chars_Str : End_Alt_Chars_Str );
++ last_i = i;
++}
++
++static void write_attributes (SLtt_Char_Type fgbg)
++{
++ int bg0, fg0;
++ int unknown_attributes;
++
++ if (Worthless_Highlight) return;
++ if (fgbg == Current_Fgbg) return;
++
++ unknown_attributes = 0;
++
++ /* Before spitting out colors, fix attributes */
++ if ((fgbg &amp; ATTR_MASK) != (Current_Fgbg &amp; ATTR_MASK))
++ {
++ if (Current_Fgbg &amp; ATTR_MASK)
++ {
++ tt_write_string(Norm_Vid_Str);
++ /* In case normal video turns off ALL attributes: */
++ if (fgbg &amp; SLTT_ALTC_MASK)
++ Current_Fgbg &amp;= ~SLTT_ALTC_MASK;
++ SLtt_set_alt_char_set (0);
++ }
++
++ if ((fgbg &amp; SLTT_ALTC_MASK)
++ != (Current_Fgbg &amp; SLTT_ALTC_MASK))
++ {
++ SLtt_set_alt_char_set ((int) (fgbg &amp; SLTT_ALTC_MASK));
++ }
++
++ if (fgbg &amp; SLTT_ULINE_MASK) tt_write_string (UnderLine_Vid_Str);
++ if (fgbg &amp; SLTT_BOLD_MASK) SLtt_bold_video ();
++ if (fgbg &amp; SLTT_REV_MASK) tt_write_string (Rev_Vid_Str);
++ if (fgbg &amp; SLTT_BLINK_MASK)
++ {
++ /* Someday Linux will have a blink mode that set high intensity
++ * background. Lets be prepared.
++ */
++ if (SLtt_Blink_Mode) tt_write_string (Blink_Vid_Str);
++ }
++ unknown_attributes = 1;
++ }
++
++ if (SLtt_Use_Ansi_Colors)
++ {
++ fg0 = (int) GET_FG(fgbg);
++ bg0 = (int) GET_BG(fgbg);
++
++ if (unknown_attributes
++ || (fg0 != (int)GET_FG(Current_Fgbg)))
++ {
++ if (fg0 == SLSMG_COLOR_DEFAULT)
++ tt_write_string (Default_Color_Fg_Str);
++ else
++ tt_printf (Color_Fg_Str, fg0, 0);
++ }
++
++ if (unknown_attributes
++ || (bg0 != (int)GET_BG(Current_Fgbg)))
++ {
++ if (bg0 == SLSMG_COLOR_DEFAULT)
++ tt_write_string (Default_Color_Bg_Str);
++ else
++ tt_printf (Color_Bg_Str, bg0, 0);
++ }
++ }
++
++ Current_Fgbg = fgbg;
++}
++
++static int Video_Initialized;
++
++void SLtt_reverse_video (int color)
++{
++ SLtt_Char_Type fgbg;
++ char *esc;
++
++ if (Worthless_Highlight) return;
++ if ((color &lt; 0) || (color &gt;= JMAX_COLORS)) return;
++
++ if (Video_Initialized == 0)
++ {
++ if (color == JNORMAL_COLOR)
++ {
++ tt_write_string (Norm_Vid_Str);
++ }
++ else tt_write_string (Rev_Vid_Str);
++ Current_Fgbg = 0xFFFFFFFFU;
++ return;
++ }
++
++ if (SLtt_Use_Ansi_Colors)
++ {
++ fgbg = Ansi_Color_Map[color].fgbg;
++ if ((esc = Ansi_Color_Map[color].custom_esc) != NULL)
++ {
++ if (fgbg != Current_Fgbg)
++ {
++ Current_Fgbg = fgbg;
++ tt_write_string (esc);
++ return;
++ }
++ }
++ }
++ else fgbg = Ansi_Color_Map[color].mono;
++
++ if (fgbg == Current_Fgbg) return;
++ write_attributes (fgbg);
++}
++
++void SLtt_normal_video (void)
++{
++ SLtt_reverse_video(JNORMAL_COLOR);
++}
++
++void SLtt_narrow_width (void)
++{
++ tt_write_string(&quot;\033[?3l&quot;);
++}
++
++void SLtt_wide_width (void)
++{
++ tt_write_string(&quot;\033[?3h&quot;);
++}
++
++/* Highest bit represents the character set. */
++#define COLOR_MASK 0x7F00
++
++#if SLTT_HAS_NON_BCE_SUPPORT
++static int bce_color_eqs (unsigned int a, unsigned int b)
++{
++ a = (a &amp; COLOR_MASK) &gt;&gt; 8;
++ b = (b &amp; COLOR_MASK) &gt;&gt; 8;
++
++ if (a == b)
++ return 1;
++
++ if (SLtt_Use_Ansi_Colors == 0)
++ return Ansi_Color_Map[a].mono == Ansi_Color_Map[b].mono;
++
++ if (Bce_Color_Offset == 0)
++ return Ansi_Color_Map[a].fgbg == Ansi_Color_Map[b].fgbg;
++
++ /* If either are color 0, then we do not know what that means since the
++ * terminal does not support BCE */
++ if ((a == 0) || (b == 0))
++ return 0;
++
++ return Ansi_Color_Map[a-1].fgbg == Ansi_Color_Map[b-1].fgbg;
++}
++#define COLOR_EQS(a,b) bce_color_eqs (a,b)
++#else
++# define COLOR_OF(x) (((unsigned int)(x) &amp; COLOR_MASK) &gt;&gt; 8)
++# define COLOR_EQS(a, b) \
++ (SLtt_Use_Ansi_Colors \
++ ? (Ansi_Color_Map[COLOR_OF(a)].fgbg == Ansi_Color_Map[COLOR_OF(b)].fgbg)\
++ : (Ansi_Color_Map[COLOR_OF(a)].mono == Ansi_Color_Map[COLOR_OF(b)].mono))
++#endif
++
++#define CHAR_EQS(a, b) (((a) == (b))\
++ || ((((a) &amp; ~COLOR_MASK) == ((b) &amp; ~COLOR_MASK))\
++ &amp;&amp; COLOR_EQS((a), (b))))
++
++/* The whole point of this routine is to prevent writing to the last column
++ * and last row on terminals with automatic margins.
++ */
++static void write_string_with_care (char *str)
++{
++ unsigned int len;
++
++ if (str == NULL) return;
++
++ len = strlen (str);
++ if (Automatic_Margins &amp;&amp; (Cursor_r + 1 == SLtt_Screen_Rows))
++ {
++ if (len + (unsigned int) Cursor_c &gt;= (unsigned int) SLtt_Screen_Cols)
++ {
++ /* For now, just do not write there. Later, something more
++ * sophisticated will be implemented.
++ */
++ if (SLtt_Screen_Cols &gt; Cursor_c)
++ len = SLtt_Screen_Cols - Cursor_c - 1;
++ else
++ len = 0;
++ }
++ }
++ tt_write (str, len);
++}
++
++static void send_attr_str (SLsmg_Char_Type *s)
++{
++ unsigned char out[256], ch, *p;
++ register SLtt_Char_Type attr;
++ register SLsmg_Char_Type sh;
++ int color, last_color = -1;
++
++ p = out;
++ while (0 != (sh = *s++))
++ {
++ ch = sh &amp; 0xFF;
++ color = ((int) sh &amp; 0xFF00) &gt;&gt; 8;
++
++#if SLTT_HAS_NON_BCE_SUPPORT
++ if (Bce_Color_Offset
++ &amp;&amp; (color &gt;= Bce_Color_Offset))
++ color -= Bce_Color_Offset;
++#endif
++
++ if (color != last_color)
++ {
++ if (SLtt_Use_Ansi_Colors) attr = Ansi_Color_Map[color &amp; 0x7F].fgbg;
++ else attr = Ansi_Color_Map[color &amp; 0x7F].mono;
++
++ if (sh &amp; 0x8000) /* alternate char set */
++ {
++ if (SLtt_Use_Blink_For_ACS)
++ {
++ if (SLtt_Blink_Mode) attr |= SLTT_BLINK_MASK;
++ }
++ else attr |= SLTT_ALTC_MASK;
++ }
++
++ if (attr != Current_Fgbg)
++ {
++ if ((ch != ' ') ||
++ /* it is a space so only consider it different if it
++ * has different attributes.
++ */
++ (attr &amp; BGALL_MASK) != (Current_Fgbg &amp; BGALL_MASK))
++ {
++ if (p != out)
++ {
++ *p = 0;
++ write_string_with_care ((char *) out);
++ Cursor_c += (int) (p - out);
++ p = out;
++ }
++
++ if (SLtt_Use_Ansi_Colors &amp;&amp; (NULL != Ansi_Color_Map[color &amp; 0x7F].custom_esc))
++ {
++ tt_write_string (Ansi_Color_Map[color &amp; 0x7F].custom_esc);
++ /* Just in case the custom escape sequence screwed up
++ * the alt character set state...
++ */
++ if ((attr &amp; SLTT_ALTC_MASK) != (Current_Fgbg &amp; SLTT_ALTC_MASK))
++ SLtt_set_alt_char_set ((int) (attr &amp; SLTT_ALTC_MASK));
++ Current_Fgbg = attr;
++ }
++ else write_attributes (attr);
++
++ last_color = color;
++ }
++ }
++ }
++ *p++ = ch;
++ }
++ *p = 0;
++ if (p != out) write_string_with_care ((char *) out);
++ Cursor_c += (int) (p - out);
++}
++
++static void forward_cursor (unsigned int n, int row)
++{
++ char buf [1024];
++
++ if (n &lt;= 4)
++ {
++ SLtt_normal_video ();
++ SLMEMSET (buf, ' ', n);
++ buf[n] = 0;
++ write_string_with_care (buf);
++ Cursor_c += n;
++ }
++ else if (Curs_F_Str != NULL)
++ {
++ Cursor_c += n;
++ n = tt_sprintf(buf, Curs_F_Str, (int) n, 0);
++ tt_write(buf, n);
++ }
++ else SLtt_goto_rc (row, (int) (Cursor_c + n));
++}
++
++
++void SLtt_smart_puts(SLsmg_Char_Type *neww, SLsmg_Char_Type *oldd, int len, int row)
++{
++ register SLsmg_Char_Type *p, *q, *qmax, *pmax, *buf;
++ SLsmg_Char_Type buffer[256];
++ unsigned int n_spaces;
++ SLsmg_Char_Type *space_match, *last_buffered_match;
++#ifdef HP_GLITCH_CODE
++ int handle_hp_glitch = 0;
++#endif
++ SLsmg_Char_Type space_char;
++#define SLTT_USE_INSERT_HACK 1
++#if SLTT_USE_INSERT_HACK
++ SLsmg_Char_Type insert_hack_prev = 0;
++ SLsmg_Char_Type insert_hack_char = 0;
++
++ if ((row + 1 == SLtt_Screen_Rows)
++ &amp;&amp; (len == SLtt_Screen_Cols)
++ &amp;&amp; (len &gt; 1)
++ &amp;&amp; (SLtt_Term_Cannot_Insert == 0)
++ &amp;&amp; Automatic_Margins)
++ {
++ insert_hack_char = neww[len-1];
++ if (oldd[len-1] == insert_hack_char)
++ insert_hack_char = 0;
++ else
++ insert_hack_prev = neww[len-2];
++ }
++#endif
++
++ q = oldd; p = neww;
++ qmax = oldd + len;
++ pmax = p + len;
++
++ /* Find out where to begin --- while they match, we are ok */
++ while (1)
++ {
++ if (q == qmax) return;
++#if SLANG_HAS_KANJI_SUPPORT
++ if (*p &amp; 0x80)
++ { /* new is kanji */
++ if ((*q &amp; 0x80) &amp;&amp; ((q + 1) &lt; qmax))
++ { /* old is also kanji */
++ if (((0xFF &amp; *q) != (0xFF &amp; *p))
++ || ((0xFF &amp; q[1]) != (0xFF &amp; p[1])))
++ break; /* both kanji, but not match */
++
++ else
++ { /* kanji match ! */
++ if (!COLOR_EQS(*q, *p)) break;
++ q++; p++;
++ if (!COLOR_EQS(*q, *p)) break;
++ /* really match! */
++ q++; p++;
++ continue;
++ }
++ }
++ else break; /* old is not kanji */
++ }
++ else
++ { /* new is not kanji */
++ if (*q &amp; 0x80) break; /* old is kanji */
++ }
++#endif
++ if (!CHAR_EQS(*q, *p)) break;
++ q++; p++;
++ }
++
++#ifdef HP_GLITCH_CODE
++ if (Has_HP_Glitch)
++ {
++ SLsmg_Char_Type *qq = q;
++
++ SLtt_goto_rc (row, (int) (p - neww));
++
++ while (qq &lt; qmax)
++ {
++ if (*qq &amp; 0xFF00)
++ {
++ SLtt_normal_video ();
++ SLtt_del_eol ();
++ qmax = q;
++ handle_hp_glitch = 1;
++ break;
++ }
++ qq++;
++ }
++ }
++#endif
++ /* Find where the last non-blank character on old/new screen is */
++
++ space_char = ' ';
++ if ((*(pmax-1) &amp; 0xFF) == ' ')
++ {
++ /* If we get here, then we can erase to the end of the line to create
++ * the final space. However, this will only work _if_ erasing will
++ * get us the correct color. If the terminal supports BCE, then this
++ * is easy. If it does not, then we can only perform this operation
++ * if the color is known via something like COLORFGBG. For now,
++ * I just will not perform the optimization for such terminals.
++ */
++ if ((Can_Background_Color_Erase)
++ &amp;&amp; SLtt_Use_Ansi_Colors)
++ space_char = *(pmax - 1);
++
++ while (pmax &gt; p)
++ {
++ pmax--;
++ if (!CHAR_EQS(*pmax, space_char))
++ {
++ pmax++;
++ break;
++ }
++ }
++ }
++
++ while (qmax &gt; q)
++ {
++ qmax--;
++ if (!CHAR_EQS(*qmax, space_char))
++ {
++ qmax++;
++ break;
++ }
++ }
++
++ last_buffered_match = buf = buffer; /* buffer is empty */
++
++#ifdef HP_GLITCH_CODE
++ if (handle_hp_glitch)
++ {
++ while (p &lt; pmax)
++ {
++ *buf++ = *p++;
++ }
++ }
++#endif
++
++#ifdef HP_GLITCH_CODE
++ if (Has_HP_Glitch == 0)
++ {
++#endif
++ /* Try use use erase to bol if possible */
++ if ((Del_Bol_Str != NULL) &amp;&amp; ((*neww &amp; 0xFF) == 32))
++ {
++ SLsmg_Char_Type *p1;
++ SLsmg_Char_Type blank;
++
++ p1 = neww;
++ if ((Can_Background_Color_Erase)
++ &amp;&amp; SLtt_Use_Ansi_Colors)
++ blank = *p1;
++ /* black+white attributes do not support bce */
++ else
++ blank = 32;
++
++ while ((p1 &lt; pmax) &amp;&amp; (CHAR_EQS (*p1, blank)))
++ p1++;
++
++ /* Is this optimization worth it? Assume Del_Bol_Str is ESC [ 1 K
++ * It costs 4 chars + the space needed to properly position the
++ * cursor, e.g., ESC [ 10;10H. So, it costs at least 13 characters.
++ */
++ if ((p1 &gt; neww + 13)
++ &amp;&amp; (p1 &gt;= p)
++ /* Avoid erasing from the end of the line */
++ &amp;&amp; ((p1 != pmax) || (pmax &lt; neww + len)))
++ {
++ int ofs = (int) (p1 - neww);
++ q = oldd + ofs;
++ p = p1;
++ SLtt_goto_rc (row, ofs - 1);
++ SLtt_reverse_video (blank &gt;&gt; 8);
++ tt_write_string (Del_Bol_Str);
++ tt_write (&quot; &quot;, 1);
++ Cursor_c += 1;
++ }
++ else
++ SLtt_goto_rc (row, (int) (p - neww));
++ }
++ else
++ SLtt_goto_rc (row, (int) (p - neww));
++#ifdef HP_GLITCH_CODE
++ }
++#endif
++
++
++ /* loop using overwrite then skip algorithm until done */
++ while (1)
++ {
++ /* while they do not match and we do not hit a space, buffer them up */
++ n_spaces = 0;
++ while (p &lt; pmax)
++ {
++ if (CHAR_EQS(*q, 32) &amp;&amp; CHAR_EQS(*p, 32))
++ {
++ /* If *q is not a space, we would have to overwrite it.
++ * However, if *q is a space, then while *p is also one,
++ * we only need to skip over the blank field.
++ */
++ space_match = p;
++ p++; q++;
++ while ((p &lt; pmax)
++ &amp;&amp; CHAR_EQS(*q, 32)
++ &amp;&amp; CHAR_EQS(*p, 32))
++ {
++ p++;
++ q++;
++ }
++ n_spaces = (unsigned int) (p - space_match);
++ break;
++ }
++#if SLANG_HAS_KANJI_SUPPORT
++ if ((*p &amp; 0x80) &amp;&amp; ((p + 1) &lt; pmax))
++ { /* new is kanji */
++ if (*q &amp; 0x80)
++ { /* old is also kanji */
++ if (((0xFF &amp; *q) != (0xFF &amp; *p))
++ || ((0xFF &amp; q[1]) != (0xFF &amp; p[1])))
++ {
++ /* both kanji, but not match */
++ *buf++ = *p++;
++ *buf++ = *p++;
++ q += 2;
++ continue;
++ }
++ else
++ { /* kanji match ? */
++ if (!COLOR_EQS(*q, *p) || !COLOR_EQS(*(q+1), *(p+1)))
++ {
++ /* code is match, but color is diff */
++ *buf++ = *p++;
++ *buf++ = *p++;
++ q += 2;
++ continue;
++ }
++ /* really match ! */
++ break;
++ }
++ }
++ else
++ { /* old is not kanji */
++ *buf++ = *p++;
++ *buf++ = *p++;
++ q += 2;
++ continue;
++ }
++ }
++ else
++ { /* new is not kanji */
++ if (*q &amp; 0x80)
++ { /* old is kanji */
++ *buf++ = *p++;
++ q++;
++ continue;
++ }
++ }
++#endif
++
++ if (CHAR_EQS(*q, *p)) break;
++ *buf++ = *p++;
++ q++;
++ }
++ *buf = 0;
++
++ if (buf != buffer) send_attr_str (buffer);
++ buf = buffer;
++
++ if (n_spaces
++ &amp;&amp; ((p &lt; pmax) /* erase to eol will achieve this effect*/
++ || (space_char != 32)))/* unless space_char is not a simple space */
++ {
++ forward_cursor (n_spaces, row);
++ }
++
++ /* Now we overwrote what we could and cursor is placed at position
++ * of a possible match of new and old. If this is the case, skip
++ * some more.
++ */
++#if !SLANG_HAS_KANJI_SUPPORT
++ while ((p &lt; pmax) &amp;&amp; CHAR_EQS(*p, *q))
++ {
++ *buf++ = *p++;
++ q++;
++ }
++#else
++ /* Kanji */
++ while (p &lt; pmax)
++ {
++ if ((*p &amp; 0x80) &amp;&amp; ((p + 1) &lt; pmax))
++ { /* new is kanji */
++ if (*q &amp; 0x80)
++ { /* old is also kanji */
++ if (((0xFF &amp; *q) == (0xFF &amp; *p))
++ &amp;&amp; ((0xFF &amp; q[1]) == (0xFF &amp; p[1])))
++ {
++ /* kanji match ? */
++ if (!COLOR_EQS(*q, *p)
++ || !COLOR_EQS(q[1], p[1]))
++ break;
++
++ *buf++ = *p++;
++ q++;
++ if (p &gt;= pmax)
++ {
++ *buf++ = 32;
++ p++;
++ break;
++ }
++ else
++ {
++ *buf++ = *p++;
++ q++;
++ continue;
++ }
++ }
++ else break; /* both kanji, but not match */
++ }
++ else break; /* old is not kanji */
++ }
++ else
++ { /* new is not kanji */
++ if (*q &amp; 0x80) break; /* old is kanji */
++ if (!CHAR_EQS(*q, *p)) break;
++ *buf++ = *p++;
++ q++;
++ }
++ }
++#endif
++ last_buffered_match = buf;
++ if (p &gt;= pmax) break;
++
++ /* jump to new position is it is greater than 5 otherwise
++ * let it sit in the buffer and output it later.
++ */
++ if ((int) (buf - buffer) &gt;= 5)
++ {
++ forward_cursor ((unsigned int) (buf - buffer), row);
++ last_buffered_match = buf = buffer;
++ }
++ }
++
++ if (buf != buffer)
++ {
++ if (q &lt; qmax)
++ {
++ if ((buf == last_buffered_match)
++ &amp;&amp; ((int) (buf - buffer) &gt;= 5))
++ {
++ forward_cursor ((unsigned int) (buf - buffer), row);
++ }
++ else
++ {
++ *buf = 0;
++ send_attr_str (buffer);
++ }
++ }
++ }
++
++ if (q &lt; qmax)
++ {
++ SLtt_reverse_video (space_char &gt;&gt; 8);
++ del_eol ();
++ }
++
++#if SLTT_USE_INSERT_HACK
++ else if (insert_hack_char)
++ {
++ SLtt_goto_rc (SLtt_Screen_Rows-1, SLtt_Screen_Cols-2);
++ buffer[0] = insert_hack_char;
++ buffer[1] = 0;
++ send_attr_str (buffer);
++ SLtt_goto_rc (SLtt_Screen_Rows-1, SLtt_Screen_Cols-2);
++ buffer[0] = insert_hack_prev;
++ SLtt_begin_insert ();
++ send_attr_str (buffer);
++ SLtt_end_insert ();
++ }
++#endif
++
++ if (Automatic_Margins &amp;&amp; (Cursor_c + 1 &gt;= SLtt_Screen_Cols)) Cursor_Set = 0;
++}
++
++static void get_color_info (void)
++{
++ char *fg, *bg;
++
++ /* Allow easy mechanism to override inadequate termcap/terminfo files. */
++ if (SLtt_Use_Ansi_Colors == 0)
++ SLtt_Use_Ansi_Colors = (NULL != getenv (&quot;COLORTERM&quot;));
++
++ if (SLtt_Use_Ansi_Colors)
++ Is_Color_Terminal = 1;
++
++#if SLTT_HAS_NON_BCE_SUPPORT
++ if (Can_Background_Color_Erase == 0)
++ Can_Background_Color_Erase = (NULL != getenv (&quot;COLORTERM_BCE&quot;));
++#endif
++
++ if (-1 == get_default_colors (&amp;fg, &amp;bg))
++ return;
++
++ /* Check to see if application has already set them. */
++ if (Color_0_Modified)
++ return;
++
++ SLtt_set_color (0, NULL, fg, bg);
++ SLtt_set_color (1, NULL, bg, fg);
++}
++
++/* termcap stuff */
++
++#ifdef __unix__
++
++static int Termcap_Initalized = 0;
++
++#ifdef USE_TERMCAP
++/* Termcap based system */
++static char Termcap_Buf[4096];
++static char Termcap_String_Buf[4096];
++static char *Termcap_String_Ptr;
++extern char *tgetstr(char *, char **);
++extern int tgetent(char *, char *);
++extern int tgetnum(char *);
++extern int tgetflag(char *);
++#else
++/* Terminfo */
++static SLterminfo_Type *Terminfo;
++#endif
++
++#define TGETFLAG(x) (SLtt_tgetflag(x) &gt; 0)
++
++static char *fixup_tgetstr (char *what)
++{
++ register char *w, *w1;
++ char *wsave;
++
++ if (what == NULL)
++ return NULL;
++
++ /* Check for AIX brain-damage */
++ if (*what == '@')
++ return NULL;
++
++ /* lose pad info --- with today's technology, term is a loser if
++ it is really needed */
++ while ((*what == '.') ||
++ ((*what &gt;= '0') &amp;&amp; (*what &lt;= '9'))) what++;
++ if (*what == '*') what++;
++
++ /* lose terminfo padding--- looks like $&lt;...&gt; */
++ w = what;
++ while (*w) if ((*w++ == '$') &amp;&amp; (*w == '&lt;'))
++ {
++ w1 = w - 1;
++ while (*w &amp;&amp; (*w != '&gt;')) w++;
++ if (*w == 0) break;
++ w++;
++ wsave = w1;
++ while ((*w1++ = *w++) != 0);
++ w = wsave;
++ }
++
++ if (*what == 0) what = NULL;
++ return what;
++}
++
++char *SLtt_tgetstr (char *s)
++{
++ if (Termcap_Initalized == 0)
++ return NULL;
++
++#ifdef USE_TERMCAP
++ s = tgetstr (s, &amp;Termcap_String_Ptr);
++#else
++ s = _SLtt_tigetstr (Terminfo, s);
++#endif
++ return fixup_tgetstr (s);
++}
++
++int SLtt_tgetnum (char *s)
++{
++ if (Termcap_Initalized == 0)
++ return -1;
++#ifdef USE_TERMCAP
++ return tgetnum (s);
++#else
++ return _SLtt_tigetnum (Terminfo, s);
++#endif
++}
++
++int SLtt_tgetflag (char *s)
++{
++ if (Termcap_Initalized == 0)
++ return -1;
++#ifdef USE_TERMCAP
++ return tgetflag (s);
++#else
++ return _SLtt_tigetflag (Terminfo, s);
++#endif
++}
++
++static int Vt100_Like = 0;
++
++void SLtt_get_terminfo (void)
++{
++ char *term;
++ int status;
++
++ term = getenv (&quot;TERM&quot;);
++ if (term == NULL)
++ SLang_exit_error(&quot;TERM environment variable needs set.&quot;);
++
++ if (0 == (status = SLtt_initialize (term)))
++ return;
++
++ if (status == -1)
++ {
++ SLang_exit_error (&quot;Unknown terminal: %s\n\
++Check the TERM environment variable.\n\
++Also make sure that the terminal is defined in the terminfo database.\n\
++Alternatively, set the TERMCAP environment variable to the desired\n\
++termcap entry.&quot;,
++ term);
++ }
++
++ if (status == -2)
++ {
++ SLang_exit_error (&quot;\
++Your terminal lacks the ability to clear the screen or position the cursor.\n&quot;);
++ }
++}
++
++/* Returns 0 if all goes well, -1 if terminal capabilities cannot be deduced,
++ * or -2 if terminal cannot position the cursor.
++ */
++int SLtt_initialize (char *term)
++{
++ char *t, ch;
++ int is_xterm;
++ int almost_vtxxx;
++
++ if (SLang_TT_Write_FD == -1)
++ {
++ /* Apparantly, this cannot fail according to the man pages. */
++ SLang_TT_Write_FD = fileno (stdout);
++ }
++
++ if (term == NULL)
++ {
++ term = getenv (&quot;TERM&quot;);
++ if (term == NULL)
++ return -1;
++ }
++
++ Linux_Console = (!strncmp (term, &quot;linux&quot;, 5)
++# ifdef linux
++ || !strncmp(term, &quot;con&quot;, 3)
++# endif
++ );
++
++ t = term;
++
++ if (strcmp(t, &quot;vt52&quot;) &amp;&amp; (*t++ == 'v') &amp;&amp; (*t++ == 't')
++ &amp;&amp; (ch = *t, (ch &gt;= '1') &amp;&amp; (ch &lt;= '9'))) Vt100_Like = 1;
++
++ is_xterm = ((0 == strncmp (term, &quot;xterm&quot;, 5))
++ || (0 == strncmp (term, &quot;rxvt&quot;, 4))
++ || (0 == strncmp (term, &quot;Eterm&quot;, 5)));
++
++ almost_vtxxx = (Vt100_Like
++ || Linux_Console
++ || is_xterm
++ || !strcmp (term, &quot;screen&quot;));
++
++# ifndef USE_TERMCAP
++ if (NULL == (Terminfo = _SLtt_tigetent (term)))
++ {
++ if (almost_vtxxx) /* Special cases. */
++ {
++ int vt102 = 1;
++ if (!strcmp (term, &quot;vt100&quot;)) vt102 = 0;
++ get_color_info ();
++ SLtt_set_term_vtxxx (&amp;vt102);
++ return 0;
++ }
++ return -1;
++ }
++# else /* USE_TERMCAP */
++ if (1 != tgetent(Termcap_Buf, term))
++ return -1;
++ Termcap_String_Ptr = Termcap_String_Buf;
++# endif /* NOT USE_TERMCAP */
++
++ Termcap_Initalized = 1;
++
++ Cls_Str = SLtt_tgetstr (&quot;cl&quot;);
++ Curs_Pos_Str = SLtt_tgetstr (&quot;cm&quot;);
++
++ if ((NULL == (Ins_Mode_Str = SLtt_tgetstr(&quot;im&quot;)))
++ || ( NULL == (Eins_Mode_Str = SLtt_tgetstr(&quot;ei&quot;)))
++ || ( NULL == (Del_Char_Str = SLtt_tgetstr(&quot;dc&quot;))))
++ SLtt_Term_Cannot_Insert = 1;
++
++ Visible_Bell_Str = SLtt_tgetstr (&quot;vb&quot;);
++ Curs_Up_Str = SLtt_tgetstr (&quot;up&quot;);
++ Rev_Scroll_Str = SLtt_tgetstr(&quot;sr&quot;);
++ Del_N_Lines_Str = SLtt_tgetstr(&quot;DL&quot;);
++ Add_N_Lines_Str = SLtt_tgetstr(&quot;AL&quot;);
++
++ /* Actually these are used to initialize terminals that use cursor
++ * addressing. Hard to believe.
++ */
++ Term_Init_Str = SLtt_tgetstr (&quot;ti&quot;);
++ Term_Reset_Str = SLtt_tgetstr (&quot;te&quot;);
++
++ /* If I do this for vtxxx terminals, arrow keys start sending ESC O A,
++ * which I do not want. This is mainly for HP terminals.
++ */
++ if ((almost_vtxxx == 0) || SLtt_Force_Keypad_Init)
++ {
++ Keypad_Init_Str = SLtt_tgetstr (&quot;ks&quot;);
++ Keypad_Reset_Str = SLtt_tgetstr (&quot;ke&quot;);
++ }
++
++ /* Make up for defective termcap/terminfo databases */
++ if ((Vt100_Like &amp;&amp; (term[2] != '1'))
++ || Linux_Console
++ || is_xterm
++ )
++ {
++ if (Del_N_Lines_Str == NULL) Del_N_Lines_Str = &quot;\033[%dM&quot;;
++ if (Add_N_Lines_Str == NULL) Add_N_Lines_Str = &quot;\033[%dL&quot;;
++ }
++
++ Scroll_R_Str = SLtt_tgetstr(&quot;cs&quot;);
++
++ SLtt_get_screen_size ();
++
++ if ((Scroll_R_Str == NULL)
++ || (((NULL == Del_N_Lines_Str) || (NULL == Add_N_Lines_Str))
++ &amp;&amp; (NULL == Rev_Scroll_Str)))
++ {
++ if (is_xterm
++ || Linux_Console
++ )
++ {
++ /* Defective termcap mode!!!! */
++ SLtt_set_term_vtxxx (NULL);
++ }
++ else SLtt_Term_Cannot_Scroll = 1;
++ }
++
++ Del_Eol_Str = SLtt_tgetstr(&quot;ce&quot;);
++ Del_Bol_Str = SLtt_tgetstr(&quot;cb&quot;);
++ if (is_xterm &amp;&amp; (Del_Bol_Str == NULL))
++ Del_Bol_Str = &quot;\033[1K&quot;;
++ if (is_xterm &amp;&amp; (Del_Eol_Str == NULL))
++ Del_Bol_Str = &quot;\033[K&quot;;
++
++ Rev_Vid_Str = SLtt_tgetstr(&quot;mr&quot;);
++ if (Rev_Vid_Str == NULL) Rev_Vid_Str = SLtt_tgetstr(&quot;so&quot;);
++
++ Bold_Vid_Str = SLtt_tgetstr(&quot;md&quot;);
++
++ /* Although xterm cannot blink, it does display the blinking characters
++ * as bold ones. Some Rxvt will display the background as high intensity.
++ */
++ if ((NULL == (Blink_Vid_Str = SLtt_tgetstr(&quot;mb&quot;)))
++ &amp;&amp; is_xterm)
++ Blink_Vid_Str = &quot;\033[5m&quot;;
++
++ UnderLine_Vid_Str = SLtt_tgetstr(&quot;us&quot;);
++
++ Start_Alt_Chars_Str = SLtt_tgetstr (&quot;as&quot;); /* smacs */
++ End_Alt_Chars_Str = SLtt_tgetstr (&quot;ae&quot;); /* rmacs */
++ Enable_Alt_Char_Set = SLtt_tgetstr (&quot;eA&quot;); /* enacs */
++ SLtt_Graphics_Char_Pairs = SLtt_tgetstr (&quot;ac&quot;);
++
++ if (NULL == SLtt_Graphics_Char_Pairs)
++ {
++ /* make up for defective termcap/terminfo */
++ if (Vt100_Like)
++ {
++ Start_Alt_Chars_Str = &quot;\016&quot;;
++ End_Alt_Chars_Str = &quot;\017&quot;;
++ Enable_Alt_Char_Set = &quot;\033)0&quot;;
++ }
++ }
++
++ /* aixterm added by willi */
++ if (is_xterm || !strncmp (term, &quot;aixterm&quot;, 7))
++ {
++ Start_Alt_Chars_Str = &quot;\016&quot;;
++ End_Alt_Chars_Str = &quot;\017&quot;;
++ Enable_Alt_Char_Set = &quot;\033(B\033)0&quot;;
++ }
++
++ if ((SLtt_Graphics_Char_Pairs == NULL) &amp;&amp;
++ ((Start_Alt_Chars_Str == NULL) || (End_Alt_Chars_Str == NULL)))
++ {
++ SLtt_Has_Alt_Charset = 0;
++ Enable_Alt_Char_Set = NULL;
++ }
++ else SLtt_Has_Alt_Charset = 1;
++
++#ifdef AMIGA
++ Enable_Alt_Char_Set = Start_Alt_Chars_Str = End_Alt_Chars_Str = NULL;
++#endif
++
++ /* status line capabilities */
++ if ((SLtt_Has_Status_Line == -1)
++ &amp;&amp; (0 != (SLtt_Has_Status_Line = TGETFLAG (&quot;hs&quot;))))
++ {
++ Disable_Status_line_Str = SLtt_tgetstr (&quot;ds&quot;);
++ Return_From_Status_Line_Str = SLtt_tgetstr (&quot;fs&quot;);
++ Goto_Status_Line_Str = SLtt_tgetstr (&quot;ts&quot;);
++ /* Status_Line_Esc_Ok = TGETFLAG(&quot;es&quot;); */
++ Num_Status_Line_Columns = SLtt_tgetnum (&quot;ws&quot;);
++ if (Num_Status_Line_Columns &lt; 0) Num_Status_Line_Columns = 0;
++ }
++
++ if (NULL == (Norm_Vid_Str = SLtt_tgetstr(&quot;me&quot;)))
++ {
++ Norm_Vid_Str = SLtt_tgetstr(&quot;se&quot;);
++ }
++
++ Cursor_Invisible_Str = SLtt_tgetstr(&quot;vi&quot;);
++ Cursor_Visible_Str = SLtt_tgetstr(&quot;ve&quot;);
++
++ Curs_F_Str = SLtt_tgetstr(&quot;RI&quot;);
++
++# if 0
++ if (NULL != Curs_F_Str)
++ {
++ Len_Curs_F_Str = strlen(Curs_F_Str);
++ }
++ else Len_Curs_F_Str = strlen(Curs_Pos_Str);
++# endif
++
++ Automatic_Margins = TGETFLAG (&quot;am&quot;);
++ /* No_Move_In_Standout = !TGETFLAG (&quot;ms&quot;); */
++# ifdef HP_GLITCH_CODE
++ Has_HP_Glitch = TGETFLAG (&quot;xs&quot;);
++# else
++ Worthless_Highlight = TGETFLAG (&quot;xs&quot;);
++# endif
++
++ if (Worthless_Highlight == 0)
++ { /* Magic cookie glitch */
++ Worthless_Highlight = (SLtt_tgetnum (&quot;sg&quot;) &gt; 0);
++ }
++
++ if (Worthless_Highlight)
++ SLtt_Has_Alt_Charset = 0;
++
++ Reset_Color_String = SLtt_tgetstr (&quot;op&quot;);
++ Color_Fg_Str = SLtt_tgetstr (&quot;AF&quot;); /* ANSI setaf */
++ Color_Bg_Str = SLtt_tgetstr (&quot;AB&quot;); /* ANSI setbf */
++ if ((Color_Fg_Str == NULL) || (Color_Bg_Str == NULL))
++ {
++ Color_Fg_Str = SLtt_tgetstr (&quot;Sf&quot;); /* setf */
++ Color_Bg_Str = SLtt_tgetstr (&quot;Sb&quot;); /* setb */
++ }
++
++ if ((Max_Terminfo_Colors = SLtt_tgetnum (&quot;Co&quot;)) &lt; 0)
++ Max_Terminfo_Colors = 8;
++
++ if ((Color_Bg_Str != NULL) &amp;&amp; (Color_Fg_Str != NULL))
++ SLtt_Use_Ansi_Colors = 1;
++ else
++ {
++#if 0
++ Color_Fg_Str = &quot;%?%p1%{7}%&gt;%t\033[1;3%p1%{8}%m%dm%e\033[3%p1%dm%;&quot;;
++ Color_Bg_Str = &quot;%?%p1%{7}%&gt;%t\033[5;4%p1%{8}%m%dm%e\033[4%p1%dm%;&quot;;
++ Max_Terminfo_Colors = 16;
++#else
++ Color_Fg_Str = &quot;\033[3%dm&quot;;
++ Color_Bg_Str = &quot;\033[4%dm&quot;;
++ Max_Terminfo_Colors = 8;
++#endif
++ }
++
++#if SLTT_HAS_NON_BCE_SUPPORT
++ Can_Background_Color_Erase = TGETFLAG (&quot;ut&quot;); /* bce */
++ /* Modern xterms have the BCE capability as well as the linux console */
++ if (Can_Background_Color_Erase == 0)
++ {
++ Can_Background_Color_Erase = (Linux_Console
++# if SLTT_XTERM_ALWAYS_BCE
++ || is_xterm
++# endif
++ );
++ }
++#endif
++ get_color_info ();
++
++
++ if ((Cls_Str == NULL)
++ || (Curs_Pos_Str == NULL))
++ return -2;
++
++ return 0;
++}
++
++#endif
++/* Unix */
++
++/* specific to vtxxx only */
++void SLtt_enable_cursor_keys (void)
++{
++#ifdef __unix__
++ if (Vt100_Like)
++#endif
++ tt_write_string(&quot;\033=\033[?1l&quot;);
++}
++
++#ifdef VMS
++int SLtt_initialize (char *term)
++{
++ SLtt_get_terminfo ();
++ return 0;
++}
++
++void SLtt_get_terminfo ()
++{
++ int zero = 0;
++
++ Color_Fg_Str = &quot;\033[3%dm&quot;;
++ Color_Bg_Str = &quot;\033[4%dm&quot;;
++ Max_Terminfo_Colors = 8;
++
++ get_color_info ();
++
++ SLtt_set_term_vtxxx(&amp;zero);
++ Start_Alt_Chars_Str = &quot;\016&quot;;
++ End_Alt_Chars_Str = &quot;\017&quot;;
++ SLtt_Has_Alt_Charset = 1;
++ SLtt_Graphics_Char_Pairs = &quot;aaffgghhjjkkllmmnnooqqssttuuvvwwxx&quot;;
++ Enable_Alt_Char_Set = &quot;\033(B\033)0&quot;;
++ SLtt_get_screen_size ();
++}
++#endif
++
++/* This sets term for vt102 terminals it parameter vt100 is 0. If vt100
++ * is non-zero, set terminal appropriate for a only vt100
++ * (no add line capability). */
++
++void SLtt_set_term_vtxxx(int *vt100)
++{
++ Norm_Vid_Str = &quot;\033[m&quot;;
++
++ Scroll_R_Str = &quot;\033[%i%d;%dr&quot;;
++ Cls_Str = &quot;\033[2J\033[H&quot;;
++ Rev_Vid_Str = &quot;\033[7m&quot;;
++ Bold_Vid_Str = &quot;\033[1m&quot;;
++ Blink_Vid_Str = &quot;\033[5m&quot;;
++ UnderLine_Vid_Str = &quot;\033[4m&quot;;
++ Del_Eol_Str = &quot;\033[K&quot;;
++ Del_Bol_Str = &quot;\033[1K&quot;;
++ Rev_Scroll_Str = &quot;\033M&quot;;
++ Curs_F_Str = &quot;\033[%dC&quot;;
++ /* Len_Curs_F_Str = 5; */
++ Curs_Pos_Str = &quot;\033[%i%d;%dH&quot;;
++ if ((vt100 == NULL) || (*vt100 == 0))
++ {
++ Ins_Mode_Str = &quot;\033[4h&quot;;
++ Eins_Mode_Str = &quot;\033[4l&quot;;
++ Del_Char_Str = &quot;\033[P&quot;;
++ Del_N_Lines_Str = &quot;\033[%dM&quot;;
++ Add_N_Lines_Str = &quot;\033[%dL&quot;;
++ SLtt_Term_Cannot_Insert = 0;
++ }
++ else
++ {
++ Del_N_Lines_Str = NULL;
++ Add_N_Lines_Str = NULL;
++ SLtt_Term_Cannot_Insert = 1;
++ }
++ SLtt_Term_Cannot_Scroll = 0;
++ /* No_Move_In_Standout = 0; */
++}
++
++int SLtt_init_video (void)
++{
++ /* send_string_to_term(&quot;\033[?6h&quot;); */
++ /* relative origin mode */
++ tt_write_string (Term_Init_Str);
++ tt_write_string (Keypad_Init_Str);
++ SLtt_reset_scroll_region();
++ SLtt_end_insert();
++ tt_write_string (Enable_Alt_Char_Set);
++ Video_Initialized = 1;
++ return 0;
++}
++
++int SLtt_reset_video (void)
++{
++ SLtt_goto_rc (SLtt_Screen_Rows - 1, 0);
++ Cursor_Set = 0;
++ SLtt_normal_video (); /* MSKermit requires this */
++ tt_write_string(Norm_Vid_Str);
++
++ Current_Fgbg = 0xFFFFFFFFU;
++ SLtt_set_alt_char_set (0);
++ if (SLtt_Use_Ansi_Colors)
++ {
++ if (Reset_Color_String == NULL)
++ {
++ SLtt_Char_Type attr;
++ if (-1 != make_color_fgbg (NULL, NULL, &amp;attr))
++ write_attributes (attr);
++ else tt_write_string (&quot;\033[0m\033[m&quot;);
++ }
++ else tt_write_string (Reset_Color_String);
++ Current_Fgbg = 0xFFFFFFFFU;
++ }
++ SLtt_erase_line ();
++ tt_write_string (Keypad_Reset_Str);
++ tt_write_string (Term_Reset_Str);
++ SLtt_flush_output ();
++ Video_Initialized = 0;
++ return 0;
++}
++
++void SLtt_bold_video (void)
++{
++ tt_write_string (Bold_Vid_Str);
++}
++
++int SLtt_set_mouse_mode (int mode, int force)
++{
++ char *term;
++
++ if (force == 0)
++ {
++ if (NULL == (term = (char *) getenv(&quot;TERM&quot;))) return -1;
++ if (strncmp (&quot;xterm&quot;, term, 5))
++ return -1;
++ }
++
++ if (mode)
++ tt_write_string (&quot;\033[?9h&quot;);
++ else
++ tt_write_string (&quot;\033[?9l&quot;);
++
++ return 0;
++}
++
++void SLtt_disable_status_line (void)
++{
++ if (SLtt_Has_Status_Line &gt; 0)
++ {
++ tt_write_string (Disable_Status_line_Str);
++ SLtt_flush_output ();
++ }
++}
++
++int SLtt_write_to_status_line (char *s, int col)
++{
++ if ((SLtt_Has_Status_Line &lt;= 0)
++ || (Goto_Status_Line_Str == NULL)
++ || (Return_From_Status_Line_Str == NULL))
++ return -1;
++
++ tt_printf (Goto_Status_Line_Str, col, 0);
++ tt_write_string (s);
++ tt_write_string (Return_From_Status_Line_Str);
++ return 0;
++}
++
++void SLtt_get_screen_size (void)
++{
++#ifdef VMS
++ int status, code;
++ unsigned short chan;
++ $DESCRIPTOR(dev_dsc, &quot;SYS$INPUT:&quot;);
++#endif
++ int r = 0, c = 0;
++
++#ifdef TIOCGWINSZ
++ struct winsize wind_struct;
++
++ do
++ {
++ if ((ioctl(1,TIOCGWINSZ,&amp;wind_struct) == 0)
++ || (ioctl(0, TIOCGWINSZ, &amp;wind_struct) == 0)
++ || (ioctl(2, TIOCGWINSZ, &amp;wind_struct) == 0))
++ {
++ c = (int) wind_struct.ws_col;
++ r = (int) wind_struct.ws_row;
++ break;
++ }
++ }
++ while (errno == EINTR);
++
++#endif
++
++#ifdef VMS
++ status = sys$assign(&amp;dev_dsc,&amp;chan,0,0,0);
++ if (status &amp; 1)
++ {
++ code = DVI$_DEVBUFSIZ;
++ status = lib$getdvi(&amp;code, &amp;chan,0, &amp;c, 0,0);
++ if (!(status &amp; 1))
++ c = 80;
++ code = DVI$_TT_PAGE;
++ status = lib$getdvi(&amp;code, &amp;chan,0, &amp;r, 0,0);
++ if (!(status &amp; 1))
++ r = 24;
++ sys$dassgn(chan);
++ }
++#endif
++
++ if (r &lt;= 0)
++ {
++ char *s = getenv (&quot;LINES&quot;);
++ if (s != NULL) r = atoi (s);
++ }
++
++ if (c &lt;= 0)
++ {
++ char *s = getenv (&quot;COLUMNS&quot;);
++ if (s != NULL) c = atoi (s);
++ }
++
++ if (r &lt;= 0) r = 24;
++ if (c &lt;= 0) c = 80;
++#if 0
++ if ((r &lt;= 0) || (r &gt; 200)) r = 24;
++ if ((c &lt;= 0) || (c &gt; 250)) c = 80;
++#endif
++ SLtt_Screen_Rows = r;
++ SLtt_Screen_Cols = c;
++}
++
++#if SLTT_HAS_NON_BCE_SUPPORT
++int _SLtt_get_bce_color_offset (void)
++{
++ if ((SLtt_Use_Ansi_Colors == 0)
++ || Can_Background_Color_Erase
++ || SLtt_Use_Blink_For_ACS) /* in this case, we cannot lose a color */
++ Bce_Color_Offset = 0;
++ else
++ {
++ if (GET_BG(Ansi_Color_Map[0].fgbg) == SLSMG_COLOR_DEFAULT)
++ Bce_Color_Offset = 0;
++ else
++ Bce_Color_Offset = 1;
++ }
++
++ return Bce_Color_Offset;
++}
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/sldisply.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slerr.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slerr.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slerr.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,181 @@
++/* error handling common to all routines. */
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++void (*SLang_VMessage_Hook) (char *, va_list);
++void (*SLang_Error_Hook)(char *);
++void (*SLang_Exit_Error_Hook)(char *, va_list);
++volatile int SLang_Error = 0;
++char *SLang_Error_Message;
++volatile int SLKeyBoard_Quit = 0;
++
++static char *get_error_string (void)
++{
++ char *str;
++
++ if (!SLang_Error) SLang_Error = SL_UNKNOWN_ERROR;
++ if (SLang_Error_Message != NULL) str = SLang_Error_Message;
++ else switch(SLang_Error)
++ {
++ case SL_NOT_IMPLEMENTED: str = &quot;Not Implemented&quot;; break;
++ case SL_APPLICATION_ERROR: str = &quot;Application Error&quot;; break;
++ case SL_VARIABLE_UNINITIALIZED: str = &quot;Variable Uninitialized&quot;; break;
++ case SL_MALLOC_ERROR : str = &quot;Malloc Error&quot;; break;
++ case SL_INTERNAL_ERROR: str = &quot;Internal Error&quot;; break;
++ case SL_STACK_OVERFLOW: str = &quot;Stack Overflow&quot;; break;
++ case SL_STACK_UNDERFLOW: str = &quot;Stack Underflow&quot;; break;
++ case SL_INTRINSIC_ERROR: str = &quot;Intrinsic Error&quot;; break;
++ case SL_USER_BREAK: str = &quot;User Break&quot;; break;
++ case SL_UNDEFINED_NAME: str = &quot;Undefined Name&quot;; break;
++ case SL_SYNTAX_ERROR: str = &quot;Syntax Error&quot;; break;
++ case SL_DUPLICATE_DEFINITION: str = &quot;Duplicate Definition&quot;; break;
++ case SL_TYPE_MISMATCH: str = &quot;Type Mismatch&quot;; break;
++ case SL_READONLY_ERROR: str = &quot;Variable is read-only&quot;; break;
++ case SL_DIVIDE_ERROR: str = &quot;Divide by zero&quot;; break;
++ case SL_OBJ_NOPEN: str = &quot;Object not opened&quot;; break;
++ case SL_OBJ_UNKNOWN: str = &quot;Object unknown&quot;; break;
++ case SL_INVALID_PARM: str = &quot;Invalid Parameter&quot;; break;
++ case SL_TYPE_UNDEFINED_OP_ERROR:
++ str = &quot;Operation not defined for datatype&quot;; break;
++ case SL_USER_ERROR:
++ str = &quot;User Error&quot;; break;
++ case SL_USAGE_ERROR:
++ str = &quot;Illegal usage of function&quot;;
++ break;
++ case SL_FLOATING_EXCEPTION:
++ str = &quot;Floating Point Exception&quot;;
++ break;
++ case SL_UNKNOWN_ERROR:
++ default: str = &quot;Unknown Error Code&quot;;
++ }
++
++ SLang_Error_Message = NULL;
++ return str;
++}
++
++void SLang_doerror (char *error)
++{
++ char *str = NULL;
++ char *err;
++ char *malloced_err_buf;
++ char err_buf [1024];
++
++ malloced_err_buf = NULL;
++
++ if (((SLang_Error == SL_USER_ERROR)
++ || (SLang_Error == SL_USAGE_ERROR))
++ &amp;&amp; (error != NULL) &amp;&amp; (*error != 0))
++ err = error;
++ else
++ {
++ char *sle = &quot;S-Lang Error: &quot;;
++ unsigned int len;
++ char *fmt;
++
++ str = get_error_string ();
++
++ fmt = &quot;%s%s%s&quot;;
++ if ((error == NULL) || (*error == 0))
++ error = &quot;&quot;;
++ else if (SLang_Error == SL_UNKNOWN_ERROR)
++ /* Do not display an unknown error message if error is non-NULL */
++ str = &quot;&quot;;
++ else
++ fmt = &quot;%s%s: %s&quot;;
++
++ len = strlen (sle) + strlen (str) + strlen(error) + 1;
++
++ err = err_buf;
++ if (len &gt;= sizeof (err_buf))
++ {
++ if (NULL == (malloced_err_buf = SLmalloc (len)))
++ err = NULL;
++ else
++ err = malloced_err_buf;
++ }
++
++ if (err != NULL) sprintf (err, fmt, sle, str, error);
++ else err = &quot;Out of memory&quot;;
++ }
++
++ if (SLang_Error_Hook == NULL)
++ {
++ fputs (err, stderr);
++ fputs(&quot;\r\n&quot;, stderr);
++ fflush (stderr);
++ }
++ else
++ (*SLang_Error_Hook)(err);
++
++ SLfree (malloced_err_buf);
++}
++
++void SLang_verror (int err_code, char *fmt, ...)
++{
++ va_list ap;
++ char err [1024];
++
++ if (err_code == 0) err_code = SL_INTRINSIC_ERROR;
++ if (SLang_Error == 0) SLang_Error = err_code;
++
++ if (fmt != NULL)
++ {
++ va_start(ap, fmt);
++ (void) _SLvsnprintf (err, sizeof (err), fmt, ap);
++ fmt = err;
++ va_end(ap);
++ }
++
++ SLang_doerror (fmt);
++}
++
++void SLang_exit_error (char *fmt, ...)
++{
++ va_list ap;
++
++ va_start (ap, fmt);
++ if (SLang_Exit_Error_Hook != NULL)
++ {
++ (*SLang_Exit_Error_Hook) (fmt, ap);
++ exit (1);
++ }
++
++ if (fmt != NULL)
++ {
++ vfprintf (stderr, fmt, ap);
++ fputs (&quot;\r\n&quot;, stderr);
++ fflush (stderr);
++ }
++ va_end (ap);
++
++ exit (1);
++}
++
++void SLang_vmessage (char *fmt, ...)
++{
++ va_list ap;
++
++ if (fmt == NULL)
++ return;
++
++ va_start (ap, fmt);
++
++ if (SLang_VMessage_Hook != NULL)
++ (*SLang_VMessage_Hook) (fmt, ap);
++ else
++ {
++ vfprintf (stdout, fmt, ap);
++ fputs (&quot;\r\n&quot;, stdout);
++ }
++
++ va_end (ap);
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slerr.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slerrno.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slerrno.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slerrno.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,219 @@
++/* The point of this file is to handle errno values in a system independent
++ * way so that they may be used in slang scripts.
++ */
++/* Copyright (c) 1998, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++#include &quot;slinclud.h&quot;
++
++#include &lt;errno.h&gt;
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++typedef struct
++{
++ char *msg;
++ int sys_errno;
++ char *symbolic_name;
++}
++Errno_Map_Type;
++
++static Errno_Map_Type Errno_Map [] =
++{
++#ifndef EPERM
++# define EPERM -1
++#endif
++ {&quot;Not owner&quot;, EPERM, &quot;EPERM&quot;},
++#ifndef ENOENT
++# define ENOENT -1
++#endif
++ {&quot;No such file or directory&quot;, ENOENT, &quot;ENOENT&quot;},
++#ifndef ESRCH
++# define ESRCH -1
++#endif
++ {&quot;No such process&quot;, ESRCH, &quot;ESRCH&quot;},
++#ifndef EINTR
++# define EINTR -1
++#endif
++ {&quot;Interrupted system call&quot;, EINTR, &quot;EINTR&quot;},
++#ifndef EIO
++# define EIO -1
++#endif
++ {&quot;I/O error&quot;, EIO, &quot;EIO&quot;},
++#ifndef ENXIO
++# define ENXIO -1
++#endif
++ {&quot;No such device or address&quot;, ENXIO, &quot;ENXIO&quot;},
++#ifndef E2BIG
++# define E2BIG -1
++#endif
++ {&quot;Arg list too long&quot;, E2BIG, &quot;E2BIG&quot;},
++#ifndef ENOEXEC
++# define ENOEXEC -1
++#endif
++ {&quot;Exec format error&quot;, ENOEXEC,&quot;ENOEXEC&quot;},
++#ifndef EBADF
++# define EBADF -1
++#endif
++ {&quot;Bad file number&quot;, EBADF, &quot;EBADF&quot;},
++#ifndef ECHILD
++# define ECHILD -1
++#endif
++ {&quot;No children&quot;, ECHILD, &quot;ECHILD&quot;},
++#ifndef EAGAIN
++# define EAGAIN -1
++#endif
++ {&quot;Try again&quot;, EAGAIN, &quot;EAGAIN&quot;},
++#ifndef ENOMEM
++# define ENOMEM -1
++#endif
++ {&quot;Not enough core&quot;, ENOMEM, &quot;ENOMEM&quot;},
++#ifndef EACCES
++# define EACCES -1
++#endif
++ {&quot;Permission denied&quot;, EACCES, &quot;EACCES&quot;},
++#ifndef EFAULT
++# define EFAULT -1
++#endif
++ {&quot;Bad address&quot;, EFAULT, &quot;EFAULT&quot;},
++#ifndef ENOTBLK
++# define ENOTBLK -1
++#endif
++ {&quot;Block device required&quot;, ENOTBLK, &quot;ENOTBLK&quot;},
++#ifndef EBUSY
++# define EBUSY -1
++#endif
++ {&quot;Mount device busy&quot;, EBUSY, &quot;EBUSY&quot;},
++#ifndef EEXIST
++# define EEXIST -1
++#endif
++ {&quot;File exists&quot;, EEXIST, &quot;EEXIST&quot;},
++#ifndef EXDEV
++# define EXDEV -1
++#endif
++ {&quot;Cross-device link&quot;, EXDEV, &quot;EXDEV&quot;},
++#ifndef ENODEV
++# define ENODEV -1
++#endif
++ {&quot;No such device&quot;, ENODEV, &quot;ENODEV&quot;},
++#ifndef ENOTDIR
++# define ENOTDIR -1
++#endif
++ {&quot;Not a directory&quot;, ENOTDIR, &quot;ENOTDIR&quot;},
++#ifndef EISDIR
++# define EISDIR -1
++#endif
++ {&quot;Is a directory&quot;, EISDIR, &quot;EISDIR&quot;},
++#ifndef EINVAL
++# define EINVAL -1
++#endif
++ {&quot;Invalid argument&quot;, EINVAL, &quot;EINVAL&quot;},
++#ifndef ENFILE
++# define ENFILE -1
++#endif
++ {&quot;File table overflow&quot;, ENFILE, &quot;ENFILE&quot;},
++#ifndef EMFILE
++# define EMFILE -1
++#endif
++ {&quot;Too many open files&quot;, EMFILE, &quot;EMFILE&quot;},
++#ifndef ENOTTY
++# define ENOTTY -1
++#endif
++ {&quot;Not a typewriter&quot;, ENOTTY, &quot;ENOTTY&quot;},
++#ifndef ETXTBSY
++# define ETXTBSY -1
++#endif
++ {&quot;Text file busy&quot;, ETXTBSY, &quot;ETXTBSY&quot;},
++#ifndef EFBIG
++# define EFBIG -1
++#endif
++ {&quot;File too large&quot;, EFBIG, &quot;EFBIG&quot;},
++#ifndef ENOSPC
++# define ENOSPC -1
++#endif
++ {&quot;No space left on device&quot;, ENOSPC, &quot;ENOSPC&quot;},
++#ifndef ESPIPE
++# define ESPIPE -1
++#endif
++ {&quot;Illegal seek&quot;, ESPIPE, &quot;ESPIPE&quot;},
++#ifndef EROFS
++# define EROFS -1
++#endif
++ {&quot;Read-only file system&quot;, EROFS, &quot;EROFS&quot;},
++#ifndef EMLINK
++# define EMLINK -1
++#endif
++ {&quot;Too many links&quot;, EMLINK, &quot;EMLINK&quot;},
++#ifndef EPIPE
++# define EPIPE -1
++#endif
++ {&quot;Broken pipe&quot;, EPIPE, &quot;EPIPE&quot;},
++#ifndef ELOOP
++# define ELOOP -1
++#endif
++ {&quot;Too many levels of symbolic links&quot;,ELOOP, &quot;ELOOP&quot;},
++#ifndef ENAMETOOLONG
++# define ENAMETOOLONG -1
++#endif
++ {&quot;File name too long&quot;, ENAMETOOLONG, &quot;ENAMETOOLONG&quot;},
++
++ {NULL, 0, NULL}
++};
++
++int _SLerrno_errno;
++
++int SLerrno_set_errno (int sys_errno)
++{
++ _SLerrno_errno = sys_errno;
++ return 0;
++}
++
++char *SLerrno_strerror (int sys_errno)
++{
++ Errno_Map_Type *e;
++
++ e = Errno_Map;
++ while (e-&gt;msg != NULL)
++ {
++ if (e-&gt;sys_errno == sys_errno)
++ return e-&gt;msg;
++
++ e++;
++ }
++
++ if (sys_errno == SL_ERRNO_NOT_IMPLEMENTED)
++ return &quot;System call not available for this platform&quot;;
++
++ return &quot;Unknown error&quot;;
++}
++
++static char *intrin_errno_string (int *sys_errno)
++{
++ return SLerrno_strerror (*sys_errno);
++}
++
++int _SLerrno_init (void)
++{
++ static Errno_Map_Type *e;
++
++ if (e != NULL) /* already initialized */
++ return 0;
++
++ if ((-1 == SLadd_intrinsic_function (&quot;errno_string&quot;, (FVOID_STAR) intrin_errno_string,
++ SLANG_STRING_TYPE, 1, SLANG_INT_TYPE))
++ || (-1 == SLadd_intrinsic_variable (&quot;errno&quot;, (VOID_STAR)&amp;_SLerrno_errno, SLANG_INT_TYPE, 1)))
++ return -1;
++
++ e = Errno_Map;
++ while (e-&gt;msg != NULL)
++ {
++ if (-1 == SLadd_intrinsic_variable (e-&gt;symbolic_name, (VOID_STAR) &amp;e-&gt;sys_errno, SLANG_INT_TYPE, 1))
++ return -1;
++ e++;
++ }
++
++ return 0;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slerrno.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slgetkey.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slgetkey.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slgetkey.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,306 @@
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++unsigned int SLang_Input_Buffer_Len = 0;
++unsigned char SLang_Input_Buffer [SL_MAX_INPUT_BUFFER_LEN];
++
++int SLang_Abort_Char = 7;
++int SLang_Ignore_User_Abort = 0;
++
++/* This has the effect of mapping all characters in the range 128-169 to
++ * ESC [ something
++ */
++
++unsigned int SLang_getkey (void)
++{
++ unsigned int imax;
++ unsigned int ch;
++
++ if (SLang_Input_Buffer_Len)
++ {
++ ch = (unsigned int) *SLang_Input_Buffer;
++ SLang_Input_Buffer_Len--;
++ imax = SLang_Input_Buffer_Len;
++
++ SLMEMCPY ((char *) SLang_Input_Buffer,
++ (char *) (SLang_Input_Buffer + 1), imax);
++ }
++ else if (SLANG_GETKEY_ERROR == (ch = _SLsys_getkey ())) return ch;
++
++#if _SLANG_MAP_VTXXX_8BIT
++# if !defined(IBMPC_SYSTEM)
++ if (ch &amp; 0x80)
++ {
++ unsigned char i;
++ i = (unsigned char) (ch &amp; 0x7F);
++ if (i &lt; ' ')
++ {
++ i += 64;
++ SLang_ungetkey (i);
++ ch = 27;
++ }
++ }
++# endif
++#endif
++ return(ch);
++}
++
++int SLang_ungetkey_string (unsigned char *s, unsigned int n)
++{
++ register unsigned char *bmax, *b, *b1;
++ if (SLang_Input_Buffer_Len + n + 3 &gt; SL_MAX_INPUT_BUFFER_LEN)
++ return -1;
++
++ b = SLang_Input_Buffer;
++ bmax = (b - 1) + SLang_Input_Buffer_Len;
++ b1 = bmax + n;
++ while (bmax &gt;= b) *b1-- = *bmax--;
++ bmax = b + n;
++ while (b &lt; bmax) *b++ = *s++;
++ SLang_Input_Buffer_Len += n;
++ return 0;
++}
++
++int SLang_buffer_keystring (unsigned char *s, unsigned int n)
++{
++
++ if (n + SLang_Input_Buffer_Len + 3 &gt; SL_MAX_INPUT_BUFFER_LEN) return -1;
++
++ SLMEMCPY ((char *) SLang_Input_Buffer + SLang_Input_Buffer_Len,
++ (char *) s, n);
++ SLang_Input_Buffer_Len += n;
++ return 0;
++}
++
++int SLang_ungetkey (unsigned char ch)
++{
++ return SLang_ungetkey_string(&amp;ch, 1);
++}
++
++int SLang_input_pending (int tsecs)
++{
++ int n;
++ unsigned char c;
++ if (SLang_Input_Buffer_Len) return (int) SLang_Input_Buffer_Len;
++
++ n = _SLsys_input_pending (tsecs);
++
++ if (n &lt;= 0) return 0;
++
++ c = (unsigned char) SLang_getkey ();
++ SLang_ungetkey_string (&amp;c, 1);
++
++ return n;
++}
++
++void SLang_flush_input (void)
++{
++ int quit = SLKeyBoard_Quit;
++
++ SLang_Input_Buffer_Len = 0;
++ SLKeyBoard_Quit = 0;
++ while (_SLsys_input_pending (0) &gt; 0)
++ {
++ (void) _SLsys_getkey ();
++ /* Set this to 0 because _SLsys_getkey may stuff keyboard buffer if
++ * key sends key sequence (OS/2, DOS, maybe VMS).
++ */
++ SLang_Input_Buffer_Len = 0;
++ }
++ SLKeyBoard_Quit = quit;
++}
++
++#ifdef IBMPC_SYSTEM
++static int Map_To_ANSI;
++int SLgetkey_map_to_ansi (int enable)
++{
++ Map_To_ANSI = enable;
++ return 0;
++}
++
++static int convert_scancode (unsigned int scan,
++ unsigned int shift,
++ int getkey,
++ unsigned int *ret_key)
++{
++ unsigned char buf[16];
++ unsigned char *b;
++ unsigned char end;
++ int is_arrow;
++
++ shift &amp;= (_SLTT_KEY_ALT|_SLTT_KEY_SHIFT|_SLTT_KEY_CTRL);
++
++ b = buf;
++ if (_SLTT_KEY_ALT == shift)
++ {
++ shift = 0;
++ *b++ = 27;
++ }
++ *b++ = 27;
++ *b++ = '[';
++
++ is_arrow = 0;
++ end = '~';
++ if (shift)
++ {
++ if (shift == _SLTT_KEY_CTRL)
++ end = '^';
++ else if (shift == _SLTT_KEY_SHIFT)
++ end = '$';
++ else shift = 0;
++ }
++
++ /* These mappings correspond to what rxvt produces under Linux */
++ switch (scan &amp; 0xFF)
++ {
++ default:
++ return -1;
++
++ case 0x47: /* home */
++ *b++ = '1';
++ break;
++ case 0x48: /* up */
++ end = 'A';
++ is_arrow = 1;
++ break;
++ case 0x49: /* PgUp */
++ *b++ = '5';
++ break;
++ case 0x4B: /* Left */
++ end = 'D';
++ is_arrow = 1;
++ break;
++ case 0x4D: /* Right */
++ end = 'C';
++ is_arrow = 1;
++ break;
++ case 0x4F: /* End */
++ *b++ = '4';
++ break;
++ case 0x50: /* Down */
++ end = 'B';
++ is_arrow = 1;
++ break;
++ case 0x51: /* PgDn */
++ *b++ = '6';
++ break;
++ case 0x52: /* Insert */
++ *b++ = '2';
++ break;
++ case 0x53: /* Delete */
++ *b++ = '3';
++ break;
++ case ';': /* F1 */
++ *b++ = '1';
++ *b++ = '1';
++ break;
++ case '&lt;': /* F2 */
++ *b++ = '1';
++ *b++ = '2';
++ break;
++ case '=': /* F3 */
++ *b++ = '1';
++ *b++ = '3';
++ break;
++
++ case '&gt;': /* F4 */
++ *b++ = '1';
++ *b++ = '4';
++ break;
++
++ case '?': /* F5 */
++ *b++ = '1';
++ *b++ = '5';
++ break;
++
++ case '@': /* F6 */
++ *b++ = '1';
++ *b++ = '7';
++ break;
++
++ case 'A': /* F7 */
++ *b++ = '1';
++ *b++ = '8';
++ break;
++
++ case 'B': /* F8 */
++ *b++ = '1';
++ *b++ = '9';
++ break;
++
++ case 'C': /* F9 */
++ *b++ = '2';
++ *b++ = '0';
++ break;
++
++ case 'D': /* F10 */
++ *b++ = '2';
++ *b++ = '1';
++ break;
++
++ case 0x57: /* F11 */
++ *b++ = '2';
++ *b++ = '3';
++ break;
++
++ case 0x58: /* F12 */
++ *b++ = '2';
++ *b++ = '4';
++ break;
++ }
++
++ if (is_arrow &amp;&amp; shift)
++ {
++ if (shift == _SLTT_KEY_CTRL)
++ end &amp;= 0x1F;
++ else
++ end |= 0x20;
++ }
++ *b++ = end;
++
++ if (getkey)
++ {
++ (void) SLang_buffer_keystring (buf + 1, (unsigned int) (b - (buf + 1)));
++ *ret_key = buf[0];
++ return 0;
++ }
++
++ (void) SLang_buffer_keystring (buf, (unsigned int) (b - buf));
++ return 0;
++}
++
++
++unsigned int _SLpc_convert_scancode (unsigned int scan,
++ unsigned int shift,
++ int getkey)
++{
++ unsigned char buf[16];
++
++ if (Map_To_ANSI)
++ {
++ if (0 == convert_scancode (scan, shift, getkey, &amp;scan))
++ return scan;
++ }
++
++ if (getkey)
++ {
++ buf[0] = scan &amp; 0xFF;
++ SLang_buffer_keystring (buf, 1);
++ return (scan &gt;&gt; 8) &amp; 0xFF;
++ }
++ buf[0] = (scan &gt;&gt; 8) &amp; 0xFF;
++ buf[1] = scan &amp; 0xFF;
++ (void) SLang_buffer_keystring (buf, 2);
++ return 0;
++}
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slgetkey.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slimport.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slimport.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slimport.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,281 @@
++/* Copyright (c) 1998, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++#define SLANG_HAS_DYNAMIC_LINKING 1
++
++#ifndef HAVE_DLFCN_H
++# undef SLANG_HAS_DYNAMIC_LINKING
++# define SLANG_HAS_DYNAMIC_LINKING 0
++#endif
++
++/* The rest of this file is in the if block */
++#if SLANG_HAS_DYNAMIC_LINKING
++
++#ifdef HAVE_DLFCN_H
++# include &lt;dlfcn.h&gt;
++#endif
++
++static char *Module_Path;
++#define MODULE_PATH_ENV_NAME &quot;SLANG_MODULE_PATH&quot;
++#ifndef MODULE_INSTALL_DIR
++# define MODULE_INSTALL_DIR &quot;/usr/local/lib/slang/modules&quot;
++#endif
++
++typedef struct _Handle_Type
++{
++ struct _Handle_Type *next;
++ char *name;
++ VOID_STAR handle;
++ void (*deinit_fun) (void);
++}
++Handle_Type;
++
++static Handle_Type *Handle_List;
++
++static void delete_handles (void)
++{
++ while (Handle_List != NULL)
++ {
++ Handle_Type *next = Handle_List-&gt;next;
++
++ if (Handle_List-&gt;deinit_fun != NULL)
++ Handle_List-&gt;deinit_fun ();
++ (void) dlclose (Handle_List-&gt;handle);
++ SLang_free_slstring (Handle_List-&gt;name);
++ SLfree ((char *)Handle_List);
++ Handle_List = next;
++ }
++}
++
++static Handle_Type *save_handle (char *name, VOID_STAR h, void (*df)(void))
++{
++ Handle_Type *l;
++
++ l = (Handle_Type *) SLmalloc (sizeof (Handle_Type));
++ if (l == NULL)
++ return NULL;
++ memset ((char *) l, 0, sizeof(Handle_Type));
++ if (NULL == (l-&gt;name = SLang_create_slstring (name)))
++ {
++ SLfree ((char *) l);
++ return NULL;
++ }
++ l-&gt;handle = h;
++ l-&gt;next = Handle_List;
++ l-&gt;deinit_fun = df;
++ Handle_List = l;
++
++ return l;
++}
++
++static Handle_Type *find_handle (char *name)
++{
++ Handle_Type *l;
++
++ l = Handle_List;
++ while (l != NULL)
++ {
++ if (0 == strcmp (l-&gt;name, name))
++ break;
++ l = l-&gt;next;
++ }
++ return l;
++}
++
++static int import_from_library (char *name,
++ char *init_fun_name, char *deinit_fun_name,
++ char *file,
++ char *ns,
++ char *ns_init_fun_name)
++{
++ VOID_STAR handle;
++ int (*init_fun) (void);
++ int (*ns_init_fun) (char *);
++ void (*deinit_fun) (void);
++ char *err;
++ char filebuf[1024];
++ char *fun_name;
++
++ if (NULL != find_handle (name))
++ return 0; /* already loaded */
++
++ while (1)
++ {
++#ifndef RTLD_GLOBAL
++# define RTLD_GLOBAL 0
++#endif
++#ifdef RTLD_NOW
++ handle = (VOID_STAR) dlopen (file, RTLD_NOW | RTLD_GLOBAL);
++#else
++ handle = (VOID_STAR) dlopen (file, RTLD_LAZY | RTLD_GLOBAL);
++#endif
++
++ if (handle != NULL)
++ break;
++
++ if (NULL == strchr (file, '/'))
++ {
++ _SLsnprintf (filebuf, sizeof (filebuf), &quot;./%s&quot;, file);
++ file = filebuf;
++ continue;
++ }
++
++ if (NULL == (err = (char *) dlerror ()))
++ err = &quot;UNKNOWN&quot;;
++
++ SLang_verror (SL_INTRINSIC_ERROR,
++ &quot;Error linking to %s: %s&quot;, file, err);
++ return -1;
++ }
++
++ fun_name = ns_init_fun_name;
++ ns_init_fun = (int (*)(char *)) dlsym (handle, fun_name);
++ if (ns_init_fun == NULL)
++ {
++ if ((ns != NULL)
++ &amp;&amp; (0 != strcmp (ns, &quot;Global&quot;)))
++ goto return_error;
++
++ fun_name = init_fun_name;
++ init_fun = (int (*)(void)) dlsym (handle, fun_name);
++ if (init_fun == NULL)
++ goto return_error;
++
++ if (-1 == (*init_fun) ())
++ {
++ dlclose (handle);
++ return -1;
++ }
++ }
++ else if (-1 == (*ns_init_fun) (ns))
++ {
++ dlclose (handle);
++ return -1;
++ }
++
++
++ deinit_fun = (void (*)(void)) dlsym (handle, deinit_fun_name);
++
++ (void) save_handle (name, handle, deinit_fun);
++ return 0;
++
++ return_error:
++
++ if (NULL == (err = (char *) dlerror ()))
++ err = &quot;UNKNOWN&quot;;
++
++ dlclose (handle);
++ SLang_verror (SL_INTRINSIC_ERROR,
++ &quot;Unable to get symbol %s from %s: %s&quot;,
++ name, file, err);
++ return -1;
++}
++
++static void import_module (void)
++{
++ char module_name[256];
++ char symbol_name[256];
++ char deinit_name[256];
++ char ns_init_name[256];
++ char *path;
++ char *file;
++ char *module;
++ char *ns = NULL;
++
++ if (SLang_Num_Function_Args == 2)
++ {
++ if (-1 == SLang_pop_slstring (&amp;ns))
++ return;
++ }
++
++ if (-1 == SLang_pop_slstring (&amp;module))
++ {
++ SLang_free_slstring (ns); /* NULL ok */
++ return;
++ }
++
++ _SLsnprintf (symbol_name, sizeof(symbol_name), &quot;init_%s_module&quot;, module);
++ _SLsnprintf (module_name, sizeof(module_name), &quot;%s-module.so&quot;, module);
++ _SLsnprintf (deinit_name, sizeof(deinit_name), &quot;deinit_%s_module&quot;, module);
++ _SLsnprintf (ns_init_name, sizeof (ns_init_name), &quot;init_%s_module_ns&quot;, module);
++
++ if (Module_Path != NULL)
++ file = SLpath_find_file_in_path (Module_Path, module_name);
++ else file = NULL;
++
++ if ((file == NULL)
++ &amp;&amp; (NULL != (path = getenv (MODULE_PATH_ENV_NAME))))
++ file = SLpath_find_file_in_path (path, module_name);
++
++ if (file == NULL)
++ file = SLpath_find_file_in_path (MODULE_INSTALL_DIR, module_name);
++
++ if (file != NULL)
++ {
++ (void) import_from_library (symbol_name, symbol_name, deinit_name, file, ns, ns_init_name);
++ SLfree (file);
++ }
++ else
++ {
++ /* Maybe the system loader can find it in LD_LIBRARY_PATH */
++ (void) import_from_library (symbol_name, symbol_name, deinit_name, module_name, ns, ns_init_name);
++ }
++}
++
++static void set_import_module_path (char *path)
++{
++ (void) SLang_set_module_load_path (path);
++}
++
++static char *get_import_module_path (void)
++{
++ char *path;
++ if (Module_Path != NULL)
++ return Module_Path;
++ if (NULL != (path = getenv (MODULE_PATH_ENV_NAME)))
++ return path;
++ return MODULE_INSTALL_DIR;
++}
++
++static SLang_Intrin_Fun_Type Module_Intrins [] =
++{
++ MAKE_INTRINSIC_0(&quot;import&quot;, import_module, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_S(&quot;set_import_module_path&quot;, set_import_module_path, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_0(&quot;get_import_module_path&quot;, get_import_module_path, SLANG_STRING_TYPE),
++ SLANG_END_INTRIN_FUN_TABLE
++};
++
++#endif /* SLANG_HAS_DYNAMIC_LINKING */
++
++int SLang_set_module_load_path (char *path)
++{
++#if SLANG_HAS_DYNAMIC_LINKING
++ if (NULL == (path = SLang_create_slstring (path)))
++ return -1;
++ SLang_free_slstring (Module_Path);
++ Module_Path = path;
++ return 0;
++#else
++ (void) path;
++ return -1;
++#endif
++}
++
++int SLang_init_import (void)
++{
++#if SLANG_HAS_DYNAMIC_LINKING
++ (void) SLang_add_cleanup_function (delete_handles);
++ return SLadd_intrin_fun_table (Module_Intrins, &quot;__IMPORT__&quot;);
++#else
++ return 0;
++#endif
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slimport.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slinclud.h
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slinclud.h (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slinclud.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,26 @@
++#ifndef _SLANG_INCLUDE_H_
++#define _SLANG_INCLUDE_H_
++
++#include &quot;config.h&quot;
++#include &quot;sl-feat.h&quot;
++
++#include &lt;stdio.h&gt;
++#include &lt;string.h&gt;
++
++#ifdef HAVE_STDLIB_H
++# include &lt;stdlib.h&gt;
++#endif
++
++#ifdef HAVE_UNISTD_H
++# include &lt;unistd.h&gt;
++#endif
++
++#ifdef HAVE_MALLOC_H
++# include &lt;malloc.h&gt;
++#endif
++
++#ifdef HAVE_MEMORY_H
++# include &lt;memory.h&gt;
++#endif
++
++#endif /* _SLANG_INCLUDE_H_ */
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slinclud.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slintall.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slintall.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slintall.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,27 @@
++/* Copyright (c) 1998, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++int SLang_init_all (void)
++{
++ if ((-1 == SLang_init_slang ())
++ || (-1 == SLang_init_slmath ())
++ || (-1 == SLang_init_posix_dir ())
++ || (-1 == SLang_init_posix_process ())
++ || (-1 == SLang_init_stdio ())
++ || (-1 == SLang_init_array ())
++ || (-1 == SLang_init_posix_io ())
++ || (-1 == SLang_init_ospath ())
++ )
++ return -1;
++
++ return 0;
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slintall.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slistruc.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slistruc.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slistruc.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,218 @@
++/* Intrinsic Structure type implementation */
++/* Copyright (c) 1998, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++/* Intrinsic structures */
++
++typedef struct
++{
++ char *name;
++ VOID_STAR addr;
++ SLang_IStruct_Field_Type *fields;
++}
++_SLang_IStruct_Type;
++
++static SLang_IStruct_Field_Type *istruct_pop_field (char *name, int no_readonly, VOID_STAR *addr)
++{
++ _SLang_IStruct_Type *s;
++ SLang_IStruct_Field_Type *f;
++ char *struct_addr;
++
++ /* Note: There is no need to free this object */
++ if (-1 == SLclass_pop_ptr_obj (SLANG_ISTRUCT_TYPE, (VOID_STAR *) &amp;s))
++ return NULL;
++
++ if (NULL == (struct_addr = *(char **)s-&gt;addr))
++ {
++ SLang_verror (SL_INTRINSIC_ERROR,
++ &quot;%s is NULL. Unable to access field&quot;, s-&gt;name);
++ return NULL;
++ }
++
++ f = s-&gt;fields;
++ while (f-&gt;field_name != NULL)
++ {
++ /* Since both these are slstrings, just test pointers */
++ if (f-&gt;field_name != name)
++ {
++ f++;
++ continue;
++ }
++
++ if (no_readonly &amp;&amp; f-&gt;read_only)
++ {
++ SLang_verror (SL_READONLY_ERROR,
++ &quot;%s.%s is read-only&quot;, s-&gt;name, name);
++ return NULL;
++ }
++
++ *addr = (VOID_STAR) (struct_addr + f-&gt;offset);
++ return f;
++ }
++
++ SLang_verror (SL_TYPE_MISMATCH,
++ &quot;%s has no field called %s&quot;, s-&gt;name, name);
++ return NULL;
++}
++
++static int istruct_sget (unsigned char type, char *name)
++{
++ SLang_IStruct_Field_Type *f;
++ VOID_STAR addr;
++ SLang_Class_Type *cl;
++
++ if (NULL == (f = istruct_pop_field (name, 0, &amp;addr)))
++ return -1;
++
++ type = f-&gt;type;
++ cl = _SLclass_get_class (type);
++
++ return (cl-&gt;cl_push_intrinsic)(f-&gt;type, addr);
++}
++
++static int istruct_sput (unsigned char type, char *name)
++{
++ SLang_IStruct_Field_Type *f;
++ VOID_STAR addr;
++ SLang_Class_Type *cl;
++
++ if (NULL == (f = istruct_pop_field (name, 1, &amp;addr)))
++ return -1;
++
++ type = f-&gt;type;
++ cl = _SLclass_get_class (type);
++
++ return (*cl-&gt;cl_pop) (type, addr);
++}
++
++static int istruct_push (unsigned char type, VOID_STAR ptr)
++{
++ _SLang_IStruct_Type *s;
++
++ s = *(_SLang_IStruct_Type **) ptr;
++ if ((s == NULL)
++ || (s-&gt;addr == NULL)
++ || (*(char **) s-&gt;addr == NULL))
++ return SLang_push_null ();
++
++ return SLclass_push_ptr_obj (type, (VOID_STAR) s);
++}
++
++static int istruct_pop (unsigned char type, VOID_STAR ptr)
++{
++ return SLclass_pop_ptr_obj (type, (VOID_STAR *)ptr);
++}
++
++static void istruct_destroy (unsigned char type, VOID_STAR ptr)
++{
++ (void) type;
++ (void) ptr;
++}
++
++/* Intrinsic struct objects are not stored in a variable. So, the address that
++ * is passed here is actually a pointer to the struct. So, pass its address
++ * to istruct_push since v is a variable. Confusing, n'est pas?
++ */
++static int istruct_push_intrinsic (unsigned char type, VOID_STAR v)
++{
++ return istruct_push (type, (VOID_STAR) &amp;v);
++}
++
++static int init_intrin_struct (void)
++{
++ SLang_Class_Type *cl;
++ static int initialized;
++
++ if (initialized)
++ return 0;
++
++ if (NULL == (cl = SLclass_allocate_class (&quot;IStruct_Type&quot;)))
++ return -1;
++
++ cl-&gt;cl_pop = istruct_pop;
++ cl-&gt;cl_push = istruct_push;
++ cl-&gt;cl_sget = istruct_sget;
++ cl-&gt;cl_sput = istruct_sput;
++ cl-&gt;cl_destroy = istruct_destroy;
++ cl-&gt;cl_push_intrinsic = istruct_push_intrinsic;
++
++ if (-1 == SLclass_register_class (cl, SLANG_ISTRUCT_TYPE, sizeof (_SLang_IStruct_Type *),
++ SLANG_CLASS_TYPE_PTR))
++ return -1;
++
++ initialized = 1;
++ return 0;
++}
++
++int SLadd_istruct_table (SLang_IStruct_Field_Type *fields, VOID_STAR addr, char *name)
++{
++ _SLang_IStruct_Type *s;
++ SLang_IStruct_Field_Type *f;
++
++ if (-1 == init_intrin_struct ())
++ return -1;
++
++ if (addr == NULL)
++ {
++ SLang_verror (SL_INVALID_PARM,
++ &quot;SLadd_istruct_table: address must be non-NULL&quot;);
++ return -1;
++ }
++
++ if (fields == NULL)
++ return -1;
++
++ /* Make the field names slstrings so that only the pointers need to be
++ * compared. However, this table may have been already been added for
++ * another instance of the intrinsic object. So, check for the presence
++ * of an slstring.
++ */
++ f = fields;
++ while (f-&gt;field_name != NULL)
++ {
++ char *fname;
++
++ fname = SLang_create_slstring (f-&gt;field_name);
++ if (fname == NULL)
++ return -1;
++
++ /* Here is the check for the slstring */
++ if (f-&gt;field_name == fname)
++ SLang_free_slstring (fname);
++ else /* replace string literal with slstring */
++ f-&gt;field_name = fname;
++
++ f++;
++ }
++
++ s = (_SLang_IStruct_Type *)SLmalloc (sizeof (_SLang_IStruct_Type));
++ if (s == NULL)
++ return -1;
++
++ memset ((char *)s, 0, sizeof (_SLang_IStruct_Type));
++ if (NULL == (s-&gt;name = SLang_create_slstring (name)))
++ {
++ SLfree ((char *) s);
++ return -1;
++ }
++
++ s-&gt;addr = addr;
++ s-&gt;fields = fields;
++
++ if (-1 == SLadd_intrinsic_variable (name, (VOID_STAR) s, SLANG_ISTRUCT_TYPE, 1))
++ {
++ SLang_free_slstring (s-&gt;name);
++ SLfree ((char *) s);
++ return -1;
++ }
++
++ return 0;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slistruc.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slkeymap.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slkeymap.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slkeymap.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,596 @@
++/* Keymap routines for SLang. The role of these keymap routines is simple:
++ * Just read keys from the tty and return a pointer to a keymap structure.
++ * That is, a keymap is simple a mapping of strings (keys from tty) to
++ * structures. Also included are routines for managing the keymaps.
++ */
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++/* We need a define a rule for upperand lower case chars that user cannot
++ change! This could be a problem for international chars! */
++
++#define UPPER_CASE_KEY(x) (((x) &gt;= 'a') &amp;&amp; ((x) &lt;= 'z') ? (x) - 32 : (x))
++#define LOWER_CASE_KEY(x) (((x) &gt;= 'A') &amp;&amp; ((x) &lt;= 'Z') ? (x) + 32 : (x))
++
++int SLang_Key_TimeOut_Flag = 0; /* true if more than 1 sec has elapsed
++ without key in multikey sequence */
++
++int SLang_Last_Key_Char;
++
++SLKeyMap_List_Type SLKeyMap_List[SLANG_MAX_KEYMAPS];
++
++static SLang_Key_Type *malloc_key(unsigned char *str)
++{
++ SLang_Key_Type *neew;
++
++ if (NULL == (neew = (SLang_Key_Type *) SLmalloc(sizeof(SLang_Key_Type))))
++ return NULL;
++
++ SLMEMSET ((char *) neew, 0, sizeof (SLang_Key_Type));
++ SLMEMCPY((char *) neew-&gt;str, (char *) str, (unsigned int) *str);
++ return(neew);
++}
++
++static SLKeyMap_List_Type *add_keymap (char *name, SLang_Key_Type *map)
++{
++ int i;
++
++ for (i = 0; i &lt; SLANG_MAX_KEYMAPS; i++)
++ {
++ if (SLKeyMap_List[i].keymap == NULL)
++ {
++ if (NULL == (name = SLang_create_slstring (name)))
++ return NULL;
++
++ SLKeyMap_List[i].keymap = map;
++ SLKeyMap_List[i].name = name;
++ return &amp;SLKeyMap_List[i];
++ }
++ }
++ SLang_Error = SL_UNKNOWN_ERROR;
++ /* SLang_doerror (&quot;Keymap quota exceeded.&quot;); */
++ return NULL;
++}
++
++FVOID_STAR SLang_find_key_function(char *name, SLKeyMap_List_Type *keymap)
++{
++ SLKeymap_Function_Type *fp = keymap -&gt; functions;
++ char ch = *name;
++
++ while ((fp != NULL) &amp;&amp; (fp-&gt;name != NULL))
++ {
++ if ((ch == *fp-&gt;name)
++ &amp;&amp; (0 == strcmp(fp-&gt;name, name)))
++ return (FVOID_STAR) fp-&gt;f;
++
++ fp++;
++ }
++ return NULL;
++}
++
++#ifdef REAL_UNIX_SYSTEM
++/* Expand termcap string specified by s. s as passed will have the format:
++ * &quot;XY)...&quot; where XY represents a termcap keyname.
++ */
++static char *process_termcap_string (char *s, char *str, int *ip, int imax)
++{
++ char c[3], *val;
++ int i;
++
++ if ((0 == (c[0] = s[0]))
++ || (0 == (c[1] = s[1]))
++ || (s[2] != ')'))
++ {
++ SLang_verror (SL_SYNTAX_ERROR, &quot;setkey: ^(%s is badly formed&quot;, s);
++ return NULL;
++ }
++ s += 3;
++
++ c[2] = 0;
++ if ((NULL == (val = SLtt_tgetstr (c)))
++ || (*val == 0))
++ return NULL;
++
++ i = *ip;
++ while ((i &lt; imax) &amp;&amp; (*val != 0))
++ {
++ str[i++] = *val++;
++ }
++ *ip = i;
++
++ return s;
++}
++#endif
++
++/* convert things like &quot;^A&quot; to 1 etc... The 0th char is the strlen INCLUDING
++ * the length character itself.
++ */
++char *SLang_process_keystring(char *s)
++{
++ /* FIXME: v2.0, make this thread safe */
++ static char str[32];
++ unsigned char ch;
++ int i;
++
++ i = 1;
++ while (*s != 0)
++ {
++ ch = (unsigned char) *s++;
++ if (ch == '^')
++ {
++ ch = *s++;
++ if (ch == 0)
++ {
++ if (i &lt; 32)
++ str[i++] = '^';
++ break;
++ }
++#ifdef REAL_UNIX_SYSTEM
++ if (ch == '(')
++ {
++ s = process_termcap_string (s, str, &amp;i, 32);
++ if (s == NULL)
++ {
++ str[0] = 1;
++ return str;
++ }
++ continue;
++ }
++#endif
++ ch = UPPER_CASE_KEY(ch);
++ if (ch == '?') ch = 127; else ch = ch - 'A' + 1;
++ }
++
++ if (i &gt;= 32) break;
++ str[i++] = ch;
++ }
++
++ if (i &gt; SLANG_MAX_KEYMAP_KEY_SEQ)
++ {
++ SLang_verror (SL_INVALID_PARM, &quot;Key sequence is too long&quot;);
++ return NULL;
++ }
++
++ str[0] = i;
++ return(str);
++}
++
++static int key_string_compare (unsigned char *a, unsigned char *b, unsigned int len)
++{
++ unsigned char *amax = a + len;
++ int cha, chb, cha_up, chb_up;
++
++ while (a &lt; amax)
++ {
++ cha = *a++;
++ chb = *b++;
++
++ if (cha == chb) continue;
++
++ cha_up = UPPER_CASE_KEY(cha);
++ chb_up = UPPER_CASE_KEY(chb);
++
++ if (cha_up == chb_up)
++ {
++ /* Use case-sensitive result. */
++ return cha - chb;
++ }
++ /* Use case-insensitive result. */
++ return cha_up - chb_up;
++ }
++ return 0;
++}
++
++static char *Define_Key_Error = &quot;Inconsistency in define key.&quot;;
++
++/* This function also performs an insertion in an ordered way. */
++static int find_the_key (char *s, SLKeyMap_List_Type *kml, SLang_Key_Type **keyp)
++{
++ unsigned char ch;
++ unsigned int str_len;
++ SLang_Key_Type *key, *last, *neew;
++ unsigned char *str;
++
++ *keyp = NULL;
++
++ if (NULL == (str = (unsigned char *) SLang_process_keystring(s)))
++ return -2;
++
++ if (1 == (str_len = str[0]))
++ return 0;
++
++ ch = str[1];
++ key = kml-&gt;keymap + ch;
++
++ if (str_len == 2)
++ {
++ if (key-&gt;next != NULL)
++ {
++ SLang_doerror (Define_Key_Error);
++ return -2;
++ }
++
++ if (key-&gt;type == SLKEY_F_INTERPRET)
++ SLang_free_slstring (key-&gt;f.s);
++
++ key-&gt;str[0] = str_len;
++ key-&gt;str[1] = ch;
++
++ *keyp = key;
++ return 0;
++ }
++
++ /* insert the key definition */
++ while (1)
++ {
++ int cmp;
++ unsigned int key_len, len;
++
++ last = key;
++ key = key-&gt;next;
++
++ if ((key != NULL) &amp;&amp; (key-&gt;str != NULL))
++ {
++ len = key_len = key-&gt;str[0];
++ if (len &gt; str_len) len = str_len;
++
++ cmp = key_string_compare (str + 1, key-&gt;str + 1, len - 1);
++
++ if (cmp &gt; 0)
++ continue;
++
++ if (cmp == 0)
++ {
++ if (key_len != str_len)
++ {
++ SLang_doerror (Define_Key_Error);
++ return -2;
++ }
++
++ if (key-&gt;type == SLKEY_F_INTERPRET)
++ SLang_free_slstring (key-&gt;f.s);
++
++ *keyp = key;
++ return 0;
++ }
++ /* Drop to cmp &lt; 0 case */
++ }
++
++ if (NULL == (neew = malloc_key(str))) return -1;
++
++ neew -&gt; next = key;
++ last -&gt; next = neew;
++
++ *keyp = neew;
++ return 0;
++ }
++}
++
++/* returns -2 if inconsistent, -1 if malloc error, 0 upon success */
++int SLkm_define_key (char *s, FVOID_STAR f, SLKeyMap_List_Type *kml)
++{
++ SLang_Key_Type *key;
++ unsigned int type = SLKEY_F_INTRINSIC;
++ int ret;
++
++ ret = find_the_key (s, kml, &amp;key);
++ if ((ret != 0) || (key == NULL))
++ return ret;
++
++ key-&gt;type = type;
++ key-&gt;f.f = f;
++ return 0;
++}
++
++int SLang_define_key (char *s, char *funct, SLKeyMap_List_Type *kml)
++{
++ SLang_Key_Type *key;
++ FVOID_STAR f;
++ int ret;
++
++ ret = find_the_key (s, kml, &amp;key);
++ if ((ret != 0) || (key == NULL))
++ return ret;
++
++ f = SLang_find_key_function(funct, kml);
++
++ if (f == NULL) /* assume interpreted */
++ {
++ char *str = SLang_create_slstring (funct);
++ if (str == NULL) return -1;
++ key-&gt;type = SLKEY_F_INTERPRET;
++ key-&gt;f.s = str;
++ }
++ else
++ {
++ key-&gt;type = SLKEY_F_INTRINSIC;
++ key-&gt;f.f = f;
++ }
++ return 0;
++}
++
++int SLkm_define_keysym (char *s, unsigned int keysym, SLKeyMap_List_Type *kml)
++{
++ SLang_Key_Type *key;
++ int ret;
++
++ ret = find_the_key (s, kml, &amp;key);
++
++ if ((ret != 0) || (key == NULL))
++ return ret;
++
++ key-&gt;type = SLKEY_F_KEYSYM;
++ key-&gt;f.keysym = keysym;
++ return 0;
++}
++
++SLang_Key_Type *SLang_do_key(SLKeyMap_List_Type *kml, int (*getkey)(void))
++{
++ register SLang_Key_Type *key, *next, *kmax;
++ unsigned int len;
++ unsigned char input_ch;
++ register unsigned char chup, chlow;
++ unsigned char key_ch = 0;
++
++ SLang_Last_Key_Char = (*getkey)();
++ SLang_Key_TimeOut_Flag = 0;
++
++ if (SLANG_GETKEY_ERROR == (unsigned int) SLang_Last_Key_Char)
++ return NULL;
++
++ input_ch = (unsigned char) SLang_Last_Key_Char;
++
++ key = (SLang_Key_Type *) &amp;((kml-&gt;keymap)[input_ch]);
++
++ /* if the next one is null, then we know this MAY be it. */
++ while (key-&gt;next == NULL)
++ {
++ if (key-&gt;type != 0)
++ return key;
++
++ /* Try its opposite case counterpart */
++ chlow = LOWER_CASE_KEY(input_ch);
++ if (input_ch == chlow)
++ input_ch = UPPER_CASE_KEY(input_ch);
++
++ key = kml-&gt;keymap + input_ch;
++ if (key-&gt;type == 0)
++ return NULL;
++ }
++
++ /* It appears to be a prefix character in a key sequence. */
++
++ len = 1; /* already read one character */
++ key = key-&gt;next; /* Now we are in the key list */
++ kmax = NULL; /* set to end of list */
++
++ while (1)
++ {
++ SLang_Key_TimeOut_Flag = 1;
++ SLang_Last_Key_Char = (*getkey)();
++ SLang_Key_TimeOut_Flag = 0;
++
++ len++;
++
++ if ((SLANG_GETKEY_ERROR == (unsigned int) SLang_Last_Key_Char)
++ || SLKeyBoard_Quit)
++ break;
++
++ input_ch = (unsigned char) SLang_Last_Key_Char;
++
++ chup = UPPER_CASE_KEY(input_ch); chlow = LOWER_CASE_KEY(input_ch);
++
++ while (key != kmax)
++ {
++ if (key-&gt;str[0] &gt; len)
++ {
++ key_ch = key-&gt;str[len];
++ if (chup == UPPER_CASE_KEY(key_ch))
++ break;
++ }
++ key = key-&gt;next;
++ }
++
++ if (key == kmax) break;
++
++ /* If the input character is lowercase, check to see if there is
++ * a lowercase match. If so, set key to it. Note: the
++ * algorithm assumes the sorting performed by key_string_compare.
++ */
++ if (input_ch != key_ch)
++ {
++ next = key-&gt;next;
++ while (next != kmax)
++ {
++ if (next-&gt;str[0] &gt; len)
++ {
++ unsigned char next_ch = next-&gt;str[len];
++ if (next_ch == input_ch)
++ {
++ key = next;
++ break;
++ }
++ if (next_ch != chup)
++ break;
++ }
++ next = next-&gt;next;
++ }
++ }
++
++ /* Ok, we found the first position of a possible match. If it
++ * is exact, we are done.
++ */
++ if ((unsigned int) key-&gt;str[0] == len + 1)
++ return key;
++
++ /* Apparantly, there are some ambiguities. Read next key to resolve
++ * the ambiguity. Adjust kmax to encompass ambiguities.
++ */
++
++ next = key-&gt;next;
++ while (next != kmax)
++ {
++ if ((unsigned int) next-&gt;str[0] &gt; len)
++ {
++ key_ch = next-&gt;str[len];
++ if (chup != UPPER_CASE_KEY(key_ch))
++ break;
++ }
++ next = next-&gt;next;
++ }
++ kmax = next;
++ }
++
++ return NULL;
++}
++
++void SLang_undefine_key(char *s, SLKeyMap_List_Type *kml)
++{
++ int n, i;
++ SLang_Key_Type *key, *next, *last, *key_root, *keymap;
++ unsigned char *str;
++
++ keymap = kml -&gt; keymap;
++ if (NULL == (str = (unsigned char *) SLang_process_keystring(s)))
++ return;
++
++ if (0 == (n = *str++ - 1)) return;
++ i = *str;
++
++ last = key_root = (SLang_Key_Type *) &amp;(keymap[i]);
++ key = key_root-&gt;next;
++
++ while (key != NULL)
++ {
++ next = key-&gt;next;
++ if (0 == SLMEMCMP ((char *)(key-&gt;str + 1), (char *) str, n))
++ {
++ if (key-&gt;type == SLKEY_F_INTERPRET)
++ SLang_free_slstring (key-&gt;f.s);
++
++ SLfree((char *) key);
++ last-&gt;next = next;
++ }
++ else last = key;
++ key = next;
++ }
++
++ if (n == 1)
++ {
++ *key_root-&gt;str = 0;
++ key_root-&gt;f.f = NULL;
++ key_root-&gt;type = 0;
++ }
++}
++
++char *SLang_make_keystring(unsigned char *s)
++{
++ static char buf [3 * SLANG_MAX_KEYMAP_KEY_SEQ + 1];
++ char *b;
++ int n;
++
++ n = *s++ - 1;
++
++ if (n &gt; SLANG_MAX_KEYMAP_KEY_SEQ)
++ {
++ SLang_verror (SL_INVALID_PARM, &quot;Key sequence is too long&quot;);
++ return NULL;
++ }
++
++ b = buf;
++ while (n--)
++ {
++ if (*s &lt; 32)
++ {
++ *b++ = '^';
++ *b++ = *s + 'A' - 1;
++ }
++ else *b++ = *s;
++ s++;
++ }
++ *b = 0;
++ return(buf);
++}
++
++static SLang_Key_Type *copy_keymap(SLKeyMap_List_Type *kml)
++{
++ int i;
++ SLang_Key_Type *neew, *old, *new_root, *km;
++
++ if (NULL == (new_root = (SLang_Key_Type *) SLcalloc(256, sizeof(SLang_Key_Type))))
++ return NULL;
++
++ if (kml == NULL) return new_root;
++ km = kml-&gt;keymap;
++
++ for (i = 0; i &lt; 256; i++)
++ {
++ old = &amp;(km[i]);
++ neew = &amp;(new_root[i]);
++
++ if (old-&gt;type == SLKEY_F_INTERPRET)
++ neew-&gt;f.s = SLang_create_slstring (old-&gt;f.s);
++ else
++ neew-&gt;f.f = old-&gt;f.f;
++
++ neew-&gt;type = old-&gt;type;
++ SLMEMCPY((char *) neew-&gt;str, (char *) old-&gt;str, (unsigned int) *old-&gt;str);
++
++ old = old-&gt;next;
++ while (old != NULL)
++ {
++ neew-&gt;next = malloc_key((unsigned char *) old-&gt;str);
++ neew = neew-&gt;next;
++
++ if (old-&gt;type == SLKEY_F_INTERPRET)
++ neew-&gt;f.s = SLang_create_slstring (old-&gt;f.s);
++ else
++ neew-&gt;f.f = old-&gt;f.f;
++
++ neew-&gt;type = old-&gt;type;
++ old = old-&gt;next;
++ }
++ neew-&gt;next = NULL;
++ }
++ return(new_root);
++}
++
++SLKeyMap_List_Type *SLang_create_keymap(char *name, SLKeyMap_List_Type *map)
++{
++ SLang_Key_Type *neew;
++ SLKeyMap_List_Type *new_map;
++
++ if ((NULL == (neew = copy_keymap(map)))
++ || (NULL == (new_map = add_keymap(name, neew)))) return NULL;
++
++ if (map != NULL) new_map -&gt; functions = map -&gt; functions;
++
++ return new_map;
++}
++
++SLKeyMap_List_Type *SLang_find_keymap(char *name)
++{
++ SLKeyMap_List_Type *kmap, *kmap_max;
++
++ kmap = SLKeyMap_List;
++ kmap_max = kmap + SLANG_MAX_KEYMAPS;
++
++ while (kmap &lt; kmap_max)
++ {
++ if ((kmap-&gt;name != NULL)
++ &amp;&amp; (0 == strcmp (kmap-&gt;name, name)))
++ return kmap;
++
++ kmap++;
++ }
++ return NULL;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slkeymap.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slkeypad.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slkeypad.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slkeypad.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,163 @@
++/* Copyright (c) 1998, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++static SLKeyMap_List_Type *Keymap_List;
++
++int SLkp_init (void)
++{
++ char esc_seq[10];
++ int i;
++
++ if (NULL == (Keymap_List = SLang_create_keymap (&quot;_SLKeypad&quot;, NULL)))
++ return -1;
++
++ esc_seq[1] = 0;
++ for (i = 1; i &lt; 256; i++)
++ {
++ esc_seq[0] = (char) i;
++ SLkm_define_keysym (esc_seq, i, Keymap_List);
++ }
++
++ /* Now add most common ones. */
++#ifndef IBMPC_SYSTEM
++ SLkm_define_keysym (&quot;^@&quot;, 0, Keymap_List);
++
++ SLkm_define_keysym (&quot;\033[A&quot;, SL_KEY_UP, Keymap_List);
++ SLkm_define_keysym (&quot;\033OA&quot;, SL_KEY_UP, Keymap_List);
++ SLkm_define_keysym (&quot;\033[B&quot;, SL_KEY_DOWN, Keymap_List);
++ SLkm_define_keysym (&quot;\033OB&quot;, SL_KEY_DOWN, Keymap_List);
++ SLkm_define_keysym (&quot;\033[C&quot;, SL_KEY_RIGHT, Keymap_List);
++ SLkm_define_keysym (&quot;\033OC&quot;, SL_KEY_RIGHT, Keymap_List);
++ SLkm_define_keysym (&quot;\033[D&quot;, SL_KEY_LEFT, Keymap_List);
++ SLkm_define_keysym (&quot;\033OD&quot;, SL_KEY_LEFT, Keymap_List);
++ SLkm_define_keysym (&quot;\033[2~&quot;, SL_KEY_IC, Keymap_List);
++ SLkm_define_keysym (&quot;\033[7~&quot;, SL_KEY_HOME, Keymap_List);
++ SLkm_define_keysym (&quot;\033[5~&quot;, SL_KEY_PPAGE, Keymap_List);
++ SLkm_define_keysym (&quot;\033[6~&quot;, SL_KEY_NPAGE, Keymap_List);
++ SLkm_define_keysym (&quot;\033[8~&quot;, SL_KEY_END, Keymap_List);
++ SLkm_define_keysym (&quot;\033[3~&quot;, SL_KEY_DELETE, Keymap_List);
++#else
++ /* Note: This will not work if SLgetkey_map_to_ansi (1) has
++ * been called.
++ */
++ SLkm_define_keysym (&quot;^@\x48&quot;, SL_KEY_UP, Keymap_List );
++ SLkm_define_keysym (&quot;^@\x50&quot;, SL_KEY_DOWN, Keymap_List );
++ SLkm_define_keysym (&quot;^@\x4d&quot;, SL_KEY_RIGHT, Keymap_List );
++ SLkm_define_keysym (&quot;^@\x4b&quot;, SL_KEY_LEFT, Keymap_List );
++ SLkm_define_keysym (&quot;^@\x47&quot;, SL_KEY_HOME, Keymap_List );
++ SLkm_define_keysym (&quot;^@\x49&quot;, SL_KEY_PPAGE, Keymap_List );
++ SLkm_define_keysym (&quot;^@\x51&quot;, SL_KEY_NPAGE, Keymap_List );
++ SLkm_define_keysym (&quot;^@\x4f&quot;, SL_KEY_END, Keymap_List );
++ SLkm_define_keysym (&quot;^@\x52&quot;, SL_KEY_IC, Keymap_List );
++ SLkm_define_keysym (&quot;^@\x53&quot;, SL_KEY_DELETE, Keymap_List );
++
++ SLkm_define_keysym (&quot;\xE0\x48&quot;, SL_KEY_UP, Keymap_List );
++ SLkm_define_keysym (&quot;\xE0\x50&quot;, SL_KEY_DOWN, Keymap_List );
++ SLkm_define_keysym (&quot;\xE0\x4d&quot;, SL_KEY_RIGHT, Keymap_List );
++ SLkm_define_keysym (&quot;\xE0\x4b&quot;, SL_KEY_LEFT, Keymap_List );
++ SLkm_define_keysym (&quot;\xE0\x47&quot;, SL_KEY_HOME, Keymap_List );
++ SLkm_define_keysym (&quot;\xE0\x49&quot;, SL_KEY_PPAGE, Keymap_List );
++ SLkm_define_keysym (&quot;\xE0\x51&quot;, SL_KEY_NPAGE, Keymap_List );
++ SLkm_define_keysym (&quot;\xE0\x4f&quot;, SL_KEY_END, Keymap_List );
++ SLkm_define_keysym (&quot;\xE0\x52&quot;, SL_KEY_IC, Keymap_List );
++ SLkm_define_keysym (&quot;\xE0\x53&quot;, SL_KEY_DELETE, Keymap_List );
++
++ strcpy (esc_seq, &quot;^@ &quot;); /* guarantees esc_seq[3] = 0. */
++
++ for (i = 0x3b; i &lt; 0x45; i++)
++ {
++ esc_seq [2] = i;
++ SLkm_define_keysym (esc_seq, SL_KEY_F(i - 0x3a), Keymap_List);
++ }
++ esc_seq[2] = 0x57; SLkm_define_keysym (esc_seq, SL_KEY_F(11), Keymap_List);
++ esc_seq[2] = 0x58; SLkm_define_keysym (esc_seq, SL_KEY_F(12), Keymap_List);
++#endif
++
++#ifdef REAL_UNIX_SYSTEM
++ strcpy (esc_seq, &quot;^(kX)&quot;);
++ for (i = 0; i &lt;= 9; i++)
++ {
++ esc_seq[3] = '0' + i;
++ SLkm_define_keysym (esc_seq, SL_KEY_F(i), Keymap_List);
++ }
++ SLkm_define_keysym (&quot;^(k;)&quot;, SL_KEY_F(10), Keymap_List);
++
++ SLkm_define_keysym (&quot;^(ku)&quot;, SL_KEY_UP, Keymap_List);
++ SLkm_define_keysym (&quot;^(kd)&quot;, SL_KEY_DOWN, Keymap_List);
++ SLkm_define_keysym (&quot;^(kl)&quot;, SL_KEY_LEFT, Keymap_List);
++ SLkm_define_keysym (&quot;^(kr)&quot;, SL_KEY_RIGHT, Keymap_List);
++ SLkm_define_keysym (&quot;^(kP)&quot;, SL_KEY_PPAGE, Keymap_List);
++ SLkm_define_keysym (&quot;^(kN)&quot;, SL_KEY_NPAGE, Keymap_List);
++ SLkm_define_keysym (&quot;^(kh)&quot;, SL_KEY_HOME, Keymap_List);
++ SLkm_define_keysym (&quot;^(@7)&quot;, SL_KEY_END, Keymap_List);
++ SLkm_define_keysym (&quot;^(K1)&quot;, SL_KEY_A1, Keymap_List);
++ SLkm_define_keysym (&quot;^(K3)&quot;, SL_KEY_A3, Keymap_List);
++ SLkm_define_keysym (&quot;^(K2)&quot;, SL_KEY_B2, Keymap_List);
++ SLkm_define_keysym (&quot;^(K4)&quot;, SL_KEY_C1, Keymap_List);
++ SLkm_define_keysym (&quot;^(K5)&quot;, SL_KEY_C3, Keymap_List);
++ SLkm_define_keysym (&quot;^(%0)&quot;, SL_KEY_REDO, Keymap_List);
++ SLkm_define_keysym (&quot;^(&amp;8)&quot;, SL_KEY_UNDO, Keymap_List);
++ SLkm_define_keysym (&quot;^(kb)&quot;, SL_KEY_BACKSPACE, Keymap_List);
++ SLkm_define_keysym (&quot;^(@8)&quot;, SL_KEY_ENTER, Keymap_List);
++ SLkm_define_keysym (&quot;^(kD)&quot;, SL_KEY_DELETE, Keymap_List);
++#endif
++
++ if (SLang_Error)
++ return -1;
++ return 0;
++}
++
++int SLkp_getkey (void)
++{
++ SLang_Key_Type *key;
++
++ key = SLang_do_key (Keymap_List, (int (*)(void)) SLang_getkey);
++ if ((key == NULL) || (key-&gt;type != SLKEY_F_KEYSYM))
++ {
++ SLang_flush_input ();
++ return SL_KEY_ERR;
++ }
++
++ return key-&gt;f.keysym;
++}
++
++int SLkp_define_keysym (char *keystr, unsigned int keysym)
++{
++ if (SLkm_define_keysym (keystr, keysym, Keymap_List) &lt; 0)
++ return -1;
++
++ return 0;
++}
++
++#if 0
++int main (int argc, char **argv)
++{
++ int ch;
++
++ SLtt_get_terminfo ();
++
++ if (-1 == SLkp_init ())
++ return 1;
++
++ SLang_init_tty (-1, 0, 0);
++
++ while ('q' != (ch = SLkp_getkey ()))
++ {
++ fprintf (stdout, &quot;Keycode = %d\r\n&quot;, ch);
++ fflush (stdout);
++ }
++
++ SLang_reset_tty ();
++
++ return 0;
++}
++#endif
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slkeypad.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/sllimits.h
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/sllimits.h (rev 0)
++++ drakx/trunk/mdk-stage1/slang/sllimits.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,64 @@
++/* Copyright (c) 1998, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++/* sllimits.h */
++
++/* slstring.c: Size of the hash table used for strings (prime numbers) */
++#ifdef __MSDOS_16BIT__
++# define SLSTRING_HASH_TABLE_SIZE 601
++# define SLASSOC_HASH_TABLE_SIZE 601
++#else
++# define SLSTRING_HASH_TABLE_SIZE 2909
++# define SLASSOC_HASH_TABLE_SIZE 2909
++#endif
++
++/* slang.c: maximum size of run time stack */
++#ifdef __MSDOS_16BIT__
++# define SLANG_MAX_STACK_LEN 500
++#else
++# define SLANG_MAX_STACK_LEN 2500
++#endif
++
++/* slang.c: This sets the size on the depth of function calls */
++#ifdef __MSDOS_16BIT__
++# define SLANG_MAX_RECURSIVE_DEPTH 50
++#else
++# define SLANG_MAX_RECURSIVE_DEPTH 250
++#endif
++
++/* slang.c: Size of the stack used for local variables */
++#ifdef __MSDOS_16BIT__
++# define SLANG_MAX_LOCAL_STACK 200
++#else
++# define SLANG_MAX_LOCAL_STACK 1024
++#endif
++
++/* slang.c: The size of the hash table used for local and global objects.
++ * These should be prime numbers.
++ */
++#define SLGLOBALS_HASH_TABLE_SIZE 2909
++#define SLLOCALS_HASH_TABLE_SIZE 73
++#define SLSTATIC_HASH_TABLE_SIZE 73
++
++/* Size of the keyboard buffer use by the ungetkey routines */
++#ifdef __MSDOS_16BIT__
++# define SL_MAX_INPUT_BUFFER_LEN 40
++#else
++# define SL_MAX_INPUT_BUFFER_LEN 1024
++#endif
++
++/* Maximum number of nested switch statements */
++#define SLANG_MAX_NESTED_SWITCH 10
++
++/* Size of the block stack (used in byte-compiling) */
++#define SLANG_MAX_BLOCK_STACK_LEN 50
++
++/* slfile.c: Max number of open file pointers */
++#ifdef __MSDOS_16BIT__
++# define SL_MAX_FILES 32
++#else
++# define SL_MAX_FILES 256
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/sllimits.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slmalloc.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slmalloc.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slmalloc.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,165 @@
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++#include &quot;slinclud.h&quot;
++
++#ifdef SL_MALLOC_DEBUG
++# undef SL_MALLOC_DEBUG
++#endif
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++#ifdef __alpha
++# define Chunk 8
++#else
++# define Chunk 4
++#endif
++
++static long Total_Allocated;
++static long Max_Single_Allocation;
++static long Max_Allocated;
++/* #define SLDEBUG_DOUT */
++
++#ifdef SLDEBUG_DOUT
++static FILE *dout;
++#endif
++
++void SLmalloc_dump_statistics (void)
++{
++#ifdef SLDEBUG_DOUT
++ fflush (dout);
++#endif
++ fprintf (stderr, &quot;Total Allocated: %ld\nHighest single allocation: %ld\nHighest Total Allocated:%ld\n&quot;,
++ Total_Allocated, Max_Single_Allocation, Max_Allocated);
++}
++
++static void register_at_exit_fun (void)
++{
++ static int is_registered = 0;
++ if (is_registered)
++ return;
++ is_registered = 1;
++
++#ifdef SLDEBUG_DOUT
++ if (dout == NULL) dout = fopen (&quot;malloc.out&quot;, &quot;w&quot;);
++#endif
++ SLang_add_cleanup_function (SLmalloc_dump_statistics);
++}
++
++static void fixup (unsigned char *p, unsigned long n, char *what)
++{
++ register_at_exit_fun ();
++
++ p += Chunk;
++ *(p - 4)= (unsigned char) ((n &gt;&gt; 24) &amp; 0xFF);
++ *(p - 3) = (unsigned char) ((n &gt;&gt; 16) &amp; 0xFF);
++ *(p - 2) = (unsigned char) ((n &gt;&gt; 8) &amp; 0xFF);
++ *(p - 1) = (unsigned char) (n &amp; 0xFF);
++ *(p + (int) n) = 27;
++ *(p + (int) (n + 1)) = 182;
++ *(p + (int) (n + 2)) = 81;
++ *(p + (int) (n + 3)) = 86;
++ Total_Allocated += (long) n;
++ if (Total_Allocated &gt; Max_Allocated) Max_Allocated = Total_Allocated;
++ if ((long) n &gt; Max_Single_Allocation)
++ Max_Single_Allocation = (long) n;
++
++#ifdef SLDEBUG_DOUT
++ fprintf (dout, &quot;ALLOC: %s\t%p %ld\n&quot;, what, p, (long) n);
++#else
++ (void) what;
++#endif
++}
++
++static void SLmalloc_doerror (char *buf)
++{
++ SLang_doerror (buf);
++}
++
++static int check_memory (unsigned char *p, char *what)
++{
++ char buf[128];
++ unsigned long n;
++
++ register_at_exit_fun ();
++
++ n = ((unsigned long) *(p - 4)) &lt;&lt; 24;
++ n |= ((unsigned long) *(p - 3)) &lt;&lt; 16;
++ n |= ((unsigned long) *(p - 2)) &lt;&lt; 8;
++ n |= (unsigned long) *(p - 1);
++
++ if (n == 0xFFFFFFFFUL)
++ {
++ sprintf (buf, &quot;%s: %p: Already FREE! Abort NOW.&quot;, what, (void*)p - Chunk);
++ SLmalloc_doerror (buf);
++ return -1;
++ }
++
++ if ((*(p + (int) n) != 27)
++ || (*(p + (int) (n + 1)) != 182)
++ || (*(p + (int) (n + 2)) != 81)
++ || (*(p + (int) (n + 3)) != 86))
++ {
++ sprintf (buf, &quot;\007%s: %p: Memory corrupt! Abort NOW.&quot;, what, (void*)p);
++ SLmalloc_doerror (buf);
++ return -1;
++ }
++
++ *(p - 4) = *(p - 3) = *(p - 2) = *(p - 1) = 0xFF;
++
++ Total_Allocated -= (long) n;
++ if (Total_Allocated &lt; 0)
++ {
++ sprintf (buf, &quot;\007%s: %p\nFreed %ld, Allocated is: %ld!\n&quot;,
++ what, (void*)p, (long) n, Total_Allocated);
++ SLang_doerror (buf);
++ }
++#ifdef SLDEBUG_DOUT
++ fprintf (dout, &quot;FREE: %s:\t%p %ld\n&quot;, what, p, (long) n);
++#endif
++ return 0;
++}
++
++void SLdebug_free (char *p)
++{
++ if (p == NULL) return;
++ if (-1 == check_memory ((unsigned char *) p, &quot;FREE&quot;)) return;
++
++ SLFREE (p - Chunk);
++}
++
++char *SLdebug_malloc (unsigned long n)
++{
++ char *p;
++
++ if ((p = (char *) SLMALLOC (n + 2 * Chunk)) == NULL) return NULL;
++
++ fixup ((unsigned char *) p, n, &quot;MALLOC&quot;);
++ return p + Chunk;
++}
++
++char *SLdebug_realloc (char *p, unsigned long n)
++{
++ if (-1 == check_memory ((unsigned char *) p, &quot;REALLOC&quot;)) return NULL;
++ if ((p = (char *) SLREALLOC (p - Chunk, n + 2 * Chunk)) == NULL) return NULL;
++ fixup ((unsigned char *) p, n, &quot;REALLOC&quot;);
++ return p + Chunk;
++}
++
++char *SLdebug_calloc (unsigned long n, unsigned long size)
++{
++ char *p;
++ int m;
++
++ /* This is tough -- hope this is a good assumption!! */
++ if (size &gt;= Chunk) m = 1; else m = Chunk;
++
++ if ((p = (char *) SLCALLOC (n + m + m, size)) == NULL) return NULL;
++ fixup ((unsigned char *) p, size * n, &quot;CALLOC&quot;);
++ return p + Chunk;
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slmalloc.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slmath.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slmath.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slmath.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,565 @@
++/* sin, cos, etc, for S-Lang */
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++
++#include &lt;math.h&gt;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++#ifdef PI
++# undef PI
++#endif
++#define PI 3.14159265358979323846264338327950288
++
++#if defined(__unix__)
++#include &lt;signal.h&gt;
++#include &lt;errno.h&gt;
++
++#define SIGNAL SLsignal
++
++static void math_floating_point_exception (int sig)
++{
++ sig = errno;
++ if (SLang_Error == 0) SLang_Error = SL_FLOATING_EXCEPTION;
++ (void) SIGNAL (SIGFPE, math_floating_point_exception);
++ errno = sig;
++}
++#endif
++
++double SLmath_hypot (double x, double y)
++{
++ double fr, fi, ratio;
++
++ fr = fabs(x);
++ fi = fabs(y);
++
++ if (fr &gt; fi)
++ {
++ ratio = y / x;
++ x = fr * sqrt (1.0 + ratio * ratio);
++ }
++ else if (fi == 0.0) x = 0.0;
++ else
++ {
++ ratio = x / y;
++ x = fi * sqrt (1.0 + ratio * ratio);
++ }
++
++ return x;
++}
++
++/* usage here is a1 a2 ... an n x ==&gt; a1x^n + a2 x ^(n - 1) + ... + an */
++static double math_poly (void)
++{
++ int n;
++ double xn = 1.0, sum = 0.0;
++ double an, x;
++
++ if ((SLang_pop_double(&amp;x, NULL, NULL))
++ || (SLang_pop_integer(&amp;n))) return(0.0);
++
++ while (n-- &gt; 0)
++ {
++ if (SLang_pop_double(&amp;an, NULL, NULL)) break;
++ sum += an * xn;
++ xn = xn * x;
++ }
++ return (double) sum;
++}
++
++static int double_math_op_result (int op, unsigned char a, unsigned char *b)
++{
++ (void) op;
++
++ if (a != SLANG_FLOAT_TYPE)
++ *b = SLANG_DOUBLE_TYPE;
++ else
++ *b = a;
++
++ return 1;
++}
++
++#ifdef HAVE_ASINH
++# define ASINH_FUN asinh
++#else
++# define ASINH_FUN my_asinh
++static double my_asinh (double x)
++{
++ return log (x + sqrt (x*x + 1));
++}
++#endif
++#ifdef HAVE_ACOSH
++# define ACOSH_FUN acosh
++#else
++# define ACOSH_FUN my_acosh
++static double my_acosh (double x)
++{
++ return log (x + sqrt(x*x - 1)); /* x &gt;= 1 */
++}
++#endif
++#ifdef HAVE_ATANH
++# define ATANH_FUN atanh
++#else
++# define ATANH_FUN my_atanh
++static double my_atanh (double x)
++{
++ return 0.5 * log ((1.0 + x)/(1.0 - x)); /* 0 &lt;= x^2 &lt; 1 */
++}
++#endif
++
++static int double_math_op (int op,
++ unsigned char type, VOID_STAR ap, unsigned int na,
++ VOID_STAR bp)
++{
++ double *a, *b;
++ unsigned int i;
++ double (*fun) (double);
++
++ (void) type;
++ a = (double *) ap;
++ b = (double *) bp;
++
++ switch (op)
++ {
++ default:
++ return 0;
++
++ case SLMATH_SINH:
++ fun = sinh;
++ break;
++ case SLMATH_COSH:
++ fun = cosh;
++ break;
++ case SLMATH_TANH:
++ fun = tanh;
++ break;
++ case SLMATH_TAN:
++ fun = tan;
++ break;
++ case SLMATH_ASIN:
++ fun = asin;
++ break;
++ case SLMATH_ACOS:
++ fun = acos;
++ break;
++ case SLMATH_ATAN:
++ fun = atan;
++ break;
++ case SLMATH_EXP:
++ fun = exp;
++ break;
++ case SLMATH_LOG:
++ fun = log;
++ break;
++ case SLMATH_LOG10:
++ fun = log10;
++ break;
++ case SLMATH_SQRT:
++ fun = sqrt;
++ break;
++ case SLMATH_SIN:
++ fun = sin;
++ break;
++ case SLMATH_COS:
++ fun = cos;
++ break;
++
++ case SLMATH_ASINH:
++ fun = ASINH_FUN;
++ break;
++ case SLMATH_ATANH:
++ fun = ATANH_FUN;
++ break;
++ case SLMATH_ACOSH:
++ fun = ACOSH_FUN;
++ break;
++
++ case SLMATH_CONJ:
++ case SLMATH_REAL:
++ for (i = 0; i &lt; na; i++)
++ b[i] = a[i];
++ return 1;
++ case SLMATH_IMAG:
++ for (i = 0; i &lt; na; i++)
++ b[i] = 0.0;
++ return 1;
++ }
++
++ for (i = 0; i &lt; na; i++)
++ b[i] = (*fun) (a[i]);
++
++ return 1;
++}
++
++static int float_math_op (int op,
++ unsigned char type, VOID_STAR ap, unsigned int na,
++ VOID_STAR bp)
++{
++ float *a, *b;
++ unsigned int i;
++ double (*fun) (double);
++
++ (void) type;
++ a = (float *) ap;
++ b = (float *) bp;
++
++
++ switch (op)
++ {
++ default:
++ return 0;
++
++ case SLMATH_SINH:
++ fun = sinh;
++ break;
++ case SLMATH_COSH:
++ fun = cosh;
++ break;
++ case SLMATH_TANH:
++ fun = tanh;
++ break;
++ case SLMATH_TAN:
++ fun = tan;
++ break;
++ case SLMATH_ASIN:
++ fun = asin;
++ break;
++ case SLMATH_ACOS:
++ fun = acos;
++ break;
++ case SLMATH_ATAN:
++ fun = atan;
++ break;
++ case SLMATH_EXP:
++ fun = exp;
++ break;
++ case SLMATH_LOG:
++ fun = log;
++ break;
++ case SLMATH_LOG10:
++ fun = log10;
++ break;
++ case SLMATH_SQRT:
++ fun = sqrt;
++ break;
++ case SLMATH_SIN:
++ fun = sin;
++ break;
++ case SLMATH_COS:
++ fun = cos;
++ break;
++
++ case SLMATH_ASINH:
++ fun = ASINH_FUN;
++ break;
++ case SLMATH_ATANH:
++ fun = ATANH_FUN;
++ break;
++ case SLMATH_ACOSH:
++ fun = ACOSH_FUN;
++ break;
++
++ case SLMATH_CONJ:
++ case SLMATH_REAL:
++ for (i = 0; i &lt; na; i++)
++ b[i] = a[i];
++ return 1;
++ case SLMATH_IMAG:
++ for (i = 0; i &lt; na; i++)
++ b[i] = 0.0;
++ return 1;
++ }
++
++ for (i = 0; i &lt; na; i++)
++ b[i] = (float) (*fun) ((double) a[i]);
++
++ return 1;
++}
++
++static int generic_math_op (int op,
++ unsigned char type, VOID_STAR ap, unsigned int na,
++ VOID_STAR bp)
++{
++ double *b;
++ unsigned int i;
++ SLang_To_Double_Fun_Type to_double;
++ double (*fun) (double);
++ unsigned int da;
++ char *a;
++
++ if (NULL == (to_double = SLarith_get_to_double_fun (type, &amp;da)))
++ return 0;
++
++ b = (double *) bp;
++ a = (char *) ap;
++
++ switch (op)
++ {
++ default:
++ return 0;
++
++ case SLMATH_SINH:
++ fun = sinh;
++ break;
++ case SLMATH_COSH:
++ fun = cosh;
++ break;
++ case SLMATH_TANH:
++ fun = tanh;
++ break;
++ case SLMATH_TAN:
++ fun = tan;
++ break;
++ case SLMATH_ASIN:
++ fun = asin;
++ break;
++ case SLMATH_ACOS:
++ fun = acos;
++ break;
++ case SLMATH_ATAN:
++ fun = atan;
++ break;
++ case SLMATH_EXP:
++ fun = exp;
++ break;
++ case SLMATH_LOG:
++ fun = log;
++ break;
++ case SLMATH_LOG10:
++ fun = log10;
++ break;
++ case SLMATH_SQRT:
++ fun = sqrt;
++ break;
++ case SLMATH_SIN:
++ fun = sin;
++ break;
++ case SLMATH_COS:
++ fun = cos;
++ break;
++
++ case SLMATH_ASINH:
++ fun = ASINH_FUN;
++ break;
++ case SLMATH_ATANH:
++ fun = ATANH_FUN;
++ break;
++ case SLMATH_ACOSH:
++ fun = ACOSH_FUN;
++ break;
++
++
++ case SLMATH_CONJ:
++ case SLMATH_REAL:
++ for (i = 0; i &lt; na; i++)
++ {
++ b[i] = to_double((VOID_STAR) a);
++ a += da;
++ }
++ return 1;
++
++ case SLMATH_IMAG:
++ for (i = 0; i &lt; na; i++)
++ b[i] = 0.0;
++ return 1;
++ }
++
++ for (i = 0; i &lt; na; i++)
++ {
++ b[i] = (*fun) (to_double ((VOID_STAR) a));
++ a += da;
++ }
++
++ return 1;
++}
++
++#if SLANG_HAS_COMPLEX
++static int complex_math_op_result (int op, unsigned char a, unsigned char *b)
++{
++ (void) a;
++ switch (op)
++ {
++ default:
++ *b = SLANG_COMPLEX_TYPE;
++ break;
++
++ case SLMATH_REAL:
++ case SLMATH_IMAG:
++ *b = SLANG_DOUBLE_TYPE;
++ break;
++ }
++ return 1;
++}
++
++static int complex_math_op (int op,
++ unsigned char type, VOID_STAR ap, unsigned int na,
++ VOID_STAR bp)
++{
++ double *a, *b;
++ unsigned int i;
++ unsigned int na2 = na * 2;
++ double *(*fun) (double *, double *);
++
++ (void) type;
++ a = (double *) ap;
++ b = (double *) bp;
++
++ switch (op)
++ {
++ default:
++ return 0;
++
++ case SLMATH_REAL:
++ for (i = 0; i &lt; na; i++)
++ b[i] = a[2 * i];
++ return 1;
++
++ case SLMATH_IMAG:
++ for (i = 0; i &lt; na; i++)
++ b[i] = a[2 * i + 1];
++ return 1;
++
++ case SLMATH_CONJ:
++ for (i = 0; i &lt; na2; i += 2)
++ {
++ b[i] = a[i];
++ b[i+1] = -a[i+1];
++ }
++ return 1;
++
++ case SLMATH_ATANH:
++ fun = SLcomplex_atanh;
++ break;
++ case SLMATH_ACOSH:
++ fun = SLcomplex_acosh;
++ break;
++ case SLMATH_ASINH:
++ fun = SLcomplex_asinh;
++ break;
++ case SLMATH_EXP:
++ fun = SLcomplex_exp;
++ break;
++ case SLMATH_LOG:
++ fun = SLcomplex_log;
++ break;
++ case SLMATH_LOG10:
++ fun = SLcomplex_log10;
++ break;
++ case SLMATH_SQRT:
++ fun = SLcomplex_sqrt;
++ break;
++ case SLMATH_SIN:
++ fun = SLcomplex_sin;
++ break;
++ case SLMATH_COS:
++ fun = SLcomplex_cos;
++ break;
++ case SLMATH_SINH:
++ fun = SLcomplex_sinh;
++ break;
++ case SLMATH_COSH:
++ fun = SLcomplex_cosh;
++ break;
++ case SLMATH_TANH:
++ fun = SLcomplex_tanh;
++ break;
++ case SLMATH_TAN:
++ fun = SLcomplex_tan;
++ break;
++ case SLMATH_ASIN:
++ fun = SLcomplex_asin;
++ break;
++ case SLMATH_ACOS:
++ fun = SLcomplex_acos;
++ break;
++ case SLMATH_ATAN:
++ fun = SLcomplex_atan;
++ break;
++ }
++
++ for (i = 0; i &lt; na2; i += 2)
++ (void) (*fun) (b + i, a + i);
++
++ return 1;
++}
++#endif
++
++static SLang_DConstant_Type DConst_Table [] =
++{
++ MAKE_DCONSTANT(&quot;E&quot;, 2.718281828459045),
++ MAKE_DCONSTANT(&quot;PI&quot;, 3.14159265358979323846264338327950288),
++ SLANG_END_DCONST_TABLE
++};
++
++static SLang_Math_Unary_Type SLmath_Table [] =
++{
++ MAKE_MATH_UNARY(&quot;sinh&quot;, SLMATH_SINH),
++ MAKE_MATH_UNARY(&quot;asinh&quot;, SLMATH_ASINH),
++ MAKE_MATH_UNARY(&quot;cosh&quot;, SLMATH_COSH),
++ MAKE_MATH_UNARY(&quot;acosh&quot;, SLMATH_ACOSH),
++ MAKE_MATH_UNARY(&quot;tanh&quot;, SLMATH_TANH),
++ MAKE_MATH_UNARY(&quot;atanh&quot;, SLMATH_ATANH),
++ MAKE_MATH_UNARY(&quot;sin&quot;, SLMATH_SIN),
++ MAKE_MATH_UNARY(&quot;cos&quot;, SLMATH_COS),
++ MAKE_MATH_UNARY(&quot;tan&quot;, SLMATH_TAN),
++ MAKE_MATH_UNARY(&quot;atan&quot;, SLMATH_ATAN),
++ MAKE_MATH_UNARY(&quot;acos&quot;, SLMATH_ACOS),
++ MAKE_MATH_UNARY(&quot;asin&quot;, SLMATH_ASIN),
++ MAKE_MATH_UNARY(&quot;exp&quot;, SLMATH_EXP),
++ MAKE_MATH_UNARY(&quot;log&quot;, SLMATH_LOG),
++ MAKE_MATH_UNARY(&quot;sqrt&quot;, SLMATH_SQRT),
++ MAKE_MATH_UNARY(&quot;log10&quot;, SLMATH_LOG10),
++#if SLANG_HAS_COMPLEX
++ MAKE_MATH_UNARY(&quot;Real&quot;, SLMATH_REAL),
++ MAKE_MATH_UNARY(&quot;Imag&quot;, SLMATH_IMAG),
++ MAKE_MATH_UNARY(&quot;Conj&quot;, SLMATH_CONJ),
++#endif
++ SLANG_END_MATH_UNARY_TABLE
++};
++
++static SLang_Intrin_Fun_Type SLang_Math_Table [] =
++{
++ MAKE_INTRINSIC_0(&quot;polynom&quot;, math_poly, SLANG_DOUBLE_TYPE),
++ SLANG_END_INTRIN_FUN_TABLE
++};
++
++int SLang_init_slmath (void)
++{
++ unsigned char *int_types;
++
++#if defined(__unix__)
++ (void) SIGNAL (SIGFPE, math_floating_point_exception);
++#endif
++
++ int_types = _SLarith_Arith_Types;
++
++ while (*int_types != SLANG_FLOAT_TYPE)
++ {
++ if (-1 == SLclass_add_math_op (*int_types, generic_math_op, double_math_op_result))
++ return -1;
++ int_types++;
++ }
++
++ if ((-1 == SLclass_add_math_op (SLANG_FLOAT_TYPE, float_math_op, double_math_op_result))
++ || (-1 == SLclass_add_math_op (SLANG_DOUBLE_TYPE, double_math_op, double_math_op_result))
++#if SLANG_HAS_COMPLEX
++ || (-1 == SLclass_add_math_op (SLANG_COMPLEX_TYPE, complex_math_op, complex_math_op_result))
++#endif
++ )
++ return -1;
++
++ if ((-1 == SLadd_math_unary_table (SLmath_Table, &quot;__SLMATH__&quot;))
++ || (-1 == SLadd_intrin_fun_table (SLang_Math_Table, NULL))
++ || (-1 == SLadd_dconstant_table (DConst_Table, NULL)))
++ return -1;
++
++ return 0;
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slmath.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slmemchr.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slmemchr.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slmemchr.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,47 @@
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++/* These routines are fast memcpy, memset routines. When available, I
++ use system rouines. For msdos, I use inline assembly. */
++
++/* The current versions only work in the forward direction only!! */
++
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++char *SLmemchr(register char *p, register char c, register int n)
++{
++ int n2;
++ register char *pmax;
++
++ pmax = p + (n - 32);
++
++ while (p &lt;= pmax)
++ {
++ if ((*p == c) || (*++p == c) || (*++p == c) || (*++p == c)
++ || (*++p == c) || (*++p == c) || (*++p == c) || (*++p == c)
++ || (*++p == c) || (*++p == c) || (*++p == c) || (*++p == c)
++ || (*++p == c) || (*++p == c) || (*++p == c) || (*++p == c)
++ || (*++p == c) || (*++p == c) || (*++p == c) || (*++p == c)
++ || (*++p == c) || (*++p == c) || (*++p == c) || (*++p == c)
++ || (*++p == c) || (*++p == c) || (*++p == c) || (*++p == c)
++ || (*++p == c) || (*++p == c) || (*++p == c) || (*++p == c))
++ return p;
++ p++;
++ }
++
++ n2 = n % 32;
++
++ while (n2--)
++ {
++ if (*p == c) return p;
++ p++;
++ }
++ return(NULL);
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slmemchr.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slmemcmp.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slmemcmp.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slmemcmp.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,76 @@
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++/* These routines are fast memcpy, memset routines. When available, I
++ use system rouines. For msdos, I use inline assembly. */
++
++/* The current versions only work in the forward direction only!! */
++
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++/* This is an UNSIGNED comparison designed for systems that either do not have
++* this function or performed a signed comparison (SunOS)
++*/
++int SLmemcmp(register char *s1, register char *s2, int n)
++{
++ register int cmp;
++ register char *s1max;
++
++ s1max = s1 + (n - 32);
++
++ while (s1 &lt;= s1max)
++ {
++ if (*s1 != *s2) return ((unsigned char) *s1 - (unsigned char) *s2);
++ if (*(s1 + 1) != *(s2 + 1)) return ((unsigned char) *(s1 + 1) - (unsigned char) *(s2 + 1));
++ if (*(s1 + 2) != *(s2 + 2)) return ((unsigned char) *(s1 + 2) - (unsigned char) *(s2 + 2));
++ if (*(s1 + 3) != *(s2 + 3)) return ((unsigned char) *(s1 + 3) - (unsigned char) *(s2 + 3));
++ if (*(s1 + 4) != *(s2 + 4)) return ((unsigned char) *(s1 + 4) - (unsigned char) *(s2 + 4));
++ if (*(s1 + 5) != *(s2 + 5)) return ((unsigned char) *(s1 + 5) - (unsigned char) *(s2 + 5));
++ if (*(s1 + 6) != *(s2 + 6)) return ((unsigned char) *(s1 + 6) - (unsigned char) *(s2 + 6));
++ if (*(s1 + 7) != *(s2 + 7)) return ((unsigned char) *(s1 + 7) - (unsigned char) *(s2 + 7));
++ if (*(s1 + 8) != *(s2 + 8)) return ((unsigned char) *(s1 + 8) - (unsigned char) *(s2 + 8));
++ if (*(s1 + 9) != *(s2 + 9)) return ((unsigned char) *(s1 + 9) - (unsigned char) *(s2 + 9));
++ if (*(s1 + 10) != *(s2 + 10)) return ((unsigned char) *(s1 + 10) - (unsigned char) *(s2 + 10));
++ if (*(s1 + 11) != *(s2 + 11)) return ((unsigned char) *(s1 + 11) - (unsigned char) *(s2 + 11));
++ if (*(s1 + 12) != *(s2 + 12)) return ((unsigned char) *(s1 + 12) - (unsigned char) *(s2 + 12));
++ if (*(s1 + 13) != *(s2 + 13)) return ((unsigned char) *(s1 + 13) - (unsigned char) *(s2 + 13));
++ if (*(s1 + 14) != *(s2 + 14)) return ((unsigned char) *(s1 + 14) - (unsigned char) *(s2 + 14));
++ if (*(s1 + 15) != *(s2 + 15)) return ((unsigned char) *(s1 + 15) - (unsigned char) *(s2 + 15));
++ if (*(s1 + 16) != *(s2 + 16)) return ((unsigned char) *(s1 + 16) - (unsigned char) *(s2 + 16));
++ if (*(s1 + 17) != *(s2 + 17)) return ((unsigned char) *(s1 + 17) - (unsigned char) *(s2 + 17));
++ if (*(s1 + 18) != *(s2 + 18)) return ((unsigned char) *(s1 + 18) - (unsigned char) *(s2 + 18));
++ if (*(s1 + 19) != *(s2 + 19)) return ((unsigned char) *(s1 + 19) - (unsigned char) *(s2 + 19));
++ if (*(s1 + 20) != *(s2 + 20)) return ((unsigned char) *(s1 + 20) - (unsigned char) *(s2 + 20));
++ if (*(s1 + 21) != *(s2 + 21)) return ((unsigned char) *(s1 + 21) - (unsigned char) *(s2 + 21));
++ if (*(s1 + 22) != *(s2 + 22)) return ((unsigned char) *(s1 + 22) - (unsigned char) *(s2 + 22));
++ if (*(s1 + 23) != *(s2 + 23)) return ((unsigned char) *(s1 + 23) - (unsigned char) *(s2 + 23));
++ if (*(s1 + 24) != *(s2 + 24)) return ((unsigned char) *(s1 + 24) - (unsigned char) *(s2 + 24));
++ if (*(s1 + 25) != *(s2 + 25)) return ((unsigned char) *(s1 + 25) - (unsigned char) *(s2 + 25));
++ if (*(s1 + 26) != *(s2 + 26)) return ((unsigned char) *(s1 + 26) - (unsigned char) *(s2 + 26));
++ if (*(s1 + 27) != *(s2 + 27)) return ((unsigned char) *(s1 + 27) - (unsigned char) *(s2 + 27));
++ if (*(s1 + 28) != *(s2 + 28)) return ((unsigned char) *(s1 + 28) - (unsigned char) *(s2 + 28));
++ if (*(s1 + 29) != *(s2 + 29)) return ((unsigned char) *(s1 + 29) - (unsigned char) *(s2 + 29));
++ if (*(s1 + 30) != *(s2 + 30)) return ((unsigned char) *(s1 + 30) - (unsigned char) *(s2 + 30));
++ if (*(s1 + 31) != *(s2 + 31)) return ((unsigned char) *(s1 + 31) - (unsigned char) *(s2 + 31));
++ s1 += 32; s2 += 32;
++ }
++
++ s1max = s1 + (n % 32);
++
++ while (s1 &lt; s1max)
++ {
++ cmp = (unsigned char) *s1 - (unsigned char) *s2;
++ if (cmp) return(cmp);
++ s1++;
++ s2++;
++ }
++
++ return(0);
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slmemcmp.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slmemcpy.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slmemcpy.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slmemcpy.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,49 @@
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++/* These routines are fast memcpy, memset routines. When available, I
++ use system rouines. For msdos, I use inline assembly. */
++
++/* The current versions only work in the forward direction only!! */
++
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++char *SLmemcpy(char *s1, char *s2, int n)
++{
++#if defined(__BORLANDC__) &amp;&amp; defined(__MSDOS__)
++ asm mov ax, ds
++ asm mov bx, si
++ asm mov dx, di
++ asm mov cx, n
++ asm les di, s1
++ asm lds si, s2
++ asm cld
++ asm rep movsb
++ asm mov ds, ax
++ asm mov si, bx
++ asm mov di, dx
++ return(s1);
++
++#else
++ register char *smax, *s = s1;
++ int n2;
++
++ n2 = n % 4;
++ smax = s + (n - 4);
++ while (s &lt;= smax)
++ {
++ *s = *s2; *(s + 1) = *(s2 + 1); *(s + 2) = *(s2 + 2); *(s + 3) = *(s2 + 3);
++ s += 4;
++ s2 += 4;
++ }
++ while (n2--) *s++ = *s2++;
++ return(s1);
++#endif
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slmemcpy.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slmemset.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slmemset.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slmemset.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,39 @@
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++/* These routines are fast memcpy, memset routines. When available, I
++ use system rouines. For msdos, I use inline assembly. */
++
++/* The current versions only work in the forward direction only!! */
++
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++void SLmemset(char *p, char space, int n)
++{
++#if defined(__BORLANDC__) &amp;&amp; defined(__MSDOS__)
++ asm mov al, space
++ asm mov dx, di
++ asm mov cx, n
++ asm les di, p
++ asm cld
++ asm rep stosb
++ asm mov di, dx
++#else
++ register char *pmax;
++
++ pmax = p + (n - 4);
++ n = n % 4;
++ while (p &lt;= pmax)
++ {
++ *p++ = space; *p++ = space; *p++ = space; *p++= space;
++ }
++ while (n--) *p++ = space;
++#endif
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slmemset.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slmisc.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slmisc.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slmisc.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,330 @@
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++#define DEBUG_MALLOC 0
++
++#if DEBUG_MALLOC
++# define SLREALLOC_FUN SLdebug_realloc
++# define SLMALLOC_FUN SLdebug_malloc
++# define SLFREE_FUN SLdebug_free
++#else
++# define SLREALLOC_FUN SLREALLOC
++# define SLMALLOC_FUN SLMALLOC
++# define SLFREE_FUN SLFREE
++#endif
++
++/* Version information goes here since this file is always needed. */
++int SLang_Version = SLANG_VERSION;
++char *SLang_Version_String = SLANG_VERSION_STRING;
++
++char *SLmake_string(char *str)
++{
++ return SLmake_nstring(str, strlen (str));
++}
++
++char *SLmake_nstring (char *str, unsigned int n)
++{
++ char *ptr;
++
++ if (NULL == (ptr = SLmalloc(n + 1)))
++ {
++ return NULL;
++ }
++ SLMEMCPY (ptr, str, n);
++ ptr[n] = 0;
++ return(ptr);
++}
++
++void SLmake_lut (unsigned char *lut, unsigned char *range, unsigned char reverse)
++{
++ register unsigned char *l = lut, *lmax = lut + 256;
++ int i, r1, r2;
++
++ while (l &lt; lmax) *l++ = reverse;
++ reverse = !reverse;
++
++ r1 = *range++;
++ while (r1)
++ {
++ r2 = *range++;
++ if ((r2 == '-') &amp;&amp; (*range != 0))
++ {
++ r2 = *range++;
++ for (i = r1; i &lt;= r2; i++) lut[i] = reverse;
++ r1 = *range++;
++ continue;
++ }
++ lut[r1] = reverse;
++ r1 = r2;
++ }
++}
++
++char *SLmalloc (unsigned int len)
++{
++ char *p;
++
++ p = (char *) SLMALLOC_FUN (len);
++ if (p == NULL)
++ SLang_Error = SL_MALLOC_ERROR;
++
++ return p;
++}
++
++void SLfree (char *p)
++{
++ if (p != NULL) SLFREE_FUN (p);
++}
++
++char *SLrealloc (char *p, unsigned int len)
++{
++ if (len == 0)
++ {
++ SLfree (p);
++ return NULL;
++ }
++
++ if (p == NULL) p = SLmalloc (len);
++ else
++ {
++ p = (char *)SLREALLOC_FUN (p, len);
++ if (p == NULL)
++ SLang_Error = SL_MALLOC_ERROR;
++ }
++ return p;
++}
++
++char *SLcalloc (unsigned int nelems, unsigned int len)
++{
++ char *p;
++
++ len = nelems * len;
++ p = SLmalloc (len);
++ if (p != NULL) SLMEMSET (p, 0, len);
++ return p;
++}
++
++/* p and ch may point to the same buffer */
++char *_SLexpand_escaped_char(char *p, char *ch)
++{
++ int i = 0;
++ int max = 0, num, base = 0;
++ char ch1;
++
++ ch1 = *p++;
++
++ switch (ch1)
++ {
++ default: num = ch1; break;
++ case 'n': num = '\n'; break;
++ case 't': num = '\t'; break;
++ case 'v': num = '\v'; break;
++ case 'b': num = '\b'; break;
++ case 'r': num = '\r'; break;
++ case 'f': num = '\f'; break;
++ case 'E': case 'e': num = 27; break;
++ case 'a': num = 7;
++ break;
++
++ /* octal */
++ case '0': case '1': case '2': case '3':
++ case '4': case '5': case '6': case '7':
++ max = '7';
++ base = 8; i = 2; num = ch1 - '0';
++ break;
++
++ case 'd': /* decimal -- S-Lang extension */
++ base = 10;
++ i = 3;
++ max = '9';
++ num = 0;
++ break;
++
++ case 'x': /* hex */
++ base = 16;
++ max = '9';
++ i = 2;
++ num = 0;
++ break;
++ }
++
++ while (i--)
++ {
++ ch1 = *p;
++
++ if ((ch1 &lt;= max) &amp;&amp; (ch1 &gt;= '0'))
++ {
++ num = base * num + (ch1 - '0');
++ }
++ else if (base == 16)
++ {
++ ch1 |= 0x20;
++ if ((ch1 &lt; 'a') || ((ch1 &gt; 'f'))) break;
++ num = base * num + 10 + (ch1 - 'a');
++ }
++ else break;
++ p++;
++ }
++
++ *ch = (char) num;
++ return p;
++}
++
++/* s and t could represent the same space */
++void SLexpand_escaped_string (register char *s, register char *t,
++ register char *tmax)
++{
++ char ch;
++
++ while (t &lt; tmax)
++ {
++ ch = *t++;
++ if (ch == '\\')
++ {
++ t = _SLexpand_escaped_char (t, &amp;ch);
++ }
++ *s++ = ch;
++ }
++ *s = 0;
++}
++
++int SLextract_list_element (char *list, unsigned int nth, char delim,
++ char *elem, unsigned int buflen)
++{
++ char *el, *elmax;
++ char ch;
++
++ while (nth &gt; 0)
++ {
++ while ((0 != (ch = *list)) &amp;&amp; (ch != delim))
++ list++;
++
++ if (ch == 0) return -1;
++
++ list++;
++ nth--;
++ }
++
++ el = elem;
++ elmax = el + (buflen - 1);
++
++ while ((0 != (ch = *list)) &amp;&amp; (ch != delim) &amp;&amp; (el &lt; elmax))
++ *el++ = *list++;
++ *el = 0;
++
++ return 0;
++}
++
++#ifndef HAVE_VSNPRINTF
++int _SLvsnprintf (char *buf, unsigned int buflen, char *fmt, va_list ap)
++{
++#if 1
++ unsigned int len;
++
++ /* On some systems vsprintf returns useless information. So, punt */
++ vsprintf (buf, fmt, ap);
++ len = strlen (buf);
++ if (len &gt;= buflen)
++ {
++ SLang_exit_error (&quot;\
++Your system lacks the vsnprintf system call and vsprintf overflowed a buffer.\n\
++The integrity of this program has been violated.\n&quot;);
++ return EOF; /* NOT reached */
++ }
++ return (int)len;
++#else
++ int status;
++
++ status = vsprintf (buf, fmt, ap);
++ if (status &gt;= (int) buflen)
++ {
++ /* If we are lucky, we will get this far. The real solution is to
++ * provide a working version of vsnprintf
++ */
++ SLang_exit_error (&quot;\
++Your system lacks the vsnprintf system call and vsprintf overflowed a buffer.\n\
++The integrity of this program has been violated.\n&quot;);
++ return EOF; /* NOT reached */
++ }
++ return status;
++#endif
++}
++#endif
++
++#ifndef HAVE_SNPRINTF
++int _SLsnprintf (char *buf, unsigned int buflen, char *fmt, ...)
++{
++ int status;
++
++ va_list ap;
++
++ va_start (ap, fmt);
++ status = _SLvsnprintf (buf, buflen, fmt, ap);
++ va_end (ap);
++
++ return status;
++}
++#endif
++
++typedef struct _Cleanup_Function_Type
++{
++ struct _Cleanup_Function_Type *next;
++ void (*f)(void);
++}
++Cleanup_Function_Type;
++
++static Cleanup_Function_Type *Cleanup_Function_List;
++
++static void cleanup_slang (void)
++{
++ while (Cleanup_Function_List != NULL)
++ {
++ Cleanup_Function_Type *next = Cleanup_Function_List-&gt;next;
++ (*Cleanup_Function_List-&gt;f)();
++ SLFREE_FUN ((char *) Cleanup_Function_List);
++ Cleanup_Function_List = next;
++ }
++}
++
++#ifndef HAVE_ATEXIT
++# ifdef HAVE_ON_EXIT
++static void on_exit_cleanup_slang (int arg_unused)
++{
++ (void) arg_unused;
++ cleanup_slang ();
++}
++# endif
++#endif
++
++int SLang_add_cleanup_function (void (*f)(void))
++{
++ Cleanup_Function_Type *l;
++
++ l = (Cleanup_Function_Type *) SLMALLOC_FUN (sizeof (Cleanup_Function_Type));
++ if (l == NULL)
++ return -1;
++
++ l-&gt;f = f;
++ l-&gt;next = Cleanup_Function_List;
++
++ if (Cleanup_Function_List == NULL)
++ {
++#ifdef HAVE_ATEXIT
++ (void) atexit (cleanup_slang);
++#else
++# ifdef HAVE_ON_EXIT
++ (void) on_exit (on_exit_cleanup_slang, 0);
++# endif
++#endif
++ }
++ Cleanup_Function_List = l;
++ return 0;
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slmisc.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slnspace.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slnspace.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slnspace.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,242 @@
++/* -*- mode: C; mode: fold; -*- */
++/* slnspace.c --- Name Space implementation */
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++static SLang_NameSpace_Type *Namespace_Tables;
++
++static SLang_NameSpace_Type *find_name_table (char *name)
++{
++ SLang_NameSpace_Type *table_list;
++
++ table_list = Namespace_Tables;
++ while (table_list != NULL)
++ {
++ if (0 == strcmp (table_list-&gt;name, name))
++ break;
++ table_list = table_list-&gt;next;
++ }
++ return table_list;
++}
++
++SLang_NameSpace_Type *_SLns_find_namespace (char *name)
++{
++ SLang_NameSpace_Type *table_list;
++
++ table_list = Namespace_Tables;
++ while (table_list != NULL)
++ {
++ if ((table_list-&gt;namespace_name != NULL)
++ &amp;&amp; (0 == strcmp (table_list-&gt;namespace_name, name)))
++ break;
++ table_list = table_list-&gt;next;
++ }
++ return table_list;
++}
++
++SLang_NameSpace_Type *_SLns_allocate_namespace (char *name, unsigned int size)
++{
++ SLang_NameSpace_Type *table_list;
++ SLang_Name_Type **nt;
++
++ if (NULL != (table_list = find_name_table (name)))
++ return table_list;
++
++ if (NULL == (name = SLang_create_slstring (name)))
++ return NULL;
++
++ if (NULL == (table_list = (SLang_NameSpace_Type *)
++ SLmalloc (sizeof (SLang_NameSpace_Type))))
++ {
++ SLang_free_slstring (name);
++ return NULL;
++ }
++
++ if (NULL == (nt = (SLang_Name_Type **) SLmalloc (sizeof (SLang_Name_Type *) * size)))
++ {
++ SLang_free_slstring (name);
++ SLfree ((char *)table_list);
++ return NULL;
++ }
++
++ memset ((char *)nt, 0, size * sizeof (SLang_Name_Type *));
++ memset ((char *) table_list, 0, sizeof (SLang_NameSpace_Type));
++
++ table_list-&gt;name = name;
++ table_list-&gt;table = nt;
++ table_list-&gt;table_size = size;
++
++ table_list-&gt;next = Namespace_Tables;
++ Namespace_Tables = table_list;
++
++ return table_list;
++}
++
++int _SLns_set_namespace_name (SLang_NameSpace_Type *t, char *name)
++{
++ SLang_NameSpace_Type *t1;
++
++ t1 = _SLns_find_namespace (name);
++ if (t1 == NULL)
++ t1 = t;
++
++ if ((t != t1) || (*name == 0))
++ {
++ SLang_verror (SL_INTRINSIC_ERROR, &quot;Namespace \&quot;%s\&quot; already exists&quot;,
++ name);
++ return -1;
++ }
++
++ if (NULL == (name = SLang_create_slstring (name)))
++ return -1;
++
++ SLang_free_slstring (t-&gt;namespace_name); /* NULL ok */
++ t-&gt;namespace_name = name;
++
++ return 0;
++}
++
++SLang_Array_Type *_SLnspace_apropos (SLang_NameSpace_Type *ns, char *pat, unsigned int what)
++{
++ SLang_Array_Type *at;
++ unsigned int table_size;
++ SLang_Name_Type *t, **table;
++ int num_matches;
++ unsigned int i;
++ SLRegexp_Type rexp;
++ unsigned char rbuf[512];
++ unsigned int two;
++
++ at = NULL;
++
++ if ((ns == NULL)
++ || ((table = ns-&gt;table) == NULL))
++ return NULL;
++
++ memset ((char *) &amp;rexp, 0, sizeof (SLRegexp_Type));
++ rexp.case_sensitive = 1;
++ rexp.buf = rbuf;
++ rexp.buf_len = sizeof (rbuf);
++ rexp.pat = (unsigned char *)pat;
++
++ if (0 != SLang_regexp_compile (&amp;rexp))
++ {
++ SLang_verror (SL_INVALID_PARM, &quot;Invalid regular expression: %s&quot;, pat);
++ return NULL;
++ }
++
++ table_size = ns-&gt;table_size;
++
++ two = 2;
++ while (two != 0)
++ {
++ two--;
++
++ num_matches = 0;
++ for (i = 0; i &lt; table_size; i++)
++ {
++ t = table[i];
++ while (t != NULL)
++ {
++ unsigned int flags;
++ char *name = t-&gt;name;
++
++ switch (t-&gt;name_type)
++ {
++ case SLANG_GVARIABLE:
++ flags = 8;
++ break;
++
++ case SLANG_ICONSTANT:
++ case SLANG_DCONSTANT:
++ case SLANG_RVARIABLE:
++ case SLANG_IVARIABLE:
++ flags = 4;
++ break;
++
++ case SLANG_INTRINSIC:
++ case SLANG_MATH_UNARY:
++ case SLANG_APP_UNARY:
++ flags = 1;
++ break;
++
++ case SLANG_FUNCTION:
++ flags = 2;
++ break;
++
++ default:
++ flags = 0;
++ break;
++ }
++
++ if ((flags &amp; what)
++ &amp;&amp; (NULL != SLang_regexp_match ((unsigned char *)name, strlen (name), &amp;rexp)))
++ {
++ if (at != NULL)
++ {
++ if (-1 == SLang_set_array_element (at, &amp;num_matches, (VOID_STAR)&amp;name))
++ goto return_error;
++ }
++ num_matches++;
++ }
++ t = t-&gt;next;
++ }
++ }
++
++ if (at == NULL)
++ {
++ at = SLang_create_array (SLANG_STRING_TYPE, 0, NULL, &amp;num_matches, 1);
++ if (at == NULL)
++ goto return_error;
++ }
++ }
++
++ return at;
++
++ return_error:
++ SLang_free_array (at);
++ return NULL;
++}
++
++SLang_NameSpace_Type *SLns_create_namespace (char *namespace_name)
++{
++ SLang_NameSpace_Type *ns;
++ static int num;
++ char name[64];
++
++ if (namespace_name == NULL)
++ namespace_name = &quot;Global&quot;;
++
++ ns = _SLns_find_namespace (namespace_name);
++ if (ns != NULL)
++ return ns;
++
++ sprintf (name, &quot; *** internal ns &lt;%d&gt; *** &quot;, num);
++
++ if (NULL == (ns = _SLns_allocate_namespace (name, SLSTATIC_HASH_TABLE_SIZE)))
++ return NULL;
++
++ num++;
++ if (-1 == _SLns_set_namespace_name (ns, namespace_name))
++ {
++ SLns_delete_namespace (ns);
++ return NULL;
++ }
++
++ return ns;
++}
++
++void SLns_delete_namespace (SLang_NameSpace_Type *ns)
++{
++ (void) ns;
++ /* V2.0 */
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slnspace.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slospath.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slospath.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slospath.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,73 @@
++/* Pathname intrinsic functions */
++/* Copyright (c) 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++static void path_concat (char *a, char *b)
++{
++ SLang_push_malloced_string (SLpath_dircat (a,b));
++}
++
++static void path_extname (char *path)
++{
++#ifdef VMS
++ char *p;
++#endif
++
++ path = SLpath_extname (path);
++#ifndef VMS
++ SLang_push_string (path);
++#else
++ p = strchr (path, ';');
++ if (p == NULL)
++ (void)SLang_push_string (p);
++ else
++ (void)SLang_push_malloced_string (SLmake_nstring (path, (unsigned int)(p - path)));
++#endif
++}
++
++static void path_basename (char *path)
++{
++ (void) SLang_push_string (SLpath_basename (path));
++}
++
++static void path_dirname (char *path)
++{
++ (void) SLang_push_malloced_string (SLpath_dirname (path));
++}
++
++static void path_sans_extname (char *path)
++{
++ (void) SLang_push_malloced_string (SLpath_pathname_sans_extname (path));
++}
++
++
++
++static SLang_Intrin_Fun_Type Path_Name_Table [] =
++{
++ MAKE_INTRINSIC_SS(&quot;path_concat&quot;, path_concat, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_S(&quot;path_extname&quot;, path_extname, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_S(&quot;path_dirname&quot;, path_dirname, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_S(&quot;path_basename&quot;, path_basename, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_S(&quot;path_sans_extname&quot;, path_sans_extname, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_S(&quot;path_is_absolute&quot;, SLpath_is_absolute_path, SLANG_INT_TYPE),
++ SLANG_END_INTRIN_FUN_TABLE
++};
++
++int SLang_init_ospath (void)
++{
++ if (-1 == SLadd_intrin_fun_table(Path_Name_Table, &quot;__OSPATH__&quot;))
++ return -1;
++
++ return 0;
++}
++
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slospath.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slpack.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slpack.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slpack.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,785 @@
++/* Pack objects as a binary string */
++/* Copyright (c) 1998, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++#include &quot;slinclud.h&quot;
++
++#include &lt;ctype.h&gt;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++#ifndef isdigit
++# define isdigit(c) (((c)&gt;='0')&amp;&amp;((c)&lt;= '9'))
++#endif
++#ifndef isspace
++# define isspace(c) (((c)==' ') || ((c)=='\t') || ((c)=='\n'))
++#endif
++
++/* format description:
++ *
++ * s = string (null padded)
++ * S = string (space padded)
++ * c = signed char
++ * C = unsigned char
++ * h = short
++ * H = unsigned short
++ * i = int
++ * I = unsigned int
++ * l = long
++ * L = unsigned long
++ * j = 16 bit signed integer (short)
++ * J = 16 bit unsigned integer (short)
++ * k = 32 bit signed integer (long)
++ * K = 32 bit unsigned integer (long)
++ * f = float (native format)
++ * F = 32 bit double
++ * d = double (native format)
++ * D = 64 bit double
++ * x = null pad byte
++ * &gt; = big-endian mode
++ * &lt; = little-endian mode
++ * = = native mode
++ */
++
++#define NATIVE_ORDER 0
++#define BIGENDIAN_ORDER 1
++#define LILENDIAN_ORDER 2
++static int Native_Byte_Order = NATIVE_ORDER;
++
++typedef struct
++{
++ char format_type;
++ unsigned char data_type;
++ unsigned int repeat;
++ unsigned int sizeof_type;
++ char pad;
++ int byteorder;
++ int is_scalar;
++}
++Format_Type;
++
++static int get_int_type_for_size (unsigned int size, unsigned char *s, unsigned char *u)
++{
++ if (sizeof (int) == size)
++ {
++ if (s != NULL) *s = SLANG_INT_TYPE;
++ if (u != NULL) *u = SLANG_UINT_TYPE;
++ return 0;
++ }
++
++ if (sizeof (short) == size)
++ {
++ if (s != NULL) *s = SLANG_SHORT_TYPE;
++ if (u != NULL) *u = SLANG_USHORT_TYPE;
++ return 1;
++ }
++
++ if (sizeof (long) == size)
++ {
++ if (s != NULL) *s = SLANG_LONG_TYPE;
++ if (u != NULL) *u = SLANG_ULONG_TYPE;
++ return 1;
++ }
++
++ if (s != NULL) *s = 0;
++ if (u != NULL) *u = 0;
++ SLang_verror (SL_NOT_IMPLEMENTED,
++ &quot;This OS does not support a %u byte int&quot;, size);
++ return -1;
++}
++
++static int get_float_type_for_size (unsigned int size, unsigned char *s)
++{
++ if (sizeof (float) == size)
++ {
++ *s = SLANG_FLOAT_TYPE;
++ return 0;
++ }
++
++ if (sizeof (double) == size)
++ {
++ *s = SLANG_DOUBLE_TYPE;
++ return 0;
++ }
++
++ SLang_verror (SL_NOT_IMPLEMENTED,
++ &quot;This OS does not support a %u byte float&quot;, size);
++ return -1;
++}
++
++static int parse_a_format (char **format, Format_Type *ft)
++{
++ char *f;
++ char ch;
++ unsigned repeat;
++
++ f = *format;
++
++ while (((ch = *f++) != 0)
++ &amp;&amp; isspace (ch))
++ ;
++
++ switch (ch)
++ {
++ default:
++ ft-&gt;byteorder = NATIVE_ORDER;
++ break;
++
++ case '=':
++ ft-&gt;byteorder = NATIVE_ORDER;
++ ch = *f++;
++ break;
++
++ case '&gt;':
++ ft-&gt;byteorder = BIGENDIAN_ORDER;
++ ch = *f++;
++ break;
++
++ case '&lt;':
++ ft-&gt;byteorder = LILENDIAN_ORDER;
++ ch = *f++;
++ break;
++ }
++
++ if (ch == 0)
++ {
++ f--;
++ *format = f;
++ return 0;
++ }
++
++ ft-&gt;format_type = ch;
++ ft-&gt;repeat = 1;
++
++ if (isdigit (*f))
++ {
++ repeat = (unsigned int) (*f - '0');
++ f++;
++
++ while (isdigit (*f))
++ {
++ unsigned int repeat10 = 10 * repeat + (unsigned int)(*f - '0');
++
++ /* Check overflow */
++ if (repeat != repeat10 / 10)
++ {
++ SLang_verror (SL_OVERFLOW,
++ &quot;Repeat count too large in [un]pack format&quot;);
++ return -1;
++ }
++ repeat = repeat10;
++ f++;
++ }
++ ft-&gt;repeat = repeat;
++ }
++
++ *format = f;
++
++ ft-&gt;is_scalar = 1;
++ ft-&gt;pad = 0;
++
++ switch (ft-&gt;format_type)
++ {
++ default:
++ SLang_verror (SL_NOT_IMPLEMENTED,
++ &quot;[un]pack format character '%c' not supported&quot;, ft-&gt;format_type);
++ return -1;
++
++ case 'D':
++ ft-&gt;sizeof_type = 8;
++ if (-1 == get_float_type_for_size (8, &amp;ft-&gt;data_type))
++ return -1;
++ break;
++
++ case 'd':
++ ft-&gt;data_type = SLANG_DOUBLE_TYPE;
++ ft-&gt;sizeof_type = sizeof (double);
++ break;
++
++ case 'F':
++ ft-&gt;sizeof_type = 4;
++ if (-1 == get_float_type_for_size (4, &amp;ft-&gt;data_type))
++ return -1;
++ break;
++ case 'f':
++ ft-&gt;data_type = SLANG_FLOAT_TYPE;
++ ft-&gt;sizeof_type = sizeof (float);
++ break;
++
++ case 'h':
++ ft-&gt;data_type = SLANG_SHORT_TYPE;
++ ft-&gt;sizeof_type = sizeof (short);
++ break;
++ case 'H':
++ ft-&gt;data_type = SLANG_USHORT_TYPE;
++ ft-&gt;sizeof_type = sizeof (unsigned short);
++ break;
++ case 'i':
++ ft-&gt;data_type = SLANG_INT_TYPE;
++ ft-&gt;sizeof_type = sizeof (int);
++ break;
++ case 'I':
++ ft-&gt;data_type = SLANG_UINT_TYPE;
++ ft-&gt;sizeof_type = sizeof (unsigned int);
++ break;
++ case 'l':
++ ft-&gt;data_type = SLANG_LONG_TYPE;
++ ft-&gt;sizeof_type = sizeof (long);
++ break;
++ case 'L':
++ ft-&gt;data_type = SLANG_ULONG_TYPE;
++ ft-&gt;sizeof_type = sizeof (unsigned long);
++ break;
++
++ /* 16 bit ints */
++ case 'j':
++ ft-&gt;sizeof_type = 2;
++ if (-1 == get_int_type_for_size (2, &amp;ft-&gt;data_type, NULL))
++ return -1;
++ break;
++ case 'J':
++ ft-&gt;sizeof_type = 2;
++ if (-1 == get_int_type_for_size (2, NULL, &amp;ft-&gt;data_type))
++ return -1;
++ break;
++
++ /* 32 bit ints */
++ case 'k':
++ ft-&gt;sizeof_type = 4;
++ if (-1 == get_int_type_for_size (4, &amp;ft-&gt;data_type, NULL))
++ return -1;
++ break;
++ case 'K':
++ ft-&gt;sizeof_type = 4;
++ if (-1 == get_int_type_for_size (4, NULL, &amp;ft-&gt;data_type))
++ return -1;
++ break;
++
++ case 'x':
++ ft-&gt;sizeof_type = 1;
++ ft-&gt;data_type = 0;
++ break;
++
++ case 'c':
++ ft-&gt;sizeof_type = 1;
++ ft-&gt;data_type = SLANG_CHAR_TYPE;
++ break;
++
++ case 'C':
++ ft-&gt;data_type = SLANG_UCHAR_TYPE;
++ ft-&gt;sizeof_type = 1;
++ break;
++
++ case 'S':
++ case 'A':
++ ft-&gt;pad = ' ';
++ case 'a':
++ case 's':
++ ft-&gt;data_type = SLANG_BSTRING_TYPE;
++ ft-&gt;sizeof_type = 1;
++ ft-&gt;is_scalar = 0;
++ break;
++ }
++ return 1;
++}
++
++static int compute_size_for_format (char *format, unsigned int *num_bytes)
++{
++ unsigned int size;
++ Format_Type ft;
++ int status;
++
++ *num_bytes = size = 0;
++
++ while (1 == (status = parse_a_format (&amp;format, &amp;ft)))
++ size += ft.repeat * ft.sizeof_type;
++
++ *num_bytes = size;
++ return status;
++}
++
++static void byte_swap64 (unsigned char *ss, unsigned int n) /*{{{*/
++{
++ unsigned char *p, *pmax, ch;
++
++ if (n == 0) return;
++ p = (unsigned char *) ss;
++ pmax = p + 8 * n;
++ while (p &lt; pmax)
++ {
++ ch = *p;
++ *p = *(p + 7);
++ *(p + 7) = ch;
++
++ ch = *(p + 6);
++ *(p + 6) = *(p + 1);
++ *(p + 1) = ch;
++
++ ch = *(p + 5);
++ *(p + 5) = *(p + 2);
++ *(p + 2) = ch;
++
++ ch = *(p + 4);
++ *(p + 4) = *(p + 3);
++ *(p + 3) = ch;
++
++ p += 8;
++ }
++}
++
++/*}}}*/
++static void byte_swap32 (unsigned char *ss, unsigned int n) /*{{{*/
++{
++ unsigned char *p, *pmax, ch;
++
++ p = (unsigned char *) ss;
++ pmax = p + 4 * n;
++ while (p &lt; pmax)
++ {
++ ch = *p;
++ *p = *(p + 3);
++ *(p + 3) = ch;
++
++ ch = *(p + 1);
++ *(p + 1) = *(p + 2);
++ *(p + 2) = ch;
++ p += 4;
++ }
++}
++
++/*}}}*/
++static void byte_swap16 (unsigned char *p, unsigned int nread) /*{{{*/
++{
++ unsigned char *pmax, ch;
++
++ pmax = p + 2 * nread;
++ while (p &lt; pmax)
++ {
++ ch = *p;
++ *p = *(p + 1);
++ *(p + 1) = ch;
++ p += 2;
++ }
++}
++
++/*}}}*/
++
++static int byteswap (int order, unsigned char *b, unsigned int size, unsigned int num)
++{
++ if (Native_Byte_Order == order)
++ return 0;
++
++ switch (size)
++ {
++ case 2:
++ byte_swap16 (b, num);
++ break;
++ case 4:
++ byte_swap32 (b, num);
++ break;
++ case 8:
++ byte_swap64 (b, num);
++ break;
++ default:
++ return -1;
++ }
++
++ return 0;
++}
++
++static void check_native_byte_order (void)
++{
++ unsigned short x;
++
++ if (Native_Byte_Order != NATIVE_ORDER)
++ return;
++
++ x = 0xFF;
++ if (*(unsigned char *)&amp;x == 0xFF)
++ Native_Byte_Order = LILENDIAN_ORDER;
++ else
++ Native_Byte_Order = BIGENDIAN_ORDER;
++}
++
++static SLang_BString_Type *
++pack_according_to_format (char *format, unsigned int nitems)
++{
++ unsigned int size, num;
++ unsigned char *buf, *b;
++ SLang_BString_Type *bs;
++ Format_Type ft;
++
++ buf = NULL;
++
++ if (-1 == compute_size_for_format (format, &amp;size))
++ goto return_error;
++
++ if (NULL == (buf = (unsigned char *) SLmalloc (size + 1)))
++ goto return_error;
++
++ b = buf;
++
++ while (1 == parse_a_format (&amp;format, &amp;ft))
++ {
++ unsigned char *ptr;
++ unsigned int repeat;
++
++ repeat = ft.repeat;
++ if (ft.data_type == 0)
++ {
++ memset ((char *) b, ft.pad, repeat);
++ b += repeat;
++ continue;
++ }
++
++ if (ft.is_scalar)
++ {
++ unsigned char *bstart;
++ num = repeat;
++
++ bstart = b;
++ while (repeat != 0)
++ {
++ unsigned int nelements;
++ SLang_Array_Type *at;
++
++ if (nitems == 0)
++ {
++ SLang_verror (SL_INVALID_PARM,
++ &quot;Not enough items for pack format&quot;);
++ goto return_error;
++ }
++
++ if (-1 == SLang_pop_array_of_type (&amp;at, ft.data_type))
++ goto return_error;
++
++ nelements = at-&gt;num_elements;
++ if (repeat &lt; nelements)
++ nelements = repeat;
++ repeat -= nelements;
++
++ nelements = nelements * ft.sizeof_type;
++ memcpy ((char *)b, (char *)at-&gt;data, nelements);
++
++ b += nelements;
++ SLang_free_array (at);
++ nitems--;
++ }
++
++ if (ft.byteorder != NATIVE_ORDER)
++ byteswap (ft.byteorder, bstart, ft.sizeof_type, num);
++
++ continue;
++ }
++
++ /* Otherwise we have a string */
++ if (-1 == SLang_pop_bstring (&amp;bs))
++ goto return_error;
++
++ ptr = SLbstring_get_pointer (bs, &amp;num);
++ if (repeat &lt; num) num = repeat;
++ memcpy ((char *)b, (char *)ptr, num);
++ b += num;
++ repeat -= num;
++ memset ((char *)b, ft.pad, repeat);
++ SLbstring_free (bs);
++ b += repeat;
++ nitems--;
++ }
++
++ *b = 0;
++ bs = SLbstring_create_malloced (buf, size, 0);
++ if (bs == NULL)
++ goto return_error;
++
++ SLdo_pop_n (nitems);
++ return bs;
++
++ return_error:
++ SLdo_pop_n (nitems);
++ if (buf != NULL)
++ SLfree ((char *) buf);
++
++ return NULL;
++}
++
++void _SLpack (void)
++{
++ SLang_BString_Type *bs;
++ char *fmt;
++ int nitems;
++
++ check_native_byte_order ();
++
++ nitems = SLang_Num_Function_Args;
++ if (nitems &lt;= 0)
++ {
++ SLang_verror (SL_SYNTAX_ERROR,
++ &quot;pack: not enough arguments&quot;);
++ return;
++ }
++
++ if ((-1 == SLreverse_stack (nitems))
++ || (-1 == SLang_pop_slstring (&amp;fmt)))
++ bs = NULL;
++ else
++ {
++ bs = pack_according_to_format (fmt, (unsigned int)nitems - 1);
++ SLang_free_slstring (fmt);
++ }
++
++ SLang_push_bstring (bs);
++ SLbstring_free (bs);
++}
++
++void _SLunpack (char *format, SLang_BString_Type *bs)
++{
++ Format_Type ft;
++ unsigned char *b;
++ unsigned int len;
++ unsigned int num_bytes;
++
++ check_native_byte_order ();
++
++ if (-1 == compute_size_for_format (format, &amp;num_bytes))
++ return;
++
++ b = SLbstring_get_pointer (bs, &amp;len);
++ if (b == NULL)
++ return;
++
++ if (len &lt; num_bytes)
++ {
++ SLang_verror (SL_INVALID_PARM,
++ &quot;unpack format %s is too large for input string&quot;,
++ format);
++ return;
++ }
++
++ while (1 == parse_a_format (&amp;format, &amp;ft))
++ {
++ char *str, *s;
++
++ if (ft.repeat == 0)
++ continue;
++
++ if (ft.data_type == 0)
++ { /* skip padding */
++ b += ft.repeat;
++ continue;
++ }
++
++ if (ft.is_scalar)
++ {
++ SLang_Array_Type *at;
++ int dims;
++
++ if (ft.repeat == 1)
++ {
++ SLang_Class_Type *cl;
++
++ cl = _SLclass_get_class (ft.data_type);
++ memcpy ((char *)cl-&gt;cl_transfer_buf, (char *)b, ft.sizeof_type);
++ if (ft.byteorder != NATIVE_ORDER)
++ byteswap (ft.byteorder, (unsigned char *)cl-&gt;cl_transfer_buf, ft.sizeof_type, 1);
++
++ if (-1 == (cl-&gt;cl_apush (ft.data_type, cl-&gt;cl_transfer_buf)))
++ return;
++ b += ft.sizeof_type;
++ continue;
++ }
++
++ dims = (int) ft.repeat;
++ at = SLang_create_array (ft.data_type, 0, NULL, &amp;dims, 1);
++ if (at == NULL)
++ return;
++
++ num_bytes = ft.repeat * ft.sizeof_type;
++ memcpy ((char *)at-&gt;data, (char *)b, num_bytes);
++ if (ft.byteorder != NATIVE_ORDER)
++ byteswap (ft.byteorder, (unsigned char *)at-&gt;data, ft.sizeof_type, ft.repeat);
++
++ if (-1 == SLang_push_array (at, 1))
++ return;
++
++ b += num_bytes;
++ continue;
++ }
++
++ len = ft.repeat;
++ str = SLmalloc (len + 1);
++ if (str == NULL)
++ return;
++
++ memcpy ((char *) str, (char *)b, len);
++ str [len] = 0;
++
++ if (ft.pad == ' ')
++ {
++ unsigned int new_len;
++
++ s = str + len;
++ while (s &gt; str)
++ {
++ s--;
++ if ((*s != ' ') &amp;&amp; (*s != 0))
++ {
++ s++;
++ break;
++ }
++ *s = 0;
++ }
++ new_len = (unsigned int) (s - str);
++
++ if (new_len != len)
++ {
++ s = SLrealloc (str, new_len + 1);
++ if (s == NULL)
++ {
++ SLfree (str);
++ return;
++ }
++ str = s;
++ len = new_len;
++ }
++ }
++
++ /* Avoid a bstring if possible */
++ s = SLmemchr (str, 0, len);
++ if (s == NULL)
++ {
++ if (-1 == SLang_push_malloced_string (str))
++ return;
++ }
++ else
++ {
++ SLang_BString_Type *new_bs;
++
++ new_bs = SLbstring_create_malloced ((unsigned char *)str, len, 1);
++ if (new_bs == NULL)
++ return;
++
++ if (-1 == SLang_push_bstring (new_bs))
++ {
++ SLfree (str);
++ return;
++ }
++ SLbstring_free (new_bs);
++ }
++
++ b += ft.repeat;
++ }
++}
++
++unsigned int _SLpack_compute_size (char *format)
++{
++ unsigned int n;
++
++ n = 0;
++ (void) compute_size_for_format (format, &amp;n);
++ return n;
++}
++
++void _SLpack_pad_format (char *format)
++{
++ unsigned int len, max_len;
++ Format_Type ft;
++ char *buf, *b;
++
++ check_native_byte_order ();
++
++ /* Just check the syntax */
++ if (-1 == compute_size_for_format (format, &amp;max_len))
++ return;
++
++ /* This should be sufficient to handle any needed xyy padding characters.
++ * I cannot see how this will be overrun
++ */
++ max_len = 4 * (strlen (format) + 1);
++ if (NULL == (buf = SLmalloc (max_len + 1)))
++ return;
++
++ b = buf;
++ len = 0;
++ while (1 == parse_a_format (&amp;format, &amp;ft))
++ {
++ struct { char a; short b; } s_h;
++ struct { char a; int b; } s_i;
++ struct { char a; long b; } s_l;
++ struct { char a; float b; } s_f;
++ struct { char a; double b; } s_d;
++ unsigned int pad;
++
++ if (ft.repeat == 0)
++ continue;
++
++ if (ft.data_type == 0)
++ { /* pad */
++ sprintf (b, &quot;x%u&quot;, ft.repeat);
++ b += strlen (b);
++ len += ft.repeat;
++ continue;
++ }
++
++ switch (ft.data_type)
++ {
++ default:
++ case SLANG_STRING_TYPE:
++ case SLANG_BSTRING_TYPE:
++ case SLANG_CHAR_TYPE:
++ case SLANG_UCHAR_TYPE:
++ pad = 0;
++ break;
++
++ case SLANG_SHORT_TYPE:
++ case SLANG_USHORT_TYPE:
++ pad = ((unsigned int) ((char *)&amp;s_h.b - (char *)&amp;s_h.a));
++ break;
++
++ case SLANG_INT_TYPE:
++ case SLANG_UINT_TYPE:
++ pad = ((unsigned int) ((char *)&amp;s_i.b - (char *)&amp;s_i.a));
++ break;
++
++ case SLANG_LONG_TYPE:
++ case SLANG_ULONG_TYPE:
++ pad = ((unsigned int) ((char *)&amp;s_l.b - (char *)&amp;s_l.a));
++ break;
++
++ case SLANG_FLOAT_TYPE:
++ pad = ((unsigned int) ((char *)&amp;s_f.b - (char *)&amp;s_f.a));
++ break;
++
++ case SLANG_DOUBLE_TYPE:
++ pad = ((unsigned int) ((char *)&amp;s_d.b - (char *)&amp;s_d.a));
++ break;
++ }
++
++ /* Pad to a length that is an integer multiple of pad. */
++ if (pad)
++ pad = pad * ((len + pad - 1)/pad) - len;
++
++ if (pad)
++ {
++ sprintf (b, &quot;x%u&quot;, pad);
++ b += strlen (b);
++ len += pad;
++ }
++
++ *b++ = ft.format_type;
++ if (ft.repeat &gt; 1)
++ {
++ sprintf (b, &quot;%u&quot;, ft.repeat);
++ b += strlen (b);
++ }
++
++ len += ft.repeat * ft.sizeof_type;
++ }
++ *b = 0;
++
++ (void) SLang_push_malloced_string (buf);
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slpack.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slparse.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slparse.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slparse.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1970 @@
++/* Copyright (c) 1998, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++static SLang_Load_Type *LLT;
++int _SLang_Compile_Line_Num_Info;
++
++static void free_token (_SLang_Token_Type *t)
++{
++ register unsigned int nrefs = t-&gt;num_refs;
++
++ if (nrefs == 0)
++ return;
++
++ if (nrefs == 1)
++ {
++ if (t-&gt;free_sval_flag)
++ {
++ if (t-&gt;type == BSTRING_TOKEN)
++ SLbstring_free (t-&gt;v.b_val);
++ else
++ _SLfree_hashed_string (t-&gt;v.s_val, strlen (t-&gt;v.s_val), t-&gt;hash);
++ t-&gt;v.s_val = NULL;
++ }
++ }
++
++ t-&gt;num_refs = nrefs - 1;
++}
++
++static void init_token (_SLang_Token_Type *t)
++{
++ memset ((char *) t, 0, sizeof (_SLang_Token_Type));
++#if _SLANG_HAS_DEBUG_CODE
++ t-&gt;line_number = -1;
++#endif
++}
++
++/* Allow room for one push back of a token. This is necessary for
++ * multiple assignment.
++ */
++static unsigned int Use_Next_Token;
++static _SLang_Token_Type Next_Token;
++#if _SLANG_HAS_DEBUG_CODE
++static int Last_Line_Number = -1;
++#endif
++
++static int unget_token (_SLang_Token_Type *ctok)
++{
++ if (SLang_Error)
++ return -1;
++ if (Use_Next_Token != 0)
++ {
++ _SLparse_error (&quot;unget_token failed&quot;, ctok, 0);
++ return -1;
++ }
++
++ Use_Next_Token++;
++ Next_Token = *ctok;
++ init_token (ctok);
++ return 0;
++}
++
++static int get_token (_SLang_Token_Type *ctok)
++{
++ if (ctok-&gt;num_refs)
++ free_token (ctok);
++
++ if (Use_Next_Token)
++ {
++ Use_Next_Token--;
++ *ctok = Next_Token;
++ return ctok-&gt;type;
++ }
++
++ return _SLget_token (ctok);
++}
++
++static int compile_token (_SLang_Token_Type *t)
++{
++#if _SLANG_HAS_DEBUG_CODE
++ if (_SLang_Compile_Line_Num_Info
++ &amp;&amp; (t-&gt;line_number != Last_Line_Number)
++ &amp;&amp; (t-&gt;line_number != -1))
++ {
++ _SLang_Token_Type tok;
++ tok.type = LINE_NUM_TOKEN;
++ tok.v.long_val = Last_Line_Number = t-&gt;line_number;
++ (*_SLcompile_ptr) (&amp;tok);
++ }
++#endif
++ (*_SLcompile_ptr) (t);
++ return 0;
++}
++
++typedef struct
++{
++#define USE_PARANOID_MAGIC 0
++#if USE_PARANOID_MAGIC
++ unsigned long magic;
++#endif
++ _SLang_Token_Type *stack;
++ unsigned int len;
++ unsigned int size;
++}
++Token_List_Type;
++
++#define MAX_TOKEN_LISTS 16
++static Token_List_Type Token_List_Stack [MAX_TOKEN_LISTS];
++static unsigned int Token_List_Stack_Depth = 0;
++static Token_List_Type *Token_List = NULL;
++
++static void init_token_list (Token_List_Type *t)
++{
++ t-&gt;size = 0;
++ t-&gt;len = 0;
++ t-&gt;stack = NULL;
++#if USE_PARANOID_MAGIC
++ t-&gt;magic = 0xABCDEF12;
++#endif
++}
++
++static void free_token_list (Token_List_Type *t)
++{
++ _SLang_Token_Type *s;
++
++ if (t == NULL)
++ return;
++#if USE_PARANOID_MAGIC
++ if (t-&gt;magic != 0xABCDEF12)
++ {
++ SLang_doerror (&quot;Magic error.&quot;);
++ return;
++ }
++#endif
++ s = t-&gt;stack;
++ if (s != NULL)
++ {
++ _SLang_Token_Type *smax = s + t-&gt;len;
++ while (s != smax)
++ {
++ if (s-&gt;num_refs) free_token (s);
++ s++;
++ }
++
++ SLfree ((char *) t-&gt;stack);
++ }
++
++ memset ((char *) t, 0, sizeof (Token_List_Type));
++}
++
++static Token_List_Type *push_token_list (void)
++{
++ if (Token_List_Stack_Depth == MAX_TOKEN_LISTS)
++ {
++ _SLparse_error (&quot;Token list stack size exceeded&quot;, NULL, 0);
++ return NULL;
++ }
++
++ Token_List = Token_List_Stack + Token_List_Stack_Depth;
++ Token_List_Stack_Depth++;
++ init_token_list (Token_List);
++ return Token_List;
++}
++
++static int pop_token_list (int do_free)
++{
++ if (Token_List_Stack_Depth == 0)
++ {
++ if (SLang_Error == 0)
++ _SLparse_error (&quot;Token list stack underflow&quot;, NULL, 0);
++ return -1;
++ }
++ Token_List_Stack_Depth--;
++
++ if (do_free) free_token_list (Token_List);
++
++ if (Token_List_Stack_Depth != 0)
++ Token_List = Token_List_Stack + (Token_List_Stack_Depth - 1);
++ else
++ Token_List = NULL;
++
++ return 0;
++}
++
++static int check_token_list_space (Token_List_Type *t, unsigned int delta_size)
++{
++ _SLang_Token_Type *st;
++ unsigned int len;
++#if USE_PARANOID_MAGIC
++ if (t-&gt;magic != 0xABCDEF12)
++ {
++ SLang_doerror (&quot;Magic error.&quot;);
++ return -1;
++ }
++#endif
++ len = t-&gt;len + delta_size;
++ if (len &lt;= t-&gt;size) return 0;
++
++ if (delta_size &lt; 4)
++ {
++ delta_size = 4;
++ len = t-&gt;len + delta_size;
++ }
++
++ st = (_SLang_Token_Type *) SLrealloc((char *) t-&gt;stack,
++ len * sizeof(_SLang_Token_Type));
++ if (st == NULL)
++ {
++ _SLparse_error (&quot;Malloc error&quot;, NULL, 0);
++ return -1;
++ }
++
++ memset ((char *) (st + t-&gt;len), 0, delta_size);
++
++ t-&gt;stack = st;
++ t-&gt;size = len;
++ return 0;
++}
++
++static int append_token (_SLang_Token_Type *t)
++{
++ if (-1 == check_token_list_space (Token_List, 1))
++ return -1;
++
++ Token_List-&gt;stack [Token_List-&gt;len] = *t;
++ Token_List-&gt;len += 1;
++ t-&gt;num_refs = 0; /* stealing it */
++ return 0;
++}
++
++static int append_token_of_type (unsigned char t)
++{
++ _SLang_Token_Type *tok;
++
++ if (-1 == check_token_list_space (Token_List, 1))
++ return -1;
++
++ /* The memset when the list was created ensures that the other fields
++ * are properly initialized.
++ */
++ tok = Token_List-&gt;stack + Token_List-&gt;len;
++ init_token (tok);
++ tok-&gt;type = t;
++ Token_List-&gt;len += 1;
++ return 0;
++}
++
++static _SLang_Token_Type *get_last_token (void)
++{
++ unsigned int len;
++
++ if ((Token_List == NULL)
++ || (0 == (len = Token_List-&gt;len)))
++ return NULL;
++
++ len--;
++ return Token_List-&gt;stack + len;
++}
++
++/* This function does NOT free the list. */
++static int compile_token_list_with_fun (int dir, Token_List_Type *list,
++ int (*f)(_SLang_Token_Type *))
++{
++ _SLang_Token_Type *t0, *t1;
++
++ if (list == NULL)
++ return -1;
++
++ if (f == NULL)
++ f = compile_token;
++
++ t0 = list-&gt;stack;
++ t1 = t0 + list-&gt;len;
++
++ if (dir &lt; 0)
++ {
++ /* backwards */
++
++ while ((SLang_Error == 0) &amp;&amp; (t1 &gt; t0))
++ {
++ t1--;
++ (*f) (t1);
++ }
++ return 0;
++ }
++
++ /* forward */
++ while ((SLang_Error == 0) &amp;&amp; (t0 &lt; t1))
++ {
++ (*f) (t0);
++ t0++;
++ }
++ return 0;
++}
++
++static int compile_token_list (void)
++{
++ if (Token_List == NULL)
++ return -1;
++
++ compile_token_list_with_fun (1, Token_List, NULL);
++ pop_token_list (1);
++ return 0;
++}
++
++/* Take all elements in the list from pos2 to the end and exchange them
++ * with the elements at pos1, e.g.,
++ * ...ABCDEabc ==&gt; ...abcABCDE
++ * where pos1 denotes A and pos2 denotes a.
++ */
++static int token_list_element_exchange (unsigned int pos1, unsigned int pos2)
++{
++ _SLang_Token_Type *s, *s1, *s2;
++ unsigned int len, nloops;
++
++ if (Token_List == NULL)
++ return -1;
++
++ s = Token_List-&gt;stack;
++ len = Token_List-&gt;len;
++
++ if ((s == NULL) || (len == 0)
++ || (pos2 &gt;= len))
++ return -1;
++
++ /* This may not be the most efficient algorithm but the number to swap
++ * is most-likely going to be small, e.g, 3
++ * The algorithm is to rotate the list. The particular rotation
++ * direction was chosen to make insert_token fast.
++ * It works like:
++ * @ ABCabcde --&gt; BCabcdeA --&gt; CabcdeAB --&gt; abcdefAB
++ * which is optimal for Abcdef sequence produced by function calls.
++ *
++ * Profiling indicates that nloops is almost always 1, whereas the inner
++ * loop can loop many times (e.g., 9 times).
++ */
++
++ s2 = s + (len - 1);
++ s1 = s + pos1;
++ nloops = pos2 - pos1;
++
++ while (nloops)
++ {
++ _SLang_Token_Type save;
++
++ s = s1;
++ save = *s;
++
++ while (s &lt; s2)
++ {
++ *s = *(s + 1);
++ s++;
++ }
++ *s = save;
++
++ nloops--;
++ }
++ return 0;
++}
++
++#if 0
++static int insert_token (_SLang_Token_Type *t, unsigned int pos)
++{
++ if (-1 == append_token (t))
++ return -1;
++
++ return token_list_element_exchange (pos, Token_List-&gt;len - 1);
++}
++#endif
++static void compile_token_of_type (unsigned char t)
++{
++ _SLang_Token_Type tok;
++
++#if _SLANG_HAS_DEBUG_CODE
++ tok.line_number = -1;
++#endif
++ tok.type = t;
++ compile_token(&amp;tok);
++}
++
++static void statement (_SLang_Token_Type *);
++static void compound_statement (_SLang_Token_Type *);
++static void expression_with_parenthesis (_SLang_Token_Type *);
++static void handle_semicolon (_SLang_Token_Type *);
++static void statement_list (_SLang_Token_Type *);
++static void variable_list (_SLang_Token_Type *, unsigned char);
++static void struct_declaration (_SLang_Token_Type *);
++static void define_function_args (_SLang_Token_Type *);
++static void typedef_definition (_SLang_Token_Type *);
++static void function_args_expression (_SLang_Token_Type *, int);
++static void expression (_SLang_Token_Type *);
++static void expression_with_commas (_SLang_Token_Type *, int);
++static void simple_expression (_SLang_Token_Type *);
++static void unary_expression (_SLang_Token_Type *);
++static void postfix_expression (_SLang_Token_Type *);
++static int check_for_lvalue (unsigned char, _SLang_Token_Type *);
++/* static void primary_expression (_SLang_Token_Type *); */
++static void block (_SLang_Token_Type *);
++static void inline_array_expression (_SLang_Token_Type *);
++static void array_index_expression (_SLang_Token_Type *);
++static void do_multiple_assignment (_SLang_Token_Type *);
++static void try_multiple_assignment (_SLang_Token_Type *);
++#if 0
++static void not_implemented (char *what)
++{
++ char err [256];
++ sprintf (err, &quot;Expression not implemented: %s&quot;, what);
++ _SLparse_error (err, NULL, 0);
++}
++#endif
++static void rpn_parse_line (_SLang_Token_Type *tok)
++{
++ do
++ {
++ /* multiple RPN tokens possible when the file looks like:
++ * . &lt;end of line&gt;
++ * . &lt;end of line&gt;
++ */
++ if (tok-&gt;type != RPN_TOKEN)
++ compile_token (tok);
++ free_token (tok);
++ }
++ while (EOF_TOKEN != _SLget_rpn_token (tok));
++}
++
++static int get_identifier_token (_SLang_Token_Type *tok)
++{
++ if (IDENT_TOKEN == get_token (tok))
++ return IDENT_TOKEN;
++
++ _SLparse_error (&quot;Expecting identifier&quot;, tok, 0);
++ return tok-&gt;type;
++}
++
++static void define_function (_SLang_Token_Type *ctok, unsigned char type)
++{
++ _SLang_Token_Type fname;
++
++ switch (type)
++ {
++ case STATIC_TOKEN:
++ type = DEFINE_STATIC_TOKEN;
++ break;
++
++ case PUBLIC_TOKEN:
++ type = DEFINE_PUBLIC_TOKEN;
++ break;
++
++ case PRIVATE_TOKEN:
++ type = DEFINE_PRIVATE_TOKEN;
++ }
++
++ init_token (&amp;fname);
++ if (IDENT_TOKEN != get_identifier_token (&amp;fname))
++ {
++ free_token (&amp;fname);
++ return;
++ }
++
++ compile_token_of_type(OPAREN_TOKEN);
++ get_token (ctok);
++ define_function_args (ctok);
++ compile_token_of_type(FARG_TOKEN);
++
++ if (ctok-&gt;type == OBRACE_TOKEN)
++ compound_statement(ctok);
++
++ else if (ctok-&gt;type != SEMICOLON_TOKEN)
++ {
++ _SLparse_error(&quot;Expecting {&quot;, ctok, 0);
++ free_token (&amp;fname);
++ return;
++ }
++
++ fname.type = type;
++ compile_token (&amp;fname);
++ free_token (&amp;fname);
++}
++
++/* statement:
++ * compound-statement
++ * if ( expression ) statement
++ * if ( expression ) statement else statement
++ * !if ( expression ) statement
++ * loop ( expression ) statement
++ * _for ( expression ) statement
++ * foreach ( expression ) statement
++ * foreach (expression ) using (expression-list) statement
++ * while ( expression ) statement
++ * do statement while (expression) ;
++ * for ( expressionopt ; expressionopt ; expressionopt ) statement
++ * ERROR_BLOCK statement
++ * EXIT_BLOCK statement
++ * USER_BLOCK0 statement
++ * USER_BLOCK1 statement
++ * USER_BLOCK2 statement
++ * USER_BLOCK3 statement
++ * USER_BLOCK4 statement
++ * forever statement
++ * break ;
++ * continue ;
++ * return expressionopt ;
++ * variable variable-list ;
++ * struct struct-decl ;
++ * define identifier function-args ;
++ * define identifier function-args compound-statement
++ * switch ( expression ) statement
++ * rpn-line
++ * at-line
++ * push ( expression )
++ * ( expression ) = expression ;
++ * expression ;
++ * expression :
++ */
++
++/* Note: This function does not return with a new token. It is up to the
++ * calling routine to handle that.
++ */
++static void statement (_SLang_Token_Type *ctok)
++{
++ unsigned char type;
++
++ if (SLang_Error)
++ return;
++
++ LLT-&gt;parse_level += 1;
++
++ switch (ctok-&gt;type)
++ {
++ case OBRACE_TOKEN:
++ compound_statement (ctok);
++ break;
++
++ case IF_TOKEN:
++ case IFNOT_TOKEN:
++ type = ctok-&gt;type;
++ get_token (ctok);
++ expression_with_parenthesis (ctok);
++ block (ctok);
++
++ if (ELSE_TOKEN != get_token (ctok))
++ {
++ compile_token_of_type (type);
++ unget_token (ctok);
++ break;
++ }
++ get_token (ctok);
++ block (ctok);
++ if (type == IF_TOKEN) type = ELSE_TOKEN; else type = NOTELSE_TOKEN;
++ compile_token_of_type (type);
++ break;
++
++ /* case IFNOT_TOKEN: */
++ case LOOP_TOKEN:
++ case _FOR_TOKEN:
++ type = ctok-&gt;type;
++ get_token (ctok);
++ expression_with_parenthesis (ctok);
++ block (ctok);
++ compile_token_of_type (type);
++ break;
++
++ case FOREACH_TOKEN:
++ get_token (ctok);
++ expression_with_parenthesis (ctok);
++
++ if (NULL == push_token_list ())
++ break;
++
++ append_token_of_type (ARG_TOKEN);
++ if (ctok-&gt;type == USING_TOKEN)
++ {
++ if (OPAREN_TOKEN != get_token (ctok))
++ {
++ _SLparse_error (&quot;Expected 'using ('&quot;, ctok, 0);
++ break;
++ }
++ get_token (ctok);
++ function_args_expression (ctok, 0);
++ }
++ append_token_of_type (EARG_TOKEN);
++
++ compile_token_list ();
++
++ block (ctok);
++ compile_token_of_type (FOREACH_TOKEN);
++ break;
++
++ case WHILE_TOKEN:
++ get_token (ctok);
++ compile_token_of_type (OBRACE_TOKEN);
++ expression_with_parenthesis (ctok);
++ compile_token_of_type (CBRACE_TOKEN);
++ block (ctok);
++ compile_token_of_type (WHILE_TOKEN);
++ break;
++
++ case DO_TOKEN:
++ get_token (ctok);
++ block (ctok);
++
++ if (WHILE_TOKEN != get_token (ctok))
++ {
++ _SLparse_error(&quot;Expecting while&quot;, ctok, 0);
++ break;
++ }
++
++ get_token (ctok);
++
++ compile_token_of_type (OBRACE_TOKEN);
++ expression_with_parenthesis (ctok);
++ compile_token_of_type (CBRACE_TOKEN);
++ compile_token_of_type (DOWHILE_TOKEN);
++ handle_semicolon (ctok);
++ break;
++
++ case FOR_TOKEN:
++
++ /* Look for (exp_opt ; exp_opt ; exp_opt ) */
++
++ if (OPAREN_TOKEN != get_token (ctok))
++ {
++ _SLparse_error(&quot;Expecting (.&quot;, ctok, 0);
++ break;
++ }
++
++ if (NULL == push_token_list ())
++ break;
++
++ append_token_of_type (OBRACE_TOKEN);
++ if (SEMICOLON_TOKEN != get_token (ctok))
++ {
++ expression (ctok);
++ if (ctok-&gt;type != SEMICOLON_TOKEN)
++ {
++ _SLparse_error(&quot;Expecting ;&quot;, ctok, 0);
++ break;
++ }
++ }
++ append_token_of_type (CBRACE_TOKEN);
++
++ append_token_of_type (OBRACE_TOKEN);
++ if (SEMICOLON_TOKEN != get_token (ctok))
++ {
++ expression (ctok);
++ if (ctok-&gt;type != SEMICOLON_TOKEN)
++ {
++ _SLparse_error(&quot;Expecting ;&quot;, ctok, 0);
++ break;
++ }
++ }
++ append_token_of_type (CBRACE_TOKEN);
++
++ append_token_of_type (OBRACE_TOKEN);
++ if (CPAREN_TOKEN != get_token (ctok))
++ {
++ expression (ctok);
++ if (ctok-&gt;type != CPAREN_TOKEN)
++ {
++ _SLparse_error(&quot;Expecting ).&quot;, ctok, 0);
++ break;
++ }
++ }
++ append_token_of_type (CBRACE_TOKEN);
++
++ compile_token_list ();
++
++ get_token (ctok);
++ block (ctok);
++ compile_token_of_type (FOR_TOKEN);
++ break;
++
++ case ERRBLK_TOKEN:
++ case EXITBLK_TOKEN:
++ case USRBLK0_TOKEN:
++ case USRBLK1_TOKEN:
++ case USRBLK2_TOKEN:
++ case USRBLK3_TOKEN:
++ case USRBLK4_TOKEN:
++ case FOREVER_TOKEN:
++ type = ctok-&gt;type;
++ get_token (ctok);
++ block (ctok);
++ compile_token_of_type (type);
++ break;
++
++ case BREAK_TOKEN:
++ case CONT_TOKEN:
++ compile_token_of_type (ctok-&gt;type);
++ get_token (ctok);
++ handle_semicolon (ctok);
++ break;
++
++ case RETURN_TOKEN:
++ if (SEMICOLON_TOKEN != get_token (ctok))
++ {
++ if (NULL == push_token_list ())
++ break;
++
++ expression (ctok);
++
++ if (ctok-&gt;type != SEMICOLON_TOKEN)
++ {
++ _SLparse_error (&quot;Expecting ;&quot;, ctok, 0);
++ break;
++ }
++ compile_token_list ();
++ }
++ compile_token_of_type (RETURN_TOKEN);
++ handle_semicolon (ctok);
++ break;
++
++ case STATIC_TOKEN:
++ case PRIVATE_TOKEN:
++ case PUBLIC_TOKEN:
++ type = ctok-&gt;type;
++ get_token (ctok);
++ if (ctok-&gt;type == VARIABLE_TOKEN)
++ {
++ get_token (ctok);
++ variable_list (ctok, type);
++ handle_semicolon (ctok);
++ break;
++ }
++ if (ctok-&gt;type == DEFINE_TOKEN)
++ {
++ define_function (ctok, type);
++ break;
++ }
++ _SLparse_error (&quot;Expecting 'variable' or 'define'&quot;, ctok, 0);
++ break;
++
++ case VARIABLE_TOKEN:
++ get_token (ctok);
++ variable_list (ctok, OBRACKET_TOKEN);
++ handle_semicolon (ctok);
++ break;
++
++ case TYPEDEF_TOKEN:
++ get_token (ctok);
++ if (NULL == push_token_list ())
++ break;
++ typedef_definition (ctok);
++ compile_token_list ();
++
++ handle_semicolon (ctok);
++ break;
++
++ case DEFINE_TOKEN:
++ define_function (ctok, DEFINE_TOKEN);
++ break;
++
++ case SWITCH_TOKEN:
++ get_token (ctok);
++ expression_with_parenthesis (ctok);
++
++ while ((SLang_Error == 0)
++ &amp;&amp; (OBRACE_TOKEN == ctok-&gt;type))
++ {
++ compile_token_of_type (OBRACE_TOKEN);
++ compound_statement (ctok);
++ compile_token_of_type (CBRACE_TOKEN);
++ get_token (ctok);
++ }
++ compile_token_of_type (SWITCH_TOKEN);
++ unget_token (ctok);
++ break;
++
++ case EOF_TOKEN:
++ break;
++#if 0
++ case PUSH_TOKEN:
++ get_token (ctok);
++ expression_list_with_parenthesis (ctok);
++ handle_semicolon (ctok);
++ break;
++#endif
++
++ case SEMICOLON_TOKEN:
++ handle_semicolon (ctok);
++ break;
++
++ case RPN_TOKEN:
++ if (POUND_TOKEN == get_token (ctok))
++ _SLcompile_byte_compiled ();
++ else if (ctok-&gt;type != EOF_TOKEN)
++ rpn_parse_line (ctok);
++ break;
++
++ case OPAREN_TOKEN: /* multiple assignment */
++ try_multiple_assignment (ctok);
++ if (ctok-&gt;type == COLON_TOKEN)
++ compile_token_of_type (COLON_TOKEN);
++ else handle_semicolon (ctok);
++ break;
++
++ default:
++
++ if (NULL == push_token_list ())
++ break;
++
++ expression (ctok);
++ compile_token_list ();
++
++ if (ctok-&gt;type == COLON_TOKEN)
++ compile_token_of_type (COLON_TOKEN);
++ else handle_semicolon (ctok);
++ break;
++ }
++
++ LLT-&gt;parse_level -= 1;
++}
++
++static void block (_SLang_Token_Type *ctok)
++{
++ compile_token_of_type (OBRACE_TOKEN);
++ statement (ctok);
++ compile_token_of_type (CBRACE_TOKEN);
++}
++
++/*
++ * statement-list:
++ * statement
++ * statement-list statement
++ */
++static void statement_list (_SLang_Token_Type *ctok)
++{
++ while ((SLang_Error == 0)
++ &amp;&amp; (ctok-&gt;type != CBRACE_TOKEN)
++ &amp;&amp; (ctok-&gt;type != EOF_TOKEN))
++ {
++ statement(ctok);
++ get_token (ctok);
++ }
++}
++
++/* compound-statement:
++ * { statement-list }
++ */
++static void compound_statement (_SLang_Token_Type *ctok)
++{
++ /* ctok-&gt;type is OBRACE_TOKEN here */
++ get_token (ctok);
++ statement_list(ctok);
++ if (CBRACE_TOKEN != ctok-&gt;type)
++ {
++ _SLparse_error (&quot;Expecting '}'&quot;, ctok, 0);
++ return;
++ }
++}
++
++/* This function is only called from statement. */
++static void expression_with_parenthesis (_SLang_Token_Type *ctok)
++{
++ if (ctok-&gt;type != OPAREN_TOKEN)
++ {
++ _SLparse_error(&quot;Expecting (&quot;, ctok, 0);
++ return;
++ }
++
++ if (NULL == push_token_list ())
++ return;
++
++ get_token (ctok);
++ expression (ctok);
++
++ if (ctok-&gt;type != CPAREN_TOKEN)
++ _SLparse_error(&quot;Expecting )&quot;, ctok, 0);
++
++ compile_token_list ();
++
++ get_token (ctok);
++}
++
++static void handle_semicolon (_SLang_Token_Type *ctok)
++{
++ if ((ctok-&gt;type == SEMICOLON_TOKEN)
++ || (ctok-&gt;type == EOF_TOKEN))
++ return;
++
++ _SLparse_error (&quot;Expecting ;&quot;, ctok, 0);
++}
++
++void _SLparse_start (SLang_Load_Type *llt)
++{
++ _SLang_Token_Type ctok;
++ SLang_Load_Type *save_llt;
++ unsigned int save_use_next_token;
++ _SLang_Token_Type save_next_token;
++ Token_List_Type *save_list;
++#if _SLANG_HAS_DEBUG_CODE
++ int save_last_line_number = Last_Line_Number;
++
++ Last_Line_Number = -1;
++#endif
++ save_use_next_token = Use_Next_Token;
++ save_next_token = Next_Token;
++ save_list = Token_List;
++ save_llt = LLT;
++ LLT = llt;
++
++ init_token (&amp;Next_Token);
++ Use_Next_Token = 0;
++ init_token (&amp;ctok);
++ get_token (&amp;ctok);
++
++ llt-&gt;parse_level = 0;
++ statement_list (&amp;ctok);
++
++ if ((SLang_Error == 0)
++ &amp;&amp; (ctok.type != EOF_TOKEN))
++ _SLparse_error (&quot;Parse ended prematurely&quot;, &amp;ctok, 0);
++
++
++ if (SLang_Error)
++ {
++ if (SLang_Error &lt; 0) /* severe error */
++ save_list = NULL;
++
++ while (Token_List != save_list)
++ {
++ if (-1 == pop_token_list (1))
++ break; /* ??? when would this happen? */
++ }
++ }
++
++ free_token (&amp;ctok);
++ LLT = save_llt;
++ if (Use_Next_Token)
++ free_token (&amp;Next_Token);
++ Use_Next_Token = save_use_next_token;
++ Next_Token = save_next_token;
++#if _SLANG_HAS_DEBUG_CODE
++ Last_Line_Number = save_last_line_number;
++#endif
++}
++
++/* variable-list:
++ * variable-decl
++ * variable-decl variable-list
++ *
++ * variable-decl:
++ * identifier
++ * identifier = simple-expression
++ */
++static void variable_list (_SLang_Token_Type *name_token, unsigned char variable_type)
++{
++ int declaring;
++ _SLang_Token_Type tok;
++
++ if (name_token-&gt;type != IDENT_TOKEN)
++ {
++ _SLparse_error (&quot;Expecting a variable name&quot;, name_token, 0);
++ return;
++ }
++
++ declaring = 0;
++ do
++ {
++ if (declaring == 0)
++ {
++ declaring = 1;
++ compile_token_of_type (variable_type);
++ }
++
++ compile_token (name_token);
++
++ init_token (&amp;tok);
++ if (ASSIGN_TOKEN == get_token (&amp;tok))
++ {
++ compile_token_of_type (CBRACKET_TOKEN);
++ declaring = 0;
++
++ get_token (&amp;tok);
++
++ push_token_list ();
++ simple_expression (&amp;tok);
++ compile_token_list ();
++
++ name_token-&gt;type = _SCALAR_ASSIGN_TOKEN;
++ compile_token (name_token);
++ }
++
++ free_token (name_token);
++ *name_token = tok;
++ }
++ while ((name_token-&gt;type == COMMA_TOKEN)
++ &amp;&amp; (IDENT_TOKEN == get_token (name_token)));
++
++ if (declaring) compile_token_of_type (CBRACKET_TOKEN);
++}
++
++/* struct-declaration:
++ * struct { struct-field-list };
++ *
++ * struct-field-list:
++ * struct-field-name , struct-field-list
++ * struct-field-name
++ *
++ * Generates code: &quot;field-name-1&quot; ... &quot;field-name-N&quot; N STRUCT_TOKEN
++ */
++static void struct_declaration (_SLang_Token_Type *ctok)
++{
++ int n;
++ _SLang_Token_Type num_tok;
++
++ if (ctok-&gt;type != OBRACE_TOKEN)
++ {
++ _SLparse_error (&quot;Expecting {&quot;, ctok, 0);
++ return;
++ }
++
++ n = 0;
++ while (IDENT_TOKEN == get_token (ctok))
++ {
++ n++;
++ ctok-&gt;type = STRING_TOKEN;
++ append_token (ctok);
++ if (COMMA_TOKEN != get_token (ctok))
++ break;
++ }
++
++ if (ctok-&gt;type != CBRACE_TOKEN)
++ {
++ _SLparse_error (&quot;Expecting }&quot;, ctok, 0);
++ return;
++ }
++ if (n == 0)
++ {
++ _SLparse_error (&quot;struct requires at least 1 field&quot;, ctok, 0);
++ return;
++ }
++
++ init_token (&amp;num_tok);
++ num_tok.type = INT_TOKEN;
++ num_tok.v.long_val = n;
++ append_token (&amp;num_tok);
++ append_token_of_type (STRUCT_TOKEN);
++
++ get_token (ctok);
++}
++
++/* struct-declaration:
++ * typedef struct { struct-field-list } Type_Name;
++ *
++ * struct-field-list:
++ * struct-field-name , struct-field-list
++ * struct-field-name
++ *
++ * Generates code: &quot;field-name-1&quot; ... &quot;field-name-N&quot; N STRUCT_TOKEN typedef
++ */
++static void typedef_definition (_SLang_Token_Type *t)
++{
++
++ if (t-&gt;type != STRUCT_TOKEN)
++ {
++ _SLparse_error (&quot;Expecting `struct'&quot;, t, 0);
++ return;
++ }
++ get_token (t);
++
++ struct_declaration (t);
++ if (t-&gt;type != IDENT_TOKEN)
++ {
++ _SLparse_error (&quot;Expecting identifier&quot;, t, 0);
++ return;
++ }
++
++ t-&gt;type = STRING_TOKEN;
++ append_token (t);
++ append_token_of_type (TYPEDEF_TOKEN);
++
++ get_token (t);
++}
++
++/* function-args:
++ * ( args-dec-opt )
++ *
++ * args-decl-opt:
++ * identifier
++ * args-decl , identifier
++ */
++static void define_function_args (_SLang_Token_Type *ctok)
++{
++ if (CPAREN_TOKEN == get_token (ctok))
++ {
++ get_token (ctok);
++ return;
++ }
++
++ compile_token_of_type(OBRACKET_TOKEN);
++
++ while ((SLang_Error == 0)
++ &amp;&amp; (ctok-&gt;type == IDENT_TOKEN))
++ {
++ compile_token (ctok);
++ if (COMMA_TOKEN != get_token (ctok))
++ break;
++
++ get_token (ctok);
++ }
++
++ if (CPAREN_TOKEN != ctok-&gt;type)
++ {
++ _SLparse_error(&quot;Expecting )&quot;, ctok, 0);
++ return;
++ }
++ compile_token_of_type(CBRACKET_TOKEN);
++
++ get_token (ctok);
++}
++
++void try_multiple_assignment (_SLang_Token_Type *ctok)
++{
++ /* This is called with ctok-&gt;type == OPAREN_TOKEN. We have no idea
++ * what follows this. There are various possibilities such as:
++ * @ () = x;
++ * @ ( expression ) = x;
++ * @ ( expression ) ;
++ * @ ( expression ) OP expression;
++ * @ ( expression ) [expression] = expression;
++ * and only the first two constitute a multiple assignment. The last
++ * two forms create the difficulty.
++ *
++ * Here is the plan. First parse (expression) and then check next token.
++ * If it is an equal operator, then it will be parsed as a multiple
++ * assignment. In fact, that is the easy part.
++ *
++ * The hard part stems from the fact that by parsing (expression), we
++ * have effectly truncated the parse if (expression) is part of a binary
++ * or unary expression. Somehow, the parsing must be resumed. The trick
++ * here is to use a dummy literal that generates no code: NO_OP_LITERAL
++ * Using it, we just call 'expression' and proceed.
++ */
++
++ if (NULL == push_token_list ())
++ return;
++
++ get_token (ctok);
++
++ if (ctok-&gt;type != CPAREN_TOKEN)
++ {
++ expression_with_commas (ctok, 1);
++ if (ctok-&gt;type != CPAREN_TOKEN)
++ {
++ _SLparse_error (&quot;Expecting )&quot;, ctok, 0);
++ return;
++ }
++ }
++
++ switch (get_token (ctok))
++ {
++ case ASSIGN_TOKEN:
++ case PLUSEQS_TOKEN:
++ case MINUSEQS_TOKEN:
++ case TIMESEQS_TOKEN:
++ case DIVEQS_TOKEN:
++ case BOREQS_TOKEN:
++ case BANDEQS_TOKEN:
++ do_multiple_assignment (ctok);
++ pop_token_list (1);
++ break;
++
++ default:
++ unget_token (ctok);
++ ctok-&gt;type = NO_OP_LITERAL;
++ expression (ctok);
++ compile_token_list ();
++ break;
++ }
++}
++
++/* Note: expression never gets compiled directly. Rather, it gets
++ * appended to the token list and then compiled by a calling
++ * routine.
++ */
++
++/* expression:
++ * simple_expression
++ * simple-expression , expression
++ * &lt;none&gt;
++ */
++static void expression_with_commas (_SLang_Token_Type *ctok, int save_comma)
++{
++ while (SLang_Error == 0)
++ {
++ if (ctok-&gt;type != COMMA_TOKEN)
++ {
++ if (ctok-&gt;type == CPAREN_TOKEN)
++ return;
++
++ simple_expression (ctok);
++
++ if (ctok-&gt;type != COMMA_TOKEN)
++ break;
++ }
++ if (save_comma) append_token (ctok);
++ get_token (ctok);
++ }
++}
++
++static void expression (_SLang_Token_Type *ctok)
++{
++ expression_with_commas (ctok, 0);
++}
++
++/* priority levels of binary operations */
++static unsigned char Binop_Level[] =
++{
++/* ADD_TOKEN */ 2,
++/* SUB_TOKEN */ 2,
++/* MUL_TOKEN */ 1,
++/* DIV_TOKEN */ 1,
++/* LT_TOKEN */ 4,
++/* LE_TOKEN */ 4,
++/* GT_TOKEN */ 4,
++/* GE_TOKEN */ 4,
++/* EQ_TOKEN */ 5,
++/* NE_TOKEN */ 5,
++/* AND_TOKEN */ 9,
++/* OR_TOKEN */ 10,
++/* MOD_TOKEN */ 1,
++/* BAND_TOKEN */ 6,
++/* SHL_TOKEN */ 3,
++/* SHR_TOKEN */ 3,
++/* BXOR_TOKEN */ 7,
++/* BOR_TOKEN */ 8,
++/* POUND_TOKEN */ 1 /* Matrix Multiplication */
++};
++
++/* % Note: simple-expression groups operators OP1 at same level. The
++ * % actual implementation will not do this.
++ * simple-expression:
++ * unary-expression
++ * binary-expression BINARY-OP unary-expression
++ * andelse xxelse-expression-list
++ * orelse xxelse-expression-list
++ *
++ * xxelse-expression-list:
++ * { expression }
++ * xxelse-expression-list { expression }
++ * binary-expression:
++ * unary-expression
++ * unary-expression BINARY-OP binary-expression
++ */
++static void simple_expression (_SLang_Token_Type *ctok)
++{
++ unsigned char type;
++ unsigned char op_stack [64];
++ unsigned char level_stack [64];
++ unsigned char level;
++ unsigned int op_num;
++
++ switch (ctok-&gt;type)
++ {
++ case ANDELSE_TOKEN:
++ case ORELSE_TOKEN:
++ type = ctok-&gt;type;
++ if (OBRACE_TOKEN != get_token (ctok))
++ {
++ _SLparse_error (&quot;Expecting '{'&quot;, ctok, 0);
++ return;
++ }
++
++ while (ctok-&gt;type == OBRACE_TOKEN)
++ {
++ append_token (ctok);
++ get_token (ctok);
++ expression (ctok);
++ if (CBRACE_TOKEN != ctok-&gt;type)
++ {
++ _SLparse_error(&quot;Expecting }&quot;, ctok, 0);
++ return;
++ }
++ append_token (ctok);
++ get_token (ctok);
++ }
++ append_token_of_type (type);
++ return;
++
++ /* avoid unary-expression if possible */
++ case STRING_TOKEN:
++ append_token (ctok);
++ get_token (ctok);
++ break;
++
++ default:
++ unary_expression (ctok);
++ break;
++ }
++
++ if (SEMICOLON_TOKEN == (type = ctok-&gt;type))
++ return;
++
++ op_num = 0;
++
++ while ((SLang_Error == 0)
++ &amp;&amp; (IS_BINARY_OP(type)))
++ {
++ level = Binop_Level[type - FIRST_BINARY_OP];
++
++ while ((op_num &gt; 0) &amp;&amp; (level_stack [op_num - 1] &lt;= level))
++ append_token_of_type (op_stack [--op_num]);
++
++ if (op_num &gt;= sizeof (op_stack) - 1)
++ {
++ _SLparse_error (&quot;Binary op stack overflow&quot;, ctok, 0);
++ return;
++ }
++
++ op_stack [op_num] = type;
++ level_stack [op_num] = level;
++ op_num++;
++
++ get_token (ctok);
++ unary_expression (ctok);
++ type = ctok-&gt;type;
++ }
++
++ while (op_num &gt; 0)
++ append_token_of_type(op_stack[--op_num]);
++}
++
++/* unary-expression:
++ * postfix-expression
++ * ++ postfix-expression
++ * -- postfix-expression
++ * case unary-expression
++ * OP3 unary-expression
++ * (OP3: + - ~ &amp; not @)
++ *
++ * Note: This grammar permits: case case case WHATEVER
++ */
++static void unary_expression (_SLang_Token_Type *ctok)
++{
++ unsigned char save_unary_ops [16];
++ unsigned int num_unary_ops;
++ unsigned char type;
++ _SLang_Token_Type *last_token;
++
++ num_unary_ops = 0;
++ while (SLang_Error == 0)
++ {
++ type = ctok-&gt;type;
++
++ switch (type)
++ {
++ case PLUSPLUS_TOKEN:
++ case MINUSMINUS_TOKEN:
++ get_token (ctok);
++ postfix_expression (ctok);
++ check_for_lvalue (type, NULL);
++ goto out_of_switch;
++
++ case ADD_TOKEN:
++ get_token (ctok); /* skip it-- it's unary here */
++ break;
++
++ case SUB_TOKEN:
++ (void) get_token (ctok);
++ if (IS_INTEGER_TOKEN (ctok-&gt;type))
++ {
++ ctok-&gt;v.long_val = -ctok-&gt;v.long_val;
++ break;
++ }
++
++ if (num_unary_ops == 16)
++ goto stack_overflow_error;
++ save_unary_ops [num_unary_ops++] = CHS_TOKEN;
++ break;
++
++ case DEREF_TOKEN:
++ case BNOT_TOKEN:
++ case NOT_TOKEN:
++ case CASE_TOKEN:
++ if (num_unary_ops == 16)
++ goto stack_overflow_error;
++
++ save_unary_ops [num_unary_ops++] = type;
++ get_token (ctok);
++ break;
++
++ /* Try to avoid -&gt;postfix_expression-&gt;primary_expression
++ * subroutine calls.
++ */
++ case STRING_TOKEN:
++ append_token (ctok);
++ get_token (ctok);
++ goto out_of_switch;
++
++ default:
++ postfix_expression (ctok);
++ goto out_of_switch;
++ }
++ }
++
++ out_of_switch:
++ if (num_unary_ops == 0)
++ return;
++
++ if ((DEREF_TOKEN == save_unary_ops[num_unary_ops - 1])
++ &amp;&amp; (NULL != (last_token = get_last_token ()))
++ &amp;&amp; (IS_ASSIGN_TOKEN(last_token-&gt;type)))
++ {
++ /* FIXME: Priority=medium
++ * This needs generalized so that things like @a.y = 1 will work properly.
++ */
++ if ((num_unary_ops != 1)
++ || (last_token-&gt;type != _SCALAR_ASSIGN_TOKEN))
++ {
++ SLang_verror (SL_NOT_IMPLEMENTED,
++ &quot;Only derefence assignments to simple variables are possible&quot;);
++ return;
++ }
++
++ last_token-&gt;type += (_DEREF_ASSIGN_TOKEN - _SCALAR_ASSIGN_TOKEN);
++ return;
++ }
++
++ while (num_unary_ops)
++ {
++ num_unary_ops--;
++ append_token_of_type (save_unary_ops [num_unary_ops]);
++ }
++ return;
++
++ stack_overflow_error:
++ _SLparse_error (&quot;Too many unary operators.&quot;, ctok, 0);
++}
++
++static int combine_namespace_tokens (_SLang_Token_Type *a, _SLang_Token_Type *b)
++{
++ char *sa, *sb, *sc;
++ unsigned int lena, lenb;
++ unsigned long hash;
++
++ /* This is somewhat of a hack. Combine the TWO identifier names
++ * (NAMESPACE) and (name) into the form NAMESPACE-&gt;name. Then when the
++ * byte compiler compiles the object it will not be found. It will then
++ * check for this hack and make the appropriate namespace lookup.
++ */
++
++ sa = a-&gt;v.s_val;
++ sb = b-&gt;v.s_val;
++
++ lena = strlen (sa);
++ lenb = strlen (sb);
++
++ sc = SLmalloc (lena + lenb + 3);
++ if (sc == NULL)
++ return -1;
++
++ strcpy (sc, sa);
++ strcpy (sc + lena, &quot;-&gt;&quot;);
++ strcpy (sc + lena + 2, sb);
++
++ sb = _SLstring_make_hashed_string (sc, lena + lenb + 2, &amp;hash);
++ SLfree (sc);
++ if (sb == NULL)
++ return -1;
++
++ /* I can free this string because no other token should be referencing it.
++ * (num_refs == 1).
++ */
++ _SLfree_hashed_string (sa, lena, a-&gt;hash);
++ a-&gt;v.s_val = sb;
++ a-&gt;hash = hash;
++
++ return 0;
++}
++
++static void append_identifier_token (_SLang_Token_Type *ctok)
++{
++ _SLang_Token_Type *last_token;
++
++ append_token (ctok);
++
++ if (NAMESPACE_TOKEN != get_token (ctok))
++ return;
++
++ if (IDENT_TOKEN != get_token (ctok))
++ {
++ _SLparse_error (&quot;Expecting name-space identifier&quot;, ctok, 0);
++ return;
++ }
++
++ last_token = get_last_token ();
++ if (-1 == combine_namespace_tokens (last_token, ctok))
++ return;
++
++ (void) get_token (ctok);
++}
++
++static int get_identifier_expr_token (_SLang_Token_Type *ctok)
++{
++ _SLang_Token_Type next_token;
++
++ if (IDENT_TOKEN != get_identifier_token (ctok))
++ return -1;
++
++ init_token (&amp;next_token);
++ if (NAMESPACE_TOKEN != get_token (&amp;next_token))
++ {
++ unget_token (&amp;next_token);
++ return IDENT_TOKEN;
++ }
++
++ if (IDENT_TOKEN != get_identifier_token (&amp;next_token))
++ {
++ free_token (&amp;next_token);
++ return -1;
++ }
++
++ if (-1 == combine_namespace_tokens (ctok, &amp;next_token))
++ {
++ free_token (&amp;next_token);
++ return -1;
++ }
++ free_token (&amp;next_token);
++ return IDENT_TOKEN;
++}
++
++/* postfix-expression:
++ * primary-expression
++ * postfix-expression [ expression ]
++ * postfix-expression ( function-args-expression )
++ * postfix-expression . identifier
++ * postfix-expression ^ unary-expression
++ * postfix-expression ++
++ * postfix-expression --
++ * postfix-expression = simple-expression
++ * postfix-expression += simple-expression
++ * postfix-expression -= simple-expression
++ *
++ * primary-expression:
++ * literal
++ * identifier-expr
++ * ( expression_opt )
++ * [ inline-array-expression ]
++ * &amp;identifier-expr
++ * struct-definition
++ * __tmp(identifier-expr)
++ *
++ * identifier-expr:
++ * identifier
++ * identifier-&gt;identifier
++ */
++static void postfix_expression (_SLang_Token_Type *ctok)
++{
++ unsigned int start_pos, end_pos;
++ unsigned char type;
++
++ if (Token_List == NULL)
++ return;
++
++ start_pos = Token_List-&gt;len;
++
++ switch (ctok-&gt;type)
++ {
++ case IDENT_TOKEN:
++ append_identifier_token (ctok);
++ break;
++
++ case CHAR_TOKEN:
++ case SHORT_TOKEN:
++ case INT_TOKEN:
++ case LONG_TOKEN:
++ case UCHAR_TOKEN:
++ case USHORT_TOKEN:
++ case UINT_TOKEN:
++ case ULONG_TOKEN:
++ case STRING_TOKEN:
++ case BSTRING_TOKEN:
++#ifdef SLANG_HAS_FLOAT
++ case DOUBLE_TOKEN:
++ case FLOAT_TOKEN:
++#endif
++#ifdef SLANG_HAS_COMPLEX
++ case COMPLEX_TOKEN:
++#endif
++ append_token (ctok);
++ get_token (ctok);
++ break;
++
++ case OPAREN_TOKEN:
++ if (CPAREN_TOKEN != get_token (ctok))
++ {
++ expression (ctok);
++ if (ctok-&gt;type != CPAREN_TOKEN)
++ _SLparse_error(&quot;Expecting )&quot;, ctok, 0);
++ }
++ get_token (ctok);
++ break;
++
++ case BAND_TOKEN:
++ if (IDENT_TOKEN != get_identifier_expr_token (ctok))
++ break;
++
++ ctok-&gt;type = _REF_TOKEN;
++ append_token (ctok);
++ get_token (ctok);
++ break;
++
++ case OBRACKET_TOKEN:
++ get_token (ctok);
++ inline_array_expression (ctok);
++ break;
++
++ case NO_OP_LITERAL:
++ /* This token was introduced by try_multiple_assignment. There,
++ * a new token_list was pushed and (expression) was evaluated.
++ * NO_OP_LITERAL represents the result of expression. However,
++ * we need to tweak the start_pos variable to point to the beginning
++ * of the token list to complete the equivalence.
++ */
++ start_pos = 0;
++ get_token (ctok);
++ break;
++
++ case STRUCT_TOKEN:
++ get_token (ctok);
++ struct_declaration (ctok);
++ break;
++
++ case TMP_TOKEN:
++ get_token (ctok);
++ if (ctok-&gt;type == OPAREN_TOKEN)
++ {
++ if (IDENT_TOKEN == get_identifier_expr_token (ctok))
++ {
++ ctok-&gt;type = TMP_TOKEN;
++ append_token (ctok);
++ get_token (ctok);
++ if (ctok-&gt;type == CPAREN_TOKEN)
++ {
++ get_token (ctok);
++ break;
++ }
++ }
++ }
++ _SLparse_error (&quot;Expecting form __tmp(NAME)&quot;, ctok, 0);
++ break;
++
++ default:
++ if (IS_INTERNAL_FUNC(ctok-&gt;type))
++ {
++ append_token (ctok);
++ get_token (ctok);
++ }
++ else
++ _SLparse_error(&quot;Expecting a PRIMARY&quot;, ctok, 0);
++ }
++
++ while (SLang_Error == 0)
++ {
++ end_pos = Token_List-&gt;len;
++ type = ctok-&gt;type;
++ switch (type)
++ {
++ case OBRACKET_TOKEN: /* X[args] ==&gt; [args] X ARRAY */
++ get_token (ctok);
++ append_token_of_type (ARG_TOKEN);
++ if (ctok-&gt;type != CBRACKET_TOKEN)
++ array_index_expression (ctok);
++
++ if (ctok-&gt;type != CBRACKET_TOKEN)
++ {
++ _SLparse_error (&quot;Expecting ']'&quot;, ctok, 0);
++ return;
++ }
++ get_token (ctok);
++ /* append_token_of_type (EARG_TOKEN); -- ARRAY_TOKEN implicitely does this */
++ token_list_element_exchange (start_pos, end_pos);
++ append_token_of_type (ARRAY_TOKEN);
++ break;
++
++ case OPAREN_TOKEN:
++ /* f(args) ==&gt; args f */
++ if (CPAREN_TOKEN != get_token (ctok))
++ {
++ function_args_expression (ctok, 1);
++ token_list_element_exchange (start_pos, end_pos);
++ }
++ else get_token (ctok);
++ break;
++
++ case DOT_TOKEN:
++ /* S.a ==&gt; &quot;a&quot; S DOT
++ * This means that if S is X[b], then X[b].a ==&gt; a b X ARRAY DOT
++ * and f(a).X[b].c ==&gt; &quot;c&quot; b &quot;X&quot; a f . ARRAY .
++ * Also, f(a).X[b] = g(x); ==&gt; x g b &quot;X&quot; a f .
++ */
++ if (IDENT_TOKEN != get_identifier_token (ctok))
++ return;
++
++ ctok-&gt;type = DOT_TOKEN;
++ append_token (ctok);
++ get_token (ctok);
++ break;
++
++ case PLUSPLUS_TOKEN:
++ case MINUSMINUS_TOKEN:
++ check_for_lvalue (type, NULL);
++ get_token (ctok);
++ break;
++
++ case ASSIGN_TOKEN:
++ case PLUSEQS_TOKEN:
++ case MINUSEQS_TOKEN:
++ case TIMESEQS_TOKEN:
++ case DIVEQS_TOKEN:
++ case BOREQS_TOKEN:
++ case BANDEQS_TOKEN:
++ check_for_lvalue (type, NULL);
++ get_token (ctok);
++ simple_expression (ctok);
++ token_list_element_exchange (start_pos, end_pos);
++ break;
++
++ case POW_TOKEN:
++ get_token (ctok);
++ unary_expression (ctok);
++ append_token_of_type (POW_TOKEN);
++ break;
++
++ default:
++ return;
++ }
++ }
++}
++
++static void function_args_expression (_SLang_Token_Type *ctok, int handle_num_args)
++{
++ unsigned char last_type, this_type;
++
++ if (handle_num_args) append_token_of_type (ARG_TOKEN);
++
++ last_type = COMMA_TOKEN;
++
++ while (SLang_Error == 0)
++ {
++ this_type = ctok-&gt;type;
++
++ switch (this_type)
++ {
++ case COMMA_TOKEN:
++ if (last_type == COMMA_TOKEN)
++ append_token_of_type (_NULL_TOKEN);
++ get_token (ctok);
++ break;
++
++ case CPAREN_TOKEN:
++ if (last_type == COMMA_TOKEN)
++ append_token_of_type (_NULL_TOKEN);
++ if (handle_num_args) append_token_of_type (EARG_TOKEN);
++ get_token (ctok);
++ return;
++
++ default:
++ simple_expression (ctok);
++ if ((ctok-&gt;type != COMMA_TOKEN)
++ &amp;&amp; (ctok-&gt;type != CPAREN_TOKEN))
++ {
++ _SLparse_error (&quot;Expecting ')'&quot;, ctok, 0);
++ break;
++ }
++ }
++ last_type = this_type;
++ }
++}
++
++static int check_for_lvalue (unsigned char eqs_type, _SLang_Token_Type *ctok)
++{
++ unsigned char type;
++
++ if ((ctok == NULL)
++ &amp;&amp; (NULL == (ctok = get_last_token ())))
++ return -1;
++
++ type = ctok-&gt;type;
++
++ eqs_type -= ASSIGN_TOKEN;
++
++ if (type == IDENT_TOKEN)
++ eqs_type += _SCALAR_ASSIGN_TOKEN;
++ else if (type == ARRAY_TOKEN)
++ eqs_type += _ARRAY_ASSIGN_TOKEN;
++ else if (type == DOT_TOKEN)
++ eqs_type += _STRUCT_ASSIGN_TOKEN;
++ else
++ {
++ _SLparse_error (&quot;Expecting LVALUE&quot;, ctok, 0);
++ return -1;
++ }
++
++ ctok-&gt;type = eqs_type;
++ return 0;
++}
++
++static void array_index_expression (_SLang_Token_Type *ctok)
++{
++ unsigned int num_commas;
++
++ num_commas = 0;
++ while (1)
++ {
++ switch (ctok-&gt;type)
++ {
++ case COLON_TOKEN:
++ if (num_commas)
++ _SLparse_error (&quot;Misplaced ':'&quot;, ctok, 0);
++ return;
++
++ case TIMES_TOKEN:
++ append_token_of_type (_INLINE_WILDCARD_ARRAY_TOKEN);
++ get_token (ctok);
++ break;
++
++ case COMMA_TOKEN:
++ _SLparse_error (&quot;Misplaced ','&quot;, ctok, 0);
++ return;
++
++ default:
++ simple_expression (ctok);
++ }
++
++ if (ctok-&gt;type != COMMA_TOKEN)
++ return;
++ num_commas++;
++ get_token (ctok);
++ }
++}
++
++/* inline-array-expression:
++ * array_index_expression
++ * simple_expression : simple_expression
++ * simple_expression : simple_expression : simple_expression
++ */
++static void inline_array_expression (_SLang_Token_Type *ctok)
++{
++ int num_colons = 0;
++
++ append_token_of_type (ARG_TOKEN);
++
++ if (ctok-&gt;type == COLON_TOKEN) /* [:...] */
++ append_token_of_type (_NULL_TOKEN);
++ else if (ctok-&gt;type != CBRACKET_TOKEN)
++ array_index_expression (ctok);
++
++ if (ctok-&gt;type == COLON_TOKEN)
++ {
++ num_colons++;
++ if ((COLON_TOKEN == get_token (ctok))
++ || (ctok-&gt;type == CBRACKET_TOKEN))
++ append_token_of_type (_NULL_TOKEN);
++ else
++ simple_expression (ctok);
++
++ if (ctok-&gt;type == COLON_TOKEN)
++ {
++ num_colons++;
++ get_token (ctok);
++ simple_expression (ctok);
++ }
++ }
++
++ if (ctok-&gt;type != CBRACKET_TOKEN)
++ {
++ _SLparse_error (&quot;Expecting ']'&quot;, ctok, 0);
++ return;
++ }
++
++ /* append_token_of_type (EARG_TOKEN); */
++ if (num_colons)
++ append_token_of_type (_INLINE_IMPLICIT_ARRAY_TOKEN);
++ else
++ append_token_of_type (_INLINE_ARRAY_TOKEN);
++ get_token (ctok);
++}
++
++static void do_multiple_assignment (_SLang_Token_Type *ctok)
++{
++ _SLang_Token_Type *s;
++ unsigned int i, k, len;
++ unsigned char assign_type;
++
++ assign_type = ctok-&gt;type;
++
++ /* The LHS token list has already been pushed. Here we do the RHS
++ * so push to another token list, process it, then come back to
++ * LHS for assignment.
++ */
++ if (NULL == push_token_list ())
++ return;
++
++ get_token (ctok);
++ expression (ctok);
++ compile_token_list ();
++
++ if (SLang_Error)
++ return;
++
++ /* Finally compile the LHS of the assignment expression
++ * that has been saved.
++ */
++ s = Token_List-&gt;stack;
++ len = Token_List-&gt;len;
++
++ if (len == 0)
++ {
++ compile_token_of_type (POP_TOKEN);
++ return;
++ }
++
++ while (len &gt; 0)
++ {
++ /* List is of form:
++ * a , b, c d e, f , g , , , h ,
++ * The missing expressions will be replaced by a POP
++ * ,,a
++ */
++
++ /* Start from back looking for a COMMA */
++ k = len - 1;
++ if (s[k].type == COMMA_TOKEN)
++ {
++ compile_token_of_type (POP_TOKEN);
++ len = k;
++ continue;
++ }
++
++ if (-1 == check_for_lvalue (assign_type, s + k))
++ return;
++
++ i = 0;
++ while (1)
++ {
++ if (s[k].type == COMMA_TOKEN)
++ {
++ i = k + 1;
++ break;
++ }
++
++ if (k == 0)
++ break;
++
++ k--;
++ }
++
++ while (i &lt; len)
++ {
++ compile_token (s + i);
++ i++;
++ }
++
++ len = k;
++ }
++
++ if (s[0].type == COMMA_TOKEN)
++ compile_token_of_type (POP_TOKEN);
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slparse.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slpath.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slpath.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slpath.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,344 @@
++/* Pathname and filename functions */
++/* Copyright (c) 1998, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++
++#ifdef HAVE_IO_H
++# include &lt;io.h&gt;
++#endif
++
++#include &lt;sys/types.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;signal.h&gt;
++#include &lt;time.h&gt;
++
++#include &lt;errno.h&gt;
++#include &lt;string.h&gt;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++/* In this file, all file names are assumed to be specified in the Unix
++ * format, or in the native format.
++ *
++ * Aboout VMS:
++ * VMS pathnames are a mess. In general, they look like
++ * node::device:[dir.dir]file.ext;version
++ * and I do not know of a well-defined Unix representation for them. So,
++ * I am going to punt and encourage users to stick to the native
++ * representation.
++ */
++
++#if defined(IBMPC_SYSTEM)
++# define PATH_SEP '\\'
++# define DRIVE_SPECIFIER ':'
++# define SEARCH_PATH_DELIMITER ';'
++# define THIS_DIR_STRING &quot;.&quot;
++#else
++# if defined(VMS)
++# define PATH_SEP ']'
++# define DRIVE_SPECIFIER ':'
++# define SEARCH_PATH_DELIMITER ' '
++# define THIS_DIR_STRING &quot;[]&quot; /* Is this correct?? */
++# else
++# define PATH_SEP '/'
++# define UNIX_PATHNAMES_OK
++# define SEARCH_PATH_DELIMITER ':'
++# define THIS_DIR_STRING &quot;.&quot;
++# endif
++#endif
++
++#ifdef UNIX_PATHNAMES_OK
++# define IS_PATH_SEP(x) ((x) == PATH_SEP)
++#else
++# define IS_PATH_SEP(x) (((x) == PATH_SEP) || ((x) == '/'))
++#endif
++
++/* If file is /a/b/c/basename, this function returns a pointer to basename */
++char *SLpath_basename (char *file)
++{
++ char *b;
++
++ if (file == NULL) return NULL;
++ b = file + strlen (file);
++
++ while (b != file)
++ {
++ b--;
++ if (IS_PATH_SEP(*b))
++ return b + 1;
++#ifdef DRIVE_SPECIFIER
++ if (*b == DRIVE_SPECIFIER)
++ return b + 1;
++#endif
++ }
++
++ return b;
++}
++
++/* Returns a malloced string */
++char *SLpath_pathname_sans_extname (char *file)
++{
++ char *b;
++
++ file = SLmake_string (file);
++ if (file == NULL)
++ return NULL;
++
++ b = file + strlen (file);
++
++ while (b != file)
++ {
++ b--;
++ if (*b == '.')
++ {
++ *b = 0;
++ return file;
++ }
++ }
++
++ return file;
++}
++
++/* If path looks like: A/B/C/D/whatever, it returns A/B/C/D as a malloced
++ * string.
++ */
++char *SLpath_dirname (char *file)
++{
++ char *b;
++
++ if (file == NULL) return NULL;
++ b = file + strlen (file);
++
++ while (b != file)
++ {
++ b--;
++ if (IS_PATH_SEP(*b))
++ {
++ if (b == file) b++;
++ break;
++ }
++
++#ifdef DRIVE_SPECIFIER
++ if (*b == DRIVE_SPECIFIER)
++ {
++ b++;
++ break;
++ }
++#endif
++ }
++
++ if (b == file)
++ return SLmake_string (THIS_DIR_STRING);
++
++ return SLmake_nstring (file, (unsigned int) (b - file));
++}
++
++/* Note: VMS filenames also contain version numbers. The caller will have
++ * to deal with that.
++ *
++ * The extension includes the '.'. If no extension is present, &quot;&quot; is returned.
++ */
++char *SLpath_extname (char *file)
++{
++ char *b;
++
++ if (NULL == (file = SLpath_basename (file)))
++ return NULL;
++
++ b = file + strlen (file);
++ while (b != file)
++ {
++ b--;
++ if (*b == '.')
++ return b;
++ }
++
++ if (*b == '.')
++ return b;
++
++ /* Do not return a literal &quot;&quot; */
++ return file + strlen (file);
++}
++
++#ifdef IBMPC_SYSTEM
++static void convert_slashes (char *f)
++{
++ while (*f)
++ {
++ if (*f == '/') *f = PATH_SEP;
++ f++;
++ }
++}
++#endif
++
++int SLpath_is_absolute_path (char *name)
++{
++#ifdef UNIX_PATHNAMES_OK
++ return (*name == '/');
++#else
++ if (IS_PATH_SEP (*name))
++ return 1;
++
++# ifdef DRIVE_SPECIFIER
++ /* Look for a drive specifier */
++ while (*name)
++ {
++ if (*name == DRIVE_SPECIFIER)
++ return 1;
++
++ name++;
++ }
++# endif
++
++ return 0;
++#endif
++}
++
++/* This returns a MALLOCED string */
++char *SLpath_dircat (char *dir, char *name)
++{
++ unsigned int len, dirlen;
++ char *file;
++#ifndef VMS
++ int requires_fixup;
++#endif
++
++ if (name == NULL)
++ name = &quot;&quot;;
++
++ if ((dir == NULL) || (SLpath_is_absolute_path (name)))
++ dir = &quot;&quot;;
++
++ /* Both VMS and MSDOS have default directories associated with each drive.
++ * That is, the meaning of something like C:X depends upon more than just
++ * the syntax of the string. Since this concept has more power under VMS
++ * it will be honored here. However, I am going to treat C:X as C:\X
++ * under MSDOS.
++ *
++ * Note!!!
++ * VMS has problems of its own regarding path names, so I am simply
++ * going to strcat. Hopefully the VMS RTL is smart enough to deal with
++ * the result.
++ */
++ dirlen = strlen (dir);
++#ifndef VMS
++ requires_fixup = (dirlen &amp;&amp; (0 == IS_PATH_SEP(dir[dirlen - 1])));
++#endif
++
++ len = dirlen + strlen (name) + 2;
++ if (NULL == (file = SLmalloc (len)))
++ return NULL;
++
++ strcpy (file, dir);
++
++#ifndef VMS
++ if (requires_fixup)
++ file[dirlen++] = PATH_SEP;
++#endif
++
++ strcpy (file + dirlen, name);
++
++#if defined(IBMPC_SYSTEM)
++ convert_slashes (file);
++#endif
++
++ return file;
++}
++
++int SLpath_file_exists (char *file)
++{
++ struct stat st;
++ int m;
++
++#if defined(__os2__) &amp;&amp; !defined(S_IFMT)
++/* IBM VA3 doesn't declare S_IFMT */
++# define S_IFMT (S_IFDIR | S_IFCHR | S_IFREG)
++#endif
++
++#ifdef _S_IFDIR
++# ifndef S_IFDIR
++# define S_IFDIR _S_IFDIR
++# endif
++#endif
++
++#ifndef S_ISDIR
++# ifdef S_IFDIR
++# define S_ISDIR(m) (((m) &amp; S_IFMT) == S_IFDIR)
++# else
++# define S_ISDIR(m) 0
++# endif
++#endif
++
++ if (file == NULL)
++ return -1;
++
++ if (stat(file, &amp;st) &lt; 0) return 0;
++ m = st.st_mode;
++
++ if (S_ISDIR(m)) return (2);
++ return 1;
++}
++
++char *SLpath_find_file_in_path (char *path, char *name)
++{
++ unsigned int max_path_len;
++ unsigned int this_path_len;
++ char *file, *dir;
++ char *p;
++ unsigned int nth;
++
++ if ((path == NULL) || (*path == 0)
++ || (name == NULL) || (*name == 0))
++ return NULL;
++
++ max_path_len = 0;
++ this_path_len = 0;
++ p = path;
++ while (*p != 0)
++ {
++ if (*p++ == SEARCH_PATH_DELIMITER)
++ {
++ if (this_path_len &gt; max_path_len) max_path_len = this_path_len;
++ this_path_len = 0;
++ }
++ else this_path_len++;
++ }
++ if (this_path_len &gt; max_path_len) max_path_len = this_path_len;
++ max_path_len++;
++
++ if (NULL == (dir = SLmalloc (max_path_len)))
++ return NULL;
++
++ nth = 0;
++ while (-1 != SLextract_list_element (path, nth, SEARCH_PATH_DELIMITER,
++ dir, max_path_len))
++ {
++ nth++;
++ if (*dir == 0)
++ continue;
++
++ if (NULL == (file = SLpath_dircat (dir, name)))
++ {
++ SLfree (dir);
++ return NULL;
++ }
++
++ if (1 == SLpath_file_exists (file))
++ {
++ SLfree (dir);
++ return file;
++ }
++
++ SLfree (file);
++ }
++
++ SLfree (dir);
++ return NULL;
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slpath.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slposdir.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slposdir.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slposdir.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1057 @@
++/* file intrinsics for S-Lang */
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++
++#if defined(__unix__) || (defined (__os2__) &amp;&amp; defined (__EMX__))
++# include &lt;sys/types.h&gt;
++#endif
++
++#ifdef HAVE_IO_H
++# include &lt;io.h&gt; /* for chmod */
++#endif
++
++#if defined(__BORLANDC__)
++# include &lt;process.h&gt;
++# include &lt;dos.h&gt;
++#endif
++
++#ifdef HAVE_FCNTL_H
++# include &lt;fcntl.h&gt;
++#endif
++#ifdef HAVE_SYS_FCNTL_H
++# include &lt;sys/fcntl.h&gt;
++#endif
++
++#ifdef __unix__
++# include &lt;sys/file.h&gt;
++#endif
++
++#if defined(__BORLANDC__)
++# include &lt;dir.h&gt;
++#endif
++
++#if defined(_MSC_VER)
++# include &lt;io.h&gt;
++#endif
++
++#if defined(__DECC) &amp;&amp; defined(VMS)
++# include &lt;unixio.h&gt;
++# include &lt;unixlib.h&gt;
++#endif
++
++#ifdef VMS
++# include &lt;stat.h&gt;
++#else
++# include &lt;sys/stat.h&gt;
++#endif
++
++#if defined(VMS)
++# define USE_LISTDIR_INTRINSIC 0
++#else
++# define USE_LISTDIR_INTRINSIC 1
++#endif
++
++#if USE_LISTDIR_INTRINSIC
++
++#if defined(__WIN32__)
++# include &lt;windows.h&gt;
++#else
++# if defined(__OS2__) &amp;&amp; defined(__IBMC__)
++# define INCL_DOS
++# define INCL_ERRORS
++# include &lt;os2.h&gt;
++# include &lt;direct.h&gt;
++# include &lt;ctype.h&gt;
++# else
++# ifdef HAVE_DIRENT_H
++# include &lt;dirent.h&gt;
++# else
++# ifdef HAVE_DIRECT_H
++# include &lt;direct.h&gt;
++# else
++# define dirent direct
++# define NEED_D_NAMLEN
++# if HAVE_SYS_NDIR_H
++# include &lt;sys/ndir.h&gt;
++# endif
++# if HAVE_SYS_DIR_H
++# include &lt;sys/dir.h&gt;
++# endif
++# if HAVE_NDIR_H
++# include &lt;ndir.h&gt;
++# endif
++# endif
++# endif
++# endif
++#endif
++
++#endif /* USE_LISTDIR_INTRINSIC */
++
++#include &lt;errno.h&gt;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++static int push_stat_struct (struct stat *st, int opt_attrs)
++{
++ char *field_names [12];
++ unsigned char field_types[12];
++ VOID_STAR field_values [12];
++ int int_values [12];
++ unsigned int i;
++
++ field_names [0] = &quot;st_dev&quot;; int_values [0] = (int) st-&gt;st_dev;
++ field_names [1] = &quot;st_ino&quot;; int_values [1] = (int) st-&gt;st_ino;
++ field_names [2] = &quot;st_mode&quot;; int_values [2] = (int) st-&gt;st_mode;
++ field_names [3] = &quot;st_nlink&quot;; int_values [3] = (int) st-&gt;st_nlink;
++ field_names [4] = &quot;st_uid&quot;; int_values [4] = (int) st-&gt;st_uid;
++ field_names [5] = &quot;st_gid&quot;; int_values [5] = (int) st-&gt;st_gid;
++ field_names [6] = &quot;st_rdev&quot;; int_values [6] = (int) st-&gt;st_rdev;
++ field_names [7] = &quot;st_size&quot;; int_values [7] = (int) st-&gt;st_size;
++ field_names [8] = &quot;st_atime&quot;; int_values [8] = (int) st-&gt;st_atime;
++ field_names [9] = &quot;st_mtime&quot;; int_values [9] = (int) st-&gt;st_mtime;
++ field_names [10] = &quot;st_ctime&quot;; int_values [10] = (int) st-&gt;st_ctime;
++
++ field_names [11] = &quot;st_opt_attrs&quot;; int_values[11] = opt_attrs;
++
++ for (i = 0; i &lt; 12; i++)
++ {
++ field_types [i] = SLANG_INT_TYPE;
++ field_values [i] = (VOID_STAR) (int_values + i);
++ }
++
++ return SLstruct_create_struct (12, field_names, field_types, field_values);
++}
++
++static void stat_cmd (char *file)
++{
++ struct stat st;
++ int status;
++ int opt_attrs;
++
++ status = stat (file, &amp;st);
++
++#if defined(__MSDOS__) || defined(__WIN32__)
++ if (status == -1)
++ {
++ unsigned int len = strlen (file);
++ if (len &amp;&amp; ((file[len-1] == '\\') || (file[len-1] == '/')))
++ {
++ file = SLmake_nstring (file, len-1);
++ if (file == NULL)
++ return;
++
++ status = stat (file, &amp;st);
++ SLfree (file);
++ }
++ }
++#endif
++ if (status == -1)
++ {
++ _SLerrno_errno = errno;
++ SLang_push_null ();
++ return;
++ }
++
++#ifdef __WIN32__
++ opt_attrs = GetFileAttributes (file);
++#else
++ opt_attrs = 0;
++#endif
++
++ push_stat_struct (&amp;st, opt_attrs);
++}
++
++static void lstat_cmd (char *file)
++{
++#ifdef HAVE_LSTAT
++ struct stat st;
++ int opt_attrs;
++
++ if (-1 == lstat (file, &amp;st))
++ {
++ _SLerrno_errno = errno;
++ SLang_push_null ();
++ return;
++ }
++
++#ifdef __WIN32__
++ opt_attrs = GetFileAttributes (file);
++#else
++ opt_attrs = 0;
++#endif
++
++ push_stat_struct (&amp;st, opt_attrs);
++#else
++ stat_cmd (file);
++#endif
++}
++
++/* Well, it appears that on some systems, these are not defined. Here I
++ * provide them. These are derived from the Linux stat.h file.
++ */
++
++#ifdef __os2__
++# ifdef __IBMC__
++/* IBM VA3 doesn't declare S_IFMT */
++# define S_IFMT (S_IFDIR | S_IFCHR | S_IFREG)
++# endif
++#endif
++
++#ifndef S_ISLNK
++# ifdef S_IFLNK
++# define S_ISLNK(m) (((m) &amp; S_IFMT) == S_IFLNK)
++# else
++# define S_ISLNK(m) 0
++# endif
++#endif
++
++#ifndef S_ISREG
++# ifdef S_IFREG
++# define S_ISREG(m) (((m) &amp; S_IFMT) == S_IFREG)
++# else
++# define S_ISREG(m) 0
++# endif
++#endif
++
++#ifndef S_ISDIR
++# ifdef S_IFDIR
++# define S_ISDIR(m) (((m) &amp; S_IFMT) == S_IFDIR)
++# else
++# define S_ISDIR(m) 0
++# endif
++#endif
++
++#ifndef S_ISCHR
++# ifdef S_IFCHR
++# define S_ISCHR(m) (((m) &amp; S_IFMT) == S_IFCHR)
++# else
++# define S_ISCHR(m) 0
++# endif
++#endif
++
++#ifndef S_ISBLK
++# ifdef S_IFBLK
++# define S_ISBLK(m) (((m) &amp; S_IFMT) == S_IFBLK)
++# else
++# define S_ISBLK(m) 0
++# endif
++#endif
++
++#ifndef S_ISFIFO
++# ifdef S_IFIFO
++# define S_ISFIFO(m) (((m) &amp; S_IFMT) == S_IFIFO)
++# else
++# define S_ISFIFO(m) 0
++# endif
++#endif
++
++#ifndef S_ISSOCK
++# ifdef S_IFSOCK
++# define S_ISSOCK(m) (((m) &amp; S_IFMT) == S_IFSOCK)
++# else
++# define S_ISSOCK(m) 0
++# endif
++#endif
++
++static char stat_is_cmd (char *what, int *mode_ptr)
++{
++ int ret;
++ int st_mode = *mode_ptr;
++
++ if (!strcmp (what, &quot;sock&quot;)) ret = S_ISSOCK(st_mode);
++ else if (!strcmp (what, &quot;fifo&quot;)) ret = S_ISFIFO(st_mode);
++ else if (!strcmp (what, &quot;blk&quot;)) ret = S_ISBLK(st_mode);
++ else if (!strcmp (what, &quot;chr&quot;)) ret = S_ISCHR(st_mode);
++ else if (!strcmp (what, &quot;dir&quot;)) ret = S_ISDIR(st_mode);
++ else if (!strcmp (what, &quot;reg&quot;)) ret = S_ISREG(st_mode);
++ else if (!strcmp (what, &quot;lnk&quot;)) ret = S_ISLNK(st_mode);
++ else
++ {
++ SLang_verror (SL_INVALID_PARM, &quot;stat_is: Unrecognized type: %s&quot;, what);
++ return -1;
++ }
++
++ return (char) (ret != 0);
++}
++
++#ifdef HAVE_READLINK
++static void readlink_cmd (char *s)
++{
++ char buf[2048];
++ int n;
++
++ n = readlink (s, buf, sizeof (buf)-1);
++ if (n == -1)
++ {
++ _SLerrno_errno = errno;
++ s = NULL;
++ }
++ else
++ {
++ buf[n] = 0;
++ s = buf;
++ }
++
++ (void) SLang_push_string (s);
++}
++#endif
++
++static int chmod_cmd (char *file, int *mode)
++{
++ if (-1 == chmod(file, (mode_t) *mode))
++ {
++ _SLerrno_errno = errno;
++ return -1;
++ }
++ return 0;
++}
++
++#ifdef HAVE_CHOWN
++static int chown_cmd (char *file, int *owner, int *group)
++{
++ int ret;
++
++ if (-1 == (ret = chown(file, (uid_t) *owner, (gid_t) *group)))
++ _SLerrno_errno = errno;
++ return ret;
++}
++#endif
++
++/* add trailing slash to dir */
++static void fixup_dir (char *dir)
++{
++#ifndef VMS
++ int n;
++
++ if ((n = strlen(dir)) &gt; 1)
++ {
++ n--;
++#if defined(IBMPC_SYSTEM)
++ if ( dir[n] != '/' &amp;&amp; dir[n] != '\\' )
++ strcat(dir, &quot;\\&quot; );
++#else
++ if (dir[n] != '/' )
++ strcat(dir, &quot;/&quot; );
++#endif
++ }
++#endif /* !VMS */
++}
++
++static void slget_cwd (void)
++{
++ char cwd[1024];
++ char *p;
++
++#ifndef HAVE_GETCWD
++ p = getwd (cwd);
++#else
++# if defined (__EMX__)
++ p = _getcwd2(cwd, 1022); /* includes drive specifier */
++# else
++ p = getcwd(cwd, 1022); /* djggp includes drive specifier */
++# endif
++#endif
++
++ if (p == NULL)
++ {
++ _SLerrno_errno = errno;
++ SLang_push_null ();
++ return;
++ }
++
++#ifndef VMS
++#ifdef __GO32__
++ /* You never know about djgpp since it favors unix */
++ {
++ char ch;
++ p = cwd;
++ while ((ch = *p) != 0)
++ {
++ if (ch == '/') *p = '\\';
++ p++;
++ }
++ }
++#endif
++ fixup_dir (cwd);
++#endif
++ SLang_push_string (cwd);
++}
++
++static int chdir_cmd (char *s)
++{
++ int ret;
++
++ while (-1 == (ret = chdir (s)))
++ {
++#ifdef EINTR
++ if (errno == EINTR)
++ continue;
++#endif
++ _SLerrno_errno = errno;
++ break;
++ }
++ return ret;
++}
++
++#ifdef VMS
++static int remove_cmd (char *);
++/* If the file looks like xxx, then change it to xxx.dir. If
++ * it looks like A:[B.xxx] then change it to A:[B]xxx.dir.
++ */
++
++static char *vms_convert_dirspec_to_vms_dir (char *str)
++{
++ char *s;
++ char *version;
++ unsigned int len;
++ char *dot;
++
++ len = strlen (str);
++
++ version = strchr (str, ';');
++ if (version == NULL)
++ version = str + len;
++ /* version points to the version of the input string */
++
++
++ if (NULL == (s = SLmalloc (len + 8)))/* allow extra space to work with */
++ return NULL;
++
++ len = (unsigned int) (version - str);
++ strncpy (s, str, len);
++ s[len] = 0;
++ str = s;
++
++ /* Lowercase the whole thing */
++ while (*s != 0)
++ {
++ *s = LOWER_CASE(*s);
++ s++;
++ }
++
++ if ((s &gt; str)
++ &amp;&amp; (s[-1] != ']'))
++ {
++ if ((s &gt;= str + 4)
++ &amp;&amp; (0 == strcmp (s - 4, &quot;.dir&quot;)))
++ s -= 4;
++ goto add_dir_version;
++ }
++
++ /* Check for one of two possibilities:
++ *
++ * dev:[x] --&gt; dev:x
++ * dev:[a.x] --&gt; dev:[a]x
++ */
++
++ if (NULL == (dot = strchr (str, '.')))
++ {
++ /* First possibility */
++ if (NULL == (s = strchr (str, '[')))
++ return str; /* let someone else figure this out */
++ while (s[1] != ']')
++ {
++ s[0] = s[1];
++ s++;
++ }
++ *s = 0;
++ goto add_dir_version;
++ }
++
++ while (NULL != (s = strchr (dot + 1, '.')))
++ dot = s;
++
++ *dot = ']';
++ s = str + (len - 1);
++
++ /* Drop */
++
++ add_dir_version:
++ strcpy (s, &quot;.dir&quot;);
++ strcpy (s+4, version);
++ return str;
++}
++#endif
++
++static int rmdir_cmd (char *s)
++{
++#ifdef VMS
++ int status;
++
++ if (NULL == (s = vms_convert_dirspec_to_vms_dir (s)))
++ return -1;
++
++ status = remove_cmd (s);
++ SLfree (s);
++
++ return status;
++
++#else
++ int ret;
++
++ while (-1 == (ret = rmdir (s)))
++ {
++#ifdef EINTR
++ if (errno == EINTR)
++ continue;
++#endif
++ _SLerrno_errno = errno;
++ break;
++ }
++ return ret;
++#endif
++}
++
++static int remove_cmd (char *s)
++{
++ int ret;
++#ifdef VMS
++# define REMOVE delete
++#else
++# ifdef REAL_UNIX_SYSTEM
++# define REMOVE unlink
++# else
++# define REMOVE remove
++# endif
++#endif
++
++ while (-1 == (ret = REMOVE (s)))
++ {
++#ifdef EINTR
++ if (errno == EINTR)
++ continue;
++#endif
++ _SLerrno_errno = errno;
++ break;
++ }
++ return ret;
++}
++
++static int rename_cmd (char *oldpath, char *newpath)
++{
++ int ret;
++ while (-1 == (ret = rename (oldpath, newpath)))
++ {
++#ifdef EINTR
++ if (errno == EINTR)
++ continue;
++#endif
++ _SLerrno_errno = errno;
++ break;
++ }
++ return ret;
++}
++
++static int mkdir_cmd (char *s, int *mode_ptr)
++{
++ int ret;
++
++ (void) mode_ptr;
++ errno = 0;
++
++#if defined (__MSDOS__) &amp;&amp; !defined(__GO32__)
++# define MKDIR(x,y) mkdir(x)
++#else
++# if defined (__os2__) &amp;&amp; !defined (__EMX__)
++# define MKDIR(x,y) mkdir(x)
++# else
++# if defined (__WIN32__) &amp;&amp; !defined (__CYGWIN32__)
++# define MKDIR(x,y) mkdir(x)
++# else
++# define MKDIR mkdir
++# endif
++# endif
++#endif
++
++ while (-1 == (ret = MKDIR(s, *mode_ptr)))
++ {
++#ifdef EINTR
++ if (errno == EINTR)
++ continue;
++#endif
++ _SLerrno_errno = errno;
++ break;
++ }
++ return ret;
++}
++
++#ifdef HAVE_MKFIFO
++static int mkfifo_cmd (char *path, int *mode)
++{
++ if (-1 == mkfifo (path, *mode))
++ {
++ _SLerrno_errno = errno;
++ return -1;
++ }
++ return 0;
++}
++#endif
++
++#if USE_LISTDIR_INTRINSIC
++
++static void free_dir_list (char **list, unsigned int num)
++{
++ unsigned int i;
++
++ if (list == NULL)
++ return;
++
++ for (i = 0; i &lt; num; i++)
++ SLang_free_slstring (list[i]);
++ SLfree ((char *) list);
++}
++
++#if defined(__WIN32__) || defined(__os2__) &amp;&amp; defined(__IBMC__)
++static int build_dirlist (char *file, char *opt, char ***listp, unsigned int *nump, unsigned int *maxnum)
++{
++# ifdef __WIN32__
++ DWORD status;
++ HANDLE h;
++ WIN32_FIND_DATA fd;
++# else
++ APIRET rc;
++ FILESTATUS3 status;
++ HDIR h;
++ FILEFINDBUF3 fd;
++ ULONG cFileNames;
++# endif
++ char *pat;
++ unsigned int len;
++ char **list;
++ unsigned int num;
++ unsigned int max_num;
++ int hok;
++
++ /* If an option is present, assume ok to list hidden files. Later
++ * I will formalize this.
++ */
++ hok = (opt != NULL);
++
++# ifdef __WIN32__
++ status = GetFileAttributes (file);
++# else
++ rc = DosQueryPathInfo(file, FIL_STANDARD, &amp;status, sizeof(FILESTATUS3));
++# endif
++
++
++# ifdef __WIN32__
++ if (status == (DWORD)-1)
++ {
++ _SLerrno_errno = ENOENT;
++ return -1;
++ }
++ if (0 == (status &amp; FILE_ATTRIBUTE_DIRECTORY))
++ {
++ _SLerrno_errno = ENOTDIR;
++ return -1;
++ }
++# else
++ if ((rc != 0) || (status.attrFile &amp; FILE_DIRECTORY) == 0)
++ {
++ /* ENOTDIR isn't defined in VA3. */
++ _SLerrno_errno = ENOENT;
++ return -1;
++ }
++# endif
++
++ len = strlen (file);
++ pat = SLmalloc (len + 3);
++ if (pat == NULL)
++ return -1;
++
++ strcpy (pat, file);
++ file = pat;
++ while (*file != 0)
++ {
++ if (*file == '/') *file = '\\';
++ file++;
++ }
++
++ if (len &amp;&amp; (pat[len-1] != '\\'))
++ {
++ pat[len] = '\\';
++ len++;
++ }
++ pat[len++] = '*';
++ pat[len] = 0;
++
++ num = 0;
++ max_num = 50;
++ list = (char **)SLmalloc (max_num * sizeof(char *));
++ if (list == NULL)
++ {
++ SLfree (pat);
++ return -1;
++ }
++
++# ifdef __WIN32__
++ h = FindFirstFile(pat, &amp;fd);
++ if (h == INVALID_HANDLE_VALUE)
++ {
++ if (ERROR_NO_MORE_FILES != GetLastError())
++ {
++ SLfree (pat);
++ SLfree ((char *)list);
++ return -1;
++ }
++ }
++# else
++ h = HDIR_CREATE;
++ cFileNames = 1;
++ rc = DosFindFirst(pat, &amp;h, FILE_READONLY | FILE_DIRECTORY |
++ FILE_ARCHIVED, &amp;fd, sizeof(fd), &amp;cFileNames, FIL_STANDARD);
++ if (rc != 0)
++ {
++ if (rc != ERROR_NO_MORE_FILES)
++ {
++ SLfree (pat);
++ SLfree ((char *)list);
++ return -1;
++ }
++ }
++# endif
++ else while (1)
++ {
++ /* Do not include hidden files in the list. Also, do not
++ * include &quot;.&quot; and &quot;..&quot; entries.
++ */
++#ifdef __WIN32__
++ file = fd.cFileName;
++#else
++ file = fd.achName;
++#endif
++ if (
++#ifdef __WIN32__
++ (hok || (0 == (fd.dwFileAttributes &amp; FILE_ATTRIBUTE_HIDDEN)))
++#else
++ (hok || (0 == (fd.attrFile &amp; FILE_HIDDEN)))
++#endif
++ &amp;&amp; ((*file != '.')
++ || ((0 != strcmp (file, &quot;.&quot;))
++ &amp;&amp; (0 != strcmp (file, &quot;..&quot;)))))
++ {
++ if (num == max_num)
++ {
++ char **new_list;
++
++ max_num += 100;
++ new_list = (char **)SLrealloc ((char *)list, max_num * sizeof (char *));
++ if (new_list == NULL)
++ goto return_error;
++
++ list = new_list;
++ }
++
++ file = SLang_create_slstring (file);
++ if (file == NULL)
++ goto return_error;
++
++ list[num] = file;
++ num++;
++ }
++
++#ifdef __WIN32__
++ if (FALSE == FindNextFile(h, &amp;fd))
++ {
++ if (ERROR_NO_MORE_FILES == GetLastError())
++ {
++ FindClose (h);
++ break;
++ }
++
++ _SLerrno_errno = errno;
++ FindClose (h);
++ goto return_error;
++ }
++#else
++ cFileNames = 1;
++ rc = DosFindNext(h, &amp;fd, sizeof(fd), &amp;cFileNames);
++ if (rc != 0)
++ {
++ if (rc == ERROR_NO_MORE_FILES)
++ {
++ DosFindClose (h);
++ break;
++ }
++
++ _SLerrno_errno = errno;
++ DosFindClose (h);
++ goto return_error;
++ }
++#endif
++ }
++
++ SLfree (pat);
++ *maxnum = max_num;
++ *nump = num;
++ *listp = list;
++ return 0;
++
++ return_error:
++ free_dir_list (list, num);
++ SLfree (pat);
++ return -1;
++}
++
++#else /* NOT __WIN32__ */
++
++static int build_dirlist (char *dir, char *opt, char ***listp, unsigned int *nump, unsigned int *maxnum)
++{
++ DIR *dp;
++ struct dirent *ep;
++ unsigned int num_files;
++ unsigned int max_num_files;
++ char **list;
++
++ (void) opt;
++
++ if (NULL == (dp = opendir (dir)))
++ {
++ _SLerrno_errno = errno;
++ return -1;
++ }
++
++ num_files = max_num_files = 0;
++ list = NULL;
++ while (NULL != (ep = readdir (dp)))
++ {
++ unsigned int len;
++ char *name;
++
++ name = ep-&gt;d_name;
++# ifdef NEED_D_NAMLEN
++ len = ep-&gt;d_namlen;
++# else
++ len = strlen (name);
++# endif
++ if ((*name == '.') &amp;&amp; (len &lt;= 2))
++ {
++ if (len == 1) continue;
++ if (name [1] == '.') continue;
++ }
++
++ if (num_files == max_num_files)
++ {
++ char **new_list;
++
++ max_num_files += 100;
++ if (NULL == (new_list = (char **) SLrealloc ((char *)list, max_num_files * sizeof(char *))))
++ goto return_error;
++
++ list = new_list;
++ }
++
++ if (NULL == (list[num_files] = SLang_create_nslstring (name, len)))
++ goto return_error;
++
++ num_files++;
++ }
++
++ closedir (dp);
++ *nump = num_files;
++ *maxnum = max_num_files;
++ *listp = list;
++ return 0;
++
++ return_error:
++ if (dp != NULL)
++ closedir (dp);
++ free_dir_list (list, num_files);
++ return -1;
++}
++# endif /* NOT __WIN32__ */
++
++static void listdir_cmd (char *dir, char *opt)
++{
++ SLang_Array_Type *at;
++ unsigned int num_files;
++ unsigned int max_num_files;
++ int inum_files;
++ char **list;
++
++ if (-1 == build_dirlist (dir, opt, &amp;list, &amp;num_files, &amp;max_num_files))
++ {
++ SLang_push_null ();
++ return;
++ }
++ /* If max_num_files == 0, then num_files == 0 and list == NULL.
++ * The realloc step below will malloc list for us.
++ */
++ if (num_files + 1 &lt; max_num_files)
++ {
++ char **new_list;
++ if (NULL == (new_list = (char **) SLrealloc ((char *)list, (num_files + 1)* sizeof(char*))))
++ {
++ free_dir_list (list, num_files);
++ SLang_push_null ();
++ return;
++ }
++ list = new_list;
++ }
++
++ inum_files = (int) num_files;
++ if (NULL == (at = SLang_create_array (SLANG_STRING_TYPE, 0, (VOID_STAR) list, &amp;inum_files, 1)))
++ {
++ free_dir_list (list, num_files);
++ SLang_push_null ();
++ return;
++ }
++
++ /* Allow the array to free this list if push fails */
++ if (-1 == SLang_push_array (at, 1))
++ SLang_push_null ();
++}
++
++static void listdir_cmd_wrap (void)
++{
++ char *s, *sopt;
++
++ sopt = NULL;
++ switch (SLang_Num_Function_Args)
++ {
++ case 2:
++ if (-1 == SLang_pop_slstring (&amp;sopt))
++ return;
++ case 1:
++ if (-1 == SLang_pop_slstring (&amp;s))
++ {
++ SLang_free_slstring (sopt);
++ return;
++ }
++ break;
++ default:
++ SLang_verror (SL_INVALID_PARM, &quot;usage: listdir (string, [opt-string]&quot;);
++ return;
++ }
++
++ listdir_cmd (s, sopt);
++ SLang_free_slstring (s);
++ SLang_free_slstring (sopt);
++}
++
++#endif /* USE_LISTDIR_INTRINSIC */
++
++#ifdef HAVE_UMASK
++static int umask_cmd (int *u)
++{
++ return umask (*u);
++}
++#endif
++
++static SLang_Intrin_Fun_Type PosixDir_Name_Table [] =
++{
++#ifdef HAVE_READLINK
++ MAKE_INTRINSIC_S(&quot;readlink&quot;, readlink_cmd, SLANG_VOID_TYPE),
++#endif
++ MAKE_INTRINSIC_S(&quot;lstat_file&quot;, lstat_cmd, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_S(&quot;stat_file&quot;, stat_cmd, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_SI(&quot;stat_is&quot;, stat_is_cmd, SLANG_CHAR_TYPE),
++#ifdef HAVE_MKFIFO
++ MAKE_INTRINSIC_SI(&quot;mkfifo&quot;, mkfifo_cmd, SLANG_INT_TYPE),
++#endif
++#ifdef HAVE_CHOWN
++ MAKE_INTRINSIC_SII(&quot;chown&quot;, chown_cmd, SLANG_INT_TYPE),
++#endif
++ MAKE_INTRINSIC_SI(&quot;chmod&quot;, chmod_cmd, SLANG_INT_TYPE),
++#ifdef HAVE_UMASK
++ MAKE_INTRINSIC_I(&quot;umask&quot;, umask_cmd, SLANG_INT_TYPE),
++#endif
++ MAKE_INTRINSIC_0(&quot;getcwd&quot;, slget_cwd, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_SI(&quot;mkdir&quot;, mkdir_cmd, SLANG_INT_TYPE),
++ MAKE_INTRINSIC_S(&quot;chdir&quot;, chdir_cmd, SLANG_INT_TYPE),
++ MAKE_INTRINSIC_S(&quot;rmdir&quot;, rmdir_cmd, SLANG_INT_TYPE),
++ MAKE_INTRINSIC_S(&quot;remove&quot;, remove_cmd, SLANG_INT_TYPE),
++ MAKE_INTRINSIC_SS(&quot;rename&quot;, rename_cmd, SLANG_INT_TYPE),
++#if USE_LISTDIR_INTRINSIC
++ MAKE_INTRINSIC(&quot;listdir&quot;, listdir_cmd_wrap, SLANG_VOID_TYPE, 0),
++#endif
++ SLANG_END_INTRIN_FUN_TABLE
++};
++
++static SLang_IConstant_Type PosixDir_Consts [] =
++{
++#ifndef S_IRWXU
++# define S_IRWXU 00700
++#endif
++ MAKE_ICONSTANT(&quot;S_IRWXU&quot;, S_IRWXU),
++#ifndef S_IRUSR
++# define S_IRUSR 00400
++#endif
++ MAKE_ICONSTANT(&quot;S_IRUSR&quot;, S_IRUSR),
++#ifndef S_IWUSR
++# define S_IWUSR 00200
++#endif
++ MAKE_ICONSTANT(&quot;S_IWUSR&quot;, S_IWUSR),
++#ifndef S_IXUSR
++# define S_IXUSR 00100
++#endif
++ MAKE_ICONSTANT(&quot;S_IXUSR&quot;, S_IXUSR),
++#ifndef S_IRWXG
++# define S_IRWXG 00070
++#endif
++ MAKE_ICONSTANT(&quot;S_IRWXG&quot;, S_IRWXG),
++#ifndef S_IRGRP
++# define S_IRGRP 00040
++#endif
++ MAKE_ICONSTANT(&quot;S_IRGRP&quot;, S_IRGRP),
++#ifndef S_IWGRP
++# define S_IWGRP 00020
++#endif
++ MAKE_ICONSTANT(&quot;S_IWGRP&quot;, S_IWGRP),
++#ifndef S_IXGRP
++# define S_IXGRP 00010
++#endif
++ MAKE_ICONSTANT(&quot;S_IXGRP&quot;, S_IXGRP),
++#ifndef S_IRWXO
++# define S_IRWXO 00007
++#endif
++ MAKE_ICONSTANT(&quot;S_IRWXO&quot;, S_IRWXO),
++#ifndef S_IROTH
++# define S_IROTH 00004
++#endif
++ MAKE_ICONSTANT(&quot;S_IROTH&quot;, S_IROTH),
++#ifndef S_IWOTH
++# define S_IWOTH 00002
++#endif
++ MAKE_ICONSTANT(&quot;S_IWOTH&quot;, S_IWOTH),
++#ifndef S_IXOTH
++# define S_IXOTH 00001
++#endif
++ MAKE_ICONSTANT(&quot;S_IXOTH&quot;, S_IXOTH),
++#ifdef __WIN32__
++ MAKE_ICONSTANT(&quot;FILE_ATTRIBUTE_ARCHIVE&quot;, FILE_ATTRIBUTE_ARCHIVE),
++ MAKE_ICONSTANT(&quot;FILE_ATTRIBUTE_COMPRESSED&quot;, FILE_ATTRIBUTE_COMPRESSED),
++ MAKE_ICONSTANT(&quot;FILE_ATTRIBUTE_NORMAL&quot;, FILE_ATTRIBUTE_NORMAL),
++ MAKE_ICONSTANT(&quot;FILE_ATTRIBUTE_DIRECTORY&quot;, FILE_ATTRIBUTE_DIRECTORY),
++ MAKE_ICONSTANT(&quot;FILE_ATTRIBUTE_HIDDEN&quot;, FILE_ATTRIBUTE_HIDDEN),
++ MAKE_ICONSTANT(&quot;FILE_ATTRIBUTE_READONLY&quot;, FILE_ATTRIBUTE_READONLY),
++ MAKE_ICONSTANT(&quot;FILE_ATTRIBUTE_SYSTEM&quot;, FILE_ATTRIBUTE_SYSTEM),
++ MAKE_ICONSTANT(&quot;FILE_ATTRIBUTE_TEMPORARY&quot;, FILE_ATTRIBUTE_TEMPORARY),
++#endif
++ SLANG_END_ICONST_TABLE
++};
++
++static int Initialized;
++
++int SLang_init_posix_dir (void)
++{
++ if (Initialized)
++ return 0;
++
++ if ((-1 == SLadd_intrin_fun_table(PosixDir_Name_Table, &quot;__POSIX_DIR__&quot;))
++ || (-1 == SLadd_iconstant_table (PosixDir_Consts, NULL))
++ || (-1 == _SLerrno_init ()))
++ return -1;
++
++ Initialized = 1;
++
++ return 0;
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slposdir.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slposio.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slposio.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slposio.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,568 @@
++/* This module implements an interface to posix system calls */
++/* file stdio intrinsics for S-Lang */
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++
++#if defined(__unix__) || (defined (__os2__) &amp;&amp; defined (__EMX__))
++# include &lt;sys/types.h&gt;
++#endif
++
++#ifdef HAVE_FCNTL_H
++# include &lt;fcntl.h&gt;
++#endif
++#ifdef HAVE_SYS_FCNTL_H
++# include &lt;sys/fcntl.h&gt;
++#endif
++
++#ifdef __unix__
++# include &lt;sys/file.h&gt;
++#endif
++
++#ifdef HAVE_IO_H
++# include &lt;io.h&gt;
++#endif
++
++#if defined(__BORLANDC__)
++# include &lt;dir.h&gt;
++#endif
++
++#if defined(__DECC) &amp;&amp; defined(VMS)
++# include &lt;unixio.h&gt;
++# include &lt;unixlib.h&gt;
++#endif
++
++#ifdef VMS
++# include &lt;stat.h&gt;
++#else
++# include &lt;sys/stat.h&gt;
++#endif
++
++#include &lt;errno.h&gt;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++struct _SLFile_FD_Type
++{
++ char *name;
++ unsigned int num_refs; /* reference counting */
++ int fd;
++ SLang_MMT_Type *stdio_mmt; /* fdopen'd stdio object */
++
++ /* methods */
++ int (*close)(int);
++ int (*read) (int, char *, unsigned int *);
++ int (*write)(int, char *, unsigned int *);
++};
++
++static int close_method (int fd)
++{
++ return close (fd);
++}
++
++static int write_method (int fd, char *buf, unsigned int *nump)
++{
++ int num;
++
++ if (-1 == (num = write (fd, buf, *nump)))
++ {
++ *nump = 0;
++ return -1;
++ }
++
++ *nump = (unsigned int) num;
++ return 0;
++}
++
++static int read_method (int fd, char *buf, unsigned int *nump)
++{
++ int num;
++
++ num = read (fd, buf, *nump);
++ if (num == -1)
++ {
++ *nump = 0;
++ return -1;
++ }
++ *nump = (unsigned int) num;
++ return 0;
++}
++
++static int check_fd (int fd)
++{
++ if (fd == -1)
++ {
++#ifdef EBADF
++ _SLerrno_errno = EBADF;
++#endif
++ return -1;
++ }
++
++ return 0;
++}
++
++static int posix_close (SLFile_FD_Type *f)
++{
++ if (-1 == check_fd (f-&gt;fd))
++ return -1;
++
++ if ((f-&gt;close != NULL)
++ &amp;&amp; (-1 == f-&gt;close (f-&gt;fd)))
++ {
++ _SLerrno_errno = errno;
++ return -1;
++ }
++
++ if (f-&gt;stdio_mmt != NULL)
++ {
++ SLang_free_mmt (f-&gt;stdio_mmt);
++ f-&gt;stdio_mmt = NULL;
++ }
++
++ f-&gt;fd = -1;
++ return 0;
++}
++
++/* Usage: Uint write (f, buf); */
++static void posix_write (SLFile_FD_Type *f, SLang_BString_Type *bstr)
++{
++ unsigned int len;
++ char *p;
++
++ if ((-1 == check_fd (f-&gt;fd))
++ || (NULL == (p = (char *)SLbstring_get_pointer (bstr, &amp;len))))
++ {
++ SLang_push_integer (-1);
++ return;
++ }
++
++ if (-1 == f-&gt;write (f-&gt;fd, p, &amp;len))
++ {
++ _SLerrno_errno = errno;
++ SLang_push_integer (-1);
++ return;
++ }
++
++ (void) SLang_push_uinteger (len);
++}
++
++/* Usage: nn = read (f, &amp;buf, n); */
++static void posix_read (SLFile_FD_Type *f, SLang_Ref_Type *ref, unsigned int *nbytes)
++{
++ unsigned int len;
++ char *b;
++ SLang_BString_Type *bstr;
++
++ b = NULL;
++
++ len = *nbytes;
++ if ((-1 == check_fd (f-&gt;fd))
++ || (NULL == (b = SLmalloc (len + 1))))
++ goto return_error;
++
++ if (-1 == f-&gt;read (f-&gt;fd, b, &amp;len))
++ {
++ _SLerrno_errno = errno;
++ goto return_error;
++ }
++
++ if (len != *nbytes)
++ {
++ char *b1 = SLrealloc (b, len + 1);
++ if (b1 == NULL)
++ goto return_error;
++ b = b1;
++ }
++
++ bstr = SLbstring_create_malloced ((unsigned char *) b, len, 0);
++ if (bstr != NULL)
++ {
++ if ((-1 != SLang_assign_to_ref (ref, SLANG_BSTRING_TYPE, (VOID_STAR)&amp;bstr))
++ &amp;&amp; (-1 != SLang_push_uinteger (len)))
++ return;
++
++ SLbstring_free (bstr);
++ b = NULL;
++ /* drop */
++ }
++
++ return_error:
++ if (b != NULL) SLfree ((char *)b);
++ (void) SLang_assign_to_ref (ref, SLANG_NULL_TYPE, NULL);
++ (void) SLang_push_integer (-1);
++}
++
++SLFile_FD_Type *SLfile_create_fd (char *name, int fd)
++{
++ SLFile_FD_Type *f;
++
++ if (NULL == (f = (SLFile_FD_Type *) SLmalloc (sizeof (SLFile_FD_Type))))
++ return NULL;
++
++ memset ((char *) f, 0, sizeof (SLFile_FD_Type));
++ if (NULL == (f-&gt;name = SLang_create_slstring (name)))
++ {
++ SLfree ((char *)f);
++ return NULL;
++ }
++
++ f-&gt;fd = fd;
++ f-&gt;num_refs = 1;
++
++ f-&gt;close = close_method;
++ f-&gt;read = read_method;
++ f-&gt;write = write_method;
++
++ return f;
++}
++
++SLFile_FD_Type *SLfile_dup_fd (SLFile_FD_Type *f0)
++{
++ SLFile_FD_Type *f;
++ int fd0, fd;
++
++ if (f0 == NULL)
++ return NULL;
++ fd0 = f0-&gt;fd;
++ if (-1 == check_fd (fd0))
++ return NULL;
++
++ while (-1 == (fd = dup (fd0)))
++ {
++#ifdef EINTR
++ if (errno == EINTR)
++ continue;
++#endif
++ _SLerrno_errno = errno;
++ return NULL;
++ }
++
++ if (NULL == (f = SLfile_create_fd (f0-&gt;name, fd)))
++ {
++ f0-&gt;close (fd);
++ return NULL;
++ }
++
++ return f;
++}
++
++int SLfile_get_fd (SLFile_FD_Type *f, int *fd)
++{
++ if (f == NULL)
++ return -1;
++
++ *fd = f-&gt;fd;
++ if (-1 == check_fd (*fd))
++ return -1;
++
++ return 0;
++}
++
++void SLfile_free_fd (SLFile_FD_Type *f)
++{
++ if (f == NULL)
++ return;
++
++ if (f-&gt;num_refs &gt; 1)
++ {
++ f-&gt;num_refs -= 1;
++ return;
++ }
++
++ if (f-&gt;fd != -1)
++ {
++ if (f-&gt;close != NULL)
++ (void) f-&gt;close (f-&gt;fd);
++
++ f-&gt;fd = -1;
++ }
++
++ if (f-&gt;stdio_mmt != NULL)
++ SLang_free_mmt (f-&gt;stdio_mmt);
++
++ SLfree ((char *) f);
++}
++
++static int pop_string_int (char **s, int *i)
++{
++ *s = NULL;
++ if ((-1 == SLang_pop_integer (i))
++ || (-1 == SLang_pop_slstring (s)))
++ return -1;
++
++ return 0;
++}
++
++static int pop_string_int_int (char **s, int *a, int *b)
++{
++ *s = NULL;
++ if ((-1 == SLang_pop_integer (b))
++ || (-1 == pop_string_int (s, a)))
++ return -1;
++
++ return 0;
++}
++
++static void posix_open (void)
++{
++ char *file;
++ int mode, flags;
++ SLFile_FD_Type *f;
++
++ switch (SLang_Num_Function_Args)
++ {
++ case 3:
++ if (-1 == pop_string_int_int (&amp;file, &amp;flags, &amp;mode))
++ {
++ SLang_push_null ();
++ return;
++ }
++ break;
++
++ case 2:
++ default:
++ if (-1 == pop_string_int (&amp;file, &amp;flags))
++ return;
++ mode = 0777;
++ break;
++ }
++
++ f = SLfile_create_fd (file, -1);
++ if (f == NULL)
++ {
++ SLang_free_slstring (file);
++ SLang_push_null ();
++ return;
++ }
++ SLang_free_slstring (file);
++
++ if (-1 == (f-&gt;fd = open (f-&gt;name, flags, mode)))
++ {
++ _SLerrno_errno = errno;
++ SLfile_free_fd (f);
++ SLang_push_null ();
++ return;
++ }
++
++ if (-1 == SLfile_push_fd (f))
++ SLang_push_null ();
++ SLfile_free_fd (f);
++}
++
++static void posix_fileno (void)
++{
++ FILE *fp;
++ SLang_MMT_Type *mmt;
++ int fd;
++ SLFile_FD_Type *f;
++ char *name;
++
++ if (-1 == SLang_pop_fileptr (&amp;mmt, &amp;fp))
++ {
++ SLang_push_null ();
++ return;
++ }
++ name = SLang_get_name_from_fileptr (mmt);
++ fd = fileno (fp);
++
++ f = SLfile_create_fd (name, fd);
++ if (f != NULL)
++ f-&gt;close = NULL; /* prevent fd from being closed
++ * when it goes out of scope
++ */
++ SLang_free_mmt (mmt);
++
++ if (-1 == SLfile_push_fd (f))
++ SLang_push_null ();
++ SLfile_free_fd (f);
++}
++
++static void posix_fdopen (SLFile_FD_Type *f, char *mode)
++{
++ if (f-&gt;stdio_mmt == NULL)
++ {
++ if (-1 == _SLstdio_fdopen (f-&gt;name, f-&gt;fd, mode))
++ return;
++
++ if (NULL == (f-&gt;stdio_mmt = SLang_pop_mmt (SLANG_FILE_PTR_TYPE)))
++ return;
++ }
++
++ (void) SLang_push_mmt (f-&gt;stdio_mmt);
++}
++
++static long posix_lseek (SLFile_FD_Type *f, long ofs, int whence)
++{
++ long status;
++
++ if (-1 == (status = lseek (f-&gt;fd, ofs, whence)))
++ _SLerrno_errno = errno;
++
++ return status;
++}
++
++static int posix_isatty (void)
++{
++ int ret;
++ SLFile_FD_Type *f;
++
++ if (SLang_peek_at_stack () == SLANG_FILE_PTR_TYPE)
++ {
++ SLang_MMT_Type *mmt;
++ FILE *fp;
++
++ if (-1 == SLang_pop_fileptr (&amp;mmt, &amp;fp))
++ return 0; /* invalid descriptor */
++
++ ret = isatty (fileno (fp));
++ SLang_free_mmt (mmt);
++ return ret;
++ }
++
++ if (-1 == SLfile_pop_fd (&amp;f))
++ return 0;
++
++ ret = isatty (f-&gt;fd);
++ SLfile_free_fd (f);
++
++ return ret;
++}
++
++static void posix_dup (SLFile_FD_Type *f)
++{
++ if ((NULL == (f = SLfile_dup_fd (f)))
++ || (-1 == SLfile_push_fd (f)))
++ SLang_push_null ();
++
++ SLfile_free_fd (f);
++}
++
++#define I SLANG_INT_TYPE
++#define V SLANG_VOID_TYPE
++#define F SLANG_FILE_FD_TYPE
++#define B SLANG_BSTRING_TYPE
++#define R SLANG_REF_TYPE
++#define U SLANG_UINT_TYPE
++#define S SLANG_STRING_TYPE
++#define L SLANG_LONG_TYPE
++static SLang_Intrin_Fun_Type Fd_Name_Table [] =
++{
++ MAKE_INTRINSIC_0(&quot;fileno&quot;, posix_fileno, V),
++ MAKE_INTRINSIC_0(&quot;isatty&quot;, posix_isatty, I),
++ MAKE_INTRINSIC_0(&quot;open&quot;, posix_open, V),
++ MAKE_INTRINSIC_3(&quot;read&quot;, posix_read, V, F, R, U),
++ MAKE_INTRINSIC_3(&quot;lseek&quot;, posix_lseek, L, F, L, I),
++ MAKE_INTRINSIC_2(&quot;fdopen&quot;, posix_fdopen, V, F, S),
++ MAKE_INTRINSIC_2(&quot;write&quot;, posix_write, V, F, B),
++ MAKE_INTRINSIC_1(&quot;dup_fd&quot;, posix_dup, V, F),
++ MAKE_INTRINSIC_1(&quot;close&quot;, posix_close, I, F),
++ SLANG_END_INTRIN_FUN_TABLE
++};
++#undef I
++#undef V
++#undef F
++#undef B
++#undef R
++#undef S
++#undef L
++#undef U
++
++static SLang_IConstant_Type PosixIO_Consts [] =
++{
++#ifdef O_RDONLY
++ MAKE_ICONSTANT(&quot;O_RDONLY&quot;, O_RDONLY),
++#endif
++#ifdef O_WRONLY
++ MAKE_ICONSTANT(&quot;O_WRONLY&quot;, O_WRONLY),
++#endif
++#ifdef O_RDWR
++ MAKE_ICONSTANT(&quot;O_RDWR&quot;, O_RDWR),
++#endif
++#ifdef O_APPEND
++ MAKE_ICONSTANT(&quot;O_APPEND&quot;, O_APPEND),
++#endif
++#ifdef O_CREAT
++ MAKE_ICONSTANT(&quot;O_CREAT&quot;, O_CREAT),
++#endif
++#ifdef O_EXCL
++ MAKE_ICONSTANT(&quot;O_EXCL&quot;, O_EXCL),
++#endif
++#ifdef O_NOCTTY
++ MAKE_ICONSTANT(&quot;O_NOCTTY&quot;, O_NOCTTY),
++#endif
++#ifdef O_NONBLOCK
++ MAKE_ICONSTANT(&quot;O_NONBLOCK&quot;, O_NONBLOCK),
++#endif
++#ifdef O_TRUNC
++ MAKE_ICONSTANT(&quot;O_TRUNC&quot;, O_TRUNC),
++#endif
++#ifndef O_BINARY
++# define O_BINARY 0
++#endif
++ MAKE_ICONSTANT(&quot;O_BINARY&quot;, O_BINARY),
++#ifndef O_TEXT
++# define O_TEXT 0
++#endif
++ MAKE_ICONSTANT(&quot;O_TEXT&quot;, O_TEXT),
++
++ SLANG_END_ICONST_TABLE
++};
++
++int SLfile_push_fd (SLFile_FD_Type *f)
++{
++ if (f == NULL)
++ return SLang_push_null ();
++
++ f-&gt;num_refs += 1;
++
++ if (0 == SLclass_push_ptr_obj (SLANG_FILE_FD_TYPE, (VOID_STAR) f))
++ return 0;
++
++ f-&gt;num_refs -= 1;
++
++ return -1;
++}
++
++int SLfile_pop_fd (SLFile_FD_Type **f)
++{
++ return SLclass_pop_ptr_obj (SLANG_FILE_FD_TYPE, (VOID_STAR *) f);
++}
++
++static void destroy_fd_type (unsigned char type, VOID_STAR ptr)
++{
++ (void) type;
++ SLfile_free_fd (*(SLFile_FD_Type **) ptr);
++}
++
++static int fd_push (unsigned char type, VOID_STAR v)
++{
++ (void) type;
++ return SLfile_push_fd (*(SLFile_FD_Type **)v);
++}
++
++int SLang_init_posix_io (void)
++{
++ SLang_Class_Type *cl;
++
++ if (NULL == (cl = SLclass_allocate_class (&quot;FD_Type&quot;)))
++ return -1;
++ cl-&gt;cl_destroy = destroy_fd_type;
++ (void) SLclass_set_push_function (cl, fd_push);
++
++ if (-1 == SLclass_register_class (cl, SLANG_FILE_FD_TYPE, sizeof (SLFile_FD_Type), SLANG_CLASS_TYPE_PTR))
++ return -1;
++
++ if ((-1 == SLadd_intrin_fun_table(Fd_Name_Table, &quot;__POSIXIO__&quot;))
++ || (-1 == SLadd_iconstant_table (PosixIO_Consts, NULL))
++ || (-1 == _SLerrno_init ()))
++ return -1;
++
++ return 0;
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slposio.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slprepr.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slprepr.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slprepr.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,427 @@
++/* Copyright (c) 1996, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++/*--------------------------------*-C-*---------------------------------*
++ * File: slprepr.c
++ *
++ * preprocessing routines
++ */
++/*{{{ notes: */
++/*
++ * various preprocessing tokens supported
++ *
++ * #ifdef TOKEN1 TOKEN2 ...
++ * - True if any of TOKEN1 TOKEN2 ... are defined
++ *
++ * #ifndef TOKEN1 TOKEN2 ...
++ * - True if none of TOKEN1 TOKEN2 ... are defined
++ *
++ * #iftrue
++ * #ifnfalse
++ * - always True
++ *
++ * #iffalse
++ * #ifntrue
++ * - always False
++ *
++ * #if$ENV
++ * - True if the enviroment variable ENV is set
++ *
++ * #ifn$ENV
++ * - True if the enviroment variable ENV is not set
++ *
++ * #if$ENV TOKEN1 TOKEN2 ...
++ * - True if the contents of enviroment variable ENV match
++ * any of TOKEN1 TOKEN2 ...
++ *
++ * #ifn$ENV TOKEN1 TOKEN2 ...
++ * - True if the contents of enviroment variable ENV do not match
++ * any of TOKEN1 TOKEN2 ...
++ *
++ * NB: For $ENV, the tokens may contain wildcard characters:
++ * '?' - match any single character
++ * '*' - match any number of characters
++ *
++ * #elif...
++ * #else
++ * #endif
++ *
++ *
++ * mj olesen
++ *----------------------------------------------------------------------*/
++/*}}}*/
++/*{{{ includes: */
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++/*}}}*/
++
++int (*SLprep_exists_hook) (char *, char);
++int (*_SLprep_eval_hook) (char *);
++
++/*{{{ SLprep_open_prep (), SLprep_close_prep () */
++int SLprep_open_prep (SLPreprocess_Type *pt)
++{
++ pt-&gt;this_level = 0;
++ pt-&gt;exec_level = 0;
++ pt-&gt;prev_exec_level = 0;
++ pt-&gt;comment_char = '%';
++ pt-&gt;preprocess_char = '#';
++ pt-&gt;flags = 0;
++ return 0;
++}
++
++void SLprep_close_prep (SLPreprocess_Type *pt)
++{
++ (void) pt;
++}
++/*}}}*/
++
++/*{{{ SLwildcard () */
++/*----------------------------------------------------------------------*
++ * Does `string' match `pattern' ?
++ *
++ * '*' in pattern matches any sub-string (including the null string)
++ * '?' matches any single char.
++ *
++ * Code taken from that donated by Paul Hudson &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">paulh at harlequin.co.uk</A>&gt;
++ * to the fvwm project.
++ * It is public domain, no strings attached. No guarantees either.
++ *----------------------------------------------------------------------*/
++static int SLwildcard (char *pattern, char *string)
++{
++ if (pattern == NULL || *pattern == '\0' || !strcmp (pattern, &quot;*&quot;))
++ return 1;
++ else if (string == NULL)
++ return 0;
++
++ while (*pattern &amp;&amp; *string) switch (*pattern)
++ {
++ case '?':
++ /* match any single character */
++ pattern++;
++ string++;
++ break;
++
++ case '*':
++ /* see if rest of pattern matches any trailing */
++ /* substring of the string. */
++ if (*++pattern == '\0')
++ return 1; /* trailing * must match rest */
++
++ while (*string)
++ {
++ if (SLwildcard (pattern, string)) return 1;
++ string++;
++ }
++ return 0;
++
++ /* break; */
++
++ default:
++ if (*pattern == '\\')
++ {
++ if (*++pattern == '\0')
++ pattern--; /* don't skip trailing backslash */
++ }
++ if (*pattern++ != *string++) return 0;
++ break;
++ }
++
++ return ((*string == '\0')
++ &amp;&amp; ((*pattern == '\0') || !strcmp (pattern, &quot;*&quot;)));
++}
++/*}}}*/
++
++#if defined(__16_BIT_SYSTEM__)
++# define MAX_DEFINES 10
++#else
++# define MAX_DEFINES 128
++#endif
++
++/* The extra one is for NULL termination */
++char *_SLdefines [MAX_DEFINES + 1];
++
++int SLdefine_for_ifdef (char *s) /*{{{*/
++{
++ unsigned int i;
++
++ for (i = 0; i &lt; MAX_DEFINES; i++)
++ {
++ char *s1 = _SLdefines [i];
++
++ if (s1 == s)
++ return 0; /* already defined (hashed string) */
++
++ if (s1 != NULL)
++ continue;
++
++ s = SLang_create_slstring (s);
++ if (s == NULL)
++ return -1;
++
++ _SLdefines[i] = s;
++ return 0;
++ }
++ return -1;
++}
++/*}}}*/
++
++/*{{{ static functions */
++static int is_any_defined(char *buf, char comment) /*{{{*/
++{
++ char *sys;
++ unsigned int i;
++
++ while (1)
++ {
++ register char ch;
++
++ /* Skip whitespace */
++ while (((ch = *buf) == ' ') || (ch == '\t'))
++ buf++;
++
++ if ((ch == '\n') || (ch == 0) || (ch == comment))
++ return 0;
++
++ i = 0;
++ while (NULL != (sys = _SLdefines [i++]))
++ {
++ unsigned int n;
++
++ if (*sys != ch)
++ continue;
++
++ n = strlen (sys);
++ if (0 == strncmp (buf, sys, n))
++ {
++ char ch1 = *(buf + n);
++
++ if ((ch1 == '\n') || (ch1 == 0) ||
++ (ch1 == ' ') || (ch1 == '\t') || (ch1 == comment))
++ return 1;
++ }
++ }
++
++ /* Skip past word */
++ while (((ch = *buf) != ' ')
++ &amp;&amp; (ch != '\n')
++ &amp;&amp; (ch != 0)
++ &amp;&amp; (ch != '\t')
++ &amp;&amp; (ch != comment))
++ buf++;
++ }
++}
++/*}}}*/
++
++static unsigned char *tokenize (unsigned char *buf, char *token, unsigned int len)
++{
++ register char *token_end;
++
++ token_end = token + (len - 1); /* allow room for \0 */
++
++ while ((token &lt; token_end) &amp;&amp; (*buf &gt; ' '))
++ *token++ = *buf++;
++
++ if (*buf &gt; ' ') return NULL; /* token too long */
++
++ *token = '\0';
++
++ while ((*buf == ' ') || (*buf == '\t')) buf++;
++
++ return buf;
++}
++
++static int is_env_defined (char *buf, char comment) /*{{{*/
++{
++ char * env, token [32];
++
++ if ((*buf &lt;= ' ') || (*buf == comment)) return 0; /* no token */
++
++ if (NULL == (buf = (char *) tokenize ((unsigned char *) buf,
++ token, sizeof (token))))
++ return 0;
++
++ if (NULL == (env = getenv (token)))
++ return 0; /* ENV not defined */
++
++ if ((*buf == '\0') || (*buf == '\n') || (*buf == comment))
++ return 1; /* no tokens, but getenv() worked */
++
++ do
++ {
++ buf = (char *) tokenize ((unsigned char *) buf, token, sizeof (token));
++ if (buf == NULL) return 0;
++
++ if (SLwildcard (token, env))
++ return 1;
++ }
++ while (*buf &amp;&amp; (*buf != '\n') &amp;&amp; (*buf != comment));
++
++ return 0;
++}
++/*}}}*/
++/*}}}*/
++
++int SLprep_line_ok (char *buf, SLPreprocess_Type *pt) /*{{{*/
++{
++ int level, prev_exec_level, exec_level;
++
++ if ((buf == NULL) || (pt == NULL)) return 1;
++
++ if (*buf != pt-&gt;preprocess_char)
++ {
++ if (pt-&gt;this_level != pt-&gt;exec_level)
++ return 0;
++
++ if (*buf == '\n') return pt-&gt;flags &amp; SLPREP_BLANK_LINES_OK;
++ if (*buf == pt-&gt;comment_char) return pt-&gt;flags &amp; SLPREP_COMMENT_LINES_OK;
++
++ return 1;
++ }
++
++ level = pt-&gt;this_level;
++ exec_level = pt-&gt;exec_level;
++ prev_exec_level = pt-&gt;prev_exec_level;
++
++ buf++;
++
++ /* Allow '#!' to pass. This could be a shell script with something
++ like '#! /local/bin/slang' */
++ if ((*buf == '!') &amp;&amp; (pt-&gt;preprocess_char == '#'))
++ return 0;
++
++ /* Allow whitespace as in '# ifdef' */
++ while ((*buf == ' ') || (*buf == '\t')) buf++;
++ if (*buf &lt; 'a') return (level == exec_level);
++
++ if (!strncmp(buf, &quot;endif&quot;, 5))
++ {
++ if (level == exec_level)
++ {
++ exec_level--;
++ prev_exec_level = exec_level;
++ }
++ level--;
++ if (level &lt; prev_exec_level) prev_exec_level = level;
++ goto done;
++ }
++
++ if ((buf[0] == 'e') &amp;&amp; (buf[1] == 'l')) /* else, elifdef, ... */
++ {
++ if ((level == exec_level + 1)
++ &amp;&amp; (prev_exec_level != level))
++ {
++ /* We are in position to execute */
++ buf += 2;
++ if ((buf[0] == 's') &amp;&amp; (buf[1] == 'e'))
++ {
++ /* &quot;else&quot; */
++ exec_level = level;
++ goto done;
++ }
++
++ /* drop through to ifdef testing. First set variable
++ * to values appropriate for ifdef testing.
++ */
++ level--; /* now == to exec level */
++ }
++ else
++ {
++ if (level == exec_level)
++ {
++ exec_level--;
++ }
++ goto done;
++ }
++ }
++
++ if ((buf[0] == 'i') &amp;&amp; (buf[1] == 'f'))
++ {
++ int truth;
++
++ if (level != exec_level)
++ {
++ /* Not interested */
++ level++;
++ goto done;
++ }
++
++ level++;
++
++ buf += 2;
++ if (buf[0] == 'n')
++ {
++ truth = 0;
++ buf++;
++ }
++ else truth = 1;
++
++ if (!strncmp (buf, &quot;def&quot;, 3))
++ truth = (truth == is_any_defined(buf + 3, pt-&gt;comment_char));
++
++ else if (!strncmp (buf, &quot;false&quot;, 5))
++ truth = !truth;
++
++ else if (*buf == '$')
++ truth = (truth == is_env_defined (buf + 1, pt-&gt;comment_char));
++
++ else if (!strncmp (buf, &quot;exists&quot;, 6)
++ &amp;&amp; (SLprep_exists_hook != NULL))
++ truth = (truth == (*SLprep_exists_hook)(buf + 6, pt-&gt;comment_char));
++
++ else if (!strncmp (buf, &quot;eval&quot;, 4)
++ &amp;&amp; (_SLprep_eval_hook != NULL))
++ truth = (truth == (*_SLprep_eval_hook) (buf + 4));
++
++ else if (0 != strncmp (buf, &quot;true&quot;, 4))
++ return 1; /* let it bomb */
++
++ if (truth)
++ {
++ exec_level = level;
++ prev_exec_level = exec_level;
++ }
++ }
++ else return 1; /* let it bomb. */
++
++ done:
++
++ if (exec_level &lt; 0) return 1;
++
++ pt-&gt;this_level = level;
++ pt-&gt;exec_level = exec_level;
++ pt-&gt;prev_exec_level = prev_exec_level;
++ return 0;
++}
++/*}}}*/
++
++/*{{{ main() - for testing only */
++#if 0
++int main ()
++{
++ char buf[1024];
++ SLPreprocess_Type pt;
++
++ SLprep_open_prep (&amp;pt);
++
++ SLdefine_for_ifdef (&quot;UNIX&quot;);
++
++ while (NULL != fgets (buf, sizeof (buf) - 1, stdin))
++ {
++ if (SLprep_line_ok (buf, &amp;pt))
++ {
++ fputs (buf, stdout);
++ }
++ }
++
++ SLprep_close_prep (&amp;pt);
++ return 0;
++}
++#endif
++/*}}}*/
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slprepr.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slproc.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slproc.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slproc.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,155 @@
++/* Process specific system calls */
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++
++#ifdef HAVE_IO_H
++# include &lt;io.h&gt; /* for chmod */
++#endif
++
++#ifdef HAVE_PROCESS_H
++# include &lt;process.h&gt; /* for getpid */
++#endif
++
++#if defined(__BORLANDC__)
++# include &lt;dos.h&gt;
++#endif
++
++#include &lt;sys/types.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;signal.h&gt;
++#include &lt;time.h&gt;
++
++#include &lt;errno.h&gt;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++#ifdef HAVE_KILL
++static int kill_cmd (int *pid, int *sig)
++{
++ int ret;
++
++ if (-1 == (ret = kill ((pid_t) *pid, *sig)))
++ _SLerrno_errno = errno;
++ return ret;
++}
++#endif
++
++static int getpid_cmd (void)
++{
++ return getpid ();
++}
++
++#ifdef HAVE_GETPPID
++static int getppid_cmd (void)
++{
++ return getppid ();
++}
++#endif
++
++#ifdef HAVE_GETGID
++static int getgid_cmd (void)
++{
++ return getgid ();
++}
++#endif
++
++#ifdef HAVE_GETEGID
++static int getegid_cmd (void)
++{
++ return getegid ();
++}
++#endif
++
++#ifdef HAVE_GETEUID
++static int geteuid_cmd (void)
++{
++ return geteuid ();
++}
++#endif
++
++#ifdef HAVE_GETUID
++static int getuid_cmd (void)
++{
++ return getuid ();
++}
++#endif
++
++#ifdef HAVE_SETGID
++static int setgid_cmd (int *gid)
++{
++ if (0 == setgid (*gid))
++ return 0;
++ _SLerrno_errno = errno;
++ return -1;
++}
++#endif
++
++#ifdef HAVE_SETPGID
++static int setpgid_cmd (int *pid, int *pgid)
++{
++ if (0 == setpgid (*pid, *pgid))
++ return 0;
++ _SLerrno_errno = errno;
++ return -1;
++}
++#endif
++
++#ifdef HAVE_SETUID
++static int setuid_cmd (int *uid)
++{
++ if (0 == setuid (*uid))
++ return 0;
++ _SLerrno_errno = errno;
++ return -1;
++}
++#endif
++
++static SLang_Intrin_Fun_Type Process_Name_Table[] =
++{
++ MAKE_INTRINSIC_0(&quot;getpid&quot;, getpid_cmd, SLANG_INT_TYPE),
++
++#ifdef HAVE_GETPPID
++ MAKE_INTRINSIC_0(&quot;getppid&quot;, getppid_cmd, SLANG_INT_TYPE),
++#endif
++#ifdef HAVE_GETGID
++ MAKE_INTRINSIC_0(&quot;getgid&quot;, getgid_cmd, SLANG_INT_TYPE),
++#endif
++#ifdef HAVE_GETEGID
++ MAKE_INTRINSIC_0(&quot;getegid&quot;, getegid_cmd, SLANG_INT_TYPE),
++#endif
++#ifdef HAVE_GETEUID
++ MAKE_INTRINSIC_0(&quot;geteuid&quot;, geteuid_cmd, SLANG_INT_TYPE),
++#endif
++#ifdef HAVE_GETUID
++ MAKE_INTRINSIC_0(&quot;getuid&quot;, getuid_cmd, SLANG_INT_TYPE),
++#endif
++#ifdef HAVE_SETGID
++ MAKE_INTRINSIC_I(&quot;setgid&quot;, setgid_cmd, SLANG_INT_TYPE),
++#endif
++#ifdef HAVE_SETPGID
++ MAKE_INTRINSIC_II(&quot;setpgid&quot;, setpgid_cmd, SLANG_INT_TYPE),
++#endif
++#ifdef HAVE_SETUID
++ MAKE_INTRINSIC_I(&quot;setuid&quot;, setuid_cmd, SLANG_INT_TYPE),
++#endif
++
++#ifdef HAVE_KILL
++ MAKE_INTRINSIC_II(&quot;kill&quot;, kill_cmd, SLANG_INT_TYPE),
++#endif
++ SLANG_END_INTRIN_FUN_TABLE
++};
++
++int SLang_init_posix_process (void)
++{
++ if ((-1 == SLadd_intrin_fun_table (Process_Name_Table, &quot;__POSIX_PROCESS__&quot;))
++ || (-1 == _SLerrno_init ()))
++ return -1;
++ return 0;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slproc.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slregexp.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slregexp.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slregexp.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,935 @@
++/* ed style regular expressions */
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++#define SET_BIT(b, n) b[(unsigned int) (n) &gt;&gt; 3] |= 1 &lt;&lt; ((unsigned int) (n) % 8)
++#define TEST_BIT(b, n) (b[(unsigned int)(n) &gt;&gt; 3] &amp; (1 &lt;&lt; ((unsigned int) (n) % 8)))
++#define LITERAL 1
++#define RANGE 2 /* [...] */
++#define ANY 3 /* . */
++#define BOL 4 /* ^ */
++#define EOL 5 /* $ */
++#define NTH_MATCH 6 /* \1 \2 ... \9 */
++#define OPAREN 7 /* \( */
++#define CPAREN 0x8 /* \) */
++#define ANY_DIGIT 0x9 /* \d */
++#define BOW 0xA /* \&lt; */
++#define EOW 0xB /* \&gt; */
++#if 0
++#define NOT_LITERAL 0xC /* \~ */
++#endif
++#define STAR 0x80 /* * */
++#define LEAST_ONCE 0x40 /* + */
++#define MAYBE_ONCE 0x20 /* ? */
++#define MANY 0x10 /* {n,m} */
++/* The rest are additions */
++#define YES_CASE (STAR | BOL)
++#define NO_CASE (STAR | EOL)
++
++#define UPPERCASE(x) (cs ? (x) : UPPER_CASE(x))
++#define LOWERCASE(x) (cs ? (x) : LOWER_CASE(x))
++
++static unsigned char Word_Chars[256];
++#define IS_WORD_CHAR(x) Word_Chars[(unsigned int) (x)]
++
++#if 0
++static int ctx-&gt;open_paren_number;
++static char Closed_Paren_Matches[10];
++
++static SLRegexp_Type *This_Reg;
++static unsigned char *This_Str;
++#endif
++
++typedef struct
++{
++ SLRegexp_Type *reg;
++ unsigned char *str;
++ unsigned int len;
++ char closed_paren_matches[10];
++ int open_paren_number;
++}
++Re_Context_Type;
++
++static unsigned char *do_nth_match (Re_Context_Type *ctx, int n, unsigned char *str, unsigned char *estr)
++{
++ unsigned char *bpos;
++
++ if (ctx-&gt;closed_paren_matches[n] == 0)
++ return NULL;
++
++ bpos = ctx-&gt;reg-&gt;beg_matches[n] + ctx-&gt;str;
++ n = ctx-&gt;reg-&gt;end_matches[n];
++ if (n == 0) return(str);
++ if (n &gt; (int) (estr - str)) return (NULL);
++
++ /* This needs fixed for case sensitive match */
++ if (0 != strncmp((char *) str, (char *) bpos, (unsigned int) n)) return (NULL);
++ str += n;
++ return (str);
++}
++
++/* returns pointer to the end of regexp or NULL */
++static unsigned char *regexp_looking_at (Re_Context_Type *ctx, register unsigned char *str, unsigned char *estr, unsigned char *buf, register int cs)
++{
++ register unsigned char p, p1;
++ unsigned char *save_str, *tmpstr;
++ int n, n0, n1;
++ int save_num_open;
++ char save_closed_matches[10];
++
++ p = *buf++;
++
++ while (p != 0)
++ {
++ /* p1 = UPPERCASE(*buf); */
++ /* if (str &lt; estr) c = UPPERCASE(*str); */
++
++ switch((unsigned char) p)
++ {
++ case BOW:
++ if ((str != ctx-&gt;str)
++ &amp;&amp; ((str &gt;= estr)
++ || IS_WORD_CHAR(*(str - 1))
++ || (0 == IS_WORD_CHAR(*str)))) return NULL;
++ break;
++
++ case EOW:
++ if ((str &lt; estr)
++ &amp;&amp; IS_WORD_CHAR (*str)) return NULL;
++ break;
++
++ case YES_CASE: cs = 1; break;
++ case NO_CASE: cs = 0; break;
++
++ case OPAREN:
++ ctx-&gt;open_paren_number++;
++ ctx-&gt;reg-&gt;beg_matches[ctx-&gt;open_paren_number] = (int) (str - ctx-&gt;str);
++ break;
++ case CPAREN:
++ n = ctx-&gt;open_paren_number;
++ while (n &gt; 0)
++ {
++ if (ctx-&gt;closed_paren_matches[n] != 0)
++ {
++ n--;
++ continue;
++ }
++ ctx-&gt;closed_paren_matches[n] = 1;
++ ctx-&gt;reg-&gt;end_matches[n] = (unsigned int) (str - (ctx-&gt;str + ctx-&gt;reg-&gt;beg_matches[n]));
++ break;
++ }
++ break;
++#ifdef NOT_LITERAL
++ case NOT_LITERAL:
++ if ((str &gt;= estr) || (*buf == UPPERCASE(*str))) return (NULL);
++ str++; buf++;
++ break;
++
++ case MAYBE_ONCE | NOT_LITERAL:
++ save_str = str;
++ if ((str &lt; estr) &amp;&amp; (*buf != UPPERCASE(*str))) str++;
++ buf++;
++ goto match_rest;
++
++ case NOT_LITERAL | LEAST_ONCE: /* match at least once */
++ if ((str &gt;= estr) || (UPPERCASE(*str) == UPPERCASE(*buf))) return (NULL);
++ str++;
++ /* drop */
++ case STAR | NOT_LITERAL:
++ save_str = str; p1 = *buf;
++ while ((str &lt; estr) &amp;&amp; (UPPERCASE(*str) != p1)) str++;
++ buf++;
++ goto match_rest;
++
++ /* this type consists of the expression + two bytes that
++ determine number of matches to perform */
++ case MANY | NOT_LITERAL:
++ p1 = *buf; buf++;
++ n = n0 = (int) (unsigned char) *buf++;
++ /* minimum number to match--- could be 0 */
++ n1 = (int) (unsigned char) *buf++;
++ /* maximum number to match */
++
++ while (n &amp;&amp; (str &lt; estr) &amp;&amp; (p1 != *str))
++ {
++ n--;
++ str++;
++ }
++ if (n) return (NULL);
++
++ save_str = str;
++ n = n1 - n0;
++ while (n &amp;&amp; (str &lt; estr) &amp;&amp; (p1 != *str))
++ {
++ n--;
++ str++;
++ }
++ goto match_rest;
++#endif /* NOT_LITERAL */
++ case LITERAL:
++ if ((str &gt;= estr) || (*buf != UPPERCASE(*str))) return (NULL);
++ str++; buf++;
++ break;
++
++ case MAYBE_ONCE | LITERAL:
++ save_str = str;
++ if ((str &lt; estr) &amp;&amp; (*buf == UPPERCASE(*str))) str++;
++ buf++;
++ goto match_rest;
++
++ case LITERAL | LEAST_ONCE: /* match at least once */
++ if ((str &gt;= estr) || (UPPERCASE(*str) != UPPERCASE(*buf))) return (NULL);
++ str++;
++ /* drop */
++ case STAR | LITERAL:
++ save_str = str; p1 = *buf;
++ while ((str &lt; estr) &amp;&amp; (UPPERCASE(*str) == p1)) str++;
++ buf++;
++ goto match_rest;
++
++ /* this type consists of the expression + two bytes that
++ determine number of matches to perform */
++ case MANY | LITERAL:
++ p1 = *buf; buf++;
++ n = n0 = (int) (unsigned char) *buf++;
++ /* minimum number to match--- could be 0 */
++ n1 = (int) (unsigned char) *buf++;
++ /* maximum number to match */
++
++ while (n &amp;&amp; (str &lt; estr) &amp;&amp; (p1 == *str))
++ {
++ n--;
++ str++;
++ }
++ if (n) return (NULL);
++
++ save_str = str;
++ n = n1 - n0;
++ while (n &amp;&amp; (str &lt; estr) &amp;&amp; (p1 == *str))
++ {
++ n--;
++ str++;
++ }
++ goto match_rest;
++
++ case NTH_MATCH:
++ if ((str = do_nth_match(ctx, (int) (unsigned char) *buf, str, estr)) == NULL) return(NULL);
++ buf++;
++ break;
++
++ case MAYBE_ONCE | NTH_MATCH:
++ save_str = str;
++ tmpstr = do_nth_match (ctx, (int) (unsigned char) *buf, str, estr);
++ buf++;
++ if (tmpstr != NULL)
++ {
++ str = tmpstr;
++ goto match_rest;
++ }
++ continue;
++
++ case LEAST_ONCE | NTH_MATCH:
++ if ((str = do_nth_match(ctx, (int) (unsigned char) *buf, str, estr)) == NULL) return(NULL);
++ /* drop */
++ case STAR | NTH_MATCH:
++ save_str = str;
++ while (NULL != (tmpstr = do_nth_match(ctx, (int) (unsigned char) *buf, str, estr)))
++ {
++ str = tmpstr;
++ }
++ buf++;
++ goto match_rest;
++
++ case MANY | NTH_MATCH: return(NULL);
++ /* needs done */
++
++ case RANGE:
++ if (str &gt;= estr) return (NULL);
++ if (TEST_BIT(buf, UPPERCASE(*str)) == 0) return (NULL);
++ buf += 32; str++;
++ break;
++
++ case MAYBE_ONCE | RANGE:
++ save_str = str;
++ if ((str &lt; estr) &amp;&amp; TEST_BIT(buf, UPPERCASE(*str))) str++;
++ buf += 32;
++ goto match_rest;
++
++ case LEAST_ONCE | RANGE:
++ if ((str &gt;= estr) || (0 == TEST_BIT(buf, UPPERCASE(*str)))) return NULL;
++ str++;
++ /* drop */
++ case STAR | RANGE:
++ save_str = str;
++ while ((str &lt; estr) &amp;&amp; TEST_BIT(buf, UPPERCASE(*str))) str++;
++ buf += 32;
++ goto match_rest;
++
++ /* The first 32 bytes correspond to the range and the two
++ * following bytes indicate the min and max number of matches.
++ */
++ case MANY | RANGE:
++ /* minimum number to match--- could be 0 */
++ n = n0 = (int) (unsigned char) *(buf + 32);
++ /* maximum number to match */
++ n1 = (int) (unsigned char) *(buf + 33);
++
++ while (n &amp;&amp; (str &lt; estr) &amp;&amp; (TEST_BIT(buf, UPPERCASE(*str))))
++ {
++ n--;
++ str++;
++ }
++ if (n) return (NULL);
++ save_str = str;
++ n = n1 - n0;
++ while (n &amp;&amp; (str &lt; estr) &amp;&amp; (TEST_BIT(buf, UPPERCASE(*str))))
++ {
++ n--;
++ str++;
++ }
++ buf += 34; /* 32 + 2 */
++ goto match_rest;
++
++ case ANY_DIGIT:
++ if ((str &gt;= estr) || (*str &gt; '9') || (*str &lt; '0')) return (NULL);
++ str++;
++ break;
++
++ case MAYBE_ONCE | ANY_DIGIT:
++ save_str = str;
++ if ((str &lt; estr) &amp;&amp; ((*str &gt; '9') || (*str &lt; '0'))) str++;
++ goto match_rest;
++
++ case LEAST_ONCE | ANY_DIGIT:
++ if ((str &gt;= estr) || ((*str &gt; '9') || (*str &lt; '0'))) return NULL;
++ str++;
++ /* drop */
++ case STAR | ANY_DIGIT:
++ save_str = str;
++ while ((str &lt; estr) &amp;&amp; ((*str &lt;= '9') &amp;&amp; (*str &gt;= '0'))) str++;
++ goto match_rest;
++
++ case MANY | ANY_DIGIT:
++ /* needs finished */
++ return (NULL);
++
++ case ANY:
++ if ((str &gt;= estr) || (*str == '\n')) return (NULL);
++ str++;
++ break;
++
++ case MAYBE_ONCE | ANY:
++ save_str = str;
++ if ((str &lt; estr) &amp;&amp; (*str != '\n')) str++;
++ goto match_rest;
++
++ case LEAST_ONCE | ANY:
++ if ((str &gt;= estr) || (*str == '\n')) return (NULL);
++ str++;
++ /* drop */
++ case STAR | ANY:
++ save_str = str;
++ while ((str &lt; estr) &amp;&amp; (*str != '\n')) str++;
++ goto match_rest;
++
++ case MANY | ANY:
++ return (NULL);
++ /* needs finished */
++
++ case EOL:
++ if ((str &gt;= estr) || (*str == '\n')) return (str);
++ return(NULL);
++
++ default: return (NULL);
++ }
++ p = *buf++;
++ continue;
++
++ match_rest:
++ if (save_str == str)
++ {
++ p = *buf++;
++ continue;
++ }
++
++ /* if (p == EOL)
++ * {
++ * if (str &lt; estr) return (NULL); else return (str);
++ * }
++ */
++
++ SLMEMCPY(save_closed_matches, ctx-&gt;closed_paren_matches, sizeof(save_closed_matches));
++ save_num_open = ctx-&gt;open_paren_number;
++ while (str &gt;= save_str)
++ {
++ tmpstr = regexp_looking_at (ctx, str, estr, buf, cs);
++ if (tmpstr != NULL) return(tmpstr);
++ SLMEMCPY(ctx-&gt;closed_paren_matches, save_closed_matches, sizeof(ctx-&gt;closed_paren_matches));
++ ctx-&gt;open_paren_number = save_num_open;
++ str--;
++ }
++ return NULL;
++ }
++ if ((p != 0) &amp;&amp; (p != EOL)) return (NULL); else return (str);
++}
++
++static void
++fixup_beg_end_matches (Re_Context_Type *ctx, SLRegexp_Type *r, unsigned char *str, unsigned char *epos)
++{
++ int i;
++
++ if (str == NULL)
++ {
++ r-&gt;beg_matches[0] = -1;
++ r-&gt;end_matches[0] = 0;
++ SLMEMSET(ctx-&gt;closed_paren_matches, 0, sizeof(ctx-&gt;closed_paren_matches));
++ }
++ else
++ {
++ r-&gt;beg_matches[0] = (int) (str - ctx-&gt;str);
++ r-&gt;end_matches[0] = (unsigned int) (epos - str);
++ }
++
++ for (i = 1; i &lt; 10; i++)
++ {
++ if (ctx-&gt;closed_paren_matches [i] == 0)
++ {
++ r-&gt;beg_matches[i] = -1;
++ r-&gt;end_matches[i] = 0;
++ }
++ }
++}
++
++static void init_re_context (Re_Context_Type *ctx, SLRegexp_Type *reg,
++ unsigned char *str, unsigned int len)
++{
++ memset ((char *) ctx, 0, sizeof (Re_Context_Type));
++ ctx-&gt;reg = reg;
++ ctx-&gt;str = str;
++ ctx-&gt;len = len;
++}
++
++unsigned char *SLang_regexp_match(unsigned char *str,
++ unsigned int len, SLRegexp_Type *reg)
++{
++ register unsigned char c = 0, *estr = str + len;
++ int cs = reg-&gt;case_sensitive, lit = 0;
++ unsigned char *buf = reg-&gt;buf, *epos = NULL;
++ Re_Context_Type ctx_buf;
++
++ if (reg-&gt;min_length &gt; len) return NULL;
++
++ init_re_context (&amp;ctx_buf, reg, str, len);
++
++ if (*buf == BOL)
++ {
++ if (NULL == (epos = regexp_looking_at (&amp;ctx_buf, str, estr, buf + 1, cs)))
++ str = NULL;
++
++ fixup_beg_end_matches (&amp;ctx_buf, reg, str, epos);
++ return str;
++ }
++
++ if (*buf == NO_CASE)
++ {
++ buf++; cs = 0;
++ }
++
++ if (*buf == YES_CASE)
++ {
++ buf++; cs = 1;
++ }
++
++ if (*buf == LITERAL)
++ {
++ lit = 1;
++ c = *(buf + 1);
++ }
++ else if ((*buf == OPAREN) &amp;&amp; (*(buf + 1) == LITERAL))
++ {
++ lit = 1;
++ c = *(buf + 2);
++ }
++
++ while (str &lt; estr)
++ {
++ ctx_buf.open_paren_number = 0;
++ memset (ctx_buf.closed_paren_matches, 0, sizeof(ctx_buf.closed_paren_matches));
++ /* take care of leading chars */
++ if (lit)
++ {
++ while ((str &lt; estr) &amp;&amp; (c != UPPERCASE(*str))) str++;
++ if (str &gt;= estr)
++ break; /* failed */
++ }
++
++ if (NULL != (epos = regexp_looking_at(&amp;ctx_buf, str, estr, buf, cs)))
++ {
++ fixup_beg_end_matches (&amp;ctx_buf, reg, str, epos);
++ return str;
++ }
++ str++;
++ }
++ fixup_beg_end_matches (&amp;ctx_buf, reg, NULL, epos);
++ return NULL;
++}
++
++static unsigned char *convert_digit(unsigned char *pat, int *nn)
++{
++ int n = 0, m = 0;
++ unsigned char c;
++ while (c = (unsigned char) *pat, (c &lt;= '9') &amp;&amp; (c &gt;= '0'))
++ {
++ pat++;
++ n = 10 * n + (c - '0');
++ m++;
++ }
++ if (m == 0)
++ {
++ return (NULL);
++ }
++ *nn = n;
++ return pat;
++}
++
++#define ERROR return (int) (pat - reg-&gt;pat)
++
++/* Returns 0 if successful or offset in pattern of error */
++int SLang_regexp_compile (SLRegexp_Type *reg)
++{
++ register unsigned char *buf, *ebuf, *pat;
++ unsigned char *last = NULL, *tmppat;
++ register unsigned char c;
++ int i, reverse = 0, n, cs;
++ int oparen = 0, nparen = 0;
++ /* substring stuff */
++ int count, last_count, this_max_mm = 0, max_mm = 0, ordinary_search,
++ no_osearch = 0, min_length = 0;
++ unsigned char *mm_p = NULL, *this_mm_p = NULL;
++ static int already_initialized;
++
++ reg-&gt;beg_matches[0] = reg-&gt;end_matches[0] = 0;
++ buf = reg-&gt;buf;
++ ebuf = (reg-&gt;buf + reg-&gt;buf_len) - 2; /* make some room */
++ pat = reg-&gt;pat;
++ cs = reg-&gt;case_sensitive;
++
++ if (already_initialized == 0)
++ {
++ SLang_init_case_tables ();
++#ifdef IBMPC_SYSTEM
++ SLmake_lut (Word_Chars, (unsigned char *) &quot;_0-9a-zA-Z\200-\232\240-\245\341-\353&quot;, 0);
++#else
++ SLmake_lut (Word_Chars, (unsigned char *) &quot;_0-9a-zA-Z\277-\326\330-\336\340-\366\370-\376&quot;, 0);
++#endif
++ already_initialized = 1;
++ }
++
++ i = 1; while (i &lt; 10)
++ {
++ reg-&gt;beg_matches[i] = -1;
++ reg-&gt;end_matches[i] = 0;
++ i++;
++ }
++
++ if (*pat == '\\')
++ {
++ if (pat[1] == 'c')
++ {
++ cs = 1;
++ pat += 2;
++ no_osearch = 1;
++ }
++ else if (pat[1] == 'C')
++ {
++ cs = 0;
++ pat += 2;
++ no_osearch = 1;
++ }
++ }
++
++ if (*pat == '^')
++ {
++ pat++;
++ *buf++ = BOL;
++ reg-&gt;must_match_bol = 1;
++ }
++ else reg-&gt;must_match_bol = 0;
++
++ if (cs != reg-&gt;case_sensitive)
++ {
++ if (cs) *buf++ = YES_CASE;
++ else *buf++ = NO_CASE;
++ }
++
++ *buf = 0;
++
++ last_count = count = 0;
++ while ((c = *pat++) != 0)
++ {
++ if (buf &gt;= ebuf - 3)
++ {
++ SLang_doerror (&quot;Pattern too large to be compiled.&quot;);
++ ERROR;
++ }
++
++ count++;
++ switch (c)
++ {
++ case '$':
++ if (*pat != 0) goto literal_char;
++ *buf++ = EOL;
++ break;
++
++ case '\\':
++ c = *pat++;
++ no_osearch = 1;
++ switch(c)
++ {
++ case 'e': c = 033; goto literal_char;
++ case 'n': c = '\n'; goto literal_char;
++ case 't': c = '\t'; goto literal_char;
++ case 'C': cs = 0; *buf++ = NO_CASE; break;
++ case 'c': cs = 1; *buf++ = YES_CASE; break;
++ case '1': case '2': case '3': case '4': case '5':
++ case '6': case '7': case '8': case '9':
++ c = c - '0';
++ if ((int) c &gt; nparen) ERROR;
++ last = buf;
++ *buf++ = NTH_MATCH; *buf++ = c;
++ break;
++#ifdef NOT_LITERAL
++ case '~': /* slang extension */
++ if ((c = *pat) == 0) ERROR;
++ pat++;
++ last = buf;
++ *buf++ = NOT_LITERAL;
++ *buf++ = c;
++ min_length++;
++ break;
++#endif
++ case 'd': /* slang extension */
++ last = buf;
++ *buf++ = ANY_DIGIT;
++ min_length++;
++ break;
++
++ case '&lt;':
++ last = NULL;
++ *buf++ = BOW;
++ break;
++
++ case '&gt;':
++ last = NULL;
++ *buf++ = EOW;
++ break;
++
++ case '{':
++ if (last == NULL) goto literal_char;
++ *last |= MANY;
++ tmppat = convert_digit(pat, &amp;n);
++ if (tmppat == NULL) ERROR;
++ pat = tmppat;
++ *buf++ = n;
++
++ min_length += (n - 1);
++
++ if (*pat == '\\')
++ {
++ *buf++ = n;
++ }
++ else if (*pat == ',')
++ {
++ pat++;
++ if (*pat == '\\')
++ {
++ n = 255;
++ }
++ else
++ {
++ tmppat = convert_digit(pat, &amp;n);
++ if (tmppat == NULL) ERROR;
++ pat = tmppat;
++ if (*pat != '\\') ERROR;
++ }
++ *buf++ = n;
++ }
++ else ERROR;
++ last = NULL;
++ pat++;
++ if (*pat != '}') ERROR;
++ pat++;
++ break; /* case '{' */
++
++ case '(':
++ oparen++;
++ if (oparen &gt; 9) ERROR;
++ *buf++ = OPAREN;
++ break;
++ case ')':
++ if (oparen == 0) ERROR;
++ oparen--;
++ nparen++;
++ *buf++ = CPAREN;
++ break;
++
++ case 0: ERROR;
++ default:
++ goto literal_char;
++ }
++ break;
++
++ case '[':
++
++ *buf = RANGE;
++ last = buf++;
++
++ if (buf + 32 &gt;= ebuf) ERROR;
++
++ for (i = 0; i &lt; 32; i++) buf[i] = 0;
++ c = *pat++;
++ if (c == '^')
++ {
++ reverse = 1;
++ SET_BIT(buf, '\n');
++ c = *pat++;
++ }
++
++ if (c == ']')
++ {
++ SET_BIT(buf, c);
++ c = *pat++;
++ }
++ while (c &amp;&amp; (c != ']'))
++ {
++ if (c == '\\')
++ {
++ c = *pat++;
++ switch(c)
++ {
++ case 'n': c = '\n'; break;
++ case 't': c = '\t'; break;
++ case 0: ERROR;
++ }
++ }
++
++ if (*pat == '-')
++ {
++ pat++;
++ while (c &lt; *pat)
++ {
++ if (cs == 0)
++ {
++ SET_BIT(buf, UPPERCASE(c));
++ SET_BIT(buf, LOWERCASE(c));
++ }
++ else SET_BIT(buf, c);
++ c++;
++ }
++ }
++ if (cs == 0)
++ {
++ SET_BIT(buf, UPPERCASE(c));
++ SET_BIT(buf, LOWERCASE(c));
++ }
++ else SET_BIT(buf, c);
++ c = *pat++;
++ }
++ if (c != ']') ERROR;
++ if (reverse) for (i = 0; i &lt; 32; i++) buf[i] = buf[i] ^ 0xFF;
++ reverse = 0;
++ buf += 32;
++ min_length++;
++ break;
++
++ case '.':
++ last = buf;
++ *buf++ = ANY;
++ min_length++;
++ break;
++
++ case '*':
++ if (last == NULL) goto literal_char;
++ *last |= STAR;
++ min_length--;
++ last = NULL;
++ break;
++
++ case '+':
++ if (last == NULL) goto literal_char;
++ *last |= LEAST_ONCE;
++ last = NULL;
++ break;
++
++ case '?':
++ if (last == NULL) goto literal_char;
++ *last |= MAYBE_ONCE;
++ last = NULL;
++ min_length--;
++ break;
++
++ literal_char:
++ default:
++ /* This is to keep track of longest substring */
++ min_length++;
++ this_max_mm++;
++ if (last_count + 1 == count)
++ {
++ if (this_max_mm == 1)
++ {
++ this_mm_p = buf;
++ }
++ else if (max_mm &lt; this_max_mm)
++ {
++ mm_p = this_mm_p;
++ max_mm = this_max_mm;
++ }
++ }
++ else
++ {
++ this_mm_p = buf;
++ this_max_mm = 1;
++ }
++
++ last_count = count;
++
++ last = buf;
++ *buf++ = LITERAL;
++ *buf++ = UPPERCASE(c);
++ }
++ }
++ *buf = 0;
++ /* Check for ordinary search */
++ ebuf = buf;
++ buf = reg-&gt;buf;
++
++ if (no_osearch) ordinary_search = 0;
++ else
++ {
++ ordinary_search = 1;
++ while (buf &lt; ebuf)
++ {
++ if (*buf != LITERAL)
++ {
++ ordinary_search = 0;
++ break;
++ }
++ buf += 2;
++ }
++ }
++
++ reg-&gt;osearch = ordinary_search;
++ reg-&gt;must_match_str[15] = 0;
++ reg-&gt;min_length = (min_length &gt; 0) ? (unsigned int) min_length : 0;
++ if (ordinary_search)
++ {
++ strncpy((char *) reg-&gt;must_match_str, (char *) reg-&gt;pat, 15);
++ reg-&gt;must_match = 1;
++ return(0);
++ }
++ /* check for longest substring of pattern */
++ reg-&gt;must_match = 0;
++ if ((mm_p == NULL) &amp;&amp; (this_mm_p != NULL)) mm_p = this_mm_p;
++ if (mm_p == NULL)
++ {
++ return (0);
++ }
++ n = 15;
++ pat = reg-&gt;must_match_str;
++ buf = mm_p;
++ while (n--)
++ {
++ if (*buf++ != LITERAL) break;
++ *pat++ = *buf++;
++ }
++ *pat = 0;
++ if (pat != reg-&gt;must_match_str) reg-&gt;must_match = 1;
++ return(0);
++}
++
++char *SLregexp_quote_string (char *re, char *buf, unsigned int buflen)
++{
++ char ch;
++ char *b, *bmax;
++
++ if (re == NULL) return NULL;
++
++ b = buf;
++ bmax = buf + buflen;
++
++ while (b &lt; bmax)
++ {
++ switch (ch = *re++)
++ {
++ case 0:
++ *b = 0;
++ return buf;
++
++ case '$':
++ case '\\':
++ case '[':
++ case ']':
++ case '.':
++ case '^':
++ case '*':
++ case '+':
++ case '?':
++ *b++ = '\\';
++ if (b == bmax) break;
++ /* drop */
++
++ default:
++ *b++ = ch;
++ }
++ }
++ return NULL;
++}
++
++#if 0
++#define MAX_EXP 4096
++int main(int argc, char **argv)
++{
++ FILE *fp;
++ char *regexp, *file;
++ char expbuf[MAX_EXP], buf[512];
++ SLRegexp_Type reg;
++
++ file = argv[2];
++ regexp = argv[1];
++
++ if (NULL == (fp = fopen(file, &quot;r&quot;)))
++ {
++ fprintf(stderr, &quot;File not open\n&quot;);
++ return(1);
++ }
++
++ reg.buf = expbuf;
++ reg.buf_len = MAX_EXP;
++ reg.pat = regexp;
++ reg.case_sensitive = 1;
++
++ if (!regexp_compile(&amp;reg)) while (NULL != fgets(buf, 511, fp))
++ {
++ if (reg.osearch)
++ {
++ if (NULL == strstr(buf, reg.pat)) continue;
++ }
++ else
++ {
++ if (reg.must_match &amp;&amp; (NULL == strstr(buf, reg.must_match_str))) continue;
++ if (0 == regexp_match(buf, buf + strlen(buf), &amp;reg)) continue;
++ }
++
++ fputs(buf, stdout);
++ }
++ return (0);
++}
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slregexp.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slrline.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slrline.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slrline.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,836 @@
++/* SLang_read_line interface --- uses SLang tty stuff */
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++#ifdef REAL_UNIX_SYSTEM
++int SLang_RL_EOF_Char = 4;
++#else
++int SLang_RL_EOF_Char = 26;
++#endif
++
++int SLang_Rline_Quit;
++static SLang_RLine_Info_Type *This_RLI;
++
++static unsigned char Char_Widths[256];
++static void position_cursor (int);
++
++static void rl_beep (void)
++{
++ putc(7, stdout);
++ fflush (stdout);
++}
++
++/* editing functions */
++static int rl_bol (void)
++{
++ if (This_RLI-&gt;point == 0) return 0;
++ This_RLI-&gt;point = 0;
++ return 1;
++}
++
++static int rl_eol (void)
++{
++ if (This_RLI-&gt;point == This_RLI-&gt;len) return 0;
++ This_RLI-&gt;point = This_RLI-&gt;len;
++ return 1;
++}
++
++static int rl_right (void)
++{
++ if (This_RLI-&gt;point == This_RLI-&gt;len) return 0;
++ This_RLI-&gt;point++;
++ return 1;
++}
++
++static int rl_left (void)
++{
++ if (This_RLI-&gt;point == 0) return 0;
++ This_RLI-&gt;point--;
++ return 1;
++}
++
++static int rl_self_insert (void)
++{
++ unsigned char *pmin, *p;
++
++ if (This_RLI-&gt;len == This_RLI-&gt;buf_len)
++ {
++ rl_beep ();
++ return 0;
++ }
++
++ pmin = This_RLI-&gt;buf + This_RLI-&gt;point;
++ p = This_RLI-&gt;buf + This_RLI-&gt;len;
++ while (p &gt; pmin)
++ {
++ *p = *(p - 1);
++ p--;
++ }
++ *pmin = SLang_Last_Key_Char;
++
++ This_RLI-&gt;len++;
++ This_RLI-&gt;point++;
++ if ((This_RLI-&gt;curs_pos + 2 &gt;= This_RLI-&gt;edit_width)
++ || (This_RLI-&gt;tt_insert == NULL)
++ || (Char_Widths[SLang_Last_Key_Char] != 1)) return 1;
++
++ (*This_RLI-&gt;tt_insert)((char) SLang_Last_Key_Char);
++ /* update screen buf */
++ p = This_RLI-&gt;old_upd + (This_RLI-&gt;len - 1);
++ pmin = This_RLI-&gt;old_upd + (This_RLI-&gt;point - 1);
++ while (p &gt; pmin)
++ {
++ *p = *(p - 1);
++ p--;
++ }
++ *pmin = SLang_Last_Key_Char;
++ return 0;
++}
++
++int SLang_rline_insert (char *s)
++{
++ unsigned char *pmin, *p;
++ int n;
++
++ n = strlen (s);
++ if (n &gt; This_RLI-&gt;buf_len - This_RLI-&gt;len)
++ n = This_RLI-&gt;buf_len - This_RLI-&gt;len;
++
++ if (n == 0) return 0;
++
++ pmin = This_RLI-&gt;buf + This_RLI-&gt;point;
++ p = This_RLI-&gt;buf + (This_RLI-&gt;len - 1);
++
++ while (p &gt;= pmin)
++ {
++ *(p + n) = *p;
++ p--;
++ }
++ SLMEMCPY ((char *) pmin, s, n);
++
++ This_RLI-&gt;len += n;
++ This_RLI-&gt;point += n;
++ return n;
++}
++
++static int rl_deln (int n)
++{
++ unsigned char *pmax, *p;
++
++ p = This_RLI-&gt;buf + This_RLI-&gt;point;
++ pmax = This_RLI-&gt;buf + This_RLI-&gt;len;
++
++ if (p + n &gt; pmax) n = (int) (pmax - p);
++ while (p &lt; pmax)
++ {
++ *p = *(p + n);
++ p++;
++ }
++ This_RLI-&gt;len -= n;
++ return n;
++}
++
++static int rl_del (void)
++{
++ return rl_deln(1);
++}
++
++static int rl_quote_insert (void)
++{
++ int err = SLang_Error;
++ SLang_Error = 0;
++ SLang_Last_Key_Char = (*This_RLI-&gt;getkey)();
++ rl_self_insert ();
++ if (SLang_Error == SL_USER_BREAK) SLang_Error = 0;
++ else SLang_Error = err;
++ return 1;
++}
++
++static int rl_trim (void)
++{
++ unsigned char *p, *pmax, *p1;
++ p = This_RLI-&gt;buf + This_RLI-&gt;point;
++ pmax = This_RLI-&gt;buf + This_RLI-&gt;len;
++
++ if (p == pmax)
++ {
++ if (p == This_RLI-&gt;buf) return 0;
++ p--;
++ }
++
++ if ((*p != ' ') &amp;&amp; (*p != '\t')) return 0;
++ p1 = p;
++ while ((p1 &lt; pmax) &amp;&amp; ((*p1 == ' ') || (*p1 == '\t'))) p1++;
++ pmax = p1;
++ p1 = This_RLI-&gt;buf;
++
++ while ((p &gt;= p1) &amp;&amp; ((*p == ' ') || (*p == '\t'))) p--;
++ if (p == pmax) return 0;
++ p++;
++
++ This_RLI-&gt;point = (int) (p - p1);
++ return rl_deln ((int) (pmax - p));
++}
++
++static int rl_bdel (void)
++{
++ if (rl_left()) return rl_del();
++ return 0;
++}
++
++static int rl_deleol (void)
++{
++ if (This_RLI-&gt;point == This_RLI-&gt;len) return 0;
++ *(This_RLI-&gt;buf + This_RLI-&gt;point) = 0;
++ This_RLI-&gt;len = This_RLI-&gt;point;
++ return 1;
++}
++
++static int rl_delete_line (void)
++{
++ This_RLI-&gt;point = 0;
++ *(This_RLI-&gt;buf + This_RLI-&gt;point) = 0;
++ This_RLI-&gt;len = 0;
++ return 1;
++}
++
++static int rl_enter (void)
++{
++ *(This_RLI-&gt;buf + This_RLI-&gt;len) = 0;
++ SLang_Rline_Quit = 1;
++ return 1;
++}
++
++static SLKeyMap_List_Type *RL_Keymap;
++
++/* This update is designed for dumb terminals. It assumes only that the
++ * terminal can backspace via ^H, and move cursor to start of line via ^M.
++ * There is a hook so the user can provide a more sophisticated update if
++ * necessary.
++ */
++
++static void position_cursor (int col)
++{
++ unsigned char *p, *pmax;
++ int dc;
++
++ if (col == This_RLI-&gt;curs_pos)
++ {
++ fflush (stdout);
++ return;
++ }
++
++ if (This_RLI-&gt;tt_goto_column != NULL)
++ {
++ (*This_RLI-&gt;tt_goto_column)(col);
++ This_RLI-&gt;curs_pos = col;
++ fflush (stdout);
++ return;
++ }
++
++ dc = This_RLI-&gt;curs_pos - col;
++ if (dc &lt; 0)
++ {
++ p = This_RLI-&gt;new_upd + This_RLI-&gt;curs_pos;
++ pmax = This_RLI-&gt;new_upd + col;
++ while (p &lt; pmax) putc((char) *p++, stdout);
++ }
++ else
++ {
++ if (dc &lt; col)
++ {
++ while (dc--) putc(8, stdout);
++ }
++ else
++ {
++ putc('\r', stdout);
++ p = This_RLI-&gt;new_upd;
++ pmax = This_RLI-&gt;new_upd + col;
++ while (p &lt; pmax) putc((char) *p++, stdout);
++ }
++ }
++ This_RLI-&gt;curs_pos = col;
++ fflush (stdout);
++}
++
++static void erase_eol (SLang_RLine_Info_Type *rli)
++{
++ unsigned char *p, *pmax;
++
++ p = rli-&gt;old_upd + rli-&gt;curs_pos;
++ pmax = rli-&gt;old_upd + rli-&gt;old_upd_len;
++
++ while (p++ &lt; pmax) putc(' ', stdout);
++
++ rli-&gt;curs_pos = rli-&gt;old_upd_len;
++}
++
++static unsigned char *spit_out(SLang_RLine_Info_Type *rli, unsigned char *p)
++{
++ unsigned char *pmax;
++ position_cursor ((int) (p - rli-&gt;new_upd));
++ pmax = rli-&gt;new_upd + rli-&gt;new_upd_len;
++ while (p &lt; pmax) putc((char) *p++, stdout);
++ rli-&gt;curs_pos = rli-&gt;new_upd_len;
++ return pmax;
++}
++
++static void really_update (SLang_RLine_Info_Type *rli, int new_curs_position)
++{
++ unsigned char *b = rli-&gt;old_upd, *p = rli-&gt;new_upd, chb, chp;
++ unsigned char *pmax;
++
++ if (rli-&gt;update_hook != NULL)
++ {
++ (*rli-&gt;update_hook)(p, rli-&gt;edit_width, new_curs_position);
++ }
++ else
++ {
++ pmax = p + rli-&gt;edit_width;
++ while (p &lt; pmax)
++ {
++ chb = *b++; chp = *p++;
++ if (chb == chp) continue;
++
++ if (rli-&gt;old_upd_len &lt;= rli-&gt;new_upd_len)
++ {
++ /* easy one */
++ (void) spit_out (rli, p - 1);
++ break;
++ }
++ spit_out(rli, p - 1);
++ erase_eol (rli);
++ break;
++ }
++ position_cursor (new_curs_position);
++ }
++
++ /* update finished, so swap */
++
++ rli-&gt;old_upd_len = rli-&gt;new_upd_len;
++ p = rli-&gt;old_upd;
++ rli-&gt;old_upd = rli-&gt;new_upd;
++ rli-&gt;new_upd = p;
++}
++
++static void RLupdate (SLang_RLine_Info_Type *rli)
++{
++ int len, dlen, start_len = 0, prompt_len = 0, tw = 0, count;
++ int want_cursor_pos;
++ unsigned char *b, chb, *b_point, *p;
++ int no_echo;
++
++ no_echo = rli-&gt;flags &amp; SL_RLINE_NO_ECHO;
++
++ b_point = (unsigned char *) (rli-&gt;buf + rli-&gt;point);
++ *(rli-&gt;buf + rli-&gt;len) = 0;
++
++ /* expand characters for output buffer --- handle prompt first.
++ * Do two passes --- first to find out where to begin upon horiz
++ * scroll and the second to actually fill the buffer. */
++ len = 0;
++ count = 2; /* once for prompt and once for buf */
++
++ b = (unsigned char *) rli-&gt;prompt;
++ while (count--)
++ {
++ if ((count == 0) &amp;&amp; no_echo)
++ break;
++
++ /* The prompt could be NULL */
++ if (b != NULL) while ((chb = *b) != 0)
++ {
++ /* This will ensure that the screen is scrolled a third of the edit
++ * width each time */
++ if (b_point == b) break;
++ dlen = Char_Widths[chb];
++ if ((chb == '\t') &amp;&amp; tw)
++ {
++ dlen = tw * ((len - prompt_len) / tw + 1) - (len - prompt_len);
++ }
++ len += dlen;
++ b++;
++ }
++ tw = rli-&gt;tab;
++ b = (unsigned char *) rli-&gt;buf;
++ if (count == 1) want_cursor_pos = prompt_len = len;
++ }
++
++ if (len &lt; rli-&gt;edit_width - rli-&gt;dhscroll) start_len = 0;
++ else if ((rli-&gt;start_column &gt; len)
++ || (rli-&gt;start_column + rli-&gt;edit_width &lt;= len))
++ {
++ start_len = len - (rli-&gt;edit_width - rli-&gt;dhscroll);
++ if (start_len &lt; 0) start_len = 0;
++ }
++ else start_len = rli-&gt;start_column;
++ rli-&gt;start_column = start_len;
++
++ want_cursor_pos = len - start_len;
++
++ /* second pass */
++ p = rli-&gt;new_upd;
++
++ len = 0;
++ count = 2;
++ b = (unsigned char *) rli-&gt;prompt;
++ if (b == NULL) b = (unsigned char *) &quot;&quot;;
++
++ while ((len &lt; start_len) &amp;&amp; (*b))
++ {
++ len += Char_Widths[*b++];
++ }
++
++ tw = 0;
++ if (*b == 0)
++ {
++ b = (unsigned char *) rli-&gt;buf;
++ while (len &lt; start_len)
++ {
++ len += Char_Widths[*b++];
++ }
++ tw = rli-&gt;tab;
++ count--;
++ }
++
++ len = 0;
++ while (count--)
++ {
++ if ((count == 0) &amp;&amp; (no_echo))
++ break;
++
++ while ((len &lt; rli-&gt;edit_width) &amp;&amp; ((chb = *b++) != 0))
++ {
++ dlen = Char_Widths[chb];
++ if (dlen == 1) *p++ = chb;
++ else
++ {
++ if ((chb == '\t') &amp;&amp; tw)
++ {
++ dlen = tw * ((len + start_len - prompt_len) / tw + 1) - (len + start_len - prompt_len);
++ len += dlen; /* ok since dlen comes out 0 */
++ if (len &gt; rli-&gt;edit_width) dlen = len - rli-&gt;edit_width;
++ while (dlen--) *p++ = ' ';
++ dlen = 0;
++ }
++ else
++ {
++ if (dlen == 3)
++ {
++ chb &amp;= 0x7F;
++ *p++ = '~';
++ }
++
++ *p++ = '^';
++ if (chb == 127) *p++ = '?';
++ else *p++ = chb + '@';
++ }
++ }
++ len += dlen;
++ }
++ /* if (start_len &gt; prompt_len) break; */
++ tw = rli-&gt;tab;
++ b = (unsigned char *) rli-&gt;buf;
++ }
++
++ rli-&gt;new_upd_len = (int) (p - rli-&gt;new_upd);
++ while (p &lt; rli-&gt;new_upd + rli-&gt;edit_width) *p++ = ' ';
++ really_update (rli, want_cursor_pos);
++}
++
++void SLrline_redraw (SLang_RLine_Info_Type *rli)
++{
++ unsigned char *p = rli-&gt;new_upd;
++ unsigned char *pmax = p + rli-&gt;edit_width;
++ while (p &lt; pmax) *p++ = ' ';
++ rli-&gt;new_upd_len = rli-&gt;edit_width;
++ really_update (rli, 0);
++ RLupdate (rli);
++}
++
++static int rl_eof_insert (void)
++{
++ if (This_RLI-&gt;len == 0)
++ {
++ SLang_Last_Key_Char = SLang_RL_EOF_Char;
++ /* rl_self_insert (); */
++ return rl_enter ();
++ }
++ return 0;
++}
++
++/* This is very naive. It knows very little about nesting and nothing
++ * about quoting.
++ */
++static void blink_match (SLang_RLine_Info_Type *rli)
++{
++ unsigned char bra, ket;
++ unsigned int delta_column;
++ unsigned char *p, *pmin;
++ int dq_level, sq_level;
++ int level;
++
++ pmin = rli-&gt;buf;
++ p = pmin + rli-&gt;point;
++ if (pmin == p)
++ return;
++
++ ket = SLang_Last_Key_Char;
++ switch (ket)
++ {
++ case ')':
++ bra = '(';
++ break;
++ case ']':
++ bra = '[';
++ break;
++ case '}':
++ bra = '{';
++ break;
++ default:
++ return;
++ }
++
++ level = 0;
++ sq_level = dq_level = 0;
++
++ delta_column = 0;
++ while (p &gt; pmin)
++ {
++ char ch;
++
++ p--;
++ delta_column++;
++ ch = *p;
++
++ if (ch == ket)
++ {
++ if ((dq_level == 0) &amp;&amp; (sq_level == 0))
++ level++;
++ }
++ else if (ch == bra)
++ {
++ if ((dq_level != 0) || (sq_level != 0))
++ continue;
++
++ level--;
++ if (level == 0)
++ {
++ rli-&gt;point -= delta_column;
++ RLupdate (rli);
++ (*rli-&gt;input_pending)(10);
++ rli-&gt;point += delta_column;
++ RLupdate (rli);
++ break;
++ }
++ if (level &lt; 0)
++ break;
++ }
++ else if (ch == '&quot;') dq_level = !dq_level;
++ else if (ch == '\'') sq_level = !sq_level;
++ }
++}
++
++int SLang_read_line (SLang_RLine_Info_Type *rli)
++{
++ unsigned char *p, *pmax;
++ SLang_Key_Type *key;
++
++ SLang_Rline_Quit = 0;
++ This_RLI = rli;
++ p = rli-&gt;old_upd; pmax = p + rli-&gt;edit_width;
++ while (p &lt; pmax) *p++ = ' ';
++
++ /* Sanity checking */
++ rli-&gt;len = strlen ((char *) rli-&gt;buf);
++ if (rli-&gt;len &gt;= rli-&gt;buf_len)
++ {
++ rli-&gt;len = 0;
++ *rli-&gt;buf = 0;
++ }
++ if (rli-&gt;point &gt; rli-&gt;len) rli-&gt;point = rli-&gt;len;
++ if (rli-&gt;point &lt; 0) rli-&gt;point = 0;
++
++ rli-&gt;curs_pos = rli-&gt;start_column = 0;
++ rli-&gt;new_upd_len = rli-&gt;old_upd_len = 0;
++
++ This_RLI-&gt;last_fun = NULL;
++ if (rli-&gt;update_hook == NULL)
++ putc ('\r', stdout);
++
++ RLupdate (rli);
++
++ while (1)
++ {
++ key = SLang_do_key (RL_Keymap, (int (*)(void)) rli-&gt;getkey);
++
++ if ((key == NULL) || (key-&gt;f.f == NULL))
++ rl_beep ();
++ else
++ {
++ if ((SLang_Last_Key_Char == SLang_RL_EOF_Char)
++ &amp;&amp; (*key-&gt;str == 2)
++ &amp;&amp; (This_RLI-&gt;len == 0))
++ rl_eof_insert ();
++ else if (key-&gt;type == SLKEY_F_INTRINSIC)
++ {
++ if ((key-&gt;f.f)())
++ RLupdate (rli);
++
++ if ((rli-&gt;flags &amp; SL_RLINE_BLINK_MATCH)
++ &amp;&amp; (rli-&gt;input_pending != NULL))
++ blink_match (rli);
++ }
++
++ if (SLang_Rline_Quit)
++ {
++ This_RLI-&gt;buf[This_RLI-&gt;len] = 0;
++ if (SLang_Error == SL_USER_BREAK)
++ {
++ SLang_Error = 0;
++ return -1;
++ }
++ return This_RLI-&gt;len;
++ }
++ }
++ if (key != NULL)
++ This_RLI-&gt;last_fun = key-&gt;f.f;
++ }
++}
++
++static int rl_abort (void)
++{
++ rl_delete_line ();
++ return rl_enter ();
++}
++
++/* TTY interface --- ANSI */
++
++static void ansi_goto_column (int n)
++{
++ putc('\r', stdout);
++ if (n) fprintf(stdout, &quot;\033[%dC&quot;, n);
++}
++
++static void rl_select_line (SLang_Read_Line_Type *p)
++{
++ This_RLI-&gt;last = p;
++ strcpy ((char *) This_RLI-&gt;buf, (char *) p-&gt;buf);
++ This_RLI-&gt;point = This_RLI-&gt;len = strlen((char *) p-&gt;buf);
++}
++static int rl_next_line (void);
++static int rl_prev_line (void)
++{
++ SLang_Read_Line_Type *prev;
++
++ if (((This_RLI-&gt;last_fun != (FVOID_STAR) rl_prev_line)
++ &amp;&amp; (This_RLI-&gt;last_fun != (FVOID_STAR) rl_next_line))
++ || (This_RLI-&gt;last == NULL))
++ {
++ prev = This_RLI-&gt;tail;
++ }
++ else prev = This_RLI-&gt;last-&gt;prev;
++
++ if (prev == NULL)
++ {
++ rl_beep ();
++ return 0;
++ }
++
++ rl_select_line (prev);
++ return 1;
++}
++static int rl_redraw (void)
++{
++ SLrline_redraw (This_RLI);
++ return 1;
++}
++
++static int rl_next_line (void)
++{
++ SLang_Read_Line_Type *next;
++
++ if (((This_RLI-&gt;last_fun != (FVOID_STAR) rl_prev_line)
++ &amp;&amp; (This_RLI-&gt;last_fun != (FVOID_STAR) rl_next_line))
++ || (This_RLI-&gt;last == NULL))
++ {
++ rl_beep ();
++ return 0;
++ }
++
++ next = This_RLI-&gt;last-&gt;next;
++
++ if (next == NULL)
++ {
++ This_RLI-&gt;len = This_RLI-&gt;point = 0;
++ *This_RLI-&gt;buf = 0;
++ This_RLI-&gt;last = NULL;
++ }
++ else rl_select_line (next);
++ return 1;
++}
++
++static SLKeymap_Function_Type SLReadLine_Functions[] =
++{
++ {&quot;up&quot;, rl_prev_line},
++ {&quot;down&quot;, rl_next_line},
++ {&quot;bol&quot;, rl_bol},
++ {&quot;eol&quot;, rl_eol},
++ {&quot;right&quot;, rl_right},
++ {&quot;left&quot;, rl_left},
++ {&quot;self_insert&quot;, rl_self_insert},
++ {&quot;bdel&quot;, rl_bdel},
++ {&quot;del&quot;, rl_del},
++ {&quot;deleol&quot;, rl_deleol},
++ {&quot;enter&quot;, rl_enter},
++ {&quot;trim&quot;, rl_trim},
++ {&quot;quoted_insert&quot;, rl_quote_insert},
++ {(char *) NULL, NULL}
++};
++
++int SLang_init_readline (SLang_RLine_Info_Type *rli)
++{
++ int ch;
++ char simple[2];
++
++ if (RL_Keymap == NULL)
++ {
++ simple[1] = 0;
++ if (NULL == (RL_Keymap = SLang_create_keymap (&quot;ReadLine&quot;, NULL)))
++ return -1;
++
++ RL_Keymap-&gt;functions = SLReadLine_Functions;
++
++ /* This breaks under some DEC ALPHA compilers (scary!) */
++#ifndef __DECC
++ for (ch = ' '; ch &lt; 256; ch++)
++ {
++ simple[0] = (char) ch;
++ SLkm_define_key (simple, (FVOID_STAR) rl_self_insert, RL_Keymap);
++ }
++#else
++ ch = ' ';
++ while (1)
++ {
++ simple[0] = (char) ch;
++ SLkm_define_key (simple, (FVOID_STAR) rl_self_insert, RL_Keymap);
++ ch = ch + 1;
++ if (ch == 256) break;
++ }
++#endif /* NOT __DECC */
++
++ simple[0] = SLang_Abort_Char;
++ SLkm_define_key (simple, (FVOID_STAR) rl_abort, RL_Keymap);
++ simple[0] = SLang_RL_EOF_Char;
++ SLkm_define_key (simple, (FVOID_STAR) rl_eof_insert, RL_Keymap);
++
++#ifndef IBMPC_SYSTEM
++ SLkm_define_key (&quot;^[[A&quot;, (FVOID_STAR) rl_prev_line, RL_Keymap);
++ SLkm_define_key (&quot;^[[B&quot;, (FVOID_STAR) rl_next_line, RL_Keymap);
++ SLkm_define_key (&quot;^[[C&quot;, (FVOID_STAR) rl_right, RL_Keymap);
++ SLkm_define_key (&quot;^[[D&quot;, (FVOID_STAR) rl_left, RL_Keymap);
++ SLkm_define_key (&quot;^[OA&quot;, (FVOID_STAR) rl_prev_line, RL_Keymap);
++ SLkm_define_key (&quot;^[OB&quot;, (FVOID_STAR) rl_next_line, RL_Keymap);
++ SLkm_define_key (&quot;^[OC&quot;, (FVOID_STAR) rl_right, RL_Keymap);
++ SLkm_define_key (&quot;^[OD&quot;, (FVOID_STAR) rl_left, RL_Keymap);
++#else
++ SLkm_define_key (&quot;^@H&quot;, (FVOID_STAR) rl_prev_line, RL_Keymap);
++ SLkm_define_key (&quot;^@P&quot;, (FVOID_STAR) rl_next_line, RL_Keymap);
++ SLkm_define_key (&quot;^@M&quot;, (FVOID_STAR) rl_right, RL_Keymap);
++ SLkm_define_key (&quot;^@K&quot;, (FVOID_STAR) rl_left, RL_Keymap);
++ SLkm_define_key (&quot;^@S&quot;, (FVOID_STAR) rl_del, RL_Keymap);
++ SLkm_define_key (&quot;^@O&quot;, (FVOID_STAR) rl_eol, RL_Keymap);
++ SLkm_define_key (&quot;^@G&quot;, (FVOID_STAR) rl_bol, RL_Keymap);
++
++ SLkm_define_key (&quot;\xE0H&quot;, (FVOID_STAR) rl_prev_line, RL_Keymap);
++ SLkm_define_key (&quot;\xE0P&quot;, (FVOID_STAR) rl_next_line, RL_Keymap);
++ SLkm_define_key (&quot;\xE0M&quot;, (FVOID_STAR) rl_right, RL_Keymap);
++ SLkm_define_key (&quot;\xE0K&quot;, (FVOID_STAR) rl_left, RL_Keymap);
++ SLkm_define_key (&quot;\xE0S&quot;, (FVOID_STAR) rl_del, RL_Keymap);
++ SLkm_define_key (&quot;\xE0O&quot;, (FVOID_STAR) rl_eol, RL_Keymap);
++ SLkm_define_key (&quot;\xE0G&quot;, (FVOID_STAR) rl_bol, RL_Keymap);
++#endif
++ SLkm_define_key (&quot;^C&quot;, (FVOID_STAR) rl_abort, RL_Keymap);
++ SLkm_define_key (&quot;^E&quot;, (FVOID_STAR) rl_eol, RL_Keymap);
++ SLkm_define_key (&quot;^G&quot;, (FVOID_STAR) rl_abort, RL_Keymap);
++ SLkm_define_key (&quot;^I&quot;, (FVOID_STAR) rl_self_insert, RL_Keymap);
++ SLkm_define_key (&quot;^A&quot;, (FVOID_STAR) rl_bol, RL_Keymap);
++ SLkm_define_key (&quot;\r&quot;, (FVOID_STAR) rl_enter, RL_Keymap);
++ SLkm_define_key (&quot;\n&quot;, (FVOID_STAR) rl_enter, RL_Keymap);
++ SLkm_define_key (&quot;^K&quot;, (FVOID_STAR) rl_deleol, RL_Keymap);
++ SLkm_define_key (&quot;^L&quot;, (FVOID_STAR) rl_deleol, RL_Keymap);
++ SLkm_define_key (&quot;^V&quot;, (FVOID_STAR) rl_del, RL_Keymap);
++ SLkm_define_key (&quot;^D&quot;, (FVOID_STAR) rl_del, RL_Keymap);
++ SLkm_define_key (&quot;^F&quot;, (FVOID_STAR) rl_right, RL_Keymap);
++ SLkm_define_key (&quot;^B&quot;, (FVOID_STAR) rl_left, RL_Keymap);
++ SLkm_define_key (&quot;^?&quot;, (FVOID_STAR) rl_bdel, RL_Keymap);
++ SLkm_define_key (&quot;^H&quot;, (FVOID_STAR) rl_bdel, RL_Keymap);
++ SLkm_define_key (&quot;^P&quot;, (FVOID_STAR) rl_prev_line, RL_Keymap);
++ SLkm_define_key (&quot;^N&quot;, (FVOID_STAR) rl_next_line, RL_Keymap);
++ SLkm_define_key (&quot;^R&quot;, (FVOID_STAR) rl_redraw, RL_Keymap);
++ SLkm_define_key (&quot;`&quot;, (FVOID_STAR) rl_quote_insert, RL_Keymap);
++ SLkm_define_key (&quot;\033\\&quot;, (FVOID_STAR) rl_trim, RL_Keymap);
++ if (SLang_Error) return -1;
++ }
++
++ if (rli-&gt;prompt == NULL) rli-&gt;prompt = &quot;&quot;;
++ if (rli-&gt;keymap == NULL) rli-&gt;keymap = RL_Keymap;
++ rli-&gt;old_upd = rli-&gt;upd_buf1;
++ rli-&gt;new_upd = rli-&gt;upd_buf2;
++ *rli-&gt;buf = 0;
++ rli-&gt;point = 0;
++
++ if (rli-&gt;flags &amp; SL_RLINE_USE_ANSI)
++ {
++ if (rli-&gt;tt_goto_column == NULL) rli-&gt;tt_goto_column = ansi_goto_column;
++ }
++
++ if (Char_Widths[0] == 2) return 0;
++
++ for (ch = 0; ch &lt; 32; ch++) Char_Widths[ch] = 2;
++ for (ch = 32; ch &lt; 256; ch++) Char_Widths[ch] = 1;
++ Char_Widths[127] = 2;
++#ifndef IBMPC_SYSTEM
++ for (ch = 128; ch &lt; 160; ch++) Char_Widths[ch] = 3;
++#endif
++
++ return 0;
++}
++
++SLang_Read_Line_Type *SLang_rline_save_line (SLang_RLine_Info_Type *rli)
++{
++ SLang_Read_Line_Type *rl = NULL;
++ unsigned char *buf;
++
++ if ((rli == NULL) || (rli-&gt;buf == NULL))
++ return NULL;
++
++ if (NULL == (rl = (SLang_Read_Line_Type *) SLmalloc (sizeof (SLang_Read_Line_Type)))
++ || (NULL == (buf = (unsigned char *) SLmake_string ((char *)rli-&gt;buf))))
++ {
++ SLfree ((char *)rl);
++ return NULL;
++ }
++ rl-&gt;buf = buf;
++ rl-&gt;buf_len = strlen ((char *)buf);
++ rl-&gt;num = rl-&gt;misc = 0;
++ rl-&gt;next = rl-&gt;prev = NULL;
++
++ if (rli-&gt;tail != NULL)
++ {
++ rli-&gt;tail-&gt;next = rl;
++ rl-&gt;prev = rli-&gt;tail;
++ }
++ rli-&gt;tail = rl;
++
++ return rl;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slrline.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slscanf.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slscanf.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slscanf.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,718 @@
++/* sscanf function for S-Lang */
++/* Copyright (c) 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++#include &lt;ctype.h&gt;
++#include &lt;math.h&gt;
++#include &lt;errno.h&gt;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++static char *skip_whitespace (char *s)
++{
++ while (isspace (*s))
++ s++;
++
++ return s;
++}
++
++static void init_map (unsigned char map[256], int base)
++{
++ memset ((char *) map, 0xFF, 256);
++
++ map['0'] = 0; map['1'] = 1; map['2'] = 2; map['3'] = 3;
++ map['4'] = 4; map['5'] = 5; map['6'] = 6; map['7'] = 7;
++ if (base == 8)
++ return;
++
++ map['8'] = 8; map['9'] = 9;
++ if (base == 10)
++ return;
++
++ map['A'] = 10; map['B'] = 11; map['C'] = 12; map['D'] = 13;
++ map['E'] = 14; map['F'] = 15; map['a'] = 10; map['b'] = 11;
++ map['c'] = 12; map['d'] = 13; map['e'] = 14; map['f'] = 15;
++}
++
++static char *get_sign (char *s, char *smax, int *sign)
++{
++ *sign = 1;
++ if (s + 1 &lt; smax)
++ {
++ if (*s == '+') s++;
++ else if (*s == '-')
++ {
++ s++;
++ *sign = -1;
++ }
++ }
++ return s;
++}
++
++
++static int parse_long (char **sp, char *smax, long *np,
++ long base, unsigned char map[256])
++{
++ char *s, *s0;
++ long n;
++ int sign;
++
++ s = s0 = get_sign (*sp, smax, &amp;sign);
++
++ n = 0;
++ while (s &lt; smax)
++ {
++ unsigned char value;
++
++ value = map [(unsigned char) *s];
++ if (value == 0xFF)
++ break;
++
++ n = base * n + value;
++ s++;
++ }
++
++ *sp = s;
++ if (s == s0)
++ return 0;
++
++ *np = n * sign;
++
++ return 1;
++}
++
++
++static int parse_int (char **sp, char *smax, int *np,
++ long base, unsigned char map[256])
++{
++ long n;
++ int status;
++
++ if (1 == (status = parse_long (sp, smax, &amp;n, base, map)))
++ *np = (int) n;
++ return status;
++}
++
++static int parse_short (char **sp, char *smax, short *np,
++ long base, unsigned char map[256])
++{
++ long n;
++ int status;
++
++ if (1 == (status = parse_long (sp, smax, &amp;n, base, map)))
++ *np = (short) n;
++ return status;
++}
++
++static int parse_ulong (char **sp, char *smax, unsigned long *np,
++ long base, unsigned char map[256])
++{
++ return parse_long (sp, smax, (long *) np, base, map);
++}
++
++static int parse_uint (char **sp, char *smax, unsigned int *np,
++ long base, unsigned char map[256])
++{
++ return parse_int (sp, smax, (int *) np, base, map);
++}
++
++static int parse_ushort (char **sp, char *smax, unsigned short *np,
++ long base, unsigned char map[256])
++{
++ return parse_short (sp, smax, (short *) np, base, map);
++}
++
++#if SLANG_HAS_FLOAT
++/*
++ * In an ideal world, strtod would be the correct function to use. However,
++ * there may be problems relying on this function because some systems do
++ * not support and some that do get it wrong. So, I will handle the parsing
++ * of the string and let atof or strtod handle the arithmetic.
++ */
++static int parse_double (char **sp, char *smax, double *d)
++{
++ char *s, *s0;
++ int sign;
++ int expon;
++ unsigned char map[256];
++ char buf[128];
++ int has_leading_zeros;
++ char *start_pos, *sign_pos;
++ char *b, *bmax;
++
++ start_pos = *sp;
++ s = get_sign (start_pos, smax, &amp;sign);
++ if (s &gt;= smax)
++ {
++ errno = _SLerrno_errno = EINVAL;
++ return 0;
++ }
++
++ /* Prepare the buffer that will be passed to strtod */
++ /* Allow the exponent to be 5 significant digits: E+xxxxx\0 */
++ bmax = buf + (sizeof (buf) - 8);
++ buf[0] = '0'; buf[1] = '.';
++ b = buf + 2;
++
++ init_map (map, 10);
++
++ /* Skip leading 0s */
++ s0 = s;
++ while ((s &lt; smax) &amp;&amp; (*s == '0'))
++ s++;
++ has_leading_zeros = (s != s0);
++
++ expon = 0;
++ while (s &lt; smax)
++ {
++ unsigned char value = map [(unsigned char) *s];
++
++ if (value == 0xFF)
++ break;
++
++ if (b &lt; bmax)
++ *b++ = *s;
++
++ expon++;
++ s++;
++ }
++
++ if ((s &lt; smax) &amp;&amp; (*s == '.'))
++ {
++ s++;
++ if (b == buf + 2) /* nothing added yet */
++ {
++ while ((s &lt; smax) &amp;&amp; (*s == '0'))
++ {
++ expon--;
++ s++;
++ }
++ }
++
++ while (s &lt; smax)
++ {
++ unsigned char value = map [(unsigned char) *s];
++
++ if (value == 0xFF)
++ break;
++
++ if (b &lt; bmax)
++ *b++ = *s;
++ s++;
++ }
++ }
++
++ if ((b == buf + 2)
++ &amp;&amp; (has_leading_zeros == 0))
++ {
++ *sp = start_pos;
++ errno = EINVAL;
++ return 0;
++ }
++
++ if ((s + 1 &lt; smax) &amp;&amp; ((*s == 'E') || (*s == 'e')))
++ {
++ int e;
++ int esign;
++
++ s0 = s;
++ s = get_sign (s + 1, smax, &amp;esign);
++ sign_pos = s;
++ e = 0;
++ while (s &lt; smax)
++ {
++ unsigned char value = map [(unsigned char) *s];
++ if (value == 0xFF)
++ break;
++ if (e &lt; 25000) /* avoid overflow if 16 bit */
++ e = 10 * e + value;
++ s++;
++ }
++#ifdef ERANGE
++ if (e &gt;= 25000)
++ errno = ERANGE;
++#endif
++ if (s == sign_pos)
++ s = s0; /* ...E-X */
++ else
++ {
++ e = esign * e;
++ expon += e;
++ }
++ }
++
++ if (expon != 0)
++ sprintf (b, &quot;e%d&quot;, expon);
++ else
++ *b = 0;
++
++ *sp = s;
++#if HAVE_STRTOD
++ *d = sign * strtod (buf, NULL);
++#else
++ *d = sign * atof (buf);
++#endif
++ return 1;
++}
++
++static int parse_float (char **sp, char *smax, float *d)
++{
++ double x;
++ if (1 == parse_double (sp, smax, &amp;x))
++ {
++ *d = (float) x;
++ return 1;
++ }
++ return 0;
++}
++#endif /* SLANG_HAS_FLOAT */
++
++static int parse_string (char **sp, char *smax, char **str)
++{
++ char *s, *s0;
++
++ s0 = s = *sp;
++ while (s &lt; smax)
++ {
++ if (isspace (*s))
++ break;
++ s++;
++ }
++ if (NULL == (*str = SLang_create_nslstring (s0, (unsigned int) (s - s0))))
++ return -1;
++
++ *sp = s;
++ return 1;
++}
++
++static int parse_bstring (char **sp, char *smax, char **str)
++{
++ char *s;
++
++ s = *sp;
++ if (NULL == (*str = SLang_create_nslstring (s, (unsigned int) (smax - s))))
++ return -1;
++
++ *sp = smax;
++ return 1;
++}
++
++static int parse_range (char **sp, char *smax, char **fp, char **str)
++{
++ char *s, *s0;
++ char *range;
++ char *f;
++ unsigned char map[256];
++ unsigned char reverse;
++
++ /* How can one represent a range with just '^'? The naive answer is
++ * is [^]. However, this may be interpreted as meaning any character
++ * but ']' and others. Let's assume that the user will not use a range
++ * to match '^'.
++ */
++ f = *fp;
++ /* f is a pointer to (one char after) [...]. */
++ if (*f == '^')
++ {
++ f++;
++ reverse = 1;
++ }
++ else reverse = 0;
++
++ s0 = f;
++ if (*f == ']')
++ f++;
++
++ while (1)
++ {
++ char ch = *f;
++
++ if (ch == 0)
++ {
++ SLang_verror (SL_INVALID_PARM, &quot;Unexpected end of range in format&quot;);
++ return -1;
++ }
++ if (ch == ']')
++ break;
++ f++;
++ }
++ if (NULL == (range = SLmake_nstring (s0, (unsigned int) (f - s0))))
++ return -1;
++ *fp = f + 1; /* skip ] */
++
++ SLmake_lut (map, (unsigned char *) range, reverse);
++ SLfree (range);
++
++ s0 = s = *sp;
++ while ((s &lt; smax) &amp;&amp; map [(unsigned char) *s])
++ s++;
++
++ if (NULL == (*str = SLang_create_nslstring (s0, (unsigned int) (s - s0))))
++ return -1;
++
++ *sp = s;
++ return 1;
++}
++
++
++int _SLang_sscanf (void)
++{
++ int num;
++ unsigned int num_refs;
++ char *format;
++ char *input_string, *input_string_max;
++ char *f, *s;
++ unsigned char map8[256], map10[256], map16[256];
++
++ if (SLang_Num_Function_Args &lt; 2)
++ {
++ SLang_verror (SL_INVALID_PARM, &quot;Int_Type sscanf (str, format, ...)&quot;);
++ return -1;
++ }
++
++ num_refs = (unsigned int) SLang_Num_Function_Args;
++ if (-1 == SLreverse_stack (num_refs))
++ return -1;
++ num_refs -= 2;
++
++ if (-1 == SLang_pop_slstring (&amp;input_string))
++ return -1;
++
++ if (-1 == SLang_pop_slstring (&amp;format))
++ {
++ SLang_free_slstring (input_string);
++ return -1;
++ }
++
++ f = format;
++ s = input_string;
++ input_string_max = input_string + strlen (input_string);
++
++ init_map (map8, 8);
++ init_map (map10, 10);
++ init_map (map16, 16);
++
++ num = 0;
++
++ while (num_refs != 0)
++ {
++ SLang_Object_Type obj;
++ SLang_Ref_Type *ref;
++ char *smax;
++ unsigned char *map;
++ int base;
++ int no_assign;
++ int is_short;
++ int is_long;
++ int status;
++ char chf;
++ unsigned int width;
++ int has_width;
++
++ chf = *f++;
++
++ if (chf == 0)
++ {
++ /* Hmmm.... what is the most useful thing to do?? */
++#if 1
++ break;
++#else
++ SLang_verror (SL_INVALID_PARM, &quot;sscanf: format not big enough for output list&quot;);
++ goto return_error;
++#endif
++ }
++
++ if (isspace (chf))
++ {
++ s = skip_whitespace (s);
++ continue;
++ }
++
++ if ((chf != '%')
++ || ((chf = *f++) == '%'))
++ {
++ if (*s != chf)
++ break;
++ s++;
++ continue;
++ }
++
++ no_assign = 0;
++ is_short = 0;
++ is_long = 0;
++ width = 0;
++ smax = input_string_max;
++
++ /* Look for the flag character */
++ if (chf == '*')
++ {
++ no_assign = 1;
++ chf = *f++;
++ }
++
++ /* Width */
++ has_width = isdigit (chf);
++ if (has_width)
++ {
++ f--;
++ (void) parse_uint (&amp;f, f + strlen(f), &amp;width, 10, map10);
++ chf = *f++;
++ }
++
++ /* Now the type modifier */
++ switch (chf)
++ {
++ case 'h':
++ is_short = 1;
++ chf = *f++;
++ break;
++
++ case 'L': /* not implemented */
++ case 'l':
++ is_long = 1;
++ chf = *f++;
++ break;
++ }
++
++ status = -1;
++
++ if ((chf != 'c') &amp;&amp; (chf != '['))
++ s = skip_whitespace (s);
++
++ if (has_width)
++ {
++ if (width &gt; (unsigned int) (input_string_max - s))
++ width = (unsigned int) (input_string_max - s);
++ smax = s + width;
++ }
++
++ /* Now the format descriptor */
++
++ map = map10;
++ base = 10;
++
++ try_again: /* used by i, x, and o, conversions */
++ switch (chf)
++ {
++ case 0:
++ SLang_verror (SL_INVALID_PARM, &quot;sscanf: Unexpected end of format&quot;);
++ goto return_error;
++ case 'D':
++ is_long = 1;
++ case 'd':
++ if (is_short)
++ {
++ obj.data_type = SLANG_SHORT_TYPE;
++ status = parse_short (&amp;s, smax, &amp;obj.v.short_val, base, map);
++ }
++ else if (is_long)
++ {
++ obj.data_type = SLANG_LONG_TYPE;
++ status = parse_long (&amp;s, smax, &amp;obj.v.long_val, base, map);
++ }
++ else
++ {
++ obj.data_type = SLANG_INT_TYPE;
++ status = parse_int (&amp;s, smax, &amp;obj.v.int_val, base, map);
++ }
++ break;
++
++
++ case 'U':
++ is_long = 1;
++ case 'u':
++ if (is_short)
++ {
++ obj.data_type = SLANG_USHORT_TYPE;
++ status = parse_ushort (&amp;s, smax, &amp;obj.v.ushort_val, base, map);
++ }
++ else if (is_long)
++ {
++ obj.data_type = SLANG_ULONG_TYPE;
++ status = parse_ulong (&amp;s, smax, &amp;obj.v.ulong_val, base, map);
++ }
++ else
++ {
++ obj.data_type = SLANG_INT_TYPE;
++ status = parse_uint (&amp;s, smax, &amp;obj.v.uint_val, base, map);
++ }
++ break;
++
++ case 'I':
++ is_long = 1;
++ case 'i':
++ if ((s + 1 &gt;= smax)
++ || (*s != 0))
++ chf = 'd';
++ else if (((s[1] == 'x') || (s[1] == 'X'))
++ &amp;&amp; (s + 2 &lt; smax))
++ {
++ s += 2;
++ chf = 'x';
++ }
++ else chf = 'o';
++ goto try_again;
++
++ case 'O':
++ is_long = 1;
++ case 'o':
++ map = map8;
++ base = 8;
++ chf = 'd';
++ goto try_again;
++
++ case 'X':
++ is_long = 1;
++ case 'x':
++ base = 16;
++ map = map16;
++ chf = 'd';
++ goto try_again;
++
++ case 'E':
++ case 'F':
++ is_long = 1;
++ case 'e':
++ case 'f':
++ case 'g':
++#if SLANG_HAS_FLOAT
++ if (is_long)
++ {
++ obj.data_type = SLANG_DOUBLE_TYPE;
++ status = parse_double (&amp;s, smax, &amp;obj.v.double_val);
++ }
++ else
++ {
++ obj.data_type = SLANG_FLOAT_TYPE;
++ status = parse_float (&amp;s, smax, &amp;obj.v.float_val);
++ }
++#else
++ SLang_verror (SL_NOT_IMPLEMENTED,
++ &quot;This version of the S-Lang does not support floating point&quot;);
++ status = -1;
++#endif
++ break;
++
++ case 's':
++ obj.data_type = SLANG_STRING_TYPE;
++ status = parse_string (&amp;s, smax, &amp;obj.v.s_val);
++ break;
++
++ case 'c':
++ if (has_width == 0)
++ {
++ obj.data_type = SLANG_UCHAR_TYPE;
++ obj.v.uchar_val = *s++;
++ status = 1;
++ break;
++ }
++ obj.data_type = SLANG_STRING_TYPE;
++ status = parse_bstring (&amp;s, smax, &amp;obj.v.s_val);
++ break;
++
++ case '[':
++ obj.data_type = SLANG_STRING_TYPE;
++ status = parse_range (&amp;s, smax, &amp;f, &amp;obj.v.s_val);
++ break;
++
++ case 'n':
++ obj.data_type = SLANG_UINT_TYPE;
++ obj.v.uint_val = (unsigned int) (s - input_string);
++ status = 1;
++ break;
++
++ default:
++ status = -1;
++ SLang_verror (SL_NOT_IMPLEMENTED, &quot;format specifier '%c' is not supported&quot;, chf);
++ break;
++ }
++
++ if (status == 0)
++ break;
++
++ if (status == -1)
++ goto return_error;
++
++ if (no_assign)
++ {
++ SLang_free_object (&amp;obj);
++ continue;
++ }
++
++ if (-1 == SLang_pop_ref (&amp;ref))
++ {
++ SLang_free_object (&amp;obj);
++ goto return_error;
++ }
++
++ if (-1 == SLang_push (&amp;obj))
++ {
++ SLang_free_object (&amp;obj);
++ SLang_free_ref (ref);
++ goto return_error;
++ }
++
++ if (-1 == _SLang_deref_assign (ref))
++ {
++ SLang_free_ref (ref);
++ goto return_error;
++ }
++ SLang_free_ref (ref);
++
++ num++;
++ num_refs--;
++ }
++
++ if (-1 == SLdo_pop_n (num_refs))
++ goto return_error;
++
++ SLang_free_slstring (format);
++ SLang_free_slstring (input_string);
++ return num;
++
++ return_error:
++ /* NULLS ok */
++ SLang_free_slstring (format);
++ SLang_free_slstring (input_string);
++ return -1;
++}
++
++
++# if SLANG_HAS_FLOAT
++
++#ifndef HAVE_STDLIB_H
++/* Oh dear. Where is the prototype for atof? If not in stdlib, then
++ * I do not know where. Not in math.h on some systems either.
++ */
++extern double atof ();
++#endif
++
++double _SLang_atof (char *s)
++{
++ double x;
++
++ s = skip_whitespace (s);
++ errno = 0;
++
++ if (1 != parse_double (&amp;s, s + strlen (s), &amp;x))
++ {
++ if ((0 == strcmp (&quot;NaN&quot;, s))
++ || (0 == strcmp (&quot;-Inf&quot;, s))
++ || (0 == strcmp (&quot;Inf&quot;, s)))
++ return atof (s); /* let this deal with it */
++#ifdef EINVAL
++ errno = _SLerrno_errno = EINVAL;
++#endif
++ return 0.0;
++ }
++ if (errno)
++ _SLerrno_errno = errno;
++ return x;
++}
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slscanf.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slscroll.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slscroll.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slscroll.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,450 @@
++/* SLang Scrolling Window Routines */
++/* Copyright (c) 1996, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++static void find_window_bottom (SLscroll_Window_Type *win)
++{
++ unsigned int nrows;
++ unsigned int hidden_mask;
++ SLscroll_Type *bot, *cline, *last_bot;
++ unsigned int row;
++
++ nrows = win-&gt;nrows;
++ hidden_mask = win-&gt;hidden_mask;
++ cline = win-&gt;current_line;
++
++ win-&gt;window_row = row = 0;
++ last_bot = bot = win-&gt;top_window_line;
++
++ while (row &lt; nrows)
++ {
++ if (bot == cline)
++ win-&gt;window_row = row;
++
++ last_bot = bot;
++
++ if (bot == NULL)
++ break;
++
++ bot = bot-&gt;next;
++
++ if (hidden_mask)
++ {
++ while ((bot != NULL) &amp;&amp; (bot-&gt;flags &amp; hidden_mask))
++ bot = bot-&gt;next;
++ }
++
++ row++;
++ }
++
++ win-&gt;bot_window_line = last_bot;
++}
++
++static int find_top_to_recenter (SLscroll_Window_Type *win)
++{
++ unsigned int nrows;
++ unsigned int hidden_mask;
++ SLscroll_Type *prev, *last_prev, *cline;
++
++ nrows = win-&gt;nrows;
++ cline = win-&gt;current_line;
++ hidden_mask = win-&gt;hidden_mask;
++
++ nrows = nrows / 2;
++
++ last_prev = prev = cline;
++
++ while (nrows &amp;&amp; (prev != NULL))
++ {
++ nrows--;
++ last_prev = prev;
++ do
++ {
++ prev = prev-&gt;prev;
++ }
++ while (hidden_mask
++ &amp;&amp; (prev != NULL)
++ &amp;&amp; (prev-&gt;flags &amp; hidden_mask));
++ }
++
++ if (prev == NULL) prev = last_prev;
++
++ win-&gt;top_window_line = prev;
++ find_window_bottom (win);
++
++ return 0;
++}
++
++#define HAS_BORDER_CODE 1
++int SLscroll_find_top (SLscroll_Window_Type *win)
++{
++ unsigned int i;
++ SLscroll_Type *cline, *prev, *next;
++ SLscroll_Type *top_window_line;
++ unsigned int nrows;
++ unsigned int hidden_mask;
++ int scroll_mode;
++ unsigned int border;
++
++ cline = win-&gt;current_line;
++ nrows = win-&gt;nrows;
++ scroll_mode = win-&gt;cannot_scroll;
++ border = win-&gt;border;
++ if (scroll_mode == 2)
++ border = 0;
++
++ if ((cline == NULL) || (nrows &lt;= 1))
++ {
++ win-&gt;top_window_line = cline;
++ find_window_bottom (win);
++ return 0;
++ }
++
++ hidden_mask = win-&gt;hidden_mask;
++
++ /* Note: top_window_line might be a bogus pointer. This means that I cannot
++ * access it unless it really corresponds to a pointer in the buffer.
++ */
++ top_window_line = win-&gt;top_window_line;
++
++ if (top_window_line == NULL)
++ return find_top_to_recenter (win);
++
++ /* Chances are that the current line is visible in the window. This means
++ * that the top window line should be above it.
++ */
++ prev = cline;
++
++ i = 0;
++
++ while ((i &lt; nrows) &amp;&amp; (prev != NULL))
++ {
++ if (prev == top_window_line)
++ {
++ SLscroll_Type *twl = top_window_line;
++ int dir = 0;
++
++ if (i &lt; border) dir = -1; else if (i + border &gt;= nrows) dir = 1;
++
++ if (dir) while (border)
++ {
++ if (dir &lt; 0) twl = twl-&gt;prev;
++ else twl = twl-&gt;next;
++
++ if (twl == NULL)
++ {
++ twl = top_window_line;
++ break;
++ }
++ if ((hidden_mask == 0)
++ || (0 == (twl-&gt;flags &amp; hidden_mask)))
++ border--;
++ }
++
++ win-&gt;top_window_line = twl;
++ find_window_bottom (win);
++ return 0;
++ }
++
++ do
++ {
++ prev = prev-&gt;prev;
++ }
++ while (hidden_mask
++ &amp;&amp; (prev != NULL)
++ &amp;&amp; (prev-&gt;flags &amp; hidden_mask));
++ i++;
++ }
++
++ /* Now check the borders of the window. Perhaps the current line lies
++ * outsider the border by a line. Only do this if terminal can scroll.
++ */
++
++ if (scroll_mode == 1)
++ return find_top_to_recenter (win);
++ else if (scroll_mode == -1)
++ scroll_mode = 0;
++
++ next = cline-&gt;next;
++ while (hidden_mask
++ &amp;&amp; (next != NULL)
++ &amp;&amp; (next-&gt;flags &amp; hidden_mask))
++ next = next-&gt;next;
++
++ if ((next != NULL)
++ &amp;&amp; (next == top_window_line))
++ {
++ /* The current line is one line above the window. This means user
++ * has moved up past the top of the window. If scroll_mode is set
++ * to scroll by pages, we need to do a page up.
++ */
++
++ win-&gt;top_window_line = cline;
++ find_window_bottom (win);
++
++ if (scroll_mode) return SLscroll_pageup (win);
++
++ return 0;
++ }
++
++ prev = cline-&gt;prev;
++
++ while (hidden_mask
++ &amp;&amp; (prev != NULL)
++ &amp;&amp; (prev-&gt;flags &amp; hidden_mask))
++ prev = prev-&gt;prev;
++
++ if ((prev == NULL)
++ || (prev != win-&gt;bot_window_line))
++ return find_top_to_recenter (win);
++
++ /* It looks like cline is below window by one line. See what line should
++ * be at top to scroll it into view. Only do this unless we are scrolling
++ * by pages.
++ */
++ if (scroll_mode)
++ {
++ win-&gt;top_window_line = cline;
++ find_window_bottom (win);
++ return 0;
++ }
++
++ i = 2;
++ while ((i &lt; nrows) &amp;&amp; (prev != NULL))
++ {
++ do
++ {
++ prev = prev-&gt;prev;
++ }
++ while (hidden_mask
++ &amp;&amp; (prev != NULL)
++ &amp;&amp; (prev-&gt;flags &amp; hidden_mask));
++ i++;
++ }
++
++ if (prev != NULL)
++ {
++ win-&gt;top_window_line = prev;
++ find_window_bottom (win);
++ return 0;
++ }
++
++ return find_top_to_recenter (win);
++}
++
++int SLscroll_find_line_num (SLscroll_Window_Type *win)
++{
++ SLscroll_Type *cline, *l;
++ unsigned int n;
++ unsigned int hidden_mask;
++
++ if (win == NULL) return -1;
++
++ hidden_mask = win-&gt;hidden_mask;
++ cline = win-&gt;current_line;
++
++ n = 1;
++
++ l = win-&gt;lines;
++ while (l != cline)
++ {
++ if ((hidden_mask == 0)
++ || (0 == (l-&gt;flags &amp; hidden_mask)))
++ n++;
++
++ l = l-&gt;next;
++ }
++
++ win-&gt;line_num = n;
++ n--;
++
++ while (l != NULL)
++ {
++ if ((hidden_mask == 0)
++ || (0 == (l-&gt;flags &amp; hidden_mask)))
++ n++;
++ l = l-&gt;next;
++ }
++ win-&gt;num_lines = n;
++
++ return 0;
++}
++
++unsigned int SLscroll_next_n (SLscroll_Window_Type *win, unsigned int n)
++{
++ unsigned int i;
++ unsigned int hidden_mask;
++ SLscroll_Type *l, *cline;
++
++ if ((win == NULL)
++ || (NULL == (cline = win-&gt;current_line)))
++ return 0;
++
++ hidden_mask = win-&gt;hidden_mask;
++ l = cline;
++ i = 0;
++ while (i &lt; n)
++ {
++ l = l-&gt;next;
++ while (hidden_mask
++ &amp;&amp; (l != NULL) &amp;&amp; (l-&gt;flags &amp; hidden_mask))
++ l = l-&gt;next;
++
++ if (l == NULL)
++ break;
++
++ i++;
++ cline = l;
++ }
++
++ win-&gt;current_line = cline;
++ win-&gt;line_num += i;
++ return i;
++}
++
++unsigned int SLscroll_prev_n (SLscroll_Window_Type *win, unsigned int n)
++{
++ unsigned int i;
++ unsigned int hidden_mask;
++ SLscroll_Type *l, *cline;
++
++ if ((win == NULL)
++ || (NULL == (cline = win-&gt;current_line)))
++ return 0;
++
++ hidden_mask = win-&gt;hidden_mask;
++ l = cline;
++ i = 0;
++ while (i &lt; n)
++ {
++ l = l-&gt;prev;
++ while (hidden_mask
++ &amp;&amp; (l != NULL) &amp;&amp; (l-&gt;flags &amp; hidden_mask))
++ l = l-&gt;prev;
++
++ if (l == NULL)
++ break;
++
++ i++;
++ cline = l;
++ }
++
++ win-&gt;current_line = cline;
++ win-&gt;line_num -= i;
++ return i;
++}
++
++int SLscroll_pageup (SLscroll_Window_Type *win)
++{
++ SLscroll_Type *l, *top;
++ unsigned int nrows, hidden_mask;
++ unsigned int n;
++
++ if (win == NULL)
++ return -1;
++
++ (void) SLscroll_find_top (win);
++
++ nrows = win-&gt;nrows;
++
++ if ((NULL != (top = win-&gt;top_window_line))
++ &amp;&amp; (nrows &gt; 2))
++ {
++ n = 0;
++ hidden_mask = win-&gt;hidden_mask;
++ l = win-&gt;current_line;
++ while ((l != NULL) &amp;&amp; (l != top))
++ {
++ l = l-&gt;prev;
++ if ((hidden_mask == 0)
++ || ((l != NULL) &amp;&amp; (0 == (l-&gt;flags &amp; hidden_mask))))
++ n++;
++ }
++
++ if (l != NULL)
++ {
++ unsigned int save_line_num;
++ int ret = 0;
++
++ win-&gt;current_line = l;
++ win-&gt;line_num -= n;
++
++ /* Compute a new top/bottom header */
++ save_line_num = win-&gt;line_num;
++
++ if ((0 == SLscroll_prev_n (win, nrows - 1))
++ &amp;&amp; (n == 0))
++ ret = -1;
++
++ win-&gt;top_window_line = win-&gt;current_line;
++ win-&gt;current_line = l;
++ win-&gt;line_num = save_line_num;
++
++ find_window_bottom (win);
++ return ret;
++ }
++ }
++
++ if (nrows &lt; 2) nrows++;
++ if (0 == SLscroll_prev_n (win, nrows - 1))
++ return -1;
++ return 0;
++}
++
++int SLscroll_pagedown (SLscroll_Window_Type *win)
++{
++ SLscroll_Type *l, *bot;
++ unsigned int nrows, hidden_mask;
++ unsigned int n;
++
++ if (win == NULL)
++ return -1;
++
++ (void) SLscroll_find_top (win);
++
++ nrows = win-&gt;nrows;
++
++ if ((NULL != (bot = win-&gt;bot_window_line))
++ &amp;&amp; (nrows &gt; 2))
++ {
++ n = 0;
++ hidden_mask = win-&gt;hidden_mask;
++ l = win-&gt;current_line;
++ while ((l != NULL) &amp;&amp; (l != bot))
++ {
++ l = l-&gt;next;
++ if ((hidden_mask == 0)
++ || ((l != NULL) &amp;&amp; (0 == (l-&gt;flags &amp; hidden_mask))))
++ n++;
++ }
++
++ if (l != NULL)
++ {
++ win-&gt;current_line = l;
++ win-&gt;top_window_line = l;
++ win-&gt;line_num += n;
++
++ find_window_bottom (win);
++
++ if (n || (bot != win-&gt;bot_window_line))
++ return 0;
++
++ return -1;
++ }
++ }
++
++ if (nrows &lt; 2) nrows++;
++ if (0 == SLscroll_next_n (win, nrows - 1))
++ return -1;
++ return 0;
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slscroll.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slsearch.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slsearch.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slsearch.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,239 @@
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++#ifdef upcase
++# undef upcase
++#endif
++
++#define upcase(ch) (cs ? ch : UPPER_CASE(ch))
++
++static unsigned char *search_forward (register unsigned char *beg,
++ unsigned char *end,
++ unsigned char *key,
++ register int key_len, int cs, int *ind)
++{
++ register unsigned char char1;
++ unsigned char *pos;
++ int j, str_len;
++ register unsigned char ch;
++ register int db;
++
++ str_len = (int) (end - beg);
++ if (str_len &lt; key_len) return (NULL);
++
++ if (key_len == 0)
++ return NULL;
++
++ char1 = key[key_len - 1];
++ beg += (key_len - 1);
++
++ while(1)
++ {
++ if (cs) while (beg &lt; end)
++ {
++ ch = *beg;
++ db = ind[(unsigned char) ch];
++ if ((db &lt; key_len) &amp;&amp; (ch == char1)) break;
++ beg += db; /* ind[(unsigned char) ch]; */
++ }
++ else while (beg &lt; end)
++ {
++ ch = *beg;
++ db = ind[(unsigned char) ch];
++ if ((db &lt; key_len) &amp;&amp;
++ (UPPER_CASE(ch) == char1)) break;
++ beg += db; /* ind[(unsigned char) ch]; */
++ }
++
++ if (beg &gt;= end) return(NULL);
++
++ pos = beg - (key_len - 1);
++ for (j = 0; j &lt; key_len; j++)
++ {
++ ch = upcase(pos[j]);
++ if (ch != (unsigned char) key[j]) break;
++ }
++
++ if (j == key_len) return(pos);
++ beg += 1;
++ }
++}
++
++static unsigned char *search_backward (unsigned char *beg,unsigned char *end,
++ unsigned char *key, int key_len,
++ int cs, int *ind)
++{
++ unsigned char ch, char1;
++ int j, str_len, ofs;
++
++ str_len = (int) (end - beg);
++ if (str_len &lt; key_len) return (NULL);
++
++ if (key_len == 0)
++ return NULL;
++
++ /* end -= (key_len - 1); */
++ end -= key_len;
++
++ char1 = key[0];
++
++ while(1)
++ {
++ while ((beg &lt;= end) &amp;&amp; (ch = *end, ch = upcase(ch), ch != char1))
++ {
++ ofs = ind[(unsigned char) ch];
++#ifdef __MSDOS__
++ /* This is needed for msdos segment wrapping problems */
++ if (beg + ofs &gt; end) return(NULL);
++#endif
++ end -= ofs;
++ }
++ if (beg &gt; end) return(NULL);
++ for (j = 1; j &lt; key_len; j++)
++ {
++ ch = upcase(end[j]);
++ if (ch != key[j]) break;
++ }
++ if (j == key_len) return(end);
++ end--;
++ }
++}
++
++unsigned char *SLsearch (unsigned char *pmin, unsigned char *pmax,
++ SLsearch_Type *st)
++{
++ if (st-&gt;dir &gt; 0) return search_forward (pmin, pmax, st-&gt;key,
++ st-&gt;key_len, st-&gt;cs, st-&gt;ind);
++ else return search_backward (pmin, pmax, st-&gt;key,
++ st-&gt;key_len, st-&gt;cs, st-&gt;ind);
++}
++
++static int Case_Tables_Ok;
++
++int SLsearch_init (char *str, int dir, int cs, SLsearch_Type *st)
++{
++ int i, maxi;
++ register int max = strlen(str);
++ unsigned char *w, *work = st-&gt;key;
++ register int *indp, *indpm;
++ int *ind = st-&gt;ind;
++
++ if (max &gt;= (int) sizeof (st-&gt;key))
++ {
++ SLang_doerror (&quot;Search string too long.&quot;);
++ return -1;
++ }
++
++ st-&gt;dir = dir; st-&gt;cs = cs;
++
++ if (!Case_Tables_Ok) SLang_init_case_tables ();
++
++ if (dir &gt; 0)
++ {
++ w = work;
++ }
++ else
++ {
++ maxi = max - 1;
++ str = str + maxi;
++ w = work + maxi;
++ }
++
++ /* for (i = 0; i &lt; 256; i++) ind[i] = max; */
++ indp = ind; indpm = ind + 256;
++ while (indp &lt; indpm)
++ {
++ *indp++ = max;
++ *indp++ = max;
++ *indp++ = max;
++ *indp++ = max;
++ }
++
++ i = 0;
++ if (cs) while (i &lt; max)
++ {
++ i++;
++ maxi = max - i;
++ *w = *str;
++ ind[(unsigned char) *str] = maxi;
++ str += dir; w += dir;
++ }
++ else while (i &lt; max)
++ {
++ i++;
++ maxi = max - i;
++ *w = UPPER_CASE(*str);
++ ind[(unsigned char) *w] = maxi;
++ ind[(unsigned char) LOWER_CASE(*str)] = maxi;
++ str += dir; w += dir;
++ }
++
++ work[max] = 0;
++ st-&gt;key_len = max;
++ return max;
++}
++
++/* 8bit clean upper and lowercase macros */
++unsigned char _SLChg_LCase_Lut[256];
++unsigned char _SLChg_UCase_Lut[256];
++
++void SLang_define_case (int *u, int *l)
++{
++ unsigned char up = (unsigned char) *u, dn = (unsigned char) *l;
++
++ _SLChg_LCase_Lut[up] = dn;
++ _SLChg_LCase_Lut[dn] = dn;
++ _SLChg_UCase_Lut[dn] = up;
++ _SLChg_UCase_Lut[up] = up;
++}
++
++void SLang_init_case_tables (void)
++{
++ int i, j;
++ if (Case_Tables_Ok) return;
++
++ for (i = 0; i &lt; 256; i++)
++ {
++ _SLChg_UCase_Lut[i] = i;
++ _SLChg_LCase_Lut[i] = i;
++ }
++
++ for (i = 'A'; i &lt;= 'Z'; i++)
++ {
++ j = i + 32;
++ _SLChg_UCase_Lut[j] = i;
++ _SLChg_LCase_Lut[i] = j;
++ }
++#ifdef PC_SYSTEM
++ /* Initialize for DOS code page 437. */
++ _SLChg_UCase_Lut[135] = 128; _SLChg_LCase_Lut[128] = 135;
++ _SLChg_UCase_Lut[132] = 142; _SLChg_LCase_Lut[142] = 132;
++ _SLChg_UCase_Lut[134] = 143; _SLChg_LCase_Lut[143] = 134;
++ _SLChg_UCase_Lut[130] = 144; _SLChg_LCase_Lut[144] = 130;
++ _SLChg_UCase_Lut[145] = 146; _SLChg_LCase_Lut[146] = 145;
++ _SLChg_UCase_Lut[148] = 153; _SLChg_LCase_Lut[153] = 148;
++ _SLChg_UCase_Lut[129] = 154; _SLChg_LCase_Lut[154] = 129;
++ _SLChg_UCase_Lut[164] = 165; _SLChg_LCase_Lut[165] = 164;
++#else
++ /* ISO Latin */
++ for (i = 192; i &lt;= 221; i++)
++ {
++ j = i + 32;
++ _SLChg_UCase_Lut[j] = i;
++ _SLChg_LCase_Lut[i] = j;
++ }
++ _SLChg_UCase_Lut[215] = 215; _SLChg_LCase_Lut[215] = 215;
++ _SLChg_UCase_Lut[223] = 223; _SLChg_LCase_Lut[223] = 223;
++ _SLChg_UCase_Lut[247] = 247; _SLChg_LCase_Lut[247] = 247;
++ _SLChg_UCase_Lut[255] = 255; _SLChg_LCase_Lut[255] = 255;
++#endif
++ Case_Tables_Ok = 1;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slsearch.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slsignal.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slsignal.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slsignal.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,336 @@
++/* Copyright (c) 1998, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++#include &quot;slinclud.h&quot;
++
++#include &lt;signal.h&gt;
++
++#ifdef HAVE_SYS_TYPES_H
++# include &lt;sys/types.h&gt;
++#endif
++#ifdef HAVE_SYS_WAIT_H
++# include &lt;sys/wait.h&gt;
++#endif
++
++#include &lt;errno.h&gt;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++/* Do not trust these environments */
++#if defined(__CYGWIN32__) || defined(__MINGW32__) || defined(AMIGA)
++# ifdef SLANG_POSIX_SIGNALS
++# undef SLANG_POSIX_SIGNALS
++# endif
++#endif
++
++/* This function will cause system calls to be restarted after signal if possible */
++SLSig_Fun_Type *SLsignal (int sig, SLSig_Fun_Type *f)
++{
++#if defined(SLANG_POSIX_SIGNALS)
++ struct sigaction old_sa, new_sa;
++
++# ifdef SIGALRM
++ /* We want system calls to be interrupted by SIGALRM. */
++ if (sig == SIGALRM) return SLsignal_intr (sig, f);
++# endif
++
++ sigemptyset (&amp;new_sa.sa_mask);
++ new_sa.sa_handler = f;
++
++ new_sa.sa_flags = 0;
++# ifdef SA_RESTART
++ new_sa.sa_flags |= SA_RESTART;
++# endif
++
++ if (-1 == sigaction (sig, &amp;new_sa, &amp;old_sa))
++ return (SLSig_Fun_Type *) SIG_ERR;
++
++ return old_sa.sa_handler;
++#else
++ /* Not POSIX. */
++ return signal (sig, f);
++#endif
++}
++
++/* This function will NOT cause system calls to be restarted after
++ * signal if possible
++ */
++SLSig_Fun_Type *SLsignal_intr (int sig, SLSig_Fun_Type *f)
++{
++#ifdef SLANG_POSIX_SIGNALS
++ struct sigaction old_sa, new_sa;
++
++ sigemptyset (&amp;new_sa.sa_mask);
++ new_sa.sa_handler = f;
++
++ new_sa.sa_flags = 0;
++# ifdef SA_INTERRUPT
++ new_sa.sa_flags |= SA_INTERRUPT;
++# endif
++
++ if (-1 == sigaction (sig, &amp;new_sa, &amp;old_sa))
++ return (SLSig_Fun_Type *) SIG_ERR;
++
++ return old_sa.sa_handler;
++#else
++ /* Not POSIX. */
++ return signal (sig, f);
++#endif
++}
++
++/* We are primarily interested in blocking signals that would cause the
++ * application to reset the tty. These include suspend signals and
++ * possibly interrupt signals.
++ */
++#ifdef SLANG_POSIX_SIGNALS
++static sigset_t Old_Signal_Mask;
++#endif
++
++static volatile unsigned int Blocked_Depth;
++
++int SLsig_block_signals (void)
++{
++#ifdef SLANG_POSIX_SIGNALS
++ sigset_t new_mask;
++#endif
++
++ Blocked_Depth++;
++ if (Blocked_Depth != 1)
++ {
++ return 0;
++ }
++
++#ifdef SLANG_POSIX_SIGNALS
++ sigemptyset (&amp;new_mask);
++# ifdef SIGQUIT
++ sigaddset (&amp;new_mask, SIGQUIT);
++# endif
++# ifdef SIGTSTP
++ sigaddset (&amp;new_mask, SIGTSTP);
++# endif
++# ifdef SIGINT
++ sigaddset (&amp;new_mask, SIGINT);
++# endif
++# ifdef SIGTTIN
++ sigaddset (&amp;new_mask, SIGTTIN);
++# endif
++# ifdef SIGTTOU
++ sigaddset (&amp;new_mask, SIGTTOU);
++# endif
++# ifdef SIGWINCH
++ sigaddset (&amp;new_mask, SIGWINCH);
++# endif
++
++ (void) sigprocmask (SIG_BLOCK, &amp;new_mask, &amp;Old_Signal_Mask);
++ return 0;
++#else
++ /* Not implemented. */
++ return -1;
++#endif
++}
++
++int SLsig_unblock_signals (void)
++{
++ if (Blocked_Depth == 0)
++ return -1;
++
++ Blocked_Depth--;
++
++ if (Blocked_Depth != 0)
++ return 0;
++
++#ifdef SLANG_POSIX_SIGNALS
++ (void) sigprocmask (SIG_SETMASK, &amp;Old_Signal_Mask, NULL);
++ return 0;
++#else
++ return -1;
++#endif
++}
++
++#ifdef MSWINDOWS
++int SLsystem (char *cmd)
++{
++ SLang_verror (SL_NOT_IMPLEMENTED, &quot;system not implemented&quot;);
++ return -1;
++}
++
++#else
++int SLsystem (char *cmd)
++{
++#ifdef SLANG_POSIX_SIGNALS
++ pid_t pid;
++ int status;
++ struct sigaction ignore;
++# ifdef SIGINT
++ struct sigaction save_intr;
++# endif
++# ifdef SIGQUIT
++ struct sigaction save_quit;
++# endif
++# ifdef SIGCHLD
++ sigset_t child_mask, save_mask;
++# endif
++
++ if (cmd == NULL) return 1;
++
++ ignore.sa_handler = SIG_IGN;
++ sigemptyset (&amp;ignore.sa_mask);
++ ignore.sa_flags = 0;
++
++# ifdef SIGINT
++ if (-1 == sigaction (SIGINT, &amp;ignore, &amp;save_intr))
++ return -1;
++# endif
++
++# ifdef SIGQUIT
++ if (-1 == sigaction (SIGQUIT, &amp;ignore, &amp;save_quit))
++ {
++ (void) sigaction (SIGINT, &amp;save_intr, NULL);
++ return -1;
++ }
++# endif
++
++# ifdef SIGCHLD
++ sigemptyset (&amp;child_mask);
++ sigaddset (&amp;child_mask, SIGCHLD);
++ if (-1 == sigprocmask (SIG_BLOCK, &amp;child_mask, &amp;save_mask))
++ {
++# ifdef SIGINT
++ (void) sigaction (SIGINT, &amp;save_intr, NULL);
++# endif
++# ifdef SIGQUIT
++ (void) sigaction (SIGQUIT, &amp;save_quit, NULL);
++# endif
++ return -1;
++ }
++# endif
++
++ pid = fork();
++
++ if (pid == -1)
++ status = -1;
++ else if (pid == 0)
++ {
++ /* Child */
++# ifdef SIGINT
++ (void) sigaction (SIGINT, &amp;save_intr, NULL);
++# endif
++# ifdef SIGQUIT
++ (void) sigaction (SIGQUIT, &amp;save_quit, NULL);
++# endif
++# ifdef SIGCHLD
++ (void) sigprocmask (SIG_SETMASK, &amp;save_mask, NULL);
++# endif
++
++ execl (&quot;/bin/sh&quot;, &quot;sh&quot;, &quot;-c&quot;, cmd, NULL);
++ _exit (127);
++ }
++ else
++ {
++ /* parent */
++ while (-1 == waitpid (pid, &amp;status, 0))
++ {
++# ifdef EINTR
++ if (errno == EINTR)
++ continue;
++# endif
++# ifdef ERESTARTSYS
++ if (errno == ERESTARTSYS)
++ continue;
++# endif
++ status = -1;
++ break;
++ }
++ }
++# ifdef SIGINT
++ if (-1 == sigaction (SIGINT, &amp;save_intr, NULL))
++ status = -1;
++# endif
++# ifdef SIGQUIT
++ if (-1 == sigaction (SIGQUIT, &amp;save_quit, NULL))
++ status = -1;
++# endif
++# ifdef SIGCHLD
++ if (-1 == sigprocmask (SIG_SETMASK, &amp;save_mask, NULL))
++ status = -1;
++# endif
++
++ return status;
++
++#else /* No POSIX Signals */
++# ifdef SIGINT
++ void (*sint)(int);
++# endif
++# ifdef SIGQUIT
++ void (*squit)(int);
++# endif
++ int status;
++
++# ifdef SIGQUIT
++ squit = SLsignal (SIGQUIT, SIG_IGN);
++# endif
++# ifdef SIGINT
++ sint = SLsignal (SIGINT, SIG_IGN);
++# endif
++ status = system (cmd);
++# ifdef SIGINT
++ SLsignal (SIGINT, sint);
++# endif
++# ifdef SIGQUIT
++ SLsignal (SIGQUIT, squit);
++# endif
++ return status;
++#endif /* POSIX_SIGNALS */
++}
++#endif
++
++#if 0
++#include &lt;windows.h&gt;
++static int msw_system (char *cmd)
++{
++ STARTUPINFO startup_info;
++ PROCESS_INFORMATION process_info;
++ int status;
++
++ if (cmd == NULL) return -1;
++
++ memset ((char *) &amp;startup_info, 0, sizeof (STARTUPINFO));
++ startup_info.cb = sizeof(STARTUPINFO);
++ startup_info.dwFlags = STARTF_USESHOWWINDOW;
++ startup_info.wShowWindow = SW_SHOWDEFAULT;
++
++ if (FALSE == CreateProcess (NULL,
++ cmd,
++ NULL,
++ NULL,
++ FALSE,
++ NORMAL_PRIORITY_CLASS|CREATE_NEW_CONSOLE,
++ NULL,
++ NULL,
++ &amp;startup_info,
++ &amp;process_info))
++ {
++ SLang_verror (0, &quot;%s: CreateProcess failed.&quot;, cmd);
++ return -1;
++ }
++
++ status = -1;
++
++ if (0xFFFFFFFFUL != WaitForSingleObject (process_info.hProcess, INFINITE))
++ {
++ DWORD exit_code;
++
++ if (TRUE == GetExitCodeProcess (process_info.hProcess, &amp;exit_code))
++ status = (int) exit_code;
++ }
++
++ CloseHandle (process_info.hThread);
++ CloseHandle (process_info.hProcess);
++
++ return status;
++}
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slsignal.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slsmg.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slsmg.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slsmg.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1584 @@
++/* SLang Screen management routines */
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++typedef struct Screen_Type
++ {
++ int n; /* number of chars written last time */
++ int flags; /* line untouched, etc... */
++ SLsmg_Char_Type *old, *neew;
++#ifndef IBMPC_SYSTEM
++ unsigned long old_hash, new_hash;
++#endif
++ }
++Screen_Type;
++
++#define TOUCHED 0x1
++#define TRASHED 0x2
++static int Screen_Trashed;
++
++#if !defined(__MSDOS_16BIT__)
++# define MAX_SCREEN_SIZE 256
++#else
++# define MAX_SCREEN_SIZE 75
++#endif
++
++Screen_Type SL_Screen[MAX_SCREEN_SIZE];
++static int Start_Col, Start_Row;
++static int Screen_Cols, Screen_Rows;
++static int This_Row, This_Col;
++static int This_Color; /* only the first 8 bits of this
++ * are used. The highest bit is used
++ * to indicate an alternate character
++ * set. This leaves 127 userdefineable
++ * color combination.
++ */
++
++#ifndef IBMPC_SYSTEM
++#define ALT_CHAR_FLAG 0x80
++#else
++#define ALT_CHAR_FLAG 0x00
++#endif
++
++#if SLTT_HAS_NON_BCE_SUPPORT &amp;&amp; !defined(IBMPC_SYSTEM)
++#define REQUIRES_NON_BCE_SUPPORT 1
++static int Bce_Color_Offset;
++#endif
++
++int SLsmg_Newline_Behavior = 0;
++int SLsmg_Backspace_Moves = 0;
++/* Backward compatibility. Not used. */
++/* int SLsmg_Newline_Moves; */
++
++static void (*tt_normal_video)(void) = SLtt_normal_video;
++static void (*tt_goto_rc)(int, int) = SLtt_goto_rc;
++static void (*tt_cls) (void) = SLtt_cls;
++static void (*tt_del_eol) (void) = SLtt_del_eol;
++static void (*tt_smart_puts) (SLsmg_Char_Type *, SLsmg_Char_Type *, int, int) = SLtt_smart_puts;
++static int (*tt_flush_output) (void) = SLtt_flush_output;
++static int (*tt_reset_video) (void) = SLtt_reset_video;
++static int (*tt_init_video) (void) = SLtt_init_video;
++static int *tt_Screen_Rows = &amp;SLtt_Screen_Rows;
++static int *tt_Screen_Cols = &amp;SLtt_Screen_Cols;
++
++#ifndef IBMPC_SYSTEM
++static void (*tt_set_scroll_region)(int, int) = SLtt_set_scroll_region;
++static void (*tt_reverse_index)(int) = SLtt_reverse_index;
++static void (*tt_reset_scroll_region)(void) = SLtt_reset_scroll_region;
++static void (*tt_delete_nlines)(int) = SLtt_delete_nlines;
++#endif
++
++#ifndef IBMPC_SYSTEM
++static int *tt_Term_Cannot_Scroll = &amp;SLtt_Term_Cannot_Scroll;
++static int *tt_Has_Alt_Charset = &amp;SLtt_Has_Alt_Charset;
++static char **tt_Graphics_Char_Pairs = &amp;SLtt_Graphics_Char_Pairs;
++static int *tt_Use_Blink_For_ACS = &amp;SLtt_Use_Blink_For_ACS;
++#endif
++
++static int Smg_Inited;
++
++static void blank_line (SLsmg_Char_Type *p, int n, unsigned char ch)
++{
++ register SLsmg_Char_Type *pmax = p + n;
++ register SLsmg_Char_Type color_ch;
++
++ color_ch = SLSMG_BUILD_CHAR(ch,This_Color);
++
++ while (p &lt; pmax)
++ {
++ *p++ = color_ch;
++ }
++}
++
++static void clear_region (int row, int n)
++{
++ int i;
++ int imax = row + n;
++
++ if (imax &gt; Screen_Rows) imax = Screen_Rows;
++ for (i = row; i &lt; imax; i++)
++ {
++ if (i &gt;= 0)
++ {
++ blank_line (SL_Screen[i].neew, Screen_Cols, ' ');
++ SL_Screen[i].flags |= TOUCHED;
++ }
++ }
++}
++
++void SLsmg_erase_eol (void)
++{
++ int r, c;
++
++ if (Smg_Inited == 0) return;
++
++ c = This_Col - Start_Col;
++ r = This_Row - Start_Row;
++
++ if ((r &lt; 0) || (r &gt;= Screen_Rows)) return;
++ if (c &lt; 0) c = 0; else if (c &gt;= Screen_Cols) return;
++ blank_line (SL_Screen[This_Row].neew + c , Screen_Cols - c, ' ');
++ SL_Screen[This_Row].flags |= TOUCHED;
++}
++
++static void scroll_up (void)
++{
++ unsigned int i, imax;
++ SLsmg_Char_Type *neew;
++
++ neew = SL_Screen[0].neew;
++ imax = Screen_Rows - 1;
++ for (i = 0; i &lt; imax; i++)
++ {
++ SL_Screen[i].neew = SL_Screen[i + 1].neew;
++ SL_Screen[i].flags |= TOUCHED;
++ }
++ SL_Screen[i].neew = neew;
++ SL_Screen[i].flags |= TOUCHED;
++ blank_line (neew, Screen_Cols, ' ');
++ This_Row--;
++}
++
++void SLsmg_gotorc (int r, int c)
++{
++ This_Row = r;
++ This_Col = c;
++}
++
++int SLsmg_get_row (void)
++{
++ return This_Row;
++}
++
++int SLsmg_get_column (void)
++{
++ return This_Col;
++}
++
++void SLsmg_erase_eos (void)
++{
++ if (Smg_Inited == 0) return;
++
++ SLsmg_erase_eol ();
++ clear_region (This_Row + 1, Screen_Rows);
++}
++
++static int This_Alt_Char;
++
++void SLsmg_set_char_set (int i)
++{
++#ifdef IBMPC_SYSTEM
++ (void) i;
++#else
++ if ((tt_Use_Blink_For_ACS != NULL)
++ &amp;&amp; (*tt_Use_Blink_For_ACS != 0))
++ return;/* alt chars not used and the alt bit
++ * is used to indicate a blink.
++ */
++
++ if (i) This_Alt_Char = ALT_CHAR_FLAG;
++ else This_Alt_Char = 0;
++
++ This_Color &amp;= 0x7F;
++ This_Color |= This_Alt_Char;
++#endif
++}
++
++void SLsmg_set_color (int color)
++{
++ if (color &lt; 0) return;
++#ifdef REQUIRES_NON_BCE_SUPPORT
++ color += Bce_Color_Offset;
++#endif
++ This_Color = color | This_Alt_Char;
++}
++
++void SLsmg_reverse_video (void)
++{
++ SLsmg_set_color (1);
++}
++
++void SLsmg_normal_video (void)
++{
++ SLsmg_set_color (0);
++}
++
++static int point_visible (int col_too)
++{
++ return ((This_Row &gt;= Start_Row) &amp;&amp; (This_Row &lt; Start_Row + Screen_Rows)
++ &amp;&amp; ((col_too == 0)
++ || ((This_Col &gt;= Start_Col)
++ &amp;&amp; (This_Col &lt; Start_Col + Screen_Cols))));
++}
++
++void SLsmg_write_string (char *str)
++{
++ SLsmg_write_nchars (str, strlen (str));
++}
++
++void SLsmg_write_nstring (char *str, unsigned int n)
++{
++ unsigned int width;
++ char blank = ' ';
++
++ /* Avoid a problem if a user accidently passes a negative value */
++ if ((int) n &lt; 0)
++ return;
++
++ if (str == NULL) width = 0;
++ else
++ {
++ width = strlen (str);
++ if (width &gt; n) width = n;
++ SLsmg_write_nchars (str, width);
++ }
++ while (width++ &lt; n) SLsmg_write_nchars (&amp;blank, 1);
++}
++
++void SLsmg_write_wrapped_string (char *s, int r, int c,
++ unsigned int dr, unsigned int dc,
++ int fill)
++{
++ register char ch, *p;
++ int maxc = (int) dc;
++
++ if ((dr == 0) || (dc == 0)) return;
++ p = s;
++ dc = 0;
++ while (1)
++ {
++ ch = *p++;
++ if ((ch == 0) || (ch == '\n'))
++ {
++ int diff;
++
++ diff = maxc - (int) dc;
++
++ SLsmg_gotorc (r, c);
++ SLsmg_write_nchars (s, dc);
++ if (fill &amp;&amp; (diff &gt; 0))
++ {
++ while (diff--) SLsmg_write_char (' ');
++ }
++ if ((ch == 0) || (dr == 1)) break;
++
++ r++;
++ dc = 0;
++ dr--;
++ s = p;
++ }
++ else if ((int) dc == maxc)
++ {
++ SLsmg_gotorc (r, c);
++ SLsmg_write_nchars (s, dc + 1);
++ if (dr == 1) break;
++
++ r++;
++ dc = 0;
++ dr--;
++ s = p;
++ }
++ else dc++;
++ }
++}
++
++int SLsmg_Tab_Width = 8;
++
++/* Minimum value for which eight bit char is displayed as is. */
++
++#ifndef IBMPC_SYSTEM
++int SLsmg_Display_Eight_Bit = 160;
++static unsigned char Alt_Char_Set[129];/* 129th is used as a flag */
++#else
++int SLsmg_Display_Eight_Bit = 128;
++#endif
++
++void SLsmg_write_nchars (char *str, unsigned int n)
++{
++ register SLsmg_Char_Type *p, old, neew, color;
++ unsigned char ch;
++ unsigned int flags;
++ int len, start_len, max_len;
++ char *str_max;
++ int newline_flag;
++#ifndef IBMPC_SYSTEM
++ int alt_char_set_flag;
++
++ alt_char_set_flag = ((This_Color &amp; ALT_CHAR_FLAG)
++ &amp;&amp; ((tt_Use_Blink_For_ACS == NULL)
++ || (*tt_Use_Blink_For_ACS == 0)));
++#endif
++
++ if (Smg_Inited == 0) return;
++
++ str_max = str + n;
++ color = This_Color;
++
++ top: /* get here only on newline */
++
++ newline_flag = 0;
++ start_len = Start_Col;
++
++ if (point_visible (0) == 0) return;
++
++ len = This_Col;
++ max_len = start_len + Screen_Cols;
++
++ p = SL_Screen[This_Row - Start_Row].neew;
++ if (len &gt; start_len) p += (len - start_len);
++
++ flags = SL_Screen[This_Row - Start_Row].flags;
++ while ((len &lt; max_len) &amp;&amp; (str &lt; str_max))
++ {
++ ch = (unsigned char) *str++;
++
++#ifndef IBMPC_SYSTEM
++ if (alt_char_set_flag)
++ ch = Alt_Char_Set [ch &amp; 0x7F];
++#endif
++ if (((ch &gt;= ' ') &amp;&amp; (ch &lt; 127))
++ || (ch &gt;= (unsigned char) SLsmg_Display_Eight_Bit)
++#ifndef IBMPC_SYSTEM
++ || alt_char_set_flag
++#endif
++ )
++ {
++ len += 1;
++ if (len &gt; start_len)
++ {
++ old = *p;
++ neew = SLSMG_BUILD_CHAR(ch,color);
++ if (old != neew)
++ {
++ flags |= TOUCHED;
++ *p = neew;
++ }
++ p++;
++ }
++ }
++
++ else if ((ch == '\t') &amp;&amp; (SLsmg_Tab_Width &gt; 0))
++ {
++ n = len;
++ n += SLsmg_Tab_Width;
++ n = SLsmg_Tab_Width - (n % SLsmg_Tab_Width);
++ if ((unsigned int) len + n &gt; (unsigned int) max_len)
++ n = (unsigned int) (max_len - len);
++ neew = SLSMG_BUILD_CHAR(' ',color);
++ while (n--)
++ {
++ len += 1;
++ if (len &gt; start_len)
++ {
++ if (*p != neew)
++ {
++ flags |= TOUCHED;
++ *p = neew;
++ }
++ p++;
++ }
++ }
++ }
++ else if ((ch == '\n')
++ &amp;&amp; (SLsmg_Newline_Behavior != SLSMG_NEWLINE_PRINTABLE))
++ {
++ newline_flag = 1;
++ break;
++ }
++ else if ((ch == 0x8) &amp;&amp; SLsmg_Backspace_Moves)
++ {
++ if (len != 0) len--;
++ }
++ else
++ {
++ if (ch &amp; 0x80)
++ {
++ neew = SLSMG_BUILD_CHAR('~',color);
++ len += 1;
++ if (len &gt; start_len)
++ {
++ if (*p != neew)
++ {
++ *p = neew;
++ flags |= TOUCHED;
++ }
++ p++;
++ if (len == max_len) break;
++ ch &amp;= 0x7F;
++ }
++ }
++
++ len += 1;
++ if (len &gt; start_len)
++ {
++ neew = SLSMG_BUILD_CHAR('^',color);
++ if (*p != neew)
++ {
++ *p = neew;
++ flags |= TOUCHED;
++ }
++ p++;
++ if (len == max_len) break;
++ }
++
++ if (ch == 127) ch = '?'; else ch = ch + '@';
++ len++;
++ if (len &gt; start_len)
++ {
++ neew = SLSMG_BUILD_CHAR(ch,color);
++ if (*p != neew)
++ {
++ *p = neew;
++ flags |= TOUCHED;
++ }
++ p++;
++ }
++ }
++ }
++
++ SL_Screen[This_Row - Start_Row].flags = flags;
++ This_Col = len;
++
++ if (SLsmg_Newline_Behavior == 0)
++ return;
++
++ if (newline_flag == 0)
++ {
++ while (str &lt; str_max)
++ {
++ if (*str == '\n') break;
++ str++;
++ }
++ if (str == str_max) return;
++ str++;
++ }
++
++ This_Row++;
++ This_Col = 0;
++ if (This_Row == Start_Row + Screen_Rows)
++ {
++ if (SLsmg_Newline_Behavior == SLSMG_NEWLINE_SCROLLS) scroll_up ();
++ }
++ goto top;
++}
++
++void SLsmg_write_char (char ch)
++{
++ SLsmg_write_nchars (&amp;ch, 1);
++}
++
++static int Cls_Flag;
++
++void SLsmg_cls (void)
++{
++ int tac;
++ if (Smg_Inited == 0) return;
++
++ tac = This_Alt_Char; This_Alt_Char = 0;
++ SLsmg_set_color (0);
++ clear_region (0, Screen_Rows);
++ This_Alt_Char = tac;
++ SLsmg_set_color (0);
++ Cls_Flag = 1;
++}
++#if 0
++static void do_copy (SLsmg_Char_Type *a, SLsmg_Char_Type *b)
++{
++ SLsmg_Char_Type *amax = a + Screen_Cols;
++
++ while (a &lt; amax) *a++ = *b++;
++}
++#endif
++
++#ifndef IBMPC_SYSTEM
++int SLsmg_Scroll_Hash_Border = 0;
++static unsigned long compute_hash (SLsmg_Char_Type *s, int n)
++{
++ register unsigned long h = 0, g;
++ register unsigned long sum = 0;
++ register SLsmg_Char_Type *smax, ch;
++ int is_blank = 2;
++
++ s += SLsmg_Scroll_Hash_Border;
++ smax = s + (n - SLsmg_Scroll_Hash_Border);
++ while (s &lt; smax)
++ {
++ ch = *s++;
++ if (is_blank &amp;&amp; (SLSMG_EXTRACT_CHAR(ch) != 32)) is_blank--;
++
++ sum += ch;
++
++ h = sum + (h &lt;&lt; 3);
++ if ((g = h &amp; 0xE0000000UL) != 0)
++ {
++ h = h ^ (g &gt;&gt; 24);
++ h = h ^ g;
++ }
++ }
++ if (is_blank) return 0;
++ return h;
++}
++
++static unsigned long Blank_Hash;
++
++static int try_scroll_down (int rmin, int rmax)
++{
++ int i, r1, r2, di, j;
++ unsigned long hash;
++ int did_scroll;
++ int color;
++ SLsmg_Char_Type *tmp;
++ int ignore;
++
++ did_scroll = 0;
++ for (i = rmax; i &gt; rmin; i--)
++ {
++ hash = SL_Screen[i].new_hash;
++ if (hash == Blank_Hash) continue;
++
++ if ((hash == SL_Screen[i].old_hash)
++#if 0
++ || ((i + 1 &lt; Screen_Rows) &amp;&amp; (hash == SL_Screen[i + 1].old_hash))
++ || ((i - 1 &gt; rmin) &amp;&amp; (SL_Screen[i].old_hash == SL_Screen[i - 1].new_hash))
++#endif
++ )
++ continue;
++
++ for (j = i - 1; j &gt;= rmin; j--)
++ {
++ if (hash == SL_Screen[j].old_hash) break;
++ }
++ if (j &lt; rmin) continue;
++
++ r2 = i; /* end scroll region */
++
++ di = i - j;
++ j--;
++ ignore = 0;
++ while ((j &gt;= rmin) &amp;&amp; (SL_Screen[j].old_hash == SL_Screen[j + di].new_hash))
++ {
++ if (SL_Screen[j].old_hash == Blank_Hash) ignore++;
++ j--;
++ }
++ r1 = j + 1;
++
++ /* If this scroll only scrolls this line into place, don't do it.
++ */
++ if ((di &gt; 1) &amp;&amp; (r1 + di + ignore == r2)) continue;
++
++ /* If there is anything in the scrolling region that is ok, abort the
++ * scroll.
++ */
++
++ for (j = r1; j &lt;= r2; j++)
++ {
++ if ((SL_Screen[j].old_hash != Blank_Hash)
++ &amp;&amp; (SL_Screen[j].old_hash == SL_Screen[j].new_hash))
++ {
++ /* See if the scroll is happens to scroll this one into place. */
++ if ((j + di &gt; r2) || (SL_Screen[j].old_hash != SL_Screen[j + di].new_hash))
++ break;
++ }
++ }
++ if (j &lt;= r2) continue;
++
++ color = This_Color; This_Color = 0;
++ did_scroll = 1;
++ (*tt_normal_video) ();
++ (*tt_set_scroll_region) (r1, r2);
++ (*tt_goto_rc) (0, 0);
++ (*tt_reverse_index) (di);
++ (*tt_reset_scroll_region) ();
++ /* Now we have a hole in the screen.
++ * Make the virtual screen look like it.
++ *
++ * Note that if the terminal does not support BCE, then we have
++ * no idea what color the hole is. So, for this case, we do not
++ * want to add Bce_Color_Offset to This_Color since if Bce_Color_Offset
++ * is non-zero, then This_Color = 0 does not match any valid color
++ * obtained by adding Bce_Color_Offset.
++ */
++ for (j = r1; j &lt;= r2; j++) SL_Screen[j].flags = TOUCHED;
++
++ while (di--)
++ {
++ tmp = SL_Screen[r2].old;
++ for (j = r2; j &gt; r1; j--)
++ {
++ SL_Screen[j].old = SL_Screen[j - 1].old;
++ SL_Screen[j].old_hash = SL_Screen[j - 1].old_hash;
++ }
++ SL_Screen[r1].old = tmp;
++ blank_line (SL_Screen[r1].old, Screen_Cols, ' ');
++ SL_Screen[r1].old_hash = Blank_Hash;
++ r1++;
++ }
++ This_Color = color;
++ }
++
++ return did_scroll;
++}
++
++static int try_scroll_up (int rmin, int rmax)
++{
++ int i, r1, r2, di, j;
++ unsigned long hash;
++ int did_scroll;
++ int color;
++ SLsmg_Char_Type *tmp;
++ int ignore;
++
++ did_scroll = 0;
++ for (i = rmin; i &lt; rmax; i++)
++ {
++ hash = SL_Screen[i].new_hash;
++ if (hash == Blank_Hash) continue;
++ if (hash == SL_Screen[i].old_hash)
++ continue;
++ /* find a match further down screen */
++ for (j = i + 1; j &lt;= rmax; j++)
++ {
++ if (hash == SL_Screen[j].old_hash) break;
++ }
++ if (j &gt; rmax) continue;
++
++ r1 = i; /* beg scroll region */
++ di = j - i; /* number of lines to scroll */
++ j++; /* since we know this is a match */
++
++ /* find end of scroll region */
++ ignore = 0;
++ while ((j &lt;= rmax) &amp;&amp; (SL_Screen[j].old_hash == SL_Screen[j - di].new_hash))
++ {
++ if (SL_Screen[j].old_hash == Blank_Hash) ignore++;
++ j++;
++ }
++ r2 = j - 1; /* end of scroll region */
++
++ /* If this scroll only scrolls this line into place, don't do it.
++ */
++ if ((di &gt; 1) &amp;&amp; (r1 + di + ignore == r2)) continue;
++
++ /* If there is anything in the scrolling region that is ok, abort the
++ * scroll.
++ */
++
++ for (j = r1; j &lt;= r2; j++)
++ {
++ if ((SL_Screen[j].old_hash != Blank_Hash)
++ &amp;&amp; (SL_Screen[j].old_hash == SL_Screen[j].new_hash))
++ {
++ if ((j - di &lt; r1) || (SL_Screen[j].old_hash != SL_Screen[j - di].new_hash))
++ break;
++ }
++
++ }
++ if (j &lt;= r2) continue;
++
++ did_scroll = 1;
++
++ /* See the above comments about BCE */
++ color = This_Color; This_Color = 0;
++ (*tt_normal_video) ();
++ (*tt_set_scroll_region) (r1, r2);
++ (*tt_goto_rc) (0, 0); /* relative to scroll region */
++ (*tt_delete_nlines) (di);
++ (*tt_reset_scroll_region) ();
++ /* Now we have a hole in the screen. Make the virtual screen look
++ * like it.
++ */
++ for (j = r1; j &lt;= r2; j++) SL_Screen[j].flags = TOUCHED;
++
++ while (di--)
++ {
++ tmp = SL_Screen[r1].old;
++ for (j = r1; j &lt; r2; j++)
++ {
++ SL_Screen[j].old = SL_Screen[j + 1].old;
++ SL_Screen[j].old_hash = SL_Screen[j + 1].old_hash;
++ }
++ SL_Screen[r2].old = tmp;
++ blank_line (SL_Screen[r2].old, Screen_Cols, ' ');
++ SL_Screen[r2].old_hash = Blank_Hash;
++ r2--;
++ }
++ This_Color = color;
++ }
++ return did_scroll;
++}
++
++static void try_scroll (void)
++{
++ int r1, rmin, rmax;
++ int num_up, num_down;
++ /* find region limits. */
++
++ for (rmax = Screen_Rows - 1; rmax &gt; 0; rmax--)
++ {
++ if (SL_Screen[rmax].new_hash != SL_Screen[rmax].old_hash)
++ {
++ r1 = rmax - 1;
++ if ((r1 == 0)
++ || (SL_Screen[r1].new_hash != SL_Screen[r1].old_hash))
++ break;
++
++ rmax = r1;
++ }
++ }
++
++ for (rmin = 0; rmin &lt; rmax; rmin++)
++ {
++ if (SL_Screen[rmin].new_hash != SL_Screen[rmin].old_hash)
++ {
++ r1 = rmin + 1;
++ if ((r1 == rmax)
++ || (SL_Screen[r1].new_hash != SL_Screen[r1].old_hash))
++ break;
++
++ rmin = r1;
++ }
++ }
++
++ /* Below, we have two scrolling algorithms. The first has the effect of
++ * scrolling lines down. This is usually appropriate when one moves
++ * up the display, e.g., with the UP arrow. The second algorithm is
++ * appropriate for going the other way. It is important to choose the
++ * correct one.
++ */
++
++ num_up = 0;
++ for (r1 = rmin; r1 &lt; rmax; r1++)
++ {
++ if (SL_Screen[r1].new_hash == SL_Screen[r1 + 1].old_hash)
++ num_up++;
++ }
++
++ num_down = 0;
++ for (r1 = rmax; r1 &gt; rmin; r1--)
++ {
++ if (SL_Screen[r1 - 1].old_hash == SL_Screen[r1].new_hash)
++ num_down++;
++ }
++
++ if (num_up &gt; num_down)
++ {
++ if (try_scroll_up (rmin, rmax))
++ return;
++
++ (void) try_scroll_down (rmin, rmax);
++ }
++ else
++ {
++ if (try_scroll_down (rmin, rmax))
++ return;
++
++ (void) try_scroll_up (rmin, rmax);
++ }
++}
++#endif /* NOT IBMPC_SYSTEM */
++
++
++#ifdef REQUIRES_NON_BCE_SUPPORT
++static void adjust_colors (void)
++{
++ int bce;
++ int i;
++
++ bce = Bce_Color_Offset;
++ Bce_Color_Offset = _SLtt_get_bce_color_offset ();
++ if (bce == Bce_Color_Offset)
++ return;
++
++ if ((tt_Use_Blink_For_ACS != NULL)
++ &amp;&amp; (*tt_Use_Blink_For_ACS != 0))
++ return; /* this mode does not support non-BCE
++ * terminals.
++ */
++
++ for (i = 0; i &lt; Screen_Rows; i++)
++ {
++ SLsmg_Char_Type *s, *smax;
++
++ SL_Screen[i].flags |= TRASHED;
++ s = SL_Screen[i].neew;
++ smax = s + Screen_Cols;
++
++ while (s &lt; smax)
++ {
++ int color = (int) SLSMG_EXTRACT_COLOR(*s);
++ int acs;
++
++ if (color &lt; 0)
++ {
++ s++;
++ continue;
++ }
++
++ acs = color &amp; 0x80;
++ color = (color &amp; 0x7F) - bce;
++ color += Bce_Color_Offset;
++ if (color &gt;= 0)
++ {
++ unsigned char ch = SLSMG_EXTRACT_CHAR(*s);
++ *s = SLSMG_BUILD_CHAR(ch, ((color&amp;0x7F)|acs));
++ }
++ s++;
++ }
++ }
++}
++#endif
++
++void SLsmg_refresh (void)
++{
++ int i;
++#ifndef IBMPC_SYSTEM
++ int trashed = 0;
++#endif
++
++ if (Smg_Inited == 0) return;
++
++ if (Screen_Trashed)
++ {
++ Cls_Flag = 1;
++ for (i = 0; i &lt; Screen_Rows; i++)
++ SL_Screen[i].flags |= TRASHED;
++#ifdef REQUIRES_NON_BCE_SUPPORT
++ adjust_colors ();
++#endif
++ }
++
++#ifndef IBMPC_SYSTEM
++ for (i = 0; i &lt; Screen_Rows; i++)
++ {
++ if (SL_Screen[i].flags == 0) continue;
++ SL_Screen[i].new_hash = compute_hash (SL_Screen[i].neew, Screen_Cols);
++ trashed = 1;
++ }
++#endif
++
++ if (Cls_Flag)
++ {
++ (*tt_normal_video) (); (*tt_cls) ();
++ }
++#ifndef IBMPC_SYSTEM
++ else if (trashed &amp;&amp; (*tt_Term_Cannot_Scroll == 0)) try_scroll ();
++#endif
++
++ for (i = 0; i &lt; Screen_Rows; i++)
++ {
++ if (SL_Screen[i].flags == 0) continue;
++
++ if (Cls_Flag || SL_Screen[i].flags &amp; TRASHED)
++ {
++ int color = This_Color;
++
++ if (Cls_Flag == 0)
++ {
++ (*tt_goto_rc) (i, 0);
++ (*tt_del_eol) ();
++ }
++ This_Color = 0;
++ blank_line (SL_Screen[i].old, Screen_Cols, ' ');
++ This_Color = color;
++ }
++
++ SL_Screen[i].old[Screen_Cols] = 0;
++ SL_Screen[i].neew[Screen_Cols] = 0;
++
++ (*tt_smart_puts) (SL_Screen[i].neew, SL_Screen[i].old, Screen_Cols, i);
++
++ SLMEMCPY ((char *) SL_Screen[i].old, (char *) SL_Screen[i].neew,
++ Screen_Cols * sizeof (SLsmg_Char_Type));
++
++ SL_Screen[i].flags = 0;
++#ifndef IBMPC_SYSTEM
++ SL_Screen[i].old_hash = SL_Screen[i].new_hash;
++#endif
++ }
++
++ if (point_visible (1)) (*tt_goto_rc) (This_Row - Start_Row, This_Col - Start_Col);
++ (*tt_flush_output) ();
++ Cls_Flag = 0;
++ Screen_Trashed = 0;
++}
++
++static int compute_clip (int row, int n, int box_start, int box_end,
++ int *rmin, int *rmax)
++{
++ int row_max;
++
++ if (n &lt; 0) return 0;
++ if (row &gt;= box_end) return 0;
++ row_max = row + n;
++ if (row_max &lt;= box_start) return 0;
++
++ if (row &lt; box_start) row = box_start;
++ if (row_max &gt;= box_end) row_max = box_end;
++ *rmin = row;
++ *rmax = row_max;
++ return 1;
++}
++
++void SLsmg_touch_lines (int row, unsigned int n)
++{
++ int i;
++ int r1, r2;
++
++ /* Allow this function to be called even when we are not initialied.
++ * Calling this function is useful after calling SLtt_set_color
++ * to force the display to be redrawn
++ */
++
++ if (Smg_Inited == 0)
++ return;
++
++ if (0 == compute_clip (row, (int) n, Start_Row, Start_Row + Screen_Rows, &amp;r1, &amp;r2))
++ return;
++
++ r1 -= Start_Row;
++ r2 -= Start_Row;
++ for (i = r1; i &lt; r2; i++)
++ {
++ SL_Screen[i].flags |= TRASHED;
++ }
++}
++
++void SLsmg_touch_screen (void)
++{
++ Screen_Trashed = 1;
++}
++
++
++#ifndef IBMPC_SYSTEM
++static char Fake_Alt_Char_Pairs [] = &quot;a:j+k+l+m+q-t+u+v+w+x|n+`+f\\g#~o,&lt;+&gt;.v-^h#0#&quot;;
++
++static void init_alt_char_set (void)
++{
++ int i;
++ unsigned char *p, *pmax, ch;
++
++ if (Alt_Char_Set[128] == 128) return;
++
++ i = 32;
++ memset ((char *)Alt_Char_Set, ' ', i);
++ while (i &lt;= 128)
++ {
++ Alt_Char_Set [i] = i;
++ i++;
++ }
++
++ /* Map to VT100 */
++ if (*tt_Has_Alt_Charset)
++ {
++ if (tt_Graphics_Char_Pairs == NULL) p = NULL;
++ else p = (unsigned char *) *tt_Graphics_Char_Pairs;
++ if (p == NULL) return;
++ }
++ else p = (unsigned char *) Fake_Alt_Char_Pairs;
++ pmax = p + strlen ((char *) p);
++
++ /* Some systems have messed up entries for this */
++ while (p &lt; pmax)
++ {
++ ch = *p++;
++ ch &amp;= 0x7F; /* should be unnecessary */
++ Alt_Char_Set [ch] = *p;
++ p++;
++ }
++}
++#endif
++
++#ifndef IBMPC_SYSTEM
++# define BLOCK_SIGNALS SLsig_block_signals ()
++# define UNBLOCK_SIGNALS SLsig_unblock_signals ()
++#else
++# define BLOCK_SIGNALS (void)0
++# define UNBLOCK_SIGNALS (void)0
++#endif
++
++static int Smg_Suspended;
++int SLsmg_suspend_smg (void)
++{
++ BLOCK_SIGNALS;
++
++ if (Smg_Suspended == 0)
++ {
++ (*tt_reset_video) ();
++ Smg_Suspended = 1;
++ }
++
++ UNBLOCK_SIGNALS;
++ return 0;
++}
++
++int SLsmg_resume_smg (void)
++{
++ BLOCK_SIGNALS;
++
++ if (Smg_Suspended == 0)
++ {
++ UNBLOCK_SIGNALS;
++ return 0;
++ }
++
++ Smg_Suspended = 0;
++
++ if (-1 == (*tt_init_video) ())
++ {
++ UNBLOCK_SIGNALS;
++ return -1;
++ }
++
++ Cls_Flag = 1;
++ SLsmg_touch_screen ();
++ SLsmg_refresh ();
++
++ UNBLOCK_SIGNALS;
++ return 0;
++}
++
++
++static void reset_smg (void)
++{
++ int i;
++ if (Smg_Inited == 0)
++ return;
++
++ for (i = 0; i &lt; Screen_Rows; i++)
++ {
++ SLfree ((char *)SL_Screen[i].old);
++ SLfree ((char *)SL_Screen[i].neew);
++ SL_Screen[i].old = SL_Screen[i].neew = NULL;
++ }
++ This_Alt_Char = This_Color = 0;
++ Smg_Inited = 0;
++}
++
++
++static int init_smg (void)
++{
++ int i, len;
++ SLsmg_Char_Type *old, *neew;
++
++ Smg_Inited = 0;
++
++#ifdef REQUIRES_NON_BCE_SUPPORT
++ Bce_Color_Offset = _SLtt_get_bce_color_offset ();
++#endif
++
++ Screen_Rows = *tt_Screen_Rows;
++ if (Screen_Rows &gt; MAX_SCREEN_SIZE)
++ Screen_Rows = MAX_SCREEN_SIZE;
++
++ Screen_Cols = *tt_Screen_Cols;
++
++ This_Col = This_Row = Start_Col = Start_Row = 0;
++
++ This_Alt_Char = 0;
++ SLsmg_set_color (0);
++ Cls_Flag = 1;
++#ifndef IBMPC_SYSTEM
++ init_alt_char_set ();
++#endif
++ len = Screen_Cols + 3;
++ for (i = 0; i &lt; Screen_Rows; i++)
++ {
++ if ((NULL == (old = (SLsmg_Char_Type *) SLmalloc (sizeof(SLsmg_Char_Type) * len)))
++ || ((NULL == (neew = (SLsmg_Char_Type *) SLmalloc (sizeof(SLsmg_Char_Type) * len)))))
++ {
++ SLfree ((char *) old);
++ return -1;
++ }
++ blank_line (old, len, ' ');
++ blank_line (neew, len, ' ');
++ SL_Screen[i].old = old;
++ SL_Screen[i].neew = neew;
++ SL_Screen[i].flags = 0;
++#ifndef IBMPC_SYSTEM
++ Blank_Hash = compute_hash (old, Screen_Cols);
++ SL_Screen[i].new_hash = SL_Screen[i].old_hash = Blank_Hash;
++#endif
++ }
++
++ _SLtt_color_changed_hook = SLsmg_touch_screen;
++ Screen_Trashed = 1;
++ Smg_Inited = 1;
++ return 0;
++}
++
++
++int SLsmg_init_smg (void)
++{
++ int ret;
++
++ BLOCK_SIGNALS;
++
++ if (Smg_Inited)
++ SLsmg_reset_smg ();
++
++ if (-1 == (*tt_init_video) ())
++ {
++ UNBLOCK_SIGNALS;
++ return -1;
++ }
++
++ if (-1 == (ret = init_smg ()))
++ (void) (*tt_reset_video)();
++
++ UNBLOCK_SIGNALS;
++ return ret;
++}
++
++int SLsmg_reinit_smg (void)
++{
++ int ret;
++
++ if (Smg_Inited == 0)
++ return SLsmg_init_smg ();
++
++ BLOCK_SIGNALS;
++ reset_smg ();
++ ret = init_smg ();
++ UNBLOCK_SIGNALS;
++ return ret;
++}
++
++void SLsmg_reset_smg (void)
++{
++ if (Smg_Inited == 0)
++ return;
++
++ BLOCK_SIGNALS;
++
++ reset_smg ();
++ (*tt_reset_video)();
++
++ UNBLOCK_SIGNALS;
++}
++
++SLsmg_Char_Type SLsmg_char_at (void)
++{
++ if (Smg_Inited == 0) return 0;
++
++ if (point_visible (1))
++ {
++ return SL_Screen[This_Row - Start_Row].neew[This_Col - Start_Col];
++ }
++ return 0;
++}
++
++void SLsmg_vprintf (char *fmt, va_list ap)
++{
++ char buf[1024];
++
++ if (Smg_Inited == 0) return;
++
++ (void) _SLvsnprintf (buf, sizeof (buf), fmt, ap);
++ SLsmg_write_string (buf);
++}
++
++void SLsmg_printf (char *fmt, ...)
++{
++ va_list ap;
++ unsigned int len;
++ char *f;
++
++ if (Smg_Inited == 0) return;
++
++ va_start(ap, fmt);
++
++ f = fmt;
++ while (*f &amp;&amp; (*f != '%'))
++ f++;
++ len = (unsigned int) (f - fmt);
++ if (len) SLsmg_write_nchars (fmt, len);
++
++ if (*f != 0)
++ SLsmg_vprintf (f, ap);
++
++ va_end (ap);
++}
++
++void SLsmg_set_screen_start (int *r, int *c)
++{
++ int orow = Start_Row, oc = Start_Col;
++
++ if (Smg_Inited == 0) return;
++
++ if (c == NULL) Start_Col = 0;
++ else
++ {
++ Start_Col = *c;
++ *c = oc;
++ }
++ if (r == NULL) Start_Row = 0;
++ else
++ {
++ Start_Row = *r;
++ *r = orow;
++ }
++}
++
++void SLsmg_draw_object (int r, int c, unsigned char object)
++{
++ This_Row = r; This_Col = c;
++
++ if (Smg_Inited == 0) return;
++
++ if (point_visible (1))
++ {
++ int color = This_Color;
++ This_Color |= ALT_CHAR_FLAG;
++ SLsmg_write_char (object);
++ This_Color = color;
++ }
++
++ This_Col = c + 1;
++}
++
++void SLsmg_draw_hline (unsigned int n)
++{
++ static unsigned char hbuf[16];
++ int count;
++ int cmin, cmax;
++ int final_col = This_Col + (int) n;
++ int save_color;
++
++ if (Smg_Inited == 0) return;
++
++ if ((This_Row &lt; Start_Row) || (This_Row &gt;= Start_Row + Screen_Rows)
++ || (0 == compute_clip (This_Col, n, Start_Col, Start_Col + Screen_Cols,
++ &amp;cmin, &amp;cmax)))
++ {
++ This_Col = final_col;
++ return;
++ }
++
++ if (hbuf[0] == 0)
++ {
++ SLMEMSET ((char *) hbuf, SLSMG_HLINE_CHAR, 16);
++ }
++
++ n = (unsigned int)(cmax - cmin);
++ count = n / 16;
++
++ save_color = This_Color;
++ This_Color |= ALT_CHAR_FLAG;
++ This_Col = cmin;
++
++ SLsmg_write_nchars ((char *) hbuf, n % 16);
++ while (count-- &gt; 0)
++ {
++ SLsmg_write_nchars ((char *) hbuf, 16);
++ }
++
++ This_Color = save_color;
++ This_Col = final_col;
++}
++
++void SLsmg_draw_vline (int n)
++{
++ unsigned char ch = SLSMG_VLINE_CHAR;
++ int c = This_Col, rmin, rmax;
++ int final_row = This_Row + n;
++ int save_color;
++
++ if (Smg_Inited == 0) return;
++
++ if (((c &lt; Start_Col) || (c &gt;= Start_Col + Screen_Cols)) ||
++ (0 == compute_clip (This_Row, n, Start_Row, Start_Row + Screen_Rows,
++ &amp;rmin, &amp;rmax)))
++ {
++ This_Row = final_row;
++ return;
++ }
++
++ save_color = This_Color;
++ This_Color |= ALT_CHAR_FLAG;
++
++ for (This_Row = rmin; This_Row &lt; rmax; This_Row++)
++ {
++ This_Col = c;
++ SLsmg_write_nchars ((char *) &amp;ch, 1);
++ }
++
++ This_Col = c; This_Row = final_row;
++ This_Color = save_color;
++}
++
++void SLsmg_draw_box (int r, int c, unsigned int dr, unsigned int dc)
++{
++ if (Smg_Inited == 0) return;
++
++ if (!dr || !dc) return;
++ This_Row = r; This_Col = c;
++ dr--; dc--;
++ SLsmg_draw_hline (dc);
++ SLsmg_draw_vline (dr);
++ This_Row = r; This_Col = c;
++ SLsmg_draw_vline (dr);
++ SLsmg_draw_hline (dc);
++ SLsmg_draw_object (r, c, SLSMG_ULCORN_CHAR);
++ SLsmg_draw_object (r, c + (int) dc, SLSMG_URCORN_CHAR);
++ SLsmg_draw_object (r + (int) dr, c, SLSMG_LLCORN_CHAR);
++ SLsmg_draw_object (r + (int) dr, c + (int) dc, SLSMG_LRCORN_CHAR);
++ This_Row = r; This_Col = c;
++}
++
++void SLsmg_fill_region (int r, int c, unsigned int dr, unsigned int dc, unsigned char ch)
++{
++ static unsigned char hbuf[16];
++ int count;
++ int dcmax, rmax;
++
++ if (Smg_Inited == 0) return;
++
++ SLsmg_gotorc (r, c);
++ r = This_Row; c = This_Col;
++
++ dcmax = Screen_Cols - This_Col;
++ if (dcmax &lt; 0)
++ return;
++
++ if (dc &gt; (unsigned int) dcmax) dc = (unsigned int) dcmax;
++
++ rmax = This_Row + dr;
++ if (rmax &gt; Screen_Rows) rmax = Screen_Rows;
++
++#if 0
++ ch = Alt_Char_Set[ch];
++#endif
++ if (ch != hbuf[0]) SLMEMSET ((char *) hbuf, (char) ch, 16);
++
++ for (This_Row = r; This_Row &lt; rmax; This_Row++)
++ {
++ This_Col = c;
++ count = dc / 16;
++ SLsmg_write_nchars ((char *) hbuf, dc % 16);
++ while (count-- &gt; 0)
++ {
++ SLsmg_write_nchars ((char *) hbuf, 16);
++ }
++ }
++
++ This_Row = r;
++}
++
++void SLsmg_forward (int n)
++{
++ This_Col += n;
++}
++
++void SLsmg_write_color_chars (SLsmg_Char_Type *s, unsigned int len)
++{
++ SLsmg_Char_Type *smax, sh;
++ char buf[32], *b, *bmax;
++ int color, save_color;
++
++ if (Smg_Inited == 0) return;
++
++ smax = s + len;
++ b = buf;
++ bmax = b + sizeof (buf);
++
++ save_color = This_Color;
++
++ while (s &lt; smax)
++ {
++ sh = *s++;
++
++ color = SLSMG_EXTRACT_COLOR(sh);
++
++#if REQUIRES_NON_BCE_SUPPORT
++ if (Bce_Color_Offset)
++ {
++ if (color &amp; 0x80)
++ color = ((color &amp; 0x7F) + Bce_Color_Offset) | 0x80;
++ else
++ color = ((color &amp; 0x7F) + Bce_Color_Offset) &amp; 0x7F;
++ }
++#endif
++
++ if ((color != This_Color) || (b == bmax))
++ {
++ if (b != buf)
++ {
++ SLsmg_write_nchars (buf, (int) (b - buf));
++ b = buf;
++ }
++ This_Color = color;
++ }
++ *b++ = (char) SLSMG_EXTRACT_CHAR(sh);
++ }
++
++ if (b != buf)
++ SLsmg_write_nchars (buf, (unsigned int) (b - buf));
++
++ This_Color = save_color;
++}
++
++unsigned int SLsmg_read_raw (SLsmg_Char_Type *buf, unsigned int len)
++{
++ unsigned int r, c;
++
++ if (Smg_Inited == 0) return 0;
++
++ if (0 == point_visible (1)) return 0;
++
++ r = (unsigned int) (This_Row - Start_Row);
++ c = (unsigned int) (This_Col - Start_Col);
++
++ if (c + len &gt; (unsigned int) Screen_Cols)
++ len = (unsigned int) Screen_Cols - c;
++
++ memcpy ((char *) buf, (char *) (SL_Screen[r].neew + c), len * sizeof (SLsmg_Char_Type));
++ return len;
++}
++
++unsigned int SLsmg_write_raw (SLsmg_Char_Type *buf, unsigned int len)
++{
++ unsigned int r, c;
++ SLsmg_Char_Type *dest;
++
++ if (Smg_Inited == 0) return 0;
++
++ if (0 == point_visible (1)) return 0;
++
++ r = (unsigned int) (This_Row - Start_Row);
++ c = (unsigned int) (This_Col - Start_Col);
++
++ if (c + len &gt; (unsigned int) Screen_Cols)
++ len = (unsigned int) Screen_Cols - c;
++
++ dest = SL_Screen[r].neew + c;
++
++ if (0 != memcmp ((char *) dest, (char *) buf, len * sizeof (SLsmg_Char_Type)))
++ {
++ memcpy ((char *) dest, (char *) buf, len * sizeof (SLsmg_Char_Type));
++ SL_Screen[r].flags |= TOUCHED;
++ }
++ return len;
++}
++
++void
++SLsmg_set_color_in_region (int color, int r, int c, unsigned int dr, unsigned int dc)
++{
++ int cmax, rmax;
++ SLsmg_Char_Type char_mask;
++
++ if (Smg_Inited == 0) return;
++
++ c -= Start_Col;
++ r -= Start_Row;
++
++ cmax = c + (int) dc;
++ rmax = r + (int) dr;
++
++ if (cmax &gt; Screen_Cols) cmax = Screen_Cols;
++ if (rmax &gt; Screen_Rows) rmax = Screen_Rows;
++
++ if (c &lt; 0) c = 0;
++ if (r &lt; 0) r = 0;
++
++#if REQUIRES_NON_BCE_SUPPORT
++ if (Bce_Color_Offset)
++ {
++ if (color &amp; 0x80)
++ color = ((color &amp; 0x7F) + Bce_Color_Offset) | 0x80;
++ else
++ color = ((color &amp; 0x7F) + Bce_Color_Offset) &amp; 0x7F;
++ }
++#endif
++ color = color &lt;&lt; 8;
++
++ char_mask = 0xFF;
++
++#ifndef IBMPC_SYSTEM
++ if ((tt_Use_Blink_For_ACS == NULL)
++ || (0 == *tt_Use_Blink_For_ACS))
++ char_mask = 0x80FF;
++#endif
++
++ while (r &lt; rmax)
++ {
++ SLsmg_Char_Type *s, *smax;
++
++ SL_Screen[r].flags |= TOUCHED;
++ s = SL_Screen[r].neew;
++ smax = s + cmax;
++ s += c;
++
++ while (s &lt; smax)
++ {
++ *s = (*s &amp; char_mask) | color;
++ s++;
++ }
++ r++;
++ }
++}
++
++void SLsmg_set_terminal_info (SLsmg_Term_Type *tt)
++{
++ if (tt == NULL) /* use default */
++ return;
++
++ if ((tt-&gt;tt_normal_video == NULL)
++ || (tt-&gt;tt_goto_rc == NULL)
++ || (tt-&gt;tt_cls == NULL)
++ || (tt-&gt;tt_del_eol == NULL)
++ || (tt-&gt;tt_smart_puts == NULL)
++ || (tt-&gt;tt_flush_output == NULL)
++ || (tt-&gt;tt_reset_video == NULL)
++ || (tt-&gt;tt_init_video == NULL)
++#ifndef IBMPC_SYSTEM
++ || (tt-&gt;tt_set_scroll_region == NULL)
++ || (tt-&gt;tt_reverse_index == NULL)
++ || (tt-&gt;tt_reset_scroll_region == NULL)
++ || (tt-&gt;tt_delete_nlines == NULL)
++ /* Variables */
++ || (tt-&gt;tt_term_cannot_scroll == NULL)
++ || (tt-&gt;tt_has_alt_charset == NULL)
++#if 0 /* These can be NULL */
++ || (tt-&gt;tt_use_blink_for_acs == NULL)
++ || (tt-&gt;tt_graphic_char_pairs == NULL)
++#endif
++ || (tt-&gt;tt_screen_cols == NULL)
++ || (tt-&gt;tt_screen_rows == NULL)
++#endif
++ )
++ SLang_exit_error (&quot;Terminal not powerful enough for SLsmg&quot;);
++
++ tt_normal_video = tt-&gt;tt_normal_video;
++ tt_goto_rc = tt-&gt;tt_goto_rc;
++ tt_cls = tt-&gt;tt_cls;
++ tt_del_eol = tt-&gt;tt_del_eol;
++ tt_smart_puts = tt-&gt;tt_smart_puts;
++ tt_flush_output = tt-&gt;tt_flush_output;
++ tt_reset_video = tt-&gt;tt_reset_video;
++ tt_init_video = tt-&gt;tt_init_video;
++
++#ifndef IBMPC_SYSTEM
++ tt_set_scroll_region = tt-&gt;tt_set_scroll_region;
++ tt_reverse_index = tt-&gt;tt_reverse_index;
++ tt_reset_scroll_region = tt-&gt;tt_reset_scroll_region;
++ tt_delete_nlines = tt-&gt;tt_delete_nlines;
++
++ tt_Term_Cannot_Scroll = tt-&gt;tt_term_cannot_scroll;
++ tt_Has_Alt_Charset = tt-&gt;tt_has_alt_charset;
++ tt_Use_Blink_For_ACS = tt-&gt;tt_use_blink_for_acs;
++ tt_Graphics_Char_Pairs = tt-&gt;tt_graphic_char_pairs;
++#endif
++
++ tt_Screen_Cols = tt-&gt;tt_screen_cols;
++ tt_Screen_Rows = tt-&gt;tt_screen_rows;
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slsmg.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slstd.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slstd.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slstd.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,724 @@
++/* -*- mode: C; mode: fold; -*- */
++/* Standard intrinsic functions for S-Lang. Included here are string
++ and array operations */
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++/*{{{ Include Files */
++
++#include &lt;time.h&gt;
++
++#ifndef __QNX__
++# if defined(__GO32__) || defined(__WATCOMC__)
++# include &lt;dos.h&gt;
++# include &lt;bios.h&gt;
++# endif
++#endif
++
++#if SLANG_HAS_FLOAT
++# include &lt;math.h&gt;
++#endif
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++/*}}}*/
++
++/* builtin stack manipulation functions */
++int SLdo_pop(void) /*{{{*/
++{
++ return SLdo_pop_n (1);
++}
++
++/*}}}*/
++
++int SLdo_pop_n (unsigned int n)
++{
++ SLang_Object_Type x;
++
++ while (n--)
++ {
++ if (SLang_pop(&amp;x)) return -1;
++ SLang_free_object (&amp;x);
++ }
++
++ return 0;
++}
++
++static void do_dup(void) /*{{{*/
++{
++ (void) SLdup_n (1);
++}
++
++/*}}}*/
++
++static int length_cmd (void)
++{
++ SLang_Class_Type *cl;
++ SLang_Object_Type obj;
++ VOID_STAR p;
++ unsigned int length;
++ int len;
++
++ if (-1 == SLang_pop (&amp;obj))
++ return -1;
++
++ cl = _SLclass_get_class (obj.data_type);
++ p = _SLclass_get_ptr_to_value (cl, &amp;obj);
++
++ len = 1;
++ if (cl-&gt;cl_length != NULL)
++ {
++ if (0 == (*cl-&gt;cl_length)(obj.data_type, p, &amp;length))
++ len = (int) length;
++ else
++ len = -1;
++ }
++
++ SLang_free_object (&amp;obj);
++ return len;
++}
++
++/* convert integer to a string of length 1 */
++static void char_cmd (int *x) /*{{{*/
++{
++ char ch, buf[2];
++
++ ch = (char) *x;
++ buf[0] = ch;
++ buf[1] = 0;
++ SLang_push_string (buf);
++}
++
++/*}}}*/
++
++/* format object into a string and returns slstring */
++char *_SLstringize_object (SLang_Object_Type *obj) /*{{{*/
++{
++ SLang_Class_Type *cl;
++ unsigned char stype;
++ VOID_STAR p;
++ char *s, *s1;
++
++ stype = obj-&gt;data_type;
++ p = (VOID_STAR) &amp;obj-&gt;v.ptr_val;
++
++ cl = _SLclass_get_class (stype);
++
++ s = (*cl-&gt;cl_string) (stype, p);
++ if (s != NULL)
++ {
++ s1 = SLang_create_slstring (s);
++ SLfree (s);
++ s = s1;
++ }
++ return s;
++}
++/*}}}*/
++
++int SLang_run_hooks(char *hook, unsigned int num_args, ...)
++{
++ unsigned int i;
++ va_list ap;
++
++ if (SLang_Error) return -1;
++
++ if (0 == SLang_is_defined (hook))
++ return 0;
++
++ (void) SLang_start_arg_list ();
++ va_start (ap, num_args);
++ for (i = 0; i &lt; num_args; i++)
++ {
++ char *arg;
++
++ arg = va_arg (ap, char *);
++ if (-1 == SLang_push_string (arg))
++ break;
++ }
++ va_end (ap);
++ (void) SLang_end_arg_list ();
++
++ if (SLang_Error) return -1;
++ return SLang_execute_function (hook);
++}
++
++static void intrin_getenv_cmd (char *s)
++{
++ SLang_push_string (getenv (s));
++}
++
++#ifdef HAVE_PUTENV
++static void intrin_putenv (void) /*{{{*/
++{
++ char *s;
++
++ /* Some putenv implementations required malloced strings. */
++ if (SLpop_string(&amp;s)) return;
++
++ if (putenv (s))
++ {
++ SLang_Error = SL_INTRINSIC_ERROR;
++ SLfree (s);
++ }
++
++ /* Note that s is NOT freed */
++}
++
++/*}}}*/
++
++#endif
++
++static void lang_print_stack (void) /*{{{*/
++{
++ char buf[32];
++ unsigned int n;
++
++ n = (unsigned int) (_SLStack_Pointer - _SLRun_Stack);
++ while (n)
++ {
++ n--;
++ sprintf (buf, &quot;(%u)&quot;, n);
++ _SLdump_objects (buf, _SLRun_Stack + n, 1, 1);
++ }
++}
++
++/*}}}*/
++
++static void byte_compile_file (char *f, int *m)
++{
++ SLang_byte_compile_file (f, *m);
++}
++
++static void intrin_type_info1 (void)
++{
++ SLang_Object_Type obj;
++ unsigned int type;
++
++ if (-1 == SLang_pop (&amp;obj))
++ return;
++
++ type = obj.data_type;
++ if (type == SLANG_ARRAY_TYPE)
++ type = obj.v.array_val-&gt;data_type;
++
++ SLang_free_object (&amp;obj);
++
++ _SLang_push_datatype (type);
++}
++
++static void intrin_type_info (void)
++{
++ SLang_Object_Type obj;
++
++ if (-1 == SLang_pop (&amp;obj))
++ return;
++
++ _SLang_push_datatype (obj.data_type);
++ SLang_free_object (&amp;obj);
++}
++
++void _SLstring_intrinsic (void) /*{{{*/
++{
++ SLang_Object_Type x;
++ char *s;
++
++ if (SLang_pop (&amp;x)) return;
++ if (NULL != (s = _SLstringize_object (&amp;x)))
++ _SLang_push_slstring (s);
++
++ SLang_free_object (&amp;x);
++}
++
++/*}}}*/
++
++static void intrin_typecast (void)
++{
++ unsigned char to_type;
++ if (0 == _SLang_pop_datatype (&amp;to_type))
++ (void) SLclass_typecast (to_type, 0, 1);
++}
++
++#if SLANG_HAS_FLOAT
++static void intrin_double (void)
++{
++ (void) SLclass_typecast (SLANG_DOUBLE_TYPE, 0, 1);
++}
++
++#endif
++
++static void intrin_int (void) /*{{{*/
++{
++ (void) SLclass_typecast (SLANG_INT_TYPE, 0, 1);
++}
++
++/*}}}*/
++
++static char *
++intrin_function_name (void)
++{
++ if (NULL == _SLang_Current_Function_Name)
++ return &quot;&quot;;
++ return _SLang_Current_Function_Name;
++}
++
++static void intrin_message (char *s)
++{
++ SLang_vmessage (&quot;%s&quot;, s);
++}
++
++static void intrin_error (char *s)
++{
++ SLang_verror (SL_USER_ERROR, &quot;%s&quot;, s);
++}
++
++static void intrin_pop_n (int *n)
++{
++ SLdo_pop_n ((unsigned int) *n);
++}
++
++static void intrin_reverse_stack (int *n)
++{
++ SLreverse_stack (*n);
++}
++
++static void intrin_roll_stack (int *n)
++{
++ SLroll_stack (*n);
++}
++
++static void usage (void)
++{
++ char *msg;
++
++ _SLstrops_do_sprintf_n (SLang_Num_Function_Args - 1); /* do not include format */
++
++ if (-1 == SLang_pop_slstring (&amp;msg))
++ return;
++
++ SLang_verror (SL_USAGE_ERROR, &quot;Usage: %s&quot;, msg);
++ SLang_free_slstring (msg);
++}
++
++/* Convert string to integer */
++static int intrin_integer (char *s)
++{
++ int i;
++
++ i = SLatoi ((unsigned char *) s);
++
++ if (SLang_Error)
++ SLang_verror (SL_TYPE_MISMATCH, &quot;Unable to convert string to integer&quot;);
++ return i;
++}
++/*}}}*/
++
++static void guess_type (char *s)
++{
++ _SLang_push_datatype (SLang_guess_type(s));
++}
++
++static int load_file (char *s)
++{
++ if (-1 == SLang_load_file (s))
++ return 0;
++ return 1;
++}
++
++static void get_doc_string (char *file, char *topic)
++{
++ FILE *fp;
++ char line[1024];
++ unsigned int topic_len, str_len;
++ char *str;
++ char ch;
++
++ if (NULL == (fp = fopen (file, &quot;r&quot;)))
++ {
++ SLang_push_null ();
++ return;
++ }
++
++ topic_len = strlen (topic);
++ ch = *topic;
++
++ while (1)
++ {
++ if (NULL == fgets (line, sizeof(line), fp))
++ {
++ fclose (fp);
++ (void) SLang_push_null ();
++ return;
++ }
++
++ if ((ch == *line)
++ &amp;&amp; (0 == strncmp (line, topic, topic_len))
++ &amp;&amp; ((line[topic_len] == '\n') || (line [topic_len] == 0)
++ || (line[topic_len] == ' ') || (line[topic_len] == '\t')))
++ break;
++ }
++
++ if (NULL == (str = SLmake_string (line)))
++ {
++ fclose (fp);
++ (void) SLang_push_null ();
++ return;
++ }
++ str_len = strlen (str);
++
++ while (NULL != fgets (line, sizeof (line), fp))
++ {
++ unsigned int len;
++ char *new_str;
++
++ ch = *line;
++ if (ch == '#') continue;
++ if (ch == '-') break;
++
++ len = strlen (line);
++ if (NULL == (new_str = SLrealloc (str, str_len + len + 1)))
++ {
++ SLfree (str);
++ str = NULL;
++ break;
++ }
++ str = new_str;
++ strcpy (str + str_len, line);
++ str_len += len;
++ }
++
++ fclose (fp);
++
++ (void) SLang_push_malloced_string (str);
++}
++
++static int push_string_array_elements (SLang_Array_Type *at)
++{
++ char **strs;
++ unsigned int num;
++ unsigned int i;
++
++ if (at == NULL)
++ return -1;
++
++ strs = (char **)at-&gt;data;
++ num = at-&gt;num_elements;
++ for (i = 0; i &lt; num; i++)
++ {
++ if (-1 == SLang_push_string (strs[i]))
++ {
++ SLdo_pop_n (i);
++ return -1;
++ }
++ }
++ SLang_push_integer ((int) num);
++ return 0;
++}
++
++
++static void intrin_apropos (void)
++{
++ int num_args;
++ char *pat;
++ char *namespace_name;
++ unsigned int flags;
++ SLang_Array_Type *at;
++
++ num_args = SLang_Num_Function_Args;
++
++ if (-1 == SLang_pop_uinteger (&amp;flags))
++ return;
++ if (-1 == SLang_pop_slstring (&amp;pat))
++ return;
++
++ namespace_name = NULL;
++ at = NULL;
++ if (num_args == 3)
++ {
++ if (-1 == SLang_pop_slstring (&amp;namespace_name))
++ goto free_and_return;
++ }
++
++ at = _SLang_apropos (namespace_name, pat, flags);
++ if (num_args == 3)
++ {
++ (void) SLang_push_array (at, 0);
++ goto free_and_return;
++ }
++
++ /* Maintain compatibility with old version of the function. That version
++ * did not take three arguments and returned everything to the stack.
++ * Yuk.
++ */
++ (void) push_string_array_elements (at);
++
++ free_and_return:
++ /* NULLs ok */
++ SLang_free_slstring (namespace_name);
++ SLang_free_slstring (pat);
++ SLang_free_array (at);
++}
++
++static int intrin_get_defines (void)
++{
++ int n = 0;
++ char **s = _SLdefines;
++
++ while (*s != NULL)
++ {
++ if (-1 == SLang_push_string (*s))
++ {
++ SLdo_pop_n ((unsigned int) n);
++ return -1;
++ }
++ s++;
++ n++;
++ }
++ return n;
++}
++
++static void intrin_get_reference (char *name)
++{
++ _SLang_push_ref (1, (VOID_STAR) _SLlocate_name (name));
++}
++
++#ifdef HAVE_SYS_UTSNAME_H
++# include &lt;sys/utsname.h&gt;
++#endif
++
++static void uname_cmd (void)
++{
++#ifdef HAVE_UNAME
++ struct utsname u;
++ char *field_names [6];
++ unsigned char field_types[6];
++ VOID_STAR field_values [6];
++ char *ptrs[6];
++ int i;
++
++ if (-1 == uname (&amp;u))
++ (void) SLang_push_null ();
++
++ field_names[0] = &quot;sysname&quot;; ptrs[0] = u.sysname;
++ field_names[1] = &quot;nodename&quot;; ptrs[1] = u.nodename;
++ field_names[2] = &quot;release&quot;; ptrs[2] = u.release;
++ field_names[3] = &quot;version&quot;; ptrs[3] = u.version;
++ field_names[4] = &quot;machine&quot;; ptrs[4] = u.machine;
++
++ for (i = 0; i &lt; 5; i++)
++ {
++ field_types[i] = SLANG_STRING_TYPE;
++ field_values[i] = (VOID_STAR) &amp;ptrs[i];
++ }
++
++ if (0 == SLstruct_create_struct (5, field_names, field_types, field_values))
++ return;
++#endif
++
++ SLang_push_null ();
++}
++
++static void uninitialize_ref_intrin (SLang_Ref_Type *ref)
++{
++ (void) _SLang_uninitialize_ref (ref);
++}
++
++static SLang_Intrin_Fun_Type SLang_Basic_Table [] = /*{{{*/
++{
++ MAKE_INTRINSIC_1(&quot;__is_initialized&quot;, _SLang_is_ref_initialized, SLANG_INT_TYPE, SLANG_REF_TYPE),
++ MAKE_INTRINSIC_S(&quot;__get_reference&quot;, intrin_get_reference, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_1(&quot;__uninitialize&quot;, uninitialize_ref_intrin, SLANG_VOID_TYPE, SLANG_REF_TYPE),
++ MAKE_INTRINSIC_SS(&quot;get_doc_string_from_file&quot;, get_doc_string, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_SS(&quot;autoload&quot;, SLang_autoload, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_S(&quot;is_defined&quot;, SLang_is_defined, SLANG_INT_TYPE),
++ MAKE_INTRINSIC_0(&quot;string&quot;, _SLstring_intrinsic, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_0(&quot;uname&quot;, uname_cmd, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_S(&quot;getenv&quot;, intrin_getenv_cmd, SLANG_VOID_TYPE),
++#ifdef HAVE_PUTENV
++ MAKE_INTRINSIC_0(&quot;putenv&quot;, intrin_putenv, SLANG_VOID_TYPE),
++#endif
++ MAKE_INTRINSIC_S(&quot;evalfile&quot;, load_file, SLANG_INT_TYPE),
++ MAKE_INTRINSIC_I(&quot;char&quot;, char_cmd, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_S(&quot;eval&quot;, SLang_load_string, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_0(&quot;dup&quot;, do_dup, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_S(&quot;integer&quot;, intrin_integer, SLANG_INT_TYPE),
++ MAKE_INTRINSIC_S(&quot;system&quot;, SLsystem, SLANG_INT_TYPE),
++ MAKE_INTRINSIC_0(&quot;_apropos&quot;, intrin_apropos, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_S(&quot;_trace_function&quot;, _SLang_trace_fun, SLANG_VOID_TYPE),
++#if SLANG_HAS_FLOAT
++ MAKE_INTRINSIC_S(&quot;atof&quot;, _SLang_atof, SLANG_DOUBLE_TYPE),
++ MAKE_INTRINSIC_0(&quot;double&quot;, intrin_double, SLANG_VOID_TYPE),
++#endif
++ MAKE_INTRINSIC_0(&quot;int&quot;, intrin_int, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_0(&quot;typecast&quot;, intrin_typecast, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_0(&quot;_stkdepth&quot;, _SLstack_depth, SLANG_INT_TYPE),
++ MAKE_INTRINSIC_I(&quot;_stk_reverse&quot;, intrin_reverse_stack, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_0(&quot;typeof&quot;, intrin_type_info, VOID_TYPE),
++ MAKE_INTRINSIC_0(&quot;_typeof&quot;, intrin_type_info1, VOID_TYPE),
++ MAKE_INTRINSIC_I(&quot;_pop_n&quot;, intrin_pop_n, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_0(&quot;_print_stack&quot;, lang_print_stack, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_I(&quot;_stk_roll&quot;, intrin_roll_stack, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_SI(&quot;byte_compile_file&quot;, byte_compile_file, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_0(&quot;_clear_error&quot;, _SLang_clear_error, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_0(&quot;_function_name&quot;, intrin_function_name, SLANG_STRING_TYPE),
++#if SLANG_HAS_FLOAT
++ MAKE_INTRINSIC_S(&quot;set_float_format&quot;, _SLset_double_format, SLANG_VOID_TYPE),
++#endif
++ MAKE_INTRINSIC_S(&quot;_slang_guess_type&quot;, guess_type, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_S(&quot;error&quot;, intrin_error, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_S(&quot;message&quot;, intrin_message, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_0(&quot;__get_defined_symbols&quot;, intrin_get_defines, SLANG_INT_TYPE),
++ MAKE_INTRINSIC_I(&quot;__pop_args&quot;, _SLstruct_pop_args, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_1(&quot;__push_args&quot;, _SLstruct_push_args, SLANG_VOID_TYPE, SLANG_ARRAY_TYPE),
++ MAKE_INTRINSIC_0(&quot;usage&quot;, usage, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_S(&quot;implements&quot;, _SLang_implements_intrinsic, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_S(&quot;use_namespace&quot;, _SLang_use_namespace_intrinsic, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_0(&quot;current_namespace&quot;, _SLang_cur_namespace_intrinsic, SLANG_STRING_TYPE),
++ MAKE_INTRINSIC_0(&quot;length&quot;, length_cmd, SLANG_INT_TYPE),
++ SLANG_END_INTRIN_FUN_TABLE
++};
++
++/*}}}*/
++
++#ifdef SLANG_DOC_DIR
++char *SLang_Doc_Dir = SLANG_DOC_DIR;
++#else
++char *SLang_Doc_Dir = &quot;&quot;;
++#endif
++
++static SLang_Intrin_Var_Type Intrin_Vars[] =
++{
++ MAKE_VARIABLE(&quot;_debug_info&quot;, &amp;_SLang_Compile_Line_Num_Info, SLANG_INT_TYPE, 0),
++ MAKE_VARIABLE(&quot;_auto_declare&quot;, &amp;_SLang_Auto_Declare_Globals, SLANG_INT_TYPE, 0),
++ MAKE_VARIABLE(&quot;_traceback&quot;, &amp;SLang_Traceback, SLANG_INT_TYPE, 0),
++ MAKE_VARIABLE(&quot;_slangtrace&quot;, &amp;_SLang_Trace, SLANG_INT_TYPE, 0),
++ MAKE_VARIABLE(&quot;_slang_version&quot;, &amp;SLang_Version, SLANG_INT_TYPE, 1),
++ MAKE_VARIABLE(&quot;_slang_version_string&quot;, &amp;SLang_Version_String, SLANG_STRING_TYPE, 1),
++ MAKE_VARIABLE(&quot;_NARGS&quot;, &amp;SLang_Num_Function_Args, SLANG_INT_TYPE, 1),
++ MAKE_VARIABLE(&quot;_slang_doc_dir&quot;, &amp;SLang_Doc_Dir, SLANG_STRING_TYPE, 1),
++ MAKE_VARIABLE(&quot;NULL&quot;, NULL, SLANG_NULL_TYPE, 1),
++ SLANG_END_INTRIN_VAR_TABLE
++};
++
++int SLang_init_slang (void) /*{{{*/
++{
++ char name[3];
++ unsigned int i;
++ char **s;
++ static char *sys_defines [] =
++ {
++#if defined(__os2__)
++ &quot;OS2&quot;,
++#endif
++#if defined(__MSDOS__)
++ &quot;MSDOS&quot;,
++#endif
++#if defined(__WIN16__)
++ &quot;WIN16&quot;,
++#endif
++#if defined (__WIN32__)
++ &quot;WIN32&quot;,
++#endif
++#if defined(__NT__)
++ &quot;NT&quot;,
++#endif
++#if defined (VMS)
++ &quot;VMS&quot;,
++#endif
++#ifdef REAL_UNIX_SYSTEM
++ &quot;UNIX&quot;,
++#endif
++#if SLANG_HAS_FLOAT
++ &quot;SLANG_DOUBLE_TYPE&quot;,
++#endif
++ NULL
++ };
++
++ if (-1 == _SLregister_types ()) return -1;
++
++ if ((-1 == SLadd_intrin_fun_table(SLang_Basic_Table, NULL))
++ || (-1 == SLadd_intrin_var_table (Intrin_Vars, NULL))
++ || (-1 == _SLang_init_slstrops ())
++ || (-1 == _SLang_init_sltime ())
++ || (-1 == _SLstruct_init ())
++#if SLANG_HAS_COMPLEX
++ || (-1 == _SLinit_slcomplex ())
++#endif
++#if SLANG_HAS_ASSOC_ARRAYS
++ || (-1 == SLang_init_slassoc ())
++#endif
++ )
++ return -1;
++
++ SLadd_global_variable (SLANG_SYSTEM_NAME);
++
++ s = sys_defines;
++ while (*s != NULL)
++ {
++ if (-1 == SLdefine_for_ifdef (*s)) return -1;
++ s++;
++ }
++
++ /* give temp global variables $0 --&gt; $9 */
++ name[2] = 0; name[0] = '$';
++ for (i = 0; i &lt; 10; i++)
++ {
++ name[1] = (char) (i + '0');
++ SLadd_global_variable (name);
++ }
++
++ SLang_init_case_tables ();
++
++ /* Now add a couple of macros */
++ SLang_load_string (&quot;.(_NARGS 1 - Sprintf error)verror&quot;);
++ SLang_load_string (&quot;.(_NARGS 1 - Sprintf message)vmessage&quot;);
++
++ if (SLang_Error)
++ return -1;
++
++ return 0;
++}
++
++/*}}}*/
++
++int SLang_set_argc_argv (int argc, char **argv)
++{
++ static int this_argc;
++ static char **this_argv;
++ int i;
++
++ if (argc &lt; 0) argc = 0;
++ this_argc = argc;
++
++ if (NULL == (this_argv = (char **) SLmalloc ((argc + 1) * sizeof (char *))))
++ return -1;
++ memset ((char *) this_argv, 0, sizeof (char *) * (argc + 1));
++
++ for (i = 0; i &lt; argc; i++)
++ {
++ if (NULL == (this_argv[i] = SLang_create_slstring (argv[i])))
++ goto return_error;
++ }
++
++ if (-1 == SLadd_intrinsic_variable (&quot;__argc&quot;, (VOID_STAR)&amp;this_argc,
++ SLANG_INT_TYPE, 1))
++ goto return_error;
++
++ if (-1 == SLang_add_intrinsic_array (&quot;__argv&quot;, SLANG_STRING_TYPE, 1,
++ (VOID_STAR) this_argv, 1, argc))
++ goto return_error;
++
++ return 0;
++
++ return_error:
++ for (i = 0; i &lt; argc; i++)
++ SLang_free_slstring (this_argv[i]); /* NULL ok */
++ SLfree ((char *) this_argv);
++
++ return -1;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slstd.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slstdio.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slstdio.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slstdio.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1050 @@
++/* file stdio intrinsics for S-Lang */
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++
++#if defined(__unix__) || (defined (__os2__) &amp;&amp; defined (__EMX__))
++# include &lt;sys/types.h&gt;
++#endif
++
++#ifdef HAVE_FCNTL_H
++# include &lt;fcntl.h&gt;
++#endif
++#ifdef HAVE_SYS_FCNTL_H
++# include &lt;sys/fcntl.h&gt;
++#endif
++
++#ifdef __unix__
++# include &lt;sys/file.h&gt;
++#endif
++
++#if defined(__BORLANDC__)
++# include &lt;io.h&gt;
++# include &lt;dir.h&gt;
++#endif
++
++#if defined(__DECC) &amp;&amp; defined(VMS)
++# include &lt;unixio.h&gt;
++# include &lt;unixlib.h&gt;
++#endif
++
++#ifdef VMS
++# include &lt;stat.h&gt;
++#else
++# include &lt;sys/stat.h&gt;
++#endif
++
++#include &lt;errno.h&gt;
++
++#define SL_APP_WANTS_FOREACH
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++typedef struct
++{
++ FILE *fp; /* kind of obvious */
++ char *file; /* file name associated with pointer */
++
++ unsigned int flags; /* modes, etc... */
++#define SL_READ 0x0001
++#define SL_WRITE 0x0002
++#define SL_BINARY 0x0004
++#define SL_FDOPEN 0x2000
++#define SL_PIPE 0x4000
++#define SL_INUSE 0x8000
++}
++SL_File_Table_Type;
++
++static SL_File_Table_Type *SL_File_Table;
++
++static SL_File_Table_Type *get_free_file_table_entry (void)
++{
++ SL_File_Table_Type *t = SL_File_Table, *tmax;
++
++ tmax = t + SL_MAX_FILES;
++ while (t &lt; tmax)
++ {
++ if (t-&gt;flags == 0)
++ {
++ memset ((char *) t, 0, sizeof (SL_File_Table_Type));
++ return t;
++ }
++ t++;
++ }
++
++ return NULL;
++}
++
++static unsigned int file_process_flags (char *mode)
++{
++ char ch;
++ unsigned int flags = 0;
++
++ while (1)
++ {
++ ch = *mode++;
++ switch (ch)
++ {
++ case 'r': flags |= SL_READ;
++ break;
++ case 'w':
++ case 'a':
++ case 'A':
++ flags |= SL_WRITE;
++ break;
++ case '+': flags |= SL_WRITE | SL_READ;
++ break;
++ case 'b': flags |= SL_BINARY;
++ break;
++ case 0:
++ return flags;
++
++ default:
++ SLang_verror (SL_INVALID_PARM, &quot;File flag %c is not supported&quot;, ch);
++ return 0;
++ }
++ }
++}
++
++static int open_file_type (char *file, int fd, char *mode,
++ FILE *(*open_fun)(char *, char *),
++ int (*close_fun)(FILE *),
++ unsigned int xflags)
++{
++ FILE *fp;
++ SL_File_Table_Type *t;
++ unsigned int flags;
++ SLang_MMT_Type *mmt;
++
++ fp = NULL;
++ t = NULL;
++ mmt = NULL;
++
++ if ((NULL == (t = get_free_file_table_entry ()))
++ || (0 == (flags = file_process_flags(mode))))
++ goto return_error;
++
++ if (fd != -1)
++ fp = fdopen (fd, mode);
++ else
++ fp = open_fun (file, mode);
++
++ if (fp == NULL)
++ {
++ _SLerrno_errno = errno;
++ goto return_error;
++ }
++
++ if (NULL == (mmt = SLang_create_mmt (SLANG_FILE_PTR_TYPE, (VOID_STAR) t)))
++ goto return_error;
++
++ t-&gt;fp = fp;
++ t-&gt;flags = flags | xflags;
++ fp = NULL; /* allow free_mmt to close fp */
++
++ if ((NULL != (t-&gt;file = SLang_create_slstring (file)))
++ &amp;&amp; (0 == SLang_push_mmt (mmt)))
++ return 0;
++
++ /* drop */
++
++ return_error:
++ if (fp != NULL) (*close_fun) (fp);
++ if (mmt != NULL) SLang_free_mmt (mmt);
++ (void) SLang_push_null ();
++ return -1;
++}
++
++/* Since some compilers do not have popen/pclose prototyped and in scope,
++ * and pc compilers sometimes have silly prototypes involving PASCAL, etc.
++ * use wrappers around the function to avoid compilation errors.
++ */
++
++static FILE *fopen_fun (char *f, char *m)
++{
++ return fopen (f, m);
++}
++static int fclose_fun (FILE *fp)
++{
++ return fclose (fp);
++}
++
++static void stdio_fopen (char *file, char *mode)
++{
++ (void) open_file_type (file, -1, mode, fopen_fun, fclose_fun, 0);
++}
++
++int _SLstdio_fdopen (char *file, int fd, char *mode)
++{
++ if (fd == -1)
++ {
++ _SLerrno_errno = EBADF;
++ (void) SLang_push_null ();
++ return -1;
++ }
++
++ return open_file_type (file, fd, mode, NULL, fclose_fun, SL_FDOPEN);
++}
++
++#ifdef HAVE_POPEN
++static int pclose_fun (FILE *fp)
++{
++ return pclose (fp);
++}
++
++static FILE *popen_fun (char *file, char *mode)
++{
++ return popen (file, mode);
++}
++
++static void stdio_popen (char *file, char *mode)
++{
++ (void) open_file_type (file, -1, mode, popen_fun, pclose_fun, SL_PIPE);
++}
++#endif
++
++/* returns pointer to file entry if it is open and consistent with
++ flags. Returns NULL otherwise */
++static SLang_MMT_Type *pop_fp (unsigned int flags, FILE **fp_ptr)
++{
++ SL_File_Table_Type *t;
++ SLang_MMT_Type *mmt;
++
++ *fp_ptr = NULL;
++
++ if (NULL == (mmt = SLang_pop_mmt (SLANG_FILE_PTR_TYPE)))
++ return NULL;
++
++ t = (SL_File_Table_Type *) SLang_object_from_mmt (mmt);
++ if ((t-&gt;flags &amp; flags)
++ &amp;&amp; (NULL != (*fp_ptr = t-&gt;fp)))
++ return mmt;
++
++ SLang_free_mmt (mmt);
++ return NULL;
++}
++
++static FILE *check_fp (SL_File_Table_Type *t, unsigned flags)
++{
++ if ((t != NULL) &amp;&amp; (t-&gt;flags &amp; flags))
++ return t-&gt;fp;
++
++ return NULL;
++}
++
++char *SLang_get_name_from_fileptr (SLang_MMT_Type *mmt)
++{
++ SL_File_Table_Type *ft;
++
++ ft = (SL_File_Table_Type *) SLang_object_from_mmt (mmt);
++ if (ft == NULL)
++ return NULL;
++ return ft-&gt;file;
++}
++
++int SLang_pop_fileptr (SLang_MMT_Type **mmt, FILE **fp)
++{
++ if (NULL == (*mmt = pop_fp (0xFFFF, fp)))
++ {
++#ifdef EBADF
++ _SLerrno_errno = EBADF;
++#endif
++ return -1;
++ }
++
++ return 0;
++}
++
++static int close_file_type (SL_File_Table_Type *t)
++{
++ int ret = 0;
++ FILE *fp;
++
++ if (t == NULL)
++ return -1;
++
++ fp = t-&gt;fp;
++
++ if (NULL == fp) ret = -1;
++ else
++ {
++ if (0 == (t-&gt;flags &amp; SL_PIPE))
++ {
++ if (EOF == (ret = fclose (fp)))
++ _SLerrno_errno = errno;
++ }
++#ifdef HAVE_POPEN
++ else
++ {
++ if (-1 == (ret = pclose (fp)))
++ _SLerrno_errno = errno;
++ }
++#endif
++ }
++
++ if (t-&gt;file != NULL) SLang_free_slstring (t-&gt;file);
++ memset ((char *) t, 0, sizeof (SL_File_Table_Type));
++ return ret;
++}
++
++static int stdio_fclose (SL_File_Table_Type *t)
++{
++ int ret;
++
++ if (NULL == check_fp (t, 0xFFFF))
++ return -1;
++
++ ret = close_file_type (t);
++
++ t-&gt;flags = SL_INUSE;
++ return ret;
++}
++
++static int read_one_line (FILE *fp, char **strp, unsigned int *lenp)
++{
++ char buf[512];
++ char *str;
++ unsigned int len;
++
++ *strp = NULL;
++ len = 0;
++ str = NULL;
++
++ while (NULL != fgets (buf, sizeof (buf), fp))
++ {
++ unsigned int dlen;
++ char *new_str;
++ int done_flag;
++
++ dlen = strlen (buf);
++ /* Note: If the file contains embedded \0 characters, then this
++ * fails to work properly since dlen will not be correct.
++ */
++ done_flag = ((dlen + 1 &lt; sizeof (buf))
++ || (buf[dlen - 1] == '\n'));
++
++ if (done_flag &amp;&amp; (str == NULL))
++ {
++ /* Avoid the malloc */
++ str = buf;
++ len = dlen;
++ break;
++ }
++
++ if (NULL == (new_str = SLrealloc (str, len + dlen + 1)))
++ {
++ SLfree (str);
++ return -1;
++ }
++
++ str = new_str;
++ strcpy (str + len, buf);
++ len += dlen;
++
++ if (done_flag) break;
++ }
++
++ if (str == NULL)
++ return 0;
++
++ *strp = SLang_create_nslstring (str, len);
++ if (str != buf) SLfree (str);
++
++ if (*strp == NULL) return -1;
++
++ *lenp = len;
++ return 1;
++}
++
++/* returns number of characters read and pushes the string to the stack.
++ If it fails, it returns -1 */
++static int stdio_fgets (SLang_Ref_Type *ref, SL_File_Table_Type *t)
++{
++ char *s;
++ unsigned int len;
++ FILE *fp;
++ int status;
++
++ if (NULL == (fp = check_fp (t, SL_READ)))
++ return -1;
++
++ status = read_one_line (fp, &amp;s, &amp;len);
++ if (status &lt;= 0)
++ return -1;
++
++ status = SLang_assign_to_ref (ref, SLANG_STRING_TYPE, (VOID_STAR)&amp;s);
++ SLang_free_slstring (s);
++
++ if (status == -1)
++ return -1;
++
++ return (int) len;
++}
++
++static void stdio_fgetslines_internal (FILE *fp, unsigned int n)
++{
++ unsigned int num_lines, max_num_lines;
++ char **list;
++ SLang_Array_Type *at;
++ int inum_lines;
++
++ if (n &gt; 1024)
++ max_num_lines = 1024;
++ else
++ {
++ max_num_lines = n;
++ if (max_num_lines == 0)
++ max_num_lines++;
++ }
++
++ list = (char **) SLmalloc (sizeof (char *) * max_num_lines);
++ if (list == NULL)
++ return;
++
++ num_lines = 0;
++ while (num_lines &lt; n)
++ {
++ int status;
++ char *line;
++ unsigned int len;
++
++ status = read_one_line (fp, &amp;line, &amp;len);
++ if (status == -1)
++ goto return_error;
++
++ if (status == 0)
++ break;
++
++ if (max_num_lines == num_lines)
++ {
++ char **new_list;
++
++ if (max_num_lines + 4096 &gt; n)
++ max_num_lines = n;
++ else
++ max_num_lines += 4096;
++
++ new_list = (char **) SLrealloc ((char *)list, sizeof (char *) * max_num_lines);
++ if (new_list == NULL)
++ {
++ SLang_free_slstring (line);
++ goto return_error;
++ }
++ list = new_list;
++ }
++
++ list[num_lines] = line;
++ num_lines++;
++ }
++
++ if (num_lines != max_num_lines)
++ {
++ char **new_list;
++
++ new_list = (char **)SLrealloc ((char *)list, sizeof (char *) * (num_lines + 1));
++ if (new_list == NULL)
++ goto return_error;
++
++ list = new_list;
++ }
++
++ inum_lines = (int) num_lines;
++ if (NULL == (at = SLang_create_array (SLANG_STRING_TYPE, 0, (VOID_STAR) list, &amp;inum_lines, 1)))
++ goto return_error;
++
++ if (-1 == SLang_push_array (at, 1))
++ SLang_push_null ();
++ return;
++
++ return_error:
++ while (num_lines &gt; 0)
++ {
++ num_lines--;
++ SLfree (list[num_lines]);
++ }
++ SLfree ((char *)list);
++ SLang_push_null ();
++}
++
++static void stdio_fgetslines (void)
++{
++ unsigned int n;
++ FILE *fp;
++ SLang_MMT_Type *mmt;
++
++ n = (unsigned int)-1;
++
++ if (SLang_Num_Function_Args == 2)
++ {
++ if (-1 == SLang_pop_uinteger (&amp;n))
++ return;
++ }
++
++ if (NULL == (mmt = pop_fp (SL_READ, &amp;fp)))
++ {
++ SLang_push_null ();
++ return;
++ }
++
++ stdio_fgetslines_internal (fp, n);
++ SLang_free_mmt (mmt);
++}
++
++
++static int stdio_fputs (char *s, SL_File_Table_Type *t)
++{
++ FILE *fp;
++
++ if (NULL == (fp = check_fp (t, SL_WRITE)))
++ return -1;
++
++ if (EOF == fputs(s, fp)) return -1;
++ return (int) strlen (s);
++}
++
++static int stdio_fflush (SL_File_Table_Type *t)
++{
++ FILE *fp;
++
++ if (NULL == (fp = check_fp (t, SL_WRITE)))
++ return -1;
++
++ if (EOF == fflush (fp))
++ {
++ _SLerrno_errno = errno;
++ return -1;
++ }
++
++ return 0;
++}
++
++/* Usage: n = fread (&amp;str, data-type, nelems, fp); */
++static void stdio_fread (SLang_Ref_Type *ref, int *data_typep, unsigned int *num_elemns, SL_File_Table_Type *t)
++{
++ char *s;
++ FILE *fp;
++ int ret;
++ unsigned int num_read, num_to_read;
++ unsigned int nbytes;
++ SLang_Class_Type *cl;
++ unsigned int sizeof_type;
++ int data_type;
++
++ ret = -1;
++ s = NULL;
++ cl = NULL;
++
++ if (NULL == (fp = check_fp (t, SL_READ)))
++ goto the_return;
++
++ /* FIXME: priority = low : I should add some mechanism to support
++ * other types.
++ */
++ data_type = *data_typep;
++
++ cl = _SLclass_get_class ((unsigned char) data_type);
++
++ if (cl-&gt;cl_fread == NULL)
++ {
++ SLang_verror (SL_NOT_IMPLEMENTED,
++ &quot;fread does not support %s objects&quot;,
++ cl-&gt;cl_name);
++ goto the_return;
++ }
++
++ sizeof_type = cl-&gt;cl_sizeof_type;
++
++ num_to_read = *num_elemns;
++ nbytes = (unsigned int) num_to_read * sizeof_type;
++
++ s = SLmalloc (nbytes + 1);
++ if (s == NULL)
++ goto the_return;
++
++ ret = cl-&gt;cl_fread (data_type, fp, (VOID_STAR)s, num_to_read, &amp;num_read);
++
++ if ((num_read == 0)
++ &amp;&amp; (num_read != num_to_read))
++ ret = -1;
++
++ if ((ret == -1) &amp;&amp; ferror (fp))
++ _SLerrno_errno = errno;
++
++ if ((ret == 0)
++ &amp;&amp; (num_read != num_to_read))
++ {
++ char *new_s;
++
++ nbytes = num_read * sizeof_type;
++ new_s = SLrealloc (s, nbytes + 1);
++ if (new_s == NULL)
++ ret = -1;
++ else
++ s = new_s;
++ }
++
++ if (ret == 0)
++ {
++ if (num_read == 1)
++ {
++ ret = SLang_assign_to_ref (ref, data_type, (VOID_STAR)s);
++ SLfree (s);
++ }
++ else if ((data_type == SLANG_CHAR_TYPE)
++ || (data_type == SLANG_UCHAR_TYPE))
++ {
++ SLang_BString_Type *bs;
++
++ bs = SLbstring_create_malloced ((unsigned char *)s, num_read, 1);
++ ret = SLang_assign_to_ref (ref, SLANG_BSTRING_TYPE, (VOID_STAR)&amp;bs);
++ SLbstring_free (bs);
++ }
++ else
++ {
++ SLang_Array_Type *at;
++ int inum_read = (int) num_read;
++ at = SLang_create_array (data_type, 0, (VOID_STAR)s, &amp;inum_read, 1);
++ ret = SLang_assign_to_ref (ref, SLANG_ARRAY_TYPE, (VOID_STAR)&amp;at);
++ SLang_free_array (at);
++ }
++ s = NULL;
++ }
++
++ the_return:
++
++ if (s != NULL)
++ SLfree (s);
++
++ if (ret == -1)
++ SLang_push_integer (ret);
++ else
++ SLang_push_uinteger (num_read);
++}
++
++/* Usage: n = fwrite (str, fp); */
++static void stdio_fwrite (SL_File_Table_Type *t)
++{
++ FILE *fp;
++ unsigned char *s;
++ unsigned int num_to_write, num_write;
++ int ret;
++ SLang_BString_Type *b;
++ SLang_Array_Type *at;
++ SLang_Class_Type *cl;
++
++ ret = -1;
++ b = NULL;
++ at = NULL;
++
++ switch (SLang_peek_at_stack ())
++ {
++ case SLANG_BSTRING_TYPE:
++ case SLANG_STRING_TYPE:
++ if (-1 == SLang_pop_bstring (&amp;b))
++ goto the_return;
++
++ if (NULL == (s = SLbstring_get_pointer (b, &amp;num_to_write)))
++ goto the_return;
++
++ cl = _SLclass_get_class (SLANG_UCHAR_TYPE);
++ break;
++
++ default:
++ if (-1 == SLang_pop_array (&amp;at, 1))
++ goto the_return;
++
++ cl = at-&gt;cl;
++ num_to_write = at-&gt;num_elements;
++ s = (unsigned char *) at-&gt;data;
++ }
++
++ if (NULL == (fp = check_fp (t, SL_WRITE)))
++ goto the_return;
++
++ if (cl-&gt;cl_fwrite == NULL)
++ {
++ SLang_verror (SL_NOT_IMPLEMENTED,
++ &quot;fwrite does not support %s objects&quot;, cl-&gt;cl_name);
++ goto the_return;
++ }
++
++ ret = cl-&gt;cl_fwrite (cl-&gt;cl_data_type, fp, s, num_to_write, &amp;num_write);
++
++ if ((ret == -1) &amp;&amp; ferror (fp))
++ _SLerrno_errno = errno;
++
++ /* drop */
++ the_return:
++ if (b != NULL)
++ SLbstring_free (b);
++ if (at != NULL)
++ SLang_free_array (at);
++
++ if (ret == -1)
++ SLang_push_integer (ret);
++ else
++ SLang_push_uinteger (num_write);
++}
++
++static int stdio_fseek (SL_File_Table_Type *t, int *ofs, int *whence)
++{
++ FILE *fp;
++
++ if (NULL == (fp = check_fp (t, 0xFFFF)))
++ return -1;
++
++ if (-1 == fseek (fp, (long) *ofs, *whence))
++ {
++ _SLerrno_errno = errno;
++ return -1;
++ }
++
++ return 0;
++}
++
++static int stdio_ftell (SL_File_Table_Type *t)
++{
++ FILE *fp;
++ long ofs;
++
++ if (NULL == (fp = check_fp (t, 0xFFFF)))
++ return -1;
++
++ if (-1L == (ofs = ftell (fp)))
++ {
++ _SLerrno_errno = errno;
++ return -1;
++ }
++
++ return (int) ofs;
++}
++
++static int stdio_feof (SL_File_Table_Type *t)
++{
++ FILE *fp;
++
++ if (NULL == (fp = check_fp (t, 0xFFFF)))
++ return -1;
++
++ return feof (fp);
++}
++
++static int stdio_ferror (SL_File_Table_Type *t)
++{
++ FILE *fp;
++
++ if (NULL == (fp = check_fp (t, 0xFFFF)))
++ return -1;
++
++ return ferror (fp);
++}
++
++static void stdio_clearerr (SL_File_Table_Type *t)
++{
++ FILE *fp;
++
++ if (NULL != (fp = check_fp (t, 0xFFFF)))
++ clearerr (fp);
++}
++
++/* () = fprintf (fp, &quot;FORMAT&quot;, arg...); */
++static int stdio_fprintf (void)
++{
++ char *s;
++ FILE *fp;
++ SLang_MMT_Type *mmt;
++ int status;
++
++ if (-1 == _SLstrops_do_sprintf_n (SLang_Num_Function_Args - 2))
++ return -1;
++
++ if (-1 == SLang_pop_slstring (&amp;s))
++ return -1;
++
++ if (NULL == (mmt = pop_fp (SL_WRITE, &amp;fp)))
++ {
++ SLang_free_slstring (s);
++ return -1;
++ }
++
++ if (EOF == fputs(s, fp))
++ status = -1;
++ else
++ status = (int) strlen (s);
++
++ SLang_free_mmt (mmt);
++ SLang_free_slstring (s);
++ return status;
++}
++
++static int stdio_printf (void)
++{
++ char *s;
++ int status;
++
++ if (-1 == _SLstrops_do_sprintf_n (SLang_Num_Function_Args - 1))
++ return -1;
++
++ if (-1 == SLang_pop_slstring (&amp;s))
++ return -1;
++
++ if (EOF == fputs(s, stdout))
++ status = -1;
++ else
++ status = (int) strlen (s);
++
++ SLang_free_slstring (s);
++ return status;
++}
++
++
++#define F SLANG_FILE_PTR_TYPE
++#define R SLANG_REF_TYPE
++#define I SLANG_INT_TYPE
++#define V SLANG_VOID_TYPE
++#define S SLANG_STRING_TYPE
++#define B SLANG_BSTRING_TYPE
++#define U SLANG_UINT_TYPE
++#define D SLANG_DATATYPE_TYPE
++static SLang_Intrin_Fun_Type Stdio_Name_Table[] =
++{
++ MAKE_INTRINSIC_0(&quot;fgetslines&quot;, stdio_fgetslines, V),
++ MAKE_INTRINSIC_SS(&quot;fopen&quot;, stdio_fopen, V),
++ MAKE_INTRINSIC_1(&quot;feof&quot;, stdio_feof, I, F),
++ MAKE_INTRINSIC_1(&quot;ferror&quot;, stdio_ferror, I, F),
++ MAKE_INTRINSIC_1(&quot;fclose&quot;, stdio_fclose, I, F),
++ MAKE_INTRINSIC_2(&quot;fgets&quot;, stdio_fgets, I, R, F),
++ MAKE_INTRINSIC_1(&quot;fflush&quot;, stdio_fflush, I, F),
++ MAKE_INTRINSIC_2(&quot;fputs&quot;, stdio_fputs, I, S, F),
++ MAKE_INTRINSIC_0(&quot;fprintf&quot;, stdio_fprintf, I),
++ MAKE_INTRINSIC_0(&quot;printf&quot;, stdio_printf, I),
++ MAKE_INTRINSIC_3(&quot;fseek&quot;, stdio_fseek, I, F, I, I),
++ MAKE_INTRINSIC_1(&quot;ftell&quot;, stdio_ftell, I, F),
++ MAKE_INTRINSIC_1(&quot;clearerr&quot;, stdio_clearerr, V, F),
++ MAKE_INTRINSIC_4(&quot;fread&quot;, stdio_fread, V, R, D, U, F),
++ MAKE_INTRINSIC_1(&quot;fwrite&quot;, stdio_fwrite, V, F),
++#ifdef HAVE_POPEN
++ MAKE_INTRINSIC_SS(&quot;popen&quot;, stdio_popen, V),
++ MAKE_INTRINSIC_1(&quot;pclose&quot;, stdio_fclose, I, F),
++#endif
++ SLANG_END_INTRIN_FUN_TABLE
++};
++#undef F
++#undef I
++#undef R
++#undef V
++#undef S
++#undef B
++#undef U
++#undef D
++
++#ifndef SEEK_SET
++# define SEEK_SET 0
++#endif
++#ifndef SEEK_CUR
++# define SEEK_CUR 1
++#endif
++#ifndef SEEK_END
++# define SEEK_END 2
++#endif
++
++static SLang_IConstant_Type Stdio_Consts [] =
++{
++ MAKE_ICONSTANT(&quot;SEEK_SET&quot;, SEEK_SET),
++ MAKE_ICONSTANT(&quot;SEEK_END&quot;, SEEK_END),
++ MAKE_ICONSTANT(&quot;SEEK_CUR&quot;, SEEK_CUR),
++ SLANG_END_ICONST_TABLE
++};
++
++static void destroy_file_type (unsigned char type, VOID_STAR ptr)
++{
++ (void) type;
++ (void) close_file_type ((SL_File_Table_Type *) ptr);
++}
++
++
++struct _SLang_Foreach_Context_Type
++{
++ SLang_MMT_Type *mmt;
++ FILE *fp;
++#define CTX_USE_LINE 1
++#define CTX_USE_CHAR 2
++ unsigned char type;
++};
++
++
++static SLang_Foreach_Context_Type *
++cl_foreach_open (unsigned char type, unsigned int num)
++{
++ SLang_Foreach_Context_Type *c;
++ SLang_MMT_Type *mmt;
++ FILE *fp;
++
++ if (NULL == (mmt = pop_fp (SL_READ, &amp;fp)))
++ return NULL;
++
++ type = CTX_USE_LINE;
++
++ switch (num)
++ {
++ char *s;
++
++ case 0:
++ type = CTX_USE_LINE;
++ break;
++
++ case 1:
++ if (-1 == SLang_pop_slstring (&amp;s))
++ {
++ SLang_free_mmt (mmt);
++ return NULL;
++ }
++ if (0 == strcmp (s, &quot;char&quot;))
++ type = CTX_USE_CHAR;
++ else if (0 == strcmp (s, &quot;line&quot;))
++ type = CTX_USE_LINE;
++ else
++ {
++ SLang_verror (SL_NOT_IMPLEMENTED,
++ &quot;using '%s' not supported by File_Type&quot;,
++ s);
++ SLang_free_slstring (s);
++ SLang_free_mmt (mmt);
++ return NULL;
++ }
++ SLang_free_slstring (s);
++ break;
++
++ default:
++ SLdo_pop_n (num);
++ SLang_verror (SL_NOT_IMPLEMENTED,
++ &quot;Usage: foreach (File_Type) using ([line|char])&quot;);
++ SLang_free_mmt (mmt);
++ return NULL;
++ }
++
++ if (NULL == (c = (SLang_Foreach_Context_Type *) SLmalloc (sizeof (SLang_Foreach_Context_Type))))
++ {
++ SLang_free_mmt (mmt);
++ return NULL;
++ }
++ memset ((char *) c, 0, sizeof (SLang_Foreach_Context_Type));
++
++ c-&gt;type = type;
++ c-&gt;mmt = mmt;
++ c-&gt;fp = fp;
++
++ return c;
++}
++
++static void cl_foreach_close (unsigned char type, SLang_Foreach_Context_Type *c)
++{
++ (void) type;
++ if (c == NULL) return;
++ SLang_free_mmt (c-&gt;mmt);
++ SLfree ((char *) c);
++}
++
++static int cl_foreach (unsigned char type, SLang_Foreach_Context_Type *c)
++{
++ int status;
++ int ch;
++ unsigned int len;
++ char *s;
++
++ (void) type;
++
++ if (c == NULL)
++ return -1;
++
++ switch (c-&gt;type)
++ {
++ case CTX_USE_CHAR:
++ if (EOF == (ch = getc (c-&gt;fp)))
++ return 0;
++ if (-1 == SLang_push_uchar ((unsigned char) ch))
++ return -1;
++ return 1;
++
++ case CTX_USE_LINE:
++ status = read_one_line (c-&gt;fp, &amp;s, &amp;len);
++ if (status &lt;= 0)
++ return status;
++ if (0 == _SLang_push_slstring (s))
++ return 1;
++ return -1;
++ }
++
++ return -1;
++}
++
++static int Stdio_Initialized;
++static SLang_MMT_Type *Stdio_Mmts[3];
++
++int SLang_init_stdio (void)
++{
++ unsigned int i;
++ SL_File_Table_Type *s;
++ SLang_Class_Type *cl;
++ char *names[3];
++
++ if (Stdio_Initialized)
++ return 0;
++
++ SL_File_Table = (SL_File_Table_Type *)SLcalloc(sizeof (SL_File_Table_Type), SL_MAX_FILES);
++ if (SL_File_Table == NULL)
++ return -1;
++
++ if (NULL == (cl = SLclass_allocate_class (&quot;File_Type&quot;)))
++ return -1;
++ cl-&gt;cl_destroy = destroy_file_type;
++ cl-&gt;cl_foreach_open = cl_foreach_open;
++ cl-&gt;cl_foreach_close = cl_foreach_close;
++ cl-&gt;cl_foreach = cl_foreach;
++
++
++ if (-1 == SLclass_register_class (cl, SLANG_FILE_PTR_TYPE, sizeof (SL_File_Table_Type), SLANG_CLASS_TYPE_MMT))
++ return -1;
++
++ if ((-1 == SLadd_intrin_fun_table(Stdio_Name_Table, &quot;__STDIO__&quot;))
++ || (-1 == SLadd_iconstant_table (Stdio_Consts, NULL))
++ || (-1 == _SLerrno_init ()))
++ return -1;
++
++ names[0] = &quot;stdin&quot;;
++ names[1] = &quot;stdout&quot;;
++ names[2] = &quot;stderr&quot;;
++
++ s = SL_File_Table;
++ s-&gt;fp = stdin; s-&gt;flags = SL_READ;
++
++ s++;
++ s-&gt;fp = stdout; s-&gt;flags = SL_WRITE;
++
++ s++;
++ s-&gt;fp = stderr; s-&gt;flags = SL_WRITE|SL_READ;
++
++ s = SL_File_Table;
++ for (i = 0; i &lt; 3; i++)
++ {
++ if (NULL == (s-&gt;file = SLang_create_slstring (names[i])))
++ return -1;
++
++ if (NULL == (Stdio_Mmts[i] = SLang_create_mmt (SLANG_FILE_PTR_TYPE, (VOID_STAR) s)))
++ return -1;
++ SLang_inc_mmt (Stdio_Mmts[i]);
++
++ if (-1 == SLadd_intrinsic_variable (s-&gt;file, (VOID_STAR)&amp;Stdio_Mmts[i], SLANG_FILE_PTR_TYPE, 1))
++ return -1;
++ s++;
++ }
++
++ Stdio_Initialized = 1;
++ return 0;
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slstdio.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slstring.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slstring.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slstring.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,546 @@
++/* Copyright (c) 1998, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++typedef struct _SLstring_Type
++{
++ struct _SLstring_Type *next;
++ unsigned int ref_count;
++ char bytes [1];
++}
++SLstring_Type;
++
++static SLstring_Type *String_Hash_Table [SLSTRING_HASH_TABLE_SIZE];
++static char Single_Char_Strings [256 * 2];
++
++#if _SLANG_OPTIMIZE_FOR_SPEED
++#define MAX_FREE_STORE_LEN 32
++static SLstring_Type *SLS_Free_Store [MAX_FREE_STORE_LEN];
++
++# define NUM_CACHED_STRINGS 601
++typedef struct
++{
++ unsigned long hash;
++ SLstring_Type *sls;
++ unsigned int len;
++}
++Cached_String_Type;
++static Cached_String_Type Cached_Strings [NUM_CACHED_STRINGS];
++
++#define GET_CACHED_STRING(s) \
++ (Cached_Strings + (unsigned int)(((unsigned long) (s)) % NUM_CACHED_STRINGS))
++
++_INLINE_
++static void cache_string (SLstring_Type *sls, unsigned int len, unsigned long hash)
++{
++ Cached_String_Type *cs;
++
++ cs = GET_CACHED_STRING(sls-&gt;bytes);
++ cs-&gt;sls = sls;
++ cs-&gt;hash = hash;
++ cs-&gt;len = len;
++}
++
++_INLINE_
++static void uncache_string (char *s)
++{
++ Cached_String_Type *cs;
++
++ cs = GET_CACHED_STRING(s);
++ if ((cs-&gt;sls != NULL)
++ &amp;&amp; (cs-&gt;sls-&gt;bytes == s))
++ cs-&gt;sls = NULL;
++}
++#endif
++
++
++
++_INLINE_
++unsigned long _SLstring_hash (unsigned char *s, unsigned char *smax)
++{
++ register unsigned long h = 0;
++ register unsigned long sum = 0;
++ unsigned char *smax4;
++
++ smax4 = smax - 4;
++
++ while (s &lt; smax4)
++ {
++ sum += s[0];
++ h = sum + (h &lt;&lt; 1);
++ sum += s[1];
++ h = sum + (h &lt;&lt; 1);
++ sum += s[2];
++ h = sum + (h &lt;&lt; 1);
++ sum += s[3];
++ h = sum + (h &lt;&lt; 1);
++
++ s += 4;
++ }
++
++ while (s &lt; smax)
++ {
++ sum += *s++;
++ h ^= sum + (h &lt;&lt; 3); /* slightly different */
++ }
++
++ return h;
++}
++
++unsigned long _SLcompute_string_hash (char *s)
++{
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ Cached_String_Type *cs;
++ SLstring_Type *sls;
++
++ cs = GET_CACHED_STRING(s);
++ if (((sls = cs-&gt;sls) != NULL)
++ &amp;&amp; (sls-&gt;bytes == s))
++ return cs-&gt;hash;
++#endif
++ return _SLstring_hash ((unsigned char *) s, (unsigned char *) s + strlen (s));
++}
++
++_INLINE_
++/* This routine works with any (long) string */
++static SLstring_Type *find_string (char *s, unsigned int len, unsigned long hash)
++{
++ SLstring_Type *sls;
++ char ch;
++
++ sls = String_Hash_Table [(unsigned int)(hash % SLSTRING_HASH_TABLE_SIZE)];
++
++ if (sls == NULL)
++ return NULL;
++
++ ch = s[0];
++ do
++ {
++ char *bytes = sls-&gt;bytes;
++
++ /* Note that we need to actually make sure that bytes[len] == 0.
++ * In this case, it is not enough to just compare pointers. In fact,
++ * this is called from create_nstring, etc... It is unlikely that the
++ * pointer is a slstring
++ */
++ if ((/* (s == bytes) || */ ((ch == bytes[0])
++ &amp;&amp; (0 == strncmp (s, bytes, len))))
++ &amp;&amp; (bytes [len] == 0))
++ break;
++
++ sls = sls-&gt;next;
++ }
++ while (sls != NULL);
++
++ return sls;
++}
++
++_INLINE_
++static SLstring_Type *find_slstring (char *s, unsigned long hash)
++{
++ SLstring_Type *sls;
++
++ sls = String_Hash_Table [(unsigned int)(hash % SLSTRING_HASH_TABLE_SIZE)];
++ while (sls != NULL)
++ {
++ if (s == sls-&gt;bytes)
++ return sls;
++
++ sls = sls-&gt;next;
++ }
++ return sls;
++}
++
++_INLINE_
++static SLstring_Type *allocate_sls (unsigned int len)
++{
++ SLstring_Type *sls;
++
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ if ((len &lt; MAX_FREE_STORE_LEN)
++ &amp;&amp; (NULL != (sls = SLS_Free_Store [len])))
++ {
++ SLS_Free_Store[len] = NULL;
++ return sls;
++ }
++#endif
++ /* FIXME: use structure padding */
++ return (SLstring_Type *) SLmalloc (len + sizeof (SLstring_Type));
++}
++
++_INLINE_
++static void free_sls (SLstring_Type *sls, unsigned int len)
++{
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ if ((len &lt; MAX_FREE_STORE_LEN)
++ &amp;&amp; (SLS_Free_Store[len] == NULL))
++ {
++ SLS_Free_Store [len] = sls;
++ return;
++ }
++#else
++ (void) len;
++#endif
++ SLfree ((char *)sls);
++}
++
++_INLINE_
++static char *create_long_string (char *s, unsigned int len, unsigned long hash)
++{
++ SLstring_Type *sls;
++
++ sls = find_string (s, len, hash);
++
++ if (sls != NULL)
++ {
++ sls-&gt;ref_count++;
++ s = sls-&gt;bytes;
++
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ cache_string (sls, len, hash);
++#endif
++ return s;
++ }
++
++ sls = allocate_sls (len);
++ if (sls == NULL)
++ return NULL;
++
++ strncpy (sls-&gt;bytes, s, len);
++ sls-&gt;bytes[len] = 0;
++ sls-&gt;ref_count = 1;
++
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ cache_string (sls, len, hash);
++#endif
++
++ hash = hash % SLSTRING_HASH_TABLE_SIZE;
++ sls-&gt;next = String_Hash_Table [(unsigned int)hash];
++ String_Hash_Table [(unsigned int)hash] = sls;
++
++ return sls-&gt;bytes;
++}
++
++_INLINE_
++static char *create_short_string (char *s, unsigned int len)
++{
++ char ch;
++
++ /* Note: if len is 0, then it does not matter what *s is. This is
++ * important for SLang_create_nslstring.
++ */
++ if (len) ch = *s; else ch = 0;
++
++ len = 2 * (unsigned int) ((unsigned char) ch);
++ Single_Char_Strings [len] = ch;
++ Single_Char_Strings [len + 1] = 0;
++ return Single_Char_Strings + len;
++}
++
++/* s cannot be NULL */
++_INLINE_
++static char *create_nstring (char *s, unsigned int len, unsigned long *hash_ptr)
++{
++ unsigned long hash;
++
++ if (len &lt; 2)
++ return create_short_string (s, len);
++
++ hash = _SLstring_hash ((unsigned char *) s, (unsigned char *) (s + len));
++ *hash_ptr = hash;
++
++ return create_long_string (s, len, hash);
++}
++
++char *SLang_create_nslstring (char *s, unsigned int len)
++{
++ unsigned long hash;
++ return create_nstring (s, len, &amp;hash);
++}
++
++char *_SLstring_make_hashed_string (char *s, unsigned int len, unsigned long *hashptr)
++{
++ unsigned long hash;
++
++ if (s == NULL) return NULL;
++
++ hash = _SLstring_hash ((unsigned char *) s, (unsigned char *) s + len);
++ *hashptr = hash;
++
++ if (len &lt; 2)
++ return create_short_string (s, len);
++
++ return create_long_string (s, len, hash);
++}
++
++char *_SLstring_dup_hashed_string (char *s, unsigned long hash)
++{
++ unsigned int len;
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ Cached_String_Type *cs;
++ SLstring_Type *sls;
++
++ if (s == NULL) return NULL;
++ if (s[0] == 0)
++ return create_short_string (s, 0);
++ if (s[1] == 0)
++ return create_short_string (s, 1);
++
++ cs = GET_CACHED_STRING(s);
++ if (((sls = cs-&gt;sls) != NULL)
++ &amp;&amp; (sls-&gt;bytes == s))
++ {
++ sls-&gt;ref_count += 1;
++ return s;
++ }
++#else
++ if (s == NULL) return NULL;
++#endif
++
++ len = strlen (s);
++#if !_SLANG_OPTIMIZE_FOR_SPEED
++ if (len &lt; 2) return create_short_string (s, len);
++#endif
++
++ return create_long_string (s, len, hash);
++}
++
++char *_SLstring_dup_slstring (char *s)
++{
++ SLstring_Type *sls;
++ unsigned int len;
++ unsigned long hash;
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ Cached_String_Type *cs;
++
++ cs = GET_CACHED_STRING(s);
++ if (((sls = cs-&gt;sls) != NULL)
++ &amp;&amp; (sls-&gt;bytes == s))
++ {
++ sls-&gt;ref_count += 1;
++ return s;
++ }
++#endif
++
++ if ((s == NULL) || ((len = strlen (s)) &lt; 2))
++ return s;
++
++ hash = _SLstring_hash ((unsigned char *)s, (unsigned char *)(s + len));
++
++ sls = find_slstring (s, hash);
++ if (sls == NULL)
++ {
++ SLang_Error = SL_INTERNAL_ERROR;
++ return NULL;
++ }
++
++ sls-&gt;ref_count++;
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ cache_string (sls, len, hash);
++#endif
++ return s;
++}
++
++static void free_sls_string (SLstring_Type *sls, char *s, unsigned int len,
++ unsigned long hash)
++{
++ SLstring_Type *sls1, *prev;
++
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ uncache_string (s);
++#endif
++
++ hash = hash % SLSTRING_HASH_TABLE_SIZE;
++
++ sls1 = String_Hash_Table [(unsigned int) hash];
++
++ prev = NULL;
++
++ /* This should not fail. */
++ while (sls1 != sls)
++ {
++ prev = sls1;
++ sls1 = sls1-&gt;next;
++ }
++
++ if (prev != NULL)
++ prev-&gt;next = sls-&gt;next;
++ else
++ String_Hash_Table [(unsigned int) hash] = sls-&gt;next;
++
++ free_sls (sls, len);
++}
++
++_INLINE_
++static void free_long_string (char *s, unsigned int len, unsigned long hash)
++{
++ SLstring_Type *sls;
++
++ if (NULL == (sls = find_slstring (s, hash)))
++ {
++ SLang_doerror (&quot;Application internal error: invalid attempt to free string&quot;);
++ return;
++ }
++
++ sls-&gt;ref_count--;
++ if (sls-&gt;ref_count != 0)
++ {
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ /* cache_string (sls, len, hash); */
++#endif
++ return;
++ }
++
++
++ free_sls_string (sls, s, len, hash);
++}
++
++/* This routine may be passed NULL-- it is not an error. */
++void SLang_free_slstring (char *s)
++{
++ unsigned long hash;
++ unsigned int len;
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ Cached_String_Type *cs;
++ SLstring_Type *sls;
++
++ cs = GET_CACHED_STRING(s);
++ if (((sls = cs-&gt;sls) != NULL)
++ &amp;&amp; (sls-&gt;bytes == s))
++ {
++ if (sls-&gt;ref_count &lt;= 1)
++ free_sls_string (sls, s, cs-&gt;len, cs-&gt;hash);
++ else
++ sls-&gt;ref_count -= 1;
++ return;
++ }
++#endif
++
++ if (s == NULL) return;
++
++ if ((len = strlen (s)) &lt; 2)
++ return;
++
++ hash = _SLstring_hash ((unsigned char *)s, (unsigned char *) s + len);
++ free_long_string (s, len, hash);
++}
++
++char *SLang_create_slstring (char *s)
++{
++ unsigned long hash;
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ Cached_String_Type *cs;
++ SLstring_Type *sls;
++
++ cs = GET_CACHED_STRING(s);
++ if (((sls = cs-&gt;sls) != NULL)
++ &amp;&amp; (sls-&gt;bytes == s))
++ {
++ sls-&gt;ref_count += 1;
++ return s;
++ }
++#endif
++
++ if (s == NULL) return NULL;
++ return create_nstring (s, strlen (s), &amp;hash);
++}
++
++void _SLfree_hashed_string (char *s, unsigned int len, unsigned long hash)
++{
++ if ((s == NULL) || (len &lt; 2)) return;
++ free_long_string (s, len, hash);
++}
++
++
++char *_SLallocate_slstring (unsigned int len)
++{
++ SLstring_Type *sls = allocate_sls (len);
++ if (sls == NULL)
++ return NULL;
++
++ return sls-&gt;bytes;
++}
++
++void _SLunallocate_slstring (char *s, unsigned int len)
++{
++ SLstring_Type *sls;
++
++ if (s == NULL)
++ return;
++
++ sls = (SLstring_Type *) (s - offsetof(SLstring_Type,bytes[0]));
++ free_sls (sls, len);
++}
++
++char *_SLcreate_via_alloced_slstring (char *s, unsigned int len)
++{
++ unsigned long hash;
++ SLstring_Type *sls;
++
++ if (s == NULL)
++ return NULL;
++
++ if (len &lt; 2)
++ {
++ char *s1 = create_short_string (s, len);
++ _SLunallocate_slstring (s, len);
++ return s1;
++ }
++
++ /* s is not going to be in the cache because when it was malloced, its
++ * value was unknown. This simplifies the coding.
++ */
++ hash = _SLstring_hash ((unsigned char *)s, (unsigned char *)s + len);
++ sls = find_string (s, len, hash);
++ if (sls != NULL)
++ {
++ sls-&gt;ref_count++;
++ _SLunallocate_slstring (s, len);
++ s = sls-&gt;bytes;
++
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ cache_string (sls, len, hash);
++#endif
++ return s;
++ }
++
++ sls = (SLstring_Type *) (s - offsetof(SLstring_Type,bytes[0]));
++ sls-&gt;ref_count = 1;
++
++#if _SLANG_OPTIMIZE_FOR_SPEED
++ cache_string (sls, len, hash);
++#endif
++
++ hash = hash % SLSTRING_HASH_TABLE_SIZE;
++ sls-&gt;next = String_Hash_Table [(unsigned int)hash];
++ String_Hash_Table [(unsigned int)hash] = sls;
++
++ return s;
++}
++
++/* Note, a and b may be ordinary strings. The result is an slstring */
++char *SLang_concat_slstrings (char *a, char *b)
++{
++ unsigned int lena, len;
++ char *c;
++
++ lena = strlen (a);
++ len = lena + strlen (b);
++
++ c = _SLallocate_slstring (len);
++ if (c == NULL)
++ return NULL;
++
++ strcpy (c, a);
++ strcpy (c + lena, b);
++
++ return _SLcreate_via_alloced_slstring (c, len);
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slstring.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slstrops.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slstrops.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slstrops.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1686 @@
++/* -*- mode: C; mode: fold; -*- */
++/* string manipulation functions for S-Lang. */
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++/*{{{ Include Files */
++
++#include &lt;time.h&gt;
++
++#ifndef __QNX__
++# if defined(__GO32__) || defined(__WATCOMC__)
++# include &lt;dos.h&gt;
++# include &lt;bios.h&gt;
++# endif
++#endif
++
++#if SLANG_HAS_FLOAT
++#include &lt;math.h&gt;
++#endif
++
++#include &lt;string.h&gt;
++#include &lt;stdarg.h&gt;
++#include &lt;ctype.h&gt;
++
++#ifndef isdigit
++# define isdigit(x) (((x) &gt;= '0') &amp;&amp; ((x) &lt;= '9'))
++#endif
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++/*}}}*/
++
++#define USE_ALLOC_STSTRING 1
++
++/*{{{ Utility Functions */
++
++static char Utility_Char_Table [256];
++static unsigned char WhiteSpace_Lut[256];
++
++static void set_utility_char_table (char *pos) /*{{{*/
++{
++ register char *t = Utility_Char_Table, *tmax;
++ register unsigned char ch;
++
++ tmax = t + 256;
++ while (t &lt; tmax) *t++ = 0;
++
++ t = Utility_Char_Table;
++ while ((ch = (unsigned char) *pos++) != 0) t[ch] = 1;
++}
++
++/*}}}*/
++
++_INLINE_
++static unsigned char *make_whitespace_lut (void)
++{
++ if (WhiteSpace_Lut[' '] != 1)
++ {
++ WhiteSpace_Lut[' '] = WhiteSpace_Lut['\r']
++ = WhiteSpace_Lut ['\n'] = WhiteSpace_Lut['\t']
++ = WhiteSpace_Lut ['\f'] = 1;
++ }
++ return WhiteSpace_Lut;
++}
++
++static unsigned char *make_lut (unsigned char *s, unsigned char *lut)
++{
++ int reverse = 0;
++
++ if (*s == '^')
++ {
++ reverse = 1;
++ s++;
++ }
++ SLmake_lut (lut, s, reverse);
++ return lut;
++}
++
++static unsigned int do_trim (char **beg, int do_beg,
++ char **end, int do_end,
++ char *white) /*{{{*/
++{
++ unsigned int len;
++ char *a, *b;
++
++ set_utility_char_table (white);
++
++ a = *beg;
++ len = strlen (a);
++ b = a + len;
++
++ if (do_beg)
++ while (Utility_Char_Table[(unsigned char) *a]) a++;
++
++ if (do_end)
++ {
++ b--;
++ while ((b &gt;= a) &amp;&amp; (Utility_Char_Table[(unsigned char) *b])) b--;
++ b++;
++ }
++
++ len = (unsigned int) (b - a);
++ *beg = a;
++ *end = b;
++ return len;
++}
++
++/*}}}*/
++
++/*}}}*/
++
++static int pop_3_strings (char **a, char **b, char **c)
++{
++ *a = *b = *c = NULL;
++ if (-1 == SLpop_string (c))
++ return -1;
++
++ if (-1 == SLpop_string (b))
++ {
++ SLfree (*c);
++ *c = NULL;
++ return -1;
++ }
++
++ if (-1 == SLpop_string (a))
++ {
++ SLfree (*b);
++ SLfree (*c);
++ *b = *c = NULL;
++ return -1;
++ }
++
++ return 0;
++}
++
++static void free_3_strings (char *a, char *b, char *c)
++{
++ SLfree (a);
++ SLfree (b);
++ SLfree (c);
++}
++
++static void strcat_cmd (void) /*{{{*/
++{
++ char *c, *c1;
++ int nargs;
++ int i;
++ char **ptrs;
++ unsigned int len;
++#if !USE_ALLOC_STSTRING
++ char buf[256];
++#endif
++ nargs = SLang_Num_Function_Args;
++ if (nargs &lt;= 0) nargs = 2;
++
++ if (NULL == (ptrs = (char **)SLmalloc (nargs * sizeof (char *))))
++ return;
++
++ memset ((char *) ptrs, 0, sizeof (char *) * nargs);
++
++ c = NULL;
++ i = nargs;
++ len = 0;
++ while (i != 0)
++ {
++ char *s;
++
++ i--;
++ if (-1 == SLang_pop_slstring (&amp;s))
++ goto free_and_return;
++ ptrs[i] = s;
++ len += strlen (s);
++ }
++#if USE_ALLOC_STSTRING
++ if (NULL == (c = _SLallocate_slstring (len)))
++ goto free_and_return;
++#else
++ len++; /* \0 char */
++ if (len &lt;= sizeof (buf))
++ c = buf;
++ else if (NULL == (c = SLmalloc (len)))
++ goto free_and_return;
++#endif
++
++ c1 = c;
++ for (i = 0; i &lt; nargs; i++)
++ {
++ strcpy (c1, ptrs[i]);
++ c1 += strlen (c1);
++ }
++
++ free_and_return:
++ for (i = 0; i &lt; nargs; i++)
++ SLang_free_slstring (ptrs[i]);
++ SLfree ((char *) ptrs);
++
++#if USE_ALLOC_STSTRING
++ (void) _SLpush_alloced_slstring (c, len);
++#else
++ if (c != buf)
++ (void) SLang_push_malloced_string (c); /* NULL ok */
++ else
++ (void) SLang_push_string (c);
++#endif
++}
++
++/*}}}*/
++
++static int _SLang_push_nstring (char *a, unsigned int len)
++{
++ a = SLang_create_nslstring (a, len);
++ if (a == NULL)
++ return -1;
++
++ return _SLang_push_slstring (a);
++}
++
++
++static void strtrim_cmd_internal (char *str, int do_beg, int do_end)
++{
++ char *beg, *end, *white;
++ int free_str;
++ unsigned int len;
++
++ /* Go through SLpop_string to get a private copy since it will be
++ * modified.
++ */
++
++ free_str = 0;
++ if (SLang_Num_Function_Args == 2)
++ {
++ white = str;
++ if (-1 == SLang_pop_slstring (&amp;str))
++ return;
++ free_str = 1;
++ }
++ else white = &quot; \t\f\r\n&quot;;
++
++ beg = str;
++ len = do_trim (&amp;beg, do_beg, &amp;end, do_end, white);
++
++ (void) _SLang_push_nstring (beg, len);
++ if (free_str)
++ SLang_free_slstring (str);
++}
++
++
++static void strtrim_cmd (char *str)
++{
++ strtrim_cmd_internal (str, 1, 1);
++}
++
++static void strtrim_beg_cmd (char *str)
++{
++ strtrim_cmd_internal (str, 1, 0);
++}
++
++static void strtrim_end_cmd (char *str)
++{
++ strtrim_cmd_internal (str, 0, 1);
++}
++
++
++static void strcompress_cmd (void) /*{{{*/
++{
++ char *str, *white, *c;
++ unsigned char *s, *beg, *end;
++ unsigned int len;
++ char pref_char;
++
++ if (SLpop_string (&amp;white)) return;
++ if (SLpop_string (&amp;str))
++ {
++ SLfree (white);
++ return;
++ }
++
++ /* The first character of white is the preferred whitespace character */
++ pref_char = *white;
++
++ beg = (unsigned char *) str;
++ (void) do_trim ((char **) &amp;beg, 1, (char **) &amp;end, 1, white);
++ SLfree (white);
++
++ /* Determine the effective length */
++ len = 0;
++ s = (unsigned char *) beg;
++ while (s &lt; end)
++ {
++ len++;
++ if (Utility_Char_Table[*s++])
++ {
++ while ((s &lt; end) &amp;&amp; Utility_Char_Table[*s]) s++;
++ }
++ }
++
++#if USE_ALLOC_STSTRING
++ c = _SLallocate_slstring (len);
++#else
++ c = SLmalloc (len + 1);
++#endif
++ if (c == NULL)
++ {
++ SLfree (str);
++ return;
++ }
++
++ s = (unsigned char *) c;
++
++ while (beg &lt; end)
++ {
++ unsigned char ch = *beg++;
++
++ if (0 == Utility_Char_Table[ch])
++ {
++ *s++ = ch;
++ continue;
++ }
++
++ *s++ = (unsigned char) pref_char;
++
++ while ((beg &lt; end) &amp;&amp; Utility_Char_Table[*beg])
++ beg++;
++ }
++
++ *s = 0;
++
++#if USE_ALLOC_STSTRING
++ (void) _SLpush_alloced_slstring (c, len);
++#else
++ SLang_push_malloced_string(c);
++#endif
++
++ SLfree(str);
++}
++
++/*}}}*/
++
++static int str_replace_cmd_1 (char *orig, char *match, char *rep, unsigned int max_num_replaces,
++ char **new_strp) /*{{{*/
++{
++ char *s, *t, *new_str;
++ unsigned int rep_len, match_len, new_len;
++ unsigned int num_replaces;
++
++ *new_strp = NULL;
++
++ match_len = strlen (match);
++
++ if (match_len == 0)
++ return 0;
++
++ num_replaces = 0;
++ s = orig;
++ while (num_replaces &lt; max_num_replaces)
++ {
++ s = strstr (s, match);
++ if (s == NULL)
++ break;
++ s += match_len;
++ num_replaces++;
++ }
++
++ if (num_replaces == 0)
++ return 0;
++
++ max_num_replaces = num_replaces;
++
++ rep_len = strlen (rep);
++
++ new_len = (strlen (orig) - num_replaces * match_len) + num_replaces * rep_len;
++ new_str = SLmalloc (new_len + 1);
++ if (new_str == NULL)
++ return -1;
++
++ s = orig;
++ t = new_str;
++
++ for (num_replaces = 0; num_replaces &lt; max_num_replaces; num_replaces++)
++ {
++ char *next_s;
++ unsigned int len;
++
++ next_s = strstr (s, match); /* cannot be NULL */
++ len = (unsigned int) (next_s - s);
++ strncpy (t, s, len);
++ t += len;
++ strcpy (t, rep);
++ t += rep_len;
++
++ s = next_s + match_len;
++ }
++ strcpy (t, s);
++ *new_strp = new_str;
++
++ return (int) num_replaces;
++}
++
++/*}}}*/
++
++static void reverse_string (char *a)
++{
++ char *b;
++
++ b = a + strlen (a);
++ while (b &gt; a)
++ {
++ char ch;
++
++ b--;
++ ch = *a;
++ *a++ = *b;
++ *b = ch;
++ }
++}
++
++static int strreplace_cmd (int *np)
++{
++ char *orig, *match, *rep;
++ char *new_str;
++ int max_num_replaces;
++ int ret;
++
++ max_num_replaces = *np;
++
++ if (-1 == pop_3_strings (&amp;orig, &amp;match, &amp;rep))
++ return -1;
++
++ if (max_num_replaces &lt; 0)
++ {
++ reverse_string (orig);
++ reverse_string (match);
++ reverse_string (rep);
++ ret = str_replace_cmd_1 (orig, match, rep, -max_num_replaces, &amp;new_str);
++ if (ret &gt; 0) reverse_string (new_str);
++ else if (ret == 0)
++ reverse_string (orig);
++ }
++ else ret = str_replace_cmd_1 (orig, match, rep, max_num_replaces, &amp;new_str);
++
++ if (ret == 0)
++ {
++ if (-1 == SLang_push_malloced_string (orig))
++ ret = -1;
++ orig = NULL;
++ }
++ else if (ret &gt; 0)
++ {
++ if (-1 == SLang_push_malloced_string (new_str))
++ ret = -1;
++ }
++
++ free_3_strings (orig, match, rep);
++ return ret;
++}
++
++static int str_replace_cmd (char *orig, char *match, char *rep)
++{
++ char *s;
++ int ret;
++
++ ret = str_replace_cmd_1 (orig, match, rep, 1, &amp;s);
++ if (ret == 1)
++ (void) SLang_push_malloced_string (s);
++ return ret;
++}
++
++
++
++static void strtok_cmd (char *str)
++{
++ _SLString_List_Type sl;
++ unsigned char white_buf[256];
++ char *s;
++ unsigned char *white;
++
++ if (SLang_Num_Function_Args == 1)
++ white = make_whitespace_lut ();
++ else
++ {
++ white = white_buf;
++ make_lut ((unsigned char *)str, white);
++ if (-1 == SLang_pop_slstring (&amp;str))
++ return;
++ }
++
++ if (-1 == _SLstring_list_init (&amp;sl, 256, 1024))
++ goto the_return;
++
++ s = str;
++ while (*s != 0)
++ {
++ char *s0;
++
++ s0 = s;
++ /* Skip whitespace */
++ while ((*s0 != 0) &amp;&amp; (0 != white[(unsigned char)*s0]))
++ s0++;
++
++ if (*s0 == 0)
++ break;
++
++ s = s0;
++ while ((*s != 0) &amp;&amp; (0 == white[(unsigned char) *s]))
++ s++;
++
++ /* sl deleted upon failure */
++ if (-1 == _SLstring_list_append (&amp;sl, SLang_create_nslstring (s0, (unsigned int) (s - s0))))
++ goto the_return;
++ }
++
++ /* Deletes sl */
++ (void) _SLstring_list_push (&amp;sl);
++
++ the_return:
++ if (white == white_buf)
++ SLang_free_slstring (str);
++}
++
++/* This routine returns the string with text removed between single character
++ comment delimiters from the set b and e. */
++
++static void str_uncomment_string_cmd (char *str, char *b, char *e) /*{{{*/
++{
++ unsigned char chb, che;
++ unsigned char *s, *cbeg, *mark;
++
++ if (strlen(b) != strlen(e))
++ {
++ SLang_doerror (&quot;Comment delimiter length mismatch.&quot;);
++ return;
++ }
++
++ set_utility_char_table (b);
++
++ if (NULL == (str = (char *) SLmake_string(str))) return;
++
++ s = (unsigned char *) str;
++
++ while ((chb = *s++) != 0)
++ {
++ if (Utility_Char_Table [chb] == 0) continue;
++
++ mark = s - 1;
++
++ cbeg = (unsigned char *) b;
++ while (*cbeg != chb) cbeg++;
++
++ che = (unsigned char) *(e + (int) (cbeg - (unsigned char *) b));
++
++ while (((chb = *s++) != 0) &amp;&amp; (chb != che));
++
++ if (chb == 0)
++ {
++ /* end of string and end not found. Just truncate it a return; */
++ *mark = 0;
++ break;
++ }
++
++ strcpy ((char *) mark, (char *)s);
++ s = mark;
++ }
++ SLang_push_malloced_string (str);
++}
++
++/*}}}*/
++
++static void str_quote_string_cmd (char *str, char *quotes, int *slash_ptr) /*{{{*/
++{
++ char *q;
++ int slash;
++ unsigned int len;
++ register char *t, *s, *q1;
++ register unsigned char ch;
++
++ slash = *slash_ptr;
++
++ if ((slash &gt; 255) || (slash &lt; 0))
++ {
++ SLang_Error = SL_INVALID_PARM;
++ return;
++ }
++
++ /* setup the utility table to have 1s at quote char postitions. */
++ set_utility_char_table (quotes);
++
++ t = Utility_Char_Table;
++ t[(unsigned int) slash] = 1;
++
++ /* calculate length */
++ s = str;
++ len = 0;
++ while ((ch = (unsigned char) *s++) != 0) if (t[ch]) len++;
++ len += (unsigned int) (s - str);
++
++ if (NULL != (q = SLmalloc(len)))
++ {
++ s = str; q1 = q;
++ while ((ch = (unsigned char) *s++) != 0)
++ {
++ if (t[ch]) *q1++ = slash;
++ *q1++ = (char) ch;
++ }
++ *q1 = 0;
++ SLang_push_malloced_string(q);
++ }
++}
++
++/*}}}*/
++
++/* returns the position of substrin in a string or null */
++static int issubstr_cmd (char *a, char *b) /*{{{*/
++{
++ char *c;
++
++ if (NULL == (c = (char *) strstr(a, b)))
++ return 0;
++
++ return 1 + (int) (c - a);
++}
++
++/*}}}*/
++
++/* returns to stack string at pos n to n + m of a */
++static void substr_cmd (char *a, int *n_ptr, int *m_ptr) /*{{{*/
++{
++ int n, m;
++ int lena;
++
++ n = *n_ptr;
++ m = *m_ptr;
++
++ lena = strlen (a);
++ if (n &gt; lena) n = lena + 1;
++ if (n &lt; 1)
++ {
++ SLang_Error = SL_INVALID_PARM;
++ return;
++ }
++
++ n--;
++ if (m &lt; 0) m = lena;
++ if (n + m &gt; lena) m = lena - n;
++
++ (void) _SLang_push_nstring (a + n, (unsigned int) m);
++}
++
++/*}}}*/
++
++/* substitute char m at positin string n in string*/
++static void strsub_cmd (int *nptr, int *mptr) /*{{{*/
++{
++ char *a;
++ int n, m;
++ unsigned int lena;
++
++ if (-1 == SLpop_string (&amp;a))
++ return;
++
++ n = *nptr;
++ m = *mptr;
++
++ lena = strlen (a);
++
++ if ((n &lt;= 0) || (lena &lt; (unsigned int) n))
++ {
++ SLang_Error = SL_INVALID_PARM;
++ SLfree(a);
++ return;
++ }
++
++ a[n - 1] = (char) m;
++
++ SLang_push_malloced_string (a);
++}
++
++/*}}}*/
++
++static void strup_cmd(void) /*{{{*/
++{
++ unsigned char c, *a;
++ char *str;
++
++ if (SLpop_string (&amp;str))
++ return;
++
++ a = (unsigned char *) str;
++ while ((c = *a) != 0)
++ {
++ /* if ((*a &gt;= 'a') &amp;&amp; (*a &lt;= 'z')) *a -= 32; */
++ *a = UPPER_CASE(c);
++ a++;
++ }
++
++ SLang_push_malloced_string (str);
++}
++
++/*}}}*/
++
++static int isdigit_cmd (char *what) /*{{{*/
++{
++ return isdigit((unsigned char)*what);
++}
++
++/*}}}*/
++static int toupper_cmd (int *ch) /*{{{*/
++{
++ return UPPER_CASE(*ch);
++}
++
++/*}}}*/
++
++static int tolower_cmd (int *ch) /*{{{*/
++{
++ return LOWER_CASE(*ch);
++}
++
++/*}}}*/
++
++static void strlow_cmd (void) /*{{{*/
++{
++ unsigned char c, *a;
++ char *str;
++
++ if (SLpop_string(&amp;str)) return;
++ a = (unsigned char *) str;
++ while ((c = *a) != 0)
++ {
++ /* if ((*a &gt;= 'a') &amp;&amp; (*a &lt;= 'z')) *a -= 32; */
++ *a = LOWER_CASE(c);
++ a++;
++ }
++
++ SLang_push_malloced_string ((char *) str);
++}
++
++/*}}}*/
++
++static SLang_Array_Type *do_strchop (char *str, int delim, int quote)
++{
++ int count;
++ char *s0, *elm;
++ register char *s1;
++ register unsigned char ch;
++ int quoted;
++ SLang_Array_Type *at;
++ char **data;
++
++ if ((quote &lt; 0) || (quote &gt; 255)
++ || (delim &lt;= 0) || (delim &gt; 255))
++ {
++ SLang_Error = SL_INVALID_PARM;
++ return NULL;
++ }
++
++ s1 = s0 = str;
++
++ quoted = 0;
++ count = 1; /* at least 1 */
++ while (1)
++ {
++ ch = (unsigned char) *s1++;
++ if ((ch == quote) &amp;&amp; quote)
++ {
++ if (*s1 == 0)
++ break;
++
++ s1++;
++ continue;
++ }
++
++ if (ch == delim)
++ {
++ count++;
++ continue;
++ }
++
++ if (ch == 0)
++ break;
++ }
++
++ if (NULL == (at = SLang_create_array (SLANG_STRING_TYPE, 0, NULL, &amp;count, 1)))
++ return NULL;
++
++ data = (char **)at-&gt;data;
++
++ count = 0;
++ s1 = s0;
++
++ while (1)
++ {
++ ch = (unsigned char) *s1;
++
++ if ((ch == quote) &amp;&amp; quote)
++ {
++ s1++;
++ if (*s1 != 0) s1++;
++ quoted = 1;
++ continue;
++ }
++
++ if ((ch == delim) || (ch == 0))
++ {
++ if (quoted == 0)
++ elm = SLang_create_nslstring (s0, (unsigned int) (s1 - s0));
++ else
++ {
++ register char ch1, *p, *p1;
++ char *tmp;
++
++ tmp = SLmake_nstring (s0, (unsigned int)(s1 - s0));
++ if (tmp == NULL)
++ break;
++
++ /* Now unquote it */
++ p = p1 = tmp;
++ do
++ {
++ ch1 = *p1++;
++ if (ch1 == '\\') ch1 = *p1++;
++ *p++ = ch1;
++ }
++ while (ch1 != 0);
++ quoted = 0;
++
++ elm = SLang_create_slstring (tmp);
++ SLfree (tmp);
++ }
++
++ if (elm == NULL)
++ break;
++
++ data[count] = elm;
++ count++;
++
++ if (ch == 0)
++ return at;
++
++ s1++; /* skip past delim */
++ s0 = s1; /* and reset */
++ }
++ else s1++;
++ }
++
++ SLang_free_array (at);
++ return NULL;
++}
++
++static void strchop_cmd (char *str, int *q, int *d)
++{
++ (void) SLang_push_array (do_strchop (str, *q, *d), 1);
++}
++
++static void strchopr_cmd (char *str, int *q, int *d)
++{
++ SLang_Array_Type *at;
++
++ if (NULL != (at = do_strchop (str, *q, *d)))
++ {
++ char **d0, **d1;
++
++ d0 = (char **) at-&gt;data;
++ d1 = d0 + (at-&gt;num_elements - 1);
++
++ while (d0 &lt; d1)
++ {
++ char *tmp;
++
++ tmp = *d0;
++ *d0 = *d1;
++ *d1 = tmp;
++ d0++;
++ d1--;
++ }
++ }
++ SLang_push_array (at, 1);
++}
++
++static int strcmp_cmd (char *a, char *b) /*{{{*/
++{
++ return strcmp(a, b);
++}
++
++/*}}}*/
++
++static int strncmp_cmd (char *a, char *b, int *n) /*{{{*/
++{
++ return strncmp(a, b, (unsigned int) *n);
++}
++
++/*}}}*/
++
++static int strlen_cmd (char *s) /*{{{*/
++{
++ return (int) strlen (s);
++}
++/*}}}*/
++
++static void extract_element_cmd (char *list, int *nth_ptr, int *delim_ptr)
++{
++ char buf[1024], *b;
++
++ b = buf;
++ if (-1 == SLextract_list_element (list, *nth_ptr, *delim_ptr, buf, sizeof(buf)))
++ b = NULL;
++
++ SLang_push_string (b);
++}
++
++/* sprintf functionality for S-Lang */
++
++static char *SLdo_sprintf (char *fmt) /*{{{*/
++{
++ register char *p = fmt, ch;
++ char *out = NULL, *outp = NULL;
++ char dfmt[1024]; /* used to hold part of format */
++ char *f;
++ VOID_STAR varp;
++ int want_width, width, precis, use_varp, int_var;
++ long long_var;
++ unsigned int len = 0, malloc_len = 0, dlen;
++ int do_free, guess_size;
++#if SLANG_HAS_FLOAT
++ int tmp1, tmp2, use_double;
++ double x;
++#endif
++ int use_long = 0;
++
++ while (1)
++ {
++ while ((ch = *p) != 0)
++ {
++ if (ch == '%')
++ break;
++ p++;
++ }
++
++ /* p points at '%' or 0 */
++
++ dlen = (unsigned int) (p - fmt);
++
++ if (len + dlen &gt;= malloc_len)
++ {
++ malloc_len = len + dlen;
++ if (out == NULL) outp = SLmalloc(malloc_len + 1);
++ else outp = SLrealloc(out, malloc_len + 1);
++ if (NULL == outp)
++ return out;
++ out = outp;
++ outp = out + len;
++ }
++
++ strncpy(outp, fmt, dlen);
++ len += dlen;
++ outp = out + len;
++ *outp = 0;
++ if (ch == 0) break;
++
++ /* bump it beyond '%' */
++ ++p;
++ fmt = p;
++
++ f = dfmt;
++ *f++ = ch;
++ /* handle flag char */
++ ch = *p++;
++
++ /* Make sure cases such as &quot;% #g&quot; can be handled. */
++ if ((ch == '-') || (ch == '+') || (ch == ' ') || (ch == '#'))
++ {
++ *f++ = ch;
++ ch = *p++;
++ if ((ch == '-') || (ch == '+') || (ch == ' ') || (ch == '#'))
++ {
++ *f++ = ch;
++ ch = *p++;
++ }
++ }
++
++
++ /* width */
++ /* I have got to parse it myself so that I can see how big it needs
++ * to be.
++ */
++ want_width = width = 0;
++ if (ch == '*')
++ {
++ if (SLang_pop_integer(&amp;width)) return (out);
++ want_width = 1;
++ ch = *p++;
++ }
++ else
++ {
++ if (ch == '0')
++ {
++ *f++ = '0';
++ ch = *p++;
++ }
++
++ while ((ch &lt;= '9') &amp;&amp; (ch &gt;= '0'))
++ {
++ width = width * 10 + (ch - '0');
++ ch = *p++;
++ want_width = 1;
++ }
++ }
++
++ if (want_width)
++ {
++ sprintf(f, &quot;%d&quot;, width);
++ f += strlen (f);
++ }
++ precis = 0;
++ /* precision -- also indicates max number of chars from string */
++ if (ch == '.')
++ {
++ *f++ = ch;
++ ch = *p++;
++ want_width = 0;
++ if (ch == '*')
++ {
++ if (SLang_pop_integer(&amp;precis)) return (out);
++ ch = *p++;
++ want_width = 1;
++ }
++ else while ((ch &lt;= '9') &amp;&amp; (ch &gt;= '0'))
++ {
++ precis = precis * 10 + (ch - '0');
++ ch = *p++;
++ want_width = 1;
++ }
++ if (want_width)
++ {
++ sprintf(f, &quot;%d&quot;, precis);
++ f += strlen (f);
++ }
++ else precis = 0;
++ }
++
++ long_var = 0;
++ int_var = 0;
++ varp = NULL;
++ guess_size = 32;
++#if SLANG_HAS_FLOAT
++ use_double = 0;
++#endif
++ use_long = 0;
++ use_varp = 0;
++ do_free = 0;
++
++ if (ch == 'l')
++ {
++ use_long = 1;
++ ch = *p++;
++ }
++ else if (ch == 'h') ch = *p++; /* not supported */
++
++ /* Now the actual format specifier */
++ switch (ch)
++ {
++ case 'S':
++ _SLstring_intrinsic ();
++ ch = 's';
++ /* drop */
++ case 's':
++ if (SLang_pop_slstring((char **) &amp;varp)) return (out);
++ do_free = 1;
++ guess_size = strlen((char *) varp);
++ use_varp = 1;
++ break;
++
++ case '%':
++ guess_size = 1;
++ do_free = 0;
++ use_varp = 1;
++ varp = (VOID_STAR) &quot;%&quot;;
++ break;
++
++ case 'c': guess_size = 1;
++ use_long = 0;
++ /* drop */
++ case 'd':
++ case 'i':
++ case 'o':
++ case 'u':
++ case 'X':
++ case 'x':
++ if (SLang_pop_long (&amp;long_var)) return(out);
++ if (use_long == 0)
++ int_var = (int) long_var;
++ else
++ *f++ = 'l';
++ break;
++
++ case 'f':
++ case 'e':
++ case 'g':
++ case 'E':
++ case 'G':
++#if SLANG_HAS_FLOAT
++ if (SLang_pop_double(&amp;x, &amp;tmp1, &amp;tmp2)) return (out);
++ use_double = 1;
++ guess_size = 256;
++ (void) tmp1; (void) tmp2;
++ use_long = 0;
++ break;
++#endif
++ case 'p':
++ guess_size = 32;
++ /* Pointer type?? Why?? */
++ if (-1 == SLdo_pop ())
++ return out;
++ varp = (VOID_STAR) _SLStack_Pointer;
++ use_varp = 1;
++ use_long = 0;
++ break;
++
++ default:
++ SLang_doerror(&quot;Invalid Format.&quot;);
++ return(out);
++ }
++ *f++ = ch; *f = 0;
++
++ width = width + precis;
++ if (width &gt; guess_size) guess_size = width;
++
++ if (len + guess_size &gt; malloc_len)
++ {
++ outp = (char *) SLrealloc(out, len + guess_size + 1);
++ if (outp == NULL)
++ {
++ SLang_Error = SL_MALLOC_ERROR;
++ return (out);
++ }
++ out = outp;
++ outp = out + len;
++ malloc_len = len + guess_size;
++ }
++
++ if (use_varp)
++ {
++ sprintf(outp, dfmt, varp);
++ if (do_free) SLang_free_slstring ((char *)varp);
++ }
++#if SLANG_HAS_FLOAT
++ else if (use_double) sprintf(outp, dfmt, x);
++#endif
++ else if (use_long) sprintf (outp, dfmt, long_var);
++ else sprintf(outp, dfmt, int_var);
++
++ len += strlen(outp);
++ outp = out + len;
++ fmt = p;
++ }
++
++ if (out != NULL)
++ {
++ outp = SLrealloc (out, (unsigned int) (outp - out) + 1);
++ if (outp != NULL) out = outp;
++ }
++
++ return (out);
++}
++
++/*}}}*/
++
++int _SLstrops_do_sprintf_n (int n) /*{{{*/
++{
++ char *p;
++ char *fmt;
++ SLang_Object_Type *ptr;
++ int ofs;
++
++ if (-1 == (ofs = SLreverse_stack (n + 1)))
++ return -1;
++
++ ptr = _SLRun_Stack + ofs;
++
++ if (SLang_pop_slstring(&amp;fmt))
++ return -1;
++
++ p = SLdo_sprintf (fmt);
++ SLang_free_slstring (fmt);
++
++ while (_SLStack_Pointer &gt; ptr)
++ SLdo_pop ();
++
++ if (SLang_Error)
++ {
++ SLfree (p);
++ return -1;
++ }
++
++ return SLang_push_malloced_string (p);
++}
++
++/*}}}*/
++
++static void sprintf_n_cmd (int *n)
++{
++ _SLstrops_do_sprintf_n (*n);
++}
++
++static void sprintf_cmd (void)
++{
++ _SLstrops_do_sprintf_n (SLang_Num_Function_Args - 1); /* do not include format */
++}
++
++/* converts string s to a form that can be used in an eval */
++static void make_printable_string(char *s) /*{{{*/
++{
++ unsigned int len;
++ register char *s1 = s, ch, *ss1;
++ char *ss;
++
++ /* compute length */
++ len = 3;
++ while ((ch = *s1++) != 0)
++ {
++ if ((ch == '\n') || (ch == '\\') || (ch == '&quot;')) len++;
++ len++;
++ }
++
++ if (NULL == (ss = SLmalloc(len)))
++ return;
++
++ s1 = s;
++ ss1 = ss;
++ *ss1++ = '&quot;';
++ while ((ch = *s1++) != 0)
++ {
++ if (ch == '\n')
++ {
++ ch = 'n';
++ *ss1++ = '\\';
++ }
++ else if ((ch == '\\') || (ch == '&quot;'))
++ {
++ *ss1++ = '\\';
++ }
++ *ss1++ = ch;
++ }
++ *ss1++ = '&quot;';
++ *ss1 = 0;
++ if (-1 == SLang_push_string (ss))
++ SLfree (ss);
++}
++
++/*}}}*/
++
++static int is_list_element_cmd (char *list, char *elem, int *d_ptr)
++{
++ char ch;
++ int d, n;
++ unsigned int len;
++ char *lbeg, *lend;
++
++ d = *d_ptr;
++
++ len = strlen (elem);
++
++ n = 1;
++ lend = list;
++
++ while (1)
++ {
++ lbeg = lend;
++ while ((0 != (ch = *lend)) &amp;&amp; (ch != (char) d)) lend++;
++
++ if ((lbeg + len == lend)
++ &amp;&amp; (0 == strncmp (elem, lbeg, len)))
++ break;
++
++ if (ch == 0)
++ {
++ n = 0;
++ break;
++ }
++ lend++; /* skip delim */
++ n++;
++ }
++
++ return n;
++}
++
++/*}}}*/
++
++/* Regular expression routines for strings */
++static SLRegexp_Type regexp_reg;
++
++static int string_match_cmd (char *str, char *pat, int *nptr) /*{{{*/
++{
++ int n;
++ unsigned int len;
++ unsigned char rbuf[512], *match;
++
++ n = *nptr;
++
++ regexp_reg.case_sensitive = 1;
++ regexp_reg.buf = rbuf;
++ regexp_reg.pat = (unsigned char *) pat;
++ regexp_reg.buf_len = sizeof (rbuf);
++
++ if (SLang_regexp_compile (&amp;regexp_reg))
++ {
++ SLang_verror (SL_INVALID_PARM, &quot;Unable to compile pattern&quot;);
++ return -1;
++ }
++
++ n--;
++ len = strlen(str);
++ if ((n &lt; 0) || ((unsigned int) n &gt;= len))
++ {
++ /* SLang_Error = SL_INVALID_PARM; */
++ return 0;
++ }
++
++ str += n;
++ len -= n;
++
++ if (NULL == (match = SLang_regexp_match((unsigned char *) str, len, &amp;regexp_reg)))
++ return 0;
++
++ /* adjust offsets */
++ regexp_reg.offset = n;
++
++ return (1 + (int) ((char *) match - str));
++}
++
++/*}}}*/
++
++static int string_match_nth_cmd (int *nptr) /*{{{*/
++{
++ int n, beg;
++
++ n = *nptr;
++
++ if ((n &lt; 0) || (n &gt; 9) || (regexp_reg.pat == NULL)
++ || ((beg = regexp_reg.beg_matches[n]) == -1))
++ {
++ SLang_Error = SL_INVALID_PARM;
++ return -1;
++ }
++ SLang_push_integer(beg + regexp_reg.offset);
++ return regexp_reg.end_matches[n];
++}
++
++/*}}}*/
++
++static char *create_delimited_string (char **list, unsigned int n,
++ char *delim)
++{
++ unsigned int len, dlen;
++ unsigned int i;
++ unsigned int num;
++ char *str, *s;
++
++ len = 1; /* allow room for \0 char */
++ num = 0;
++ for (i = 0; i &lt; n; i++)
++ {
++ if (list[i] == NULL) continue;
++ len += strlen (list[i]);
++ num++;
++ }
++
++ dlen = strlen (delim);
++ if (num &gt; 1)
++ len += (num - 1) * dlen;
++
++ if (NULL == (str = SLmalloc (len)))
++ return NULL;
++
++ *str = 0;
++ s = str;
++ i = 0;
++
++ while (num &gt; 1)
++ {
++ while (list[i] == NULL)
++ i++;
++
++ strcpy (s, list[i]);
++ s += strlen (list[i]);
++ strcpy (s, delim);
++ s += dlen;
++ i++;
++ num--;
++ }
++
++ if (num)
++ {
++ while (list[i] == NULL)
++ i++;
++
++ strcpy (s, list[i]);
++ }
++
++ return str;
++}
++
++static void create_delimited_string_cmd (int *nptr)
++{
++ unsigned int n, i;
++ char **strings;
++ char *str;
++
++ str = NULL;
++
++ n = 1 + (unsigned int) *nptr; /* n includes delimiter */
++
++ if (NULL == (strings = (char **)SLmalloc (n * sizeof (char *))))
++ {
++ SLdo_pop_n (n);
++ return;
++ }
++ memset((char *)strings, 0, n * sizeof (char *));
++
++ i = n;
++ while (i != 0)
++ {
++ i--;
++ if (-1 == SLang_pop_slstring (strings + i))
++ goto return_error;
++ }
++
++ str = create_delimited_string (strings + 1, (n - 1), strings[0]);
++ /* drop */
++ return_error:
++ for (i = 0; i &lt; n; i++) SLang_free_slstring (strings[i]);
++ SLfree ((char *)strings);
++
++ (void) SLang_push_malloced_string (str); /* NULL Ok */
++}
++
++static void strjoin_cmd (char *delim)
++{
++ SLang_Array_Type *at;
++ char *str;
++
++ if (-1 == SLang_pop_array_of_type (&amp;at, SLANG_STRING_TYPE))
++ return;
++
++ str = create_delimited_string ((char **)at-&gt;data, at-&gt;num_elements, delim);
++ SLang_free_array (at);
++ (void) SLang_push_malloced_string (str); /* NULL Ok */
++}
++
++static void str_delete_chars_cmd (char *s, char *d)
++{
++ unsigned char lut[256];
++ unsigned char *s1, *s2;
++ unsigned char ch;
++
++ make_lut ((unsigned char *)d, lut);
++ if (NULL == (s = SLmake_string (s)))
++ return;
++
++ s1 = s2 = (unsigned char *) s;
++ while ((ch = *s2++) != 0)
++ {
++ if (0 == lut[ch])
++ *s1++ = ch;
++ }
++ *s1 = 0;
++
++ (void) SLang_push_malloced_string (s);
++}
++
++static unsigned char *make_lut_string (unsigned char *s)
++{
++ unsigned char lut[256];
++ unsigned char *l;
++ unsigned int i;
++
++ /* Complement-- a natural order is imposed */
++ make_lut (s, lut);
++ l = lut;
++ for (i = 1; i &lt; 256; i++)
++ {
++ if (lut[i])
++ *l++ = (unsigned char) i;
++ }
++ *l = 0;
++ return (unsigned char *) SLmake_string ((char *)lut);
++}
++
++static unsigned char *make_str_range (unsigned char *s)
++{
++ unsigned char *s1, *range;
++ unsigned int num;
++ unsigned char ch;
++ int len;
++
++ if (*s == '^')
++ return make_lut_string (s);
++
++ num = 0;
++ s1 = s;
++ while ((ch = *s1++) != 0)
++ {
++ unsigned char ch1;
++
++ ch1 = *s1;
++ if (ch1 == '-')
++ {
++ s1++;
++ ch1 = *s1;
++ len = (int)ch1 - (int)ch;
++ if (len &lt; 0)
++ len = -len;
++
++ num += (unsigned int) len;
++ if (ch1 != 0)
++ s1++;
++ }
++
++ num++;
++ }
++
++ range = (unsigned char *)SLmalloc (num + 1);
++ if (range == NULL)
++ return NULL;
++
++ s1 = s;
++ s = range;
++ while ((ch = *s1++) != 0)
++ {
++ unsigned char ch1;
++ unsigned int i;
++
++ ch1 = *s1;
++ if (ch1 != '-')
++ {
++ *s++ = ch;
++ continue;
++ }
++
++ s1++;
++ ch1 = *s1;
++
++ if (ch &gt; ch1)
++ {
++ if (ch1 == 0)
++ ch1 = 1;
++
++ for (i = (unsigned int) ch; i &gt;= (unsigned int) ch1; i--)
++ *s++ = (unsigned char) i;
++
++ if (*s1 == 0)
++ break;
++ }
++ else
++ {
++ for (i = (unsigned int) ch; i &lt;= (unsigned int) ch1; i++)
++ *s++ = (unsigned char) i;
++ }
++ s1++;
++ }
++
++#if 0
++ if (range + num != s)
++ SLang_verror (SL_INTERNAL_ERROR, &quot;make_str_range: num wrong&quot;);
++#endif
++ *s = 0;
++
++ return range;
++}
++
++static void strtrans_cmd (char *s, unsigned char *from, unsigned char *to)
++{
++ unsigned char map[256];
++ char *s1;
++ unsigned int i;
++ unsigned char ch;
++ unsigned char last_to;
++ unsigned char *from_range, *to_range;
++
++ for (i = 0; i &lt; 256; i++) map[i] = (unsigned char) i;
++
++ if (*to == 0)
++ {
++ str_delete_chars_cmd (s, (char *)from);
++ return;
++ }
++
++ from_range = make_str_range (from);
++ if (from_range == NULL)
++ return;
++ to_range = make_str_range (to);
++ if (to_range == NULL)
++ {
++ SLfree ((char *)from_range);
++ return;
++ }
++
++ from = from_range;
++ to = to_range;
++
++ last_to = 0;
++ while ((ch = *from++) != 0)
++ {
++ unsigned char to_ch;
++
++ if (0 == (to_ch = *to++))
++ {
++ do
++ {
++ map[ch] = last_to;
++ }
++ while (0 != (ch = *from++));
++ break;
++ }
++
++ last_to = map[ch] = to_ch;
++ }
++
++ SLfree ((char *)from_range);
++ SLfree ((char *)to_range);
++
++ s = SLmake_string (s);
++ if (s == NULL)
++ return;
++
++ s1 = s;
++ while ((ch = (unsigned char) *s1) != 0)
++ *s1++ = (char) map[ch];
++
++ (void) SLang_push_malloced_string (s);
++}
++
++
++static SLang_Intrin_Fun_Type Strops_Table [] = /*{{{*/
++{
++ MAKE_INTRINSIC_I(&quot;create_delimited_string&quot;, create_delimited_string_cmd, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_SS(&quot;strcmp&quot;, strcmp_cmd, SLANG_INT_TYPE),
++ MAKE_INTRINSIC_SSI(&quot;strncmp&quot;, strncmp_cmd, SLANG_INT_TYPE),
++ MAKE_INTRINSIC_0(&quot;strcat&quot;, strcat_cmd, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_S(&quot;strlen&quot;, strlen_cmd, SLANG_INT_TYPE),
++ MAKE_INTRINSIC_SII(&quot;strchop&quot;, strchop_cmd, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_SII(&quot;strchopr&quot;, strchopr_cmd, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_I(&quot;strreplace&quot;, strreplace_cmd, SLANG_INT_TYPE),
++ MAKE_INTRINSIC_SSS(&quot;str_replace&quot;, str_replace_cmd, SLANG_INT_TYPE),
++ MAKE_INTRINSIC_SII(&quot;substr&quot;, substr_cmd, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_SS(&quot;is_substr&quot;, issubstr_cmd, SLANG_INT_TYPE),
++ MAKE_INTRINSIC_II(&quot;strsub&quot;, strsub_cmd, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_SII(&quot;extract_element&quot;, extract_element_cmd, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_SSI(&quot;is_list_element&quot;, is_list_element_cmd, SLANG_INT_TYPE),
++ MAKE_INTRINSIC_SSI(&quot;string_match&quot;, string_match_cmd, SLANG_INT_TYPE),
++ MAKE_INTRINSIC_I(&quot;string_match_nth&quot;, string_match_nth_cmd, SLANG_INT_TYPE),
++ MAKE_INTRINSIC_0(&quot;strlow&quot;, strlow_cmd, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_I(&quot;tolower&quot;, tolower_cmd, SLANG_INT_TYPE),
++ MAKE_INTRINSIC_I(&quot;toupper&quot;, toupper_cmd, SLANG_INT_TYPE),
++ MAKE_INTRINSIC_0(&quot;strup&quot;, strup_cmd, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_S(&quot;isdigit&quot;, isdigit_cmd, SLANG_INT_TYPE),
++ MAKE_INTRINSIC_S(&quot;strtrim&quot;, strtrim_cmd, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_S(&quot;strtrim_end&quot;, strtrim_end_cmd, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_S(&quot;strtrim_beg&quot;, strtrim_beg_cmd, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_0(&quot;strcompress&quot;, strcompress_cmd, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_I(&quot;Sprintf&quot;, sprintf_n_cmd, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_0(&quot;sprintf&quot;, sprintf_cmd, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_0(&quot;sscanf&quot;, _SLang_sscanf, SLANG_INT_TYPE),
++ MAKE_INTRINSIC_S(&quot;make_printable_string&quot;, make_printable_string, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_SSI(&quot;str_quote_string&quot;, str_quote_string_cmd, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_SSS(&quot;str_uncomment_string&quot;, str_uncomment_string_cmd, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_II(&quot;define_case&quot;, SLang_define_case, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_S(&quot;strtok&quot;, strtok_cmd, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_S(&quot;strjoin&quot;, strjoin_cmd, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_SSS(&quot;strtrans&quot;, strtrans_cmd, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_SS(&quot;str_delete_chars&quot;, str_delete_chars_cmd, SLANG_VOID_TYPE),
++
++ SLANG_END_INTRIN_FUN_TABLE
++};
++
++/*}}}*/
++
++int _SLang_init_slstrops (void)
++{
++ return SLadd_intrin_fun_table (Strops_Table, NULL);
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slstrops.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slstruct.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slstruct.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slstruct.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,932 @@
++/* Structure type implementation */
++/* Copyright (c) 1998, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++#include &quot;slinclud.h&quot;
++
++#define SL_APP_WANTS_FOREACH
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++void _SLstruct_delete_struct (_SLang_Struct_Type *s)
++{
++ _SLstruct_Field_Type *field, *field_max;
++
++ if (s == NULL) return;
++
++ if (s-&gt;num_refs &gt; 1)
++ {
++ s-&gt;num_refs -= 1;
++ return;
++ }
++
++ field = s-&gt;fields;
++ if (field != NULL)
++ {
++ field_max = field + s-&gt;nfields;
++
++ while (field &lt; field_max)
++ {
++ SLang_free_object (&amp;field-&gt;obj);
++ SLang_free_slstring (field-&gt;name); /* could be NULL */
++ field++;
++ }
++ SLfree ((char *) s-&gt;fields);
++ }
++ SLfree ((char *) s);
++}
++
++static _SLang_Struct_Type *allocate_struct (unsigned int nfields)
++{
++ _SLang_Struct_Type *s;
++ _SLstruct_Field_Type *f;
++ unsigned int i, size;
++
++ s = (_SLang_Struct_Type *) SLmalloc (sizeof (_SLang_Struct_Type));
++ if (s == NULL) return NULL;
++
++ SLMEMSET((char *) s, 0, sizeof (_SLang_Struct_Type));
++
++ size = nfields * sizeof(_SLstruct_Field_Type);
++ if (NULL == (f = (_SLstruct_Field_Type *) SLmalloc (size)))
++ {
++ SLfree ((char *) s);
++ return NULL;
++ }
++ SLMEMSET ((char *) f, 0, size);
++ s-&gt;nfields = nfields;
++ s-&gt;fields = f;
++
++ /* By default, all structs will be created with elements set to NULL. I
++ * do not know whether or not it is better to use SLANG_UNDEFINED_TYPE.
++ */
++ for (i = 0; i &lt; nfields; i++)
++ f[i].obj.data_type = SLANG_NULL_TYPE;
++
++ return s;
++}
++
++static int push_struct_of_type (unsigned char type, _SLang_Struct_Type *s)
++{
++ SLang_Object_Type obj;
++
++ obj.data_type = type;
++ obj.v.struct_val = s;
++ s-&gt;num_refs += 1;
++
++ if (0 == SLang_push (&amp;obj))
++ return 0;
++
++ s-&gt;num_refs -= 1;
++ return -1;
++}
++
++int _SLang_push_struct (_SLang_Struct_Type *s)
++{
++ return push_struct_of_type (SLANG_STRUCT_TYPE, s);
++}
++
++int _SLang_pop_struct (_SLang_Struct_Type **sp)
++{
++ SLang_Object_Type obj;
++ SLang_Class_Type *cl;
++ unsigned char type;
++
++ if (0 != SLang_pop (&amp;obj))
++ return -1;
++
++ type = obj.data_type;
++ if (type != SLANG_STRUCT_TYPE)
++ {
++ cl = _SLclass_get_class (type);
++ if (cl-&gt;cl_struct_def == NULL)
++ {
++ *sp = NULL;
++ SLang_free_object (&amp;obj);
++ SLang_verror (SL_TYPE_MISMATCH,
++ &quot;Expecting struct type object. Found %s&quot;,
++ cl-&gt;cl_name);
++ return -1;
++ }
++ }
++
++ *sp = obj.v.struct_val;
++ return 0;
++}
++
++static void struct_destroy (unsigned char type, VOID_STAR vs)
++{
++ (void) type;
++ _SLstruct_delete_struct (*(_SLang_Struct_Type **) vs);
++}
++
++static int struct_push (unsigned char type, VOID_STAR ptr)
++{
++ return push_struct_of_type (type, *(_SLang_Struct_Type **) ptr);
++}
++
++static _SLstruct_Field_Type *find_field (_SLang_Struct_Type *s, char *name)
++{
++ _SLstruct_Field_Type *f, *fmax;
++
++ f = s-&gt;fields;
++ fmax = f + s-&gt;nfields;
++
++ while (f &lt; fmax)
++ {
++ /* Since both these are slstrings, only compare pointer */
++ if (name == f-&gt;name)
++ return f;
++
++ f++;
++ }
++
++ return NULL;
++}
++
++static _SLstruct_Field_Type *pop_field (_SLang_Struct_Type *s, char *name)
++{
++ _SLstruct_Field_Type *f;
++
++ f = find_field (s, name);
++ if (f == NULL)
++ SLang_verror (SL_SYNTAX_ERROR, &quot;struct has no field named %s&quot;, name);
++ return f;
++}
++
++int SLstruct_create_struct (unsigned int nfields,
++ char **field_names,
++ unsigned char *field_types,
++ VOID_STAR *field_values)
++{
++ _SLang_Struct_Type *s;
++ _SLstruct_Field_Type *f;
++ unsigned int i;
++
++ if (NULL == (s = allocate_struct (nfields)))
++ return -1;
++
++ f = s-&gt;fields;
++ for (i = 0; i &lt; nfields; i++)
++ {
++ unsigned char type;
++ SLang_Class_Type *cl;
++ VOID_STAR value;
++ char *name = field_names [i];
++
++ if (name == NULL)
++ {
++ SLang_verror (SL_INVALID_PARM, &quot;A struct field name cannot be NULL&quot;);
++ goto return_error;
++ }
++
++ if (NULL == (f-&gt;name = SLang_create_slstring (name)))
++ goto return_error;
++
++ if ((field_values == NULL)
++ || (NULL == (value = field_values [i])))
++ {
++ f++;
++ continue;
++ }
++
++ type = field_types[i];
++ cl = _SLclass_get_class (type);
++
++ if ((-1 == (cl-&gt;cl_push (type, value)))
++ || (-1 == SLang_pop (&amp;f-&gt;obj)))
++ goto return_error;
++
++ f++;
++ }
++
++ if (0 == _SLang_push_struct (s))
++ return 0;
++ /* drop */
++
++ return_error:
++ _SLstruct_delete_struct (s);
++ return -1;
++}
++
++/* Interpreter interface */
++
++int _SLstruct_define_struct (void)
++{
++ int nfields;
++ _SLang_Struct_Type *s;
++ _SLstruct_Field_Type *f;
++
++ if (-1 == SLang_pop_integer (&amp;nfields))
++ return -1;
++
++ if (nfields &lt;= 0)
++ {
++ SLang_verror (SL_INVALID_PARM, &quot;Number of struct fields must be &gt; 0&quot;);
++ return -1;
++ }
++
++ if (NULL == (s = allocate_struct (nfields)))
++ return -1;
++
++ f = s-&gt;fields;
++ while (nfields)
++ {
++ char *name;
++
++ nfields--;
++ if (-1 == SLang_pop_slstring (&amp;name))
++ {
++ _SLstruct_delete_struct (s);
++ return -1;
++ }
++ f[nfields].name = name;
++ }
++
++ if (-1 == _SLang_push_struct (s))
++ {
++ _SLstruct_delete_struct (s);
++ return -1;
++ }
++ return 0;
++}
++
++/* Simply make a struct that contains the same fields as struct s. Do not
++ * duplicate the field values.
++ */
++static _SLang_Struct_Type *make_struct_shell (_SLang_Struct_Type *s)
++{
++ _SLang_Struct_Type *new_s;
++ _SLstruct_Field_Type *new_f, *old_f;
++ unsigned int i, nfields;
++
++ nfields = s-&gt;nfields;
++ if (NULL == (new_s = allocate_struct (nfields)))
++ return NULL;
++
++ new_f = new_s-&gt;fields;
++ old_f = s-&gt;fields;
++
++ for (i = 0; i &lt; nfields; i++)
++ {
++ if (NULL == (new_f[i].name = SLang_create_slstring (old_f[i].name)))
++ {
++ _SLstruct_delete_struct (new_s);
++ return NULL;
++ }
++ }
++ return new_s;
++}
++
++static int struct_init_array_object (unsigned char type, VOID_STAR addr)
++{
++ SLang_Class_Type *cl;
++ _SLang_Struct_Type *s;
++
++ cl = _SLclass_get_class (type);
++ if (NULL == (s = make_struct_shell (cl-&gt;cl_struct_def)))
++ return -1;
++
++ s-&gt;num_refs = 1;
++ *(_SLang_Struct_Type **) addr = s;
++ return 0;
++}
++
++static int
++typedefed_struct_datatype_deref (unsigned char type)
++{
++ SLang_Class_Type *cl;
++ _SLang_Struct_Type *s;
++
++ cl = _SLclass_get_class (type);
++ if (NULL == (s = make_struct_shell (cl-&gt;cl_struct_def)))
++ return -1;
++
++ if (-1 == push_struct_of_type (type, s))
++ {
++ _SLstruct_delete_struct (s);
++ return -1;
++ }
++
++ return 0;
++}
++
++static _SLang_Struct_Type *duplicate_struct (_SLang_Struct_Type *s)
++{
++ _SLang_Struct_Type *new_s;
++ _SLstruct_Field_Type *new_f, *f, *fmax;
++
++ new_s = make_struct_shell (s);
++
++ if (new_s == NULL)
++ return NULL;
++
++ f = s-&gt;fields;
++ fmax = f + s-&gt;nfields;
++ new_f = new_s-&gt;fields;
++
++ while (f &lt; fmax)
++ {
++ SLang_Object_Type *obj;
++
++ obj = &amp;f-&gt;obj;
++ if (obj-&gt;data_type != SLANG_UNDEFINED_TYPE)
++ {
++ if ((-1 == _SLpush_slang_obj (obj))
++ || (-1 == SLang_pop (&amp;new_f-&gt;obj)))
++ {
++ _SLstruct_delete_struct (new_s);
++ return NULL;
++ }
++ }
++ new_f++;
++ f++;
++ }
++
++ return new_s;
++}
++
++static int struct_dereference (unsigned char type, VOID_STAR addr)
++{
++ _SLang_Struct_Type *s;
++
++ if (NULL == (s = duplicate_struct (*(_SLang_Struct_Type **) addr)))
++ return -1;
++
++ if (-1 == push_struct_of_type (type, s))
++ {
++ _SLstruct_delete_struct (s);
++ return -1;
++ }
++
++ return 0;
++}
++
++/*{{{ foreach */
++
++struct _SLang_Foreach_Context_Type
++{
++ _SLang_Struct_Type *s;
++ char *next_field_name;
++};
++
++static SLang_Foreach_Context_Type *
++struct_foreach_open (unsigned char type, unsigned int num)
++{
++ SLang_Foreach_Context_Type *c;
++ _SLang_Struct_Type *s;
++ char *next_name;
++
++ (void) type;
++
++ if (-1 == _SLang_pop_struct (&amp;s))
++ return NULL;
++
++ switch (num)
++ {
++ case 0:
++ next_name = SLang_create_slstring (&quot;next&quot;);
++ break;
++
++ case 1:
++ if (-1 == SLang_pop_slstring (&amp;next_name))
++ next_name = NULL;
++ break;
++
++ default:
++ next_name = NULL;
++ SLang_verror (SL_NOT_IMPLEMENTED,
++ &quot;'foreach (Struct_Type) using' requires single control value&quot;);
++ SLdo_pop_n (num);
++ break;
++ }
++
++ if (next_name == NULL)
++ {
++ _SLstruct_delete_struct (s);
++ return NULL;
++ }
++
++ c = (SLang_Foreach_Context_Type *)SLmalloc (sizeof (SLang_Foreach_Context_Type));
++ if (c == NULL)
++ {
++ _SLstruct_delete_struct (s);
++ SLang_free_slstring (next_name);
++ return NULL;
++ }
++ memset ((char *) c, 0, sizeof (SLang_Foreach_Context_Type));
++
++ c-&gt;next_field_name = next_name;
++ c-&gt;s = s;
++
++ return c;
++}
++
++static void struct_foreach_close (unsigned char type, SLang_Foreach_Context_Type *c)
++{
++ (void) type;
++ if (c == NULL) return;
++
++ SLang_free_slstring (c-&gt;next_field_name);
++ if (c-&gt;s != NULL) _SLstruct_delete_struct (c-&gt;s);
++ SLfree ((char *) c);
++}
++
++static int struct_foreach (unsigned char type, SLang_Foreach_Context_Type *c)
++{
++ _SLstruct_Field_Type *f;
++ _SLang_Struct_Type *next_s;
++
++ (void) type;
++
++ if (c == NULL)
++ return -1;
++
++ if (c-&gt;s == NULL)
++ return 0; /* done */
++
++ if (-1 == _SLang_push_struct (c-&gt;s))
++ return -1;
++
++ /* Now get the next one ready for the next foreach loop */
++
++ next_s = NULL;
++ if (NULL != (f = find_field (c-&gt;s, c-&gt;next_field_name)))
++ {
++ SLang_Class_Type *cl;
++
++ cl = _SLclass_get_class (f-&gt;obj.data_type);
++ /* Note that I cannot simply look for SLANG_STRUCT_TYPE since the
++ * user may have typedefed another struct type. So, look at the
++ * class methods.
++ */
++ if (cl-&gt;cl_foreach_open == struct_foreach_open)
++ {
++ next_s = f-&gt;obj.v.struct_val;
++ next_s-&gt;num_refs += 1;
++ }
++ }
++
++ _SLstruct_delete_struct (c-&gt;s);
++ c-&gt;s = next_s;
++
++ /* keep going */
++ return 1;
++}
++
++/*}}}*/
++
++static int struct_sput (unsigned char type, char *name)
++{
++ _SLang_Struct_Type *s;
++ _SLstruct_Field_Type *f;
++ SLang_Object_Type obj;
++
++ (void) type;
++
++ if (-1 == _SLang_pop_struct (&amp;s))
++ return -1;
++
++ if ((NULL == (f = pop_field (s, name)))
++ || (-1 == SLang_pop (&amp;obj)))
++ {
++ _SLstruct_delete_struct (s);
++ return -1;
++ }
++
++ SLang_free_object (&amp;f-&gt;obj);
++ f-&gt;obj = obj;
++ _SLstruct_delete_struct (s);
++ return 0;
++}
++
++static int struct_sget (unsigned char type, char *name)
++{
++ _SLang_Struct_Type *s;
++ _SLstruct_Field_Type *f;
++ int ret;
++
++ (void) type;
++
++ if (-1 == _SLang_pop_struct (&amp;s))
++ return -1;
++
++ if (NULL == (f = pop_field (s, name)))
++ {
++ _SLstruct_delete_struct (s);
++ return -1;
++ }
++
++ ret = _SLpush_slang_obj (&amp;f-&gt;obj);
++ _SLstruct_delete_struct (s);
++ return ret;
++}
++
++static int struct_typecast
++ (unsigned char a_type, VOID_STAR ap, unsigned int na,
++ unsigned char b_type, VOID_STAR bp)
++{
++ _SLang_Struct_Type **a, **b;
++ unsigned int i;
++
++ (void) a_type;
++ (void) b_type;
++
++ a = (_SLang_Struct_Type **) ap;
++ b = (_SLang_Struct_Type **) bp;
++ for (i = 0; i &lt; na; i++)
++ {
++ b[i] = a[i];
++ if (a[i] != NULL)
++ a[i]-&gt;num_refs += 1;
++ }
++
++ return 1;
++}
++
++int _SLstruct_define_typedef (void)
++{
++ char *type_name;
++ _SLang_Struct_Type *s, *s1;
++ SLang_Class_Type *cl;
++
++ if (-1 == SLang_pop_slstring (&amp;type_name))
++ return -1;
++
++ if (-1 == _SLang_pop_struct (&amp;s))
++ {
++ SLang_free_slstring (type_name);
++ return -1;
++ }
++
++ if (NULL == (s1 = make_struct_shell (s)))
++ {
++ SLang_free_slstring (type_name);
++ _SLstruct_delete_struct (s);
++ return -1;
++ }
++
++ _SLstruct_delete_struct (s);
++
++ if (NULL == (cl = SLclass_allocate_class (type_name)))
++ {
++ SLang_free_slstring (type_name);
++ _SLstruct_delete_struct (s1);
++ return -1;
++ }
++ SLang_free_slstring (type_name);
++
++ cl-&gt;cl_struct_def = s1;
++ cl-&gt;cl_init_array_object = struct_init_array_object;
++ cl-&gt;cl_datatype_deref = typedefed_struct_datatype_deref;
++ cl-&gt;cl_destroy = struct_destroy;
++ cl-&gt;cl_push = struct_push;
++ cl-&gt;cl_dereference = struct_dereference;
++ cl-&gt;cl_foreach_open = struct_foreach_open;
++ cl-&gt;cl_foreach_close = struct_foreach_close;
++ cl-&gt;cl_foreach = struct_foreach;
++
++ cl-&gt;cl_sget = struct_sget;
++ cl-&gt;cl_sput = struct_sput;
++
++ if (-1 == SLclass_register_class (cl,
++ SLANG_VOID_TYPE, /* any open slot */
++ sizeof (_SLang_Struct_Type),
++ SLANG_CLASS_TYPE_PTR))
++ {
++ /* FIXME: Priority=low */
++ /* There is a memory leak here if this fails... */
++ return -1;
++ }
++ /* Note: typecast from a user type struct type allowed but not the other
++ * way.
++ */
++ if (-1 == SLclass_add_typecast (cl-&gt;cl_data_type, SLANG_STRUCT_TYPE, struct_typecast, 1))
++ return -1;
++
++ return 0;
++}
++
++static int
++struct_datatype_deref (unsigned char stype)
++{
++ (void) stype;
++
++ if (SLang_peek_at_stack () == SLANG_ARRAY_TYPE)
++ {
++ SLang_Array_Type *at;
++ int status;
++
++ if (-1 == SLang_pop_array_of_type (&amp;at, SLANG_STRING_TYPE))
++ return -1;
++
++ status = SLstruct_create_struct (at-&gt;num_elements,
++ (char **) at-&gt;data, NULL, NULL);
++
++ SLang_free_array (at);
++ return status;
++ }
++
++ SLang_push_integer (SLang_Num_Function_Args);
++ return _SLstruct_define_struct ();
++}
++
++static int register_struct (void)
++{
++ SLang_Class_Type *cl;
++
++ if (NULL == (cl = SLclass_allocate_class (&quot;Struct_Type&quot;)))
++ return -1;
++
++ (void) SLclass_set_destroy_function (cl, struct_destroy);
++ (void) SLclass_set_push_function (cl, struct_push);
++ cl-&gt;cl_dereference = struct_dereference;
++ cl-&gt;cl_datatype_deref = struct_datatype_deref;
++
++ cl-&gt;cl_foreach_open = struct_foreach_open;
++ cl-&gt;cl_foreach_close = struct_foreach_close;
++ cl-&gt;cl_foreach = struct_foreach;
++
++ cl-&gt;cl_sget = struct_sget;
++ cl-&gt;cl_sput = struct_sput;
++
++ if (-1 == SLclass_register_class (cl, SLANG_STRUCT_TYPE, sizeof (_SLang_Struct_Type),
++ SLANG_CLASS_TYPE_PTR))
++ return -1;
++
++ return 0;
++}
++
++static void get_struct_field_names (_SLang_Struct_Type *s)
++{
++ SLang_Array_Type *a;
++ char **data;
++ int i, nfields;
++ _SLstruct_Field_Type *f;
++
++ nfields = (int) s-&gt;nfields;
++
++ if (NULL == (a = SLang_create_array (SLANG_STRING_TYPE, 0, NULL, &amp;nfields, 1)))
++ return;
++
++ f = s-&gt;fields;
++ data = (char **) a-&gt;data;
++ for (i = 0; i &lt; nfields; i++)
++ {
++ /* Since we are dealing with hashed strings, the next call should not
++ * fail. If it does, the interpreter will handle it at some other
++ * level.
++ */
++ data [i] = SLang_create_slstring (f[i].name);
++ }
++
++ SLang_push_array (a, 1);
++}
++
++static int push_struct_fields (_SLang_Struct_Type *s)
++{
++ _SLstruct_Field_Type *f, *fmax;
++ int num;
++
++ f = s-&gt;fields;
++ fmax = f + s-&gt;nfields;
++
++ num = 0;
++ while (fmax &gt; f)
++ {
++ fmax--;
++ if (-1 == _SLpush_slang_obj (&amp;fmax-&gt;obj))
++ break;
++
++ num++;
++ }
++
++ return num;
++}
++
++/* Syntax: set_struct_field (s, name, value); */
++static void struct_set_field (void)
++{
++ _SLang_Struct_Type *s;
++ _SLstruct_Field_Type *f;
++ SLang_Object_Type obj;
++ char *name;
++
++ if (-1 == SLang_pop (&amp;obj))
++ return;
++
++ if (-1 == SLang_pop_slstring (&amp;name))
++ {
++ SLang_free_object (&amp;obj);
++ return;
++ }
++
++ if (-1 == _SLang_pop_struct (&amp;s))
++ {
++ SLang_free_slstring (name);
++ SLang_free_object (&amp;obj);
++ return;
++ }
++
++ if (NULL == (f = pop_field (s, name)))
++ {
++ _SLstruct_delete_struct (s);
++ SLang_free_slstring (name);
++ SLang_free_object (&amp;obj);
++ return;
++ }
++
++ SLang_free_object (&amp;f-&gt;obj);
++ f-&gt;obj = obj;
++
++ _SLstruct_delete_struct (s);
++ SLang_free_slstring (name);
++}
++
++/* Syntax: set_struct_fields (s, values....); */
++static void set_struct_fields (void)
++{
++ unsigned int n;
++ _SLang_Struct_Type *s;
++ _SLstruct_Field_Type *f;
++
++ n = (unsigned int) SLang_Num_Function_Args;
++
++ if (-1 == SLreverse_stack (n))
++ return;
++
++ n--;
++ if (-1 == _SLang_pop_struct (&amp;s))
++ {
++ SLdo_pop_n (n);
++ return;
++ }
++
++ if (n &gt; s-&gt;nfields)
++ {
++ SLdo_pop_n (n);
++ SLang_verror (SL_INVALID_PARM, &quot;Too many values for structure&quot;);
++ _SLstruct_delete_struct (s);
++ return;
++ }
++
++ f = s-&gt;fields;
++ while (n &gt; 0)
++ {
++ SLang_Object_Type obj;
++
++ if (-1 == SLang_pop (&amp;obj))
++ break;
++
++ SLang_free_object (&amp;f-&gt;obj);
++ f-&gt;obj = obj;
++
++ f++;
++ n--;
++ }
++
++ _SLstruct_delete_struct (s);
++}
++
++static void get_struct_field (char *name)
++{
++ (void) struct_sget (0, name);
++}
++
++static int is_struct_type (void)
++{
++ SLang_Object_Type obj;
++ unsigned char type;
++ int status;
++
++ if (-1 == SLang_pop (&amp;obj))
++ return -1;
++
++ type = obj.data_type;
++ if (type == SLANG_STRUCT_TYPE)
++ status = 1;
++ else
++ status = (NULL != _SLclass_get_class (type)-&gt;cl_struct_def);
++ SLang_free_object (&amp;obj);
++ return status;
++}
++
++
++static SLang_Intrin_Fun_Type Struct_Table [] =
++{
++ MAKE_INTRINSIC_1(&quot;get_struct_field_names&quot;, get_struct_field_names, SLANG_VOID_TYPE, SLANG_STRUCT_TYPE),
++ MAKE_INTRINSIC_1(&quot;get_struct_field&quot;, get_struct_field, SLANG_VOID_TYPE, SLANG_STRING_TYPE),
++ MAKE_INTRINSIC_1(&quot;_push_struct_field_values&quot;, push_struct_fields, SLANG_INT_TYPE, SLANG_STRUCT_TYPE),
++ MAKE_INTRINSIC_0(&quot;set_struct_field&quot;, struct_set_field, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_0(&quot;set_struct_fields&quot;, set_struct_fields, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_0(&quot;is_struct_type&quot;, is_struct_type, SLANG_INT_TYPE),
++ /* MAKE_INTRINSIC_I(&quot;_create_struct&quot;, create_struct, SLANG_VOID_TYPE), */
++ SLANG_END_INTRIN_FUN_TABLE
++};
++
++int _SLstruct_init (void)
++{
++ if ((-1 == SLadd_intrin_fun_table (Struct_Table, NULL))
++ || (-1 == register_struct ()))
++ return -1;
++
++ return 0;
++}
++
++void _SLstruct_pop_args (int *np)
++{
++ SLang_Array_Type *at;
++ int i, n;
++ _SLang_Struct_Type **data;
++
++ n = *np;
++
++ if (n &lt; 0)
++ {
++ SLang_Error = SL_INVALID_PARM;
++ return;
++ }
++
++ data = (_SLang_Struct_Type **) SLmalloc ((n + 1) * sizeof (_SLang_Struct_Type *));
++ if (data == NULL)
++ {
++ SLdo_pop_n (n);
++ return;
++ }
++
++ memset ((char *)data, 0, n * sizeof (_SLang_Struct_Type *));
++
++ i = n;
++ while (i &gt; 0)
++ {
++ _SLang_Struct_Type *s;
++ _SLstruct_Field_Type *f;
++
++ i--;
++
++ if (NULL == (s = allocate_struct (1)))
++ goto return_error;
++
++ data[i] = s;
++ s-&gt;num_refs += 1; /* keeping a copy */
++
++ f = s-&gt;fields;
++ if (NULL == (f-&gt;name = SLang_create_slstring (&quot;value&quot;)))
++ goto return_error;
++
++ if (-1 == SLang_pop (&amp;f-&gt;obj))
++ goto return_error;
++ }
++
++ if (NULL == (at = SLang_create_array (SLANG_STRUCT_TYPE, 0,
++ (VOID_STAR) data, &amp;n, 1)))
++ goto return_error;
++
++ (void) SLang_push_array (at, 1);
++ return;
++
++ return_error:
++ for (i = 0; i &lt; n; i++)
++ {
++ _SLang_Struct_Type *s;
++
++ s = data[i];
++ if (s != NULL)
++ _SLstruct_delete_struct (s);
++ }
++
++ SLfree ((char *) data);
++}
++
++void _SLstruct_push_args (SLang_Array_Type *at)
++{
++ _SLang_Struct_Type **sp;
++ unsigned int num;
++
++ if (at-&gt;data_type != SLANG_STRUCT_TYPE)
++ {
++ SLang_Error = SL_TYPE_MISMATCH;
++ return;
++ }
++
++ sp = (_SLang_Struct_Type **) at-&gt;data;
++ num = at-&gt;num_elements;
++
++ while ((SLang_Error == 0) &amp;&amp; (num &gt; 0))
++ {
++ _SLang_Struct_Type *s;
++
++ num--;
++ if (NULL == (s = *sp++))
++ {
++ SLang_push_null ();
++ continue;
++ }
++
++ /* I should check to see if the value field is present, but... */
++ (void) _SLpush_slang_obj (&amp;s-&gt;fields-&gt;obj);
++ }
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slstruct.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/sltermin.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/sltermin.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/sltermin.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1155 @@
++/* This file contains enough terminfo reading capabilities sufficient for
++ * the slang SLtt interface.
++ */
++
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++/*
++ * The majority of the comments found in the file were taken from the
++ * term(4) man page on an SGI.
++ */
++
++/* Short integers are stored in two 8-bit bytes. The first byte contains
++ * the least significant 8 bits of the value, and the second byte contains
++ * the most significant 8 bits. (Thus, the value represented is
++ * 256*second+first.) The value -1 is represented by 0377,0377, and the
++ * value -2 is represented by 0376,0377; other negative values are illegal.
++ * The -1 generally means that a capability is missing from this terminal.
++ * The -2 means that the capability has been cancelled in the terminfo
++ * source and also is to be considered missing.
++ */
++
++static int make_integer (unsigned char *buf)
++{
++ register int lo, hi;
++ lo = (int) *buf++; hi = (int) *buf;
++ if (hi == 0377)
++ {
++ if (lo == 0377) return -1;
++ if (lo == 0376) return -2;
++ }
++ return lo + 256 * hi;
++}
++
++/*
++ * The compiled file is created from the source file descriptions of the
++ * terminals (see the -I option of infocmp) by using the terminfo compiler,
++ * tic, and read by the routine setupterm [see curses(3X).] The file is
++ * divided into six parts in the following order: the header, terminal
++ * names, boolean flags, numbers, strings, and string table.
++ *
++ * The header section begins the file. This section contains six short
++ * integers in the format described below. These integers are (1) the magic
++ * number (octal 0432); (2) the size, in bytes, of the names section; (3)
++ * the number of bytes in the boolean section; (4) the number of short
++ * integers in the numbers section; (5) the number of offsets (short
++ * integers) in the strings section; (6) the size, in bytes, of the string
++ * table.
++ */
++
++#define MAGIC 0432
++
++/* In this structure, all char * fields are malloced EXCEPT if the
++ * structure is SLTERMCAP. In that case, only terminal_names is malloced
++ * and the other fields are pointers into it.
++ */
++struct _SLterminfo_Type
++{
++#define SLTERMINFO 1
++#define SLTERMCAP 2
++ unsigned int flags;
++
++ unsigned int name_section_size;
++ char *terminal_names;
++
++ unsigned int boolean_section_size;
++ unsigned char *boolean_flags;
++
++ unsigned int num_numbers;
++ unsigned char *numbers;
++
++ unsigned int num_string_offsets;
++ unsigned char *string_offsets;
++
++ unsigned int string_table_size;
++ char *string_table;
++
++};
++
++static char *tcap_getstr (char *, SLterminfo_Type *);
++static int tcap_getnum (char *, SLterminfo_Type *);
++static int tcap_getflag (char *, SLterminfo_Type *);
++static int tcap_getent (char *, SLterminfo_Type *);
++
++static FILE *open_terminfo (char *file, SLterminfo_Type *h)
++{
++ FILE *fp;
++ unsigned char buf[12];
++
++ /* Alan Cox reported a security problem here if the application using the
++ * library is setuid. So, I need to make sure open the file as a normal
++ * user. Unfortunately, there does not appear to be a portable way of
++ * doing this, so I am going to use 'setfsgid' and 'setfsuid', which
++ * are not portable.
++ *
++ * I will also look into the use of setreuid, seteuid and setregid, setegid.
++ * FIXME: Priority=medium
++ */
++ fp = fopen (file, &quot;rb&quot;);
++ if (fp == NULL) return NULL;
++
++ if ((12 == fread ((char *) buf, 1, 12, fp) &amp;&amp; (MAGIC == make_integer (buf))))
++ {
++ h-&gt;name_section_size = make_integer (buf + 2);
++ h-&gt;boolean_section_size = make_integer (buf + 4);
++ h-&gt;num_numbers = make_integer (buf + 6);
++ h-&gt;num_string_offsets = make_integer (buf + 8);
++ h-&gt;string_table_size = make_integer (buf + 10);
++ }
++ else
++ {
++ fclose (fp);
++ fp = NULL;
++ }
++ return fp;
++}
++
++/*
++ * The terminal names section comes next. It contains the first line of the
++ * terminfo description, listing the various names for the terminal,
++ * separated by the bar ( | ) character (see term(5)). The section is
++ * terminated with an ASCII NUL character.
++ */
++
++/* returns pointer to malloced space */
++static unsigned char *read_terminfo_section (FILE *fp, unsigned int size)
++{
++ char *s;
++
++ if (NULL == (s = (char *) SLmalloc (size))) return NULL;
++ if (size != fread (s, 1, size, fp))
++ {
++ SLfree (s);
++ return NULL;
++ }
++ return (unsigned char *) s;
++}
++
++static char *read_terminal_names (FILE *fp, SLterminfo_Type *t)
++{
++ return t-&gt;terminal_names = (char *) read_terminfo_section (fp, t-&gt;name_section_size);
++}
++
++/*
++ * The boolean flags have one byte for each flag. This byte is either 0 or
++ * 1 as the flag is present or absent. The value of 2 means that the flag
++ * has been cancelled. The capabilities are in the same order as the file
++ * &lt;term.h&gt;.
++ */
++
++static unsigned char *read_boolean_flags (FILE *fp, SLterminfo_Type *t)
++{
++ /* Between the boolean section and the number section, a null byte is
++ * inserted, if necessary, to ensure that the number section begins on an
++ * even byte offset. All short integers are aligned on a short word
++ * boundary.
++ */
++
++ unsigned int size = (t-&gt;name_section_size + t-&gt;boolean_section_size) % 2;
++ size += t-&gt;boolean_section_size;
++
++ return t-&gt;boolean_flags = read_terminfo_section (fp, size);
++}
++
++/*
++ * The numbers section is similar to the boolean flags section. Each
++ * capability takes up two bytes, and is stored as a short integer. If the
++ * value represented is -1 or -2, the capability is taken to be missing.
++ */
++
++static unsigned char *read_numbers (FILE *fp, SLterminfo_Type *t)
++{
++ return t-&gt;numbers = read_terminfo_section (fp, 2 * t-&gt;num_numbers);
++}
++
++/* The strings section is also similar. Each capability is stored as a
++ * short integer, in the format above. A value of -1 or -2 means the
++ * capability is missing. Otherwise, the value is taken as an offset from
++ * the beginning of the string table. Special characters in ^X or \c
++ * notation are stored in their interpreted form, not the printing
++ * representation. Padding information ($&lt;nn&gt;) and parameter information
++ * (%x) are stored intact in uninterpreted form.
++ */
++
++static unsigned char *read_string_offsets (FILE *fp, SLterminfo_Type *t)
++{
++ return t-&gt;string_offsets = (unsigned char *) read_terminfo_section (fp, 2 * t-&gt;num_string_offsets);
++}
++
++/* The final section is the string table. It contains all the values of
++ * string capabilities referenced in the string section. Each string is
++ * null terminated.
++ */
++
++static char *read_string_table (FILE *fp, SLterminfo_Type *t)
++{
++ return t-&gt;string_table = (char *) read_terminfo_section (fp, t-&gt;string_table_size);
++}
++
++/*
++ * Compiled terminfo(4) descriptions are placed under the directory
++ * /usr/share/lib/terminfo. In order to avoid a linear search of a huge
++ * UNIX system directory, a two-level scheme is used:
++ * /usr/share/lib/terminfo/c/name where name is the name of the terminal,
++ * and c is the first character of name. Thus, att4425 can be found in the
++ * file /usr/share/lib/terminfo/a/att4425. Synonyms for the same terminal
++ * are implemented by multiple links to the same compiled file.
++ */
++
++#define MAX_TI_DIRS 7
++static char *Terminfo_Dirs [MAX_TI_DIRS] =
++{
++ NULL, /* $HOME/.terminfo */
++ NULL, /* $TERMINFO */
++ &quot;/usr/share/terminfo&quot;,
++ &quot;/usr/lib/terminfo&quot;,
++ &quot;/usr/share/lib/terminfo&quot;,
++ &quot;/etc/terminfo&quot;,
++ &quot;/usr/local/lib/terminfo&quot;
++};
++
++SLterminfo_Type *_SLtt_tigetent (char *term)
++{
++ char *tidir;
++ int i;
++ FILE *fp = NULL;
++ char file[1024];
++ static char home_ti [1024];
++ char *home;
++ SLterminfo_Type *ti;
++
++ if (
++ (term == NULL)
++#ifdef SLANG_UNTIC
++ &amp;&amp; (SLang_Untic_Terminfo_File == NULL)
++#endif
++ )
++ return NULL;
++
++ if (NULL == (ti = (SLterminfo_Type *) SLmalloc (sizeof (SLterminfo_Type))))
++ {
++ return NULL;
++ }
++
++#ifdef SLANG_UNTIC
++ if (SLang_Untic_Terminfo_File != NULL)
++ {
++ fp = open_terminfo (SLang_Untic_Terminfo_File, ti);
++ goto fp_open_label;
++ }
++ else
++#endif
++ /* If we are on a termcap based system, use termcap */
++ if (0 == tcap_getent (term, ti)) return ti;
++
++ if (NULL != (home = getenv (&quot;HOME&quot;)))
++ {
++ strncpy (home_ti, home, sizeof (home_ti) - 11);
++ home_ti [sizeof(home_ti) - 11] = 0;
++ strcat (home_ti, &quot;/.terminfo&quot;);
++ Terminfo_Dirs [0] = home_ti;
++ }
++
++ Terminfo_Dirs[1] = getenv (&quot;TERMINFO&quot;);
++ i = 0;
++ while (i &lt; MAX_TI_DIRS)
++ {
++ tidir = Terminfo_Dirs[i];
++ if ((tidir != NULL)
++ &amp;&amp; (sizeof (file) &gt; strlen (tidir) + 2 + strlen (term)))
++ {
++ sprintf (file, &quot;%s/%c/%s&quot;, tidir, *term, term);
++ if (NULL != (fp = open_terminfo (file, ti)))
++ break;
++ }
++ i++;
++ }
++#ifdef SLANG_UNTIC
++ fp_open_label:
++#endif
++
++ if (fp != NULL)
++ {
++ if (NULL != read_terminal_names (fp, ti))
++ {
++ if (NULL != read_boolean_flags (fp, ti))
++ {
++ if (NULL != read_numbers (fp, ti))
++ {
++ if (NULL != read_string_offsets (fp, ti))
++ {
++ if (NULL != read_string_table (fp, ti))
++ {
++ /* success */
++ fclose (fp);
++ ti-&gt;flags = SLTERMINFO;
++ return ti;
++ }
++ SLfree ((char *)ti-&gt;string_offsets);
++ }
++ SLfree ((char *)ti-&gt;numbers);
++ }
++ SLfree ((char *)ti-&gt;boolean_flags);
++ }
++ SLfree ((char *)ti-&gt;terminal_names);
++ }
++ fclose (fp);
++ }
++
++ SLfree ((char *)ti);
++ return NULL;
++}
++
++#ifdef SLANG_UNTIC
++# define UNTIC_COMMENT(x) ,x
++#else
++# define UNTIC_COMMENT(x)
++#endif
++
++typedef struct
++{
++ char name[3];
++ int offset;
++#ifdef SLANG_UNTIC
++ char *comment;
++#endif
++}
++Tgetstr_Map_Type;
++
++/* I need to add: K1-5, %0-5(not important), @8, &amp;8... */
++static Tgetstr_Map_Type Tgetstr_Map [] =
++{
++ {&quot;!1&quot;, 212 UNTIC_COMMENT(&quot;shifted key&quot;)},
++ {&quot;!2&quot;, 213 UNTIC_COMMENT(&quot;shifted key&quot;)},
++ {&quot;!3&quot;, 214 UNTIC_COMMENT(&quot;shifted key&quot;)},
++ {&quot;#1&quot;, 198 UNTIC_COMMENT(&quot;shifted key&quot;)},
++ {&quot;#2&quot;, 199 UNTIC_COMMENT(&quot;Key S-Home&quot;)},
++ {&quot;#3&quot;, 200 UNTIC_COMMENT(&quot;Key S-Insert&quot;)},
++ {&quot;#4&quot;, 201 UNTIC_COMMENT(&quot;Key S-Left&quot;)},
++ {&quot;%0&quot;, 177 UNTIC_COMMENT(&quot;redo key&quot;)},
++ {&quot;%1&quot;, 168 UNTIC_COMMENT(&quot;help key&quot;)},
++ {&quot;%2&quot;, 169 UNTIC_COMMENT(&quot;mark key&quot;)},
++ {&quot;%3&quot;, 170 UNTIC_COMMENT(&quot;message key&quot;)},
++ {&quot;%4&quot;, 171 UNTIC_COMMENT(&quot;move key&quot;)},
++ {&quot;%5&quot;, 172 UNTIC_COMMENT(&quot;next key&quot;)},
++ {&quot;%6&quot;, 173 UNTIC_COMMENT(&quot;open key&quot;)},
++ {&quot;%7&quot;, 174 UNTIC_COMMENT(&quot;options key&quot;)},
++ {&quot;%8&quot;, 175 UNTIC_COMMENT(&quot;previous key&quot;)},
++ {&quot;%9&quot;, 176 UNTIC_COMMENT(&quot;print key&quot;)},
++ {&quot;%a&quot;, 202 UNTIC_COMMENT(&quot;shifted key&quot;)},
++ {&quot;%b&quot;, 203 UNTIC_COMMENT(&quot;shifted key&quot;)},
++ {&quot;%c&quot;, 204 UNTIC_COMMENT(&quot;Key S-Next&quot;)},
++ {&quot;%d&quot;, 205 UNTIC_COMMENT(&quot;shifted key&quot;)},
++ {&quot;%e&quot;, 206 UNTIC_COMMENT(&quot;Key S-Previous&quot;)},
++ {&quot;%f&quot;, 207 UNTIC_COMMENT(&quot;shifted key&quot;)},
++ {&quot;%g&quot;, 208 UNTIC_COMMENT(&quot;shifted key&quot;)},
++ {&quot;%h&quot;, 209 UNTIC_COMMENT(&quot;shifted key&quot;)},
++ {&quot;%i&quot;, 210 UNTIC_COMMENT(&quot;Key S-Right&quot;)},
++ {&quot;%j&quot;, 211 UNTIC_COMMENT(&quot;shifted key&quot;)},
++ {&quot;&amp;0&quot;, 187 UNTIC_COMMENT(&quot;shifted key&quot;)},
++ {&quot;&amp;1&quot;, 178 UNTIC_COMMENT(&quot;reference key&quot;)},
++ {&quot;&amp;2&quot;, 179 UNTIC_COMMENT(&quot;refresh key&quot;)},
++ {&quot;&amp;3&quot;, 180 UNTIC_COMMENT(&quot;replace key&quot;)},
++ {&quot;&amp;4&quot;, 181 UNTIC_COMMENT(&quot;restart key&quot;)},
++ {&quot;&amp;5&quot;, 182 UNTIC_COMMENT(&quot;resume key&quot;)},
++ {&quot;&amp;6&quot;, 183 UNTIC_COMMENT(&quot;save key&quot;)},
++ {&quot;&amp;7&quot;, 184 UNTIC_COMMENT(&quot;suspend key&quot;)},
++ {&quot;&amp;8&quot;, 185 UNTIC_COMMENT(&quot;undo key&quot;)},
++ {&quot;&amp;9&quot;, 186 UNTIC_COMMENT(&quot;shifted key&quot;)},
++ {&quot;*0&quot;, 197 UNTIC_COMMENT(&quot;shifted key&quot;)},
++ {&quot;*1&quot;, 188 UNTIC_COMMENT(&quot;shifted key&quot;)},
++ {&quot;*2&quot;, 189 UNTIC_COMMENT(&quot;shifted key&quot;)},
++ {&quot;*3&quot;, 190 UNTIC_COMMENT(&quot;shifted key&quot;)},
++ {&quot;*4&quot;, 191 UNTIC_COMMENT(&quot;Key S-Delete&quot;)},
++ {&quot;*5&quot;, 192 UNTIC_COMMENT(&quot;shifted key&quot;)},
++ {&quot;*6&quot;, 193 UNTIC_COMMENT(&quot;select key&quot;)},
++ {&quot;*7&quot;, 194 UNTIC_COMMENT(&quot;Key S-End&quot;)},
++ {&quot;*8&quot;, 195 UNTIC_COMMENT(&quot;shifted key&quot;)},
++ {&quot;*9&quot;, 196 UNTIC_COMMENT(&quot;shifted key&quot;)},
++ {&quot;@0&quot;, 167 UNTIC_COMMENT(&quot;find key&quot;)},
++ {&quot;@1&quot;, 158 UNTIC_COMMENT(&quot;begin key&quot;)},
++ {&quot;@2&quot;, 159 UNTIC_COMMENT(&quot;cancel key&quot;)},
++ {&quot;@3&quot;, 160 UNTIC_COMMENT(&quot;close key&quot;)},
++ {&quot;@4&quot;, 161 UNTIC_COMMENT(&quot;command key&quot;)},
++ {&quot;@5&quot;, 162 UNTIC_COMMENT(&quot;copy key&quot;)},
++ {&quot;@6&quot;, 163 UNTIC_COMMENT(&quot;create key&quot;)},
++ {&quot;@7&quot;, 164 UNTIC_COMMENT(&quot;Key End&quot;)},
++ {&quot;@8&quot;, 165 UNTIC_COMMENT(&quot;enter/send key&quot;)},
++ {&quot;@9&quot;, 166 UNTIC_COMMENT(&quot;exit key&quot;)},
++ {&quot;AB&quot;, 360 UNTIC_COMMENT(&quot;set ANSI color background&quot;)},
++ {&quot;AF&quot;, 359 UNTIC_COMMENT(&quot;set ANSI color foreground&quot;)},
++ {&quot;AL&quot;, 110 UNTIC_COMMENT(&quot;parm_insert_line&quot;)},
++ {&quot;CC&quot;, 9 UNTIC_COMMENT(&quot;terminal settable cmd character in prototype !?&quot;)},
++ {&quot;CM&quot;, 15 UNTIC_COMMENT(&quot;memory relative cursor addressing&quot;)},
++ {&quot;CW&quot;, 277 UNTIC_COMMENT(&quot;define a window #1 from #2, #3 to #4, #5&quot;)},
++ {&quot;DC&quot;, 105 UNTIC_COMMENT(&quot;delete #1 chars&quot;)},
++ {&quot;DI&quot;, 280 UNTIC_COMMENT(&quot;dial number #1&quot;)},
++ {&quot;DK&quot;, 275 UNTIC_COMMENT(&quot;display clock at (#1,#2)&quot;)},
++ {&quot;DL&quot;, 106 UNTIC_COMMENT(&quot;parm_delete_line&quot;)},
++ {&quot;DO&quot;, 107 UNTIC_COMMENT(&quot;down #1 lines&quot;)},
++ {&quot;F1&quot;, 216 UNTIC_COMMENT(&quot;key_f11&quot;)},
++ {&quot;F2&quot;, 217 UNTIC_COMMENT(&quot;key_f12&quot;)},
++ {&quot;F3&quot;, 218 UNTIC_COMMENT(&quot;key_f13&quot;)},
++ {&quot;F4&quot;, 219 UNTIC_COMMENT(&quot;key_f14&quot;)},
++ {&quot;F5&quot;, 220 UNTIC_COMMENT(&quot;key_f15&quot;)},
++ {&quot;F6&quot;, 221 UNTIC_COMMENT(&quot;key_f16&quot;)},
++ {&quot;F7&quot;, 222 UNTIC_COMMENT(&quot;key_f17&quot;)},
++ {&quot;F8&quot;, 223 UNTIC_COMMENT(&quot;key_f18&quot;)},
++ {&quot;F9&quot;, 224 UNTIC_COMMENT(&quot;key_f19&quot;)},
++ {&quot;FA&quot;, 225 UNTIC_COMMENT(&quot;key_f20&quot;)},
++ {&quot;FB&quot;, 226 UNTIC_COMMENT(&quot;F21 function key&quot;)},
++ {&quot;FC&quot;, 227 UNTIC_COMMENT(&quot;F22 function key&quot;)},
++ {&quot;FD&quot;, 228 UNTIC_COMMENT(&quot;F23 function key&quot;)},
++ {&quot;FE&quot;, 229 UNTIC_COMMENT(&quot;F24 function key&quot;)},
++ {&quot;FF&quot;, 230 UNTIC_COMMENT(&quot;F25 function key&quot;)},
++ {&quot;FG&quot;, 231 UNTIC_COMMENT(&quot;F26 function key&quot;)},
++ {&quot;FH&quot;, 232 UNTIC_COMMENT(&quot;F27 function key&quot;)},
++ {&quot;FI&quot;, 233 UNTIC_COMMENT(&quot;F28 function key&quot;)},
++ {&quot;FJ&quot;, 234 UNTIC_COMMENT(&quot;F29 function key&quot;)},
++ {&quot;FK&quot;, 235 UNTIC_COMMENT(&quot;F30 function key&quot;)},
++ {&quot;FL&quot;, 236 UNTIC_COMMENT(&quot;F31 function key&quot;)},
++ {&quot;FM&quot;, 237 UNTIC_COMMENT(&quot;F32 function key&quot;)},
++ {&quot;FN&quot;, 238 UNTIC_COMMENT(&quot;F33 function key&quot;)},
++ {&quot;FO&quot;, 239 UNTIC_COMMENT(&quot;F34 function key&quot;)},
++ {&quot;FP&quot;, 240 UNTIC_COMMENT(&quot;F35 function key&quot;)},
++ {&quot;FQ&quot;, 241 UNTIC_COMMENT(&quot;F36 function key&quot;)},
++ {&quot;FR&quot;, 242 UNTIC_COMMENT(&quot;F37 function key&quot;)},
++ {&quot;FS&quot;, 243 UNTIC_COMMENT(&quot;F38 function key&quot;)},
++ {&quot;FT&quot;, 244 UNTIC_COMMENT(&quot;F39 function key&quot;)},
++ {&quot;FU&quot;, 245 UNTIC_COMMENT(&quot;F40 function key&quot;)},
++ {&quot;FV&quot;, 246 UNTIC_COMMENT(&quot;F41 function key&quot;)},
++ {&quot;FW&quot;, 247 UNTIC_COMMENT(&quot;F42 function key&quot;)},
++ {&quot;FX&quot;, 248 UNTIC_COMMENT(&quot;F43 function key&quot;)},
++ {&quot;FY&quot;, 249 UNTIC_COMMENT(&quot;F44 function key&quot;)},
++ {&quot;FZ&quot;, 250 UNTIC_COMMENT(&quot;F45 function key&quot;)},
++ {&quot;Fa&quot;, 251 UNTIC_COMMENT(&quot;F46 function key&quot;)},
++ {&quot;Fb&quot;, 252 UNTIC_COMMENT(&quot;F47 function key&quot;)},
++ {&quot;Fc&quot;, 253 UNTIC_COMMENT(&quot;F48 function key&quot;)},
++ {&quot;Fd&quot;, 254 UNTIC_COMMENT(&quot;F49 function key&quot;)},
++ {&quot;Fe&quot;, 255 UNTIC_COMMENT(&quot;F50 function key&quot;)},
++ {&quot;Ff&quot;, 256 UNTIC_COMMENT(&quot;F51 function key&quot;)},
++ {&quot;Fg&quot;, 257 UNTIC_COMMENT(&quot;F52 function key&quot;)},
++ {&quot;Fh&quot;, 258 UNTIC_COMMENT(&quot;F53 function key&quot;)},
++ {&quot;Fi&quot;, 259 UNTIC_COMMENT(&quot;F54 function key&quot;)},
++ {&quot;Fj&quot;, 260 UNTIC_COMMENT(&quot;F55 function key&quot;)},
++ {&quot;Fk&quot;, 261 UNTIC_COMMENT(&quot;F56 function key&quot;)},
++ {&quot;Fl&quot;, 262 UNTIC_COMMENT(&quot;F57 function key&quot;)},
++ {&quot;Fm&quot;, 263 UNTIC_COMMENT(&quot;F58 function key&quot;)},
++ {&quot;Fn&quot;, 264 UNTIC_COMMENT(&quot;F59 function key&quot;)},
++ {&quot;Fo&quot;, 265 UNTIC_COMMENT(&quot;F60 function key&quot;)},
++ {&quot;Fp&quot;, 266 UNTIC_COMMENT(&quot;F61 function key&quot;)},
++ {&quot;Fq&quot;, 267 UNTIC_COMMENT(&quot;F62 function key&quot;)},
++ {&quot;Fr&quot;, 268 UNTIC_COMMENT(&quot;F63 function key&quot;)},
++ {&quot;G1&quot;, 400 UNTIC_COMMENT(&quot;single upper right&quot;)},
++ {&quot;G2&quot;, 398 UNTIC_COMMENT(&quot;single upper left&quot;)},
++ {&quot;G3&quot;, 399 UNTIC_COMMENT(&quot;single lower left&quot;)},
++ {&quot;G4&quot;, 401 UNTIC_COMMENT(&quot;single lower right&quot;)},
++ {&quot;GC&quot;, 408 UNTIC_COMMENT(&quot;single intersection&quot;)},
++ {&quot;GD&quot;, 405 UNTIC_COMMENT(&quot;tee pointing down&quot;)},
++ {&quot;GH&quot;, 406 UNTIC_COMMENT(&quot;single horizontal line&quot;)},
++ {&quot;GL&quot;, 403 UNTIC_COMMENT(&quot;tee pointing left&quot;)},
++ {&quot;GR&quot;, 402 UNTIC_COMMENT(&quot;tee pointing right&quot;)},
++ {&quot;GU&quot;, 404 UNTIC_COMMENT(&quot;tee pointing up&quot;)},
++ {&quot;GV&quot;, 407 UNTIC_COMMENT(&quot;single vertical line&quot;)},
++ {&quot;Gm&quot;, 358 UNTIC_COMMENT(&quot;Curses should get button events&quot;)},
++ {&quot;HU&quot;, 279 UNTIC_COMMENT(&quot;hang-up phone&quot;)},
++ {&quot;IC&quot;, 108 UNTIC_COMMENT(&quot;insert #1 chars&quot;)},
++ {&quot;Ic&quot;, 299 UNTIC_COMMENT(&quot;initialize color #1 to (#2,#3,#4)&quot;)},
++ {&quot;Ip&quot;, 300 UNTIC_COMMENT(&quot;Initialize color pair #1 to fg=(#2,#3,#4), bg=(#5,#6,#7)&quot;)},
++ {&quot;K1&quot;, 139 UNTIC_COMMENT(&quot;upper left of keypad&quot;)},
++ {&quot;K2&quot;, 141 UNTIC_COMMENT(&quot;center of keypad&quot;)},
++ {&quot;K3&quot;, 140 UNTIC_COMMENT(&quot;upper right of keypad&quot;)},
++ {&quot;K4&quot;, 142 UNTIC_COMMENT(&quot;lower left of keypad&quot;)},
++ {&quot;K5&quot;, 143 UNTIC_COMMENT(&quot;lower right of keypad&quot;)},
++ {&quot;Km&quot;, 355 UNTIC_COMMENT(&quot;Mouse event has occurred&quot;)},
++ {&quot;LE&quot;, 111 UNTIC_COMMENT(&quot;move #1 chars to the left&quot;)},
++ {&quot;LF&quot;, 157 UNTIC_COMMENT(&quot;turn off soft labels&quot;)},
++ {&quot;LO&quot;, 156 UNTIC_COMMENT(&quot;turn on soft labels&quot;)},
++ {&quot;Lf&quot;, 273 UNTIC_COMMENT(&quot;label format&quot;)},
++ {&quot;MC&quot;, 270 UNTIC_COMMENT(&quot;clear right and left soft margins&quot;)},
++ {&quot;ML&quot;, 271 UNTIC_COMMENT(&quot;set left soft margin&quot;)},
++ {&quot;ML&quot;, 368 UNTIC_COMMENT(&quot;Set both left and right margins to #1, #2&quot;)},
++ {&quot;MR&quot;, 272 UNTIC_COMMENT(&quot;set right soft margin&quot;)},
++ {&quot;MT&quot;, 369 UNTIC_COMMENT(&quot;Sets both top and bottom margins to #1, #2&quot;)},
++ {&quot;Mi&quot;, 356 UNTIC_COMMENT(&quot;Mouse status information&quot;)},
++ {&quot;PA&quot;, 285 UNTIC_COMMENT(&quot;pause for 2-3 seconds&quot;)},
++ {&quot;PU&quot;, 283 UNTIC_COMMENT(&quot;select pulse dialling&quot;)},
++ {&quot;QD&quot;, 281 UNTIC_COMMENT(&quot;dial number #1 without checking&quot;)},
++ {&quot;RA&quot;, 152 UNTIC_COMMENT(&quot;turn off automatic margins&quot;)},
++ {&quot;RC&quot;, 276 UNTIC_COMMENT(&quot;remove clock&quot;)},
++ {&quot;RF&quot;, 215 UNTIC_COMMENT(&quot;send next input char (for ptys)&quot;)},
++ {&quot;RI&quot;, 112 UNTIC_COMMENT(&quot;parm_right_cursor&quot;)},
++ {&quot;RQ&quot;, 357 UNTIC_COMMENT(&quot;Request mouse position&quot;)},
++ {&quot;RX&quot;, 150 UNTIC_COMMENT(&quot;turn off xon/xoff handshaking&quot;)},
++ {&quot;S1&quot;, 378 UNTIC_COMMENT(&quot;Display PC character&quot;)},
++ {&quot;S2&quot;, 379 UNTIC_COMMENT(&quot;Enter PC character display mode&quot;)},
++ {&quot;S3&quot;, 380 UNTIC_COMMENT(&quot;Exit PC character display mode&quot;)},
++ {&quot;S4&quot;, 381 UNTIC_COMMENT(&quot;Enter PC scancode mode&quot;)},
++ {&quot;S5&quot;, 382 UNTIC_COMMENT(&quot;Exit PC scancode mode&quot;)},
++ {&quot;S6&quot;, 383 UNTIC_COMMENT(&quot;PC terminal options&quot;)},
++ {&quot;S7&quot;, 384 UNTIC_COMMENT(&quot;Escape for scancode emulation&quot;)},
++ {&quot;S8&quot;, 385 UNTIC_COMMENT(&quot;Alternate escape for scancode emulation&quot;)},
++ {&quot;SA&quot;, 151 UNTIC_COMMENT(&quot;turn on automatic margins&quot;)},
++ {&quot;SC&quot;, 274 UNTIC_COMMENT(&quot;set clock, #1 hrs #2 mins #3 secs&quot;)},
++ {&quot;SF&quot;, 109 UNTIC_COMMENT(&quot;scroll forward #1 lines&quot;)},
++ {&quot;SR&quot;, 113 UNTIC_COMMENT(&quot;scroll back #1 lines&quot;)},
++ {&quot;SX&quot;, 149 UNTIC_COMMENT(&quot;turn on xon/xoff handshaking&quot;)},
++ {&quot;Sb&quot;, 303 UNTIC_COMMENT(&quot;set background (color)&quot;)},
++ {&quot;Sf&quot;, 302 UNTIC_COMMENT(&quot;set foreground (color)&quot;)},
++ {&quot;TO&quot;, 282 UNTIC_COMMENT(&quot;select touch tone dialing&quot;)},
++ {&quot;UP&quot;, 114 UNTIC_COMMENT(&quot;up #1 lines&quot;)},
++ {&quot;WA&quot;, 286 UNTIC_COMMENT(&quot;wait for dial-tone&quot;)},
++ {&quot;WG&quot;, 278 UNTIC_COMMENT(&quot;go to window #1&quot;)},
++ {&quot;XF&quot;, 154 UNTIC_COMMENT(&quot;XOFF character&quot;)},
++ {&quot;XN&quot;, 153 UNTIC_COMMENT(&quot;XON character&quot;)},
++ {&quot;Xh&quot;, 386 UNTIC_COMMENT(&quot;Enter horizontal highlight mode&quot;)},
++ {&quot;Xl&quot;, 387 UNTIC_COMMENT(&quot;Enter left highlight mode&quot;)},
++ {&quot;Xo&quot;, 388 UNTIC_COMMENT(&quot;Enter low highlight mode&quot;)},
++ {&quot;Xr&quot;, 389 UNTIC_COMMENT(&quot;Enter right highlight mode&quot;)},
++ {&quot;Xt&quot;, 390 UNTIC_COMMENT(&quot;Enter top highlight mode&quot;)},
++ {&quot;Xv&quot;, 391 UNTIC_COMMENT(&quot;Enter vertical highlight mode&quot;)},
++ {&quot;Xy&quot;, 370 UNTIC_COMMENT(&quot;Repeat bit image cell #1 #2 times&quot;)},
++ {&quot;YZ&quot;, 377 UNTIC_COMMENT(&quot;Set page length to #1 lines&quot;)},
++ {&quot;Yv&quot;, 372 UNTIC_COMMENT(&quot;Move to beginning of same row&quot;)},
++ {&quot;Yw&quot;, 373 UNTIC_COMMENT(&quot;Give name for color #1&quot;)},
++ {&quot;Yx&quot;, 374 UNTIC_COMMENT(&quot;Define rectangualar bit image region&quot;)},
++ {&quot;Yy&quot;, 375 UNTIC_COMMENT(&quot;End a bit-image region&quot;)},
++ {&quot;Yz&quot;, 376 UNTIC_COMMENT(&quot;Change to ribbon color #1&quot;)},
++ {&quot;ZA&quot;, 304 UNTIC_COMMENT(&quot;Change number of characters per inch&quot;)},
++ {&quot;ZB&quot;, 305 UNTIC_COMMENT(&quot;Change number of lines per inch&quot;)},
++ {&quot;ZC&quot;, 306 UNTIC_COMMENT(&quot;Change horizontal resolution&quot;)},
++ {&quot;ZD&quot;, 307 UNTIC_COMMENT(&quot;Change vertical resolution&quot;)},
++ {&quot;ZE&quot;, 308 UNTIC_COMMENT(&quot;Define a character&quot;)},
++ {&quot;ZF&quot;, 309 UNTIC_COMMENT(&quot;Enter double-wide mode&quot;)},
++ {&quot;ZG&quot;, 310 UNTIC_COMMENT(&quot;Enter draft-quality mode&quot;)},
++ {&quot;ZH&quot;, 311 UNTIC_COMMENT(&quot;Enter italic mode&quot;)},
++ {&quot;ZI&quot;, 312 UNTIC_COMMENT(&quot;Start leftward carriage motion&quot;)},
++ {&quot;ZJ&quot;, 313 UNTIC_COMMENT(&quot;Start micro-motion mode&quot;)},
++ {&quot;ZK&quot;, 314 UNTIC_COMMENT(&quot;Enter NLQ mode&quot;)},
++ {&quot;ZL&quot;, 315 UNTIC_COMMENT(&quot;Wnter normal-quality mode&quot;)},
++ {&quot;ZM&quot;, 316 UNTIC_COMMENT(&quot;Enter shadow-print mode&quot;)},
++ {&quot;ZN&quot;, 317 UNTIC_COMMENT(&quot;Enter subscript mode&quot;)},
++ {&quot;ZO&quot;, 318 UNTIC_COMMENT(&quot;Enter superscript mode&quot;)},
++ {&quot;ZP&quot;, 319 UNTIC_COMMENT(&quot;Start upward carriage motion&quot;)},
++ {&quot;ZQ&quot;, 320 UNTIC_COMMENT(&quot;End double-wide mode&quot;)},
++ {&quot;ZR&quot;, 321 UNTIC_COMMENT(&quot;End italic mode&quot;)},
++ {&quot;ZS&quot;, 322 UNTIC_COMMENT(&quot;End left-motion mode&quot;)},
++ {&quot;ZT&quot;, 323 UNTIC_COMMENT(&quot;End micro-motion mode&quot;)},
++ {&quot;ZU&quot;, 324 UNTIC_COMMENT(&quot;End shadow-print mode&quot;)},
++ {&quot;ZV&quot;, 325 UNTIC_COMMENT(&quot;End subscript mode&quot;)},
++ {&quot;ZW&quot;, 326 UNTIC_COMMENT(&quot;End superscript mode&quot;)},
++ {&quot;ZX&quot;, 327 UNTIC_COMMENT(&quot;End reverse character motion&quot;)},
++ {&quot;ZY&quot;, 328 UNTIC_COMMENT(&quot;Like column_address in micro mode&quot;)},
++ {&quot;ZZ&quot;, 329 UNTIC_COMMENT(&quot;Like cursor_down in micro mode&quot;)},
++ {&quot;Za&quot;, 330 UNTIC_COMMENT(&quot;Like cursor_left in micro mode&quot;)},
++ {&quot;Zb&quot;, 331 UNTIC_COMMENT(&quot;Like cursor_right in micro mode&quot;)},
++ {&quot;Zc&quot;, 332 UNTIC_COMMENT(&quot;Like row_address in micro mode&quot;)},
++ {&quot;Zd&quot;, 333 UNTIC_COMMENT(&quot;Like cursor_up in micro mode&quot;)},
++ {&quot;Ze&quot;, 334 UNTIC_COMMENT(&quot;Match software bits to print-head pins&quot;)},
++ {&quot;Zf&quot;, 335 UNTIC_COMMENT(&quot;Like parm_down_cursor in micro mode&quot;)},
++ {&quot;Zg&quot;, 336 UNTIC_COMMENT(&quot;Like parm_left_cursor in micro mode&quot;)},
++ {&quot;Zh&quot;, 337 UNTIC_COMMENT(&quot;Like parm_right_cursor in micro mode&quot;)},
++ {&quot;Zi&quot;, 338 UNTIC_COMMENT(&quot;Like parm_up_cursor in micro mode&quot;)},
++ {&quot;Zj&quot;, 339 UNTIC_COMMENT(&quot;Select character set&quot;)},
++ {&quot;Zk&quot;, 340 UNTIC_COMMENT(&quot;Set bottom margin at current line&quot;)},
++ {&quot;Zl&quot;, 341 UNTIC_COMMENT(&quot;Set bottom margin at line #1 or #2 lines from bottom&quot;)},
++ {&quot;Zm&quot;, 342 UNTIC_COMMENT(&quot;Set left (right) margin at column #1 (#2)&quot;)},
++ {&quot;Zn&quot;, 343 UNTIC_COMMENT(&quot;Set right margin at column #1&quot;)},
++ {&quot;Zo&quot;, 344 UNTIC_COMMENT(&quot;Set top margin at current line&quot;)},
++ {&quot;Zp&quot;, 345 UNTIC_COMMENT(&quot;Set top (bottom) margin at row #1 (#2)&quot;)},
++ {&quot;Zq&quot;, 346 UNTIC_COMMENT(&quot;Start printing bit image braphics&quot;)},
++ {&quot;Zr&quot;, 347 UNTIC_COMMENT(&quot;Start character set definition&quot;)},
++ {&quot;Zs&quot;, 348 UNTIC_COMMENT(&quot;Stop printing bit image graphics&quot;)},
++ {&quot;Zt&quot;, 349 UNTIC_COMMENT(&quot;End definition of character aet&quot;)},
++ {&quot;Zu&quot;, 350 UNTIC_COMMENT(&quot;List of subscriptable characters&quot;)},
++ {&quot;Zv&quot;, 351 UNTIC_COMMENT(&quot;List of superscriptable characters&quot;)},
++ {&quot;Zw&quot;, 352 UNTIC_COMMENT(&quot;Printing any of these chars causes CR&quot;)},
++ {&quot;Zx&quot;, 353 UNTIC_COMMENT(&quot;No motion for subsequent character&quot;)},
++ {&quot;Zy&quot;, 354 UNTIC_COMMENT(&quot;List of character set names&quot;)},
++ {&quot;Zz&quot;, 371 UNTIC_COMMENT(&quot;Move to next row of the bit image&quot;)},
++ {&quot;ac&quot;, 146 UNTIC_COMMENT(&quot;acs_chars&quot;)},
++ {&quot;ae&quot;, 38 UNTIC_COMMENT(&quot;exit_alt_charset_mode&quot;)},
++ {&quot;al&quot;, 53 UNTIC_COMMENT(&quot;insert line&quot;)},
++ {&quot;as&quot;, 25 UNTIC_COMMENT(&quot;enter_alt_charset_mode&quot;)},
++ {&quot;bc&quot;, 395 UNTIC_COMMENT(&quot;move left, if not ^H&quot;)},
++ {&quot;bl&quot;, 1 UNTIC_COMMENT(&quot;audible signal (bell)&quot;)},
++ {&quot;bt&quot;, 0 UNTIC_COMMENT(&quot;back tab&quot;)},
++ {&quot;bx&quot;, 411 UNTIC_COMMENT(&quot;box chars primary set&quot;)},
++ {&quot;cb&quot;, 269 UNTIC_COMMENT(&quot;Clear to beginning of line&quot;)},
++ {&quot;cd&quot;, 7 UNTIC_COMMENT(&quot;clear to end of screen&quot;)},
++ {&quot;ce&quot;, 6 UNTIC_COMMENT(&quot;clr_eol&quot;)},
++ {&quot;ch&quot;, 8 UNTIC_COMMENT(&quot;horizontal position #1, absolute&quot;)},
++ {&quot;ci&quot;, 363 UNTIC_COMMENT(&quot;Init sequence for multiple codesets&quot;)},
++ {&quot;cl&quot;, 5 UNTIC_COMMENT(&quot;clear screen and home cursor&quot;)},
++ {&quot;cm&quot;, 10 UNTIC_COMMENT(&quot;move to row #1 columns #2&quot;)},
++ {&quot;cr&quot;, 2 UNTIC_COMMENT(&quot;carriage return&quot;)},
++ {&quot;cs&quot;, 3 UNTIC_COMMENT(&quot;change region to line #1 to line #2&quot;)},
++ {&quot;ct&quot;, 4 UNTIC_COMMENT(&quot;clear all tab stops&quot;)},
++ {&quot;cv&quot;, 127 UNTIC_COMMENT(&quot;vertical position #1 absolute&quot;)},
++ {&quot;dc&quot;, 21 UNTIC_COMMENT(&quot;delete character&quot;)},
++ {&quot;dl&quot;, 22 UNTIC_COMMENT(&quot;delete line&quot;)},
++ {&quot;dm&quot;, 29 UNTIC_COMMENT(&quot;enter delete mode&quot;)},
++ {&quot;do&quot;, 11 UNTIC_COMMENT(&quot;down one line&quot;)},
++ {&quot;ds&quot;, 23 UNTIC_COMMENT(&quot;disable status line&quot;)},
++ {&quot;dv&quot;, 362 UNTIC_COMMENT(&quot;Indicate language/codeset support&quot;)},
++ {&quot;eA&quot;, 155 UNTIC_COMMENT(&quot;enable alternate char set&quot;)},
++ {&quot;ec&quot;, 37 UNTIC_COMMENT(&quot;erase #1 characters&quot;)},
++ {&quot;ed&quot;, 41 UNTIC_COMMENT(&quot;end delete mode&quot;)},
++ {&quot;ei&quot;, 42 UNTIC_COMMENT(&quot;exit insert mode&quot;)},
++ {&quot;ff&quot;, 46 UNTIC_COMMENT(&quot;hardcopy terminal page eject&quot;)},
++ {&quot;fh&quot;, 284 UNTIC_COMMENT(&quot;flash switch hook&quot;)},
++ {&quot;fs&quot;, 47 UNTIC_COMMENT(&quot;return from status line&quot;)},
++ {&quot;hd&quot;, 24 UNTIC_COMMENT(&quot;half a line down&quot;)},
++ {&quot;ho&quot;, 12 UNTIC_COMMENT(&quot;home cursor (if no cup)&quot;)},
++ {&quot;hu&quot;, 137 UNTIC_COMMENT(&quot;half a line up&quot;)},
++ {&quot;i1&quot;, 48 UNTIC_COMMENT(&quot;initialization string&quot;)},
++ {&quot;i2&quot;, 392 UNTIC_COMMENT(&quot;secondary initialization string&quot;)},
++ {&quot;i3&quot;, 50 UNTIC_COMMENT(&quot;initialization string&quot;)},
++ {&quot;iP&quot;, 138 UNTIC_COMMENT(&quot;path name of program for initialization&quot;)},
++ {&quot;ic&quot;, 52 UNTIC_COMMENT(&quot;insert character&quot;)},
++ {&quot;if&quot;, 51 UNTIC_COMMENT(&quot;name of initialization file&quot;)},
++ {&quot;im&quot;, 31 UNTIC_COMMENT(&quot;enter insert mode&quot;)},
++ {&quot;ip&quot;, 54 UNTIC_COMMENT(&quot;insert padding after inserted character&quot;)},
++ {&quot;is&quot;, 49 UNTIC_COMMENT(&quot;initialization string&quot;)},
++ {&quot;k0&quot;, 65 UNTIC_COMMENT(&quot;F0 function key&quot;)},
++ {&quot;k1&quot;, 66 UNTIC_COMMENT(&quot;F1 function key&quot;)},
++ {&quot;k2&quot;, 68 UNTIC_COMMENT(&quot;F2 function key&quot;)},
++ {&quot;k3&quot;, 69 UNTIC_COMMENT(&quot;F3 function key&quot;)},
++ {&quot;k4&quot;, 70 UNTIC_COMMENT(&quot;F4 function key&quot;)},
++ {&quot;k5&quot;, 71 UNTIC_COMMENT(&quot;F5 function key&quot;)},
++ {&quot;k6&quot;, 72 UNTIC_COMMENT(&quot;F6 function key&quot;)},
++ {&quot;k7&quot;, 73 UNTIC_COMMENT(&quot;F7 function key&quot;)},
++ {&quot;k8&quot;, 74 UNTIC_COMMENT(&quot;F8 fucntion key&quot;)},
++ {&quot;k9&quot;, 75 UNTIC_COMMENT(&quot;F9 function key&quot;)},
++ {&quot;k;&quot;, 67 UNTIC_COMMENT(&quot;F10 function key&quot;)},
++ {&quot;kA&quot;, 78 UNTIC_COMMENT(&quot;insert-line key&quot;)},
++ {&quot;kB&quot;, 148 UNTIC_COMMENT(&quot;back-tab key&quot;)},
++ {&quot;kC&quot;, 57 UNTIC_COMMENT(&quot;clear-screen or erase key&quot;)},
++ {&quot;kD&quot;, 59 UNTIC_COMMENT(&quot;delete-character key&quot;)},
++ {&quot;kE&quot;, 63 UNTIC_COMMENT(&quot;clear-to-end-of-line key&quot;)},
++ {&quot;kF&quot;, 84 UNTIC_COMMENT(&quot;scroll-forward key&quot;)},
++ {&quot;kH&quot;, 80 UNTIC_COMMENT(&quot;last-line key&quot;)},
++ {&quot;kI&quot;, 77 UNTIC_COMMENT(&quot;insert-character key&quot;)},
++ {&quot;kL&quot;, 60 UNTIC_COMMENT(&quot;delete-line key&quot;)},
++ {&quot;kM&quot;, 62 UNTIC_COMMENT(&quot;sent by rmir or smir in insert mode&quot;)},
++ {&quot;kN&quot;, 81 UNTIC_COMMENT(&quot;next-page key&quot;)},
++ {&quot;kP&quot;, 82 UNTIC_COMMENT(&quot;prev-page key&quot;)},
++ {&quot;kR&quot;, 85 UNTIC_COMMENT(&quot;scroll-backward key&quot;)},
++ {&quot;kS&quot;, 64 UNTIC_COMMENT(&quot;clear-to-end-of-screen key&quot;)},
++ {&quot;kT&quot;, 86 UNTIC_COMMENT(&quot;set-tab key&quot;)},
++ {&quot;ka&quot;, 56 UNTIC_COMMENT(&quot;clear-all-tabs key&quot;)},
++ {&quot;kb&quot;, 55 UNTIC_COMMENT(&quot;backspace key&quot;)},
++ {&quot;kd&quot;, 61 UNTIC_COMMENT(&quot;down-arrow key&quot;)},
++ {&quot;ke&quot;, 88 UNTIC_COMMENT(&quot;leave 'keyboard_transmit' mode&quot;)},
++ {&quot;kh&quot;, 76 UNTIC_COMMENT(&quot;home key&quot;)},
++ {&quot;kl&quot;, 79 UNTIC_COMMENT(&quot;left-arrow key&quot;)},
++ {&quot;ko&quot;, 396 UNTIC_COMMENT(&quot;list of self-mapped keycaps&quot;)},
++ {&quot;kr&quot;, 83 UNTIC_COMMENT(&quot;right-arrow key&quot;)},
++ {&quot;ks&quot;, 89 UNTIC_COMMENT(&quot;enter 'keyboard_transmit' mode&quot;)},
++ {&quot;kt&quot;, 58 UNTIC_COMMENT(&quot;clear-tab key&quot;)},
++ {&quot;ku&quot;, 87 UNTIC_COMMENT(&quot;up-arrow key&quot;)},
++ {&quot;l0&quot;, 90 UNTIC_COMMENT(&quot;label on function key f0 if not f0&quot;)},
++ {&quot;l1&quot;, 91 UNTIC_COMMENT(&quot;label on function key f1 if not f1&quot;)},
++ {&quot;l2&quot;, 93 UNTIC_COMMENT(&quot;label on function key f2 if not f2&quot;)},
++ {&quot;l3&quot;, 94 UNTIC_COMMENT(&quot;label on function key f3 if not f3&quot;)},
++ {&quot;l4&quot;, 95 UNTIC_COMMENT(&quot;label on function key f4 if not f4&quot;)},
++ {&quot;l5&quot;, 96 UNTIC_COMMENT(&quot;lable on function key f5 if not f5&quot;)},
++ {&quot;l6&quot;, 97 UNTIC_COMMENT(&quot;label on function key f6 if not f6&quot;)},
++ {&quot;l7&quot;, 98 UNTIC_COMMENT(&quot;label on function key f7 if not f7&quot;)},
++ {&quot;l8&quot;, 99 UNTIC_COMMENT(&quot;label on function key f8 if not f8&quot;)},
++ {&quot;l9&quot;, 100 UNTIC_COMMENT(&quot;label on function key f9 if not f9&quot;)},
++ {&quot;la&quot;, 92 UNTIC_COMMENT(&quot;label on function key f10 if not f10&quot;)},
++ {&quot;le&quot;, 14 UNTIC_COMMENT(&quot;move left one space&quot;)},
++ {&quot;ll&quot;, 18 UNTIC_COMMENT(&quot;last line, first column (if no cup)&quot;)},
++ {&quot;ma&quot;, 397 UNTIC_COMMENT(&quot;map arrow keys rogue(1) motion keys&quot;)},
++ {&quot;mb&quot;, 26 UNTIC_COMMENT(&quot;turn on blinking&quot;)},
++ {&quot;md&quot;, 27 UNTIC_COMMENT(&quot;turn on bold (extra bright) mode&quot;)},
++ {&quot;me&quot;, 39 UNTIC_COMMENT(&quot;turn off all attributes&quot;)},
++ {&quot;mh&quot;, 30 UNTIC_COMMENT(&quot;turn on half-bright mode&quot;)},
++ {&quot;mk&quot;, 32 UNTIC_COMMENT(&quot;turn on blank mode (characters invisible)&quot;)},
++ {&quot;ml&quot;, 409 UNTIC_COMMENT(&quot;memory lock above&quot;)},
++ {&quot;mm&quot;, 102 UNTIC_COMMENT(&quot;turn on meta mode (8th-bit on)&quot;)},
++ {&quot;mo&quot;, 101 UNTIC_COMMENT(&quot;turn off meta mode&quot;)},
++ {&quot;mp&quot;, 33 UNTIC_COMMENT(&quot;turn on protected mode&quot;)},
++ {&quot;mr&quot;, 34 UNTIC_COMMENT(&quot;turn on reverse video mode&quot;)},
++ {&quot;mu&quot;, 410 UNTIC_COMMENT(&quot;memory unlock&quot;)},
++ {&quot;nd&quot;, 17 UNTIC_COMMENT(&quot;move right one space&quot;)},
++ {&quot;nl&quot;, 394 UNTIC_COMMENT(&quot;use to move down&quot;)},
++ {&quot;nw&quot;, 103 UNTIC_COMMENT(&quot;newline (behave like cr followed by lf)&quot;)},
++ {&quot;oc&quot;, 298 UNTIC_COMMENT(&quot;Set all color pairs to the original ones&quot;)},
++ {&quot;op&quot;, 297 UNTIC_COMMENT(&quot;Set default pair to its original value&quot;)},
++ {&quot;pO&quot;, 144 UNTIC_COMMENT(&quot;turn on printer for #1 bytes&quot;)},
++ {&quot;pc&quot;, 104 UNTIC_COMMENT(&quot;padding char (instead of null)&quot;)},
++ {&quot;pf&quot;, 119 UNTIC_COMMENT(&quot;turn off printer&quot;)},
++ {&quot;pk&quot;, 115 UNTIC_COMMENT(&quot;program function key #1 to type string #2&quot;)},
++ {&quot;pl&quot;, 116 UNTIC_COMMENT(&quot;program function key #1 to execute string #2&quot;)},
++ {&quot;pn&quot;, 147 UNTIC_COMMENT(&quot;program label #1 to show string #2&quot;)},
++ {&quot;po&quot;, 120 UNTIC_COMMENT(&quot;turn on printer&quot;)},
++ {&quot;ps&quot;, 118 UNTIC_COMMENT(&quot;print contents of screen&quot;)},
++ {&quot;px&quot;, 117 UNTIC_COMMENT(&quot;program function key #1 to transmit string #2&quot;)},
++ {&quot;r1&quot;, 122 UNTIC_COMMENT(&quot;reset string&quot;)},
++ {&quot;r2&quot;, 123 UNTIC_COMMENT(&quot;reset string&quot;)},
++ {&quot;r3&quot;, 124 UNTIC_COMMENT(&quot;reset string&quot;)},
++ {&quot;rP&quot;, 145 UNTIC_COMMENT(&quot;like ip but when in insert mode&quot;)},
++ {&quot;rc&quot;, 126 UNTIC_COMMENT(&quot;restore cursor to last position of sc&quot;)},
++ {&quot;rf&quot;, 125 UNTIC_COMMENT(&quot;name of reset file&quot;)},
++ {&quot;rp&quot;, 121 UNTIC_COMMENT(&quot;repeat char #1 #2 times&quot;)},
++ {&quot;rs&quot;, 393 UNTIC_COMMENT(&quot;terminal reset string&quot;)},
++ {&quot;s0&quot;, 364 UNTIC_COMMENT(&quot;Shift to code set 0 (EUC set 0, ASCII)&quot;)},
++ {&quot;s1&quot;, 365 UNTIC_COMMENT(&quot;Shift to code set 1&quot;)},
++ {&quot;s2&quot;, 366 UNTIC_COMMENT(&quot;Shift to code set 2&quot;)},
++ {&quot;s3&quot;, 367 UNTIC_COMMENT(&quot;Shift to code set 3&quot;)},
++ {&quot;sa&quot;, 131 UNTIC_COMMENT(&quot;define video attributes #1-#9 (PG9)&quot;)},
++ {&quot;sc&quot;, 128 UNTIC_COMMENT(&quot;save current cursor position&quot;)},
++ {&quot;se&quot;, 43 UNTIC_COMMENT(&quot;exit standout mode&quot;)},
++ {&quot;sf&quot;, 129 UNTIC_COMMENT(&quot;scroll text up&quot;)},
++ {&quot;so&quot;, 35 UNTIC_COMMENT(&quot;begin standout mode&quot;)},
++ {&quot;sp&quot;, 301 UNTIC_COMMENT(&quot;Set current color pair to #1&quot;)},
++ {&quot;sr&quot;, 130 UNTIC_COMMENT(&quot;scroll text down&quot;)},
++ {&quot;st&quot;, 132 UNTIC_COMMENT(&quot;set a tab in every row, current columns&quot;)},
++ {&quot;ta&quot;, 134 UNTIC_COMMENT(&quot;tab to next 8-space hardware tab stop&quot;)},
++ {&quot;te&quot;, 40 UNTIC_COMMENT(&quot;strings to end programs using cup&quot;)},
++ {&quot;ti&quot;, 28 UNTIC_COMMENT(&quot;string to start programs using cup&quot;)},
++ {&quot;ts&quot;, 135 UNTIC_COMMENT(&quot;move to status line&quot;)},
++ {&quot;u0&quot;, 287 UNTIC_COMMENT(&quot;User string #0&quot;)},
++ {&quot;u1&quot;, 288 UNTIC_COMMENT(&quot;User string #1&quot;)},
++ {&quot;u2&quot;, 289 UNTIC_COMMENT(&quot;User string #2&quot;)},
++ {&quot;u3&quot;, 290 UNTIC_COMMENT(&quot;User string #3&quot;)},
++ {&quot;u4&quot;, 291 UNTIC_COMMENT(&quot;User string #4&quot;)},
++ {&quot;u5&quot;, 292 UNTIC_COMMENT(&quot;User string #5&quot;)},
++ {&quot;u6&quot;, 293 UNTIC_COMMENT(&quot;User string #6&quot;)},
++ {&quot;u7&quot;, 294 UNTIC_COMMENT(&quot;User string #7&quot;)},
++ {&quot;u8&quot;, 295 UNTIC_COMMENT(&quot;User string #8&quot;)},
++ {&quot;u9&quot;, 296 UNTIC_COMMENT(&quot;User string #9&quot;)},
++ {&quot;uc&quot;, 136 UNTIC_COMMENT(&quot;underline char and move past it&quot;)},
++ {&quot;ue&quot;, 44 UNTIC_COMMENT(&quot;exit underline mode&quot;)},
++ {&quot;up&quot;, 19 UNTIC_COMMENT(&quot;up one line&quot;)},
++ {&quot;us&quot;, 36 UNTIC_COMMENT(&quot;begin underline mode&quot;)},
++ {&quot;vb&quot;, 45 UNTIC_COMMENT(&quot;visible bell (may not move cursor)&quot;)},
++ {&quot;ve&quot;, 16 UNTIC_COMMENT(&quot;make cursor appear normal (undo civis/cvvis)&quot;)},
++ {&quot;vi&quot;, 13 UNTIC_COMMENT(&quot;make cursor invisible&quot;)},
++ {&quot;vs&quot;, 20 UNTIC_COMMENT(&quot;make cursor very visible&quot;)},
++ {&quot;wi&quot;, 133 UNTIC_COMMENT(&quot;current window is lines #1-#2 cols #3-#4&quot;)},
++ {&quot;xl&quot;, 361 UNTIC_COMMENT(&quot;Program function key #1 to type string #2 and show string #3&quot;)},
++ {&quot;&quot;, -1 UNTIC_COMMENT(NULL)}
++};
++
++static int compute_cap_offset (char *cap, SLterminfo_Type *t, Tgetstr_Map_Type *map, unsigned int max_ofs)
++{
++ char cha, chb;
++
++ (void) t;
++ cha = *cap++; chb = *cap;
++
++ while (*map-&gt;name != 0)
++ {
++ if ((cha == *map-&gt;name) &amp;&amp; (chb == *(map-&gt;name + 1)))
++ {
++ if (map-&gt;offset &gt;= (int) max_ofs) return -1;
++ return map-&gt;offset;
++ }
++ map++;
++ }
++ return -1;
++}
++
++char *_SLtt_tigetstr (SLterminfo_Type *t, char *cap)
++{
++ int offset;
++
++ if (t == NULL)
++ return NULL;
++
++ if (t-&gt;flags == SLTERMCAP) return tcap_getstr (cap, t);
++
++ offset = compute_cap_offset (cap, t, Tgetstr_Map, t-&gt;num_string_offsets);
++ if (offset &lt; 0) return NULL;
++ offset = make_integer (t-&gt;string_offsets + 2 * offset);
++ if (offset &lt; 0) return NULL;
++ return t-&gt;string_table + offset;
++}
++
++static Tgetstr_Map_Type Tgetnum_Map[] =
++{
++ {&quot;BT&quot;, 30 UNTIC_COMMENT(&quot;number of buttons on mouse&quot;)},
++ {&quot;Co&quot;, 13 UNTIC_COMMENT(&quot;maximum numbers of colors on screen&quot;)},
++ {&quot;MW&quot;, 12 UNTIC_COMMENT(&quot;maxumum number of defineable windows&quot;)},
++ {&quot;NC&quot;, 15 UNTIC_COMMENT(&quot;video attributes that can't be used with colors&quot;)},
++ {&quot;Nl&quot;, 8 UNTIC_COMMENT(&quot;number of labels on screen&quot;)},
++ {&quot;Ya&quot;, 16 UNTIC_COMMENT(&quot;numbers of bytes buffered before printing&quot;)},
++ {&quot;Yb&quot;, 17 UNTIC_COMMENT(&quot;spacing of pins vertically in pins per inch&quot;)},
++ {&quot;Yc&quot;, 18 UNTIC_COMMENT(&quot;spacing of dots horizontally in dots per inch&quot;)},
++ {&quot;Yd&quot;, 19 UNTIC_COMMENT(&quot;maximum value in micro_..._address&quot;)},
++ {&quot;Ye&quot;, 20 UNTIC_COMMENT(&quot;maximum value in parm_..._micro&quot;)},
++ {&quot;Yf&quot;, 21 UNTIC_COMMENT(&quot;character size when in micro mode&quot;)},
++ {&quot;Yg&quot;, 22 UNTIC_COMMENT(&quot;line size when in micro mode&quot;)},
++ {&quot;Yh&quot;, 23 UNTIC_COMMENT(&quot;numbers of pins in print-head&quot;)},
++ {&quot;Yi&quot;, 24 UNTIC_COMMENT(&quot;horizontal resolution in units per line&quot;)},
++ {&quot;Yj&quot;, 25 UNTIC_COMMENT(&quot;vertical resolution in units per line&quot;)},
++ {&quot;Yk&quot;, 26 UNTIC_COMMENT(&quot;horizontal resolution in units per inch&quot;)},
++ {&quot;Yl&quot;, 27 UNTIC_COMMENT(&quot;vertical resolution in units per inch&quot;)},
++ {&quot;Ym&quot;, 28 UNTIC_COMMENT(&quot;print rate in chars per second&quot;)},
++ {&quot;Yn&quot;, 29 UNTIC_COMMENT(&quot;character step size when in double wide mode&quot;)},
++ {&quot;Yo&quot;, 31 UNTIC_COMMENT(&quot;number of passed for each bit-image row&quot;)},
++ {&quot;Yp&quot;, 32 UNTIC_COMMENT(&quot;type of bit-image device&quot;)},
++ {&quot;co&quot;, 0 UNTIC_COMMENT(&quot;number of columns in aline&quot;)},
++ {&quot;dB&quot;, 36 UNTIC_COMMENT(&quot;padding required for ^H&quot;)},
++ {&quot;dC&quot;, 34 UNTIC_COMMENT(&quot;pad needed for CR&quot;)},
++ {&quot;dN&quot;, 35 UNTIC_COMMENT(&quot;pad needed for LF&quot;)},
++ {&quot;dT&quot;, 37 UNTIC_COMMENT(&quot;padding required for ^I&quot;)},
++ {&quot;it&quot;, 1 UNTIC_COMMENT(&quot;tabs initially every # spaces&quot;)},
++ {&quot;kn&quot;, 38 UNTIC_COMMENT(&quot;count of function keys&quot;)},
++ {&quot;lh&quot;, 9 UNTIC_COMMENT(&quot;rows in each label&quot;)},
++ {&quot;li&quot;, 2 UNTIC_COMMENT(&quot;number of lines on screen or page&quot;)},
++ {&quot;lm&quot;, 3 UNTIC_COMMENT(&quot;lines of memory if &gt; line. 0 =&gt; varies&quot;)},
++ {&quot;lw&quot;, 10 UNTIC_COMMENT(&quot;columns in each label&quot;)},
++ {&quot;ma&quot;, 11 UNTIC_COMMENT(&quot;maximum combined attributes terminal can handle&quot;)},
++ {&quot;pa&quot;, 14 UNTIC_COMMENT(&quot;maximum number of color-pairs on the screen&quot;)},
++ {&quot;pb&quot;, 5 UNTIC_COMMENT(&quot;lowest baud rate where padding needed&quot;)},
++ {&quot;sg&quot;, 4 UNTIC_COMMENT(&quot;number of blank chars left by smso or rmso&quot;)},
++ {&quot;ug&quot;, 33 UNTIC_COMMENT(&quot;number of blanks left by ul&quot;)},
++ {&quot;vt&quot;, 6 UNTIC_COMMENT(&quot;virtual terminal number (CB/unix)&quot;)},
++ {&quot;ws&quot;, 7 UNTIC_COMMENT(&quot;columns in status line&quot;)},
++ {&quot;&quot;, -1 UNTIC_COMMENT(NULL)}
++};
++
++int _SLtt_tigetnum (SLterminfo_Type *t, char *cap)
++{
++ int offset;
++
++ if (t == NULL)
++ return -1;
++
++ if (t-&gt;flags == SLTERMCAP) return tcap_getnum (cap, t);
++
++ offset = compute_cap_offset (cap, t, Tgetnum_Map, t-&gt;num_numbers);
++ if (offset &lt; 0) return -1;
++ return make_integer (t-&gt;numbers + 2 * offset);
++}
++
++static Tgetstr_Map_Type Tgetflag_Map[] =
++{
++ {&quot;5i&quot;, 22 UNTIC_COMMENT(&quot;printer won't echo on screen&quot;)},
++ {&quot;HC&quot;, 23 UNTIC_COMMENT(&quot;cursor is hard to see&quot;)},
++ {&quot;MT&quot;, 40 UNTIC_COMMENT(&quot;has meta key&quot;)},
++ {&quot;ND&quot;, 26 UNTIC_COMMENT(&quot;scrolling region is non-destructive&quot;)},
++ {&quot;NL&quot;, 41 UNTIC_COMMENT(&quot;move down with \n&quot;)},
++ {&quot;NP&quot;, 25 UNTIC_COMMENT(&quot;pad character does not exist&quot;)},
++ {&quot;NR&quot;, 24 UNTIC_COMMENT(&quot;smcup does not reverse rmcup&quot;)},
++ {&quot;YA&quot;, 30 UNTIC_COMMENT(&quot;only positive motion for hpa/mhpa caps&quot;)},
++ {&quot;YB&quot;, 31 UNTIC_COMMENT(&quot;using cr turns off micro mode&quot;)},
++ {&quot;YC&quot;, 32 UNTIC_COMMENT(&quot;printer needs operator to change character set&quot;)},
++ {&quot;YD&quot;, 33 UNTIC_COMMENT(&quot;only positive motion for vpa/mvpa caps&quot;)},
++ {&quot;YE&quot;, 34 UNTIC_COMMENT(&quot;printing in last column causes cr&quot;)},
++ {&quot;YF&quot;, 35 UNTIC_COMMENT(&quot;changing character pitch changes resolution&quot;)},
++ {&quot;YG&quot;, 36 UNTIC_COMMENT(&quot;changing line pitch changes resolution&quot;)},
++ {&quot;am&quot;, 1 UNTIC_COMMENT(&quot;terminal has automatic margins&quot;)},
++ {&quot;bs&quot;, 37 UNTIC_COMMENT(&quot;uses ^H to move left&quot;)},
++ {&quot;bw&quot;, 0 UNTIC_COMMENT(&quot;cub1 wraps from column 0 to last column&quot;)},
++ {&quot;cc&quot;, 27 UNTIC_COMMENT(&quot;terminal can re-define existing colors&quot;)},
++ {&quot;da&quot;, 11 UNTIC_COMMENT(&quot;display may be retained above the screen&quot;)},
++ {&quot;db&quot;, 12 UNTIC_COMMENT(&quot;display may be retained below the screen&quot;)},
++ {&quot;eo&quot;, 5 UNTIC_COMMENT(&quot;can erase overstrikes with a blank&quot;)},
++ {&quot;es&quot;, 16 UNTIC_COMMENT(&quot;escape can be used on the status line&quot;)},
++ {&quot;gn&quot;, 6 UNTIC_COMMENT(&quot;generic line type&quot;)},
++ {&quot;hc&quot;, 7 UNTIC_COMMENT(&quot;hardcopy terminal&quot;)},
++ {&quot;hl&quot;, 29 UNTIC_COMMENT(&quot;terminal uses only HLS color notation (tektronix)&quot;)},
++ {&quot;hs&quot;, 9 UNTIC_COMMENT(&quot;has extra status line&quot;)},
++ {&quot;hz&quot;, 18 UNTIC_COMMENT(&quot;can't print ~'s (hazeltine)&quot;)},
++ {&quot;in&quot;, 10 UNTIC_COMMENT(&quot;insert mode distinguishes nulls&quot;)},
++ {&quot;km&quot;, 8 UNTIC_COMMENT(&quot;Has a meta key, sets msb high&quot;)},
++ {&quot;mi&quot;, 13 UNTIC_COMMENT(&quot;safe to move while in insert mode&quot;)},
++ {&quot;ms&quot;, 14 UNTIC_COMMENT(&quot;safe to move while in standout mode&quot;)},
++ {&quot;nc&quot;, 39 UNTIC_COMMENT(&quot;no way to go to start of line&quot;)},
++ {&quot;ns&quot;, 38 UNTIC_COMMENT(&quot;crt cannot scroll&quot;)},
++ {&quot;nx&quot;, 21 UNTIC_COMMENT(&quot;padding won't work, xon/xoff required&quot;)},
++ {&quot;os&quot;, 15 UNTIC_COMMENT(&quot;terminal can overstrike&quot;)},
++ {&quot;pt&quot;, 42 UNTIC_COMMENT(&quot;has 8-char tabs invoked with ^I&quot;)},
++ {&quot;ul&quot;, 19 UNTIC_COMMENT(&quot;underline character overstrikes&quot;)},
++ {&quot;ut&quot;, 28 UNTIC_COMMENT(&quot;screen erased with background color&quot;)},
++ {&quot;xb&quot;, 2 UNTIC_COMMENT(&quot;beehive (f1=escape, f2=ctrl C)&quot;)},
++ {&quot;xn&quot;, 4 UNTIC_COMMENT(&quot;newline ignored after 80 cols (concept)&quot;)},
++ {&quot;xo&quot;, 20 UNTIC_COMMENT(&quot;terminal uses xon/xoff handshaking&quot;)},
++ {&quot;xr&quot;, 43 UNTIC_COMMENT(&quot;return clears the line&quot;)},
++ {&quot;xs&quot;, 3 UNTIC_COMMENT(&quot;standout not erased by overwriting (hp)&quot;)},
++ {&quot;xt&quot;, 17 UNTIC_COMMENT(&quot;tabs destructive, magic so char (t1061)&quot;)},
++ {&quot;&quot;, -1 UNTIC_COMMENT(NULL)}
++};
++
++int _SLtt_tigetflag (SLterminfo_Type *t, char *cap)
++{
++ int offset;
++
++ if (t == NULL) return -1;
++
++ if (t-&gt;flags == SLTERMCAP) return tcap_getflag (cap, t);
++
++ offset = compute_cap_offset (cap, t, Tgetflag_Map, t-&gt;boolean_section_size);
++
++ if (offset &lt; 0) return -1;
++ return (int) *(t-&gt;boolean_flags + offset);
++}
++
++/* These are my termcap routines. They only work with the TERMCAP environment
++ * variable. This variable must contain the termcap entry and NOT the file.
++ */
++
++static int tcap_getflag (char *cap, SLterminfo_Type *t)
++{
++ char a, b;
++ char *f = (char *) t-&gt;boolean_flags;
++ char *fmax;
++
++ if (f == NULL) return 0;
++ fmax = f + t-&gt;boolean_section_size;
++
++ a = *cap;
++ b = *(cap + 1);
++ while (f &lt; fmax)
++ {
++ if ((a == f[0]) &amp;&amp; (b == f[1]))
++ return 1;
++ f += 2;
++ }
++ return 0;
++}
++
++static char *tcap_get_cap (unsigned char *cap, unsigned char *caps, unsigned int len)
++{
++ unsigned char c0, c1;
++ unsigned char *caps_max;
++
++ c0 = cap[0];
++ c1 = cap[1];
++
++ if (caps == NULL) return NULL;
++ caps_max = caps + len;
++ while (caps &lt; caps_max)
++ {
++ if ((c0 == caps[0]) &amp;&amp; (c1 == caps[1]))
++ {
++ return (char *) caps + 3;
++ }
++ caps += (int) caps[2];
++ }
++ return NULL;
++}
++
++static int tcap_getnum (char *cap, SLterminfo_Type *t)
++{
++ cap = tcap_get_cap ((unsigned char *) cap, t-&gt;numbers, t-&gt;num_numbers);
++ if (cap == NULL) return -1;
++ return atoi (cap);
++}
++
++static char *tcap_getstr (char *cap, SLterminfo_Type *t)
++{
++ return tcap_get_cap ((unsigned char *) cap, (unsigned char *) t-&gt;string_table, t-&gt;string_table_size);
++}
++
++static int tcap_extract_field (unsigned char *t0)
++{
++ register unsigned char ch, *t = t0;
++ while (((ch = *t) != 0) &amp;&amp; (ch != ':')) t++;
++ if (ch == ':') return (int) (t - t0);
++ return -1;
++}
++
++int SLtt_Try_Termcap = 1;
++static int tcap_getent (char *term, SLterminfo_Type *ti)
++{
++ unsigned char *termcap, ch;
++ unsigned char *buf, *b;
++ unsigned char *t;
++ int len;
++
++ if (SLtt_Try_Termcap == 0) return -1;
++#if 1
++ /* XFREE86 xterm sets the TERMCAP environment variable to an invalid
++ * value. Specifically, it lacks the tc= string.
++ */
++ if (!strncmp (term, &quot;xterm&quot;, 5))
++ return -1;
++#endif
++ termcap = (unsigned char *) getenv (&quot;TERMCAP&quot;);
++ if ((termcap == NULL) || (*termcap == '/')) return -1;
++
++ /* We have a termcap so lets use it provided it does not have a reference
++ * to another terminal via tc=. In that case, use terminfo. The alternative
++ * would be to parse the termcap file which I do not want to do right now.
++ * Besides, this is a terminfo based system and if the termcap were parsed
++ * terminfo would almost never get a chance to run. In addition, the tc=
++ * thing should not occur if tset is used to set the termcap entry.
++ */
++ t = termcap;
++ while ((len = tcap_extract_field (t)) != -1)
++ {
++ if ((len &gt; 3) &amp;&amp; (t[0] == 't') &amp;&amp; (t[1] == 'c') &amp;&amp; (t[2] == '='))
++ return -1;
++ t += (len + 1);
++ }
++
++ /* malloc some extra space just in case it is needed. */
++ len = strlen ((char *) termcap) + 256;
++ if (NULL == (buf = (unsigned char *) SLmalloc ((unsigned int) len))) return -1;
++
++ b = buf;
++
++ /* The beginning of the termcap entry contains the names of the entry.
++ * It is terminated by a colon.
++ */
++
++ ti-&gt;terminal_names = (char *) b;
++ t = termcap;
++ len = tcap_extract_field (t);
++ if (len &lt; 0)
++ {
++ SLfree ((char *)buf);
++ return -1;
++ }
++ strncpy ((char *) b, (char *) t, (unsigned int) len);
++ b[len] = 0;
++ b += len + 1;
++ ti-&gt;name_section_size = len;
++
++ /* Now, we are really at the start of the termcap entries. Point the
++ * termcap variable here since we want to refer to this a number of times.
++ */
++ termcap = t + (len + 1);
++
++ /* Process strings first. */
++ ti-&gt;string_table = (char *) b;
++ t = termcap;
++ while (-1 != (len = tcap_extract_field (t)))
++ {
++ unsigned char *b1;
++ unsigned char *tmax;
++
++ /* We are looking for: XX=something */
++ if ((len &lt; 4) || (t[2] != '=') || (*t == '.'))
++ {
++ t += len + 1;
++ continue;
++ }
++ tmax = t + len;
++ b1 = b;
++
++ while (t &lt; tmax)
++ {
++ ch = *t++;
++ if ((ch == '\\') &amp;&amp; (t &lt; tmax))
++ {
++ t = (unsigned char *) _SLexpand_escaped_char ((char *) t, (char *) &amp;ch);
++ }
++ else if ((ch == '^') &amp;&amp; (t &lt; tmax))
++ {
++ ch = *t++;
++ if (ch == '?') ch = 127;
++ else ch = (ch | 0x20) - ('a' - 1);
++ }
++ *b++ = ch;
++ }
++ /* Null terminate it. */
++ *b++ = 0;
++ len = (int) (b - b1);
++ b1[2] = (unsigned char) len; /* replace the = by the length */
++ /* skip colon to next field. */
++ t++;
++ }
++ ti-&gt;string_table_size = (int) (b - (unsigned char *) ti-&gt;string_table);
++
++ /* Now process the numbers. */
++
++ t = termcap;
++ ti-&gt;numbers = b;
++ while (-1 != (len = tcap_extract_field (t)))
++ {
++ unsigned char *b1;
++ unsigned char *tmax;
++
++ /* We are looking for: XX#NUMBER */
++ if ((len &lt; 4) || (t[2] != '#') || (*t == '.'))
++ {
++ t += len + 1;
++ continue;
++ }
++ tmax = t + len;
++ b1 = b;
++
++ while (t &lt; tmax)
++ {
++ *b++ = *t++;
++ }
++ /* Null terminate it. */
++ *b++ = 0;
++ len = (int) (b - b1);
++ b1[2] = (unsigned char) len; /* replace the # by the length */
++ t++;
++ }
++ ti-&gt;num_numbers = (int) (b - ti-&gt;numbers);
++
++ /* Now process the flags. */
++ t = termcap;
++ ti-&gt;boolean_flags = b;
++ while (-1 != (len = tcap_extract_field (t)))
++ {
++ /* We are looking for: XX#NUMBER */
++ if ((len != 2) || (*t == '.') || (*t &lt;= ' '))
++ {
++ t += len + 1;
++ continue;
++ }
++ b[0] = t[0];
++ b[1] = t[1];
++ t += 3;
++ b += 2;
++ }
++ ti-&gt;boolean_section_size = (int) (b - ti-&gt;boolean_flags);
++ ti-&gt;flags = SLTERMCAP;
++ return 0;
++}
++
++
++/* These routines are provided only for backward binary compatability.
++ * They will vanish in V2.x
++ */
++char *SLtt_tigetent (char *s)
++{
++ return (char *) _SLtt_tigetent (s);
++}
++
++extern char *SLtt_tigetstr (char *s, char **p)
++{
++ if (p == NULL)
++ return NULL;
++ return _SLtt_tigetstr ((SLterminfo_Type *) *p, s);
++}
++
++extern int SLtt_tigetnum (char *s, char **p)
++{
++ if (p == NULL)
++ return -1;
++ return _SLtt_tigetnum ((SLterminfo_Type *) *p, s);
++}
++
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/sltermin.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/sltime.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/sltime.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/sltime.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,310 @@
++/* time related system calls */
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++
++#include &lt;sys/types.h&gt;
++#include &lt;time.h&gt;
++
++#if defined(__BORLANDC__)
++# include &lt;dos.h&gt;
++#endif
++#if defined(__GO32__) || defined(__WATCOMC__)
++# include &lt;dos.h&gt;
++# include &lt;bios.h&gt;
++#endif
++
++#include &lt;errno.h&gt;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++#ifdef __WIN32__
++#include &lt;windows.h&gt;
++/* Sleep is defined badly in MSVC... */
++# ifdef _MSC_VER
++# define sleep(n) _sleep((n)*1000)
++# else
++# ifdef sleep
++# undef sleep
++# endif
++# define sleep(x) if(x)Sleep((x)*1000)
++# endif
++#endif
++
++
++#if defined(IBMPC_SYSTEM)
++/* For other system (Unix and VMS), _SLusleep is in sldisply.c */
++int _SLusleep (unsigned long s)
++{
++ sleep (s/1000000L);
++ s = s % 1000000L;
++
++# if defined(__WIN32__)
++ Sleep (s/1000);
++#else
++# if defined(__IBMC__)
++ DosSleep(s/1000);
++# else
++# if defined(_MSC_VER)
++ _sleep (s/1000);
++# endif
++# endif
++#endif
++ return 0;
++}
++#endif
++
++#if defined(__IBMC__) &amp;&amp; !defined(_AIX)
++/* sleep is not a standard function in VA3. */
++unsigned int sleep (unsigned int seconds)
++{
++ DosSleep(1000L * ((long)seconds));
++ return 0;
++}
++#endif
++
++static char *ctime_cmd (unsigned long *tt)
++{
++ char *t;
++
++ t = ctime ((time_t *) tt);
++ t[24] = 0; /* knock off \n */
++ return (t);
++}
++
++static void sleep_cmd (void)
++{
++ unsigned int secs;
++#if SLANG_HAS_FLOAT
++ unsigned long usecs;
++ double x;
++
++ if (-1 == SLang_pop_double (&amp;x, NULL, NULL))
++ return;
++
++ if (x &lt; 0.0)
++ x = 0.0;
++ secs = (unsigned int) x;
++ sleep (secs);
++ x -= (double) secs;
++ usecs = (unsigned long) (1e6 * x);
++ if (usecs &gt; 0) _SLusleep (usecs);
++#else
++ if (-1 == SLang_pop_uinteger (&amp;secs))
++ return;
++ if (secs != 0) sleep (secs);
++#endif
++}
++
++static unsigned long _time_cmd (void)
++{
++ return (unsigned long) time (NULL);
++}
++
++#if defined(__GO32__)
++static char *djgpp_current_time (void) /*{{{*/
++{
++ union REGS rg;
++ unsigned int year;
++ unsigned char month, day, weekday, hour, minute, sec;
++ char days[] = &quot;SunMonTueWedThuFriSat&quot;;
++ char months[] = &quot;JanFebMarAprMayJunJulAugSepOctNovDec&quot;;
++ static char the_date[26];
++
++ rg.h.ah = 0x2A;
++#ifndef __WATCOMC__
++ int86(0x21, &amp;rg, &amp;rg);
++ year = rg.x.cx &amp; 0xFFFF;
++#else
++ int386(0x21, &amp;rg, &amp;rg);
++ year = rg.x.ecx &amp; 0xFFFF;
++#endif
++
++ month = 3 * (rg.h.dh - 1);
++ day = rg.h.dl;
++ weekday = 3 * rg.h.al;
++
++ rg.h.ah = 0x2C;
++
++#ifndef __WATCOMC__
++ int86(0x21, &amp;rg, &amp;rg);
++#else
++ int386(0x21, &amp;rg, &amp;rg);
++#endif
++
++ hour = rg.h.ch;
++ minute = rg.h.cl;
++ sec = rg.h.dh;
++
++ /* we want this form: Thu Apr 14 15:43:39 1994\n */
++ sprintf(the_date, &quot;%.3s %.3s%3d %02d:%02d:%02d %d\n&quot;,
++ days + weekday, months + month,
++ day, hour, minute, sec, year);
++ return the_date;
++}
++
++/*}}}*/
++
++#endif
++
++char *SLcurrent_time_string (void) /*{{{*/
++{
++ char *the_time;
++#ifndef __GO32__
++ time_t myclock;
++
++ myclock = time((time_t *) 0);
++ the_time = (char *) ctime(&amp;myclock);
++#else
++ the_time = djgpp_current_time ();
++#endif
++ /* returns the form Sun Sep 16 01:03:52 1985\n\0 */
++ the_time[24] = '\0';
++ return(the_time);
++}
++
++/*}}}*/
++
++static int push_tm_struct (struct tm *tms)
++{
++ char *field_names [9];
++ unsigned char field_types[9];
++ VOID_STAR field_values [9];
++ int int_values [9];
++ unsigned int i;
++
++ if (tms == NULL)
++ return SLang_push_null ();
++
++ field_names [0] = &quot;tm_sec&quot;; int_values [0] = tms-&gt;tm_sec;
++ field_names [1] = &quot;tm_min&quot;; int_values [1] = tms-&gt;tm_min;
++ field_names [2] = &quot;tm_hour&quot;; int_values [2] = tms-&gt;tm_hour;
++ field_names [3] = &quot;tm_mday&quot;; int_values [3] = tms-&gt;tm_mday;
++ field_names [4] = &quot;tm_mon&quot;; int_values [4] = tms-&gt;tm_mon;
++ field_names [5] = &quot;tm_year&quot;; int_values [5] = tms-&gt;tm_year;
++ field_names [6] = &quot;tm_wday&quot;; int_values [6] = tms-&gt;tm_wday;
++ field_names [7] = &quot;tm_yday&quot;; int_values [7] = tms-&gt;tm_yday;
++ field_names [8] = &quot;tm_isdst&quot;; int_values [8] = tms-&gt;tm_isdst;
++
++ for (i = 0; i &lt; 9; i++)
++ {
++ field_types [i] = SLANG_INT_TYPE;
++ field_values [i] = (VOID_STAR) (int_values + i);
++ }
++
++ return SLstruct_create_struct (9, field_names, field_types, field_values);
++}
++
++
++static void localtime_cmd (long *t)
++{
++ time_t tt = (time_t) *t;
++ (void) push_tm_struct (localtime (&amp;tt));
++}
++
++static void gmtime_cmd (long *t)
++{
++#ifdef HAVE_GMTIME
++ time_t tt = (time_t) *t;
++ (void) push_tm_struct (gmtime (&amp;tt));
++#else
++ localtime_cmd (t);
++#endif
++}
++
++#ifdef HAVE_TIMES
++
++# ifdef HAVE_SYS_TIMES_H
++# include &lt;sys/times.h&gt;
++# endif
++
++#include &lt;limits.h&gt;
++
++#ifdef CLK_TCK
++# define SECS_PER_TICK (1.0/(double)CLK_TCK)
++#else
++# ifdef CLOCKS_PER_SEC
++# define SECS_PER_TICK (1.0/(double)CLOCKS_PER_SEC)
++# else
++# define SECS_PER_TICK (1.0/60.0)
++# endif
++#endif
++
++static void times_cmd (void)
++{
++ double dvals[4];
++ struct tms t;
++ VOID_STAR field_values[4];
++ char *field_names[4];
++ unsigned int i;
++ unsigned char field_types[4];
++
++ (void) times (&amp;t);
++
++ field_names[0] = &quot;tms_utime&quot;; dvals[0] = (double)t.tms_utime;
++ field_names[1] = &quot;tms_stime&quot;; dvals[1] = (double)t.tms_stime;
++ field_names[2] = &quot;tms_cutime&quot;; dvals[2] = (double)t.tms_cutime;
++ field_names[3] = &quot;tms_cstime&quot;; dvals[3] = (double)t.tms_cstime;
++
++ for (i = 0; i &lt; 4; i++)
++ {
++ dvals[i] *= SECS_PER_TICK;
++ field_values[i] = (VOID_STAR) &amp;dvals[i];
++ field_types[i] = SLANG_DOUBLE_TYPE;
++ }
++ (void) SLstruct_create_struct (4, field_names, field_types, field_values);
++}
++
++static struct tms Tic_TMS;
++
++static void tic_cmd (void)
++{
++ (void) times (&amp;Tic_TMS);
++}
++
++static double toc_cmd (void)
++{
++ struct tms t;
++ double d;
++
++ (void) times (&amp;t);
++ d = ((t.tms_utime - Tic_TMS.tms_utime)
++ + (t.tms_stime - Tic_TMS.tms_stime)) * SECS_PER_TICK;
++ Tic_TMS = t;
++ return d;
++}
++
++#endif /* HAVE_TIMES */
++
++
++static SLang_Intrin_Fun_Type Time_Funs_Table [] =
++{
++ MAKE_INTRINSIC_1(&quot;ctime&quot;, ctime_cmd, SLANG_STRING_TYPE, SLANG_ULONG_TYPE),
++ MAKE_INTRINSIC_0(&quot;sleep&quot;, sleep_cmd, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_0(&quot;_time&quot;, _time_cmd, SLANG_ULONG_TYPE),
++ MAKE_INTRINSIC_0(&quot;time&quot;, SLcurrent_time_string, SLANG_STRING_TYPE),
++ MAKE_INTRINSIC_1(&quot;localtime&quot;, localtime_cmd, SLANG_VOID_TYPE, SLANG_LONG_TYPE),
++ MAKE_INTRINSIC_1(&quot;gmtime&quot;, gmtime_cmd, SLANG_VOID_TYPE, SLANG_LONG_TYPE),
++
++#ifdef HAVE_TIMES
++ MAKE_INTRINSIC_0(&quot;times&quot;, times_cmd, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_0(&quot;tic&quot;, tic_cmd, SLANG_VOID_TYPE),
++ MAKE_INTRINSIC_0(&quot;toc&quot;, toc_cmd, SLANG_DOUBLE_TYPE),
++#endif
++ SLANG_END_INTRIN_FUN_TABLE
++};
++
++int _SLang_init_sltime (void)
++{
++#ifdef HAVE_TIMES
++ (void) tic_cmd ();
++#endif
++ return SLadd_intrin_fun_table (Time_Funs_Table, NULL);
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/sltime.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/sltoken.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/sltoken.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/sltoken.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,1702 @@
++/* Copyright (c) 1998, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++#include &quot;slinclud.h&quot;
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++#define MAX_TOKEN_LEN 254
++#define MAX_FILE_LINE_LEN 256
++
++static char Empty_Line[1] = {0};
++
++static int Default_Compile_Line_Num_Info;
++static char *Input_Line = Empty_Line;
++static char *Input_Line_Pointer;
++
++static SLPreprocess_Type *This_SLpp;
++
++static SLang_Load_Type *LLT;
++
++static char *map_token_to_string (_SLang_Token_Type *tok)
++{
++ char *s;
++ static char numbuf [32];
++ unsigned char type;
++ s = NULL;
++
++ if (tok != NULL) type = tok-&gt;type;
++ else type = 0;
++
++ switch (type)
++ {
++ case 0:
++ s = &quot;??&quot;;
++ break;
++
++ case CHAR_TOKEN:
++ case SHORT_TOKEN:
++ case INT_TOKEN:
++ case LONG_TOKEN:
++ s = numbuf;
++ sprintf (s, &quot;%ld&quot;, tok-&gt;v.long_val);
++ break;
++
++ case UCHAR_TOKEN:
++ case USHORT_TOKEN:
++ case UINT_TOKEN:
++ case ULONG_TOKEN:
++ s = numbuf;
++ sprintf (s, &quot;%lu&quot;, (unsigned long)tok-&gt;v.long_val);
++ break;
++
++ case OBRACKET_TOKEN: s = &quot;[&quot;; break;
++ case CBRACKET_TOKEN: s = &quot;]&quot;; break;
++ case OPAREN_TOKEN: s = &quot;(&quot;; break;
++ case CPAREN_TOKEN: s = &quot;)&quot;; break;
++ case OBRACE_TOKEN: s = &quot;{&quot;; break;
++ case CBRACE_TOKEN: s = &quot;}&quot;; break;
++ case DEREF_TOKEN: s = &quot;@&quot;; break;
++ case POUND_TOKEN: s = &quot;#&quot;; break;
++ case COMMA_TOKEN: s = &quot;,&quot;; break;
++ case SEMICOLON_TOKEN: s = &quot;;&quot;; break;
++ case COLON_TOKEN: s = &quot;:&quot;; break;
++
++#if SLANG_HAS_FLOAT
++ case FLOAT_TOKEN:
++ case DOUBLE_TOKEN:
++ case COMPLEX_TOKEN:
++#endif
++ case IDENT_TOKEN:
++ if ((tok-&gt;free_sval_flag == 0) || (tok-&gt;num_refs == 0))
++ break;
++ /* drop */
++ default:
++ s = tok-&gt;v.s_val;
++ break;
++ }
++
++ if (s == NULL)
++ {
++ s = numbuf;
++ sprintf (s, &quot;(0x%02X)&quot;, type);
++ }
++
++ return s;
++}
++
++static char *make_line_file_error (char *buf, unsigned int buflen,
++ _SLang_Token_Type *tok, char *dsc, int line, char *file)
++{
++#if _SLANG_HAS_DEBUG_CODE
++ if (tok != NULL) line = tok-&gt;line_number;
++#endif
++ if (file == NULL) file = &quot;??&quot;;
++
++ (void) _SLsnprintf (buf, buflen, &quot;%s: found '%s', line %d, file: %s&quot;,
++ dsc, map_token_to_string (tok), line, file);
++
++ return buf;
++}
++
++void _SLparse_error(char *str, _SLang_Token_Type *tok, int flag)
++{
++ char buf [1024];
++
++ if (str == NULL)
++ str = &quot;Parse Error&quot;;
++
++ make_line_file_error (buf, sizeof (buf), tok, str, LLT-&gt;line_num, (char *) LLT-&gt;name);
++
++ if ((flag == 0) &amp;&amp; SLang_Error)
++ return;
++
++ SLang_verror (SL_SYNTAX_ERROR, &quot;%s&quot;, buf);
++}
++
++static void do_line_file_error (int line, char *file)
++{
++ SLang_verror (SL_SYNTAX_ERROR,
++ &quot;called from line %d, file: %s&quot;, line, file);
++}
++
++#define ALPHA_CHAR 1
++#define DIGIT_CHAR 2
++#define EXCL_CHAR 3
++#define SEP_CHAR 4
++#define OP_CHAR 5
++#define DOT_CHAR 6
++#define BOLDOT_CHAR 7
++#define DQUOTE_CHAR 8
++#define QUOTE_CHAR 9
++#define COMMENT_CHAR 10
++#define NL_CHAR 11
++#define BAD_CHAR 12
++#define WHITE_CHAR 13
++
++#define CHAR_EOF 255
++
++#define CHAR_CLASS(c) (Char_Type_Table[(c)][0])
++#define CHAR_DATA(c) (Char_Type_Table[(c)][1])
++
++/* In this table, if a single character can represent an operator, e.g.,
++ * '&amp;' (BAND_TOKEN), then it must be placed before multiple-character
++ * operators that begin with the same character, e.g., &quot;&amp;=&quot;. See
++ * get_op_token to see how this is exploited.
++ *
++ * The third character null terminates the operator string. This is for
++ * the token structure.
++ */
++static char Operators [29][4] =
++{
++#define OFS_EXCL 0
++ {'!', '=', 0, NE_TOKEN},
++#define OFS_POUND 1
++ {'#', 0, 0, POUND_TOKEN},
++#define OFS_BAND 2
++ {'&amp;', 0, 0, BAND_TOKEN},
++ {'&amp;', '&amp;', 0, EOF_TOKEN},
++ {'&amp;', '=', 0, BANDEQS_TOKEN},
++#define OFS_STAR 5
++ {'*', 0, 0, TIMES_TOKEN},
++ {'*', '=', 0, TIMESEQS_TOKEN},
++#define OFS_PLUS 7
++ {'+', 0, 0, ADD_TOKEN},
++ {'+', '+', 0, PLUSPLUS_TOKEN},
++ {'+', '=', 0, PLUSEQS_TOKEN},
++#define OFS_MINUS 10
++ {'-', 0, 0, SUB_TOKEN},
++ {'-', '-', 0, MINUSMINUS_TOKEN},
++ {'-', '=', 0, MINUSEQS_TOKEN},
++ {'-', '&gt;', 0, NAMESPACE_TOKEN},
++#define OFS_DIV 14
++ {'/', 0, 0, DIV_TOKEN},
++ {'/', '=', 0, DIVEQS_TOKEN},
++#define OFS_LT 16
++ {'&lt;', 0, 0, LT_TOKEN},
++ {'&lt;', '=', 0, LE_TOKEN},
++#define OFS_EQS 18
++ {'=', 0, 0, ASSIGN_TOKEN},
++ {'=', '=', 0, EQ_TOKEN},
++#define OFS_GT 20
++ {'&gt;', 0, 0, GT_TOKEN},
++ {'&gt;', '=', 0, GE_TOKEN},
++#define OFS_AT 22
++ {'@', 0, 0, DEREF_TOKEN},
++#define OFS_POW 23
++ {'^', 0, 0, POW_TOKEN},
++#define OFS_BOR 24
++ {'|', 0, 0, BOR_TOKEN},
++ {'|', '|', 0, EOF_TOKEN},
++ {'|', '=', 0, BOREQS_TOKEN},
++#define OFS_BNOT 27
++ {'~', 0, 0, BNOT_TOKEN},
++ { 0, 0, 0, EOF_TOKEN}
++};
++
++static unsigned char Char_Type_Table[256][2] =
++{
++ { NL_CHAR, 0 }, /* 0x0 */ { BAD_CHAR, 0 }, /* 0x1 */
++ { BAD_CHAR, 0 }, /* 0x2 */ { BAD_CHAR, 0 }, /* 0x3 */
++ { BAD_CHAR, 0 }, /* 0x4 */ { BAD_CHAR, 0 }, /* 0x5 */
++ { BAD_CHAR, 0 }, /* 0x6 */ { BAD_CHAR, 0 }, /* 0x7 */
++ { WHITE_CHAR, 0 }, /* 0x8 */ { WHITE_CHAR, 0 }, /* 0x9 */
++ { NL_CHAR, 0 }, /* \n */ { WHITE_CHAR, 0 }, /* 0xb */
++ { WHITE_CHAR, 0 }, /* 0xc */ { WHITE_CHAR, 0 }, /* \r */
++ { BAD_CHAR, 0 }, /* 0xe */ { BAD_CHAR, 0 }, /* 0xf */
++ { BAD_CHAR, 0 }, /* 0x10 */ { BAD_CHAR, 0 }, /* 0x11 */
++ { BAD_CHAR, 0 }, /* 0x12 */ { BAD_CHAR, 0 }, /* 0x13 */
++ { BAD_CHAR, 0 }, /* 0x14 */ { BAD_CHAR, 0 }, /* 0x15 */
++ { BAD_CHAR, 0 }, /* 0x16 */ { BAD_CHAR, 0 }, /* 0x17 */
++ { BAD_CHAR, 0 }, /* 0x18 */ { BAD_CHAR, 0 }, /* 0x19 */
++ { BAD_CHAR, 0 }, /* 0x1a */ { BAD_CHAR, 0 }, /* 0x1b */
++ { BAD_CHAR, 0 }, /* 0x1c */ { BAD_CHAR, 0 }, /* 0x1d */
++ { BAD_CHAR, 0 }, /* 0x1e */ { BAD_CHAR, 0 }, /* 0x1f */
++ { WHITE_CHAR, 0 }, /* 0x20 */ { EXCL_CHAR, OFS_EXCL }, /* ! */
++ { DQUOTE_CHAR, 0 }, /* &quot; */ { OP_CHAR, OFS_POUND }, /* # */
++ { ALPHA_CHAR, 0 }, /* $ */ { NL_CHAR, 0 },/* % */
++ { OP_CHAR, OFS_BAND }, /* &amp; */ { QUOTE_CHAR, 0 }, /* ' */
++ { SEP_CHAR, OPAREN_TOKEN }, /* ( */ { SEP_CHAR, CPAREN_TOKEN }, /* ) */
++ { OP_CHAR, OFS_STAR }, /* * */ { OP_CHAR, OFS_PLUS}, /* + */
++ { SEP_CHAR, COMMA_TOKEN }, /* , */ { OP_CHAR, OFS_MINUS }, /* - */
++ { DOT_CHAR, 0 }, /* . */ { OP_CHAR, OFS_DIV }, /* / */
++ { DIGIT_CHAR, 0 }, /* 0 */ { DIGIT_CHAR, 0 }, /* 1 */
++ { DIGIT_CHAR, 0 }, /* 2 */ { DIGIT_CHAR, 0 }, /* 3 */
++ { DIGIT_CHAR, 0 }, /* 4 */ { DIGIT_CHAR, 0 }, /* 5 */
++ { DIGIT_CHAR, 0 }, /* 6 */ { DIGIT_CHAR, 0 }, /* 7 */
++ { DIGIT_CHAR, 0 }, /* 8 */ { DIGIT_CHAR, 0 }, /* 9 */
++ { SEP_CHAR, COLON_TOKEN }, /* : */ { SEP_CHAR, SEMICOLON_TOKEN }, /* ; */
++ { OP_CHAR, OFS_LT }, /* &lt; */ { OP_CHAR, OFS_EQS }, /* = */
++ { OP_CHAR, OFS_GT }, /* &gt; */ { BAD_CHAR, 0 }, /* ? */
++ { OP_CHAR, OFS_AT}, /* @ */ { ALPHA_CHAR, 0 }, /* A */
++ { ALPHA_CHAR, 0 }, /* B */ { ALPHA_CHAR, 0 }, /* C */
++ { ALPHA_CHAR, 0 }, /* D */ { ALPHA_CHAR, 0 }, /* E */
++ { ALPHA_CHAR, 0 }, /* F */ { ALPHA_CHAR, 0 }, /* G */
++ { ALPHA_CHAR, 0 }, /* H */ { ALPHA_CHAR, 0 }, /* I */
++ { ALPHA_CHAR, 0 }, /* J */ { ALPHA_CHAR, 0 }, /* K */
++ { ALPHA_CHAR, 0 }, /* L */ { ALPHA_CHAR, 0 }, /* M */
++ { ALPHA_CHAR, 0 }, /* N */ { ALPHA_CHAR, 0 }, /* O */
++ { ALPHA_CHAR, 0 }, /* P */ { ALPHA_CHAR, 0 }, /* Q */
++ { ALPHA_CHAR, 0 }, /* R */ { ALPHA_CHAR, 0 }, /* S */
++ { ALPHA_CHAR, 0 }, /* T */ { ALPHA_CHAR, 0 }, /* U */
++ { ALPHA_CHAR, 0 }, /* V */ { ALPHA_CHAR, 0 }, /* W */
++ { ALPHA_CHAR, 0 }, /* X */ { ALPHA_CHAR, 0 }, /* Y */
++ { ALPHA_CHAR, 0 }, /* Z */ { SEP_CHAR, OBRACKET_TOKEN }, /* [ */
++ { BAD_CHAR, 0 }, /* \ */ { SEP_CHAR, CBRACKET_TOKEN }, /* ] */
++ { OP_CHAR, OFS_POW }, /* ^ */ { ALPHA_CHAR, 0 }, /* _ */
++ { BAD_CHAR, 0 }, /* ` */ { ALPHA_CHAR, 0 }, /* a */
++ { ALPHA_CHAR, 0 }, /* b */ { ALPHA_CHAR, 0 }, /* c */
++ { ALPHA_CHAR, 0 }, /* d */ { ALPHA_CHAR, 0 }, /* e */
++ { ALPHA_CHAR, 0 }, /* f */ { ALPHA_CHAR, 0 }, /* g */
++ { ALPHA_CHAR, 0 }, /* h */ { ALPHA_CHAR, 0 }, /* i */
++ { ALPHA_CHAR, 0 }, /* j */ { ALPHA_CHAR, 0 }, /* k */
++ { ALPHA_CHAR, 0 }, /* l */ { ALPHA_CHAR, 0 }, /* m */
++ { ALPHA_CHAR, 0 }, /* n */ { ALPHA_CHAR, 0 }, /* o */
++ { ALPHA_CHAR, 0 }, /* p */ { ALPHA_CHAR, 0 }, /* q */
++ { ALPHA_CHAR, 0 }, /* r */ { ALPHA_CHAR, 0 }, /* s */
++ { ALPHA_CHAR, 0 }, /* t */ { ALPHA_CHAR, 0 }, /* u */
++ { ALPHA_CHAR, 0 }, /* v */ { ALPHA_CHAR, 0 }, /* w */
++ { ALPHA_CHAR, 0 }, /* x */ { ALPHA_CHAR, 0 }, /* y */
++ { ALPHA_CHAR, 0 }, /* z */ { SEP_CHAR, OBRACE_TOKEN }, /* { */
++ { OP_CHAR, OFS_BOR }, /* | */ { SEP_CHAR, CBRACE_TOKEN }, /* } */
++ { OP_CHAR, OFS_BNOT }, /* ~ */ { BAD_CHAR, 0 }, /* 0x7f */
++
++ { ALPHA_CHAR, 0 }, /* &#128; */ { ALPHA_CHAR, 0 }, /* &#129; */
++ { ALPHA_CHAR, 0 }, /* &#130; */ { ALPHA_CHAR, 0 }, /* &#131; */
++ { ALPHA_CHAR, 0 }, /* &#132; */ { ALPHA_CHAR, 0 }, /*
+ */
++ { ALPHA_CHAR, 0 }, /* &#134; */ { ALPHA_CHAR, 0 }, /* &#135; */
++ { ALPHA_CHAR, 0 }, /* &#136; */ { ALPHA_CHAR, 0 }, /* &#137; */
++ { ALPHA_CHAR, 0 }, /* &#138; */ { ALPHA_CHAR, 0 }, /* &#139; */
++ { ALPHA_CHAR, 0 }, /* &#140; */ { ALPHA_CHAR, 0 }, /* &#141; */
++ { ALPHA_CHAR, 0 }, /* &#142; */ { ALPHA_CHAR, 0 }, /* &#143; */
++ { ALPHA_CHAR, 0 }, /* &#144; */ { ALPHA_CHAR, 0 }, /* &#145; */
++ { ALPHA_CHAR, 0 }, /* &#146; */ { ALPHA_CHAR, 0 }, /* &#147; */
++ { ALPHA_CHAR, 0 }, /* &#148; */ { ALPHA_CHAR, 0 }, /* &#149; */
++ { ALPHA_CHAR, 0 }, /* &#150; */ { ALPHA_CHAR, 0 }, /* &#151; */
++ { ALPHA_CHAR, 0 }, /* &#152; */ { ALPHA_CHAR, 0 }, /* &#153; */
++ { ALPHA_CHAR, 0 }, /* &#154; */ { ALPHA_CHAR, 0 }, /* &#155; */
++ { ALPHA_CHAR, 0 }, /* &#156; */ { ALPHA_CHAR, 0 }, /* &#157; */
++ { ALPHA_CHAR, 0 }, /* &#158; */ { ALPHA_CHAR, 0 }, /* &#159; */
++ { ALPHA_CHAR, 0 }, /* &#160; */ { ALPHA_CHAR, 0 }, /* &#161; */
++ { ALPHA_CHAR, 0 }, /* &#162; */ { ALPHA_CHAR, 0 }, /* &#163; */
++ { ALPHA_CHAR, 0 }, /* &#164; */ { ALPHA_CHAR, 0 }, /* &#165; */
++ { ALPHA_CHAR, 0 }, /* &#166; */ { ALPHA_CHAR, 0 }, /* &#167; */
++ { ALPHA_CHAR, 0 }, /* &#168; */ { ALPHA_CHAR, 0 }, /* &#169; */
++ { ALPHA_CHAR, 0 }, /* &#170; */ { ALPHA_CHAR, 0 }, /* &#171; */
++ { ALPHA_CHAR, 0 }, /* &#172; */ { ALPHA_CHAR, 0 }, /* &#173; */
++ { ALPHA_CHAR, 0 }, /* &#174; */ { ALPHA_CHAR, 0 }, /* &#175; */
++ { ALPHA_CHAR, 0 }, /* &#176; */ { ALPHA_CHAR, 0 }, /* &#177; */
++ { ALPHA_CHAR, 0 }, /* &#178; */ { ALPHA_CHAR, 0 }, /* &#179; */
++ { ALPHA_CHAR, 0 }, /* &#180; */ { ALPHA_CHAR, 0 }, /* &#181; */
++ { ALPHA_CHAR, 0 }, /* &#182; */ { ALPHA_CHAR, 0 }, /* &#183; */
++ { ALPHA_CHAR, 0 }, /* &#184; */ { ALPHA_CHAR, 0 }, /* &#185; */
++ { ALPHA_CHAR, 0 }, /* &#186; */ { ALPHA_CHAR, 0 }, /* &#187; */
++ { ALPHA_CHAR, 0 }, /* &#188; */ { ALPHA_CHAR, 0 }, /* &#189; */
++ { ALPHA_CHAR, 0 }, /* &#190; */ { ALPHA_CHAR, 0 }, /* &#191; */
++ { ALPHA_CHAR, 0 }, /* &#192; */ { ALPHA_CHAR, 0 }, /* &#193; */
++ { ALPHA_CHAR, 0 }, /* &#194; */ { ALPHA_CHAR, 0 }, /* &#195; */
++ { ALPHA_CHAR, 0 }, /* &#196; */ { ALPHA_CHAR, 0 }, /* &#197; */
++ { ALPHA_CHAR, 0 }, /* &#198; */ { ALPHA_CHAR, 0 }, /* &#199; */
++ { ALPHA_CHAR, 0 }, /* &#200; */ { ALPHA_CHAR, 0 }, /* &#201; */
++ { ALPHA_CHAR, 0 }, /* &#202; */ { ALPHA_CHAR, 0 }, /* &#203; */
++ { ALPHA_CHAR, 0 }, /* &#204; */ { ALPHA_CHAR, 0 }, /* &#205; */
++ { ALPHA_CHAR, 0 }, /* &#206; */ { ALPHA_CHAR, 0 }, /* &#207; */
++ { ALPHA_CHAR, 0 }, /* &#208; */ { ALPHA_CHAR, 0 }, /* &#209; */
++ { ALPHA_CHAR, 0 }, /* &#210; */ { ALPHA_CHAR, 0 }, /* &#211; */
++ { ALPHA_CHAR, 0 }, /* &#212; */ { ALPHA_CHAR, 0 }, /* &#213; */
++ { ALPHA_CHAR, 0 }, /* &#214; */ { ALPHA_CHAR, 0 }, /* &#215; */
++ { ALPHA_CHAR, 0 }, /* &#216; */ { ALPHA_CHAR, 0 }, /* &#217; */
++ { ALPHA_CHAR, 0 }, /* &#218; */ { ALPHA_CHAR, 0 }, /* &#219; */
++ { ALPHA_CHAR, 0 }, /* &#220; */ { ALPHA_CHAR, 0 }, /* &#221; */
++ { ALPHA_CHAR, 0 }, /* &#222; */ { ALPHA_CHAR, 0 }, /* &#223; */
++ { ALPHA_CHAR, 0 }, /* &#224; */ { ALPHA_CHAR, 0 }, /* &#225; */
++ { ALPHA_CHAR, 0 }, /* &#226; */ { ALPHA_CHAR, 0 }, /* &#227; */
++ { ALPHA_CHAR, 0 }, /* &#228; */ { ALPHA_CHAR, 0 }, /* &#229; */
++ { ALPHA_CHAR, 0 }, /* &#230; */ { ALPHA_CHAR, 0 }, /* &#231; */
++ { ALPHA_CHAR, 0 }, /* &#232; */ { ALPHA_CHAR, 0 }, /* &#233; */
++ { ALPHA_CHAR, 0 }, /* &#234; */ { ALPHA_CHAR, 0 }, /* &#235; */
++ { ALPHA_CHAR, 0 }, /* &#236; */ { ALPHA_CHAR, 0 }, /* &#237; */
++ { ALPHA_CHAR, 0 }, /* &#238; */ { ALPHA_CHAR, 0 }, /* &#239; */
++ { ALPHA_CHAR, 0 }, /* &#240; */ { ALPHA_CHAR, 0 }, /* &#241; */
++ { ALPHA_CHAR, 0 }, /* &#242; */ { ALPHA_CHAR, 0 }, /* &#243; */
++ { ALPHA_CHAR, 0 }, /* &#244; */ { ALPHA_CHAR, 0 }, /* &#245; */
++ { ALPHA_CHAR, 0 }, /* &#246; */ { ALPHA_CHAR, 0 }, /* &#247; */
++ { ALPHA_CHAR, 0 }, /* &#248; */ { ALPHA_CHAR, 0 }, /* &#249; */
++ { ALPHA_CHAR, 0 }, /* &#250; */ { ALPHA_CHAR, 0 }, /* &#251; */
++ { ALPHA_CHAR, 0 }, /* &#252; */ { ALPHA_CHAR, 0 }, /* &#253; */
++ { ALPHA_CHAR, 0 }, /* &#254; */ { ALPHA_CHAR, 0 }, /* &#255; */
++};
++
++int _SLcheck_identifier_syntax (char *name)
++{
++ unsigned char *p;
++
++ p = (unsigned char *) name;
++ if (ALPHA_CHAR == Char_Type_Table[*p][0]) while (1)
++ {
++ unsigned ch;
++ unsigned char type;
++
++ ch = *++p;
++
++ type = Char_Type_Table [ch][0];
++ if ((type != ALPHA_CHAR) &amp;&amp; (type != DIGIT_CHAR))
++ {
++ if (ch == 0)
++ return 0;
++ break;
++ }
++ }
++
++ SLang_verror (SL_SYNTAX_ERROR,
++ &quot;Name %s contains an illegal character&quot;, name);
++ return -1;
++}
++
++static unsigned char prep_get_char (void)
++{
++ register unsigned char ch;
++
++ if (0 != (ch = *Input_Line_Pointer++))
++ return ch;
++
++ Input_Line_Pointer--;
++ return 0;
++}
++
++static void unget_prep_char (unsigned char ch)
++{
++ if ((Input_Line_Pointer != Input_Line)
++ &amp;&amp; (ch != 0))
++ Input_Line_Pointer--;
++ /* *Input_Line_Pointer = ch; -- Do not modify the Input_Line */
++}
++
++#include &quot;keywhash.c&quot;
++
++static int get_ident_token (_SLang_Token_Type *tok, unsigned char *s, unsigned int len)
++{
++ unsigned char ch;
++ unsigned char type;
++ Keyword_Table_Type *table;
++
++ while (1)
++ {
++ ch = prep_get_char ();
++ type = CHAR_CLASS (ch);
++ if ((type != ALPHA_CHAR) &amp;&amp; (type != DIGIT_CHAR))
++ {
++ unget_prep_char (ch);
++ break;
++ }
++ s [len++] = ch;
++ }
++
++ s[len] = 0;
++
++ /* check if keyword */
++ table = is_keyword ((char *) s, len);
++ if (table != NULL)
++ {
++ tok-&gt;v.s_val = table-&gt;name;
++ return (tok-&gt;type = table-&gt;type);
++ }
++
++ tok-&gt;v.s_val = _SLstring_make_hashed_string ((char *)s, len, &amp;tok-&gt;hash);
++ tok-&gt;free_sval_flag = 1;
++ return (tok-&gt;type = IDENT_TOKEN);
++}
++
++static int get_number_token (_SLang_Token_Type *tok, unsigned char *s, unsigned int len)
++{
++ unsigned char ch;
++ unsigned char type;
++
++ /* Look for pattern [0-9.xX]*([eE][-+]?[digits])?[ijfhul]? */
++ while (1)
++ {
++ ch = prep_get_char ();
++
++ type = CHAR_CLASS (ch);
++ if ((type != DIGIT_CHAR) &amp;&amp; (type != DOT_CHAR))
++ {
++ if ((ch != 'x') &amp;&amp; (ch != 'X'))
++ break;
++ /* It must be hex */
++ do
++ {
++ if (len == (MAX_TOKEN_LEN - 1))
++ goto too_long_return_error;
++
++ s[len++] = ch;
++ ch = prep_get_char ();
++ type = CHAR_CLASS (ch);
++ }
++ while ((type == DIGIT_CHAR) || (type == ALPHA_CHAR));
++ break;
++ }
++ if (len == (MAX_TOKEN_LEN - 1))
++ goto too_long_return_error;
++ s [len++] = ch;
++ }
++
++ /* At this point, type and ch are synchronized */
++
++ if ((ch == 'e') || (ch == 'E'))
++ {
++ if (len == (MAX_TOKEN_LEN - 1))
++ goto too_long_return_error;
++ s[len++] = ch;
++ ch = prep_get_char ();
++ if ((ch == '+') || (ch == '-'))
++ {
++ if (len == (MAX_TOKEN_LEN - 1))
++ goto too_long_return_error;
++ s[len++] = ch;
++ ch = prep_get_char ();
++ }
++
++ while (DIGIT_CHAR == (type = CHAR_CLASS(ch)))
++ {
++ if (len == (MAX_TOKEN_LEN - 1))
++ goto too_long_return_error;
++ s[len++] = ch;
++ ch = prep_get_char ();
++ }
++ }
++
++ while (ALPHA_CHAR == type)
++ {
++ if (len == (MAX_TOKEN_LEN - 1))
++ goto too_long_return_error;
++ s[len++] = ch;
++ ch = prep_get_char ();
++ type = CHAR_CLASS(ch);
++ }
++
++ unget_prep_char (ch);
++ s[len] = 0;
++
++ switch (SLang_guess_type ((char *) s))
++ {
++ default:
++ tok-&gt;v.s_val = (char *) s;
++ _SLparse_error (&quot;Not a number&quot;, tok, 0);
++ return (tok-&gt;type = EOF_TOKEN);
++
++#if SLANG_HAS_FLOAT
++ case SLANG_FLOAT_TYPE:
++ tok-&gt;v.s_val = _SLstring_make_hashed_string ((char *)s, len, &amp;tok-&gt;hash);
++ tok-&gt;free_sval_flag = 1;
++ return (tok-&gt;type = FLOAT_TOKEN);
++
++ case SLANG_DOUBLE_TYPE:
++ tok-&gt;v.s_val = _SLstring_make_hashed_string ((char *)s, len, &amp;tok-&gt;hash);
++ tok-&gt;free_sval_flag = 1;
++ return (tok-&gt;type = DOUBLE_TOKEN);
++#endif
++#if SLANG_HAS_COMPLEX
++ case SLANG_COMPLEX_TYPE:
++ tok-&gt;v.s_val = _SLstring_make_hashed_string ((char *)s, len, &amp;tok-&gt;hash);
++ tok-&gt;free_sval_flag = 1;
++ return (tok-&gt;type = COMPLEX_TOKEN);
++#endif
++ case SLANG_CHAR_TYPE:
++ tok-&gt;v.long_val = (char)SLatol (s);
++ return tok-&gt;type = CHAR_TOKEN;
++ case SLANG_UCHAR_TYPE:
++ tok-&gt;v.long_val = (unsigned char)SLatol (s);
++ return tok-&gt;type = UCHAR_TOKEN;
++ case SLANG_SHORT_TYPE:
++ tok-&gt;v.long_val = (short)SLatol (s);
++ return tok-&gt;type = SHORT_TOKEN;
++ case SLANG_USHORT_TYPE:
++ tok-&gt;v.long_val = (unsigned short)SLatoul (s);
++ return tok-&gt;type = USHORT_TOKEN;
++ case SLANG_INT_TYPE:
++ tok-&gt;v.long_val = (int)SLatol (s);
++ return tok-&gt;type = INT_TOKEN;
++ case SLANG_UINT_TYPE:
++ tok-&gt;v.long_val = (unsigned int)SLatoul (s);
++ return tok-&gt;type = UINT_TOKEN;
++ case SLANG_LONG_TYPE:
++ tok-&gt;v.long_val = SLatol (s);
++ return tok-&gt;type = LONG_TOKEN;
++ case SLANG_ULONG_TYPE:
++ tok-&gt;v.long_val = SLatoul (s);
++ return tok-&gt;type = ULONG_TOKEN;
++ }
++
++ too_long_return_error:
++ _SLparse_error (&quot;Number too long for buffer&quot;, NULL, 0);
++ return (tok-&gt;type == EOF_TOKEN);
++}
++
++static int get_op_token (_SLang_Token_Type *tok, char ch)
++{
++ unsigned int offset;
++ char second_char;
++ unsigned char type;
++ char *name;
++
++ /* operators are: + - / * ++ -- += -= = == != &gt; &lt; &gt;= &lt;= | etc..
++ * These lex to the longest valid operator token.
++ */
++
++ offset = CHAR_DATA((unsigned char) ch);
++ if (0 == Operators [offset][1])
++ {
++ name = Operators [offset];
++ type = name [3];
++ }
++ else
++ {
++ type = EOF_TOKEN;
++ name = NULL;
++ }
++
++ second_char = prep_get_char ();
++ do
++ {
++ if (second_char == Operators[offset][1])
++ {
++ name = Operators [offset];
++ type = name [3];
++ break;
++ }
++ offset++;
++ }
++ while (ch == Operators[offset][0]);
++
++ tok-&gt;type = type;
++
++ if (type == EOF_TOKEN)
++ {
++ _SLparse_error (&quot;Operator not supported&quot;, NULL, 0);
++ return type;
++ }
++
++ tok-&gt;v.s_val = name;
++
++ if (name[1] == 0)
++ unget_prep_char (second_char);
++
++ return type;
++}
++
++/* If this returns non-zero, then it is a binary string */
++static int expand_escaped_string (register char *s,
++ register char *t, register char *tmax,
++ unsigned int *lenp)
++{
++ char *s0;
++ int is_binary = 0;
++ char ch;
++
++ s0 = s;
++ while (t &lt; tmax)
++ {
++ ch = *t++;
++ if (ch == '\\')
++ {
++ t = _SLexpand_escaped_char (t, &amp;ch);
++ if (ch == 0) is_binary = 1;
++ }
++ *s++ = ch;
++ }
++ *s = 0;
++
++ *lenp = (unsigned char) (s - s0);
++ return is_binary;
++}
++
++static int get_string_token (_SLang_Token_Type *tok, unsigned char quote_char,
++ unsigned char *s)
++{
++ unsigned char ch;
++ unsigned int len = 0;
++ int has_quote = 0;
++ int is_binary;
++
++ while (1)
++ {
++ ch = prep_get_char ();
++ if (ch == 0)
++ {
++ _SLparse_error(&quot;Expecting quote-character&quot;, NULL, 0);
++ return (tok-&gt;type = EOF_TOKEN);
++ }
++ if (ch == quote_char) break;
++
++ s[len++] = ch;
++
++ if (len == (MAX_TOKEN_LEN - 1))
++ {
++ _SLparse_error (&quot;String too long for buffer&quot;, NULL, 0);
++ return (tok-&gt;type == EOF_TOKEN);
++ }
++
++ if (ch == '\\')
++ {
++ has_quote = 1;
++ ch = prep_get_char ();
++ s[len++] = ch;
++ }
++ }
++
++ s[len] = 0;
++
++ if (has_quote)
++ is_binary = expand_escaped_string ((char *) s, (char *)s, (char *)s + len, &amp;len);
++ else is_binary = 0;
++
++ if ('&quot;' == quote_char)
++ {
++ tok-&gt;free_sval_flag = 1;
++ if (is_binary)
++ {
++ tok-&gt;v.b_val = SLbstring_create (s, len);
++ return tok-&gt;type = BSTRING_TOKEN;
++ }
++ else
++ {
++ tok-&gt;v.s_val = _SLstring_make_hashed_string ((char *)s,
++ len,
++ &amp;tok-&gt;hash);
++ tok-&gt;free_sval_flag = 1;
++ return (tok-&gt;type = STRING_TOKEN);
++ }
++ }
++
++ /* else single character */
++ if (s[1] != 0)
++ {
++ _SLparse_error(&quot;Single char expected&quot;, NULL, 0);
++ return (tok-&gt;type = EOF_TOKEN);
++ }
++
++ tok-&gt;v.long_val = s[0];
++ return (tok-&gt;type = UCHAR_TOKEN);
++}
++
++static int extract_token (_SLang_Token_Type *tok, unsigned char ch, unsigned char t)
++{
++ unsigned char s [MAX_TOKEN_LEN];
++ unsigned int slen;
++
++ s[0] = (char) ch;
++ slen = 1;
++
++ switch (t)
++ {
++ case ALPHA_CHAR:
++ return get_ident_token (tok, s, slen);
++
++ case OP_CHAR:
++ return get_op_token (tok, ch);
++
++ case DIGIT_CHAR:
++ return get_number_token (tok, s, slen);
++
++ case EXCL_CHAR:
++ ch = prep_get_char ();
++ s [slen++] = ch;
++ t = CHAR_CLASS(ch);
++ if (t == ALPHA_CHAR) return get_ident_token (tok, s, slen);
++ if (t == OP_CHAR)
++ {
++ unget_prep_char (ch);
++ return get_op_token (tok, '!');
++ }
++ _SLparse_error(&quot;Misplaced !&quot;, NULL, 0);
++ return -1;
++
++ case DOT_CHAR:
++ ch = prep_get_char ();
++ if (DIGIT_CHAR == CHAR_CLASS(ch))
++ {
++ s [slen++] = ch;
++ return get_number_token (tok, s, slen);
++ }
++ unget_prep_char (ch);
++ return (tok-&gt;type = DOT_TOKEN);
++
++ case SEP_CHAR:
++ return (tok-&gt;type = CHAR_DATA(ch));
++
++ case DQUOTE_CHAR:
++ case QUOTE_CHAR:
++ return get_string_token (tok, ch, s);
++
++ default:
++ _SLparse_error(&quot;Invalid character&quot;, NULL, 0);
++ return (tok-&gt;type = EOF_TOKEN);
++ }
++}
++
++int _SLget_rpn_token (_SLang_Token_Type *tok)
++{
++ unsigned char ch;
++
++ tok-&gt;v.s_val = &quot;??&quot;;
++ while ((ch = *Input_Line_Pointer) != 0)
++ {
++ unsigned char t;
++
++ Input_Line_Pointer++;
++ if (WHITE_CHAR == (t = CHAR_CLASS(ch)))
++ continue;
++
++ if (NL_CHAR == t)
++ break;
++
++ return extract_token (tok, ch, t);
++ }
++ Input_Line_Pointer = Empty_Line;
++ return EOF_TOKEN;
++}
++
++int _SLget_token (_SLang_Token_Type *tok)
++{
++ unsigned char ch;
++ unsigned char t;
++
++ tok-&gt;num_refs = 1;
++ tok-&gt;free_sval_flag = 0;
++ tok-&gt;v.s_val = &quot;??&quot;;
++#if _SLANG_HAS_DEBUG_CODE
++ tok-&gt;line_number = LLT-&gt;line_num;
++#endif
++ if (SLang_Error || (Input_Line == NULL))
++ return (tok-&gt;type = EOF_TOKEN);
++
++ while (1)
++ {
++ ch = *Input_Line_Pointer++;
++ if (WHITE_CHAR == (t = CHAR_CLASS (ch)))
++ continue;
++
++ if (t != NL_CHAR)
++ return extract_token (tok, ch, t);
++
++ do
++ {
++ LLT-&gt;line_num++;
++#if _SLANG_HAS_DEBUG_CODE
++ tok-&gt;line_number++;
++#endif
++ Input_Line = LLT-&gt;read(LLT);
++ if ((NULL == Input_Line) || SLang_Error)
++ {
++ Input_Line_Pointer = Input_Line = NULL;
++ return (tok-&gt;type = EOF_TOKEN);
++ }
++ }
++ while (0 == SLprep_line_ok(Input_Line, This_SLpp));
++
++ Input_Line_Pointer = Input_Line;
++ if (*Input_Line_Pointer == '.')
++ {
++ Input_Line_Pointer++;
++ return tok-&gt;type = RPN_TOKEN;
++ }
++ }
++}
++
++static int prep_exists_function (char *line, char comment)
++{
++ char buf[MAX_FILE_LINE_LEN], *b, *bmax;
++ unsigned char ch;
++
++ bmax = buf + (sizeof (buf) - 1);
++
++ while (1)
++ {
++ /* skip whitespace */
++ while ((ch = (unsigned char) *line),
++ ch &amp;&amp; (ch != '\n') &amp;&amp; (ch &lt;= ' '))
++ line++;
++
++ if ((ch &lt;= '\n')
++ || (ch == (unsigned char) comment)) break;
++
++ b = buf;
++ while ((ch = (unsigned char) *line) &gt; ' ')
++ {
++ if (b &lt; bmax) *b++ = (char) ch;
++ line++;
++ }
++ *b = 0;
++
++ if (SLang_is_defined (buf))
++ return 1;
++ }
++
++ return 0;
++}
++
++static int prep_eval_expr (char *expr)
++{
++ int ret;
++
++ if (0 != SLang_load_string (expr))
++ return -1;
++ if (-1 == SLang_pop_integer (&amp;ret))
++ return -1;
++ return (ret != 0);
++}
++
++
++int SLang_load_object (SLang_Load_Type *x)
++{
++ SLPreprocess_Type this_pp;
++ SLPreprocess_Type *save_this_pp;
++ SLang_Load_Type *save_llt;
++ char *save_input_line, *save_input_line_ptr;
++#if _SLANG_HAS_DEBUG_CODE
++ int save_compile_line_num_info;
++#endif
++ int save_auto_declare_variables;
++
++ if (SLprep_exists_hook == NULL)
++ SLprep_exists_hook = prep_exists_function;
++
++ if (_SLprep_eval_hook == NULL)
++ _SLprep_eval_hook = prep_eval_expr;
++
++ if (-1 == SLprep_open_prep (&amp;this_pp)) return -1;
++
++ if (-1 == _SLcompile_push_context (x))
++ return -1;
++
++#if _SLANG_HAS_DEBUG_CODE
++ save_compile_line_num_info = _SLang_Compile_Line_Num_Info;
++#endif
++ save_this_pp = This_SLpp;
++ save_input_line = Input_Line;
++ save_input_line_ptr = Input_Line_Pointer;
++ save_llt = LLT;
++ save_auto_declare_variables = _SLang_Auto_Declare_Globals;
++
++ This_SLpp = &amp;this_pp;
++ Input_Line_Pointer = Input_Line = Empty_Line;
++ LLT = x;
++
++ x-&gt;line_num = 0;
++ x-&gt;parse_level = 0;
++ _SLang_Auto_Declare_Globals = x-&gt;auto_declare_globals;
++
++#if _SLANG_HAS_DEBUG_CODE
++ _SLang_Compile_Line_Num_Info = Default_Compile_Line_Num_Info;
++#endif
++
++ _SLparse_start (x);
++ if (SLang_Error)
++ do_line_file_error (x-&gt;line_num, x-&gt;name);
++
++ _SLang_Auto_Declare_Globals = save_auto_declare_variables;
++
++ if (SLang_Error) SLang_restart (0);
++
++ (void) _SLcompile_pop_context ();
++
++ Input_Line = save_input_line;
++ Input_Line_Pointer = save_input_line_ptr;
++ LLT = save_llt;
++ This_SLpp = save_this_pp;
++
++#if _SLANG_HAS_DEBUG_CODE
++ _SLang_Compile_Line_Num_Info = save_compile_line_num_info;
++#endif
++
++ if (SLang_Error) return -1;
++ return 0;
++}
++
++SLang_Load_Type *SLallocate_load_type (char *name)
++{
++ SLang_Load_Type *x;
++
++ if (NULL == (x = (SLang_Load_Type *)SLmalloc (sizeof (SLang_Load_Type))))
++ return NULL;
++ memset ((char *) x, 0, sizeof (SLang_Load_Type));
++
++ if (name == NULL) name = &quot;&quot;;
++
++ x-&gt;name = SLang_create_slstring (name);
++ if (x-&gt;name == NULL)
++ {
++ SLfree ((char *) x);
++ return NULL;
++ }
++ return x;
++}
++
++void SLdeallocate_load_type (SLang_Load_Type *x)
++{
++ if (x != NULL)
++ {
++ SLang_free_slstring (x-&gt;name);
++ SLfree ((char *) x);
++ }
++}
++
++typedef struct
++{
++ char *string;
++ char *ptr;
++}
++String_Client_Data_Type;
++
++static char *read_from_string (SLang_Load_Type *x)
++{
++ String_Client_Data_Type *data;
++ char *s, *s1, ch;
++
++ data = (String_Client_Data_Type *)x-&gt;client_data;
++ s1 = s = data-&gt;ptr;
++
++ if (*s == 0)
++ return NULL;
++
++ while ((ch = *s) != 0)
++ {
++ s++;
++ if (ch == '\n')
++ break;
++ }
++
++ data-&gt;ptr = s;
++ return s1;
++}
++
++int SLang_load_string (char *string)
++{
++ SLang_Load_Type *x;
++ String_Client_Data_Type data;
++ int ret;
++
++ if (string == NULL)
++ return -1;
++
++ /* Grab a private copy in case loading modifies string */
++ if (NULL == (string = SLang_create_slstring (string)))
++ return -1;
++
++ /* To avoid creating a static data space for every string loaded,
++ * all string objects will be regarded as identical. So, identify
++ * all of them by ***string***
++ */
++ if (NULL == (x = SLallocate_load_type (&quot;***string***&quot;)))
++ {
++ SLang_free_slstring (string);
++ return -1;
++ }
++
++ x-&gt;client_data = (VOID_STAR) &amp;data;
++ x-&gt;read = read_from_string;
++
++ data.ptr = data.string = string;
++ if (-1 == (ret = SLang_load_object (x)))
++ SLang_verror (SLang_Error, &quot;called from eval: %s&quot;, string);
++
++ SLang_free_slstring (string);
++ SLdeallocate_load_type (x);
++ return ret;
++}
++
++typedef struct
++{
++ char *buf;
++ FILE *fp;
++}
++File_Client_Data_Type;
++
++char *SLang_User_Prompt;
++static char *read_from_file (SLang_Load_Type *x)
++{
++ FILE *fp;
++ File_Client_Data_Type *c;
++
++ c = (File_Client_Data_Type *)x-&gt;client_data;
++ fp = c-&gt;fp;
++
++ if ((fp == stdin) &amp;&amp; (SLang_User_Prompt != NULL))
++ {
++ fputs (SLang_User_Prompt, stdout);
++ fflush (stdout);
++ }
++
++ return fgets (c-&gt;buf, MAX_FILE_LINE_LEN, c-&gt;fp);
++}
++
++/* Note that file could be freed from Slang during run of this routine
++ * so get it and store it !! (e.g., autoloading)
++ */
++int (*SLang_Load_File_Hook) (char *);
++int SLang_load_file (char *f)
++{
++ File_Client_Data_Type client_data;
++ SLang_Load_Type *x;
++ char *name, *buf;
++ FILE *fp;
++
++ if (SLang_Load_File_Hook != NULL)
++ return (*SLang_Load_File_Hook) (f);
++
++ if (f == NULL) name = &quot;&lt;stdin&gt;&quot;; else name = f;
++
++ name = SLang_create_slstring (name);
++ if (name == NULL)
++ return -1;
++
++ if (NULL == (x = SLallocate_load_type (name)))
++ {
++ SLang_free_slstring (name);
++ return -1;
++ }
++
++ buf = NULL;
++
++ if (f != NULL)
++ fp = fopen (f, &quot;r&quot;);
++ else
++ fp = stdin;
++
++ if (fp == NULL)
++ SLang_verror (SL_OBJ_NOPEN, &quot;Unable to open %s&quot;, name);
++ else if (NULL != (buf = SLmalloc (MAX_FILE_LINE_LEN + 1)))
++ {
++ client_data.fp = fp;
++ client_data.buf = buf;
++ x-&gt;client_data = (VOID_STAR) &amp;client_data;
++ x-&gt;read = read_from_file;
++
++ (void) SLang_load_object (x);
++ }
++
++ if ((fp != NULL) &amp;&amp; (fp != stdin))
++ fclose (fp);
++
++ SLfree (buf);
++ SLang_free_slstring (name);
++ SLdeallocate_load_type (x);
++
++ if (SLang_Error)
++ return -1;
++
++ return 0;
++}
++
++int SLang_guess_type (char *t)
++{
++ char *p;
++ register char ch;
++ int modifier = 0;
++
++ if (*t == '-') t++;
++ p = t;
++
++#if SLANG_HAS_FLOAT
++ if (*p != '.')
++ {
++#endif
++ modifier = 0;
++ while ((*p &gt;= '0') &amp;&amp; (*p &lt;= '9')) p++;
++ if (t == p) return (SLANG_STRING_TYPE);
++ if ((*p == 'x') &amp;&amp; (p == t + 1)) /* 0x?? */
++ {
++ modifier |= 8;
++ p++;
++ while (ch = *p,
++ ((ch &gt;= '0') &amp;&amp; (ch &lt;= '9'))
++ || (((ch | 0x20) &gt;= 'a') &amp;&amp; ((ch | 0x20) &lt;= 'f'))) p++;
++ }
++
++ /* Now look for UL, LU, UH, HU, L, H modifiers */
++ while ((ch = *p) != 0)
++ {
++ ch |= 0x20;
++ if (ch == 'h') modifier |= 1;
++ else if (ch == 'l') modifier |= 2;
++ else if (ch == 'u') modifier |= 4;
++ else break;
++ p++;
++ }
++ if ((1|2) == (modifier &amp; (1|2))) /* hl present */
++ return SLANG_STRING_TYPE;
++
++ if (ch == 0)
++ {
++ if ((modifier &amp; 0x7) == 0) return SLANG_INT_TYPE;
++ if (modifier &amp; 4)
++ {
++ if (modifier &amp; 1) return SLANG_USHORT_TYPE;
++ if (modifier &amp; 2) return SLANG_ULONG_TYPE;
++ return SLANG_UINT_TYPE;
++ }
++ if (modifier &amp; 1) return SLANG_SHORT_TYPE;
++ if (modifier &amp; 2) return SLANG_LONG_TYPE;
++ return SLANG_INT_TYPE;
++ }
++
++ if (modifier) return SLANG_STRING_TYPE;
++#if SLANG_HAS_FLOAT
++ }
++
++ /* now down to double case */
++ if (*p == '.')
++ {
++ p++;
++ while ((*p &gt;= '0') &amp;&amp; (*p &lt;= '9')) p++;
++ }
++ if (*p == 0) return(SLANG_DOUBLE_TYPE);
++ if ((*p != 'e') &amp;&amp; (*p != 'E'))
++ {
++# if SLANG_HAS_COMPLEX
++ if (((*p == 'i') || (*p == 'j'))
++ &amp;&amp; (p[1] == 0))
++ return SLANG_COMPLEX_TYPE;
++# endif
++ if (((*p | 0x20) == 'f') &amp;&amp; (p[1] == 0))
++ return SLANG_FLOAT_TYPE;
++
++ return SLANG_STRING_TYPE;
++ }
++
++ p++;
++ if ((*p == '-') || (*p == '+')) p++;
++ while ((*p &gt;= '0') &amp;&amp; (*p &lt;= '9')) p++;
++ if (*p != 0)
++ {
++# if SLANG_HAS_COMPLEX
++ if (((*p == 'i') || (*p == 'j'))
++ &amp;&amp; (p[1] == 0))
++ return SLANG_COMPLEX_TYPE;
++# endif
++ if (((*p | 0x20) == 'f') &amp;&amp; (p[1] == 0))
++ return SLANG_FLOAT_TYPE;
++
++ return SLANG_STRING_TYPE;
++ }
++ return SLANG_DOUBLE_TYPE;
++#else
++ return SLANG_STRING_TYPE;
++#endif /* SLANG_HAS_FLOAT */
++}
++
++static int hex_atoul (unsigned char *s, unsigned long *ul)
++{
++ register unsigned char ch;
++ register unsigned long value;
++ register int base;
++
++ s++; /* skip the leading 0 */
++
++ /* look for 'x' which indicates hex */
++ if ((*s | 0x20) == 'x')
++ {
++ base = 16;
++ s++;
++ if (*s == 0)
++ {
++ SLang_Error = SL_SYNTAX_ERROR;
++ return -1;
++ }
++ }
++ else base = 8;
++
++ value = 0;
++ while ((ch = *s++) != 0)
++ {
++ char ch1 = ch | 0x20;
++ switch (ch1)
++ {
++ default:
++ SLang_Error = SL_SYNTAX_ERROR;
++ break;
++
++ case 'u':
++ case 'l':
++ case 'h':
++ *ul = value;
++ return 0;
++
++ case '8':
++ case '9':
++ if (base != 16) SLang_Error = SL_SYNTAX_ERROR;
++ /* drop */
++ case '0':
++ case '1':
++ case '2':
++ case '3':
++ case '4':
++ case '5':
++ case '6':
++ case '7':
++ ch1 -= '0';
++ break;
++
++ case 'a':
++ case 'b':
++ case 'c':
++ case 'd':
++ case 'e':
++ case 'f':
++ if (base != 16) SLang_Error = SL_SYNTAX_ERROR;
++ ch1 = (ch1 - 'a') + 10;
++ break;
++ }
++ value = value * base + ch1;
++ }
++ *ul = value;
++ return 0;
++}
++
++/* Note: These routines do not check integer overflow. I would use the C
++ * library functions atol and atoul but some implementations check overflow
++ * and some do not. The following implementations provide a consistent
++ * behavior.
++ */
++unsigned long SLatoul (unsigned char *s)
++{
++ int sign;
++ unsigned long value;
++
++ if (*s == '-') sign = -1;
++ else
++ {
++ sign = 1;
++ if (*s == '+') s++;
++ }
++
++ if (*s == '0')
++ {
++ if (-1 == hex_atoul (s, &amp;value))
++ return (unsigned long) -1;
++ }
++ else
++ {
++ while (WHITE_CHAR == CHAR_CLASS(*s))
++ s++;
++
++ value = 0;
++ while (DIGIT_CHAR == CHAR_CLASS(*s))
++ {
++ value = value * 10 + (unsigned long) (*s - '0');
++ s++;
++ }
++ }
++
++ if (sign == -1)
++ value = (unsigned long)-1L * value;
++
++ return value;
++}
++
++long SLatol (unsigned char *s)
++{
++ while (WHITE_CHAR == CHAR_CLASS(*s))
++ s++;
++
++ if (*s == '-')
++ {
++ long value = (long) SLatoul (s+1);
++ return -value;
++ }
++ return (long) SLatoul (s);
++}
++
++int SLatoi (unsigned char *s)
++{
++ return (int) SLatol (s);
++}
++
++static char *check_byte_compiled_token (char *buf)
++{
++ unsigned int len_lo, len_hi, len;
++
++ len_lo = (unsigned char) *Input_Line_Pointer++;
++ if ((len_lo &lt; 32)
++ || ((len_hi = (unsigned char)*Input_Line_Pointer++) &lt; 32)
++ || ((len = (len_lo - 32) | ((len_hi - 32) &lt;&lt; 7)) &gt;= MAX_TOKEN_LEN))
++ {
++ SLang_doerror (&quot;Byte compiled file appears corrupt&quot;);
++ return NULL;
++ }
++
++ SLMEMCPY (buf, Input_Line_Pointer, len);
++ buf += len;
++ Input_Line_Pointer += len;
++ *buf = 0;
++ return buf;
++}
++
++void _SLcompile_byte_compiled (void)
++{
++ unsigned char type;
++ _SLang_Token_Type tok;
++ char buf[MAX_TOKEN_LEN];
++ char *ebuf;
++ unsigned int len;
++
++ memset ((char *) &amp;tok, 0, sizeof (_SLang_Token_Type));
++
++ while (SLang_Error == 0)
++ {
++ top_of_switch:
++ type = (unsigned char) *Input_Line_Pointer++;
++ switch (type)
++ {
++ case '\n':
++ case 0:
++ if (NULL == (Input_Line = LLT-&gt;read(LLT)))
++ {
++ Input_Line_Pointer = Input_Line = NULL;
++ return;
++ }
++ Input_Line_Pointer = Input_Line;
++ goto top_of_switch;
++
++ case LINE_NUM_TOKEN:
++ case CHAR_TOKEN:
++ case UCHAR_TOKEN:
++ case SHORT_TOKEN:
++ case USHORT_TOKEN:
++ case INT_TOKEN:
++ case UINT_TOKEN:
++ case LONG_TOKEN:
++ case ULONG_TOKEN:
++ if (NULL == check_byte_compiled_token (buf))
++ return;
++ tok.v.long_val = atol (buf);
++ break;
++
++ case COMPLEX_TOKEN:
++ case FLOAT_TOKEN:
++ case DOUBLE_TOKEN:
++ if (NULL == check_byte_compiled_token (buf))
++ return;
++ tok.v.s_val = buf;
++ break;
++
++ case ESC_STRING_TOKEN:
++ if (NULL == (ebuf = check_byte_compiled_token (buf)))
++ return;
++ tok.v.s_val = buf;
++ if (expand_escaped_string (buf, buf, ebuf, &amp;len))
++ {
++ tok.hash = len;
++ type = _BSTRING_TOKEN;
++ }
++ else
++ {
++ tok.hash = _SLstring_hash ((unsigned char *)buf, (unsigned char *)buf + len);
++ type = STRING_TOKEN;
++ }
++ break;
++
++ case TMP_TOKEN:
++ case DEFINE_TOKEN:
++ case DEFINE_STATIC_TOKEN:
++ case DEFINE_PRIVATE_TOKEN:
++ case DEFINE_PUBLIC_TOKEN:
++ case DOT_TOKEN:
++ case STRING_TOKEN:
++ case IDENT_TOKEN:
++ case _REF_TOKEN:
++ case _DEREF_ASSIGN_TOKEN:
++ case _SCALAR_ASSIGN_TOKEN:
++ case _SCALAR_PLUSEQS_TOKEN:
++ case _SCALAR_MINUSEQS_TOKEN:
++ case _SCALAR_TIMESEQS_TOKEN:
++ case _SCALAR_DIVEQS_TOKEN:
++ case _SCALAR_BOREQS_TOKEN:
++ case _SCALAR_BANDEQS_TOKEN:
++ case _SCALAR_PLUSPLUS_TOKEN:
++ case _SCALAR_POST_PLUSPLUS_TOKEN:
++ case _SCALAR_MINUSMINUS_TOKEN:
++ case _SCALAR_POST_MINUSMINUS_TOKEN:
++ case _STRUCT_ASSIGN_TOKEN:
++ case _STRUCT_PLUSEQS_TOKEN:
++ case _STRUCT_MINUSEQS_TOKEN:
++ case _STRUCT_TIMESEQS_TOKEN:
++ case _STRUCT_DIVEQS_TOKEN:
++ case _STRUCT_BOREQS_TOKEN:
++ case _STRUCT_BANDEQS_TOKEN:
++ case _STRUCT_POST_MINUSMINUS_TOKEN:
++ case _STRUCT_MINUSMINUS_TOKEN:
++ case _STRUCT_POST_PLUSPLUS_TOKEN:
++ case _STRUCT_PLUSPLUS_TOKEN:
++ if (NULL == (ebuf = check_byte_compiled_token (buf)))
++ return;
++ tok.v.s_val = buf;
++ tok.hash = _SLstring_hash ((unsigned char *)buf, (unsigned char *)ebuf);
++ break;
++
++ default:
++ break;
++ }
++ tok.type = type;
++
++ (*_SLcompile_ptr) (&amp;tok);
++ }
++}
++
++static int escape_string (unsigned char *s, unsigned char *smax,
++ unsigned char *buf, unsigned char *buf_max,
++ int *is_escaped)
++{
++ unsigned char ch;
++
++ *is_escaped = 0;
++ while (buf &lt; buf_max)
++ {
++ if (s == smax)
++ {
++ *buf = 0;
++ return 0;
++ }
++
++ ch = *s++;
++ switch (ch)
++ {
++ default:
++ *buf++ = ch;
++ break;
++
++ case 0:
++ *buf++ = '\\';
++ if (buf &lt; buf_max) *buf++ = 'x';
++ if (buf &lt; buf_max) *buf++ = '0';
++ if (buf &lt; buf_max) *buf++ = '0';
++ *is_escaped = 1;
++ break; /* return 0; */
++
++ case '\n':
++ *buf++ = '\\';
++ if (buf &lt; buf_max) *buf++ = 'n';
++ *is_escaped = 1;
++ break;
++
++ case '\r':
++ *buf++ = '\\';
++ if (buf &lt; buf_max) *buf++ = 'r';
++ *is_escaped = 1;
++ break;
++
++ case 0x1A: /* ^Z */
++ *buf++ = '\\';
++ if (buf &lt; buf_max) *buf++ = 'x';
++ if (buf &lt; buf_max) *buf++ = '1';
++ if (buf &lt; buf_max) *buf++ = 'A';
++ *is_escaped = 1;
++ break;
++
++ case '\\':
++ *buf++ = ch;
++ if (buf &lt; buf_max) *buf++ = ch;
++ *is_escaped = 1;
++ break;
++ }
++ }
++ _SLparse_error (&quot;String too long to byte-compile&quot;, NULL, 0);
++ return -1;
++}
++
++static FILE *Byte_Compile_Fp;
++static unsigned int Byte_Compile_Line_Len;
++
++static int bytecomp_write_data (char *buf, unsigned int len)
++{
++ char *err = &quot;Write Error&quot;;
++
++ if ((Byte_Compile_Line_Len + len + 1) &gt;= MAX_FILE_LINE_LEN)
++ {
++ if (EOF == fputs (&quot;\n&quot;, Byte_Compile_Fp))
++ {
++ SLang_doerror (err);
++ return -1;
++ }
++ Byte_Compile_Line_Len = 0;
++ }
++
++ if (EOF == fputs (buf, Byte_Compile_Fp))
++ {
++ SLang_doerror (err);
++ return -1;
++ }
++ Byte_Compile_Line_Len += len;
++ return 0;
++}
++
++static void byte_compile_token (_SLang_Token_Type *tok)
++{
++ unsigned char buf [MAX_TOKEN_LEN + 4], *buf_max;
++ unsigned int len;
++ char *b3;
++ int is_escaped;
++ unsigned char *s;
++
++ if (SLang_Error) return;
++
++ buf [0] = (unsigned char) tok-&gt;type;
++ buf [1] = 0;
++
++ buf_max = buf + sizeof(buf);
++ b3 = (char *) buf + 3;
++
++ switch (tok-&gt;type)
++ {
++ case LINE_NUM_TOKEN:
++ case CHAR_TOKEN:
++ case SHORT_TOKEN:
++ case INT_TOKEN:
++ case LONG_TOKEN:
++ sprintf (b3, &quot;%ld&quot;, tok-&gt;v.long_val);
++ break;
++
++ case UCHAR_TOKEN:
++ case USHORT_TOKEN:
++ case UINT_TOKEN:
++ case ULONG_TOKEN:
++ sprintf (b3, &quot;%lu&quot;, tok-&gt;v.long_val);
++ break;
++
++ case _BSTRING_TOKEN:
++ s = (unsigned char *) tok-&gt;v.s_val;
++ len = (unsigned int) tok-&gt;hash;
++
++ if (-1 == escape_string (s, s + len,
++ (unsigned char *)b3, buf_max,
++ &amp;is_escaped))
++ return;
++
++ buf[0] = ESC_STRING_TOKEN;
++ break;
++
++ case BSTRING_TOKEN:
++ if (NULL == (s = SLbstring_get_pointer (tok-&gt;v.b_val, &amp;len)))
++ return;
++
++ if (-1 == escape_string (s, s + len,
++ (unsigned char *)b3, buf_max,
++ &amp;is_escaped))
++ return;
++ buf[0] = ESC_STRING_TOKEN;
++ break;
++
++ case STRING_TOKEN:
++ s = (unsigned char *)tok-&gt;v.s_val;
++
++ if (-1 == escape_string (s, s + strlen ((char *)s),
++ (unsigned char *)b3, buf_max,
++ &amp;is_escaped))
++ return;
++
++ if (is_escaped)
++ buf[0] = ESC_STRING_TOKEN;
++ break;
++
++ /* a _SCALAR_* token is attached to an identifier. */
++ case _DEREF_ASSIGN_TOKEN:
++ case _SCALAR_ASSIGN_TOKEN:
++ case _SCALAR_PLUSEQS_TOKEN:
++ case _SCALAR_MINUSEQS_TOKEN:
++ case _SCALAR_TIMESEQS_TOKEN:
++ case _SCALAR_DIVEQS_TOKEN:
++ case _SCALAR_BOREQS_TOKEN:
++ case _SCALAR_BANDEQS_TOKEN:
++ case _SCALAR_PLUSPLUS_TOKEN:
++ case _SCALAR_POST_PLUSPLUS_TOKEN:
++ case _SCALAR_MINUSMINUS_TOKEN:
++ case _SCALAR_POST_MINUSMINUS_TOKEN:
++ case DOT_TOKEN:
++ case TMP_TOKEN:
++ case DEFINE_TOKEN:
++ case DEFINE_STATIC_TOKEN:
++ case DEFINE_PRIVATE_TOKEN:
++ case DEFINE_PUBLIC_TOKEN:
++ case FLOAT_TOKEN:
++ case DOUBLE_TOKEN:
++ case COMPLEX_TOKEN:
++ case IDENT_TOKEN:
++ case _REF_TOKEN:
++ case _STRUCT_ASSIGN_TOKEN:
++ case _STRUCT_PLUSEQS_TOKEN:
++ case _STRUCT_MINUSEQS_TOKEN:
++ case _STRUCT_TIMESEQS_TOKEN:
++ case _STRUCT_DIVEQS_TOKEN:
++ case _STRUCT_BOREQS_TOKEN:
++ case _STRUCT_BANDEQS_TOKEN:
++ case _STRUCT_POST_MINUSMINUS_TOKEN:
++ case _STRUCT_MINUSMINUS_TOKEN:
++ case _STRUCT_POST_PLUSPLUS_TOKEN:
++ case _STRUCT_PLUSPLUS_TOKEN:
++ strcpy (b3, tok-&gt;v.s_val);
++ break;
++
++ default:
++ b3 = NULL;
++ }
++
++ if (b3 != NULL)
++ {
++ len = strlen (b3);
++ buf[1] = (unsigned char) ((len &amp; 0x7F) + 32);
++ buf[2] = (unsigned char) (((len &gt;&gt; 7) &amp; 0x7F) + 32);
++ len += 3;
++ }
++ else len = 1;
++
++ (void) bytecomp_write_data ((char *)buf, len);
++}
++
++int SLang_byte_compile_file (char *name, int method)
++{
++ char file [1024];
++
++ (void) method;
++ if (strlen (name) + 2 &gt;= sizeof (file))
++ {
++ SLang_verror (SL_INVALID_PARM, &quot;Filename too long&quot;);
++ return -1;
++ }
++ sprintf (file, &quot;%sc&quot;, name);
++ if (NULL == (Byte_Compile_Fp = fopen (file, &quot;w&quot;)))
++ {
++ SLang_verror(SL_OBJ_NOPEN, &quot;%s: unable to open&quot;, file);
++ return -1;
++ }
++
++ Byte_Compile_Line_Len = 0;
++ if (-1 != bytecomp_write_data (&quot;.#&quot;, 2))
++ {
++ _SLcompile_ptr = byte_compile_token;
++ (void) SLang_load_file (name);
++ _SLcompile_ptr = _SLcompile;
++
++ (void) bytecomp_write_data (&quot;\n&quot;, 1);
++ }
++
++ if (EOF == fclose (Byte_Compile_Fp))
++ SLang_doerror (&quot;Write Error&quot;);
++
++ if (SLang_Error)
++ {
++ SLang_verror (0, &quot;Error processing %s&quot;, name);
++ return -1;
++ }
++ return 0;
++}
++
++int SLang_generate_debug_info (int x)
++{
++ int y = Default_Compile_Line_Num_Info;
++ Default_Compile_Line_Num_Info = x;
++ return y;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/sltoken.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/sltypes.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/sltypes.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/sltypes.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,966 @@
++/* Basic type operations for S-Lang */
++/* Copyright (c) 1992, 1996, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++
++#if SLANG_HAS_FLOAT
++# include &lt;math.h&gt;
++#endif
++
++#define SL_APP_WANTS_FOREACH /* for String_Type */
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++int SLpop_string (char **s) /*{{{*/
++{
++ char *sls;
++
++ *s = NULL;
++
++ if (-1 == SLang_pop_slstring (&amp;sls))
++ return -1;
++
++ if (NULL == (*s = SLmake_string (sls)))
++ {
++ SLang_free_slstring (sls);
++ return -1;
++ }
++
++ SLang_free_slstring (sls);
++ return 0;
++}
++
++/*}}}*/
++
++int SLang_pop_slstring (char **s) /*{{{*/
++{
++ return SLclass_pop_ptr_obj (SLANG_STRING_TYPE, (VOID_STAR *)s);
++}
++
++/*}}}*/
++
++/* if *data != 0, string should be freed upon use. */
++int SLang_pop_string(char **s, int *data) /*{{{*/
++{
++ if (SLpop_string (s))
++ return -1;
++
++ *data = 1;
++ return 0;
++}
++
++/*}}}*/
++
++int _SLang_push_slstring (char *s)
++{
++ if (0 == SLclass_push_ptr_obj (SLANG_STRING_TYPE, (VOID_STAR)s))
++ return 0;
++
++ SLang_free_slstring (s);
++ return -1;
++}
++
++int _SLpush_alloced_slstring (char *s, unsigned int len)
++{
++ if (NULL == (s = _SLcreate_via_alloced_slstring (s, len)))
++ return -1;
++
++ return _SLang_push_slstring (s);
++}
++
++int SLang_push_string (char *t) /*{{{*/
++{
++ if (t == NULL)
++ return SLang_push_null ();
++
++ if (NULL == (t = SLang_create_slstring (t)))
++ return -1;
++
++ return _SLang_push_slstring (t);
++}
++
++/*}}}*/
++
++int _SLang_dup_and_push_slstring (char *s)
++{
++ if (NULL == (s = _SLstring_dup_slstring (s)))
++ return SLang_push_null ();
++
++ return _SLang_push_slstring (s);
++}
++
++
++/* This function _always_ frees the malloced string */
++int SLang_push_malloced_string (char *c) /*{{{*/
++{
++ int ret;
++
++ ret = SLang_push_string (c);
++ SLfree (c);
++
++ return ret;
++}
++
++/*}}}*/
++
++#if 0
++static int int_int_power (int a, int b)
++{
++ int r, s;
++
++ if (a == 0) return 0;
++ if (b &lt; 0) return 0;
++ if (b == 0) return 1;
++
++ s = 1;
++ if (a &lt; 0)
++ {
++ if ((b % 2) == 1) s = -1;
++ a = -a;
++ }
++
++ /* FIXME: Priority=low
++ * This needs optimized
++ */
++ r = 1;
++ while (b)
++ {
++ r = r * a;
++ b--;
++ }
++ return r * s;
++}
++#endif
++
++static int
++string_string_bin_op_result (int op, unsigned char a, unsigned char b,
++ unsigned char *c)
++{
++ (void) a;
++ (void) b;
++ switch (op)
++ {
++ default:
++ return 0;
++
++ case SLANG_PLUS:
++ *c = SLANG_STRING_TYPE;
++ break;
++
++ case SLANG_GT:
++ case SLANG_GE:
++ case SLANG_LT:
++ case SLANG_LE:
++ case SLANG_EQ:
++ case SLANG_NE:
++ *c = SLANG_CHAR_TYPE;
++ break;
++ }
++ return 1;
++}
++
++static int
++string_string_bin_op (int op,
++ unsigned char a_type, VOID_STAR ap, unsigned int na,
++ unsigned char b_type, VOID_STAR bp, unsigned int nb,
++ VOID_STAR cp)
++{
++ char *ic;
++ char **a, **b, **c;
++ unsigned int n, n_max;
++ unsigned int da, db;
++
++ (void) a_type;
++ (void) b_type;
++
++ if (na == 1) da = 0; else da = 1;
++ if (nb == 1) db = 0; else db = 1;
++
++ if (na &gt; nb) n_max = na; else n_max = nb;
++
++ a = (char **) ap;
++ b = (char **) bp;
++ for (n = 0; n &lt; n_max; n++)
++ {
++ if ((*a == NULL) || (*b == NULL))
++ {
++ SLang_verror (SL_VARIABLE_UNINITIALIZED, &quot;String element[%u] not initialized for binary operation&quot;, n);
++ return -1;
++ }
++ a += da; b += db;
++ }
++
++ a = (char **) ap;
++ b = (char **) bp;
++ ic = (char *) cp;
++ c = NULL;
++
++ switch (op)
++ {
++ case SLANG_DIVIDE:
++ case SLANG_MINUS:
++ default:
++ return 0;
++
++ case SLANG_PLUS:
++ /* Concat */
++ c = (char **) cp;
++ for (n = 0; n &lt; n_max; n++)
++ {
++ if (NULL == (c[n] = SLang_concat_slstrings (*a, *b)))
++ goto return_error;
++
++ a += da; b += db;
++ }
++ break;
++
++ case SLANG_NE:
++ for (n = 0; n &lt; n_max; n++)
++ {
++ ic [n] = (0 != strcmp (*a, *b));
++ a += da;
++ b += db;
++ }
++ break;
++ case SLANG_GT:
++ for (n = 0; n &lt; n_max; n++)
++ {
++ ic [n] = (strcmp (*a, *b) &gt; 0);
++ a += da;
++ b += db;
++ }
++ break;
++ case SLANG_GE:
++ for (n = 0; n &lt; n_max; n++)
++ {
++ ic [n] = (strcmp (*a, *b) &gt;= 0);
++ a += da;
++ b += db;
++ }
++ break;
++ case SLANG_LT:
++ for (n = 0; n &lt; n_max; n++)
++ {
++ ic [n] = (strcmp (*a, *b) &lt; 0);
++ a += da;
++ b += db;
++ }
++ break;
++ case SLANG_LE:
++ for (n = 0; n &lt; n_max; n++)
++ {
++ ic [n] = (strcmp (*a, *b) &lt;= 0);
++ a += da;
++ b += db;
++ }
++ break;
++ case SLANG_EQ:
++ for (n = 0; n &lt; n_max; n++)
++ {
++ ic [n] = (strcmp (*a, *b) == 0);
++ a += da;
++ b += db;
++ }
++ break;
++ }
++ return 1;
++
++ return_error:
++ if (c != NULL)
++ {
++ unsigned int nn;
++ for (nn = 0; nn &lt; n; nn++)
++ {
++ SLang_free_slstring (c[nn]);
++ c[nn] = NULL;
++ }
++ for (nn = n; nn &lt; n_max; nn++)
++ c[nn] = NULL;
++ }
++ return -1;
++}
++
++static void string_destroy (unsigned char unused, VOID_STAR s)
++{
++ (void) unused;
++ SLang_free_slstring (*(char **) s);
++}
++
++static int string_push (unsigned char unused, VOID_STAR sptr)
++{
++ (void) unused;
++ return SLang_push_string (*(char **) sptr);
++}
++
++static int string_cmp (unsigned char unused, VOID_STAR ap, VOID_STAR bp, int *c)
++{
++ char *a, *b;
++ (void) unused;
++
++ a = *(char **) ap;
++ b = *(char **) bp;
++ if (a != b)
++ {
++ if (a == NULL) *c = -1;
++ else if (b == NULL) *c = 1;
++ else *c = strcmp (a, b);
++ return 0;
++ }
++ *c = 0;
++ return 0;
++}
++
++static int string_to_int (unsigned char a_type, VOID_STAR ap, unsigned int na,
++ unsigned char b_type, VOID_STAR bp)
++{
++ char **s;
++ unsigned int i;
++ int *b;
++
++ (void) a_type;
++ (void) b_type;
++
++ s = (char **) ap;
++ b = (int *) bp;
++ for (i = 0; i &lt; na; i++)
++ {
++ if (s[i] == NULL) b[i] = 0;
++ else b[i] = s[i][0];
++ }
++ return 1;
++}
++
++struct _SLang_Foreach_Context_Type
++{
++ char *string;
++ unsigned int n;
++};
++
++static SLang_Foreach_Context_Type *
++string_foreach_open (unsigned char type, unsigned int num)
++{
++ char *s;
++ SLang_Foreach_Context_Type *c;
++
++ (void) type;
++ if (num != 0)
++ {
++ SLang_verror (SL_NOT_IMPLEMENTED,
++ &quot;'foreach using' form not supported by String_Type&quot;);
++ SLdo_pop_n (num + 1);
++ return NULL;
++ }
++ if (-1 == SLang_pop_slstring (&amp;s))
++ return NULL;
++
++ c = (SLang_Foreach_Context_Type *)SLmalloc (sizeof (SLang_Foreach_Context_Type));
++ if (c == NULL)
++ {
++ SLang_free_slstring (s);
++ return NULL;
++ }
++
++ memset ((char *) c, 0, sizeof (SLang_Foreach_Context_Type));
++ c-&gt;string = s;
++
++ return c;
++}
++
++static void string_foreach_close (unsigned char type, SLang_Foreach_Context_Type *c)
++{
++ (void) type;
++ if (c == NULL) return;
++ SLang_free_slstring (c-&gt;string);
++ SLfree ((char *) c);
++}
++
++static int string_foreach (unsigned char type, SLang_Foreach_Context_Type *c)
++{
++ char ch;
++
++ (void) type;
++ ch = c-&gt;string[c-&gt;n];
++ if (ch == 0)
++ return 0; /* done */
++
++ c-&gt;n += 1;
++
++ if (-1 == SLclass_push_int_obj (SLANG_INT_TYPE, ch))
++ return -1;
++
++ return 1;
++}
++
++int _SLstring_list_push (_SLString_List_Type *p)
++{
++ unsigned int num;
++ int inum;
++ SLang_Array_Type *at;
++ char **buf;
++
++ if ((buf = p-&gt;buf) == NULL)
++ return SLang_push_null ();
++
++ num = p-&gt;num;
++ inum = (int) num;
++
++ if (num == 0) num++;
++ if (num != p-&gt;max_num)
++ {
++ if (NULL == (buf = (char **)SLrealloc ((char *) buf, sizeof (char *) * num)))
++ {
++ _SLstring_list_delete (p);
++ return -1;
++ }
++ p-&gt;max_num = num;
++ p-&gt;buf = buf;
++ }
++
++ if (NULL == (at = SLang_create_array (SLANG_STRING_TYPE, 0, (VOID_STAR) buf, &amp;inum, 1)))
++ {
++ _SLstring_list_delete (p);
++ return -1;
++ }
++ p-&gt;buf = NULL;
++ _SLstring_list_delete (p);
++ return SLang_push_array (at, 1);
++}
++
++int _SLstring_list_init (_SLString_List_Type *p, unsigned int max_num, unsigned int delta_num)
++{
++ if (NULL == (p-&gt;buf = (char **) SLmalloc (max_num * sizeof (char *))))
++ return -1;
++
++ p-&gt;max_num = max_num;
++ p-&gt;num = 0;
++ p-&gt;delta_num = delta_num;
++ return 0;
++}
++
++int _SLstring_list_append (_SLString_List_Type *p, char *s)
++{
++ if (s == NULL)
++ {
++ _SLstring_list_delete (p);
++ return -1;
++ }
++
++ if (p-&gt;max_num == p-&gt;num)
++ {
++ char **b;
++ unsigned int max_num = p-&gt;num + p-&gt;delta_num;
++ b = (char **)SLrealloc ((char *)p-&gt;buf, max_num * sizeof (char *));
++ if (b == NULL)
++ {
++ _SLstring_list_delete (p);
++ SLang_free_slstring (s);
++ return -1;
++ }
++ p-&gt;buf = b;
++ p-&gt;max_num = max_num;
++ }
++
++ p-&gt;buf[p-&gt;num] = s;
++ p-&gt;num++;
++ return 0;
++}
++
++void _SLstring_list_delete (_SLString_List_Type *p)
++{
++ if (p-&gt;buf != NULL)
++ {
++ unsigned int i, imax;
++ char **buf = p-&gt;buf;
++ imax = p-&gt;num;
++ for (i = 0; i &lt; imax; i++)
++ SLang_free_slstring (buf[i]);
++ SLfree ((char *)buf);
++ p-&gt;buf = NULL;
++ }
++}
++
++/* Ref type */
++int SLang_pop_ref (SLang_Ref_Type **ref)
++{
++ return SLclass_pop_ptr_obj (SLANG_REF_TYPE, (VOID_STAR *)ref);
++}
++
++/* Note: This is ok if ptr is NULL. Some routines rely on this behavior */
++int _SLang_push_ref (int is_global, VOID_STAR ptr)
++{
++ SLang_Ref_Type *r;
++
++ if (ptr == NULL)
++ return SLang_push_null ();
++
++ r = (SLang_Ref_Type *) SLmalloc (sizeof (SLang_Ref_Type));
++ if (r == NULL) return -1;
++
++ r-&gt;is_global = is_global;
++ r-&gt;v.nt = (SLang_Name_Type *) ptr;
++
++ if (-1 == SLclass_push_ptr_obj (SLANG_REF_TYPE, (VOID_STAR) r))
++ {
++ SLfree ((char *) r);
++ return -1;
++ }
++ return 0;
++}
++
++static void ref_destroy (unsigned char type, VOID_STAR ptr)
++{
++ (void) type;
++ SLfree ((char *) *(SLang_Ref_Type **)ptr);
++}
++
++void SLang_free_ref (SLang_Ref_Type *ref)
++{
++ SLfree ((char *) ref);
++}
++
++static int ref_push (unsigned char type, VOID_STAR ptr)
++{
++ SLang_Ref_Type *ref;
++
++ (void) type;
++
++ ref = *(SLang_Ref_Type **) ptr;
++
++ if (ref == NULL)
++ return SLang_push_null ();
++
++ return _SLang_push_ref (ref-&gt;is_global, (VOID_STAR) ref-&gt;v.nt);
++}
++
++int SLang_assign_to_ref (SLang_Ref_Type *ref, unsigned char type, VOID_STAR v)
++{
++ SLang_Object_Type *stkptr;
++ SLang_Class_Type *cl;
++
++ cl = _SLclass_get_class (type);
++
++ /* Use apush since this function is passing ``array'' bytes rather than the
++ * address of the data. I need to somehow make this more consistent. To
++ * see what I mean, consider:
++ *
++ * double z[2];
++ * char *s = &quot;silly&quot;;
++ * int i;
++ *
++ * SLang_assign_to_ref (ref, SLANG_INT_TYPE, &amp;i);
++ * SLang_assign_to_ref (ref, SLANG_STRING_TYPE, &amp;s);
++ * SLang_assign_to_ref (ref, SLANG_COMPLEX_TYPE, z);
++ *
++ * That is, all external routines that take a VOID_STAR argument need to
++ * be documented such that how the function should be called with the
++ * various class_types.
++ */
++ if (-1 == (*cl-&gt;cl_apush) (type, v))
++ return -1;
++
++ stkptr = _SLStack_Pointer;
++ if (0 == _SLang_deref_assign (ref))
++ return 0;
++
++ if (stkptr != _SLStack_Pointer)
++ SLdo_pop ();
++
++ return -1;
++}
++
++static char *ref_string (unsigned char type, VOID_STAR ptr)
++{
++ SLang_Ref_Type *ref;
++
++ (void) type;
++ ref = *(SLang_Ref_Type **) ptr;
++ if (ref-&gt;is_global)
++ {
++ char *name, *s;
++
++ name = ref-&gt;v.nt-&gt;name;
++ if ((name != NULL)
++ &amp;&amp; (NULL != (s = SLmalloc (strlen(name) + 2))))
++ {
++ *s = '&amp;';
++ strcpy (s + 1, name);
++ return s;
++ }
++
++ return NULL;
++ }
++ return SLmake_string (&quot;Local Variable Reference&quot;);
++}
++
++static int ref_dereference (unsigned char unused, VOID_STAR ptr)
++{
++ (void) unused;
++ return _SLang_dereference_ref (*(SLang_Ref_Type **) ptr);
++}
++
++static int ref_cmp (unsigned char type, VOID_STAR a, VOID_STAR b, int *c)
++{
++ SLang_Ref_Type *ra, *rb;
++
++ (void) type;
++
++ ra = *(SLang_Ref_Type **)a;
++ rb = *(SLang_Ref_Type **)b;
++
++ if (ra == NULL)
++ {
++ if (rb == NULL) *c = 0;
++ else *c = -1;
++ return 0;
++ }
++ if (rb == NULL)
++ {
++ *c = 1;
++ return 0;
++ }
++
++ if (ra-&gt;v.nt == rb-&gt;v.nt)
++ *c = 0;
++ else *c = strcmp (ra-&gt;v.nt-&gt;name, rb-&gt;v.nt-&gt;name);
++ return 0;
++}
++
++
++SLang_Name_Type *SLang_pop_function (void)
++{
++ SLang_Ref_Type *ref;
++ SLang_Name_Type *f;
++
++ if (SLang_peek_at_stack () == SLANG_STRING_TYPE)
++ {
++ char *name;
++
++ if (-1 == SLang_pop_slstring (&amp;name))
++ return NULL;
++
++ if (NULL == (f = SLang_get_function (name)))
++ {
++ SLang_verror (SL_UNDEFINED_NAME, &quot;Function %s does not exist&quot;, name);
++ SLang_free_slstring (name);
++ return NULL;
++ }
++ SLang_free_slstring (name);
++ return f;
++ }
++
++ if (-1 == SLang_pop_ref (&amp;ref))
++ return NULL;
++
++ f = SLang_get_fun_from_ref (ref);
++ SLang_free_ref (ref);
++ return f;
++}
++
++/* This is a placeholder for version 2 */
++void SLang_free_function (SLang_Name_Type *f)
++{
++ (void) f;
++}
++
++/* NULL type */
++int SLang_push_null (void)
++{
++ return SLclass_push_ptr_obj (SLANG_NULL_TYPE, NULL);
++}
++
++int SLang_pop_null (void)
++{
++ SLang_Object_Type obj;
++ return _SLang_pop_object_of_type (SLANG_NULL_TYPE, &amp;obj, 0);
++}
++
++static int null_push (unsigned char unused, VOID_STAR ptr_unused)
++{
++ (void) unused; (void) ptr_unused;
++ return SLang_push_null ();
++}
++
++static int null_pop (unsigned char type, VOID_STAR ptr)
++{
++ (void) type;
++
++ if (-1 == SLang_pop_null ())
++ return -1;
++
++ *(char **) ptr = NULL;
++ return 0;
++}
++
++/* Implement foreach (NULL) using (whatever) to do nothing. This is useful
++ * because suppose that X is a list but is NULL in some situations. Then
++ * when it is NULL, we want foreach(X) to do nothing.
++ */
++static SLang_Foreach_Context_Type *
++null_foreach_open (unsigned char type, unsigned int num)
++{
++ (void) type;
++ SLdo_pop_n (num + 1);
++ return (SLang_Foreach_Context_Type *)1;
++}
++
++static void null_foreach_close (unsigned char type, SLang_Foreach_Context_Type *c)
++{
++ (void) type;
++ (void) c;
++}
++
++static int null_foreach (unsigned char type, SLang_Foreach_Context_Type *c)
++{
++ (void) type;
++ (void) c;
++ return 0;
++}
++
++static int null_to_bool (unsigned char type, int *t)
++{
++ (void) type;
++ *t = 0;
++ return SLang_pop_null ();
++}
++
++/* AnyType */
++int _SLanytype_typecast (unsigned char a_type, VOID_STAR ap, unsigned int na,
++ unsigned char b_type, VOID_STAR bp)
++{
++ SLang_Class_Type *cl;
++ SLang_Any_Type **any;
++ unsigned int i;
++ unsigned int sizeof_type;
++
++ (void) b_type;
++
++ any = (SLang_Any_Type **) bp;
++
++ cl = _SLclass_get_class (a_type);
++ sizeof_type = cl-&gt;cl_sizeof_type;
++
++ for (i = 0; i &lt; na; i++)
++ {
++ if ((-1 == (*cl-&gt;cl_apush) (a_type, ap))
++ || (-1 == SLang_pop_anytype (&amp;any[i])))
++ {
++ while (i != 0)
++ {
++ i--;
++ SLang_free_anytype (any[i]);
++ any[i] = NULL;
++ }
++ return -1;
++ }
++ ap = (VOID_STAR)((char *)ap + sizeof_type);
++ }
++
++ return 1;
++}
++
++int SLang_pop_anytype (SLang_Any_Type **any)
++{
++ SLang_Object_Type *obj;
++
++ *any = NULL;
++
++ if (NULL == (obj = (SLang_Object_Type *) SLmalloc (sizeof (SLang_Object_Type))))
++ return -1;
++
++ if (-1 == SLang_pop (obj))
++ {
++ SLfree ((char *) obj);
++ return -1;
++ }
++ *any = (SLang_Any_Type *)obj;
++ return 0;
++}
++
++/* This function will result in an object that is represented by the
++ * anytype object.
++ */
++int SLang_push_anytype (SLang_Any_Type *any)
++{
++ return _SLpush_slang_obj ((SLang_Object_Type *)any);
++}
++
++/* After this call, the stack will contain an Any_Type object */
++static int anytype_push (unsigned char type, VOID_STAR ptr)
++{
++ SLang_Any_Type *obj;
++
++ /* Push the object onto the stack, then pop it back off into our anytype
++ * container. That way, any memory managing associated with the type
++ * will be performed automatically. Another way to think of it is that
++ * pushing an Any_Type onto the stack will create another copy of the
++ * object represented by it.
++ */
++ if (-1 == _SLpush_slang_obj (*(SLang_Object_Type **)ptr))
++ return -1;
++
++ if (-1 == SLang_pop_anytype (&amp;obj))
++ return -1;
++
++ /* There is no need to reference count the anytype objects since every
++ * push results in a new anytype container.
++ */
++ if (-1 == SLclass_push_ptr_obj (type, (VOID_STAR) obj))
++ {
++ SLang_free_anytype (obj);
++ return -1;
++ }
++
++ return 0;
++}
++
++static void anytype_destroy (unsigned char type, VOID_STAR ptr)
++{
++ SLang_Object_Type *obj;
++
++ (void) type;
++ obj = *(SLang_Object_Type **)ptr;
++ SLang_free_object (obj);
++ SLfree ((char *) obj);
++}
++
++void SLang_free_anytype (SLang_Any_Type *any)
++{
++ if (any != NULL)
++ anytype_destroy (SLANG_ANY_TYPE, (VOID_STAR) &amp;any);
++}
++
++static int anytype_dereference (unsigned char unused, VOID_STAR ptr)
++{
++ (void) unused;
++ return _SLpush_slang_obj (*(SLang_Object_Type **) ptr);
++}
++
++/* SLANG_INTP_TYPE */
++static int intp_push (unsigned char unused, VOID_STAR ptr)
++{
++ (void) unused;
++ return SLclass_push_int_obj (SLANG_INT_TYPE, **(int **)ptr);
++}
++
++static int intp_pop (unsigned char unused, VOID_STAR ptr)
++{
++ (void) unused;
++ return SLang_pop_integer (*(int **) ptr);
++}
++
++static int undefined_push (unsigned char t, VOID_STAR p)
++{
++ (void) t; (void) p;
++ if (SLang_Error == 0)
++ SLang_Error = SL_VARIABLE_UNINITIALIZED;
++ return -1;
++}
++
++int _SLregister_types (void)
++{
++ SLang_Class_Type *cl;
++
++ /* A good compiler should optimize this code away. */
++ if ((sizeof(short) != SIZEOF_SHORT)
++ || (sizeof(int) != SIZEOF_INT)
++ || (sizeof(long) != SIZEOF_LONG)
++ || (sizeof(float) != SIZEOF_FLOAT)
++ || (sizeof(double) != SIZEOF_DOUBLE))
++ SLang_exit_error (&quot;S-Lang Library not built properly. Fix SIZEOF_* in config.h and recompile&quot;);
++
++ if (-1 == _SLclass_init ())
++ return -1;
++
++ /* Undefined Type */
++ if (NULL == (cl = SLclass_allocate_class (&quot;Undefined_Type&quot;)))
++ return -1;
++ (void) SLclass_set_push_function (cl, undefined_push);
++ (void) SLclass_set_pop_function (cl, undefined_push);
++ if (-1 == SLclass_register_class (cl, SLANG_UNDEFINED_TYPE, sizeof (int),
++ SLANG_CLASS_TYPE_SCALAR))
++ return -1;
++ /* Make Void_Type a synonym for Undefined_Type. Note that this does
++ * not mean that Void_Type represents SLANG_VOID_TYPE. Void_Type is
++ * used by array_map to indicate no array is to be created.
++ */
++ if (-1 == SLclass_create_synonym (&quot;Void_Type&quot;, SLANG_UNDEFINED_TYPE))
++ return -1;
++
++ if (-1 == _SLarith_register_types ())
++ return -1;
++
++ /* SLANG_INTP_TYPE */
++ if (NULL == (cl = SLclass_allocate_class (&quot;_IntegerP_Type&quot;)))
++ return -1;
++ (void) SLclass_set_push_function (cl, intp_push);
++ (void) SLclass_set_pop_function (cl, intp_pop);
++ if (-1 == SLclass_register_class (cl, SLANG_INTP_TYPE, sizeof (int),
++ SLANG_CLASS_TYPE_SCALAR))
++ return -1;
++
++ /* String Type */
++
++ if (NULL == (cl = SLclass_allocate_class (&quot;String_Type&quot;)))
++ return -1;
++ (void) SLclass_set_destroy_function (cl, string_destroy);
++ (void) SLclass_set_push_function (cl, string_push);
++ cl-&gt;cl_foreach_open = string_foreach_open;
++ cl-&gt;cl_foreach_close = string_foreach_close;
++ cl-&gt;cl_foreach = string_foreach;
++ cl-&gt;cl_cmp = string_cmp;
++ if (-1 == SLclass_register_class (cl, SLANG_STRING_TYPE, sizeof (char *),
++ SLANG_CLASS_TYPE_PTR))
++ return -1;
++
++ /* ref Type */
++ if (NULL == (cl = SLclass_allocate_class (&quot;Ref_Type&quot;)))
++ return -1;
++ cl-&gt;cl_dereference = ref_dereference;
++ cl-&gt;cl_push = ref_push;
++ cl-&gt;cl_destroy = ref_destroy;
++ cl-&gt;cl_string = ref_string;
++ cl-&gt;cl_cmp = ref_cmp;
++ if (-1 == SLclass_register_class (cl, SLANG_REF_TYPE,
++ sizeof (SLang_Ref_Type *),
++ SLANG_CLASS_TYPE_PTR))
++ return -1;
++
++ /* NULL Type */
++
++ if (NULL == (cl = SLclass_allocate_class (&quot;Null_Type&quot;)))
++ return -1;
++ cl-&gt;cl_push = null_push;
++ cl-&gt;cl_pop = null_pop;
++ cl-&gt;cl_foreach_open = null_foreach_open;
++ cl-&gt;cl_foreach_close = null_foreach_close;
++ cl-&gt;cl_foreach = null_foreach;
++ cl-&gt;cl_to_bool = null_to_bool;
++ if (-1 == SLclass_register_class (cl, SLANG_NULL_TYPE, sizeof (char *),
++ SLANG_CLASS_TYPE_SCALAR))
++ return -1;
++
++ /* AnyType */
++ if (NULL == (cl = SLclass_allocate_class (&quot;Any_Type&quot;)))
++ return -1;
++ (void) SLclass_set_push_function (cl, anytype_push);
++ (void) SLclass_set_destroy_function (cl, anytype_destroy);
++ cl-&gt;cl_dereference = anytype_dereference;
++ if (-1 == SLclass_register_class (cl, SLANG_ANY_TYPE, sizeof (VOID_STAR),
++ SLANG_CLASS_TYPE_PTR))
++ return -1;
++
++ if (-1 == _SLang_init_bstring ())
++ return -1;
++
++ if ((-1 == SLclass_add_typecast (SLANG_STRING_TYPE, SLANG_INT_TYPE, string_to_int, 0))
++ || (-1 == SLclass_add_binary_op (SLANG_STRING_TYPE, SLANG_STRING_TYPE, string_string_bin_op, string_string_bin_op_result)))
++ return -1;
++
++ return 0;
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/sltypes.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slutty.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slutty.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slutty.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,596 @@
++/* slutty.c --- Unix Low level terminal (tty) functions for S-Lang */
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++#include &quot;slinclud.h&quot;
++
++#include &lt;signal.h&gt;
++/* sequent support thanks to Kenneth Lorber &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">keni at oasys.dt.navy.mil</A>&gt; */
++/* SYSV (SYSV ISC R3.2 v3.0) provided by <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">iain.lea at erlm.siemens.de</A> */
++
++#if defined (_AIX) &amp;&amp; !defined (_ALL_SOURCE)
++# define _ALL_SOURCE /* so NBBY is defined in &lt;sys/types.h&gt; */
++#endif
++
++#include &lt;sys/time.h&gt;
++#include &lt;sys/types.h&gt;
++
++#ifdef SYSV
++# include &lt;fcntl.h&gt;
++# ifndef CRAY
++# include &lt;sys/termio.h&gt;
++# include &lt;sys/stream.h&gt;
++# include &lt;sys/ptem.h&gt;
++# include &lt;sys/tty.h&gt;
++# endif
++#endif
++
++#ifdef __BEOS__
++/* Prototype for select */
++# include &lt;net/socket.h&gt;
++#endif
++
++#include &lt;sys/file.h&gt;
++
++#ifndef sun
++# include &lt;sys/ioctl.h&gt;
++#endif
++
++#ifdef __QNX__
++# include &lt;sys/select.h&gt;
++#endif
++
++#include &lt;sys/stat.h&gt;
++#include &lt;errno.h&gt;
++
++#if defined (_AIX) &amp;&amp; !defined (FD_SET)
++# include &lt;sys/select.h&gt; /* for FD_ISSET, FD_SET, FD_ZERO */
++#endif
++
++#ifndef O_RDWR
++# include &lt;fcntl.h&gt;
++#endif
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++
++int SLang_TT_Read_FD = -1;
++int SLang_TT_Baud_Rate;
++
++#ifdef HAVE_TERMIOS_H
++# if !defined(HAVE_TCGETATTR) || !defined(HAVE_TCSETATTR)
++# undef HAVE_TERMIOS_H
++# endif
++#endif
++
++#ifndef HAVE_TERMIOS_H
++
++# if !defined(CBREAK) &amp;&amp; defined(sun)
++# ifndef BSD_COMP
++# define BSD_COMP 1
++# endif
++# include &lt;sys/ioctl.h&gt;
++# endif
++
++typedef struct
++ {
++ struct tchars t;
++ struct ltchars lt;
++ struct sgttyb s;
++ }
++TTY_Termio_Type;
++#else
++# include &lt;termios.h&gt;
++typedef struct termios TTY_Termio_Type;
++#endif
++
++static TTY_Termio_Type Old_TTY;
++
++#ifdef HAVE_TERMIOS_H
++typedef struct
++{
++ unsigned int key;
++ unsigned int value;
++} Baud_Rate_Type;
++
++static Baud_Rate_Type Baud_Rates [] =
++{
++#ifdef B0
++ {B0, 0},
++#endif
++#ifdef B50
++ {B50, 50},
++#endif
++#ifdef B75
++ {B75, 75},
++#endif
++#ifdef B110
++ {B110, 110},
++#endif
++#ifdef B134
++ {B134, 134},
++#endif
++#ifdef B150
++ {B150, 150},
++#endif
++#ifdef B200
++ {B200, 200},
++#endif
++#ifdef B300
++ {B300, 300},
++#endif
++#ifdef B600
++ {B600, 600},
++#endif
++#ifdef B1200
++ {B1200, 1200},
++#endif
++#ifdef B1800
++ {B1800, 1800},
++#endif
++#ifdef B2400
++ {B2400, 2400},
++#endif
++#ifdef B4800
++ {B4800, 4800},
++#endif
++#ifdef B9600
++ {B9600, 9600},
++#endif
++#ifdef B19200
++ {B19200, 19200},
++#endif
++#ifdef B38400
++ {B38400, 38400},
++#endif
++#ifdef B57600
++ {B57600, 57600},
++#endif
++#ifdef B115200
++ {B115200, 115200},
++#endif
++#ifdef B230400
++ {B230400, 230400},
++#endif
++ {0, 0}
++};
++
++static void
++set_baud_rate (TTY_Termio_Type *tty)
++{
++#ifdef HAVE_CFGETOSPEED
++ unsigned int speed;
++ Baud_Rate_Type *b, *bmax;
++
++ if (SLang_TT_Baud_Rate)
++ return; /* already set */
++
++ speed = (unsigned int) cfgetospeed (tty);
++
++ b = Baud_Rates;
++ bmax = b + (sizeof (Baud_Rates)/sizeof(Baud_Rates[0]));
++ while (b &lt; bmax)
++ {
++ if (b-&gt;key == speed)
++ {
++ SLang_TT_Baud_Rate = b-&gt;value;
++ return;
++ }
++ b++;
++ }
++#else
++ (void) tty;
++#endif
++}
++
++#endif /* HAVE_TERMIOS_H */
++
++#ifdef HAVE_TERMIOS_H
++# define GET_TERMIOS(fd, x) tcgetattr(fd, x)
++# define SET_TERMIOS(fd, x) tcsetattr(fd, TCSADRAIN, x)
++#else
++# ifdef TCGETS
++# define GET_TERMIOS(fd, x) ioctl(fd, TCGETS, x)
++# define SET_TERMIOS(fd, x) ioctl(fd, TCSETS, x)
++# else
++# define X(x,m) &amp;(((TTY_Termio_Type *)(x))-&gt;m)
++# define GET_TERMIOS(fd, x) \
++ ((ioctl(fd, TIOCGETC, X(x,t)) || \
++ ioctl(fd, TIOCGLTC, X(x,lt)) || \
++ ioctl(fd, TIOCGETP, X(x,s))) ? -1 : 0)
++# define SET_TERMIOS(fd, x) \
++ ((ioctl(fd, TIOCSETC, X(x,t)) ||\
++ ioctl(fd, TIOCSLTC, X(x,lt)) || \
++ ioctl(fd, TIOCSETP, X(x,s))) ? -1 : 0)
++# endif
++#endif
++
++static int TTY_Inited = 0;
++static int TTY_Open = 0;
++
++#ifdef ultrix /* Ultrix gets _POSIX_VDISABLE wrong! */
++# define NULL_VALUE -1
++#else
++# ifdef _POSIX_VDISABLE
++# define NULL_VALUE _POSIX_VDISABLE
++# else
++# define NULL_VALUE 255
++# endif
++#endif
++
++int SLang_init_tty (int abort_char, int no_flow_control, int opost)
++{
++ TTY_Termio_Type newtty;
++
++ SLsig_block_signals ();
++
++ if (TTY_Inited)
++ {
++ SLsig_unblock_signals ();
++ return 0;
++ }
++
++ TTY_Open = 0;
++
++ if ((SLang_TT_Read_FD == -1)
++ || (1 != isatty (SLang_TT_Read_FD)))
++ {
++#ifdef O_RDWR
++# ifndef __BEOS__ /* I have been told that BEOS will HANG if passed /dev/tty */
++ if ((SLang_TT_Read_FD = open(&quot;/dev/tty&quot;, O_RDWR)) &gt;= 0)
++ {
++ TTY_Open = 1;
++ }
++# endif
++#endif
++ if (TTY_Open == 0)
++ {
++ SLang_TT_Read_FD = fileno (stderr);
++ if (1 != isatty (SLang_TT_Read_FD))
++ {
++ SLang_TT_Read_FD = fileno (stdin);
++ if (1 != isatty (SLang_TT_Read_FD))
++ {
++ fprintf (stderr, &quot;Failed to open terminal.&quot;);
++ return -1;
++ }
++ }
++ }
++ }
++
++ SLang_Abort_Char = abort_char;
++
++ /* Some systems may not permit signals to be blocked. As a result, the
++ * return code must be checked.
++ */
++ while (-1 == GET_TERMIOS(SLang_TT_Read_FD, &amp;Old_TTY))
++ {
++ if (errno != EINTR)
++ {
++ SLsig_unblock_signals ();
++ return -1;
++ }
++ }
++
++ while (-1 == GET_TERMIOS(SLang_TT_Read_FD, &amp;newtty))
++ {
++ if (errno != EINTR)
++ {
++ SLsig_unblock_signals ();
++ return -1;
++ }
++ }
++
++#ifndef HAVE_TERMIOS_H
++ newtty.s.sg_flags &amp;= ~(ECHO);
++ newtty.s.sg_flags &amp;= ~(CRMOD);
++ /* if (Flow_Control == 0) newtty.s.sg_flags &amp;= ~IXON; */
++ newtty.t.t_eofc = 1;
++ if (abort_char == -1) SLang_Abort_Char = newtty.t.t_intrc;
++ newtty.t.t_intrc = SLang_Abort_Char; /* ^G */
++ newtty.t.t_quitc = 255;
++ newtty.lt.t_suspc = 255; /* to ignore ^Z */
++ newtty.lt.t_dsuspc = 255; /* to ignore ^Y */
++ newtty.lt.t_lnextc = 255;
++ newtty.s.sg_flags |= CBREAK; /* do I want cbreak or raw????? */
++#else
++
++ /* get baud rate */
++
++ newtty.c_iflag &amp;= ~(ECHO | INLCR | ICRNL);
++#ifdef ISTRIP
++ /* newtty.c_iflag &amp;= ~ISTRIP; */
++#endif
++ if (opost == 0) newtty.c_oflag &amp;= ~OPOST;
++
++ set_baud_rate (&amp;newtty);
++
++ if (no_flow_control) newtty.c_iflag &amp;= ~IXON; else newtty.c_iflag |= IXON;
++
++ newtty.c_cc[VEOF] = 1;
++ newtty.c_cc[VMIN] = 1;
++ newtty.c_cc[VTIME] = 0;
++ newtty.c_lflag = ISIG | NOFLSH;
++ if (abort_char == -1) SLang_Abort_Char = newtty.c_cc[VINTR];
++ newtty.c_cc[VINTR] = SLang_Abort_Char; /* ^G */
++ newtty.c_cc[VQUIT] = NULL_VALUE;
++ newtty.c_cc[VSUSP] = NULL_VALUE; /* to ignore ^Z */
++#ifdef VDSUSP
++ newtty.c_cc[VDSUSP] = NULL_VALUE; /* to ignore ^Y */
++#endif
++#ifdef VLNEXT
++ newtty.c_cc[VLNEXT] = NULL_VALUE; /* to ignore ^V ? */
++#endif
++#ifdef VSWTCH
++ newtty.c_cc[VSWTCH] = NULL_VALUE; /* to ignore who knows what */
++#endif
++#endif /* NOT HAVE_TERMIOS_H */
++
++ while (-1 == SET_TERMIOS(SLang_TT_Read_FD, &amp;newtty))
++ {
++ if (errno != EINTR)
++ {
++ SLsig_unblock_signals ();
++ return -1;
++ }
++ }
++
++ TTY_Inited = 1;
++ SLsig_unblock_signals ();
++ return 0;
++}
++
++void SLtty_set_suspend_state (int mode)
++{
++ TTY_Termio_Type newtty;
++
++ SLsig_block_signals ();
++
++ if (TTY_Inited == 0)
++ {
++ SLsig_unblock_signals ();
++ return;
++ }
++
++ while ((-1 == GET_TERMIOS (SLang_TT_Read_FD, &amp;newtty))
++ &amp;&amp; (errno == EINTR))
++ ;
++
++#ifndef HAVE_TERMIOS_H
++ /* I do not know if all systems define the t_dsuspc field */
++ if (mode == 0)
++ {
++ newtty.lt.t_suspc = 255;
++ newtty.lt.t_dsuspc = 255;
++ }
++ else
++ {
++ newtty.lt.t_suspc = Old_TTY.lt.t_suspc;
++ newtty.lt.t_dsuspc = Old_TTY.lt.t_dsuspc;
++ }
++#else
++ if (mode == 0)
++ {
++ newtty.c_cc[VSUSP] = NULL_VALUE;
++#ifdef VDSUSP
++ newtty.c_cc[VDSUSP] = NULL_VALUE;
++#endif
++ }
++ else
++ {
++ newtty.c_cc[VSUSP] = Old_TTY.c_cc[VSUSP];
++#ifdef VDSUSP
++ newtty.c_cc[VDSUSP] = Old_TTY.c_cc[VDSUSP];
++#endif
++ }
++#endif
++
++ while ((-1 == SET_TERMIOS (SLang_TT_Read_FD, &amp;newtty))
++ &amp;&amp; (errno == EINTR))
++ ;
++
++ SLsig_unblock_signals ();
++}
++
++void SLang_reset_tty (void)
++{
++ SLsig_block_signals ();
++
++ if (TTY_Inited == 0)
++ {
++ SLsig_unblock_signals ();
++ return;
++ }
++
++ while ((-1 == SET_TERMIOS(SLang_TT_Read_FD, &amp;Old_TTY))
++ &amp;&amp; (errno == EINTR))
++ ;
++
++ if (TTY_Open)
++ {
++ while ((-1 == close (SLang_TT_Read_FD))
++ &amp;&amp; (errno == EINTR))
++ ;
++
++ TTY_Open = 0;
++ SLang_TT_Read_FD = -1;
++ }
++
++ TTY_Inited = 0;
++ SLsig_unblock_signals ();
++}
++
++static void default_sigint (int sig)
++{
++ sig = errno; /* use parameter */
++
++ SLKeyBoard_Quit = 1;
++ if (SLang_Ignore_User_Abort == 0) SLang_Error = SL_USER_BREAK;
++ SLsignal_intr (SIGINT, default_sigint);
++ errno = sig;
++}
++
++int SLang_set_abort_signal (void (*hand)(int))
++{
++ int save_errno = errno;
++ SLSig_Fun_Type *f;
++
++ if (hand == NULL) hand = default_sigint;
++ f = SLsignal_intr (SIGINT, hand);
++
++ errno = save_errno;
++
++ if (f == (SLSig_Fun_Type *) SIG_ERR)
++ return -1;
++
++ return 0;
++}
++
++#ifndef FD_SET
++#define FD_SET(fd, tthis) *(tthis) = 1 &lt;&lt; (fd)
++#define FD_ZERO(tthis) *(tthis) = 0
++#define FD_ISSET(fd, tthis) (*(tthis) &amp; (1 &lt;&lt; fd))
++typedef int fd_set;
++#endif
++
++static fd_set Read_FD_Set;
++
++/* HACK: If &gt; 0, use 1/10 seconds. If &lt; 0, use 1/1000 seconds */
++
++int _SLsys_input_pending(int tsecs)
++{
++ struct timeval wait;
++ long usecs, secs;
++
++ if (TTY_Inited == 0) return -1;
++
++ if (tsecs &gt;= 0)
++ {
++ secs = tsecs / 10;
++ usecs = (tsecs % 10) * 100000;
++ }
++ else
++ {
++ tsecs = -tsecs;
++ secs = tsecs / 1000;
++ usecs = (tsecs % 1000) * 1000;
++ }
++
++ wait.tv_sec = secs;
++ wait.tv_usec = usecs;
++
++ FD_ZERO(&amp;Read_FD_Set);
++ FD_SET(SLang_TT_Read_FD, &amp;Read_FD_Set);
++
++ return select(SLang_TT_Read_FD + 1, &amp;Read_FD_Set, NULL, NULL, &amp;wait);
++}
++
++int (*SLang_getkey_intr_hook) (void);
++
++static int handle_interrupt (void)
++{
++ if (SLang_getkey_intr_hook != NULL)
++ {
++ int save_tty_fd = SLang_TT_Read_FD;
++
++ if (-1 == (*SLang_getkey_intr_hook) ())
++ return -1;
++
++ if (save_tty_fd != SLang_TT_Read_FD)
++ return -1;
++ }
++
++ return 0;
++}
++
++unsigned int _SLsys_getkey (void)
++{
++ unsigned char c;
++
++ if (TTY_Inited == 0)
++ {
++ int ic = fgetc (stdin);
++ if (ic == EOF) return SLANG_GETKEY_ERROR;
++ return (unsigned int) ic;
++ }
++
++ while (1)
++ {
++ int ret;
++
++ if (SLKeyBoard_Quit)
++ return SLang_Abort_Char;
++
++ if (0 == (ret = _SLsys_input_pending (100)))
++ continue;
++
++ if (ret != -1)
++ break;
++
++ if (SLKeyBoard_Quit)
++ return SLang_Abort_Char;
++
++ if (errno == EINTR)
++ {
++ if (-1 == handle_interrupt ())
++ return SLANG_GETKEY_ERROR;
++
++ continue;
++ }
++
++ break; /* let read handle it */
++ }
++
++ while (1)
++ {
++ int status = read(SLang_TT_Read_FD, (char *) &amp;c, 1);
++
++ if (status &gt; 0)
++ break;
++
++ if (status == 0)
++ {
++ /* We are at the end of a file. Let application handle it. */
++ return SLANG_GETKEY_ERROR;
++ }
++
++ if (errno == EINTR)
++ {
++ if (-1 == handle_interrupt ())
++ return SLANG_GETKEY_ERROR;
++
++ if (SLKeyBoard_Quit)
++ return SLang_Abort_Char;
++
++ continue;
++ }
++#ifdef EAGAIN
++ if (errno == EAGAIN)
++ {
++ sleep (1);
++ continue;
++ }
++#endif
++#ifdef EWOULDBLOCK
++ if (errno == EWOULDBLOCK)
++ {
++ sleep (1);
++ continue;
++ }
++#endif
++#ifdef EIO
++ if (errno == EIO)
++ {
++ SLang_exit_error (&quot;_SLsys_getkey: EIO error.&quot;);
++ }
++#endif
++ return SLANG_GETKEY_ERROR;
++ }
++
++ return((unsigned int) c);
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slutty.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/slang/slxstrng.c
+===================================================================
+--- drakx/trunk/mdk-stage1/slang/slxstrng.c (rev 0)
++++ drakx/trunk/mdk-stage1/slang/slxstrng.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,43 @@
++/* Copyright (c) 1992, 1999, 2001 John E. Davis
++ * This file is part of the S-Lang library.
++ *
++ * You may distribute under the terms of either the GNU General Public
++ * License or the Perl Artistic License.
++ */
++
++/* These routines are simple and inefficient. They were designed to work on
++ * SunOS when using Electric Fence.
++ */
++
++#include &quot;slang.h&quot;
++#include &quot;_slang.h&quot;
++char *SLstrcpy(register char *aa, register char *b)
++{
++ char *a = aa;
++ while ((*a++ = *b++) != 0);
++ return aa;
++}
++
++int SLstrcmp(register char *a, register char *b)
++{
++ while (*a &amp;&amp; (*a == *b))
++ {
++ a++;
++ b++;
++ }
++ if (*a) return((unsigned char) *a - (unsigned char) *b);
++ else if (*b) return ((unsigned char) *a - (unsigned char) *b);
++ else return 0;
++}
++
++char *SLstrncpy(char *a, register char *b,register int n)
++{
++ register char *aa = a;
++ while ((n &gt; 0) &amp;&amp; *b)
++ {
++ *aa++ = *b++;
++ n--;
++ }
++ while (n-- &gt; 0) *aa++ = 0;
++ return (a);
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/slang/slxstrng.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/stage1.c
+===================================================================
+--- drakx/trunk/mdk-stage1/stage1.c (rev 0)
++++ drakx/trunk/mdk-stage1/stage1.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,478 @@
++/*
++ * Guillaume Cottenceau (was <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000-2004 Mandriva
++ *
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Portions from Erik Troan (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ewt at redhat.com</A>)
++ *
++ * Copyright 1996 Red Hat Software
++ *
++ */
++
++#include &lt;stdlib.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;sys/ioctl.h&gt;
++#include &lt;sys/mount.h&gt;
++#include &lt;string.h&gt;
++#include &lt;errno.h&gt;
++#include &lt;ctype.h&gt;
++#include &lt;stdarg.h&gt;
++#include &lt;signal.h&gt;
++#include &lt;linux/unistd.h&gt;
++#include &lt;libldetect.h&gt;
++
++#include &quot;stage1.h&quot;
++
++#include &quot;log.h&quot;
++#include &quot;probing.h&quot;
++#include &quot;frontend.h&quot;
++#include &quot;modules.h&quot;
++#include &quot;tools.h&quot;
++#include &quot;utils.h&quot;
++#include &quot;automatic.h&quot;
++#include &quot;mount.h&quot;
++#include &quot;thirdparty.h&quot;
++
++#ifdef ENABLE_PCMCIA
++#include &quot;pcmcia/pcmcia.h&quot;
++#endif
++
++#ifndef DISABLE_CDROM
++#include &quot;cdrom.h&quot;
++#endif
++
++#ifndef DISABLE_NETWORK
++#include &quot;network.h&quot;
++#endif
++
++#ifndef DISABLE_DISK
++#include &quot;disk.h&quot;
++#endif
++
++
++/************************************************************
++ * globals */
++
++
++
++void fatal_error(char *msg)
++{
++ printf(&quot;FATAL ERROR IN STAGE1: %s\n\nI can't recover from this.\nYou may reboot your system.\n&quot;, msg);
++ while (1);
++}
++
++
++/************************************************************
++ * special frontend functs
++ * (the principle is to not pollute frontend code with stage1-specific stuff) */
++
++void stg1_error_message(char *msg, ...)
++{
++ va_list args;
++ va_start(args, msg);
++ unset_automatic();
++ verror_message(msg, args);
++ va_end(args);
++}
++
++void stg1_fatal_message(char *msg, ...)
++{
++ va_list args;
++ va_start(args, msg);
++ unset_automatic();
++ verror_message(msg, args);
++ va_end(args);
++ exit(1);
++}
++
++void stg1_info_message(char *msg, ...)
++{
++ va_list args;
++ va_start(args, msg);
++ if (IS_AUTOMATIC) {
++ vlog_message(msg, args);
++ return;
++ }
++ vinfo_message(msg, args);
++ va_end(args);
++}
++
++
++#ifdef SPAWN_SHELL
++static pid_t shell_pid = 0;
++
++/************************************************************
++ * spawns a shell on console #2 */
++static void spawn_shell(void)
++{
++ int fd;
++ char * shell_name[] = { &quot;/sbin/sh&quot;, NULL };
++
++ log_message(&quot;spawning a shell&quot;);
++
++ if (!IS_TESTING) {
++ fd = open(&quot;/dev/tty2&quot;, O_RDWR);
++ if (fd == -1) {
++ log_message(&quot;cannot open /dev/tty2 -- no shell will be provided&quot;);
++ return;
++ }
++ else if (access(shell_name[0], X_OK)) {
++ log_message(&quot;cannot open shell - %s doesn't exist&quot;, shell_name[0]);
++ return;
++ }
++
++ if (!(shell_pid = fork())) {
++ dup2(fd, 0);
++ dup2(fd, 1);
++ dup2(fd, 2);
++
++ close(fd);
++ setsid();
++ if (ioctl(0, TIOCSCTTY, NULL))
++ log_perror(&quot;could not set new controlling tty&quot;);
++
++ execv(shell_name[0], shell_name);
++ log_message(&quot;execve of %s failed: %s&quot;, shell_name[0], strerror(errno));
++ exit(-1);
++ }
++
++ close(fd);
++ }
++}
++#endif
++
++#ifdef SPAWN_INTERACTIVE
++char * interactive_fifo = &quot;/tmp/stage1-fifo&quot;;
++static pid_t interactive_pid = 0;
++
++/* spawns my small interactive on console #6 */
++static void spawn_interactive(void)
++{
++ int fd;
++ char * dev = &quot;/dev/tty6&quot;;
++
++ printf(&quot;spawning my interactive on %s\n&quot;, dev);
++
++ if (!IS_TESTING) {
++ fd = open(dev, O_RDWR);
++ if (fd == -1) {
++ printf(&quot;cannot open %s -- no interactive\n&quot;, dev);
++ return;
++ }
++
++ if (mkfifo(interactive_fifo, O_RDWR)) {
++ printf(&quot;cannot create fifo -- no interactive\n&quot;);
++ return;
++ }
++
++ if (!(interactive_pid = fork())) {
++ int fif_out;
++
++ dup2(fd, 0);
++ dup2(fd, 1);
++ dup2(fd, 2);
++
++ close(fd);
++ setsid();
++ if (ioctl(0, TIOCSCTTY, NULL))
++ perror(&quot;could not set new controlling tty&quot;);
++
++ fif_out = open(interactive_fifo, O_WRONLY);
++ printf(&quot;Please enter your command (availables: [+,-] [rescue]).\n&quot;);
++
++ while (1) {
++ char s[50];
++ int i = 0;
++ printf(&quot;? &quot;);
++ fflush(stdout);
++ read(0, &amp;(s[i++]), 1);
++ fcntl(0, F_SETFL, O_NONBLOCK);
++ while (read(0, &amp;(s[i++]), 1) &gt; 0 &amp;&amp; i &lt; sizeof(s));
++ fcntl(0, F_SETFL, 0);
++ write(fif_out, s, i-2);
++ printf(&quot;Ok.\n&quot;);
++ }
++ }
++
++ close(fd);
++ }
++}
++#endif
++
++
++#ifdef ENABLE_PCMCIA
++static void handle_pcmcia(void)
++{
++ char * pcmcia_adapter;
++ if (kernel_version() == 2) {
++ stg1_error_message(&quot;We now use kernel pcmcia support and this won't work with a 2.2 kernel.&quot;);
++ return;
++ }
++
++ pcmcia_adapter = pcmcia_probe();
++ if (!pcmcia_adapter) {
++ log_message(&quot;no pcmcia adapter found&quot;);
++ return;
++ }
++ my_insmod(&quot;pcmcia_core&quot;, ANY_DRIVER_TYPE, NULL, 0);
++ my_insmod(pcmcia_adapter, ANY_DRIVER_TYPE, NULL, 0);
++ /* ds is an alias for pcmcia in recent 2.6 kernels
++ but we don't have modules.alias in install, so try to load both */
++ my_insmod(&quot;ds&quot;, ANY_DRIVER_TYPE, NULL, 0);
++ my_insmod(&quot;pcmcia&quot;, ANY_DRIVER_TYPE, NULL, 0);
++
++ /* setup a dynamic resource database for non statically mapped PCMCIA sockets */
++ pcmcia_socket_startup(-1);
++
++ add_to_env(&quot;PCMCIA&quot;, pcmcia_adapter);
++}
++#endif
++
++#ifndef ENABLE_NETWORK_STANDALONE
++static void handle_hid(void)
++{
++ struct hid_entries entry_list;
++ unsigned int i;
++
++ entry_list = hid_probe();
++ for (i = 0; i &lt; entry_list.nb; i++) {
++ if (entry_list.entries[i].module != NULL)
++ my_insmod(entry_list.entries[i].module, ANY_DRIVER_TYPE, NULL, 0);
++ }
++}
++
++
++/************************************************************
++ */
++
++static void method_select_and_prepare(void)
++{
++ enum return_type results;
++ char * choice;
++ char * means[10], * means_auto[10];
++ int i;
++
++#ifndef DISABLE_DISK
++ char * disk_install = &quot;Hard disk&quot;; char * disk_install_auto = &quot;disk&quot;;
++#endif
++#ifndef DISABLE_CDROM
++ char * cdrom_install = &quot;CDROM drive&quot;; char * cdrom_install_auto = &quot;cdrom&quot;;
++#endif
++#ifndef DISABLE_NETWORK
++ char * network_nfs_install = &quot;NFS server&quot;; char * network_nfs_install_auto = &quot;nfs&quot;;
++ char * network_ftp_install = &quot;FTP server&quot;; char * network_ftp_install_auto = &quot;ftp&quot;;
++ char * network_http_install = &quot;HTTP server&quot;; char * network_http_install_auto = &quot;http&quot;;
++#ifndef DISABLE_KA
++ char * network_ka_install = &quot;KA server&quot;; char * network_ka_install_auto = &quot;ka&quot;;
++#endif
++#endif
++ char * thirdparty_install = &quot;Load third party modules&quot;; char * thirdparty_install_auto = &quot;thirdparty&quot;;
++
++ i = 0;
++#ifndef DISABLE_NETWORK
++ means[i] = network_nfs_install; means_auto[i++] = network_nfs_install_auto;
++ means[i] = network_ftp_install; means_auto[i++] = network_ftp_install_auto;
++ means[i] = network_http_install; means_auto[i++] = network_http_install_auto;
++#ifndef DISABLE_KA
++ means[i] = network_ka_install; means_auto[i++] = network_ka_install_auto;
++#endif
++#endif
++#ifndef DISABLE_CDROM
++ means[i] = cdrom_install; means_auto[i++] = cdrom_install_auto;
++#endif
++#ifndef DISABLE_DISK
++ means[i] = disk_install; means_auto[i++] = disk_install_auto;
++#endif
++ means[i] = thirdparty_install; means_auto[i++] = thirdparty_install_auto;
++ means[i] = NULL;
++
++ unlink(IMAGE_LOCATION);
++
++ results = ask_from_list_auto(&quot;Please choose the installation method.&quot;, means, &amp;choice, &quot;method&quot;, means_auto);
++
++ if (results != RETURN_OK)
++ return method_select_and_prepare();
++
++#ifndef DISABLE_CDROM
++ if (!strcmp(choice, cdrom_install))
++ results = cdrom_prepare();
++#endif
++
++#ifndef DISABLE_DISK
++ if (!strcmp(choice, disk_install))
++ results = disk_prepare();
++#endif
++
++#ifndef DISABLE_NETWORK
++ if (!strcmp(choice, network_nfs_install))
++ results = nfs_prepare();
++
++ if (!strcmp(choice, network_ftp_install))
++ results = ftp_prepare();
++
++ if (!strcmp(choice, network_http_install))
++ results = http_prepare();
++
++#ifndef DISABLE_KA
++ if (!strcmp(choice, network_ka_install))
++ results = ka_prepare();
++#endif
++#endif
++
++ if (!strcmp(choice, thirdparty_install)) {
++ thirdparty_load_modules();
++ return method_select_and_prepare();
++ }
++
++ if (results != RETURN_OK)
++ return method_select_and_prepare();
++
++ /* try to find third party modules on the install media */
++ thirdparty_load_media_modules();
++}
++#endif
++
++static enum return_type create_initial_fs_symlinks(char* symlinks)
++{
++ FILE *f;
++ char buf[5000];
++
++ if (scall(!(f = fopen(symlinks, &quot;rb&quot;)), &quot;fopen&quot;))
++ return RETURN_ERROR;
++ while (fgets(buf, sizeof(buf), f)) {
++ char oldpath[500], newpath[500];
++ buf[strlen(buf)-1] = '\0'; // trim \n
++ if (sscanf(buf, &quot;%s %s&quot;, oldpath, newpath) != 2) {
++ sprintf(oldpath, &quot;%s%s&quot;, STAGE2_LOCATION, buf);
++ sprintf(newpath, &quot;%s&quot;, buf);
++ }
++ recursiveRemove_if_it_exists(newpath);
++ log_message(&quot;creating symlink %s -&gt; %s&quot;, oldpath, newpath);
++ if (scall(symlink(oldpath, newpath), &quot;symlink&quot;))
++ return RETURN_ERROR;
++ }
++ fclose(f);
++ return RETURN_OK;
++}
++
++void finish_preparing(void)
++{
++ recursiveRemove(&quot;/init&quot;);
++
++ if (create_initial_fs_symlinks(STAGE2_LOCATION &quot;/usr/share/symlinks&quot;) != RETURN_OK)
++ stg1_fatal_message(&quot;Fatal error finishing initialization.&quot;);
++
++ /* /tmp/syslog is used by the second init, so it must be copied now, not in stage2 */
++ /* we remove it to ensure the old one is not copied over it in stage2 */
++
++#ifdef SPAWN_SHELL
++ if (shell_pid != 0) {
++ int fd;
++ const char *clear = &quot;\033[H\033[J&quot;;
++ kill(shell_pid, 9);
++ log_message(&quot;killed shell&quot;);
++ fd = open(&quot;/dev/tty2&quot;, O_RDWR);
++ write(fd, clear, strlen(clear));
++ close(fd);
++ }
++#endif
++}
++
++int main(int argc __attribute__ ((unused)), char **argv __attribute__ ((unused)), char **env)
++{
++#ifdef ENABLE_NETWORK_STANDALONE
++ open_log();
++ init_frontend(&quot;&quot;);
++
++ unlink(&quot;/etc/resolv.conf&quot;); /* otherwise it is read-only */
++ set_param(MODE_AUTOMATIC);
++ grab_automatic_params(&quot;network:dhcp&quot;);
++
++ intf_select_and_up();
++ finish_frontend();
++ return 0;
++#else
++ if (getenv(&quot;DEBUGSTAGE1&quot;)) {
++ set_param(MODE_DEBUGSTAGE1);
++ set_param(MODE_TESTING);
++ }
++
++#ifdef SPAWN_INTERACTIVE
++ spawn_interactive();
++#endif
++
++ open_log();
++ log_message(&quot;welcome to the &quot; DISTRIB_NAME &quot; install (mdk-stage1, version &quot; DISTRIB_VERSION &quot; built &quot; __DATE__ &quot; &quot; __TIME__&quot;)&quot;);
++ process_cmdline();
++#ifdef SPAWN_SHELL
++ spawn_shell();
++#endif
++ init_modules_insmoding();
++ init_firmware_loader();
++ init_frontend(&quot;Welcome to &quot; DISTRIB_DESCR &quot;, &quot; __DATE__ &quot; &quot; __TIME__);
++
++ probe_that_type(VIRTIO_DEVICES, BUS_ANY);
++
++ /* load usb interface as soon as possible, helps usb mouse detection in stage2 */
++ probe_that_type(USB_CONTROLLERS, BUS_USB);
++
++ if (IS_THIRDPARTY)
++ thirdparty_load_modules();
++
++#ifdef ENABLE_PCMCIA
++ if (!IS_NOAUTO)
++ handle_pcmcia();
++#endif
++
++ handle_hid();
++
++ if (IS_CHANGEDISK)
++ stg1_info_message(&quot;You are starting the installation with an alternate booting method. &quot;
++ &quot;Please change your disk, and insert the Installation disk.&quot;);
++
++ if (IS_RESCUE &amp;&amp; total_memory() &lt; MEM_LIMIT_RESCUE) {
++ stg1_error_message(&quot;You are starting the rescue with a low memory configuration. &quot;
++ &quot;Our experience shows that your system may crash at any point &quot;
++ &quot;or lock up for no apparent reason. Continue at &quot;
++ &quot;your own risk. Alternatively, you may reboot your system now.&quot;);
++ }
++
++ method_select_and_prepare();
++
++ thirdparty_destroy();
++
++ if (access(STAGE2_LOCATION, R_OK) != 0)
++ if (symlink(IMAGE_LOCATION_REL &quot;/&quot; LIVE_LOCATION_REL, STAGE2_LOCATION) != 0)
++ log_perror(&quot;symlink from &quot; IMAGE_LOCATION_REL &quot;/&quot; LIVE_LOCATION_REL &quot; to &quot; STAGE2_LOCATION &quot; failed&quot;);
++
++#ifdef SPAWN_INTERACTIVE
++ if (interactive_pid != 0)
++ kill(interactive_pid, 9);
++#endif
++
++ finish_preparing();
++
++ finish_frontend();
++ close_log();
++
++ if (IS_RESCUE)
++ return 66; /* ask init to exec new init */
++ else
++ return 0x35; /* ask init to run stage2 binary */
++#endif
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/stage1.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/stage1.h
+===================================================================
+--- drakx/trunk/mdk-stage1/stage1.h (rev 0)
++++ drakx/trunk/mdk-stage1/stage1.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,62 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Portions from Erik Troan (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ewt at redhat.com</A>)
++ *
++ * Copyright 1996 Red Hat Software
++ *
++ */
++
++#ifndef _STAGE1_H_
++#define _STAGE1_H_
++
++#include &quot;config-stage1.h&quot;
++#include &quot;params.h&quot;
++
++
++/* Some global stuff */
++
++extern char * interactive_fifo;
++
++#define MODE_TESTING (1 &lt;&lt; 0)
++#define MODE_RESCUE (1 &lt;&lt; 3)
++#define MODE_AUTOMATIC (1 &lt;&lt; 4)
++#define MODE_KEEP_MOUNTED (1 &lt;&lt; 5) /* for rescue */
++#define MODE_DEBUGSTAGE1 (1 &lt;&lt; 6)
++#define MODE_RAMDISK (1 &lt;&lt; 9)
++#define MODE_CHANGEDISK (1 &lt;&lt; 10)
++#define MODE_THIRDPARTY (1 &lt;&lt; 11)
++#define MODE_NOAUTO (1 &lt;&lt; 12)
++#define MODE_NETAUTO (1 &lt;&lt; 13)
++#define MODE_RECOVERY (1 &lt;&lt; 14)
++
++#define IS_TESTING (get_param(MODE_TESTING))
++#define IS_RESCUE (get_param(MODE_RESCUE))
++#define IS_AUTOMATIC (get_param(MODE_AUTOMATIC))
++#define IS_DEBUGSTAGE1 (get_param(MODE_DEBUGSTAGE1))
++#define IS_CHANGEDISK (get_param(MODE_CHANGEDISK))
++#define IS_THIRDPARTY (get_param(MODE_THIRDPARTY))
++#define IS_NOAUTO (get_param(MODE_NOAUTO))
++#define IS_NETAUTO (get_param(MODE_NETAUTO))
++#define IS_RECOVERY (get_param(MODE_RECOVERY))
++#define KEEP_MOUNTED (!IS_RESCUE || get_param(MODE_KEEP_MOUNTED))
++
++void fatal_error(char *msg) __attribute__ ((noreturn));
++
++
++void stg1_error_message(char *msg, ...) __attribute__ ((format (printf, 1, 2)));
++void stg1_info_message(char *msg, ...) __attribute__ ((format (printf, 1, 2)));
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/stage1.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/stdio-frontend.c
+===================================================================
+--- drakx/trunk/mdk-stage1/stdio-frontend.c (rev 0)
++++ drakx/trunk/mdk-stage1/stdio-frontend.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,357 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++
++/*
++ * Each different frontend must implement all functions defined in frontend.h
++ */
++
++
++#include &lt;stdlib.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;string.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;stdarg.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;sys/ioctl.h&gt;
++#include &lt;termios.h&gt;
++
++#include &lt;probing.h&gt;
++
++#include &quot;frontend.h&quot;
++#include &quot;utils.h&quot;
++
++void init_frontend(char * welcome_msg)
++{
++ printf(welcome_msg);
++ printf(&quot;\n&quot;);
++}
++
++
++void finish_frontend(void)
++{
++}
++
++static void get_any_response(void)
++{
++ unsigned char t;
++ printf(&quot;\n\t(press &lt;enter&gt; to proceed)&quot;);
++ fflush(stdout);
++ read(0, &amp;t, 1);
++ fcntl(0, F_SETFL, O_NONBLOCK);
++ while (read(0, &amp;t, 1) &gt; 0);
++ fcntl(0, F_SETFL, 0);
++}
++
++static int get_int_response(void)
++{
++ char s[50];
++ int j = 0;
++ unsigned int i = 0; /* (0) tied to Cancel */
++ fflush(stdout);
++ read(0, &amp;(s[i++]), 1);
++ fcntl(0, F_SETFL, O_NONBLOCK);
++ do {
++ int v = s[i-1];
++ if (v &gt;= '0' &amp;&amp; v &lt;= '9')
++ j = j*10 + (v - '0');
++ } while (read(0, &amp;(s[i++]), 1) &gt; 0 &amp;&amp; i &lt; sizeof(s));
++ fcntl(0, F_SETFL, 0);
++ return j;
++}
++
++static char * get_string_response(char * initial_string)
++{
++ /* I won't use a scanf/%s since I also want the null string to be accepted -- also, I want the initial_string */
++ char s[500];
++ int i = 0;
++ char buf[10];
++ int b_index = 0;
++ char b;
++
++ struct termios t;
++
++ memset(s, '\0', sizeof(s));
++
++ if (initial_string) {
++ printf(initial_string);
++ strcpy(s, initial_string);
++ i = strlen(s);
++ }
++
++ /* from ncurses/tinfo/lib_raw.c:(cbreak) */
++ tcgetattr(0, &amp;t);
++ t.c_lflag &amp;= ~ICANON;
++ t.c_lflag |= ISIG;
++ t.c_lflag &amp;= ~ECHO;
++ t.c_iflag &amp;= ~ICRNL;
++ t.c_cc[VMIN] = 1;
++ t.c_cc[VTIME] = 0;
++ tcsetattr(0, TCSADRAIN, &amp;t);
++
++ fflush(stdout);
++
++ fcntl(0, F_SETFL, O_NONBLOCK);
++
++ while (1) {
++ if (read(0, &amp;b, 1) &gt; 0) {
++ if (b_index == 1) {
++ if (b == 91) {
++ buf[b_index] = b;
++ b_index++;
++ continue;
++ }
++ else
++ b_index = 0;
++ }
++ if (b_index == 2) {
++ if (b == 67) {
++ if (s[i] != '\0') {
++ printf(&quot;\033[C&quot;);
++ i++;
++ }
++ }
++ if (b == 68) {
++ if (i &gt; 0) {
++ printf(&quot;\033[D&quot;);
++ i--;
++ }
++ }
++ b_index = 0;
++ continue;
++ }
++
++ if (b == 13)
++ break;
++ if (b == 127) {
++ if (i &gt; 0) {
++ printf(&quot;\033[D&quot;);
++ printf(&quot; &quot;);
++ printf(&quot;\033[D&quot;);
++ if (s[i] == '\0')
++ s[i-1] = '\0';
++ else
++ s[i-1] = ' ';
++ i--;
++ }
++ } else if (b == 27) {
++ buf[b_index] = b;
++ b_index++;
++ } else {
++ printf(&quot;%c&quot;, b);
++ s[i] = b;
++ i++;
++ }
++ }
++ }
++
++ t.c_lflag |= ICANON;
++ t.c_lflag |= ECHO;
++ t.c_iflag |= ICRNL;
++ tcsetattr(0, TCSADRAIN, &amp;t);
++
++ fcntl(0, F_SETFL, 0);
++
++ printf(&quot;\n&quot;);
++ return strdup(s);
++}
++
++static void blocking_msg(char *type, char *fmt, va_list ap)
++{
++ printf(type);
++ vprintf(fmt, ap);
++ get_any_response();
++}
++
++void verror_message(char *msg, va_list ap)
++{
++ blocking_msg(&quot;&gt; Error! &quot;, msg, ap);
++}
++
++void vinfo_message(char *msg, va_list ap)
++{
++ blocking_msg(&quot;&gt; Notice: &quot;, msg, ap);
++}
++
++void vwait_message(char *msg, va_list ap)
++{
++ printf(&quot;Please wait: &quot;);
++ vprintf(msg, ap);
++ fflush(stdout);
++}
++
++void remove_wait_message(void)
++{
++ printf(&quot;\n&quot;);
++}
++
++
++static int size_progress;
++static int actually_drawn;
++#define PROGRESS_SIZE 45
++void init_progression_raw(char *msg, int size)
++{
++ int i;
++ size_progress = size;
++ printf(&quot;%s &quot;, msg);
++ if (size) {
++ actually_drawn = 0;
++ for (i=0; i&lt;PROGRESS_SIZE; i++)
++ printf(&quot;.&quot;);
++ printf(&quot;]\033[G%s [&quot;, msg); /* only works on ANSI-compatibles */
++ fflush(stdout);
++ } else
++ printf(&quot;\n&quot;);
++}
++
++void update_progression_raw(int current_size)
++{
++ if (size_progress) {
++ if (current_size &gt; size_progress)
++ current_size = size_progress;
++ while ((int)((current_size*PROGRESS_SIZE)/size_progress) &gt; actually_drawn) {
++ printf(&quot;*&quot;);
++ actually_drawn++;
++ }
++ } else
++ printf(&quot;\033[GStatus: [%8d] bytes loaded...&quot;, current_size);
++
++ fflush(stdout);
++}
++
++void end_progression_raw(void)
++{
++ if (size_progress) {
++ update_progression_raw(size_progress);
++ printf(&quot;]\n&quot;);
++ } else
++ printf(&quot; done.\n&quot;);
++}
++
++
++enum return_type ask_from_list_index(char *msg, char ** elems, char ** elems_comments, int *answer)
++{
++ int justify_number = 1;
++ void print_choice_number(int i) {
++ char tmp[500];
++ snprintf(tmp, sizeof(tmp), &quot;[%%%dd]&quot;, justify_number);
++ printf(tmp, i);
++ }
++ int i = 1;
++ int j = 0;
++
++ if (string_array_length(elems) &gt;= 10)
++ justify_number = 2;
++
++ i = 1;
++
++ printf(&quot;&gt; %s\n&quot;, msg);
++ print_choice_number(0);
++ printf(&quot; Cancel&quot;);
++
++ while (elems &amp;&amp; *elems) {
++ if (elems_comments &amp;&amp; *elems_comments) {
++ printf(&quot;\n&quot;);
++ print_choice_number(i);
++ printf(&quot; %s (%s)&quot;, *elems, *elems_comments);
++ j = 0;
++ } else {
++ if (j == 0)
++ printf(&quot;\n&quot;);
++ print_choice_number(i);
++ printf(&quot; %-14s &quot;, *elems);
++ j++;
++ }
++ if (j == 4)
++ j = 0;
++
++ if (elems_comments)
++ elems_comments++;
++ i++;
++ elems++;
++ }
++
++ printf(&quot;\n? &quot;);
++
++ j = get_int_response();
++
++ if (j == 0)
++ return RETURN_BACK;
++
++ if (j &gt;= 1 &amp;&amp; j &lt;= i) {
++ *answer = j - 1;
++ return RETURN_OK;
++ }
++
++ return RETURN_ERROR;
++}
++
++
++enum return_type ask_yes_no(char *msg)
++{
++ int j;
++
++ printf(&quot;&gt; %s\n[0] Yes [1] No [2] Back\n? &quot;, msg);
++
++ j = get_int_response();
++
++ if (j == 0)
++ return RETURN_OK;
++ else if (j == 2)
++ return RETURN_BACK;
++ else return RETURN_ERROR;
++}
++
++
++enum return_type ask_from_entries(char *msg, char ** questions, char *** answers, int entry_size UNUSED, void (*callback_func)(char ** strings) UNUSED)
++{
++ int j, i = 0;
++ char ** already_answers = NULL;
++
++ printf(&quot;&gt; %s\n&quot;, msg);
++
++ while (questions &amp;&amp; *questions) {
++ printf(&quot;(%c) %s\n&quot;, i + 'a', *questions);
++ i++;
++ questions++;
++ }
++
++ if (*answers == NULL)
++ *answers = (char **) malloc(sizeof(char *) * i);
++ else
++ already_answers = *answers;
++
++ while (1) {
++ int r;
++ for (j = 0 ; j &lt; i ; j++) {
++ printf(&quot;(%c) ? &quot;, j + 'a');
++ if (already_answers &amp;&amp; *already_answers) {
++ (*answers)[j] = get_string_response(*already_answers);
++ already_answers++;
++ } else
++ (*answers)[j] = get_string_response(NULL);
++
++ }
++ printf(&quot;[0] Cancel [1] Accept [2] Re-enter answers\n? &quot;);
++ r = get_int_response();
++ if (r == 0)
++ return RETURN_BACK;
++ if (r == 1)
++ return RETURN_OK;
++ }
++}
++
++
++void suspend_to_console(void) {}
++void resume_from_suspend(void) {}
+
+
+Property changes on: drakx/trunk/mdk-stage1/stdio-frontend.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/sysfs/Makefile
+===================================================================
+--- drakx/trunk/mdk-stage1/sysfs/Makefile (rev 0)
++++ drakx/trunk/mdk-stage1/sysfs/Makefile 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,39 @@
++ #******************************************************************************
++ #
++ # Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ # Olivier Blin (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">blino at mandriva.com</A>)
++ #
++ # Copyright 2006 Mandriva
++ #
++ # This software may be freely redistributed under the terms of the GNU
++ # public license.
++ #
++ # You should have received a copy of the GNU General Public License
++ # along with this program; if not, write to the Free Software
++ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ #
++ #*****************************************************************************
++
++# minimal sysfs library ripped from sysfsutils-2.0.0
++
++top_dir = ..
++
++include $(top_dir)/Makefile.common
++
++TARGET = libsysfs.a
++
++all: $(TARGET)
++
++clean:
++ rm -f *.o $(TARGET)
++
++FLAGS = -D__linux__ -Wall -Werror -Wno-deprecated-declarations -Os -fomit-frame-pointer -pipe -c -I.. -D_BSD_SOURCE
++
++OBJS = sysfs_attr.o sysfs_utils.o
++
++$(TARGET): $(OBJS)
++ ar -cru $@ $^
++ ranlib $@
++
++$(OBJS): %.o: %.c
++ $(DIET) gcc $(FLAGS) $(INCLUDES) -c $&lt; -o $@
+
+
+Property changes on: drakx/trunk/mdk-stage1/sysfs/Makefile
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/sysfs/libsysfs.h
+===================================================================
+--- drakx/trunk/mdk-stage1/sysfs/libsysfs.h (rev 0)
++++ drakx/trunk/mdk-stage1/sysfs/libsysfs.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,90 @@
++/*
++ * libsysfs.h
++ *
++ * Header Definitions for libsysfs
++ *
++ * Copyright (C) IBM Corp. 2004-2005
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++#ifndef _LIBSYSFS_H_
++#define _LIBSYSFS_H_
++
++#include &lt;sys/types.h&gt;
++#include &lt;string.h&gt;
++
++#define SYSFS_FSTYPE_NAME &quot;sysfs&quot;
++#define SYSFS_PROC_MNTS &quot;/proc/mounts&quot;
++#define SYSFS_BUS_NAME &quot;bus&quot;
++#define SYSFS_CLASS_NAME &quot;class&quot;
++#define SYSFS_BLOCK_NAME &quot;block&quot;
++#define SYSFS_DEVICES_NAME &quot;devices&quot;
++#define SYSFS_DRIVERS_NAME &quot;drivers&quot;
++#define SYSFS_MODULE_NAME &quot;module&quot;
++#define SYSFS_NAME_ATTRIBUTE &quot;name&quot;
++#define SYSFS_MOD_PARM_NAME &quot;parameters&quot;
++#define SYSFS_MOD_SECT_NAME &quot;sections&quot;
++#define SYSFS_UNKNOWN &quot;unknown&quot;
++#define SYSFS_PATH_ENV &quot;SYSFS_PATH&quot;
++
++#define SYSFS_PATH_MAX 256
++#define SYSFS_NAME_LEN 64
++#define SYSFS_BUS_ID_SIZE 32
++
++/* mount path for sysfs, can be overridden by exporting SYSFS_PATH */
++#define SYSFS_MNT_PATH &quot;/sys&quot;
++
++enum sysfs_attribute_method {
++ SYSFS_METHOD_SHOW = 0x01, /* attr can be read by user */
++ SYSFS_METHOD_STORE = 0x02, /* attr can be changed by user */
++};
++
++/*
++ * NOTE:
++ * 1. We have the statically allocated &quot;name&quot; as the first element of all
++ * the structures. This feature is used in the &quot;sorter&quot; function for dlists
++ * 2. As is the case with attrlist
++ * 3. As is the case with path
++ */
++struct sysfs_attribute {
++ char name[SYSFS_NAME_LEN];
++ char path[SYSFS_PATH_MAX];
++ char *value;
++ unsigned short len; /* value length */
++ enum sysfs_attribute_method method; /* show and store */
++};
++
++#ifdef __cplusplus
++extern &quot;C&quot; {
++#endif
++
++/*
++ * Function Prototypes
++ */
++extern int sysfs_get_name_from_path(const char *path, char *name, size_t len);
++
++/* sysfs directory and file access */
++extern void sysfs_close_attribute(struct sysfs_attribute *sysattr);
++extern struct sysfs_attribute *sysfs_open_attribute(const char *path);
++extern int sysfs_read_attribute(struct sysfs_attribute *sysattr);
++extern int sysfs_write_attribute(struct sysfs_attribute *sysattr,
++ const char *new_value, size_t len);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _LIBSYSFS_H_ */
+
+
+Property changes on: drakx/trunk/mdk-stage1/sysfs/libsysfs.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/sysfs/sysfs.h
+===================================================================
+--- drakx/trunk/mdk-stage1/sysfs/sysfs.h (rev 0)
++++ drakx/trunk/mdk-stage1/sysfs/sysfs.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,64 @@
++/*
++ * sysfs.h
++ *
++ * Internal Header Definitions for libsysfs
++ *
++ * Copyright (C) IBM Corp. 2003-2005
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++#ifndef _SYSFS_H_
++#define _SYSFS_H_
++
++#include &lt;stdio.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;string.h&gt;
++#include &lt;ctype.h&gt;
++#include &lt;dirent.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;errno.h&gt;
++
++#define safestrcpy(to, from) strncpy(to, from, sizeof(to)-1)
++#define safestrcat(to, from) strncat(to, from, sizeof(to) - strlen(to)-1)
++
++#define safestrcpymax(to, from, max) \
++do { \
++ to[max-1] = '\0'; \
++ strncpy(to, from, max-1); \
++} while (0)
++
++#define safestrcatmax(to, from, max) \
++do { \
++ to[max-1] = '\0'; \
++ strncat(to, from, max - strlen(to)-1); \
++} while (0)
++
++extern struct sysfs_attribute *get_attribute(void *dev, const char *name);
++extern struct dlist *read_dir_subdirs(const char *path);
++extern struct dlist *read_dir_links(const char *path);
++extern struct dlist *get_dev_attributes_list(void *dev);
++extern struct dlist *get_attributes_list(struct dlist *alist, const char *path);
++
++/* Debugging */
++#ifdef DEBUG
++#define dprintf(format, arg...) fprintf(stderr, format, ## arg)
++#else
++#define dprintf(format, arg...) do { } while (0)
++#endif
++
++#endif /* _SYSFS_H_ */
+
+
+Property changes on: drakx/trunk/mdk-stage1/sysfs/sysfs.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/sysfs/sysfs_attr.c
+===================================================================
+--- drakx/trunk/mdk-stage1/sysfs/sysfs_attr.c (rev 0)
++++ drakx/trunk/mdk-stage1/sysfs/sysfs_attr.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,241 @@
++/*
++ * sysfs_dir.c
++ *
++ * Directory utility functions for libsysfs
++ *
++ * Copyright (C) IBM Corp. 2003-2005
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++#include &quot;libsysfs.h&quot;
++#include &quot;sysfs.h&quot;
++
++/**
++ * sysfs_close_attribute: closes and cleans up attribute
++ * @sysattr: attribute to close.
++ */
++void sysfs_close_attribute(struct sysfs_attribute *sysattr)
++{
++ if (sysattr) {
++ if (sysattr-&gt;value)
++ free(sysattr-&gt;value);
++ free(sysattr);
++ }
++}
++
++/**
++ * alloc_attribute: allocates and initializes attribute structure
++ * returns struct sysfs_attribute with success and NULL with error.
++ */
++static struct sysfs_attribute *alloc_attribute(void)
++{
++ return (struct sysfs_attribute *)
++ calloc(1, sizeof(struct sysfs_attribute));
++}
++
++/**
++ * sysfs_open_attribute: creates sysfs_attribute structure
++ * @path: path to attribute.
++ * returns sysfs_attribute struct with success and NULL with error.
++ */
++struct sysfs_attribute *sysfs_open_attribute(const char *path)
++{
++ struct sysfs_attribute *sysattr = NULL;
++ struct stat fileinfo;
++
++ if (!path) {
++ errno = EINVAL;
++ return NULL;
++ }
++ sysattr = alloc_attribute();
++ if (!sysattr) {
++ dprintf(&quot;Error allocating attribute at %s\n&quot;, path);
++ return NULL;
++ }
++ if (sysfs_get_name_from_path(path, sysattr-&gt;name,
++ SYSFS_NAME_LEN) != 0) {
++ dprintf(&quot;Error retrieving attrib name from path: %s\n&quot;, path);
++ sysfs_close_attribute(sysattr);
++ return NULL;
++ }
++ safestrcpy(sysattr-&gt;path, path);
++ if ((stat(sysattr-&gt;path, &amp;fileinfo)) != 0) {
++ dprintf(&quot;Stat failed: No such attribute?\n&quot;);
++ sysattr-&gt;method = 0;
++ free(sysattr);
++ sysattr = NULL;
++ } else {
++ if (fileinfo.st_mode &amp; S_IRUSR)
++ sysattr-&gt;method |= SYSFS_METHOD_SHOW;
++ if (fileinfo.st_mode &amp; S_IWUSR)
++ sysattr-&gt;method |= SYSFS_METHOD_STORE;
++ }
++
++ return sysattr;
++}
++
++/**
++ * sysfs_read_attribute: reads value from attribute
++ * @sysattr: attribute to read
++ * returns 0 with success and -1 with error.
++ */
++int sysfs_read_attribute(struct sysfs_attribute *sysattr)
++{
++ char *fbuf = NULL;
++ char *vbuf = NULL;
++ ssize_t length = 0;
++ long pgsize = 0;
++ int fd;
++
++ if (!sysattr) {
++ errno = EINVAL;
++ return -1;
++ }
++ if (!(sysattr-&gt;method &amp; SYSFS_METHOD_SHOW)) {
++ dprintf(&quot;Show method not supported for attribute %s\n&quot;,
++ sysattr-&gt;path);
++ errno = EACCES;
++ return -1;
++ }
++ pgsize = getpagesize();
++ fbuf = (char *)calloc(1, pgsize+1);
++ if (!fbuf) {
++ dprintf(&quot;calloc failed\n&quot;);
++ return -1;
++ }
++ if ((fd = open(sysattr-&gt;path, O_RDONLY)) &lt; 0) {
++ dprintf(&quot;Error reading attribute %s\n&quot;, sysattr-&gt;path);
++ free(fbuf);
++ return -1;
++ }
++ length = read(fd, fbuf, pgsize);
++ if (length &lt; 0) {
++ dprintf(&quot;Error reading from attribute %s\n&quot;, sysattr-&gt;path);
++ close(fd);
++ free(fbuf);
++ return -1;
++ }
++ if (sysattr-&gt;len &gt; 0) {
++ if ((sysattr-&gt;len == length) &amp;&amp;
++ (!(strncmp(sysattr-&gt;value, fbuf, length)))) {
++ close(fd);
++ free(fbuf);
++ return 0;
++ }
++ free(sysattr-&gt;value);
++ }
++ sysattr-&gt;len = length;
++ close(fd);
++ vbuf = (char *)realloc(fbuf, length+1);
++ if (!vbuf) {
++ dprintf(&quot;realloc failed\n&quot;);
++ free(fbuf);
++ return -1;
++ }
++ sysattr-&gt;value = vbuf;
++
++ return 0;
++}
++
++/**
++ * sysfs_write_attribute: write value to the attribute
++ * @sysattr: attribute to write
++ * @new_value: value to write
++ * @len: length of &quot;new_value&quot;
++ * returns 0 with success and -1 with error.
++ */
++int sysfs_write_attribute(struct sysfs_attribute *sysattr,
++ const char *new_value, size_t len)
++{
++ int fd;
++ int length;
++
++ if (!sysattr || !new_value || len == 0) {
++ errno = EINVAL;
++ return -1;
++ }
++
++ if (!(sysattr-&gt;method &amp; SYSFS_METHOD_STORE)) {
++ dprintf (&quot;Store method not supported for attribute %s\n&quot;,
++ sysattr-&gt;path);
++ errno = EACCES;
++ return -1;
++ }
++ if (sysattr-&gt;method &amp; SYSFS_METHOD_SHOW) {
++ /*
++ * read attribute again to see if we can get an updated value
++ */
++ if ((sysfs_read_attribute(sysattr))) {
++ dprintf(&quot;Error reading attribute\n&quot;);
++ return -1;
++ }
++ if ((strncmp(sysattr-&gt;value, new_value, sysattr-&gt;len)) == 0 &amp;&amp;
++ (len == sysattr-&gt;len)) {
++ dprintf(&quot;Attr %s already has the requested value %s\n&quot;,
++ sysattr-&gt;name, new_value);
++ return 0;
++ }
++ }
++ /*
++ * open O_WRONLY since some attributes have no &quot;read&quot; but only
++ * &quot;write&quot; permission
++ */
++ if ((fd = open(sysattr-&gt;path, O_WRONLY)) &lt; 0) {
++ dprintf(&quot;Error reading attribute %s\n&quot;, sysattr-&gt;path);
++ return -1;
++ }
++
++ length = write(fd, new_value, len);
++ if (length &lt; 0) {
++ dprintf(&quot;Error writing to the attribute %s - invalid value?\n&quot;,
++ sysattr-&gt;name);
++ close(fd);
++ return -1;
++ } else if ((unsigned int)length != len) {
++ dprintf(&quot;Could not write %zd bytes to attribute %s\n&quot;,
++ len, sysattr-&gt;name);
++ /*
++ * since we could not write user supplied number of bytes,
++ * restore the old value if one available
++ */
++ if (sysattr-&gt;method &amp; SYSFS_METHOD_SHOW) {
++ length = write(fd, sysattr-&gt;value, sysattr-&gt;len);
++ close(fd);
++ return -1;
++ }
++ }
++
++ /*
++ * Validate length that has been copied. Alloc appropriate area
++ * in sysfs_attribute. Verify first if the attribute supports reading
++ * (show method). If it does not, do not bother
++ */
++ if (sysattr-&gt;method &amp; SYSFS_METHOD_SHOW) {
++ if (length != sysattr-&gt;len) {
++ sysattr-&gt;value = (char *)realloc
++ (sysattr-&gt;value, length);
++ sysattr-&gt;len = length;
++ safestrcpymax(sysattr-&gt;value, new_value, length);
++ } else {
++ /*&quot;length&quot; of the new value is same as old one */
++ safestrcpymax(sysattr-&gt;value, new_value, length);
++ }
++ }
++
++ close(fd);
++ return 0;
++}
++
+
+
+Property changes on: drakx/trunk/mdk-stage1/sysfs/sysfs_attr.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/sysfs/sysfs_utils.c
+===================================================================
+--- drakx/trunk/mdk-stage1/sysfs/sysfs_utils.c (rev 0)
++++ drakx/trunk/mdk-stage1/sysfs/sysfs_utils.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,59 @@
++/*
++ * sysfs_utils.c
++ *
++ * System utility functions for libsysfs
++ *
++ * Copyright (C) IBM Corp. 2003-2005
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++#include &quot;libsysfs.h&quot;
++#include &quot;sysfs.h&quot;
++
++/**
++ * sysfs_get_name_from_path: returns last name from a &quot;/&quot; delimited path
++ * @path: path to get name from
++ * @name: where to put name
++ * @len: size of name
++ */
++int sysfs_get_name_from_path(const char *path, char *name, size_t len)
++{
++ char tmp[SYSFS_PATH_MAX];
++ char *n = NULL;
++
++ if (!path || !name || len == 0) {
++ errno = EINVAL;
++ return -1;
++ }
++ memset(tmp, 0, SYSFS_PATH_MAX);
++ safestrcpy(tmp, path);
++ n = strrchr(tmp, '/');
++ if (n == NULL) {
++ errno = EINVAL;
++ return -1;
++ }
++ if (*(n+1) == '\0') {
++ *n = '\0';
++ n = strrchr(tmp, '/');
++ if (n == NULL) {
++ errno = EINVAL;
++ return -1;
++ }
++ }
++ n++;
++ safestrcpymax(name, n, len);
++ return 0;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/sysfs/sysfs_utils.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/thirdparty.c
+===================================================================
+--- drakx/trunk/mdk-stage1/thirdparty.c (rev 0)
++++ drakx/trunk/mdk-stage1/thirdparty.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,460 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ * Olivier Blin (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">oblin at mandriva.com</A>)
++ *
++ * Copyright 2005 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#include &lt;stdlib.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;string.h&gt;
++#include &lt;sys/mount.h&gt;
++#include &lt;sys/utsname.h&gt;
++
++#include &quot;stage1.h&quot;
++#include &quot;tools.h&quot;
++#include &quot;utils.h&quot;
++#include &quot;log.h&quot;
++#include &quot;modules.h&quot;
++#include &quot;mount.h&quot;
++#include &quot;frontend.h&quot;
++#include &quot;partition.h&quot;
++#include &quot;automatic.h&quot;
++#include &quot;probing.h&quot;
++
++#include &quot;thirdparty.h&quot;
++
++#define THIRDPARTY_MOUNT_LOCATION &quot;/tmp/thirdparty&quot;
++
++#define N_PCITABLE_ENTRIES 100
++static struct pcitable_entry pcitable[N_PCITABLE_ENTRIES];
++static int pcitable_len = 0;
++
++static enum return_type thirdparty_choose_device(char ** device, int probe_only)
++{
++ char ** medias, ** medias_models;
++ char ** ptr, ** ptr_models;
++#ifndef DISABLE_DISK
++ char ** disk_medias, ** disk_medias_models;
++ int disk_count;
++ char * parts[50];
++ char * parts_comments[50];
++#endif
++#ifndef DISABLE_CDROM
++ char ** cdrom_medias, ** cdrom_medias_models;
++ int cdrom_count;
++#endif
++ char * floppy_dev;
++ enum return_type results;
++ int count = 0;
++
++ wait_message(&quot;Looking for floppy, disk and cdrom devices ...&quot;);
++
++#ifndef DISABLE_DISK
++ disk_count = get_disks(&amp;disk_medias, &amp;disk_medias_models);
++ count += disk_count;
++#endif
++#ifndef DISABLE_CDROM
++ cdrom_count = get_cdroms(&amp;cdrom_medias, &amp;cdrom_medias_models);
++ count += cdrom_count;
++#endif
++
++ floppy_dev = floppy_device();
++ if (floppy_dev &amp;&amp; strstr(floppy_dev, &quot;/dev/&quot;) == floppy_dev) {
++ floppy_dev = floppy_dev + 5;
++ }
++ if (floppy_dev)
++ count += 1;
++
++ remove_wait_message();
++
++ if (count == 0) {
++ stg1_error_message(&quot;I can't find any floppy, disk or cdrom on this system. &quot;
++ &quot;No third-party kernel modules will be used.&quot;);
++ return RETURN_BACK;
++ }
++
++ if (probe_only) {
++#ifndef DISABLE_DISK
++ free(disk_medias);
++ free(disk_medias_models);
++#endif
++#ifndef DISABLE_CDROM
++ free(cdrom_medias);
++ free(cdrom_medias_models);
++#endif
++ return RETURN_OK;
++ }
++
++ ptr = medias = malloc((count + 1) * sizeof(char *));
++ ptr_models =medias_models = malloc((count + 1) * sizeof(char *));
++#ifndef DISABLE_DISK
++ memcpy(ptr, disk_medias, disk_count * sizeof(char *));
++ memcpy(ptr_models, disk_medias_models, disk_count * sizeof(char *));
++ free(disk_medias);
++ free(disk_medias_models);
++ ptr += disk_count;
++ ptr_models += disk_count;
++#endif
++#ifndef DISABLE_CDROM
++ memcpy(ptr, cdrom_medias, cdrom_count * sizeof(char *));
++ memcpy(ptr_models, cdrom_medias_models, cdrom_count * sizeof(char *));
++ free(cdrom_medias);
++ free(cdrom_medias_models);
++ cdrom_medias = ptr; /* used later to know if a cdrom is selected */
++ ptr += cdrom_count;
++ ptr_models += cdrom_count;
++#endif
++ if (floppy_dev) {
++ ptr[0] = floppy_dev;
++ ptr_models[0] = &quot;Floppy device&quot;;
++ ptr++;
++ ptr_models++;
++ }
++ ptr[0] = NULL;
++ ptr_models[0] = NULL;
++
++ if (count == 1) {
++ *device = medias[0];
++ } else {
++ results = ask_from_list_comments(&quot;If you want to insert third-party kernel modules, &quot;
++ &quot;please select the disk containing the modules.&quot;,
++ medias, medias_models, device);
++ if (results != RETURN_OK)
++ return results;
++ }
++
++ if (floppy_dev &amp;&amp; streq(*device, floppy_dev)) {
++ /* a floppy is selected, don't try to list partitions */
++ return RETURN_OK;
++ }
++
++#ifndef DISABLE_CDROM
++ for (ptr = cdrom_medias; ptr &lt; cdrom_medias + cdrom_count; ptr++) {
++ if (*device == *ptr) {
++ /* a cdrom is selected, don't try to list partitions */
++ log_message(&quot;thirdparty: a cdrom is selected, using it (%s)&quot;, *device);
++ return RETURN_OK;
++ }
++ }
++#endif
++
++#ifndef DISABLE_DISK
++ /* a disk or usb key is selected */
++ if (list_partitions(*device, parts, parts_comments)) {
++ stg1_error_message(&quot;Could not read partitions information.&quot;);
++ return RETURN_ERROR;
++ }
++
++ if (parts[0] == NULL) {
++ stg1_error_message(&quot;No partition found.&quot;);
++ return RETURN_ERROR;
++ }
++
++ /* only one partition has been discovered, don't ask which one to use */
++ if (parts[1] == NULL) {
++ log_message(&quot;thirdparty: found only one partition on device (%s)&quot;, parts[0]);
++ *device = parts[0];
++ return RETURN_OK;
++ }
++
++ results = ask_from_list_comments(&quot;Please select the partition containing &quot;
++ &quot;the third party modules.&quot;,
++ parts, parts_comments, device);
++ if (results == RETURN_OK)
++ return RETURN_OK;
++#endif
++
++ stg1_error_message(&quot;Sorry, no third party device can be used.&quot;);
++
++ return RETURN_BACK;
++}
++
++
++static enum return_type thirdparty_mount_device(char * device)
++{
++ log_message(&quot;third party: trying to mount device %s&quot;, device);
++ if (try_mount(device, THIRDPARTY_MOUNT_LOCATION) != 0) {
++ stg1_error_message(&quot;I can't mount the selected device (%s).&quot;, device);
++ return RETURN_ERROR;
++ }
++ return RETURN_OK;
++}
++
++
++static enum return_type thirdparty_prompt_modules(const char *modules_location, char ** modules_list)
++{
++ enum return_type results;
++ char final_name[500];
++ char *module_name;
++ int rc;
++ char * questions[] = { &quot;Options&quot;, NULL };
++ static char ** answers = NULL;
++
++ while (1) {
++ results = ask_from_list(&quot;Which driver would you like to insmod?&quot;, modules_list, &amp;module_name);
++ if (results != RETURN_OK)
++ break;
++
++ sprintf(final_name, &quot;%s/%s&quot;, modules_location, module_name);
++
++ results = ask_from_entries(&quot;Please enter the options:&quot;, questions, &amp;answers, 24, NULL);
++ if (results != RETURN_OK)
++ continue;
++
++ rc = insmod_local_file(final_name, answers[0]);
++ if (rc) {
++ log_message(&quot;\tfailed&quot;);
++ stg1_error_message(&quot;Insmod failed.&quot;);
++ }
++ }
++ return RETURN_OK;
++}
++
++
++static int pcitable_orderer(const void *a, const void *b)
++{
++ int ret;
++ struct pcitable_entry *ap = (struct pcitable_entry *)a;
++ struct pcitable_entry *bp = (struct pcitable_entry *)b;
++
++ if ((ret = ap-&gt;vendor - bp-&gt;vendor) != 0)
++ return ret;
++ if ((ret = ap-&gt;device - bp-&gt;device) != 0)
++ return ret;
++ if ((ret = ap-&gt;subvendor - bp-&gt;subvendor) != 0)
++ return ret;
++ if ((ret = ap-&gt;subdevice - bp-&gt;subdevice) != 0)
++ return ret;
++
++ return 0;
++}
++
++
++static void thirdparty_load_pcitable(const char *modules_location)
++{
++ char pcitable_filename[100];
++ FILE * f = NULL;
++
++ sprintf(pcitable_filename, &quot;%s/pcitable&quot;, modules_location);
++ if (!(f = fopen(pcitable_filename, &quot;rb&quot;))) {
++ log_message(&quot;third_party: no external pcitable found&quot;);
++ return;
++ }
++ pcitable_len = 0;
++ while (pcitable_len &lt; N_PCITABLE_ENTRIES) {
++ char buf[200];
++ struct pcitable_entry *e;
++ if (!fgets(buf, sizeof(buf), f)) break;
++ e = &amp;pcitable[pcitable_len++];
++ if (sscanf(buf, &quot;%hx\t%hx\t\&quot;%[^ \&quot;]\&quot;\t\&quot;%[^\&quot;]\&quot;&quot;, &amp;e-&gt;vendor, &amp;e-&gt;device, e-&gt;module, e-&gt;description) == 4)
++ e-&gt;subvendor = e-&gt;subdevice = PCITABLE_MATCH_ALL;
++ else
++ sscanf(buf, &quot;%hx\t%hx\t%x\t%x\t\&quot;%[^ \&quot;]\&quot;\t\&quot;%[^\&quot;]\&quot;&quot;, &amp;e-&gt;vendor, &amp;e-&gt;device, &amp;e-&gt;subvendor, &amp;e-&gt;subdevice, e-&gt;module, e-&gt;description);
++ }
++ fclose(f);
++
++ /* sort pcitable by most specialised entries first */
++ qsort(pcitable, pcitable_len, sizeof(pcitable[0]), pcitable_orderer);
++}
++
++
++static int thirdparty_is_detected(char *driver) {
++ int i, j;
++
++ for (i = 0; i &lt; detected_devices_len ; i++) {
++ /* first look for the IDs in the third-party pcitable */
++ for (j = 0; j &lt; pcitable_len ; j++) {
++ if (pcitable[j].vendor == detected_devices[i].vendor &amp;&amp;
++ pcitable[j].device == detected_devices[i].device &amp;&amp;
++ !strcmp(pcitable[j].module, driver)) {
++ const int subvendor = pcitable[j].subvendor;
++ const int subdevice = pcitable[j].subdevice;
++ if ((subvendor == PCITABLE_MATCH_ALL &amp;&amp; subdevice == PCITABLE_MATCH_ALL) ||
++ (subvendor == detected_devices[i].subvendor &amp;&amp; subdevice == detected_devices[i].subdevice)) {
++ log_message(&quot;probing: found device for module %s&quot;, driver);
++ return 1;
++ }
++ }
++ }
++ /* if not found, compare with the detected driver */
++ if (!strcmp(detected_devices[i].module, driver)) {
++ log_message(&quot;probing: found device for module %s&quot;, driver);
++ return 1;
++ }
++ }
++
++ return 0;
++}
++
++static enum return_type thirdparty_autoload_modules(const char *modules_location, char ** modules_list, FILE *f, int load_detected_only)
++{
++ while (1) {
++ char final_name[500];
++ char module[500];
++ char * options;
++ char ** entry = modules_list;
++
++ if (!fgets(module, sizeof(module), f)) break;
++ if (module[0] == '#' || strlen(module) == 0)
++ continue;
++
++ while (module[strlen(module)-1] == '\n')
++ module[strlen(module)-1] = '\0';
++ options = strchr(module, ' ');
++ if (options) {
++ options[0] = '\0';
++ options++;
++ }
++
++ if (load_detected_only &amp;&amp; !thirdparty_is_detected(module)) {
++ log_message(&quot;third party: no device detected for module %s, skipping&quot;, module);
++ continue;
++ }
++
++ log_message(&quot;third party: auto-loading module (%s) with options (%s)&quot;, module, options);
++ while (entry &amp;&amp; *entry) {
++ if (!strncmp(*entry, module, strlen(module)) &amp;&amp; (*entry)[strlen(module)] == '.') {
++ sprintf(final_name, &quot;%s/%s&quot;, modules_location, *entry);
++ if (insmod_local_file(final_name, options)) {
++ log_message(&quot;\t%s (third party media): failed&quot;, *entry);
++ stg1_error_message(&quot;Insmod %s (third party media) failed.&quot;, *entry);
++ }
++ break;
++ }
++ entry++;
++ }
++ if (!entry || !*entry) {
++ enum insmod_return ret = my_insmod(module, ANY_DRIVER_TYPE, options, 0);
++ if (ret != INSMOD_OK) {
++ log_message(&quot;\t%s (marfile): failed&quot;, module);
++ stg1_error_message(&quot;Insmod %s (marfile) failed.&quot;, module);
++ }
++ }
++ }
++
++ return RETURN_OK;
++}
++
++static enum return_type thirdparty_try_directory(char * root_directory, int interactive) {
++ char modules_location[100];
++ char modules_location_release[100];
++ char *list_filename;
++ FILE *f_load, *f_detect;
++ char **modules_list, **modules_list_release;
++ struct utsname kernel_uname;
++
++ /* look first in the specific third-party directory */
++ snprintf(modules_location, sizeof(modules_location), &quot;%s&quot; THIRDPARTY_DIRECTORY, root_directory);
++ modules_list = list_directory(modules_location);
++
++ /* if it's empty, look in the root of selected device */
++ if (!modules_list || !modules_list[0]) {
++ modules_location[strlen(root_directory)] = '\0';
++ modules_list = list_directory(modules_location);
++ if (interactive)
++ add_to_env(&quot;THIRDPARTY_DIR&quot;, &quot;&quot;);
++ } else {
++ if (interactive)
++ add_to_env(&quot;THIRDPARTY_DIR&quot;, THIRDPARTY_DIRECTORY);
++ }
++
++ if (uname(&amp;kernel_uname)) {
++ log_perror(&quot;uname failed&quot;);
++ return RETURN_ERROR;
++ }
++ snprintf(modules_location_release, sizeof(modules_location_release), &quot;%s/%s&quot;, modules_location, kernel_uname.release);
++ modules_list_release = list_directory(modules_location_release);
++ if (modules_list_release &amp;&amp; modules_list_release[0]) {
++ strcpy(modules_location, modules_location_release);
++ modules_list = modules_list_release;
++ }
++
++ log_message(&quot;third party: using modules location %s&quot;, modules_location);
++
++ if (!modules_list || !*modules_list) {
++ log_message(&quot;third party: no modules found&quot;);
++ if (interactive)
++ stg1_error_message(&quot;No modules found on selected device.&quot;);
++ return RETURN_ERROR;
++ }
++
++ list_filename = alloca(strlen(modules_location) + 10 /* max: &quot;/to_detect&quot; */ + 1);
++
++ sprintf(list_filename, &quot;%s/to_load&quot;, modules_location);
++ f_load = fopen(list_filename, &quot;rb&quot;);
++ if (f_load) {
++ thirdparty_autoload_modules(modules_location, modules_list, f_load, 0);
++ fclose(f_load);
++ }
++
++ sprintf(list_filename, &quot;%s/to_detect&quot;, modules_location);
++ f_detect = fopen(list_filename, &quot;rb&quot;);
++ if (f_detect) {
++ probing_detect_devices();
++ thirdparty_load_pcitable(modules_location);
++ thirdparty_autoload_modules(modules_location, modules_list, f_detect, 1);
++ fclose(f_detect);
++ }
++
++ if (f_load || f_detect)
++ return RETURN_OK;
++ else if (interactive) {
++ if (IS_AUTOMATIC)
++ stg1_error_message(&quot;I can't find a \&quot;to_load\&quot; file. Please select the modules manually.&quot;);
++ log_message(&quot;third party: no \&quot;to_load\&quot; file, prompting for modules&quot;);
++ return thirdparty_prompt_modules(modules_location, modules_list);
++ } else {
++ return RETURN_OK;
++ }
++}
++
++void thirdparty_load_media_modules(void)
++{
++ thirdparty_try_directory(IMAGE_LOCATION, 0);
++}
++
++void thirdparty_load_modules(void)
++{
++ enum return_type results;
++ char * device;
++
++ device = NULL;
++ if (IS_AUTOMATIC) {
++ device = get_auto_value(&quot;thirdparty&quot;);
++ thirdparty_choose_device(NULL, 1); /* probe only to create devices */
++ log_message(&quot;third party: trying automatic device %s&quot;, device);
++ if (thirdparty_mount_device(device) != RETURN_OK)
++ device = NULL;
++ }
++
++ while (!device || streq(device, &quot;&quot;)) {
++ results = thirdparty_choose_device(&amp;device, 0);
++ if (results == RETURN_BACK)
++ return;
++ if (thirdparty_mount_device(device) != RETURN_OK)
++ device = NULL;
++ }
++
++ log_message(&quot;third party: using device %s&quot;, device);
++ add_to_env(&quot;THIRDPARTY_DEVICE&quot;, device);
++
++ results = thirdparty_try_directory(THIRDPARTY_MOUNT_LOCATION, 1);
++ umount(THIRDPARTY_MOUNT_LOCATION);
++
++ if (results != RETURN_OK)
++ return thirdparty_load_modules();
++}
++
++void thirdparty_destroy(void)
++{
++ probing_destroy();
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/thirdparty.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/thirdparty.h
+===================================================================
+--- drakx/trunk/mdk-stage1/thirdparty.h (rev 0)
++++ drakx/trunk/mdk-stage1/thirdparty.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,35 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ * Olivier Blin (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">oblin at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#ifndef _THIRDPARTY_H_
++#define _THIRDPARTY_H_
++
++#define THIRDPARTY_DIRECTORY &quot;/install/thirdparty&quot;
++
++/* load third party modules present on install media
++ * use to_load and to_detect files in /install/thirdparty
++ * do not prompt user
++ */
++void thirdparty_load_media_modules(void);
++
++/* load modules if to_load or to_detect files are present
++ * prompt user if no to_load file is present
++ */
++void thirdparty_load_modules(void);
++
++/* destroy all data structures related to the thirdparty module */
++void thirdparty_destroy(void);
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/thirdparty.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/tools.c
+===================================================================
+--- drakx/trunk/mdk-stage1/tools.c (rev 0)
++++ drakx/trunk/mdk-stage1/tools.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,361 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Portions from Erik Troan (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ewt at redhat.com</A>)
++ *
++ * Copyright 1996 Red Hat Software
++ *
++ */
++
++#include &lt;stdlib.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;sys/time.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;string.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;dirent.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/mount.h&gt;
++#include &lt;sys/poll.h&gt;
++#include &lt;errno.h&gt;
++#include &lt;sys/ioctl.h&gt;
++#include &lt;linux/fd.h&gt;
++#include &quot;stage1.h&quot;
++#include &quot;log.h&quot;
++#include &quot;mount.h&quot;
++#include &quot;frontend.h&quot;
++#include &quot;automatic.h&quot;
++
++#include &quot;tools.h&quot;
++#include &quot;utils.h&quot;
++#include &quot;params.h&quot;
++#include &quot;probing.h&quot;
++#include &quot;modules.h&quot;
++#include &quot;lomount.h&quot;
++
++int image_has_stage2()
++{
++ return access(COMPRESSED_FILE_REL(IMAGE_LOCATION &quot;/&quot;), R_OK) == 0 ||
++ access(IMAGE_LOCATION &quot;/&quot; LIVE_LOCATION_REL, R_OK) == 0;
++}
++
++enum return_type create_IMAGE_LOCATION(char *location_full)
++{
++ struct stat statbuf;
++ int offset = strncmp(location_full, IMAGE_LOCATION_DIR, sizeof(IMAGE_LOCATION_DIR) - 1) == 0 ? sizeof(IMAGE_LOCATION_DIR) - 1 : 0;
++ char *with_arch = asprintf_(&quot;%s/%s&quot;, location_full, ARCH);
++
++ log_message(&quot;trying %s&quot;, with_arch);
++
++ if (stat(with_arch, &amp;statbuf) == 0 &amp;&amp; S_ISDIR(statbuf.st_mode))
++ location_full = with_arch;
++
++ log_message(&quot;assuming %s is a mirror tree&quot;, location_full + offset);
++
++ unlink(IMAGE_LOCATION);
++ if (symlink(location_full + offset, IMAGE_LOCATION) != 0)
++ return RETURN_ERROR;
++
++ return RETURN_OK;
++}
++
++int ramdisk_possible(void)
++{
++ if (total_memory() &gt; (IS_RESCUE ? MEM_LIMIT_RESCUE : MEM_LIMIT_DRAKX))
++ return 1;
++ else {
++ log_message(&quot;warning, ramdisk is not possible due to low mem!&quot;);
++ return 0;
++ }
++}
++
++int compressed_image_preload(void)
++{
++ if (total_memory() &gt; (IS_RESCUE ? MEM_LIMIT_RESCUE_PRELOAD : MEM_LIMIT_DRAKX_PRELOAD))
++ return 1;
++ else {
++ log_message(&quot;warning, not preloading compressed due to low mem&quot;);
++ return 0;
++ }
++}
++
++enum return_type save_fd(int from_fd, char * to, void (*callback_func)(int overall))
++{
++ FILE * f_to;
++ size_t quantity __attribute__((aligned(16))), overall = 0;
++ char buf[4096] __attribute__((aligned(4096)));
++ int ret = RETURN_ERROR;
++
++ if (!(f_to = fopen(to, &quot;w&quot;))) {
++ log_perror(to);
++ goto close_from;
++ }
++
++ do {
++ quantity = read(from_fd, buf, sizeof(buf));
++ if (quantity &gt; 0) {
++ if (fwrite(buf, 1, quantity, f_to) != quantity) {
++ log_message(&quot;short write (%s)&quot;, strerror(errno));
++ goto cleanup;
++ }
++ } else if (quantity == -1) {
++ log_message(&quot;an error occured: %s&quot;, strerror(errno));
++ goto cleanup;
++ }
++
++ if (callback_func) {
++ overall += quantity;
++ callback_func(overall);
++ }
++ } while (quantity);
++
++ ret = RETURN_OK;
++
++ cleanup:
++ fclose(f_to);
++ close_from:
++ close(from_fd);
++
++ return ret;
++}
++
++enum return_type copy_file(char * from, char * to, void (*callback_func)(int overall))
++{
++ int from_fd;
++
++ log_message(&quot;copy_file: %s -&gt; %s&quot;, from, to);
++
++ from_fd = open(from, O_RDONLY);
++ if (from_fd != -1) {
++ return save_fd(from_fd, to, callback_func);
++ } else {
++ log_perror(from);
++ return RETURN_ERROR;
++ }
++}
++
++enum return_type recursiveRemove(char *file)
++{
++ struct stat sb;
++
++ if (lstat(file, &amp;sb) != 0) {
++ log_message(&quot;failed to stat %s: %d&quot;, file, errno);
++ return RETURN_ERROR;
++ }
++
++ /* only descend into subdirectories if device is same as dir */
++ if (S_ISDIR(sb.st_mode)) {
++ char * strBuf = alloca(strlen(file) + 1024);
++ DIR * dir;
++ struct dirent * d;
++
++ if (!(dir = opendir(file))) {
++ log_message(&quot;error opening %s: %d&quot;, file, errno);
++ return RETURN_ERROR;
++ }
++ while ((d = readdir(dir))) {
++ if (!strcmp(d-&gt;d_name, &quot;.&quot;) || !strcmp(d-&gt;d_name, &quot;..&quot;))
++ continue;
++
++ strcpy(strBuf, file);
++ strcat(strBuf, &quot;/&quot;);
++ strcat(strBuf, d-&gt;d_name);
++
++ if (recursiveRemove(strBuf) != 0) {
++ closedir(dir);
++ return RETURN_ERROR;
++ }
++ }
++ closedir(dir);
++
++ if (rmdir(file)) {
++ log_message(&quot;failed to rmdir %s: %d&quot;, file, errno);
++ return RETURN_ERROR;
++ }
++ } else {
++ if (unlink(file) != 0) {
++ log_message(&quot;failed to remove %s: %d&quot;, file, errno);
++ return RETURN_ERROR;
++ }
++ }
++ return RETURN_OK;
++}
++
++enum return_type recursiveRemove_if_it_exists(char *file)
++{
++ struct stat sb;
++
++ if (lstat(file, &amp;sb) != 0) {
++ /* if file doesn't exist, simply return OK */
++ return RETURN_OK;
++ }
++
++ return recursiveRemove(file);
++}
++
++enum return_type mount_compressed_image(char *compressed_image, char *location_mount)
++{
++ if (lomount(compressed_image, location_mount, NULL, 1)) {
++ stg1_error_message(&quot;Could not mount compressed loopback :(.&quot;);
++ return RETURN_ERROR;
++ }
++ return RETURN_OK;
++}
++
++enum return_type preload_mount_compressed_fd(int compressed_fd, int image_size, char *image_name, char *location_mount)
++{
++ int ret;
++ char *compressed_tmpfs = asprintf_(&quot;/tmp/%s&quot;, image_name);
++ char *buf = &quot;Loading program into memory...&quot;;
++ init_progression(buf, image_size);
++ ret = save_fd(compressed_fd, compressed_tmpfs, update_progression);
++ end_progression();
++ if (ret != RETURN_OK)
++ return ret;
++
++ return mount_compressed_image(compressed_tmpfs, location_mount);
++}
++
++enum return_type mount_compressed_image_may_preload(char *image_name, char *location_mount, int preload)
++{
++ char *compressed_image = asprintf_(&quot;%s/%s&quot;, COMPRESSED_LOCATION, image_name);
++
++ log_message(&quot;mount_compressed_may_preload: %s into %s (preload = %d)&quot;, compressed_image, location_mount, preload);
++
++ if (access(compressed_image, R_OK) != 0) return RETURN_ERROR;
++
++ if (preload) {
++ int compressed_fd = open(compressed_image, O_RDONLY);
++ if (compressed_fd != -1) {
++ return preload_mount_compressed_fd(compressed_fd, file_size(compressed_image), image_name, location_mount);
++ } else {
++ log_perror(compressed_image);
++ return RETURN_ERROR;
++ }
++ } else {
++ return mount_compressed_image(compressed_image, location_mount);
++ }
++}
++
++enum return_type may_load_compressed_image(void)
++{
++ if (!IS_RESCUE &amp;&amp; access(IMAGE_LOCATION &quot;/&quot; LIVE_LOCATION_REL, R_OK) == 0) {
++ /* LIVE install */
++ return RETURN_OK;
++ } else {
++ /* compressed install */
++ return mount_compressed_image_may_preload(COMPRESSED_NAME(&quot;&quot;), STAGE2_LOCATION, compressed_image_preload());
++ }
++}
++
++enum return_type load_compressed_fd(int fd, int size)
++{
++ return preload_mount_compressed_fd(fd, size, COMPRESSED_NAME(&quot;&quot;), STAGE2_LOCATION);
++}
++
++int try_mount(char * dev, char * location)
++{
++ char device_fullname[50];
++ snprintf(device_fullname, sizeof(device_fullname), &quot;/dev/%s&quot;, dev);
++
++ if (my_mount(device_fullname, location, &quot;ext4&quot;, 0) == -1 &amp;&amp;
++ my_mount(device_fullname, location, &quot;vfat&quot;, 0) == -1 &amp;&amp;
++ my_mount(device_fullname, location, &quot;ntfs&quot;, 0) == -1 &amp;&amp;
++ my_mount(device_fullname, location, &quot;reiserfs&quot;, 0) == -1 &amp;&amp;
++ my_mount(device_fullname, location, &quot;reiser4&quot;, 0) == -1 &amp;&amp;
++ my_mount(device_fullname, location, &quot;jfs&quot;, 0) == -1 &amp;&amp;
++ my_mount(device_fullname, location, &quot;xfs&quot;, 0) == -1 &amp;&amp;
++ my_mount(device_fullname, location, &quot;iso9660&quot;, 0) == -1) {
++ return 1;
++ }
++
++ return 0;
++}
++
++#ifndef DISABLE_DISK
++int get_disks(char *** names, char *** models)
++{
++ char ** ptr;
++ int count = 0;
++
++ my_insmod(&quot;ide_disk&quot;, ANY_DRIVER_TYPE, NULL, 0);
++ my_insmod(&quot;sd_mod&quot;, ANY_DRIVER_TYPE, NULL, 0);
++
++ get_medias(DISK, names, models, BUS_ANY);
++
++ ptr = *names;
++ while (ptr &amp;&amp; *ptr) {
++ count++;
++ ptr++;
++ }
++
++ return count;
++}
++#endif
++
++#ifndef DISABLE_CDROM
++int get_cdroms(char *** names, char *** models)
++{
++ char ** ptr;
++ int count = 0;
++
++ my_insmod(&quot;ide_cd_mod&quot;, ANY_DRIVER_TYPE, NULL, 0);
++ my_insmod(&quot;sr_mod&quot;, ANY_DRIVER_TYPE, NULL, 0);
++
++ get_medias(CDROM, names, models, BUS_ANY);
++
++ ptr = *names;
++ while (ptr &amp;&amp; *ptr) {
++ count++;
++ ptr++;
++ }
++
++ return count;
++}
++#endif
++
++char * floppy_device(void)
++{
++ char ** names, ** models;
++ int fd;
++ my_insmod(&quot;floppy&quot;, ANY_DRIVER_TYPE, NULL, 0);
++ fd = open(&quot;/dev/fd0&quot;, O_RDONLY|O_NONBLOCK);
++ if (fd != -1) {
++ char drivtyp[17];
++ if (!ioctl(fd, FDGETDRVTYP, (void *)drivtyp)) {
++ struct floppy_drive_struct ds;
++ log_message(&quot;/dev/fd0 type: %s&quot;, drivtyp);
++ if (!ioctl(fd, FDPOLLDRVSTAT, &amp;ds)) {
++ log_message(&quot;\ttrack: %d&quot;, ds.track);
++ if (ds.track &gt;= 0) {
++ close(fd);
++ return &quot;/dev/fd0&quot;;
++ }
++ }
++ } else {
++ log_perror(&quot;can't FDGETDRVTYP /dev/fd0&quot;);
++ }
++ close(fd);
++ }
++ log_message(&quot;seems that you don't have a regular floppy drive&quot;);
++ my_insmod(&quot;sd_mod&quot;, ANY_DRIVER_TYPE, NULL, 0);
++ get_medias(FLOPPY, &amp;names, &amp;models, BUS_ANY);
++ if (names &amp;&amp; *names)
++ return asprintf_(&quot;/dev/%s&quot;, *names);
++ else
++ return NULL;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/tools.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/tools.h
+===================================================================
+--- drakx/trunk/mdk-stage1/tools.h (rev 0)
++++ drakx/trunk/mdk-stage1/tools.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,49 @@
++
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Portions from Erik Troan (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ewt at redhat.com</A>)
++ *
++ * Copyright 1996 Red Hat Software
++ *
++ */
++
++#ifndef _TOOLS_H_
++#define _TOOLS_H_
++
++#include &lt;stdlib.h&gt;
++#include &quot;bootsplash.h&quot;
++
++int image_has_stage2();
++enum return_type create_IMAGE_LOCATION(char *location_full);
++int ramdisk_possible(void);
++enum return_type copy_file(char * from, char * to, void (*callback_func)(int overall));
++enum return_type recursiveRemove(char *file);
++enum return_type recursiveRemove_if_it_exists(char *file);
++enum return_type preload_mount_compressed_fd(int compressed_fd, int image_size, char *image_name, char *location_mount);
++enum return_type mount_compressed_image(char *compressed_image, char *location_mount);
++enum return_type mount_compressed_image_may_preload(char *image_name, char *location_mount, int preload);
++enum return_type load_compressed_fd(int fd, int size);
++enum return_type may_load_compressed_image(void);
++int try_mount(char * dev, char * location);
++#ifndef DISABLE_DISK
++int get_disks(char *** names, char *** models);
++#endif
++#ifndef DISABLE_CDROM
++int get_cdroms(char *** names, char *** models);
++#endif
++char * floppy_device(void);
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/tools.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/url.c
+===================================================================
+--- drakx/trunk/mdk-stage1/url.c (rev 0)
++++ drakx/trunk/mdk-stage1/url.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,560 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Portions from Erik Troan &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ewt at redhat.com</A>&gt; and Matt Wilson &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">msw at redhat.com</A>&gt;
++ *
++ * Copyright 1999 Red Hat, Inc.
++ *
++ */
++
++#include &lt;alloca.h&gt;
++#include &lt;sys/socket.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;netinet/in_systm.h&gt;
++
++#include &lt;ctype.h&gt;
++#include &lt;errno.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;netdb.h&gt;
++#include &lt;stdarg.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;string.h&gt;
++#include &lt;strings.h&gt;
++#include &lt;sys/socket.h&gt;
++#include &lt;sys/time.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;sys/poll.h&gt;
++
++#include &lt;netinet/in.h&gt;
++#include &lt;netinet/ip.h&gt;
++#include &lt;arpa/inet.h&gt;
++
++#include &quot;dns.h&quot;
++#include &quot;log.h&quot;
++#include &quot;tools.h&quot;
++#include &quot;utils.h&quot;
++
++#include &quot;url.h&quot;
++
++
++#define TIMEOUT_SECS 60
++#define BUFFER_SIZE 4096
++#define HTTP_MAX_RECURSION 5
++
++
++static int ftp_check_response(int sock, char ** str)
++{
++ static char buf[BUFFER_SIZE + 1];
++ int bufLength = 0;
++ struct pollfd polls;
++ char * chptr, * start;
++ int bytesRead, rc = 0;
++ int doesContinue = 1;
++ char errorCode[4];
++
++ errorCode[0] = '\0';
++
++ do {
++ polls.fd = sock;
++ polls.events = POLLIN;
++ if (poll(&amp;polls, 1, TIMEOUT_SECS*1000) != 1)
++ return FTPERR_BAD_SERVER_RESPONSE;
++
++ bytesRead = read(sock, buf + bufLength, sizeof(buf) - bufLength - 1);
++
++ bufLength += bytesRead;
++
++ buf[bufLength] = '\0';
++
++ /* divide the response into lines, checking each one to see if
++ we are finished or need to continue */
++
++ start = chptr = buf;
++
++ do {
++ while (*chptr != '\n' &amp;&amp; *chptr) chptr++;
++
++ if (*chptr == '\n') {
++ *chptr = '\0';
++ if (*(chptr - 1) == '\r') *(chptr - 1) = '\0';
++ if (str) *str = start;
++
++ if (errorCode[0]) {
++ if (!strncmp(start, errorCode, 3) &amp;&amp; start[3] == ' ')
++ doesContinue = 0;
++ } else {
++ strncpy(errorCode, start, 3);
++ errorCode[3] = '\0';
++ if (start[3] != '-') {
++ doesContinue = 0;
++ }
++ }
++
++ start = chptr + 1;
++ chptr++;
++ } else {
++ chptr++;
++ }
++ } while (*chptr);
++
++ if (doesContinue &amp;&amp; chptr &gt; start) {
++ memcpy(buf, start, chptr - start - 1);
++ bufLength = chptr - start - 1;
++ } else {
++ bufLength = 0;
++ }
++ } while (doesContinue);
++
++ if (*errorCode == '4' || *errorCode == '5') {
++ if (!strncmp(errorCode, &quot;550&quot;, 3)) {
++ return FTPERR_FILE_NOT_FOUND;
++ }
++
++ return FTPERR_BAD_SERVER_RESPONSE;
++ }
++
++ if (rc) return rc;
++
++ return 0;
++}
++
++static int ftp_command(int sock, char * command, char * param)
++{
++ char buf[500];
++ int rc;
++
++ snprintf(buf, sizeof(buf), &quot;%s%s%s\r\n&quot;, command, param ? &quot; &quot; : &quot;&quot;, param ? param : &quot;&quot;);
++
++ if (write(sock, buf, strlen(buf)) != (ssize_t)strlen(buf)) {
++ return FTPERR_SERVER_IO_ERROR;
++ }
++
++ if ((rc = ftp_check_response(sock, NULL)))
++ return rc;
++
++ return 0;
++}
++
++static int get_host_address(char * host, struct in_addr * address)
++{
++ if (isdigit(host[0])) {
++ if (!inet_aton(host, address)) {
++ return FTPERR_BAD_HOST_ADDR;
++ }
++ } else {
++ if (mygethostbyname(host, address))
++ return FTPERR_BAD_HOSTNAME;
++ }
++
++ return 0;
++}
++
++int ftp_open_connection(char * host, char * name, char * password, char * proxy)
++{
++ int sock;
++ struct in_addr serverAddress;
++ struct sockaddr_in destPort;
++ int rc;
++ int port = 21;
++
++ if (!strcmp(name, &quot;&quot;)) {
++ name = &quot;anonymous&quot;;
++ password = &quot;-drakx@&quot;;
++ }
++
++ if (strcmp(proxy, &quot;&quot;)) {
++ name = asprintf_(&quot;%s@%s&quot;, name, host);
++ host = proxy;
++ }
++
++ if ((rc = get_host_address(host, &amp;serverAddress))) return rc;
++
++ sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
++ if (sock &lt; 0) {
++ return FTPERR_FAILED_CONNECT;
++ }
++
++ destPort.sin_family = AF_INET;
++ destPort.sin_port = htons(port);
++ destPort.sin_addr = serverAddress;
++
++ if (connect(sock, (struct sockaddr *) &amp;destPort, sizeof(destPort))) {
++ close(sock);
++ return FTPERR_FAILED_CONNECT;
++ }
++
++ /* ftpCheckResponse() assumes the socket is nonblocking */
++ if (fcntl(sock, F_SETFL, O_NONBLOCK)) {
++ close(sock);
++ return FTPERR_FAILED_CONNECT;
++ }
++
++ if ((rc = ftp_check_response(sock, NULL))) {
++ return rc;
++ }
++
++ if ((rc = ftp_command(sock, &quot;USER&quot;, name))) {
++ close(sock);
++ return rc;
++ }
++
++ if ((rc = ftp_command(sock, &quot;PASS&quot;, password))) {
++ close(sock);
++ return rc;
++ }
++
++ if ((rc = ftp_command(sock, &quot;TYPE&quot;, &quot;I&quot;))) {
++ close(sock);
++ return rc;
++ }
++
++ return sock;
++}
++
++
++int ftp_data_command(int sock, char * command, char * param)
++{
++ int dataSocket;
++ struct sockaddr_in dataAddress;
++ int i, j;
++ char * passReply;
++ char * chptr;
++ char retrCommand[500];
++ int rc;
++
++ if (write(sock, &quot;PASV\r\n&quot;, 6) != 6) {
++ return FTPERR_SERVER_IO_ERROR;
++ }
++ if ((rc = ftp_check_response(sock, &amp;passReply)))
++ return FTPERR_PASSIVE_ERROR;
++
++ chptr = passReply;
++ while (*chptr &amp;&amp; *chptr != '(') chptr++;
++ if (*chptr != '(') return FTPERR_PASSIVE_ERROR;
++ chptr++;
++ passReply = chptr;
++ while (*chptr &amp;&amp; *chptr != ')') chptr++;
++ if (*chptr != ')') return FTPERR_PASSIVE_ERROR;
++ *chptr-- = '\0';
++
++ while (*chptr &amp;&amp; *chptr != ',') chptr--;
++ if (*chptr != ',') return FTPERR_PASSIVE_ERROR;
++ chptr--;
++ while (*chptr &amp;&amp; *chptr != ',') chptr--;
++ if (*chptr != ',') return FTPERR_PASSIVE_ERROR;
++ *chptr++ = '\0';
++
++ /* now passReply points to the IP portion, and chptr points to the
++ port number portion */
++
++ dataAddress.sin_family = AF_INET;
++ if (sscanf(chptr, &quot;%d,%d&quot;, &amp;i, &amp;j) != 2) {
++ return FTPERR_PASSIVE_ERROR;
++ }
++ dataAddress.sin_port = htons((i &lt;&lt; 8) + j);
++
++ chptr = passReply;
++ while (*chptr++) {
++ if (*chptr == ',') *chptr = '.';
++ }
++
++ if (!inet_aton(passReply, &amp;dataAddress.sin_addr))
++ return FTPERR_PASSIVE_ERROR;
++
++ dataSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
++ if (dataSocket &lt; 0) {
++ return FTPERR_FAILED_CONNECT;
++ }
++
++ if (!param)
++ sprintf(retrCommand, &quot;%s\r\n&quot;, command);
++ else
++ sprintf(retrCommand, &quot;%s %s\r\n&quot;, command, param);
++
++ i = strlen(retrCommand);
++
++ if (write(sock, retrCommand, i) != i) {
++ return FTPERR_SERVER_IO_ERROR;
++ }
++
++ if (connect(dataSocket, (struct sockaddr *) &amp;dataAddress,
++ sizeof(dataAddress))) {
++ close(dataSocket);
++ return FTPERR_FAILED_DATA_CONNECT;
++ }
++
++ if ((rc = ftp_check_response(sock, NULL))) {
++ close(dataSocket);
++ return rc;
++ }
++
++ return dataSocket;
++}
++
++
++int ftp_get_filesize(int sock, char * remotename)
++{
++ int size = 0;
++ char buf[2000];
++ char file[500];
++ char * ptr;
++ int fd, rc, tot;
++ int i;
++
++ strcpy(buf, remotename);
++ ptr = strrchr(buf, '/');
++ if (!*ptr)
++ return -1;
++ *ptr = '\0';
++
++ strcpy(file, ptr+1);
++
++ if ((rc = ftp_command(sock, &quot;CWD&quot;, buf))) {
++ return -1;
++ }
++
++ fd = ftp_data_command(sock, &quot;LIST&quot;, file);
++ if (fd &lt;= 0) {
++ close(sock);
++ return -1;
++ }
++
++ ptr = buf;
++ while ((tot = read(fd, ptr, sizeof(buf) - (ptr - buf) - 1)) != 0)
++ ptr += tot;
++ *ptr = '\0';
++ close(fd);
++
++ if (!(ptr = strstr(buf, file))) {
++ log_message(&quot;FTP/get_filesize: Bad mood, directory does not contain searched file (%s)&quot;, file);
++ if (ftp_end_data_command(sock))
++ close(sock);
++ return -1;
++ }
++
++ for (i=0; i&lt;4; i++) {
++ while (*ptr &amp;&amp; *ptr != ' ')
++ ptr--;
++ while (*ptr &amp;&amp; *ptr == ' ')
++ ptr--;
++ }
++ while (*ptr &amp;&amp; *ptr != ' ')
++ ptr--;
++
++ if (ptr)
++ size = charstar_to_int(ptr+1);
++ else
++ size = 0;
++
++ if (ftp_end_data_command(sock)) {
++ close(sock);
++ return -1;
++ }
++
++ return size;
++}
++
++
++int ftp_start_download(int sock, char * remotename, int * size)
++{
++ if ((*size = ftp_get_filesize(sock, remotename)) == -1) {
++ log_message(&quot;FTP: could not get filesize (trying to continue)&quot;);
++ *size = 0;
++ }
++ return ftp_data_command(sock, &quot;RETR&quot;, remotename);
++}
++
++
++int ftp_end_data_command(int sock)
++{
++ if (ftp_check_response(sock, NULL))
++ return FTPERR_BAD_SERVER_RESPONSE;
++
++ return 0;
++}
++
++
++char *str_ftp_error(int error)
++{
++ return error == FTPERR_PASSIVE_ERROR ? &quot;error with passive connection&quot; :
++ error == FTPERR_FAILED_CONNECT ? &quot;couldn't connect to server&quot; :
++ error == FTPERR_FILE_NOT_FOUND ? &quot;file not found&quot; :
++ error == FTPERR_BAD_SERVER_RESPONSE ? &quot;bad server response (server too busy?)&quot; :
++ NULL;
++}
++
++
++static int _http_download_file(char * hostname, char * remotename, int * size, char * proxyprotocol, char * proxyname, char * proxyport, int recursion)
++{
++ char * buf;
++ char headers[4096];
++ char * nextChar = headers;
++ int statusCode;
++ struct in_addr serverAddress;
++ struct pollfd polls;
++ int sock;
++ int rc;
++ struct sockaddr_in destPort;
++ const char * header_content_length = &quot;Content-Length: &quot;;
++ const char * header_location = &quot;Location: <A HREF="http://">http://</A>&quot;;
++ char * http_server_name;
++ int http_server_port;
++
++ if (proxyprotocol) {
++ http_server_name = proxyname;
++ http_server_port = atoi(proxyport);
++ } else {
++ http_server_name = hostname;
++ http_server_port = 80;
++ }
++
++ log_message(&quot;HTTP: connecting to server %s:%i (%s)&quot;,
++ http_server_name, http_server_port,
++ proxyprotocol ? &quot;proxy&quot; : &quot;no proxy&quot;);
++
++ if ((rc = get_host_address(http_server_name, &amp;serverAddress))) return rc;
++
++ sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
++ if (sock &lt; 0) {
++ return FTPERR_FAILED_CONNECT;
++ }
++
++ destPort.sin_family = AF_INET;
++ destPort.sin_port = htons(http_server_port);
++ destPort.sin_addr = serverAddress;
++
++ if (connect(sock, (struct sockaddr *) &amp;destPort, sizeof(destPort))) {
++ close(sock);
++ return FTPERR_FAILED_CONNECT;
++ }
++
++ buf = proxyprotocol ? asprintf_(&quot;GET %<A HREF="s://%s%s">s://%s%s</A> HTTP/1.0\r\nHost: %s\r\n\r\n&quot;, proxyprotocol, hostname, remotename, hostname)
++ : asprintf_(&quot;GET %s HTTP/1.0\r\nHost: %s\r\n\r\n&quot;, remotename, hostname);
++
++ write(sock, buf, strlen(buf));
++
++ /* This is fun; read the response a character at a time until we:
++
++ 1) Get our first \r\n; which lets us check the return code
++ 2) Get a \r\n\r\n, which means we're done */
++
++ *nextChar = '\0';
++ statusCode = 0;
++ while (!strstr(headers, &quot;\r\n\r\n&quot;)) {
++ polls.fd = sock;
++ polls.events = POLLIN;
++ rc = poll(&amp;polls, 1, TIMEOUT_SECS*1000);
++
++ if (rc == 0) {
++ close(sock);
++ return FTPERR_SERVER_TIMEOUT;
++ } else if (rc &lt; 0) {
++ close(sock);
++ return FTPERR_SERVER_IO_ERROR;
++ }
++
++ if (read(sock, nextChar, 1) != 1) {
++ close(sock);
++ return FTPERR_SERVER_IO_ERROR;
++ }
++
++ nextChar++;
++ *nextChar = '\0';
++
++ if (nextChar - headers == sizeof(headers)) {
++ close(sock);
++ return FTPERR_SERVER_IO_ERROR;
++ }
++
++ if (!statusCode &amp;&amp; strstr(headers, &quot;\r\n&quot;)) {
++ char * start, * end;
++
++ start = headers;
++ while (!isspace(*start) &amp;&amp; *start) start++;
++ if (!*start) {
++ close(sock);
++ return FTPERR_SERVER_IO_ERROR;
++ }
++ start++;
++
++ end = start;
++ while (!isspace(*end) &amp;&amp; *end) end++;
++ if (!*end) {
++ close(sock);
++ return FTPERR_SERVER_IO_ERROR;
++ }
++
++ *end = '\0';
++ log_message(&quot;HTTP: server response '%s'&quot;, start);
++ if (streq(start, &quot;404&quot;)) {
++ close(sock);
++ return FTPERR_FILE_NOT_FOUND;
++ } else if (streq(start, &quot;302&quot;)) {
++ log_message(&quot;HTTP: found, but document has moved&quot;);
++ statusCode = 302;
++ } else if (streq(start, &quot;200&quot;)) {
++ statusCode = 200;
++ } else {
++ close(sock);
++ return FTPERR_BAD_SERVER_RESPONSE;
++ }
++
++ *end = ' ';
++ }
++ }
++
++ if (statusCode == 302) {
++ if (recursion &gt;= HTTP_MAX_RECURSION) {
++ log_message(&quot;HTTP: too many levels of recursion, aborting&quot;);
++ close(sock);
++ return FTPERR_UNKNOWN;
++ }
++ if ((buf = strstr(headers, header_location))) {
++ char * found_host;
++ char *found_file;
++ found_host = buf + strlen(header_location);
++ if ((found_file = index(found_host, '/'))) {
++ if ((buf = index(found_file, '\r'))) {
++ buf[0] = '\0';
++ remotename = strdup(found_file);
++ found_file[0] = '\0';
++ hostname = strdup(found_host);
++ log_message(&quot;HTTP: redirected to new host \&quot;%s\&quot; and file \&quot;%s\&quot;&quot;, hostname, remotename);
++ }
++ }
++
++ }
++ /*
++ * don't fail if new URL can't be parsed,
++ * asking the same URL may work if the DNS server are doing round-robin
++ */
++ return _http_download_file(hostname, remotename, size, proxyprotocol, proxyname, proxyport, recursion + 1);
++ }
++
++ if ((buf = strstr(headers, header_content_length)))
++ *size = charstar_to_int(buf + strlen(header_content_length));
++ else
++ *size = 0;
++
++ return sock;
++}
++
++
++int http_download_file(char * hostname, char * remotename, int * size, char * proxyprotocol, char * proxyname, char * proxyport)
++{
++ return _http_download_file(hostname, remotename, size, proxyprotocol, proxyname, proxyport, 0);
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/url.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/url.h
+===================================================================
+--- drakx/trunk/mdk-stage1/url.h (rev 0)
++++ drakx/trunk/mdk-stage1/url.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,46 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * Portions from Erik Troan &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ewt at redhat.com</A>&gt; and Matt Wilson &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">msw at redhat.com</A>&gt;
++ *
++ * Copyright 1999 Red Hat, Inc.
++ *
++ */
++
++#ifndef _URL_H_
++#define _URL_H_
++
++int ftp_open_connection(char * host, char * name, char * password, char * proxy);
++int ftp_get_filesize(int sock, char * remotename);
++int ftp_start_download(int sock, char * remotename, int * size);
++int ftp_end_data_command(int sock);
++char *str_ftp_error(int error);
++
++int http_download_file(char * hostname, char * remotename, int * size, char * proxyprotocol, char * proxyname, char * proxyport);
++
++
++#define FTPERR_BAD_SERVER_RESPONSE -1
++#define FTPERR_SERVER_IO_ERROR -2
++#define FTPERR_SERVER_TIMEOUT -3
++#define FTPERR_BAD_HOST_ADDR -4
++#define FTPERR_BAD_HOSTNAME -5
++#define FTPERR_FAILED_CONNECT -6
++#define FTPERR_FILE_IO_ERROR -7
++#define FTPERR_PASSIVE_ERROR -8
++#define FTPERR_FAILED_DATA_CONNECT -9
++#define FTPERR_FILE_NOT_FOUND -10
++#define FTPERR_UNKNOWN -100
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/url.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/usb-resource/Makefile
+===================================================================
+--- drakx/trunk/mdk-stage1/usb-resource/Makefile (rev 0)
++++ drakx/trunk/mdk-stage1/usb-resource/Makefile 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,25 @@
++ #******************************************************************************
++ #
++ # $Id: Makefile 253685 2009-03-06 14:27:29Z tv $
++ #
++ # Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ #
++ # Copyright 2000 Mandriva
++ #
++ # This software may be freely redistributed under the terms of the GNU
++ # public license.
++ #
++ # You should have received a copy of the GNU General Public License
++ # along with this program; if not, write to the Free Software
++ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ #
++ #*****************************************************************************
++
++
++all: usb-ids.h
++
++usb-ids.h: /usr/share/ldetect-lst/usbtable.gz update-usb-ids.pl
++ perl update-usb-ids.pl &gt; $@ || rm -f $@
++
++clean:
++ rm -f usb-ids.h
+
+
+Property changes on: drakx/trunk/mdk-stage1/usb-resource/Makefile
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/usb-resource/update-usb-ids.pl
+===================================================================
+--- drakx/trunk/mdk-stage1/usb-resource/update-usb-ids.pl (rev 0)
++++ drakx/trunk/mdk-stage1/usb-resource/update-usb-ids.pl 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,24 @@
++#!/usr/bin/perl
++
++use lib '../kernel';
++use strict;
++use MDK::Common;
++
++my @modules = chomp_(`perl ../../kernel/modules.pl pci_modules4stage1 &quot;bus/usb&quot;`)
++ or die &quot;unable to get USB controller modules&quot;;
++print &quot;char *usb_controller_modules[] = {
++&quot;;
++printf qq|\t&quot;%s&quot;,\n|, $_ foreach @modules;
++print &quot;};
++unsigned int usb_controller_modules_len = sizeof(usb_controller_modules) / sizeof(char *);
++&quot;;
++
+<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">+ at modules</A> = chomp_(`perl ../../kernel/modules.pl pci_modules4stage1 &quot;network/usb disk/usb&quot;`)
++ or die &quot;unable to get USB modules&quot;;
++
++print &quot;char *usb_modules[] = {
++&quot;;
++printf qq|\t&quot;%s&quot;,\n|, $_ foreach @modules;
++print &quot;};
++unsigned int usb_modules_len = sizeof(usb_modules) / sizeof(char *);
++&quot;;
+
+
+Property changes on: drakx/trunk/mdk-stage1/usb-resource/update-usb-ids.pl
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: drakx/trunk/mdk-stage1/utils.c
+===================================================================
+--- drakx/trunk/mdk-stage1/utils.c (rev 0)
++++ drakx/trunk/mdk-stage1/utils.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,191 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#include &lt;stdlib.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;string.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;ctype.h&gt;
++#include &lt;dirent.h&gt;
++#include &lt;sys/utsname.h&gt;
++
++#include &quot;utils.h&quot;
++#include &quot;log.h&quot;
++
++// warning, many things rely on the fact that:
++// - when failing it returns 0
++// - it stops on first non-digit char
++int charstar_to_int(const char * s)
++{
++ int number = 0;
++ while (*s &amp;&amp; isdigit(*s)) {
++ number = (number * 10) + (*s - '0');
++ s++;
++ }
++ return number;
++}
++
++off_t file_size(const char * path)
++{
++ struct stat statr;
++ if (stat(path, &amp;statr))
++ return -1;
++ else
++ return statr.st_size;
++}
++
++char * cat_file(const char * file, struct stat * s) {
++ char * buf;
++ int fd = open(file, O_RDONLY);
++ if (fd == -1) {
++ log_perror(file);
++ return NULL;
++ }
++
++ fstat(fd, s);
++ buf = malloc(s-&gt;st_size + 1);
++ if (read(fd, buf, s-&gt;st_size) != (ssize_t)s-&gt;st_size) {
++ close(fd);
++ free(buf);
++ log_perror(file);
++ return NULL;
++ }
++ buf[s-&gt;st_size] = '\0';
++ close(fd);
++
++ return buf;
++}
++
++int line_counts(const char * buf) {
++ const char * ptr = buf;
++ int line = 0;
++ while (ptr) {
++ line++;
++ ptr = strchr(ptr + 1, '\n');
++ }
++ return line;
++}
++
++int total_memory(void)
++{
++ int value;
++
++ /* drakx powered: use /proc/kcore and rounds every 4 Mbytes */
++ value = 4 * ((int)((float)file_size(&quot;/proc/kcore&quot;) / 1024 / 1024 / 4 + 0.5));
++ log_message(&quot;Total Memory: %d Mbytes&quot;, value);
++
++ return value;
++}
++
++/* pixel's */
++void * memdup(void *src, size_t size)
++{
++ void * r;
++ r = malloc(size);
++ memcpy(r, src, size);
++ return r;
++}
++
++
++void add_to_env(char * name, char * value)
++{
++ FILE* fakeenv = fopen(&quot;/tmp/env&quot;, &quot;a&quot;);
++ if (fakeenv) {
++ char* e = asprintf_(&quot;%s=%s\n&quot;, name, value);
++ fwrite(e, 1, strlen(e), fakeenv);
++ free(e);
++ fclose(fakeenv);
++ } else
++ log_message(&quot;couldn't fopen to fake env&quot;);
++}
++
++char ** list_directory(char * direct)
++{
++ char * tmp[50000]; /* in /dev there can be many many files.. */
++ int i = 0;
++ struct dirent *ep;
++ DIR *dp = opendir(direct);
++ while (dp &amp;&amp; (ep = readdir(dp))) {
++ if (strcmp(ep-&gt;d_name, &quot;.&quot;) &amp;&amp; strcmp(ep-&gt;d_name, &quot;..&quot;)) {
++ tmp[i] = strdup(ep-&gt;d_name);
++ i++;
++ }
++ }
++ if (dp)
++ closedir(dp);
++ tmp[i] = NULL;
++ return memdup(tmp, sizeof(char*) * (i+1));
++}
++
++
++int string_array_length(char ** a)
++{
++ int i = 0;
++ if (!a)
++ return -1;
++ while (a &amp;&amp; *a) {
++ a++;
++ i++;
++ }
++ return i;
++}
++
++int kernel_version(void)
++{
++ struct utsname val;
++ if (uname(&amp;val)) {
++ log_perror(&quot;uname failed&quot;);
++ return -1;
++ }
++ return charstar_to_int(val.release + 2);
++}
++
++char * asprintf_(const char *msg, ...)
++{
++ int n;
++ char * s;
++ char dummy;
++ va_list arg_ptr;
++ va_start(arg_ptr, msg);
++ n = vsnprintf(&amp;dummy, sizeof(dummy), msg, arg_ptr);
++ va_start(arg_ptr, msg);
++ if ((s = malloc(n + 1))) {
++ vsnprintf(s, n + 1, msg, arg_ptr);
++ va_end(arg_ptr);
++ return s;
++ }
++ va_end(arg_ptr);
++ return strdup(&quot;&quot;);
++}
++
++int scall_(int retval, char * msg, char * file, int line)
++{
++ char tmp[5000];
++ sprintf(tmp, &quot;%s(%s:%d) failed&quot;, msg, file, line);
++ if (retval)
++ log_perror(tmp);
++ return retval;
++}
++
++void lowercase(char *s)
++{
++ int i = 0;
++ while (s[i]) {
++ s[i] = tolower(s[i]);
++ i++;
++ }
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/utils.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/utils.h
+===================================================================
+--- drakx/trunk/mdk-stage1/utils.h (rev 0)
++++ drakx/trunk/mdk-stage1/utils.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,38 @@
++/*
++ * Guillaume Cottenceau (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">gc at mandriva.com</A>)
++ *
++ * Copyright 2000 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#ifndef _UTILS_H_
++#define _UTILS_H_
++
++#include &lt;sys/stat.h&gt;
++
++int charstar_to_int(const char * s);
++off_t file_size(const char * path);
++char * cat_file(const char * file, struct stat * s);
++int line_counts(const char * buf);
++int total_memory(void);
++void * memdup(void *src, size_t size);
++void add_to_env(char * name, char * value);
++char ** list_directory(char * direct);
++int string_array_length(char ** a);
++int kernel_version(void);
++char * asprintf_(const char *msg, ...);
++int scall_(int retval, char * msg, char * file, int line);
++#define scall(retval, msg) scall_(retval, msg, __FILE__, __LINE__)
++void lowercase(char *s);
++
++#define ptr_begins_static_str(pointer,static_str) (!strncmp(pointer,static_str,sizeof(static_str)-1))
++#define streq(a,b) (!strcmp(a,b))
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/utils.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/wireless.c
+===================================================================
+--- drakx/trunk/mdk-stage1/wireless.c (rev 0)
++++ drakx/trunk/mdk-stage1/wireless.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,160 @@
++/*
++ * Olivier Blin (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">oblin at mandriva.com</A>)
++ *
++ * Copyright 2005 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#include &lt;sys/ioctl.h&gt;
++#include &lt;sys/types.h&gt;
++#include &lt;sys/socket.h&gt;
++#include &lt;errno.h&gt;
++#include &lt;stdio.h&gt;
++#include &lt;string.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;linux/types.h&gt;
++#include &lt;linux/if.h&gt;
++#include &lt;linux/wireless.h&gt;
++
++#include &quot;automatic.h&quot;
++#include &quot;stage1.h&quot;
++#include &quot;log.h&quot;
++#include &quot;utils.h&quot;
++#include &quot;wireless.h&quot;
++
++static int wireless_ioctl(int socket, const char *ifname, int request, struct iwreq *wrq);
++static int wireless_set_mode_managed(int socket, const char *ifname);
++static int wireless_disable_key(int socket, const char *ifname);
++static int wireless_set_restricted_key(int socket, const char *ifname, const char *key);
++static int wireless_set_essid(int socket, const char *ifname, const char *essid);
++
++int wireless_open_socket()
++{
++ return socket(AF_INET, SOCK_DGRAM, 0);
++}
++
++int wireless_close_socket(int socket)
++{
++ return close(socket);
++}
++
++static int wireless_ioctl(int socket, const char *ifname, int request, struct iwreq *wrq)
++{
++ strncpy(wrq-&gt;ifr_name, ifname, IFNAMSIZ);
++ return ioctl(socket, request, wrq);
++}
++
++int wireless_is_aware(int socket, const char *ifname)
++{
++ struct iwreq wrq;
++ return wireless_ioctl(socket, ifname, SIOCGIWNAME, &amp;wrq) == 0;
++}
++
++static int wireless_set_mode_managed(int socket, const char *ifname)
++{
++ struct iwreq wrq;
++
++ wrq.u.mode = IW_MODE_INFRA; /* managed */
++
++ return wireless_ioctl(socket, ifname, SIOCSIWMODE, &amp;wrq) == 0;
++}
++
++static int wireless_set_essid(int socket, const char *ifname, const char *essid)
++{
++ struct iwreq wrq;
++
++ wrq.u.essid.flags = 1;
++ wrq.u.essid.pointer = (void *) essid;
++ wrq.u.essid.length = strlen(essid) + 1;
++
++ return wireless_ioctl(socket, ifname, SIOCSIWESSID, &amp;wrq) == 0;
++}
++
++static int wireless_disable_key(int socket, const char *ifname)
++{
++ struct iwreq wrq;
++
++ wrq.u.data.flags = IW_ENCODE_DISABLED;
++ wrq.u.data.pointer = NULL;
++ wrq.u.data.length = 0;
++
++ return wireless_ioctl(socket, ifname, SIOCSIWENCODE, &amp;wrq) == 0;
++}
++
++static int wireless_set_restricted_key(int socket, const char *ifname, const char *key)
++{
++ struct iwreq wrq;
++ char real_key[IW_ENCODING_TOKEN_MAX];
++ int key_len = 0;
++ unsigned int tmp;
++
++ while (sscanf(key + 2*key_len, &quot;%2X&quot;, &amp;tmp) == 1)
++ real_key[key_len++] = (char) tmp;
++
++ wrq.u.data.flags = IW_ENCODE_RESTRICTED;
++ wrq.u.data.pointer = (char *) real_key;
++ wrq.u.data.length = key_len;
++
++ return wireless_ioctl(socket, ifname, SIOCSIWENCODE, &amp;wrq) == 0;
++}
++
++enum return_type configure_wireless(const char *ifname)
++{
++ enum return_type results;
++ char * questions[] = { &quot;ESSID&quot;, &quot;WEP key&quot;, NULL };
++ char * questions_auto[] = { &quot;essid&quot;, &quot;wep_key&quot; };
++ static char ** answers = NULL;
++ int wsock = wireless_open_socket();
++
++ if (!wireless_is_aware(wsock, ifname)) {
++ log_message(&quot;interface %s doesn't support wireless&quot;, ifname);
++ wireless_close_socket(wsock);
++ return RETURN_OK;
++ }
++
++ results = ask_from_entries_auto(&quot;Please enter your wireless settings. &quot;
++ &quot;The ESSID is your wireless network identifier. &quot;
++ &quot;The WEP key must be entered in hexadecimal, without any separator.&quot;,
++ questions, &amp;answers, 32, questions_auto, NULL);
++ if (results != RETURN_OK) {
++ wireless_close_socket(wsock);
++ return RETURN_BACK;
++ }
++
++ if (!wireless_set_mode_managed(wsock, ifname)) {
++ stg1_error_message(&quot;unable to set mode Managed on device \&quot;%s\&quot;: %s&quot;, ifname, strerror(errno));
++ wireless_close_socket(wsock);
++ return RETURN_ERROR;
++ }
++
++ if (answers[1] &amp;&amp; !streq(answers[1], &quot;&quot;)) {
++ log_message(&quot;setting WEP key \&quot;%s\&quot; on device \&quot;%s\&quot;&quot;, answers[1], ifname);
++ if (!wireless_set_restricted_key(wsock, ifname, answers[1])) {
++ stg1_error_message(&quot;unable to set WEP key \&quot;%s\&quot; on device \&quot;%s\&quot;: %s&quot;, answers[1], ifname, strerror(errno));
++ return RETURN_ERROR;
++ }
++ } else {
++ log_message(&quot;disabling WEP key on device \&quot;%s\&quot;&quot;, ifname);
++ if (!wireless_disable_key(wsock, ifname)) {
++ stg1_error_message(&quot;unable to disable WEP key on device \&quot;%s\&quot;: %s&quot;, ifname, strerror(errno));
++ return RETURN_ERROR;
++ }
++ }
++
++ /* most devices perform discovery when ESSID is set, it needs to be last */
++ log_message(&quot;setting ESSID \&quot;%s\&quot; on device \&quot;%s\&quot;&quot;, answers[0], ifname);
++ if (!wireless_set_essid(wsock, ifname, answers[0])) {
++ stg1_error_message(&quot;unable to set ESSID \&quot;%s\&quot; on device \&quot;%s\&quot;: %s&quot;, answers[0], ifname, strerror(errno));
++ return RETURN_ERROR;
++ }
++
++ wireless_close_socket(wsock);
++ return RETURN_OK;
++}
+
+
+Property changes on: drakx/trunk/mdk-stage1/wireless.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/wireless.h
+===================================================================
+--- drakx/trunk/mdk-stage1/wireless.h (rev 0)
++++ drakx/trunk/mdk-stage1/wireless.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,25 @@
++/*
++ * Olivier Blin (<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">oblin at mandriva.com</A>)
++ *
++ * Copyright 2005 Mandriva
++ *
++ * This software may be freely redistributed under the terms of the GNU
++ * public license.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#ifndef _WIRELESS_H_
++#define _WIRELESS_H_
++
++#include &quot;frontend.h&quot;
++
++int wireless_open_socket();
++int wireless_close_socket(int socket);
++int wireless_is_aware(int socket, const char *ifname);
++enum return_type configure_wireless(const char *ifname);
++
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/wireless.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/zlibsupport.c
+===================================================================
+--- drakx/trunk/mdk-stage1/zlibsupport.c (rev 0)
++++ drakx/trunk/mdk-stage1/zlibsupport.c 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,119 @@
++/* Support for compressed modules. Willy Tarreau &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">willy at meta-x.org</A>&gt;
++ * did the support for modutils, Andrey Borzenkov &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">arvidjaar at mail.ru</A>&gt;
++ * ported it to module-init-tools, and I said it was too ugly to live
++ * and rewrote it 8).
++ *
++ * (C) 2003 Rusty Russell, IBM Corporation.
++ */
++#include &lt;sys/types.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;fcntl.h&gt;
++#include &lt;stdlib.h&gt;
++#include &lt;unistd.h&gt;
++#include &lt;sys/mman.h&gt;
++
++#include &quot;zlibsupport.h&quot;
++
++#ifdef CONFIG_USE_ZLIB
++#include &lt;zlib.h&gt;
++
++void *grab_contents(gzFile *gzfd, unsigned long *size)
++{
++ unsigned int max = 16384;
++ void *buffer = malloc(max);
++ int ret;
++
++ if (!buffer)
++ return NULL;
++
++ *size = 0;
++ while ((ret = gzread(gzfd, buffer + *size, max - *size)) &gt; 0) {
++ *size += ret;
++ if (*size == max) {
++ void *p;
++
++ p = realloc(buffer, max *= 2);
++ if (!p)
++ goto out_err;
++
++ buffer = p;
++ }
++ }
++ if (ret &lt; 0)
++ goto out_err;
++
++ return buffer;
++
++out_err:
++ free(buffer);
++ return NULL;
++}
++
++void *grab_fd(int fd, unsigned long *size)
++{
++ gzFile gzfd;
++
++ gzfd = gzdopen(fd, &quot;rb&quot;);
++ if (!gzfd)
++ return NULL;
++
++ /* gzclose(gzfd) would close fd, which would drop locks.
++ Don't blame zlib: POSIX locking semantics are so horribly
++ broken that they should be ripped out. */
++ return grab_contents(gzfd, size);
++}
++
++/* gzopen handles uncompressed files transparently. */
++void *grab_file(const char *filename, unsigned long *size)
++{
++ gzFile gzfd;
++ void *buffer;
++
++ gzfd = gzopen(filename, &quot;rb&quot;);
++ if (!gzfd)
++ return NULL;
++ buffer = grab_contents(gzfd, size);
++ gzclose(gzfd);
++ return buffer;
++}
++
++void release_file(void *data, unsigned long size)
++{
++ free(data);
++}
++#else /* ... !CONFIG_USE_ZLIB */
++
++void *grab_fd(int fd, unsigned long *size)
++{
++ struct stat st;
++ void *map;
++ int ret;
++
++ ret = fstat(fd, &amp;st);
++ if (ret &lt; 0)
++ return NULL;
++ *size = st.st_size;
++ map = mmap(0, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
++ if (map == MAP_FAILED)
++ map = NULL;
++ return map;
++}
++
++void *grab_file(const char *filename, unsigned long *size)
++{
++ int fd;
++ void *map;
++
++ fd = open(filename, O_RDONLY, 0);
++ if (fd &lt; 0)
++ return NULL;
++ map = grab_fd(fd, size);
++ close(fd);
++ return map;
++}
++
++void release_file(void *data, unsigned long size)
++{
++ munmap(data, size);
++}
++#endif
+
+
+Property changes on: drakx/trunk/mdk-stage1/zlibsupport.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+
+Added: drakx/trunk/mdk-stage1/zlibsupport.h
+===================================================================
+--- drakx/trunk/mdk-stage1/zlibsupport.h (rev 0)
++++ drakx/trunk/mdk-stage1/zlibsupport.h 2011-02-07 00:01:56 UTC (rev 451)
+@@ -0,0 +1,11 @@
++#ifndef _ZLIB_SUPPORT_H
++#define _ZLIB_SUPPORT_H
++
++/* Grab file. Decompresses if that is supported. Returns NULL on error. */
++extern void *grab_file(const char *filename, unsigned long *size);
++extern void *grab_fd(int fd, unsigned long *size);
++
++/* Free it up. */
++extern void release_file(void *data, unsigned long size);
++
++#endif /* _ZLIB_SUPPORT_H */
+
+
+Property changes on: drakx/trunk/mdk-stage1/zlibsupport.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+-------------- next part --------------
+An HTML attachment was scrubbed...
+URL: &lt;/pipermail/mageia-sysadm/attachments/20110207/6feaa886/attachment-0001.html&gt;
+</PRE>
+
+<!--endarticle-->
+ <HR>
+ <P><UL>
+ <!--threads-->
+ <LI>Previous message: <A HREF="002827.html">[Mageia-sysadm] [450] Import cleaned tools
+</A></li>
+ <LI>Next message: <A HREF="002582.html">[Mageia-sysadm] [452] Do not get mirrorlist from Mandriva
+</A></li>
+ <LI> <B>Messages sorted by:</B>
+ <a href="date.html#2835">[ date ]</a>
+ <a href="thread.html#2835">[ thread ]</a>
+ <a href="subject.html#2835">[ subject ]</a>
+ <a href="author.html#2835">[ author ]</a>
+ </LI>
+ </UL>
+
+<hr>
+<a href="https://www.mageia.org/mailman/listinfo/mageia-sysadm">More information about the Mageia-sysadm
+mailing list</a><br>
+</body></html>