[Mageia-sysadm] [451] Import stage1

root at mageia.org root at mageia.org
Mon Feb 7 01:03:48 CET 2011


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 (pixel at mandriva.com) (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 (ewt at redhat.com) 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=\"$(DISTRIB_NAME)\" -DDISTRIB_VERSION=\"$(DISTRIB_VERSION)\" -DDISTRIB_TYPE=\"$(DISTRIB_TYPE)\" -DDISTRIB_DESCR=\"$(DISTRIB_DESCR)\" $(ADDITIONAL_DEFS) -D_FILE_OFFSET_BITS=64 -DARCH=\"$(ARCHDIR)\" -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 \
+		[ "$$n" = "." ] || 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 $<
+
+$(STAGE1OBJS-NETWORK): %-NETWORK.o: %.c
+	$(DIET) $(COMPILE) $(INCLUDES) $(NETWORK_DEFS) $(PCMCIA_DEFS) $(USB_DEFS_GEN) -DENABLE_ADDITIONAL_MODULES -c $< -o $@
+
+$(STAGE1OBJS-NETWORK-STANDALONE): %-NETWORK-STANDALONE.o: %.c
+	$(DIET) $(COMPILE) $(INCLUDES) $(NETWORK_STANDALONE_DEFS) $(USB_DEFS_GEN) -c $< -o $@
+
+$(STAGE1OBJS-FULL): %-FULL.o: %.c
+	$(DIET) $(COMPILE) $(INCLUDES) -DSPAWN_SHELL $(USB_DEFS_GEN) $(PCMCIA_DEFS) -DENABLE_BOOTSPLASH -c $< -o $@
+
+.c.o:
+	$(DIET) $(COMPILE) $(INCLUDES) -DENABLE_BOOTSPLASH -c $<
+
+
+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 ".svn" ]; then \
+	    $(MAKE) dist-svn; \
+	    elif [ -e "../.git" ]; then \
+	    $(MAKE) dist-git; \
+	    else \
+	    echo "Unknown SCM (not SVN nor GIT)";\
+	    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 >mdk-stage1/$(PRODUCT)-$(VERSION).tar.bz2;
+
+.depend:
+	$(CPP) $(CFLAGS) -M $(ALLSRC) > .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 (gc at mandriva.com)
+ #
+ # 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 && 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 "ide-generic" support (incorrectly removed in 1.17), the
+  module that we want to avoid is "ide-pci-generic" (previously "generic"),
+  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 "killed shell" 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 "--usb" option instead of "usb"
+  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 "GUI" as rescue "menu"
+
+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 (gc at mandriva.com)
+ *
+ * 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 <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <resolv.h>
+#include <signal.h>
+
+#include "stage1.h"
+#include "log.h"
+#include "network.h"
+#include "modules.h"
+#include "utils.h"
+#include "frontend.h"
+#include "automatic.h"
+
+#include "adsl.h"
+
+
+static enum return_type adsl_connect(struct interface_info * intf, char * username, char * password, char * acname)
+{
+	char pppoe_call[500];
+	char * pppd_launch[] = { "/sbin/pppd", "pty", pppoe_call, "noipdefault", "noauth", "default-asyncmap", "defaultroute",
+				 "hide-password", "nodetach", "usepeerdns", "local", "mtu", "1492", "mru", "1492", "noaccomp",
+				 "noccp", "nobsdcomp", "nodeflate", "nopcomp", "novj", "novjccomp", "user", username,
+				 "password", password, "lcp-echo-interval", "20", "lcp-echo-failure", "3", "lock", "persist", NULL };
+	int fd;
+	int retries = 10;
+	char * tty_adsl = "/dev/tty6";
+	enum return_type status = RETURN_ERROR;
+	pid_t ppp_pid;
+
+	snprintf(pppoe_call, sizeof(pppoe_call), "/sbin/pppoe -p /var/run/pppoe.conf-adsl.pid.pppoe -I %s -T 80 -U -m 1412", intf->device);
+
+        if (!streq(acname, "")) {
+                strcat(pppoe_call, "-C ");
+                strcat(pppoe_call, acname);
+        }
+
+	fd = open(tty_adsl, O_RDWR);
+	if (fd == -1) {
+		log_message("cannot open tty -- no pppd");
+		return RETURN_ERROR;
+	}
+	else if (access(pppd_launch[0], X_OK)) {
+		log_message("cannot open pppd - %s doesn't exist", 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("could not set new controlling tty");
+		
+		printf("\t(exec of pppd)\n");
+		execv(pppd_launch[0], pppd_launch);
+		log_message("execve of %s failed: %s", pppd_launch[0], strerror(errno));
+		exit(-1);
+	}
+	close(fd);
+	while (retries > 0 && kill(ppp_pid, 0) == 0) {
+		FILE * f;
+		if ((f = fopen("/var/run/pppd.tdb", "rb"))) {
+			while (1) {
+				char buf[500];
+				char *p;
+				if (!fgets(buf, sizeof(buf), f))
+					break;
+				p = strstr(buf, "IPLOCAL=");
+				if (p) {
+					struct sockaddr_in addr;
+					if (inet_aton(p + 8, &addr.sin_addr))
+						intf->ip = addr.sin_addr;
+					status = RETURN_OK;
+				}
+			}
+			fclose(f);
+			if (status == RETURN_OK) {
+				log_message("PPP: connected!");
+				break;
+			}
+		}
+		retries--;
+		log_message("PPP: <sleep>");
+		sleep(2);
+	}
+
+	if (status != RETURN_OK) {
+		log_message("PPP: could not connect");
+		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[] = { "Username", "Password", "AC Name", NULL };
+	char * questions_auto[] = { "adsluser", "adslpass", "adslacname", NULL };
+	static char ** answers = NULL;
+	enum return_type results;
+
+	inet_aton("10.0.0.10", &addr);
+	memcpy(&intf->ip, &addr, sizeof(addr));
+
+	inet_aton("255.255.255.0", &addr);
+	memcpy(&intf->netmask, &addr, sizeof(addr));
+
+	*((uint32_t *) &intf->broadcast) = (*((uint32_t *) &intf->ip) &
+					    *((uint32_t *) &intf->netmask)) | ~(*((uint32_t *) &intf->netmask));
+
+	intf->is_ptp = 0;
+
+	if (configure_net_device(intf)) {
+		stg1_error_message("Could not configure..");
+		return RETURN_ERROR;
+	}
+
+	results = ask_from_entries_auto("Please enter the username and password for your ADSL account.\n"
+                                        "Leave blank the AC Name field if you don't know what it means.\n"
+					"(Warning! only PPPoE protocol is supported)",
+					questions, &answers, 40, questions_auto, NULL);
+	if (results != RETURN_OK)
+		return results;
+
+	intf->boot_proto = BOOTPROTO_ADSL_PPPOE;
+
+	wait_message("Waiting for ADSL connection to show up...");
+	my_insmod("ppp_generic", ANY_DRIVER_TYPE, NULL, 1);
+	my_insmod("ppp_async", ANY_DRIVER_TYPE, NULL, 1);
+	results = adsl_connect(intf, answers[0], answers[1], answers[2]);
+	remove_wait_message();
+
+	if (results != RETURN_OK) {
+		wait_message("Retrying the ADSL connection...");
+		results = adsl_connect(intf, answers[0], answers[1], answers[2]);
+		remove_wait_message();
+	} else {
+		intf->user = strdup(answers[0]);
+		intf->pass = strdup(answers[1]);
+		intf->acname = strdup(answers[2]);
+	}
+
+	if (results != RETURN_OK) {
+		stg1_error_message("I could not connect to the ADSL network.");
+		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 (gc at mandriva.com)
+ *
+ * Copyright 2000 Mandriva
+ *
+ * View the homepage: http://us.mandriva.com/~gc/html/stage1.html
+ *
+ *
+ * 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 "stage1.h"
+#include "network.h"
+
+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 (gc at mandriva.com)
+ *
+ * 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 "kickstart", by name but
+ * also by design (less code pollution).
+ *
+ */
+
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include "tools.h"
+#include "utils.h"
+#include "stage1.h"
+#include "frontend.h"
+#include "log.h"
+
+#include "automatic.h"
+
+
+static struct param_elem * automatic_params;
+static char * value_not_bound = "";
+
+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] != ':' && line[i] != '\0')
+			i++;
+		name = memdup(&line[j], i-j + 1);
+		name[i-j] = 0;
+
+		k = i+1;
+		i++;
+		while (line[i] != ',' && line[i] != '\0')
+			i++;
+		value = memdup(&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("AUTOMATIC MODE: got %d params", p-1);
+}
+
+
+char * get_auto_value(char * auto_param)
+{
+	struct param_elem * ptr = automatic_params;
+
+	struct param_elem short_aliases[] =
+		{ { "method", "met" }, { "network", "netw" }, { "interface", "int" }, { "gateway", "gat" },
+		  { "netmask", "netm" }, { "adsluser", "adslu" }, { "adslpass", "adslp" }, { "hostname", "hos" },
+		  { "domain", "dom" }, { "server", "ser" }, { "directory", "dir" }, { "user", "use" },
+		  { "pass", "pas" }, { "disk", "dis" }, { "partition", "par" }, { "proxy_host", "proxh" },
+		  { "proxy_port", "proxp" }, { NULL, NULL } };
+	struct param_elem * ptr_alias = short_aliases;
+	while (ptr_alias->name) {
+		if (streq(auto_param, ptr_alias->name))
+			break;
+		ptr_alias++;
+	}
+
+	while (ptr->name) {
+		if (streq(ptr->name, auto_param)
+		    || (ptr_alias->name && streq(ptr_alias->value, ptr->name)))
+			return ptr->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 && *elems) {
+			if (!strcmp(tmp, *elems_auto)) {
+				*choice = *elems;
+				log_message("AUTOMATIC: parameter %s for %s means returning %s", 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 && *elems) {
+			if (!strcmp(tmp, *elems_auto)) {
+				*choice = *elems;
+				log_message("AUTOMATIC: parameter %s for %s means returning %s", 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 && *questions) {
+			tmp_answers[i] = get_auto_value(*questions_auto);
+			log_message("AUTOMATIC: question %s answers %s because of param %s", *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 (gc at mandriva.com)
+ *
+ * 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 "kickstart", by name but
+ * also by design (no code pollution).
+ *
+ */
+
+#ifndef _AUTOMATIC_H_
+#define _AUTOMATIC_H_
+
+#include "stage1.h"
+
+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 (pixel at mandriva.com)
+ *
+ * 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 <stdio.h>
+#include "bootsplash.h"
+#include "frontend.h"
+#include "log.h"
+
+static int total_size;
+static float previous;
+static FILE* splash = NULL;
+
+static void update_progression_only(int current_size)
+{
+	if (splash && total_size) {
+		float ratio = (float) (current_size + 1) / total_size;
+		if (ratio > previous + 0.01) {
+			fprintf(splash, "show %d\n", (int) (ratio * 65534));
+			fflush(splash);
+			previous = ratio;
+		}
+	}
+}
+
+static void open_bootsplash(void)
+{
+	if (!splash) splash = fopen("/proc/splash", "w");
+	if (!splash) log_message("opening /proc/splash failed");
+}
+
+void exit_bootsplash(void)
+{
+	log_message("exiting bootsplash");
+	open_bootsplash();
+	if (splash) {
+		fprintf(splash, "verbose\n");
+		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 (pixel at mandriva.com)
+ *
+ * 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 (gc at mandriva.com)
+ *
+ * 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 (ewt at redhat.com)
+ *
+ * Copyright 1996 Red Hat Software 
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/mount.h>
+#include "stage1.h"
+#include "frontend.h"
+#include "modules.h"
+#include "probing.h"
+#include "log.h"
+#include "mount.h"
+#include "tools.h"
+#include "utils.h"
+
+#include "cdrom.h"
+
+
+static int mount_that_cd_device(char * dev_name)
+{
+	char device_fullname[50];
+	int mount_result;
+
+	snprintf(device_fullname, sizeof(device_fullname), "/dev/%s", dev_name);
+
+	mount_result = my_mount(device_fullname, MEDIA_LOCATION, "iso9660", 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("That CDROM disc does not seem to be a " DISTRIB_NAME " Installation CDROM.\nRetry with another disc?");
+		if (results == RETURN_OK)
+			return try_with_device(dev_name, dev_model);
+		return results;
+	}
+
+	log_message("found a " DISTRIB_NAME " CDROM, good news!");
+
+	may_load_compressed_image();
+
+	if (!KEEP_MOUNTED)
+		/* in rescue mode, we don't need the media anymore */
+		umount(MEDIA_LOCATION);
+
+        add_to_env("METHOD", "cdrom");
+	return RETURN_OK;
+}		
+
+static enum return_type try_with_device(char * dev_name, char * dev_model)
+{
+	wait_message("Trying to access a CDROM disc (drive %s)", 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), "I can't access a " DISTRIB_NAME " Installation disc in your CDROM drive (%s).\nRetry?", 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 && *ptr) {
+		char ** p;
+		for (p = already_tried; p && *p; p++)
+			if (streq(*p, *ptr)) 
+				goto try_automatic_already_tried;
+		*p = strdup(*ptr);
+		*(p+1) = NULL;
+
+		wait_message("Trying to access " DISTRIB_NAME " CDROM disc (drive %s)", *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("ide_cd_mod", ANY_DRIVER_TYPE, NULL, 0);
+
+	if (IS_AUTOMATIC) {
+		get_medias(CDROM, &medias, &medias_models, BUS_IDE);
+		if ((i = try_automatic(medias, medias_models)) != -1)
+			return do_with_device(medias[i], medias_models[i]);
+		
+		get_medias(CDROM, &medias, &medias_models, BUS_PCMCIA);
+		if ((i = try_automatic(medias, medias_models)) != -1)
+			return do_with_device(medias[i], medias_models[i]);
+		
+		my_insmod("sr_mod", ANY_DRIVER_TYPE, NULL, 0);
+		get_medias(CDROM, &medias, &medias_models, BUS_SCSI);
+		if ((i = try_automatic(medias, medias_models)) != -1)
+			return do_with_device(medias[i], medias_models[i]);
+		
+		get_medias(CDROM, &medias, &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("sd_mod", ANY_DRIVER_TYPE, NULL, 0);
+		get_medias(DISK, &medias, &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("sr_mod", ANY_DRIVER_TYPE, NULL, 0);
+
+
+	get_medias(CDROM, &medias, &medias_models, BUS_ANY);
+        ptr = medias;
+        while (ptr && *ptr) {
+                count++;
+                ptr++;
+        }
+
+	if (count == 0) {
+		if (!already_probed_ide_generic) {
+			already_probed_ide_generic = 1;
+			my_insmod("ide_generic", ANY_DRIVER_TYPE, NULL, 0);
+			return cdrom_prepare();
+		}
+		stg1_error_message("No CDROM device found.");
+		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("Please choose the CDROM drive to use for the installation.", medias, medias_models, &choice);
+	if (results == RETURN_OK) {
+		char ** model = medias_models;
+		ptr = medias;
+		while (ptr && *ptr && model && *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 (gc at mandriva.com)
+ *
+ * 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 (ewt at redhat.com)
+ *
+ * Copyright 1996 Red Hat Software 
+ *
+ */
+
+#ifndef _CDROM_H_
+#define _CDROM_H_
+
+#include "stage1.h"
+
+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 (gc at mandriva.com)
+ *
+ * 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 "install/stage2/live/"
+#define COMPRESSED_LOCATION_REL  "install/stage2/"
+#define COMPRESSED_STAGE2_NAME "mdkinst.sqfs"
+#define COMPRESSED_RESCUE_NAME "rescue.sqfs"
+#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 -> image/mdk/mirror/dir
+   - IMAGE_LOCATION is a symlink image -> loop/i586 and iso file is loopback mounted in LOOP_LOCATION
+ */
+#define MEDIA_LOCATION_REL "media"
+#define MEDIA_LOCATION IMAGE_LOCATION_DIR MEDIA_LOCATION_REL
+
+#define LOOP_LOCATION_REL "loop"
+#define LOOP_LOCATION IMAGE_LOCATION_DIR LOOP_LOCATION_REL
+
+#define IMAGE_LOCATION_REL "image"
+#define IMAGE_LOCATION_DIR "/tmp/"
+#define IMAGE_LOCATION IMAGE_LOCATION_DIR IMAGE_LOCATION_REL
+
+#define COMPRESSED_LOCATION IMAGE_LOCATION "/" 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 "/tmp/stage2"
+
+
+/* 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 "api.mandriva.com"
+#define MIRRORLIST_PATH "/mirrors"
+#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 (gc at mandriva.com)
+ *
+ * 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 (ewt at redhat.com)
+ *
+ * Copyright 1996 Red Hat Software 
+ *
+ */
+
+/*
+ * Portions from GRUB  --  GRand Unified Bootloader
+ * Copyright (C) 2000  Free Software Foundation, Inc.
+ */
+
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <net/route.h>
+#include <errno.h>
+#include <net/ethernet.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <sys/time.h>
+#include <time.h>
+#include <fcntl.h>
+#include <sys/poll.h>
+
+#include "stage1.h"
+#include "log.h"
+#include "tools.h"
+#include "utils.h"
+#include "network.h"
+#include "frontend.h"
+#include "automatic.h"
+
+#include "dhcp.h"
+
+
+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 > 0; (length2 -= 2), sp++)
+		csum += *sp;
+	
+	while (csum >> 16)
+		csum = (csum & 0xffff) + (csum >> 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 *) &req.ifr_addr;
+	
+	strcpy(req.ifr_name, device);
+	addrp->sin_family = AF_INET;
+	addrp->sin_port = 0;
+	memset(&addrp->sin_addr, 0, sizeof(addrp->sin_addr));
+	
+	req.ifr_flags = 0; /* take it down */
+	if (ioctl(s, SIOCSIFFLAGS, &req)) {
+		log_perror("SIOCSIFFLAGS (downing)");
+		return -1;
+	}
+    
+	addrp->sin_family = AF_INET;
+	addrp->sin_addr.s_addr = htonl(0);
+	if (ioctl(s, SIOCSIFADDR, &req)) {
+		log_perror("SIOCSIFADDR");
+		return -1;
+	}
+
+	req.ifr_flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING;
+	if (ioctl(s, SIOCSIFFLAGS, &req)) {
+		log_perror("SIOCSIFFLAGS (upping)");
+		return -1;
+	}
+
+	memset(&route, 0, sizeof(route));
+	memcpy(&route.rt_gateway, addrp, sizeof(*addrp));
+	
+	addrp->sin_family = AF_INET;
+	addrp->sin_port = 0;
+	addrp->sin_addr.s_addr = INADDR_ANY;
+	memcpy(&route.rt_dst, addrp, sizeof(*addrp));
+	memcpy(&route.rt_genmask, addrp, sizeof(*addrp));
+	
+	route.rt_dev = device;
+	route.rt_flags = RTF_UP;
+	route.rt_metric = 0;
+	
+	if (ioctl(s, SIOCADDRT, &route)) {
+		if (errno != EEXIST) {
+			close(s);
+			log_perror("SIOCADDRT");
+			return -1;
+		}
+	}
+	
+	if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &true, sizeof(true))) {
+		close(s);
+		log_perror("setsockopt");
+		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("Bringing up networking...");
+	sleep(2);
+	remove_wait_message();
+
+	return 0;
+}
+
+
+void set_missing_ip_info(struct interface_info * intf)
+{
+	bp_int32 ipNum = *((bp_int32 *) &intf->ip);
+	bp_int32 nmNum;
+
+	if (intf->netmask.s_addr == 0)
+		inet_aton(guess_netmask(inet_ntoa(intf->ip)), &intf->netmask);
+
+	nmNum = *((bp_int32 *) &intf->netmask);
+
+	if (intf->broadcast.s_addr == 0)
+		*((bp_int32 *) &intf->broadcast) = (ipNum & nmNum) | ~(nmNum);
+
+	if (intf->network.s_addr == 0)
+		*((bp_int32 *) &intf->network) = ipNum & nmNum;
+}
+
+static void parse_reply(struct bootp_request * breq, struct interface_info * intf)
+{
+	unsigned char * chptr;
+	unsigned char option, length;
+
+	if (breq->bootfile && strlen(breq->bootfile) > 0) {
+                if (IS_NETAUTO)
+                        add_to_env("KICKSTART", breq->bootfile);
+                else
+                        log_message("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");
+        }
+	
+	memcpy(&intf->ip, &breq->yiaddr, 4);
+
+	chptr = (unsigned char *) breq->vendor;
+	chptr += 4;
+	while (*chptr != 0xFF && (void *) chptr < (void *) breq->vendor + DHCP_VENDOR_LENGTH) {
+		char tmp_str[500];
+		option = *chptr++;
+		if (!option)
+			continue;
+		length = *chptr++;
+
+		switch (option) {
+		case BOOTP_OPTION_DNS:
+			memcpy(&dns_server, chptr, sizeof(dns_server));
+			log_message("got dns %s", inet_ntoa(dns_server));
+			if (length >= sizeof(dns_server)*2) {
+				memcpy(&dns_server2, chptr+sizeof(dns_server), sizeof(dns_server2));
+				log_message("got dns2 %s", inet_ntoa(dns_server2));
+			}
+			break;
+
+		case BOOTP_OPTION_NETMASK:
+			memcpy(&intf->netmask, chptr, sizeof(intf->netmask));
+			log_message("got netmask %s", inet_ntoa(intf->netmask));
+			break;
+		    
+		case BOOTP_OPTION_DOMAIN:
+			memcpy(tmp_str, chptr, length);
+			tmp_str[length] = '\0';
+			domain = strdup(tmp_str);
+			log_message("got domain %s", domain);
+			break;
+
+		case BOOTP_OPTION_BROADCAST:
+			memcpy(&intf->broadcast, chptr, sizeof(intf->broadcast));
+			log_message("got broadcast %s", inet_ntoa(intf->broadcast));
+			break;
+
+		case BOOTP_OPTION_GATEWAY:
+			memcpy(&gateway, chptr, sizeof(gateway));
+			log_message("got gateway %s", inet_ntoa(gateway));
+			break;
+
+		}
+
+		chptr += length;
+	}
+
+	set_missing_ip_info(intf);
+}
+
+
+static void init_vendor_codes(struct bootp_request * breq) {
+	memcpy(breq->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->opcode = BOOTP_OPCODE_REQUEST;
+	
+	strcpy(req.ifr_name, device);
+	if (ioctl(sock, SIOCGIFHWADDR, &req)) {
+		log_perror("SIOCSIFHWADDR");
+		return -1;
+	}
+	
+	breq->hw = req.ifr_hwaddr.sa_family;
+	breq->hwlength = IFHWADDRLEN;	
+	memcpy(breq->hwaddr, req.ifr_hwaddr.sa_data, IFHWADDRLEN);
+	memcpy(gen_hwaddr, req.ifr_hwaddr.sa_data, IFHWADDRLEN);
+	
+	breq->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->vendor + 4;
+	while (*chptr != 0xFF && *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 (&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 > BACKOFF_LIMIT)
+		exp = BACKOFF_LIMIT;
+	
+	if (!seed)
+		/* Initialize linear congruential generator.  */
+		seed = (currticks () + *(long *) &gen_hwaddr + ((short *) gen_hwaddr)[2]);
+  
+	/* Simplified version of the LCG given in Bruce Scheier's
+	   "Applied Cryptography".  */
+	q = seed / 53668;
+	if ((seed = 40014 * (seed - 53668 * q) - 12211 * q) < 0)
+		seed += 2147483563l;
+	
+	/* Compute mask.  */
+	for (tmo = 63; tmo <= 60 * TICKS_PER_SEC && --exp > 0; tmo = 2 * tmo + 1)
+		;
+  
+	/* Sleep.  */
+	log_message("<sleep>");
+	
+	for (tmo = (tmo & seed) + currticks (); currticks () < 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->id = starttime = currticks();
+	breq->secs = 0;
+
+	sin = socket(AF_PACKET, SOCK_DGRAM, ntohs(ETH_P_IP));
+	if (sin < 0) {
+		log_perror("af_packet socket");
+		return -1;
+	}
+
+	while (retry <= MAX_ARP_RETRIES) {
+		i = sizeof(*breq);
+
+		if (sendto(s, breq, i, 0, (struct sockaddr *) server_addr, sizeof(*server_addr)) != i) {
+			close(s);
+			log_perror("sendto");
+			return -1;
+		}
+		
+		polls.fd = sin;
+		polls.events = POLLIN;
+
+		while (poll(&polls, 1, timeout*1000) == 1) {
+
+			if ((j = recv(sin, eth_packet, sizeof(eth_packet), 0)) == -1) {
+				log_perror("recv");
+				continue;
+			}
+			
+			/* We need to do some basic sanity checking of the header */
+			if (j < (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->tot_len) > j)
+				continue;
+
+			j = ntohs(ip_hdr->tot_len);
+			
+			if (ip_hdr->protocol != IPPROTO_UDP)
+				continue;
+			
+			udp_hdr = (void *) (eth_packet + sizeof(*ip_hdr));
+
+			if (ntohs(udp_hdr->source) != BOOTP_SERVER_PORT)
+				continue;
+			
+			if (ntohs(udp_hdr->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->id != breq->id)
+				continue;
+			if (bresp->opcode != BOOTP_OPCODE_REPLY)
+				continue;
+			if (bresp->hwlength != breq->hwlength)
+				continue;
+			if (memcmp(bresp->hwaddr, breq->hwaddr, bresp->hwlength))
+				continue;
+			if (get_vendor_code(bresp, DHCP_OPTION_TYPE, &type) || type != dhcp_type)
+				continue;
+			if (memcmp(bresp->vendor, vendor_cookie, 4))
+				continue;
+			return 0;
+		}
+		rfc951_sleep(retry);
+		breq->secs = htons ((currticks () - starttime) / 20);
+		retry++;
+		timeout *= 2;
+		if (timeout > 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->vendor;
+	chptr += 4;
+	while (*chptr != 0xFF && *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 < 0) {
+		log_perror("socket");
+		return RETURN_ERROR;
+	}
+
+	{
+		enum return_type results;
+		char * questions[] = { "Host name", "Domain name", NULL };
+		char * questions_auto[] = { "hostname", "domain" };
+		static char ** answers = NULL;
+		char * boulet;
+
+		client_id_str = client_id_hwaddr = NULL;
+		
+		results = ask_from_entries_auto("If the DHCP server needs to know you by name; please fill in this information. "
+						"Valid answers are for example: `mybox' for hostname and `mynetwork.com' for "
+						"domain name, for a machine called `mybox.mynetwork.com' on the Internet.",
+						questions, &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 && *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, "%s.%s", dhcp_hostname, dhcp_domain);
+			}
+		}
+	}
+
+	if (initial_setup_interface(intf->device, s) != 0) {
+		close(s);
+		return RETURN_ERROR;
+	}
+
+	if (prepare_request(&breq, s, intf->device) != 0) {
+		close(s);
+		return RETURN_ERROR;
+	}
+
+	messageType = DHCP_TYPE_DISCOVER;
+	add_vendor_code(&breq, DHCP_OPTION_TYPE, 1, &messageType);
+
+	/* add pieces needed to have DDNS/DHCP IP selection based on requested name */
+	if (dhcp_hostname && *dhcp_hostname) { /* pick client id form based on absence or presence of domain name */
+		if (*dhcp_domain) /* alternate style <hostname>.<domainname> */
+			add_vendor_code(&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 "1".  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(&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(&breq, BOOTP_OPTION_HOSTNAME, strlen(dhcp_hostname), dhcp_hostname);
+		log_message("DHCP: telling server to use name = %s", dhcp_hostname);
+	}
+
+	memset(&client_addr.sin_addr, 0, sizeof(&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 *) &client_addr, sizeof(client_addr))) {
+		log_perror("bind");
+		return RETURN_ERROR;
+	}
+
+	broadcast_addr.sin_family = AF_INET;
+	broadcast_addr.sin_port = htons(BOOTP_SERVER_PORT);	/* bootp server */
+	memset(&broadcast_addr.sin_addr, 0xff, sizeof(broadcast_addr.sin_addr));  /* broadcast */
+
+	log_message("DHCP: sending DISCOVER");
+
+	wait_message("Sending DHCP request...");
+	i = handle_transaction(s, &breq, &bresp, &broadcast_addr, DHCP_TYPE_OFFER);
+	remove_wait_message();
+
+	if (i != 0) {
+		stg1_error_message("No DHCP reply received.");
+		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(&bresp, DHCP_OPTION_SERVER, &server_addr.sin_addr)) {
+		close(s);
+		log_message("DHCPOFFER didn't include server address");
+		return RETURN_ERROR;
+	}
+
+	init_vendor_codes(&breq);
+	messageType = DHCP_TYPE_REQUEST;
+	add_vendor_code(&breq, DHCP_OPTION_TYPE, 1, &messageType);
+	add_vendor_code(&breq, DHCP_OPTION_SERVER, 4, &server_addr.sin_addr);
+	add_vendor_code(&breq, DHCP_OPTION_REQADDR, 4, &bresp.yiaddr);
+
+	/* if used the first time, then have to use it again */
+	if (dhcp_hostname && *dhcp_hostname) { /* add pieces needed to have DDNS/DHCP IP selection based on requested name */
+		if (dhcp_domain && *dhcp_domain) /* alternate style */
+			add_vendor_code(&breq, DHCP_OPTION_CLIENT_IDENTIFIER, strlen(client_id_str+1)+1, client_id_str);
+		else /* usual style (aka windows / dhcpcd) */
+			add_vendor_code(&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(&breq, BOOTP_OPTION_HOSTNAME, strlen(dhcp_hostname), dhcp_hostname);
+	}
+
+	aShort = ntohs(sizeof(struct bootp_request));
+	add_vendor_code(&breq, DHCP_OPTION_MAXSIZE, 2, &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(&breq, DHCP_OPTION_OPTIONREQ, num_options, requested_options);
+
+	/* request a lease of 1 hour */
+	i = htonl(60 * 60);
+	add_vendor_code(&breq, DHCP_OPTION_LEASE, 4, &i);
+
+	log_message("DHCP: sending REQUEST");
+
+	i = handle_transaction(s, &breq, &bresp, &broadcast_addr, DHCP_TYPE_ACK);
+
+	if (i != 0) {
+		close(s);
+		return RETURN_ERROR;
+	}
+
+	if (get_vendor_code(&bresp, DHCP_OPTION_LEASE, &lease)) {
+		log_message("failed to get lease time\n");
+		return RETURN_ERROR;
+	}
+	lease = ntohl(lease);
+
+	close(s);
+
+	intf->netmask.s_addr = 0;
+	intf->broadcast.s_addr = 0;
+	intf->network.s_addr = 0;
+
+	parse_reply(&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 (gc at mandriva.com)
+ *
+ * Copyright 2000 Mandriva
+ *
+ * View the homepage: http://us.mandriva.com/~gc/html/stage1.html
+ *
+ *
+ * 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 "stage1.h"
+#include "network.h"
+
+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 (gc at mandriva.com)
+ * Olivier Blin (oblin at mandriva.com)
+ *
+ * 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 (ewt at redhat.com)
+ *
+ * Copyright 1996 Red Hat Software 
+ *
+ */
+
+#include <unistd.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <libgen.h>
+#include "stage1.h"
+#include "frontend.h"
+#include "log.h"
+#include "tools.h"
+#include "utils.h"
+#include "lomount.h"
+
+char * extract_list_directory(char * direct)
+{
+	char ** full = list_directory(direct);
+	char tmp[20000] = "";
+	int i;
+	for (i=0; i<50 ; i++) {
+		if (!full || !*full)
+			break;
+		strcat(tmp, *full);
+		strcat(tmp, "\n");
+		full++;
+	}
+	return strdup(tmp);
+}
+
+static void choose_iso_in_directory(char *directory, char *location_full) 
+{
+	char **file;
+	char *stage2_isos[100] = { "Use directory as a mirror tree", "-----" };
+	int stage2_iso_number = 2;
+
+	log_message("\"%s\" exists and is a directory, looking for iso files", directory);
+
+	for (file = list_directory(directory); *file; file++) {
+		char isofile[500];
+		char * loopdev = NULL;
+
+		if (strstr(*file, ".iso") != *file + strlen(*file) - 4)
+			/* file doesn't end in .iso, skipping */
+			continue;
+			
+		strcpy(isofile, directory);
+		strcat(isofile, "/");
+		strcat(isofile, *file);
+
+		if (lomount(isofile, LOOP_LOCATION, &loopdev, 0)) {
+			log_message("unable to mount iso file \"%s\", skipping", isofile);
+			continue;
+		}
+		symlink(LOOP_LOCATION_REL "/" ARCH, IMAGE_LOCATION);
+
+		if (image_has_stage2()) {
+			log_message("stage2 installer found in ISO image \"%s\"", isofile);
+			stage2_isos[stage2_iso_number++] = strdup(*file);
+		} else {
+			log_message("ISO image \"%s\" doesn't contain stage2 installer", isofile);
+		}
+
+		unlink(IMAGE_LOCATION);
+		umount(LOOP_LOCATION);
+		del_loop(loopdev);
+	}
+
+	stage2_isos[stage2_iso_number] = NULL;
+
+	if (stage2_iso_number > 2) {
+		enum return_type results;
+		do {
+			results = ask_from_list("Please choose the ISO image to be used to install the "
+						DISTRIB_NAME " Distribution.",
+						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, "/");
+					strcat(location_full, *file);
+					log_message("installer will use ISO image \"%s\"", location_full);
+				}
+			}
+		} while (results == RETURN_ERROR);
+	} else {
+		log_message("no ISO image found in \"%s\" directory", 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, &statbuf) && S_ISDIR(statbuf.st_mode)) {
+		choose_iso_in_directory(directory, location_full);
+	}
+
+	loopdev = NULL;
+	if (!stat(location_full, &statbuf) && !S_ISDIR(statbuf.st_mode)) {
+		log_message("%s exists and is not a directory, assuming this is an ISO image", location_full);
+		if (lomount(location_full, LOOP_LOCATION, &loopdev, 0)) {
+			stg1_error_message("Could not mount file %s as an ISO image of the " DISTRIB_NAME " Distribution.", location_full);
+			return RETURN_ERROR;
+		}
+		symlink(LOOP_LOCATION_REL "/" ARCH, IMAGE_LOCATION);
+		add_to_env("ISOPATH", location_full);
+		add_to_env("METHOD", method_iso);
+	} else {
+		create_IMAGE_LOCATION(location_full);
+		add_to_env("METHOD", method_live);
+	}
+
+	if (access(IMAGE_LOCATION "/" COMPRESSED_LOCATION_REL, R_OK)) {
+		stg1_error_message("I can't find the " DISTRIB_NAME " Distribution in the specified directory. "
+				   "(I need the subdirectory " COMPRESSED_LOCATION_REL ")\n"
+				   "Here's a short extract of the files in the directory:\n"
+				   "%s", extract_list_directory(IMAGE_LOCATION));
+		ret = RETURN_BACK;
+	} else if (may_load_compressed_image() != RETURN_OK) {
+		stg1_error_message("Could not load program into memory.");
+		ret = RETURN_ERROR;
+	}
+
+	if (ret == RETURN_OK)
+		log_message("found the " DISTRIB_NAME " Installation, good news!");
+
+	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 (gc at mandriva.com)
+ * Olivier Blin (oblin at mandriva.com)
+ *
+ * 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 (ewt at redhat.com)
+ *
+ * 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 (gc at mandriva.com)
+ *
+ * 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 (ewt at redhat.com)
+ *
+ * Copyright 1996 Red Hat Software 
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <libgen.h>
+#include "stage1.h"
+#include "frontend.h"
+#include "modules.h"
+#include "probing.h"
+#include "log.h"
+#include "tools.h"
+#include "utils.h"
+#include "mount.h"
+#include "automatic.h"
+#include "directory.h"
+#include "partition.h"
+
+#include "disk.h"
+
+static enum return_type try_automatic_with_partition(char *dev) {
+	enum return_type results;
+	int mounted;
+	wait_message("Trying to access " DISTRIB_NAME " disk (partition %s)", 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, "disk", "disk-iso");
+			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("Trying to access " DISTRIB_NAME " disk (drive %s)", model);
+	if (list_partitions(disk, parts, parts_comments)) {
+		stg1_error_message("Could not read partitions information.");
+		return RETURN_ERROR;
+	}
+	remove_wait_message();
+	dev = parts;
+	while (dev && *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 && *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[] = { "Directory or ISO images directory or ISO image", NULL };
+	char * questions_location_auto[] = { "directory", 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("Could not read partitions information.");
+		return RETURN_ERROR;
+        }
+
+        /* uglyness to allow auto starting with devfs */
+        if (!IS_AUTOMATIC || streq((choice = get_auto_value("partition")), "")) {
+                if (parts[0] == NULL) {
+                        stg1_error_message("No partition found.");
+                        return RETURN_ERROR;
+                }
+
+                results = ask_from_list_comments_auto("Please select the partition containing the copy of the "
+						      DISTRIB_NAME " Distribution install source.",
+                                                      parts, parts_comments, &choice, "partition", parts);
+                if (results != RETURN_OK)
+                        return results;
+        }
+
+	/* in testing mode, assume the partition is already mounted on MEDIA_LOCATION */
+        if (!IS_TESTING && try_mount(choice, MEDIA_LOCATION)) {
+		stg1_error_message("I can't find a valid filesystem (tried: ext2, vfat, ntfs, reiserfs). "
+                                   "Make sure the partition has been cleanly unmounted.");
+		return try_with_device(dev_name);
+	}
+
+ ask_dir:
+	if (ask_from_entries_auto("Please enter the directory (or ISO image file) containing the "
+				  DISTRIB_NAME " Distribution install source.",
+				  questions_location, &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, "/");
+	strcat(location_full, answers_location[0]);
+
+	if (access(location_full, R_OK)) {
+		char * path = strdup(answers_location[0]);
+		stg1_error_message("Directory or ISO image file could not be found on partition.\n"
+			      "Here's a short extract of the files in the directory %s:\n"
+			      "%s", dirname(path), extract_list_directory(dirname(location_full)));
+		free(path);
+		goto ask_dir;
+	}
+
+	results = try_with_directory(location_full, "disk", "disk-iso");
+	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(&medias, &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("ide_generic", ANY_DRIVER_TYPE, NULL, 0);
+			return disk_prepare();
+		}
+		stg1_error_message("No DISK drive found.");
+		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("Please select the disk containing the copy of the "
+					      DISTRIB_NAME " Distribution install source.",
+					      medias, medias_models, &choice, "disk", 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 (gc at mandriva.com)
+ *
+ * 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 (ewt at redhat.com)
+ *
+ * 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 (gc at mandriva.com)
+ *
+ * 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 (ewt at redhat.com)
+ *
+ * Copyright 1996 Red Hat Software 
+ *
+ */
+
+#include <stdlib.h>
+
+// dietlibc can do hostname lookup, whereas glibc can't when linked statically :-(
+
+#if defined(__dietlibc__)
+
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <resolv.h>
+
+#include "network.h"
+#include "log.h"
+
+#include "dns.h"
+
+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 && domain) {
+		// gethostbyname from dietlibc doesn't support domain handling
+		char fully_qualified[500];
+		sprintf(fully_qualified, "%s.%s", name, domain);
+		h = gethostbyname(fully_qualified);
+	}
+
+	if (h && h->h_addr_list && (h->h_addr_list)[0]) {
+		memcpy(addr, (h->h_addr_list)[0], sizeof(*addr));
+		log_message("is-at: %s", inet_ntoa(*addr));
+		return 0;
+	}
+
+	log_message("unknown host %s", 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, &in))
+		return NULL;
+	host = gethostbyaddr(&(in.s_addr), sizeof(in.s_addr) /* INADDRSZ */, AF_INET);
+	if (host && host->h_name)
+		return host->h_name;
+	return NULL;
+}
+
+#elif defined(__GLIBC__)
+  
+#include <alloca.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <resolv.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "log.h"
+
+#include "dns.h"
+
+/* 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 *) &response, sizeof(response));
+	if (len <= 0)
+		return -1;
+
+	if (ntohs(response.hdr.rcode) != NOERROR)
+		return -1;
+
+	ancount = ntohs(response.hdr.ancount);
+	if (ancount < 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 >= 0 && data < 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 <= 0) return -1;
+			if (queryType == T_PTR && 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 && 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 < 4; i++) {
+		chptr = strbuf;
+		while (*chptr && *chptr != '.')
+			chptr++;
+		*chptr = '\0';
+		
+		if (chptr - strbuf > 3) return NULL;
+		splits[i] = strbuf;
+		strbuf = chptr + 1;
+	}
+	
+	sprintf(ipnum, "%s.%s.%s.%s.in-addr.arpa", splits[3], splits[2], splits[1], splits[0]);
+	
+	rc = do_query(ipnum, T_PTR, &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("is-at %s", inet_ntoa(*addr));
+	return rc;
+}
+
+#else
+
+#error "Unsupported C library"
+
+#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 (gc at mandriva.com)
+ *
+ * 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 (ewt at redhat.com)
+ *
+ * Copyright 1996 Red Hat Software 
+ *
+ */
+
+#ifndef H_DNS
+#define H_DNS 
+
+#include <netinet/in.h>
+
+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 "menu.lst" 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 "tftpserver" 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 ]
+
+	http://people.mandriva.com/~gc/html/stage1.html
+
+
+[ 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 "stage 2") 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 "physically" to a floppy with the
+command:
+
+# dd if=<boot-disk> of=/dev/fd0
+
+Our boot disks are called "cdrom.img", "network.img", 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 "cdrom.img" 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 "hd.img" 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 "network.img" 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
+"pcmcia.img" 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
+"log.h" 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 "expert" and "rescue" 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 "rescue.img" file.
+Just hit "F1" at boot time, type in "rescue", 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 "automatic" 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 "virtual" question answered automatically,
+either from a list or from a free field.
+
+
+Keywords are:
+
+
+`method' <- (nfs,ftp,http,cdrom,disk)
+
+if nfs/ftp/http:
+
+    `network' <- (static,dhcp,adsl)
+
+    if multiple interfaces detected:
+
+        `interface' <- (list-of-detected-interfaces)
+         if "auto":
+           use the first interface with a link beat
+         if "wired":
+           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' <- (list-of-detected-disks)
+
+    `partition' <- (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 "short_aliases".
+
+This gives for example for:
+
+	automatic=method:nfs,network:static,ip:192.168.1.24,server:192.168.1.7,directory:/stable/i586
+==>
+	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 "Update Modules" (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 "mke2fs /dev/fd0" 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 "to_load". 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 <kernel-version>. They must be
+gzipped if the installed kernel modules are gzipped.
+
+You may need to specify the "category" 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 "updatemodules"
+
+   (you may do that by pressing F1 then entering "linux updatemodules")
+
+
+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:
+
+[root at obiwan 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
+[root at obiwan 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
+[root at obiwan 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
+[root at obiwan mnt]# 
+--=----=----=----=----=----=----=----=----=--
+
+
+3. The program reads the special file "to_load" 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 "fat" from the standard modules
+before "msdos" 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 (gc at mandriva.com)
+ *
+ * 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 (gc at mandriva.com)
+ *
+ * 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 <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include <probing.h>
+
+#include "frontend.h"
+
+
+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, &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 (gc at mandriva.com)
+ *
+ * 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 <stdarg.h>
+
+/* '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 (gc at mandriva.com)
+ *
+ * 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 (ewt at redhat.com)
+ *
+ * Copyright 1996 Red Hat Software 
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mount.h>
+#include <linux/un.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <linux/unistd.h>
+#include <sys/select.h>
+#include <sys/ioctl.h>
+
+#include <sys/syscall.h>
+#define syslog(...) syscall(__NR_syslog, __VA_ARGS__)
+#define reboot(...) syscall(__NR_reboot, __VA_ARGS__)
+
+#include "config-stage1.h"
+#include <linux/cdrom.h>
+
+#if defined(__powerpc__)
+#define TIOCSCTTY     0x540E
+#endif
+
+
+#define BINARY "/sbin/stage1"
+#define BINARY_STAGE2 "/usr/bin/runinstall2"
+
+
+char * env[] = {
+	"PATH=/usr/bin:/bin:/sbin:/usr/sbin:/mnt/sbin:/mnt/usr/sbin:/mnt/bin:/mnt/usr/bin",
+	"LD_LIBRARY_PATH=/lib:/usr/lib:/mnt/lib:/mnt/usr/lib:/usr/X11R6/lib:/mnt/usr/X11R6/lib"
+#if defined(__x86_64__) || defined(__ppc64__)
+	":/lib64:/usr/lib64:/usr/X11R6/lib64:/mnt/lib64:/mnt/usr/lib64:/mnt/usr/X11R6/lib64"
+#endif
+	,
+	"HOME=/",
+	"TERM=linux",
+	"TERMINFO=/etc/terminfo",
+	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("FATAL ERROR IN INIT: %s\n\nI can't recover from this, please reboot manually and send bugreport.\n", msg);
+        select(0, NULL, NULL, NULL, NULL);
+}
+
+void print_error(char *msg)
+{
+	printf("E: %s\n", msg);
+}
+
+void print_warning(char *msg)
+{
+	printf("W: %s\n", msg);
+}
+
+void print_int_init(int fd, int i)
+{
+	char buf[10];
+	char * chptr = buf + 9;
+	int j = 0;
+	
+	if (i < 0)
+	{
+		write(1, "-", 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("/proc/kmsg", O_RDONLY,0);
+	if (in < 0) {
+		print_error("could not open /proc/kmsg");
+		return;
+	}
+
+        mkdir("/tmp", 0755);
+	if ((log = open("/tmp/syslog", O_WRONLY | O_CREAT | O_APPEND, 0644)) < 0) {
+		print_error("error opening /tmp/syslog");
+		sleep(5);
+		return;
+	}
+
+	if ((klog_pid = fork())) {
+		close(in);
+		close(log);
+		return;
+	} else {
+		close(0); 
+		close(1);
+		close(2);
+	}
+	
+	out = open("/dev/tty4", O_WRONLY, 0);
+	if (out < 0) 
+		print_warning("couldn't open tty for syslog -- still using /tmp/syslog\n");
+
+	/* now open the syslog socket */
+// ############# LINUX 2.4 /dev/log IS BUGGED! --> apparently the syslogs can't reach me, and it's full up after a while
+//	  sockaddr.sun_family = AF_UNIX;
+//	  strncpy(sockaddr.sun_path, "/dev/log", UNIX_PATH_MAX);
+//	  sock = socket(AF_UNIX, SOCK_STREAM, 0);
+//	  if (sock < 0) {
+//		  printf("error creating socket: %d\n", errno);
+//		  sleep(5);
+//	  }
+//
+//	  print_str_init(log, "] got socket\n");
+//	  if (bind(sock, (struct sockaddr *) &sockaddr, sizeof(sockaddr.sun_family) + strlen(sockaddr.sun_path)))	{
+//		  print_str_init(log, "] bind error: ");
+//		  print_int_init(log, errno);
+//		  print_str_init(log, "\n");
+//		  sleep(//	  }
+//
+//	  print_str_init(log, "] bound socket\n");
+//	  chmod("/dev/log", 0666);
+//	  if (listen(sock, 5)) {
+//		  print_str_init(log, "] listen error: ");
+//		  print_int_init(log, errno);
+//		  print_str_init(log, "\n");
+//		  sleep(5);
+//	  }
+
+	/* disable on-console syslog output */
+	syslog(8, NULL, 1);
+
+	print_str_init(log, "] kernel/system logger ok\n");
+	FD_ZERO(&unixs);
+	while (1) {
+		memcpy(&readset, &unixs, sizeof(unixs));
+
+		if (sock >= 0)
+			FD_SET(sock, &readset);
+		FD_SET(in, &readset);
+		
+		i = select(20, &readset, NULL, NULL, NULL);
+		if (i <= 0)
+			continue;
+
+		/* has /proc/kmsg things to tell us? */
+		if (FD_ISSET(in, &readset)) {
+			i = read(in, buf, sizeof(buf));
+			if (i > 0) {
+				if (out >= 0)
+					write(out, buf, i);
+				write(log, buf, i);
+			}
+		} 
+
+		/* the socket has moved, new stuff to do */
+		if (sock >= 0 && FD_ISSET(sock, &readset)) {
+			s = sizeof(sockaddr);
+			readfd = accept(sock, (struct sockaddr *) &sockaddr, &s);
+			if (readfd < 0) {
+				char * msg_error = "] error in accept\n";
+				if (out >= 0)
+					write(out, msg_error, strlen(msg_error));
+				write(log, msg_error, strlen(msg_error));
+				close(sock);
+				sock = -1;
+			}
+			else
+				FD_SET(readfd, &unixs);
+		}
+	}
+}
+
+
+#define LOOP_CLR_FD	0x4C01
+
+void del_loops(void) 
+{
+        char loopdev[] = "/dev/loop0";
+        char chloopdev[] = "/dev/chloop0";
+        int i;
+        for (i=0; i<8; i++) {
+                int fd;
+                loopdev[9] = '0' + i;
+                fd = open(loopdev, O_RDONLY, 0);
+                if (fd > 0) {
+                        if (!ioctl(fd, LOOP_CLR_FD, 0))
+                                printf("\t%s\n", loopdev);
+                        close(fd);
+                }
+                chloopdev[11] = '0' + i;
+                fd = open(chloopdev, O_RDONLY, 0);
+                if (fd > 0) {
+                        if (!ioctl(fd, LOOP_CLR_FD, 0))
+                                printf("\t%s\n", 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("unmounting filesystems...\n"); 
+	
+	fd = open("/proc/mounts", O_RDONLY, 0);
+	if (fd < 1) {
+		print_error("failed to open /proc/mounts");
+		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, "nfs"))
+                        disallow_eject = 1;
+		if (strcmp(fs[numfs].name, "/")
+                    && !strstr(fs[numfs].dev, "ram")
+                    && strcmp(fs[numfs].name, "/dev")
+                    && strcmp(fs[numfs].name, "/sys")
+                    && strncmp(fs[numfs].name, "/proc", 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 < numfs; i++) {
+			/*printf("trying with %s\n", fs[i].name);*/
+                        del_loops();
+			if (fs[i].mounted && umount(fs[i].name) == 0) { 
+				printf("\t%s\n", fs[i].name);
+				fs[i].mounted = 0;
+				nb++;
+			}
+		}
+	} while (nb);
+	
+	for (i = nb = 0; i < numfs; i++)
+		if (fs[i].mounted) {
+			printf("\tumount failed: %s\n", fs[i].name);
+			if (strcmp(fs[i].fs, "ext3") == 0) nb++; /* don't count not-ext3 umount failed */
+		}
+
+	
+	if (nb) {
+		printf("failed to umount some filesystems\n");
+                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("/var/run/rebootctl", O_RDONLY, 0)) > 0) {
+                char buf[100];
+                int i = read(fd, buf, sizeof(buf));
+                close(fd);
+                if (strstr(buf, "halt"))
+                        reboot_magic = BMAGIC_POWEROFF;
+                return i > 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 > 1 && argv[1][0] >= '0' && argv[1][0] <= '9') {
+                printf("This is no normal init, sorry.\n"
+                       "Call `reboot' or `halt' directly.\n");
+                return 0;
+        }
+
+	if (!testing) {
+		/* turn off screen blanking */
+		printf("\033[9;0]");
+		printf("\033[8]");
+	}
+	else
+		printf("*** TESTING MODE *** (pid is %d)\n", getpid());
+
+
+	if (!testing) {
+		mkdir("/proc", 0755);
+		if (mount("/proc", "/proc", "proc", 0, NULL))
+			fatal_error("Unable to mount proc filesystem");
+		mkdir("/sys", 0755);
+		if (mount("none", "/sys", "sysfs", 0, NULL))
+			fatal_error("Unable to mount sysfs filesystem");
+	}
+	
+
+	/* ignore Control-C and keyboard stop signals */
+	signal(SIGINT, SIG_IGN);
+	signal(SIGTSTP, SIG_IGN);
+
+	if (!testing) {
+		fd = open("/dev/console", O_RDWR, 0);
+		if (fd < 0)
+			fatal_error("failed to open /dev/console");
+		
+		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("could not set new controlling tty");
+
+	if (!testing) {
+		char my_hostname[] = "localhost";
+		sethostname(my_hostname, sizeof(my_hostname));
+		/* the default domainname (as of 2.0.35) is "(none)", which confuses 
+		   glibc */
+		setdomainname("", 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("proceeding, please wait...\n");
+		}
+
+                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("error in exec of %s :-( [%d]\n", child_argv[0], errno);
+                        return 0;
+                }
+
+                do {
+                        childpid = wait4(-1, &wait_status, 0, NULL);
+                } while (childpid != installpid);
+
+		counter++;
+        } while (WIFEXITED(wait_status) && 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) && WEXITSTATUS(wait_status) == exit_value_proceed) {
+		kill(klog_pid, 9);
+		printf("proceeding, please wait...\n");
+
+		{
+			char * child_argv[2] = { "/sbin/init", NULL };
+			execve(child_argv[0], child_argv, env);
+		}
+		fatal_error("failed to exec /sbin/init");
+        } else if (!WIFEXITED(wait_status) || WEXITSTATUS(wait_status) != 0) {
+		printf("exited abnormally :-( ");
+		if (WIFSIGNALED(wait_status))
+			printf("-- received signal %d", WTERMSIG(wait_status));
+		printf("\n");
+	  	abnormal_termination = 1;
+        }
+
+        if (!abnormal_termination) {
+                int i;
+                for (i=0; i<50; i++)
+                        printf("\n");  /* cleanup startkde messages */
+        }
+
+	if (testing)
+		return 0;
+
+	sync(); sync();
+	sleep(2);
+
+	printf("sending termination signals...");
+	kill(-1, 15);
+	sleep(2);
+	printf("done\n");
+
+	printf("sending kill signals...");
+	kill(-1, 9);
+	sleep(2);
+	printf("done\n");
+
+	unmount_filesystems();
+
+	sync(); sync();
+
+	if (!abnormal_termination) {
+                if (reboot_magic == BMAGIC_REBOOT) {
+#ifdef DEBUG
+                        printf("automatic reboot in 10 seconds\n");
+                        sleep(10);
+#endif
+                        reboot(0xfee1dead, 672274793, reboot_magic);
+                } else {
+                        printf("you may safely poweroff your computer now\n");
+                }
+	} else {
+		printf("you may safely reboot or halt your system\n");
+	}
+
+        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 "ka.h"
+#include <sys/mount.h>
+#include "mount.h"
+#include <sys/wait.h>
+#include <dirent.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+
+#include "config-stage1.h"
+#include "frontend.h"
+#include "log.h"
+#include "tools.h"
+
+struct in_addr next_server = { 0 };
+
+#if 0
+static void save_stuff_for_rescue(void) 
+{
+  copy_file("/etc/resolv.conf", STAGE2_LOCATION "/etc/resolv.conf", NULL);
+}
+#endif
+
+static void my_pause(void) {
+	unsigned char t;
+	fflush(stdout);
+	read(0, &t, 1);
+}
+
+static enum return_type ka_wait_for_stage2(int count)
+{
+	char * ramdisk = "/dev/ram3"; /* warning, verify that this file exists in the initrd*/
+	char * ka_launch[] = { "/ka/ka-d-client", "-w","-s","getstage2","-e","(cd /tmp/stage2; tar -x -f - )", NULL }; /* The command line for ka_launch */
+	char * mkfs_launch[] = { "/sbin/mke2fs", "-m", "0", ramdisk, NULL}; /* The mkfs command for formating the ramdisk */
+
+	log_message("KA: Preparing to receive stage 2....");
+        wait_message("Preparing to receive stage 2");
+
+	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("KA: Can't execute %s\n<press Enter>\n", mkfs_launch[0]);
+		my_pause();
+		return KAERR_CANTFORK;
+	}
+	while (wait4(-1, &wait_status, 0, NULL) != pida) {}; /* Waiting the end of mkfs */
+	remove_wait_message();
+
+        wait_message("Mounting /dev/ram3 at %s", STAGE2_LOCATION);
+	if (my_mount(ramdisk, STAGE2_LOCATION, "ext2", 1)) {/* Trying to mount the ramdisk */
+		return RETURN_ERROR;
+	}
+	remove_wait_message();
+
+	log_message("KA: Waiting for stage 2....");
+	wait_message("Waiting for rescue from KA server (Try %d/%d)", 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, "%s: Failed to fork()\n", strerror(errno));
+		exit(13);
+	} else if ( pid == 0 ) {
+	  //	  close(2);
+		execv(ka_launch[0], ka_launch);
+	} else {
+		// wpid = wait(&status);   /* Child's exit status */
+		wpid = wait4(-1, &status, 0, NULL);
+		if ( wpid == -1 ) {
+			fprintf(stderr,"%s: wait()\n", strerror(errno));
+			return RETURN_ERROR;
+		} else if ( wpid != pid )
+			abort();
+		else {
+			if ( WIFEXITED(status) ) {
+				printf("Exited: $? = %d\n", WEXITSTATUS(status));
+			} else if ( WIFSIGNALED(status) ) {
+				printf("Signal: %d%s\n", WTERMSIG(status), WCOREDUMP(status) ? " with core file." : "");
+			}
+		}
+	}
+
+	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("KA: Can't execute %s\n<press Enter>\n", ka_launch[0]);
+	//  log_message("KA: Can't execute %s\n<press Enter>\n", ka_launch[0]);
+	//  my_pause();
+	//  return KAERR_CANTFORK;
+	//}
+
+	//while (wait4(-1, &wait_status, 0, NULL) != pid) {}; /* Waiting the end of duplication */
+	//  log_message("kalaunch ret %d\n", 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 ("/ka/tftpserver","w");
+
+	if (f != NULL) {
+		/* Writing the NEXT_SERVER value of the DHCP Request in the /ka/tftpserver file */
+		fprintf(f,"%s\n",inet_ntoa(next_server));
+		fclose(f);
+	}
+
+	log_message("KA: Trying to retrieve stage2 from server");
+	log_message("KA: ka_wait_for_stage2");
+	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,"/ka");
+			DIR *dp = opendir(dir);
+
+			/* Does the STAGE2_LOCATION/ka directory exists ? = Does the rescue with ka well downloaded ?*/
+			if (!dp) {
+				log_message("KA: Server not found !");
+				/* Be sure that the STAGE2_LOCATION isn't mounted after receiving a wrong rescue */
+				if (umount (STAGE2_LOCATION)) {
+					log_perror("KA: Unable to umount STAGE2");
+				}
+				int cpt;
+
+				if (server_failure++ == KA_MAX_RETRY){
+					/* if the KA server can't be reach KA_MAX_RETRY times */
+					char * reboot_launch[] = { "/sbin/reboot", NULL};
+					for (cpt=5; cpt>0; cpt--) {
+						wait_message("!!! Can't reach a valid KA server !!! (Rebooting in %d sec)",cpt);
+						sleep (1);
+					}
+					/* Rebooting the computer to avoid infinite loop on ka mode */
+					execv(reboot_launch[0], reboot_launch);
+				}
+
+				for (cpt=5; cpt>0; cpt--) {
+					wait_message("KA server not found ! (Try %d/%d in %d sec)",server_failure,KA_MAX_RETRY,cpt);
+					log_message("Ka not found %d/%d", server_failure,KA_MAX_RETRY);
+					sleep (1);
+				}
+				remove_wait_message();
+				/* We should try another time*/
+				results=RETURN_BACK;
+				continue;
+			}
+
+			if (dp) {
+				log_message("KA: Stage 2 downloaded successfully");
+				closedir(dp); /* Closing the /ka directory */
+				server_failure=1; /* Resetting server_failure */
+				results = RETURN_OK;
+			}
+		}
+
+		log_message("KA: Preparing chroot");
+		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("KA: Unable to umount STAGE2");
+		// return RETURN_ERROR;
+		//      }
+		//    }
+	} while (results == RETURN_BACK);
+
+	//  method_name = strdup("ka");
+	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 (gc at mandriva.com)
+ *
+ * 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 (ewt at redhat.com)
+ *
+ * Copyright 1996 Red Hat Software 
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include "stage1.h"
+
+#include "log.h"
+
+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, "* ");
+		vfprintf(logfile, s, args);
+		fprintf(logfile, "\n");
+		fflush(logfile);
+	}
+	if (logtty) {
+		fprintf(logtty, "* ");
+		vfprintf(logtty, s, args_copy);
+		fprintf(logtty, "\n");
+		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("%s: %s", msg, strerror(errno));
+}
+
+
+void open_log(void)
+{
+	if (!IS_TESTING) {
+		logtty  = fopen("/dev/tty3", "w");
+		logfile = fopen("/tmp/stage1.log", "w");
+	}
+	else
+		logfile = fopen("debug.log", "w");
+}
+
+void close_log(void)
+{
+	if (logfile) {
+		log_message("stage1: disconnecting life support systems");
+		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 (gc at mandriva.com)
+ *
+ * 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 (ewt at redhat.com)
+ *
+ * Copyright 1996 Red Hat Software 
+ *
+ */
+
+
+#ifndef _LOG_H_
+#define _LOG_H_
+
+#include <stdarg.h>
+
+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 (gc at mandriva.com)
+ *
+ * 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 <sys/types.h>
+#include <sys/mount.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "stage1.h"
+#include "frontend.h"
+#include "log.h"
+#include "mount.h"
+#include "modules.h"
+
+#include "lomount.h"
+
+
+#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)) < 0)
+		return 1;
+  
+	if ((fd = open (device, mode)) < 0) {
+		close(ffd);
+		return 1;
+	}
+
+	memset(&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("CRITICAL Couldn't lock into memory! %s (memlock)", strerror(errno));
+		  return 1;
+	  }
+#endif
+
+	if (ioctl(fd, LOOP_SET_FD, ffd) < 0) {
+		close(fd);
+		close(ffd);
+		return 1;
+	}
+
+	if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 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<256; i++) {
+                int fd;
+		char ldev[100];
+		sprintf(ldev, "/dev/loop%d", i);
+                ensure_dev_exists(ldev);
+                fd = open(ldev, O_RDONLY);
+                if (!ioctl(fd, LOOP_GET_STATUS, &loopinfo)) {
+                        close(fd);
+                        continue;
+                }
+                if (errno == ENXIO) {
+                        log_message("%s is available", ldev);
+                        close(fd);
+                        return strdup(ldev);
+                } else {
+                        log_perror("LOOP_GET_STATUS(unexpected error)");
+                        close(fd);
+                        continue;
+                }
+        }
+        return NULL;
+}
+
+void
+del_loop(char * loopdev)
+{
+	int fd;
+
+        if (!loopdev)
+                return;
+
+	if ((fd = open (loopdev, O_RDONLY)) < 0)
+		return;
+
+	if (ioctl (fd, LOOP_CLR_FD, 0) < 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("loop", ANY_DRIVER_TYPE, "max_loop=256", 1);
+	if (compressed) {
+	    my_insmod("sqlzma", ANY_DRIVER_TYPE, NULL, 1);
+	    my_insmod("squashfs_lzma", ANY_DRIVER_TYPE, NULL, 1);
+	    my_insmod("squashfs", ANY_DRIVER_TYPE, NULL, 1);
+	}
+
+        if (!(loopdev = find_free_loop())) {
+		log_message("could not find a free loop");
+		return 1;
+        }
+        if (dev)
+                *dev = loopdev;
+
+	if (set_loop(loopdev, loopfile)) {
+		log_message("set_loop failed on %s (%s)", loopdev, strerror(errno));
+		return 1;
+	}
+  
+	if (my_mount(loopdev, where, compressed ? "squashfs" : "iso9660", 0)) {
+		del_loop(loopdev);
+		return 1;
+	}
+
+	log_message("lomount succeeded for %s on %s", 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 (gc at mandriva.com)
+ *
+ * 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 (gc at mandriva.com)
+ *
+ * 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 "stage1.h"
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/utsname.h>
+#include "log.h"
+#include "utils.h"
+#include "frontend.h"
+#include "mount.h"
+#include "zlibsupport.h"
+
+#include "modules.h"
+
+#define UEVENT_HELPER_FILE "/sys/kernel/uevent_helper"
+#define UEVENT_HELPER_VALUE "/sbin/hotplug"
+
+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 "Invalid module format";
+	case ENOENT:
+		return "Unknown symbol in module";
+	case ESRCH:
+		return "Module has wrong symbol version";
+	case EINVAL:
+		return "Invalid parameters";
+	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, &len);
+                
+	if (!file) {
+		log_perror(asprintf_("\terror reading %s", path));
+		return -1;
+	}
+                
+	rc = init_module(file, len, options ? options : "");
+	if (rc)
+		log_message("\terror: %s", moderror(errno));
+	return rc;
+}
+
+static char *kernel_module_extension(void)
+{
+	return ".ko.gz";
+}
+
+
+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 && *p) {
+		if (*p == '-')
+			*p = '_';
+		p++;
+	}
+
+	return modname;
+}
+
+static void find_modules_directory(void)
+{
+	struct utsname kernel_uname;
+	char * prefix = "/lib/modules";
+	char * release;
+	if (uname(&kernel_uname)) {
+		fatal_error("uname failed");
+	}
+	release = kernel_uname.release;
+	sprintf(modules_directory , "%s/%s", prefix, release);
+}
+
+static int load_modules_dependencies(void)
+{
+	char * deps_file = asprintf_("%s/%s", modules_directory, "modules.dep");
+	char * buf, * ptr, * start, * end;
+	struct stat s;
+	int line, i;
+
+	log_message("loading modules dependencies");
+	buf = cat_file(deps_file, &s);
+	if (!buf)
+		return -1;
+	line = line_counts(buf);
+	modules_deps = malloc(sizeof(*modules_deps) * (line+1));
+
+	start = buf;
+	line = 0;
+	while (start < (buf+s.st_size) && *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 && (*ptr == ' ')) ptr++;
+
+		/* sort of a good line */
+		modules_deps[line].filename = start[0] == '/' ? strdup(start) : asprintf_("%s/%s", modules_directory, start);
+		modules_deps[line].modname = filename2modname(start);
+
+		start = ptr;
+		i = 0;
+		while (start && *start && i < 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 && *start && *start == ' ')
+				start++;
+		}
+		if(i >= sizeof(tmp_deps)/sizeof(char *)-1) {
+			log_message("warning, more than %zu dependencies for module %s",
+				    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_("%s/%s", modules_directory, "modules.description");
+	char * buf, * ptr, * start, * end;
+	struct stat s;
+	int line;
+
+	log_message("loading modules descriptions");
+
+	buf = cat_file(descr_file, &s);
+	if (!buf)
+		return -1;
+	line = line_counts(buf);
+	modules_descr = malloc(sizeof(*modules_descr) * (line+1));
+
+	start = buf;
+	line = 0;
+	while (start < (buf+s.st_size) && *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("warning, unable to set firmware loader");
+		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("warning, error initing modules stuff, modules loading disabled");
+	}
+	if (load_modules_descriptions()) {
+		log_message("warning, error initing modules stuff");
+	}
+}
+
+
+static void add_modules_conf(char * str)
+{
+	static char data[5000] = "";
+	char * target = "/tmp/modules.conf";
+	int fd;
+
+	if (strlen(data) + strlen(str) >= sizeof(data))
+		return;
+
+	strcat(data, str);
+	strcat(data, "\n");
+
+	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("/proc/modules", "rb"))) {
+                while (1) {
+                        char buf[500];
+                        if (!fgets(buf, sizeof(buf), f)) break;
+                        if (!strncmp(name, buf, strlen(name)) && 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 && dep->modname && strcmp(dep->modname, mod_name)) dep++;
+
+	if (dep && dep->modname && dep->deps) {
+		char ** one_dep;
+		one_dep = dep->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 && dep->filename) {
+	       filename = dep->filename;
+	} else {
+		log_message("warning: unable to get module filename for %s", mod_name);
+		filename = mod_name;
+	}
+
+	if (module_already_present(mod_name))
+		return INSMOD_OK;
+
+	log_message("needs %s", 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("have to insmod %s", mod_name);
+
+#ifndef DISABLE_NETWORK
+	if (type == NETWORK_DEVICES)
+		net_devices = get_net_devices();
+#endif
+
+#ifdef ENABLE_NETWORK_STANDALONE
+	{
+		char *cmd = options ? asprintf_("/sbin/modprobe %s %s", mod_name, options) : 
+			              asprintf_("/sbin/modprobe %s", mod_name);
+		log_message("running %s", cmd);
+		i = system(cmd);
+	}
+#else
+	i = insmod_with_deps(mod_name, options, allow_modules_floppy);
+#endif
+	if (i == 0) {
+		log_message("\tsucceeded %s", mod_name);
+#ifndef DISABLE_NETWORK
+		if (type == NETWORK_DEVICES) {
+			char ** new_net_devices = get_net_devices();
+			while (new_net_devices && *new_net_devices) {
+				char alias[500];
+				char ** ptr = net_devices;
+				while (ptr && *ptr) {
+					if (!strcmp(*new_net_devices, *ptr))
+						goto already_present;
+					ptr++;
+				}
+				sprintf(alias, "alias %s %s", *new_net_devices, mod_name);
+				add_modules_conf(alias);
+				log_message("NET: %s", alias);
+				net_discovered_interface(*new_net_devices);
+				
+			already_present:
+				new_net_devices++;
+			}
+		}
+#endif
+	} else
+		log_message("warning, insmod failed (%s %s) (%d)", mod_name, options, i);
+	
+	return i;
+
+}
+
+static enum return_type insmod_with_options(char * mod, enum driver_type type)
+{
+	char * questions[] = { "Options", NULL };
+	static char ** answers = NULL;
+	enum return_type results;
+	char options[500] = "options ";
+
+	results = ask_from_entries("Please enter the parameters to give to the kernel:", questions, &answers, 24, NULL);
+	if (results != RETURN_OK)
+		return results;
+
+	strcat(options, mod);
+	strcat(options, " ");
+	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("Insmod failed.");
+		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 && *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 && descr->modname && strcmp(descr->modname, *p_modules)) descr++;
+		if (descr)
+			*p_descrs = descr->description;
+
+		p_dlist++;
+		p_modules++;
+		p_descrs++;
+	}
+	*p_modules = NULL;
+	*p_descrs = NULL;
+
+	if (modules && *modules) {
+		char * mytype;
+		char msg[200];
+		if (type == MEDIA_ADAPTERS)
+			mytype = "MEDIA";
+		else if (type == NETWORK_DEVICES)
+			mytype = "NET";
+		else
+			return RETURN_ERROR;
+
+		snprintf(msg, sizeof(msg), "Which driver should I try to gain %s access?", mytype);
+		results = ask_from_list_comments(msg, modules, descrs, &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 (gc at mandriva.com)
+ *
+ * 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 "stage1.h"
+#include "probing.h"
+
+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 (gc at mandriva.com)
+ *
+ * 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 (ewt at redhat.com)
+ *
+ * Copyright 1996 Red Hat Software 
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include "log.h"
+#include "utils.h"
+#include "modules.h"
+
+#include "mount.h"
+
+
+
+/* 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 = &dev[5]; /* we really need that dev be passed as /dev/something.. */
+
+	if (!stat(dev, &buf))
+		return 0; /* if the file already exists, we assume it's correct */
+
+	if (ptr_begins_static_str(name, "sd")) {
+		/* SCSI disks */
+		major = 8;
+		minor = (name[2] - 'a') << 4;
+		if (name[3] && name[4]) {
+			minor += 10 + (name[4] - '0');
+			if (name[3] > 1 || name[4] > 5) {
+				log_message("I don't know how to create device %s, please post bugreport to me!", dev);
+				return -1;
+			}
+		} else if (name[3])
+			minor += (name[3] - '0');
+	} else if (ptr_begins_static_str(name, "hd")) {
+		/* 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] && name[4])
+			minor += 10 + (name[4] - '0');
+		else if (name[3])
+			minor += (name[3] - '0');
+	} else if (ptr_begins_static_str(name , "sr")) {
+		/* SCSI cd's */
+		major = 11;
+		minor = name[2] - '0';
+	} else if (ptr_begins_static_str(name, "ida/") ||
+		   ptr_begins_static_str(name, "cciss/")) {
+		/* Compaq Smart Array "ida/c0d0{p1}" */
+		ptr = strchr(name, '/');
+		mkdir("/dev/ida", 0755);
+		mkdir("/dev/cciss", 0755);
+		major = ptr_begins_static_str(name, "ida/") ? 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, "rd/")) {
+		/* DAC960 "rd/cXdXXpX" */
+		mkdir("/dev/rd", 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, "loop")) {
+		major = 7;
+		minor = name[4] - '0';
+	} else if (ptr_begins_static_str(name, "chloop")) {
+		major = 100;
+		minor = name[6] - '0';
+	} else {
+		log_message("I don't know how to create device %s, please post bugreport to me!", 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, "nfs")) {
+	    rc = ensure_dev_exists(dev);
+	    if (rc != 0) {
+		    log_message("could not create required device file");
+		    return -1;
+	    }
+	}
+
+	log_message("mounting %s on %s as type %s", dev, location, fs);
+
+	if (stat(location, &buf)) {
+		if (mkdir(location, 0755)) {
+			log_perror("could not create location dir");
+			return -1;
+		}
+	} else if (!S_ISDIR(buf.st_mode)) {
+		log_message("not a dir %s, will unlink and mkdir", location);
+		if (unlink(location)) {
+			log_perror("could not unlink");
+			return -1;
+		}
+		if (mkdir(location, 0755)) {
+			log_perror("could not create location dir");
+			return -1;
+		}
+	}
+
+	if (!strcmp(fs, "supermount")) {
+		my_insmod("supermount", ANY_DRIVER_TYPE, NULL, 1);
+		my_insmod("isofs", ANY_DRIVER_TYPE, NULL, 1);
+		opts = alloca(500);
+                sprintf(opts, "dev=%s,fs=iso9660,tray_lock=always", dev);
+                dev = "none";
+	}
+
+#ifndef DISABLE_MEDIAS
+	if (!strcmp(fs, "vfat")) {
+		my_insmod("nls_cp437", ANY_DRIVER_TYPE, NULL, 1);
+		my_insmod("nls_iso8859_1", ANY_DRIVER_TYPE, NULL, 1);
+		my_insmod("vfat", ANY_DRIVER_TYPE, NULL, 1);
+		opts = "check=relaxed";
+	}
+
+	if (!strcmp(fs, "ntfs")) {
+		my_insmod("ntfs", ANY_DRIVER_TYPE, NULL, 1);
+	}
+
+	if (!strcmp(fs, "reiserfs"))
+		my_insmod("reiserfs", ANY_DRIVER_TYPE, NULL, 1);
+
+	if (!strcmp(fs, "reiser4"))
+		my_insmod("reiser4", ANY_DRIVER_TYPE, NULL, 1);
+
+	if (!strcmp(fs, "jfs"))
+		my_insmod("jfs", ANY_DRIVER_TYPE, NULL, 1);
+
+	if (!strcmp(fs, "xfs"))
+		my_insmod("xfs", ANY_DRIVER_TYPE, NULL, 1);
+
+	if (!strcmp(fs, "ext4"))
+		my_insmod("ext4", ANY_DRIVER_TYPE, NULL, 1);
+
+#endif
+	if (!strcmp(fs, "iso9660"))
+		my_insmod("isofs", ANY_DRIVER_TYPE, NULL, 1);
+
+#ifndef DISABLE_NETWORK
+	if (!strcmp(fs, "nfs")) {
+		my_insmod("nfs", ANY_DRIVER_TYPE, NULL, 1);
+		log_message("preparing nfsmount for %s", dev);
+		rc = nfsmount_prepare(dev, &opts);
+		if (rc != 0)
+			return rc;
+	}
+#endif
+
+	rc = mount(dev, location, fs, flags, opts);
+	if (rc != 0) {
+		log_perror("mount failed");
+		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 (gc at mandriva.com)
+ *
+ * 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 (ewt at redhat.com)
+ *
+ * Copyright 1996 Red Hat Software 
+ *
+ */
+
+#ifndef _MOUNT_H_
+#define _MOUNT_H_
+
+#ifndef DISABLE_NETWORK
+#include "nfsmount.h"
+#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 <rpc/rpc.h>
+
+#define MNTPATHLEN 1024
+#define MNTNAMLEN 255
+#define FHSIZE 32
+
+typedef char fhandle[FHSIZE];
+#ifdef __cplusplus 
+extern "C" 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 "C" 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 "C" 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 "C" 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 "C" 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 "C" 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 "C" 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 "C" 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 "C" 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 "C" 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 "C" void * mountproc_null_1(void *, CLIENT *);
+extern "C" void * mountproc_null_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_MNT ((u_long)1)
+extern "C" fhstatus * mountproc_mnt_1(dirpath *, CLIENT *);
+extern "C" fhstatus * mountproc_mnt_1_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC_DUMP ((u_long)2)
+extern "C" mountlist * mountproc_dump_1(void *, CLIENT *);
+extern "C" mountlist * mountproc_dump_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_UMNT ((u_long)3)
+extern "C" void * mountproc_umnt_1(dirpath *, CLIENT *);
+extern "C" void * mountproc_umnt_1_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC_UMNTALL ((u_long)4)
+extern "C" void * mountproc_umntall_1(void *, CLIENT *);
+extern "C" void * mountproc_umntall_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_EXPORT ((u_long)5)
+extern "C" exports * mountproc_export_1(void *, CLIENT *);
+extern "C" exports * mountproc_export_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_EXPORTALL ((u_long)6)
+extern "C" exports * mountproc_exportall_1(void *, CLIENT *);
+extern "C" 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 (gc at mandriva.com)
+ *
+ * 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 (ewt at redhat.com)
+ *
+ * Copyright 1996 Red Hat Software 
+ *
+ */
+
+#include "stage1.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <net/route.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <sys/utsname.h>
+
+#include "frontend.h"
+#include "modules.h"
+#include "probing.h"
+#include "log.h"
+#include "tools.h"
+#include "utils.h"
+#include "mount.h"
+#include "automatic.h"
+#include "dhcp.h"
+#include "adsl.h"
+#include "url.h"
+#include "dns.h"
+
+#include "network.h"
+#include "directory.h"
+#include "wireless.h"
+
+#ifndef DISABLE_KA
+#include "ka.h"
+#endif
+
+static void error_message_net(void)  /* reduce code size */
+{
+	stg1_error_message("Could not configure network.");
+}
+
+
+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(&ia, &intf->ip, sizeof(intf->ip));
+	strcpy(ip, inet_ntoa(ia));
+	
+	memcpy(&ia, &intf->netmask, sizeof(intf->netmask));
+	strcpy(nm, inet_ntoa(ia));
+	
+	memcpy(&ia, &intf->broadcast, sizeof(intf->broadcast));
+	strcpy(bc, inet_ntoa(ia));
+	
+	memcpy(&ia, &intf->network, sizeof(intf->network));
+	strcpy(nw, inet_ntoa(ia));
+
+	log_message("configuring device %s ip: %s nm: %s nw: %s bc: %s", intf->device, ip, nm, nw, bc);
+
+	if (IS_TESTING)
+		return 0;
+
+	s = socket(AF_INET, SOCK_DGRAM, 0);
+	if (s < 0) {
+		log_perror("socket");
+		error_message_net();
+		return 1;
+	}
+
+	strcpy(req.ifr_name, intf->device);
+
+	if (intf->is_up == 1) {
+		log_message("interface already up, downing before reconfigure");
+
+		req.ifr_flags = 0;
+		if (ioctl(s, SIOCSIFFLAGS, &req)) {
+			close(s);
+			log_perror("SIOCSIFFLAGS (downing)");
+			error_message_net();
+			return 1;
+		}
+	}
+		
+	/* sets IP address */
+	addr.sin_port = 0;
+	memcpy(&addr.sin_addr, &intf->ip, sizeof(intf->ip));
+	memcpy(&req.ifr_addr, &addr, sizeof(addr));
+	if (ioctl(s, SIOCSIFADDR, &req)) {
+		close(s);
+		log_perror("SIOCSIFADDR");
+		error_message_net();
+		return 1;
+	}
+
+	/* sets broadcast */
+	memcpy(&addr.sin_addr, &intf->broadcast, sizeof(intf->broadcast));
+	memcpy(&req.ifr_broadaddr, &addr, sizeof(addr));
+	if (ioctl(s, SIOCSIFBRDADDR, &req)) {
+		close(s);
+		log_perror("SIOCSIFBRDADDR");
+		error_message_net();
+		return 1;
+	}
+
+	/* sets netmask */
+	memcpy(&addr.sin_addr, &intf->netmask, sizeof(intf->netmask));
+	memcpy(&req.ifr_netmask, &addr, sizeof(addr));
+	if (ioctl(s, SIOCSIFNETMASK, &req)) {
+		close(s);
+		log_perror("SIOCSIFNETMASK");
+		error_message_net();
+		return 1;
+	}
+
+	if (intf->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, &req)) {
+		close(s);
+		log_perror("SIOCSIFFLAGS (upping)");
+		error_message_net();
+		return 1;
+	}
+
+	memset(&route, 0, sizeof(route));
+	route.rt_dev = intf->device;
+	route.rt_flags = RTF_UP;
+	
+	memcpy(&addr.sin_addr, &intf->network, sizeof(intf->network));
+	memcpy(&route.rt_dst, &addr, sizeof(addr));
+	
+	memcpy(&addr.sin_addr, &intf->netmask, sizeof(intf->netmask));
+	memcpy(&route.rt_genmask, &addr, sizeof(addr));
+
+	/* adds route */
+	if (ioctl(s, SIOCADDRT, &route)) {
+		close(s);
+		log_perror("SIOCADDRT");
+		error_message_net();
+		return 1;
+	}
+
+	close(s);
+
+	intf->is_up = 1;
+
+	if (intf->boot_proto != BOOTPROTO_DHCP && !streq(intf->device, "lo")) {
+		/* 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("Bringing up networking...");
+		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("no gateway provided, can't add default route");
+		return 0;
+	}
+
+	s = socket(AF_INET, SOCK_DGRAM, 0);
+	if (s < 0) {
+		close(s);
+		log_perror("socket");
+		error_message_net();
+		return 1;
+	}
+
+	memset(&route, 0, sizeof(route));
+
+	addr.sin_family = AF_INET;
+	addr.sin_port = 0;
+	addr.sin_addr = gateway;
+	memcpy(&route.rt_gateway, &addr, sizeof(addr));
+
+	addr.sin_addr.s_addr = INADDR_ANY;
+	memcpy(&route.rt_dst, &addr, sizeof(addr));
+	memcpy(&route.rt_genmask, &addr, sizeof(addr));
+
+	route.rt_flags = RTF_UP | RTF_GATEWAY;
+	route.rt_metric = 0;
+
+	if (ioctl(s, SIOCADDRT, &route)) {
+		close(s);
+		log_perror("SIOCADDRT");
+		error_message_net();
+		return 1;
+	}
+
+	close(s);
+	
+	return 0;
+}
+
+
+static int write_resolvconf(void)
+{
+	char * filename = "/etc/resolv.conf";
+	FILE * f;
+	
+	if (dns_server.s_addr == 0) {
+		log_message("resolvconf needs a dns server");
+		return -1;
+	}
+
+	f = fopen(filename, "w");
+	if (!f) {
+		log_perror(filename);
+		return -1;
+	}
+
+	if (domain)
+		fprintf(f, "search %s\n", domain); /* we can live without the domain search (user will have to enter fully-qualified names) */
+	fprintf(f, "nameserver %s\n", inet_ntoa(dns_server));
+	if (dns_server2.s_addr != 0)
+		fprintf(f, "nameserver %s\n", 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 = "/tmp/network";
+	char file_intf[500];
+	FILE * f;
+	
+	f = fopen(file_network, "w");
+	if (!f) {
+		log_perror(file_network);
+		return -1;
+	}
+
+	fprintf(f, "NETWORKING=yes\n");
+	fprintf(f, "FORWARD_IPV4=false\n");
+
+	if (hostname && !intf->boot_proto == BOOTPROTO_DHCP)
+		fprintf(f, "HOSTNAME=%s\n", hostname);
+	if (gateway.s_addr != 0)
+		fprintf(f, "GATEWAY=%s\n", inet_ntoa(gateway));
+
+	fclose(f);
+
+	
+	strcpy(file_intf, "/tmp/ifcfg-");
+	strcat(file_intf, intf->device);
+
+	f = fopen(file_intf, "w");
+	if (!f) {
+		log_perror(file_intf);
+		return -1;
+	}
+
+	fprintf(f, "DEVICE=%s\n", intf->device);
+
+	if (intf->boot_proto == BOOTPROTO_DHCP) {
+		fprintf(f, "BOOTPROTO=dhcp\n");
+		if (dhcp_hostname && !streq(dhcp_hostname, ""))
+			fprintf(f, "DHCP_HOSTNAME=%s\n", dhcp_hostname);
+	} else if (intf->boot_proto == BOOTPROTO_STATIC) {
+		fprintf(f, "BOOTPROTO=static\n");
+		fprintf(f, "IPADDR=%s\n", inet_ntoa(intf->ip));
+		fprintf(f, "NETMASK=%s\n", inet_ntoa(intf->netmask));
+		fprintf(f, "NETWORK=%s\n", inet_ntoa(intf->network));
+		fprintf(f, "BROADCAST=%s\n", inet_ntoa(intf->broadcast));
+		if (domain)
+			fprintf(f, "DOMAIN=%s\n", domain);
+		if (dns_server.s_addr != 0)
+			fprintf(f, "DNS1=%s\n", inet_ntoa(dns_server));
+		if (dns_server2.s_addr != 0)
+			fprintf(f, "DNS2=%s\n", inet_ntoa(dns_server2));
+	} else if (intf->boot_proto == BOOTPROTO_ADSL_PPPOE) {
+		fprintf(f, "BOOTPROTO=adsl_pppoe\n");
+		fprintf(f, "USER=%s\n", intf->user);
+		fprintf(f, "PASS=%s\n", intf->pass);
+		fprintf(f, "ACNAME=%s\n", intf->acname);
+	}
+
+	fclose(f);
+
+	return 0;
+}
+
+
+char * guess_netmask(char * ip_addr)
+{
+	struct in_addr addr;
+	unsigned long int tmp;
+
+	if (streq(ip_addr, "") || !inet_aton(ip_addr, &addr))
+		return "";
+
+	log_message("guessing netmask");
+
+	tmp = ntohl(addr.s_addr);
+	
+	if (((tmp & 0xFF000000) >> 24) <= 127)
+		return "255.0.0.0";
+	else if (((tmp & 0xFF000000) >> 24) <= 191)
+		return "255.255.0.0";
+	else 
+		return "255.255.255.0";
+}
+
+
+char * guess_domain_from_hostname(char *hostname)
+{
+	char *domain = strchr(strdup(hostname), '.');
+	if (!domain || domain[1] == '\0') {
+		log_message("unable to guess domain from hostname: %s", 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], "") || !inet_aton(strings[0], &addr))
+		return;
+        done = 1;
+
+	if (!strcmp(strings[1], "")) {
+		char * ptr;
+		strings[1] = strdup(strings[0]);
+		ptr = strrchr(strings[1], '.');
+		if (ptr)
+			*(ptr+1) = '\0';
+	}
+
+	if (!strcmp(strings[2], ""))
+		strings[2] = strdup(strings[1]);
+
+	if (!strcmp(strings[3], ""))
+		strings[3] = strdup(guess_netmask(strings[0]));
+}
+
+
+static enum return_type setup_network_interface(struct interface_info * intf)
+{
+	enum return_type results;
+	char * bootprotos[] = { "DHCP", "Static", "ADSL", NULL };
+	char * bootprotos_auto[] = { "dhcp", "static", "adsl" };
+	char * choice;
+
+	results = ask_from_list_auto("Please select your network connection type.", bootprotos, &choice, "network", bootprotos_auto);
+	if (results != RETURN_OK)
+		return results;
+
+	if (!strcmp(choice, "Static")) {
+		char * questions[] = { "IP of this machine", "IP of DNS", "IP of default gateway", "Netmask", NULL };
+		char * questions_auto[] = { "ip", "dns", "gateway", "netmask" };
+		static char ** answers = NULL;
+		struct in_addr addr;
+
+		results = ask_from_entries_auto("Please enter the network information. (leave netmask blank for Internet standard)",
+						questions, &answers, 16, questions_auto, static_ip_callback);
+		if (results != RETURN_OK)
+			return setup_network_interface(intf);
+
+		if (streq(answers[0], "") || !inet_aton(answers[0], &addr)) {
+			stg1_error_message("Invalid IP address.");
+			return setup_network_interface(intf);
+		}
+		memcpy(&intf->ip, &addr, sizeof(addr));
+
+		if (!inet_aton(answers[1], &dns_server)) {
+			log_message("invalid DNS");
+			dns_server.s_addr = 0; /* keep an understandable state */
+		}
+
+		if (streq(answers[0], answers[1])) {
+			log_message("IP and DNS are the same, guess you don't want a DNS, disabling it");
+			dns_server.s_addr = 0; /* keep an understandable state */
+		}
+
+		if (!inet_aton(answers[2], &gateway)) {
+			log_message("invalid gateway");
+			gateway.s_addr = 0; /* keep an understandable state */
+		}
+
+		if ((streq(answers[3], "") && inet_aton(guess_netmask(answers[0]), &addr))
+		    || inet_aton(answers[3], &addr))
+			memcpy(&intf->netmask, &addr, sizeof(addr));
+		else {
+			stg1_error_message("Invalid netmask.");
+			return setup_network_interface(intf);
+		}
+
+		*((uint32_t *) &intf->broadcast) = (*((uint32_t *) &intf->ip) &
+						    *((uint32_t *) &intf->netmask)) | ~(*((uint32_t *) &intf->netmask));
+
+		inet_aton("255.255.255.255", &addr);
+		if (!memcmp(&addr, &intf->netmask, sizeof(addr))) {
+			log_message("netmask is 255.255.255.255 -> point to point device");
+			intf->network = gateway;
+			intf->is_ptp = 1;
+		} else {
+			*((uint32_t *) &intf->network) = *((uint32_t *) &intf->ip) & *((uint32_t *) &intf->netmask);
+			intf->is_ptp = 0;
+		}
+		intf->boot_proto = BOOTPROTO_STATIC;
+
+		if (configure_net_device(intf))
+			return RETURN_ERROR;
+
+	} else if (streq(choice, "DHCP")) {
+		results = perform_dhcp(intf);
+
+		if (results == RETURN_BACK)
+			return setup_network_interface(intf);
+		if (results == RETURN_ERROR)
+			return results;
+		intf->boot_proto = BOOTPROTO_DHCP;
+
+		if (configure_net_device(intf))
+			return RETURN_ERROR;
+
+	} else if (streq(choice, "ADSL")) {
+		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 && domain)
+		return RETURN_OK;
+
+	dnshostname = mygethostbyaddr(inet_ntoa(intf->ip));
+
+	if (dnshostname) {
+		if (intf->boot_proto == BOOTPROTO_STATIC)
+			hostname = strdup(dnshostname);
+		domain = guess_domain_from_hostname(dnshostname);
+		if (domain) {
+			log_message("got hostname and domain from dns entry, %s and %s", dnshostname, domain);
+			return RETURN_OK;
+		}
+	} else
+		log_message("reverse name lookup on self failed");
+
+	if (domain)
+		return RETURN_OK;
+
+	dnshostname = NULL;
+	if (dns_server.s_addr != 0) {
+		wait_message("Trying to resolve dns...");
+		dnshostname = mygethostbyaddr(inet_ntoa(dns_server));
+		remove_wait_message();
+		if (dnshostname) {
+			log_message("got DNS fullname, %s", dnshostname);
+			domain = guess_domain_from_hostname(dnshostname);
+		} else
+			log_message("reverse name lookup on DNS failed");
+	} else
+		log_message("no DNS, unable to guess domain");
+
+	if (domain) {
+		log_message("got domain from DNS fullname, %s", domain);
+	} else {
+		enum return_type results;
+		char * questions[] = { "Host name", "Domain name", NULL };
+		char * questions_auto[] = { "hostname", "domain" };
+		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("I could not guess hostname and domain name; please fill in this information. "
+						    "Valid answers are for example: `mybox' for hostname and `mynetwork.com' for "
+						    "domain name, for a machine called `mybox.mynetwork.com' on the Internet.",
+						    questions, &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("using hostname %s", hostname);
+	log_message("using domain %s", 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("af_packet", ANY_DRIVER_TYPE, NULL, 1);
+
+	do {
+		results = configure_wireless(intf->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, "lo");
+		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(&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 < 0) {
+		return NULL;
+	}
+
+	ptr = interfaces;
+	while (ptr && *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)&edata;
+			if (ioctl(s, SIOCETHTOOL, &ifr) == 0 && edata.data) {
+				close(s);
+				log_message("NETWORK: choosing interface %s (link beat detected)", *ptr);
+				return *ptr;
+			}
+		}
+		ptr++;
+	}
+
+	log_message("NETWORK: no interface has a link beat");
+
+	if (detection_mode == AUTO_DETECTION_WIRED) {
+		ptr = interfaces;
+		while (ptr && *ptr) {
+			if (!wireless_is_aware(s, *interfaces)) {
+				close(s);
+				log_message("NETWORK: choosing interface %s (wired interface)", *ptr);
+				return *ptr;
+			}
+			ptr++;
+		}
+		log_message("NETWORK: no interface is wired");
+	}
+
+	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 && *ptr) {
+		count++;
+		ptr++;
+	}
+
+	if (count == 0) {
+		stg1_error_message("No NET device found.\n"
+				   "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.");
+		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 "auto" and "wired" are not in the interfaces list */
+	if (IS_AUTOMATIC) {
+		enum auto_detection_type auto_detect = AUTO_DETECTION_NONE;
+		if (streq(get_auto_value("interface"), "auto"))
+			auto_detect = AUTO_DETECTION_ALL;
+		else if (streq(get_auto_value("interface"), "wired"))
+			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("Please choose the NET device to use for the installation.",
+					      interfaces, descriptions, &choice, "interface", 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[] = { "HTTP proxy host", "HTTP proxy port", NULL };
+	char *questions_auto[] = { "proxy_host", "proxy_port", NULL };
+	static char ** answers = NULL;
+	enum return_type results;
+	
+	results = ask_from_entries_auto("Please enter HTTP proxy host and port if you need it, else leave them blank or cancel.",
+					questions, &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, "://");
+	if (!protocol_sep) {
+		log_message("NETWORK: no protocol in \"%s\"", 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("NETWORK: no hostname in \"%s\"", 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 && http_proxy_port && !streq(http_proxy_host, "") && !streq(http_proxy_port, "");
+	lowercase(type);
+	snprintf(path, sizeof(path), "%s/%s.%s.%s.list", MIRRORLIST_PATH, type, version, ARCH);
+
+	fd = http_download_file(MIRRORLIST_HOST, path, &size, use_http_proxy ? "http" : NULL, http_proxy_host, http_proxy_port);
+	if (fd < 0) {
+		log_message("HTTP: unable to get mirrors list from %s (%s)", MIRRORLIST_HOST, path);
+		return RETURN_ERROR;
+	}
+
+	while (read(fd, line + line_pos, 1) > 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, ",type=distrib,"))
+				continue;
+
+			url = strstr(line, ",url=");
+			if (!url)
+				continue;
+			url += 5;
+
+			if (url_split(url, protocol, &mirrorlist[0][mirror_idx], &mirrorlist[1][mirror_idx]) < 0)
+				continue;
+
+			mirror_idx++;
+		} else {
+			line_pos++;
+		}
+
+		if (mirror_idx >= 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("Please select a mirror from the list below.",
+					      mirrorlist[0], NULL, &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[] = { "Specify the mirror manually", DISTRIB_VERSION, NULL };
+	char *version = DISTRIB_VERSION;
+
+	do {
+		results = ask_from_list("Please select a medium from the list below.", versions, &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] = "Specify the mirror manually";
+				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 < num_interfaces ; i++)
+		if (!strcmp(intf[i].device, iface))
+			sel_intf = &(intf[i]);
+	
+	if (sel_intf == NULL) {
+		sel_intf = &(intf[num_interfaces]);
+		strcpy(sel_intf->device, iface);
+		sel_intf->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[] = { "NFS server name", DISTRIB_NAME " directory", NULL };
+	char * questions_auto[] = { "server", "directory", 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("Please enter the name or IP address of your NFS server, "
+						"and the directory containing the " DISTRIB_NAME " Distribution.",
+						questions, &answers, 40, questions_auto, NULL);
+		if (results != RETURN_OK || streq(answers[0], "")) {
+			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, ":");
+		strcat(nfsmount_location, answers[1]);
+		
+		if (my_mount(nfsmount_location, MEDIA_LOCATION, "nfs", 0) == -1) {
+			stg1_error_message("I can't mount the directory from the NFS server.");
+			results = RETURN_BACK;
+			continue;
+		}
+		free(nfsmount_location); nfsmount_location = NULL;
+
+		results = try_with_directory(MEDIA_LOCATION, "nfs", "nfs-iso");
+		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[] = { "FTP server", DISTRIB_NAME " directory", "Login", "Password", NULL };
+	char * questions_auto[] = { "server", "directory", "user", "pass", 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("FTP install needs more than %d Mbytes of memory (detected %d Mbytes). You may want to try an NFS install.",
+				   MEM_LIMIT_DRAKX, total_memory());
+		return RETURN_ERROR;
+	}
+
+	results = intf_select_and_up();
+
+	if (results != RETURN_OK)
+		return results;
+
+	get_http_proxy(&http_proxy_host, &http_proxy_port);
+	use_http_proxy = http_proxy_host && http_proxy_port && !streq(http_proxy_host, "") && !streq(http_proxy_port, "");
+
+	uname(&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, "ftp", &answers[0], &answers[1]);
+
+			if (results == RETURN_BACK)
+				return ftp_prepare();
+
+                        if (use_http_proxy) {
+                            results = ask_yes_no("Do you want to use this HTTP proxy for FTP connections too ?");
+
+			    if (results == RETURN_BACK)
+				return ftp_prepare();
+
+                            use_http_proxy = results == RETURN_OK;
+                        }
+		}
+
+		results = ask_from_entries_auto("Please enter the name or IP address of the FTP server, "
+						"the directory containing the " DISTRIB_NAME " Distribution, "
+						"and the login/pass if necessary (leave login blank for anonymous). ",
+						questions, &answers, 40, questions_auto, NULL);
+		if (results != RETURN_OK || streq(answers[0], "")) {
+			unset_automatic(); /* we are in a fallback mode */
+			return ftp_prepare();
+		}
+
+		strcpy(location_full, answers[1][0] == '/' ? "" : "/");
+		strcat(location_full, answers[1]);
+
+		if (use_http_proxy) {
+		        log_message("FTP: don't connect to %s directly, will use proxy", answers[0]);
+		} else {
+		        log_message("FTP: trying to connect to %s", answers[0]);
+			ftp_serv_response = ftp_open_connection(answers[0], answers[2], answers[3], "");
+                        if (ftp_serv_response < 0) {
+                                log_message("FTP: error connect %d", ftp_serv_response);
+                                if (ftp_serv_response == FTPERR_BAD_HOSTNAME)
+                                        stg1_error_message("Error: bad hostname.");
+                                else if (ftp_serv_response == FTPERR_FAILED_CONNECT)
+                                        stg1_error_message("Error: failed to connect to remote host.");
+                                else
+                                        stg1_error_message("Error: couldn't connect.");
+                                results = RETURN_BACK;
+                                continue;
+                        }
+                }
+
+		strcat(location_full, COMPRESSED_FILE_REL("/"));
+
+		log_message("FTP: trying to retrieve %s", location_full);
+
+		if (use_http_proxy) {
+			if (strcmp(answers[2], "")) {
+			        strcpy(ftp_hostname, answers[2]); /* user name */
+				strcat(ftp_hostname, ":");
+				strcat(ftp_hostname, answers[3]); /* password */
+				strcat(ftp_hostname, "@");
+			} else {
+			    strcpy(ftp_hostname, "");
+			}
+			strcat(ftp_hostname, answers[0]);
+			fd = http_download_file(ftp_hostname, location_full, &size, "ftp", http_proxy_host, http_proxy_port);
+		} else {
+		        fd = ftp_start_download(ftp_serv_response, location_full, &size);
+		}
+
+		if (fd < 0) {
+			char *msg = str_ftp_error(fd);
+			log_message("FTP: error get %d for remote file %s", fd, location_full);
+			stg1_error_message("Error: %s.", msg ? msg : "couldn't retrieve Installation program");
+			results = RETURN_BACK;
+			continue;
+		}
+
+		log_message("FTP: size of download %d bytes", 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("METHOD", "http");
+		        sprintf(location_full, "ftp://%s%s", ftp_hostname, answers[1]);
+		        add_to_env("URLPREFIX", location_full);
+			add_to_env("PROXY", http_proxy_host);
+			add_to_env("PROXYPORT", http_proxy_port);
+		} else {
+                        add_to_env("METHOD", "ftp");
+		        add_to_env("HOST", answers[0]);
+			add_to_env("PREFIX", answers[1]);
+			if (!streq(answers[2], "")) {
+			        add_to_env("LOGIN", answers[2]);
+				add_to_env("PASSWORD", answers[3]);
+			}
+		}
+	}
+	while (results == RETURN_BACK);
+
+	return RETURN_OK;
+}
+
+enum return_type http_prepare(void)
+{
+	char * questions[] = { "HTTP server", DISTRIB_NAME " directory", NULL };
+	char * questions_auto[] = { "server", "directory", NULL };
+	static char ** answers = NULL;
+	enum return_type results;
+	char *http_proxy_host, *http_proxy_port;
+
+	if (!ramdisk_possible()) {
+		stg1_error_message("HTTP install needs more than %d Mbytes of memory (detected %d Mbytes). You may want to try an NFS install.",
+				   MEM_LIMIT_DRAKX, total_memory());
+		return RETURN_ERROR;
+	}
+
+	results = intf_select_and_up();
+
+	if (results != RETURN_OK)
+		return results;
+
+        get_http_proxy(&http_proxy_host, &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, "http", &answers[0], &answers[1]);
+
+			if (results == RETURN_BACK)
+				return ftp_prepare();
+		}
+
+		results = ask_from_entries_auto("Please enter the name or IP address of the HTTP server, "
+						"and the directory containing the " DISTRIB_NAME " Distribution.",
+						questions, &answers, 40, questions_auto, NULL);
+		if (results != RETURN_OK || streq(answers[0], "")) {
+			unset_automatic(); /* we are in a fallback mode */
+			return http_prepare();
+		}
+
+		strcpy(location_full, answers[1][0] == '/' ? "" : "/");
+		strcat(location_full, answers[1]);
+		strcat(location_full, COMPRESSED_FILE_REL("/"));
+
+		log_message("HTTP: trying to retrieve %s from %s", location_full, answers[0]);
+		
+		use_http_proxy = http_proxy_host && http_proxy_port && !streq(http_proxy_host, "") && !streq(http_proxy_port, "");
+
+		fd = http_download_file(answers[0], location_full, &size, use_http_proxy ? "http" : NULL, http_proxy_host, http_proxy_port);
+		if (fd < 0) {
+			log_message("HTTP: error %d", fd);
+			if (fd == FTPERR_FAILED_CONNECT)
+				stg1_error_message("Error: couldn't connect to server.");
+			else
+				stg1_error_message("Error: couldn't get file (%s).", location_full);
+			results = RETURN_BACK;
+			continue;
+		}
+
+		log_message("HTTP: size of download %d bytes", size);
+		
+		if (load_compressed_fd(fd, size) != RETURN_OK) {
+			unset_automatic(); /* we are in a fallback mode */
+			return RETURN_ERROR;
+                }
+
+                add_to_env("METHOD", "http");
+		sprintf(location_full, "http://%s%s%s", answers[0], answers[1][0] == '/' ? "" : "/", answers[1]);
+		add_to_env("URLPREFIX", location_full);
+                if (!streq(http_proxy_host, ""))
+			add_to_env("PROXY", http_proxy_host);
+                if (!streq(http_proxy_port, ""))
+			add_to_env("PROXYPORT", 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("KA install needs more than %d Mbytes of memory (detected %d Mbytes).",
+				   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 (gc at mandriva.com)
+ *
+ * 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 (ewt at redhat.com)
+ *
+ * Copyright 1996 Red Hat Software 
+ *
+ */
+
+#ifndef _NETWORK_H_
+#define _NETWORK_H_
+
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+
+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 (gc at mandriva.com)
+ #
+ # 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=\"0.50.19\"
+
+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 $< -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 <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+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->data = bu;
+
+    bu->text = strdup(text);
+    bu->compact = compact;
+    co->ops = &buttonOps;
+
+    if (bu->compact) {
+	co->height = 1;
+	co->width = strlen(text) + 3;
+    } else {
+	co->height = 4;
+	co->width = strlen(text) + 5;
+    }
+
+    co->top = row;
+    co->left = left;
+    co->takesFocus = 1;
+    co->isMapped = 0;
+
+    newtGotorc(co->top, co->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->data;
+
+    free(bu->text);
+    free(bu);
+    free(co);
+}
+
+static void buttonPlace(newtComponent co, int newLeft, int newTop) {
+    co->top = newTop;
+    co->left = newLeft;
+
+    newtGotorc(co->top, co->left);
+}
+
+static void buttonDraw(newtComponent co) {
+    buttonDrawIt(co, 0, 0);
+}
+
+static void buttonDrawIt(newtComponent co, int active, int pushed) {
+    struct button * bu = co->data;
+
+    if (!co->isMapped) return;
+
+    SLsmg_set_color(NEWT_COLORSET_BUTTON);
+
+    if (bu->compact) {
+	if (active)
+	    SLsmg_set_color(NEWT_COLORSET_COMPACTBUTTON);
+	else
+	    SLsmg_set_color(NEWT_COLORSET_BUTTON);
+	newtGotorc(co->top+ pushed, co->left + 1 + pushed);
+	SLsmg_write_char('<');
+	SLsmg_write_string(bu->text);
+	SLsmg_write_char('>');
+    } else {
+	if (pushed) {
+	    SLsmg_set_color(NEWT_COLORSET_BUTTON);
+	    newtDrawBox(co->left + 1, co->top + 1, co->width - 1, 3, 0);
+
+	    SLsmg_set_color(NEWT_COLORSET_WINDOW);
+	    newtClearBox(co->left, co->top, co->width, 1);
+	    newtClearBox(co->left, co->top, 1, co->height);
+	} else {
+	    newtDrawBox(co->left, co->top, co->width - 1, 3, 1);
+	}
+
+	buttonDrawText(co, active, pushed);
+    }
+}
+
+static void buttonDrawText(newtComponent co, int active, int pushed) {
+    struct button * bu = co->data;
+
+    if (pushed) pushed = 1;
+
+    if (active)
+	SLsmg_set_color(NEWT_COLORSET_ACTBUTTON);
+    else
+	SLsmg_set_color(NEWT_COLORSET_BUTTON);
+
+    newtGotorc(co->top + 1 + pushed, co->left + 1 + pushed);
+    SLsmg_write_char(' ');
+    SLsmg_write_string(bu->text);
+    SLsmg_write_char(' ');
+}
+
+static struct eventResult buttonEvent(newtComponent co,
+				      struct event ev) {
+    struct eventResult er;
+    struct button * bu = co->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->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 &&
+		  co->top <= ev.u.mouse.y &&
+		  co->top + co->height - !bu->compact > ev.u.mouse.y &&
+		  co->left <= ev.u.mouse.x &&
+		  co->left + co->width - !bu->compact > ev.u.mouse.x) {
+		  if (!bu->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 <stdarg.h>
+
+#include "newt.h"
+
+/* 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 < 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 <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+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, " *", NULL);
+    rb = co->data;
+    rb->type = RADIO;
+
+    rb->prevButton = prevButton;
+
+    for (curr = co; curr; curr = rb->prevButton) {
+	rb = curr->data;
+	rb->lastButton = co;
+    }
+
+    return co;
+}
+
+newtComponent newtRadioGetCurrent(newtComponent setMember) {
+    struct checkbox * rb = setMember->data;
+
+    setMember = rb->lastButton;
+    rb = setMember->data;
+
+    while (rb && rb->value != '*') {
+	setMember = rb->prevButton;
+	if (!setMember)
+	  return NULL;
+	rb = setMember->data;
+    }
+
+    return setMember;
+}
+
+char newtCheckboxGetValue(newtComponent co) {
+    struct checkbox * cb = co->data;
+
+    return cb->value;
+}
+
+void newtCheckboxSetValue(newtComponent co, char value) {
+    struct checkbox * cb = co->data;
+
+    *cb->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 = " *";
+
+    co = malloc(sizeof(*co));
+    cb = malloc(sizeof(struct checkbox));
+    co->data = cb;
+    cb->flags = 0;
+    if (result)
+	cb->result = result;
+    else
+	cb->result = &cb->value;
+
+    cb->text = strdup(text);
+    cb->seq = strdup(seq);
+    cb->type = CHECK;
+    cb->hasFocus = 0;
+    cb->inactive = COLORSET_CHECKBOX;
+    cb->active = COLORSET_ACTCHECKBOX;
+    defValue ? (*cb->result = defValue) : (*cb->result = cb->seq[0]);
+
+    co->ops = &cbOps;
+
+    co->callback = NULL;
+    co->height = 1;
+    co->width = strlen(text) + 4;
+    co->top = top;
+    co->left = left;
+    co->takesFocus = 1;
+
+    return co;
+}
+
+void newtCheckboxSetFlags(newtComponent co, int flags, enum newtFlagsSense sense) {
+    struct checkbox * cb = co->data;
+    int row, col;
+
+    cb->flags = newtSetFlags(cb->flags, flags, sense);
+
+    if (!(cb->flags & NEWT_FLAG_DISABLED))
+	co->takesFocus = 1;
+    else
+	co->takesFocus = 0;
+
+    newtGetrc(&row, &col);
+    cbDraw(co);
+    newtGotorc(row, col);
+}
+
+static void cbDraw(newtComponent c) {
+    struct checkbox * cb = c->data;
+
+    if (c->top == -1 || !c->isMapped) return;
+
+    if (cb->flags & NEWT_FLAG_DISABLED) {
+	cb->inactive = NEWT_COLORSET_DISENTRY;
+	cb->active = NEWT_COLORSET_DISENTRY;
+    } else {
+	cb->inactive = COLORSET_CHECKBOX;
+	cb->active = COLORSET_ACTCHECKBOX;
+    }
+
+    SLsmg_set_color(cb->inactive);
+
+    newtGotorc(c->top, c->left);
+
+    switch (cb->type) {
+      case RADIO:
+	SLsmg_write_string("( ) ");
+	break;
+
+      case CHECK:
+	SLsmg_write_string("[ ] ");
+	break;
+
+      default:
+	break;
+    }
+
+    SLsmg_write_string(cb->text);
+
+    if (cb->hasFocus)
+	SLsmg_set_color(cb->active);
+
+    newtGotorc(c->top, c->left + 1);
+    SLsmg_write_char(*cb->result);
+}
+
+static void cbDestroy(newtComponent co) {
+    struct checkbox * cb = co->data;
+
+    free(cb->text);
+    free(cb->seq);
+    free(cb);
+    free(co);
+}
+
+struct eventResult cbEvent(newtComponent co, struct event ev) {
+    struct checkbox * cb = co->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->hasFocus = 1;
+	    cbDraw(co);
+	    er.result = ER_SWALLOWED;
+	    break;
+
+	  case EV_UNFOCUS:
+	    cb->hasFocus = 0;
+	    cbDraw(co);
+	    er.result = ER_SWALLOWED;
+	    break;
+
+	  case EV_KEYPRESS:
+	    if (ev.u.key == ' ') {
+		if (cb->type == RADIO) {
+		    makeActive(co);
+		} else if (cb->type == CHECK) {
+		    cur = strchr(cb->seq, *cb->result);
+		    if (!cur)
+			*cb->result = *cb->seq;
+		    else {
+			cur++;
+			if (! *cur)
+			    *cb->result = *cb->seq;
+			else
+			    *cb->result = *cur;
+		    }
+		    cbDraw(co);
+		    er.result = ER_SWALLOWED;
+
+		    if (co->callback)
+			co->callback(co, co->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->type == RADIO) {
+		    makeActive(co);
+		} else if (cb->type == CHECK) {
+		    cur = strchr(cb->seq, *cb->result);
+		    if (!cur)
+			*cb->result = *cb->seq;
+		    else {
+			cur++;
+			if (! *cur)
+			    *cb->result = *cb->seq;
+			else
+			    *cb->result = *cur;
+		    }
+		    cbDraw(co);
+		    er.result = ER_SWALLOWED;
+
+		    if (co->callback)
+			co->callback(co, co->callbackData);
+		}
+	    }
+	}
+    } else
+	er.result = ER_IGNORED;
+
+    return er;
+}
+
+static void makeActive(newtComponent co) {
+    struct checkbox * cb = co->data;
+    struct checkbox * rb;
+    newtComponent curr;
+
+    /* find the one that's turned off */
+    curr = cb->lastButton;
+    rb = curr->data;
+    while (curr && rb->value == rb->seq[0]) {
+	curr = rb->prevButton;
+	if (curr) rb = curr->data;
+    }
+    if (curr) {
+	rb->value = rb->seq[0];
+	cbDraw(curr);
+    }
+    cb->value = cb->seq[1];
+    cbDraw(co);
+
+    if (co->callback)
+	co->callback(co, co->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 <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+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->branch && item->selected == what) || (what == COUNT_EXPOSED))
+	    count++;
+	if (item->branch || (what == COUNT_EXPOSED && item->selected))
+	    count += countItems(item->branch, what);
+	item = item->next;
+    }
+
+    return count;
+}
+
+static void doBuildFlatList(struct CheckboxTree * ct, struct items * item) {
+    while (item) {
+    	ct->flatList[ct->flatCount++] = item;
+	if (item->branch && item->selected) doBuildFlatList(ct, item->branch);
+	item = item->next;
+    }
+}
+
+static void buildFlatList(newtComponent co) {
+    struct CheckboxTree * ct = co->data;
+
+    if (ct->flatList) free(ct->flatList);
+    ct->flatCount = countItems(ct->itemlist, COUNT_EXPOSED);
+
+    ct->flatList = malloc(sizeof(*ct->flatList) * (ct->flatCount+1));
+    ct->flatCount = 0;
+    doBuildFlatList(ct, ct->itemlist);
+    ct->flatList[ct->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->data == data) {
+	    if (path) path[items->depth] = where;
+	    if (len) *len = items->depth + 1;
+	    return 1;
+	}
+
+	if (items->branch && doFindItemPath(items->branch, data, path, len)) {
+	    if (path) path[items->depth] = where;
+	    return 1;
+	}
+
+	items = items->next;
+	where++;
+    }
+
+    return 0;
+}
+
+int * newtCheckboxTreeFindItem(newtComponent co, void * data) {
+    int len;
+    int * path;
+    struct CheckboxTree * ct = co->data;
+
+    if (!doFindItemPath(ct->itemlist, data, NULL, &len)) return NULL;
+
+    path = malloc(sizeof(*path) * (len + 1));
+    doFindItemPath(ct->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->data;
+
+    numIndexes = 0;
+    while (indexes[numIndexes] != NEWT_ARG_LAST) numIndexes++;
+
+    if (!ct->itemlist) {
+	if (numIndexes > 1) return -1;
+
+    	ct->itemlist = malloc(sizeof(*ct->itemlist));
+    	item = ct->itemlist;
+	item->prev = NULL;
+	item->next = NULL;
+    } else {
+	curList = ct->itemlist;
+	listPtr = &ct->itemlist;
+
+	i = 0;
+	index = indexes[i];
+	while (i < numIndexes) {
+	    item = curList;
+
+	    if (index == NEWT_ARG_APPEND) {
+	    	item = NULL;
+	    } else {
+		while (index && item) 
+		    item = item->next, index--;
+	    }
+
+	    i++;
+	    if (i < numIndexes) {
+		curList = item->branch;
+		listPtr = &item->branch;
+		if (!curList && (i + 1 != numIndexes)) return -1;
+
+		index = indexes[i];
+	    }
+	}
+
+	if (!curList) { 			/* create a new branch */
+	    item = malloc(sizeof(*curList->prev));
+	    item->next = item->prev = NULL;
+	    *listPtr = item;
+	} else if (!item) {			/* append to end */
+	    item = curList;
+	    while (item->next) item = item->next;
+	    item->next = malloc(sizeof(*curList->prev));
+	    item->next->prev = item;
+	    item = item->next;
+	    item->next = NULL;
+	} else { 
+	    newNode = malloc(sizeof(*newNode));
+	    newNode->prev = item->prev;
+	    newNode->next = item;
+
+	    if (item->prev) item->prev->next = newNode;
+	    item->prev = newNode;
+	    item = newNode;
+	    if (!item->prev) *listPtr = item;
+	}
+    }
+    	
+    item->text = strdup(text);
+    item->data = data;
+    if (flags & NEWT_FLAG_SELECTED) {
+    	item->selected = 1;
+    } else {
+	item->selected = 0;
+    }
+    item->flags = flags;
+    item->branch = NULL;
+    item->depth = numIndexes - 1;
+
+    i = 4 + (3 * item->depth);
+
+    if ((strlen(text) + i + ct->pad) > (size_t)co->width) {
+	co->width = strlen(text) + i + ct->pad;
+    }
+
+    return 0;
+}
+
+static struct items * findItem(struct items * items, const void * data) {
+    struct items * i;
+
+    while (items) {
+	if (items->data == data) return items;
+    	if (items->branch) {
+	    i = findItem(items->branch, data);
+	    if (i) return i;
+	}
+
+	items = items->next;
+    }
+
+    return NULL;
+}
+
+static void listSelected(struct items * items, int * num, const void ** list, int seqindex) {
+    while (items) {
+	    if ((seqindex ? items->selected==seqindex : items->selected) && !items->branch)
+	    list[(*num)++] = (void *) items->data;
+	if (items->branch)
+	    listSelected(items->branch, num, list, seqindex);
+	items = items->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->data;
+	
+    if (seqnum) {
+	    while( ct->seq[seqindex] && ( ct->seq[seqindex] != seqnum )) seqindex++;
+    } else {
+	    seqindex = 0;
+    }
+
+    *numitems = countItems(ct->itemlist, (seqindex ? seqindex : COUNT_SELECTED));
+    if (!*numitems) return NULL;
+    
+    retval = malloc(*numitems * sizeof(void *));
+    *numitems = 0;
+    listSelected(ct->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->callback = NULL;
+    co->data = ct;
+    co->ops = &ctOps;
+    co->takesFocus = 1;
+    co->height = height;
+    co->width = 0;
+    co->isMapped = 0;
+    ct->itemlist = NULL;
+    ct->firstItem = NULL;
+    ct->currItem = NULL;
+    ct->flatList = NULL;
+	if (seq)
+	  ct->seq = strdup(seq);
+	else
+	  ct->seq = strdup(" *");
+    if (flags & NEWT_FLAG_SCROLL) {
+	ct->sb = newtVerticalScrollbar(left, top, height,
+				       COLORSET_LISTBOX, COLORSET_ACTLISTBOX);
+	ct->pad = 2;
+    } else {
+	ct->sb = NULL;
+	ct->pad = 0;
+    }
+    
+    return co;
+}
+
+static void ctMapped(newtComponent co, int isMapped) {
+    struct CheckboxTree * ct = co->data;
+
+    co->isMapped = isMapped;
+    if (ct->sb)
+	ct->sb->ops->mapped(ct->sb, isMapped);
+}
+
+static void ctPlace(newtComponent co, int newLeft, int newTop) {
+    struct CheckboxTree * ct = co->data;
+
+    co->top = newTop;
+    co->left = newLeft;
+
+    if (ct->sb)
+	ct->sb->ops->place(ct->sb, co->left + co->width - 1, co->top);
+}
+
+int ctSetItem(newtComponent co, struct items *item, enum newtFlagsSense sense)
+{
+    struct CheckboxTree * ct = co->data;
+    struct items * currItem;
+    struct items * firstItem;
+    
+    if (!item)
+	return 1;
+    
+    switch(sense) {
+	case NEWT_FLAGS_RESET:
+	    item->selected = 0;
+	    break;
+	case NEWT_FLAGS_SET:
+	    item->selected = 1;
+	    break;
+	case NEWT_FLAGS_TOGGLE:
+	    if (item->branch)
+	      item->selected = !item->selected;
+	    else {
+		    item->selected++;
+		    if (item->selected==strlen(ct->seq))
+		      item->selected = 0;
+	    }
+	    break;
+    }
+
+    if (item->branch) {
+    	currItem = *ct->currItem;
+	firstItem = *ct->firstItem;
+
+    	buildFlatList(co);
+
+    	ct->currItem = ct->flatList;
+	while (*ct->currItem != currItem) ct->currItem++;
+
+    	ct->firstItem = ct->flatList;
+    	if (ct->flatCount > co->height) {
+		struct items ** last = ct->flatList + ct->flatCount - co->height;
+		while (*ct->firstItem != firstItem && ct->firstItem != last)
+		    ct->firstItem++;
+	}
+    }
+
+    return 0;
+}
+
+static void ctSetItems(struct items *item, int selected)
+{
+    for (; item; item = item->next) {
+	if (!item->branch)
+	    item->selected = selected;
+	else
+	    ctSetItems(item->branch, selected);
+    }
+}
+
+static void ctDraw(newtComponent co) {
+    struct CheckboxTree * ct = co->data;
+    struct items ** item; 
+    int i, j;
+    char * spaces = NULL;
+    int currRow = -1;
+
+    if (!co->isMapped) return ;
+
+    if (!ct->firstItem) {
+	buildFlatList(co);
+	ct->firstItem = ct->currItem = ct->flatList;
+    }
+
+    item = ct->firstItem;
+    
+    i = 0;
+    while (*item && i < co->height) {
+	newtGotorc(co->top + i, co->left);
+	if (*item == *ct->currItem) {
+	    SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX);
+	    currRow = co->top + i;
+	} else
+	    SLsmg_set_color(NEWT_COLORSET_LISTBOX);
+
+	for (j = 0; j < (*item)->depth; j++)
+	    SLsmg_write_string("   ");
+
+	if ((*item)->branch) {
+	    if ((*item)->selected) 
+		SLsmg_write_string("<-> ");
+	    else
+		SLsmg_write_string("<+> ");
+	} else {
+	    char tmp[5];
+	    snprintf(tmp,5,"[%c] ",ct->seq[(*item)->selected]);
+	    SLsmg_write_string(tmp);
+	}
+
+	SLsmg_write_nstring((*item)->text, co->width - 4 - 
+					   (3 * (*item)->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 < co->height) {
+	spaces = alloca(co->width);
+	memset(spaces, ' ', co->width);
+	SLsmg_set_color(NEWT_COLORSET_LISTBOX);
+    }
+    while (i < co->height) {
+	newtGotorc(co->top + i, co->left);
+	SLsmg_write_nstring(spaces, co->width);
+	i++;
+    }
+    
+    if(ct->sb) {
+	newtScrollbarSet(ct->sb, ct->currItem - ct->flatList, 
+			 ct->flatCount - 1);
+	ct->sb->ops->draw(ct->sb);
+    }
+
+    newtGotorc(currRow, co->left + 1);
+}
+
+static void ctDestroy(newtComponent co) {
+    struct CheckboxTree * ct = co->data;
+    struct items * item, * nextitem;
+
+    nextitem = item = ct->itemlist;
+
+    while (item != NULL) {
+	nextitem = item->next;
+	free(item->text);
+	free(item);
+	item = nextitem;
+    }
+
+    free(ct->seq);
+    free(ct);
+    free(co);
+}
+
+struct eventResult ctEvent(newtComponent co, struct event ev) {
+    struct CheckboxTree * ct = co->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 && key != ' ') {
+	    for (selnum = 0; ct->seq[selnum]; selnum++)
+	    if (key == ct->seq[selnum])
+		break;
+	    if (!ct->seq[selnum])
+		switch (key) {
+		case '-': selnum = 0; break;
+		case '+':
+		case '*': selnum = 1; break;
+		}
+	    if (ct->seq[selnum])
+		key = '*';
+	}
+	switch(key) {
+	case ' ':
+	case NEWT_KEY_ENTER:
+	    ctSetItem(co, *ct->currItem, NEWT_FLAGS_TOGGLE);
+	    er.result = ER_SWALLOWED;
+	    if (!(*ct->currItem)->branch || (*ct->currItem)->selected)
+		key = NEWT_KEY_DOWN;
+	    else
+		key = '*';
+	    break;
+	case '*':
+	    if ((*ct->currItem)->branch) {
+		ctSetItems((*ct->currItem)->branch, selnum);
+		if (!(*ct->currItem)->selected)
+		    key = NEWT_KEY_DOWN;
+	    } else {
+		(*ct->currItem)->selected = selnum;
+		key = NEWT_KEY_DOWN;
+	    }
+	    er.result = ER_SWALLOWED;
+	    break;
+	}
+	switch (key) {
+	case '*':
+	    ctDraw(co);
+	    if(co->callback) co->callback(co, co->callbackData);
+	    return er;
+	case NEWT_KEY_HOME:
+	    ct->currItem = ct->flatList;
+	    ct->firstItem = ct->flatList;
+	    ctDraw(co);
+	    if(co->callback) co->callback(co, co->callbackData);
+	    er.result = ER_SWALLOWED;
+	    return er;
+	case NEWT_KEY_END:
+	    ct->currItem = ct->flatList + ct->flatCount - 1;
+	    if (ct->flatCount <= co->height)
+		ct->firstItem = ct->flatList;
+	    else
+		ct->firstItem = ct->flatList + ct->flatCount - co->height;
+	    ctDraw(co);
+	    if(co->callback) co->callback(co, co->callbackData);
+	    er.result = ER_SWALLOWED;
+	    return er;
+	case NEWT_KEY_DOWN:
+	    if (ev.u.key != NEWT_KEY_DOWN) {
+		if(co->callback) co->callback(co, co->callbackData);
+		if (strlen(ct->seq) != 2) {
+		    ctDraw(co);
+		    return er;
+		}
+	    }
+	    if ((ct->currItem - ct->flatList + 1) < ct->flatCount) {
+		ct->currItem++;
+
+		if (ct->currItem - ct->firstItem >= co->height) 
+		    ct->firstItem++;
+
+		ctDraw(co);
+	    } else if (ev.u.key != NEWT_KEY_DOWN)
+	        ctDraw(co);
+	    if(co->callback) co->callback(co, co->callbackData);
+	    er.result = ER_SWALLOWED;
+	    return er;
+	case NEWT_KEY_UP:
+	    if (ct->currItem != ct->flatList) {
+		ct->currItem--;
+
+		if (ct->currItem < ct->firstItem)
+		    ct->firstItem = ct->currItem;
+		    
+		ctDraw(co);
+	    }
+	    er.result = ER_SWALLOWED;
+	    if(co->callback) co->callback(co, co->callbackData);
+	    return er;
+	case NEWT_KEY_PGUP:
+	    if (ct->firstItem - co->height < ct->flatList) {
+	    	ct->firstItem = ct->currItem = ct->flatList;
+	    } else {
+		ct->currItem -= co->height;
+		ct->firstItem -= co->height;
+	    }
+
+	    ctDraw(co);
+	    if(co->callback) co->callback(co, co->callbackData);
+	    er.result = ER_SWALLOWED;
+	    return er;
+	case NEWT_KEY_PGDN:
+	    listEnd = ct->flatList + ct->flatCount - 1;
+	    lastItem = ct->firstItem + co->height - 1;
+
+	    if (lastItem + co->height > listEnd) {
+	    	ct->firstItem = listEnd - co->height + 1;
+		ct->currItem = listEnd;
+	    } else {
+	    	ct->currItem += co->height;
+		ct->firstItem += co->height;
+	    }
+
+	    ctDraw(co);
+	    if(co->callback) co->callback(co, co->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->data;
+
+    if (!ct->currItem) return NULL;
+    return (*ct->currItem)->data;
+}
+
+void newtCheckboxTreeSetEntry(newtComponent co, const void * data, const char * text)
+{
+    struct CheckboxTree * ct;
+    struct items * item;
+    int i;
+
+    if (!co) return;
+    ct = co->data;
+    item = findItem(ct->itemlist, data);
+    if (!item) return;
+
+    free(item->text);
+    item->text = strdup(text);
+
+    i = 4 + (3 * item->depth);
+
+    if ((strlen(text) + i + ct->pad) > (size_t)co->width) {
+	co->width = strlen(text) + i + ct->pad;
+    }
+
+    ctDraw(co);
+}
+
+char newtCheckboxTreeGetEntryValue(newtComponent co, const void * data)
+{
+    struct CheckboxTree * ct;
+    struct items * item;
+
+    if (!co) return -1;
+    ct = co->data;
+    item = findItem(ct->itemlist, data);
+    if (!item) return -1;
+    if (item->branch)
+	return item->selected ? NEWT_CHECKBOXTREE_EXPANDED : NEWT_CHECKBOXTREE_COLLAPSED;
+    else
+	return ct->seq[item->selected];
+}
+
+void newtCheckboxTreeSetEntryValue(newtComponent co, const void * data, char value)
+{
+    struct CheckboxTree * ct;
+    struct items * item;
+    int i;
+
+    if (!co) return;
+    ct = co->data;
+    item = findItem(ct->itemlist, data);
+    if (!item || item->branch) return;
+
+    for(i = 0; ct->seq[i]; i++)
+	if (value == ct->seq[i])
+	    break;
+
+    if (!ct->seq[i]) return;
+    item->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 <ctype.h>
+#include <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+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->data;
+
+    if ((strlen(value) + 1) > (unsigned int)en->bufAlloced) {
+	free(en->buf);
+	en->bufAlloced = strlen(value) + 1;
+	en->buf = malloc(en->bufAlloced);
+	if (en->resultPtr) *en->resultPtr = en->buf;
+    }
+    memset(en->buf, 0, en->bufAlloced);		/* clear the buffer */
+    strcpy(en->buf, value);
+    en->bufUsed = strlen(value);
+    en->firstChar = 0;
+    if (cursorAtEnd)
+	en->cursorPosition = en->bufUsed;
+    else
+	en->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->data = en;
+
+    co->top = top;
+    co->left = left;
+    co->height = 1;
+    co->width = width;
+    co->isMapped = 0;
+    co->callback = NULL;
+
+    co->ops = &entryOps;
+
+    en->flags = flags;
+    en->cursorPosition = 0;
+    en->firstChar = 0;
+    en->bufUsed = 0;
+    en->bufAlloced = width + 1;
+    en->filter = NULL;
+
+    if (!(en->flags & NEWT_FLAG_DISABLED))
+	co->takesFocus = 1;
+    else
+	co->takesFocus = 0;
+
+    if (initialValue && strlen(initialValue) > (unsigned int)width) {
+	en->bufAlloced = strlen(initialValue) + 1;
+    }
+    en->buf = malloc(en->bufAlloced);
+    en->resultPtr = resultPtr;
+    if (en->resultPtr) *en->resultPtr = en->buf;
+
+    memset(en->buf, 0, en->bufAlloced);
+    if (initialValue) {
+	strcpy(en->buf, initialValue);
+	en->bufUsed = strlen(initialValue);
+	en->cursorPosition = en->bufUsed;
+    } else {
+	*en->buf = '\0';
+	en->bufUsed = 0;
+	en->cursorPosition = 0;
+    }
+
+    return co;
+}
+
+static void entryDraw(newtComponent co) {
+    struct entry * en = co->data;
+    int i;
+    char * chptr;
+    int len;
+
+    if (!co->isMapped) return;
+
+    if (en->flags & NEWT_FLAG_DISABLED)
+	SLsmg_set_color(NEWT_COLORSET_DISENTRY);
+    else
+	SLsmg_set_color(NEWT_COLORSET_ENTRY);
+
+    if (en->flags & NEWT_FLAG_HIDDEN) {
+	newtGotorc(co->top, co->left);
+	for (i = 0; i < co->width; i++)
+	    SLsmg_write_char('_');
+	newtGotorc(co->top, co->left);
+
+	return;
+    }
+
+    newtGotorc(co->top, co->left);
+
+    if (en->cursorPosition < en->firstChar) {
+	/* scroll to the left */
+	en->firstChar = en->cursorPosition;
+    } else if ((en->firstChar + co->width) <= en->cursorPosition) {
+	/* scroll to the right */
+	en->firstChar = en->cursorPosition - co->width + 1;
+    }
+
+    chptr = en->buf + en->firstChar;
+
+    if (en->flags & 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 <= co->width) {
+	i = len;
+	SLsmg_write_string(chptr);
+	while (i < co->width) {
+	    SLsmg_write_char('_');
+	    i++;
+	}
+    } else {
+	SLsmg_write_nstring(chptr, co->width);
+    }
+
+    if (en->flags & NEWT_FLAG_HIDDEN)
+	newtGotorc(co->top, co->left);
+    else
+	newtGotorc(co->top, co->left + (en->cursorPosition - en->firstChar));
+}
+
+void newtEntrySetFlags(newtComponent co, int flags, enum newtFlagsSense sense) {
+    struct entry * en = co->data;
+    int row, col;
+
+    en->flags = newtSetFlags(en->flags, flags, sense);
+
+    if (!(en->flags & NEWT_FLAG_DISABLED))
+	co->takesFocus = 1;
+    else
+	co->takesFocus = 0;
+
+    newtGetrc(&row, &col);
+    entryDraw(co);
+    newtGotorc(row, col);
+}
+
+static void entryDestroy(newtComponent co) {
+    struct entry * en = co->data;
+
+    free(en->buf);
+    free(en);
+    free(co);
+}
+
+static struct eventResult entryEvent(newtComponent co,
+				     struct event ev) {
+    struct entry * en = co->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->flags & NEWT_FLAG_HIDDEN)
+		newtGotorc(co->top, co->left);
+	    else
+		newtGotorc(co->top, co->left +
+			   (en->cursorPosition - en->firstChar));
+	    er.result = ER_SWALLOWED;
+	    break;
+
+	case EV_UNFOCUS:
+	    newtCursorOff();
+	    newtGotorc(0, 0);
+	    er.result = ER_SWALLOWED;
+	    if (co->callback)
+		co->callback(co, co->callbackData);
+	    break;
+
+	case EV_KEYPRESS:
+	    ch = ev.u.key;
+	    if (en->filter)
+		ch = en->filter(co, en->filterData, ch, en->cursorPosition);
+	    if (ch) er = entryHandleKey(co, ch);
+	    break;
+
+	case EV_MOUSE:
+	    if ((ev.u.mouse.type == MOUSE_BUTTON_DOWN) &&
+		(en->flags ^ NEWT_FLAG_HIDDEN)) {
+		if (strlen(en->buf) >= (size_t) (ev.u.mouse.x - co->left)) {
+		    en->cursorPosition = ev.u.mouse.x - co->left;
+		    newtGotorc(co->top,
+			       co->left +(en->cursorPosition - en->firstChar));
+		} else {
+		    en->cursorPosition = strlen(en->buf);
+		    newtGotorc(co->top,
+			       co->left +(en->cursorPosition - en->firstChar));
+		}
+	    }
+	    break;
+	}
+    } else
+	er.result = ER_IGNORED;
+
+    return er;
+}
+
+static struct eventResult entryHandleKey(newtComponent co, int key) {
+    struct entry * en = co->data;
+    struct eventResult er;
+    char * chptr, * insPoint;
+
+    er.result = ER_SWALLOWED;
+    switch (key) {
+      case '\r':				/* Return */
+	if (en->flags & NEWT_FLAG_RETURNEXIT) {
+	    er.result = ER_EXITFORM;
+	} else {
+	    er.result = ER_NEXTCOMP;
+	}
+	break;
+
+      case '\001':				/* ^A */
+      case NEWT_KEY_HOME:
+	en->cursorPosition = 0;
+	break;
+
+      case '\005':				/* ^E */
+      case NEWT_KEY_END:
+	en->cursorPosition = en->bufUsed;
+	break;
+
+      case '\013':				/* ^K */
+	en->bufUsed = en->cursorPosition;
+	memset(en->buf + en->bufUsed, 0, en->bufAlloced - en->bufUsed);
+	break;
+
+      case '\002':				/* ^B */
+      case NEWT_KEY_LEFT:
+	if (en->cursorPosition)
+	    en->cursorPosition--;
+	break;
+
+      case '\004':
+      case NEWT_KEY_DELETE:
+	chptr = en->buf + en->cursorPosition;
+	if (*chptr) {
+	    chptr++;
+	    while (*chptr) {
+		*(chptr - 1) = *chptr;
+		chptr++;
+	    }
+	    *(chptr - 1) = '\0';
+	    en->bufUsed--;
+	}
+	break;
+
+      case NEWT_KEY_BKSPC:
+	if (en->cursorPosition) {
+	    /* if this isn't true, there's nothing to erase */
+	    chptr = en->buf + en->cursorPosition;
+	    en->bufUsed--;
+	    en->cursorPosition--;
+	    while (*chptr) {
+		*(chptr - 1) = *chptr;
+		chptr++;
+	    }
+	    *(chptr - 1) = '\0';
+	}
+	break;
+
+      case '\006':				/* ^B */
+      case NEWT_KEY_RIGHT:
+	if (en->cursorPosition < en->bufUsed)
+	    en->cursorPosition++;
+	break;
+
+      default:
+	if ((key >= 0x20 && key <= 0x7e) || (key >= 0xa0 && key <= 0xff)) {
+	    if (!(en->flags & NEWT_FLAG_SCROLL) && en->bufUsed >= co->width) {
+		SLtt_beep();
+		break;
+	    }
+
+	    if ((en->bufUsed + 1) == en->bufAlloced) {
+		en->bufAlloced += 20;
+		en->buf = realloc(en->buf, en->bufAlloced);
+		if (en->resultPtr) *en->resultPtr = en->buf;
+		memset(en->buf + en->bufUsed + 1, 0, 20);
+	    }
+
+	    if (en->cursorPosition == en->bufUsed) {
+		en->bufUsed++;
+	    } else {
+		/* insert the new character */
+
+		/* chptr is the last character in the string */
+		chptr = (en->buf + en->bufUsed) - 1;
+		if ((en->bufUsed + 1) == en->bufAlloced) {
+		    /* this string fills the buffer, so clip it */
+		    chptr--;
+		} else
+		    en->bufUsed++;
+
+		insPoint = en->buf + en->cursorPosition;
+
+		while (chptr >= insPoint) {
+		    *(chptr + 1) = *chptr;
+		    chptr--;
+		}
+
+	    }
+
+	    en->buf[en->cursorPosition++] = key;
+	} else {
+	    er.result = ER_IGNORED;
+	}
+    }
+
+    entryDraw(co);
+
+    return er;
+}
+
+char * newtEntryGetValue(newtComponent co) {
+    struct entry * en = co->data;
+
+    return en->buf;
+}
+
+void newtEntrySetFilter(newtComponent co, newtEntryFilter filter, void * data) {
+    struct entry * en = co->data;
+    en->filter = filter;
+    en->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 <unistd.h>
+#include <slang.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+
+/****************************************************************************
+    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->data;
+    struct element * el = form->elements + compNum;
+
+    if ((co->top + form->vertOffset) > el->top) return 0;
+    if ((co->top + form->vertOffset + co->height) <
+	    (el->top + el->co->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->data = form;
+    co->width = 0;
+    co->height = 0;
+    co->top = -1;
+    co->left = -1;
+    co->isMapped = 0;
+
+    co->takesFocus = 0;			/* we may have 0 components */
+    co->ops = &formOps;
+
+    form->help = help;
+    form->flags = flags;
+    form->numCompsAlloced = 5;
+    form->numComps = 0;
+    form->currComp = -1;
+    form->vertOffset = 0;
+    form->fixedHeight = 0;
+    form->numRows = 0;
+    form->numFds = 0;
+    form->maxFd = 0;
+    form->fds = NULL;
+    form->beenSet = 0;
+    form->elements = malloc(sizeof(*(form->elements)) * form->numCompsAlloced);
+
+    form->background = COLORSET_WINDOW;
+    form->hotKeys = malloc(sizeof(int));
+    form->numHotKeys = 0;
+    form->timer = 0;
+    form->lastTimeout.tv_sec = form->lastTimeout.tv_usec = 0;
+    if (!(form->flags & NEWT_FLAG_NOF12)) {
+	newtFormAddHotKey(co, NEWT_KEY_F12);
+    }
+
+    if (vertBar)
+	form->vertBar = vertBar;
+    else
+	form->vertBar = NULL;
+
+    form->helpTag = help;
+    form->helpCb = helpCallback;
+
+    return co;
+}
+
+newtComponent newtFormGetCurrent(newtComponent co) {
+    struct form * form = co->data;
+
+    return form->elements[form->currComp].co;
+}
+
+void newtFormSetCurrent(newtComponent co, newtComponent subco) {
+    struct form * form = co->data;
+    int i, new;
+
+    for (i = 0; i < form->numComps; i++) {
+	 if (form->elements[i].co == subco) break;
+    }
+
+    if (form->elements[i].co != subco) return;
+    new = i;
+
+    if (co->isMapped && !componentFits(co, new)) {
+	gotoComponent(form, -1);
+	form->vertOffset = form->elements[new].top - co->top - 1;
+	if (form->vertOffset > (form->numRows - co->height))
+	    form->vertOffset = form->numRows - co->height;
+    }
+
+    gotoComponent(form, new);
+}
+
+void newtFormSetTimer(newtComponent co, int millisecs) {
+    struct form * form = co->data;
+
+    form->timer = millisecs;
+    form->lastTimeout.tv_usec = 0;
+    form->lastTimeout.tv_sec = 0;
+}
+
+void newtFormSetHeight(newtComponent co, int height) {
+    struct form * form = co->data;
+
+    form->fixedHeight = 1;
+    co->height = height;
+}
+
+void newtFormSetWidth(newtComponent co, int width) {
+    co->width = width;
+}
+
+void newtFormAddComponent(newtComponent co, newtComponent newco) {
+    struct form * form = co->data;
+
+    co->takesFocus = 1;
+
+    if (form->numCompsAlloced == form->numComps) {
+	form->numCompsAlloced += 5;
+	form->elements = realloc(form->elements,
+			    sizeof(*(form->elements)) * form->numCompsAlloced);
+    }
+
+    /* we grab real values for these a bit later */
+    form->elements[form->numComps].left = -2;
+    form->elements[form->numComps].top = -2;
+    form->elements[form->numComps].co = newco;
+
+    if (newco->takesFocus && form->currComp == -1)
+	form->currComp = form->numComps;
+
+    form->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->data;
+    int vertDelta, horizDelta;
+    struct element * el;
+    int i;
+
+    newtFormSetSize(co);
+
+    vertDelta = top - co->top;
+    horizDelta = left - co->left;
+    co->top = top;
+    co->left = left;
+
+    for (i = 0, el = form->elements; i < form->numComps; i++, el++) {
+	el->co->top += vertDelta;
+	el->top += vertDelta;
+	el->co->left += horizDelta;
+	el->left += horizDelta;
+    }
+}
+
+void newtDrawForm(newtComponent co) {
+    struct form * form = co->data;
+    struct element * el;
+    int i;
+
+    newtFormSetSize(co);
+
+    SLsmg_set_color(form->background);
+    newtClearBox(co->left, co->top, co->width, co->height);
+    for (i = 0, el = form->elements; i < form->numComps; i++, el++) {
+	/* the scrollbar *always* fits somewhere */
+	if (el->co == form->vertBar) {
+	    el->co->ops->mapped(el->co, 1);
+	    el->co->ops->draw(el->co);
+	} else {
+	    /* only draw it if it'll fit on the screen vertically */
+	    if (componentFits(co, i)) {
+		el->co->top = el->top - form->vertOffset;
+		el->co->ops->mapped(el->co, 1);
+		el->co->ops->draw(el->co);
+	    } else {
+		el->co->ops->mapped(el->co, 0);
+	    }
+	}
+    }
+
+    if (form->vertBar)
+	newtScrollbarSet(form->vertBar, form->vertOffset,
+			 form->numRows - co->height);
+}
+
+static struct eventResult formEvent(newtComponent co, struct event ev) {
+    struct form * form = co->data;
+    newtComponent subco = form->elements[form->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->numComps) return er;
+
+    subco = form->elements[form->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->numComps) {
+	    i = form->currComp;
+	    num = 0;
+	    while (er.result == ER_IGNORED && num != form->numComps ) {
+		er = form->elements[i].co->ops->event(form->elements[i].co, ev);
+
+		num++;
+		i++;
+		if (i == form->numComps) i = 0;
+	    }
+	}
+
+	break;
+
+      case EV_NORMAL:
+	  if (ev.event == EV_MOUSE) {
+	      found = 0;
+	      for (i = 0, el = form->elements; i < form->numComps; i++, el++) {
+		  if ((el->co->top <= ev.u.mouse.y) &&
+		      (el->co->top + el->co->height > ev.u.mouse.y) &&
+		      (el->co->left <= ev.u.mouse.x) &&
+		      (el->co->left + el->co->width > ev.u.mouse.x)) {
+		      found = 1;
+		      if (el->co->takesFocus) {
+			  gotoComponent(form, i);
+			  subco = form->elements[form->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->ops->event(subco, ev);
+	switch (er.result) {
+	  case ER_NEXTCOMP:
+	    er.result = ER_SWALLOWED;
+	    dir = 1;
+	    break;
+
+	  case ER_EXITFORM:
+	    form->exitComp = subco;
+	    break;
+
+	  default:
+	    break;
+	}
+	break;
+
+      case EV_LATE:
+	er = subco->ops->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->currComp;
+
+	if (page) {
+	    new += dir * co->height;
+	    if (new < 0)
+		new = 0;
+	    else if (new >= form->numComps)
+		new = (form->numComps - 1);
+
+	    while (!form->elements[new].co->takesFocus)
+		new = new - dir;
+	} else {
+	    do {
+		new += dir;
+
+		if (wrap) {
+		    if (new < 0)
+			new = form->numComps - 1;
+		    else if (new >= form->numComps)
+			new = 0;
+		} else if (new < 0 || new >= form->numComps)
+		    return er;
+	    } while (!form->elements[new].co->takesFocus);
+	}
+
+	/* make sure this component is visible */
+	if (!componentFits(co, new)) {
+	    gotoComponent(form, -1);
+
+	    if (dir < 0) {
+		/* make the new component the first one */
+		form->vertOffset = form->elements[new].top - co->top;
+	    } else {
+		/* make the new component the last one */
+		form->vertOffset = (form->elements[new].top +
+					form->elements[new].co->height) -
+				    (co->top + co->height);
+	    }
+
+	    if (form->vertOffset < 0) form->vertOffset = 0;
+	    if (form->vertOffset > (form->numRows - co->height))
+		form->vertOffset = form->numRows - co->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->data;
+    int i;
+
+    /* first, destroy all of the components */
+    for (i = 0; i < form->numComps; i++) {
+	subco = form->elements[i].co;
+	if (subco->ops->destroy) {
+	    subco->ops->destroy(subco);
+	} else {
+	    if (subco->data) free(subco->data);
+	    free(subco);
+	}
+    }
+
+    if (form->hotKeys) free(form->hotKeys);
+
+    free(form->elements);
+    free(form);
+    free(co);
+}
+
+newtComponent newtRunForm(newtComponent co) {
+    struct newtExitStruct es;
+
+    newtFormRun(co, &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->data;
+
+    form->numHotKeys++;
+    form->hotKeys = realloc(form->hotKeys, sizeof(int) * form->numHotKeys);
+    form->hotKeys[form->numHotKeys - 1] = key;
+}
+
+void newtFormSetSize(newtComponent co) {
+    struct form * form = co->data;
+    int delta, i;
+    struct element * el;
+
+    if (form->beenSet) return;
+
+    form->beenSet = 1;
+
+    if (!form->numComps) return;
+
+    co->width = 0;
+    if (!form->fixedHeight) co->height = 0;
+
+    co->top = form->elements[0].co->top;
+    co->left = form->elements[0].co->left;
+    for (i = 0, el = form->elements; i < form->numComps; i++, el++) {
+	if (el->co->ops == &formOps)
+	    newtFormSetSize(el->co);
+
+ 	el->left = el->co->left;
+ 	el->top = el->co->top;
+
+	if (co->left > el->co->left) {
+	    delta = co->left - el->co->left;
+	    co->left -= delta;
+	    co->width += delta;
+	}
+
+	if (co->top > el->co->top) {
+	    delta = co->top - el->co->top;
+	    co->top -= delta;
+	    if (!form->fixedHeight)
+		co->height += delta;
+	}
+
+	if ((co->left + co->width) < (el->co->left + el->co->width))
+	    co->width = (el->co->left + el->co->width) - co->left;
+
+	if (!form->fixedHeight) {
+	    if ((co->top + co->height) < (el->co->top + el->co->height))
+		co->height = (el->co->top + el->co->height) - co->top;
+	}
+
+	if ((el->co->top + el->co->height - co->top) > form->numRows) {
+	    form->numRows = el->co->top + el->co->height - co->top;
+	}
+    }
+}
+
+void newtFormRun(newtComponent co, struct newtExitStruct * es) {
+    struct form * form = co->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->currComp == -1) {
+	gotoComponent(form, 0);
+    } else
+	gotoComponent(form, form->currComp);
+
+    while (!done) {
+	newtRefresh();
+
+	FD_ZERO(&readSet);
+	FD_ZERO(&writeSet);
+	FD_SET(0, &readSet);
+	max = form->maxFd;
+
+	for (i = 0; i < form->numFds; i++) {
+	    if (form->fds[i].flags & NEWT_FD_READ)
+		FD_SET(form->fds[i].fd, &readSet);
+	    if (form->fds[i].flags & NEWT_FD_WRITE)
+		FD_SET(form->fds[i].fd, &writeSet);
+	}
+
+	if (form->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->lastTimeout.tv_sec && !form->lastTimeout.tv_usec)
+		gettimeofday(&form->lastTimeout, NULL);
+
+	    nextTimeout.tv_sec = form->lastTimeout.tv_sec + 
+		    (form->timer / 1000);
+	    nextTimeout.tv_usec = form->lastTimeout.tv_usec + 
+				    (form->timer % 1000) * 1000;
+
+	    gettimeofday(&now, 0);
+
+	    if (now.tv_sec > 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 > nextTimeout.tv_usec)
+		    timeout.tv_usec = 0;
+		else
+		    timeout.tv_usec = nextTimeout.tv_usec - now.tv_usec;
+	    } else if (now.tv_sec < nextTimeout.tv_sec) {
+		timeout.tv_sec = nextTimeout.tv_sec - now.tv_sec;
+		if (now.tv_usec > 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, &readSet, &writeSet, NULL, 
+			form->timer ? &timeout : NULL);
+	if (i < 0) continue;	/* ?? What should we do here? */
+
+	if (i == 0) {
+	    done = 1;
+	    es->reason = NEWT_EXIT_TIMER;
+	    gettimeofday(&form->lastTimeout, NULL);
+	} else
+	{
+	    if (FD_ISSET(0, &readSet)) {
+
+		key = newtGetKey();
+
+		if (key == NEWT_KEY_RESIZE) {
+		    /* newtResizeScreen(1); */
+		    continue;
+		}
+
+		for (i = 0; i < form->numHotKeys; i++) {
+		    if (form->hotKeys[i] == key) {
+			es->reason = NEWT_EXIT_HOTKEY;
+			es->u.key = key;
+			done = 1;
+			break;
+		    }
+		}
+
+		if (key == NEWT_KEY_F1 && form->helpTag && form->helpCb)
+		    form->helpCb(co, form->helpTag);
+
+		if (!done) {
+		    ev.event = EV_KEYPRESS;
+		    ev.u.key = key;
+
+		    er = sendEvent(co, ev);
+
+		    if (er.result == ER_EXITFORM) {
+			done = 1;
+			es->reason = NEWT_EXIT_COMPONENT;
+			es->u.co = form->exitComp;
+		    }
+		}
+	    } else {
+		es->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->ops->event(co, ev);
+
+    if (er.result == ER_IGNORED) {
+	ev.when = EV_NORMAL;
+	er = co->ops->event(co, ev);
+    }
+
+    if (er.result == ER_IGNORED) {
+	ev.when = EV_LATE;
+	er = co->ops->event(co, ev);
+    }
+
+    return er;
+}
+
+static void gotoComponent(struct form * form, int newComp) {
+    struct event ev;
+
+    if (form->currComp != -1) {
+	ev.event = EV_UNFOCUS;
+	sendEvent(form->elements[form->currComp].co, ev);
+    }
+
+    form->currComp = newComp;
+
+    if (form->currComp != -1) {
+	ev.event = EV_FOCUS;
+	ev.when = EV_NORMAL;
+	sendEvent(form->elements[form->currComp].co, ev);
+    }
+}
+
+void newtComponentAddCallback(newtComponent co, newtCallback f, void * data) {
+    co->callback = f;
+    co->callbackData = data;
+}
+
+void newtComponentTakesFocus(newtComponent co, int val) {
+    co->takesFocus = val;
+}
+
+void newtFormSetBackground(newtComponent co, int color) {
+    struct form * form = co->data;
+
+    form->background = color;
+}
+
+void newtFormWatchFd(newtComponent co, int fd, int fdFlags) {
+    struct form * form = co->data;
+
+    form->fds = realloc(form->fds, (form->numFds + 1) * sizeof(*form->fds));
+    form->fds[form->numFds].fd = fd;
+    form->fds[form->numFds++].flags = fdFlags;
+    if (form->maxFd < fd) form->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 <alloca.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+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->rows = rows;
+    grid->cols = cols;
+
+    grid->fields = malloc(sizeof(*grid->fields) * cols);
+    while (cols--) {
+	grid->fields[cols] = malloc(sizeof(**(grid->fields)) * rows);
+	memset(grid->fields[cols], 0, sizeof(**(grid->fields)) * rows);
+    }
+
+    grid->width = grid->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 = &grid->fields[col][row];
+
+    if (field->type == NEWT_GRID_SUBGRID) 
+	newtGridFree(field->u.grid, 1);
+
+    field->type = type;
+    field->u.co = (void *) val;
+
+    field->padLeft = padLeft;
+    field->padRight = padRight;
+    field->padTop = padTop;
+    field->padBottom = padBottom;
+    field->anchor = anchor;
+    field->flags = flags;
+
+    grid->width = grid->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 < 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->cols);
+    memset(widths, 0, sizeof(*widths) * grid->cols);
+    heights = alloca(sizeof(*heights) * grid->rows);
+    memset(heights, 0, sizeof(*heights) * grid->rows);
+
+    minWidth = 0;
+    for (row = 0; row < grid->rows; row++) {
+	i = 0;
+	for (col = 0; col < grid->cols; col++) {
+	    field = &grid->fields[col][row];
+	    if (field->type == NEWT_GRID_SUBGRID) {
+		/* we'll have to redo this later */
+		if (field->u.grid->width == -1) 
+		    shuffleGrid(field->u.grid, left, top, 0);
+		j = field->u.grid->width;
+	    } else if (field->type == NEWT_GRID_COMPONENT) {
+		if (field->u.co->ops == formOps)
+		    newtFormSetSize(field->u.co);
+		j = field->u.co->width;
+	    } else 
+		j = 0;
+
+	    j += field->padLeft + field->padRight;
+
+	    if (j > widths[col]) widths[col] = j;
+	    i += widths[col];
+	}
+
+	if (i > minWidth) minWidth = i;
+    }
+
+    minHeight = 0;
+    for (col = 0; col < grid->cols; col++) {
+	i = 0;
+	for (row = 0; row < grid->rows; row++) {
+	    field = &grid->fields[col][row];
+	    if (field->type == NEWT_GRID_SUBGRID) {
+		/* we'll have to redo this later */
+		if (field->u.grid->height == -1) 
+		    shuffleGrid(field->u.grid, 0, 0, 0);
+		j = field->u.grid->height;
+	    } else if (field->type == NEWT_GRID_COMPONENT){
+		j = field->u.co->height;
+	    } else 
+		j = 0;
+
+	    j += field->padTop + field->padBottom;
+
+	    if (j > heights[row]) heights[row] = j;
+	    i += heights[row];
+	}
+
+	if (i > minHeight) minHeight = i;
+    }
+
+    /* this catches the -1 case */
+    if (grid->width < minWidth) grid->width = minWidth;		/* ack! */
+    if (grid->height < minHeight) grid->height = minHeight;	/* ditto! */
+
+    if (!set) return;
+
+    distSpace(grid->width - minWidth, grid->cols, widths);
+    distSpace(grid->height - minHeight, grid->rows, heights);
+
+    thisTop = top;
+    for (row = 0; row < grid->rows; row++) {
+	i = 0;
+	thisLeft = left;
+	for (col = 0; col < grid->cols; col++) {
+	    field = &grid->fields[col][row];
+
+	    if (field->type == NEWT_GRID_EMPTY) continue;
+
+	    x = thisLeft + field->padLeft;
+	    remx = widths[col] - field->padLeft - field->padRight;
+	    y = thisTop + field->padTop;
+	    remy = heights[row] - field->padTop - field->padBottom;
+
+	    if (field->type == NEWT_GRID_SUBGRID) {
+		remx -= field->u.grid->width;
+		remy -= field->u.grid->height;
+	    } else if (field->type == NEWT_GRID_COMPONENT) {
+		remx -= field->u.co->width;
+		remy -= field->u.co->height;
+	    }
+
+	    if (!(field->flags & NEWT_GRID_FLAG_GROWX)) {
+		if (field->anchor & NEWT_ANCHOR_RIGHT)
+		    x += remx;
+		else if (!(field->anchor & NEWT_ANCHOR_LEFT))
+		    x += (remx / 2);
+	    }
+	 
+	    if (!(field->flags & NEWT_GRID_FLAG_GROWY)) {
+		if (field->anchor & NEWT_ANCHOR_BOTTOM)
+		    y += remx;
+		else if (!(field->anchor & NEWT_ANCHOR_TOP))
+		    y += (remy / 2);
+	    }
+
+	    if (field->type == NEWT_GRID_SUBGRID) {
+		if (field->flags & NEWT_GRID_FLAG_GROWX)
+		    field->u.grid->width = widths[col] - field->padLeft 
+						- field->padRight;
+		if (field->flags & NEWT_GRID_FLAG_GROWY)
+		    field->u.grid->height = heights[col] - field->padTop
+						- field->padBottom;
+
+		shuffleGrid(field->u.grid, x, y, 1);
+	    } else if (field->type == NEWT_GRID_COMPONENT) {
+		field->u.co->ops->place(field->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 < grid->cols; col++) {
+	if (recurse) {
+	    for (row = 0; row < grid->rows; row++) {
+		if (grid->fields[col][row].type == NEWT_GRID_SUBGRID)
+		    newtGridFree(grid->fields[col][row].u.grid, 1);
+	    }
+	}
+
+	free(grid->fields[col]);
+    }
+
+    free(grid->fields);
+    free(grid);
+}
+
+void newtGridGetSize(newtGrid grid, int * width, int * height) {
+    if (grid->width == -1 || grid->height == -1) {
+	grid->width = grid->height = -1;
+	shuffleGrid(grid, 0, 0, 1);
+    }
+
+    *width = grid->width;
+    *height = grid->height;
+}
+
+void newtGridWrappedWindow(newtGrid grid, char * title) {
+    int width, height, offset = 0;
+
+    newtGridGetSize(grid, &width, &height);
+    if ((size_t)width < 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, &width, &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 < grid->cols; col++) {
+	for (row = 0; row < grid->rows; row++) {
+	    if (grid->fields[col][row].type == NEWT_GRID_SUBGRID && recurse)
+		newtGridAddComponentsToForm(grid->fields[col][row].u.grid,
+					    form, 1);
+	    else if (grid->fields[col][row].type == NEWT_GRID_COMPONENT)
+		newtFormAddComponent(form, grid->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 < 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 <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+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->data = la;
+
+    co->ops = &labelOps;
+
+    co->height = 1;
+    co->width = strlen(text);
+    co->top = top;
+    co->left = left;
+    co->takesFocus = 0;
+
+    la->length = strlen(text);
+    la->text = strdup(text);
+
+    return co;
+}
+
+void newtLabelSetText(newtComponent co, const char * text) {
+    int newLength;
+    struct label * la = co->data;
+
+    newLength = strlen(text);
+    if (newLength <= la->length) {
+	memset(la->text, ' ', la->length);
+	memcpy(la->text, text, newLength);
+    } else {
+	free(la->text);
+	la->text = strdup(text);
+	la->length = newLength;
+	co->width = newLength;
+    }
+
+    labelDraw(co);
+}
+
+static void labelDraw(newtComponent co) {
+    struct label * la = co->data;
+
+    if (co->isMapped == -1) return;
+
+    SLsmg_set_color(COLORSET_LABEL);
+
+    newtGotorc(co->top, co->left);
+    SLsmg_write_string(la->text);
+}
+
+static void labelDestroy(newtComponent co) {
+    struct label * la = co->data;
+
+    free(la->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 <sopwith at cuc.edu>
+   (from the original listbox by Erik Troan <ewt at redhat.com>)
+   and contributed to newt for use under the LGPL license.
+   Copyright (C) 1996, 1997 Elliot Lee */
+
+#include <slang.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+
+/* 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->data;
+
+    co->isMapped = isMapped;
+    if (li->sb)
+	li->sb->ops->mapped(li->sb, isMapped);
+}
+
+static void listboxPlace(newtComponent co, int newLeft, int newTop) {
+    struct listbox * li = co->data;
+
+    co->top = newTop;
+    co->left = newLeft;
+
+    if (li->sb)
+	li->sb->ops->place(li->sb, co->left + co->width - li->bdxAdjust - 1,
+			   co->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->boxItems = NULL;
+    li->numItems = 0;
+    li->currItem = 0;
+    li->numSelected = 0;
+    li->isActive = 0;
+    li->userHasSetWidth = 0;
+    li->startShowItem = 0;
+    li->sbAdjust = 0;
+    li->bdxAdjust = 0;
+    li->bdyAdjust = 0;
+    li->flags = flags & (NEWT_FLAG_RETURNEXIT | NEWT_FLAG_BORDER |
+			 NEWT_FLAG_MULTIPLE);
+
+    if (li->flags & NEWT_FLAG_BORDER) {
+	li->bdxAdjust = 2;
+	li->bdyAdjust = 1;
+    }
+
+    co->height = height;
+    li->curHeight = co->height - (2 * li->bdyAdjust);
+
+    if (height) {
+	li->grow = 0;
+	if (flags & NEWT_FLAG_SCROLL) {
+	    sb = newtVerticalScrollbar(left, top + li->bdyAdjust,
+					li->curHeight,
+					COLORSET_LISTBOX, COLORSET_ACTLISTBOX);
+	    li->sbAdjust = 3;
+	} else {
+	    sb = NULL;
+	}
+    } else {
+	li->grow = 1;
+	sb = NULL;
+    }
+
+    li->sb = sb;
+    co->data = li;
+    co->isMapped = 0;
+    co->left = left;
+    co->top = top;
+    co->ops = &listboxOps;
+    co->takesFocus = 1;
+    co->callback = NULL;
+
+    updateWidth(co, li, 5);
+
+    return co;
+}
+
+static inline void updateWidth(newtComponent co, struct listbox * li,
+				int maxField) {
+    li->curWidth = maxField;
+    co->width = li->curWidth + li->sbAdjust + 2 * li->bdxAdjust;
+
+    if (li->sb)
+	li->sb->left = co->left + co->width - li->bdxAdjust - 1;
+}
+
+void newtListboxSetCurrentByKey(newtComponent co, void * key) {
+    struct listbox * li = co->data;
+    struct items * item;
+    int i;
+
+    item = li->boxItems, i = 0;
+    while (item && item->data != key)
+	item = item->next, i++;
+
+    if (item)
+	newtListboxSetCurrent(co, i);
+}
+
+void newtListboxSetCurrent(newtComponent co, int num)
+{
+    struct listbox * li = co->data;
+
+    if (num >= li->numItems)
+	li->currItem = li->numItems - 1;
+    else if (num < 0)
+	li->currItem = 0;
+    else
+	li->currItem = num;
+
+    if (li->currItem < li->startShowItem)
+	li->startShowItem = li->currItem;
+    else if (li->currItem - li->startShowItem > li->curHeight - 1)
+	li->startShowItem = li->currItem - li->curHeight + 1;
+    if (li->startShowItem + li->curHeight > li->numItems)
+	li->startShowItem = li->numItems - li->curHeight;
+    if(li->startShowItem < 0)
+	li->startShowItem = 0;
+
+    newtListboxRealSetCurrent(co);
+}
+
+static void newtListboxRealSetCurrent(newtComponent co)
+{
+    struct listbox * li = co->data;
+
+    if(li->sb)
+	newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
+    listboxDraw(co);
+    if(co->callback) co->callback(co, co->callbackData);
+}
+
+void newtListboxSetWidth(newtComponent co, int width) {
+    struct listbox * li = co->data;
+
+    co->width = width;
+    li->curWidth = co->width - li->sbAdjust - 2 * li->bdxAdjust;
+    li->userHasSetWidth = 1;
+    if (li->sb) li->sb->left = co->width + co->left - 1;
+    listboxDraw(co);
+}
+
+void * newtListboxGetCurrent(newtComponent co) {
+    struct listbox * li = co->data;
+    int i;
+    struct items *item;
+
+    for(i = 0, item = li->boxItems; item != NULL && i < li->currItem;
+	i++, item = item->next);
+
+    if (item)
+	return (void *)item->data;
+    else
+	return NULL;
+}
+
+void newtListboxSelectItem(newtComponent co, const void * key,
+	enum newtFlagsSense sense)
+{
+    struct listbox * li = co->data;
+    int i;
+    struct items * item;
+
+    item = li->boxItems, i = 0;
+    while (item && item->data != key)
+	item = item->next, i++;
+
+    if (!item) return;
+
+    if (item->isSelected)
+	li->numSelected--;
+
+    switch(sense) {
+	case NEWT_FLAGS_RESET:
+		item->isSelected = 0; break;
+	case NEWT_FLAGS_SET:
+		item->isSelected = 1; break;
+	case NEWT_FLAGS_TOGGLE:
+		item->isSelected = !item->isSelected;
+    }
+
+    if (item->isSelected)
+	li->numSelected++;
+
+    listboxDraw(co);
+}
+
+void newtListboxClearSelection(newtComponent co)
+{
+    struct items *item;
+    struct listbox * li = co->data;
+
+    for(item = li->boxItems; item != NULL;
+	item = item->next)
+	item->isSelected = 0;
+    li->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->data;
+    if(!li || !li->numSelected) return NULL;
+
+    retval = malloc(li->numSelected * sizeof(void *));
+    for(i = 0, item = li->boxItems; item != NULL;
+	item = item->next)
+	if(item->isSelected)
+	    retval[i++] = (void *)item->data;
+    *numitems = li->numSelected;
+    return retval;
+}
+
+void newtListboxSetEntry(newtComponent co, int num, const char * text) {
+    struct listbox * li = co->data;
+    int i;
+    struct items *item;
+
+    for(i = 0, item = li->boxItems; item != NULL && i < num;
+	i++, item = item->next);
+
+    if(!item)
+	return;
+    else {
+	free(item->text);
+	item->text = strdup(text);
+    }
+    if (li->userHasSetWidth == 0 && strlen(text) > (size_t)li->curWidth) {
+	updateWidth(co, li, strlen(text));
+    }
+
+    if (num >= li->startShowItem && num <= li->startShowItem + co->height)
+	listboxDraw(co);
+}
+
+void newtListboxSetData(newtComponent co, int num, void * data) {
+    struct listbox * li = co->data;
+    int i;
+    struct items *item;
+
+    for(i = 0, item = li->boxItems; item != NULL && i < num;
+	i++, item = item->next);
+
+    item->data = data;
+}
+
+int newtListboxAppendEntry(newtComponent co, const char * text,
+	                const void * data) {
+    struct listbox * li = co->data;
+    struct items *item;
+
+    if(li->boxItems) {
+	for (item = li->boxItems; item->next != NULL; item = item->next);
+
+	item = item->next = malloc(sizeof(struct items));
+    } else {
+	item = li->boxItems = malloc(sizeof(struct items));
+    }
+
+    if (!li->userHasSetWidth && text && (strlen(text) > (size_t)li->curWidth))
+	updateWidth(co, li, strlen(text));
+
+    item->text = strdup(text); item->data = data; item->next = NULL;
+    item->isSelected = 0;
+
+    if (li->grow)
+	co->height++, li->curHeight++;
+    li->numItems++;
+
+    return 0;
+}
+
+int newtListboxInsertEntry(newtComponent co, const char * text,
+	                   const void * data, void * key) {
+    struct listbox * li = co->data;
+    struct items *item, *t;
+
+    if (li->boxItems) {
+	if (key) {
+	    item = li->boxItems;
+	    while (item && item->data != key) item = item->next;
+
+	    if (!item) return 1;
+
+	    t = item->next;
+	    item = item->next = malloc(sizeof(struct items));
+	    item->next = t;
+	} else {
+	    t = li->boxItems;
+	    item = li->boxItems = malloc(sizeof(struct items));
+	    item->next = t;
+	}
+    } else if (key) {
+	return 1;
+    } else {
+	item = li->boxItems = malloc(sizeof(struct items));
+	item->next = NULL;
+    }
+
+    if (!li->userHasSetWidth && text && (strlen(text) > (size_t)li->curWidth))
+	updateWidth(co, li, strlen(text));
+
+    item->text = strdup(text?text:"(null)"); item->data = data;
+    item->isSelected = 0;
+
+    if (li->sb)
+	li->sb->left = co->left + co->width - li->bdxAdjust - 1;
+    li->numItems++;
+
+    listboxDraw(co);
+
+    return 0;
+}
+
+int newtListboxDeleteEntry(newtComponent co, void * key) {
+    struct listbox * li = co->data;
+    int widest = 0, t;
+    struct items *item, *item2 = NULL;
+    int num;
+
+    if (li->boxItems == NULL || li->numItems <= 0)
+	return 0;
+
+    num = 0;
+
+    item2 = NULL, item = li->boxItems;
+    while (item && item->data != key) {
+	item2 = item;
+	item = item->next;
+	num++;
+    }
+
+    if (!item)
+	return -1;
+
+    if (item2)
+	item2->next = item->next;
+    else
+	li->boxItems = item->next;
+
+    free(item->text);
+    free(item);
+    li->numItems--;
+
+    if (!li->userHasSetWidth) {
+	widest = 0;
+	for (item = li->boxItems; item != NULL; item = item->next)
+	    if ((t = strlen(item->text)) > widest) widest = t;
+    }
+
+    if (li->currItem >= num)
+	li->currItem--;
+
+    if (!li->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->data) == NULL)
+	return;
+    for(anitem = li->boxItems; anitem != NULL; anitem = nextitem) {
+	nextitem = anitem->next;
+	free(anitem->text);
+	free(anitem);
+    }
+    li->numItems = li->numSelected = li->currItem = li->startShowItem = 0;
+    li->boxItems = NULL;
+    if (!li->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->data;
+    int i;
+    struct items *item;
+
+    if (!li->boxItems || num >= li->numItems) {
+	if(text)
+	    *text = NULL;
+	if(data)
+	    *data = NULL;
+	return;
+    }
+
+    i = 0;
+    item = li->boxItems;
+    while (item && i < num) {
+	i++, item = item->next;
+    }
+
+    if (item) {
+	if (text)
+	    *text = item->text;
+	if (data)
+	    *data = (void *)item->data;
+    }
+}
+
+static void listboxDraw(newtComponent co)
+{
+    struct listbox * li = co->data;
+    struct items *item;
+    int i, j;
+
+    if (!co->isMapped) return ;
+
+    if(li->flags & NEWT_FLAG_BORDER) {
+      if(li->isActive)
+	  SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX);
+      else
+          SLsmg_set_color(NEWT_COLORSET_LISTBOX);
+
+      newtDrawBox(co->left, co->top, co->width, co->height, 0);
+    }
+
+    if(li->sb)
+	li->sb->ops->draw(li->sb);
+
+    SLsmg_set_color(NEWT_COLORSET_LISTBOX);
+
+    for(i = 0, item = li->boxItems; item != NULL && i < li->startShowItem;
+	i++, item = item->next);
+
+    j = i;
+
+    for (i = 0; item != NULL && i < li->curHeight; i++, item = item->next) {
+	if (!item->text) continue;
+
+	newtGotorc(co->top + i + li->bdyAdjust, co->left + li->bdxAdjust);
+	if(j + i == li->currItem) {
+	    if(item->isSelected)
+		SLsmg_set_color(NEWT_COLORSET_ACTSELLISTBOX);
+	    else
+		SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX);
+	} else if(item->isSelected)
+	    SLsmg_set_color(NEWT_COLORSET_SELLISTBOX);
+	else
+	    SLsmg_set_color(NEWT_COLORSET_LISTBOX);
+
+	SLsmg_write_nstring(item->text, li->curWidth);
+
+    }
+    newtGotorc(co->top + (li->currItem - li->startShowItem), co->left);
+}
+
+static struct eventResult listboxEvent(newtComponent co, struct event ev) {
+    struct eventResult er;
+    struct listbox * li = co->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->isActive) break;
+
+	switch(ev.u.key) {
+	  case ' ':
+	    if(!(li->flags & NEWT_FLAG_MULTIPLE)) break;
+	    newtListboxSelectItem(co, li->boxItems[li->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->numItems <= 0) break;
+	    if(li->currItem < li->numItems - 1) {
+		li->currItem++;
+		if(li->currItem > (li->startShowItem + li->curHeight - 1)) {
+		    li->startShowItem = li->currItem - li->curHeight + 1;
+		    if(li->startShowItem + li->curHeight > li->numItems)
+			li->startShowItem = li->numItems - li->curHeight;
+		}
+		if(li->sb)
+		    newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
+		listboxDraw(co);
+	    }
+	    if(co->callback) co->callback(co, co->callbackData);
+	    er.result = ER_SWALLOWED;
+	    break;
+
+	  case NEWT_KEY_ENTER:
+	    if(li->numItems <= 0) break;
+	    if(li->flags & NEWT_FLAG_RETURNEXIT)
+		er.result = ER_EXITFORM;
+	    break;
+
+	  case NEWT_KEY_UP:
+	    if(li->numItems <= 0) break;
+	    if(li->currItem > 0) {
+		li->currItem--;
+		if(li->currItem < li->startShowItem)
+		    li->startShowItem = li->currItem;
+		if(li->sb)
+		    newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
+		listboxDraw(co);
+	    }
+	    if(co->callback) co->callback(co, co->callbackData);
+	    er.result = ER_SWALLOWED;
+	    break;
+
+	  case NEWT_KEY_PGUP:
+	    if(li->numItems <= 0) break;
+	    li->startShowItem -= li->curHeight - 1;
+	    if(li->startShowItem < 0)
+		li->startShowItem = 0;
+	    li->currItem -= li->curHeight - 1;
+	    if(li->currItem < 0)
+		li->currItem = 0;
+	    newtListboxRealSetCurrent(co);
+	    er.result = ER_SWALLOWED;
+	    break;
+
+	  case NEWT_KEY_PGDN:
+	    if(li->numItems <= 0) break;
+	    li->startShowItem += li->curHeight;
+	    if(li->startShowItem > (li->numItems - li->curHeight)) {
+		li->startShowItem = li->numItems - li->curHeight;
+	    }
+	    li->currItem += li->curHeight;
+	    if(li->currItem >= li->numItems) {
+		li->currItem = li->numItems - 1;
+	    }
+	    newtListboxRealSetCurrent(co);
+	    er.result = ER_SWALLOWED;
+	    break;
+
+	  case NEWT_KEY_HOME:
+	    if(li->numItems <= 0) break;
+	    newtListboxSetCurrent(co, 0);
+	    er.result = ER_SWALLOWED;
+	    break;
+
+	  case NEWT_KEY_END:
+	    if(li->numItems <= 0) break;
+	    li->startShowItem = li->numItems - li->curHeight;
+	    if(li->startShowItem < 0)
+		li->startShowItem = 0;
+	    li->currItem = li->numItems - 1;
+	    newtListboxRealSetCurrent(co);
+	    er.result = ER_SWALLOWED;
+	    break;
+	  default:
+	      if (li->numItems <= 0) break;
+              if (ev.u.key < NEWT_KEY_EXTRA_BASE && isalpha(ev.u.key)) {
+		  for(i = 0, item = li->boxItems; item != NULL &&
+			  i < li->currItem; i++, item = item->next);
+
+		  if (item && item->text && (toupper(*item->text) == toupper(ev.u.key))) {
+		      item = item->next;
+		      i++;
+		  } else { 
+		      item = li->boxItems;
+		      i = 0;
+		  }
+		  while (item && item->text &&
+			 toupper(*item->text) != toupper(ev.u.key)) {
+		      item = item->next;
+		      i++;
+		  }
+		  if (item) {
+		      li->currItem = i;
+		      if(li->currItem < li->startShowItem ||
+			 li->currItem > li->startShowItem)
+			  li->startShowItem =
+			      li->currItem > li->numItems - li->curHeight ?
+			      li->startShowItem = li->numItems - li->curHeight :
+			      li->currItem;
+		      if(li->sb)
+			  newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
+		      newtListboxRealSetCurrent(co);
+		      er.result = ER_SWALLOWED;
+		  }
+	      }
+	}
+	break;
+
+      case EV_FOCUS:
+	li->isActive = 1;
+	listboxDraw(co);
+	er.result = ER_SWALLOWED;
+	break;
+
+      case EV_UNFOCUS:
+	li->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->sb &&
+	    ev.u.mouse.x == co->left + co->width - li->bdxAdjust - 1 &&
+	    ev.u.mouse.y == co->top + li->bdyAdjust) {
+	    if(li->numItems <= 0) break;
+	    if(li->currItem > 0) {
+		li->currItem--;
+		if(li->currItem < li->startShowItem)
+		    li->startShowItem = li->currItem;
+		if(li->sb)
+		    newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
+		listboxDraw(co);
+	    }
+	    if(co->callback) co->callback(co, co->callbackData);
+	    er.result = ER_SWALLOWED;
+	    break;
+	}
+	/* Down scroll arrow */
+	if (li->sb &&
+	    ev.u.mouse.x == co->left + co->width - li->bdxAdjust - 1 &&
+	    ev.u.mouse.y == co->top + co->height - li->bdyAdjust - 1) {
+	    if(li->numItems <= 0) break;
+	    if(li->currItem < li->numItems - 1) {
+		li->currItem++;
+		if(li->currItem > (li->startShowItem + li->curHeight - 1)) {
+		    li->startShowItem = li->currItem - li->curHeight + 1;
+		    if(li->startShowItem + li->curHeight > li->numItems)
+			li->startShowItem = li->numItems - li->curHeight;
+		}
+		if(li->sb)
+		    newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
+		listboxDraw(co);
+	    }
+	    if(co->callback) co->callback(co, co->callbackData);
+	    er.result = ER_SWALLOWED;
+	    break;
+	}
+	if ((ev.u.mouse.y >= co->top + li->bdyAdjust) &&
+	    (ev.u.mouse.y <= co->top + co->height - (li->bdyAdjust * 2)) &&
+	    (ev.u.mouse.x >= co->left + li->bdxAdjust) &&
+	    (ev.u.mouse.x <= co->left + co->width + (li->bdxAdjust * 2))) {
+	    li->currItem = li->startShowItem +
+		(ev.u.mouse.y - li->bdyAdjust - co->top);
+	    newtListboxRealSetCurrent(co);
+	    listboxDraw(co);
+	    if(co->callback) co->callback(co, co->callbackData);
+	    er.result = ER_SWALLOWED;
+	    break;
+	}
+    }
+
+    return er;
+}
+
+static void listboxDestroy(newtComponent co) {
+    struct listbox * li = co->data;
+    struct items * item, * nextitem;
+
+    nextitem = item = li->boxItems;
+
+    while (item != NULL) {
+	nextitem = item->next;
+	free(item->text);
+	free(item);
+	item = nextitem;
+    }
+
+    if (li->sb) li->sb->ops->destroy(li->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 <slang.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/signal.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+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 =
+"  <Tab>/<Alt-Tab> between elements   |  <Space> selects   |  <F12> next screen"
+;
+
+const struct newtColors newtDefaultColorPalette = {
+	  "cyan", "black", 			/* root fg, bg */
+	  "black", "blue",			/* border fg, bg */
+	  "white", "blue",			/* window fg, bg */
+	  "white", "black",			/* shadow fg, bg */
+	  "white", "blue",			/* title fg, bg */
+	  "black", "cyan",			/* button fg, bg */
+	  "yellow", "cyan",			/* active button fg, bg */
+	  "yellow", "blue",			/* checkbox fg, bg */
+	  "blue", "brown",			/* active checkbox fg, bg */
+	  "yellow", "blue",			/* entry box fg, bg */
+	  "white", "blue",			/* label fg, bg */
+	  "black", "cyan",			/* listbox fg, bg */
+	  "yellow", "cyan",			/* active listbox fg, bg */
+	  "white", "blue",			/* textbox fg, bg */
+	  "cyan", "black",			/* active textbox fg, bg */
+	  "white", "blue",			/* help line */
+	  "yellow", "blue",			/* root text */
+	  "blue",					/* scale full */
+	  "red",					/* scale empty */
+	  "blue", "cyan",				/* disabled entry fg, bg */
+	  "white", "blue",			/* compact button fg, bg */
+	  "yellow", "red",			/* active & sel listbox */
+	  "black", "brown"			/* selected listbox */
+};
+
+static const struct keymap keymap[] = {
+	{ "\033OA", 		NEWT_KEY_UP, 		"kh" },
+	{ "\033[A", 		NEWT_KEY_UP, 		"ku" },
+	{ "\033OB", 		NEWT_KEY_DOWN, 		"kd" },
+	{ "\033[B", 		NEWT_KEY_DOWN, 		"kd" },
+	{ "\033[C", 		NEWT_KEY_RIGHT, 	"kr" },
+	{ "\033OC", 		NEWT_KEY_RIGHT, 	"kr" },
+	{ "\033[D", 		NEWT_KEY_LEFT, 		"kl" },
+	{ "\033OD", 		NEWT_KEY_LEFT, 		"kl" },
+	{ "\033[H",		NEWT_KEY_HOME, 		"kh" },
+	{ "\033[1~",		NEWT_KEY_HOME, 		"kh" },
+	{ "\033Ow",		NEWT_KEY_END, 		"kH" },
+	{ "\033[4~",		NEWT_KEY_END, 		"kH" },
+
+	{ "\033[3~",		NEWT_KEY_DELETE,	"kl" },
+	{ "\033[2~", 		NEWT_KEY_INSERT,	NULL },
+
+	{ "\033\t",		NEWT_KEY_UNTAB,		NULL },
+
+	{ "\033[5~",		NEWT_KEY_PGUP,		NULL },
+	{ "\033[6~",		NEWT_KEY_PGDN,		NULL },
+	{ "\033V",		NEWT_KEY_PGUP, 		"kH" },
+	{ "\033v",		NEWT_KEY_PGUP, 		"kH" },
+
+	{ "\033[[A",		NEWT_KEY_F1,		NULL },
+	{ "\033[[B",		NEWT_KEY_F2,		NULL },
+	{ "\033[[C",		NEWT_KEY_F3,		NULL },
+	{ "\033[[D",		NEWT_KEY_F4,		NULL },
+	{ "\033[[E",		NEWT_KEY_F5,		NULL },
+
+	{ "\033OP",		NEWT_KEY_F1,		NULL },
+	{ "\033OQ",		NEWT_KEY_F2,		NULL },
+	{ "\033OR",		NEWT_KEY_F3,		NULL },
+	{ "\033OS",		NEWT_KEY_F4,		NULL },
+
+	{ "\033[11~",		NEWT_KEY_F1,		NULL },
+	{ "\033[12~",		NEWT_KEY_F2,		NULL },
+	{ "\033[13~",		NEWT_KEY_F3,		NULL },
+	{ "\033[14~",		NEWT_KEY_F4,		NULL },
+	{ "\033[15~",		NEWT_KEY_F5,		NULL },
+	{ "\033[17~",		NEWT_KEY_F6,		NULL },
+	{ "\033[18~",		NEWT_KEY_F7,		NULL },
+	{ "\033[19~",		NEWT_KEY_F8,		NULL },
+	{ "\033[20~",		NEWT_KEY_F9,		NULL },
+	{ "\033[21~",		NEWT_KEY_F10,		NULL },
+	{ "\033[23~",		NEWT_KEY_F11,		NULL },
+	{ "\033[24~",		NEWT_KEY_F12,		NULL },
+
+	{ NULL, 	0, 			NULL },	/* LEAVE this one */
+};
+static char keyPrefix = '\033';
+
+static const char * version = "Newt windowing library version " VERSION
+			" - (C) 1996-2000 Red Hat Software. "
+		        "Redistributable under the term of the Library "
+		        "GNU Public License. "
+			"Written by Erik Troan\n";
+
+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("");
+
+    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 = "NEWT_MONO";
+
+    /* 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(&sa, 0, sizeof(sa));
+    sa.sa_handler = handleSigwinch;
+    sigaction(SIGWINCH, &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, "", colors.rootFg, colors.rootBg);
+    SLtt_set_color(NEWT_COLORSET_BORDER, "", colors.borderFg, colors.borderBg);
+    SLtt_set_color(NEWT_COLORSET_WINDOW, "", colors.windowFg, colors.windowBg);
+    SLtt_set_color(NEWT_COLORSET_SHADOW, "", colors.shadowFg, colors.shadowBg);
+    SLtt_set_color(NEWT_COLORSET_TITLE, "", colors.titleFg, colors.titleBg);
+    SLtt_set_color(NEWT_COLORSET_BUTTON, "", colors.buttonFg, colors.buttonBg);
+    SLtt_set_color(NEWT_COLORSET_ACTBUTTON, "", colors.actButtonFg,
+			colors.actButtonBg);
+    SLtt_set_color(NEWT_COLORSET_CHECKBOX, "", colors.checkboxFg,
+			colors.checkboxBg);
+    SLtt_set_color(NEWT_COLORSET_ACTCHECKBOX, "", colors.actCheckboxFg,
+			colors.actCheckboxBg);
+    SLtt_set_color(NEWT_COLORSET_ENTRY, "", colors.entryFg, colors.entryBg);
+    SLtt_set_color(NEWT_COLORSET_LABEL, "", colors.labelFg, colors.labelBg);
+    SLtt_set_color(NEWT_COLORSET_LISTBOX, "", colors.listboxFg,
+			colors.listboxBg);
+    SLtt_set_color(NEWT_COLORSET_ACTLISTBOX, "", colors.actListboxFg,
+			colors.actListboxBg);
+    SLtt_set_color(NEWT_COLORSET_TEXTBOX, "", colors.textboxFg,
+			colors.textboxBg);
+    SLtt_set_color(NEWT_COLORSET_ACTTEXTBOX, "", colors.actTextboxFg,
+			colors.actTextboxBg);
+    SLtt_set_color(NEWT_COLORSET_HELPLINE, "", colors.helpLineFg,
+			colors.helpLineBg);
+    SLtt_set_color(NEWT_COLORSET_ROOTTEXT, "", colors.rootTextFg,
+			colors.rootTextBg);
+
+    SLtt_set_color(NEWT_COLORSET_EMPTYSCALE, "", "black",
+			colors.emptyScale);
+    SLtt_set_color(NEWT_COLORSET_FULLSCALE, "", "black",
+			colors.fullScale);
+    SLtt_set_color(NEWT_COLORSET_DISENTRY, "", colors.disabledEntryFg,
+			colors.disabledEntryBg);
+
+    SLtt_set_color(NEWT_COLORSET_COMPACTBUTTON, "", colors.compactButtonFg,
+			colors.compactButtonBg);
+
+    SLtt_set_color(NEWT_COLORSET_ACTSELLISTBOX, "", colors.actSelListboxFg,
+		   colors.actSelListboxBg);
+    SLtt_set_color(NEWT_COLORSET_SELLISTBOX, "", 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 && 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->code; curr++) {
+	    if (curr->str) {
+		if (!strcmp(curr->str, buf))
+		    return curr->code;
+	    }
+	}
+    }
+
+    for (curr = keymap; curr->code; curr++) {
+	if (curr->str) {
+	    if (!strcmp(curr->str, buf))
+		return curr->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 > 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->left = left;
+    currentWindow->top = top;
+    currentWindow->width = width;
+    currentWindow->height = height;
+    currentWindow->title = title ? strdup(title) : NULL;
+
+    currentWindow->buffer = malloc(sizeof(short) * (width + 3) * (height + 3));
+
+    row = top - 1;
+    col = left - 1;
+    n = 0;
+    for (j = 0; j < height + 3; j++, row++) {
+	SLsmg_gotorc(row, col);
+	SLsmg_read_raw((SLsmg_Char_Type *)currentWindow->buffer + n,
+				currentWindow->width + 3);
+	n += currentWindow->width + 3;
+    }
+
+    SLsmg_set_color(NEWT_COLORSET_BORDER);
+    SLsmg_draw_box(top - 1, left - 1, height + 2, width + 2);
+
+    if (currentWindow->title) {
+	i = strlen(currentWindow->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->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 < (top + height + 1); i++) {
+	SLsmg_gotorc(i, left + width + 1);
+	SLsmg_write_string(" ");
+    }
+
+    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) && (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->top - 1;
+    col = currentWindow->left - 1;
+    for (j = 0; j < currentWindow->height + 3; j++, row++) {
+	SLsmg_gotorc(row, col);
+	SLsmg_write_raw((SLsmg_Char_Type *)currentWindow->buffer + n,
+				currentWindow->width + 3);
+	n += currentWindow->width + 3;
+    }
+
+    free(currentWindow->buffer);
+    free(currentWindow->title);
+
+    if (currentWindow == windowStack)
+	currentWindow = NULL;
+    else
+	currentWindow--;
+
+    SLsmg_set_char_set(0);
+
+    newtRefresh();
+}
+
+void newtGetWindowPos(int * x, int * y) {
+    if (currentWindow) {
+	*x = currentWindow->left;
+	*y = currentWindow->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->top;
+	newCol += currentWindow->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->top;
+	left += currentWindow->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->top;
+	left += currentWindow->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->code; curr++) {
+	if (!curr->str)
+	    curr->str = SLtt_tgetstr(curr->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(&set);
+
+    tv.tv_sec = usecs / 1000000;
+    tv.tv_usec = usecs % 1000000;
+
+    select(0, &set, &set, &set, &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 < 0) {
+	col = SLtt_Screen_Cols + col;
+    }
+
+    if (row < 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 & (~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->left = newLeft;
+    c->top = newTop;
+}
+
+void newtDefaultMappedHandler(newtComponent c, int isMapped) {
+    c->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 "C" {
+#endif
+
+#include <stdarg.h>
+
+#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 << 0)
+#define NEWT_FLAG_HIDDEN 	(1 << 1)
+#define NEWT_FLAG_SCROLL 	(1 << 2)
+#define NEWT_FLAG_DISABLED 	(1 << 3)
+/* OBSOLETE #define NEWT_FLAG_NOSCROLL 	(1 << 4)	for listboxes */
+#define NEWT_FLAG_BORDER	(1 << 5)
+#define NEWT_FLAG_WRAP		(1 << 6)
+#define NEWT_FLAG_NOF12		(1 << 7)
+#define NEWT_FLAG_MULTIPLE      (1 << 8)
+#define NEWT_FLAG_SELECTED	(1 << 9)
+#define NEWT_FLAG_CHECKBOX	(1 << 10)
+#define NEWT_FLAG_PASSWORD      (1 << 11)  /* draw '*'  of chars in entrybox */
+#define NEWT_FD_READ		(1 << 0)
+#define NEWT_FD_WRITE		(1 << 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 << 0)
+#define NEWT_ANCHOR_RIGHT		(1 << 1)
+#define NEWT_ANCHOR_TOP			(1 << 2)
+#define NEWT_ANCHOR_BOTTOM		(1 << 3)
+
+#define NEWT_GRID_FLAG_GROWX		(1 << 0)
+#define NEWT_GRID_FLAG_GROWY		(1 << 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 "C" { */
+#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 <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+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->data = sc;
+
+    co->ops = &scaleOps;
+
+    co->height = 1;
+    co->width = width;
+    co->top = top;
+    co->left = left;
+    co->takesFocus = 0;
+
+    sc->fullValue = fullValue;
+    sc->charsSet = 0;
+
+    return co;
+}
+
+void newtScaleSet(newtComponent co, unsigned int amount) {
+    struct scale * sc = co->data;
+    int newCharsSet;
+
+    newCharsSet = (amount * co->width) / sc->fullValue;
+    
+    if (newCharsSet != sc->charsSet) {
+	sc->charsSet = newCharsSet;
+	scaleDraw(co);
+    }
+}
+
+static void scaleDraw(newtComponent co) {
+    struct scale * sc = co->data;
+    int i;
+
+    if (co->top == -1) return;
+
+    newtGotorc(co->top, co->left);
+
+    SLsmg_set_color(NEWT_COLORSET_FULLSCALE);
+    for (i = 0; i < sc->charsSet; i++)
+	SLsmg_write_string(" ");
+
+    SLsmg_set_color(NEWT_COLORSET_EMPTYSCALE);
+    for (i = 0; i < (co->width - sc->charsSet); i++)
+	SLsmg_write_string(" ");
+}


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 <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+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->data;
+    int new;
+
+    if (sb->arrows)
+	new = (where * (co->height - 3)) / (total ? total : 1) + 1;
+    else
+	new = (where * (co->height - 1)) / (total ? total : 1);
+    if (new != sb->curr) {
+	sbDrawThumb(co, 0);
+	sb->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->data = sb;
+
+    if (!strcmp(getenv("TERM"), "linux") && height >= 2) {
+	sb->arrows = 1;
+	sb->curr = 1;
+    } else {
+	sb->arrows = 0;
+	sb->curr = 0;
+    }
+    sb->cs = normalColorset;
+    sb->csThumb = thumbColorset;
+
+    co->ops = &sbOps;
+    co->isMapped = 0;
+    co->left = left;
+    co->top = top;
+    co->height = height;
+    co->width = 1;
+    co->takesFocus = 0;  
+    
+    return co;
+}
+
+static void sbDraw(newtComponent co) {
+    struct scrollbar * sb = co->data;
+    int i;
+
+    if (!co->isMapped) return;
+
+    SLsmg_set_color(sb->cs);
+
+    SLsmg_set_char_set(1);
+    if (sb->arrows) {
+	newtGotorc(co->top, co->left);
+ 	SLsmg_write_char('\x2d');
+	for (i = 1; i < co->height - 1; i++) {
+	    newtGotorc(i + co->top, co->left);
+	    SLsmg_write_char('\x61');
+	}
+	newtGotorc(co->top + co->height - 1, co->left);
+ 	SLsmg_write_char('\x2e');
+    } else {
+	for (i = 0; i < co->height; i++) {
+	    newtGotorc(i + co->top, co->left);
+	    SLsmg_write_char('\x61');
+	}
+    }
+
+    SLsmg_set_char_set(0);
+
+    sbDrawThumb(co, 1);
+}
+
+static void sbDrawThumb(newtComponent co, int isOn) {
+    struct scrollbar * sb = co->data;
+    char ch = isOn ? '#' : '\x61';
+
+    if (!co->isMapped) return;
+
+    newtGotorc(sb->curr + co->top, co->left);
+    SLsmg_set_char_set(1);
+
+    /*if (isOn)
+	SLsmg_set_color(sb->csThumb);
+    else*/
+	SLsmg_set_color(sb->cs);
+
+    SLsmg_write_char(ch);
+    SLsmg_set_char_set(0);
+}
+
+static void sbDestroy(newtComponent co) {
+    struct scrollbar * sb = co->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 <ctype.h>
+#include <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+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->data;
+
+    co->isMapped = isMapped;
+    if (tb->sb)
+	tb->sb->ops->mapped(tb->sb, isMapped);
+}
+
+static void textboxPlace(newtComponent co, int newLeft, int newTop) {
+    struct textbox * tb = co->data;
+
+    co->top = newTop;
+    co->left = newLeft;
+
+    if (tb->sb)
+	tb->sb->ops->place(tb->sb, co->left + co->width - 1, co->top);
+}
+
+void newtTextboxSetHeight(newtComponent co, int height) {
+    co->height = height;
+}
+
+int newtTextboxGetNumLines(newtComponent co) {
+    struct textbox * tb = co->data;
+
+    return (tb->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,
+				  &actWidth, &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->data = tb;
+
+    co->ops = &textboxOps;
+
+    co->height = height;
+    co->top = top;
+    co->left = left;
+    co->takesFocus = 0;
+    co->width = width;
+
+    tb->doWrap = flags & NEWT_FLAG_WRAP;
+    tb->numLines = 0;
+    tb->linesAlloced = 0;
+    tb->lines = NULL;
+    tb->topLine = 0;
+    tb->textWidth = width;
+
+    if (flags & NEWT_FLAG_SCROLL) {
+	co->width += 2;
+	tb->sb = newtVerticalScrollbar(co->left + co->width - 1, co->top, 
+			   co->height, COLORSET_TEXTBOX, COLORSET_TEXTBOX);
+    } else {
+	tb->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) > bufAlloced) {
+	    bufAlloced += strlen(text) / 2;
+	    buf = realloc(buf, bufAlloced + 1);
+	    dest = buf + bufUsed;
+	}
+	if (*src == '\t') {
+	    i = 8 - (linePos & 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 <= (unsigned char)(c&0xff) && (unsigned char)(c&0xff) <= 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 && text < end) {
+	    if (end - text < width) {
+		if (result) {
+		    strncat(result, text, end - text);
+		    strcat(result, "\n");
+		    height++;
+		}
+
+		if (end - text < (width / 2))
+		    howbad += ((width / 2) - (end - text)) / 2;
+		text = end;
+		if (*text) text++;
+	    } else {
+	        chptr = text;
+	        kanji = 0;
+	        for ( i = 0; i < width - 1; i++ ) {
+		    if ( !iseuckanji(*chptr)) {
+			kanji = 0;
+		    } else if ( kanji == 1 ) {
+		        kanji = 2; 
+		    } else {
+		        kanji = 1;
+		    }
+		    chptr++;
+		}
+	        if (kanji == 0) {
+		    while (chptr > text && !isspace(*chptr)) chptr--;
+		    while (chptr > text && isspace(*chptr)) chptr--;
+		    chptr++;
+		}
+		
+		if (chptr-text == 1 && !isspace(*chptr))
+		  chptr = text + width - 1;
+
+		if (chptr > 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, "\n");
+		    height++;
+		}
+
+	        if (isspace(*chptr))
+		    text = chptr + 1;
+		else
+		  text = chptr;
+		while (isspace(*text)) text++;
+	    }
+	}
+    }
+
+//    if (result) printf("result: %s\n", 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 <= max; i++) {
+	    doReflow(expandedText, NULL, i, &howbad, NULL);
+
+	    if (minbad == -1 || howbad < minbad) {
+		minbad = howbad;
+		minbadwidth = i;
+	    }
+ 	}
+
+	width = minbadwidth;
+    }
+
+    doReflow(expandedText, &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->data;
+    char * reflowed, * expanded;
+    int badness, height;
+
+    if (tb->lines) {
+	free(tb->lines);
+	tb->linesAlloced = tb->numLines = 0;
+    }
+
+    expanded = expandTabs(text);
+
+    if (tb->doWrap) {
+	doReflow(expanded, &reflowed, tb->textWidth, &badness, &height);
+	free(expanded);
+	expanded = reflowed;
+    }
+
+    for (start = expanded; *start; start++)
+	if (*start == '\n') tb->linesAlloced++;
+
+    /* This ++ leaves room for an ending line w/o a \n */
+    tb->linesAlloced++;
+    tb->lines = malloc(sizeof(char *) * tb->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->data;
+
+    if (len > tb->textWidth) len = tb->textWidth;
+
+    tb->lines[tb->numLines] = malloc(tb->textWidth + 1);
+    memset(tb->lines[tb->numLines], ' ', tb->textWidth); 
+    memcpy(tb->lines[tb->numLines], s, len);
+    tb->lines[tb->numLines++][tb->textWidth] = '\0';
+}
+
+static void textboxDraw(newtComponent c) {
+    int i;
+    struct textbox * tb = c->data;
+    int size;
+
+    if (tb->sb) {
+	size = tb->numLines - c->height;
+	newtScrollbarSet(tb->sb, tb->topLine, size ? size : 0);
+	tb->sb->ops->draw(tb->sb);
+    }
+
+    SLsmg_set_color(NEWT_COLORSET_TEXTBOX);
+   
+    for (i = 0; (i + tb->topLine) < tb->numLines && i < c->height; i++) {
+	newtGotorc(c->top + i, c->left);
+	SLsmg_write_string(tb->lines[i + tb->topLine]);
+    }
+}
+
+static struct eventResult textboxEvent(newtComponent co, 
+				      struct event ev) {
+    struct textbox * tb = co->data;
+    struct eventResult er;
+
+    er.result = ER_IGNORED;
+
+    if (ev.when == EV_EARLY && ev.event == EV_KEYPRESS && tb->sb) {
+	switch (ev.u.key) {
+	  case NEWT_KEY_UP:
+	    if (tb->topLine) tb->topLine--;
+	    textboxDraw(co);
+	    er.result = ER_SWALLOWED;
+	    break;
+
+	  case NEWT_KEY_DOWN:
+	    if (tb->topLine < (tb->numLines - co->height)) tb->topLine++;
+	    textboxDraw(co);
+	    er.result = ER_SWALLOWED;
+	    break;
+
+	  case NEWT_KEY_PGDN:
+	    tb->topLine += co->height;
+	    if (tb->topLine > (tb->numLines - co->height)) {
+		tb->topLine = tb->numLines - co->height;
+		if (tb->topLine < 0) tb->topLine = 0;
+	    }
+	    textboxDraw(co);
+	    er.result = ER_SWALLOWED;
+	    break;
+
+	  case NEWT_KEY_PGUP:
+	    tb->topLine -= co->height;
+	    if (tb->topLine < 0) tb->topLine = 0;
+	    textboxDraw(co);
+	    er.result = ER_SWALLOWED;
+	    break;
+	}
+    }
+    if (ev.when == EV_EARLY && ev.event == EV_MOUSE && tb->sb) {
+	/* Top scroll arrow */
+	if (ev.u.mouse.x == co->width && ev.u.mouse.y == co->top) {
+	    if (tb->topLine) tb->topLine--;
+	    textboxDraw(co);
+	    
+	    er.result = ER_SWALLOWED;
+	}
+	/* Bottom scroll arrow */
+	if (ev.u.mouse.x == co->width &&
+	    ev.u.mouse.y == co->top + co->height - 1) {
+	    if (tb->topLine < (tb->numLines - co->height)) tb->topLine++;
+	    textboxDraw(co);
+	    
+	    er.result = ER_SWALLOWED;
+	}
+    }
+    return er;
+}
+
+static void textboxDestroy(newtComponent co) {
+    int i;
+    struct textbox * tb = co->data;
+
+    for (i = 0; i < tb->numLines; i++) 
+	free(tb->lines[i]);
+    free(tb->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 <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "errno.h"
+#include "newt.h"
+
+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 >= size || i == -1);
+
+    flowedText = newtReflowText(buf, 50, 5, 5, &width, &height);
+    if (height > 6) {
+	free(flowedText);
+	flowedText = newtReflowText(buf, 60, 5, 5, &width, &height);
+    }
+    free(buf);
+
+    if (height > 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, &b1, button2, &b2, 
+				   button3, &b3, NULL);
+    } else if (button2) {
+	buttonGrid = newtButtonBar(button1, &b1, button2, &b2, NULL);
+    } else {
+	buttonGrid = newtButtonBar(button1, &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 < maxListHeight) maxListHeight = i;
+    needScroll = i > 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 < 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] && rc < 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 < 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 < 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 < numItems; rc++)
+	*items[rc].value = strdup(*items[rc].value);
+
+    for (rc = 0; result != buttons[rc] && rc < 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 (gc at mandriva.com)
+ *
+ * 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 (ewt at redhat.com)
+ *
+ * Copyright 1996 Red Hat Software 
+ *
+ */
+
+
+/*
+ * Each different frontend must implement all functions defined in frontend.h
+ */
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <sys/time.h>
+#include "newt/newt.h"
+
+#include <probing.h>
+
+#include "frontend.h"
+
+void init_frontend(char * welcome_msg)
+{
+	int i;
+	for (i=0; i<38; i++) printf("\n");
+	newtInit();
+	newtCls();
+
+	if (welcome_msg[0]) {
+		char *msg;
+		int cols, rows;
+		newtGetScreenSize(&cols, &rows);
+		asprintf(&msg, " %-*s", cols - 1, welcome_msg);
+		newtDrawRootText(0, 0, msg);
+		free(msg);
+		newtPushHelpLine(" <Alt-F1> for here, <Alt-F3> to see the logs, <Alt-F4> for kernel msg");
+	}
+	newtRefresh();
+}
+
+
+void finish_frontend(void)
+{
+	newtFinished();
+}
+
+
+void verror_message(char *msg, va_list ap)
+{
+	newtWinMessagev("Error", "Ok", msg, ap);
+}
+
+void vinfo_message(char *msg, va_list ap)
+{
+	newtWinMessagev("Notice", "Ok", msg, ap);
+}
+
+
+void vwait_message(char *msg, va_list ap)
+{
+	int width, height;
+	char * title = "Please wait...";
+	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 >= size || i == -1);
+
+	flowed = newtReflowText(buf, 60, 5, 5, &width, &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, "Please wait...");
+		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 <= size_progress)
+			newtScaleSet(scale, current_size);
+		newtRefresh();
+	}
+	else {
+		struct timeval t;
+		int time;
+		static int last_time = -1;
+		gettimeofday(&t, NULL);
+		time = t.tv_sec*3 + t.tv_usec/300000;
+		if (time != last_time) {
+			char msg_prog_final[500];
+			sprintf(msg_prog_final, "%s (%d bytes read) ", 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 && *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], " (");
+			    strcat(items[i], *elems_comments);
+			    strcat(items[i], ")");
+		    }
+		    elems_comments++;
+		    i++;
+		    elems++;
+	    }
+	    items[i] = NULL;
+	}
+
+	rc = newtWinMenu("Please choose...", msg, 52, 5, 5, 7, elems_comments ? items : elems, answer, "Ok", "Cancel", NULL);
+
+	if (rc == 2)
+		return RETURN_BACK;
+
+	return RETURN_OK;
+}
+
+enum return_type ask_yes_no(char *msg)
+{
+	int rc;
+
+	rc = newtWinTernary("Please answer...", "Yes", "No", "Back", 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 && *entries) {
+		*ptr = newtEntryGetValue(*entries);
+		entries++;
+		ptr++;
+	}
+
+	callback_real_function(strings);
+
+	ptr = strings;
+	entries = data;
+	while (entries && *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 < 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 < 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 < numItems; rc++)
+		*items[rc].value = strdup(*items[rc].value);
+	
+	for (rc = 0; result != buttons[rc] && rc < 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 && *questions) {
+		entries[i].text = *questions;
+		entries[i].flags = NEWT_FLAG_SCROLL | (!strcmp(*questions, "Password") ? 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 < i ; j++) {
+		entries[j].value = &((*answers)[j]);
+		if (already_answers && *already_answers) {
+			*(entries[j].value) = *already_answers;
+			already_answers++;
+		} else
+			*(entries[j].value) = NULL;
+	}
+
+	rc = mynewtWinEntries("Please fill in entries...", msg, 52, 5, 5, entry_size, callback_func, entries, "Ok", "Cancel", 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 (gc at mandriva.com)
+ *
+ * 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 <jrs at world.std.com>
+ *
+ * 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, biro at yggdrasil.com (Ross Biro): allow all port
+ * numbers to be specified on the command line.
+ *
+ * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen at uni-paderborn.de>:
+ * Omit the call to connect() for Linux version 1.3.11 or later.
+ *
+ * Wed Oct  1 23:55:28 1997: Dick Streefland <dick_streefland at tasking.com>
+ * Implemented the "bg", "fg" and "retry" mount options for NFS.
+ *
+ * 1999-02-22 Arkadiusz Miśkiewicz <misiek at pld.ORG.PL>
+ * - added Native Language Support
+ * 
+ * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
+ * plus NFSv3 stuff.
+ *
+ * 2003-04-14 David Black <david.black at xilinx.com>
+ * - 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 <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <netdb.h>
+#include <time.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_clnt.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/utsname.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <values.h>
+
+#include "nfsmount.h"
+
+#ifdef HAVE_rpcsvc_nfs_prot_h
+#include <rpcsvc/nfs_prot.h>
+#else
+#include <linux/nfs.h>
+#define nfsstat nfs_stat
+#endif
+
+#include "nfs_mount4.h"
+
+#include "log.h"
+#include "dns.h"
+
+#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 >= 4) ? 3 : 2)
+
+bool_t
+xdr_fhandle3 (XDR *xdrs, fhandle3 *objp)
+{
+	 if (!xdr_bytes (xdrs, (char **)&objp->fhandle3_val, (u_int *) &objp->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, &objp->fhandle))
+		 return FALSE;
+	 if (!xdr_array (xdrs, (char **)&objp->auth_flavours.auth_flavours_val, (u_int *) &objp->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, &objp->fhs_status))
+		 return FALSE;
+	switch (objp->fhs_status) {
+	case MNT_OK:
+		 if (!xdr_mountres3_ok (xdrs, &objp->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, &objp->fhs_status))
+		 return FALSE;
+	switch (objp->fhs_status) {
+	case 0:
+		 if (!xdr_fhandle (xdrs, objp->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(&my_utsname) == 0) {
+		p = atoi(strtok(my_utsname.release, "."));
+		q = atoi(strtok(NULL, "."));
+		r = atoi(strtok(NULL, "."));
+		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 < MAKE_VERSION(2,1,32))
+		  nfs_mount_version = 1;
+	     else if (kernel_version < MAKE_VERSION(2,2,18))
+		  nfs_mount_version = 3;
+	     else if (kernel_version < MAKE_VERSION(2,3,0))
+		  nfs_mount_version = 4; /* since 2.2.18pre9 */
+	     else if (kernel_version < MAKE_VERSION(2,3,99))
+		  nfs_mount_version = 3;
+	     else
+		  nfs_mount_version = 4; /* since 2.3.99pre4 */
+	}
+	if (nfs_mount_version > NFS_MOUNT_VERSION)
+	     nfs_mount_version = NFS_MOUNT_VERSION;
+        log_message("nfsmount: kernel_nfs_mount_version: %d", 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 > 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->sin_port = PMAPPORT;
+	pmap = pmap_getmaps(server_addr);
+
+	while (pmap) {
+		if (pmap->pml_map.pm_prog != prog)
+			goto next;
+		if (!version && p.pm_vers > pmap->pml_map.pm_vers)
+			goto next;
+		if (version > 2 && pmap->pml_map.pm_vers != version)
+			goto next;
+		if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
+			goto next;
+		if (pmap->pml_map.pm_vers > MAX_NFSPROT ||
+		    (proto && p.pm_prot && pmap->pml_map.pm_prot != proto) ||
+		    (port && pmap->pml_map.pm_port != port))
+			goto next;
+		memcpy(&p, &pmap->pml_map, sizeof(p));
+	next:
+		pmap = pmap->pml_next;
+	}
+	if (!p.pm_vers)
+		p.pm_vers = MOUNTVERS;
+	if (!p.pm_prot)
+		p.pm_prot = IPPROTO_TCP;
+	return &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) >= sizeof(hostdir)) {
+		log_message("nfsmount: excessively long host:dir argument");
+		goto fail;
+	}
+	strcpy(hostdir, spec);
+	if ((s = strchr(hostdir, ':'))) {
+		hostname = hostdir;
+		dirname = s + 1;
+		*s = '\0';
+	} else {
+		log_message("nfsmount: directory to mount not in host:dir format");
+		goto fail;
+	}
+
+	server_addr.sin_family = AF_INET;
+#ifdef HAVE_inet_aton
+	if (!inet_aton(hostname, &server_addr.sin_addr))
+#endif
+	{
+		if (mygethostbyname(hostname, &server_addr.sin_addr)) {
+			log_message("nfsmount: can't get address for %s", hostname);
+			goto fail;
+		}
+	}
+
+	memcpy (&mount_server_addr, &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(&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 >= 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 >= 2
+	if (nfs_mount_version >= 2)
+		data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
+#endif
+#if NFS_MOUNT_VERSION >= 3
+	if (nfs_mount_version >= 3)
+		data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
+#endif
+#if NFS_MOUNT_VERSION >= 4
+	if (nfs_mount_version >= 4)
+		data.flags |= (broken_suid ? NFS_MOUNT_BROKEN_SUID : 0);
+#endif
+	if (nfsvers > MAX_NFSPROT) {
+		log_message("NFSv%d not supported!", nfsvers);
+		return 0;
+	}
+	if (mountvers > MAX_NFSPROT) {
+		log_message("NFSv%d not supported!", nfsvers);
+		return 0;
+	}
+	if (nfsvers && !mountvers)
+		mountvers = (nfsvers < 3) ? 1 : nfsvers;
+	if (nfsvers && nfsvers < mountvers)
+		mountvers = nfsvers;
+
+	/* Adjust options if none specified */
+	if (!data.timeo)
+		data.timeo = tcp ? 70 : 7;
+
+#ifdef NFS_MOUNT_DEBUG
+	log_message("rsize = %d, wsize = %d, timeo = %d, retrans = %d",
+	       data.rsize, data.wsize, data.timeo, data.retrans);
+	log_message("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)",
+	       data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
+	log_message("port = %d, retry = %d, flags = %.8x",
+	       port, retry, data.flags);
+	log_message("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d",
+	       mountprog, mountvers, nfsprog, nfsvers);
+	log_message("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d",
+	       (data.flags & NFS_MOUNT_SOFT) != 0,
+	       (data.flags & NFS_MOUNT_INTR) != 0,
+	       (data.flags & NFS_MOUNT_POSIX) != 0,
+	       (data.flags & NFS_MOUNT_NOCTO) != 0,
+	       (data.flags & NFS_MOUNT_NOAC) != 0);
+#if NFS_MOUNT_VERSION >= 2
+	log_message("tcp = %d",
+	       (data.flags & NFS_MOUNT_TCP) != 0);
+#endif
+#endif
+
+	data.version = nfs_mount_version;
+	*mount_opts = (char *) &data;
+
+
+	/* create mount deamon client */
+	/* See if the nfs host = mount host. */
+	if (mounthost) {
+		if (mounthost[0] >= '0' && mounthost[0] <= '9') {
+			mount_server_addr.sin_family = AF_INET;
+			mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
+		} else {
+                        if (mygethostbyname(mounthost, &mount_server_addr.sin_addr)) {
+				log_message("nfsmount: can't get address for %s", mounthost);
+				goto fail;
+			}
+		}
+	}
+
+	/*
+	 * The following loop implements the mount retries. On the first
+	 * call, "running_bg" is 0. When the mount times out, and the
+	 * "bg" 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 "running_bg" set to 1.
+	 *
+	 * The case where the mount point is not present and the "bg"
+	 * option is set, is treated as a timeout. This is done to
+	 * support nested mounts.
+	 *
+	 * The "retry" 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 < 30)
+				sleep(30);
+
+			pm_mnt = get_mountport(&mount_server_addr,
+					       mountprog,
+					       mountvers,
+					       proto,
+					       mountport,
+					       nfs_mount_version);
+
+			/* contact the mount daemon via TCP */
+			mount_server_addr.sin_port = htons(pm_mnt->pm_port);
+			msock = RPC_ANYSOCK;
+
+			switch (pm_mnt->pm_prot) {
+			case IPPROTO_UDP:
+				mclient = clntudp_create(&mount_server_addr,
+							 pm_mnt->pm_prog,
+							 pm_mnt->pm_vers,
+							 retry_timeout,
+							 &msock);
+				if (mclient)
+					break;
+				mount_server_addr.sin_port =
+					htons(pm_mnt->pm_port);
+				msock = RPC_ANYSOCK;
+			case IPPROTO_TCP:
+				mclient = clnttcp_create(&mount_server_addr,
+							 pm_mnt->pm_prog,
+							 pm_mnt->pm_vers,
+							 &msock, 0, 0);
+				break;
+			default:
+				mclient = 0;
+			}
+
+			if (mclient) {
+				/* try to mount hostname:dirname */
+				mclient->cl_auth = authunix_create_default();
+
+				/* make pointers in xdr_mountres3 NULL so
+				 * that xdr_array allocates memory for us
+				 */
+				memset(&status, 0, sizeof(status));
+
+				log_message("nfsmount: doing client call in nfs version: %ld", pm_mnt->pm_vers);
+				if (pm_mnt->pm_vers == 3)
+					clnt_stat = clnt_call(mclient,
+						     MOUNTPROC3_MNT,
+						     (xdrproc_t) xdr_dirpath,
+						     (caddr_t) &dirname,
+						     (xdrproc_t) xdr_mountres3,
+						     (caddr_t) &status,
+						     total_timeout);
+				else
+					clnt_stat = clnt_call(mclient,
+						     MOUNTPROC_MNT,
+						     (xdrproc_t) xdr_dirpath,
+						     (caddr_t) &dirname,
+						     (xdrproc_t) xdr_fhstatus,
+						     (caddr_t) &status,
+						     total_timeout);
+
+				if (clnt_stat == RPC_SUCCESS)
+                                        goto succeeded;
+
+                                if (prevt == 0)
+                                        log_message("could not call server: probably protocol or version error");
+                                auth_destroy(mclient->cl_auth);
+                                clnt_destroy(mclient);
+                                mclient = 0;
+                                close(msock);
+			} else {
+                                log_message("could not create rpc client: host probably not found or NFS server is down");
+			}
+			prevt = t;
+
+		        goto fail;
+
+ succeeded:
+	nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers;
+
+	if (nfsvers == 2) {
+		if (status.nfsv2.fhs_status != 0) {
+			log_message("nfsmount: %s:%s failed, reason given by server: %s",
+                                    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 >= 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 >= 4
+		fhandle3 *fhandle;
+		if (status.nfsv3.fhs_status != 0) {
+			log_message("nfsmount: %s:%s failed, reason given by server: %s",
+                                    hostname, dirname, nfs_strerror(status.nfsv3.fhs_status));
+			goto fail;
+		}
+		fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
+		memset(data.old_root.data, 0, NFS_FHSIZE);
+		memset(&data.root, 0, sizeof(data.root));
+		data.root.size = fhandle->fhandle3_len;
+		memcpy(data.root.data,
+		       (char *) fhandle->fhandle3_val,
+		       fhandle->fhandle3_len);
+
+		data.flags |= NFS_MOUNT_VER3;
+#endif
+	}
+
+	/* create nfs socket for kernel */
+
+	if (tcp) {
+		if (nfs_mount_version < 3) {
+	     		log_message("NFS over TCP is not supported.");
+			goto fail;
+		}
+		fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+	} else
+		fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+	if (fsock < 0) {
+		log_perror("nfs socket");
+		goto fail;
+	}
+	if (bindresvport(fsock, 0) < 0) {
+		log_perror("nfs bindresvport");
+		goto fail;
+	}
+	if (port == 0) {
+		server_addr.sin_port = PMAPPORT;
+		port = pmap_getport(&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 && tcp == 1) {
+			log_message("NFS server reported TCP not available, retrying with UDP...");
+			tcp = 0;
+			goto retry_mount;
+		}
+#endif
+
+		if (port == 0)
+			port = NFS_PORT;
+#ifdef NFS_MOUNT_DEBUG
+		else
+			log_message("used portmapper to find NFS port");
+#endif
+	}
+#ifdef NFS_MOUNT_DEBUG
+	log_message("using port %d for nfs deamon", 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() <= 66314
+	    && connect(fsock, (struct sockaddr *) &server_addr,
+		       sizeof (server_addr)) < 0) {
+		log_perror("nfs connect");
+		goto fail;
+	}
+
+	/* prepare data structure for kernel */
+
+	data.fd = fsock;
+	memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
+	strncpy(data.hostname, hostname, sizeof(data.hostname));
+
+	/* clean up */
+
+	auth_destroy(mclient->cl_auth);
+	clnt_destroy(mclient);
+	close(msock);
+	return 0;
+
+	/* abort */
+
+ fail:
+	if (msock != -1) {
+		if (mclient) {
+			auth_destroy(mclient->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 <schwab at LS5.informatik.uni-dortmund.de>: change errno:
+ * "after #include <errno.h> the symbol errno is reserved for any use,
+ *  it cannot even be used as a struct tag or field name".
+ */
+
+#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, "unknown nfs status return value: %d", 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 <rpc/rpc.h>
+
+int nfsmount_prepare(const char *spec, char **mount_opts);
+
+
+#ifdef __cplusplus
+extern "C" {
+#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 <asm/types.h>
+#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&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&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&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&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&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&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&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&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 (gc at mandriva.com)
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "params.h"
+#include "utils.h"
+#include "automatic.h"
+#include "log.h"
+#include "bootsplash.h"
+
+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("TESTING: opening cmdline... ");
+
+		if ((fd = open("cmdline", O_RDONLY)) == -1)
+			log_message("TESTING: could not open cmdline");
+	}
+
+	if (fd == -1) {
+		log_message("opening /proc/cmdline... ");
+
+		if ((fd = open("/proc/cmdline", O_RDONLY)) == -1)
+			fatal_error("could not open /proc/cmdline");
+	}
+
+	size = read(fd, buf, sizeof(buf));
+	buf[size-1] = '\0'; // -1 to eat the \n
+	close(fd);
+
+	log_message("\t%s", buf);
+
+	i = 0;
+	while (buf[i] != '\0') {
+		char *name, *value = NULL;
+		int j = i;
+		while (buf[i] != ' ' && buf[i] != '=' && buf[i] != '\0')
+			i++;
+		if (i == j) {
+			i++;
+			continue;
+		}
+		name = memdup(&buf[j], i-j + 1);
+		name[i-j] = '\0';
+
+		if (buf[i] == '=') {
+			int k = i+1;
+			i++;
+			while (buf[i] != ' ' && buf[i] != '\0')
+				i++;
+			value = memdup(&buf[k], i-k + 1);
+			value[i-k] = '\0';
+		}
+
+		params[param_number].name = name;
+		params[param_number].value = value;
+		param_number++;
+		if (!strcmp(name, "changedisk")) set_param(MODE_CHANGEDISK);
+		if (!strcmp(name, "updatemodules") ||
+		    !strcmp(name, "thirdparty")) set_param(MODE_THIRDPARTY);
+		if (!strcmp(name, "rescue") ||
+	            !strcmp(name, "kamethod")) set_param(MODE_RESCUE);
+		if (!strcmp(name, "rescue")) set_param(MODE_RESCUE);
+		if (!strcmp(name, "keepmounted")) set_param(MODE_KEEP_MOUNTED);
+		if (!strcmp(name, "noauto")) set_param(MODE_NOAUTO);
+		if (!strcmp(name, "netauto")) set_param(MODE_NETAUTO);
+		if (!strcmp(name, "debugstage1")) set_param(MODE_DEBUGSTAGE1);
+		if (!strcmp(name, "automatic")) {
+			set_param(MODE_AUTOMATIC);
+			grab_automatic_params(value);
+		}
+		if (buf[i] == '\0')
+			break;
+		i++;
+	}
+
+	if (IS_AUTOMATIC && strcmp(get_auto_value("thirdparty"), "")) {
+		set_param(MODE_THIRDPARTY);
+	}
+
+	log_message("\tgot %d args", 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 <= 0) {
+		fd = open(interactive_fifo, O_RDONLY);
+		if (fd == -1)
+			return (stage1_mode & i);
+		fcntl(fd, F_SETFL, O_NONBLOCK);
+	}
+
+	if (fd > 0) {
+		if ((nb = read(fd, buf, sizeof(buf))) > 0) {
+			buf[nb] = '\0';
+			ptr = buf;
+			while ((ptr = strstr(ptr, "+ "))) {
+				if (!strncmp(ptr+2, "rescue", 6)) set_param(MODE_RESCUE);
+				ptr++;
+			}
+			ptr = buf;
+			while ((ptr = strstr(ptr, "- "))) {
+				if (!strncmp(ptr+2, "rescue", 6)) unset_param(MODE_RESCUE);
+				ptr++;
+			}
+		}
+	}
+#endif
+
+	return (stage1_mode & i);
+}
+
+char * get_param_valued(char *param_name)
+{
+	int i;
+	for (i = 0; i < 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 &= ~i;
+}
+
+void unset_automatic(void)
+{
+	log_message("unsetting automatic");
+	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 (gc at mandriva.com)
+ *
+ * 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 (gc at mandriva.com)
+ *
+ * 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 (ewt at redhat.com)
+ *
+ * Copyright 1996 Red Hat Software 
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <libgen.h>
+#include "stage1.h"
+#include "frontend.h"
+#include "modules.h"
+#include "probing.h"
+#include "log.h"
+#include "mount.h"
+#include "automatic.h"
+
+#include "disk.h"
+#include "partition.h"
+
+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("seek failed");
+		return -1;
+	}
+	count = read(fd, buf, strlen(anch.anchor));
+	if (count != strlen(anch.anchor)) {
+		log_perror("read failed");
+		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[] = { 
+		{ "Linux Swap", { 4086, "SWAP-SPACE" }, { 0, NULL }, { 0, NULL } },
+		{ "Linux Swap", { 4086, "SWAPSPACE2" }, { 0, NULL }, { 0, NULL } },
+		{ "Ext2", { 0x438, "\x53\xEF" }, { 0, NULL }, { 0, NULL } },
+		{ "ReiserFS", { 0x10034, "ReIsErFs" }, { 0, NULL }, { 0, NULL } },
+		{ "ReiserFS", { 0x10034, "ReIsEr2Fs" }, { 0, NULL }, { 0, NULL } },
+		{ "XFS", { 0, "XFSB" }, { 0x200, "XAGF" }, { 0x400, "XAGI" } },
+		{ "JFS", { 0x8000, "JFS1" }, { 0, NULL }, { 0, NULL } },
+		{ "NTFS", { 0x1FE, "\x55\xAA" }, { 0x3, "NTFS" }, { 0, NULL } },
+		{ "FAT32", { 0x1FE, "\x55\xAA" }, { 0x52, "FAT32" }, { 0, NULL } },
+		{ "FAT", { 0x1FE, "\x55\xAA" }, { 0x36, "FAT" }, { 0, NULL } },
+		{ "Linux LVM", { 0, "HM\1\0" }, { 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, "/dev/");
+	strcat(device_fullname, dev);
+
+	if (ensure_dev_exists(device_fullname))
+		return NULL;
+	log_message("guessing type of %s", device_fullname);
+
+	if ((fd = open(device_fullname, O_RDONLY, 0)) < 0) {
+		log_perror("open");
+		return NULL;
+	}
+	
+	for (i=0; i<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("/proc/partitions", "rb")) || !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, " %d %d %d %s", &major, &minor, &blocks, name);
+		if ((strstr(name, dev_name) == name) && (blocks > 1) && (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], "size: %d Mbytes", blocks >> 10);
+			if (partition_type) {
+				strcat(comments[i], ", type: ");
+				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 (oblin at mandriva.com)
+ *
+ * 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 (ewt at redhat.com)
+ *
+ * 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 (gc at mandriva.com)
+ #
+ # 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 > $@ || { 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 => 'network/main|gigabit|tokenring|wireless|pcmcia',
+    medias_ide  => 'disk/ide',
+    medias_other => 'disk/scsi|hardware_raid|sata bus/firewire',
+);
+
+foreach my $type (keys %t) {
+    my @modules = chomp_(`perl ../../kernel/modules.pl pci_modules4stage1 "$t{$type}"`)
+	or die "unable to get PCI modules";
+
+    print "#ifndef DISABLE_".uc($type)."
+char* ${type}_pci_modules[] = {
+";
+    printf qq|\t"%s",\n|, $_ foreach @modules;
+    print "};
+unsigned int ${type}_pci_modules_len = sizeof(${type}_pci_modules) / sizeof(char *);
+#endif
+
+";
+}


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 (gc at mandriva.com)
+ #
+ # 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) $<
+	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 $< -o $@
+
+pcmcia_probe.o: probe.c
+	$(DIET) gcc -fPIC $(FLAGS) $(INCLUDES) -c $< -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 "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * 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
+ * <dahinds at users.sourceforge.net>.  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 "GPL"), 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) > 0) && ((n) < 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 "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * 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
+ * <dahinds at users.sourceforge.net>.  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 "GPL"), 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)<<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 > 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 "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * 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
+ * <dahinds at users.sourceforge.net>.  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 "GPL"), 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 "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * 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
+ * <dahinds at users.sourceforge.net>.  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 "GPL"), 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 "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * 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
+ * <dahinds at users.sourceforge.net>.  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 "GPL"), 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 <linux/types.h>
+#else
+#include <sys/types.h>
+#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 "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * 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
+ * <dahinds at users.sourceforge.net>.  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 "GPL"), 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 "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * 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
+ * <dahinds at users.sourceforge.net>.  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 "GPL"), 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 <pcmcia_/driver_ops.h>
+#include <pcmcia_/bulkmem.h>
+
+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) && ((l->state & ~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 "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * 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
+ * <dahinds at users.sourceforge.net>.  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 "GPL"), 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)<<2))
+#define I365_MEM(map)	(0x10+((map)<<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 << (map))
+#define I365_ENA_MEM(map)	(0x01 << (map))
+
+/* Flags for I365_IOCTL */
+#define I365_IOCTL_MASK(map)	(0x0F << (map<<2))
+#define I365_IOCTL_WAIT(map)	(0x08 << (map<<2))
+#define I365_IOCTL_0WS(map)	(0x04 << (map<<2))
+#define I365_IOCTL_IOCS16(map)	(0x02 << (map<<2))
+#define I365_IOCTL_16BIT(map)	(0x01 << (map<<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) << 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 <linux at brodo.de>
+ *
+ *  The initial developer of the original code is David A. Hinds
+ *  <dahinds at users.sourceforge.net>.  Portions created by David A. Hinds
+ *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * License: GPL v2
+ */
+
+#undef src
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <syslog.h>
+
+#ifdef HAS_WORDEXP
+#include <wordexp.h>
+#else
+#include <glob.h>
+#endif
+
+#define src 1
+
+#include "yacc_config.h"
+
+#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	\"([^"]|\\.)*\"
+
+%%
+
+source[ \t]+	BEGIN(src); return SOURCE;
+<src>[^\n]+	do_source(yytext); BEGIN(INITIAL);
+<<EOF>>		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 = &source_stack[source_stack_ptr];
+#ifdef HAS_WORDEXP
+    while (s->fileno < s->word.we_wordc) {
+	char *fn = s->word.we_wordv[s->fileno];
+#else
+    while (s->fileno < s->glob.gl_pathc) {
+	char *fn = s->glob.gl_pathv[s->fileno];
+#endif
+	s->file = fopen(fn, "r");
+	if (s->file == NULL) {
+	    if (strpbrk(fn, "?*[") == NULL)
+		syslog(LOG_ERR, "could not open '%s': %m", fn);
+	    s->fileno++;
+	} else {
+	    current_lineno = 1;
+	    current_file = strdup(fn);
+	    yy_switch_to_buffer(yy_create_buffer(s->file, YY_BUF_SIZE));
+	    source_stack_ptr++;
+	    s->fileno++;
+	    return 0;
+	}
+    }
+    return -1;
+}
+
+static void do_source(char *fn)
+{
+    struct source_stack *s = &source_stack[source_stack_ptr];
+
+    if (source_stack_ptr >= MAX_SOURCE_DEPTH) {
+	syslog(LOG_ERR, "source depth limit exceeded");
+	return;
+    }
+#ifdef HAS_WORDEXP
+    wordexp(fn, &s->word, 0);
+#else
+    glob(fn, GLOB_NOCHECK, NULL, &s->glob);
+#endif
+    s->fileno = 0;
+    s->buffer = YY_CURRENT_BUFFER;
+    s->lineno = current_lineno;
+    s->filename = current_file;
+    get_glob();
+}
+
+static int do_eof(void)
+{
+    struct source_stack *s = &source_stack[--source_stack_ptr];
+    if (source_stack_ptr < 0) {
+	if (parse_env == 0) {
+	    char *t = getenv("PCMCIA_OPTS");
+	    if (t == NULL) return -1;
+	    parse_env = 1;
+	    source_stack_ptr = 0;
+	    current_file = "PCMCIA_OPTS";
+	    current_lineno = 1;
+	    yy_scan_string(t);
+	    return 0;
+	} else
+	    return -1;
+    }
+    fclose(s->file);
+    free(current_file);
+    yy_delete_buffer(YY_CURRENT_BUFFER);
+    if (get_glob() != 0) {
+	yy_switch_to_buffer(s->buffer);
+	current_lineno = s->lineno;
+	current_file = s->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, "r");
+    if (!f) {
+	syslog(LOG_ERR, "could not open '%s': %m", 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*"([^"]*)",\s*"([^"]*)"\s*}/
+	  and $probes{"$1$2"} = { vendor => $1, device => $2, driver => $3, name => $4 };
+    }
+}
+
+require '/usr/bin/merge2pcitable.pl';
+my $drivers = read_pcitable("/usr/share/ldetect-lst/pcitable");
+
+my %pcitable = map_each {
+    $::a =~ /^(....)(....)/ or die;
+    "$1$2" => { vendor => $1, device => $2, driver => $::b->[0], name => $::b->[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 "Missing in `probe.c':\n",
+      map { 
+	  my $p = $pcitable{$_};
+	  qq(    { 0x$p->{vendor}, 0x$p->{device}, "yenta_socket", "$p->{name}" },\n);
+      } sort @missing_in_probe_c;
+}
+
+my @res;
+foreach my $id (keys %probes) {
+    my $p = $probes{$id};
+    my $r = $pcitable{$id};
+    if (!$r || $r->{driver} ne 'yenta_socket') {
+	push @res, qq(0x$p->{vendor}\t0x$p->{device}\t"yenta_socket"\t") . ($r ? $r->{name} : '(COMPLETELY MISSING)') . qq("\n);
+    }
+    if ($r && $r->{driver} ne 'unknown' && $r->{driver} ne $p->{driver}) {
+	warn "WARNING: $id: pcitable:$r->{driver} vs probe.c:$p->{driver}\n";
+    }
+}
+if (@res) {
+    print "\n", "Missing in pcitable:\n", 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 (gc at mandriva.com)
+ *
+ * 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 (gc at mandriva.com)
+ *
+ * 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 /anonymous at projects.sourceforge.net:/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 "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" 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
+    <dahinds at users.sourceforge.net>.  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 "GPL"), 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 <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+//mdk-stage1// #include <pcmcia/config.h>
+#include "log.h"
+#include "pcmcia.h"
+
+/*====================================================================*/
+
+//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, "i82365", "Cirrus Logic CL 6729" },
+    { 0x1013, 0x1110, "yenta_socket", "Cirrus Logic PD 6832" },
+    { 0x10b3, 0xb106, "yenta_socket", "SMC 34C90" },
+    { 0x1180, 0x0465, "yenta_socket", "Ricoh RL5C465" },
+    { 0x1180, 0x0466, "yenta_socket", "Ricoh RL5C466" },
+    { 0x1180, 0x0475, "yenta_socket", "Ricoh RL5C475" },
+    { 0x1180, 0x0476, "yenta_socket", "Ricoh RL5C476" },
+    { 0x1180, 0x0477, "yenta_socket", "Ricoh RL5C477" },
+    { 0x1180, 0x0478, "yenta_socket", "Ricoh RL5C478" },
+    { 0x104c, 0xac12, "yenta_socket", "Texas Instruments PCI1130" }, 
+    { 0x104c, 0xac13, "yenta_socket", "Texas Instruments PCI1031" }, 
+    { 0x104c, 0xac15, "yenta_socket", "Texas Instruments PCI1131" }, 
+    { 0x104c, 0xac1a, "yenta_socket", "Texas Instruments PCI1210" }, 
+    { 0x104c, 0xac1e, "yenta_socket", "Texas Instruments PCI1211" }, 
+    { 0x104c, 0xac17, "yenta_socket", "Texas Instruments PCI1220" }, 
+    { 0x104c, 0xac19, "yenta_socket", "Texas Instruments PCI1221" }, 
+    { 0x104c, 0xac1c, "yenta_socket", "Texas Instruments PCI1225" }, 
+    { 0x104c, 0xac16, "yenta_socket", "Texas Instruments PCI1250" }, 
+    { 0x104c, 0xac1d, "yenta_socket", "Texas Instruments PCI1251A" }, 
+    { 0x104c, 0xac1f, "yenta_socket", "Texas Instruments PCI1251B" }, 
+    { 0x104c, 0xac50, "yenta_socket", "Texas Instruments PCI1410" }, 
+    { 0x104c, 0xac51, "yenta_socket", "Texas Instruments PCI1420" }, 
+    { 0x104c, 0xac1b, "yenta_socket", "Texas Instruments PCI1450" }, 
+    { 0x104c, 0xac52, "yenta_socket", "Texas Instruments PCI1451" }, 
+    { 0x104c, 0xac56, "yenta_socket", "Texas Instruments PCI1510" }, 
+    { 0x104c, 0xac55, "yenta_socket", "Texas Instruments PCI1520" }, 
+    { 0x104c, 0xac54, "yenta_socket", "Texas Instruments PCI1620" }, 
+    { 0x104c, 0xac41, "yenta_socket", "Texas Instruments PCI4410" }, 
+    { 0x104c, 0xac40, "yenta_socket", "Texas Instruments PCI4450" }, 
+    { 0x104c, 0xac42, "yenta_socket", "Texas Instruments PCI4451" }, 
+    { 0x104c, 0xac44, "yenta_socket", "Texas Instruments PCI4510" }, 
+    { 0x104c, 0xac46, "yenta_socket", "Texas Instruments PCI4520" }, 
+    { 0x104c, 0xac49, "yenta_socket", "Texas Instruments PCI7410" }, 
+    { 0x104c, 0xac47, "yenta_socket", "Texas Instruments PCI7510" }, 
+    { 0x104c, 0xac48, "yenta_socket", "Texas Instruments PCI7610" }, 
+    { 0x104c, 0xac8e, "yenta_socket", "Texas Instruments PCI7420" },
+    { 0x1217, 0x6729, "i82365", "O2 Micro 6729" }, 
+    { 0x1217, 0x673a, "i82365", "O2 Micro 6730" }, 
+    { 0x1217, 0x6832, "yenta_socket", "O2 Micro 6832/6833" }, 
+    { 0x1217, 0x6836, "yenta_socket", "O2 Micro 6836/6860" }, 
+    { 0x1217, 0x6872, "yenta_socket", "O2 Micro 6812" }, 
+    { 0x1217, 0x6925, "yenta_socket", "O2 Micro 6922" }, 
+    { 0x1217, 0x6933, "yenta_socket", "O2 Micro 6933" }, 
+    { 0x1217, 0x6972, "yenta_socket", "O2 Micro 6912" }, 
+    { 0x1217, 0x7114, "yenta_socket", "O2 Micro 711M1" },
+    { 0x1179, 0x0603, "i82365", "Toshiba ToPIC95-A" }, 
+    { 0x1179, 0x060a, "yenta_socket", "Toshiba ToPIC95-B" }, 
+    { 0x1179, 0x060f, "yenta_socket", "Toshiba ToPIC97" }, 
+    { 0x1179, 0x0617, "yenta_socket", "Toshiba ToPIC100" }, 
+    { 0x119b, 0x1221, "i82365", "Omega Micro 82C092G" }, 
+    { 0x8086, 0x1221, "i82092", "Intel 82092AA_0" }, 
+    { 0x8086, 0x1222, "i82092", "Intel 82092AA_1" }, 
+    { 0x1524, 0x1211, "yenta_socket", "ENE 1211" },
+    { 0x1524, 0x1225, "yenta_socket", "ENE 1225" },
+    { 0x1524, 0x1410, "yenta_socket", "ENE 1410" },
+    { 0x1524, 0x1411, "yenta_socket", "ENE Technology CB1411" },
+    { 0x1524, 0x1420, "yenta_socket", "ENE 1420" },
+};
+#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("PCMCIA: probing PCI bus..");
+
+    if ((f = fopen("/proc/bus/pci/devices", "r")) != NULL) {
+	while (fgets(s, 256, f) != NULL) {
+	    u_int n = strtoul(s+5, NULL, 16);
+	    vendor = (n >> 16); device = (n & 0xffff);
+	    for (i = 0; i < PCI_COUNT; i++)
+		if ((vendor == pci_id[i].vendor) &&
+		    (device == pci_id[i].device)) break;
+	    if (i < PCI_COUNT) {
+		name = pci_id[i].name;
+		driver = pci_id[i].modname;
+	    }
+	}
+    }
+//mdk-stage1// else if ((f = fopen("/proc/pci", "r")) != NULL) {
+//mdk-stage1// 	while (fgets(s, 256, f) != NULL) {
+//mdk-stage1// 	    t = strstr(s, "Device id=");
+//mdk-stage1// 	    if (t) {
+//mdk-stage1// 		device = strtoul(t+10, NULL, 16);
+//mdk-stage1// 		t = strstr(s, "Vendor id=");
+//mdk-stage1// 		vendor = strtoul(t+10, NULL, 16);
+//mdk-stage1// 		for (i = 0; i < PCI_COUNT; i++)
+//mdk-stage1// 		    if ((vendor == pci_id[i].vendor) &&
+//mdk-stage1// 			(device == pci_id[i].device)) break;
+//mdk-stage1// 	    } else
+//mdk-stage1// 		for (i = 0; i < 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, "CardBus bridge");
+//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("i82365\n");
+//mdk-stage1// 	else
+	    log_message("\t%s found, 2 sockets (driver %s).", name, driver);
+	return 0;
+    } else {
+//mdk-stage1// 	if (!module)
+	    log_message("\tnot found.");
+	return -ENODEV;
+    }
+}
+//mdk-stage1// #endif
+
+/*====================================================================*/
+
+//mdk-stage1// #ifdef CONFIG_ISA
+//mdk-stage1// 
+//mdk-stage1// #ifdef __GLIBC__
+#include <sys/io.h>
+//mdk-stage1// #else
+//mdk-stage1// #include <asm/io.h>
+//mdk-stage1// #endif
+typedef u_short ioaddr_t;
+
+#include "i82365.h"
+#include "cirrus.h"
+#include "vg468.h"
+
+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 &= ~mask;
+    i365_set(sock, reg, d);
+}
+
+int i365_probe(void)
+{
+    int val, sock, done;
+    char *name = "i82365sl";
+
+//mdk-stage1// if (!module)
+    log_message("PCMCIA: probing for Intel PCIC (ISA)..");
+//mdk-stage1//     if (verbose) printf("\n");
+    
+    sock = done = 0;
+    if (ioperm(i365_base, 4, 1)) {
+               log_perror("PCMCIA: ioperm");
+               return -1;
+    }
+    ioperm(0x80, 1, 1);
+    for (; sock < 2; sock++) {
+	val = i365_get(sock, I365_IDENT);
+//mdk-stage1//	if (verbose)
+//mdk-stage1//	    printf("  ident(%d)=%#2.2x", sock, val); 
+	switch (val) {
+	case 0x82:
+	    name = "i82365sl A step";
+	    break;
+	case 0x83:
+	    name = "i82365sl B step";
+	    break;
+	case 0x84:
+	    name = "VLSI 82C146";
+	    break;
+	case 0x88: case 0x89: case 0x8a:
+	    name = "IBM Clone";
+	    break;
+	case 0x8b: case 0x8c:
+	    break;
+	default:
+	    done = 1;
+	}
+	if (done) break;
+    }
+
+//mdk-stage1//    if (verbose) printf("\n  ");
+    if (sock == 0) {
+//mdk-stage1//	if (!module)
+	log_message("\tnot found.");
+	return -ENODEV;
+    }
+
+    if ((sock == 2) && (strcmp(name, "VLSI 82C146") == 0))
+	name = "i82365sl DF";
+
+    /* 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 & I365_IDENT_VADEM) {
+	if ((val & 7) < 4)
+	    name = "Vadem VG-468";
+	else
+	    name = "Vadem VG-469";
+	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 & PD67_INFO_CHIP_ID) == PD67_INFO_CHIP_ID) {
+	val = i365_get(0, PD67_CHIP_INFO);
+	if ((val & PD67_INFO_CHIP_ID) == 0) {
+	    if (val & PD67_INFO_SLOTS)
+		name = "Cirrus CL-PD672x";
+	    else {
+		name = "Cirrus CL-PD6710";
+		sock = 1;
+	    }
+	    i365_set(0, PD67_EXT_INDEX, 0xe5);
+	    if (i365_get(0, PD67_EXT_INDEX) != 0xe5)
+		name = "VIA VT83C469";
+	}
+    }
+
+//mdk-stage1//    if (module)
+//mdk-stage1//	printf("i82365\n");
+//mdk-stage1//    else
+	printf("\t%s found, %d sockets.\n", name, sock);
+    return 0;
+    
+} /* i365_probe */
+
+//mdk-stage1//#endif /* CONFIG_ISA */
+
+/*====================================================================*/
+
+//mdk-stage1//#ifdef CONFIG_ISA
+
+#include "tcic.h"
+
+//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) & 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) & 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 & TCIC_ILOCKTEST_ID_MASK) >> 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 < 0x10; i += 2)
+	if (tcic_getw(base, i) == 0xffff)
+	    return -1;
+
+//mdk-stage1//    if (!module)
+    log_message("\tat %#3.3x: ", 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("PCMCIA: probing for Databook TCIC-2 (ISA).."); fflush(stdout);
+    
+    if (ioperm(TCIC_BASE, 16, 1)) {
+	    log_perror("PCMCIA: ioperm");
+	    return -1;
+    }
+    ioperm(0x80, 1, 1);
+    sock = tcic_probe_at(TCIC_BASE);
+    
+    if (sock <= 0) {
+//mdk-stage1//	if (!module)
+	    log_message("\tnot found.");
+	return -ENODEV;
+    }
+
+//mdk-stage1//    if (module)
+//mdk-stage1//	printf("tcic\n");
+//mdk-stage1//    else {
+	id = get_tcic_id(TCIC_BASE);
+	switch (id) {
+	case TCIC_ID_DB86082:
+	    log_message("DB86082"); break;
+	case TCIC_ID_DB86082A:
+	    log_message("DB86082A"); break;
+	case TCIC_ID_DB86084:
+	    log_message("DB86084"); break;
+	case TCIC_ID_DB86084A:
+	    log_message("DB86084A"); break;
+	case TCIC_ID_DB86072:
+	    log_message("DB86072"); break;
+	case TCIC_ID_DB86184:
+	    log_message("DB86184"); break;
+	case TCIC_ID_DB86082B:
+	    log_message("DB86082B"); break;
+	default:
+	    log_message("Unknown TCIC-2 ID 0x%02x", id);
+	}
+	log_message(" found at %#6x, %d sockets.", 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, "t:vxm")) != -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 < argc)) {
+//mdk-stage1// 	fprintf(stderr, "usage: %s [-t tcic_base] [-v] [-m]\n", 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 "i82365";
+	else if (!tcic_probe())
+		return "tcic";
+	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 <linux at brodo.de>
+ *
+ *  The initial developer of the original code is David A. Hinds
+ *  <dahinds at users.sourceforge.net>.  Portions created by David A. Hinds
+ *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * License: GPL v2
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include <sysfs/libsysfs.h>
+
+#include "startup.h"
+
+/* 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 = "/etc/pcmcia";
+
+enum {
+        RESOURCE_MEM,
+        RESOURCE_IO,
+        MAX_RESOURCE_FILES
+};
+
+
+static const char *resource_files[MAX_RESOURCE_FILES] = {
+	[RESOURCE_MEM]	= "available_resources_mem",
+	[RESOURCE_IO]	= "available_resources_io",
+};
+
+#define PATH_TO_SOCKET "/sys/class/pcmcia_socket/"
+
+
+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 >= MAX_RESOURCE_FILES)
+		return -EINVAL;
+
+	if (end <= start)
+		return -EINVAL;
+
+	dprintf("%d %d %d 0x%lx 0x%lx\n", socket_no, type, action, start, end);
+
+	snprintf(file, SYSFS_PATH_MAX, PATH_TO_SOCKET "pcmcia_socket%u/%s",
+		socket_no, resource_files[type]);
+
+	switch(action) {
+	case ADD_MANAGED_RESOURCE:
+		len = snprintf(content, SYSFS_PATH_MAX,
+			       "0x%08lx - 0x%08lx", start, end);
+		break;
+
+	case REMOVE_MANAGED_RESOURCE:
+		len = snprintf(content, SYSFS_PATH_MAX,
+			       "- 0x%08lx - 0x%08lx", start, end);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	dprintf("content is %s\n", content);
+
+	dprintf("file is %s\n", file);
+
+	attr = sysfs_open_attribute(file);
+	if (!attr)
+		return -ENODEV;
+
+	dprintf("open, len %d\n", len);
+
+	ret = sysfs_write_attribute(attr, content, len);
+
+	dprintf("ret is %d\n", 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
+		 "pcmcia_socket%u/available_resources_setup_done",
+		 socket_no);
+
+	attr = sysfs_open_attribute(file);
+	if (!attr)
+		return -ENODEV;
+
+	ret = sysfs_write_attribute(attr, "42", 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 >= 32)
+		return -EINVAL;
+
+	len = snprintf(file, SYSFS_PATH_MAX, PATH_TO_SOCKET
+		 "pcmcia_socket%u/card_irq_mask",
+		 socket_no);
+	dprintf("file is %s\n", file);
+
+	attr = sysfs_open_attribute(file);
+	if (!attr)
+		return -ENODEV;
+
+	dprintf("open, len %d\n", len);
+
+	ret = sysfs_read_attribute(attr);
+	if (ret) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (!attr->value || (attr->len < 6)) {
+		ret = -EIO;
+		goto out;
+	}
+
+	ret = sscanf(attr->value, "0x%x\n", &mask);
+
+	new_mask = 1 << irq;
+
+	mask &= ~new_mask;
+
+	len = snprintf(content, SYSFS_PATH_MAX, "0x%04x", mask);
+
+	dprintf("content is %s\n", 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, "chdir to %s failed: %m", configpath);
+	exit(EXIT_FAILURE);
+    }
+    parse_configfile("config.opts");
+    return;
+}
+
+
+static void adjust_resources(unsigned int socket_no)
+{
+    adjust_list_t *al;
+
+    for (al = root_adjust; al; al = al->next) {
+	    switch (al->adj.Resource) {
+	    case RES_MEMORY_RANGE:
+		    add_available_resource(socket_no, RESOURCE_MEM,
+					   al->adj.Action,
+					   al->adj.resource.memory.Base,
+					   al->adj.resource.memory.Base +
+					   al->adj.resource.memory.Size - 1);
+		    break;
+	    case RES_IO_RANGE:
+		    add_available_resource(socket_no, RESOURCE_IO,
+					   al->adj.Action,
+					   al->adj.resource.io.BasePort,
+					   al->adj.resource.io.BasePort +
+					   al->adj.resource.io.NumPorts - 1);
+		    break;
+	    case RES_IRQ:
+		    if(al->adj.Action == REMOVE_MANAGED_RESOURCE)
+			    disallow_irq(socket_no, al->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("SOCKET_NO"))) {
+		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 < MAX_SOCKS; i++) {
+		if ((socket != i) && (!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 < MAX_SOCKS; i++) {
+		if ((socket_no != i) && (!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
+ *  <dahinds at users.sourceforge.net>.  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 "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * 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
+ * <dahinds at users.sourceforge.net>.  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 "GPL"), 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<<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<<5)
+#define TCIC_AUX_PCTL		(1<<5)
+#define TCIC_AUX_WCTL		(2<<5)
+#define TCIC_AUX_EXTERN		(3<<5)
+#define TCIC_AUX_PDATA		(4<<5)
+#define TCIC_AUX_SYSCFG		(5<<5)
+#define TCIC_AUX_ILOCK		(6<<5)
+#define TCIC_AUX_TEST		(7<<5)
+
+/* Flags for TCIC_PWR */
+#define TCIC_PWR_VCC(sock)	(0x01<<(sock))
+#define TCIC_PWR_VCC_MASK	0x03
+#define TCIC_PWR_VPP(sock)	(0x08<<(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)<<3)
+#define TCIC_SCF2(sock) (((sock)<<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)<<2))<<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)<<1))<<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 "3.1.29"
+#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 "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * 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
+ * <dahinds at users.sourceforge.net>.  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 "GPL"), 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 <linux at brodo.de>
+ *
+ *  The initial developer of the original code is David A. Hinds
+ *  <dahinds at users.sourceforge.net>.  Portions created by David A. Hinds
+ *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * License: GPL v2
+ */
+    
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <sys/types.h>
+
+#include "startup.h"
+
+/* 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 <str> STRING
+%type <num> NUMBER
+%type <adjust> adjust resource
+%%
+list:	  /* nothing */
+	| list adjust
+		{
+		    adjust_list_t **tail = &root_adjust;
+		    while (*tail != NULL) tail = &(*tail)->next;
+		    *tail = $2;
+		}
+	;
+
+adjust:   INCLUDE resource
+		{
+		    $2->adj.Action = ADD_MANAGED_RESOURCE;
+		    $$ = $2;
+		}
+	| EXCLUDE resource
+		{
+		    $2->adj.Action = REMOVE_MANAGED_RESOURCE;
+		    $$ = $2;
+		}
+	| RESERVE resource
+		{
+		    $2->adj.Action = ADD_MANAGED_RESOURCE;
+		    $2->adj.Attributes |= RES_RESERVED;
+		    $$ = $2;
+		}
+	| adjust ',' resource
+		{
+		    $3->adj.Action = $1->adj.Action;
+		    $3->adj.Attributes = $1->adj.Attributes;
+		    $3->next = $1;
+		    $$ = $3;
+		}
+	;
+
+resource: IRQ_NO NUMBER
+		{
+		    $$ = calloc(sizeof(adjust_list_t), 1);
+		    $$->adj.Resource = RES_IRQ;
+		    $$->adj.resource.irq.IRQ = $2;
+		}
+	| PORT NUMBER '-' NUMBER
+		{
+		    if (($4 < $2) || ($4 > 0xffff)) {
+			yyerror("invalid port range 0x%x-0x%x", $2, $4);
+			YYERROR;
+		    }
+		    $$ = calloc(sizeof(adjust_list_t), 1);
+		    $$->adj.Resource = RES_IO_RANGE;
+		    $$->adj.resource.io.BasePort = $2;
+		    $$->adj.resource.io.NumPorts = $4 - $2 + 1;
+		}
+	| MEMORY NUMBER '-' NUMBER
+		{
+		    if ($4 < $2) {
+			yyerror("invalid address range 0x%x-0x%x", $2, $4);
+			YYERROR;
+		    }
+		    $$ = calloc(sizeof(adjust_list_t), 1);
+		    $$->adj.Resource = RES_MEMORY_RANGE;
+		    $$->adj.resource.memory.Base = $2;
+		    $$->adj.resource.memory.Size = $4 - $2 + 1;
+		}
+	;
+
+%%
+void yyerror(char *msg, ...)
+{
+     va_list ap;
+     char str[256];
+
+     va_start(ap, msg);
+     sprintf(str, "error in file '%s' line %d: ",
+	     current_file, current_lineno);
+     vsprintf(str+strlen(str), msg, ap);
+#if YYDEBUG
+     fprintf(stderr, "%s\n", str);
+#else
+     syslog(LOG_ERR, "%s", 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 (blino at mandriva.com)
+ #
+ # 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 > $@ || { 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
+}
+ at aliases or die "unable to get PCMCIA aliases";
+
+print '
+struct pcmcia_alias {
+	const char      *modalias;
+	const char      *module;
+};
+
+';
+
+my %t = ( 
+    network => 'network/pcmcia',
+    medias  => 'disk/pcmcia',
+);
+
+foreach my $type (keys %t) {
+    my @modules = chomp_(`perl ../../kernel/modules.pl pci_modules4stage1 "$t{$type}"`)
+	or die "unable to get PCMCIA modules";
+
+    print "#ifndef DISABLE_".uc($type)."
+struct pcmcia_alias ${type}_pcmcia_ids[] = {
+";
+    print qq|\t{ "$_->[0]", "$_->[1]" },\n| foreach grep { member($_->[1], @modules) } @aliases;
+    print "};
+unsigned int ${type}_pcmcia_num_ids = sizeof(${type}_pcmcia_ids) / sizeof(struct pcmcia_alias);
+
+#endif
+
+";
+
+}


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
+  `"" * "" 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 >= 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 "--"
+  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-<linkname>.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 <n> will send log messages to file
+  descriptor <n> 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
+  <nickwalker at email.com>.  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
+"privileged" options file: /etc/ppp/options or an options file in the
+/etc/ppp/peers directory.  There is a new "call" 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 "NO CARRIER"
+ABORT "NO DIALTONE"
+ABORT "ERROR"
+ABORT "NO ANSWER"
+ABORT "BUSY"
+ABORT "Username/Password Incorrect"
+"" "at"
+OK "at&d2&c1"
+OK "atdt2479381"
+"name:" "^Uusername"
+"word:" "\qpassword"
+"annex" "\q^Uppp"
+"Switching to PPP-ppp-Switching to PPP"
+
+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 "quiet" 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 "office" and is on a
+local ethernet subnet.  Call the home machine "home" and give it an IP
+address on the same subnet as "office".  We'll require both machines
+to authenticate themselves to each other.
+
+Set up the files on "office" 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	"beware the frub-jub"	home
+office	home	"bird, my son!%&*"	-
+
+Set up a modem on a serial port so that users can dial in to the
+modem and get a login prompt.
+
+On "home", set up the files as follows:
+
+/etc/ppp/options contains the same as on "office".
+
+/etc/ppp/chap-secrets contains:
+
+home	office	"beware the frub-jub"	-
+office	home	"bird, my son!%&*"	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 "NO CARRIER"
+ABORT "NO DIALTONE"
+ABORT "ERROR"
+ABORT "NO ANSWER"
+ABORT "BUSY"
+ABORT "ogin incorrect"
+"" "at"
+OK "at&d2&c1"
+OK "atdt2479381"
+"name:" "^Uusername"
+"word:" "\qpassword"
+"$" "\q^U/usr/sbin/pppd proxyarp"
+"~"
+
+You will need to change the details.  Note that the "$" in the
+second-last line is expecting the shell prompt after a successful
+login - you may need to change it to "%" 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 "daemon" and levels
+ranging from "debug" to "error".
+
+Usually it is useful to see messages of level "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" 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
+"info" as well, in which case you would change "daemon.notice" to
+"daemon.info".
+
+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
+"Serial link is not 8-bit clean".  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
+"Serial line is looped back".  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 "~" 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 "peer authentication required but no
+authentication files accessible".
+
+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:
+
+  ""	  *	  ""	  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 "client").
+	* The name of the machine that is authenticating the client
+	  (the "server").
+	* 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 `"' 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 "client" and a "server" 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 "client" and the "server" 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	"our little secret"	-
+
+and the corresponding entry on the server could look like this:
+
+	ay	bee	"our little secret"	123.45.67.89
+
+
+------------------------------------------------------------------------
+
+Q: Explain about PAP and CHAP?
+
+PAP stands for the Password Authentication Protocol.  With this
+protocol, the "client" (the machine that needs to authenticate itself)
+sends its name and a password, in clear text, to the "server".  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 "challenge" - 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&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 "software carrier detect" 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 "softcar" 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 "Unsupported protocol (...) received".  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 "Protocol-Reject for unsupported protocol ...".
+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 "ioctl(TIOCSETD): Operation
+not permitted".  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 "can't open /dev/vd: No such device".
+
+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 "options VDDRV".  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 "pppd --help".
+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
+"LCP: timeout sending Config-Requests" 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 "chat '' AT OK"
+
+To reset the modem and enable auto-answer, use:
+
+	pppd ttyS0 115200 modem crtscts init "chat '' ATZ OK ATS0=1 OK"

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 "pppd.h" 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 > 0, pppd will wait that many seconds before checking again.
+If it is <= 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 "*" 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/<pppd-version> (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 "pppd.h" 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 "compress" 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 "please help me get connected to my ISP" -
+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 <paulus at linuxcare.com>
+Solaris 2		James Carlson <james.d.carlson at east.sun.com>
+SunOS 4.x		Adi Masputra <adi.masputra at sun.com>
+
+
+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:
+
+	ftp://linuxcare.com.au/pub/ppp/
+
+
+($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          rosenqui at strataware.com
+(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:
+
+    <ftp://ftp.microsoft.com/developr/rfc/chapexts.txt>
+
+In short, MS-CHAP is identified as <auth chap 80> 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 "debug" option and
+see something like the following in your logs, the remote server is
+requesting MS-CHAP:
+
+  rcvd [LCP ConfReq id=0x2 <asyncmap 0x0> <auth chap 80> <magic 0x46a3>]
+                                           ^^^^^^^^^^^^
+
+The standard pppd implementation will indicate its lack of support for
+MS-CHAP by NAKing it:
+
+  sent [LCP ConfNak id=0x2 <auth chap 05>]
+
+Windows NT Server systems are often configured to "Accept only
+Microsoft Authentication" (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 "make clean" and "make" as described below.  Linux users
+should not need to modify their Makefiles.  Instead,
+just do "make CHAPMS=1 USE_CRYPT=1".
+
+If you don't have encrypt and setkey, you will need Eric Young's
+libdes library.  You can find it in:
+
+ftp://ftp.funet.fi/pub/crypt/mirrors/ftp.psy.uq.oz.au/DES/libdes-3.06.tar.gz
+
+Australian residents can get libdes from Eric Young's site:
+
+ftp://ftp.psy.uq.oz.au/pub/Crypto/DES/libdes-3.06.tar.gz
+
+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 "-DCHAPMS" in the
+CFLAGS or COMPILE_FLAGS macro, and that the LIBS macro (or LDADD for
+BSD systems) contains "-ldes".  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 "make clean" and then a "make" 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
+"man pppd") and read the description in there.  Basically, you need to
+edit the "chap-secrets" 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 "RemoteHost" 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 "remotename" parameter.  The "Account" is the Windows NT
+account name you have been told to use when dialing, and the "Secret" is
+the password for that account.  For example, if your service provider calls
+their machine "DialupNT" and tells you your account and password are
+"customer47" and "foobar", 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 "remotename" option, either on the command line or in
+your "options" 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 <other options>
+
+or add:
+
+    name customer47
+    remotename DialupNT
+
+to your PPPD "options" file.
+
+The "remotename" 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 <other options>
+
+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 "chapexts.txt" 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 "E=" is the error number from the table above, and the "R=" 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 "destest" 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 "CLIENT"
+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 <stdio.h>
+
+#include "pppd.h"
+#include "chap.h"
+#include "chap_ms.h"
+
+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, "Usage: %s <16-hexchar challenge> <password>\n",
+        argv[0]); exit(1);
+    }
+
+    sscanf(argv[1], "%2x%2x%2x%2x%2x%2x%2x%2x",
+           challengeInt + 0, challengeInt + 1, challengeInt + 2,
+           challengeInt + 3, challengeInt + 4, challengeInt + 5,
+           challengeInt + 6, challengeInt + 7);
+
+    for (i = 0; i < sizeof(challenge); i++)
+        challenge[i] = (u_char)challengeInt[i];
+
+    ChapMS(&cstate, challenge, sizeof(challenge), argv[2], strlen(argv[2]));
+    printf("Response length is %d, response is:", cstate.resp_length);
+
+    for (i = 0; i < cstate.resp_length; i++) {
+        if (i % 8 == 0)
+            putchar('\n');
+        printf("%02X ", (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 "chap-secrets" 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 "-DCBCP_SUPPORT"
+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 <sys/types.h> 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 <sys/types.h> 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 majordomo at vger.kernel.org with a line in the body saying
+
+subscribe linux-ppp
+
+To leave the mailing list, send an email to majordomo at vger.kernel.org
+with a line in the body saying
+
+unsubscribe linux-ppp
+
+To send a message to the list, email it to linux-ppp at vger.kernel.org.
+You don't have to be subscribed to send messages to the list.
+
+You can also email me (paulus at linuxcare.com.au) 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 "" 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
+         ""            don't wait for any prompt, but instead...
+	 AT	       send the string "AT"
+	 OK	       expect the response "OK", 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 & 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 "daemon".  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 ("interface configuration") 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 "ifconfig -a" 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<UP,LOOPBACK,RUNNING,MULTICAST,IPv4> mtu 8232 index 1
+        inet 127.0.0.1 netmask ff000000 
+hme0: flags=1000843<UP,BROADCAST,RUNNING,MULTICAST,IPv4> 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<UP,LOOPBACK,RUNNING,MULTICAST,IPv6> mtu 8252 index 1
+        inet6 ::1/128 
+hme0: flags=2000841<UP,RUNNING,MULTICAST,IPv6> mtu 1500 index 2
+        ether 8:0:20:8d:38:c1 
+        inet6 fe80::a00:20ff:fe8d:38c1/10 
+hme0:1: flags=2080841<UP,RUNNING,MULTICAST,ADDRCONF,IPv6> mtu 1500 index 2
+        inet6 fec0::56:a00:20ff:fe8d:38c1/64 
+hme0:2: flags=2080841<UP,RUNNING,MULTICAST,ADDRCONF,IPv6> mtu 1500 index 2
+        inet6 2000::56:a00:20ff:fe8d:38c1/64 
+hme0:3: flags=2080841<UP,RUNNING,MULTICAST,ADDRCONF,IPv6> mtu 1500 index 2
+        inet6 2::56:a00:20ff:fe8d:38c1/64 
+ppp0: flags=10008d1<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST,IPv4> mtu 1500 index 12
+        inet 172.16.1.1 --> 172.16.1.2 netmask ffffff00 
+ppp0: flags=2202851<UP,POINTOPOINT,RUNNING,MULTICAST,UNNUMBERED,NONUD,IPv6> mtu 1500 index 12
+        inet6 fe80::a00:20ff:fe8d:38c1/10 --> 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 "make install" 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="syncinit se_hdlc0 nrzi=no speed=64000 txc=rxc rxc=rxc"
+ 
+/usr/sbin/pppd $dev sync $baud novj noauth $local: connect "$connect"
+
+
+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 "CC = gcc".  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 "if_ppp" 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 "NO CARRIER"
+ABORT "NO DIALTONE"
+ABORT "ERROR"
+ABORT "NO ANSWER"
+ABORT "BUSY"
+ABORT "Username/Password Incorrect"
+"" "at"
+OK "at&d2&c1"
+OK "atdt2479381"
+"name:" "^Uusername"
+"word:" "\qpassword"
+"annex" "ppp"
+"Switching to PPP-ppp-Switching to PPP"
+
+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	*	"password"
+
+(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 "nodetach" 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<n>.pid in /var/run (or /etc/ppp on older systems such as SunOS or
+Ultrix).  Here <n> 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 @@
+.\" -*- nroff -*-
+.\" manual page [] for chat 1.8
+.\" $Id: chat.8 195720 2001-06-11 11:44:34Z gc $
+.\" SH section heading
+.\" SS subsection heading
+.\" LP paragraph
+.\" IP indented paragraph
+.\" TP hanging label
+.TH CHAT 8 "22 May 1999" "Chat Version 1.22"
+.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<chat file>
+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<timeout>
+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<report file>
+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<phone number>
+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<phone number 2>
+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 "expect-send" pairs of strings,
+separated by spaces, with an optional "subexpect-subsend" 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
+"ogin:". 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 "ogin:". If the first "ogin:" 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 "ssword:". 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 "expect" 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 "ogin:" rather than "login:". It is possible
+that the leading "l" 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 "ogin:" rather than "login:" and "ssword:" rather than
+"password:".
+.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 "abort" 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 "Dialling your ISP...\\n" 
+.br
+\'' ATDT5551212 
+.br
+TIMEOUT 120
+.br
+SAY "Waiting up to 2 minutes for connection ... "
+.br
+CONNECT '' 
+.br
+SAY "Connected, now logging in ...\n"
+.br
+ogin: account
+.br
+ssword: pass
+.br
+$ \c
+SAY "Logged in OK ...\n"
+\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 "report" 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 "CONNECT" 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 "expect-send"
+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 "Bad Login"
+.br
+\'Callback Password:' Call_back_password
+.br
+TIMEOUT 120
+.br
+CONNECT \\c
+.br
+HANGUP ON
+.br
+ABORT "NO CARRIER"
+.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 "-subsend" 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 "BUSY"
+was received from the modem as opposed to "NO DIAL TONE". 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 "ABORT"
+ *  5 - the second string declared as "ABORT"
+ *  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 <andras at cityweb.de>.
+ *
+ *	12-May-99 added a feature to read data to be sent from a file,
+ *	if the send string starts with @.  Idea from gpk <gpk at onramp.net>.
+ *
+ *	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 <kdart at cisco.com>
+ *	
+ *
+ *	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 "NO CARRIER" (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, "NO CARRIER" is a valid, non
+ *      fatal string. As soon as we got called back (probably get "CONNECT"),
+ *      we should re-arm the ABORT "NO CARRIER". 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 <Francis at SwissMail.Com>
+ * 		Thu May 15 17:15:40 MET DST 1997
+ *
+ *
+ *      Added -r "report file" switch & REPORT keyword.
+ *              Robert Geer <bgeer at xmission.com>
+ *
+ *      Added -s "use stderr" and -S "don't use syslog" switches.
+ *              June 18, 1997
+ *              Karl O. Pinc <kop at meme.com>
+ *
+ *
+ *	Added -e "echo" switch & ECHO keyword
+ *		Dick Streefland <dicks at tasking.nl>
+ *
+ *
+ *	Considerable updates and modifications by
+ *		Al Longyear <longyear at pobox.com>
+ *		Paul Mackerras <paulus at cs.anu.edu.au>
+ *
+ *
+ *	The original author is:
+ *
+ *		Karl Fox <karl at MorningStar.Com>
+ *		Morning Star Technologies, Inc.
+ *		1760 Zollinger Road
+ *		Columbus, OH  43221
+ *		(614)451-1883
+ *
+ */
+
+#ifndef __STDC__
+#define const
+#endif
+
+#ifndef lint
+static const char rcsid[] = "$Id: chat.c 195720 2001-06-11 11:44:34Z gc $";
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <time.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <syslog.h>
+
+#ifndef TERMIO
+#undef	TERMIOS
+#define TERMIOS
+#endif
+
+#ifdef TERMIO
+#include <termio.h>
+#endif
+#ifdef TERMIOS
+#include <termios.h>
+#endif
+
+#define	STR_LEN	1024
+
+#ifndef SIGTYPE
+#define SIGTYPE void
+#endif
+
+#undef __P
+#undef __V
+
+#ifdef __STDC__
+#include <stdarg.h>
+#define __V(x)	x
+#define __P(x)	x
+#else
+#include <varargs.h>
+#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) < sys_nerr? sys_errlist[(n)] :\
+				 "unknown error")
+#endif
+
+/*************** Micro getopt() *********************************************/
+#define	OPTION(c,v)	(_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \
+				(--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\
+				&&!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0))
+#define	OPTARG(c,v)	(_O&2?**v||(++v,--c)?(_O=1,--c,*v++): \
+				(_O=4,(char*)0):(char*)0)
+#define	OPTONLYARG(c,v)	(_O&2&&**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, "memory error!");
+
+    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, "a");
+		if (report_fp != NULL) {
+		    if (verbose)
+			fprintf (report_fp, "Opening \"%s\"...\n",
+				 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("chat", LOG_PID);
+#else
+	openlog("chat", 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, "r");
+    if (cfp == NULL)
+	fatal(1, "%s -- open failed: %m", 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 == '"' || *sp == '\'') {
+		quote = *sp++;
+		arg = sp;
+		while (*sp != quote) {
+		    if (*sp == '\0')
+			fatal(1, "unterminated quote (line %d)", linect);
+
+		    if (*sp++ == '\\') {
+			if (*sp != '\0')
+			    ++sp;
+		    }
+		}
+	    }
+	    else {
+		arg = sp;
+		while (*sp != '\0' && *sp != ' ' && *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, "\
+Usage: %s [-e] [-E] [-v] [-V] [-t timeout] [-r report-file]\n\
+     [-T phone-number] [-U phone-number2] {-f chat-file | chat-script}\n", 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, "%s", line);
+    if (to_stderr)
+	fprintf(stderr, "%s\n", 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, "%s", line);
+    if (to_stderr)
+	fprintf(stderr, "%s\n", 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, "Can't get file mode flags on stdin: %m");
+
+    if (fcntl(0, F_SETFL, flags | O_NONBLOCK) == -1)
+	fatal(2, "Can't set file mode flags on stdin: %m");
+
+    if (verbose)
+	logf("alarm");
+}
+
+void unalarm()
+{
+    int flags;
+
+    if ((flags = fcntl(0, F_GETFL, 0)) == -1)
+	fatal(2, "Can't get file mode flags on stdin: %m");
+
+    if (fcntl(0, F_SETFL, flags & ~O_NONBLOCK) == -1)
+	fatal(2, "Can't set file mode flags on stdin: %m");
+}
+
+SIGTYPE sigint(signo)
+int signo;
+{
+    fatal(2, "SIGINT");
+}
+
+SIGTYPE sigterm(signo)
+int signo;
+{
+    fatal(2, "SIGTERM");
+}
+
+SIGTYPE sighup(signo)
+int signo;
+{
+    fatal(2, "SIGHUP");
+}
+
+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 (&t) < 0)
+	fatal(2, "Can't get terminal parameters: %m");
+
+    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 (&t) < 0)
+	fatal(2, "Can't set terminal parameters: %m");
+#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 <= sizeof(report_buffer)) {
+	    alarm(1);
+	    c = get_char();
+	    alarm(0);
+	    if (c < 0 || iscntrl(c))
+		break;
+	    report_buffer[rep_len] = c;
+	    ++rep_len;
+	}
+	report_buffer[rep_len] = 0;
+	fprintf (report_fp, "chat:  %s\n", report_buffer);
+    }
+    if (report_file != (char *) 0 && report_fp != (FILE *) NULL) {
+	if (verbose)
+	    fprintf (report_fp, "Closing \"%s\".\n", report_file);
+	fclose (report_fp);
+	report_fp = (FILE *) NULL;
+    }
+
+#if defined(get_term_param)
+    if (have_tty_parameters) {
+	if (set_term_param (&saved_tty_parameters) < 0)
+	    fatal(2, "Can't restore terminal parameters: %m");
+    }
+#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) >= '0') && ((chr) <= '7'))
+#define isalnumx(chr)	((((chr) >= '0') && ((chr) <= '9')) \
+			 || (((chr) >= 'a') && ((chr) <= 'z')) \
+			 || (((chr) >= 'A') && ((chr) <= 'Z')) \
+			 || (chr) == '_')
+
+    s1 = temp;
+    while (*s) {
+	cur_chr = *s++;
+	if (cur_chr == '^') {
+	    cur_chr = *s++;
+	    if (cur_chr == '\0') {
+		*s1++ = '^';
+		break;
+	    }
+	    cur_chr &= 0x1F;
+	    if (cur_chr != 0) {
+		*s1++ = cur_chr;
+	    }
+	    continue;
+	}
+	
+	if (use_env && 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 && *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 && phone_num) {
+		for (phchar = phone_num; *phchar != '\0'; phchar++) 
+		    *s1++ = *phchar;
+	    }
+	    else {
+		*s1++ = '\\';
+		*s1++ = 'T';
+	    }
+	    break;
+
+	case 'U':
+	    if (sending && 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 &= 0x07;
+		if (isoctal (*s)) {
+		    cur_chr <<= 3;
+		    cur_chr |= *s++ - '0';
+		    if (isoctal (*s)) {
+			cur_chr <<= 3;
+			cur_chr |= *s++ - '0';
+		    }
+		}
+
+		if (cur_chr != 0 || sending) {
+		    if (sending && (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   = "";
+    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, "HANGUP") == 0) {
+	++hup_next;
+        return;
+    }
+ 
+    if (strcmp(s, "ABORT") == 0) {
+	++abort_next;
+	return;
+    }
+
+    if (strcmp(s, "CLR_ABORT") == 0) {
+	++clear_abort_next;
+	return;
+    }
+
+    if (strcmp(s, "REPORT") == 0) {
+	++report_next;
+	return;
+    }
+
+    if (strcmp(s, "CLR_REPORT") == 0) {
+	++clear_report_next;
+	return;
+    }
+
+    if (strcmp(s, "TIMEOUT") == 0) {
+	++timeout_next;
+	return;
+    }
+
+    if (strcmp(s, "ECHO") == 0) {
+	++echo_next;
+	return;
+    }
+
+    if (strcmp(s, "SAY") == 0) {
+	++say_next;
+	return;
+    }
+
+/*
+ * Fetch the expect and reply string.
+ */
+    for (;;) {
+	expect = expect_strtok (s, "-");
+	s      = (char *) 0;
+
+	if (expect == (char *) 0)
+	    return;
+
+	reply = expect_strtok (s, "-");
+
+/*
+ * 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("Failed (%s)", fail_reason);
+    else
+	logf("Failed");
+    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 & 0x80) ? "M-" : "";
+    c &= 0x7F;
+
+    if (c < 32)
+	sprintf(string, "%s^%c", meta, (int)c + '@');
+    else if (c == 127)
+	sprintf(string, "%s^?", meta);
+    else
+	sprintf(string, "%s%c", 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, "OFF") == 0)
+           signal(SIGHUP, SIG_IGN);
+        else
+           signal(SIGHUP, sighup);
+        return;
+    }
+
+    if (echo_next) {
+	echo_next = 0;
+	echo = (strcmp(s, "ON") == 0);
+	return;
+    }
+
+    if (abort_next) {
+	char *s1;
+	
+	abort_next = 0;
+	
+	if (n_aborts >= MAX_ABORTS)
+	    fatal(2, "Too many ABORT strings");
+	
+	s1 = clean(s, 0);
+	
+	if (strlen(s1) > strlen(s)
+	    || strlen(s1) + 1 > sizeof(fail_buffer))
+	    fatal(1, "Illegal or too-long ABORT string ('%v')", s);
+
+	abort_string[n_aborts++] = s1;
+
+	if (verbose)
+	    logf("abort on (%v)", 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) > strlen(s)
+	    || strlen(s1) + 1 > sizeof(fail_buffer))
+	    fatal(1, "Illegal or too-long CLR_ABORT string ('%v')", s);
+
+        old_max = n_aborts;
+	for (i=0; i < n_aborts; i++) {
+	    if ( strcmp(s1,abort_string[i]) == 0 ) {
+		free(abort_string[i]);
+		abort_string[i] = NULL;
+		pack++;
+		n_aborts--;
+		if (verbose)
+		    logf("clear abort on (%v)", s);
+	    }
+	}
+        free(s1);
+	if (pack)
+	    pack_array(abort_string,old_max);
+	return;
+    }
+
+    if (report_next) {
+	char *s1;
+	
+	report_next = 0;
+	if (n_reports >= MAX_REPORTS)
+	    fatal(2, "Too many REPORT strings");
+	
+	s1 = clean(s, 0);
+	
+	if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1)
+	    fatal(1, "Illegal or too-long REPORT string ('%v')", s);
+	
+	report_string[n_reports++] = s1;
+	
+	if (verbose)
+	    logf("report (%v)", 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) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1)
+	    fatal(1, "Illegal or too-long REPORT string ('%v')", s);
+
+	old_max = n_reports;
+	for (i=0; i < n_reports; i++) {
+	    if ( strcmp(s1,report_string[i]) == 0 ) {
+		free(report_string[i]);
+		report_string[i] = NULL;
+		pack++;
+		n_reports--;
+		if (verbose)
+		    logf("clear report (%v)", s);
+	    }
+	}
+        free(s1);
+        if (pack)
+	    pack_array(report_string,old_max);
+	
+	return;
+    }
+
+    if (timeout_next) {
+	timeout_next = 0;
+	timeout = atoi(s);
+	
+	if (timeout <= 0)
+	    timeout = DEFAULT_CHAT_TIMEOUT;
+
+	if (verbose)
+	    logf("timeout set to %d seconds", 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, "r");
+	    if (f == NULL)
+		fatal(1, "%s -- open failed: %m", fn);
+	    while (n < STR_LEN - 1) {
+		int nr = fread(&file_data[n], 1, STR_LEN - 1 - n, f);
+		if (nr < 0)
+		    fatal(1, "%s -- read error", 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 > 0 && file_data[n-1] == '\n')
+		--n;
+	    file_data[n] = 0;
+	    s = file_data;
+	}
+    }
+
+    if (strcmp(s, "EOT") == 0)
+	s = "^D\\c";
+    else if (strcmp(s, "BREAK") == 0)
+	s = "\\K\\c";
+
+    if (!put_string(s))
+	fatal(1, "Failed");
+}
+
+int get_char()
+{
+    int status;
+    char c;
+
+    status = read(0, &c, 1);
+
+    switch (status) {
+    case 1:
+	return ((int)c & 0x7F);
+
+    default:
+	logf("warning: read() on stdin returned %d", status);
+
+    case -1:
+	if ((status = fcntl(0, F_GETFL, 0)) == -1)
+	    fatal(2, "Can't get file mode flags on stdin: %m");
+
+	if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1)
+	    fatal(2, "Can't set file mode flags on stdin: %m");
+	
+	return (-1);
+    }
+}
+
+int put_char(c)
+int c;
+{
+    int status;
+    char ch = c;
+
+    usleep(10000);		/* inter-character typing delay (?) */
+
+    status = write(1, &ch, 1);
+
+    switch (status) {
+    case 1:
+	return (0);
+	
+    default:
+	logf("warning: write() on stdout returned %d", status);
+	
+    case -1:
+	if ((status = fcntl(0, F_GETFL, 0)) == -1)
+	    fatal(2, "Can't get file mode flags on stdin, %m");
+
+	if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1)
+	    fatal(2, "Can't set file mode flags on stdin: %m");
+	
+	return (-1);
+    }
+}
+
+int write_char (c)
+int c;
+{
+    if (alarmed || put_char(c) < 0) {
+	alarm(0);
+	alarmed = 0;
+
+	if (verbose) {
+	    if (errno == EINTR || errno == EWOULDBLOCK)
+		logf(" -- write timed out");
+	    else
+		logf(" -- write failed: %m");
+	}
+	return (0);
+    }
+    return (1);
+}
+
+int put_string (s)
+register char *s;
+{
+    quiet = 0;
+    s = clean(s, 1);
+
+    if (verbose) {
+	if (quiet)
+	    logf("send (??????)");
+	else
+	    logf("send (%v)", 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, "\n", 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 > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1;
+
+    if (verbose)
+	logf("expect (%v)", string);
+
+    if (len > STR_LEN) {
+	logf("expect string is too long");
+	exit_code = 1;
+	return 0;
+    }
+
+    if (len == 0) {
+	if (verbose)
+	    logf("got it");
+	return (1);
+    }
+
+    alarm(timeout);
+    alarmed = 0;
+
+    while ( ! alarmed && (c = get_char()) >= 0) {
+	int n, abort_len, report_len;
+
+	if (echo)
+	    echo_stderr(c);
+	if (verbose && c == '\n') {
+	    if (s == logged)
+		logf("");	/* blank line */
+	    else
+		logf("%0.*v", s - logged, logged);
+	    logged = s + 1;
+	}
+
+	*s++ = c;
+
+	if (verbose && s >= logged + 80) {
+	    logf("%0.*v", s - logged, logged);
+	    logged = s;
+	}
+
+	if (Verbose) {
+	   if (c == '\n')
+	       fputc( '\n', stderr );
+	   else if (c != '\r')
+	       fprintf( stderr, "%s", character(c) );
+	}
+
+	if (!report_gathering) {
+	    for (n = 0; n < n_reports; ++n) {
+		if ((report_string[n] != (char*) NULL) &&
+		    s - temp >= (report_len = strlen(report_string[n])) &&
+		    strncmp(s - report_len, report_string[n], report_len) == 0) {
+		    time_t time_now   = time ((time_t*) NULL);
+		    struct tm* tm_now = localtime (&time_now);
+
+		    strftime (report_buffer, 20, "%b %d %H:%M:%S ", 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, "chat:  %s\n", report_buffer);
+	    }
+	}
+
+	if (s - temp >= len &&
+	    c == string[len - 1] &&
+	    strncmp(s - len, string, len) == 0) {
+	    if (verbose) {
+		if (s > logged)
+		    logf("%0.*v", s - logged, logged);
+		logf(" -- got it\n");
+	    }
+
+	    alarm(0);
+	    alarmed = 0;
+	    return (1);
+	}
+
+	for (n = 0; n < n_aborts; ++n) {
+	    if (s - temp >= (abort_len = strlen(abort_string[n])) &&
+		strncmp(s - abort_len, abort_string[n], abort_len) == 0) {
+		if (verbose) {
+		    if (s > logged)
+			logf("%0.*v", s - logged, logged);
+		    logf(" -- failed");
+		}
+
+		alarm(0);
+		alarmed = 0;
+		exit_code = n + 4;
+		strcpy(fail_reason = fail_buffer, abort_string[n]);
+		return (0);
+	    }
+	}
+
+	if (s >= end) {
+	    if (logged < s - minlen) {
+		if (verbose)
+		    logf("%0.*v", s - logged, logged);
+		logged = s;
+	    }
+	    s -= minlen;
+	    memmove(temp, s, minlen);
+	    logged = temp + (logged - s);
+	    s = temp + minlen;
+	}
+
+	if (alarmed && verbose)
+	    logf("warning: alarm synchronization problem");
+    }
+
+    alarm(0);
+    
+    if (verbose && printed) {
+	if (alarmed)
+	    logf(" -- read timed out");
+	else
+	    logf(" -- read failed: %m");
+    }
+
+    exit_code = 3;
+    alarmed   = 0;
+    return (0);
+}
+
+/*
+ * Gross kludge to handle Solaris versions >= 2.6 having usleep.
+ */
+#ifdef SOL2
+#include <sys/param.h>
+#if MAXUID > 65536		/* then this is Solaris 2.6 or later */
+#undef NO_USLEEP
+#endif
+#endif /* SOL2 */
+
+#ifdef NO_USLEEP
+#include <sys/types.h>
+#include <sys/time.h>
+
+/*
+  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, &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 < end; i++) {
+	if (array[i] == NULL) {
+	    for (j = i+1; j < end; ++j)
+		if (array[j] != NULL)
+		    array[i++] = array[j];
+	    for (; i < 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 > 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[] = "0123456789abcdef";
+
+    buf0 = buf;
+    --buflen;
+    while (buflen > 0) {
+	for (f = fmt; *f != '%' && *f != 0; ++f)
+	    ;
+	if (f > fmt) {
+	    len = f - fmt;
+	    if (len > 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 < 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':		/* "visible" string */
+	case 'q':		/* quoted string */
+	    quoted = c == 'q';
+	    p = va_arg(args, unsigned char *);
+	    if (fillch == '0' && prec > 0) {
+		n = prec;
+	    } else {
+		n = strlen((char *)p);
+		if (prec > 0 && prec < n)
+		    n = prec;
+	    }
+	    while (n > 0 && buflen > 0) {
+		c = *p++;
+		--n;
+		if (!quoted && c >= 0x80) {
+		    OUTCHAR('M');
+		    OUTCHAR('-');
+		    c -= 0x80;
+		}
+		if (quoted && (c == '"' || c == '\\'))
+		    OUTCHAR('\\');
+		if (c < 0x20 || (0x7f <= c && c < 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 >> 4]);
+			    OUTCHAR(hexchars[c & 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 > num + neg) {
+		*--str = hexchars[val % base];
+		val = val / base;
+		if (--prec <= 0 && 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 > 0 && len > prec)
+		len = prec;
+	}
+	if (width > 0) {
+	    if (width > buflen)
+		width = buflen;
+	    if ((n = width - len) > 0) {
+		buflen -= n;
+		for (; n > 0; --n)
+		    *buf++ = fillch;
+	    }
+	}
+	if (len > 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->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__) && (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 "zlib.h"
+
+#if defined(KERNEL) || defined(_KERNEL)
+/* Assume this is a *BSD or SVR4 kernel */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/systm.h>
+#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 <linux/string.h>
+#define HAVE_MEMCPY
+
+#else /* not kernel */
+
+#if defined(MSDOS)||defined(VMS)||defined(CRAY)||defined(WIN32)||defined(RISCOS)
+#   include <stddef.h>
+#   include <errno.h>
+#else
+    extern int errno;
+#endif
+#ifdef STDC
+#  include <string.h>
+#  include <stdlib.h>
+#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->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 >= 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 <alloc.h>
+#  else /* MSC or DJGPP */
+#    include <malloc.h>
+#  endif
+#endif
+
+#ifdef OS2
+#  define OS_CODE  0x06
+#endif
+
+#ifdef WIN32 /* Window 95 & Windows NT */
+#  define OS_CODE  0x0b
+#endif
+
+#if defined(VAXC) || defined(VMS)
+#  define OS_CODE  0x02
+#  define FOPEN(name, mode) \
+     fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#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) ""
+#endif
+
+#if defined(pyr)
+#  define NO_MEMCPY
+#endif
+#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(_MSC_VER)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+  * You may have to use the same strategy for Borland C (untested).
+  */
+#  define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !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 <stdio.h>
+#  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>1) fprintf x ;}
+#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (verbose>1 && (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)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->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 "zutil.h" */
+
+/* ===========================================================================
+ * 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 >= 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 >= 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 <= 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->pending_buf[s->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)->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 "deflation" 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 & 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&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.,"DEFLATE Compressed Data Format Specification".
+ *      Available in ftp://ds.internic.net/rfc/rfc1951.txt
+ *
+ *      A description of the Rabin and Karp algorithm is given in the book
+ *         "Algorithms" 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 "deflate.h" */
+
+char deflate_copyright[] = " deflate 1.0.4 Copyright 1995-1996 Jean-loup Gailly ";
+/*
+  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 >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 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)<<s->hash_shift) ^ (c)) & s->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->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+    s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \
+    s->head[s->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->head[s->hash_size-1] = NIL; \
+    zmemzero((charf *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->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->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 <= 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->msg = Z_NULL;
+#ifndef NO_ZCFUNCS
+    if (strm->zalloc == Z_NULL) {
+	strm->zalloc = zcalloc;
+	strm->opaque = (voidpf)0;
+    }
+    if (strm->zfree == Z_NULL) strm->zfree = zcfree;
+#endif
+
+    if (level == Z_DEFAULT_COMPRESSION) level = 6;
+
+    if (windowBits < 0) { /* undocumented feature: suppress zlib header */
+        noheader = 1;
+        windowBits = -windowBits;
+    }
+    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+        windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+	strategy < 0 || strategy > 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->state = (struct internal_state FAR *)s;
+    s->strm = strm;
+
+    s->noheader = noheader;
+    s->w_bits = windowBits;
+    s->w_size = 1 << s->w_bits;
+    s->w_mask = s->w_size - 1;
+
+    s->hash_bits = memLevel + 7;
+    s->hash_size = 1 << s->hash_bits;
+    s->hash_mask = s->hash_size - 1;
+    s->hash_shift =  ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+    s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+    s->prev   = (Posf *)  ZALLOC(strm, s->w_size, sizeof(Pos));
+    s->head   = (Posf *)  ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+    s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+    overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+    s->pending_buf = (uchf *) overlay;
+    s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+    if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+        s->pending_buf == Z_NULL) {
+        strm->msg = (char*)ERR_MSG(Z_MEM_ERROR);
+        deflateEnd (strm);
+        return Z_MEM_ERROR;
+    }
+    s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+    s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+    s->level = level;
+    s->strategy = strategy;
+    s->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->state == Z_NULL || dictionary == Z_NULL)
+	return Z_STREAM_ERROR;
+
+    s = (deflate_state *) strm->state;
+    if (s->status != INIT_STATE) return Z_STREAM_ERROR;
+
+    strm->adler = adler32(strm->adler, dictionary, dictLength);
+
+    if (length < MIN_MATCH) return Z_OK;
+    if (length > MAX_DIST(s)) {
+	length = MAX_DIST(s);
+#ifndef USE_DICT_HEAD
+	dictionary += dictLength - length; /* use the tail of the dictionary */
+#endif
+    }
+    zmemcpy((charf *)s->window, dictionary, length);
+    s->strstart = length;
+    s->block_start = (long)length;
+
+    /* Insert all strings in the hash table (except for the last two bytes).
+     * s->lookahead stays null, so s->ins_h will be recomputed at the next
+     * call of fill_window.
+     */
+    s->ins_h = s->window[0];
+    UPDATE_HASH(s, s->ins_h, s->window[1]);
+    for (n = 0; n <= 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->state == Z_NULL ||
+        strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR;
+
+    strm->total_in = strm->total_out = 0;
+    strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+    strm->data_type = Z_UNKNOWN;
+
+    s = (deflate_state *)strm->state;
+    s->pending = 0;
+    s->pending_out = s->pending_buf;
+
+    if (s->noheader < 0) {
+        s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */
+    }
+    s->status = s->noheader ? BUSY_STATE : INIT_STATE;
+    strm->adler = 1;
+    s->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->state == Z_NULL) return Z_STREAM_ERROR;
+    s = (deflate_state *) strm->state;
+
+    if (level == Z_DEFAULT_COMPRESSION) {
+	level = 6;
+    }
+    if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+	return Z_STREAM_ERROR;
+    }
+    func = configuration_table[s->level].func;
+
+    if (func != configuration_table[level].func && strm->total_in != 0) {
+	/* Flush the last buffer: */
+	err = deflate(strm, Z_PARTIAL_FLUSH);
+    }
+    if (s->level != level) {
+	s->level = level;
+	s->max_lazy_match   = configuration_table[level].max_lazy;
+	s->good_match       = configuration_table[level].good_length;
+	s->nice_match       = configuration_table[level].nice_length;
+	s->max_chain_length = configuration_table[level].max_chain;
+    }
+    s->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 >> 8));
+    put_byte(s, (Byte)(b & 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->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->state;
+    unsigned len = s->pending;
+
+    if (len > strm->avail_out) len = strm->avail_out;
+    if (len == 0) return;
+
+    if (strm->next_out != Z_NULL) {
+	zmemcpy(strm->next_out, s->pending_out, len);
+	strm->next_out += len;
+    }
+    s->pending_out += len;
+    strm->total_out += len;
+    strm->avail_out  -= len;
+    s->pending -= len;
+    if (s->pending == 0) {
+        s->pending_out = s->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->state == Z_NULL ||
+	flush > Z_FINISH || flush < 0) {
+        return Z_STREAM_ERROR;
+    }
+    s = (deflate_state *) strm->state;
+
+    if ((strm->next_in == Z_NULL && strm->avail_in != 0) ||
+	(s->status == FINISH_STATE && flush != Z_FINISH)) {
+        ERR_RETURN(strm, Z_STREAM_ERROR);
+    }
+    if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+    s->strm = strm; /* just in case */
+    old_flush = s->last_flush;
+    s->last_flush = flush;
+
+    /* Write the zlib header */
+    if (s->status == INIT_STATE) {
+
+        uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+        uInt level_flags = (s->level-1) >> 1;
+
+        if (level_flags > 3) level_flags = 3;
+        header |= (level_flags << 6);
+	if (s->strstart != 0) header |= PRESET_DICT;
+        header += 31 - (header % 31);
+
+        s->status = BUSY_STATE;
+        putShortMSB(s, header);
+
+	/* Save the adler32 of the preset dictionary: */
+	if (s->strstart != 0) {
+	    putShortMSB(s, (uInt)(strm->adler >> 16));
+	    putShortMSB(s, (uInt)(strm->adler & 0xffff));
+	}
+	strm->adler = 1L;
+    }
+
+    /* Flush as much pending output as possible */
+    if (s->pending != 0) {
+        flush_pending(strm);
+        if (strm->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->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->avail_in == 0 && flush <= old_flush &&
+	       flush != Z_FINISH) {
+        ERR_RETURN(strm, Z_BUF_ERROR);
+    }
+
+    /* User must not provide more input after the first FINISH: */
+    if (s->status == FINISH_STATE && strm->avail_in != 0) {
+        ERR_RETURN(strm, Z_BUF_ERROR);
+    }
+
+    /* Start a new block or continue the current one.
+     */
+    if (strm->avail_in != 0 || s->lookahead != 0 ||
+        (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+        block_state bstate;
+
+	bstate = (*(configuration_table[s->level].func))(s, flush);
+
+        if (bstate == finish_started || bstate == finish_done) {
+            s->status = FINISH_STATE;
+        }
+        if (bstate == need_more || bstate == finish_started) {
+	    if (strm->avail_out == 0) {
+	        s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+	    }
+	    return Z_OK;
+	    /* If flush != Z_NO_FLUSH && 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->avail_out == 0) {
+	      s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+	      return Z_OK;
+	    }
+        }
+    }
+    Assert(strm->avail_out > 0, "bug2");
+
+    if (flush != Z_FINISH) return Z_OK;
+    if (s->noheader) return Z_STREAM_END;
+
+    /* Write the zlib trailer (adler32) */
+    putShortMSB(s, (uInt)(strm->adler >> 16));
+    putShortMSB(s, (uInt)(strm->adler & 0xffff));
+    flush_pending(strm);
+    /* If avail_out is zero, the application will call deflate again
+     * to flush the rest.
+     */
+    s->noheader = -1; /* write the trailer only once! */
+    return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int deflateEnd (strm)
+    z_streamp strm;
+{
+    int status;
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    s = (deflate_state *) strm->state;
+
+    status = s->status;
+    if (status != INIT_STATE && status != BUSY_STATE &&
+	status != FINISH_STATE) {
+      return Z_STREAM_ERROR;
+    }
+
+    /* Deallocate in reverse order of allocations: */
+    TRY_FREE(strm, s->pending_buf);
+    TRY_FREE(strm, s->head);
+    TRY_FREE(strm, s->prev);
+    TRY_FREE(strm, s->window);
+
+    ZFREE(strm, s);
+    strm->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->state == Z_NULL)
+        return Z_STREAM_ERROR;
+    ss = (deflate_state *) source->state;
+
+    zmemcpy(dest, source, sizeof(*dest));
+
+    ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+    if (ds == Z_NULL) return Z_MEM_ERROR;
+    dest->state = (struct internal_state FAR *) ds;
+    zmemcpy(ds, ss, sizeof(*ds));
+    ds->strm = dest;
+
+    ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
+    ds->prev   = (Posf *)  ZALLOC(dest, ds->w_size, sizeof(Pos));
+    ds->head   = (Posf *)  ZALLOC(dest, ds->hash_size, sizeof(Pos));
+    overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
+    ds->pending_buf = (uchf *) overlay;
+
+    if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
+        ds->pending_buf == Z_NULL) {
+        deflateEnd (dest);
+        return Z_MEM_ERROR;
+    }
+    /* ??? following zmemcpy doesn't work for 16-bit MSDOS */
+    zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+    zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
+    zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
+    zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+    ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+    ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+    ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+    ds->l_desc.dyn_tree = ds->dyn_ltree;
+    ds->d_desc.dyn_tree = ds->dyn_dtree;
+    ds->bl_desc.dyn_tree = ds->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->state == Z_NULL) return 0;
+    
+    return ((deflate_state *)(strm->state))->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->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->avail_in;
+
+    if (len > size) len = size;
+    if (len == 0) return 0;
+
+    strm->avail_in  -= len;
+
+    if (!((deflate_state *)(strm->state))->noheader) {
+        strm->adler = adler32(strm->adler, strm->next_in, len);
+    }
+    zmemcpy(buf, strm->next_in, len);
+    strm->next_in  += len;
+    strm->total_in += len;
+
+    return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+    deflate_state *s;
+{
+    s->window_size = (ulg)2L*s->w_size;
+
+    CLEAR_HASH(s);
+
+    /* Set the default configuration parameters:
+     */
+    s->max_lazy_match   = configuration_table[s->level].max_lazy;
+    s->good_match       = configuration_table[s->level].good_length;
+    s->nice_match       = configuration_table[s->level].nice_length;
+    s->max_chain_length = configuration_table[s->level].max_chain;
+
+    s->strstart = 0;
+    s->block_start = 0L;
+    s->lookahead = 0;
+    s->match_length = s->prev_length = MIN_MATCH-1;
+    s->match_available = 0;
+    s->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 <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->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->max_chain_length;/* max hash chain length */
+    register Bytef *scan = s->window + s->strstart; /* current string */
+    register Bytef *match;                       /* matched string */
+    register int len;                           /* length of current match */
+    int best_len = s->prev_length;              /* best match length so far */
+    int nice_match = s->nice_match;             /* stop if match long enough */
+    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+        s->strstart - (IPos)MAX_DIST(s) : NIL;
+    /* Stop when cur_match becomes <= limit. To simplify the code,
+     * we prevent matches with the string of window index 0.
+     */
+    Posf *prev = s->prev;
+    uInt wmask = s->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->window + s->strstart + MAX_MATCH - 1;
+    register ush scan_start = *(ushf*)scan;
+    register ush scan_end   = *(ushf*)(scan+best_len-1);
+#else
+    register Bytef *strend = s->window + s->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 >= 8 and MAX_MATCH-2 multiple of 16.
+     * It is easy to get rid of this optimization if necessary.
+     */
+    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+    /* Do not waste too much time if we already have a good match: */
+    if (s->prev_length >= s->good_match) {
+        chain_length >>= 2;
+    }
+    /* Do not look for matches beyond the end of the input. This is necessary
+     * to make deflate deterministic.
+     */
+    if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+    do {
+        Assert(cur_match < s->strstart, "no future");
+        match = s->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) && 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 >= 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], "scan[2]?");
+        scan++, match++;
+        do {
+        } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 scan < strend);
+        /* The funny "do {}" generates better code on most compilers */
+
+        /* Here, scan <= window+strstart+257 */
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+        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 >= 8.
+         */
+        scan += 2, match++;
+        Assert(*scan == *match, "match[2]?");
+
+        /* We check for insufficient lookahead only every 8th comparison;
+         * the 256th check will be made at strstart+258.
+         */
+        do {
+        } while (*++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 scan < strend);
+
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+        len = MAX_MATCH - (int)(strend - scan);
+        scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+        if (len > best_len) {
+            s->match_start = cur_match;
+            best_len = len;
+            if (len >= 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 & wmask]) > limit
+             && --chain_length != 0);
+
+    if ((uInt)best_len <= s->lookahead) return best_len;
+    return s->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->window + match,
+                (charf *)s->window + start, length) != EQUAL) {
+        fprintf(stderr, " start %u, match %u, length %d\n",
+		start, match, length);
+        do {
+	    fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+	} while (--length != 0);
+        z_error("invalid match");
+    }
+    if (z_verbose > 1) {
+        fprintf(stderr,"\\[%d,%d]", start-match, length);
+        do { putc(s->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 < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= 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->w_size;
+
+    do {
+        more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+        /* Deal with !@#$% 64K limit: */
+        if (more == 0 && s->strstart == 0 && s->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->strstart >= wsize+MAX_DIST(s)) {
+
+            zmemcpy((charf *)s->window, (charf *)s->window+wsize,
+                   (unsigned)wsize);
+            s->match_start -= wsize;
+            s->strstart    -= wsize; /* we now have strstart >= MAX_DIST */
+            s->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 > 0
+               later. (Using level 0 permanently is not an optimal usage of
+               zlib, so we don't care about this pathological case.)
+             */
+            n = s->hash_size;
+            p = &s->head[n];
+            do {
+                m = *--p;
+                *p = (Pos)(m >= wsize ? m-wsize : NIL);
+            } while (--n);
+
+            n = wsize;
+            p = &s->prev[n];
+            do {
+                m = *--p;
+                *p = (Pos)(m >= 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->strm->avail_in == 0) return;
+
+        /* If there was no sliding:
+         *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+         *    more == window_size - lookahead - strstart
+         * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+         * => more >= window_size - 2*WSIZE + 2
+         * In the BIG_MEM or MMAP case (not yet supported),
+         *   window_size == input_size + MIN_LOOKAHEAD  &&
+         *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+         * Otherwise, window_size == 2*WSIZE so more >= 2.
+         * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+         */
+        Assert(more >= 2, "more < 2");
+
+        n = read_buf(s->strm, (charf *)s->window + s->strstart + s->lookahead,
+                     more);
+        s->lookahead += n;
+
+        /* Initialize the hash value now that we have some input: */
+        if (s->lookahead >= MIN_MATCH) {
+            s->ins_h = s->window[s->strstart];
+            UPDATE_HASH(s, s->ins_h, s->window[s->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->lookahead < MIN_LOOKAHEAD && s->strm->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->block_start >= 0L ? \
+                   (charf *)&s->window[(unsigned)s->block_start] : \
+                   (charf *)Z_NULL), \
+		(ulg)((long)s->strstart - s->block_start), \
+		(eof)); \
+   s->block_start = s->strstart; \
+   flush_pending(s->strm); \
+   Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, eof) { \
+   FLUSH_BLOCK_ONLY(s, eof); \
+   if (s->strm->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 > s->pending_buf_size - 5) {
+        max_block_size = s->pending_buf_size - 5;
+    }
+
+    /* Copy as much as possible from input to output: */
+    for (;;) {
+        /* Fill the window as much as possible: */
+        if (s->lookahead <= 1) {
+
+            Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+		   s->block_start >= (long)s->w_size, "slide too late");
+
+            fill_window(s);
+            if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+	Assert(s->block_start >= 0L, "block gone");
+
+	s->strstart += s->lookahead;
+	s->lookahead = 0;
+
+	/* Emit a stored block if pending_buf will be full: */
+ 	max_start = s->block_start + max_block_size;
+        if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
+	    /* strstart == 0 is possible when wraparound on 16-bit machine */
+	    s->lookahead = (uInt)(s->strstart - max_start);
+	    s->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->strstart - (uInt)s->block_start >= 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->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+	        return need_more;
+	    }
+            if (s->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->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         * At this point we have always match_length < MIN_MATCH
+         */
+        if (hash_head != NIL && s->strstart - hash_head <= 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->strategy != Z_HUFFMAN_ONLY) {
+                s->match_length = longest_match (s, hash_head);
+            }
+            /* longest_match() sets match_start */
+        }
+        if (s->match_length >= MIN_MATCH) {
+            check_match(s, s->strstart, s->match_start, s->match_length);
+
+            bflush = _tr_tally(s, s->strstart - s->match_start,
+                               s->match_length - MIN_MATCH);
+
+            s->lookahead -= s->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->match_length <= s->max_insert_length &&
+                s->lookahead >= MIN_MATCH) {
+                s->match_length--; /* string at strstart already in hash table */
+                do {
+                    s->strstart++;
+                    INSERT_STRING(s, s->strstart, hash_head);
+                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+                     * always MIN_MATCH bytes ahead.
+                     */
+                } while (--s->match_length != 0);
+                s->strstart++; 
+            } else {
+                s->strstart += s->match_length;
+                s->match_length = 0;
+                s->ins_h = s->window[s->strstart];
+                UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+                Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+                /* If lookahead < 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,"%c", s->window[s->strstart]));
+            bflush = _tr_tally (s, 0, s->window[s->strstart]);
+            s->lookahead--;
+            s->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->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+	        return need_more;
+	    }
+            if (s->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->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         */
+        s->prev_length = s->match_length, s->prev_match = s->match_start;
+        s->match_length = MIN_MATCH-1;
+
+        if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+            s->strstart - hash_head <= 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->strategy != Z_HUFFMAN_ONLY) {
+                s->match_length = longest_match (s, hash_head);
+            }
+            /* longest_match() sets match_start */
+
+            if (s->match_length <= 5 && (s->strategy == Z_FILTERED ||
+                 (s->match_length == MIN_MATCH &&
+                  s->strstart - s->match_start > TOO_FAR))) {
+
+                /* If prev_match is also MIN_MATCH, match_start is garbage
+                 * but we will ignore the current match anyway.
+                 */
+                s->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->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+            uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+            /* Do not insert strings in hash table beyond this. */
+
+            check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+            bflush = _tr_tally(s, s->strstart -1 - s->prev_match,
+                               s->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->lookahead -= s->prev_length-1;
+            s->prev_length -= 2;
+            do {
+                if (++s->strstart <= max_insert) {
+                    INSERT_STRING(s, s->strstart, hash_head);
+                }
+            } while (--s->prev_length != 0);
+            s->match_available = 0;
+            s->match_length = MIN_MATCH-1;
+            s->strstart++;
+
+            if (bflush) FLUSH_BLOCK(s, 0);
+
+        } else if (s->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,"%c", s->window[s->strstart-1]));
+            if (_tr_tally (s, 0, s->window[s->strstart-1])) {
+                FLUSH_BLOCK_ONLY(s, 0);
+            }
+            s->strstart++;
+            s->lookahead--;
+            if (s->strm->avail_out == 0) return need_more;
+        } else {
+            /* There is no previous match to compare with, wait for
+             * the next step to decide.
+             */
+            s->match_available = 1;
+            s->strstart++;
+            s->lookahead--;
+        }
+    }
+    Assert (flush != Z_NO_FLUSH, "no flush?");
+    if (s->match_available) {
+        Tracevv((stderr,"%c", s->window[s->strstart-1]));
+        _tr_tally (s, 0, s->window[s->strstart-1]);
+        s->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 "deflation" 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.,"'Deflate' Compressed Data Format Specification".
+ *      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 "deflate.h" */
+
+#ifdef DEBUG_ZLIB
+#  include <ctype.h>
+#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>2) fprintf(stderr,"\ncd %3d ",(c)); \
+       send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+#define d_code(dist) \
+   ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>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) & 0xff)); \
+    put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 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," l %2d v %4x ", length, value));
+    Assert(length > 0 && length <= 15, "invalid length");
+    s->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->bi_valid > (int)Buf_size - length) {
+        s->bi_buf |= (value << s->bi_valid);
+        put_short(s, s->bi_buf);
+        s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+        s->bi_valid += length - Buf_size;
+    } else {
+        s->bi_buf |= value << s->bi_valid;
+        s->bi_valid += length;
+    }
+}
+#else /* !DEBUG_ZLIB */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+  if (s->bi_valid > (int)Buf_size - len) {\
+    int val = value;\
+    s->bi_buf |= (val << s->bi_valid);\
+    put_short(s, s->bi_buf);\
+    s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+    s->bi_valid += len - Buf_size;\
+  } else {\
+    s->bi_buf |= (value) << s->bi_valid;\
+    s->bi_valid += len;\
+  }\
+}
+#endif /* DEBUG_ZLIB */
+
+
+#define MAX(a,b) (a >= 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) -> length code (0..28) */
+    length = 0;
+    for (code = 0; code < LENGTH_CODES-1; code++) {
+        base_length[code] = length;
+        for (n = 0; n < (1<<extra_lbits[code]); n++) {
+            length_code[length++] = (uch)code;
+        }
+    }
+    Assert (length == 256, "tr_static_init: length != 256");
+    /* 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) -> dist code (0..29) */
+    dist = 0;
+    for (code = 0 ; code < 16; code++) {
+        base_dist[code] = dist;
+        for (n = 0; n < (1<<extra_dbits[code]); n++) {
+            dist_code[dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: dist != 256");
+    dist >>= 7; /* from now on, all distances are divided by 128 */
+    for ( ; code < D_CODES; code++) {
+        base_dist[code] = dist << 7;
+        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+            dist_code[256 + dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+    /* Construct the codes of the static literal tree */
+    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+    n = 0;
+    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+    while (n <= 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 < 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->compressed_len = 0L;
+
+    s->l_desc.dyn_tree = s->dyn_ltree;
+    s->l_desc.stat_desc = &static_l_desc;
+
+    s->d_desc.dyn_tree = s->dyn_dtree;
+    s->d_desc.stat_desc = &static_d_desc;
+
+    s->bl_desc.dyn_tree = s->bl_tree;
+    s->bl_desc.stat_desc = &static_bl_desc;
+
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+    s->last_eob_len = 8; /* enough lookahead for inflate */
+#ifdef DEBUG_ZLIB
+    s->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 < L_CODES;  n++) s->dyn_ltree[n].Freq = 0;
+    for (n = 0; n < D_CODES;  n++) s->dyn_dtree[n].Freq = 0;
+    for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+    s->dyn_ltree[END_BLOCK].Freq = 1;
+    s->opt_len = s->static_len = 0L;
+    s->last_lit = s->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->heap[SMALLEST]; \
+    s->heap[SMALLEST] = s->heap[s->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 < tree[m].Freq || \
+   (tree[n].Freq == tree[m].Freq && depth[n] <= 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->heap[k];
+    int j = k << 1;  /* left son of k */
+    while (j <= s->heap_len) {
+        /* Set j to the smallest of the two sons: */
+        if (j < s->heap_len &&
+            smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+            j++;
+        }
+        /* Exit if v is smaller than both sons */
+        if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+        /* Exchange v with the smallest son */
+        s->heap[k] = s->heap[j];  k = j;
+
+        /* And continue down the tree, setting j to the left son of k */
+        j <<= 1;
+    }
+    s->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->dyn_tree;
+    int max_code   = desc->max_code;
+    ct_data *stree = desc->stat_desc->static_tree;
+    intf *extra    = desc->stat_desc->extra_bits;
+    int base       = desc->stat_desc->extra_base;
+    int max_length = desc->stat_desc->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 <= MAX_BITS; bits++) s->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->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+    for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+        n = s->heap[h];
+        bits = tree[tree[n].Dad].Len + 1;
+        if (bits > max_length) bits = max_length, overflow++;
+        tree[n].Len = (ush)bits;
+        /* We overwrite tree[n].Dad which is no longer needed */
+
+        if (n > max_code) continue; /* not a leaf node */
+
+        s->bl_count[bits]++;
+        xbits = 0;
+        if (n >= base) xbits = extra[n-base];
+        f = tree[n].Freq;
+        s->opt_len += (ulg)f * (bits + xbits);
+        if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+    }
+    if (overflow == 0) return;
+
+    Trace((stderr,"\nbit length overflow\n"));
+    /* 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->bl_count[bits] == 0) bits--;
+        s->bl_count[bits]--;      /* move one leaf down the tree */
+        s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+        s->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 > 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->bl_count[bits];
+        while (n != 0) {
+            m = s->heap[--h];
+            if (m > max_code) continue;
+            if (tree[m].Len != (unsigned) bits) {
+                Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+                s->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 <= MAX_BITS; bits++) {
+        next_code[bits] = code = (code + bl_count[bits-1]) << 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<<MAX_BITS)-1,
+            "inconsistent bit counts");
+    Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+    for (n = 0;  n <= 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,"\nn %3d %c l %2d c %4x (%x) ",
+             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->dyn_tree;
+    ct_data *stree  = desc->stat_desc->static_tree;
+    int elems       = desc->stat_desc->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->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+    for (n = 0; n < elems; n++) {
+        if (tree[n].Freq != 0) {
+            s->heap[++(s->heap_len)] = max_code = n;
+            s->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->heap_len < 2) {
+        node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+        tree[node].Freq = 1;
+        s->depth[node] = 0;
+        s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+        /* node is 0 or 1 so it does not have extra bits */
+    }
+    desc->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->heap_len/2; n >= 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->heap[SMALLEST]; /* m = node of next least frequency */
+
+        s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+        s->heap[--(s->heap_max)] = m;
+
+        /* Create a new node father of n and m */
+        tree[node].Freq = tree[n].Freq + tree[m].Freq;
+        s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1);
+        tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+        if (tree == s->bl_tree) {
+            fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+        }
+#endif
+        /* and insert the new node in the heap */
+        s->heap[SMALLEST] = node++;
+        pqdownheap(s, tree, SMALLEST);
+
+    } while (s->heap_len >= 2);
+
+    s->heap[--(s->heap_max)] = s->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->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 <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            s->bl_tree[curlen].Freq += count;
+        } else if (curlen != 0) {
+            if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+            s->bl_tree[REP_3_6].Freq++;
+        } else if (count <= 10) {
+            s->bl_tree[REPZ_3_10].Freq++;
+        } else {
+            s->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 <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+        } else if (curlen != 0) {
+            if (curlen != prevlen) {
+                send_code(s, curlen, s->bl_tree); count--;
+            }
+            Assert(count >= 3 && count <= 6, " 3_6?");
+            send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+        } else if (count <= 10) {
+            send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+        } else {
+            send_code(s, REPZ_11_138, s->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->dyn_ltree, s->l_desc.max_code);
+    scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+    /* Build the bit length tree: */
+    build_tree(s, (tree_desc *)(&(s->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 >= 3; max_blindex--) {
+        if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+    }
+    /* Update opt_len to include the bit length tree and counts */
+    s->opt_len += 3*(max_blindex+1) + 5+5+4;
+    Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+            s->opt_len, s->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 >= 257, dcodes >= 1, blcodes >= 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 >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+    Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+            "too many codes");
+    Tracev((stderr, "\nbl counts: "));
+    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 < blcodes; rank++) {
+        Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+        send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+    }
+    Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+    Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+    Tracev((stderr, "\ndist tree: sent %ld", s->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<<1)+eof, 3);  /* send block type */
+    s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+    s->compressed_len += (stored_len + 4) << 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 << 1), 3);
+    bi_windup(s);
+    s->compressed_len = (s->compressed_len + 3) & ~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<<1, 3);
+    send_code(s, END_BLOCK, static_ltree);
+    s->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->last_eob_len + 10 - s->bi_valid < 9) {
+        send_bits(s, STATIC_TREES<<1, 3);
+        send_code(s, END_BLOCK, static_ltree);
+        s->compressed_len += 10L;
+        bi_flush(s);
+    }
+    s->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->level > 0) {
+
+	 /* Check if the file is ascii or binary */
+	if (s->data_type == Z_UNKNOWN) set_data_type(s);
+
+	/* Construct the literal and distance trees */
+	build_tree(s, (tree_desc *)(&(s->l_desc)));
+	Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+		s->static_len));
+
+	build_tree(s, (tree_desc *)(&(s->d_desc)));
+	Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+		s->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->opt_len+3+7)>>3;
+	static_lenb = (s->static_len+3+7)>>3;
+
+	Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+		opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+		s->last_lit));
+
+	if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+    } else {
+        Assert(buf != (char*)0, "lost buf");
+	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 && s->compressed_len == 0L) { /* force stored file */
+#  else
+    if (stored_len <= opt_lenb && eof && s->compressed_len==0L && seekable()) {
+#  endif
+        /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
+        if (buf == (charf*)0) error ("block vanished");
+
+        copy_block(s, buf, (unsigned)stored_len, 0); /* without header */
+        s->compressed_len = stored_len << 3;
+        s->method = STORED;
+    } else
+#endif /* STORED_FILE_OK */
+
+#ifdef FORCE_STORED
+    if (buf != (char*)0) { /* force stored block */
+#else
+    if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+                       /* 4: two words for the lengths */
+#endif
+        /* The test buf != NULL is only necessary if LIT_BUFSIZE > 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 <= 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 >= 0) { /* force static trees */
+#else
+    } else if (static_lenb == opt_lenb) {
+#endif
+        send_bits(s, (STATIC_TREES<<1)+eof, 3);
+        compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
+        s->compressed_len += 3 + s->static_len;
+    } else {
+        send_bits(s, (DYN_TREES<<1)+eof, 3);
+        send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+                       max_blindex+1);
+        compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
+        s->compressed_len += 3 + s->opt_len;
+    }
+    Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+    init_block(s);
+
+    if (eof) {
+        bi_windup(s);
+        s->compressed_len += 7;  /* align on byte boundary */
+    }
+    Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+           s->compressed_len-7*eof));
+
+    return s->compressed_len >> 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->d_buf[s->last_lit] = (ush)dist;
+    s->l_buf[s->last_lit++] = (uch)lc;
+    if (dist == 0) {
+        /* lc is the unmatched char */
+        s->dyn_ltree[lc].Freq++;
+    } else {
+        s->matches++;
+        /* Here, lc is the match length - MIN_MATCH */
+        dist--;             /* dist = match distance - 1 */
+        Assert((ush)dist < (ush)MAX_DIST(s) &&
+               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+               (ush)d_code(dist) < (ush)D_CODES,  "_tr_tally: bad match");
+
+        s->dyn_ltree[length_code[lc]+LITERALS+1].Freq++;
+        s->dyn_dtree[d_code(dist)].Freq++;
+    }
+
+    /* Try to guess if it is profitable to stop the current block here */
+    if (s->level > 2 && (s->last_lit & 0xfff) == 0) {
+        /* Compute an upper bound for the compressed length */
+        ulg out_length = (ulg)s->last_lit*8L;
+        ulg in_length = (ulg)((long)s->strstart - s->block_start);
+        int dcode;
+        for (dcode = 0; dcode < D_CODES; dcode++) {
+            out_length += (ulg)s->dyn_dtree[dcode].Freq *
+                (5L+extra_dbits[dcode]);
+        }
+        out_length >>= 3;
+        Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+               s->last_lit, in_length, out_length,
+               100L - out_length*100L/in_length));
+        if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+    }
+    return (s->last_lit == s->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->last_lit != 0) do {
+        dist = s->d_buf[lx];
+        lc = s->l_buf[lx++];
+        if (dist == 0) {
+            send_code(s, lc, ltree); /* send a literal byte */
+            Tracecv(isgraph(lc), (stderr," '%c' ", 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 < D_CODES, "bad d_code");
+
+            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->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow");
+
+    } while (lx < s->last_lit);
+
+    send_code(s, END_BLOCK, ltree);
+    s->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 <= 6 or >= 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 < 7)        bin_freq += s->dyn_ltree[n++].Freq;
+    while (n < 128)    ascii_freq += s->dyn_ltree[n++].Freq;
+    while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq;
+    s->data_type = (Byte)(bin_freq > (ascii_freq >> 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 <= len <= 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 & 1;
+        code >>= 1, res <<= 1;
+    } while (--len > 0);
+    return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+    deflate_state *s;
+{
+    if (s->bi_valid == 16) {
+        put_short(s, s->bi_buf);
+        s->bi_buf = 0;
+        s->bi_valid = 0;
+    } else if (s->bi_valid >= 8) {
+        put_byte(s, (Byte)s->bi_buf);
+        s->bi_buf >>= 8;
+        s->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->bi_valid > 8) {
+        put_short(s, s->bi_buf);
+    } else if (s->bi_valid > 0) {
+        put_byte(s, (Byte)s->bi_buf);
+    }
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+#ifdef DEBUG_ZLIB
+    s->bits_sent = (s->bits_sent+7) & ~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->last_eob_len = 8; /* enough lookahead for inflate */
+
+    if (header) {
+        put_short(s, (ush)len);   
+        put_short(s, (ush)~len);
+#ifdef DEBUG_ZLIB
+        s->bits_sent += 2*16;
+#endif
+    }
+#ifdef DEBUG_ZLIB
+    s->bits_sent += (ulg)len<<3;
+#endif
+    /* bundle up the put_byte(s, *buf++) calls */
+    zmemcpy(&s->pending_buf[s->pending], buf, len);
+    s->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 "zutil.h" */
+
+/* +++ 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->state == Z_NULL)
+    return Z_STREAM_ERROR;
+  z->total_in = z->total_out = 0;
+  z->msg = Z_NULL;
+  z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
+  inflate_blocks_reset(z->state->blocks, z, &c);
+  Trace((stderr, "inflate: reset\n"));
+  return Z_OK;
+}
+
+
+int inflateEnd(z)
+z_streamp z;
+{
+  uLong c;
+
+  if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
+    return Z_STREAM_ERROR;
+  if (z->state->blocks != Z_NULL)
+    inflate_blocks_free(z->state->blocks, z, &c);
+  ZFREE(z, z->state);
+  z->state = Z_NULL;
+  Trace((stderr, "inflate: end\n"));
+  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->msg = Z_NULL;
+#ifndef NO_ZCFUNCS
+  if (z->zalloc == Z_NULL)
+  {
+    z->zalloc = zcalloc;
+    z->opaque = (voidpf)0;
+  }
+  if (z->zfree == Z_NULL) z->zfree = zcfree;
+#endif
+  if ((z->state = (struct internal_state FAR *)
+       ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
+    return Z_MEM_ERROR;
+  z->state->blocks = Z_NULL;
+
+  /* handle undocumented nowrap option (no zlib header or check) */
+  z->state->nowrap = 0;
+  if (w < 0)
+  {
+    w = - w;
+    z->state->nowrap = 1;
+  }
+
+  /* set window size */
+  if (w < 8 || w > 15)
+  {
+    inflateEnd(z);
+    return Z_STREAM_ERROR;
+  }
+  z->state->wbits = (uInt)w;
+
+  /* create inflate_blocks state */
+  if ((z->state->blocks =
+      inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w))
+      == Z_NULL)
+  {
+    inflateEnd(z);
+    return Z_MEM_ERROR;
+  }
+  Trace((stderr, "inflate: allocated\n"));
+
+  /* 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->avail_in==0)goto empty;r=Z_OK;}
+#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
+
+int inflate(z, f)
+z_streamp z;
+int f;
+{
+  int r;
+  uInt b;
+
+  if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL || f < 0)
+    return Z_STREAM_ERROR;
+  r = Z_BUF_ERROR;
+  while (1) switch (z->state->mode)
+  {
+    case METHOD:
+      NEEDBYTE
+      if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
+      {
+        z->state->mode = BAD;
+        z->msg = (char*)"unknown compression method";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
+      {
+        z->state->mode = BAD;
+        z->msg = (char*)"invalid window size";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      z->state->mode = FLAG;
+    case FLAG:
+      NEEDBYTE
+      b = NEXTBYTE;
+      if (((z->state->sub.method << 8) + b) % 31)
+      {
+        z->state->mode = BAD;
+        z->msg = (char*)"incorrect header check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      Trace((stderr, "inflate: zlib header ok\n"));
+      if (!(b & PRESET_DICT))
+      {
+        z->state->mode = BLOCKS;
+	break;
+      }
+      z->state->mode = DICT4;
+    case DICT4:
+      NEEDBYTE
+      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+      z->state->mode = DICT3;
+    case DICT3:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+      z->state->mode = DICT2;
+    case DICT2:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+      z->state->mode = DICT1;
+    case DICT1:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE;
+      z->adler = z->state->sub.check.need;
+      z->state->mode = DICT0;
+      return Z_NEED_DICT;
+    case DICT0:
+      z->state->mode = BAD;
+      z->msg = (char*)"need dictionary";
+      z->state->sub.marker = 0;       /* can try inflateSync */
+      return Z_STREAM_ERROR;
+    case BLOCKS:
+      r = inflate_blocks(z->state->blocks, z, r);
+      if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0)
+	  r = inflate_packet_flush(z->state->blocks);
+      if (r == Z_DATA_ERROR)
+      {
+        z->state->mode = BAD;
+        z->state->sub.marker = 0;       /* can try inflateSync */
+        break;
+      }
+      if (r != Z_STREAM_END)
+        return r;
+      r = Z_OK;
+      inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
+      if (z->state->nowrap)
+      {
+        z->state->mode = DONE;
+        break;
+      }
+      z->state->mode = CHECK4;
+    case CHECK4:
+      NEEDBYTE
+      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+      z->state->mode = CHECK3;
+    case CHECK3:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+      z->state->mode = CHECK2;
+    case CHECK2:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+      z->state->mode = CHECK1;
+    case CHECK1:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE;
+
+      if (z->state->sub.check.was != z->state->sub.check.need)
+      {
+        z->state->mode = BAD;
+        z->msg = (char*)"incorrect data check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      Trace((stderr, "inflate: zlib check ok\n"));
+      z->state->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->state->mode = BAD;
+  z->msg = (char *)"need more for packet flush";
+  z->state->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->state == Z_NULL || z->state->mode != DICT0)
+    return Z_STREAM_ERROR;
+
+  if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR;
+  z->adler = 1L;
+
+  if (length >= ((uInt)1<<z->state->wbits))
+  {
+    length = (1<<z->state->wbits)-1;
+    dictionary += dictLength - length;
+  }
+  inflate_set_dictionary(z->state->blocks, dictionary, length);
+  z->state->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 "caught up";
+ * i.e. no pending output (hence s->read equals s->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->state->mode != BLOCKS)
+	return Z_DATA_ERROR;
+    return inflate_addhistory(z->state->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->state == Z_NULL)
+    return Z_STREAM_ERROR;
+  if (z->state->mode != BAD)
+  {
+    z->state->mode = BAD;
+    z->state->sub.marker = 0;
+  }
+  if ((n = z->avail_in) == 0)
+    return Z_BUF_ERROR;
+  p = z->next_in;
+  m = z->state->sub.marker;
+
+  /* search */
+  while (n && m < 4)
+  {
+    if (*p == (Byte)(m < 2 ? 0 : 0xff))
+      m++;
+    else if (*p)
+      m = 0;
+    else
+      m = 4 - m;
+    p++, n--;
+  }
+
+  /* restore */
+  z->total_in += p - z->next_in;
+  z->next_in = p;
+  z->avail_in = n;
+  z->state->sub.marker = m;
+
+  /* return no joy or set up to restart on a new block */
+  if (m != 4)
+    return Z_DATA_ERROR;
+  r = z->total_in;  w = z->total_out;
+  inflateReset(z);
+  z->total_in = r;  z->total_out = w;
+  z->state->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 "zutil.h" */
+/* #include "infblock.h" */
+
+/* +++ 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->bitb=b;s->bitk=k;}
+#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
+#define UPDOUT {s->write=q;}
+#define UPDATE {UPDBITS UPDIN UPDOUT}
+#define LEAVE {UPDATE return inflate_flush(s,z,r);}
+/*   get bytes and bits */
+#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
+#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
+#define NEXTBYTE (n--,*p++)
+#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define DUMPBITS(j) {b>>=(j);k-=(j);}
+/*   output bytes */
+#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)
+#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
+#define WWRAP {if(q==s->end&&s->read!=s->window){q=s->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->checkfn != Z_NULL)
+    *c = s->check;
+  if (s->mode == BTREE || s->mode == DTREE)
+    ZFREE(z, s->sub.trees.blens);
+  if (s->mode == CODES)
+  {
+    inflate_codes_free(s->sub.decode.codes, z);
+    inflate_trees_free(s->sub.decode.td, z);
+    inflate_trees_free(s->sub.decode.tl, z);
+  }
+  s->mode = TYPE;
+  s->bitk = 0;
+  s->bitb = 0;
+  s->read = s->write = s->window;
+  if (s->checkfn != Z_NULL)
+    z->adler = s->check = (*s->checkfn)(0L, Z_NULL, 0);
+  Trace((stderr, "inflate:   blocks reset\n"));
+}
+
+
+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->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
+  {
+    ZFREE(z, s);
+    return Z_NULL;
+  }
+  s->end = s->window + w;
+  s->checkfn = c;
+  s->mode = TYPE;
+  Trace((stderr, "inflate:   blocks allocated\n"));
+  inflate_blocks_reset(s, z, &s->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->mode)
+  {
+    case TYPE:
+      NEEDBITS(3)
+      t = (uInt)b & 7;
+      s->last = t & 1;
+      switch (t >> 1)
+      {
+        case 0:                         /* stored */
+          Trace((stderr, "inflate:     stored block%s\n",
+                 s->last ? " (last)" : ""));
+          DUMPBITS(3)
+          t = k & 7;                    /* go to byte boundary */
+          DUMPBITS(t)
+          s->mode = LENS;               /* get length of stored block */
+          break;
+        case 1:                         /* fixed */
+          Trace((stderr, "inflate:     fixed codes block%s\n",
+                 s->last ? " (last)" : ""));
+          {
+            uInt bl, bd;
+            inflate_huft *tl, *td;
+
+            inflate_trees_fixed(&bl, &bd, &tl, &td);
+            s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
+            if (s->sub.decode.codes == Z_NULL)
+            {
+              r = Z_MEM_ERROR;
+              LEAVE
+            }
+            s->sub.decode.tl = Z_NULL;  /* don't try to free these */
+            s->sub.decode.td = Z_NULL;
+          }
+          DUMPBITS(3)
+          s->mode = CODES;
+          break;
+        case 2:                         /* dynamic */
+          Trace((stderr, "inflate:     dynamic codes block%s\n",
+                 s->last ? " (last)" : ""));
+          DUMPBITS(3)
+          s->mode = TABLE;
+          break;
+        case 3:                         /* illegal */
+          DUMPBITS(3)
+          s->mode = BADB;
+          z->msg = (char*)"invalid block type";
+          r = Z_DATA_ERROR;
+          LEAVE
+      }
+      break;
+    case LENS:
+      NEEDBITS(32)
+      if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
+      {
+        s->mode = BADB;
+        z->msg = (char*)"invalid stored block lengths";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+      s->sub.left = (uInt)b & 0xffff;
+      b = k = 0;                      /* dump bits */
+      Tracev((stderr, "inflate:       stored length %u\n", s->sub.left));
+      s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);
+      break;
+    case STORED:
+      if (n == 0)
+        LEAVE
+      NEEDOUT
+      t = s->sub.left;
+      if (t > n) t = n;
+      if (t > m) t = m;
+      zmemcpy(q, p, t);
+      p += t;  n -= t;
+      q += t;  m -= t;
+      if ((s->sub.left -= t) != 0)
+        break;
+      Tracev((stderr, "inflate:       stored end, %lu total out\n",
+              z->total_out + (q >= s->read ? q - s->read :
+              (s->end - s->read) + (q - s->window))));
+      s->mode = s->last ? DRY : TYPE;
+      break;
+    case TABLE:
+      NEEDBITS(14)
+      s->sub.trees.table = t = (uInt)b & 0x3fff;
+#ifndef PKZIP_BUG_WORKAROUND
+      if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
+      {
+        s->mode = BADB;
+        z->msg = (char*)"too many length or distance symbols";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+#endif
+      t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
+      if (t < 19)
+        t = 19;
+      if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
+      {
+        r = Z_MEM_ERROR;
+        LEAVE
+      }
+      DUMPBITS(14)
+      s->sub.trees.index = 0;
+      Tracev((stderr, "inflate:       table sizes ok\n"));
+      s->mode = BTREE;
+    case BTREE:
+      while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
+      {
+        NEEDBITS(3)
+        s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
+        DUMPBITS(3)
+      }
+      while (s->sub.trees.index < 19)
+        s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
+      s->sub.trees.bb = 7;
+      t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
+                             &s->sub.trees.tb, z);
+      if (t != Z_OK)
+      {
+        ZFREE(z, s->sub.trees.blens);
+        r = t;
+        if (r == Z_DATA_ERROR)
+          s->mode = BADB;
+        LEAVE
+      }
+      s->sub.trees.index = 0;
+      Tracev((stderr, "inflate:       bits tree ok\n"));
+      s->mode = DTREE;
+    case DTREE:
+      while (t = s->sub.trees.table,
+             s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
+      {
+        inflate_huft *h;
+        uInt i, j, c;
+
+        t = s->sub.trees.bb;
+        NEEDBITS(t)
+        h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
+        t = h->word.what.Bits;
+        c = h->more.Base;
+        if (c < 16)
+        {
+          DUMPBITS(t)
+          s->sub.trees.blens[s->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 & inflate_mask[i];
+          DUMPBITS(i)
+          i = s->sub.trees.index;
+          t = s->sub.trees.table;
+          if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
+              (c == 16 && i < 1))
+          {
+            inflate_trees_free(s->sub.trees.tb, z);
+            ZFREE(z, s->sub.trees.blens);
+            s->mode = BADB;
+            z->msg = (char*)"invalid bit length repeat";
+            r = Z_DATA_ERROR;
+            LEAVE
+          }
+          c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
+          do {
+            s->sub.trees.blens[i++] = c;
+          } while (--j);
+          s->sub.trees.index = i;
+        }
+      }
+      inflate_trees_free(s->sub.trees.tb, z);
+      s->sub.trees.tb = Z_NULL;
+      {
+        uInt bl, bd;
+        inflate_huft *tl, *td;
+        inflate_codes_statef *c;
+
+        bl = 9;         /* must be <= 9 for lookahead assumptions */
+        bd = 6;         /* must be <= 9 for lookahead assumptions */
+        t = s->sub.trees.table;
+#ifdef DEBUG_ZLIB
+      inflate_hufts = 0;
+#endif
+        t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
+                                  s->sub.trees.blens, &bl, &bd, &tl, &td, z);
+        ZFREE(z, s->sub.trees.blens);
+        if (t != Z_OK)
+        {
+          if (t == (uInt)Z_DATA_ERROR)
+            s->mode = BADB;
+          r = t;
+          LEAVE
+        }
+        Tracev((stderr, "inflate:       trees ok, %d * %d bytes used\n",
+              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->sub.decode.codes = c;
+        s->sub.decode.tl = tl;
+        s->sub.decode.td = td;
+      }
+      s->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->sub.decode.codes, z);
+      inflate_trees_free(s->sub.decode.td, z);
+      inflate_trees_free(s->sub.decode.tl, z);
+      LOAD
+      Tracev((stderr, "inflate:       codes end, %lu total out\n",
+              z->total_out + (q >= s->read ? q - s->read :
+              (s->end - s->read) + (q - s->window))));
+      if (!s->last)
+      {
+        s->mode = TYPE;
+        break;
+      }
+      if (k > 7)              /* return unused byte, if any */
+      {
+        Assert(k < 16, "inflate_codes grabbed too many bytes")
+        k -= 8;
+        n++;
+        p--;                    /* can always return one */
+      }
+      s->mode = DRY;
+    case DRY:
+      FLUSH
+      if (s->read != s->write)
+        LEAVE
+      s->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->window);
+  ZFREE(z, s);
+  Trace((stderr, "inflate:   blocks freed\n"));
+  return Z_OK;
+}
+
+
+void inflate_set_dictionary(s, d, n)
+inflate_blocks_statef *s;
+const Bytef *d;
+uInt  n;
+{
+  zmemcpy((charf *)s->window, d, n);
+  s->read = s->write = s->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 "caught up";
+ * i.e. no pending output (hence s->read equals s->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->read != s->write)
+	return Z_STREAM_ERROR;
+    if (s->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 > m) t = m;
+	/* update check information */
+	if (s->checkfn != Z_NULL)
+	    s->check = (*s->checkfn)(s->check, q, t);
+	zmemcpy(q, p, t);
+	q += t;
+	p += t;
+	n -= t;
+	z->total_out += t;
+	s->read = q;    /* drag read pointer forward */
+/*      WWRAP  */ 	/* expand WWRAP macro by hand to handle s->read */
+	if (q == s->end) {
+	    s->read = q = s->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->mode != LENS)
+	return Z_DATA_ERROR;
+    s->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 "zutil.h" */
+/* #include "inftrees.h" */
+
+char inflate_copyright[] = " inflate 1.0.4 Copyright 1995-1996 Mark Adler ";
+/*
+  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 "simple" 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 <= BMAX) */
+uInt n;                 /* number of codes (assumed <= 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 <= 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 <= BMAX; j++)
+    if (c[j])
+      break;
+  k = j;                        /* minimum code length */
+  if ((uInt)l < j)
+    l = j;
+  for (i = BMAX; i; i--)
+    if (c[i])
+      break;
+  g = i;                        /* maximum code length */
+  if ((uInt)l > i)
+    l = i;
+  *m = l;
+
+
+  /* Adjust last length count to fill out codes, if needed */
+  for (y = 1 << j; j < i; j++, y <<= 1)
+    if ((y -= c[j]) < 0)
+      return Z_DATA_ERROR;
+  if ((y -= c[i]) < 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 < 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 <= 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 > 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 > (uInt)l ? l : z;        /* table size upper limit */
+        if ((f = 1 << (j = k - w)) > 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 < z)
+            while (++j < z)     /* try smaller tables up to z bits */
+            {
+              if ((f <<= 1) <= *++xp)
+                break;          /* enough codes to use up j bits */
+              f -= *xp;         /* else deduct codes from patterns */
+            }
+        }
+        z = 1 << 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 = &(q->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 >> (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 >= v + n)
+        r.exop = 128 + 64;      /* out of values--invalid code */
+      else if (*p < s)
+      {
+        r.exop = (Byte)(*p < 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 << (k - w);
+      for (j = i >> w; j < z; j += f)
+        q[j] = r;
+
+      /* backwards increment the k-bit code i */
+      for (j = 1 << (k - 1); i & j; j >>= 1)
+        i ^= j;
+      i ^= j;
+
+      /* backup over finished tables */
+      while ((i & ((1 << 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 && 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->msg = (char*)"oversubscribed dynamic bit lengths tree";
+  else if (r == Z_BUF_ERROR || *bb == 0)
+  {
+    inflate_trees_free(*tb, z);
+    z->msg = (char*)"incomplete dynamic bit lengths tree";
+    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->msg = (char*)"oversubscribed literal/length tree";
+    else if (r != Z_MEM_ERROR)
+    {
+      inflate_trees_free(*tl, z);
+      z->msg = (char*)"incomplete literal/length tree";
+      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 && nl > 257))
+  {
+    if (r == Z_DATA_ERROR)
+      z->msg = (char*)"oversubscribed distance tree";
+    else if (r == Z_BUF_ERROR) {
+#ifdef PKZIP_BUG_WORKAROUND
+      r = Z_OK;
+    }
+#else
+      inflate_trees_free(*td, z);
+      z->msg = (char*)"incomplete distance tree";
+      r = Z_DATA_ERROR;
+    }
+    else if (r != Z_MEM_ERROR)
+    {
+      z->msg = (char*)"empty distance tree with lengths";
+      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) && n <= *(intf *)q,
+         "inflate_trees falloc overflow");
+  *(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)&f;
+
+    /* literal table */
+    for (k = 0; k < 144; k++)
+      c[k] = 8;
+    for (; k < 256; k++)
+      c[k] = 9;
+    for (; k < 280; k++)
+      c[k] = 7;
+    for (; k < 288; k++)
+      c[k] = 8;
+    fixed_bl = 7;
+    huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z);
+
+    /* distance table */
+    for (k = 0; k < 30; k++)
+      c[k] = 5;
+    fixed_bd = 5;
+    huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z);
+
+    /* done */
+    Assert(f == 0, "invalid build of fixed tables");
+    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)->next;
+    (q - 1)->next = p;
+    p = q;
+    q = r;
+  }
+  /* Go through linked list, freeing from the malloced (t[-1]) address. */
+  while (p != Z_NULL)
+  {
+    q = (--p)->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 "zutil.h" */
+/* #include "inftrees.h" */
+/* #include "infblock.h" */
+/* #include "infcodes.h" */
+/* #include "infutil.h" */
+
+/* +++ 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 "i:"=input, "o:"=output, "x:"=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->mode = START;
+    c->lbits = (Byte)bl;
+    c->dbits = (Byte)bd;
+    c->ltree = tl;
+    c->dtree = td;
+    Tracev((stderr, "inflate:       codes new\n"));
+  }
+  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->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->mode)
+  {             /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+    case START:         /* x: set up for LEN */
+#ifndef SLOW
+      if (m >= 258 && n >= 10)
+      {
+        UPDATE
+        r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
+        LOAD
+        if (r != Z_OK)
+        {
+          c->mode = r == Z_STREAM_END ? WASH : BADCODE;
+          break;
+        }
+      }
+#endif /* !SLOW */
+      c->sub.code.need = c->lbits;
+      c->sub.code.tree = c->ltree;
+      c->mode = LEN;
+    case LEN:           /* i: get length/literal/eob next */
+      j = c->sub.code.need;
+      NEEDBITS(j)
+      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+      DUMPBITS(t->bits)
+      e = (uInt)(t->exop);
+      if (e == 0)               /* literal */
+      {
+        c->sub.lit = t->base;
+        Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                 "inflate:         literal '%c'\n" :
+                 "inflate:         literal 0x%02x\n", t->base));
+        c->mode = LIT;
+        break;
+      }
+      if (e & 16)               /* length */
+      {
+        c->sub.copy.get = e & 15;
+        c->len = t->base;
+        c->mode = LENEXT;
+        break;
+      }
+      if ((e & 64) == 0)        /* next table */
+      {
+        c->sub.code.need = e;
+        c->sub.code.tree = t->next;
+        break;
+      }
+      if (e & 32)               /* end of block */
+      {
+        Tracevv((stderr, "inflate:         end of block\n"));
+        c->mode = WASH;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = (char*)"invalid literal/length code";
+      r = Z_DATA_ERROR;
+      LEAVE
+    case LENEXT:        /* i: getting length extra (have base) */
+      j = c->sub.copy.get;
+      NEEDBITS(j)
+      c->len += (uInt)b & inflate_mask[j];
+      DUMPBITS(j)
+      c->sub.code.need = c->dbits;
+      c->sub.code.tree = c->dtree;
+      Tracevv((stderr, "inflate:         length %u\n", c->len));
+      c->mode = DIST;
+    case DIST:          /* i: get distance next */
+      j = c->sub.code.need;
+      NEEDBITS(j)
+      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+      DUMPBITS(t->bits)
+      e = (uInt)(t->exop);
+      if (e & 16)               /* distance */
+      {
+        c->sub.copy.get = e & 15;
+        c->sub.copy.dist = t->base;
+        c->mode = DISTEXT;
+        break;
+      }
+      if ((e & 64) == 0)        /* next table */
+      {
+        c->sub.code.need = e;
+        c->sub.code.tree = t->next;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = (char*)"invalid distance code";
+      r = Z_DATA_ERROR;
+      LEAVE
+    case DISTEXT:       /* i: getting distance extra */
+      j = c->sub.copy.get;
+      NEEDBITS(j)
+      c->sub.copy.dist += (uInt)b & inflate_mask[j];
+      DUMPBITS(j)
+      Tracevv((stderr, "inflate:         distance %u\n", c->sub.copy.dist));
+      c->mode = COPY;
+    case COPY:          /* o: copying bytes in window, waiting for space */
+#ifndef __TURBOC__ /* Turbo C bug for following expression */
+      f = (uInt)(q - s->window) < c->sub.copy.dist ?
+          s->end - (c->sub.copy.dist - (q - s->window)) :
+          q - c->sub.copy.dist;
+#else
+      f = q - c->sub.copy.dist;
+      if ((uInt)(q - s->window) < c->sub.copy.dist)
+        f = s->end - (c->sub.copy.dist - (uInt)(q - s->window));
+#endif
+      while (c->len)
+      {
+        NEEDOUT
+        OUTBYTE(*f++)
+        if (f == s->end)
+          f = s->window;
+        c->len--;
+      }
+      c->mode = START;
+      break;
+    case LIT:           /* o: got literal, waiting for output space */
+      NEEDOUT
+      OUTBYTE(c->sub.lit)
+      c->mode = START;
+      break;
+    case WASH:          /* o: got eob, possibly more output */
+      FLUSH
+      if (s->read != s->write)
+        LEAVE
+      c->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, "inflate:       codes free\n"));
+}
+/* --- 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 "zutil.h" */
+/* #include "infblock.h" */
+/* #include "inftrees.h" */
+/* #include "infcodes.h" */
+/* #include "infutil.h" */
+
+#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->next_out;
+  q = s->read;
+
+  /* compute number of bytes to copy as far as end of window */
+  n = (uInt)((q <= s->write ? s->write : s->end) - q);
+  if (n > z->avail_out) n = z->avail_out;
+  if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+  /* update counters */
+  z->avail_out -= n;
+  z->total_out += n;
+
+  /* update check information */
+  if (s->checkfn != Z_NULL)
+    z->adler = s->check = (*s->checkfn)(s->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->end)
+  {
+    /* wrap pointers */
+    q = s->window;
+    if (s->write == s->end)
+      s->write = s->window;
+
+    /* compute bytes to copy */
+    n = (uInt)(s->write - q);
+    if (n > z->avail_out) n = z->avail_out;
+    if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+    /* update counters */
+    z->avail_out -= n;
+    z->total_out += n;
+
+    /* update check information */
+    if (s->checkfn != Z_NULL)
+      z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+    /* copy */
+    if (p != Z_NULL) {
+      zmemcpy(p, q, n);
+      p += n;
+    }
+    q += n;
+  }
+
+  /* update pointers */
+  z->next_out = p;
+  s->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 "zutil.h" */
+/* #include "inftrees.h" */
+/* #include "infblock.h" */
+/* #include "infcodes.h" */
+/* #include "infutil.h" */
+/* #include "inffast.h" */
+
+#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<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define UNGRAB {n+=(c=k>>3);p-=c;k&=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 >= 258 && n >= 10 */
+    /* get literal/length code */
+    GRABBITS(20)                /* max bits for literal/length code */
+    if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
+    {
+      DUMPBITS(t->bits)
+      Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                "inflate:         * literal '%c'\n" :
+                "inflate:         * literal 0x%02x\n", t->base));
+      *q++ = (Byte)t->base;
+      m--;
+      continue;
+    }
+    do {
+      DUMPBITS(t->bits)
+      if (e & 16)
+      {
+        /* get extra bits for length */
+        e &= 15;
+        c = t->base + ((uInt)b & inflate_mask[e]);
+        DUMPBITS(e)
+        Tracevv((stderr, "inflate:         * length %u\n", c));
+
+        /* decode distance base of block to copy */
+        GRABBITS(15);           /* max bits for distance code */
+        e = (t = td + ((uInt)b & md))->exop;
+        do {
+          DUMPBITS(t->bits)
+          if (e & 16)
+          {
+            /* get extra bits to add to distance base */
+            e &= 15;
+            GRABBITS(e)         /* get extra bits (up to 13) */
+            d = t->base + ((uInt)b & inflate_mask[e]);
+            DUMPBITS(e)
+            Tracevv((stderr, "inflate:         * distance %u\n", d));
+
+            /* do the copy */
+            m -= c;
+            if ((uInt)(q - s->window) >= 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->window); /* bytes from offset to end */
+              r = s->end - e;           /* pointer to offset */
+              if (c > e)                /* if source crosses, */
+              {
+                c -= e;                 /* copy to end of window */
+                do {
+                  *q++ = *r++;
+                } while (--e);
+                r = s->window;          /* copy rest from start of window */
+              }
+            }
+            do {                        /* copy all or what's left */
+              *q++ = *r++;
+            } while (--c);
+            break;
+          }
+          else if ((e & 64) == 0)
+            e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop;
+          else
+          {
+            z->msg = (char*)"invalid distance code";
+            UNGRAB
+            UPDATE
+            return Z_DATA_ERROR;
+          }
+        } while (1);
+        break;
+      }
+      if ((e & 64) == 0)
+      {
+        if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0)
+        {
+          DUMPBITS(t->bits)
+          Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                    "inflate:         * literal '%c'\n" :
+                    "inflate:         * literal 0x%02x\n", t->base));
+          *q++ = (Byte)t->base;
+          m--;
+          break;
+        }
+      }
+      else if (e & 32)
+      {
+        Tracevv((stderr, "inflate:         * end of block\n"));
+        UNGRAB
+        UPDATE
+        return Z_STREAM_END;
+      }
+      else
+      {
+        z->msg = (char*)"invalid literal/length code";
+        UNGRAB
+        UPDATE
+        return Z_DATA_ERROR;
+      }
+    } while (1);
+  } while (m >= 258 && n >= 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 <stdio.h>
+#endif
+
+/* #include "zutil.h" */
+
+#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] = {
+"need dictionary",     /* Z_NEED_DICT       2  */
+"stream end",          /* Z_STREAM_END      1  */
+"",                    /* Z_OK              0  */
+"file error",          /* Z_ERRNO         (-1) */
+"stream error",        /* Z_STREAM_ERROR  (-2) */
+"data error",          /* Z_DATA_ERROR    (-3) */
+"insufficient memory", /* Z_MEM_ERROR     (-4) */
+"buffer error",        /* Z_BUF_ERROR     (-5) */
+"incompatible version",/* Z_VERSION_ERROR (-6) */
+""};
+
+
+const char *zlibVersion()
+{
+    return ZLIB_VERSION;
+}
+
+#ifdef DEBUG_ZLIB
+void z_error (m)
+    char *m;
+{
+    fprintf(stderr, "%s\n", 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 < len; j++) {
+        if (s1[j] != s2[j]) return 2*(s1[j] > 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)) && !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 < 65520L) {
+        buf = farmalloc(bsize);
+        if (*(ush*)&buf != 0) return buf;
+    } else {
+        buf = farmalloc(bsize + 16L);
+    }
+    if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+    table[next_ptr].org_ptr = buf;
+
+    /* Normalize the pointer to seg:0 */
+    *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+    *(ush*)&buf = 0;
+    table[next_ptr++].new_ptr = buf;
+    return buf;
+}
+
+void  zcfree (voidpf opaque, voidpf ptr)
+{
+    int n;
+    if (*(ush*)&ptr != 0) { /* object < 64K */
+        farfree(ptr);
+        return;
+    }
+    /* Find the original pointer */
+    for (n = 0; n < next_ptr; n++) {
+        if (ptr != table[n].new_ptr) continue;
+
+        farfree(table[n].org_ptr);
+        while (++n < next_ptr) {
+            table[n-1] = table[n];
+        }
+        next_ptr--;
+        return;
+    }
+    ptr = opaque; /* just to make some compilers happy */
+    Assert(0, "zcfree: ptr not found");
+}
+#endif
+#endif /* __TURBOC__ */
+
+
+#if defined(M_I86) && !defined(__32BIT__)
+/* Microsoft C in 16-bit mode */
+
+#  define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER < 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 "zlib.h" */
+
+#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) <= 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 & 0xffff;
+    unsigned long s2 = (adler >> 16) & 0xffff;
+    int k;
+
+    if (buf == Z_NULL) return 1L;
+
+    while (len > 0) {
+        k = len < NMAX ? len : NMAX;
+        len -= k;
+        while (k >= 16) {
+            DO16(buf);
+	    buf += 16;
+            k -= 16;
+        }
+        if (k != 0) do {
+            s1 += *buf++;
+	    s2 += s1;
+        } while (--k);
+        s1 %= BASE;
+        s2 %= BASE;
+    }
+    return (s2 << 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
+  gzip at prep.ai.mit.edu    madler at alumni.caltech.edu
+
+
+  The data format used by the zlib library is described by RFCs (Request for
+  Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
+  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef _ZLIB_H
+#define _ZLIB_H
+
+#ifdef __cplusplus
+extern "C" {
+#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 "standard" 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__)) && !defined(WIN32)
+#  define WIN32
+#endif
+#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386)
+#  ifndef __32BIT__
+#    define __32BIT__
+#  endif
+#endif
+#if defined(__MSDOS__) && !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) && !defined(__32BIT__)
+#  define MAXSEG_64K
+#endif
+#ifdef MSDOS
+#  define UNALIGNED_OK
+#endif
+
+#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32))  && !defined(STDC)
+#  define STDC
+#endif
+#if (defined(__STDC__) || defined(__cplusplus)) && !defined(STDC)
+#  define STDC
+#endif
+
+#ifndef STDC
+#  ifndef const /* cannot use !defined(STDC) && !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 << (windowBits+2)   +  1 << (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="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << 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)) && !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__) && (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__) && 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)) && defined(ZLIB_DLL)
+#  include <windows.h>
+#  define EXPORT  WINAPI
+#else
+#  define EXPORT
+#endif
+
+#endif /* _ZCONF_H */
+/* --- zconf.h */
+
+#define ZLIB_VERSION "1.0.4P"
+
+/* 
+     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 < 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->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<<(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->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->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->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<<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 < 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 ("rb" or "wb") but can also include a compression level
+   ("wb9").  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) && !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="NeXTStep"
+#  else
+  system=`uname -s`
+  release=`uname -r`
+  machine=`uname -p`
+  arch=`uname -m`
+#  fi
+state="unknown"
+
+case $system in
+  Linux)
+    makext="linux";
+    ksrc="linux";
+    state="known";;
+  SunOS)
+    case $release in
+#      [0-3]*)	state="ancient";;
+#      4*)	state="known"; ksrc="sunos4"; makext="sunos4";;
+      5.[1-6]*)	state="known"; ksrc="solaris"; makext="sol2";;
+      5.[7-9]*)	state="known"; ksrc="solaris"; makext="sol2";
+              case $arch in
+		sun4u)	lp64='y';;
+		*)	;;
+	      esac;;
+    esac;;
+    NetBSD|FreeBSD|ULTRIX|OSF1|NeXTStep|SINIX-?|UNIX_SV|UNIX_System_V)
+      state="notincluded";;
+#    NetBSD)
+#      makext="bsd";
+#      case $release in
+#        0.*)	state="ancient";;
+#        1.0*)	state="ancient";;
+#        1.1*)	state="known"; ksrc="netbsd-1.1";;
+#        1.2*)	state="known"; ksrc="netbsd-1.2"; makext="netbsd-1.2";;
+#        1.[3-9]*|[2-9]*)
+#  		state="late"; ksrc="netbsd-1.2";;
+#      esac;;
+#    ULTRIX)
+#      makext="ultrix";
+#      case $release in
+#        [0-3]*)	state="ancient";;
+#        4.[01]*)	state="early"; ksrc="ultrix";;
+#        4.[234])	state="known"; ksrc="ultrix";;
+#      esac;;
+#    OSF1)
+#      makext="osf";
+#      case $release in
+#        V1.*)   state="neolithic"; ksrc="osf1";;
+#        V[23].*)	state="neolithic"; ksrc="osf1";;
+#        V4.*)	state="known"; ksrc="osf1";;
+#        V[5-9]*) state="late"; ksrc="osf1";;
+#      esac;;
+#    FreeBSD)
+#      makext="bsd";
+#      case $release in
+#        1.*)	state="known"; ksrc="freebsd-old";;
+#        2.[01]*)	state="known"; ksrc="freebsd-2.0";;
+#        2.2.[2-7]*) state="late"; ksrc="freebsd-2.0";;
+#        2.2.8*)   state="known"; ksrc="freebsd-2.2.8";;
+#        3.[0-1]*)	state="known"; ksrc="freebsd-3.0";;
+#      esac;;
+#    NeXTStep)
+#      makext="NeXT";
+#      ksrc="NeXT";
+#      state="known";;
+#    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 "$ksrc" ]; then :; else
+  state="notincluded"
+  unset ksrc
+fi
+
+case $state in
+  neolithic) 
+    echo "This is a newer release on an outdated OS ($system)."
+    echo " This software may or may not work on this OS."
+    echo " You may want to download an older version of PPP for this OS.";;
+  ancient)
+    echo "This is an old release of a supported OS ($system)."
+    echo "This software cannot be used as-is on this system,"
+    echo "but you may be able to port it.  Good luck!"
+    exit;;
+  early)
+    echo "This is an old release of a supported OS ($system)."
+    echo "This software should install and run on this system,"
+    echo "but it hasn't been tested.";;
+  late)
+    echo "This is a newer release of $system than is supported by"
+    echo "this software.  It may or may not work.";;
+  unknown)
+    echo "This software has not been ported to this system.  Sorry.";;
+  notincluded)
+    echo "Support for this system has not been included"
+    echo "in this distribution.  Sorry.";;
+esac
+
+orig_makext=$makext
+
+if [ -d "$ksrc" ]; then
+  echo "Creating links to Makefiles."
+  rm -f Makefile
+  ln -s $ksrc/Makefile.top Makefile
+  echo "  Makefile -> $ksrc/Makefile.top"
+  if [ "$ksrc" = solaris ]; then
+    # Point to 64-bit Makefile extension
+    if [ "$lp64" = y ]; then 
+      makext=$makext-64 
+    fi
+    rm -f $ksrc/Makefile
+    ln -s Makefile.$makext $ksrc/Makefile
+    echo "  $ksrc/Makefile -> Makefile.$makext"
+    # Restore extension
+    if [ "$lp64" = 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 "  $dir/Makefile -> Makefile.$makext"
+    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 "26 Sep 1999"
+.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 <glib.h>
+#include <gdk/gdk.h>
+#include <gtk/gtkwindow.h>
+#include <gtk/gtkmain.h>
+#include <gtk/gtkbutton.h>
+#include <gtk/gtkvbox.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtksignal.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+
+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<0)
+      syslog(LOG_ERR, "write error on outpipe: %m");
+    else
+      syslog(LOG_ERR, "short write on outpipe");
+    err=1;
+  }
+  gtk_main_quit();
+}
+
+int main(int argc, char **argv)
+{
+  GtkWidget *mainwindow, *vbox, *question, *answer, *ok;
+  char buf[1024];
+  gtk_init(&argc, &argv);
+
+  openlog(argv[0], LOG_PID, LOG_DAEMON);
+  if(argc!=4) {
+    syslog(LOG_WARNING, "Usage error");
+    return 1;
+  }
+  outfd=atoi(argv[3]);
+  mainwindow=gtk_window_new(GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_title(GTK_WINDOW(mainwindow), "pppgetpass");
+  gtk_signal_connect(GTK_OBJECT(mainwindow), "destroy",
+                     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] && argv[2][0])
+    snprintf(buf, sizeof buf, "Password for PPP client %s on server %s: ", argv[1], argv[2]);
+  else if(argv[1][0] && !argv[2][0])
+    snprintf(buf, sizeof buf, "Password for PPP client %s: ", argv[1]);
+  else if(!argv[1][0] && argv[2][0])
+    snprintf(buf, sizeof buf, "Password for PPP on server %s: ", argv[2]);
+  else
+    snprintf(buf, sizeof buf, "Enter PPP password: ");
+  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("OK");
+  gtk_box_pack_start(GTK_BOX(vbox), ok, FALSE, TRUE, 0);
+  gtk_signal_connect(GTK_OBJECT(ok), "clicked",
+                     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 "$DISPLAY" ]; then
+  exec pppgetpass.vt "$@"
+else
+  exec pppgetpass.gtk "$@"
+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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <syslog.h>
+#include <termios.h>
+#include <sys/vt.h>
+
+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("/dev/console", O_RDWR);
+
+  uid=getuid();
+  gid=getgid();
+  seteuid(uid);
+
+  openlog(argv[0], LOG_PID, LOG_DAEMON);
+
+  if(argc!=4) {
+    syslog(LOG_WARNING, "Usage error");
+    return 1;
+  }
+
+  if(console<0) {
+    syslog(LOG_ERR, "open(/dev/console): %m");
+    return 1;
+  }
+
+  if(ioctl(console, VT_GETSTATE, &origstate)<0) {
+    syslog(LOG_ERR, "VT_GETSTATE: %m");
+    return 1;
+  }
+
+  if(uid) {
+    if(!console_owner(uid, origstate.v_active)) {
+      int i;
+      for(i=0;i<64;++i) {
+        if(i!=origstate.v_active && console_owner(uid, i))
+          break;
+      }
+      if(i==64) {
+        syslog(LOG_WARNING, "run by uid %lu not at console", (unsigned long)uid);
+        return 1;
+      }
+    }
+  }
+
+  if(ioctl(console, VT_OPENQRY, &openvtnum)<0) {
+    syslog(LOG_ERR, "VT_OPENQRY: %m");
+    return 1;
+  }
+  if(openvtnum==-1) {
+    syslog(LOG_ERR, "No free VTs");
+    return 1;
+  }
+
+  snprintf(openvtname, sizeof openvtname, "/dev/tty%d", openvtnum);
+  seteuid(0);
+  openvt=open(openvtname, O_RDWR);
+  if(openvt<0) {
+    seteuid(uid);
+    syslog(LOG_ERR, "open(%s): %m", openvtname);
+    return 1;
+  }
+
+  chowned=fchown(openvt, uid, gid);
+  if(chowned<0) {
+    seteuid(uid);
+    syslog(LOG_ERR, "fchown(%s): %m", openvtname);
+    return 1;
+  }
+
+  close(console);
+
+  if(ioctl(openvt, VT_ACTIVATE, openvtnum)<0) {
+    seteuid(uid);
+    syslog(LOG_ERR, "VT_ACTIVATE(%d): %m", openvtnum);
+    return 1;
+  }
+
+  while(ioctl(openvt, VT_WAITACTIVE, openvtnum)<0) {
+    if(errno!=EINTR) {
+      ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+      seteuid(uid);
+      syslog(LOG_ERR, "VT_WAITACTIVE(%d): %m", openvtnum);
+      return 1;
+    }
+  }
+
+  seteuid(uid);
+  fp=fdopen(openvt, "r+");
+  if(!fp) {
+    seteuid(0);
+    ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+    seteuid(uid);
+    syslog(LOG_ERR, "fdopen(%s): %m", openvtname);
+    return 1;
+  }
+
+  if(tcgetattr(openvt, &t)<0) {
+    seteuid(0);
+    ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+    seteuid(uid);
+    syslog(LOG_ERR, "tcgetattr(%s): %m", openvtname);
+    return 1;
+  }
+  t.c_lflag &= ~ECHO;
+  if(tcsetattr(openvt, TCSANOW, &t)<0) {
+    seteuid(0);
+    ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+    seteuid(uid);
+    syslog(LOG_ERR, "tcsetattr(%s): %m", openvtname);
+    return 1;
+  }
+
+  if(fprintf(fp, "\033[2J\033[H")<0) {
+    seteuid(0);
+    ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+    seteuid(uid);
+    syslog(LOG_ERR, "write error on %s: %m", openvtname);
+    return 1;
+  }
+  if(argv[1][0] && argv[2][0]) {
+    if(fprintf(fp, "Password for PPP client %s on server %s: ", argv[1], argv[2])<0) {
+      seteuid(0);
+      ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+      seteuid(uid);
+      syslog(LOG_ERR, "write error on %s: %m", openvtname);
+      return 1;
+    }
+  } else if(argv[1][0] && !argv[2][0]) {
+    if(fprintf(fp, "Password for PPP client %s: ", argv[1])<0) {
+      syslog(LOG_ERR, "write error on %s: %m", openvtname);
+      seteuid(0);
+      ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+      seteuid(uid);
+      return 1;
+    }
+  } else if(!argv[1][0] && argv[2][0]) {
+    if(fprintf(fp, "Password for PPP on server %s: ", argv[2])<0) {
+      seteuid(0);
+      ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+      seteuid(uid);
+      syslog(LOG_ERR, "write error on %s: %m", openvtname);
+      return 1;
+    }
+  } else {
+    if(fprintf(fp, "Enter PPP password: ")<0) {
+      seteuid(0);
+      ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+      seteuid(uid);
+      syslog(LOG_ERR, "write error on %s: %m", 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, "read error on %s: %m", 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<0)
+      syslog(LOG_ERR, "write error on outpipe: %m");
+    else
+      syslog(LOG_ERR, "short write on outpipe");
+    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, "/dev/tty%d", cons);
+  if(stat(name, &st)<0) {
+    if(errno!=ENOENT)
+      syslog(LOG_ERR, "stat(%s): %m", 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 "AS IS" 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	"2.3.11"


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 "AS IS" 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] << 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) & 0x1F)	/* number of bits requested */
+#define BSD_VERSION(x)		((x) >> 5)	/* version of option format */
+#define BSD_CURRENT_VERSION	1		/* current version number */
+#define BSD_MAKE_OPT(v, n)	(((v) << 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) >> 4) + DEFLATE_MIN_SIZE)
+#define DEFLATE_METHOD(x)	((x) & 0x0F)
+#define DEFLATE_MAKE_OPT(w)	((((w) - DEFLATE_MIN_SIZE) << 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 "AS IS" 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] << 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) >> 8) ^ fcstab[((fcs) ^ (c)) & 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)) && !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 "AS IS" 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] << 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) & 0x1F)	/* number of bits requested */
+#define BSD_VERSION(x)		((x) >> 5)	/* version of option format */
+#define BSD_CURRENT_VERSION	1		/* current version number */
+#define BSD_MAKE_OPT(v, n)	(((v) << 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) >> 4) + DEFLATE_MIN_SIZE)
+#define DEFLATE_METHOD(x)	((x) & 0x0F)
+#define DEFLATE_MAKE_OPT(w)	((((w) - DEFLATE_MIN_SIZE) << 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 "AS IS" 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] << 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) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
+
+/*
+ * A 32-bit unsigned integral type.
+ */
+
+#if !defined(__BIT_TYPES_DEFINED__) && !defined(_BITYPES) \
+ && !defined(__FreeBSD__) && (NS_TARGET < 40) && !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 << 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 "AS IS" 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' << 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 "link active" 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 (van at helios.ee.lbl.gov), Dec 31, 1989:
+ *	- Initial distribution.
+ */
+
+#ifndef _SLCOMPRESS_H_
+#define _SLCOMPRESS_H_
+
+#define MAX_STATES 16		/* must be > 2 and < 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 & receiver); and compressed
+ * TCP (described above).
+ *
+ * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and
+ * is logically part of the 4-bit "changes" 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 "IP packet".
+ */
+
+/* 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
+
+
+/*
+ * "state" 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 & 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 (van at helios.ee.lbl.gov), Dec 31, 1989:
+ *	- Initial distribution.
+ */
+
+#ifndef _VJCOMPRESS_H_
+#define _VJCOMPRESS_H_
+
+#define MAX_STATES 16		/* must be > 2 and < 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 & receiver); and compressed
+ * TCP (described above).
+ *
+ * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and
+ * is logically part of the 4-bit "changes" 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 "IP packet".
+ */
+
+/* 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
+
+
+/*
+ * "state" 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 & 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 <pcap.h>
+
+/*
+ * 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) > (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 <net/net_globals.h>
+#endif
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stream.h>
+#include <net/ppp_defs.h>
+#include "ppp_mod.h"
+
+#ifdef SVR4
+#include <sys/byteorder.h>
+#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 <net/ppp-comp.h>
+
+#if DO_BSD_COMPRESS
+
+/*
+ * PPP "BSD compress" 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 << (b)) - 1)
+#define BADCODEM1	MAXCODE(BSD_MAX_BITS)
+
+#define BSD_HASH(prefix,suffix,hshift)	((((u_int32_t)(suffix)) << (hshift)) \
+					 ^ (u_int32_t)(prefix))
+#define BSD_KEY(prefix,suffix)		((((u_int32_t)(suffix)) << 16) \
+					 + (u_int32_t)(prefix))
+
+#define CHECK_GAP	10000		/* Ratio check interval */
+
+#define RATIO_SCALE_LOG	8
+#define RATIO_SCALE	(1<<RATIO_SCALE_LOG)
+#define RATIO_MAX	(0x7fffffff>>RATIO_SCALE_LOG)
+
+#define DECOMP_CHUNK	256
+
+/*
+ * clear the dictionary
+ */
+static void
+bsd_clear(db)
+    struct bsd_db *db;
+{
+    db->clear_count++;
+    db->max_ent = FIRST-1;
+    db->n_bits = BSD_INIT_BITS;
+    db->ratio = 0;
+    db->bytes_out = 0;
+    db->in_count = 0;
+    db->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->in_count >= db->checkpoint) {
+	/* age the ratio by limiting the size of the counts */
+	if (db->in_count >= RATIO_MAX
+	    || db->bytes_out >= RATIO_MAX) {
+	    db->in_count -= db->in_count/4;
+	    db->bytes_out -= db->bytes_out/4;
+	}
+
+	db->checkpoint = db->in_count + CHECK_GAP;
+
+	if (db->max_ent >= db->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->in_count <= RATIO_MAX.
+	     */
+	    new_ratio = db->in_count << RATIO_SCALE_LOG;
+	    if (db->bytes_out != 0)
+		new_ratio /= db->bytes_out;
+
+	    if (new_ratio < db->ratio || new_ratio < 1 * RATIO_SCALE) {
+		bsd_clear(db);
+		return 1;
+	    }
+	    db->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->unc_bytes = db->uncomp_bytes;
+    stats->unc_packets = db->uncomp_count;
+    stats->comp_bytes = db->comp_bytes;
+    stats->comp_packets = db->comp_count;
+    stats->inc_bytes = db->incomp_bytes;
+    stats->inc_packets = db->incomp_count;
+    stats->ratio = db->in_count;
+    out = db->bytes_out;
+    if (stats->ratio <= 0x7fffff)
+	stats->ratio <<= 8;
+    else
+	out >>= 8;
+    if (out != 0)
+	stats->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->seqno = 0;
+    bsd_clear(db);
+    db->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->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->dict));
+
+    if (!decomp) {
+	db->lens = NULL;
+    } else {
+#ifdef __osf__
+	db->lens = (u_short *) ALLOC_SLEEP((maxmaxcode+1) * sizeof(db->lens[0]));
+#else
+	db->lens = (u_short *) ALLOC_NOSLEEP((maxmaxcode+1) * sizeof(db->lens[0]));
+#endif
+	if (!db->lens) {
+	    FREE(db, newlen);
+	    return NULL;
+	}
+    }
+
+    db->totlen = newlen;
+    db->hsize = hsize;
+    db->hshift = hshift;
+    db->maxmaxcode = maxmaxcode;
+    db->maxbits = bits;
+
+    return (void *) db;
+}
+
+static void
+bsd_free(state)
+    void *state;
+{
+    struct bsd_db *db = (struct bsd_db *) state;
+
+    if (db->lens)
+	FREE(db->lens, (db->maxmaxcode+1) * sizeof(db->lens[0]));
+    FREE(db, db->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 < 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->maxbits
+	|| decomp && db->lens == NULL)
+	return 0;
+
+    if (decomp) {
+	i = LAST+1;
+	while (i != 0)
+	    db->lens[--i] = 1;
+    }
+    i = db->hsize;
+    while (i != 0) {
+	db->dict[--i].codem1 = BADCODEM1;
+	db->dict[i].cptr = 0;
+    }
+
+    db->unit = unit;
+    db->hdrlen = hdrlen;
+    db->mru = mru;
+    if (debug)
+	db->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->hshift;
+    u_int max_ent = db->max_ent;
+    u_int n_bits = db->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 >= cp_end) {				\
+	    m->b_wptr = wptr;				\
+	    m = m->b_cont;				\
+	    if (m) {					\
+		wptr = m->b_wptr;			\
+		cp_end = m->b_datap->db_lim;		\
+	    } else					\
+		wptr = NULL;				\
+	}						\
+    }							\
+    ++olen;						\
+}
+
+#define OUTPUT(ent) {					\
+    bitno -= n_bits;					\
+    accm |= ((ent) << bitno);				\
+    do {						\
+	PUTBYTE(accm >> 24);				\
+	accm <<= 8;					\
+	bitno += 8;					\
+    } while (bitno <= 24);				\
+}
+
+    /*
+     * First get the protocol and check that we're
+     * interested in this packet.
+     */
+    *mretp = NULL;
+    rptr = mp->b_rptr;
+    if (rptr + PPP_HDRLEN > mp->b_wptr) {
+	if (!pullupmsg(mp, PPP_HDRLEN))
+	    return 0;
+	rptr = mp->b_rptr;
+    }
+    ent = PPP_PROTOCOL(rptr);		/* get the protocol */
+    if (ent < 0x21 || ent > 0xf9)
+	return 0;
+
+    /* Don't generate compressed packets which are larger than
+       the uncompressed packet. */
+    if (maxolen > slen)
+	maxolen = slen;
+
+    /* Allocate enough message blocks to give maxolen total space. */
+    mnp = &mret;
+    for (olen = maxolen; olen > 0; ) {
+	m = allocb((olen < 4096? olen: 4096), BPRI_MED);
+	*mnp = m;
+	if (m == NULL) {
+	    if (mret != NULL) {
+		freemsg(mret);
+		mnp = &mret;
+	    }
+	    break;
+	}
+	mnp = &m->b_cont;
+	olen -= m->b_datap->db_lim - m->b_wptr;
+    }
+    *mnp = NULL;
+
+    if ((m = mret) != NULL) {
+	wptr = m->b_wptr;
+	cp_end = m->b_datap->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->seqno >> 8;
+	wptr[5] = db->seqno;
+	wptr += PPP_HDRLEN + BSD_OVHD;
+    }
+    ++db->seqno;
+    rptr += PPP_HDRLEN;
+
+    slen = mp->b_wptr - rptr;
+    ilen = slen + 1;
+    np = mp->b_cont;
+    for (;;) {
+	if (slen <= 0) {
+	    if (!np)
+		break;
+	    rptr = np->b_rptr;
+	    slen = np->b_wptr - rptr;
+	    np = np->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 = &db->dict[hval];
+
+	/* Validate and then check the entry. */
+	if (dictp->codem1 >= max_ent)
+	    goto nomatch;
+	if (dictp->f.fcode == fcode) {
+	    ent = dictp->codem1+1;
+	    continue;	/* found (prefix,suffix) */
+	}
+
+	/* continue probing until a match or invalid entry */
+	disp = (hval == 0) ? 1 : hval;
+	do {
+	    hval += disp;
+	    if (hval >= db->hsize)
+		hval -= db->hsize;
+	    dictp = &db->dict[hval];
+	    if (dictp->codem1 >= max_ent)
+		goto nomatch;
+	} while (dictp->f.fcode != fcode);
+	ent = dictp->codem1 + 1;	/* finally found (prefix,suffix) */
+	continue;
+
+    nomatch:
+	OUTPUT(ent);		/* output the prefix */
+
+	/* code -> hashtable */
+	if (max_ent < db->maxmaxcode) {
+	    struct bsd_dict *dictp2;
+	    /* expand code size if needed */
+	    if (max_ent >= MAXCODE(n_bits))
+		db->n_bits = ++n_bits;
+
+	    /* Invalidate old hash table entry using
+	     * this code, and then take it over.
+	     */
+	    dictp2 = &db->dict[max_ent+1];
+	    if (db->dict[dictp2->cptr].codem1 == max_ent)
+		db->dict[dictp2->cptr].codem1 = BADCODEM1;
+	    dictp2->cptr = hval;
+	    dictp->codem1 = max_ent;
+	    dictp->f.fcode = fcode;
+
+	    db->max_ent = ++max_ent;
+	}
+	ent = c;
+    }
+
+    OUTPUT(ent);		/* output the last code */
+    db->bytes_out += olen;
+    db->in_count += ilen;
+    if (bitno < 32)
+	++db->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 << (bitno-8))) >> 24);
+
+    /*
+     * Increase code size if we would have without the packet
+     * boundary and as the decompressor will.
+     */
+    if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode)
+	db->n_bits++;
+
+    db->uncomp_bytes += ilen;
+    ++db->uncomp_count;
+    if (olen + PPP_HDRLEN + BSD_OVHD > maxolen && mret != NULL) {
+	/* throw away the compressed stuff if it is longer than uncompressed */
+	freemsg(mret);
+	mret = NULL;
+	++db->incomp_count;
+	db->incomp_bytes += ilen;
+    } else if (wptr != NULL) {
+	m->b_wptr = wptr;
+	if (m->b_cont) {
+	    freemsg(m->b_cont);
+	    m->b_cont = NULL;
+	}
+	++db->comp_count;
+	db->comp_bytes += olen + BSD_OVHD;
+    }
+
+    *mretp = mret;
+    return olen + PPP_HDRLEN + BSD_OVHD;
+#undef OUTPUT
+#undef PUTBYTE
+}
+
+
+/*
+ * Update the "BSD Compress" 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->hshift;
+    u_int max_ent = db->max_ent;
+    u_int n_bits = db->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->b_rptr;
+    if (rptr + PPP_HDRLEN > dmsg->b_wptr) {
+	if (!pullupmsg(dmsg, PPP_HDRLEN))
+	    return;
+	rptr = dmsg->b_rptr;
+    }
+    ent = PPP_PROTOCOL(rptr);		/* get the protocol */
+    if (ent < 0x21 || ent > 0xf9)
+	return;
+
+    db->seqno++;
+    ilen = 1;		/* count the protocol as 1 byte */
+    rptr += PPP_HDRLEN;
+    for (;;) {
+	slen = dmsg->b_wptr - rptr;
+	if (slen <= 0) {
+	    dmsg = dmsg->b_cont;
+	    if (!dmsg)
+		break;
+	    rptr = dmsg->b_rptr;
+	    continue;		/* skip zero-length buffers */
+	}
+	ilen += slen;
+
+	do {
+	    c = *rptr++;
+	    fcode = BSD_KEY(ent, c);
+	    hval = BSD_HASH(ent, c, hshift);
+	    dictp = &db->dict[hval];
+
+	    /* validate and then check the entry */
+	    if (dictp->codem1 >= max_ent)
+		goto nomatch;
+	    if (dictp->f.fcode == fcode) {
+		ent = dictp->codem1+1;
+		continue;   /* found (prefix,suffix) */
+	    }
+
+	    /* continue probing until a match or invalid entry */
+	    disp = (hval == 0) ? 1 : hval;
+	    do {
+		hval += disp;
+		if (hval >= db->hsize)
+		    hval -= db->hsize;
+		dictp = &db->dict[hval];
+		if (dictp->codem1 >= max_ent)
+		    goto nomatch;
+	    } while (dictp->f.fcode != fcode);
+	    ent = dictp->codem1+1;
+	    continue;	/* finally found (prefix,suffix) */
+
+	nomatch:		/* output (count) the prefix */
+	    bitno += n_bits;
+
+	    /* code -> hashtable */
+	    if (max_ent < db->maxmaxcode) {
+		struct bsd_dict *dictp2;
+		/* expand code size if needed */
+		if (max_ent >= MAXCODE(n_bits))
+		    db->n_bits = ++n_bits;
+
+		/* Invalidate previous hash table entry
+		 * assigned this code, and then take it over.
+		 */
+		dictp2 = &db->dict[max_ent+1];
+		if (db->dict[dictp2->cptr].codem1 == max_ent)
+		    db->dict[dictp2->cptr].codem1 = BADCODEM1;
+		dictp2->cptr = hval;
+		dictp->codem1 = max_ent;
+		dictp->f.fcode = fcode;
+
+		db->max_ent = ++max_ent;
+		db->lens[max_ent] = db->lens[ent]+1;
+	    }
+	    ent = c;
+	} while (--slen != 0);
+    }
+    bitno += n_bits;		/* output (count) the last code */
+    db->bytes_out += bitno/8;
+    db->in_count += ilen;
+    (void)bsd_check(db);
+
+    ++db->incomp_count;
+    db->incomp_bytes += ilen;
+    ++db->uncomp_count;
+    db->uncomp_bytes += ilen;
+
+    /* Increase code size if we would have without the packet
+     * boundary and as the decompressor will.
+     */
+    if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode)
+	db->n_bits++;
+}
+
+
+/*
+ * Decompress "BSD Compress"
+ *
+ * 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 "after" 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->max_ent;
+    u_int32_t accm = 0;
+    u_int bitno = 32;		/* 1st valid bit in accm */
+    u_int n_bits = db->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->b_rptr;
+    if (rptr + PPP_HDRLEN + BSD_OVHD >= cmsg->b_wptr) {
+	if (!pullupmsg(cmsg, PPP_HDRLEN + BSD_OVHD + 1)) {
+	    if (db->debug)
+		printf("bsd_decomp%d: failed to pullup\n", db->unit);
+	    return DECOMP_ERROR;
+	}
+	rptr = cmsg->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] << 8) + rptr[1];
+    rptr += BSD_OVHD;
+    ilen = len = cmsg->b_wptr - rptr;
+
+    /*
+     * Check the sequence number and give up if it is not what we expect.
+     */
+    if (seq != db->seqno++) {
+	if (db->debug)
+	    printf("bsd_decomp%d: bad sequence # %d, expected %d\n",
+		   db->unit, seq, db->seqno - 1);
+	return DECOMP_ERROR;
+    }
+
+    /*
+     * Allocate one message block to start with.
+     */
+    if ((dmsg = allocb(DECOMP_CHUNK + db->hdrlen, BPRI_MED)) == NULL)
+	return DECOMP_ERROR;
+    mret = dmsg;
+    dmsg->b_wptr += db->hdrlen;
+    dmsg->b_rptr = wptr = dmsg->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->b_datap->db_lim - wptr;
+
+    oldcode = CLEAR;
+    explen = 0;
+    for (;;) {
+	if (len == 0) {
+	    cmsg = cmsg->b_cont;
+	    if (!cmsg)		/* quit at end of message */
+		break;
+	    rptr = cmsg->b_rptr;
+	    len = cmsg->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++ << bitno;
+	--len;
+	if (tgtbitno < bitno)
+	    continue;
+	incode = accm >> tgtbitno;
+	accm <<= 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 > 0 || cmsg->b_cont != 0) {
+		if (cmsg->b_cont)
+		    len += msgdsize(cmsg->b_cont);
+		if (len > 0) {
+		    freemsg(dmsg);
+		    if (db->debug)
+			printf("bsd_decomp%d: bad CLEAR\n", db->unit);
+		    return DECOMP_FATALERROR;
+		}
+	    }
+	    bsd_clear(db);
+	    explen = ilen = 0;
+	    break;
+	}
+
+	if (incode > max_ent + 2 || incode > db->maxmaxcode
+	    || incode > max_ent && oldcode == CLEAR) {
+	    freemsg(dmsg);
+	    if (db->debug) {
+		printf("bsd_decomp%d: bad code 0x%x oldcode=0x%x ",
+		       db->unit, incode, oldcode);
+		printf("max_ent=0x%x dlen=%d seqno=%d\n",
+		       max_ent, dlen, db->seqno);
+	    }
+	    return DECOMP_FATALERROR;	/* probably a bug */
+	}
+
+	/* Special case for KwKwK string. */
+	if (incode > max_ent) {
+	    finchar = oldcode;
+	    extra = 1;
+	} else {
+	    finchar = incode;
+	    extra = 0;
+	}
+
+	codelen = db->lens[finchar];
+	explen += codelen + extra;
+	if (explen > db->mru + 1) {
+	    freemsg(dmsg);
+	    if (db->debug)
+		printf("bsd_decomp%d: ran out of mru\n", db->unit);
+	    return DECOMP_FATALERROR;
+	}
+
+	/*
+	 * Decode this code and install it in the decompressed buffer.
+	 */
+	space -= codelen + extra;
+	if (space < 0) {
+	    /* Allocate another message block. */
+	    dmsg->b_wptr = wptr;
+	    dlen = codelen + extra;
+	    if (dlen < DECOMP_CHUNK)
+		dlen = DECOMP_CHUNK;
+	    if ((dmsg->b_cont = allocb(dlen, BPRI_MED)) == NULL) {
+		freemsg(dmsg);
+		return DECOMP_ERROR;
+	    }
+	    dmsg = dmsg->b_cont;
+	    wptr = dmsg->b_wptr;
+	    space = dmsg->b_datap->db_lim - wptr - codelen - extra;
+	}
+	p = (wptr += codelen);
+	while (finchar > LAST) {
+	    dictp = &db->dict[db->dict[finchar].cptr];
+#ifdef DEBUG
+	    --codelen;
+	    if (codelen <= 0) {
+		freemsg(dmsg);
+		printf("bsd_decomp%d: fell off end of chain ", db->unit);
+		printf("0x%x at 0x%x by 0x%x, max_ent=0x%x\n",
+		       incode, finchar, db->dict[finchar].cptr, max_ent);
+		return DECOMP_FATALERROR;
+	    }
+	    if (dictp->codem1 != finchar-1) {
+		freemsg(dmsg);
+		printf("bsd_decomp%d: bad code chain 0x%x finchar=0x%x ",
+		       db->unit, incode, finchar);
+		printf("oldcode=0x%x cptr=0x%x codem1=0x%x\n", oldcode,
+		       db->dict[finchar].cptr, dictp->codem1);
+		return DECOMP_FATALERROR;
+	    }
+#endif
+	    *--p = dictp->f.hs.suffix;
+	    finchar = dictp->f.hs.prefix;
+	}
+	*--p = finchar;
+
+#ifdef DEBUG
+	if (--codelen != 0)
+	    printf("bsd_decomp%d: short by %d after code 0x%x, max_ent=0x%x\n",
+		   db->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 && max_ent < db->maxmaxcode) {
+	    struct bsd_dict *dictp2;
+	    u_int32_t fcode;
+	    int hval, disp;
+
+	    fcode = BSD_KEY(oldcode,finchar);
+	    hval = BSD_HASH(oldcode,finchar,db->hshift);
+	    dictp = &db->dict[hval];
+
+	    /* look for a free hash table entry */
+	    if (dictp->codem1 < max_ent) {
+		disp = (hval == 0) ? 1 : hval;
+		do {
+		    hval += disp;
+		    if (hval >= db->hsize)
+			hval -= db->hsize;
+		    dictp = &db->dict[hval];
+		} while (dictp->codem1 < max_ent);
+	    }
+
+	    /*
+	     * Invalidate previous hash table entry
+	     * assigned this code, and then take it over
+	     */
+	    dictp2 = &db->dict[max_ent+1];
+	    if (db->dict[dictp2->cptr].codem1 == max_ent) {
+		db->dict[dictp2->cptr].codem1 = BADCODEM1;
+	    }
+	    dictp2->cptr = hval;
+	    dictp->codem1 = max_ent;
+	    dictp->f.fcode = fcode;
+
+	    db->max_ent = ++max_ent;
+	    db->lens[max_ent] = db->lens[oldcode]+1;
+
+	    /* Expand code size if needed. */
+	    if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) {
+		db->n_bits = ++n_bits;
+		tgtbitno = 32-n_bits;
+	    }
+	}
+	oldcode = incode;
+    }
+    dmsg->b_wptr = wptr;
+
+    /*
+     * Keep the checkpoint right so that incompressible packets
+     * clear the dictionary at the right times.
+     */
+    db->bytes_out += ilen;
+    db->in_count += explen;
+    if (bsd_check(db) && db->debug) {
+	printf("bsd_decomp%d: peer should have cleared dictionary\n",
+	       db->unit);
+    }
+
+    ++db->comp_count;
+    db->comp_bytes += ilen + BSD_OVHD;
+    ++db->uncomp_count;
+    db->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 "AS IS" 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 <net/net_globals.h>
+#endif
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stream.h>
+#include <net/ppp_defs.h>
+#include "ppp_mod.h"
+
+#define PACKETPTR	mblk_t *
+#include <net/ppp-comp.h>
+
+#ifdef __osf__
+#include "zlib.h"
+#else
+#include "../common/zlib.h"
+#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->size = size;
+    z->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->size = size;
+    z->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->guard != GUARD_MAGIC) {
+	printf("ppp: z_free of corrupted chunk at %x (%x, %x)\n",
+	       z, z->size, z->guard);
+	return;
+    }
+    FREE(z, z->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 && 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 < 9 || w_size > 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->strm.next_in = NULL;
+    state->strm.zalloc = (alloc_func) z_alloc_init;
+    state->strm.zfree = (free_func) z_free;
+    if (deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION, DEFLATE_METHOD_VAL,
+		     -w_size, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
+	FREE(state, sizeof(*state));
+	return NULL;
+    }
+
+    state->strm.zalloc = (alloc_func) z_alloc;
+    state->w_size = w_size;
+    bzero(&state->stats, sizeof(state->stats));
+    return (void *) state;
+}
+
+static void
+z_comp_free(arg)
+    void *arg;
+{
+    struct deflate_state *state = (struct deflate_state *) arg;
+
+    deflateEnd(&state->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 < CILEN_DEFLATE
+	|| (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT)
+	|| options[1] != CILEN_DEFLATE
+	|| DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
+	|| DEFLATE_SIZE(options[2]) != state->w_size
+	|| options[3] != DEFLATE_CHK_SEQUENCE)
+	return 0;
+
+    state->seqno = 0;
+    state->unit = unit;
+    state->hdrlen = hdrlen;
+    state->debug = debug;
+
+    deflateReset(&state->strm);
+
+    return 1;
+}
+
+static void
+z_comp_reset(arg)
+    void *arg;
+{
+    struct deflate_state *state = (struct deflate_state *) arg;
+
+    state->seqno = 0;
+    deflateReset(&state->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->b_rptr;
+    if (rptr + PPP_HDRLEN > mp->b_wptr) {
+	if (!pullupmsg(mp, PPP_HDRLEN))
+	    return 0;
+	rptr = mp->b_rptr;
+    }
+    proto = PPP_PROTOCOL(rptr);
+    if (proto > 0x3fff || proto == 0xfd || proto == 0xfb)
+	return orig_len;
+
+    /* Allocate one mblk initially. */
+    if (maxolen > orig_len)
+	maxolen = orig_len;
+    if (maxolen <= PPP_HDRLEN + 2) {
+	wspace = 0;
+	m = NULL;
+    } else {
+	wspace = maxolen + state->hdrlen;
+	if (wspace > 4096)
+	    wspace = 4096;
+	m = allocb(wspace, BPRI_MED);
+    }
+    if (m != NULL) {
+	*mret = m;
+	if (state->hdrlen + PPP_HDRLEN + 2 < wspace) {
+	    m->b_rptr += state->hdrlen;
+	    m->b_wptr = m->b_rptr;
+	    wspace -= state->hdrlen;
+	}
+	wptr = m->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 >> 8;
+	wptr[3] = PPP_COMP;
+	wptr += PPP_HDRLEN;
+	wptr[0] = state->seqno >> 8;
+	wptr[1] = state->seqno;
+	wptr += 2;
+	state->strm.next_out = wptr;
+	state->strm.avail_out = wspace - (PPP_HDRLEN + 2);
+    } else {
+	state->strm.next_out = NULL;
+	state->strm.avail_out = 1000000;
+    }
+    ++state->seqno;
+
+    rptr += (proto > 0xff)? 2: 3;	/* skip 1st proto byte if 0 */
+    state->strm.next_in = rptr;
+    state->strm.avail_in = mp->b_wptr - rptr;
+    mp = mp->b_cont;
+    flush = (mp == NULL)? Z_PACKET_FLUSH: Z_NO_FLUSH;
+    olen = 0;
+    for (;;) {
+	r = deflate(&state->strm, flush);
+	if (r != Z_OK) {
+	    printf("z_compress: deflate returned %d (%s)\n",
+		   r, (state->strm.msg? state->strm.msg: ""));
+	    break;
+	}
+	if (flush != Z_NO_FLUSH && state->strm.avail_out != 0)
+	    break;		/* all done */
+	if (state->strm.avail_in == 0 && mp != NULL) {
+	    state->strm.next_in = mp->b_rptr;
+	    state->strm.avail_in = mp->b_wptr - mp->b_rptr;
+	    mp = mp->b_cont;
+	    if (mp == NULL)
+		flush = Z_PACKET_FLUSH;
+	}
+	if (state->strm.avail_out == 0) {
+	    if (m != NULL) {
+		m->b_wptr += wspace;
+		olen += wspace;
+		wspace = maxolen - olen;
+		if (wspace <= 0) {
+		    wspace = 0;
+		    m->b_cont = NULL;
+		} else {
+		    if (wspace < 32)
+			wspace = 32;
+		    else if (wspace > 4096)
+			wspace = 4096;
+		    m->b_cont = allocb(wspace, BPRI_MED);
+		}
+		m = m->b_cont;
+		if (m != NULL) {
+		    state->strm.next_out = m->b_wptr;
+		    state->strm.avail_out = wspace;
+		}
+	    }
+	    if (m == NULL) {
+		state->strm.next_out = NULL;
+		state->strm.avail_out = 1000000;
+	    }
+	}
+    }
+    if (m != NULL) {
+	m->b_wptr += wspace - state->strm.avail_out;
+	olen += wspace - state->strm.avail_out;
+    }
+
+    /*
+     * See if we managed to reduce the size of the packet.
+     */
+    if (olen < orig_len && m != NULL) {
+	state->stats.comp_bytes += olen;
+	state->stats.comp_packets++;
+    } else {
+	if (*mret != NULL) {
+	    freemsg(*mret);
+	    *mret = NULL;
+	}
+	state->stats.inc_bytes += orig_len;
+	state->stats.inc_packets++;
+	olen = orig_len;
+    }
+    state->stats.unc_bytes += orig_len;
+    state->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->stats;
+    stats->ratio = stats->unc_bytes;
+    out = stats->comp_bytes + stats->unc_bytes;
+    if (stats->ratio <= 0x7ffffff)
+	stats->ratio <<= 8;
+    else
+	out >>= 8;
+    if (out != 0)
+	stats->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[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 < 9 || w_size > 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->strm.next_out = NULL;
+    state->strm.zalloc = (alloc_func) z_alloc_init;
+    state->strm.zfree = (free_func) z_free;
+    if (inflateInit2(&state->strm, -w_size) != Z_OK) {
+	FREE(state, sizeof(*state));
+	return NULL;
+    }
+
+    state->strm.zalloc = (alloc_func) z_alloc;
+    state->w_size = w_size;
+    bzero(&state->stats, sizeof(state->stats));
+    return (void *) state;
+}
+
+static void
+z_decomp_free(arg)
+    void *arg;
+{
+    struct deflate_state *state = (struct deflate_state *) arg;
+
+    inflateEnd(&state->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 < CILEN_DEFLATE
+	|| (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT)
+	|| options[1] != CILEN_DEFLATE
+	|| DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
+	|| DEFLATE_SIZE(options[2]) != state->w_size
+	|| options[3] != DEFLATE_CHK_SEQUENCE)
+	return 0;
+
+    state->seqno = 0;
+    state->unit = unit;
+    state->hdrlen = hdrlen;
+    state->debug = debug;
+    state->mru = mru;
+
+    inflateReset(&state->strm);
+
+    return 1;
+}
+
+static void
+z_decomp_reset(arg)
+    void *arg;
+{
+    struct deflate_state *state = (struct deflate_state *) arg;
+
+    state->seqno = 0;
+    inflateReset(&state->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 "after" 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->b_rptr;
+    for (i = 0; i < PPP_HDRLEN + DEFLATE_OVHD; ++i) {
+	while (rptr >= mi->b_wptr) {
+	    mi = mi->b_cont;
+	    if (mi == NULL)
+		return DECOMP_ERROR;
+	    rptr = mi->b_rptr;
+	}
+	hdr[i] = *rptr++;
+    }
+
+    /* Check the sequence number. */
+    seq = (hdr[PPP_HDRLEN] << 8) + hdr[PPP_HDRLEN+1];
+    if (seq != state->seqno) {
+#if !DEFLATE_DEBUG
+	if (state->debug)
+#endif
+	    printf("z_decompress%d: bad seq # %d, expected %d\n",
+		   state->unit, seq, state->seqno);
+	return DECOMP_ERROR;
+    }
+    ++state->seqno;
+
+    /* Allocate an output message block. */
+    mo = allocb(DECOMP_CHUNK + state->hdrlen, BPRI_MED);
+    if (mo == NULL)
+	return DECOMP_ERROR;
+    mo_head = mo;
+    mo->b_cont = NULL;
+    mo->b_rptr += state->hdrlen;
+    mo->b_wptr = wptr = mo->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->strm.next_in = rptr;
+    state->strm.avail_in = mi->b_wptr - rptr;
+    mi = mi->b_cont;
+    flush = (mi == NULL)? Z_PACKET_FLUSH: Z_NO_FLUSH;
+    rlen = state->strm.avail_in + PPP_HDRLEN + DEFLATE_OVHD;
+    state->strm.next_out = wptr + 3;
+    state->strm.avail_out = 1;
+    decode_proto = 1;
+
+    /*
+     * Call inflate, supplying more input or output as needed.
+     */
+    for (;;) {
+	r = inflate(&state->strm, flush);
+	if (r != Z_OK) {
+#if !DEFLATE_DEBUG
+	    if (state->debug)
+#endif
+		printf("z_decompress%d: inflate returned %d (%s)\n",
+		       state->unit, r, (state->strm.msg? state->strm.msg: ""));
+	    freemsg(mo_head);
+	    return DECOMP_FATALERROR;
+	}
+	if (flush != Z_NO_FLUSH && state->strm.avail_out != 0)
+	    break;		/* all done */
+	if (state->strm.avail_in == 0 && mi != NULL) {
+	    state->strm.next_in = mi->b_rptr;
+	    state->strm.avail_in = mi->b_wptr - mi->b_rptr;
+	    rlen += state->strm.avail_in;
+	    mi = mi->b_cont;
+	    if (mi == NULL)
+		flush = Z_PACKET_FLUSH;
+	}
+	if (state->strm.avail_out == 0) {
+	    if (decode_proto) {
+		state->strm.avail_out = ospace - PPP_HDRLEN;
+		if ((wptr[3] & 1) == 0) {
+		    /* 2-byte protocol field */
+		    wptr[2] = wptr[3];
+		    --state->strm.next_out;
+		    ++state->strm.avail_out;
+		}
+		decode_proto = 0;
+	    } else {
+		mo->b_wptr += ospace;
+		olen += ospace;
+		mo->b_cont = allocb(DECOMP_CHUNK, BPRI_MED);
+		mo = mo->b_cont;
+		if (mo == NULL) {
+		    freemsg(mo_head);
+		    return DECOMP_ERROR;
+		}
+		state->strm.next_out = mo->b_rptr;
+		state->strm.avail_out = ospace = DECOMP_CHUNK;
+	    }
+	}
+    }
+    if (decode_proto) {
+	freemsg(mo_head);
+	return DECOMP_ERROR;
+    }
+    mo->b_wptr += ospace - state->strm.avail_out;
+    olen += ospace - state->strm.avail_out;
+
+#if DEFLATE_DEBUG
+    if (olen > state->mru + PPP_HDRLEN)
+	printf("ppp_deflate%d: exceeded mru (%d > %d)\n",
+	       state->unit, olen, state->mru + PPP_HDRLEN);
+#endif
+
+    state->stats.unc_bytes += olen;
+    state->stats.unc_packets++;
+    state->stats.comp_bytes += rlen;
+    state->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->b_rptr;
+    if (rptr + PPP_HDRLEN > mi->b_wptr) {
+	if (!pullupmsg(mi, PPP_HDRLEN))
+	    return;
+	rptr = mi->b_rptr;
+    }
+    proto = PPP_PROTOCOL(rptr);
+    if (proto > 0x3fff || proto == 0xfd || proto == 0xfb)
+	return;
+
+    ++state->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->b_wptr - mi->b_rptr;
+    state->strm.next_in = rptr + 3;
+    state->strm.avail_in = rlen - 3;
+    if (proto > 0xff) {
+	--state->strm.next_in;
+	++state->strm.avail_in;
+    }
+    for (;;) {
+	r = inflateIncomp(&state->strm);
+	if (r != Z_OK) {
+	    /* gak! */
+#if !DEFLATE_DEBUG
+	    if (state->debug)
+#endif
+		printf("z_incomp%d: inflateIncomp returned %d (%s)\n",
+		       state->unit, r, (state->strm.msg? state->strm.msg: ""));
+	    return;
+	}
+	mi = mi->b_cont;
+	if (mi == NULL)
+	    break;
+	state->strm.next_in = mi->b_rptr;
+	state->strm.avail_in = mi->b_wptr - mi->b_rptr;
+	rlen += state->strm.avail_in;
+    }
+
+    /*
+     * Update stats.
+     */
+    state->stats.inc_bytes += rlen;
+    state->stats.inc_packets++;
+    state->stats.unc_bytes += rlen;
+    state->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 "AS IS" 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 <sys/types.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/netisr.h>
+#include <net/ppp_defs.h>
+#include <net/pppio.h>
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#ifdef __osf__
+#include <sys/ioctl.h>
+#include <net/if_types.h>
+#else
+#include <sys/sockio.h>
+#endif
+#include "ppp_mod.h"
+
+#include <sys/stream.h>
+
+#ifdef SNIT_SUPPORT
+#include <sys/time.h>
+#include <net/nit_if.h>
+#include <netinet/if_ether.h>
+#endif
+
+#ifdef __osf__
+#define SIOCSIFMTU SIOCSIPMTU
+#define SIOCGIFMTU SIOCRIPMTU
+#define IFA_ADDR(ifa)   (*(ifa)->ifa_addr)
+#else
+#define IFA_ADDR(ifa)   ((ifa)->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, "if_ppp", 0, INFPSZ, 4096, 128
+};
+
+static struct qinit rinit = {
+    if_ppp_rput, NULL, if_ppp_open, if_ppp_close, NULL, &minfo, NULL
+};
+
+static struct qinit winit = {
+    if_ppp_wput, NULL, NULL, NULL, NULL, &minfo, NULL
+};
+
+struct streamtab if_pppinfo = {
+    &rinit, &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 > 0)
+	return EBUSY;
+    for (i = 0; i < 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->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->q_ptr = (caddr_t) sp;
+	WR(q)->q_ptr = (caddr_t) sp;
+	sp->unit = -1;		/* no interface unit attached at present */
+	sp->q = WR(q);
+	sp->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->q_ptr;
+    if (sp != 0) {
+	if (sp->flags & DBGLOG)
+	    printf("if_ppp closed, q=%x sp=%x\n", q, sp);
+	if (sp->unit >= 0) {
+	    if (sp->unit < ppp_nalloc) {
+		states[sp->unit] = 0;
+		ifp = ifs[sp->unit];
+		if (ifp != 0)
+		    ifp->if_flags &= ~(IFF_UP | IFF_RUNNING);
+#ifdef DEBUG
+	    } else {
+		printf("if_ppp: unit %d nonexistent!\n", sp->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->q_ptr;
+    switch (mp->b_datap->db_type) {
+    case M_DATA:
+	/*
+	 * Now why would we be getting data coming in here??
+	 */
+	if (sp->flags & DBGLOG)
+	    printf("if_ppp: got M_DATA len=%d\n", msgdsize(mp));
+	freemsg(mp);
+	break;
+
+    case M_IOCTL:
+	iop = (struct iocblk *) mp->b_rptr;
+	error = EINVAL;
+
+	if (sp->flags & DBGLOG)
+	    printf("if_ppp: got ioctl cmd=%x count=%d\n",
+		   iop->ioc_cmd, iop->ioc_count);
+
+	switch (iop->ioc_cmd) {
+	case PPPIO_NEWPPA:		/* well almost */
+	    if (iop->ioc_count != sizeof(int) || sp->unit >= 0)
+		break;
+	    if ((error = NOTSUSER()) != 0)
+		break;
+	    unit = *(int *)mp->b_cont->b_rptr;
+
+	    /* Check that this unit isn't already in use */
+	    if (unit < ppp_nalloc && states[unit] != 0) {
+		error = EADDRINUSE;
+		break;
+	    }
+
+	    /* Extend ifs and states arrays if necessary. */
+	    error = ENOSR;
+	    if (unit >= ppp_nalloc) {
+		int newn;
+		struct ifnet **newifs;
+		if_ppp_t **newstates;
+
+		newn = unit + 4;
+		if (sp->flags & DBGLOG)
+		    printf("if_ppp: extending ifs to %d\n", 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->if_name = "ppp";
+		ifp->if_unit = unit;
+		ifp->if_mtu = PPP_MTU;
+		ifp->if_flags = IFF_POINTOPOINT | IFF_RUNNING;
+#ifndef __osf__
+#ifdef IFF_MULTICAST
+		ifp->if_flags |= IFF_MULTICAST;
+#endif
+#endif /* __osf__ */
+		ifp->if_output = if_ppp_output;
+#ifdef __osf__
+		ifp->if_version = "Point-to-Point Protocol, version 2.3.11";
+		ifp->if_mediamtu = PPP_MTU;
+		ifp->if_type = IFT_PPP;
+		ifp->if_hdrlen = PPP_HDRLEN;
+		ifp->if_addrlen = 0;
+		ifp->if_flags |= IFF_NOARP | IFF_SIMPLEX | IFF_NOTRAILERS;
+#ifdef IFF_VAR_MTU
+		ifp->if_flags |= IFF_VAR_MTU;
+#endif
+#ifdef NETMASTERCPU
+		ifp->if_affinity = NETMASTERCPU;
+#endif
+#endif
+		ifp->if_ioctl = if_ppp_ioctl;
+		ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
+		if_attach(ifp);
+		if (sp->flags & DBGLOG)
+		    printf("if_ppp: created unit %d\n", unit);
+	    } else {
+		ifp->if_mtu = PPP_MTU;
+		ifp->if_flags |= IFF_RUNNING;
+	    }
+
+	    states[unit] = sp;
+	    sp->unit = unit;
+
+	    error = 0;
+	    iop->ioc_count = 0;
+	    if (sp->flags & DBGLOG)
+		printf("if_ppp: attached unit %d, sp=%x q=%x\n", unit,
+		       sp, sp->q);
+	    break;
+
+	case PPPIO_DEBUG:
+	    error = -1;
+	    if (iop->ioc_count == sizeof(int)) {
+		if (*(int *)mp->b_cont->b_rptr == PPPDBG_LOG + PPPDBG_IF) {
+		    printf("if_ppp: debug log enabled, q=%x sp=%x\n", q, sp);
+		    sp->flags |= DBGLOG;
+		    error = 0;
+		    iop->ioc_count = 0;
+		}
+	    }
+	    break;
+
+	default:
+	    error = -1;
+	    break;
+	}
+
+	if (sp->flags & DBGLOG)
+	    printf("if_ppp: ioctl result %d\n", error);
+	if (error < 0)
+	    putnext(q, mp);
+	else if (error == 0) {
+	    mp->b_datap->db_type = M_IOCACK;
+	    qreply(q, mp);
+	} else {
+	    mp->b_datap->db_type = M_IOCNAK;
+	    iop->ioc_count = 0;
+	    iop->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->q_ptr;
+    switch (mp->b_datap->db_type) {
+    case M_DATA:
+	/*
+	 * Convert the message into an mbuf chain
+	 * and inject it into the network code.
+	 */
+	if (sp->flags & DBGLOG)
+	    printf("if_ppp: rput pkt len %d data %x %x %x %x %x %x %x %x\n",
+		   msgdsize(mp), mp->b_rptr[0], mp->b_rptr[1], mp->b_rptr[2],
+		   mp->b_rptr[3], mp->b_rptr[4], mp->b_rptr[5], mp->b_rptr[6],
+		   mp->b_rptr[7]);
+
+	if (sp->unit < 0) {
+	    freemsg(mp);
+	    break;
+	}
+	if (sp->unit >= ppp_nalloc || (ifp = ifs[sp->unit]) == 0) {
+#ifdef DEBUG
+	    printf("if_ppp: no unit %d!\n", sp->unit);
+#endif
+	    freemsg(mp);
+	    break;
+	}
+
+	if ((ifp->if_flags & IFF_UP) == 0) {
+	    freemsg(mp);
+	    break;
+	}
+	++ifp->if_ipackets;
+
+	proto = PPP_PROTOCOL(mp->b_rptr);
+	adjmsg(mp, PPP_HDRLEN);
+	len = msgdsize(mp);
+	mb = make_mbufs(mp, sizeof(struct ifnet *));
+	freemsg(mp);
+	if (mb == NULL) {
+	    if (sp->flags & DBGLOG)
+		printf("if_ppp%d: make_mbufs failed\n", ifp->if_unit);
+	    ++ifp->if_ierrors;
+	    break;
+	}
+
+#ifdef SNIT_SUPPORT
+	if (proto == PPP_IP && (ifp->if_flags & IFF_PROMISC)) {
+	    struct nit_if nif;
+
+	    nif.nif_header = (caddr_t) &snit_ehdr;
+	    nif.nif_hdrlen = sizeof(snit_ehdr);
+	    nif.nif_bodylen = len;
+	    nif.nif_promisc = 0;
+	    snit_intr(ifp, mb, &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->m_pkthdr.rcvif = ifp;
+        mb->m_pkthdr.len = len;
+#else
+	mb->m_off -= sizeof(struct ifnet *);
+	mb->m_len += sizeof(struct ifnet *);
+	*mtod(mb, struct ifnet **) = ifp;
+#endif
+
+	inq = 0;
+	switch (proto) {
+	case PPP_IP:
+	    inq = &ipintrq;
+	    schednetisr(NETISR_IP);
+	}
+
+	if (inq != 0) {
+	    s = splhigh();
+	    if (IF_QFULL(inq)) {
+		IF_DROP(inq);
+		++ifp->if_ierrors;
+		if (sp->flags & DBGLOG)
+		    printf("if_ppp: inq full, proto=%x\n", proto);
+		m_freem(mb);
+	    } else {
+		IF_ENQUEUE(inq, mb);
+	    }
+	    splx(s);
+	} else {
+	    if (sp->flags & DBGLOG)
+		printf("if_ppp%d: proto=%x?\n", ifp->if_unit, proto);
+	    ++ifp->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->if_flags & IFF_UP) == 0) {
+	m_freem(m0);
+	return ENETDOWN;
+    }
+
+    if ((unsigned)ifp->if_unit >= ppp_nalloc) {
+#ifdef DEBUG
+	printf("if_ppp_output: unit %d?\n", ifp->if_unit);
+#endif
+	m_freem(m0);
+	return EINVAL;
+    }
+    sp = states[ifp->if_unit];
+    if (sp == 0) {
+#ifdef DEBUG
+	printf("if_ppp_output: no queue?\n");
+#endif
+	m_freem(m0);
+	return ENETDOWN;
+    }
+
+    if (sp->flags & DBGLOG) {
+	p = mtod(m0, u_char *);
+	printf("if_ppp_output%d: af=%d data=%x %x %x %x %x %x %x %x q=%x\n",
+	       ifp->if_unit, dst->sa_family, p[0], p[1], p[2], p[3], p[4],
+	       p[5], p[6], p[7], sp->q);
+    }
+
+    switch (dst->sa_family) {
+    case AF_INET:
+	proto = PPP_IP;
+#ifdef SNIT_SUPPORT
+	if (ifp->if_flags & IFF_PROMISC) {
+	    struct nit_if nif;
+	    struct mbuf *m;
+	    int len;
+
+	    for (len = 0, m = m0; m != NULL; m = m->m_next)
+		len += m->m_len;
+	    nif.nif_header = (caddr_t) &snit_ehdr;
+	    nif.nif_hdrlen = sizeof(snit_ehdr);
+	    nif.nif_bodylen = len;
+	    nif.nif_promisc = 0;
+	    snit_intr(ifp, m0, &nif);
+	}
+#endif
+	break;
+
+    default:
+	m_freem(m0);
+	return EAFNOSUPPORT;
+    }
+
+    ++ifp->if_opackets;
+    mp = make_message(m0, PPP_HDRLEN);
+    m_freem(m0);
+    if (mp == 0) {
+	++ifp->if_oerrors;
+	return ENOBUFS;
+    }
+    mp->b_rptr -= PPP_HDRLEN;
+    mp->b_rptr[0] = PPP_ALLSTATIONS;
+    mp->b_rptr[1] = PPP_UI;
+    mp->b_rptr[2] = proto >> 8;
+    mp->b_rptr[3] = proto;
+
+    s = splstr();
+    if (sp->flags & DBGLOG)
+	printf("if_ppp: putnext(%x, %x), r=%x w=%x p=%x\n",
+	       sp->q, mp, mp->b_rptr, mp->b_wptr, proto);
+    putnext(sp->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->if_flags & IFF_RUNNING) == 0)
+	    ifp->if_flags &= ~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->ifr_data, &mtu, sizeof (u_short));
+        ifr->ifr_mtu = mtu;
+#endif
+
+	if (ifr->ifr_mtu < PPP_MINMTU || ifr->ifr_mtu > PPP_MAXMTU) {
+	    error = EINVAL;
+	    break;
+	}
+	ifp->if_mtu = ifr->ifr_mtu;
+	break;
+
+    case SIOCGIFMTU:
+	ifr->ifr_mtu = ifp->if_mtu;
+	break;
+
+    case SIOCADDMULTI:
+    case SIOCDELMULTI:
+	switch(ifr->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 = &head;
+    space = 0;
+    cp = mp->b_rptr;
+#ifdef __osf__
+    MGETHDR(m, M_DONTWAIT, MT_DATA);
+    m->m_len = 0;
+    space = MHLEN;
+    *prevp = m;
+    prevp = &m->m_next;
+    dp = mtod(m, unsigned char *);
+    len -= space;
+    off = 0;
+#endif
+    for (;;) {
+	while (cp >= mp->b_wptr) {
+	    mp = mp->b_cont;
+	    if (mp == 0) {
+		*prevp = 0;
+		return head;
+	    }
+	    cp = mp->b_rptr;
+	}
+	n = mp->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 > 2 * MLEN) {
+#ifdef __osf__
+		MCLGET(m, M_DONTWAIT);
+#else
+		MCLGET(m);
+#endif
+	    }
+#ifdef __osf__
+	    space = ((m->m_flags & M_EXT) ? MCLBYTES : MLEN);
+#else
+	    space = (m->m_off > MMAXOFF? MCLBYTES: MLEN) - off;
+	    m->m_off += off;
+#endif
+	    m->m_len = 0;
+	    len -= space;
+	    dp = mtod(m, unsigned char *);
+	    off = 0;
+	    prevp = &m->m_next;
+	}
+	if (n > space)
+	    n = space;
+	bcopy(cp, dp, n);
+	cp += n;
+	dp += n;
+	space -= n;
+	m->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->m_next)
+	len += nm->m_len;
+    prevp = &head;
+    space = 0;
+    cp = mtod(m, unsigned char *);
+    nb = m->m_len;
+    for (;;) {
+	while (nb <= 0) {
+	    m = m->m_next;
+	    if (m == 0) {
+		*prevp = 0;
+		return head;
+	    }
+	    cp = mtod(m, unsigned char *);
+	    nb = m->m_len;
+	}
+	if (space == 0) {
+	    space = len + off;
+	    if (space > ALLOCB_MAX)
+		space = ALLOCB_MAX;
+	    mp = allocb(space, BPRI_LO);
+	    *prevp = mp;
+	    if (mp == 0) {
+		if (head != 0)
+		    freemsg(head);
+		return 0;
+	    }
+	    dp = mp->b_rptr += off;
+	    space -= off;
+	    len -= space;
+	    off = 0;
+	    prevp = &mp->b_cont;
+	}
+	n = nb < space? nb: space;
+	bcopy(cp, dp, n);
+	cp += n;
+	dp += n;
+	nb -= n;
+	space -= n;
+	mp->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 <net/route.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcp_timer.h>
+#include <netinet/tcp_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+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 != &tcb; pcb = pcb->inp_next)
+	if (pcb->inp_route.ro_rt && pcb->inp_route.ro_rt->rt_ifp == ifp)
+	    in_losing(pcb);
+    for (pcb = udb.inp_next; pcb != &udb; pcb = pcb->inp_next)
+	if (pcb->inp_route.ro_rt && pcb->inp_route.ro_rt->rt_ifp == ifp)
+	    in_losing(pcb);
+
+    /*
+     * Delete routes through all addresses of the interface.
+     */
+    for (ifa = ifp->if_addrlist; ifa != 0; ifa = ifa->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 = &in_ifaddr; *inap != 0; ) {
+	if ((*inap)->ia_ifa.ifa_ifp == ifp)
+	    *inap = (*inap)->ia_next;
+	else
+	    inap = &(*inap)->ia_next;
+    }
+
+    /*
+     * Delete the interface from the ifnet list.
+     */
+    for (ifpp = &ifnet; (*ifpp) != 0; ) {
+	if (*ifpp == ifp)
+	    break;
+	ifpp = &(*ifpp)->if_next;
+    }
+    if (*ifpp == 0)
+	printf("couldn't find interface ppp%d in ifnet list\n", ifp->if_unit);
+    else
+	*ifpp = ifp->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 "AS IS" 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 <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#include <sys/errno.h>
+#ifdef __osf__
+#include <sys/ioctl.h>
+#include <sys/cmn_err.h>
+#define queclass(mp)	((mp)->b_band & QPCTL)
+#else
+#include <sys/ioccom.h>
+#endif
+#include <sys/time.h>
+#ifdef SVR4
+#include <sys/cmn_err.h>
+#include <sys/conf.h>
+#include <sys/dlpi.h>
+#include <sys/ddi.h>
+#ifdef SOL2
+#include <sys/ksynch.h>
+#include <sys/kstat.h>
+#include <sys/sunddi.h>
+#include <sys/ethernet.h>
+#else
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#endif /* SOL2 */
+#else /* not SVR4 */
+#include <sys/user.h>
+#endif /* SVR4 */
+#include <net/ppp_defs.h>
+#include <net/pppio.h>
+#include "ppp_mod.h"
+
+/*
+ * Modifications marked with #ifdef PRIOQ are for priority queueing of
+ * interactive traffic, and are due to Marko Zec <zec at japa.tel.fer.hr>.
+ */
+#ifdef PRIOQ
+#endif	/* PRIOQ */
+
+#include <netinet/in.h>	/* 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) && defined(SOL2)
+#define ETHERTYPE_ALLSAP   0
+#endif /* !defined(ETHERTYPE_ALLSAP) && defined(SOL2) */
+
+#if !defined(PPP_ALLSAP) && defined(SOL2)
+#define PPP_ALLSAP  PPP_ALLSTATIONS
+#endif /* !defined(PPP_ALLSAP) && 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(&ppp_lower_lock, RW_WRITER)
+#define LOCK_LOWER_R	rw_enter(&ppp_lower_lock, RW_READER)
+#define TRYLOCK_LOWER_R	rw_tryenter(&ppp_lower_lock, RW_READER)
+#define UNLOCK_LOWER	rw_exit(&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 >= 2
+#define US_PROMISC	0x40	/* stream is promiscuous */
+#endif /* DL_CURRENT_VERSION >= 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 & packets using unlisted ports will be treated as "default".
+ * If IPPORT_DEFAULT is not listed here, "default" packets will be 
+ * assigned lowest priority.
+ * Each line should be terminated with "0".
+ * Line containing only "0" 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, "ppp", 0, 512, 512, 384
+#else
+    PPP_ID, "ppp", 0, 512, 512, 128
+#endif	/* PRIOQ */
+};
+
+static struct qinit pppurint = {
+    pppurput, pppursrv, pppopen, pppclose, NULL, &ppp_info, NULL
+};
+
+static struct qinit pppuwint = {
+    pppuwput, pppuwsrv, NULL, NULL, NULL, &ppp_info, NULL
+};
+
+static struct qinit ppplrint = {
+    ppplrput, ppplrsrv, NULL, NULL, NULL, &ppp_info, NULL
+};
+
+static struct qinit ppplwint = {
+    ppplwput, ppplwsrv, NULL, NULL, NULL, &ppp_info, NULL
+};
+
+#ifdef LACHTCP
+extern struct ifstats *ifstats;
+int pppdevflag = 0;
+#endif
+
+struct streamtab pppinfo = {
+    &pppurint, &pppuwint,
+    &ppplrint, &ppplwint
+};
+
+int ppp_count;
+
+/*
+ * How we maintain statistics.
+ */
+#ifdef SOL2
+#define INCR_IPACKETS(ppa)				\
+	if (ppa->kstats != 0) {				\
+	    KSTAT_NAMED_PTR(ppa->kstats)[0].value.ul++;	\
+	}
+#define INCR_IERRORS(ppa)				\
+	if (ppa->kstats != 0) {				\
+	    KSTAT_NAMED_PTR(ppa->kstats)[1].value.ul++;	\
+	}
+#define INCR_OPACKETS(ppa)				\
+	if (ppa->kstats != 0) {				\
+	    KSTAT_NAMED_PTR(ppa->kstats)[2].value.ul++;	\
+	}
+#define INCR_OERRORS(ppa)				\
+	if (ppa->kstats != 0) {				\
+	    KSTAT_NAMED_PTR(ppa->kstats)[3].value.ul++;	\
+	}
+#endif
+
+#ifdef LACHTCP
+#define INCR_IPACKETS(ppa)	ppa->ifstats.ifs_ipackets++;
+#define INCR_IERRORS(ppa)	ppa->ifstats.ifs_ierrors++;
+#define INCR_OPACKETS(ppa)	ppa->ifstats.ifs_opackets++;
+#define INCR_OERRORS(ppa)	ppa->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->q_ptr)
+	DRV_OPEN_OK(dev);	/* device is already open */
+
+#ifdef PRIOQ
+    /* Calculate max_bband & 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 = &minor_devs; (up = *prevp) != 0; prevp = &up->nextmn) {
+	    if (up->mn != mn)
+		break;
+	    ++mn;
+	}
+    } else {
+#ifdef SVR4
+	mn = getminor(*devp);
+#else
+	mn = minor(dev);
+#endif
+	for (prevp = &minor_devs; (up = *prevp) != 0; prevp = &up->nextmn) {
+	    if (up->mn >= mn)
+		break;
+	}
+	if (up->mn == mn) {
+	    /* this can't happen */
+	    q->q_ptr = WR(q)->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("pppopen: out of kernel memory\n");
+	OPEN_ERROR(ENXIO);
+    }
+    up->nextmn = *prevp;
+    *prevp = up;
+    up->mn = mn;
+#ifdef SVR4
+    *devp = makedevice(getmajor(*devp), mn);
+#endif
+    up->q = q;
+    if (NOTSUSER() == 0)
+	up->flags |= US_PRIV;
+#ifndef NO_DLPI
+    up->state = DL_UNATTACHED;
+#endif
+#ifdef LACHTCP
+    up->ifflags = IFF_UP | IFF_POINTOPOINT;
+#endif
+    up->sap = -1;
+    up->last_sent = up->last_recv = time;
+    up->npmode = NPMODE_DROP;
+    q->q_ptr = (caddr_t) up;
+    WR(q)->q_ptr = (caddr_t) up;
+    noenable(WR(q));
+#ifdef SOL2
+    mutex_init(&up->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->q_ptr;
+    if (up == 0) {
+	DPRINT("pppclose: q_ptr = 0\n");
+	return 0;
+    }
+    if (up->flags & US_DBGLOG)
+	DPRINT2("ppp/%d: close, flags=%x\n", up->mn, up->flags);
+    if (up->flags & US_CONTROL) {
+#ifdef LACHTCP
+	struct ifstats *ifp, *pifp;
+#endif
+	if (up->lowerq != 0) {
+	    /* Gack! the lower stream should have be unlinked earlier! */
+	    DPRINT1("ppp%d: lower stream still connected on close?\n",
+		    up->mn);
+	    LOCK_LOWER_W;
+	    up->lowerq->q_ptr = 0;
+	    RD(up->lowerq)->q_ptr = 0;
+	    up->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->next; as != 0; as = asnext) {
+	    asnext = as->next;
+	    as->next = 0;
+	    as->ppa = 0;
+	    if (as->flags & US_BLOCKED) {
+		as->flags &= ~US_BLOCKED;
+		flushq(WR(as->q), FLUSHDATA);
+	    }
+	}
+	for (upp = &ppas; *upp != 0; upp = &(*upp)->nextppa)
+	    if (*upp == up) {
+		*upp = up->nextppa;
+		break;
+	    }
+#ifdef LACHTCP
+	/* Remove the statistics from the active list.  */
+	for (ifp = ifstats, pifp = 0; ifp; ifp = ifp->ifs_next) {
+	    if (ifp == &up->ifstats) {
+		if (pifp)
+		    pifp->ifs_next = ifp->ifs_next;
+		else
+		    ifstats = ifp->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->ppa) != 0) {
+	    for (; as->next != 0; as = as->next)
+		if (as->next == up) {
+		    as->next = up->next;
+		    break;
+		}
+	}
+    }
+
+#ifdef SOL2
+    if (up->kstats)
+	kstat_delete(up->kstats);
+    mutex_destroy(&up->stats_lock);
+#endif
+
+    q->q_ptr = NULL;
+    WR(q)->q_ptr = NULL;
+
+    for (prevp = &minor_devs; *prevp != 0; prevp = &(*prevp)->nextmn) {
+	if (*prevp == up) {
+	    *prevp = up->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->q_ptr;
+    if (us == 0) {
+	DPRINT("pppuwput: q_ptr = 0!\n");
+	return 0;
+    }
+    if (mp == 0) {
+	DPRINT1("pppuwput/%d: mp = 0!\n", us->mn);
+	return 0;
+    }
+    if (mp->b_datap == 0) {
+	DPRINT1("pppuwput/%d: mp->b_datap = 0!\n", us->mn);
+	return 0;
+    }
+    switch (mp->b_datap->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->flags & US_DBGLOG)
+	    DPRINT3("ppp/%d: uwput M_DATA len=%d flags=%x\n",
+		    us->mn, msgdsize(mp), us->flags);
+	if (us->ppa == 0 || msgdsize(mp) > us->ppa->mtu + PPP_HDRLEN
+#ifndef NO_DLPI
+	    || (us->flags & US_CONTROL) == 0
+#endif /* NO_DLPI */
+	    ) {
+	    DPRINT1("pppuwput: junk data len=%d\n", msgdsize(mp));
+	    freemsg(mp);
+	    break;
+	}
+#ifdef NO_DLPI
+	if ((us->flags & US_CONTROL) == 0 && !pass_packet(us, mp, 1))
+	    break;
+#endif
+	if (!send_data(mp, us))
+	    putq(q, mp);
+	break;
+
+    case M_IOCTL:
+	iop = (struct iocblk *) mp->b_rptr;
+	error = EINVAL;
+	if (us->flags & US_DBGLOG)
+	    DPRINT3("ppp/%d: ioctl %x count=%d\n",
+		    us->mn, iop->ioc_cmd, iop->ioc_count);
+	switch (iop->ioc_cmd) {
+#if defined(SOL2)
+	case DLIOCRAW:	    /* raw M_DATA mode */
+	    us->flags |= US_RAWDATA;
+	    error = 0;
+	    break;
+#endif /* defined(SOL2) */
+	case I_LINK:
+	    if ((us->flags & US_CONTROL) == 0 || us->lowerq != 0)
+		break;
+	    if (mp->b_cont == 0) {
+		DPRINT1("pppuwput/%d: ioctl I_LINK b_cont = 0!\n", us->mn);
+		break;
+	    }
+	    lb = (struct linkblk *) mp->b_cont->b_rptr;
+	    lq = lb->l_qbot;
+	    if (lq == 0) {
+		DPRINT1("pppuwput/%d: ioctl I_LINK l_qbot = 0!\n", us->mn);
+		break;
+	    }
+	    LOCK_LOWER_W;
+	    us->lowerq = lq;
+	    lq->q_ptr = (caddr_t) q;
+	    RD(lq)->q_ptr = (caddr_t) us->q;
+	    UNLOCK_LOWER;
+	    iop->ioc_count = 0;
+	    error = 0;
+	    us->flags &= ~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->ppa_id);
+	    putctl4(lq, M_CTL, PPPCTL_MRU, us->mru);
+	    putctl4(lq, M_CTL, PPPCTL_MTU, us->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->q_next != NULL; tlq = tlq->q_next)
+		;
+            strqset(tlq, QHIWAT, 0, 256);
+            strqset(tlq, QLOWAT, 0, 128);
+            unfreezestr(lq);
+#endif	/* PRIOQ */
+	    break;
+
+	case I_UNLINK:
+	    if (mp->b_cont == 0) {
+		DPRINT1("pppuwput/%d: ioctl I_UNLINK b_cont = 0!\n", us->mn);
+		break;
+	    }
+	    lb = (struct linkblk *) mp->b_cont->b_rptr;
+#if DEBUG
+	    if (us->lowerq != lb->l_qbot) {
+		DPRINT2("ppp unlink: lowerq=%x qbot=%x\n",
+			us->lowerq, lb->l_qbot);
+		break;
+	    }
+#endif
+	    iop->ioc_count = 0;
+	    qwriter(q, mp, detach_lower, PERIM_OUTER);
+	    error = -1;
+	    break;
+
+	case PPPIO_NEWPPA:
+	    if (us->flags & US_CONTROL)
+		break;
+	    if ((us->flags & US_PRIV) == 0) {
+		error = EPERM;
+		break;
+	    }
+	    /* Arrange to return an int */
+	    if ((mq = mp->b_cont) == 0
+		|| mq->b_datap->db_lim - mq->b_rptr < sizeof(int)) {
+		mq = allocb(sizeof(int), BPRI_HI);
+		if (mq == 0) {
+		    error = ENOSR;
+		    break;
+		}
+		if (mp->b_cont != 0)
+		    freemsg(mp->b_cont);
+		mp->b_cont = mq;
+		mq->b_cont = 0;
+	    }
+	    iop->ioc_count = sizeof(int);
+	    mq->b_wptr = mq->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->ioc_count != sizeof(int) || us->ppa != 0)
+		break;
+	    if (mp->b_cont == 0) {
+		DPRINT1("pppuwput/%d: ioctl PPPIO_ATTACH b_cont = 0!\n", us->mn);
+		break;
+	    }
+	    n = *(int *)mp->b_cont->b_rptr;
+	    for (ppa = ppas; ppa != 0; ppa = ppa->nextppa)
+		if (ppa->ppa_id == n)
+		    break;
+	    if (ppa == 0)
+		break;
+	    us->ppa = ppa;
+	    iop->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->ioc_count != sizeof(int) || us->ppa == 0)
+		break;
+	    if (mp->b_cont == 0) {
+		DPRINT1("pppuwput/%d: ioctl PPPIO_BIND b_cont = 0!\n", us->mn);
+		break;
+	    }
+	    n = *(int *)mp->b_cont->b_rptr;
+	    /* n must be a valid PPP network protocol number. */
+	    if (n < 0x21 || n > 0x3fff || (n & 0x101) != 1)
+		break;
+	    /* check that no other stream is bound to this sap already. */
+	    for (os = us->ppa; os != 0; os = os->next)
+		if (os->sap == n)
+		    break;
+	    if (os != 0)
+		break;
+	    us->sap = n;
+	    iop->ioc_count = 0;
+	    error = 0;
+	    break;
+#endif /* NO_DLPI */
+
+	case PPPIO_MRU:
+	    if (iop->ioc_count != sizeof(int) || (us->flags & US_CONTROL) == 0)
+		break;
+	    if (mp->b_cont == 0) {
+		DPRINT1("pppuwput/%d: ioctl PPPIO_MRU b_cont = 0!\n", us->mn);
+		break;
+	    }
+	    n = *(int *)mp->b_cont->b_rptr;
+	    if (n <= 0 || n > PPP_MAXMRU)
+		break;
+	    if (n < PPP_MRU)
+		n = PPP_MRU;
+	    us->mru = n;
+	    if (us->lowerq)
+		putctl4(us->lowerq, M_CTL, PPPCTL_MRU, n);
+	    error = 0;
+	    iop->ioc_count = 0;
+	    break;
+
+	case PPPIO_MTU:
+	    if (iop->ioc_count != sizeof(int) || (us->flags & US_CONTROL) == 0)
+		break;
+	    if (mp->b_cont == 0) {
+		DPRINT1("pppuwput/%d: ioctl PPPIO_MTU b_cont = 0!\n", us->mn);
+		break;
+	    }
+	    n = *(int *)mp->b_cont->b_rptr;
+	    if (n <= 0 || n > PPP_MAXMTU)
+		break;
+	    us->mtu = n;
+#ifdef LACHTCP
+	    /* The MTU reported in netstat, not used as IP max packet size! */
+	    us->ifstats.ifs_mtu = n;
+#endif
+	    if (us->lowerq)
+		putctl4(us->lowerq, M_CTL, PPPCTL_MTU, n);
+	    error = 0;
+	    iop->ioc_count = 0;
+	    break;
+
+	case PPPIO_LASTMOD:
+	    us->flags |= US_LASTMOD;
+	    error = 0;
+	    break;
+
+	case PPPIO_DEBUG:
+	    if (iop->ioc_count != sizeof(int))
+		break;
+	    if (mp->b_cont == 0) {
+		DPRINT1("pppuwput/%d: ioctl PPPIO_DEBUG b_cont = 0!\n", us->mn);
+		break;
+	    }
+	    n = *(int *)mp->b_cont->b_rptr;
+	    if (n == PPPDBG_DUMP + PPPDBG_DRIVER) {
+		qwriter(q, NULL, debug_dump, PERIM_OUTER);
+		iop->ioc_count = 0;
+		error = -1;
+	    } else if (n == PPPDBG_LOG + PPPDBG_DRIVER) {
+		DPRINT1("ppp/%d: debug log enabled\n", us->mn);
+		us->flags |= US_DBGLOG;
+		iop->ioc_count = 0;
+		error = 0;
+	    } else {
+		if (us->ppa == 0 || us->ppa->lowerq == 0)
+		    break;
+		putnext(us->ppa->lowerq, mp);
+		error = -1;
+	    }
+	    break;
+
+	case PPPIO_NPMODE:
+	    if (iop->ioc_count != 2 * sizeof(int))
+		break;
+	    if ((us->flags & US_CONTROL) == 0)
+		break;
+	    if (mp->b_cont == 0) {
+		DPRINT1("pppuwput/%d: ioctl PPPIO_NPMODE b_cont = 0!\n", us->mn);
+		break;
+	    }
+	    sap = ((int *)mp->b_cont->b_rptr)[0];
+	    for (nps = us->next; nps != 0; nps = nps->next) {
+		if (us->flags & US_DBGLOG)
+		    DPRINT2("us = 0x%x, us->next->sap = 0x%x\n", nps, nps->sap);
+		if (nps->sap == sap)
+		    break;
+	    }
+	    if (nps == 0) {
+		if (us->flags & US_DBGLOG)
+		    DPRINT2("ppp/%d: no stream for sap %x\n", us->mn, sap);
+		break;
+	    }
+	    /* XXX possibly should use qwriter here */
+	    nps->npmode = (enum NPmode) ((int *)mp->b_cont->b_rptr)[1];
+	    if (nps->npmode != NPMODE_QUEUE && (nps->flags & US_BLOCKED) != 0)
+		qenable(WR(nps->q));
+	    iop->ioc_count = 0;
+	    error = 0;
+	    break;
+
+	case PPPIO_GIDLE:
+	    if ((ppa = us->ppa) == 0)
+		break;
+	    mq = allocb(sizeof(struct ppp_idle), BPRI_HI);
+	    if (mq == 0) {
+		error = ENOSR;
+		break;
+	    }
+	    if (mp->b_cont != 0)
+		freemsg(mp->b_cont);
+	    mp->b_cont = mq;
+	    mq->b_cont = 0;
+	    pip = (struct ppp_idle *) mq->b_wptr;
+	    pip->xmit_idle = time - ppa->last_sent;
+	    pip->recv_idle = time - ppa->last_recv;
+	    mq->b_wptr += sizeof(struct ppp_idle);
+	    iop->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->ioc_count != sizeof(struct ifreq) || us->ppa == 0)
+	        break;
+	    ifr = (struct ifreq *)mp->b_cont->b_rptr;
+	    /* Find the unit number in the interface name.  */
+	    for (i = 0; i < IFNAMSIZ; i++) {
+		if (ifr->ifr_name[i] == 0 ||
+		    (ifr->ifr_name[i] >= '0' &&
+		     ifr->ifr_name[i] <= '9'))
+		    break;
+		else
+		    us->ifname[i] = ifr->ifr_name[i];
+	    }
+	    us->ifname[i] = 0;
+
+	    /* Convert the unit number to binary.  */
+	    for (n = 0; i < IFNAMSIZ; i++) {
+		if (ifr->ifr_name[i] == 0) {
+		    break;
+		}
+	        else {
+		    n = n * 10 + ifr->ifr_name[i] - '0';
+		}
+	    }
+
+	    /* Verify the ppa.  */
+	    if (us->ppa->ppa_id != n)
+		break;
+	    ppa = us->ppa;
+
+	    /* Set up the netstat block.  */
+	    strncpy (ppa->ifname, us->ifname, IFNAMSIZ);
+
+	    ppa->ifstats.ifs_name = ppa->ifname;
+	    ppa->ifstats.ifs_unit = n;
+	    ppa->ifstats.ifs_active = us->state != DL_UNBOUND;
+	    ppa->ifstats.ifs_mtu = ppa->mtu;
+
+	    /* Link in statistics used by netstat.  */
+	    ppa->ifstats.ifs_next = ifstats;
+	    ifstats = &ppa->ifstats;
+
+	    iop->ioc_count = 0;
+	    error = 0;
+	    break;
+
+	case SIOCGIFFLAGS:
+	    if (!(us->flags & US_CONTROL)) {
+		if (us->ppa)
+		    us = us->ppa;
+	        else
+		    break;
+	    }
+	    ((struct iocblk_in *)iop)->ioc_ifflags = us->ifflags;
+	    error = 0;
+	    break;
+
+	case SIOCSIFFLAGS:
+	    if (!(us->flags & US_CONTROL)) {
+		if (us->ppa)
+		    us = us->ppa;
+		else
+		    break;
+	    }
+	    us->ifflags = ((struct iocblk_in *)iop)->ioc_ifflags;
+	    error = 0;
+	    break;
+
+	case SIOCSIFADDR:
+	    if (!(us->flags & US_CONTROL)) {
+		if (us->ppa)
+		    us = us->ppa;
+		else
+		    break;
+	    }
+	    us->ifflags |= IFF_RUNNING;
+	    ((struct iocblk_in *)iop)->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->b_rptr)->dl_primitive = DL_INFO_REQ;
+	    mq->b_wptr = mq->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->ppa == 0 || us->ppa->lowerq == 0)
+		break;
+	    us->ioc_id = iop->ioc_id;
+	    error = -1;
+	    switch (iop->ioc_cmd) {
+	    case PPPIO_GETSTAT:
+	    case PPPIO_GETCSTAT:
+		if (us->flags & US_LASTMOD) {
+		    error = EINVAL;
+		    break;
+		}
+		putnext(us->ppa->lowerq, mp);
+		break;
+	    default:
+		if (us->flags & US_PRIV)
+		    putnext(us->ppa->lowerq, mp);
+		else {
+		    DPRINT1("ppp ioctl %x rejected\n", iop->ioc_cmd);
+		    error = EPERM;
+		}
+		break;
+	    }
+	    break;
+	}
+
+	if (error > 0) {
+	    iop->ioc_error = error;
+	    mp->b_datap->db_type = M_IOCNAK;
+	    qreply(q, mp);
+	} else if (error == 0) {
+	    mp->b_datap->db_type = M_IOCACK;
+	    qreply(q, mp);
+	}
+	break;
+
+    case M_FLUSH:
+	if (us->flags & US_DBGLOG)
+	    DPRINT2("ppp/%d: flush %x\n", us->mn, *mp->b_rptr);
+	if (*mp->b_rptr & FLUSHW)
+	    flushq(q, FLUSHDATA);
+	if (*mp->b_rptr & FLUSHR) {
+	    *mp->b_rptr &= ~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->b_rptr;
+    int size = mp->b_wptr - mp->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 >= 2
+    dl_phys_addr_ack_t	*paddrack;
+    static struct ether_addr eaddr = {0};
+#endif
+
+    if (us->flags & US_DBGLOG)
+	DPRINT3("ppp/%d: dlpi prim %x len=%d\n", us->mn,
+		d->dl_primitive, size);
+    switch (d->dl_primitive) {
+    case DL_INFO_REQ:
+	if (size < sizeof(dl_info_req_t))
+	    goto badprim;
+	if ((reply = allocb(sizeof(dl_info_ack_t), BPRI_HI)) == 0)
+	    break;		/* should do bufcall */
+	reply->b_datap->db_type = M_PCPROTO;
+	info = (dl_info_ack_t *) reply->b_wptr;
+	reply->b_wptr += sizeof(dl_info_ack_t);
+	bzero((caddr_t) info, sizeof(dl_info_ack_t));
+	info->dl_primitive = DL_INFO_ACK;
+	info->dl_max_sdu = us->ppa? us->ppa->mtu: PPP_MAXMTU;
+	info->dl_min_sdu = 1;
+	info->dl_addr_length = sizeof(uint);
+	info->dl_mac_type = DL_ETHER;	/* a bigger lie */
+	info->dl_current_state = us->state;
+	info->dl_service_mode = DL_CLDLS;
+	info->dl_provider_style = DL_STYLE2;
+#if DL_CURRENT_VERSION >= 2
+	info->dl_sap_length = sizeof(uint);
+	info->dl_version = DL_CURRENT_VERSION;
+#endif
+	qreply(q, reply);
+	break;
+
+    case DL_ATTACH_REQ:
+	if (size < sizeof(dl_attach_req_t))
+	    goto badprim;
+	if (us->state != DL_UNATTACHED || us->ppa != 0) {
+	    dlpi_error(q, us, DL_ATTACH_REQ, DL_OUTSTATE, 0);
+	    break;
+	}
+	for (ppa = ppas; ppa != 0; ppa = ppa->nextppa)
+	    if (ppa->ppa_id == d->attach_req.dl_ppa)
+		break;
+	if (ppa == 0) {
+	    dlpi_error(q, us, DL_ATTACH_REQ, DL_BADPPA, 0);
+	    break;
+	}
+	us->ppa = ppa;
+	qwriter(q, mp, attach_ppa, PERIM_OUTER);
+	return;
+
+    case DL_DETACH_REQ:
+	if (size < sizeof(dl_detach_req_t))
+	    goto badprim;
+	if (us->state != DL_UNBOUND || us->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 < sizeof(dl_bind_req_t))
+	    goto badprim;
+	if (us->state != DL_UNBOUND || us->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->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->bind_req.dl_sap;
+	us->req_sap = sap;
+
+#if defined(SOL2)
+	if (us->flags & US_DBGLOG)
+	    DPRINT2("DL_BIND_REQ: ip gives sap = 0x%x, us = 0x%x", 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("DL_BIND_REQ: unrecognized sap = 0x%x, us = 0x%x", sap, us);
+	    dlpi_error(q, us, DL_BIND_REQ, DL_BADADDR, 0);
+	    break;
+	}
+#else
+	if (sap == ETHERTYPE_IP)
+	    sap = PPP_IP;
+	if (sap < 0x21 || sap > 0x3fff || (sap & 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->ppa; os != 0; os = os->next)
+	    if (os->sap == sap)
+		break;
+	if (os != 0) {
+	    dlpi_error(q, us, DL_BIND_REQ, DL_NOADDR, 0);
+	    break;
+	}
+
+	us->sap = sap;
+	us->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->b_wptr;
+	reply->b_wptr += sizeof(dl_bind_ack_t) + sizeof(uint);
+	reply->b_datap->db_type = M_PCPROTO;
+	bzero((caddr_t) ackp, sizeof(dl_bind_ack_t));
+	ackp->dl_primitive = DL_BIND_ACK;
+	ackp->dl_sap = sap;
+	ackp->dl_addr_length = sizeof(uint);
+	ackp->dl_addr_offset = sizeof(dl_bind_ack_t);
+	*(uint *)(ackp+1) = sap;
+	qreply(q, reply);
+	break;
+
+    case DL_UNBIND_REQ:
+	if (size < sizeof(dl_unbind_req_t))
+	    goto badprim;
+	if (us->state != DL_IDLE) {
+	    dlpi_error(q, us, DL_UNBIND_REQ, DL_OUTSTATE, 0);
+	    break;
+	}
+	us->sap = -1;
+	us->state = DL_UNBOUND;
+#ifdef LACHTCP
+	us->ppa->ifstats.ifs_active = 0;
+#endif
+	dlpi_ok(q, DL_UNBIND_REQ);
+	break;
+
+    case DL_UNITDATA_REQ:
+	if (size < sizeof(dl_unitdata_req_t))
+	    goto badprim;
+	if (us->state != DL_IDLE) {
+	    dlpi_error(q, us, DL_UNITDATA_REQ, DL_OUTSTATE, 0);
+	    break;
+	}
+	if ((ppa = us->ppa) == 0) {
+	    cmn_err(CE_CONT, "ppp: in state dl_idle but ppa == 0?\n");
+	    break;
+	}
+	len = mp->b_cont == 0? 0: msgdsize(mp->b_cont);
+	if (len > ppa->mtu) {
+	    DPRINT2("dlpi data too large (%d > %d)\n", len, ppa->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->b_cont)
+	    promisc_sendup(ppa, mp->b_cont, us->sap, 0);
+#endif /* defined(SOL2) */
+
+	mp->b_band = 0;
+#ifdef PRIOQ
+        /* Extract s_port & d_port from IP-packet, the code is a bit
+           dirty here, but so am I, too... */
+        if (mp->b_datap->db_type == M_PROTO && us->sap == PPP_IP
+	    && mp->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->b_cont->b_rptr; /* bb points to IP-header*/
+	    len = mp->b_cont->b_wptr - mp->b_cont->b_rptr;
+            syn = 0;
+	    s_port = IPPORT_DEFAULT;
+	    d_port = IPPORT_DEFAULT;
+	    if (len >= 20) {	/* 20 = minimum length of IP header */
+		iphlen = (bb[0] & 0x0f) * 4;
+		tlh = bb + iphlen;
+		len -= iphlen;
+		switch (bb[9]) {
+		case IPPROTO_TCP:
+		    if (len >= 20) {	      /* min length of TCP header */
+			s_port = (tlh[0] << 8) + tlh[1];
+			d_port = (tlh[2] << 8) + tlh[3];
+			syn = tlh[13] & 0x02;
+		    }
+		    break;
+		case IPPROTO_UDP:
+		    if (len >= 8) {	      /* min length of UDP header */
+			s_port = (tlh[0] << 8) + tlh[1];
+			d_port = (tlh[2] << 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 && band_unset)
+                    if (s_port == *ptr || d_port == *ptr++) {
+                        mp->b_band = cur_band;
+                        band_unset = 0;
+                        break;
+		    }
+                ptr++;
+                cur_band--;
+	    }
+            if (band_unset)
+		mp->b_band = def_band;
+            /* It may be usable to urge SYN packets a bit */
+            if (syn)
+		mp->b_band++;
+	}
+#endif	/* PRIOQ */
+	/* this assumes PPP_HDRLEN <= sizeof(dl_unitdata_req_t) */
+	if (mp->b_datap->db_ref > 1) {
+	    np = allocb(PPP_HDRLEN, BPRI_HI);
+	    if (np == 0)
+		break;		/* gak! */
+	    np->b_cont = mp->b_cont;
+	    mp->b_cont = 0;
+	    freeb(mp);
+	    mp = np;
+	} else
+	    mp->b_datap->db_type = M_DATA;
+	/* XXX should use dl_dest_addr_offset/length here,
+	   but we would have to translate ETHERTYPE_IP -> PPP_IP */
+	mp->b_wptr = mp->b_rptr + PPP_HDRLEN;
+	mp->b_rptr[0] = PPP_ALLSTATIONS;
+	mp->b_rptr[1] = PPP_UI;
+	mp->b_rptr[2] = us->sap >> 8;
+	mp->b_rptr[3] = us->sap;
+	if (pass_packet(us, mp, 1)) {
+	    if (!send_data(mp, us))
+		putq(q, mp);
+	}
+	return;
+
+#if DL_CURRENT_VERSION >= 2
+    case DL_PHYS_ADDR_REQ:
+	if (size < 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->b_datap->db_type = M_PCPROTO;
+	paddrack = (dl_phys_addr_ack_t *) reply->b_wptr;
+	reply->b_wptr += sizeof(dl_phys_addr_ack_t);
+	bzero((caddr_t) paddrack, sizeof(dl_phys_addr_ack_t)+ETHERADDRL);
+	paddrack->dl_primitive = DL_PHYS_ADDR_ACK;
+	paddrack->dl_addr_length = ETHERADDRL;
+	paddrack->dl_addr_offset = sizeof(dl_phys_addr_ack_t);
+	bcopy(&eaddr, reply->b_wptr, ETHERADDRL);
+	reply->b_wptr += ETHERADDRL;
+	qreply(q, reply);
+	break;
+
+#if defined(SOL2)
+    case DL_PROMISCON_REQ:
+	if (size < sizeof(dl_promiscon_req_t))
+	    goto badprim;
+	us->flags |= US_PROMISC;
+	dlpi_ok(q, DL_PROMISCON_REQ);
+	break;
+
+    case DL_PROMISCOFF_REQ:
+	if (size < sizeof(dl_promiscoff_req_t))
+	    goto badprim;
+	us->flags &= ~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 >= 2 */
+
+#if DL_CURRENT_VERSION >= 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->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->dl_primitive, DL_OUTSTATE, 0);
+	break;
+
+    case DL_UDQOS_REQ:
+	dlpi_error(q, us, d->dl_primitive, DL_BADQOSTYPE, 0);
+	break;
+
+#if DL_CURRENT_VERSION >= 2
+    case DL_TEST_RES:
+    case DL_XID_RES:
+	break;
+#endif
+
+    default:
+	cmn_err(CE_CONT, "ppp: unknown dlpi prim 0x%x\n", d->dl_primitive);
+	/* fall through */
+    badprim:
+	dlpi_error(q, us, d->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->flags & US_DBGLOG)
+        DPRINT3("ppp/%d: dlpi error, prim=%x, err=%x\n", us->mn, prim, err);
+    reply = allocb(sizeof(dl_error_ack_t), BPRI_HI);
+    if (reply == 0)
+	return;			/* XXX should do bufcall */
+    reply->b_datap->db_type = M_PCPROTO;
+    errp = (dl_error_ack_t *) reply->b_wptr;
+    reply->b_wptr += sizeof(dl_error_ack_t);
+    errp->dl_primitive = DL_ERROR_ACK;
+    errp->dl_error_primitive = prim;
+    errp->dl_errno = err;
+    errp->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->b_datap->db_type = M_PCPROTO;
+    okp = (dl_ok_ack_t *) reply->b_wptr;
+    reply->b_wptr += sizeof(dl_ok_ack_t);
+    okp->dl_primitive = DL_OK_ACK;
+    okp->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->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 < 0) {
+	/* pass only if link already up, and don't update time */
+	if (ppa->lowerq == 0) {
+	    freemsg(mp);
+	    return 0;
+	}
+	pass = 1;
+    } else if (pass) {
+	if (outbound)
+	    ppa->last_sent = time;
+	else
+	    ppa->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->flags & US_BLOCKED) || us->npmode == NPMODE_QUEUE)
+	return 0;
+    ppa = us->ppa;
+    if (ppa == 0 || us->npmode == NPMODE_DROP || us->npmode == NPMODE_ERROR) {
+	if (us->flags & US_DBGLOG)
+	    DPRINT2("ppp/%d: dropping pkt (npmode=%d)\n", us->mn, us->npmode);
+	freemsg(mp);
+	return 1;
+    }
+    if (ppa->lowerq == 0) {
+	/* try to send it up the control stream */
+        if (bcanputnext(ppa->q, mp->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->q, np);
+	    return 1;
+	}
+    } else {
+        if (bcanputnext(ppa->lowerq, mp->b_band)) {
+	    MT_ENTER(&ppa->stats_lock);
+	    ppa->stats.ppp_opackets++;
+	    ppa->stats.ppp_obytes += msgdsize(mp);
+#ifdef INCR_OPACKETS
+	    INCR_OPACKETS(ppa);
+#endif
+	    MT_EXIT(&ppa->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->lowerq, mp);
+	    return 1;
+	}
+    }
+    us->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->q_ptr;
+    if (us == 0) {
+	DPRINT("new_ppa: q_ptr = 0!\n");
+	return;
+    }
+
+    usp = &ppas;
+    ppa_id = 0;
+    while ((up = *usp) != 0 && ppa_id == up->ppa_id) {
+	++ppa_id;
+	usp = &up->nextppa;
+    }
+    us->ppa_id = ppa_id;
+    us->ppa = us;
+    us->next = 0;
+    us->nextppa = *usp;
+    *usp = us;
+    us->flags |= US_CONTROL;
+    us->npmode = NPMODE_PASS;
+
+    us->mtu = PPP_MTU;
+    us->mru = PPP_MRU;
+
+#ifdef SOL2
+    /*
+     * Create a kstats record for our statistics, so netstat -i works.
+     */
+    if (us->kstats == 0) {
+	char unit[32];
+
+	sprintf(unit, "ppp%d", us->ppa->ppa_id);
+	us->kstats = kstat_create("ppp", us->ppa->ppa_id, unit,
+				  "net", KSTAT_TYPE_NAMED, 4, 0);
+	if (us->kstats != 0) {
+	    kstat_named_t *kn = KSTAT_NAMED_PTR(us->kstats);
+
+	    strcpy(kn[0].name, "ipackets");
+	    kn[0].data_type = KSTAT_DATA_ULONG;
+	    strcpy(kn[1].name, "ierrors");
+	    kn[1].data_type = KSTAT_DATA_ULONG;
+	    strcpy(kn[2].name, "opackets");
+	    kn[2].data_type = KSTAT_DATA_ULONG;
+	    strcpy(kn[3].name, "oerrors");
+	    kn[3].data_type = KSTAT_DATA_ULONG;
+	    kstat_install(us->kstats);
+	}
+    }
+#endif /* SOL2 */
+
+    *(int *)mp->b_cont->b_rptr = ppa_id;
+    mp->b_datap->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->q_ptr;
+    if (us == 0) {
+	DPRINT("attach_ppa: q_ptr = 0!\n");
+	return;
+    }
+
+#ifndef NO_DLPI
+    us->state = DL_UNBOUND;
+#endif
+    for (t = us->ppa; t->next != 0; t = t->next)
+	;
+    t->next = us;
+    us->next = 0;
+    if (mp->b_datap->db_type == M_IOCTL) {
+	mp->b_datap->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->q_ptr;
+    if (us == 0) {
+	DPRINT("detach_ppa: q_ptr = 0!\n");
+	return;
+    }
+
+    for (t = us->ppa; t->next != 0; t = t->next)
+	if (t->next == us) {
+	    t->next = us->next;
+	    break;
+	}
+    us->next = 0;
+    us->ppa = 0;
+#ifndef NO_DLPI
+    us->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->q_ptr;
+    if (us == 0) {
+	DPRINT("detach_lower: q_ptr = 0!\n");
+	return;
+    }
+
+    LOCK_LOWER_W;
+    us->lowerq->q_ptr = 0;
+    RD(us->lowerq)->q_ptr = 0;
+    us->lowerq = 0;
+    UNLOCK_LOWER;
+
+    /* Unblock streams which now feed back up the control stream. */
+    qenable(us->q);
+
+    mp->b_datap->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->q_ptr;
+    if (us == 0) {
+	DPRINT("pppuwsrv: q_ptr = 0!\n");
+	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->flags & US_CONTROL) {
+	for (as = us->next; as != 0; as = as->next)
+	    qenable(WR(as->q));
+    }
+
+    /* Try to send on any data queued here. */
+    us->flags &= ~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->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->q_ptr;
+    if (ppa == 0) {
+	DPRINT("pppurput: q_ptr = 0!\n");
+	return 0;
+    }
+
+    switch (mp->b_datap->db_type) {
+    case M_CTL:
+	MT_ENTER(&ppa->stats_lock);
+	switch (*mp->b_rptr) {
+	case PPPCTL_IERROR:
+#ifdef INCR_IERRORS
+	    INCR_IERRORS(ppa);
+#endif
+	    ppa->stats.ppp_ierrors++;
+	    break;
+	case PPPCTL_OERROR:
+#ifdef INCR_OERRORS
+	    INCR_OERRORS(ppa);
+#endif
+	    ppa->stats.ppp_oerrors++;
+	    break;
+	}
+	MT_EXIT(&ppa->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->b_rptr;
+	for (us = ppa; us != 0; us = us->next)
+	    if (us->ioc_id == iop->ioc_id)
+		break;
+	if (us == 0)
+	    freemsg(mp);
+	else
+	    putnext(us->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("ppp/%d: couldn't allocate eof message!\n", ppa->mn);
+	    break;
+	}
+	putnext(ppa->q, mp);
+	break;
+
+    default:
+	if (mp->b_datap->db_type == M_DATA) {
+	    len = msgdsize(mp);
+	    if (mp->b_wptr - mp->b_rptr < PPP_HDRLEN) {
+		PULLUP(mp, PPP_HDRLEN);
+		if (mp == 0) {
+		    DPRINT1("ppp_urput: msgpullup failed (len=%d)\n", len);
+		    break;
+		}
+	    }
+	    MT_ENTER(&ppa->stats_lock);
+	    ppa->stats.ppp_ipackets++;
+	    ppa->stats.ppp_ibytes += len;
+#ifdef INCR_IPACKETS
+	    INCR_IPACKETS(ppa);
+#endif
+	    MT_EXIT(&ppa->stats_lock);
+
+	    proto = PPP_PROTOCOL(mp->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 < 0x8000 && (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->rblocked && !canput(us->q))
+		    us->rblocked = 1;
+		if (!us->rblocked)
+		    putq(us->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->q))
+	    putnext(ppa->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->q_ptr;
+    if (us == 0) {
+	DPRINT("pppursrv: q_ptr = 0!\n");
+	return 0;
+    }
+
+    if (us->flags & 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->lowerq == 0) {
+	    as = us;
+	    do {
+		if (as->flags & US_BLOCKED)
+		    qenable(WR(as->q));
+		as = as->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->b_rptr);
+	    if (proto < 0x8000 && (as = find_dest(us, proto)) != 0) {
+		if (!canput(as->q))
+		    break;
+		putq(as->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->next; as != 0; as = as->next)
+		as->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->lowerq != 0)
+	    qenable(RD(us->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->b_rptr);
+	    mp->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->b_datap->db_type = M_PROTO;
+	    ud = (dl_unitdata_ind_t *) hdr->b_wptr;
+	    hdr->b_wptr += sizeof(dl_unitdata_ind_t) + 2 * sizeof(uint);
+	    hdr->b_cont = mp;
+	    ud->dl_primitive = DL_UNITDATA_IND;
+	    ud->dl_dest_addr_length = sizeof(uint);
+	    ud->dl_dest_addr_offset = sizeof(dl_unitdata_ind_t);
+	    ud->dl_src_addr_length = sizeof(uint);
+	    ud->dl_src_addr_offset = ud->dl_dest_addr_offset + sizeof(uint);
+#if DL_CURRENT_VERSION >= 2
+	    ud->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->req_sap;	/* dest SAP */
+	    ((uint *)(ud + 1))[1] = us->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->ppa)
+	    qenable(us->ppa->q);
+    }
+
+    return 0;
+}
+
+static upperstr_t *
+find_dest(ppa, proto)
+    upperstr_t *ppa;
+    int proto;
+{
+    upperstr_t *us;
+
+    for (us = ppa->next; us != 0; us = us->next)
+	if (proto == us->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) && (proto != PPP_IPV6))
+	return (upperstr_t *)0;
+
+    for ( ; us; us = us->next) {
+	if ((us->flags & US_PROMISC) && (us->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->b_wptr += sizeof(struct ether_header);
+    bzero((caddr_t)eh->b_rptr, sizeof(struct ether_header));
+    ((struct ether_header *)eh->b_rptr)->ether_type = htons((short)type);
+    eh->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->b_datap->db_type = M_PROTO;
+    dh->b_wptr = dh->b_datap->db_lim;
+    dh->b_rptr = dh->b_wptr - size;
+
+    dlu = (dl_unitdata_ind_t *)dh->b_rptr;
+    dlu->dl_primitive = DL_UNITDATA_IND;
+    dlu->dl_dest_addr_length = 0;
+    dlu->dl_dest_addr_offset = sizeof(dl_unitdata_ind_t);
+    dlu->dl_src_addr_length = 0;
+    dlu->dl_src_addr_offset = sizeof(dl_unitdata_ind_t);
+    dlu->dl_group_address = 0;
+
+    dh->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->b_rptr += PPP_HDRLEN;
+
+	    for ( ; nprus = find_promisc(prus->next, proto); 
+		    prus = nprus) {
+
+		if (dup_dup_mp = dupmsg(dup_mp)) {
+		    if (canputnext(prus->q)) {
+			if (prus->flags & US_RAWDATA) {
+			    dup_dup_mp = prepend_ether(prus, dup_dup_mp, proto);
+			    putnext(prus->q, dup_dup_mp);
+			} else {
+			    dup_dup_mp = prepend_udind(prus, dup_dup_mp, proto);
+			    putnext(prus->q, dup_dup_mp);
+			}
+		    } else {
+			DPRINT("ppp_urput: data to promisc q dropped\n");
+			freemsg(dup_dup_mp);
+		    }
+		}
+	    }
+
+	    if (canputnext(prus->q)) {
+		if (prus->flags & US_RAWDATA) {
+		    dup_mp = prepend_ether(prus, dup_mp, proto);
+		    putnext(prus->q, dup_mp);
+		} else {
+		    dup_mp = prepend_udind(prus, dup_mp, proto);
+		    putnext(prus->q, dup_mp);
+		}
+	    } else {
+		DPRINT("ppp_urput: data to promisc q dropped\n");
+		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->b_datap->db_type) {
+    case M_IOCTL:
+	iop = (struct iocblk *) mp->b_rptr;
+	iop->ioc_error = EINVAL;
+	mp->b_datap->db_type = M_IOCNAK;
+	qreply(q, mp);
+	return 0;
+    case M_FLUSH:
+	if (*mp->b_rptr & FLUSHR)
+	    flushq(q, FLUSHDATA);
+	if (*mp->b_rptr & FLUSHW) {
+	    *mp->b_rptr &= ~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->q_ptr;
+    if (uq == 0) {
+	UNLOCK_LOWER;
+	DPRINT1("ppplrput: q = %x, uq = 0??\n", 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 && 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->q_ptr;
+    if (uq == 0) {
+	UNLOCK_LOWER;
+	flushq(q, FLUSHALL);
+	DPRINT1("ppplrsrv: q = %x, uq = 0??\n", 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->b_datap->db_type = type;
+    mp->b_wptr[0] = code;
+    mp->b_wptr[1] = val;
+    mp->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->b_datap->db_type = type;
+    mp->b_wptr[0] = code;
+    ((short *)mp->b_wptr)[1] = val;
+    mp->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("ppp upper streams:\n");
+    for (us = minor_devs; us != 0; us = us->nextmn) {
+	uq = us->q;
+	DPRINT3(" %d: q=%x rlev=%d",
+		us->mn, uq, (uq? qsize(uq): 0));
+	DPRINT3(" wlev=%d flags=0x%b", (uq? qsize(WR(uq)): 0),
+		us->flags, "\020\1priv\2control\3blocked\4last");
+	DPRINT3(" state=%x sap=%x req_sap=%x", us->state, us->sap,
+		us->req_sap);
+	if (us->ppa == 0)
+	    DPRINT(" ppa=?\n");
+	else
+	    DPRINT1(" ppa=%d\n", us->ppa->ppa_id);
+	if (us->flags & US_CONTROL) {
+	    lq = us->lowerq;
+	    DPRINT3("    control for %d lq=%x rlev=%d",
+		    us->ppa_id, lq, (lq? qsize(RD(lq)): 0));
+	    DPRINT3(" wlev=%d mru=%d mtu=%d\n",
+		    (lq? qsize(lq): 0), us->mru, us->mtu);
+	}
+    }
+    mp->b_datap->db_type = M_IOCACK;
+    qreply(q, mp);
+}
+
+#ifdef FILTER_PACKETS
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+
+#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 dm at garage.uun.org (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->b_rptr);
+    if (us->flags & US_DBGLOG)
+        DPRINT3("ppp/%d: filter, proto=0x%x, out=%d\n", us->mn, proto, outbound);
+
+    switch (proto)
+    {
+    case PPP_IP:
+	if ((mp->b_wptr - mp->b_rptr) == PPP_HDRLEN && mp->b_cont != 0) {
+	    temp_mp = mp->b_cont;
+    	    len = msgdsize(temp_mp);
+	    hlen = (len < MAX_IPHDR) ? len : MAX_IPHDR;
+	    PULLUP(temp_mp, hlen);
+	    if (temp_mp == 0) {
+		DPRINT2("ppp/%d: filter, pullup next failed, len=%d\n", 
+			us->mn, hlen);
+		mp->b_cont = 0;		/* PULLUP() freed the rest */
+	        freemsg(mp);
+	        return 0;
+	    }
+	    ip = (struct ip *)mp->b_cont->b_rptr;
+	}
+	else {
+	    len = msgdsize(mp);
+	    hlen = (len < (PPP_HDRLEN+MAX_IPHDR)) ? len : (PPP_HDRLEN+MAX_IPHDR);
+	    PULLUP(mp, hlen);
+	    if (mp == 0) {
+		DPRINT2("ppp/%d: filter, pullup failed, len=%d\n", 
+			us->mn, hlen);
+	        return 0;
+	    }
+	    ip = (struct ip *)(mp->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->proto != -1; pft++) {
+	    if (ip->ip_p == pft->proto) {
+		switch(pft->proto) {
+		case IPPROTO_UDP:
+		    if (((struct udphdr *) &((int *)ip)[ip->ip_hl])->uh_dport
+				== htons(pft->port)) goto endfor;
+		    break;
+		case IPPROTO_TCP:
+		    if (((struct tcphdr *) &((int *)ip)[ip->ip_hl])->th_dport
+				== htons(pft->port)) goto endfor;
+		    break;
+		}	
+	    }
+	}
+	endfor:
+	if (pft->proto != -1) {
+	    if (us->flags & US_DBGLOG)
+		DPRINT3("ppp/%d: found IP pkt, proto=0x%x (%d)\n", 
+				us->mn, pft->proto, pft->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->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 <adi.masputra at sun.com>, 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 "AS IS" 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 <sys/types.h>
+#include <sys/param.h>
+#include <sys/stream.h>
+#include <sys/errno.h>
+
+#ifdef SVR4
+#include <sys/conf.h>
+#include <sys/kmem.h>
+#include <sys/cmn_err.h>
+#include <sys/ddi.h>
+#else
+#include <sys/user.h>
+#ifdef __osf__
+#include <sys/cmn_err.h>
+#endif
+#endif /* SVR4 */
+
+#include <net/ppp_defs.h>
+#include <net/pppio.h>
+#include "ppp_mod.h"
+
+/*
+ * 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 >= 0 ? x : (-x))
+#endif /* SOL2 */
+
+/*
+ * Extract byte i of message mp 
+ */
+#define MSG_BYTE(mp, i)	((i) < (mp)->b_wptr - (mp)->b_rptr? (mp)->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 <= (code = MSG_BYTE((mp), 4)) && code <= 7)
+
+/*
+ * Standard STREAMS declarations
+ */
+static struct module_info minfo = {
+    0x7d23, "ppp_ahdl", 0, INFPSZ, 32768, 512
+};
+
+static struct qinit rinit = {
+    ahdlc_rput, NULL, ahdlc_open, ahdlc_close, NULL, &minfo, NULL
+};
+
+static struct qinit winit = {
+    ahdlc_wput, NULL, NULL, NULL, NULL, &minfo, NULL
+};
+
+#if defined(SVR4) && !defined(SOL2)
+int phdldevflag = 0;
+#define ppp_ahdlcinfo phdlinfo
+#endif /* defined(SVR4) && !defined(SOL2) */
+
+struct streamtab ppp_ahdlcinfo = {
+    &rinit,			    /* ptr to st_rdinit */
+    &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->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->q_ptr	 = (caddr_t) state;
+    WR(q)->q_ptr = (caddr_t) state;
+
+#if defined(USE_MUTEX)
+    mutex_init(&state->lock, NULL, MUTEX_DEFAULT, NULL);
+    mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+
+    state->xaccm[0] = ~0;	    /* escape 0x00 through 0x1f */
+    state->xaccm[3] = 0x60000000;   /* escape 0x7d and 0x7e */
+    state->mru	    = PPP_MRU;	    /* default of 1500 bytes */
+#if defined(SOL2)
+    state->flag_time = drv_usectohz(FLAG_TIME);
+#endif /* SOL2 */
+
+#if defined(USE_MUTEX)
+    mutex_exit(&state->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->q_ptr;
+
+    if (state == 0) {
+	DPRINT("state == 0 in ahdlc_close\n");
+	return 0;
+    }
+
+#if defined(USE_MUTEX)
+    mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+
+    if (state->rx_buf != 0) {
+	freemsg(state->rx_buf);
+	state->rx_buf = 0;
+    }
+
+#if defined(USE_MUTEX)
+    mutex_exit(&state->lock);
+    mutex_destroy(&state->lock);
+#endif /* USE_MUTEX */
+
+    FREE(q->q_ptr, sizeof(ahdlc_state_t));
+    q->q_ptr	     = NULL;
+    OTHERQ(q)->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->q_ptr;
+    if (state == 0) {
+	DPRINT("state == 0 in ahdlc_wput\n");
+	freemsg(mp);
+	return 0;
+    }
+
+    switch (mp->b_datap->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->b_rptr;
+	error = EINVAL;
+	switch (iop->ioc_cmd) {
+	case PPPIO_XACCM:
+	    if ((iop->ioc_count < sizeof(u_int32_t)) || 
+		(iop->ioc_count > sizeof(ext_accm))) {
+		break;
+	    }
+	    if (mp->b_cont == 0) {
+		DPRINT1("ahdlc_wput/%d: PPPIO_XACCM b_cont = 0!\n", state->unit);
+		break;
+	    }
+#if defined(USE_MUTEX)
+	    mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+	    bcopy((caddr_t)mp->b_cont->b_rptr, (caddr_t)state->xaccm,
+		  iop->ioc_count);
+	    state->xaccm[2] &= ~0x40000000;	/* don't escape 0x5e */
+	    state->xaccm[3] |= 0x60000000;	/* do escape 0x7d, 0x7e */
+#if defined(USE_MUTEX)
+	    mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+	    iop->ioc_count = 0;
+	    error = 0;
+	    break;
+
+	case PPPIO_RACCM:
+	    if (iop->ioc_count != sizeof(u_int32_t))
+		break;
+	    if (mp->b_cont == 0) {
+		DPRINT1("ahdlc_wput/%d: PPPIO_RACCM b_cont = 0!\n", state->unit);
+		break;
+	    }
+#if defined(USE_MUTEX)
+	    mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+	    bcopy((caddr_t)mp->b_cont->b_rptr, (caddr_t)&state->raccm,
+		  sizeof(u_int32_t));
+#if defined(USE_MUTEX)
+	    mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+	    iop->ioc_count = 0;
+	    error = 0;
+	    break;
+
+	case PPPIO_GCLEAN:
+	    np = allocb(sizeof(int), BPRI_HI);
+	    if (np == 0) {
+		error = ENOSR;
+		break;
+	    }
+	    if (mp->b_cont != 0)
+		freemsg(mp->b_cont);
+	    mp->b_cont = np;
+#if defined(USE_MUTEX)
+	    mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+	    *(int *)np->b_wptr = state->flags & RCV_FLAGS;
+#if defined(USE_MUTEX)
+	    mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+	    np->b_wptr += sizeof(int);
+	    iop->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->b_cont != 0)
+		freemsg(mp->b_cont);
+	    mp->b_cont = np;
+	    psp = (struct ppp_stats *) np->b_wptr;
+	    np->b_wptr += sizeof(struct ppp_stats);
+	    bzero((caddr_t)psp, sizeof(struct ppp_stats));
+	    psp->p = state->stats;
+	    iop->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 < 0)
+	    putnext(q, mp);
+	else if (error == 0) {
+	    mp->b_datap->db_type = M_IOCACK;
+	    qreply(q, mp);
+	} else {
+	    mp->b_datap->db_type = M_IOCNAK;
+	    iop->ioc_count = 0;
+	    iop->ioc_error = error;
+	    qreply(q, mp);
+	}
+	break;
+
+    case M_CTL:
+	switch (*mp->b_rptr) {
+	case PPPCTL_MTU:
+#if defined(USE_MUTEX)
+	    mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+	    state->mtu = ((unsigned short *)mp->b_rptr)[1];
+#if defined(USE_MUTEX)
+	    mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+	    freemsg(mp);
+	    break;
+	case PPPCTL_MRU:
+#if defined(USE_MUTEX)
+	    mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+	    state->mru = ((unsigned short *)mp->b_rptr)[1];
+#if defined(USE_MUTEX)
+	    mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+	    freemsg(mp);
+	    break;
+	case PPPCTL_UNIT:
+#if defined(USE_MUTEX)
+	    mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+	    state->unit = mp->b_rptr[1];
+#if defined(USE_MUTEX)
+	    mutex_exit(&state->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->q_ptr;
+    if (state == 0) {
+	DPRINT("state == 0 in ahdlc_rput\n");
+	freemsg(mp);
+	return 0;
+    }
+
+    switch (mp->b_datap->db_type) {
+    case M_DATA:
+	ahdlc_decode(q, mp);
+	freemsg(mp);
+	break;
+
+    case M_HANGUP:
+#if defined(USE_MUTEX)
+	mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+	if (state->rx_buf != 0) {
+	    /* XXX would like to send this up for debugging */
+	    freemsg(state->rx_buf);
+	    state->rx_buf = 0;
+	}
+	state->flags = IFLUSH;
+#if defined(USE_MUTEX)
+	mutex_exit(&state->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) >> 5] & (1 << ((c) & 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) < 4) {
+	return;
+    }
+
+    state = (ahdlc_state_t *)q->q_ptr;
+#if defined(USE_MUTEX)
+    mutex_enter(&state->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)	 << 1) +		/* input block x 2 */
+		(sizeof(fcs)	 << 2) +		/* HDLC FCS x 4 */
+		(sizeof(uchar_t) << 1);			/* HDLC flags x 2 */
+
+    outmp = allocb(outmp_len, BPRI_MED);
+    if (outmp == NULL) {
+	state->stats.ppp_oerrors++;
+#if defined(USE_MUTEX)
+	mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+	putctl1(RD(q)->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, &lbolt) != -1) {
+	if (ABS((clock_t)lbolt - state->lbolt) > state->flag_time) {
+	    *outmp->b_wptr++ = PPP_FLAG;
+	} 
+	state->lbolt = lbolt;
+    } else {
+	*outmp->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->q_next) == 0) {
+	*outmp->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) && 
+	      (MSG_BYTE(mp, 1) == PPP_UI) && 
+	      (MSG_BYTE(mp, 2) == (PPP_LCP >> 8)) &&
+	      (MSG_BYTE(mp, 3) == (PPP_LCP & 0xff)) &&
+	      LCP_USE_DFLT(mp));
+
+    xaccm = state->xaccm;
+    if (is_lcp) {
+	bcopy((caddr_t)state->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->b_cont) {
+	if (tmp->b_datap->db_type == M_DATA) {
+	    for (dp = tmp->b_rptr; dp < tmp->b_wptr; dp++) {
+		fcs = PPP_FCS(fcs, *dp);
+		if (IN_TX_MAP(*dp, xaccm)) {
+		    *outmp->b_wptr++ = PPP_ESCAPE;
+		    *outmp->b_wptr++ = *dp ^ PPP_TRANS;
+		} else {
+		    *outmp->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) & 0xff;
+    if (IN_TX_MAP(fcs_val, xaccm)) {
+	*outmp->b_wptr++ = PPP_ESCAPE;
+	*outmp->b_wptr++ = fcs_val ^ PPP_TRANS;
+    } else {
+	*outmp->b_wptr++ = fcs_val;
+    }
+
+    fcs_val = ((fcs ^ 0xffff) >> 8) & 0xff;
+    if (IN_TX_MAP(fcs_val, xaccm)) {
+	*outmp->b_wptr++ = PPP_ESCAPE;
+	*outmp->b_wptr++ = fcs_val ^ PPP_TRANS;
+    } else {
+	*outmp->b_wptr++ = fcs_val;
+    }
+
+    /*
+     * And finally, append the HDLC flag, and send it away
+     */
+    *outmp->b_wptr++ = PPP_FLAG;
+
+    state->stats.ppp_obytes += msgdsize(outmp);
+    state->stats.ppp_opackets++;
+
+#if defined(USE_MUTEX)
+    mutex_exit(&state->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)) < 0x20) && \
+			(m) & (1 << (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->b_wptr - mp->b_rptr == msgdsize(mp)) && 
+         ((intpointer_t)mp->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->q_ptr;
+
+#if defined(USE_MUTEX)
+    mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+
+    state->stats.ppp_ibytes += msgdsize(mp);
+
+    for (dp = mp->b_rptr; dp < mp->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 & 0x80)
+	    state->flags |= RCV_B7_1;
+	else
+	    state->flags |= RCV_B7_0;
+
+	if (paritytab[*dp >> 5] & (1 << (*dp & 0x1f)))
+	    state->flags |= RCV_ODDP;
+	else
+	    state->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->flags & IFLUSH) ||
+		(state->rx_buf == 0) ||
+		(msgdsize(state->rx_buf) == 0)) {
+
+		state->flags &= ~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->rx_buf;
+
+	    if (state->infcs == PPP_GOODFCS) {
+		state->stats.ppp_ipackets++;
+		adjmsg(om, -PPP_FCSLEN);
+		putnext(q, om);
+	    } else {
+		DPRINT2("ppp%d: bad fcs (len=%d)\n",
+                    state->unit, msgdsize(state->rx_buf));
+		freemsg(state->rx_buf);
+		state->flags &= ~(IFLUSH | ESCAPED);
+		state->stats.ppp_ierrors++;
+		putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
+	    }
+
+	    state->rx_buf = 0;
+	    continue;
+	}
+
+	if (state->flags & 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->rx_buf == 0) {
+	    state->rx_buf_size  = (state->mru < PPP_MRU ? PPP_MRU : state->mru);
+	    state->rx_buf_size += (sizeof(u_int32_t) << 3);
+	    state->rx_buf = allocb(state->rx_buf_size, BPRI_MED);
+
+	    /*
+	     * If allocation fails, try again on the next frame
+	     */
+	    if (state->rx_buf == 0) {
+		state->flags |= IFLUSH;
+		continue;
+	    }
+	    state->flags &= ~(IFLUSH | ESCAPED);
+	    state->infcs  = PPP_INITFCS;
+	}
+
+	if (*dp == PPP_ESCAPE) {
+	    state->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->flags & ESCAPED) {
+	    *dp ^= PPP_TRANS;
+	    state->flags &= ~ESCAPED;
+	} else if (IN_RX_MAP(*dp, state->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->rx_buf) < state->rx_buf_size) {
+	    state->infcs = PPP_FCS(state->infcs, *dp);
+	    *state->rx_buf->b_wptr++ = *dp;
+	} else {
+	    DPRINT2("ppp%d: frame too long (%d)\n",
+		state->unit, msgdsize(state->rx_buf));
+	    freemsg(state->rx_buf);
+	    state->rx_buf     = 0;
+	    state->flags     |= IFLUSH;
+	}
+    }
+
+#if defined(USE_MUTEX)
+    mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+}
+
+static int
+msg_byte(mp, i)
+    mblk_t *mp;
+    unsigned int i;
+{
+    while (mp != 0 && i >= mp->b_wptr - mp->b_rptr)
+	mp = mp->b_cont;
+    if (mp == 0)
+	return -1;
+    return mp->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 "AS IS" 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 <sys/types.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/stream.h>
+
+#ifdef SVR4
+#include <sys/conf.h>
+#include <sys/cmn_err.h>
+#include <sys/ddi.h>
+#else
+#include <sys/user.h>
+#ifdef __osf__
+#include <sys/cmn_err.h>
+#endif
+#endif /* SVR4 */
+
+#include <net/ppp_defs.h>
+#include <net/pppio.h>
+#include "ppp_mod.h"
+
+#ifdef __osf__
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#endif
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <net/vjcompress.h>
+
+#define PACKETPTR	mblk_t *
+#include <net/ppp-comp.h>
+
+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) < (mp)->b_wptr - (mp)->b_rptr? (mp)->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 <= (code = MSG_BYTE((mp), 4)) && code <= 7)
+
+#define PPP_COMP_ID 0xbadf
+static struct module_info minfo = {
+#ifdef PRIOQ
+    PPP_COMP_ID, "ppp_comp", 0, INFPSZ, 16512, 16384,
+#else
+    PPP_COMP_ID, "ppp_comp", 0, INFPSZ, 16384, 4096,
+#endif
+};
+
+static struct qinit r_init = {
+    ppp_comp_rput, ppp_comp_rsrv, ppp_comp_open, ppp_comp_close,
+    NULL, &minfo, NULL
+};
+
+static struct qinit w_init = {
+    ppp_comp_wput, ppp_comp_wsrv, NULL, NULL, NULL, &minfo, NULL
+};
+
+#if defined(SVR4) && !defined(SOL2)
+int pcmpdevflag = 0;
+#define ppp_compinfo pcmpinfo
+#endif
+struct streamtab ppp_compinfo = {
+    &r_init, &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) < (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
+    &ppp_bsd_compress,
+#endif
+#if DO_DEFLATE
+    &ppp_deflate,
+    &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->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)->q_ptr = q->q_ptr = (caddr_t) cp;
+	cp->mru = PPP_MRU;
+	cp->mtu = PPP_MTU;
+	cp->xstate = NULL;
+	cp->rstate = NULL;
+	vj_compress_init(&cp->vj_comp, -1);
+#ifdef __osf__
+	if (!(thread = kernel_thread_w_arg(first_task, ppp_comp_alloc, (void *)cp)))
+		OPEN_ERROR(ENOSR);
+	cp->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->q_ptr;
+    if (cp != NULL) {
+	if (cp->xstate != NULL)
+	    (*cp->xcomp->comp_free)(cp->xstate);
+	if (cp->rstate != NULL)
+	    (*cp->rcomp->decomp_free)(cp->rstate);
+#ifdef __osf__
+	if (!cp->thread)
+	    printf("ppp_comp_close: NULL thread!\n");
+	else
+	    thread_terminate(cp->thread);
+#endif
+	FREE(cp, sizeof(comp_state_t));
+	q->q_ptr = NULL;
+	OTHERQ(q)->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) && (MAJOR_VERSION <= 2)
+
+    /* In 2.x and earlier the argument gets passed
+     * in the thread structure itself.  Yuck.
+     */
+    thread = current_thread();
+    cp = thread->reply_port;
+    thread->reply_port = PORT_NULL;
+
+#endif
+
+    for (;;) {
+	assert_wait((vm_offset_t)&cp->memreq.thread_status, TRUE);
+	thread_block();
+
+	if (thread_should_halt(current_thread()))
+	    thread_halt_self();
+	cmd = cp->memreq.cmd;
+	compressor_options = &cp->memreq.comp_opts[0];
+	len = compressor_options[1];
+	if (cmd == PPPIO_XCOMP) {
+	    cp->memreq.returned_mem = cp->xcomp->comp_alloc(compressor_options, len);
+	    if (!cp->memreq.returned_mem) {
+		cp->memreq.thread_status = ENOSR;
+	    } else {
+		cp->memreq.thread_status = 0;
+	    }
+	} else {
+	    cp->memreq.returned_mem = cp->rcomp->decomp_alloc(compressor_options, len);
+	    if (!cp->memreq.returned_mem) {
+	        cp->memreq.thread_status = ENOSR;
+	    } else {
+		cp->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 "sleep"
+ * 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->q_ptr;
+    if (cp == 0) {
+	DPRINT("cp == 0 in ppp_comp_wput\n");
+	freemsg(mp);
+	return 0;
+    }
+
+    switch (mp->b_datap->db_type) {
+
+    case M_DATA:
+	putq(q, mp);
+	break;
+
+    case M_IOCTL:
+	iop = (struct iocblk *) mp->b_rptr;
+	error = EINVAL;
+	switch (iop->ioc_cmd) {
+
+	case PPPIO_CFLAGS:
+	    /* set/get CCP state */
+	    if (iop->ioc_count != 2 * sizeof(int))
+		break;
+	    if (mp->b_cont == 0) {
+		DPRINT1("ppp_comp_wput/%d: PPPIO_CFLAGS b_cont = 0!\n", cp->unit);
+		break;
+	    }
+	    flags = ((int *) mp->b_cont->b_rptr)[0];
+	    mask = ((int *) mp->b_cont->b_rptr)[1];
+	    cp->flags = (cp->flags & ~mask) | (flags & mask);
+	    if ((mask & CCP_ISOPEN) && (flags & CCP_ISOPEN) == 0) {
+		if (cp->xstate != NULL) {
+		    (*cp->xcomp->comp_free)(cp->xstate);
+		    cp->xstate = NULL;
+		}
+		if (cp->rstate != NULL) {
+		    (*cp->rcomp->decomp_free)(cp->rstate);
+		    cp->rstate = NULL;
+		}
+		cp->flags &= ~CCP_ISUP;
+	    }
+	    error = 0;
+	    iop->ioc_count = sizeof(int);
+	    ((int *) mp->b_cont->b_rptr)[0] = cp->flags;
+	    mp->b_cont->b_wptr = mp->b_cont->b_rptr + sizeof(int);
+	    break;
+
+	case PPPIO_VJINIT:
+	    /*
+	     * Initialize VJ compressor/decompressor
+	     */
+	    if (iop->ioc_count != 2)
+		break;
+	    if (mp->b_cont == 0) {
+		DPRINT1("ppp_comp_wput/%d: PPPIO_VJINIT b_cont = 0!\n", cp->unit);
+		break;
+	    }
+	    nxslots = mp->b_cont->b_rptr[0] + 1;
+	    nrslots = mp->b_cont->b_rptr[1] + 1;
+	    if (nxslots > MAX_STATES || nrslots > MAX_STATES)
+		break;
+	    vj_compress_init(&cp->vj_comp, nxslots);
+	    cp->vj_last_ierrors = cp->stats.ppp_ierrors;
+	    error = 0;
+	    iop->ioc_count = 0;
+	    break;
+
+	case PPPIO_XCOMP:
+	case PPPIO_RCOMP:
+	    if (iop->ioc_count <= 0)
+		break;
+	    if (mp->b_cont == 0) {
+		DPRINT1("ppp_comp_wput/%d: PPPIO_[XR]COMP b_cont = 0!\n", cp->unit);
+		break;
+	    }
+	    opt_data = mp->b_cont->b_rptr;
+	    len = mp->b_cont->b_wptr - opt_data;
+	    if (len > iop->ioc_count)
+		len = iop->ioc_count;
+	    if (opt_data[1] < 2 || opt_data[1] > len)
+		break;
+	    for (comp = ppp_compressors; *comp != NULL; ++comp)
+		if ((*comp)->compress_proto == opt_data[0]) {
+		    /* here's the handler! */
+		    error = 0;
+#ifndef __osf__
+		    if (iop->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->xstate != NULL) {
+			    (*cp->xcomp->comp_free)(cp->xstate);
+			    cp->xstate = NULL;
+			}
+			cp->xcomp = *comp;
+			cp->xstate = (*comp)->comp_alloc(opt_data, len);
+			if (cp->xstate == NULL)
+			    error = ENOSR;
+		    } else {
+			if (cp->rstate != NULL) {
+			    (*cp->rcomp->decomp_free)(cp->rstate);
+			    cp->rstate = NULL;
+			}
+			cp->rcomp = *comp;
+			cp->rstate = (*comp)->decomp_alloc(opt_data, len);
+			if (cp->rstate == NULL)
+			    error = ENOSR;
+		    }
+#else
+		    if ((error = cp->memreq.thread_status) != EAGAIN)
+		    if (iop->ioc_cmd == PPPIO_XCOMP) {
+			if (cp->xstate) {
+			    (*cp->xcomp->comp_free)(cp->xstate);
+			    cp->xstate = 0;
+			}
+			/* sanity check for compressor options
+			 */
+			if (sizeof (cp->memreq.comp_opts) < len) {
+			    printf("can't handle options for compressor %d (%d)\n", opt_data[0],
+				opt_data[1]);
+			    cp->memreq.thread_status = ENOSR;
+			    cp->memreq.returned_mem = 0;
+			}
+			/* fill in request for the thread and kick it off
+			 */
+			if (cp->memreq.thread_status == 0 && !cp->memreq.returned_mem) {
+			    bcopy(opt_data, cp->memreq.comp_opts, len);
+			    cp->memreq.cmd = PPPIO_XCOMP;
+			    cp->xcomp = *comp;
+			    error = cp->memreq.thread_status = EAGAIN;
+			    thread_wakeup((vm_offset_t)&cp->memreq.thread_status);
+			} else {
+			    cp->xstate = cp->memreq.returned_mem;
+			    cp->memreq.returned_mem = 0;
+			    cp->memreq.thread_status = 0;
+			}
+		    } else {
+			if (cp->rstate) {
+			    (*cp->rcomp->decomp_free)(cp->rstate);
+			    cp->rstate = NULL;
+			}
+			if (sizeof (cp->memreq.comp_opts) < len) {
+			    printf("can't handle options for compressor %d (%d)\n", opt_data[0],
+				opt_data[1]);
+			    cp->memreq.thread_status = ENOSR;
+			    cp->memreq.returned_mem = 0;
+			}
+			if (cp->memreq.thread_status == 0 && !cp->memreq.returned_mem) {
+			    bcopy(opt_data, cp->memreq.comp_opts, len);
+			    cp->memreq.cmd = PPPIO_RCOMP;
+			    cp->rcomp = *comp;
+			    error = cp->memreq.thread_status = EAGAIN;
+			    thread_wakeup((vm_offset_t)&cp->memreq.thread_status);
+			} else {
+			    cp->rstate = cp->memreq.returned_mem;
+			    cp->memreq.returned_mem = 0;
+			    cp->memreq.thread_status = 0;
+			}
+		    }
+#endif
+		    break;
+		}
+	    iop->ioc_count = 0;
+	    break;
+
+	case PPPIO_GETSTAT:
+	    if ((cp->flags & 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->b_cont != 0)
+		freemsg(mp->b_cont);
+	    mp->b_cont = np;
+	    psp = (struct ppp_stats *) np->b_wptr;
+	    np->b_wptr += sizeof(struct ppp_stats);
+	    iop->ioc_count = sizeof(struct ppp_stats);
+	    psp->p = cp->stats;
+	    psp->vj = cp->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->b_cont != 0)
+		freemsg(mp->b_cont);
+	    mp->b_cont = np;
+	    csp = (struct ppp_comp_stats *) np->b_wptr;
+	    np->b_wptr += sizeof(struct ppp_comp_stats);
+	    iop->ioc_count = sizeof(struct ppp_comp_stats);
+	    bzero((caddr_t)csp, sizeof(struct ppp_comp_stats));
+	    if (cp->xstate != 0)
+		(*cp->xcomp->comp_stat)(cp->xstate, &csp->c);
+	    if (cp->rstate != 0)
+		(*cp->rcomp->decomp_stat)(cp->rstate, &csp->d);
+	    error = 0;
+	    break;
+
+	case PPPIO_DEBUG:
+	    if (iop->ioc_count != sizeof(int))
+		break;
+	    if (mp->b_cont == 0) {
+		DPRINT1("ppp_comp_wput/%d: PPPIO_DEBUG b_cont = 0!\n", cp->unit);
+		break;
+	    }
+	    n = *(int *)mp->b_cont->b_rptr;
+	    if (n == PPPDBG_LOG + PPPDBG_COMP) {
+		DPRINT1("ppp_comp%d: debug log enabled\n", cp->unit);
+		cp->flags |= DBGLOG;
+		error = 0;
+		iop->ioc_count = 0;
+	    } else {
+		error = -1;
+	    }
+	    break;
+
+	case PPPIO_LASTMOD:
+	    cp->flags |= LAST_MOD;
+	    error = 0;
+	    break;
+
+	default:
+	    error = -1;
+	    break;
+	}
+
+	if (error < 0)
+	    putnext(q, mp);
+	else if (error == 0) {
+	    mp->b_datap->db_type = M_IOCACK;
+	    qreply(q, mp);
+	} else {
+	    mp->b_datap->db_type = M_IOCNAK;
+	    iop->ioc_error = error;
+	    iop->ioc_count = 0;
+	    qreply(q, mp);
+	}
+	break;
+
+    case M_CTL:
+	switch (*mp->b_rptr) {
+	case PPPCTL_MTU:
+	    cp->mtu = ((unsigned short *)mp->b_rptr)[1];
+	    break;
+	case PPPCTL_MRU:
+	    cp->mru = ((unsigned short *)mp->b_rptr)[1];
+	    break;
+	case PPPCTL_UNIT:
+	    cp->unit = mp->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->q_ptr;
+    if (cp == 0) {
+	DPRINT("cp == 0 in ppp_comp_wsrv\n");
+	return 0;
+    }
+
+    while ((mp = getq(q)) != 0) {
+	/* assert(mp->b_datap->db_type == M_DATA) */
+#ifdef PRIOQ
+        if (!bcanputnext(q,mp->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 < PPP_HDRLEN) {
+	    DPRINT1("ppp_comp_wsrv: bogus short packet (%d)\n", len);
+	    freemsg(mp);
+	    cp->stats.ppp_oerrors++;
+	    putctl1(RD(q)->q_next, M_CTL, PPPCTL_OERROR);
+	    continue;
+	}
+	proto = (MSG_BYTE(mp, 2) << 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 > len)
+	    hlen = len;
+	if (mp->b_wptr < mp->b_rptr + hlen || mp->b_datap->db_ref > 1) {
+	    PULLUP(mp, hlen);
+	    if (mp == 0) {
+		DPRINT1("ppp_comp_wsrv: pullup failed (%d)\n", hlen);
+		cp->stats.ppp_oerrors++;
+		putctl1(RD(q)->q_next, M_CTL, PPPCTL_OERROR);
+		continue;
+	    }
+	}
+
+	/*
+	 * Do VJ compression if requested.
+	 */
+	if (proto == PPP_IP && (cp->flags & COMP_VJC)) {
+	    ip = (struct ip *) (mp->b_rptr + PPP_HDRLEN);
+	    if (ip->ip_p == IPPROTO_TCP) {
+		type = vj_compress_tcp(ip, len - PPP_HDRLEN, &cp->vj_comp,
+				       (cp->flags & COMP_VJCCID), &vjhdr);
+		switch (type) {
+		case TYPE_UNCOMPRESSED_TCP:
+		    mp->b_rptr[3] = proto = PPP_VJC_UNCOMP;
+		    break;
+		case TYPE_COMPRESSED_TCP:
+		    dp = vjhdr - PPP_HDRLEN;
+		    dp[1] = mp->b_rptr[1]; /* copy control field */
+		    dp[0] = mp->b_rptr[0]; /* copy address field */
+		    dp[2] = 0;		   /* set protocol field */
+		    dp[3] = proto = PPP_VJC_COMP;
+		    mp->b_rptr = dp;
+		    break;
+		}
+	    }
+	}
+
+	/*
+	 * Do packet compression if enabled.
+	 */
+	if (proto == PPP_CCP)
+	    ppp_comp_ccp(q, mp, 0);
+	else if (proto != PPP_LCP && (cp->flags & CCP_COMP_RUN)
+		 && cp->xstate != NULL) {
+	    len = msgdsize(mp);
+	    (*cp->xcomp->compress)(cp->xstate, &cmp, mp, len,
+			(cp->flags & CCP_ISUP? cp->mtu + PPP_HDRLEN: 0));
+	    if (cmp != NULL) {
+#ifdef PRIOQ
+		cmp->b_band=mp->b_band;
+#endif PRIOQ
+		freemsg(mp);
+		mp = cmp;
+	    }
+	}
+
+	/*
+	 * Do address/control and protocol compression if enabled.
+	 */
+	if ((cp->flags & COMP_AC)
+	    && !(proto == PPP_LCP && LCP_USE_DFLT(mp))) {
+	    mp->b_rptr += 2;	/* drop the address & ctrl fields */
+	    if (proto < 0x100 && (cp->flags & COMP_PROT))
+		++mp->b_rptr;	/* drop the high protocol byte */
+	} else if (proto < 0x100 && (cp->flags & COMP_PROT)) {
+	    /* shuffle up the address & ctrl fields */
+	    mp->b_rptr[2] = mp->b_rptr[1];
+	    mp->b_rptr[1] = mp->b_rptr[0];
+	    ++mp->b_rptr;
+	}
+
+	cp->stats.ppp_opackets++;
+	cp->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->q_ptr;
+    if (cp == 0) {
+	DPRINT("cp == 0 in ppp_comp_rput\n");
+	freemsg(mp);
+	return 0;
+    }
+
+    switch (mp->b_datap->db_type) {
+
+    case M_DATA:
+	putq(q, mp);
+	break;
+
+    case M_IOCACK:
+	iop = (struct iocblk *) mp->b_rptr;
+	switch (iop->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->b_cont == 0 || iop->ioc_count != sizeof(struct ppp_stats))
+		break;
+	    psp = (struct ppp_stats *) mp->b_cont->b_rptr;
+	    psp->vj = cp->vj_comp.stats;
+	    break;
+	}
+	putnext(q, mp);
+	break;
+
+    case M_CTL:
+	switch (mp->b_rptr[0]) {
+	case PPPCTL_IERROR:
+	    ++cp->stats.ppp_ierrors;
+	    break;
+	case PPPCTL_OERROR:
+	    ++cp->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->q_ptr;
+    if (cp == 0) {
+	DPRINT("cp == 0 in ppp_comp_rsrv\n");
+	return 0;
+    }
+
+    while ((mp = getq(q)) != 0) {
+	/* assert(mp->b_datap->db_type == M_DATA) */
+	if (!canputnext(q)) {
+	    putbq(q, mp);
+	    break;
+	}
+
+	len = msgdsize(mp);
+	cp->stats.ppp_ibytes += len;
+	cp->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 & 1) == 0) {
+	    ++i;
+	    proto = (proto << 8) + MSG_BYTE(mp, i);
+	}
+	hlen = i + 1;
+
+	/*
+	 * Now reconstruct a complete, contiguous PPP header at the
+	 * start of the packet.
+	 */
+	if (hlen < ((cp->flags & DECOMP_AC)? 0: 2)
+	           + ((cp->flags & DECOMP_PROT)? 1: 2)) {
+	    /* count these? */
+	    goto bad;
+	}
+	if (mp->b_rptr + hlen > mp->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->b_rptr + hlen - PPP_HDRLEN;
+	    if (dp < mp->b_datap->db_base || mp->b_datap->db_ref > 1) {
+		np = allocb(PPP_HDRLEN, BPRI_MED);
+		if (np == 0)
+		    goto bad;
+		np->b_cont = mp;
+		mp->b_rptr += hlen;
+		mp = np;
+		dp = mp->b_wptr;
+		mp->b_wptr += PPP_HDRLEN;
+	    } else
+		mp->b_rptr = dp;
+
+	    dp[0] = PPP_ALLSTATIONS;
+	    dp[1] = PPP_UI;
+	    dp[2] = proto >> 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->b_rptr);
+	if (proto == PPP_CCP) {
+	    len = msgdsize(mp);
+	    if (mp->b_wptr < mp->b_rptr + len) {
+		PULLUP(mp, len);
+		if (mp == 0)
+		    goto bad;
+	    }
+	    ppp_comp_ccp(q, mp, 1);
+	} else if (proto == PPP_COMP) {
+	    if ((cp->flags & CCP_ISUP)
+		&& (cp->flags & CCP_DECOMP_RUN) && cp->rstate
+		&& (cp->flags & CCP_ERR) == 0) {
+		rv = (*cp->rcomp->decompress)(cp->rstate, mp, &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->flags |= CCP_ERROR;
+		    ++cp->stats.ppp_ierrors;
+		    putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
+		    break;
+		case DECOMP_FATALERROR:
+		    cp->flags |= CCP_FATALERROR;
+		    ++cp->stats.ppp_ierrors;
+		    putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
+		    break;
+		}
+	    }
+	} else if (cp->rstate && (cp->flags & CCP_DECOMP_RUN)) {
+	    (*cp->rcomp->incomp)(cp->rstate, mp);
+	}
+
+	/*
+	 * Now do VJ decompression.
+	 */
+	proto = PPP_PROTOCOL(mp->b_rptr);
+	if (proto == PPP_VJC_COMP || proto == PPP_VJC_UNCOMP) {
+	    len = msgdsize(mp) - PPP_HDRLEN;
+	    if ((cp->flags & DECOMP_VJC) == 0 || len <= 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->b_rptr + PPP_HDRLEN;
+	    if (dp >= mp->b_wptr) {
+		np = np->b_cont;
+		dp = np->b_rptr;
+	    }
+
+	    /*
+	     * Make sure we have sufficient contiguous data at this point.
+	     */
+	    hlen = (proto == PPP_VJC_COMP)? MAX_VJHDR: MAX_IPHDR;
+	    if (hlen > len)
+		hlen = len;
+	    if (np->b_wptr < dp + hlen || np->b_datap->db_ref > 1) {
+		PULLUP(mp, hlen + PPP_HDRLEN);
+		if (mp == 0)
+		    goto bad;
+		np = mp;
+		dp = np->b_rptr + PPP_HDRLEN;
+	    }
+
+	    if (proto == PPP_VJC_COMP) {
+		/*
+		 * Decompress VJ-compressed packet.
+		 * First reset compressor if an input error has occurred.
+		 */
+		if (cp->stats.ppp_ierrors != cp->vj_last_ierrors) {
+		    if (cp->flags & DBGLOG)
+			DPRINT1("ppp%d: resetting VJ\n", cp->unit);
+		    vj_uncompress_err(&cp->vj_comp);
+		    cp->vj_last_ierrors = cp->stats.ppp_ierrors;
+		}
+
+		vjlen = vj_uncompress_tcp(dp, np->b_wptr - dp, len,
+					  &cp->vj_comp, &iphdr, &iphlen);
+		if (vjlen < 0) {
+		    if (cp->flags & DBGLOG)
+			DPRINT2("ppp%d: vj_uncomp_tcp failed, pkt len %d\n",
+				cp->unit, len);
+		    ++cp->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->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->b_rptr;	/* prepend mblk with TCP/IP hdr */
+		dp[0] = PPP_ALLSTATIONS; /* reconstruct PPP header */
+		dp[1] = PPP_UI;
+		dp[2] = PPP_IP >> 8;
+		dp[3] = PPP_IP;
+		bcopy((caddr_t)iphdr, (caddr_t)dp + PPP_HDRLEN, iphlen);
+		np->b_wptr = dp + iphlen + PPP_HDRLEN;
+		np->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->b_wptr - mp->b_rptr > 4) {
+		    bcopy((caddr_t)mp->b_rptr, (caddr_t)np->b_wptr, 4);
+		    mp->b_rptr += 4;
+		    np->b_wptr += 4;
+		} else {
+		    bcopy((caddr_t)mp->b_rptr, (caddr_t)np->b_wptr,
+			  mp->b_wptr - mp->b_rptr);
+		    np->b_wptr += mp->b_wptr - mp->b_rptr;
+		    np->b_cont = mp->b_cont;
+		    freeb(mp);
+		}
+
+		mp = np;
+
+	    } else {
+		/*
+		 * "Decompress" a VJ-uncompressed packet.
+		 */
+		cp->vj_last_ierrors = cp->stats.ppp_ierrors;
+		if (!vj_uncompress_uncomp(dp, hlen, &cp->vj_comp)) {
+		    if (cp->flags & DBGLOG)
+			DPRINT2("ppp%d: vj_uncomp_uncomp failed, pkt len %d\n",
+				cp->unit, len);
+		    ++cp->vj_last_ierrors;  /* don't need to reset next time */
+		    goto bad;
+		}
+		mp->b_rptr[3] = PPP_IP;	/* fix up the PPP protocol field */
+	    }
+	}
+
+	putnext(q, mp);
+	continue;
+
+    bad:
+	if (mp != 0)
+	    freemsg(mp);
+	cp->stats.ppp_ierrors++;
+	putctl1(q->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 < PPP_HDRLEN + CCP_HDRLEN)
+	return;
+
+    cp = (comp_state_t *) q->q_ptr;
+    dp = mp->b_rptr + PPP_HDRLEN;
+    len -= PPP_HDRLEN;
+    clen = CCP_LENGTH(dp);
+    if (clen > len)
+	return;
+
+    switch (CCP_CODE(dp)) {
+    case CCP_CONFREQ:
+    case CCP_TERMREQ:
+    case CCP_TERMACK:
+	cp->flags &= ~CCP_ISUP;
+	break;
+
+    case CCP_CONFACK:
+	if ((cp->flags & (CCP_ISOPEN | CCP_ISUP)) == CCP_ISOPEN
+	    && clen >= CCP_HDRLEN + CCP_OPT_MINLEN
+	    && clen >= CCP_HDRLEN + CCP_OPT_LENGTH(dp + CCP_HDRLEN)) {
+	    if (!rcvd) {
+		if (cp->xstate != NULL
+		    && (*cp->xcomp->comp_init)
+		        (cp->xstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN,
+			 cp->unit, 0, ((cp->flags & DBGLOG) != 0)))
+		    cp->flags |= CCP_COMP_RUN;
+	    } else {
+		if (cp->rstate != NULL
+		    && (*cp->rcomp->decomp_init)
+		        (cp->rstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN,
+			 cp->unit, 0, cp->mru, ((cp->flags & DBGLOG) != 0)))
+		    cp->flags = (cp->flags & ~CCP_ERR) | CCP_DECOMP_RUN;
+	    }
+	}
+	break;
+
+    case CCP_RESETACK:
+	if (cp->flags & CCP_ISUP) {
+	    if (!rcvd) {
+		if (cp->xstate && (cp->flags & CCP_COMP_RUN))
+		    (*cp->xcomp->comp_reset)(cp->xstate);
+	    } else {
+		if (cp->rstate && (cp->flags & CCP_DECOMP_RUN)) {
+		    (*cp->rcomp->decomp_reset)(cp->rstate);
+		    cp->flags &= ~CCP_ERROR;
+		}
+	    }
+	}
+	break;
+    }
+}
+
+#if 0
+dump_msg(mp)
+    mblk_t *mp;
+{
+    dblk_t *db;
+
+    while (mp != 0) {
+	db = mp->b_datap;
+	DPRINT2("mp=%x cont=%x ", mp, mp->b_cont);
+	DPRINT3("rptr=%x wptr=%x datap=%x\n", mp->b_rptr, mp->b_wptr, db);
+	DPRINT2("  base=%x lim=%x", db->db_base, db->db_lim);
+	DPRINT2(" ref=%d type=%d\n", db->db_ref, db->db_type);
+	mp = mp->b_cont;
+    }
+}
+#endif
+
+static int
+msg_byte(mp, i)
+    mblk_t *mp;
+    unsigned int i;
+{
+    while (mp != 0 && i >= mp->b_wptr - mp->b_rptr)
+	mp = mp->b_cont;
+    if (mp == 0)
+	return -1;
+    return mp->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 <sys/kmem.h>
+#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 <sys/kmem_alloc.h>	/* 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 <sys/malloc.h>
+
+/* 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 "FREE" 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 <sys/proc.h>
+#define NOTSUSER()		(suser(u.u_procp->p_rcred, &u.u_acflag) ? EPERM : 0)
+
+/* #include "ppp_osf.h" */
+
+#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 <sys/strlog.h>
+#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)->q_qinfo->qi_putp)((q), (mp)))
+# define canputnext(q)	canput((q)->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 (van at helios.ee.lbl.gov), Dec 31, 1989:
+ *	- Initial distribution.
+ *
+ * Modified June 1993 by Paul Mackerras, paulus at cs.anu.edu.au,
+ * 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 <sys/types.h>
+#include <sys/param.h>
+
+#ifdef SVR4
+#ifndef __GNUC__
+#include <sys/byteorder.h>	/* for ntohl, etc. */
+#else
+/* make sure we don't get the gnu "fixed" one! */
+#include "/usr/include/sys/byteorder.h"
+#endif
+#endif
+
+#ifdef __osf__
+#include <net/net_globals.h>
+#endif
+#include <netinet/in.h>
+
+#ifdef AIX4
+#define _NETINET_IN_SYSTM_H_
+typedef u_long  n_long;
+#else
+#include <netinet/in_systm.h>
+#endif
+
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+
+#include <net/ppp_defs.h>
+#include <net/vjcompress.h>
+
+#ifndef VJ_NO_STATS
+#define INCR(counter) ++comp->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)&0xf)
+#define getth_off(base)	((((base).th_xoff)&0xf0)>>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->tstate;
+
+    if (max_state == -1)
+	max_state = MAX_STATES - 1;
+    bzero((char *)comp, sizeof(*comp));
+    for (i = max_state; i > 0; --i) {
+	tstate[i].cs_id = i;
+	tstate[i].cs_next = &tstate[i - 1];
+    }
+    tstate[0].cs_next = &tstate[max_state];
+    tstate[0].cs_id = 0;
+    comp->last_cs = &tstate[0];
+    comp->last_recv = 255;
+    comp->last_xmit = 255;
+    comp->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) >= 256) { \
+		*cp++ = 0; \
+		cp[1] = (n); \
+		cp[0] = (n) >> 8; \
+		cp += 2; \
+	} else { \
+		*cp++ = (n); \
+	} \
+}
+#define ENCODEZ(n) { \
+	if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \
+		*cp++ = 0; \
+		cp[1] = (n); \
+		cp[0] = (n) >> 8; \
+		cp += 2; \
+	} else { \
+		*cp++ = (n); \
+	} \
+}
+
+#define DECODEL(f) { \
+	if (*cp == 0) {\
+		u_int32_t tmp = ntohl(f) + ((cp[1] << 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] << 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] << 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->last_cs->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->ip_off & htons(0x3fff)) || mlen < 40)
+	return (TYPE_IP);
+
+    th = (struct tcphdr *)&((int *)ip)[hlen];
+    if ((th->th_flags & (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 & we don't have to do any reordering if it's used.
+     */
+    INCR(vjs_packets);
+    if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr ||
+	ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr ||
+	*(int *)th != ((int *)&cs->cs_ip)[getip_hl(cs->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->last_cs;
+
+	do {
+	    lcs = cs; cs = cs->cs_next;
+	    INCR(vjs_searches);
+	    if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr
+		&& ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr
+		&& *(int *)th == ((int *)&cs->cs_ip)[getip_hl(cs->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->last_cs = lcs;
+	hlen += getth_off(*th);
+	hlen <<= 2;
+	if (hlen > mlen)
+	    return (TYPE_IP);
+	goto uncompressed;
+
+    found:
+	/*
+	 * Found it -- move to the front on the connection list.
+	 */
+	if (cs == lastcs)
+	    comp->last_cs = lcs;
+	else {
+	    lcs->cs_next = cs->cs_next;
+	    cs->cs_next = lastcs->cs_next;
+	    lastcs->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 &
+     * type of service.  The 2nd line checks the "Don't fragment" 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 & current datagram, we send the
+     * current datagram `uncompressed'.
+     */
+    oth = (struct tcphdr *)&((int *)&cs->cs_ip)[hlen];
+    deltaS = hlen;
+    hlen += getth_off(*th);
+    hlen <<= 2;
+    if (hlen > mlen)
+	return (TYPE_IP);
+
+    if (((u_short *)ip)[0] != ((u_short *)&cs->cs_ip)[0] ||
+	((u_short *)ip)[3] != ((u_short *)&cs->cs_ip)[3] ||
+	((u_short *)ip)[4] != ((u_short *)&cs->cs_ip)[4] ||
+	getth_off(*th) != getth_off(*oth) ||
+	(deltaS > 5 && BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) ||
+	(getth_off(*th) > 5 && BCMP(th + 1, oth + 1, (getth_off(*th) - 5) << 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->th_flags & TH_URG) {
+	deltaS = ntohs(th->th_urp);
+	ENCODEZ(deltaS);
+	changes |= NEW_U;
+    } else if (th->th_urp != oth->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->th_win) - ntohs(oth->th_win))) > 0) {
+	ENCODE(deltaS);
+	changes |= NEW_W;
+    }
+
+    if ((deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack)) > 0) {
+	if (deltaA > 0xffff)
+	    goto uncompressed;
+	ENCODE(deltaA);
+	changes |= NEW_A;
+    }
+
+    if ((deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq)) > 0) {
+	if (deltaS > 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->ip_len != cs->cs_ip.ip_len &&
+	    ntohs(cs->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 && deltaS == ntohs(cs->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->cs_ip.ip_len) - hlen) {
+	    /* special case for data xfer */
+	    changes = SPECIAL_D;
+	    cp = new_seq;
+	}
+	break;
+    }
+
+    deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id);
+    if (deltaS != 1) {
+	ENCODEZ(deltaS);
+	changes |= NEW_I;
+    }
+    if (th->th_flags & 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->th_sum);
+    BCOPY(ip, &cs->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->last_xmit != cs->cs_id) {
+	comp->last_xmit = cs->cs_id;
+	hlen -= deltaS + 4;
+	*vjhdrp = (cp += hlen);
+	*cp++ = changes | NEW_C;
+	*cp++ = cs->cs_id;
+    } else {
+	hlen -= deltaS + 3;
+	*vjhdrp = (cp += hlen);
+	*cp++ = changes;
+    }
+    *cp++ = deltaA >> 8;
+    *cp++ = deltaA;
+    BCOPY(new_seq, cp, deltaS);
+    INCR(vjs_compressed);
+    return (TYPE_COMPRESSED_TCP);
+
+    /*
+     * Update connection state cs & 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, &cs->cs_ip, hlen);
+    ip->ip_p = cs->cs_id;
+    comp->last_xmit = cs->cs_id;
+    return (TYPE_UNCOMPRESSED_TCP);
+}
+
+/*
+ * Called when we may have missed a packet.
+ */
+void
+vj_uncompress_err(comp)
+    struct vjcompress *comp;
+{
+    comp->flags |= VJF_TOSS;
+    INCR(vjs_errorin);
+}
+
+/*
+ * "Uncompress" 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) << 2;
+    if (ip->ip_p >= MAX_STATES
+	|| hlen + sizeof(struct tcphdr) > buflen
+	|| (hlen += getth_off(*((struct tcphdr *)&((char *)ip)[hlen])) << 2)
+	    > buflen
+	|| hlen > MAX_HDR) {
+	comp->flags |= VJF_TOSS;
+	INCR(vjs_errorin);
+	return (0);
+    }
+    cs = &comp->rstate[comp->last_recv = ip->ip_p];
+    comp->flags &=~ VJF_TOSS;
+    ip->ip_p = IPPROTO_TCP;
+    BCOPY(ip, &cs->cs_ip, hlen);
+    cs->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 & 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 >= MAX_STATES)
+	    goto bad;
+
+	comp->flags &=~ VJF_TOSS;
+	comp->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->flags & VJF_TOSS) {
+	    INCR(vjs_tossed);
+	    return (-1);
+	}
+    }
+    cs = &comp->rstate[comp->last_recv];
+    hlen = getip_hl(cs->cs_ip) << 2;
+    th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen];
+    th->th_sum = htons((*cp << 8) | cp[1]);
+    cp += 2;
+    if (changes & TCP_PUSH_BIT)
+	th->th_flags |= TH_PUSH;
+    else
+	th->th_flags &=~ TH_PUSH;
+
+    switch (changes & SPECIALS_MASK) {
+    case SPECIAL_I:
+	{
+	    register u_int32_t i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;
+	    /* some compilers can't nest inline assembler.. */
+	    tmp = ntohl(th->th_ack) + i;
+	    th->th_ack = htonl(tmp);
+	    tmp = ntohl(th->th_seq) + i;
+	    th->th_seq = htonl(tmp);
+	}
+	break;
+
+    case SPECIAL_D:
+	/* some compilers can't nest inline assembler.. */
+	tmp = ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;
+	th->th_seq = htonl(tmp);
+	break;
+
+    default:
+	if (changes & NEW_U) {
+	    th->th_flags |= TH_URG;
+	    DECODEU(th->th_urp);
+	} else
+	    th->th_flags &=~ TH_URG;
+	if (changes & NEW_W)
+	    DECODES(th->th_win);
+	if (changes & NEW_A)
+	    DECODEL(th->th_ack);
+	if (changes & NEW_S)
+	    DECODEL(th->th_seq);
+	break;
+    }
+    if (changes & NEW_I) {
+	DECODES(cs->cs_ip.ip_id);
+    } else {
+	cs->cs_ip.ip_id = ntohs(cs->cs_ip.ip_id) + 1;
+	cs->cs_ip.ip_id = htons(cs->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 < 0)
+	/* we must have dropped some characters (crc should detect
+	 * this but the old slip framing won't) */
+	goto bad;
+
+    total_len += cs->cs_hlen - vjlen;
+    cs->cs_ip.ip_len = htons(total_len);
+
+    /* recompute the ip header checksum */
+    bp = (u_short *) &cs->cs_ip;
+    cs->cs_ip.ip_sum = 0;
+    for (changes = 0; hlen > 0; hlen -= 2)
+	changes += *bp++;
+    changes = (changes & 0xffff) + (changes >> 16);
+    changes = (changes & 0xffff) + (changes >> 16);
+    cs->cs_ip.ip_sum = ~ changes;
+
+    *hdrp = (u_char *) &cs->cs_ip;
+    *hlenp = cs->cs_hlen;
+    return vjlen;
+
+ bad:
+    comp->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 (gc at mandriva.com)
+ #
+ # 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 $< -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 "Pluggable Authentication Modules", 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) >.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 "Pluggable Authentication Modules", 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>/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) >.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 "Pluggable Authentication Modules", 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) >.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='"/var/run/"'
+
+#
+# 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=\"/usr/spool/locks\"
+
+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	"$Id: auth.c 195734 2001-06-11 14:46:02Z gc $"
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <utmp.h>
+#include <fcntl.h>
+#if defined(_PATH_LASTLOG) && defined(_linux_)
+#include <lastlog.h>
+#endif
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#ifdef USE_PAM
+#include <security/pam_appl.h>
+#endif
+
+#ifdef HAS_SHADOW
+#include <shadow.h>
+#ifndef PW_PPP
+#define PW_PPP PW_LOGIN
+#endif
+#endif
+
+#include "pppd.h"
+#include "fsm.h"
+#include "lcp.h"
+#include "ipcp.h"
+#include "upap.h"
+#include "chap.h"
+#ifdef CBCP_SUPPORT
+#include "cbcp.h"
+#endif
+#include "pathnames.h"
+
+#include <time.h>
+
+static const char rcsid[] = RCSID;
+
+/* Bits in scan_authfile return value */
+#define NONWILD_SERVER	1
+#define NONWILD_CLIENT	2
+
+#define ISWILD(word)	(word[0] == '*' && 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[] = {
+    { "auth", o_bool, &auth_required,
+      "Require authentication from peer", OPT_PRIO | 1 },
+    { "noauth", o_bool, &auth_required,
+      "Don't require peer to authenticate", OPT_PRIOSUB | OPT_PRIV,
+      &allow_any_ip },
+    { "require-pap", o_bool, &lcp_wantoptions[0].neg_upap,
+      "Require PAP authentication from peer",
+      OPT_PRIOSUB | 1, &auth_required },
+    { "+pap", o_bool, &lcp_wantoptions[0].neg_upap,
+      "Require PAP authentication from peer",
+      OPT_ALIAS | OPT_PRIOSUB | 1, &auth_required },
+    { "require-chap", o_bool, &lcp_wantoptions[0].neg_chap,
+      "Require CHAP authentication from peer",
+      OPT_PRIOSUB | 1, &auth_required },
+    { "+chap", o_bool, &lcp_wantoptions[0].neg_chap,
+      "Require CHAP authentication from peer",
+      OPT_ALIAS | OPT_PRIOSUB | 1, &auth_required },
+
+    { "refuse-pap", o_bool, &refuse_pap,
+      "Don't agree to auth to peer with PAP", 1 },
+    { "-pap", o_bool, &refuse_pap,
+      "Don't allow PAP authentication with peer", OPT_ALIAS | 1 },
+
+    { "refuse-chap", o_bool, &refuse_chap,
+      "Don't agree to auth to peer with CHAP", 1 },
+    { "-chap", o_bool, &refuse_chap,
+      "Don't allow CHAP authentication with peer", OPT_ALIAS | 1 },
+
+    { "name", o_string, our_name,
+      "Set local name for authentication",
+      OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, MAXNAMELEN },
+
+    { "+ua", o_special, (void *)setupapfile,
+      "Get PAP user and password from file",
+      OPT_PRIO | OPT_A2STRVAL, &uafname },
+
+    { "user", o_string, user,
+      "Set name for auth with peer", OPT_PRIO | OPT_STATIC, NULL, MAXNAMELEN },
+
+    { "password", o_string, passwd,
+      "Password for authenticating us to the peer",
+      OPT_PRIO | OPT_STATIC | OPT_HIDE, NULL, MAXSECRETLEN },
+
+    { "usehostname", o_bool, &usehostname,
+      "Must use hostname for authentication", 1 },
+
+    { "remotename", o_string, remote_name,
+      "Set remote name for authentication", OPT_PRIO | OPT_STATIC,
+      &explicit_remote, MAXNAMELEN },
+
+    { "login", o_bool, &uselogin,
+      "Use system password database for PAP", 1 },
+
+    { "papcrypt", o_bool, &cryptpap,
+      "PAP passwords are encrypted", 1 },
+
+    { "privgroup", o_special, (void *)privgroup,
+      "Allow group members to use privileged options", OPT_PRIV | OPT_A2LIST },
+
+    { "allow-ip", o_special, (void *)set_noauth_addr,
+      "Set IP address(es) which can be used without authentication",
+      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("+ua file name");
+    seteuid(getuid());
+    ufile = fopen(fname, "r");
+    seteuid(0);
+    if (ufile == NULL) {
+	option_error("unable to open user login data file %s", 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("unable to read user login data file %s", fname);
+	return 0;
+    }
+    fclose(ufile);
+
+    /* get rid of newlines */
+    l = strlen(u);
+    if (l > 0 && u[l-1] == '\n')
+	u[l-1] = 0;
+    l = strlen(p);
+    if (l > 0 && p[l-1] == '\n')
+	p[l-1] = 0;
+
+    if (override_value("user", option_priority, fname))
+	strlcpy(user, u, sizeof(user));
+    if (override_value("passwd", 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("group %s is unknown", *argv);
+	return 0;
+    }
+    for (i = 0; i < ngroups; ++i) {
+	if (groups[i] == g->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 `"" * "" 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("allow-ip argument");
+    wp->word = (char *) (wp + 1);
+    wp->next = noauth_addrs;
+    BCOPY(addr, wp->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("Connection terminated.");
+}
+
+/*
+ * 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 && 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->enabled_flag)
+	    continue;
+        if (protp->protocol != PPP_LCP && protp->lowerdown != NULL)
+	    (*protp->lowerdown)(unit);
+        if (protp->protocol < 0xC000 && protp->close != NULL)
+	    (*protp->close)(unit, "LCP down");
+    }
+    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 = &lcp_wantoptions[unit];
+    lcp_options *go = &lcp_gotoptions[unit];
+    lcp_options *ho = &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->protocol != PPP_LCP && protp->enabled_flag
+	    && protp->lowerup != NULL)
+	    (*protp->lowerup)(unit);
+
+    if (auth_required && !(go->neg_chap || go->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 "" and a password of "".  If that's not OK,
+	 * boot it out.
+	 */
+	if (noauth_addrs != NULL) {
+	    set_allowed_addrs(unit, NULL, NULL);
+	} else if (!wo->neg_upap || uselogin || !null_login(unit)) {
+	    warn("peer refused to authenticate: terminating link");
+	    lcp_close(unit, "peer refused to authenticate");
+	    status = EXIT_PEER_AUTH_FAILED;
+	    return;
+	}
+    }
+
+    new_phase(PHASE_AUTHENTICATE);
+    used_login = 0;
+    auth = 0;
+    if (go->neg_chap) {
+	ChapAuthPeer(unit, our_name, go->chap_mdtype);
+	auth |= CHAP_PEER;
+    } else if (go->neg_upap) {
+	upap_authpeer(unit);
+	auth |= PAP_PEER;
+    }
+    if (ho->neg_chap) {
+	ChapAuthWithPeer(unit, user, ho->chap_mdtype);
+	auth |= CHAP_WITHPEER;
+    } else if (ho->neg_upap) {
+	if (passwd[0] == 0) {
+	    passwd_from_file = 1;
+	    if (!get_pap_passwd(passwd))
+		error("No secret found for PAP login");
+	}
+	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 = &lcp_gotoptions[unit];
+
+    /*
+     * If the peer had to authenticate, run the auth-up script now.
+     */
+    if (go->neg_chap || go->neg_upap) {
+	auth_state = s_up;
+	if (auth_script_state == s_down && 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->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 && !nodetach)
+		detach();
+	    return;
+	}
+    }
+#endif /* HAVE_MULTILINK */
+
+#ifdef PPP_FILTER
+    if (!demand)
+	set_filters(&pass_filter, &active_filter);
+#endif
+    for (i = 0; (protp = protocols[i]) != NULL; ++i)
+        if (protp->protocol < 0xC000 && protp->enabled_flag
+	    && protp->open != NULL) {
+	    (*protp->open)(0);
+	    if (protp->protocol != PPP_CCP)
+		++num_np_open;
+	}
+
+    if (num_np_open == 0)
+	/* nothing to do */
+	lcp_close(0, "No network protocols running");
+}
+
+/*
+ * 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, "Authentication failed");
+    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("auth_peer_success: unknown protocol %x", protocol);
+	return;
+    }
+
+    /*
+     * Save the authenticated name of the peer for later.
+     */
+    if (namelen > sizeof(peer_authname) - 1)
+	namelen = sizeof(peer_authname) - 1;
+    BCOPY(name, peer_authname, namelen);
+    peer_authname[namelen] = 0;
+    script_setenv("PEERNAME", peer_authname, 0);
+
+    /*
+     * If there is no more authentication still to be done,
+     * proceed to the network (or callback) phase.
+     */
+    if ((auth_pending[unit] &= ~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, "Failed to authenticate ourselves to peer");
+    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("auth_withpeer_success: unknown protocol %x", protocol);
+	bit = 0;
+    }
+
+    /*
+     * If there is no more authentication still being done,
+     * proceed to the network (or callback) phase.
+     */
+    if ((auth_pending[unit] &= ~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 > 0)
+	    TIMEOUT(check_idle, NULL, tlim);
+
+	/*
+	 * Set a timeout to close the connection once the maximum
+	 * connect time has expired.
+	 */
+	if (maxconnect > 0)
+	    TIMEOUT(connect_time_expired, 0, maxconnect);
+
+	/*
+	 * Detach now, if the updetach option was given.
+	 */
+	if (updetach && !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 <= 0) {
+	/* no further use for the link: shut up shop. */
+	lcp_close(0, "No network protocols running");
+    }
+}
+
+/*
+ * 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, &idle))
+	return;
+    if (idle_time_hook != 0) {
+	tlim = idle_time_hook(&idle);
+    } else {
+	itime = MIN(idle.xmit_idle, idle.recv_idle);
+	tlim = idle_time_limit - itime;
+    }
+    if (tlim <= 0) {
+	/* link is idle: shut it down. */
+	notice("Terminating connection due to lack of activity.");
+	lcp_close(0, "Link inactive");
+	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("Connect time expired");
+    lcp_close(0, "Connect time expired");	/* Close connection */
+    status = EXIT_CONNECT_TIME;
+}
+
+/*
+ * auth_check_options - called to check authentication options.
+ */
+void
+auth_check_options()
+{
+    lcp_options *wo = &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 && !allow_any_ip && have_route_to(0) && !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->neg_chap && !wo->neg_upap) {
+	    wo->neg_chap = 1;
+	    wo->neg_upap = 1;
+	}
+    } else {
+	wo->neg_chap = 0;
+	wo->neg_upap = 0;
+    }
+
+    /*
+     * Check whether we have appropriate secrets to use
+     * to authenticate the peer.
+     */
+    lacks_ip = 0;
+    can_auth = wo->neg_upap && (uselogin || have_pap_secret(&lacks_ip));
+    if (!can_auth && wo->neg_chap) {
+	can_auth = have_chap_secret((explicit_remote? remote_name: NULL),
+				    our_name, 1, &lacks_ip);
+    }
+
+    if (auth_required && !can_auth && noauth_addrs == NULL) {
+	if (default_auth) {
+	    option_error(
+"By default the remote system is required to authenticate itself");
+	    option_error(
+"(because this system has a default route to the internet)");
+	} else if (explicit_remote)
+	    option_error(
+"The remote system (%s) is required to authenticate itself",
+			 remote_name);
+	else
+	    option_error(
+"The remote system is required to authenticate itself");
+	option_error(
+"but I couldn't find any suitable secret (password) for it to use to do so.");
+	if (lacks_ip)
+	    option_error(
+"(None of the available passwords would let it use an IP address.)");
+
+	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 = &lcp_gotoptions[unit];
+    lcp_options *ao = &lcp_allowoptions[0];
+
+    ao->neg_upap = !refuse_pap && (passwd[0] != 0 || get_pap_passwd(NULL));
+    ao->neg_chap = !refuse_chap
+	&& (passwd[0] != 0
+	    || have_chap_secret(user, (explicit_remote? remote_name: NULL),
+				0, NULL));
+
+    if (go->neg_upap && !uselogin && !have_pap_secret(NULL))
+	go->neg_upap = 0;
+    if (go->neg_chap) {
+	if (!have_chap_secret((explicit_remote? remote_name: NULL),
+			      our_name, 1, NULL))
+	    go->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), "%.*v", passwdlen, apasswd);
+    slprintf(user, sizeof(user), "%.*v", userlen, auser);
+    *msg = "";
+
+    /*
+     * Check if a plugin wants to handle this.
+     */
+    if (pap_auth_hook) {
+	ret = (*pap_auth_hook)(user, passwd, msg, &addrs, &opts);
+	if (ret >= 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, "r");
+    if (f == NULL) {
+	error("Can't open PAP password file %s: %m", filename);
+
+    } else {
+	check_access(f, filename);
+	if (scan_authfile(f, user, our_name, secret, &addrs, &opts, filename) < 0) {
+	    warn("no PAP secret found for %s", user);
+	} else {
+	    /*
+	     * If the secret is "@login", it means to check
+	     * the password against the login database.
+	     */
+	    int login_secret = strcmp(secret, "@login") == 0;
+	    ret = UPAP_AUTHACK;
+	    if (uselogin || login_secret) {
+		/* login option or secret is @login */
+		ret = plogin(user, passwd, msg);
+		if (ret == UPAP_AUTHNAK)
+		    warn("PAP login failure for %s", user);
+		else
+		    used_login = 1;
+	    }
+	    if (secret[0] != 0 && !login_secret) {
+		/* password given in pap-secrets - must match */
+		if ((cryptpap || strcmp(passwd, secret) != 0)
+		    && strcmp(crypt(passwd, secret), secret) != 0) {
+		    ret = UPAP_AUTHNAK;
+		    warn("PAP authentication failure for %s", user);
+		}
+	    }
+	}
+	fclose(f);
+    }
+
+    if (ret == UPAP_AUTHNAK) {
+        if (**msg == 0)
+	    *msg = "Login incorrect";
+	/*
+	 * 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++ >= 10) {
+	    warn("%d LOGIN FAILURES ON %s, %s", attempts, devnam, user);
+	    lcp_close(unit, "login failed");
+	}
+	if (attempts > 3)
+	    sleep((u_int) (attempts - 3) * 5);
+	if (opts != NULL)
+	    free_wordlist(opts);
+
+    } else {
+	attempts = 0;			/* Reset count */
+	if (**msg == 0)
+	    *msg = "Login ok";
+	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 < num_msg; replies++) {
+        switch (msg[replies]->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 = {
+    &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 ("ppp", user, &PAM_conversation, &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 && !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->sp_expire > 0 && now >= spwd->sp_expire)
+	    || ((spwd->sp_max >= 0 && spwd->sp_max < 10000)
+		&& spwd->sp_lstchg >= 0
+		&& now >= spwd->sp_lstchg + spwd->sp_max)) {
+	    warn("Password for %s has expired", user);
+	    return (UPAP_AUTHNAK);
+	}
+	pw->pw_passwd = spwd->sp_pwdp;
+    }
+#endif
+
+    /*
+     * If no passwd, don't let them login.
+     */
+    if (pw->pw_passwd == NULL || strlen(pw->pw_passwd) < 2
+	|| strcmp(crypt(passwd, pw->pw_passwd), pw->pw_passwd) != 0)
+	return (UPAP_AUTHNAK);
+
+#endif /* #ifdef USE_PAM */
+
+    /*
+     * Write a wtmp entry for this user.
+     */
+
+    tty = devnam;
+    if (strncmp(tty, "/dev/", 5) == 0)
+	tty += 5;
+//    logwtmp(tty, user, remote_name);		/* Add wtmp login entry */
+
+#if defined(_PATH_LASTLOG) && !defined(USE_PAM)
+    if (pw != (struct passwd *)NULL) {
+	    struct lastlog ll;
+	    int fd;
+
+	    if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
+		(void)lseek(fd, (off_t)(pw->pw_uid * sizeof(ll)), SEEK_SET);
+		memset((void *)&ll, 0, sizeof(ll));
+		(void)time(&ll.ll_time);
+		(void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
+		(void)write(fd, (char *)&ll, sizeof(ll));
+		(void)close(fd);
+	    }
+    }
+#endif /* _PATH_LASTLOG and not USE_PAM */
+
+    info("user %s logged in", 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, "/dev/", 5) == 0)
+	tty += 5;
+//    logwtmp(tty, "", "");		/* Wipe out utmp logout entry */
+#endif /* ! USE_PAM */
+    logged_in = 0;
+}
+
+
+/*
+ * null_login - Check if a username of "" and a password of "" 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, "r");
+    if (f == NULL)
+	return 0;
+    check_access(f, filename);
+
+    i = scan_authfile(f, "", our_name, secret, &addrs, &opts, filename);
+    ret = i >= 0 && 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 >= 0)
+	    return ret;
+    }
+
+    filename = _PATH_UPAPFILE;
+    f = fopen(filename, "r");
+    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 < 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 >= 0)
+	    return ret;
+    }
+
+    filename = _PATH_UPAPFILE;
+    f = fopen(filename, "r");
+    if (f == NULL)
+	return 0;
+
+    ret = scan_authfile(f, (explicit_remote? remote_name: NULL), our_name,
+			NULL, &addrs, NULL, filename);
+    fclose(f);
+    if (ret >= 0 && !some_ip_ok(addrs)) {
+	if (lacks_ipp != 0)
+	    *lacks_ipp = 1;
+	ret = -1;
+    }
+    if (addrs != 0)
+	free_wordlist(addrs);
+
+    return ret >= 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, "r");
+    if (f == NULL)
+	return 0;
+
+    if (client != NULL && client[0] == 0)
+	client = NULL;
+    else if (server != NULL && server[0] == 0)
+	server = NULL;
+
+    ret = scan_authfile(f, client, server, NULL, &addrs, NULL, filename);
+    fclose(f);
+    if (ret >= 0 && need_ip && !some_ip_ok(addrs)) {
+	if (lacks_ipp != 0)
+	    *lacks_ipp = 1;
+	ret = -1;
+    }
+    if (addrs != 0)
+	free_wordlist(addrs);
+
+    return ret >= 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 && passwd[0] != 0) {
+	strlcpy(secbuf, passwd, sizeof(secbuf));
+    } else {
+	filename = _PATH_CHAPFILE;
+	addrs = NULL;
+	secbuf[0] = 0;
+
+	f = fopen(filename, "r");
+	if (f == NULL) {
+	    error("Can't open chap secret file %s: %m", filename);
+	    return 0;
+	}
+	check_access(f, filename);
+
+	ret = scan_authfile(f, client, server, secbuf, &addrs, &opts, filename);
+	fclose(f);
+	if (ret < 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 > MAXSECRETLEN) {
+	error("Secret for %s on %s is too long", 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 = &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 = &addrs; *plink != NULL; plink = &(*plink)->next)
+	;
+    *plink = noauth_addrs;
+
+    n = 0;
+    for (ap = addrs; ap != NULL; ap = ap->next) {
+	/* "-" means no addresses authorized, "*" means any address allowed */
+	ptr_word = ap->word;
+	if (strcmp(ptr_word, "-") == 0)
+	    break;
+	if (strcmp(ptr_word, "*") == 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, &endp, 10);
+	    if (bit_count <= 0 || bit_count > 32) {
+		warn("invalid address length %v in auth. address list",
+		     ptr_mask+1);
+		continue;
+	    }
+	    bit_count = 32 - bit_count;	/* # bits in host part */
+	    if (*endp == '+') {
+		offset = ifunit + 1;
+		++endp;
+	    }
+	    if (*endp != 0) {
+		warn("invalid address length syntax: %v", ptr_mask+1);
+		continue;
+	    }
+	    *ptr_mask = '\0';
+	    mask <<= bit_count;
+	}
+
+	hp = gethostbyname(ptr_word);
+	if (hp != NULL && hp->h_addrtype == AF_INET) {
+	    a = *(u_int32_t *)hp->h_addr;
+	} else {
+		printf("*** getnetbyname is unsupported, please report bug! ***\n");
+		return;
+	}
+
+	if (ptr_mask != NULL)
+	    *ptr_mask = '/';
+
+	if (a == (u_int32_t)-1L) {
+	    warn("unknown host %s in auth. address list", ap->word);
+	    continue;
+	}
+	if (offset != 0) {
+	    if (offset >= ~mask) {
+		warn("interface unit %d too large for subnet %v",
+		     ifunit, ptr_word);
+		continue;
+	    }
+	    a = htonl((ntohl(a) & mask) + offset);
+	    mask = ~(u_int32_t)0;
+	}
+	ip[n].mask = htonl(mask);
+	ip[n].base = a & ip[n].mask;
+	++n;
+	if (~mask == 0 && 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
+	&& (wo->hisaddr == 0 || !auth_ip_addr(unit, wo->hisaddr))) {
+	wo->hisaddr = suggested_ip;
+	/*
+	 * Do we insist on this address?  No, if there are other
+	 * addresses authorized than the suggested one.
+	 */
+	if (n > 1)
+	    wo->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 >= 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 & addrs->mask) == addrs->base)
+	    return addrs->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 >> 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->next) {
+	if (addrs->word[0] == '-')
+	    break;
+	if (addrs->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), &sbuf) < 0) {
+	warn("cannot stat secret file %s: %m", filename);
+    } else if ((sbuf.st_mode & (S_IRWXG | S_IRWXO)) != 0) {
+	warn("Warning - secret file %s has world and/or group access",
+	     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 >= 0.  The return value has
+ * NONWILD_CLIENT set if the secret didn't have "*" for the client, and
+ * NONWILD_SERVER set if the secret didn't have "*" for the server.
+ * Any following words on the line up to a "--" (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, &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 && getword(f, word, &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 && strcmp(word, client) != 0 && !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, &newline, filename))
+	    break;
+	if (newline)
+	    continue;
+	if (!ISWILD(word)) {
+	    if (server != NULL && 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 <= best_flag)
+	    continue;
+
+	/*
+	 * Get the secret.
+	 */
+	if (!getword(f, word, &newline, filename))
+	    break;
+	if (newline)
+	    continue;
+
+	if (secret != NULL) {
+	    /*
+	     * Special syntax: @/pathname means read secret from file.
+	     */
+	    if (word[0] == '@' && word[1] == '/') {
+		strlcpy(atfile, word+1, sizeof(atfile));
+		if ((sf = fopen(atfile, "r")) == NULL) {
+		    warn("can't open indirect secret file %s", atfile);
+		    continue;
+		}
+		check_access(sf, atfile);
+		if (!getword(sf, word, &xxx, atfile)) {
+		    warn("no secret in indirect secret file %s", atfile);
+		    fclose(sf);
+		    continue;
+		}
+		fclose(sf);
+	    }
+	    strlcpy(lsecret, word, sizeof(lsecret));
+	}
+
+	/*
+	 * Now read address authorization info and make a wordlist.
+	 */
+	app = &alist;
+	for (;;) {
+	    if (!getword(f, word, &newline, filename) || newline)
+		break;
+	    ap = (struct wordlist *)
+		    malloc(sizeof(struct wordlist) + strlen(word) + 1);
+	    if (ap == NULL)
+		novm("authorized addresses");
+	    ap->word = (char *) (ap + 1);
+	    strcpy(ap->word, word);
+	    *app = ap;
+	    app = &ap->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 = &addr_list; (ap = *app) != NULL; app = &ap->next)
+	if (strcmp(ap->word, "--") == 0)
+	    break;
+    /* ap = start of options */
+    if (ap != NULL) {
+	ap = ap->next;		/* first option */
+	free(*app);			/* free the "--" 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->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->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 && pw->pw_name != NULL)
+	user_name = pw->pw_name;
+    else {
+	slprintf(struid, sizeof(struid), "%d", getuid());
+	user_name = struid;
+    }
+    slprintf(strspeed, sizeof(strspeed), "%d", 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	"$Id: cbcp.c 195720 2001-06-11 11:44:34Z gc $"
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include "pppd.h"
+#include "cbcp.h"
+#include "fsm.h"
+#include "lcp.h"
+
+static const char rcsid[] = RCSID;
+
+/*
+ * Options.
+ */
+static int setcbcp __P((char **));
+
+static option_t cbcp_option_list[] = {
+    { "callback", o_special, setcbcp,
+      "Ask for callback", OPT_PRIO | OPT_A2STRVAL, &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,
+    "CBCP",
+    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("callback number");
+    cbcp[0].us_type |= (1 << CB_CONF_USER);
+    cbcp[0].us_type |= (1 << CB_CONF_ADMIN);
+    return (1);
+}
+
+/* init state */
+static void
+cbcp_init(iface)
+    int iface;
+{
+    cbcp_state *us;
+
+    us = &cbcp[iface];
+    memset(us, 0, sizeof(cbcp_state));
+    us->us_unit = iface;
+    us->us_type |= (1 << CB_CONF_NO);
+}
+
+/* lower layer is up */
+static void
+cbcp_lowerup(iface)
+    int iface;
+{
+    cbcp_state *us = &cbcp[iface];
+
+    dbglog("cbcp_lowerup");
+    dbglog("want: %d", us->us_type);
+
+    if (us->us_type == CB_CONF_USER)
+        dbglog("phone no: %s", us->us_number);
+}
+
+static void
+cbcp_open(unit)
+    int unit;
+{
+    dbglog("cbcp_open");
+}
+
+/* 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 = &cbcp[unit];
+
+    inp = inpacket;
+
+    if (pktlen < CBCP_MINLEN) {
+        error("CBCP packet is too small");
+	return;
+    }
+
+    GETCHAR(code, inp);
+    GETCHAR(id, inp);
+    GETSHORT(len, inp);
+
+#if 0
+    if (len > pktlen) {
+        error("CBCP packet: invalid length");
+        return;
+    }
+#endif
+
+    len -= CBCP_MINLEN;
+ 
+    switch(code) {
+    case CBCP_REQ:
+        us->us_id = id;
+	cbcp_recvreq(us, inp, len);
+	break;
+
+    case CBCP_RESP:
+	dbglog("CBCP_RESP received");
+	break;
+
+    case CBCP_ACK:
+	if (id != us->us_id)
+	    dbglog("id doesn't match: expected %d recv %d",
+		   us->us_id, id);
+
+	cbcp_recvack(us, inp, len);
+	break;
+
+    default:
+	break;
+    }
+}
+
+/* protocol was rejected by foe */
+void cbcp_protrej(int iface)
+{
+}
+
+char *cbcp_codenames[] = {
+    "Request", "Response", "Ack"
+};
+
+char *cbcp_optionnames[] = {
+    "NoCallback",
+    "UserDefined",
+    "AdminDefined",
+    "List"
+};
+
+/* 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 < HEADERLEN)
+	return 0;
+    pstart = p;
+    GETCHAR(code, p);
+    GETCHAR(id, p);
+    GETSHORT(len, p);
+    if (len < HEADERLEN || len > plen)
+	return 0;
+
+    if (code >= 1 && code <= sizeof(cbcp_codenames) / sizeof(char *))
+	printer(arg, " %s", cbcp_codenames[code-1]);
+    else
+	printer(arg, " code=0x%x", code); 
+
+    printer(arg, " id=0x%x", id);
+    len -= HEADERLEN;
+
+    switch (code) {
+    case CBCP_REQ:
+    case CBCP_RESP:
+    case CBCP_ACK:
+        while(len >= 2) {
+	    GETCHAR(opt, p);
+	    GETCHAR(olen, p);
+
+	    if (olen < 2 || olen > len) {
+	        break;
+	    }
+
+	    printer(arg, " <");
+	    len -= olen;
+
+	    if (opt >= 1 && opt <= sizeof(cbcp_optionnames) / sizeof(char *))
+	    	printer(arg, " %s", cbcp_optionnames[opt-1]);
+	    else
+	        printer(arg, " option=0x%x", opt); 
+
+	    if (olen > 2) {
+	        GETCHAR(delay, p);
+		printer(arg, " delay = %d", delay);
+	    }
+
+	    if (olen > 3) {
+	        int addrt;
+		char str[256];
+
+		GETCHAR(addrt, p);
+		memcpy(str, p, olen - 4);
+		str[olen - 4] = 0;
+		printer(arg, " number = %s", str);
+	    }
+	    printer(arg, ">");
+	    break;
+	}
+
+    default:
+	break;
+    }
+
+    for (; len > 0; --len) {
+	GETCHAR(code, p);
+	printer(arg, " %.2x", 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("length: %d", len);
+
+	GETCHAR(type, pckt);
+	GETCHAR(opt_len, pckt);
+
+	if (opt_len > 2)
+	    GETCHAR(delay, pckt);
+
+	us->us_allowed |= (1 << type);
+
+	switch(type) {
+	case CB_CONF_NO:
+	    dbglog("no callback allowed");
+	    break;
+
+	case CB_CONF_USER:
+	    dbglog("user callback allowed");
+	    if (opt_len > 4) {
+	        GETCHAR(addr_type, pckt);
+		memcpy(address, pckt, opt_len - 4);
+		address[opt_len - 4] = 0;
+		if (address[0])
+		    dbglog("address: %s", address);
+	    }
+	    break;
+
+	case CB_CONF_ADMIN:
+	    dbglog("user admin defined allowed");
+	    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->us_allowed & us->us_type;
+    dbglog("cbcp_resp cb_type=%d", cb_type);
+
+#if 0
+    if (!cb_type)
+        lcp_down(us->us_unit);
+#endif
+
+    if (cb_type & ( 1 << CB_CONF_USER ) ) {
+	dbglog("cbcp_resp CONF_USER");
+	PUTCHAR(CB_CONF_USER, bufp);
+	len = 3 + 1 + strlen(us->us_number) + 1;
+	PUTCHAR(len , bufp);
+	PUTCHAR(5, bufp); /* delay */
+	PUTCHAR(1, bufp);
+	BCOPY(us->us_number, bufp, strlen(us->us_number) + 1);
+	cbcp_send(us, CBCP_RESP, buf, len);
+	return;
+    }
+
+    if (cb_type & ( 1 << CB_CONF_ADMIN ) ) {
+	dbglog("cbcp_resp CONF_ADMIN");
+        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 & ( 1 << CB_CONF_NO ) ) {
+        dbglog("cbcp_resp CONF_NO");
+	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->us_id, outp);
+    PUTSHORT(outlen, outp);
+    
+    if (len)
+        BCOPY(buf, outp, len);
+
+    output(us->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 > 2)
+	    GETCHAR(delay, pckt);
+
+	if (opt_len > 4) {
+	    GETCHAR(addr_type, pckt);
+	    memcpy(address, pckt, opt_len - 4);
+	    address[opt_len - 4] = 0;
+	    if (address[0])
+	        dbglog("peer will call: %s", 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, "Call me back, please");
+    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 "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ */
+
+#define RCSID	"$Id: ccp.c 195720 2001-06-11 11:44:34Z gc $"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "pppd.h"
+#include "fsm.h"
+#include "ccp.h"
+#include <net/ppp-comp.h>
+
+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[] = {
+    { "noccp", o_bool, &ccp_protent.enabled_flag,
+      "Disable CCP negotiation" },
+    { "-ccp", o_bool, &ccp_protent.enabled_flag,
+      "Disable CCP negotiation", OPT_ALIAS },
+
+    { "bsdcomp", o_special, (void *)setbsdcomp,
+      "Request BSD-Compress packet compression",
+      OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, bsd_value },
+    { "nobsdcomp", o_bool, &ccp_wantoptions[0].bsd_compress,
+      "don't allow BSD-Compress", OPT_PRIOSUB | OPT_A2CLR,
+      &ccp_allowoptions[0].bsd_compress },
+    { "-bsdcomp", o_bool, &ccp_wantoptions[0].bsd_compress,
+      "don't allow BSD-Compress", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR,
+      &ccp_allowoptions[0].bsd_compress },
+
+    { "deflate", o_special, (void *)setdeflate,
+      "request Deflate compression",
+      OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, deflate_value },
+    { "nodeflate", o_bool, &ccp_wantoptions[0].deflate,
+      "don't allow Deflate compression", OPT_PRIOSUB | OPT_A2CLR,
+      &ccp_allowoptions[0].deflate },
+    { "-deflate", o_bool, &ccp_wantoptions[0].deflate,
+      "don't allow Deflate compression", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR,
+      &ccp_allowoptions[0].deflate },
+
+    { "nodeflatedraft", o_bool, &ccp_wantoptions[0].deflate_draft,
+      "don't use draft deflate #", OPT_A2COPY,
+      &ccp_allowoptions[0].deflate_draft },
+
+    { "predictor1", o_bool, &ccp_wantoptions[0].predictor_1,
+      "request Predictor-1", 1, &ccp_allowoptions[0].predictor_1, OPT_PRIO },
+    { "nopredictor1", o_bool, &ccp_wantoptions[0].predictor_1,
+      "don't allow Predictor-1", OPT_PRIOSUB | OPT_A2CLR,
+      &ccp_allowoptions[0].predictor_1 },
+    { "-predictor1", o_bool, &ccp_wantoptions[0].predictor_1,
+      "don't allow Predictor-1", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR,
+      &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,
+    "CCP",
+    "Compressed",
+    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,
+    "CCP"
+};
+
+/*
+ * 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, &endp, 0);
+    if (endp != str && *endp == ',') {
+	str = endp + 1;
+	abits = strtol(str, &endp, 0);
+    }
+    if (*endp != 0 || endp == str) {
+	option_error("invalid parameter '%s' for bsdcomp option", *argv);
+	return 0;
+    }
+    if ((rbits != 0 && (rbits < BSD_MIN_BITS || rbits > BSD_MAX_BITS))
+	|| (abits != 0 && (abits < BSD_MIN_BITS || abits > BSD_MAX_BITS))) {
+	option_error("bsdcomp option values must be 0 or %d .. %d",
+		     BSD_MIN_BITS, BSD_MAX_BITS);
+	return 0;
+    }
+    if (rbits > 0) {
+	ccp_wantoptions[0].bsd_compress = 1;
+	ccp_wantoptions[0].bsd_bits = rbits;
+    } else
+	ccp_wantoptions[0].bsd_compress = 0;
+    if (abits > 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? "%d": "%d,%d", rbits, abits);
+
+    return 1;
+}
+
+static int
+setdeflate(argv)
+    char **argv;
+{
+    int rbits, abits;
+    char *str, *endp;
+
+    str = *argv;
+    abits = rbits = strtol(str, &endp, 0);
+    if (endp != str && *endp == ',') {
+	str = endp + 1;
+	abits = strtol(str, &endp, 0);
+    }
+    if (*endp != 0 || endp == str) {
+	option_error("invalid parameter '%s' for deflate option", *argv);
+	return 0;
+    }
+    if ((rbits != 0 && (rbits < DEFLATE_MIN_SIZE || rbits > DEFLATE_MAX_SIZE))
+	|| (abits != 0 && (abits < DEFLATE_MIN_SIZE
+			  || abits > DEFLATE_MAX_SIZE))) {
+	option_error("deflate option values must be 0 or %d .. %d",
+		     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("deflate option value of %d changed to %d to avoid zlib bug",
+	     DEFLATE_MIN_SIZE, DEFLATE_MIN_WORKS);
+    }
+    if (rbits > 0) {
+	ccp_wantoptions[0].deflate = 1;
+	ccp_wantoptions[0].deflate_size = rbits;
+    } else
+	ccp_wantoptions[0].deflate = 0;
+    if (abits > 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? "%d": "%d,%d", rbits, abits);
+
+    return 1;
+}
+
+/*
+ * ccp_init - initialize CCP.
+ */
+static void
+ccp_init(unit)
+    int unit;
+{
+    fsm *f = &ccp_fsm[unit];
+
+    f->unit = unit;
+    f->protocol = PPP_CCP;
+    f->callbacks = &ccp_callbacks;
+    fsm_init(f);
+
+    memset(&ccp_wantoptions[unit],  0, sizeof(ccp_options));
+    memset(&ccp_gotoptions[unit],   0, sizeof(ccp_options));
+    memset(&ccp_allowoptions[unit], 0, sizeof(ccp_options));
+    memset(&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 = &ccp_fsm[unit];
+
+    if (f->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->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(&ccp_fsm[unit], reason);
+}
+
+/*
+ * ccp_lowerup - we may now transmit CCP packets.
+ */
+static void
+ccp_lowerup(unit)
+    int unit;
+{
+    fsm_lowerup(&ccp_fsm[unit]);
+}
+
+/*
+ * ccp_lowerdown - we may not transmit CCP packets.
+ */
+static void
+ccp_lowerdown(unit)
+    int unit;
+{
+    fsm_lowerdown(&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 = &ccp_fsm[unit];
+    int oldstate;
+
+    /*
+     * Check for a terminate-request so we can print a message.
+     */
+    oldstate = f->state;
+    fsm_input(f, p, len);
+    if (oldstate == OPENED && p[0] == TERMREQ && f->state != OPENED)
+	notice("Compression disabled by peer.");
+
+    /*
+     * If we get a terminate-ack and we're not asking for compression,
+     * close CCP.
+     */
+    if (oldstate == REQSENT && p[0] == TERMACK
+	&& !ANY_COMPRESS(ccp_gotoptions[unit]))
+	ccp_close(unit, "No compression negotiated");
+}
+
+/*
+ * 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->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->unit] & RACK_PENDING && id == f->reqid) {
+	    ccp_localstate[f->unit] &= ~(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(&ccp_fsm[unit]);
+}
+
+/*
+ * ccp_resetci - initialize at start of negotiation.
+ */
+static void
+ccp_resetci(f)
+    fsm *f;
+{
+    ccp_options *go = &ccp_gotoptions[f->unit];
+    u_char opt_buf[16];
+
+    *go = ccp_wantoptions[f->unit];
+    all_rejected[f->unit] = 0;
+
+    /*
+     * Check whether the kernel knows about the various
+     * compression methods we might request.
+     */
+    if (go->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->unit, opt_buf, CILEN_BSD_COMPRESS, 0) <= 0)
+	    go->bsd_compress = 0;
+    }
+    if (go->deflate) {
+	if (go->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->unit, opt_buf, CILEN_DEFLATE, 0) <= 0)
+		go->deflate_correct = 0;
+	}
+	if (go->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->unit, opt_buf, CILEN_DEFLATE, 0) <= 0)
+		go->deflate_draft = 0;
+	}
+	if (!go->deflate_correct && !go->deflate_draft)
+	    go->deflate = 0;
+    }
+    if (go->predictor_1) {
+	opt_buf[0] = CI_PREDICTOR_1;
+	opt_buf[1] = CILEN_PREDICTOR_1;
+	if (ccp_test(f->unit, opt_buf, CILEN_PREDICTOR_1, 0) <= 0)
+	    go->predictor_1 = 0;
+    }
+    if (go->predictor_2) {
+	opt_buf[0] = CI_PREDICTOR_2;
+	opt_buf[1] = CILEN_PREDICTOR_2;
+	if (ccp_test(f->unit, opt_buf, CILEN_PREDICTOR_2, 0) <= 0)
+	    go->predictor_2 = 0;
+    }
+}
+
+/*
+ * ccp_cilen - Return total length of our configuration info.
+ */
+static int
+ccp_cilen(f)
+    fsm *f;
+{
+    ccp_options *go = &ccp_gotoptions[f->unit];
+
+    return (go->bsd_compress? CILEN_BSD_COMPRESS: 0)
+	+ (go->deflate? CILEN_DEFLATE: 0)
+	+ (go->predictor_1? CILEN_PREDICTOR_1: 0)
+	+ (go->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 = &ccp_gotoptions[f->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->deflate) {
+	p[0] = go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT;
+	p[1] = CILEN_DEFLATE;
+	p[2] = DEFLATE_MAKE_OPT(go->deflate_size);
+	p[3] = DEFLATE_CHK_SEQUENCE;
+	for (;;) {
+	    res = ccp_test(f->unit, p, CILEN_DEFLATE, 0);
+	    if (res > 0) {
+		p += CILEN_DEFLATE;
+		break;
+	    }
+	    if (res < 0 || go->deflate_size <= DEFLATE_MIN_WORKS) {
+		go->deflate = 0;
+		break;
+	    }
+	    --go->deflate_size;
+	    p[2] = DEFLATE_MAKE_OPT(go->deflate_size);
+	}
+	if (p != p0 && go->deflate_correct && go->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->bsd_compress) {
+	p[0] = CI_BSD_COMPRESS;
+	p[1] = CILEN_BSD_COMPRESS;
+	p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits);
+	if (p != p0) {
+	    p += CILEN_BSD_COMPRESS;	/* not the first option */
+	} else {
+	    for (;;) {
+		res = ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 0);
+		if (res > 0) {
+		    p += CILEN_BSD_COMPRESS;
+		    break;
+		}
+		if (res < 0 || go->bsd_bits <= BSD_MIN_BITS) {
+		    go->bsd_compress = 0;
+		    break;
+		}
+		--go->bsd_bits;
+		p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits);
+	    }
+	}
+    }
+    /* XXX Should Predictor 2 be preferable to Predictor 1? */
+    if (go->predictor_1) {
+	p[0] = CI_PREDICTOR_1;
+	p[1] = CILEN_PREDICTOR_1;
+	if (p == p0 && ccp_test(f->unit, p, CILEN_PREDICTOR_1, 0) <= 0) {
+	    go->predictor_1 = 0;
+	} else {
+	    p += CILEN_PREDICTOR_1;
+	}
+    }
+    if (go->predictor_2) {
+	p[0] = CI_PREDICTOR_2;
+	p[1] = CILEN_PREDICTOR_2;
+	if (p == p0 && ccp_test(f->unit, p, CILEN_PREDICTOR_2, 0) <= 0) {
+	    go->predictor_2 = 0;
+	} else {
+	    p += CILEN_PREDICTOR_2;
+	}
+    }
+
+    go->method = (p > 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 = &ccp_gotoptions[f->unit];
+    u_char *p0 = p;
+
+    if (go->deflate) {
+	if (len < CILEN_DEFLATE
+	    || p[0] != (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT)
+	    || p[1] != CILEN_DEFLATE
+	    || p[2] != DEFLATE_MAKE_OPT(go->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->deflate_correct && go->deflate_draft) {
+	    if (len < CILEN_DEFLATE
+		|| p[0] != CI_DEFLATE_DRAFT
+		|| p[1] != CILEN_DEFLATE
+		|| p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
+		|| p[3] != DEFLATE_CHK_SEQUENCE)
+		return 0;
+	    p += CILEN_DEFLATE;
+	    len -= CILEN_DEFLATE;
+	}
+    }
+    if (go->bsd_compress) {
+	if (len < CILEN_BSD_COMPRESS
+	    || p[0] != CI_BSD_COMPRESS || p[1] != CILEN_BSD_COMPRESS
+	    || p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits))
+	    return 0;
+	p += CILEN_BSD_COMPRESS;
+	len -= CILEN_BSD_COMPRESS;
+	/* XXX Cope with first/fast ack */
+	if (p == p0 && len == 0)
+	    return 1;
+    }
+    if (go->predictor_1) {
+	if (len < 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 && len == 0)
+	    return 1;
+    }
+    if (go->predictor_2) {
+	if (len < 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 && 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 = &ccp_gotoptions[f->unit];
+    ccp_options no;		/* options we've seen already */
+    ccp_options try;		/* options to ask for next time */
+
+    memset(&no, 0, sizeof(no));
+    try = *go;
+
+    if (go->deflate && len >= CILEN_DEFLATE
+	&& p[0] == (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT)
+	&& 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]) < DEFLATE_MIN_WORKS
+	    || p[3] != DEFLATE_CHK_SEQUENCE)
+	    try.deflate = 0;
+	else if (DEFLATE_SIZE(p[2]) < go->deflate_size)
+	    try.deflate_size = DEFLATE_SIZE(p[2]);
+	p += CILEN_DEFLATE;
+	len -= CILEN_DEFLATE;
+	if (go->deflate_correct && go->deflate_draft
+	    && len >= CILEN_DEFLATE && p[0] == CI_DEFLATE_DRAFT
+	    && p[1] == CILEN_DEFLATE) {
+	    p += CILEN_DEFLATE;
+	    len -= CILEN_DEFLATE;
+	}
+    }
+
+    if (go->bsd_compress && len >= CILEN_BSD_COMPRESS
+	&& p[0] == CI_BSD_COMPRESS && 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]) < go->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->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 = &ccp_gotoptions[f->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 && all_rejected[f->unit])
+	return -1;
+
+    if (go->deflate && len >= CILEN_DEFLATE
+	&& p[0] == (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT)
+	&& p[1] == CILEN_DEFLATE) {
+	if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
+	    || p[3] != DEFLATE_CHK_SEQUENCE)
+	    return 0;		/* Rej is bad */
+	if (go->deflate_correct)
+	    try.deflate_correct = 0;
+	else
+	    try.deflate_draft = 0;
+	p += CILEN_DEFLATE;
+	len -= CILEN_DEFLATE;
+	if (go->deflate_correct && go->deflate_draft
+	    && len >= CILEN_DEFLATE && p[0] == CI_DEFLATE_DRAFT
+	    && p[1] == CILEN_DEFLATE) {
+	    if (p[2] != DEFLATE_MAKE_OPT(go->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 && !try.deflate_draft)
+	    try.deflate = 0;
+    }
+    if (go->bsd_compress && len >= CILEN_BSD_COMPRESS
+	&& p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) {
+	if (p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits))
+	    return 0;
+	try.bsd_compress = 0;
+	p += CILEN_BSD_COMPRESS;
+	len -= CILEN_BSD_COMPRESS;
+    }
+    if (go->predictor_1 && len >= CILEN_PREDICTOR_1
+	&& p[0] == CI_PREDICTOR_1 && p[1] == CILEN_PREDICTOR_1) {
+	try.predictor_1 = 0;
+	p += CILEN_PREDICTOR_1;
+	len -= CILEN_PREDICTOR_1;
+    }
+    if (go->predictor_2 && len >= CILEN_PREDICTOR_2
+	&& p[0] == CI_PREDICTOR_2 && p[1] == CILEN_PREDICTOR_2) {
+	try.predictor_2 = 0;
+	p += CILEN_PREDICTOR_2;
+	len -= CILEN_PREDICTOR_2;
+    }
+
+    if (len != 0)
+	return 0;
+
+    if (f->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 = &ccp_hisoptions[f->unit];
+    ccp_options *ao = &ccp_allowoptions[f->unit];
+
+    ret = CONFACK;
+    retp = p0 = p;
+    len = *lenp;
+
+    memset(ho, 0, sizeof(ccp_options));
+    ho->method = (len > 0)? p[0]: -1;
+
+    while (len > 0) {
+	newret = CONFACK;
+	if (len < 2 || p[1] < 2 || p[1] > 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->deflate || clen != CILEN_DEFLATE
+		    || (!ao->deflate_correct && type == CI_DEFLATE)
+		    || (!ao->deflate_draft && type == CI_DEFLATE_DRAFT)) {
+		    newret = CONFREJ;
+		    break;
+		}
+
+		ho->deflate = 1;
+		ho->deflate_size = nb = DEFLATE_SIZE(p[2]);
+		if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL
+		    || p[3] != DEFLATE_CHK_SEQUENCE
+		    || nb > ao->deflate_size || nb < DEFLATE_MIN_WORKS) {
+		    newret = CONFNAK;
+		    if (!dont_nak) {
+			p[2] = DEFLATE_MAKE_OPT(ao->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->unit, p, CILEN_DEFLATE, 1);
+			if (res > 0)
+			    break;		/* it's OK now */
+			if (res < 0 || nb == DEFLATE_MIN_WORKS || dont_nak) {
+			    newret = CONFREJ;
+			    p[2] = DEFLATE_MAKE_OPT(ho->deflate_size);
+			    break;
+			}
+			newret = CONFNAK;
+			--nb;
+			p[2] = DEFLATE_MAKE_OPT(nb);
+		    }
+		}
+		break;
+
+	    case CI_BSD_COMPRESS:
+		if (!ao->bsd_compress || clen != CILEN_BSD_COMPRESS) {
+		    newret = CONFREJ;
+		    break;
+		}
+
+		ho->bsd_compress = 1;
+		ho->bsd_bits = nb = BSD_NBITS(p[2]);
+		if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION
+		    || nb > ao->bsd_bits || nb < BSD_MIN_BITS) {
+		    newret = CONFNAK;
+		    if (!dont_nak) {
+			p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, ao->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->unit, p, CILEN_BSD_COMPRESS, 1);
+			if (res > 0)
+			    break;
+			if (res < 0 || nb == BSD_MIN_BITS || dont_nak) {
+			    newret = CONFREJ;
+			    p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION,
+						ho->bsd_bits);
+			    break;
+			}
+			newret = CONFNAK;
+			--nb;
+			p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, nb);
+		    }
+		}
+		break;
+
+	    case CI_PREDICTOR_1:
+		if (!ao->predictor_1 || clen != CILEN_PREDICTOR_1) {
+		    newret = CONFREJ;
+		    break;
+		}
+
+		ho->predictor_1 = 1;
+		if (p == p0
+		    && ccp_test(f->unit, p, CILEN_PREDICTOR_1, 1) <= 0) {
+		    newret = CONFREJ;
+		}
+		break;
+
+	    case CI_PREDICTOR_2:
+		if (!ao->predictor_2 || clen != CILEN_PREDICTOR_2) {
+		    newret = CONFREJ;
+		    break;
+		}
+
+		ho->predictor_2 = 1;
+		if (p == p0
+		    && ccp_test(f->unit, p, CILEN_PREDICTOR_2, 1) <= 0) {
+		    newret = CONFREJ;
+		}
+		break;
+
+	    default:
+		newret = CONFREJ;
+	    }
+	}
+
+	if (newret == CONFNAK && dont_nak)
+	    newret = CONFREJ;
+	if (!(newret == CONFACK || (newret == CONFNAK && ret == CONFREJ))) {
+	    /* we're returning this option */
+	    if (newret == CONFREJ && 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 && *lenp == retp - p0)
+	    all_rejected[f->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 "(none)";
+    switch (opt->method) {
+    case CI_DEFLATE:
+    case CI_DEFLATE_DRAFT:
+	if (opt2 != NULL && opt2->deflate_size != opt->deflate_size)
+	    slprintf(result, sizeof(result), "Deflate%s (%d/%d)",
+		     (opt->method == CI_DEFLATE_DRAFT? "(old#)": ""),
+		     opt->deflate_size, opt2->deflate_size);
+	else
+	    slprintf(result, sizeof(result), "Deflate%s (%d)",
+		     (opt->method == CI_DEFLATE_DRAFT? "(old#)": ""),
+		     opt->deflate_size);
+	break;
+    case CI_BSD_COMPRESS:
+	if (opt2 != NULL && opt2->bsd_bits != opt->bsd_bits)
+	    slprintf(result, sizeof(result), "BSD-Compress (%d/%d)",
+		     opt->bsd_bits, opt2->bsd_bits);
+	else
+	    slprintf(result, sizeof(result), "BSD-Compress (%d)",
+		     opt->bsd_bits);
+	break;
+    case CI_PREDICTOR_1:
+	return "Predictor 1";
+    case CI_PREDICTOR_2:
+	return "Predictor 2";
+    default:
+	slprintf(result, sizeof(result), "Method %d", opt->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 = &ccp_gotoptions[f->unit];
+    ccp_options *ho = &ccp_hisoptions[f->unit];
+    char method1[64];
+
+    ccp_flags_set(f->unit, 1, 1);
+    if (ANY_COMPRESS(*go)) {
+	if (ANY_COMPRESS(*ho)) {
+	    if (go->method == ho->method) {
+		notice("%s compression enabled", method_name(go, ho));
+	    } else {
+		strlcpy(method1, method_name(go, NULL), sizeof(method1));
+		notice("%s / %s compression enabled",
+		       method1, method_name(ho, NULL));
+	    }
+	} else
+	    notice("%s receive compression enabled", method_name(go, NULL));
+    } else if (ANY_COMPRESS(*ho))
+	notice("%s transmit compression enabled", method_name(ho, NULL));
+}
+
+/*
+ * CCP has gone down - inform the kernel driver.
+ */
+static void
+ccp_down(f)
+    fsm *f;
+{
+    if (ccp_localstate[f->unit] & RACK_PENDING)
+	UNTIMEOUT(ccp_rack_timeout, f);
+    ccp_localstate[f->unit] = 0;
+    ccp_flags_set(f->unit, 1, 0);
+}
+
+/*
+ * Print the contents of a CCP packet.
+ */
+static char *ccp_codenames[] = {
+    "ConfReq", "ConfAck", "ConfNak", "ConfRej",
+    "TermReq", "TermAck", "CodeRej",
+    NULL, NULL, NULL, NULL, NULL, NULL,
+    "ResetReq", "ResetAck",
+};
+
+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 < HEADERLEN)
+	return 0;
+    code = p[0];
+    id = p[1];
+    len = (p[2] << 8) + p[3];
+    if (len < HEADERLEN || len > plen)
+	return 0;
+
+    if (code >= 1 && code <= sizeof(ccp_codenames) / sizeof(char *)
+	&& ccp_codenames[code-1] != NULL)
+	printer(arg, " %s", ccp_codenames[code-1]);
+    else
+	printer(arg, " code=0x%x", code);
+    printer(arg, " id=0x%x", id);
+    len -= HEADERLEN;
+    p += HEADERLEN;
+
+    switch (code) {
+    case CONFREQ:
+    case CONFACK:
+    case CONFNAK:
+    case CONFREJ:
+	/* print list of possible compression methods */
+	while (len >= 2) {
+	    code = p[0];
+	    optlen = p[1];
+	    if (optlen < 2 || optlen > len)
+		break;
+	    printer(arg, " <");
+	    len -= optlen;
+	    optend = p + optlen;
+	    switch (code) {
+	    case CI_DEFLATE:
+	    case CI_DEFLATE_DRAFT:
+		if (optlen >= CILEN_DEFLATE) {
+		    printer(arg, "deflate%s %d",
+			    (code == CI_DEFLATE_DRAFT? "(old#)": ""),
+			    DEFLATE_SIZE(p[2]));
+		    if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL)
+			printer(arg, " method %d", DEFLATE_METHOD(p[2]));
+		    if (p[3] != DEFLATE_CHK_SEQUENCE)
+			printer(arg, " check %d", p[3]);
+		    p += CILEN_DEFLATE;
+		}
+		break;
+	    case CI_BSD_COMPRESS:
+		if (optlen >= CILEN_BSD_COMPRESS) {
+		    printer(arg, "bsd v%d %d", BSD_VERSION(p[2]),
+			    BSD_NBITS(p[2]));
+		    p += CILEN_BSD_COMPRESS;
+		}
+		break;
+	    case CI_PREDICTOR_1:
+		if (optlen >= CILEN_PREDICTOR_1) {
+		    printer(arg, "predictor 1");
+		    p += CILEN_PREDICTOR_1;
+		}
+		break;
+	    case CI_PREDICTOR_2:
+		if (optlen >= CILEN_PREDICTOR_2) {
+		    printer(arg, "predictor 2");
+		    p += CILEN_PREDICTOR_2;
+		}
+		break;
+	    }
+	    while (p < optend)
+		printer(arg, " %.2x", *p++);
+	    printer(arg, ">");
+	}
+	break;
+
+    case TERMACK:
+    case TERMREQ:
+	if (len > 0 && *p >= ' ' && *p < 0x7f) {
+	    print_string((char *)p, len, printer, arg);
+	    p += len;
+	    len = 0;
+	}
+	break;
+    }
+
+    /* dump out the rest of the packet in hex */
+    while (--len >= 0)
+	printer(arg, " %.2x", *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 = &ccp_fsm[unit];
+    if (f->state == OPENED) {
+	if (ccp_fatal_error(unit)) {
+	    /*
+	     * Disable compression by taking CCP down.
+	     */
+	    error("Lost compression sync: disabling compression");
+	    ccp_close(unit, "Lost compression sync");
+	} 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->unit] & RACK_PENDING)) {
+		fsm_sdata(f, CCP_RESETREQ, f->reqid = ++f->id, NULL, 0);
+		TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT);
+		ccp_localstate[f->unit] |= RACK_PENDING;
+	    } else
+		ccp_localstate[f->unit] |= RREQ_REPEAT;
+	}
+    }
+}
+
+/*
+ * Timeout waiting for reset-ack.
+ */
+static void
+ccp_rack_timeout(arg)
+    void *arg;
+{
+    fsm *f = arg;
+
+    if (f->state == OPENED && ccp_localstate[f->unit] & RREQ_REPEAT) {
+	fsm_sdata(f, CCP_RESETREQ, f->reqid, NULL, 0);
+	TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT);
+	ccp_localstate[f->unit] &= ~RREQ_REPEAT;
+    } else
+	ccp_localstate[f->unit] &= ~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 "AS IS" 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	"$Id: chap.c 195720 2001-06-11 11:44:34Z gc $"
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include "pppd.h"
+#include "chap.h"
+#include "md5.h"
+#ifdef CHAPMS
+#include "chap_ms.h"
+#endif
+
+static const char rcsid[] = RCSID;
+
+/*
+ * Command-line options.
+ */
+static option_t chap_option_list[] = {
+    { "chap-restart", o_int, &chap[0].timeouttime,
+      "Set timeout for CHAP", OPT_PRIO },
+    { "chap-max-challenge", o_int, &chap[0].max_transmits,
+      "Set max #xmits for challenge", OPT_PRIO },
+    { "chap-interval", o_int, &chap[0].chal_interval,
+      "Set interval for rechallenge", OPT_PRIO },
+#ifdef MSLANMAN
+    { "ms-lanman", o_bool, &ms_lanman,
+      "Use LanMan passwd when using MS-CHAP", 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,
+    "CHAP",
+    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 = &chap[unit];
+
+    BZERO(cstate, sizeof(*cstate));
+    cstate->unit = unit;
+    cstate->clientstate = CHAPCS_INITIAL;
+    cstate->serverstate = CHAPSS_INITIAL;
+    cstate->timeouttime = CHAP_DEFTIMEOUT;
+    cstate->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 = &chap[unit];
+
+    cstate->resp_name = our_name;
+    cstate->resp_type = digest;
+
+    if (cstate->clientstate == CHAPCS_INITIAL ||
+	cstate->clientstate == CHAPCS_PENDING) {
+	/* lower layer isn't up - wait until later */
+	cstate->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->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 = &chap[unit];
+  
+    cstate->chal_name = our_name;
+    cstate->chal_type = digest;
+
+    if (cstate->serverstate == CHAPSS_INITIAL ||
+	cstate->serverstate == CHAPSS_PENDING) {
+	/* lower layer isn't up - wait until later */
+	cstate->serverstate = CHAPSS_PENDING;
+	return;
+    }
+
+    ChapGenChallenge(cstate);
+    ChapSendChallenge(cstate);		/* crank it up dude! */
+    cstate->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->serverstate != CHAPSS_INITIAL_CHAL &&
+	cstate->serverstate != CHAPSS_RECHALLENGE)
+	return;
+
+    if (cstate->chal_transmits >= cstate->max_transmits) {
+	/* give up on peer */
+	error("Peer failed to respond to CHAP challenge");
+	cstate->serverstate = CHAPSS_BADAUTH;
+	auth_peer_fail(cstate->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->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->serverstate != CHAPSS_OPEN)
+	return;
+
+    ChapGenChallenge(cstate);
+    ChapSendChallenge(cstate);
+    cstate->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 = &chap[unit];
+  
+    if (cstate->clientstate == CHAPCS_INITIAL)
+	cstate->clientstate = CHAPCS_CLOSED;
+    else if (cstate->clientstate == CHAPCS_PENDING)
+	cstate->clientstate = CHAPCS_LISTEN;
+
+    if (cstate->serverstate == CHAPSS_INITIAL)
+	cstate->serverstate = CHAPSS_CLOSED;
+    else if (cstate->serverstate == CHAPSS_PENDING) {
+	ChapGenChallenge(cstate);
+	ChapSendChallenge(cstate);
+	cstate->serverstate = CHAPSS_INITIAL_CHAL;
+    }
+}
+
+
+/*
+ * ChapLowerDown - The lower layer is down.
+ *
+ * Cancel all timeouts.
+ */
+static void
+ChapLowerDown(unit)
+    int unit;
+{
+    chap_state *cstate = &chap[unit];
+  
+    /* Timeout(s) pending?  Cancel if so. */
+    if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||
+	cstate->serverstate == CHAPSS_RECHALLENGE)
+	UNTIMEOUT(ChapChallengeTimeout, cstate);
+    else if (cstate->serverstate == CHAPSS_OPEN
+	     && cstate->chal_interval != 0)
+	UNTIMEOUT(ChapRechallenge, cstate);
+    if (cstate->clientstate == CHAPCS_RESPONSE)
+	UNTIMEOUT(ChapResponseTimeout, cstate);
+
+    cstate->clientstate = CHAPCS_INITIAL;
+    cstate->serverstate = CHAPSS_INITIAL;
+}
+
+
+/*
+ * ChapProtocolReject - Peer doesn't grok CHAP.
+ */
+static void
+ChapProtocolReject(unit)
+    int unit;
+{
+    chap_state *cstate = &chap[unit];
+
+    if (cstate->serverstate != CHAPSS_INITIAL &&
+	cstate->serverstate != CHAPSS_CLOSED)
+	auth_peer_fail(unit, PPP_CHAP);
+    if (cstate->clientstate != CHAPCS_INITIAL &&
+	cstate->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 = &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 < CHAP_HEADERLEN) {
+	CHAPDEBUG(("ChapInput: rcvd short header."));
+	return;
+    }
+    GETCHAR(code, inp);
+    GETCHAR(id, inp);
+    GETSHORT(len, inp);
+    if (len < CHAP_HEADERLEN) {
+	CHAPDEBUG(("ChapInput: rcvd illegal length."));
+	return;
+    }
+    if (len > packet_len) {
+	CHAPDEBUG(("ChapInput: rcvd short packet."));
+	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("Unknown CHAP code (%d) received.", 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->clientstate == CHAPCS_CLOSED ||
+	cstate->clientstate == CHAPCS_PENDING) {
+	CHAPDEBUG(("ChapReceiveChallenge: in state %d", cstate->clientstate));
+	return;
+    }
+
+    if (len < 2) {
+	CHAPDEBUG(("ChapReceiveChallenge: rcvd short packet."));
+	return;
+    }
+
+    GETCHAR(rchallenge_len, inp);
+    len -= sizeof (u_char) + rchallenge_len;	/* now name field length */
+    if (len < 0) {
+	CHAPDEBUG(("ChapReceiveChallenge: rcvd short packet."));
+	return;
+    }
+    rchallenge = inp;
+    INCPTR(rchallenge_len, inp);
+
+    if (len >= 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 && rhostname[0] == 0)) {
+	strlcpy(rhostname, remote_name, sizeof(rhostname));
+	CHAPDEBUG(("ChapReceiveChallenge: using '%q' as remote name",
+		   rhostname));
+    }
+
+    /* get secret for authenticating ourselves with the specified host */
+    if (!get_secret(cstate->unit, cstate->resp_name, rhostname,
+		    secret, &secret_len, 0)) {
+	secret_len = 0;		/* assume null secret if can't find one */
+	warn("No CHAP secret found for authenticating us to %q", rhostname);
+    }
+
+    /* cancel response send timeout if necessary */
+    if (cstate->clientstate == CHAPCS_RESPONSE)
+	UNTIMEOUT(ChapResponseTimeout, cstate);
+
+    cstate->resp_id = id;
+    cstate->resp_transmits = 0;
+
+    /*  generate MD based on negotiated type */
+    switch (cstate->resp_type) { 
+
+    case CHAP_DIGEST_MD5:
+	MD5Init(&mdContext);
+	MD5Update(&mdContext, &cstate->resp_id, 1);
+	MD5Update(&mdContext, secret, secret_len);
+	MD5Update(&mdContext, rchallenge, rchallenge_len);
+	MD5Final(hash, &mdContext);
+	BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE);
+	cstate->resp_length = MD5_SIGNATURE_SIZE;
+	break;
+
+#ifdef CHAPMS
+    case CHAP_MICROSOFT:
+	ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len);
+	break;
+#endif
+
+    default:
+	CHAPDEBUG(("unknown digest type %d", cstate->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->serverstate == CHAPSS_CLOSED ||
+	cstate->serverstate == CHAPSS_PENDING) {
+	CHAPDEBUG(("ChapReceiveResponse: in state %d", cstate->serverstate));
+	return;
+    }
+
+    if (id != cstate->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->serverstate == CHAPSS_OPEN) {
+	ChapSendStatus(cstate, CHAP_SUCCESS);
+	return;
+    }
+    if (cstate->serverstate == CHAPSS_BADAUTH) {
+	ChapSendStatus(cstate, CHAP_FAILURE);
+	return;
+    }
+
+    if (len < 2) {
+	CHAPDEBUG(("ChapReceiveResponse: rcvd short packet."));
+	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 < 0) {
+	CHAPDEBUG(("ChapReceiveResponse: rcvd short packet."));
+	return;
+    }
+
+    UNTIMEOUT(ChapChallengeTimeout, cstate);
+
+    if (len >= 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->unit, (explicit_remote? remote_name: rhostname),
+		    cstate->chal_name, secret, &secret_len, 1)) {
+	warn("No CHAP secret found for authenticating %q", rhostname);
+    } else {
+
+	/*  generate MD based on negotiated type */
+	switch (cstate->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(&mdContext);
+	    MD5Update(&mdContext, &cstate->chal_id, 1);
+	    MD5Update(&mdContext, secret, secret_len);
+	    MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
+	    MD5Final(hash, &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(("unknown digest type %d", cstate->chal_type));
+	}
+    }
+
+    BZERO(secret, sizeof(secret));
+    ChapSendStatus(cstate, code);
+
+    if (code == CHAP_SUCCESS) {
+	old_state = cstate->serverstate;
+	cstate->serverstate = CHAPSS_OPEN;
+	if (old_state == CHAPSS_INITIAL_CHAL) {
+	    auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len);
+	}
+	if (cstate->chal_interval != 0)
+	    TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval);
+	notice("CHAP peer authentication succeeded for %q", rhostname);
+
+    } else {
+	error("CHAP peer authentication failed for remote host %q", rhostname);
+	cstate->serverstate = CHAPSS_BADAUTH;
+	auth_peer_fail(cstate->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->clientstate == CHAPCS_OPEN)
+	/* presumably an answer to a duplicate response */
+	return;
+
+    if (cstate->clientstate != CHAPCS_RESPONSE) {
+	/* don't know what this is */
+	CHAPDEBUG(("ChapReceiveSuccess: in state %d\n", cstate->clientstate));
+	return;
+    }
+
+    UNTIMEOUT(ChapResponseTimeout, cstate);
+
+    /*
+     * Print message.
+     */
+    if (len > 0)
+	PRINTMSG(inp, len);
+
+    cstate->clientstate = CHAPCS_OPEN;
+
+    auth_withpeer_success(cstate->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->clientstate != CHAPCS_RESPONSE) {
+	/* don't know what this is */
+	CHAPDEBUG(("ChapReceiveFailure: in state %d\n", cstate->clientstate));
+	return;
+    }
+
+    UNTIMEOUT(ChapResponseTimeout, cstate);
+
+    /*
+     * Print message.
+     */
+    if (len > 0)
+	PRINTMSG(inp, len);
+
+    error("CHAP authentication failed");
+    auth_withpeer_fail(cstate->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->chal_len;
+    name_len = strlen(cstate->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->chal_id, outp);
+    PUTSHORT(outlen, outp);
+
+    PUTCHAR(chal_len, outp);		/* put length of challenge */
+    BCOPY(cstate->challenge, outp, chal_len);
+    INCPTR(chal_len, outp);
+
+    BCOPY(cstate->chal_name, outp, name_len);	/* append hostname */
+
+    output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
+  
+    TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);
+    ++cstate->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), "Welcome to %s.", hostname);
+    else
+	slprintf(msg, sizeof(msg), "I don't like you.  Go 'way.");
+    msglen = strlen(msg);
+
+    outlen = CHAP_HEADERLEN + msglen;
+    outp = outpacket_buf;
+
+    MAKEHEADER(outp, PPP_CHAP);	/* paste in a header */
+  
+    PUTCHAR(code, outp);
+    PUTCHAR(cstate->chal_id, outp);
+    PUTSHORT(outlen, outp);
+    BCOPY(msg, outp, msglen);
+    output(cstate->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->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->chal_len = chal_len;
+    cstate->chal_id = ++cstate->id;
+    cstate->chal_transmits = 0;
+
+    /* generate a random string */
+    for (i = 0; i < 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->resp_length;
+    name_len = strlen(cstate->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->resp_id, outp);	/* copy id from challenge packet */
+    PUTSHORT(outlen, outp);		/* packet length */
+
+    PUTCHAR(md_len, outp);		/* length of MD */
+    BCOPY(cstate->response, outp, md_len);	/* copy MD to buffer */
+    INCPTR(md_len, outp);
+
+    BCOPY(cstate->resp_name, outp, name_len); /* append our name */
+
+    /* send the packet */
+    output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
+
+    cstate->clientstate = CHAPCS_RESPONSE;
+    TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime);
+    ++cstate->resp_transmits;
+}
+
+/*
+ * ChapPrintPkt - print the contents of a CHAP packet.
+ */
+static char *ChapCodenames[] = {
+    "Challenge", "Response", "Success", "Failure"
+};
+
+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 < CHAP_HEADERLEN)
+	return 0;
+    GETCHAR(code, p);
+    GETCHAR(id, p);
+    GETSHORT(len, p);
+    if (len < CHAP_HEADERLEN || len > plen)
+	return 0;
+
+    if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *))
+	printer(arg, " %s", ChapCodenames[code-1]);
+    else
+	printer(arg, " code=0x%x", code);
+    printer(arg, " id=0x%x", id);
+    len -= CHAP_HEADERLEN;
+    switch (code) {
+    case CHAP_CHALLENGE:
+    case CHAP_RESPONSE:
+	if (len < 1)
+	    break;
+	clen = p[0];
+	if (len < clen + 1)
+	    break;
+	++p;
+	nlen = len - clen - 1;
+	printer(arg, " <");
+	for (; clen > 0; --clen) {
+	    GETCHAR(x, p);
+	    printer(arg, "%.2x", x);
+	}
+	printer(arg, ">, name = ");
+	print_string((char *)p, nlen, printer, arg);
+	break;
+    case CHAP_FAILURE:
+    case CHAP_SUCCESS:
+	printer(arg, " ");
+	print_string((char *)p, len, printer, arg);
+	break;
+    default:
+	for (clen = len; clen > 0; --clen) {
+	    GETCHAR(x, p);
+	    printer(arg, " %.2x", 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.
+ * http://www.strataware.com/
+ *
+ * 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 / lpesonen at clinet.fi, 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 "ms-lanman". 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	"$Id: chap_ms.c 195720 2001-06-11 11:44:34Z gc $"
+
+#ifdef CHAPMS
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+#include "pppd.h"
+#include "chap.h"
+#include "chap_ms.h"
+#include "md4.h"
+
+#ifndef USE_CRYPT
+#include <des.h>
+#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("ChallengeResponse - ZPasswordHash %.*B",
+	   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("ChallengeResponse - response %.24B", 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, "DesEncrypt: 8 octet input : %.8B", clear));
+#endif
+
+    Expand(clear, des_input);
+    encrypt(des_input, 0);
+    Collapse(des_input, cipher);
+
+#if 0
+    CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %.8B", 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(&des_key, key_schedule);
+
+#if 0
+    CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %.8B", clear));
+#endif
+
+    des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
+
+#if 0
+    CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %.8B", 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] << 8;
+    word |= (unsigned)input[startBit / 8 + 1];
+
+    word >>= 15 - (startBit % 8 + 7);
+
+    return word & 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 "bit" 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 < 64; in++){
+		c = *in;
+                for(j = 7; j >= 0; j--)
+                        *out++ = (c >> j) & 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 < 64; i += 8, out++) {
+	    c = 0;
+	    for (j = 7; j >= 0; j--, in++)
+		c |= *in << j;
+	    *out = c & 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, "MakeKey: 56-bit input : %.7B", key));
+    CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %.8B", 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 < secret_len; i++)
+	unicodePassword[i * 2] = (u_char)secret[i];
+
+    MD4Init(&md4Context);
+    MD4Update(&md4Context, unicodePassword, mdlen);
+
+    MD4Final(hash, &md4Context); 	/* Tell MD4 we're done */
+
+    ChallengeResponse(rchallenge, hash, response->NTResp);
+}
+
+#ifdef MSLANMAN
+static u_char *StdText = (u_char *)"KGS!@#$%"; /* 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 < 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->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, "ChapMS: secret is '%.*s'", secret_len, secret));
+#endif
+    BZERO(&response, sizeof(response));
+
+    /* Calculate both always */
+    ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response);
+
+#ifdef MSLANMAN
+    ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response);
+
+    /* prefered method is set by option  */
+    response.UseNT = !ms_lanman;
+#else
+    response.UseNT = 1;
+#endif
+
+    BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);
+    cstate->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.
+ * http://www.strataware.com/
+ *
+ * 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	"$Id: demand.c 195720 2001-06-11 11:44:34Z gc $"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#ifdef PPP_FILTER
+#include <net/if.h>
+#include <net/bpf.h>
+#include <pcap.h>
+#endif
+
+#include "pppd.h"
+#include "fsm.h"
+#include "ipcp.h"
+#include "lcp.h"
+
+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 < PPP_MRU) */
+	framemax = PPP_MRU;
+    framemax += PPP_HDRLEN + PPP_FCSLEN;
+    frame = malloc(framemax);
+    if (frame == NULL)
+	novm("demand frame");
+    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(&pass_filter, &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->enabled_flag && protp->demand_conf != NULL)
+	    if (!((*protp->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->enabled_flag && protp->demand_conf != NULL)
+	    sifnpmode(0, protp->protocol & ~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->enabled_flag && protp->demand_conf != NULL)
+	    sifnpmode(0, protp->protocol & ~0x8000, NPMODE_ERROR);
+    get_loop_output();
+
+    /* discard all saved packets */
+    for (pkt = pend_q; pkt != NULL; pkt = nextpkt) {
+	nextpkt = pkt->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->enabled_flag && protp->demand_conf != NULL)
+	    sifnpmode(0, protp->protocol & ~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 > 0; --n) {
+	c = *p++;
+	if (c == PPP_FLAG) {
+	    if (!escape_flag && !flush_flag
+		&& framelen > 2 && 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 >= 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("from loop: %P", frame, len); */
+    if (len < PPP_HDRLEN)
+	return 0;
+    if ((PPP_PROTOCOL(frame) & 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->length = len;
+	pkt->next = NULL;
+	memcpy(pkt->data, frame, len);
+	if (pend_q == NULL)
+	    pend_q = pkt;
+	else
+	    pend_qtail->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->next;
+	if (PPP_PROTOCOL(pkt->data) == proto) {
+	    output(0, pkt->data, pkt->length);
+	    free(pkt);
+	} else {
+	    if (prev == NULL)
+		pend_q = pkt;
+	    else
+		prev->next = pkt;
+	    prev = pkt;
+	}
+    }
+    pend_qtail = prev;
+    if (prev != NULL)
+	prev->next = NULL;
+}
+
+/*
+ * Scan a packet to decide whether it is an "active" 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 < PPP_HDRLEN)
+	return 0;
+    proto = PPP_PROTOCOL(p);
+#ifdef PPP_FILTER
+    if (pass_filter.bf_len != 0
+	&& bpf_filter(pass_filter.bf_insns, p, len, len) == 0)
+	return 0;
+    if (active_filter.bf_len != 0
+	&& bpf_filter(active_filter.bf_insns, p, len, len) == 0)
+	return 0;
+#endif
+    for (i = 0; (protp = protocols[i]) != NULL; ++i) {
+	if (protp->protocol < 0xC000 && (protp->protocol & ~0x8000) == proto) {
+	    if (!protp->enabled_flag)
+		return 0;
+	    if (protp->active_pkt == NULL)
+		return 1;
+	    return (*protp->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 <Tommi.Komulainen at iki.fi>
+
+    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	"$Id: eui64.c 195720 2001-06-11 11:44:34Z gc $"
+
+#include "pppd.h"
+
+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, "%02x%02x:%02x%02x:%02x%02x:%02x%02x",
+	     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 <Tommi.Komulainen at iki.fi>
+
+    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	"this file should only be included when INET6 is defined"
+#endif /* not defined(INET6) */
+
+#if defined(SOL2)
+#include <netinet/in.h>
+
+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]) && \
+				((e).e32[1] == (o).e32[1]))
+#define eui64_zero(e)		(e).e32[0] = (e).e32[1] = 0;
+
+#define eui64_copy(s, d)	memcpy(&(d), &(s), sizeof(eui64_t))
+
+#define eui64_magic(e)		do {			\
+				(e).e32[0] = magic();	\
+				(e).e32[1] = magic();	\
+				(e).e8[0] &= ~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	"$Id: fsm.c 195720 2001-06-11 11:44:34Z gc $"
+
+/*
+ * TODO:
+ * Randomize fsm id on link/init.
+ * Deal with variable outgoing MTU.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "pppd.h"
+#include "fsm.h"
+
+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)->callbacks->proto_name)
+
+int peer_mru[NUM_PPP];
+
+
+/*
+ * fsm_init - Initialize fsm.
+ *
+ * Initialize fsm state.
+ */
+void
+fsm_init(f)
+    fsm *f;
+{
+    f->state = INITIAL;
+    f->flags = 0;
+    f->id = 0;				/* XXX Start with random id? */
+    f->timeouttime = DEFTIMEOUT;
+    f->maxconfreqtransmits = DEFMAXCONFREQS;
+    f->maxtermtransmits = DEFMAXTERMREQS;
+    f->maxnakloops = DEFMAXNAKLOOPS;
+    f->term_reason_len = 0;
+}
+
+
+/*
+ * fsm_lowerup - The lower layer is up.
+ */
+void
+fsm_lowerup(f)
+    fsm *f;
+{
+    switch( f->state ){
+    case INITIAL:
+	f->state = CLOSED;
+	break;
+
+    case STARTING:
+	if( f->flags & OPT_SILENT )
+	    f->state = STOPPED;
+	else {
+	    /* Send an initial configure-request */
+	    fsm_sconfreq(f, 0);
+	    f->state = REQSENT;
+	}
+	break;
+
+    default:
+	FSMDEBUG(("%s: Up event in state %d!", PROTO_NAME(f), f->state));
+    }
+}
+
+
+/*
+ * fsm_lowerdown - The lower layer is down.
+ *
+ * Cancel all timeouts and inform upper layers.
+ */
+void
+fsm_lowerdown(f)
+    fsm *f;
+{
+    switch( f->state ){
+    case CLOSED:
+	f->state = INITIAL;
+	break;
+
+    case STOPPED:
+	f->state = STARTING;
+	if( f->callbacks->starting )
+	    (*f->callbacks->starting)(f);
+	break;
+
+    case CLOSING:
+	f->state = INITIAL;
+	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
+	break;
+
+    case STOPPING:
+    case REQSENT:
+    case ACKRCVD:
+    case ACKSENT:
+	f->state = STARTING;
+	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
+	break;
+
+    case OPENED:
+	if( f->callbacks->down )
+	    (*f->callbacks->down)(f);
+	f->state = STARTING;
+	break;
+
+    default:
+	FSMDEBUG(("%s: Down event in state %d!", PROTO_NAME(f), f->state));
+    }
+}
+
+
+/*
+ * fsm_open - Link is allowed to come up.
+ */
+void
+fsm_open(f)
+    fsm *f;
+{
+    switch( f->state ){
+    case INITIAL:
+	f->state = STARTING;
+	if( f->callbacks->starting )
+	    (*f->callbacks->starting)(f);
+	break;
+
+    case CLOSED:
+	if( f->flags & OPT_SILENT )
+	    f->state = STOPPED;
+	else {
+	    /* Send an initial configure-request */
+	    fsm_sconfreq(f, 0);
+	    f->state = REQSENT;
+	}
+	break;
+
+    case CLOSING:
+	f->state = STOPPING;
+	/* fall through */
+    case STOPPED:
+    case OPENED:
+	if( f->flags & 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->term_reason = reason;
+    f->term_reason_len = (reason == NULL? 0: strlen(reason));
+    switch( f->state ){
+    case STARTING:
+	f->state = INITIAL;
+	break;
+    case STOPPED:
+	f->state = CLOSED;
+	break;
+    case STOPPING:
+	f->state = CLOSING;
+	break;
+
+    case REQSENT:
+    case ACKRCVD:
+    case ACKSENT:
+    case OPENED:
+	if( f->state != OPENED )
+	    UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
+	else if( f->callbacks->down )
+	    (*f->callbacks->down)(f);	/* Inform upper layers we're down */
+
+	/* Init restart counter, send Terminate-Request */
+	f->retransmits = f->maxtermtransmits;
+	fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
+		  (u_char *) f->term_reason, f->term_reason_len);
+	TIMEOUT(fsm_timeout, f, f->timeouttime);
+	--f->retransmits;
+
+	f->state = CLOSING;
+	break;
+    }
+}
+
+
+/*
+ * fsm_timeout - Timeout expired.
+ */
+static void
+fsm_timeout(arg)
+    void *arg;
+{
+    fsm *f = (fsm *) arg;
+
+    switch (f->state) {
+    case CLOSING:
+    case STOPPING:
+	if( f->retransmits <= 0 ){
+	    /*
+	     * We've waited for an ack long enough.  Peer probably heard us.
+	     */
+	    f->state = (f->state == CLOSING)? CLOSED: STOPPED;
+	    if( f->callbacks->finished )
+		(*f->callbacks->finished)(f);
+	} else {
+	    /* Send Terminate-Request */
+	    fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
+		      (u_char *) f->term_reason, f->term_reason_len);
+	    TIMEOUT(fsm_timeout, f, f->timeouttime);
+	    --f->retransmits;
+	}
+	break;
+
+    case REQSENT:
+    case ACKRCVD:
+    case ACKSENT:
+	if (f->retransmits <= 0) {
+	    warn("%s: timeout sending Config-Requests\n", PROTO_NAME(f));
+	    f->state = STOPPED;
+	    if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished )
+		(*f->callbacks->finished)(f);
+
+	} else {
+	    /* Retransmit the configure-request */
+	    if (f->callbacks->retransmit)
+		(*f->callbacks->retransmit)(f);
+	    fsm_sconfreq(f, 1);		/* Re-send Configure-Request */
+	    if( f->state == ACKRCVD )
+		f->state = REQSENT;
+	}
+	break;
+
+    default:
+	FSMDEBUG(("%s: Timeout event in state %d!", PROTO_NAME(f), f->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 < HEADERLEN) {
+	FSMDEBUG(("fsm_input(%x): Rcvd short header.", f->protocol));
+	return;
+    }
+    GETCHAR(code, inp);
+    GETCHAR(id, inp);
+    GETSHORT(len, inp);
+    if (len < HEADERLEN) {
+	FSMDEBUG(("fsm_input(%x): Rcvd illegal length.", f->protocol));
+	return;
+    }
+    if (len > l) {
+	FSMDEBUG(("fsm_input(%x): Rcvd short packet.", f->protocol));
+	return;
+    }
+    len -= HEADERLEN;		/* subtract header length */
+
+    if( f->state == INITIAL || f->state == STARTING ){
+	FSMDEBUG(("fsm_input(%x): Rcvd packet in state %d.",
+		  f->protocol, f->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->callbacks->extcode
+	   || !(*f->callbacks->extcode)(f, code, id, inp, len) )
+	    fsm_sdata(f, CODEREJ, ++f->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->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->callbacks->down )
+	    (*f->callbacks->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->state = REQSENT;
+	break;
+    }
+
+    /*
+     * Pass the requested configuration options
+     * to protocol-specific code for checking.
+     */
+    if (f->callbacks->reqci){		/* Check CI */
+	reject_if_disagree = (f->nakloops >= f->maxnakloops);
+	code = (*f->callbacks->reqci)(f, inp, &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->state == ACKRCVD) {
+	    UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
+	    f->state = OPENED;
+	    if (f->callbacks->up)
+		(*f->callbacks->up)(f);	/* Inform upper layers */
+	} else
+	    f->state = ACKSENT;
+	f->nakloops = 0;
+
+    } else {
+	/* we sent CONFACK or CONFREJ */
+	if (f->state != ACKRCVD)
+	    f->state = REQSENT;
+	if( code == CONFNAK )
+	    ++f->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->reqid || f->seen_ack)		/* Expected id? */
+	return;					/* Nope, toss... */
+    if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len):
+	  (len == 0)) ){
+	/* Ack is bad - ignore it */
+	error("Received bad configure-ack: %P", inp, len);
+	return;
+    }
+    f->seen_ack = 1;
+
+    switch (f->state) {
+    case CLOSED:
+    case STOPPED:
+	fsm_sdata(f, TERMACK, id, NULL, 0);
+	break;
+
+    case REQSENT:
+	f->state = ACKRCVD;
+	f->retransmits = f->maxconfreqtransmits;
+	break;
+
+    case ACKRCVD:
+	/* Huh? an extra valid Ack? oh well... */
+	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
+	fsm_sconfreq(f, 0);
+	f->state = REQSENT;
+	break;
+
+    case ACKSENT:
+	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
+	f->state = OPENED;
+	f->retransmits = f->maxconfreqtransmits;
+	if (f->callbacks->up)
+	    (*f->callbacks->up)(f);	/* Inform upper layers */
+	break;
+
+    case OPENED:
+	/* Go down and restart negotiation */
+	if (f->callbacks->down)
+	    (*f->callbacks->down)(f);	/* Inform upper layers */
+	fsm_sconfreq(f, 0);		/* Send initial Configure-Request */
+	f->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->reqid || f->seen_ack)	/* Expected id? */
+	return;				/* Nope, toss... */
+    proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci;
+    if (!proc || !(ret = proc(f, inp, len))) {
+	/* Nak/reject is bad - ignore it */
+	error("Received bad configure-nak/rej: %P", inp, len);
+	return;
+    }
+    f->seen_ack = 1;
+
+    switch (f->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 < 0)
+	    f->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->state = REQSENT;
+	break;
+
+    case OPENED:
+	/* Go down and restart negotiation */
+	if (f->callbacks->down)
+	    (*f->callbacks->down)(f);	/* Inform upper layers */
+	fsm_sconfreq(f, 0);		/* Send initial Configure-Request */
+	f->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->state) {
+    case ACKRCVD:
+    case ACKSENT:
+	f->state = REQSENT;		/* Start over but keep trying */
+	break;
+
+    case OPENED:
+	if (len > 0) {
+	    info("%s terminated by peer (%0.*v)", PROTO_NAME(f), len, p);
+	} else
+	    info("%s terminated by peer", PROTO_NAME(f));
+	if (f->callbacks->down)
+	    (*f->callbacks->down)(f);	/* Inform upper layers */
+	f->retransmits = 0;
+	f->state = STOPPING;
+	TIMEOUT(fsm_timeout, f, f->timeouttime);
+	break;
+    }
+
+    fsm_sdata(f, TERMACK, id, NULL, 0);
+}
+
+
+/*
+ * fsm_rtermack - Receive Terminate-Ack.
+ */
+static void
+fsm_rtermack(f)
+    fsm *f;
+{
+    switch (f->state) {
+    case CLOSING:
+	UNTIMEOUT(fsm_timeout, f);
+	f->state = CLOSED;
+	if( f->callbacks->finished )
+	    (*f->callbacks->finished)(f);
+	break;
+    case STOPPING:
+	UNTIMEOUT(fsm_timeout, f);
+	f->state = STOPPED;
+	if( f->callbacks->finished )
+	    (*f->callbacks->finished)(f);
+	break;
+
+    case ACKRCVD:
+	f->state = REQSENT;
+	break;
+
+    case OPENED:
+	if (f->callbacks->down)
+	    (*f->callbacks->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 < HEADERLEN) {
+	FSMDEBUG(("fsm_rcoderej: Rcvd short Code-Reject packet!"));
+	return;
+    }
+    GETCHAR(code, inp);
+    GETCHAR(id, inp);
+    warn("%s: Rcvd Code-Reject for code %d, id %d", PROTO_NAME(f), code, id);
+
+    if( f->state == ACKRCVD )
+	f->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->state ){
+    case CLOSING:
+	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
+	/* fall through */
+    case CLOSED:
+	f->state = CLOSED;
+	if( f->callbacks->finished )
+	    (*f->callbacks->finished)(f);
+	break;
+
+    case STOPPING:
+    case REQSENT:
+    case ACKRCVD:
+    case ACKSENT:
+	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
+	/* fall through */
+    case STOPPED:
+	f->state = STOPPED;
+	if( f->callbacks->finished )
+	    (*f->callbacks->finished)(f);
+	break;
+
+    case OPENED:
+	if( f->callbacks->down )
+	    (*f->callbacks->down)(f);
+
+	/* Init restart counter, send Terminate-Request */
+	f->retransmits = f->maxtermtransmits;
+	fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
+		  (u_char *) f->term_reason, f->term_reason_len);
+	TIMEOUT(fsm_timeout, f, f->timeouttime);
+	--f->retransmits;
+
+	f->state = STOPPING;
+	break;
+
+    default:
+	FSMDEBUG(("%s: Protocol-reject event in state %d!",
+		  PROTO_NAME(f), f->state));
+    }
+}
+
+
+/*
+ * fsm_sconfreq - Send a Configure-Request.
+ */
+static void
+fsm_sconfreq(f, retransmit)
+    fsm *f;
+    int retransmit;
+{
+    u_char *outp;
+    int cilen;
+
+    if( f->state != REQSENT && f->state != ACKRCVD && f->state != ACKSENT ){
+	/* Not currently negotiating - reset options */
+	if( f->callbacks->resetci )
+	    (*f->callbacks->resetci)(f);
+	f->nakloops = 0;
+    }
+
+    if( !retransmit ){
+	/* New request - reset retransmission counter, use new ID */
+	f->retransmits = f->maxconfreqtransmits;
+	f->reqid = ++f->id;
+    }
+
+    f->seen_ack = 0;
+
+    /*
+     * Make up the request packet
+     */
+    outp = outpacket_buf + PPP_HDRLEN + HEADERLEN;
+    if( f->callbacks->cilen && f->callbacks->addci ){
+	cilen = (*f->callbacks->cilen)(f);
+	if( cilen > peer_mru[f->unit] - HEADERLEN )
+	    cilen = peer_mru[f->unit] - HEADERLEN;
+	if (f->callbacks->addci)
+	    (*f->callbacks->addci)(f, outp, &cilen);
+    } else
+	cilen = 0;
+
+    /* send the request to our peer */
+    fsm_sdata(f, CONFREQ, f->reqid, outp, cilen);
+
+    /* start the retransmit timer */
+    --f->retransmits;
+    TIMEOUT(fsm_timeout, f, f->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 > peer_mru[f->unit] - HEADERLEN)
+	datalen = peer_mru[f->unit] - HEADERLEN;
+    if (datalen && data != outp + PPP_HDRLEN + HEADERLEN)
+	BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen);
+    outlen = datalen + HEADERLEN;
+    MAKEHEADER(outp, f->protocol);
+    PUTCHAR(code, outp);
+    PUTCHAR(id, outp);
+    PUTSHORT(outlen, outp);
+    output(f->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	"$Id: ipcp.c 198597 2002-05-13 15:34:06Z gc $"
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "pppd.h"
+#include "fsm.h"
+#include "ipcp.h"
+#include "pathnames.h"
+
+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 */
+    "IPCP"			/* 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[] = {
+    { "noip", o_bool, &ipcp_protent.enabled_flag,
+      "Disable IP and IPCP" },
+    { "-ip", o_bool, &ipcp_protent.enabled_flag,
+      "Disable IP and IPCP", OPT_ALIAS },
+
+    { "novj", o_bool, &ipcp_wantoptions[0].neg_vj,
+      "Disable VJ compression", OPT_A2CLR, &ipcp_allowoptions[0].neg_vj },
+    { "-vj", o_bool, &ipcp_wantoptions[0].neg_vj,
+      "Disable VJ compression", OPT_ALIAS | OPT_A2CLR,
+      &ipcp_allowoptions[0].neg_vj },
+
+    { "novjccomp", o_bool, &ipcp_wantoptions[0].cflag,
+      "Disable VJ connection-ID compression", OPT_A2CLR,
+      &ipcp_allowoptions[0].cflag },
+    { "-vjccomp", o_bool, &ipcp_wantoptions[0].cflag,
+      "Disable VJ connection-ID compression", OPT_ALIAS | OPT_A2CLR,
+      &ipcp_allowoptions[0].cflag },
+
+    { "vj-max-slots", o_special, (void *)setvjslots,
+      "Set maximum VJ header slots",
+      OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, vj_value },
+
+    { "ipcp-accept-local", o_bool, &ipcp_wantoptions[0].accept_local,
+      "Accept peer's address for us", 1 },
+    { "ipcp-accept-remote", o_bool, &ipcp_wantoptions[0].accept_remote,
+      "Accept peer's address for it", 1 },
+
+    { "ipparam", o_string, &ipparam,
+      "Set ip script parameter", OPT_PRIO },
+
+    { "noipdefault", o_bool, &disable_defaultip,
+      "Don't use name for default IP adrs", 1 },
+
+    { "ms-dns", 1, (void *)setdnsaddr,
+      "DNS address for the peer's use" },
+    { "ms-wins", 1, (void *)setwinsaddr,
+      "Nameserver for SMB over TCP/IP for peer" },
+
+    { "ipcp-restart", o_int, &ipcp_fsm[0].timeouttime,
+      "Set timeout for IPCP", OPT_PRIO },
+    { "ipcp-max-terminate", o_int, &ipcp_fsm[0].maxtermtransmits,
+      "Set max #xmits for term-reqs", OPT_PRIO },
+    { "ipcp-max-configure", o_int, &ipcp_fsm[0].maxconfreqtransmits,
+      "Set max #xmits for conf-reqs", OPT_PRIO },
+    { "ipcp-max-failure", o_int, &ipcp_fsm[0].maxnakloops,
+      "Set max #conf-naks for IPCP", OPT_PRIO },
+
+    { "defaultroute", o_bool, &ipcp_wantoptions[0].default_route,
+      "Add default route", OPT_ENABLE|1, &ipcp_allowoptions[0].default_route },
+    { "nodefaultroute", o_bool, &ipcp_allowoptions[0].default_route,
+      "disable defaultroute option", OPT_A2CLR,
+      &ipcp_wantoptions[0].default_route },
+    { "-defaultroute", o_bool, &ipcp_allowoptions[0].default_route,
+      "disable defaultroute option", OPT_ALIAS | OPT_A2CLR,
+      &ipcp_wantoptions[0].default_route },
+
+    { "proxyarp", o_bool, &ipcp_wantoptions[0].proxy_arp,
+      "Add proxy ARP entry", OPT_ENABLE|1, &ipcp_allowoptions[0].proxy_arp },
+    { "noproxyarp", o_bool, &ipcp_allowoptions[0].proxy_arp,
+      "disable proxyarp option", OPT_A2CLR,
+      &ipcp_wantoptions[0].proxy_arp },
+    { "-proxyarp", o_bool, &ipcp_allowoptions[0].proxy_arp,
+      "disable proxyarp option", OPT_ALIAS | OPT_A2CLR,
+      &ipcp_wantoptions[0].proxy_arp },
+
+    { "usepeerdns", o_bool, &usepeerdns,
+      "Ask peer for DNS address(es)", 1 },
+
+    { "netmask", o_special, (void *)setnetmask,
+      "set netmask", OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, netmask_str },
+
+    { "IP addresses", o_wild, (void *) &setipaddr,
+      "set local and remote IP addresses",
+      OPT_NOARG | OPT_A2PRINTER, (void *) &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,
+    "IPCP",
+    "IP",
+    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 ? "ACK" : \
+			 (x) == CONFNAK ? "NAK" : "REJ")
+
+/*
+ * 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), "%I", 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, &value))
+	return 0;
+    if (value < 2 || value > 16) {
+	option_error("vj-max-slots value must be between 2 and 16");
+	return 0;
+    }
+    ipcp_wantoptions [0].maxslotindex =
+        ipcp_allowoptions[0].maxslotindex = value - 1;
+    slprintf(vj_value, sizeof(vj_value), "%d", 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("invalid address parameter '%s' for ms-dns option",
+			 *argv);
+	    return 0;
+	}
+	dns = *(u_int32_t *)hp->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("invalid address parameter '%s' for ms-wins option",
+			 *argv);
+	    return 0;
+	}
+	wins = *(u_int32_t *)hp->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 = &ipcp_wantoptions[0];
+    static int prio_local = 0, prio_remote = 0;
+
+    /*
+     * IP address pair separated by ":".
+     */
+    if ((colon = strchr(arg, ':')) == NULL)
+	return 0;
+    if (!doit)
+	return 1;
+  
+    /*
+     * If colon first character, then no local addr.
+     */
+    if (colon != arg && option_priority >= prio_local) {
+	*colon = '\0';
+	if ((local = inet_addr(arg)) == (u_int32_t) -1) {
+	    if ((hp = gethostbyname(arg)) == NULL) {
+		option_error("unknown host: %s", arg);
+		return 0;
+	    }
+	    local = *(u_int32_t *)hp->h_addr;
+	}
+	if (bad_ip_adrs(local)) {
+	    option_error("bad local IP address %s", ip_ntoa(local));
+	    return 0;
+	}
+	if (local != 0)
+	    wo->ouraddr = local;
+	*colon = ':';
+	prio_local = option_priority;
+    }
+  
+    /*
+     * If colon last character, then no remote addr.
+     */
+    if (*++colon != '\0' && option_priority >= prio_remote) {
+	if ((remote = inet_addr(colon)) == (u_int32_t) -1) {
+	    if ((hp = gethostbyname(colon)) == NULL) {
+		option_error("unknown host: %s", colon);
+		return 0;
+	    }
+	    remote = *(u_int32_t *)hp->h_addr;
+	    if (remote_name[0] == 0)
+		strlcpy(remote_name, colon, sizeof(remote_name));
+	}
+	if (bad_ip_adrs(remote)) {
+	    option_error("bad remote IP address %s", ip_ntoa(remote));
+	    return 0;
+	}
+	if (remote != 0)
+	    wo->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 = &ipcp_wantoptions[0];
+
+	if (wo->ouraddr != 0)
+		printer(arg, "%I", wo->ouraddr);
+	printer(arg, ":");
+	if (wo->hisaddr != 0)
+		printer(arg, "%I", wo->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, &mask);
+
+    mask = htonl(mask);
+
+    if (n == 0 || p[n] != 0 || (netmask & ~mask) != 0) {
+	option_error("invalid netmask value '%s'", *argv);
+	return 0;
+    }
+
+    netmask = mask;
+    slprintf(netmask_str, sizeof(netmask_str), "%I", 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, &endp, 0);
+	if (endp == p)
+	    return 0;
+	if (b > 255) {
+	    if (n < 3)
+		return 0;
+	    /* accept e.g. 0xffffff00 */
+	    *vp = b;
+	    return endp - p0;
+	}
+	v |= b << (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 = &ipcp_fsm[unit];
+    ipcp_options *wo = &ipcp_wantoptions[unit];
+    ipcp_options *ao = &ipcp_allowoptions[unit];
+
+    f->unit = unit;
+    f->protocol = PPP_IPCP;
+    f->callbacks = &ipcp_callbacks;
+    fsm_init(&ipcp_fsm[unit]);
+
+    memset(wo, 0, sizeof(*wo));
+    memset(ao, 0, sizeof(*ao));
+
+    wo->neg_addr = 1;
+    wo->neg_vj = 1;
+    wo->vj_protocol = IPCP_VJ_COMP;
+    wo->maxslotindex = MAX_STATES - 1; /* really max index */
+    wo->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->neg_addr = 1;
+    ao->neg_vj = 1;
+    ao->maxslotindex = MAX_STATES - 1;
+    ao->cflag = 1;
+
+    /*
+     * XXX These control whether the user may use the proxyarp
+     * and defaultroute options.
+     */
+    ao->proxy_arp = 1;
+    ao->default_route = 1;
+}
+
+
+/*
+ * ipcp_open - IPCP is allowed to come up.
+ */
+static void
+ipcp_open(unit)
+    int unit;
+{
+    fsm_open(&ipcp_fsm[unit]);
+}
+
+
+/*
+ * ipcp_close - Take IPCP down.
+ */
+static void
+ipcp_close(unit, reason)
+    int unit;
+    char *reason;
+{
+    fsm_close(&ipcp_fsm[unit], reason);
+}
+
+
+/*
+ * ipcp_lowerup - The lower layer is up.
+ */
+static void
+ipcp_lowerup(unit)
+    int unit;
+{
+    fsm_lowerup(&ipcp_fsm[unit]);
+}
+
+
+/*
+ * ipcp_lowerdown - The lower layer is down.
+ */
+static void
+ipcp_lowerdown(unit)
+    int unit;
+{
+    fsm_lowerdown(&ipcp_fsm[unit]);
+}
+
+
+/*
+ * ipcp_input - Input IPCP packet.
+ */
+static void
+ipcp_input(unit, p, len)
+    int unit;
+    u_char *p;
+    int len;
+{
+    fsm_input(&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(&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 = &ipcp_wantoptions[f->unit];
+    ipcp_options *go = &ipcp_gotoptions[f->unit];
+
+    wo->req_addr = wo->neg_addr && ipcp_allowoptions[f->unit].neg_addr;
+    if (wo->ouraddr == 0)
+	wo->accept_local = 1;
+    if (wo->hisaddr == 0)
+	wo->accept_remote = 1;
+    wo->req_dns1 = usepeerdns;	/* Request DNS addresses from the peer */
+    wo->req_dns2 = usepeerdns;
+    *go = *wo;
+    if (!ask_for_local)
+	go->ouraddr = 0;
+    if (ip_choose_hook)
+	ip_choose_hook(&wo->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 = &ipcp_gotoptions[f->unit];
+    ipcp_options *wo = &ipcp_wantoptions[f->unit];
+    ipcp_options *ho = &ipcp_hisoptions[f->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->neg_addr && !go->neg_addr && !go->old_addrs) {
+	/* use the old style of address negotiation */
+	go->neg_addr = 1;
+	go->old_addrs = 1;
+    }
+    if (wo->neg_vj && !go->neg_vj && !go->old_vj) {
+	/* try an older style of VJ negotiation */
+	/* use the old style only if the peer did */
+	if (ho->neg_vj && ho->old_vj) {
+	    go->neg_vj = 1;
+	    go->old_vj = 1;
+	    go->vj_protocol = ho->vj_protocol;
+	}
+    }
+
+    return (LENCIADDR(go->neg_addr, go->old_addrs) +
+	    LENCIVJ(go->neg_vj, go->old_vj) +
+	    LENCIDNS(go->req_dns1) +
+	    LENCIDNS(go->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 = &ipcp_gotoptions[f->unit];
+    int len = *lenp;
+
+#define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \
+    if (neg) { \
+	int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \
+	if (len >= 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 >= 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 >= 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->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
+	      go->old_addrs, go->ouraddr, go->hisaddr);
+
+    ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
+	    go->maxslotindex, go->cflag);
+
+    ADDCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]);
+
+    ADDCIDNS(CI_MS_DNS2, go->req_dns2, go->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 = &ipcp_gotoptions[f->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) < 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) < 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) < 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->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
+	      go->old_addrs, go->ouraddr, go->hisaddr);
+
+    ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
+	    go->maxslotindex, go->cflag);
+
+    ACKCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]);
+
+    ACKCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]);
+
+    /*
+     * If there are any remaining CIs, then this packet is bad.
+     */
+    if (len != 0)
+	goto bad;
+    return (1);
+
+bad:
+    IPCPDEBUG(("ipcp_ackci: received bad Ack!"));
+    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 = &ipcp_gotoptions[f->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(&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->neg && \
+	len >= (cilen = (old? CILEN_ADDRS: CILEN_ADDR)) && \
+	p[1] == cilen && \
+	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->neg && \
+	((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && \
+	len >= cilen && \
+	p[0] == opt) { \
+	len -= cilen; \
+	INCPTR(2, p); \
+	GETSHORT(cishort, p); \
+	no.neg = 1; \
+        code \
+    }
+
+#define NAKCIDNS(opt, neg, code) \
+    if (go->neg && \
+	((cilen = p[1]) == CILEN_ADDR) && \
+	len >= cilen && \
+	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->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, go->old_addrs,
+	      if (go->accept_local && ciaddr1) { /* Do we know our address? */
+		  try.ouraddr = ciaddr1;
+	      }
+	      if (go->accept_remote && 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 < go->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 > CILEN_VOID) {
+	GETCHAR(citype, p);
+	GETCHAR(cilen, p);
+	if( (len -= cilen) < 0 )
+	    goto bad;
+	next = p + cilen - 2;
+
+	switch (citype) {
+	case CI_COMPRESSTYPE:
+	    if (go->neg_vj || no.neg_vj ||
+		(cilen != CILEN_VJ && cilen != CILEN_COMPRESS))
+		goto bad;
+	    no.neg_vj = 1;
+	    break;
+	case CI_ADDRS:
+	    if ((go->neg_addr && go->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 && go->accept_local)
+		try.ouraddr = ciaddr1;
+	    GETLONG(l, p);
+	    ciaddr2 = htonl(l);
+	    if (ciaddr2 && go->accept_remote)
+		try.hisaddr = ciaddr2;
+	    no.old_addrs = 1;
+	    break;
+	case CI_ADDR:
+	    if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR)
+		goto bad;
+	    try.old_addrs = 0;
+	    GETLONG(l, p);
+	    ciaddr1 = htonl(l);
+	    if (ciaddr1 && go->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->state != OPENED)
+	*go = try;
+
+    return 1;
+
+bad:
+    IPCPDEBUG(("ipcp_nakci: received bad Nak!"));
+    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 = &ipcp_gotoptions[f->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->neg && \
+	len >= (cilen = old? CILEN_ADDRS: CILEN_ADDR) && \
+	p[1] == cilen && \
+	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->neg && \
+	p[1] == (old? CILEN_COMPRESS : CILEN_VJ) && \
+	len >= p[1] && \
+	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->neg && \
+	((cilen = p[1]) == CILEN_ADDR) && \
+	len >= cilen && \
+	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->old_addrs? CI_ADDRS: CI_ADDR), neg_addr,
+	      go->old_addrs, go->ouraddr, go->hisaddr);
+
+    REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj,
+	    go->maxslotindex, go->cflag);
+
+    REJCIDNS(CI_MS_DNS1, req_dns1, go->dnsaddr[0]);
+
+    REJCIDNS(CI_MS_DNS2, req_dns2, go->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->state != OPENED)
+	*go = try;
+    return 1;
+
+bad:
+    IPCPDEBUG(("ipcp_rejci: received bad Reject!"));
+    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 = &ipcp_wantoptions[f->unit];
+    ipcp_options *ho = &ipcp_hisoptions[f->unit];
+    ipcp_options *ao = &ipcp_allowoptions[f->unit];
+    ipcp_options *go = &ipcp_gotoptions[f->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 < 2 ||			/* Not enough data for CI header or */
+	    p[1] < 2 ||			/*  CI length too small or */
+	    p[1] > l) {			/*  CI length too big? */
+	    IPCPDEBUG(("ipcp_reqci: bad CI length!"));
+	    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->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->hisaddr
+		&& (ciaddr1 == 0 || !wo->accept_remote)) {
+		orc = CONFNAK;
+		if (!reject_if_disagree) {
+		    DECPTR(sizeof(u_int32_t), p);
+		    tl = ntohl(wo->hisaddr);
+		    PUTLONG(tl, p);
+		}
+	    } else if (ciaddr1 == 0 && wo->hisaddr == 0) {
+		/*
+		 * If neither we nor he knows his address, reject the option.
+		 */
+		orc = CONFREJ;
+		wo->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->ouraddr) {
+		if (ciaddr2 == 0 || !wo->accept_local) {
+		    orc = CONFNAK;
+		    if (!reject_if_disagree) {
+			DECPTR(sizeof(u_int32_t), p);
+			tl = ntohl(wo->ouraddr);
+			PUTLONG(tl, p);
+		    }
+		} else {
+		    go->ouraddr = ciaddr2;	/* accept peer's idea */
+		}
+	    }
+
+	    ho->neg_addr = 1;
+	    ho->old_addrs = 1;
+	    ho->hisaddr = ciaddr1;
+	    ho->ouraddr = ciaddr2;
+	    break;
+
+	case CI_ADDR:
+	    if (!ao->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->hisaddr
+		&& (ciaddr1 == 0 || !wo->accept_remote)) {
+		orc = CONFNAK;
+		if (!reject_if_disagree) {
+		    DECPTR(sizeof(u_int32_t), p);
+		    tl = ntohl(wo->hisaddr);
+		    PUTLONG(tl, p);
+		}
+	    } else if (ciaddr1 == 0 && wo->hisaddr == 0) {
+		/*
+		 * Don't ACK an address of 0.0.0.0 - reject it instead.
+		 */
+		orc = CONFREJ;
+		wo->req_addr = 0;	/* don't NAK with 0.0.0.0 later */
+		break;
+	    }
+	
+	    ho->neg_addr = 1;
+	    ho->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->dnsaddr[d] == 0 ||
+		cilen != CILEN_ADDR) {	/* Check CI length */
+		orc = CONFREJ;		/* Reject CI */
+		break;
+	    }
+	    GETLONG(tl, p);
+	    if (htonl(tl) != ao->dnsaddr[d]) {
+                DECPTR(sizeof(u_int32_t), p);
+		tl = ntohl(ao->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->winsaddr[d] == 0 ||
+		cilen != CILEN_ADDR) {	/* Check CI length */
+		orc = CONFREJ;		/* Reject CI */
+		break;
+	    }
+	    GETLONG(tl, p);
+	    if (htonl(tl) != ao->winsaddr[d]) {
+                DECPTR(sizeof(u_int32_t), p);
+		tl = ntohl(ao->winsaddr[d]);
+		PUTLONG(tl, p);
+		orc = CONFNAK;
+            }
+            break;
+	
+	case CI_COMPRESSTYPE:
+	    if (!ao->neg_vj ||
+		(cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) {
+		orc = CONFREJ;
+		break;
+	    }
+	    GETSHORT(cishort, p);
+
+	    if (!(cishort == IPCP_VJ_COMP ||
+		  (cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) {
+		orc = CONFREJ;
+		break;
+	    }
+
+	    ho->neg_vj = 1;
+	    ho->vj_protocol = cishort;
+	    if (cilen == CILEN_VJ) {
+		GETCHAR(maxslotindex, p);
+		if (maxslotindex > ao->maxslotindex) { 
+		    orc = CONFNAK;
+		    if (!reject_if_disagree){
+			DECPTR(1, p);
+			PUTCHAR(ao->maxslotindex, p);
+		    }
+		}
+		GETCHAR(cflag, p);
+		if (cflag && !ao->cflag) {
+		    orc = CONFNAK;
+		    if (!reject_if_disagree){
+			DECPTR(1, p);
+			PUTCHAR(wo->cflag, p);
+		    }
+		}
+		ho->maxslotindex = maxslotindex;
+		ho->cflag = cflag;
+	    } else {
+		ho->old_vj = 1;
+		ho->maxslotindex = MAX_STATES - 1;
+		ho->cflag = 1;
+	    }
+	    break;
+
+	default:
+	    orc = CONFREJ;
+	    break;
+	}
+endswitch:
+	if (orc == CONFACK &&		/* 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 &&		/* 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 && !ho->neg_addr &&
+	wo->req_addr && !reject_if_disagree) {
+	if (rc == CONFACK) {
+	    rc = CONFNAK;
+	    ucp = inp;			/* reset pointer */
+	    wo->req_addr = 0;		/* don't ask again */
+	}
+	PUTCHAR(CI_ADDR, ucp);
+	PUTCHAR(CILEN_ADDR, ucp);
+	tl = ntohl(wo->hisaddr);
+	PUTLONG(tl, ucp);
+    }
+
+    *len = ucp - inp;			/* Compute output length */
+    IPCPDEBUG(("ipcp: returning Configure-%s", 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 = &ipcp_wantoptions[0];
+
+    /*
+     * Default our local IP address based on our hostname.
+     * If local IP address already given, don't bother.
+     */
+    if (wo->ouraddr == 0 && !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->accept_local = 1;	/* don't insist on this default value */
+	if ((hp = gethostbyname(hostname)) != NULL) {
+	    local = *(u_int32_t *)hp->h_addr;
+	    if (local != 0 && !bad_ip_adrs(local))
+		wo->ouraddr = local;
+	}
+    }
+    ask_for_local = wo->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 = &ipcp_wantoptions[u];
+
+    if (wo->hisaddr == 0) {
+	/* make up an arbitrary address for the peer */
+	wo->hisaddr = htonl(0x0a707070 + ifunit);
+	wo->accept_remote = 1;
+    }
+    if (wo->ouraddr == 0) {
+	/* make up an arbitrary address for us */
+	wo->ouraddr = htonl(0x0a404040 + ifunit);
+	wo->accept_local = 1;
+	ask_for_local = 0;	/* don't tell the peer this address */
+    }
+    if (!sifaddr(u, wo->ouraddr, wo->hisaddr, GetMask(wo->ouraddr)))
+	return 0;
+    if (!sifup(u))
+	return 0;
+    if (!sifnpmode(u, PPP_IP, NPMODE_QUEUE))
+	return 0;
+    if (wo->default_route)
+	if (sifdefaultroute(u, wo->ouraddr, wo->hisaddr))
+	    default_route_set[u] = 1;
+    if (wo->proxy_arp)
+	if (sifproxyarp(u, wo->hisaddr))
+	    proxy_arp_set[u] = 1;
+
+    notice("local  IP address %I", wo->ouraddr);
+    notice("remote IP address %I", wo->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 = &ipcp_hisoptions[f->unit];
+    ipcp_options *go = &ipcp_gotoptions[f->unit];
+    ipcp_options *wo = &ipcp_wantoptions[f->unit];
+
+    IPCPDEBUG(("ipcp: up"));
+
+    /*
+     * We must have a non-zero IP address for both ends of the link.
+     */
+    if (!ho->neg_addr)
+	ho->hisaddr = wo->hisaddr;
+
+    if (go->ouraddr == 0) {
+	error("Could not determine local IP address");
+	ipcp_close(f->unit, "Could not determine local IP address");
+	return;
+    }
+    if (ho->hisaddr == 0) {
+	ho->hisaddr = htonl(0x0a404040 + ifunit);
+	warn("Could not determine remote IP address: defaulting to %I",
+	     ho->hisaddr);
+    }
+    script_setenv("IPLOCAL", ip_ntoa(go->ouraddr), 0);
+    script_setenv("IPREMOTE", ip_ntoa(ho->hisaddr), 1);
+
+    if (usepeerdns && (go->dnsaddr[0] || go->dnsaddr[1])) {
+	script_setenv("USEPEERDNS", "1", 0);
+	if (go->dnsaddr[0])
+	    script_setenv("DNS1", ip_ntoa(go->dnsaddr[0]), 0);
+	if (go->dnsaddr[1])
+	    script_setenv("DNS2", ip_ntoa(go->dnsaddr[1]), 0);
+	create_resolv(go->dnsaddr[0], go->dnsaddr[1]);
+    }
+
+    /*
+     * Check that the peer is allowed to use the IP address it wants.
+     */
+    if (!auth_ip_addr(f->unit, ho->hisaddr)) {
+	error("Peer is not authorized to use remote address %I", ho->hisaddr);
+	ipcp_close(f->unit, "Unauthorized remote IP address");
+	return;
+    }
+
+    /* set tcp compression */
+    sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->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->ouraddr != wo->ouraddr || ho->hisaddr != wo->hisaddr) {
+	    ipcp_clear_addrs(f->unit, wo->ouraddr, wo->hisaddr);
+	    if (go->ouraddr != wo->ouraddr) {
+		warn("Local IP address changed to %I", go->ouraddr);
+		script_setenv("OLDIPLOCAL", ip_ntoa(wo->ouraddr), 0);
+		wo->ouraddr = go->ouraddr;
+	    } else
+		script_unsetenv("OLDIPLOCAL");
+	    if (ho->hisaddr != wo->hisaddr) {
+		warn("Remote IP address changed to %I", ho->hisaddr);
+		script_setenv("OLDIPREMOTE", ip_ntoa(wo->hisaddr), 0);
+		wo->hisaddr = ho->hisaddr;
+	    } else
+		script_unsetenv("OLDIPREMOTE");
+
+	    /* Set the interface to the new addresses */
+	    mask = GetMask(go->ouraddr);
+	    if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
+		if (debug)
+		    warn("Interface configuration failed");
+		ipcp_close(f->unit, "Interface configuration failed");
+		return;
+	    }
+
+	    /* assign a default route through the interface if required */
+	    if (ipcp_wantoptions[f->unit].default_route) 
+		if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr))
+		    default_route_set[f->unit] = 1;
+
+	    /* Make a proxy ARP entry if requested. */
+	    if (ipcp_wantoptions[f->unit].proxy_arp)
+		if (sifproxyarp(f->unit, ho->hisaddr))
+		    proxy_arp_set[f->unit] = 1;
+
+	}
+	demand_rexmit(PPP_IP);
+	sifnpmode(f->unit, PPP_IP, NPMODE_PASS);
+
+    } else {
+	/*
+	 * Set IP addresses and (if specified) netmask.
+	 */
+	mask = GetMask(go->ouraddr);
+
+#if !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
+	if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
+	    if (debug)
+		warn("Interface configuration failed");
+	    ipcp_close(f->unit, "Interface configuration failed");
+	    return;
+	}
+#endif
+
+	/* bring the interface up for IP */
+	if (!sifup(f->unit)) {
+	    if (debug)
+		warn("Interface failed to come up");
+	    ipcp_close(f->unit, "Interface configuration failed");
+	    return;
+	}
+
+#if (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
+	if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
+	    if (debug)
+		warn("Interface configuration failed");
+	    ipcp_close(f->unit, "Interface configuration failed");
+	    return;
+	}
+#endif
+	sifnpmode(f->unit, PPP_IP, NPMODE_PASS);
+
+	/* assign a default route through the interface if required */
+	if (ipcp_wantoptions[f->unit].default_route) 
+	    if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr))
+		default_route_set[f->unit] = 1;
+
+	/* Make a proxy ARP entry if requested. */
+	if (ipcp_wantoptions[f->unit].proxy_arp)
+	    if (sifproxyarp(f->unit, ho->hisaddr))
+		proxy_arp_set[f->unit] = 1;
+
+	ipcp_wantoptions[0].ouraddr = go->ouraddr;
+
+	notice("local  IP address %I", go->ouraddr);
+	notice("remote IP address %I", ho->hisaddr);
+	if (go->dnsaddr[0])
+	    notice("primary   DNS address %I", go->dnsaddr[0]);
+	if (go->dnsaddr[1])
+	    notice("secondary DNS address %I", go->dnsaddr[1]);
+    }
+
+    np_up(f->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 && 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(("ipcp: down"));
+    /* XXX a bit IPv4-centric here, we only need to get the stats
+     * before the interface is marked down. */
+    update_link_stats(f->unit);
+    if (ip_down_hook)
+	ip_down_hook();
+    if (ipcp_is_up) {
+	ipcp_is_up = 0;
+	np_down(f->unit, PPP_IP);
+    }
+    sifvjcomp(f->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->unit, PPP_IP, NPMODE_QUEUE);
+    } else {
+	sifnpmode(f->unit, PPP_IP, NPMODE_DROP);
+	sifdown(f->unit);
+	ipcp_clear_addrs(f->unit, ipcp_gotoptions[f->unit].ouraddr,
+			 ipcp_hisoptions[f->unit].hisaddr);
+    }
+
+    /* Execute the ip-down script */
+    if (ipcp_script_state == s_up && 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->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), "%d", baud_rate);
+    slprintf(strlocal, sizeof(strlocal), "%I", ipcp_gotoptions[0].ouraddr);
+    slprintf(strremote, sizeof(strremote), "%I", 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, "w");
+    if (f == NULL) {
+	error("Failed to create %s: %m", _PATH_RESOLV);
+	return;
+    }
+
+    if (peerdns1)
+	fprintf(f, "nameserver %s\n", ip_ntoa(peerdns1));
+
+    if (peerdns2)
+	fprintf(f, "nameserver %s\n", ip_ntoa(peerdns2));
+
+    if (ferror(f))
+	error("Write failed to %s: %m", _PATH_RESOLV);
+
+    fclose(f);
+}
+
+/*
+ * ipcp_printpkt - print the contents of an IPCP packet.
+ */
+static char *ipcp_codenames[] = {
+    "ConfReq", "ConfAck", "ConfNak", "ConfRej",
+    "TermReq", "TermAck", "CodeRej"
+};
+
+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 < HEADERLEN)
+	return 0;
+    pstart = p;
+    GETCHAR(code, p);
+    GETCHAR(id, p);
+    GETSHORT(len, p);
+    if (len < HEADERLEN || len > plen)
+	return 0;
+
+    if (code >= 1 && code <= sizeof(ipcp_codenames) / sizeof(char *))
+	printer(arg, " %s", ipcp_codenames[code-1]);
+    else
+	printer(arg, " code=0x%x", code);
+    printer(arg, " id=0x%x", id);
+    len -= HEADERLEN;
+    switch (code) {
+    case CONFREQ:
+    case CONFACK:
+    case CONFNAK:
+    case CONFREJ:
+	/* print option list */
+	while (len >= 2) {
+	    GETCHAR(code, p);
+	    GETCHAR(olen, p);
+	    p -= 2;
+	    if (olen < 2 || olen > len) {
+		break;
+	    }
+	    printer(arg, " <");
+	    len -= olen;
+	    optend = p + olen;
+	    switch (code) {
+	    case CI_ADDRS:
+		if (olen == CILEN_ADDRS) {
+		    p += 2;
+		    GETLONG(cilong, p);
+		    printer(arg, "addrs %I", htonl(cilong));
+		    GETLONG(cilong, p);
+		    printer(arg, " %I", htonl(cilong));
+		}
+		break;
+	    case CI_COMPRESSTYPE:
+		if (olen >= CILEN_COMPRESS) {
+		    p += 2;
+		    GETSHORT(cishort, p);
+		    printer(arg, "compress ");
+		    switch (cishort) {
+		    case IPCP_VJ_COMP:
+			printer(arg, "VJ");
+			break;
+		    case IPCP_VJ_COMP_OLD:
+			printer(arg, "old-VJ");
+			break;
+		    default:
+			printer(arg, "0x%x", cishort);
+		    }
+		}
+		break;
+	    case CI_ADDR:
+		if (olen == CILEN_ADDR) {
+		    p += 2;
+		    GETLONG(cilong, p);
+		    printer(arg, "addr %I", htonl(cilong));
+		}
+		break;
+	    case CI_MS_DNS1:
+	    case CI_MS_DNS2:
+	        p += 2;
+		GETLONG(cilong, p);
+		printer(arg, "ms-dns%d %I", code - CI_MS_DNS1 + 1,
+			htonl(cilong));
+		break;
+	    case CI_MS_WINS1:
+	    case CI_MS_WINS2:
+	        p += 2;
+		GETLONG(cilong, p);
+		printer(arg, "ms-wins %I", htonl(cilong));
+		break;
+	    }
+	    while (p < optend) {
+		GETCHAR(code, p);
+		printer(arg, " %.2x", code);
+	    }
+	    printer(arg, ">");
+	}
+	break;
+
+    case TERMACK:
+    case TERMREQ:
+	if (len > 0 && *p >= ' ' && *p < 0x7f) {
+	    printer(arg, " ");
+	    print_string((char *)p, len, printer, arg);
+	    p += len;
+	    len = 0;
+	}
+	break;
+    }
+
+    /* print the rest of the bytes in the packet */
+    for (; len > 0; --len) {
+	GETCHAR(code, p);
+	printer(arg, " %.2x", 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] << 8) + (x)[1])
+#define get_iphl(x)	(((unsigned char *)(x))[0] & 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] >> 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 < IP_HDRLEN)
+	return 0;
+    if ((get_ipoff(pkt) & IP_OFFMASK) != 0)
+	return 0;
+    if (get_ipproto(pkt) != IPPROTO_TCP)
+	return 1;
+    hlen = get_iphl(pkt) * 4;
+    if (len < hlen + TCP_HDRLEN)
+	return 0;
+    tcp = pkt + hlen;
+    if ((get_tcpflags(tcp) & TH_FIN) != 0 && 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	/* "old" mode (option # = 0x0037) */
+#define IPCP_VJMODE_RFC1172 2	/* "old-rfc"mode (option # = 0x002d) */
+#define IPCP_VJMODE_RFC1332 3	/* "new-rfc"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	/* "old" (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 <Tommi.Komulainen at iki.fi>
+
+    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 Francis.Dupont at inria.fr, INRIA Rocquencourt,
+    Alain.Durand at imag.fr, IMAG,
+    Jean-Luc.Richier at imag.fr, IMAG-LSR.
+
+    Copyright (c) 1998, 1999 Francis.Dupont at inria.fr, GIE DYADE,
+    Alain.Durand at imag.fr, IMAG,
+    Jean-Luc.Richier at imag.fr, IMAG-LSR.
+
+    Ce travail a été fait au sein du GIE DYADE (Groupement d'Intérêt
+    Économique ayant pour membres BULL S.A. et l'INRIA).
+
+    Ce logiciel informatique est disponible aux conditions
+    usuelles dans la recherche, c'est-à-dire qu'il peut
+    être utilisé, copié, modifié, distribué à l'unique
+    condition que ce texte soit conservé 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é à l'élaboration de ce logiciel ne peut
+    être utilisé sans son accord préalable explicite.
+
+    Ce logiciel est fourni tel quel sans aucune garantie,
+    support ou responsabilité d'aucune sorte.
+    Ce logiciel est dérivé de sources d'origine
+    "University of California at Berkeley" et
+    "Digital Equipment Corporation" couvertes par des copyrights.
+
+    L'Institut d'Informatique et de Mathématiques Appliquées de Grenoble (IMAG)
+    est une fédération d'unités mixtes de recherche du CNRS, de l'Institut National
+    Polytechnique de Grenoble et de l'Université Joseph Fourier regroupant
+    sept laboratoires dont le laboratoire Logiciels, Systèmes, Réseaux (LSR).
+
+    This work has been done in the context of GIE DYADE (joint R & D venture
+    between BULL S.A. and INRIA).
+
+    This software is available with usual "research" 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 "as is" without any
+    warranties, support or liabilities of any kind.
+    This software is derived from source code from
+    "University of California at Berkeley" and
+    "Digital Equipment Corporation" 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	"$Id: ipv6cp.c 215411 2007-04-25 12:26:16Z pixel $"
+
+/*
+ * TODO: 
+ *
+ * Proxy Neighbour Discovery.
+ *
+ * Better defines for selecting the ordering of
+ *   interface up / set address. (currently checks for __linux__,
+ *   since SVR4 && (SNI || __USLC__) didn't work properly)
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "pppd.h"
+#include "fsm.h"
+#include "ipcp.h"
+#include "ipv6cp.h"
+#include "magic.h"
+#include "pathnames.h"
+
+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 */
+    "IPV6CP"			/* 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[] = {
+    { "ipv6", o_special, (void *)setifaceid,
+      "Set interface identifiers for IPV6",
+      OPT_A2PRINTER, (void *)printifaceid },
+
+    { "+ipv6", o_bool, &ipv6cp_protent.enabled_flag,
+      "Enable IPv6 and IPv6CP", OPT_PRIO | 1 },
+    { "noipv6", o_bool, &ipv6cp_protent.enabled_flag,
+      "Disable IPv6 and IPv6CP", OPT_PRIOSUB },
+    { "-ipv6", o_bool, &ipv6cp_protent.enabled_flag,
+      "Disable IPv6 and IPv6CP", OPT_PRIOSUB | OPT_ALIAS },
+
+    { "ipv6cp-accept-local", o_bool, &ipv6cp_allowoptions[0].accept_local,
+      "Accept peer's interface identifier for us", 1 },
+
+    { "ipv6cp-use-ipaddr", o_bool, &ipv6cp_allowoptions[0].use_ip,
+      "Use (default) IPv4 address as interface identifier", 1 },
+
+#if defined(SOL2)
+    { "ipv6cp-use-persistent", o_bool, &ipv6cp_wantoptions[0].use_persistent,
+      "Use uniquely-available persistent value for link local address", 1 },
+#endif /* defined(SOL2) */
+
+    { "ipv6cp-restart", o_int, &ipv6cp_fsm[0].timeouttime,
+      "Set timeout for IPv6CP", OPT_PRIO },
+    { "ipv6cp-max-terminate", o_int, &ipv6cp_fsm[0].maxtermtransmits,
+      "Set max #xmits for term-reqs", OPT_PRIO },
+    { "ipv6cp-max-configure", o_int, &ipv6cp_fsm[0].maxconfreqtransmits,
+      "Set max #xmits for conf-reqs", OPT_PRIO },
+    { "ipv6cp-max-failure", o_int, &ipv6cp_fsm[0].maxnakloops,
+      "Set max #conf-naks for IPv6CP", 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,
+    "IPV6CP",
+    "IPV6",
+    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 ? "ACK" : \
+			 (x) == CONFNAK ? "NAK" : "REJ")
+
+/*
+ * 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 = &ipv6cp_wantoptions[0];
+    struct in6_addr addr;
+    static int prio_local, prio_remote;
+
+#define VALIDID(a) ( (((a).s6_addr32[0] == 0) && ((a).s6_addr32[1] == 0)) && \
+			(((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, &addr) == 0 || !VALIDID(addr)) {
+	    option_error("Illegal interface identifier (local): %s", arg);
+	    return 0;
+	}
+
+	if (option_priority >= prio_local) {
+	    eui64_copy(addr.s6_addr32[2], wo->ourid);
+	    wo->opt_local = 1;
+	    prio_local = option_priority;
+	}
+	*comma = c;
+    }
+    
+    /*
+     * If comma last character, the no remote identifier
+     */
+    if (*comma != 0 && *++comma != '\0') {
+	if (inet_pton(AF_INET6, comma, &addr) == 0 || !VALIDID(addr)) {
+	    option_error("Illegal interface identifier (remote): %s", comma);
+	    return 0;
+	}
+	if (option_priority >= prio_remote) {
+	    eui64_copy(addr.s6_addr32[2], wo->hisid);
+	    wo->opt_remote = 1;
+	    prio_remote = option_priority;
+	}
+    }
+
+    if (override_value("+ipv6", 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 = &ipv6cp_wantoptions[0];
+
+	if (wo->opt_local)
+		printer(arg, "%s", llv6_ntoa(wo->ourid));
+	printer(arg, ",");
+	if (wo->opt_remote)
+		printer(arg, "%s", llv6_ntoa(wo->hisid));
+}
+
+/*
+ * Make a string representation of a network address.
+ */
+char *
+llv6_ntoa(ifaceid)
+    eui64_t ifaceid;
+{
+    static char b[64];
+
+    sprintf(b, "fe80::%s", eui64_ntoa(ifaceid));
+    return b;
+}
+
+
+/*
+ * ipv6cp_init - Initialize IPV6CP.
+ */
+static void
+ipv6cp_init(unit)
+    int unit;
+{
+    fsm *f = &ipv6cp_fsm[unit];
+    ipv6cp_options *wo = &ipv6cp_wantoptions[unit];
+    ipv6cp_options *ao = &ipv6cp_allowoptions[unit];
+
+    f->unit = unit;
+    f->protocol = PPP_IPV6CP;
+    f->callbacks = &ipv6cp_callbacks;
+    fsm_init(&ipv6cp_fsm[unit]);
+
+    memset(wo, 0, sizeof(*wo));
+    memset(ao, 0, sizeof(*ao));
+
+    wo->accept_local = 1;
+    wo->neg_ifaceid = 1;
+    ao->neg_ifaceid = 1;
+
+#ifdef IPV6CP_COMP
+    wo->neg_vj = 1;
+    ao->neg_vj = 1;
+    wo->vj_protocol = IPV6CP_COMP;
+#endif
+
+}
+
+
+/*
+ * ipv6cp_open - IPV6CP is allowed to come up.
+ */
+static void
+ipv6cp_open(unit)
+    int unit;
+{
+    fsm_open(&ipv6cp_fsm[unit]);
+}
+
+
+/*
+ * ipv6cp_close - Take IPV6CP down.
+ */
+static void
+ipv6cp_close(unit, reason)
+    int unit;
+    char *reason;
+{
+    fsm_close(&ipv6cp_fsm[unit], reason);
+}
+
+
+/*
+ * ipv6cp_lowerup - The lower layer is up.
+ */
+static void
+ipv6cp_lowerup(unit)
+    int unit;
+{
+    fsm_lowerup(&ipv6cp_fsm[unit]);
+}
+
+
+/*
+ * ipv6cp_lowerdown - The lower layer is down.
+ */
+static void
+ipv6cp_lowerdown(unit)
+    int unit;
+{
+    fsm_lowerdown(&ipv6cp_fsm[unit]);
+}
+
+
+/*
+ * ipv6cp_input - Input IPV6CP packet.
+ */
+static void
+ipv6cp_input(unit, p, len)
+    int unit;
+    u_char *p;
+    int len;
+{
+    fsm_input(&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(&ipv6cp_fsm[unit]);
+}
+
+
+/*
+ * ipv6cp_resetci - Reset our CI.
+ */
+static void
+ipv6cp_resetci(f)
+    fsm *f;
+{
+    ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
+    ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
+
+    wo->req_ifaceid = wo->neg_ifaceid && ipv6cp_allowoptions[f->unit].neg_ifaceid;
+    
+    if (!wo->opt_local) {
+	eui64_magic_nz(wo->ourid);
+    }
+    
+    *go = *wo;
+    eui64_zero(go->hisid);	/* last proposed interface identifier */
+}
+
+
+/*
+ * ipv6cp_cilen - Return length of our CI.
+ */
+static int
+ipv6cp_cilen(f)
+    fsm *f;
+{
+    ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
+
+#define LENCIVJ(neg)		(neg ? CILEN_COMPRESS : 0)
+#define LENCIIFACEID(neg)	(neg ? CILEN_IFACEID : 0)
+
+    return (LENCIIFACEID(go->neg_ifaceid) +
+	    LENCIVJ(go->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 = &ipv6cp_gotoptions[f->unit];
+    int len = *lenp;
+
+#define ADDCIVJ(opt, neg, val) \
+    if (neg) { \
+	int vjlen = CILEN_COMPRESS; \
+	if (len >= 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 >= idlen) { \
+	    PUTCHAR(opt, ucp); \
+	    PUTCHAR(idlen, ucp); \
+	    eui64_put(val1, ucp); \
+	    len -= idlen; \
+	} else \
+	    neg = 0; \
+    }
+
+    ADDCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid);
+
+    ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->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 = &ipv6cp_gotoptions[f->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) < 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) < 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->neg_ifaceid, go->ourid);
+
+    ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol);
+
+    /*
+     * If there are any remaining CIs, then this packet is bad.
+     */
+    if (len != 0)
+	goto bad;
+    return (1);
+
+bad:
+    IPV6CPDEBUG(("ipv6cp_ackci: received bad Ack!"));
+    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 = &ipv6cp_gotoptions[f->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(&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->neg && \
+	len >= (cilen = CILEN_IFACEID) && \
+	p[1] == cilen && \
+	p[0] == opt) { \
+	len -= cilen; \
+	INCPTR(2, p); \
+	eui64_get(ifaceid, p); \
+	no.neg = 1; \
+	code \
+    }
+
+#define NAKCIVJ(opt, neg, code) \
+    if (go->neg && \
+	((cilen = p[1]) == CILEN_COMPRESS) && \
+	len >= cilen && \
+	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->accept_local) {
+		  while (eui64_iszero(ifaceid) || 
+			 eui64_equals(ifaceid, go->hisid)) /* bad luck */
+		      eui64_magic(ifaceid);
+		  try.ourid = ifaceid;
+		  IPV6CPDEBUG(("local LL address %s", 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 > CILEN_VOID) {
+	GETCHAR(citype, p);
+	GETCHAR(cilen, p);
+	if( (len -= cilen) < 0 )
+	    goto bad;
+	next = p + cilen - 2;
+
+	switch (citype) {
+	case CI_COMPRESSTYPE:
+	    if (go->neg_vj || no.neg_vj ||
+		(cilen != CILEN_COMPRESS))
+		goto bad;
+	    no.neg_vj = 1;
+	    break;
+	case CI_IFACEID:
+	    if (go->neg_ifaceid || no.neg_ifaceid || cilen != CILEN_IFACEID)
+		goto bad;
+	    try.neg_ifaceid = 1;
+	    eui64_get(ifaceid, p);
+	    if (go->accept_local) {
+		while (eui64_iszero(ifaceid) || 
+		       eui64_equals(ifaceid, go->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->state != OPENED)
+	*go = try;
+
+    return 1;
+
+bad:
+    IPV6CPDEBUG(("ipv6cp_nakci: received bad Nak!"));
+    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 = &ipv6cp_gotoptions[f->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->neg && \
+	len >= (cilen = CILEN_IFACEID) && \
+	p[1] == cilen && \
+	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->neg && \
+	p[1] == CILEN_COMPRESS && \
+	len >= p[1] && \
+	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->ourid);
+
+    REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->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->state != OPENED)
+	*go = try;
+    return 1;
+
+bad:
+    IPV6CPDEBUG(("ipv6cp_rejci: received bad Reject!"));
+    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 = &ipv6cp_wantoptions[f->unit];
+    ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit];
+    ipv6cp_options *ao = &ipv6cp_allowoptions[f->unit];
+    ipv6cp_options *go = &ipv6cp_gotoptions[f->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 < 2 ||			/* Not enough data for CI header or */
+	    p[1] < 2 ||			/*  CI length too small or */
+	    p[1] > l) {			/*  CI length too big? */
+	    IPV6CPDEBUG(("ipv6cp_reqci: bad CI length!"));
+	    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(("ipv6cp: received interface identifier "));
+
+	    if (!ao->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(("(%s)", llv6_ntoa(ifaceid)));
+	    if (eui64_iszero(ifaceid) && eui64_iszero(go->ourid)) {
+		orc = CONFREJ;		/* Reject CI */
+		break;
+	    }
+	    if (!eui64_iszero(wo->hisid) && 
+		!eui64_equals(ifaceid, wo->hisid) && 
+		eui64_iszero(go->hisid)) {
+		    
+		orc = CONFNAK;
+		ifaceid = wo->hisid;
+		go->hisid = ifaceid;
+		DECPTR(sizeof(ifaceid), p);
+		eui64_put(ifaceid, p);
+	    } else
+	    if (eui64_iszero(ifaceid) || eui64_equals(ifaceid, go->ourid)) {
+		orc = CONFNAK;
+		if (eui64_iszero(go->hisid))	/* first time, try option */
+		    ifaceid = wo->hisid;
+		while (eui64_iszero(ifaceid) || 
+		       eui64_equals(ifaceid, go->ourid)) /* bad luck */
+		    eui64_magic(ifaceid);
+		go->hisid = ifaceid;
+		DECPTR(sizeof(ifaceid), p);
+		eui64_put(ifaceid, p);
+	    }
+
+	    ho->neg_ifaceid = 1;
+	    ho->hisid = ifaceid;
+	    break;
+
+	case CI_COMPRESSTYPE:
+	    IPV6CPDEBUG(("ipv6cp: received COMPRESSTYPE "));
+	    if (!ao->neg_vj ||
+		(cilen != CILEN_COMPRESS)) {
+		orc = CONFREJ;
+		break;
+	    }
+	    GETSHORT(cishort, p);
+	    IPV6CPDEBUG(("(%d)", cishort));
+
+#ifdef IPV6CP_COMP
+	    if (!(cishort == IPV6CP_COMP)) {
+		orc = CONFREJ;
+		break;
+	    }
+
+	    ho->neg_vj = 1;
+	    ho->vj_protocol = cishort;
+	    break;
+#else
+	    orc = CONFREJ;
+	    break;
+#endif
+
+	default:
+	    orc = CONFREJ;
+	    break;
+	}
+
+endswitch:
+	IPV6CPDEBUG((" (%s)\n", CODENAME(orc)));
+
+	if (orc == CONFACK &&		/* 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 &&		/* 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 && !ho->neg_ifaceid &&
+	wo->req_ifaceid && !reject_if_disagree) {
+	if (rc == CONFACK) {
+	    rc = CONFNAK;
+	    ucp = inp;				/* reset pointer */
+	    wo->req_ifaceid = 0;		/* don't ask again */
+	}
+	PUTCHAR(CI_IFACEID, ucp);
+	PUTCHAR(CILEN_IFACEID, ucp);
+	eui64_put(wo->hisid, ucp);
+    }
+
+    *len = ucp - inp;			/* Compute output length */
+    IPV6CPDEBUG(("ipv6cp: returning Configure-%s", 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 = &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->use_persistent) && (!wo->opt_local) && (!wo->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(&wo->ourid)) {
+	    wo->opt_local = 1;
+	}
+    }
+#endif
+
+    if (!wo->opt_local) {	/* init interface identifier */
+	if (wo->use_ip && eui64_iszero(wo->ourid)) {
+	    eui64_setlo32(wo->ourid, ntohl(ipcp_wantoptions[0].ouraddr));
+	    if (!eui64_iszero(wo->ourid))
+		wo->opt_local = 1;
+	}
+	
+	while (eui64_iszero(wo->ourid))
+	    eui64_magic(wo->ourid);
+    }
+
+    if (!wo->opt_remote) {
+	if (wo->use_ip && eui64_iszero(wo->hisid)) {
+	    eui64_setlo32(wo->hisid, ntohl(ipcp_wantoptions[0].hisaddr));
+	    if (!eui64_iszero(wo->hisid))
+		wo->opt_remote = 1;
+	}
+    }
+
+    if (demand && (eui64_iszero(wo->ourid) || eui64_iszero(wo->hisid))) {
+	option_error("local/remote LL address required for demand-dialling\n");
+	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 = &ipv6cp_wantoptions[u];
+
+#if defined(__linux__) || defined(SOL2) || (defined(SVR4) && (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->ourid, wo->hisid))
+	return 0;
+#if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
+    if (!sifup(u))
+	return 0;
+#endif
+    if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE))
+	return 0;
+
+    notice("ipv6_demand_conf");
+    notice("local  LL address %s", llv6_ntoa(wo->ourid));
+    notice("remote LL address %s", llv6_ntoa(wo->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 = &ipv6cp_hisoptions[f->unit];
+    ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
+    ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
+
+    IPV6CPDEBUG(("ipv6cp: up"));
+
+    /*
+     * We must have a non-zero LL address for both ends of the link.
+     */
+    if (!ho->neg_ifaceid)
+	ho->hisid = wo->hisid;
+
+    if(!no_ifaceid_neg) {
+	if (eui64_iszero(ho->hisid)) {
+	    error("Could not determine remote LL address");
+	    ipv6cp_close(f->unit, "Could not determine remote LL address");
+	    return;
+	}
+	if (eui64_iszero(go->ourid)) {
+	    error("Could not determine local LL address");
+	    ipv6cp_close(f->unit, "Could not determine local LL address");
+	    return;
+	}
+	if (eui64_equals(go->ourid, ho->hisid)) {
+	    error("local and remote LL addresses are equal");
+	    ipv6cp_close(f->unit, "local and remote LL addresses are equal");
+	    return;
+	}
+    }
+    script_setenv("LLLOCAL", llv6_ntoa(go->ourid), 0);
+    script_setenv("LLREMOTE", llv6_ntoa(ho->hisid), 0);
+
+#ifdef IPV6CP_COMP
+    /* set tcp compression */
+    sif6comp(f->unit, ho->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->ourid, wo->ourid) || 
+	    ! eui64_equals(ho->hisid, wo->hisid)) {
+	    if (! eui64_equals(go->ourid, wo->ourid))
+		warn("Local LL address changed to %s", 
+		     llv6_ntoa(go->ourid));
+	    if (! eui64_equals(ho->hisid, wo->hisid))
+		warn("Remote LL address changed to %s", 
+		     llv6_ntoa(ho->hisid));
+	    ipv6cp_clear_addrs(f->unit, go->ourid, ho->hisid);
+
+	    /* Set the interface to the new addresses */
+	    if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
+		if (debug)
+		    warn("sif6addr failed");
+		ipv6cp_close(f->unit, "Interface configuration failed");
+		return;
+	    }
+
+	}
+	demand_rexmit(PPP_IPV6);
+	sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
+
+    } else {
+	/*
+	 * Set LL addresses
+	 */
+#if !defined(__linux__) && !defined(SOL2) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
+	if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
+	    if (debug)
+		warn("sif6addr failed");
+	    ipv6cp_close(f->unit, "Interface configuration failed");
+	    return;
+	}
+#endif
+
+	/* bring the interface up for IPv6 */
+#if defined(SOL2)
+	if (!sif6up(f->unit)) {
+	    if (debug)
+		warn("sifup failed (IPV6)");
+	    ipv6cp_close(f->unit, "Interface configuration failed");
+	    return;
+	}
+#else
+	if (!sifup(f->unit)) {
+	    if (debug)
+		warn("sifup failed (IPV6)");
+	    ipv6cp_close(f->unit, "Interface configuration failed");
+	    return;
+	}
+#endif /* defined(SOL2) */
+
+#if defined(__linux__) || defined(SOL2) || (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
+	if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
+	    if (debug)
+		warn("sif6addr failed");
+	    ipv6cp_close(f->unit, "Interface configuration failed");
+	    return;
+	}
+#endif
+	sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
+
+	notice("local  LL address %s", llv6_ntoa(go->ourid));
+	notice("remote LL address %s", llv6_ntoa(ho->hisid));
+    }
+
+    np_up(f->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 && 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(("ipv6cp: down"));
+    update_link_stats(f->unit);
+    if (ipv6cp_is_up) {
+	ipv6cp_is_up = 0;
+	np_down(f->unit, PPP_IPV6);
+    }
+#ifdef IPV6CP_COMP
+    sif6comp(f->unit, 0);
+#endif
+
+    /*
+     * If we are doing dial-on-demand, set the interface
+     * to queue up outgoing packets (for now).
+     */
+    if (demand) {
+	sifnpmode(f->unit, PPP_IPV6, NPMODE_QUEUE);
+    } else {
+	sifnpmode(f->unit, PPP_IPV6, NPMODE_DROP);
+#if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC)))
+#if defined(SOL2)
+	sif6down(f->unit);
+#else
+	sifdown(f->unit);
+#endif /* defined(SOL2) */
+#endif
+	ipv6cp_clear_addrs(f->unit, 
+			   ipv6cp_gotoptions[f->unit].ourid,
+			   ipv6cp_hisoptions[f->unit].hisid);
+#if defined(__linux__) || (defined(SVR4) && (defined(SNI) || defined(__USLC)))
+	sifdown(f->unit);
+#endif
+    }
+
+    /* Execute the ipv6-down script */
+    if (ipv6cp_script_state == s_up && 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->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, "%d", 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[] = {
+    "ConfReq", "ConfAck", "ConfNak", "ConfRej",
+    "TermReq", "TermAck", "CodeRej"
+};
+
+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 < HEADERLEN)
+	return 0;
+    pstart = p;
+    GETCHAR(code, p);
+    GETCHAR(id, p);
+    GETSHORT(len, p);
+    if (len < HEADERLEN || len > plen)
+	return 0;
+
+    if (code >= 1 && code <= sizeof(ipv6cp_codenames) / sizeof(char *))
+	printer(arg, " %s", ipv6cp_codenames[code-1]);
+    else
+	printer(arg, " code=0x%x", code);
+    printer(arg, " id=0x%x", id);
+    len -= HEADERLEN;
+    switch (code) {
+    case CONFREQ:
+    case CONFACK:
+    case CONFNAK:
+    case CONFREJ:
+	/* print option list */
+	while (len >= 2) {
+	    GETCHAR(code, p);
+	    GETCHAR(olen, p);
+	    p -= 2;
+	    if (olen < 2 || olen > len) {
+		break;
+	    }
+	    printer(arg, " <");
+	    len -= olen;
+	    optend = p + olen;
+	    switch (code) {
+	    case CI_COMPRESSTYPE:
+		if (olen >= CILEN_COMPRESS) {
+		    p += 2;
+		    GETSHORT(cishort, p);
+		    printer(arg, "compress ");
+		    printer(arg, "0x%x", cishort);
+		}
+		break;
+	    case CI_IFACEID:
+		if (olen == CILEN_IFACEID) {
+		    p += 2;
+		    eui64_get(ifaceid, p);
+		    printer(arg, "addr %s", llv6_ntoa(ifaceid));
+		}
+		break;
+	    }
+	    while (p < optend) {
+		GETCHAR(code, p);
+		printer(arg, " %.2x", code);
+	    }
+	    printer(arg, ">");
+	}
+	break;
+
+    case TERMACK:
+    case TERMREQ:
+	if (len > 0 && *p >= ' ' && *p < 0x7f) {
+	    printer(arg, " ");
+	    print_string((char *)p, len, printer, arg);
+	    p += len;
+	    len = 0;
+	}
+	break;
+    }
+
+    /* print the rest of the bytes in the packet */
+    for (; len > 0; --len) {
+	GETCHAR(code, p);
+	printer(arg, " %.2x", 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] >> 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 < IP6_HDRLEN)
+	return 0;
+    if (get_ip6nh(pkt) == IP6_NHDR_FRAG)
+	return 0;
+    if (get_ip6nh(pkt) != IPPROTO_TCP)
+	return 1;
+    if (len < IP6_HDRLEN + TCP_HDRLEN)
+	return 0;
+    tcp = pkt + IP6_HDRLEN;
+    if ((get_tcpflags(tcp) & TH_FIN) != 0 && 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 <Tommi.Komulainen at iki.fi>
+
+    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 Francis.Dupont at inria.fr, INRIA Rocquencourt,
+    Alain.Durand at imag.fr, IMAG,
+    Jean-Luc.Richier at imag.fr, IMAG-LSR.
+
+    Copyright (c) 1998, 1999 Francis.Dupont at inria.fr, GIE DYADE,
+    Alain.Durand at imag.fr, IMAG,
+    Jean-Luc.Richier at imag.fr, IMAG-LSR.
+
+    Ce travail a été fait au sein du GIE DYADE (Groupement d'Intérêt
+    Économique ayant pour membres BULL S.A. et l'INRIA).
+
+    Ce logiciel informatique est disponible aux conditions
+    usuelles dans la recherche, c'est-à-dire qu'il peut
+    être utilisé, copié, modifié, distribué à l'unique
+    condition que ce texte soit conservé 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é à l'élaboration de ce logiciel ne peut
+    être utilisé sans son accord préalable explicite.
+
+    Ce logiciel est fourni tel quel sans aucune garantie,
+    support ou responsabilité d'aucune sorte.
+    Ce logiciel est dérivé de sources d'origine
+    "University of California at Berkeley" et
+    "Digital Equipment Corporation" couvertes par des copyrights.
+
+    L'Institut d'Informatique et de Mathématiques Appliquées de Grenoble (IMAG)
+    est une fédération d'unités mixtes de recherche du CNRS, de l'Institut National
+    Polytechnique de Grenoble et de l'Université Joseph Fourier regroupant
+    sept laboratoires dont le laboratoire Logiciels, Systèmes, Réseaux (LSR).
+
+    This work has been done in the context of GIE DYADE (joint R & D venture
+    between BULL S.A. and INRIA).
+
+    This software is available with usual "research" 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 "as is" without any
+    warranties, support or liabilities of any kind.
+    This software is derived from source code from
+    "University of California at Berkeley" and
+    "Digital Equipment Corporation" 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	"$Id: ipxcp.c 195720 2001-06-11 11:44:34Z gc $"
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include "pppd.h"
+#include "fsm.h"
+#include "ipxcp.h"
+#include "pathnames.h"
+#include "magic.h"
+
+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 (&ipxcp_wantoptions[0])
+#define ao (&ipxcp_allowoptions[0])
+#define go (&ipxcp_gotoptions[0])
+#define ho (&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 */
+    "IPXCP"			/* 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[] = {
+    { "ipx", o_bool, &ipxcp_protent.enabled_flag,
+      "Enable IPXCP (and IPX)", OPT_PRIO | 1 },
+    { "+ipx", o_bool, &ipxcp_protent.enabled_flag,
+      "Enable IPXCP (and IPX)", OPT_PRIOSUB | OPT_ALIAS | 1 },
+    { "noipx", o_bool, &ipxcp_protent.enabled_flag,
+      "Disable IPXCP (and IPX)", OPT_PRIOSUB },
+    { "-ipx", o_bool, &ipxcp_protent.enabled_flag,
+      "Disable IPXCP (and IPX)", OPT_PRIOSUB | OPT_ALIAS },
+
+    { "ipx-network", o_uint32, &ipxcp_wantoptions[0].our_network,
+      "Set our IPX network number", OPT_PRIO, &ipxcp_wantoptions[0].neg_nn },
+
+    { "ipxcp-accept-network", o_bool, &ipxcp_wantoptions[0].accept_network,
+      "Accept peer IPX network number", 1,
+      &ipxcp_allowoptions[0].accept_network },
+
+    { "ipx-node", o_special, (void *)setipxnode,
+      "Set IPX node number", OPT_A2PRINTER, (void *)printipxnode },
+
+    { "ipxcp-accept-local", o_bool, &ipxcp_wantoptions[0].accept_local,
+      "Accept our IPX address", 1,
+      &ipxcp_allowoptions[0].accept_local },
+
+    { "ipxcp-accept-remote", o_bool, &ipxcp_wantoptions[0].accept_remote,
+      "Accept peer's IPX address", 1,
+      &ipxcp_allowoptions[0].accept_remote },
+
+    { "ipx-routing", o_int, &ipxcp_wantoptions[0].router,
+      "Set IPX routing proto number", OPT_PRIO,
+      &ipxcp_wantoptions[0].neg_router },
+
+    { "ipx-router-name", o_special, setipxname,
+      "Set IPX router name", OPT_PRIO | OPT_A2STRVAL | OPT_STATIC,
+       &ipxcp_wantoptions[0].name },
+
+    { "ipxcp-restart", o_int, &ipxcp_fsm[0].timeouttime,
+      "Set timeout for IPXCP", OPT_PRIO },
+    { "ipxcp-max-terminate", o_int, &ipxcp_fsm[0].maxtermtransmits,
+      "Set max #xmits for IPXCP term-reqs", OPT_PRIO },
+    { "ipxcp-max-configure", o_int, &ipxcp_fsm[0].maxconfreqtransmits,
+      "Set max #xmits for IPXCP conf-reqs", OPT_PRIO },
+    { "ipxcp-max-failure", o_int, &ipxcp_fsm[0].maxnakloops,
+      "Set max #conf-naks for IPXCP", 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,
+    "IPXCP",
+    "IPX",
+    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 ? "ACK" : \
+			 (x) == CONFNAK ? "NAK" : "REJ")
+
+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 << (num))
+
+/*
+ * Convert from internal to external notation
+ */
+
+static short int
+to_external(internal)
+short int internal;
+{
+    short int  external;
+
+    if (internal & 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), "%x", 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 < 5; ++indx) {
+	    dst[indx] <<= 4;
+	    dst[indx] |= (dst[indx + 1] >> 4) & 0x0F;
+	}
+
+	item = toupper (*src) - '0';
+	if (item > 9)
+	    item -= 7;
+
+	dst[5] = (dst[5] << 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 >= ipx_prio_our) {
+	    memcpy(&ipxcp_wantoptions[0].our_node[0], our_node, 6);
+	    ipx_prio_our = option_priority;
+	}
+	if (have_his && option_priority >= ipx_prio_his) {
+	    memcpy(&ipxcp_wantoptions[0].his_node[0], his_node, 6);
+	    ipx_prio_his = option_priority;
+	}
+        return 1;
+    }
+
+    option_error("invalid parameter '%s' for ipx-node option", *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, "%.2x%.2x%.2x%.2x%.2x%.2x",
+			p[0], p[1], p[2], p[3], p[4], p[5]);
+	printer(arg, ":");
+	p = ipxcp_wantoptions[0].his_node;
+	if (ipx_prio_his)
+		printer(arg, "%.2x%.2x%.2x%.2x%.2x%.2x",
+			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) && ch != '_') {
+	    option_error("IPX router name must be alphanumeric or _");
+	    return 0;
+	}
+
+	if (count >= sizeof (ipxcp_wantoptions[0].name) - 1) {
+	    option_error("IPX router name is limited to %d characters",
+			 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 = &ipxcp_fsm[unit];
+
+    f->unit	 = unit;
+    f->protocol	 = PPP_IPXCP;
+    f->callbacks = &ipxcp_callbacks;
+    fsm_init(&ipxcp_fsm[unit]);
+
+    memset (wo->name,	  0, sizeof (wo->name));
+    memset (wo->our_node, 0, sizeof (wo->our_node));
+    memset (wo->his_node, 0, sizeof (wo->his_node));
+
+    wo->neg_nn	       = 1;
+    wo->neg_complete   = 1;
+    wo->network	       = 0;
+
+    ao->neg_node       = 1;
+    ao->neg_nn	       = 1;
+    ao->neg_name       = 1;
+    ao->neg_complete   = 1;
+    ao->neg_router     = 1;
+
+    ao->accept_local   = 0;
+    ao->accept_remote  = 0;
+    ao->accept_network = 0;
+
+    wo->tried_rip      = 0;
+    wo->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 < 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(&ipxcp_fsm[unit]);
+}
+
+/*
+ * ipxcp_close - Take IPXCP down.
+ */
+static void
+ipxcp_close(unit, reason)
+    int unit;
+    char *reason;
+{
+    fsm_close(&ipxcp_fsm[unit], reason);
+}
+
+
+/*
+ * ipxcp_lowerup - The lower layer is up.
+ */
+static void
+ipxcp_lowerup(unit)
+    int unit;
+{
+    fsm_lowerup(&ipxcp_fsm[unit]);
+}
+
+
+/*
+ * ipxcp_lowerdown - The lower layer is down.
+ */
+static void
+ipxcp_lowerdown(unit)
+    int unit;
+{
+    fsm_lowerdown(&ipxcp_fsm[unit]);
+}
+
+
+/*
+ * ipxcp_input - Input IPXCP packet.
+ */
+static void
+ipxcp_input(unit, p, len)
+    int unit;
+    u_char *p;
+    int len;
+{
+    fsm_input(&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(&ipxcp_fsm[unit]);
+}
+
+
+/*
+ * ipxcp_resetci - Reset our CI.
+ */
+static void
+ipxcp_resetci(f)
+    fsm *f;
+{
+    wo->req_node = wo->neg_node && ao->neg_node;
+    wo->req_nn	 = wo->neg_nn	&& ao->neg_nn;
+
+    if (wo->our_network == 0) {
+	wo->neg_node	   = 1;
+	ao->accept_network = 1;
+    }
+/*
+ * If our node number is zero then change it.
+ */
+    if (zero_node (wo->our_node)) {
+	inc_node (wo->our_node);
+	ao->accept_local = 1;
+	wo->neg_node	 = 1;
+    }
+/*
+ * If his node number is zero then change it.
+ */
+    if (zero_node (wo->his_node)) {
+	inc_node (wo->his_node);
+	ao->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->router == 0) {
+	ao->router |= BIT(RIP_SAP);
+	wo->router |= BIT(RIP_SAP);
+    }
+
+    /* Always specify a routing protocol unless it was REJected. */
+    wo->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->neg_nn	    ? CILEN_NETN     : 0;
+    len += go->neg_node	    ? CILEN_NODEN    : 0;
+    len += go->neg_name	    ? CILEN_NAME + strlen (go->name) - 1 : 0;
+
+    /* RFC says that defaults should not be included. */
+    if (go->neg_router && to_external(go->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->neg_nn) {
+	PUTCHAR (IPX_NETWORK_NUMBER, ucp);
+	PUTCHAR (CILEN_NETN, ucp);
+	PUTLONG (go->our_network, ucp);
+    }
+
+    if (go->neg_node) {
+	int indx;
+	PUTCHAR (IPX_NODE_NUMBER, ucp);
+	PUTCHAR (CILEN_NODEN, ucp);
+	for (indx = 0; indx < sizeof (go->our_node); ++indx)
+	    PUTCHAR (go->our_node[indx], ucp);
+    }
+
+    if (go->neg_name) {
+	int cilen = strlen (go->name);
+	int indx;
+	PUTCHAR (IPX_ROUTER_NAME, ucp);
+	PUTCHAR (CILEN_NAME + cilen - 1, ucp);
+	for (indx = 0; indx < cilen; ++indx)
+	    PUTCHAR (go->name [indx], ucp);
+    }
+
+    if (go->neg_router) {
+        short external = to_external (go->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) < 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 < 0) \
+	    break; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != (count + 2) || \
+	    citype != opt) \
+	    break; \
+	for (indx = 0; indx < count; ++indx) {\
+	    GETCHAR(cichar, p); \
+	    if (cichar != ((u_char *) &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) < 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 < 2) \
+	    break; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != CILEN_PROTOCOL || citype != opt) \
+	    break; \
+	len -= cilen; \
+	if (len < 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->neg_nn,	    go->our_network);
+	ACKCINODE     (IPX_NODE_NUMBER,	    go->neg_node,   go->our_node);
+	ACKCINAME     (IPX_ROUTER_NAME,	    go->neg_name,   go->name);
+	if (len > 0)
+		ACKCIPROTO    (IPX_ROUTER_PROTOCOL, go->neg_router, go->router);
+/*
+ * This is the end of the record.
+ */
+	if (len == 0)
+	    return (1);
+    } while (0);
+/*
+ * The frame is invalid
+ */
+    IPXCPDEBUG(("ipxcp_ackci: received bad Ack!"));
+    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(&no, sizeof(no));
+    try = *go;
+
+    while (len > CILEN_VOID) {
+	GETCHAR (citype, p);
+	GETCHAR (cilen,	 p);
+	len -= cilen;
+	if (len < 0)
+	    goto bad;
+	next = &p [cilen - CILEN_VOID];
+
+	switch (citype) {
+	case IPX_NETWORK_NUMBER:
+	    if (!go->neg_nn || no.neg_nn || (cilen != CILEN_NETN))
+		goto bad;
+	    no.neg_nn = 1;
+
+	    GETLONG(l, p);
+	    if (l && ao->accept_network)
+		try.our_network = l;
+	    break;
+
+	case IPX_NODE_NUMBER:
+	    if (!go->neg_node || no.neg_node || (cilen != CILEN_NODEN))
+		goto bad;
+	    no.neg_node = 1;
+
+	    if (!zero_node (p) && ao->accept_local &&
+		! compare_node (p, ho->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->neg_router || (cilen < CILEN_PROTOCOL))
+		goto bad;
+
+	    GETSHORT (s, p);
+	    if (s > 15)         /* This is just bad, but ignore for now. */
+	        break;
+
+	    s = BIT(s);
+	    if (no.router & 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 "NONE".
+     */
+    try.router &= (ao->router | BIT(IPX_NONE));
+    if (try.router == 0 && ao->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->state != OPENED)
+	*go = try;
+
+    return 1;
+
+bad:
+    IPXCPDEBUG(("ipxcp_nakci: received bad Nak!"));
+    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 && p[0] == opt) { \
+	if ((len -= CILEN_NETN) < 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 && p[0] == opt) { \
+	int indx, count = cnt; \
+	len -= (count + 2); \
+	if (len < 0) \
+	    break; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != (count + 2) || \
+	    citype != opt) \
+	    break; \
+	for (indx = 0; indx < count; ++indx) {\
+	    GETCHAR(cichar, p); \
+	    if (cichar != ((u_char *) &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 && p[0] == opt) { \
+	if ((len -= CILEN_VOID) < 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 && p[0] == opt) { \
+	if ((len -= CILEN_PROTOCOL) < 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->state != OPENED)
+		*go = try;
+	    return (1);
+	}
+    } while (0);
+/*
+ * The frame is invalid at this point.
+ */
+    IPXCPDEBUG(("ipxcp_rejci: received bad Reject!"));
+    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 < 2 ||			/* Not enough data for CI header or */
+	    p[1] < 2 ||			/*  CI length too small or */
+	    p[1] > l) {			/*  CI length too big? */
+	    IPXCPDEBUG(("ipxcp_reqci: bad CI length!"));
+	    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->neg_nn || cilen != CILEN_NETN ) {
+		orc = CONFREJ;
+		break;		
+	    }
+	    GETLONG(cinetwork, p);
+
+	    /* If the network numbers match then acknowledge them. */
+	    if (cinetwork != 0) {
+		ho->his_network = cinetwork;
+		ho->neg_nn	= 1;
+		if (wo->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->accept_network || cinetwork < wo->our_network) {
+		    DECPTR (sizeof (u_int32_t), p);
+		    PUTLONG (wo->our_network, p);
+		    orc = CONFNAK;
+		}
+		break;
+	    }
+/*
+ * The peer sent '0' for the network. Give it ours if we have one.
+ */
+	    if (go->our_network != 0) {
+		DECPTR (sizeof (u_int32_t), p);
+		PUTLONG (wo->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->his_node);
+	    ho->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->his_node)) {
+		orc = CONFNAK;
+		copy_node (wo->his_node, p);
+		INCPTR (sizeof (wo->his_node), p);
+		break;
+	    }
+/*
+ * If you have given me the expected network node number then I'll accept
+ * it now.
+ */
+	    if (compare_node (wo->his_node, ho->his_node)) {
+		orc = CONFACK;
+		ho->neg_node = 1;
+		INCPTR (sizeof (wo->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->his_node, go->our_node)) {
+		inc_node (ho->his_node);
+		orc = CONFNAK;
+		copy_node (ho->his_node, p);
+		INCPTR (sizeof (wo->his_node), p);
+		break;
+	    }
+/*
+ * If we don't accept a new value then NAK it.
+ */
+	    if (! ao->accept_remote) {
+		copy_node (wo->his_node, p);
+		INCPTR (sizeof (wo->his_node), p);
+		orc = CONFNAK;
+		break;
+	    }
+	    orc = CONFACK;
+	    ho->neg_node = 1;
+	    INCPTR (sizeof (wo->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->neg_router || cilen < CILEN_PROTOCOL ) {
+		orc = CONFREJ;
+		break;		
+	    }
+
+	    GETSHORT (cishort, p);
+
+	    if (wo->neg_router == 0) {
+	        wo->neg_router = 1;
+		wo->router     = BIT(IPX_NONE);
+	    }
+
+	    if ((cishort == IPX_NONE && ho->router != 0) ||
+		(ho->router & BIT(IPX_NONE))) {
+		orc = CONFREJ;
+		break;
+	    }
+
+	    cishort = BIT(cishort);
+	    if (ho->router & cishort) {
+		orc = CONFREJ;
+		break;
+	    }
+
+	    ho->router	  |= cishort;
+	    ho->neg_router = 1;
+
+	    /* Finally do not allow a router protocol which we do not
+	       support. */
+
+	    if ((cishort & (ao->router | BIT(IPX_NONE))) == 0) {
+	        int protocol;
+
+		if (cishort == BIT(NLSP) &&
+		    (ao->router & BIT(RIP_SAP)) &&
+		    !wo->tried_rip) {
+		    protocol      = RIP_SAP;
+		    wo->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 >= CILEN_NAME) {
+		int name_size = cilen - CILEN_NAME;
+		if (name_size > sizeof (ho->name))
+		    name_size = sizeof (ho->name) - 1;
+		memset (ho->name, 0, sizeof (ho->name));
+		memcpy (ho->name, p, name_size);
+		ho->name [name_size] = '\0';
+		ho->neg_name = 1;
+		orc = CONFACK;
+		break;
+	    }
+	    orc = CONFREJ;
+	    break;
+/*
+ * This is advisorary.
+ */
+	case IPX_COMPLETE:
+	    if (cilen != CILEN_COMPLETE)
+		orc = CONFREJ;
+	    else {
+		ho->neg_complete = 1;
+		orc = CONFACK;
+	    }
+	    break;
+/*
+ * All other entries are not known at this time.
+ */
+	default:
+	    orc = CONFREJ;
+	    break;
+	}
+endswitch:
+	if (orc == CONFACK &&		/* 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 &&		/* 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 && !ho->neg_node &&
+	wo->req_nn && !reject_if_disagree) {
+	if (rc == CONFACK) {
+	    rc = CONFNAK;
+	    wo->req_nn = 0;		/* don't ask again */
+	    ucp = inp;			/* reset pointer */
+	}
+
+	if (zero_node (wo->his_node))
+	    inc_node (wo->his_node);
+
+	PUTCHAR (IPX_NODE_NUMBER, ucp);
+	PUTCHAR (CILEN_NODEN, ucp);
+	copy_node (wo->his_node, ucp);
+	INCPTR (sizeof (wo->his_node), ucp);
+    }
+
+    *len = ucp - inp;			/* Compute output length */
+    IPXCPDEBUG(("ipxcp: returning Configure-%s", 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->unit;
+
+    IPXCPDEBUG(("ipxcp: up"));
+
+    /* The default router protocol is RIP/SAP. */
+    if (ho->router == 0)
+        ho->router = BIT(RIP_SAP);
+
+    if (go->router == 0)
+        go->router = BIT(RIP_SAP);
+
+    /* Fetch the network number */
+    if (!ho->neg_nn)
+	ho->his_network = wo->his_network;
+
+    if (!ho->neg_node)
+	copy_node (wo->his_node, ho->his_node);
+
+    if (!wo->neg_node && !go->neg_node)
+	copy_node (wo->our_node, go->our_node);
+
+    if (zero_node (go->our_node)) {
+        static char errmsg[] = "Could not determine local IPX node address";
+	if (debug)
+	    error(errmsg);
+	ipxcp_close(f->unit, errmsg);
+	return;
+    }
+
+    go->network = go->our_network;
+    if (ho->his_network != 0 && ho->his_network > go->network)
+	go->network = ho->his_network;
+
+    if (go->network == 0) {
+        static char errmsg[] = "Can not determine network number";
+	if (debug)
+	    error(errmsg);
+	ipxcp_close (unit, errmsg);
+	return;
+    }
+
+    /* bring the interface up */
+    if (!sifup(unit)) {
+	if (debug)
+	    warn("sifup failed (IPX)");
+	ipxcp_close(unit, "Interface configuration failed");
+	return;
+    }
+    ipxcp_is_up = 1;
+
+    /* set the network number for IPX */
+    if (!sipxfaddr(unit, go->network, go->our_node)) {
+	if (debug)
+	    warn("sipxfaddr failed");
+	ipxcp_close(unit, "Interface configuration failed");
+	return;
+    }
+
+    np_up(f->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(("ipxcp: down"));
+
+    if (!ipxcp_is_up)
+	return;
+    ipxcp_is_up = 0;
+    np_down(f->unit, PPP_IPX);
+    cipxfaddr(f->unit);
+    sifnpmode(f->unit, PPP_IPX, NPMODE_DROP);
+    sifdown(f->unit);
+    ipxcp_script (f, _PATH_IPXDOWN);
+}
+
+
+/*
+ * ipxcp_finished - possibly shut down the lower layers.
+ */
+static void
+ipxcp_finished(f)
+    fsm *f;
+{
+    np_finished(f->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), "%d", getpid());
+    slprintf(strspeed, sizeof(strspeed),"%d", baud_rate);
+
+    strproto_lcl[0] = '\0';
+    if (go->neg_router && ((go->router & BIT(IPX_NONE)) == 0)) {
+	if (go->router & BIT(RIP_SAP))
+	    strlcpy (strproto_lcl, "RIP ", sizeof(strproto_lcl));
+	if (go->router & BIT(NLSP))
+	    strlcat (strproto_lcl, "NLSP ", sizeof(strproto_lcl));
+    }
+
+    if (strproto_lcl[0] == '\0')
+	strlcpy (strproto_lcl, "NONE ", sizeof(strproto_lcl));
+
+    strproto_lcl[strlen (strproto_lcl)-1] = '\0';
+
+    strproto_rmt[0] = '\0';
+    if (ho->neg_router && ((ho->router & BIT(IPX_NONE)) == 0)) {
+	if (ho->router & BIT(RIP_SAP))
+	    strlcpy (strproto_rmt, "RIP ", sizeof(strproto_rmt));
+	if (ho->router & BIT(NLSP))
+	    strlcat (strproto_rmt, "NLSP ", sizeof(strproto_rmt));
+    }
+
+    if (strproto_rmt[0] == '\0')
+	strlcpy (strproto_rmt, "NONE ", sizeof(strproto_rmt));
+
+    strproto_rmt[strlen (strproto_rmt)-1] = '\0';
+
+    strlcpy (strnetwork, ipx_ntoa (go->network), sizeof(strnetwork));
+
+    slprintf (strlocal, sizeof(strlocal), "%0.6B", go->our_node);
+
+    slprintf (strremote, sizeof(strremote), "%0.6B", ho->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->name;
+    argv[10] = ho->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[] = {
+    "ConfReq", "ConfAck", "ConfNak", "ConfRej",
+    "TermReq", "TermAck", "CodeRej"
+};
+
+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 < HEADERLEN)
+	return 0;
+    pstart = p;
+    GETCHAR(code, p);
+    GETCHAR(id, p);
+    GETSHORT(len, p);
+    if (len < HEADERLEN || len > plen)
+	return 0;
+
+    if (code >= 1 && code <= sizeof(ipxcp_codenames) / sizeof(char *))
+	printer(arg, " %s", ipxcp_codenames[code-1]);
+    else
+	printer(arg, " code=0x%x", code);
+    printer(arg, " id=0x%x", id);
+    len -= HEADERLEN;
+    switch (code) {
+    case CONFREQ:
+    case CONFACK:
+    case CONFNAK:
+    case CONFREJ:
+	/* print option list */
+	while (len >= 2) {
+	    GETCHAR(code, p);
+	    GETCHAR(olen, p);
+	    p -= 2;
+	    if (olen < CILEN_VOID || olen > len) {
+		break;
+	    }
+	    printer(arg, " <");
+	    len -= olen;
+	    optend = p + olen;
+	    switch (code) {
+	    case IPX_NETWORK_NUMBER:
+		if (olen == CILEN_NETN) {
+		    p += 2;
+		    GETLONG(cilong, p);
+		    printer (arg, "network %s", ipx_ntoa (cilong));
+		}
+		break;
+	    case IPX_NODE_NUMBER:
+		if (olen == CILEN_NODEN) {
+		    p += 2;
+		    printer (arg, "node ");
+		    while (p < optend) {
+			GETCHAR(code, p);
+			printer(arg, "%.2x", (int) (unsigned int) (unsigned char) code);
+		    }
+		}
+		break;
+	    case IPX_COMPRESSION_PROTOCOL:
+		if (olen == CILEN_COMPRESS) {
+		    p += 2;
+		    GETSHORT (cishort, p);
+		    printer (arg, "compression %d", (int) cishort);
+		}
+		break;
+	    case IPX_ROUTER_PROTOCOL:
+		if (olen == CILEN_PROTOCOL) {
+		    p += 2;
+		    GETSHORT (cishort, p);
+		    printer (arg, "router proto %d", (int) cishort);
+		}
+		break;
+	    case IPX_ROUTER_NAME:
+		if (olen >= CILEN_NAME) {
+		    p += 2;
+		    printer (arg, "router name \"");
+		    while (p < optend) {
+			GETCHAR(code, p);
+			if (code >= 0x20 && code <= 0x7E)
+			    printer (arg, "%c", (int) (unsigned int) (unsigned char) code);
+			else
+			    printer (arg, " \\%.2x", (int) (unsigned int) (unsigned char) code);
+		    }
+		    printer (arg, "\"");
+		}
+		break;
+	    case IPX_COMPLETE:
+		if (olen == CILEN_COMPLETE) {
+		    p += 2;
+		    printer (arg, "complete");
+		}
+		break;
+	    default:
+		break;
+	    }
+
+	    while (p < optend) {
+		GETCHAR(code, p);
+		printer(arg, " %.2x", (int) (unsigned int) (unsigned char) code);
+	    }
+	    printer(arg, ">");
+	}
+	break;
+
+    case TERMACK:
+    case TERMREQ:
+	if (len > 0 && *p >= ' ' && *p < 0x7f) {
+	    printer(arg, " ");
+	    print_string(p, len, printer, arg);
+	    p += len;
+	    len = 0;
+	}
+	break;
+    }
+
+    /* print the rest of the bytes in the packet */
+    for (; len > 0; --len) {
+	GETCHAR(code, p);
+	printer(arg, " %.2x", (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	"$Id: lcp.c 195720 2001-06-11 11:44:34Z gc $"
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "pppd.h"
+#include "fsm.h"
+#include "lcp.h"
+#include "chap.h"
+#include "magic.h"
+
+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 */
+    { "-all", o_special_noarg, (void *)noopt,
+      "Don't request/allow any LCP options" },
+
+    { "noaccomp", o_bool, &lcp_wantoptions[0].neg_accompression,
+      "Disable address/control compression",
+      OPT_A2CLR, &lcp_allowoptions[0].neg_accompression },
+    { "-ac", o_bool, &lcp_wantoptions[0].neg_accompression,
+      "Disable address/control compression",
+      OPT_ALIAS | OPT_A2CLR, &lcp_allowoptions[0].neg_accompression },
+
+    { "asyncmap", o_uint32, &lcp_wantoptions[0].asyncmap,
+      "Set asyncmap (for received packets)",
+      OPT_OR, &lcp_wantoptions[0].neg_asyncmap },
+    { "-as", o_uint32, &lcp_wantoptions[0].asyncmap,
+      "Set asyncmap (for received packets)",
+      OPT_ALIAS | OPT_OR, &lcp_wantoptions[0].neg_asyncmap },
+    { "default-asyncmap", o_uint32, &lcp_wantoptions[0].asyncmap,
+      "Disable asyncmap negotiation",
+      OPT_OR | OPT_NOARG | OPT_VAL(~0U) | OPT_A2CLR,
+      &lcp_allowoptions[0].neg_asyncmap },
+    { "-am", o_uint32, &lcp_wantoptions[0].asyncmap,
+      "Disable asyncmap negotiation",
+      OPT_ALIAS | OPT_OR | OPT_NOARG | OPT_VAL(~0U) | OPT_A2CLR,
+      &lcp_allowoptions[0].neg_asyncmap },
+
+    { "nomagic", o_bool, &lcp_wantoptions[0].neg_magicnumber,
+      "Disable magic number negotiation (looped-back line detection)",
+      OPT_A2CLR, &lcp_allowoptions[0].neg_magicnumber },
+    { "-mn", o_bool, &lcp_wantoptions[0].neg_magicnumber,
+      "Disable magic number negotiation (looped-back line detection)",
+      OPT_ALIAS | OPT_A2CLR, &lcp_allowoptions[0].neg_magicnumber },
+
+    { "mru", o_int, &lcp_wantoptions[0].mru,
+      "Set MRU (maximum received packet size) for negotiation",
+      OPT_PRIO, &lcp_wantoptions[0].neg_mru },
+    { "default-mru", o_bool, &lcp_wantoptions[0].neg_mru,
+      "Disable MRU negotiation (use default 1500)",
+      OPT_PRIOSUB | OPT_A2CLR, &lcp_allowoptions[0].neg_mru },
+    { "-mru", o_bool, &lcp_wantoptions[0].neg_mru,
+      "Disable MRU negotiation (use default 1500)",
+      OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR, &lcp_allowoptions[0].neg_mru },
+
+    { "mtu", o_int, &lcp_allowoptions[0].mru,
+      "Set our MTU", OPT_LIMITS, NULL, MAXMRU, MINMRU },
+
+    { "nopcomp", o_bool, &lcp_wantoptions[0].neg_pcompression,
+      "Disable protocol field compression",
+      OPT_A2CLR, &lcp_allowoptions[0].neg_pcompression },
+    { "-pc", o_bool, &lcp_wantoptions[0].neg_pcompression,
+      "Disable protocol field compression",
+      OPT_ALIAS | OPT_A2CLR, &lcp_allowoptions[0].neg_pcompression },
+
+    { "passive", o_bool, &lcp_wantoptions[0].passive,
+      "Set passive mode", 1 },
+    { "-p", o_bool, &lcp_wantoptions[0].passive,
+      "Set passive mode", OPT_ALIAS | 1 },
+
+    { "silent", o_bool, &lcp_wantoptions[0].silent,
+      "Set silent mode", 1 },
+
+    { "lcp-echo-failure", o_int, &lcp_echo_fails,
+      "Set number of consecutive echo failures to indicate link failure",
+      OPT_PRIO },
+    { "lcp-echo-interval", o_int, &lcp_echo_interval,
+      "Set time in seconds between LCP echo requests", OPT_PRIO },
+    { "lcp-restart", o_int, &lcp_fsm[0].timeouttime,
+      "Set time in seconds between LCP retransmissions", OPT_PRIO },
+    { "lcp-max-terminate", o_int, &lcp_fsm[0].maxtermtransmits,
+      "Set maximum number of LCP terminate-request transmissions", OPT_PRIO },
+    { "lcp-max-configure", o_int, &lcp_fsm[0].maxconfreqtransmits,
+      "Set maximum number of LCP configure-request transmissions", OPT_PRIO },
+    { "lcp-max-failure", o_int, &lcp_fsm[0].maxnakloops,
+      "Set limit on number of LCP configure-naks", OPT_PRIO },
+
+    { "receive-all", o_bool, &lax_recv,
+      "Accept all received control characters", 1 },
+
+#ifdef HAVE_MULTILINK
+    { "mrru", o_int, &lcp_wantoptions[0].mrru,
+      "Maximum received packet size for multilink bundle",
+      OPT_PRIO, &lcp_wantoptions[0].neg_mrru },
+
+    { "mpshortseq", o_bool, &lcp_wantoptions[0].neg_ssnhf,
+      "Use short sequence numbers in multilink headers",
+      OPT_PRIO | 1, &lcp_allowoptions[0].neg_ssnhf },
+    { "nompshortseq", o_bool, &lcp_wantoptions[0].neg_ssnhf,
+      "Don't use short sequence numbers in multilink headers",
+      OPT_PRIOSUB | OPT_A2CLR, &lcp_allowoptions[0].neg_ssnhf },
+
+    { "endpoint", o_special, (void *) setendpoint,
+      "Endpoint discriminator for multilink",
+      OPT_PRIO | OPT_A2PRINTER, (void *) printendpoint },
+#endif /* HAVE_MULTILINK */
+
+    { "noendpoint", o_bool, &noendpoint,
+      "Don't send or accept multilink endpoint discriminator", 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 */
+    "LCP"			/* 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,
+    "LCP",
+    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 ? "ACK" : \
+			 (x) == CONFNAK ? "NAK" : "REJ")
+
+/*
+ * noopt - Disable all options (why?).
+ */
+static int
+noopt(argv)
+    char **argv;
+{
+    BZERO((char *) &lcp_wantoptions[0], sizeof (struct lcp_options));
+    BZERO((char *) &lcp_allowoptions[0], sizeof (struct lcp_options));
+
+    return (1);
+}
+
+#ifdef HAVE_MULTILINK
+static int
+setendpoint(argv)
+    char **argv;
+{
+    if (str_to_epdisc(&lcp_wantoptions[0].endpoint, *argv)) {
+	lcp_wantoptions[0].neg_endpoint = 1;
+	return 1;
+    }
+    option_error("Can't parse '%s' as an endpoint discriminator", *argv);
+    return 0;
+}
+
+static void
+printendpoint(opt, printer, arg)
+    option_t *opt;
+    void (*printer) __P((void *, char *, ...));
+    void *arg;
+{
+	printer(arg, "%s", epdisc_to_str(&lcp_wantoptions[0].endpoint));
+}
+#endif /* HAVE_MULTILINK */
+
+/*
+ * lcp_init - Initialize LCP.
+ */
+static void
+lcp_init(unit)
+    int unit;
+{
+    fsm *f = &lcp_fsm[unit];
+    lcp_options *wo = &lcp_wantoptions[unit];
+    lcp_options *ao = &lcp_allowoptions[unit];
+
+    f->unit = unit;
+    f->protocol = PPP_LCP;
+    f->callbacks = &lcp_callbacks;
+
+    fsm_init(f);
+
+    BZERO(wo, sizeof(*wo));
+    wo->neg_mru = 1;
+    wo->mru = DEFMRU;
+    wo->neg_asyncmap = 1;
+    wo->chap_mdtype = CHAP_DIGEST_MD5;
+    wo->neg_magicnumber = 1;
+    wo->neg_pcompression = 1;
+    wo->neg_accompression = 1;
+
+    BZERO(ao, sizeof(*ao));
+    ao->neg_mru = 1;
+    ao->mru = MAXMRU;
+    ao->neg_asyncmap = 1;
+    ao->neg_chap = 1;
+    ao->chap_mdtype = CHAP_DIGEST_MD5;
+    ao->neg_upap = 1;
+    ao->neg_magicnumber = 1;
+    ao->neg_pcompression = 1;
+    ao->neg_accompression = 1;
+#ifdef CBCP_SUPPORT
+    ao->neg_cbcp = 1;
+#endif
+    ao->neg_endpoint = 1;
+}
+
+
+/*
+ * lcp_open - LCP is allowed to come up.
+ */
+void
+lcp_open(unit)
+    int unit;
+{
+    fsm *f = &lcp_fsm[unit];
+    lcp_options *wo = &lcp_wantoptions[unit];
+
+    f->flags &= ~(OPT_PASSIVE | OPT_SILENT);
+    if (wo->passive)
+	f->flags |= OPT_PASSIVE;
+    if (wo->silent)
+	f->flags |= OPT_SILENT;
+    fsm_open(f);
+}
+
+
+/*
+ * lcp_close - Take LCP down.
+ */
+void
+lcp_close(unit, reason)
+    int unit;
+    char *reason;
+{
+    fsm *f = &lcp_fsm[unit];
+
+    if (phase != PHASE_DEAD)
+	new_phase(PHASE_TERMINATE);
+    if (f->state == STOPPED && f->flags & (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->state = CLOSED;
+	lcp_finished(f);
+
+    } else
+	fsm_close(&lcp_fsm[unit], reason);
+}
+
+
+/*
+ * lcp_lowerup - The lower layer is up.
+ */
+void
+lcp_lowerup(unit)
+    int unit;
+{
+    lcp_options *wo = &lcp_wantoptions[unit];
+    fsm *f = &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->neg_pcompression, wo->neg_accompression);
+    peer_mru[unit] = PPP_MRU;
+
+    if (listen_time != 0) {
+	f->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 = &lcp_fsm[unit];
+
+    if (f->flags & DELAYED_UP)
+	f->flags &= ~DELAYED_UP;
+    else
+	fsm_lowerdown(&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->flags & DELAYED_UP) {
+	f->flags &= ~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 = &lcp_fsm[unit];
+
+    if (f->flags & DELAYED_UP) {
+	f->flags &= ~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->state != OPENED)
+	    break;
+	magp = inp;
+	PUTLONG(lcp_gotoptions[f->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 < 2) {
+	LCPDEBUG(("lcp_rprotrej: Rcvd short Protocol-Reject packet!"));
+	return;
+    }
+
+    GETSHORT(prot, inp);
+
+    /*
+     * Protocol-Reject packets received in any state other than the LCP
+     * OPENED state SHOULD be silently discarded.
+     */
+    if( f->state != OPENED ){
+	LCPDEBUG(("Protocol-Reject discarded: LCP in state %d", f->state));
+	return;
+    }
+
+    /*
+     * Upcall the proper Protocol-Reject routine.
+     */
+    for (i = 0; (protp = protocols[i]) != NULL; ++i)
+	if (protp->protocol == prot && protp->enabled_flag) {
+	    (*protp->protrej)(f->unit);
+	    return;
+	}
+
+    warn("Protocol-Reject for unsupported protocol 0x%x", prot);
+}
+
+
+/*
+ * lcp_protrej - A Protocol-Reject was received.
+ */
+/*ARGSUSED*/
+static void
+lcp_protrej(unit)
+    int unit;
+{
+    /*
+     * Can't reject LCP!
+     */
+    error("Received Protocol-Reject for LCP!");
+    fsm_protreject(&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(&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 = &lcp_wantoptions[f->unit];
+    lcp_options *go = &lcp_gotoptions[f->unit];
+    lcp_options *ao = &lcp_allowoptions[f->unit];
+
+    wo->magicnumber = magic();
+    wo->numloops = 0;
+    *go = *wo;
+    if (!multilink) {
+	go->neg_mrru = 0;
+	go->neg_ssnhf = 0;
+	go->neg_endpoint = 0;
+    }
+    if (noendpoint)
+	ao->neg_endpoint = 0;
+    peer_mru[f->unit] = PPP_MRU;
+    auth_reset(f->unit);
+}
+
+
+/*
+ * lcp_cilen - Return length of our CI.
+ */
+static int
+lcp_cilen(f)
+    fsm *f;
+{
+    lcp_options *go = &lcp_gotoptions[f->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->neg_mru && go->mru != DEFMRU) +
+	    LENCILONG(go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) +
+	    LENCICHAP(go->neg_chap) +
+	    LENCISHORT(!go->neg_chap && go->neg_upap) +
+	    LENCILQR(go->neg_lqr) +
+	    LENCICBCP(go->neg_cbcp) +
+	    LENCILONG(go->neg_magicnumber) +
+	    LENCIVOID(go->neg_pcompression) +
+	    LENCIVOID(go->neg_accompression) +
+	    LENCISHORT(go->neg_mrru) +
+	    LENCIVOID(go->neg_ssnhf) +
+	    (go->neg_endpoint? CILEN_CHAR + go->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 = &lcp_gotoptions[f->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 < len; ++i) \
+	    PUTCHAR(val[i], ucp); \
+    }
+
+    ADDCISHORT(CI_MRU, go->neg_mru && go->mru != DEFMRU, go->mru);
+    ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF,
+	      go->asyncmap);
+    ADDCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);
+    ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
+    ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
+    ADDCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
+    ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
+    ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
+    ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
+    ADDCISHORT(CI_MRRU, go->neg_mrru, go->mrru);
+    ADDCIVOID(CI_SSNHF, go->neg_ssnhf);
+    ADDCIENDP(CI_EPDISC, go->neg_endpoint, go->endpoint.class,
+	      go->endpoint.value, go->endpoint.length);
+
+    if (ucp - start_ucp != *lenp) {
+	/* this should never happen, because peer_mtu should be 1500 */
+	error("Bug in lcp_addci: wrong length");
+    }
+}
+
+
+/*
+ * 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 = &lcp_gotoptions[f->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) < 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) < 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) < 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) < 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) < 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) < 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) < 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 < vlen; ++i) { \
+	    GETCHAR(cichar, p); \
+	    if (cichar != val[i]) \
+		goto bad; \
+	} \
+    }
+
+    ACKCISHORT(CI_MRU, go->neg_mru && go->mru != DEFMRU, go->mru);
+    ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF,
+	      go->asyncmap);
+    ACKCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);
+    ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
+    ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
+    ACKCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
+    ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
+    ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
+    ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
+    ACKCISHORT(CI_MRRU, go->neg_mrru, go->mrru);
+    ACKCIVOID(CI_SSNHF, go->neg_ssnhf);
+    ACKCIENDP(CI_EPDISC, go->neg_endpoint, go->endpoint.class,
+	      go->endpoint.value, go->endpoint.length);
+
+    /*
+     * If there are any remaining CIs, then this packet is bad.
+     */
+    if (len != 0)
+	goto bad;
+    return (1);
+bad:
+    LCPDEBUG(("lcp_acki: received bad Ack!"));
+    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 = &lcp_gotoptions[f->unit];
+    lcp_options *wo = &lcp_wantoptions[f->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(&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->neg && \
+	len >= CILEN_VOID && \
+	p[1] == CILEN_VOID && \
+	p[0] == opt) { \
+	len -= CILEN_VOID; \
+	INCPTR(CILEN_VOID, p); \
+	no.neg = 1; \
+	try.neg = 0; \
+    }
+#define NAKCICHAP(opt, neg, code) \
+    if (go->neg && \
+	len >= CILEN_CHAP && \
+	p[1] == CILEN_CHAP && \
+	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->neg && \
+	len >= CILEN_CHAR && \
+	p[1] == CILEN_CHAR && \
+	p[0] == opt) { \
+	len -= CILEN_CHAR; \
+	INCPTR(2, p); \
+	GETCHAR(cichar, p); \
+	no.neg = 1; \
+	code \
+    }
+#define NAKCISHORT(opt, neg, code) \
+    if (go->neg && \
+	len >= CILEN_SHORT && \
+	p[1] == CILEN_SHORT && \
+	p[0] == opt) { \
+	len -= CILEN_SHORT; \
+	INCPTR(2, p); \
+	GETSHORT(cishort, p); \
+	no.neg = 1; \
+	code \
+    }
+#define NAKCILONG(opt, neg, code) \
+    if (go->neg && \
+	len >= CILEN_LONG && \
+	p[1] == CILEN_LONG && \
+	p[0] == opt) { \
+	len -= CILEN_LONG; \
+	INCPTR(2, p); \
+	GETLONG(cilong, p); \
+	no.neg = 1; \
+	code \
+    }
+#define NAKCILQR(opt, neg, code) \
+    if (go->neg && \
+	len >= CILEN_LQR && \
+	p[1] == CILEN_LQR && \
+	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->neg && \
+	len >= CILEN_CHAR && \
+	p[0] == opt && \
+	p[1] >= CILEN_CHAR && \
+	p[1] <= 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->neg_mru && go->mru != DEFMRU) {
+	NAKCISHORT(CI_MRU, neg_mru,
+		   if (cishort <= wo->mru || cishort <= DEFMRU)
+		       try.mru = cishort;
+		   );
+    }
+
+    /*
+     * Add any characters they want to our (receive-side) asyncmap.
+     */
+    if (go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) {
+	NAKCILONG(CI_ASYNCMAP, neg_asyncmap,
+		  try.asyncmap = go->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->neg_chap || go->neg_upap)
+	&& len >= CILEN_SHORT
+	&& p[0] == CI_AUTHTYPE && p[1] >= CILEN_SHORT && p[1] <= len) {
+	cilen = p[1];
+	len -= cilen;
+	no.neg_chap = go->neg_chap;
+	no.neg_upap = go->neg_upap;
+	INCPTR(2, p);
+        GETSHORT(cishort, p);
+	if (cishort == PPP_PAP && 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->neg_chap)
+		goto bad;
+	    try.neg_chap = 0;
+
+	} else if (cishort == PPP_CHAP && cilen == CILEN_CHAP) {
+	    GETCHAR(cichar, p);
+	    if (go->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->chap_mdtype) {
+#ifdef CHAPMS
+		    if (cichar == CHAP_MICROSOFT)
+			go->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->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->neg_mrru) {
+	NAKCISHORT(CI_MRRU, neg_mrru,
+		   if (cishort <= wo->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 > CILEN_VOID) {
+	GETCHAR(citype, p);
+	GETCHAR(cilen, p);
+	if (cilen < CILEN_VOID || (len -= cilen) < 0)
+	    goto bad;
+	next = p + cilen - 2;
+
+	switch (citype) {
+	case CI_MRU:
+	    if ((go->neg_mru && go->mru != DEFMRU)
+		|| no.neg_mru || cilen != CILEN_SHORT)
+		goto bad;
+	    GETSHORT(cishort, p);
+	    if (cishort < DEFMRU) {
+		try.neg_mru = 1;
+		try.mru = cishort;
+	    }
+	    break;
+	case CI_ASYNCMAP:
+	    if ((go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF)
+		|| no.neg_asyncmap || cilen != CILEN_LONG)
+		goto bad;
+	    break;
+	case CI_AUTHTYPE:
+	    if (go->neg_chap || no.neg_chap || go->neg_upap || no.neg_upap)
+		goto bad;
+	    break;
+	case CI_MAGICNUMBER:
+	    if (go->neg_magicnumber || no.neg_magicnumber ||
+		cilen != CILEN_LONG)
+		goto bad;
+	    break;
+	case CI_PCOMPRESSION:
+	    if (go->neg_pcompression || no.neg_pcompression
+		|| cilen != CILEN_VOID)
+		goto bad;
+	    break;
+	case CI_ACCOMPRESSION:
+	    if (go->neg_accompression || no.neg_accompression
+		|| cilen != CILEN_VOID)
+		goto bad;
+	    break;
+	case CI_QUALITY:
+	    if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR)
+		goto bad;
+	    break;
+	case CI_MRRU:
+	    if (go->neg_mrru || no.neg_mrru || cilen != CILEN_SHORT)
+		goto bad;
+	    break;
+	case CI_SSNHF:
+	    if (go->neg_ssnhf || no.neg_ssnhf || cilen != CILEN_VOID)
+		goto bad;
+	    try.neg_ssnhf = 1;
+	    break;
+	case CI_EPDISC:
+	    if (go->neg_endpoint || no.neg_endpoint || cilen < 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->state != OPENED) {
+	if (looped_back) {
+	    if (++try.numloops >= lcp_loopbackfail) {
+		notice("Serial line is looped back.");
+		lcp_close(f->unit, "Loopback detected");
+		status = EXIT_LOOPBACK;
+	    }
+	} else
+	    try.numloops = 0;
+	*go = try;
+    }
+
+    return 1;
+
+bad:
+    LCPDEBUG(("lcp_nakci: received bad Nak!"));
+    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 = &lcp_gotoptions[f->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->neg && \
+	len >= CILEN_VOID && \
+	p[1] == CILEN_VOID && \
+	p[0] == opt) { \
+	len -= CILEN_VOID; \
+	INCPTR(CILEN_VOID, p); \
+	try.neg = 0; \
+    }
+#define REJCISHORT(opt, neg, val) \
+    if (go->neg && \
+	len >= CILEN_SHORT && \
+	p[1] == CILEN_SHORT && \
+	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->neg && \
+	len >= CILEN_CHAP && \
+	p[1] == CILEN_CHAP && \
+	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->neg && \
+	len >= CILEN_LONG && \
+	p[1] == CILEN_LONG && \
+	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->neg && \
+	len >= CILEN_LQR && \
+	p[1] == CILEN_LQR && \
+	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->neg && \
+	len >= CILEN_CBCP && \
+	p[1] == CILEN_CBCP && \
+	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->neg && \
+	len >= CILEN_CHAR + vlen && \
+	p[0] == opt && \
+	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 < vlen; ++i) { \
+	    GETCHAR(cichar, p); \
+	    if (cichar != val[i]) \
+		goto bad; \
+	} \
+	try.neg = 0; \
+    }
+
+    REJCISHORT(CI_MRU, neg_mru, go->mru);
+    REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap);
+    REJCICHAP(CI_AUTHTYPE, neg_chap, PPP_CHAP, go->chap_mdtype);
+    if (!go->neg_chap) {
+	REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP);
+    }
+    REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period);
+    REJCICBCP(CI_CALLBACK, neg_cbcp, CBCP_OPT);
+    REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber);
+    REJCIVOID(CI_PCOMPRESSION, neg_pcompression);
+    REJCIVOID(CI_ACCOMPRESSION, neg_accompression);
+    REJCISHORT(CI_MRRU, neg_mrru, go->mrru);
+    REJCIVOID(CI_SSNHF, neg_ssnhf);
+    REJCIENDP(CI_EPDISC, neg_endpoint, go->endpoint.class,
+	      go->endpoint.value, go->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->state != OPENED)
+	*go = try;
+    return 1;
+
+bad:
+    LCPDEBUG(("lcp_rejci: received bad Reject!"));
+    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 = &lcp_gotoptions[f->unit];
+    lcp_options *ho = &lcp_hisoptions[f->unit];
+    lcp_options *ao = &lcp_allowoptions[f->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 < 2 ||			/* Not enough data for CI header or */
+	    p[1] < 2 ||			/*  CI length too small or */
+	    p[1] > l) {			/*  CI length too big? */
+	    LCPDEBUG(("lcp_reqci: bad CI length!"));
+	    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->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 < MINMRU) {
+		orc = CONFNAK;		/* Nak CI */
+		PUTCHAR(CI_MRU, nakp);
+		PUTCHAR(CILEN_SHORT, nakp);
+		PUTSHORT(MINMRU, nakp);	/* Give him a hint */
+		break;
+	    }
+	    ho->neg_mru = 1;		/* Remember he sent MRU */
+	    ho->mru = cishort;		/* And remember value */
+	    break;
+
+	case CI_ASYNCMAP:
+	    if (!ao->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->asyncmap & ~cilong) != 0) {
+		orc = CONFNAK;
+		PUTCHAR(CI_ASYNCMAP, nakp);
+		PUTCHAR(CILEN_LONG, nakp);
+		PUTLONG(ao->asyncmap | cilong, nakp);
+		break;
+	    }
+	    ho->neg_asyncmap = 1;
+	    ho->asyncmap = cilong;
+	    break;
+
+	case CI_AUTHTYPE:
+	    if (cilen < CILEN_SHORT ||
+		!(ao->neg_upap || ao->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->neg_upap and ao->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->neg_chap ||	/* we've already accepted CHAP */
+		    cilen != CILEN_SHORT) {
+		    LCPDEBUG(("lcp_reqci: rcvd AUTHTYPE PAP, rejecting..."));
+		    orc = CONFREJ;
+		    break;
+		}
+		if (!ao->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->chap_mdtype, nakp);
+		    /* XXX if we can do CHAP_MICROSOFT as well, we should
+		       probably put in another option saying so */
+		    break;
+		}
+		ho->neg_upap = 1;
+		break;
+	    }
+	    if (cishort == PPP_CHAP) {
+		if (ho->neg_upap ||	/* we've already accepted PAP */
+		    cilen != CILEN_CHAP) {
+		    LCPDEBUG(("lcp_reqci: rcvd AUTHTYPE CHAP, rejecting..."));
+		    orc = CONFREJ;
+		    break;
+		}
+		if (!ao->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
+		    && cichar != CHAP_MICROSOFT
+#endif
+		    ) {
+		    orc = CONFNAK;
+		    PUTCHAR(CI_AUTHTYPE, nakp);
+		    PUTCHAR(CILEN_CHAP, nakp);
+		    PUTSHORT(PPP_CHAP, nakp);
+		    PUTCHAR(ao->chap_mdtype, nakp);
+		    break;
+		}
+		ho->chap_mdtype = cichar; /* save md type */
+		ho->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->neg_upap || ao->neg_chap.)
+	     */
+	    orc = CONFNAK;
+	    PUTCHAR(CI_AUTHTYPE, nakp);
+	    if (ao->neg_chap) {
+		PUTCHAR(CILEN_CHAP, nakp);
+		PUTSHORT(PPP_CHAP, nakp);
+		PUTCHAR(ao->chap_mdtype, nakp);
+	    } else {
+		PUTCHAR(CILEN_SHORT, nakp);
+		PUTSHORT(PPP_PAP, nakp);
+	    }
+	    break;
+
+	case CI_QUALITY:
+	    if (!ao->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->lqr_period, nakp);
+		break;
+	    }
+	    break;
+
+	case CI_MAGICNUMBER:
+	    if (!(ao->neg_magicnumber || go->neg_magicnumber) ||
+		cilen != CILEN_LONG) {
+		orc = CONFREJ;
+		break;
+	    }
+	    GETLONG(cilong, p);
+
+	    /*
+	     * He must have a different magic number.
+	     */
+	    if (go->neg_magicnumber &&
+		cilong == go->magicnumber) {
+		cilong = magic();	/* Don't put magic() inside macro! */
+		orc = CONFNAK;
+		PUTCHAR(CI_MAGICNUMBER, nakp);
+		PUTCHAR(CILEN_LONG, nakp);
+		PUTLONG(cilong, nakp);
+		break;
+	    }
+	    ho->neg_magicnumber = 1;
+	    ho->magicnumber = cilong;
+	    break;
+
+
+	case CI_PCOMPRESSION:
+	    if (!ao->neg_pcompression ||
+		cilen != CILEN_VOID) {
+		orc = CONFREJ;
+		break;
+	    }
+	    ho->neg_pcompression = 1;
+	    break;
+
+	case CI_ACCOMPRESSION:
+	    if (!ao->neg_accompression ||
+		cilen != CILEN_VOID) {
+		orc = CONFREJ;
+		break;
+	    }
+	    ho->neg_accompression = 1;
+	    break;
+
+	case CI_MRRU:
+	    if (!ao->neg_mrru || !multilink ||
+		cilen != CILEN_SHORT) {
+		orc = CONFREJ;
+		break;
+	    }
+
+	    GETSHORT(cishort, p);
+	    /* possibly should insist on a minimum/maximum MRRU here */
+	    ho->neg_mrru = 1;
+	    ho->mrru = cishort;
+	    break;
+
+	case CI_SSNHF:
+	    if (!ao->neg_ssnhf || !multilink ||
+		cilen != CILEN_VOID) {
+		orc = CONFREJ;
+		break;
+	    }
+	    ho->neg_ssnhf = 1;
+	    break;
+
+	case CI_EPDISC:
+	    if (!ao->neg_endpoint ||
+		cilen < CILEN_CHAR ||
+		cilen > CILEN_CHAR + MAX_ENDP_LEN) {
+		orc = CONFREJ;
+		break;
+	    }
+	    GETCHAR(cichar, p);
+	    cilen -= CILEN_CHAR;
+	    ho->neg_endpoint = 1;
+	    ho->endpoint.class = cichar;
+	    ho->endpoint.length = cilen;
+	    BCOPY(p, ho->endpoint.value, cilen);
+	    INCPTR(cilen, p);
+	    break;
+
+	default:
+	    LCPDEBUG(("lcp_reqci: rcvd unknown option %d", citype));
+	    orc = CONFREJ;
+	    break;
+	}
+
+endswitch:
+	if (orc == CONFACK &&		/* 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? */
+		&& 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(("lcp_reqci: returning CONF%s.", CODENAME(rc)));
+    return (rc);			/* Return final code */
+}
+
+
+/*
+ * lcp_up - LCP has come UP.
+ */
+static void
+lcp_up(f)
+    fsm *f;
+{
+    lcp_options *wo = &lcp_wantoptions[f->unit];
+    lcp_options *ho = &lcp_hisoptions[f->unit];
+    lcp_options *go = &lcp_gotoptions[f->unit];
+    lcp_options *ao = &lcp_allowoptions[f->unit];
+    int mtu;
+
+    if (!go->neg_magicnumber)
+	go->magicnumber = 0;
+    if (!ho->neg_magicnumber)
+	ho->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->neg_mru? ho->mru: PPP_MRU;
+#ifdef HAVE_MULTILINK
+    if (!(multilink && go->neg_mrru && ho->neg_mrru))
+#endif /* HAVE_MULTILINK */
+	netif_set_mtu(f->unit, MIN(mtu, ao->mru));
+    ppp_send_config(f->unit, mtu,
+		    (ho->neg_asyncmap? ho->asyncmap: 0xffffffff),
+		    ho->neg_pcompression, ho->neg_accompression);
+    ppp_recv_config(f->unit, (go->neg_mru? MAX(wo->mru, go->mru): PPP_MRU),
+		    (lax_recv? 0: go->neg_asyncmap? go->asyncmap: 0xffffffff),
+		    go->neg_pcompression, go->neg_accompression);
+
+    if (ho->neg_mru)
+	peer_mru[f->unit] = ho->mru;
+
+    lcp_echo_lowerup(f->unit);  /* Enable echo messages */
+
+    link_established(f->unit);
+}
+
+
+/*
+ * lcp_down - LCP has gone DOWN.
+ *
+ * Alert other protocols.
+ */
+static void
+lcp_down(f)
+    fsm *f;
+{
+    lcp_options *go = &lcp_gotoptions[f->unit];
+
+    lcp_echo_lowerdown(f->unit);
+
+    link_down(f->unit);
+
+    ppp_send_config(f->unit, PPP_MRU, 0xffffffff, 0, 0);
+    ppp_recv_config(f->unit, PPP_MRU,
+		    (go->neg_asyncmap? go->asyncmap: 0xffffffff),
+		    go->neg_pcompression, go->neg_accompression);
+    peer_mru[f->unit] = PPP_MRU;
+}
+
+
+/*
+ * lcp_starting - LCP needs the lower layer up.
+ */
+static void
+lcp_starting(f)
+    fsm *f;
+{
+    link_required(f->unit);
+}
+
+
+/*
+ * lcp_finished - LCP has finished with the lower layer.
+ */
+static void
+lcp_finished(f)
+    fsm *f;
+{
+    link_terminated(f->unit);
+}
+
+
+/*
+ * lcp_printpkt - print the contents of an LCP packet.
+ */
+static char *lcp_codenames[] = {
+    "ConfReq", "ConfAck", "ConfNak", "ConfRej",
+    "TermReq", "TermAck", "CodeRej", "ProtRej",
+    "EchoReq", "EchoRep", "DiscReq"
+};
+
+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 < HEADERLEN)
+	return 0;
+    pstart = p;
+    GETCHAR(code, p);
+    GETCHAR(id, p);
+    GETSHORT(len, p);
+    if (len < HEADERLEN || len > plen)
+	return 0;
+
+    if (code >= 1 && code <= sizeof(lcp_codenames) / sizeof(char *))
+	printer(arg, " %s", lcp_codenames[code-1]);
+    else
+	printer(arg, " code=0x%x", code);
+    printer(arg, " id=0x%x", id);
+    len -= HEADERLEN;
+    switch (code) {
+    case CONFREQ:
+    case CONFACK:
+    case CONFNAK:
+    case CONFREJ:
+	/* print option list */
+	while (len >= 2) {
+	    GETCHAR(code, p);
+	    GETCHAR(olen, p);
+	    p -= 2;
+	    if (olen < 2 || olen > len) {
+		break;
+	    }
+	    printer(arg, " <");
+	    len -= olen;
+	    optend = p + olen;
+	    switch (code) {
+	    case CI_MRU:
+		if (olen == CILEN_SHORT) {
+		    p += 2;
+		    GETSHORT(cishort, p);
+		    printer(arg, "mru %d", cishort);
+		}
+		break;
+	    case CI_ASYNCMAP:
+		if (olen == CILEN_LONG) {
+		    p += 2;
+		    GETLONG(cilong, p);
+		    printer(arg, "asyncmap 0x%x", cilong);
+		}
+		break;
+	    case CI_AUTHTYPE:
+		if (olen >= CILEN_SHORT) {
+		    p += 2;
+		    printer(arg, "auth ");
+		    GETSHORT(cishort, p);
+		    switch (cishort) {
+		    case PPP_PAP:
+			printer(arg, "pap");
+			break;
+		    case PPP_CHAP:
+			printer(arg, "chap");
+			if (p < optend) {
+			    switch (*p) {
+			    case CHAP_DIGEST_MD5:
+				printer(arg, " MD5");
+				++p;
+				break;
+#ifdef CHAPMS
+			    case CHAP_MICROSOFT:
+				printer(arg, " m$oft");
+				++p;
+				break;
+#endif
+			    }
+			}
+			break;
+		    default:
+			printer(arg, "0x%x", cishort);
+		    }
+		}
+		break;
+	    case CI_QUALITY:
+		if (olen >= CILEN_SHORT) {
+		    p += 2;
+		    printer(arg, "quality ");
+		    GETSHORT(cishort, p);
+		    switch (cishort) {
+		    case PPP_LQR:
+			printer(arg, "lqr");
+			break;
+		    default:
+			printer(arg, "0x%x", cishort);
+		    }
+		}
+		break;
+	    case CI_CALLBACK:
+		if (olen >= CILEN_CHAR) {
+		    p += 2;
+		    printer(arg, "callback ");
+		    GETCHAR(cishort, p);
+		    switch (cishort) {
+		    case CBCP_OPT:
+			printer(arg, "CBCP");
+			break;
+		    default:
+			printer(arg, "0x%x", cishort);
+		    }
+		}
+		break;
+	    case CI_MAGICNUMBER:
+		if (olen == CILEN_LONG) {
+		    p += 2;
+		    GETLONG(cilong, p);
+		    printer(arg, "magic 0x%x", cilong);
+		}
+		break;
+	    case CI_PCOMPRESSION:
+		if (olen == CILEN_VOID) {
+		    p += 2;
+		    printer(arg, "pcomp");
+		}
+		break;
+	    case CI_ACCOMPRESSION:
+		if (olen == CILEN_VOID) {
+		    p += 2;
+		    printer(arg, "accomp");
+		}
+		break;
+	    case CI_MRRU:
+		if (olen == CILEN_SHORT) {
+		    p += 2;
+		    GETSHORT(cishort, p);
+		    printer(arg, "mrru %d", cishort);
+		}
+		break;
+	    case CI_SSNHF:
+		if (olen == CILEN_VOID) {
+		    p += 2;
+		    printer(arg, "ssnhf");
+		}
+		break;
+	    case CI_EPDISC:
+#ifdef HAVE_MULTILINK
+		if (olen >= CILEN_CHAR) {
+		    struct epdisc epd;
+		    p += 2;
+		    GETCHAR(epd.class, p);
+		    epd.length = olen - CILEN_CHAR;
+		    if (epd.length > MAX_ENDP_LEN)
+			epd.length = MAX_ENDP_LEN;
+		    if (epd.length > 0) {
+			BCOPY(p, epd.value, epd.length);
+			p += epd.length;
+		    }
+		    printer(arg, "endpoint [%s]", epdisc_to_str(&epd));
+		}
+#else
+		printer(arg, "endpoint");
+#endif
+		break;
+	    }
+	    while (p < optend) {
+		GETCHAR(code, p);
+		printer(arg, " %.2x", code);
+	    }
+	    printer(arg, ">");
+	}
+	break;
+
+    case TERMACK:
+    case TERMREQ:
+	if (len > 0 && *p >= ' ' && *p < 0x7f) {
+	    printer(arg, " ");
+	    print_string((char *)p, len, printer, arg);
+	    p += len;
+	    len = 0;
+	}
+	break;
+
+    case ECHOREQ:
+    case ECHOREP:
+    case DISCREQ:
+	if (len >= 4) {
+	    GETLONG(cilong, p);
+	    printer(arg, " magic=0x%x", cilong);
+	    p += 4;
+	    len -= 4;
+	}
+	break;
+    }
+
+    /* print the rest of the bytes in the packet */
+    for (i = 0; i < len && i < 32; ++i) {
+	GETCHAR(code, p);
+	printer(arg, " %.2x", code);
+    }
+    if (i < len) {
+	printer(arg, " ...");
+	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->state == OPENED) {
+	info("No response to %d echo-requests", lcp_echos_pending);
+        notice("Serial link appears to be disconnected.");
+        lcp_close(f->unit, "Peer not responding");
+	status = EXIT_PEER_DEAD;
+    }
+}
+
+/*
+ * Timer expired for the LCP echo requests from this process.
+ */
+
+static void
+LcpEchoCheck (f)
+    fsm *f;
+{
+    LcpSendEchoRequest (f);
+    if (f->state != OPENED)
+	return;
+
+    /*
+     * Start the timer for the next interval.
+     */
+    if (lcp_echo_timer_running)
+	warn("assertion lcp_echo_timer_running==0 failed");
+    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 < 4) {
+	dbglog("lcp: received short Echo-Reply, length %d", len);
+	return;
+    }
+    GETLONG(magic, inp);
+    if (lcp_gotoptions[f->unit].neg_magicnumber
+	&& magic == lcp_gotoptions[f->unit].magicnumber) {
+	warn("appear to have received our own echo-reply!");
+	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 >= lcp_echo_fails) {
+            LcpLinkFailure(f);
+	    lcp_echos_pending = 0;
+	}
+    }
+
+    /*
+     * Make and send the echo request frame.
+     */
+    if (f->state == OPENED) {
+        lcp_magic = lcp_gotoptions[f->unit].magicnumber;
+	pktp = pkt;
+	PUTLONG(lcp_magic, pktp);
+        fsm_sdata(f, ECHOREQ, lcp_echo_number++ & 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 = &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 = &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	"$Id: magic.c 195734 2001-06-11 14:46:02Z gc $"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include "pppd.h"
+#include "magic.h"
+
+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(&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	"$Id: main.c 195734 2001-06-11 14:46:02Z gc $"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <netdb.h>
+#include <utmp.h>
+#include <pwd.h>
+#include <setjmp.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "pppd.h"
+#include "magic.h"
+#include "fsm.h"
+#include "lcp.h"
+#include "ipcp.h"
+#ifdef INET6
+#include "ipv6cp.h"
+#endif
+#include "upap.h"
+#include "chap.h"
+#include "ccp.h"
+#include "pathnames.h"
+#include "tdb.h"
+
+#ifdef CBCP_SUPPORT
+#include "cbcp.h"
+#endif
+
+#ifdef IPX_CHANGE
+#include "ipxcp.h"
+#endif /* IPX_CHANGE */
+#ifdef AT_CHANGE
+#include "atcp.h"
+#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 = "Sorry - this system lacks PPP kernel support\n";
+
+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 "protocol" table.
+ * One entry per supported protocol.
+ * The last entry must be NULL.
+ */
+struct protent *protocols[] = {
+    &lcp_protent,
+    &pap_protent,
+    &chap_protent,
+#ifdef CBCP_SUPPORT
+    &cbcp_protent,
+#endif
+    &ipcp_protent,
+#ifdef INET6
+    &ipv6cp_protent,
+#endif
+    &ccp_protent,
+#ifdef IPX_CHANGE
+    &ipxcp_protent,
+#endif
+#ifdef AT_CHANGE
+    &atcp_protent,
+#endif
+    NULL
+};
+
+/*
+ * If PPP_DRV_NAME is not defined, use the default "ppp" as the device name.
+ */
+#if !defined(PPP_DRV_NAME)
+#define PPP_DRV_NAME	"ppp"
+#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("/dev/null", O_RDWR)) >= 0) {
+	while (0 <= i && i <= 2)
+	    i = dup(i);
+	if (i >= 0)
+	    close(i);
+    }
+
+    script_env = NULL;
+
+    /* Initialize syslog facilities */
+    reopen_log();
+
+    if (gethostname(hostname, MAXNAMELEN) < 0 ) {
+	option_error("Couldn't get hostname: %m");
+	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), "%d", uid);
+    script_setenv("ORIG_UID", 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->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->process_extra_options)
+	(*the_channel->process_extra_options)();
+
+    if (debug)
+	setlogmask(LOG_UPTO(LOG_DEBUG));
+
+    /*
+     * Check that we are running as root.
+     */
+    if (geteuid() != 0) {
+	option_error("must be root to run %s, since it is not setuid-root",
+		     argv[0]);
+	exit(EXIT_NOT_ROOT);
+    }
+
+    if (!ppp_available()) {
+	option_error("%s", 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->check_options != NULL)
+	    (*protp->check_options)();
+    if (the_channel->check_options)
+	(*the_channel->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), "pppd%d", getpid());
+	update_db_entry();
+    } else {
+	warn("Warning: couldn't open ppp database %s", _PATH_PPPDB);
+	if (multilink) {
+	    warn("Warning: disabling multilink");
+	    multilink = 0;
+	}
+    }
+
+    /*
+     * Detach ourselves from the terminal, if required,
+     * and identify who is running us.
+     */
+    if (!nodetach && !updetach)
+	detach();
+    p = getlogin();
+    if (p == NULL) {
+	pw = getpwuid(uid);
+	if (pw != NULL && pw->pw_name != NULL)
+	    p = pw->pw_name;
+	else
+	    p = "(unknown)";
+    }
+    syslog(LOG_NOTICE, "pppd %s started by %s, uid %d", VERSION, p, uid);
+    script_setenv("PPPLOGNAME", p, 0);
+
+    if (devnam[0])
+	script_setenv("DEVICE", devnam, 1);
+    slprintf(numbuf, sizeof(numbuf), "%d", getpid());
+    script_setenv("PPPD_PID", 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 && !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 && !persist)
+		    break;
+		if (get_loop_output())
+		    break;
+	    }
+	    remove_fd(fd_loop);
+	    if (kill_link && !persist)
+		break;
+
+	    /*
+	     * Now we want to bring up the link.
+	     */
+	    demand_block();
+	    info("Starting link");
+	}
+
+	new_phase(PHASE_SERIALCONN);
+
+	devfd = the_channel->connect();
+	if (devfd < 0)
+	    goto fail;
+
+	/* set up the serial device as a ppp interface */
+	tdb_writelock(pppdb);
+	fd_ppp = the_channel->establish_ppp(devfd);
+	if (fd_ppp < 0) {
+	    tdb_writeunlock(pppdb);
+	    status = EXIT_FATAL_ERROR;
+	    goto disconnect;
+	}
+
+	if (!demand && ifunit >= 0)
+	    set_ifunit(1);
+	tdb_writeunlock(pppdb);
+
+	/*
+	 * Start opening the connection and wait for
+	 * incoming events (reply, timeout, etc.).
+	 */
+	notice("Connect: %s <--> %s", ifname, ppp_devnam);
+	gettimeofday(&start_time, NULL);
+	link_stats_valid = 0;
+	script_unsetenv("CONNECT_TIME");
+	script_unsetenv("BYTES_SENT");
+	script_unsetenv("BYTES_RCVD");
+	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, "User request");
+	    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("Connect time %d.%d minutes.", t/10, t%10);
+	    info("Sent %u bytes, received %u bytes.",
+		 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
+		&& unlink(pidfilename) < 0 && errno != ENOENT) 
+		warn("unable to delete pid file %s: %m", 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->disestablish_ppp(devfd);
+	fd_ppp = -1;
+	if (!hungup)
+	    lcp_lowerdown(0);
+	if (!demand)
+	    script_unsetenv("IFNAME");
+
+	/*
+	 * 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->disconnect();
+
+    fail:
+	if (the_channel->cleanup)
+	    (*the_channel->cleanup)();
+
+	if (!demand) {
+	    if (pidfilename[0] != 0
+		&& unlink(pidfilename) < 0 && errno != ENOENT) 
+		warn("unable to delete pid file %s: %m", pidfilename);
+	    pidfilename[0] = 0;
+	}
+
+	if (!persist || (maxfail > 0 && unsuccess >= maxfail))
+	    break;
+
+	if (demand)
+	    demand_discard();
+	t = need_holdoff? holdoff: 0;
+	if (holdoff_hook)
+	    t = (*holdoff_hook)();
+	if (t > 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 > 0) {
+	if (debug) {
+	    struct subprocess *chp;
+	    dbglog("Waiting for %d child processes...", n_children);
+	    for (chp = children; chp != NULL; chp = chp->next)
+		dbglog("  script %s, pid %d", chp->prog, chp->pid);
+	}
+	if (reap_kids(1) < 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, &mask, NULL);
+	if (got_sighup || got_sigterm || got_sigusr2 || got_sigchld) {
+	    sigprocmask(SIG_UNBLOCK, &mask, NULL);
+	} else {
+	    waiting = 1;
+	    sigprocmask(SIG_UNBLOCK, &mask, NULL);
+	    wait_input(timeleft(&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(&mask);
+    sigaddset(&mask, SIGHUP);
+    sigaddset(&mask, SIGINT);
+    sigaddset(&mask, SIGTERM);
+    sigaddset(&mask, SIGCHLD);
+    sigaddset(&mask, SIGUSR2);
+
+#define SIGNAL(s, handler)	do { \
+	sa.sa_handler = handler; \
+	if (sigaction(s, &sa, NULL) < 0) \
+	    fatal("Couldn't establish signal handler (%d): %m", 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("Using interface %s%d", PPP_DRV_NAME, ifunit);
+    slprintf(ifname, sizeof(ifname), "%s%d", PPP_DRV_NAME, ifunit);
+    script_setenv("IFNAME", 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()) < 0) {
+	error("Couldn't detach (fork failed: %m)");
+	die(1);			/* or just return? */
+    }
+    if (pid != 0) {
+	/* parent */
+	notify(pidchange, pid);
+	exit(0);		/* parent dies */
+    }
+    setsid();
+    chdir("/");
+    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), "%d", getpid());
+    script_setenv("PPPD_PID", numbuf, 1);
+}
+
+/*
+ * reopen_log - (re)open our connection to syslog.
+ */
+void
+reopen_log()
+{
+#ifdef ULTRIX
+    openlog("pppd", LOG_PID);
+#else
+    openlog("pppd", 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), "%s%s.pid",
+	     _PATH_VARRUN, ifname);
+    if ((pidfile = fopen(pidfilename, "w")) != NULL) {
+	fprintf(pidfile, "%d\n", getpid());
+	(void) fclose(pidfile);
+    } else {
+	error("Failed to create pid file %s: %m", pidfilename);
+	pidfilename[0] = 0;
+    }
+}
+
+static void
+create_linkpidfile()
+{
+    FILE *pidfile;
+
+    if (linkname[0] == 0)
+	return;
+    script_setenv("LINKNAME", linkname, 1);
+    slprintf(linkpidfile, sizeof(linkpidfile), "%sppp-%s.pid",
+	     _PATH_VARRUN, linkname);
+    if ((pidfile = fopen(linkpidfile, "w")) != NULL) {
+	fprintf(pidfile, "%d\n", getpid());
+	if (ifname[0])
+	    fprintf(pidfile, "%s\n", ifname);
+	(void) fclose(pidfile);
+    } else {
+	error("Failed to create pid file %s: %m", 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,	"IP" },
+    { 0x23,	"OSI Network Layer" },
+    { 0x25,	"Xerox NS IDP" },
+    { 0x27,	"DECnet Phase IV" },
+    { 0x29,	"Appletalk" },
+    { 0x2b,	"Novell IPX" },
+    { 0x2d,	"VJ compressed TCP/IP" },
+    { 0x2f,	"VJ uncompressed TCP/IP" },
+    { 0x31,	"Bridging PDU" },
+    { 0x33,	"Stream Protocol ST-II" },
+    { 0x35,	"Banyan Vines" },
+    { 0x39,	"AppleTalk EDDP" },
+    { 0x3b,	"AppleTalk SmartBuffered" },
+    { 0x3d,	"Multi-Link" },
+    { 0x3f,	"NETBIOS Framing" },
+    { 0x41,	"Cisco Systems" },
+    { 0x43,	"Ascom Timeplex" },
+    { 0x45,	"Fujitsu Link Backup and Load Balancing (LBLB)" },
+    { 0x47,	"DCA Remote Lan" },
+    { 0x49,	"Serial Data Transport Protocol (PPP-SDTP)" },
+    { 0x4b,	"SNA over 802.2" },
+    { 0x4d,	"SNA" },
+    { 0x4f,	"IP6 Header Compression" },
+    { 0x6f,	"Stampede Bridging" },
+    { 0xfb,	"single-link compression" },
+    { 0xfd,	"1st choice compression" },
+    { 0x0201,	"802.1d Hello Packets" },
+    { 0x0203,	"IBM Source Routing BPDU" },
+    { 0x0205,	"DEC LANBridge100 Spanning Tree" },
+    { 0x0231,	"Luxcom" },
+    { 0x0233,	"Sigma Network Systems" },
+    { 0x8021,	"Internet Protocol Control Protocol" },
+    { 0x8023,	"OSI Network Layer Control Protocol" },
+    { 0x8025,	"Xerox NS IDP Control Protocol" },
+    { 0x8027,	"DECnet Phase IV Control Protocol" },
+    { 0x8029,	"Appletalk Control Protocol" },
+    { 0x802b,	"Novell IPX Control Protocol" },
+    { 0x8031,	"Bridging NCP" },
+    { 0x8033,	"Stream Protocol Control Protocol" },
+    { 0x8035,	"Banyan Vines Control Protocol" },
+    { 0x803d,	"Multi-Link Control Protocol" },
+    { 0x803f,	"NETBIOS Framing Control Protocol" },
+    { 0x8041,	"Cisco Systems Control Protocol" },
+    { 0x8043,	"Ascom Timeplex" },
+    { 0x8045,	"Fujitsu LBLB Control Protocol" },
+    { 0x8047,	"DCA Remote Lan Network Control Protocol (RLNCP)" },
+    { 0x8049,	"Serial Data Control Protocol (PPP-SDCP)" },
+    { 0x804b,	"SNA over 802.2 Control Protocol" },
+    { 0x804d,	"SNA Control Protocol" },
+    { 0x804f,	"IP6 Header Compression Control Protocol" },
+    { 0x006f,	"Stampede Bridging Control Protocol" },
+    { 0x80fb,	"Single Link Compression Control Protocol" },
+    { 0x80fd,	"Compression Control Protocol" },
+    { 0xc021,	"Link Control Protocol" },
+    { 0xc023,	"Password Authentication Protocol" },
+    { 0xc025,	"Link Quality Report" },
+    { 0xc027,	"Shiva Password Authentication Protocol" },
+    { 0xc029,	"CallBack Control Protocol (CBCP)" },
+    { 0xc081,	"Container Control Protocol" },
+    { 0xc223,	"Challenge Handshake Authentication Protocol" },
+    { 0xc281,	"Proprietary Authentication Protocol" },
+    { 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->proto != 0; ++lp)
+	if (proto == lp->proto)
+	    return lp->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 < 0)
+	return;
+
+    if (len == 0) {
+	notice("Modem hangup");
+	hungup = 1;
+	status = EXIT_HANGUP;
+	lcp_lowerdown(0);	/* serial link is no longer available */
+	link_terminated(0);
+	return;
+    }
+
+    if (debug /*&& (debugflags & DBG_INPACKET)*/)
+	dbglog("rcvd %P", p, len);
+
+    if (len < PPP_HDRLEN) {
+	MAINDEBUG(("io(): Received short packet."));
+	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 && lcp_fsm[0].state != OPENED) {
+	MAINDEBUG(("get_input: Received non-LCP packet when LCP not open."));
+	return;
+    }
+
+    /*
+     * Until we get past the authentication phase, toss all packets
+     * except LCP, LQR and authentication packets.
+     */
+    if (phase <= PHASE_AUTHENTICATE
+	&& !(protocol == PPP_LCP || protocol == PPP_LQR
+	     || protocol == PPP_PAP || protocol == PPP_CHAP)) {
+	MAINDEBUG(("get_input: discarding proto 0x%x in phase %d",
+		   protocol, phase));
+	return;
+    }
+
+    /*
+     * Upcall the proper protocol input routine.
+     */
+    for (i = 0; (protp = protocols[i]) != NULL; ++i) {
+	if (protp->protocol == protocol && protp->enabled_flag) {
+	    (*protp->input)(0, p, len);
+	    return;
+	}
+        if (protocol == (protp->protocol & ~0x8000) && protp->enabled_flag
+	    && protp->datainput != NULL) {
+	    (*protp->datainput)(0, p, len);
+	    return;
+	}
+    }
+
+    if (debug) {
+	const char *pname = protocol_name(protocol);
+	if (pname != NULL)
+	    warn("Unsupported protocol '%s' (0x%x) received", pname, protocol);
+	else
+	    warn("Unsupported protocol 0x%x received", 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, "Exit.");
+    exit(status);
+}
+
+/*
+ * cleanup - restore anything which needs to be restored before we exit
+ */
+/* ARGSUSED */
+static void
+cleanup()
+{
+    sys_cleanup();
+
+    if (fd_ppp >= 0)
+	the_channel->disestablish_ppp(devfd);
+    if (the_channel->cleanup)
+	(*the_channel->cleanup)();
+
+    if (pidfilename[0] != 0 && unlink(pidfilename) < 0 && errno != ENOENT) 
+	warn("unable to delete pid file %s: %m", pidfilename);
+    pidfilename[0] = 0;
+    if (linkpidfile[0] != 0 && unlink(linkpidfile) < 0 && errno != ENOENT) 
+	warn("unable to delete pid file %s: %m", 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, &link_stats)
+	|| gettimeofday(&now, NULL) < 0)
+	return;
+    link_connect_time = now.tv_sec - start_time.tv_sec;
+    link_stats_valid = 1;
+
+    slprintf(numbuf, sizeof(numbuf), "%d", link_connect_time);
+    script_setenv("CONNECT_TIME", numbuf, 0);
+    slprintf(numbuf, sizeof(numbuf), "%d", link_stats.bytes_out);
+    script_setenv("BYTES_SENT", numbuf, 0);
+    slprintf(numbuf, sizeof(numbuf), "%d", link_stats.bytes_in);
+    script_setenv("BYTES_RCVD", 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(("Timeout %p:%p in %d.%03d seconds.", func, arg,
+	       time / 1000, time % 1000));
+  
+    /*
+     * Allocate timeout.
+     */
+    if ((newp = (struct callout *) malloc(sizeof(struct callout))) == NULL)
+	fatal("Out of memory in timeout()!");
+    newp->c_arg = arg;
+    newp->c_func = func;
+    gettimeofday(&timenow, NULL);
+    newp->c_time.tv_sec = timenow.tv_sec + secs;
+    newp->c_time.tv_usec = timenow.tv_usec + usecs;
+    if (newp->c_time.tv_usec >= 1000000) {
+	newp->c_time.tv_sec += newp->c_time.tv_usec / 1000000;
+	newp->c_time.tv_usec %= 1000000;
+    }
+
+    /*
+     * Find correct place and link it in.
+     */
+    for (pp = &callout; (p = *pp); pp = &p->c_next)
+	if (newp->c_time.tv_sec < p->c_time.tv_sec
+	    || (newp->c_time.tv_sec == p->c_time.tv_sec
+		&& newp->c_time.tv_usec < p->c_time.tv_usec))
+	    break;
+    newp->c_next = p;
+    *pp = newp;
+}
+
+
+/*
+ * untimeout - Unschedule a timeout.
+ */
+void
+untimeout(func, arg)
+    void (*func) __P((void *));
+    void *arg;
+{
+    struct callout **copp, *freep;
+  
+    MAINDEBUG(("Untimeout %p:%p.", func, arg));
+  
+    /*
+     * Find first matching timeout and remove it from the list.
+     */
+    for (copp = &callout; (freep = *copp); copp = &freep->c_next)
+	if (freep->c_func == func && freep->c_arg == arg) {
+	    *copp = freep->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(&timenow, NULL) < 0)
+	    fatal("Failed to get time of day: %m");
+	if (!(p->c_time.tv_sec < timenow.tv_sec
+	      || (p->c_time.tv_sec == timenow.tv_sec
+		  && p->c_time.tv_usec <= timenow.tv_usec)))
+	    break;		/* no, it's not time yet */
+
+	callout = p->c_next;
+	(*p->c_func)(p->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(&timenow, NULL);
+    tvp->tv_sec = callout->c_time.tv_sec - timenow.tv_sec;
+    tvp->tv_usec = callout->c_time.tv_usec - timenow.tv_usec;
+    if (tvp->tv_usec < 0) {
+	tvp->tv_usec += 1000000;
+	tvp->tv_sec -= 1;
+    }
+    if (tvp->tv_sec < 0)
+	tvp->tv_sec = tvp->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, &act, &oldact);
+    sigaction(sig, &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("Hangup (SIGHUP)");
+    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("Terminating on signal %d.", 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("Fatal signal %d", 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 < 0) {
+	--conn_running;
+	error("Failed to create child process: %m");
+	return -1;
+    }
+
+    if (pid != 0) {
+	if (dont_wait) {
+	    record_child(pid, program, NULL, NULL);
+	    status = 0;
+	} else {
+	    while (waitpid(pid, &status, 0) < 0) {
+		if (errno == EINTR)
+		    continue;
+		fatal("error waiting for (dis)connection process: %m");
+	    }
+	    --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)) >= 0) {
+	if (fd > 2) {
+	    close(fd);
+	    break;
+	}
+    }
+
+    /* dup in and out to fds > 2 */
+    in = dup(in);
+    out = dup(out);
+    if (log_to_fd >= 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->close)
+	(*the_channel->close)();
+    closelog();
+
+    /* dup the in, out, err fds to 0, 1, 2 */
+    dup2(in, 0);
+    close(in);
+    dup2(out, 1);
+    close(out);
+    if (errfd >= 0) {
+	dup2(errfd, 2);
+	close(errfd);
+    }
+
+    setuid(uid);
+    if (getuid() != uid) {
+	error("setuid failed");
+	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("could not exec %s: %m", 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 > 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, &sbuf) < 0 || !S_ISREG(sbuf.st_mode)
+	|| (sbuf.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0) {
+	if (must_exist || errno != ENOENT)
+	    warn("Can't execute %s: %m", prog);
+	return 0;
+    }
+
+    pid = fork();
+    if (pid == -1) {
+	error("Failed to create child process for %s: %m", 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 ("/");	/* 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->close)
+	    (*the_channel->close)();
+
+        /* Don't pass handles to the PPP device, even by accident. */
+	new_fd = open (_PATH_DEVNULL, O_RDWR);
+	if (new_fd >= 0) {
+	    if (new_fd != 0) {
+	        dup2  (new_fd, 0); /* stdin <- /dev/null */
+		close (new_fd);
+	    }
+	    dup2 (0, 1); /* stdout -> /dev/null */
+	    dup2 (0, 2); /* stderr -> /dev/null */
+	}
+
+#ifdef BSD
+	/* Force the priority back to zero if pppd is running higher. */
+	if (setpriority (PRIO_PROCESS, 0, 0) < 0)
+	    warn("can't reset priority to 0: %m"); 
+#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, "Can't execute %s: %m", prog);
+	    closelog();
+	}
+	_exit(-1);
+    }
+
+    if (debug)
+	dbglog("Script %s started (pid %d)", 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("losing track of %s process", prog);
+    } else {
+	chp->pid = pid;
+	chp->prog = prog;
+	chp->done = done;
+	chp->arg = arg;
+	chp->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, &status, (waitfor? 0: WNOHANG))) != -1
+	   && pid != 0) {
+	for (prevp = &children; (chp = *prevp) != NULL; prevp = &chp->next) {
+	    if (chp->pid == pid) {
+		--n_children;
+		*prevp = chp->next;
+		break;
+	    }
+	}
+	if (WIFSIGNALED(status)) {
+	    warn("Child process %s (pid %d) terminated with signal %d",
+		 (chp? chp->prog: "??"), pid, WTERMSIG(status));
+	} else if (debug)
+	    dbglog("Script %s finished (pid %d), status = 0x%x",
+		   (chp? chp->prog: "??"), pid, status);
+	if (chp && chp->done)
+	    (*chp->done)(chp->arg);
+	if (chp)
+	    free(chp);
+    }
+    if (pid == -1) {
+	if (errno == ECHILD)
+	    return -1;
+	if (errno != EINTR)
+	    error("Error waiting for child process: %m");
+    }
+    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("notifier struct");
+    np->next = *notif;
+    np->func = func;
+    np->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 = &np->next) {
+	if (np->func == func && np->arg == arg) {
+	    *notif = np->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->next;
+	(*np->func)(np->arg, val);
+    }
+}
+
+/*
+ * novm - log an error message saying we ran out of memory, and die.
+ */
+void
+novm(msg)
+    char *msg;
+{
+    fatal("Virtual memory exhausted allocating %s\n", 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, "%s=%s", 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 && p[varl] == '=') {
+		if (p[-1] && pppdb != NULL)
+		    delete_db_key(p);
+		free(p-1);
+		script_env[i] = newstring;
+		if (iskey && 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 >= 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 && p[vl] == '=') {
+	    if (p[-1] && 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("database entry");
+    q = vbuf;
+    for (i = 0; (p = script_env[i]) != 0; ++i)
+	q += slprintf(q, vbuf + vlen - q, "%s;", 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("tdb_store failed: %s", 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("tdb_store key failed: %s", 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(&MD)
+**   -- For each full block (64 bytes) X you wish to process, call
+**          MD4Update(&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(&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(&MD)
+*/
+
+/* Implementation notes:
+** This implementation assumes that ints are 32-bit quantities.
+*/
+
+#define TRUE  1
+#define FALSE 0
+
+/* Compile-time includes
+*/
+#include <stdio.h>
+#include "md4.h"
+#include "pppd.h"
+
+/* Compile-time declarations of MD4 "magic constants".
+*/
+#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 "rot" operator uses the variable "tmp".
+** It assumes tmp is declared as unsigned int, so that the >>
+** operator will shift in zeros rather than extending the sign bit.
+*/
+#define f(X,Y,Z)             ((X&Y) | ((~X)&Z))
+#define g(X,Y,Z)             ((X&Y) | (X&Z) | (Y&Z))
+#define h(X,Y,Z)             (X^Y^Z)
+#define rot(X,S)             (tmp=X,(tmp<<S) | (tmp>>(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<4;i++)
+    for (j=0;j<32;j=j+8)
+      printf("%02x",(MDp->buffer[i]>>j) & 0xFF);
+}
+
+/* MD4Init(MDp)
+** Initialize message digest buffer MDp.
+** This is a user-callable routine.
+*/
+void
+MD4Init(MDp)
+MD4_CTX *MDp;
+{
+  int i;
+  MDp->buffer[0] = I0;
+  MDp->buffer[1] = I1;
+  MDp->buffer[2] = I2;
+  MDp->buffer[3] = I3;
+  for (i=0;i<8;i++) MDp->count[i] = 0;
+  MDp->done = 0;
+}
+
+/* MDblock(MDp,X)
+** Update message digest buffer MDp->buffer using 16-word data block X.
+** Assumes all 16 words of X are full of data.
+** Does not update MDp->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 < 16; ++i) {
+    X[i] = Xb[0] + (Xb[1] << 8) + (Xb[2] << 16) + (Xb[3] << 24);
+    Xb += 4;
+  }
+
+  A = MDp->buffer[0];
+  B = MDp->buffer[1];
+  C = MDp->buffer[2];
+  D = MDp->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->buffer[0] += A;
+  MDp->buffer[1] += B;
+  MDp->buffer[2] += C;
+  MDp->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 < 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 "courtesy close" 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->done is true.
+  */
+  if (count == 0 && MDp->done) return;
+  /* check to see if MD is already done and report error */
+  if (MDp->done)
+  { printf("\nError: MD4Update MD already done."); return; }
+
+  /* Add count to MDp->count */
+  tmp = count;
+  p = MDp->count;
+  while (tmp)
+  { tmp += *p;
+  *p++ = tmp;
+  tmp = tmp >> 8;
+  }
+
+  /* Process data */
+  if (count == 512)
+  { /* Full block of data to handle */
+    MDblock(MDp,X);
+  }
+  else if (count > 512) /* Check for count too large */
+  {
+    printf("\nError: MD4Update called with illegal count value %d.",
+	   count);
+    return;
+  }
+  else /* partial block -- must be last block so finish up */
+  {
+    /* Find out how many bytes and residual bits there are */
+    byte = count >> 3;
+    bit =  count & 7;
+    /* Copy X into XX since we need to modify it */
+    for (i=0;i<=byte;i++)   XX[i] = X[i];
+    for (i=byte+1;i<64;i++) XX[i] = 0;
+    /* Add padding '1' bit and low-order zeros in last byte */
+    mask = 1 << (7 - bit);
+    XX[byte] = (XX[byte] | mask) & ~( mask - 1);
+    /* If room for bit count, finish up with this block */
+    if (byte <= 55)
+    {
+      for (i=0;i<8;i++) XX[56+i] = MDp->count[i];
+      MDblock(MDp,XX);
+    }
+    else /* need to do two blocks to finish up */
+    {
+      MDblock(MDp,XX);
+      for (i=0;i<56;i++) XX[i] = 0;
+      for (i=0;i<8;i++)  XX[56+i] = MDp->count[i];
+      MDblock(MDp,XX);
+    }
+    /* Set flag saying we're done with MD computation */
+    MDp->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 < 4; ++i) {
+    w = MD->buffer[i];
+    for (j = 0; j < 4; ++j) {
+      *buf++ = w;
+      w >>= 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 "count" 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 < 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 "RSA Data Security, Inc. MD5 Message-     **
+ ** Digest Algorithm" 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 "derived from the RSA  **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" 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 "as  **
+ ** is" 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 <stdlib.h>
+#include <string.h>
+
+#include "md5.h"
+
+/*
+ ***********************************************************************
+ **  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->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) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~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) << (n)) | ((x) >> (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->i[0] = mdContext->i[1] = (UINT4)0;
+
+  /* Load magic initialization constants.
+   */
+  mdContext->buf[0] = (UINT4)0x67452301;
+  mdContext->buf[1] = (UINT4)0xefcdab89;
+  mdContext->buf[2] = (UINT4)0x98badcfe;
+  mdContext->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->i[0] >> 3) & 0x3F);
+
+  /* update number of bits */
+  if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0])
+    mdContext->i[1]++;
+  mdContext->i[0] += ((UINT4)inLen << 3);
+  mdContext->i[1] += ((UINT4)inLen >> 29);
+
+  while (inLen--) {
+    /* add new character to buffer, increment mdi */
+    mdContext->in[mdi++] = *inBuf++;
+
+    /* transform if necessary */
+    if (mdi == 0x40) {
+      for (i = 0, ii = 0; i < 16; i++, ii += 4)
+        in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
+                (((UINT4)mdContext->in[ii+2]) << 16) |
+                (((UINT4)mdContext->in[ii+1]) << 8) |
+                ((UINT4)mdContext->in[ii]);
+      Transform (mdContext->buf, in);
+      mdi = 0;
+    }
+  }
+}
+
+/* The routine MD5Final terminates the message-digest computation and
+   ends with the desired message digest in mdContext->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->i[0];
+  in[15] = mdContext->i[1];
+
+  /* compute number of bytes mod 64 */
+  mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+  /* pad out to 56 mod 64 */
+  padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
+  MD5Update (mdContext, PADDING, padLen);
+
+  /* append length in bits and transform */
+  for (i = 0, ii = 0; i < 14; i++, ii += 4)
+    in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
+            (((UINT4)mdContext->in[ii+2]) << 16) |
+            (((UINT4)mdContext->in[ii+1]) << 8) |
+            ((UINT4)mdContext->in[ii]);
+  Transform (mdContext->buf, in);
+
+  /* store buffer in digest */
+  for (i = 0, ii = 0; i < 4; i++, ii += 4) {
+    mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
+    mdContext->digest[ii+1] =
+      (unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
+    mdContext->digest[ii+2] =
+      (unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
+    mdContext->digest[ii+3] =
+      (unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
+  }
+  memcpy(hash, mdContext->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&~z instead of y&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 "RSA Data Security, Inc. MD5 Message-     **
+ ** Digest Algorithm" 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 "derived from the RSA  **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" 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 "as  **
+ ** is" 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 <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <errno.h>
+#include <signal.h>
+#include <netinet/in.h>
+
+#include "pppd.h"
+#include "fsm.h"
+#include "lcp.h"
+#include "tdb.h"
+
+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->length = 4;			\
+	ep->value[0] = addr >> 24;	\
+	ep->value[1] = addr >> 16;	\
+	ep->value[2] = addr >> 8;	\
+	ep->value[3] = addr;		\
+} while (0)
+
+#define LOCAL_IP_ADDR(addr)						  \
+	(((addr) & 0xff000000) == 0x0a000000		/* 10.x.x.x */	  \
+	 || ((addr) & 0xfff00000) == 0xac100000		/* 172.16.x.x */  \
+	 || ((addr) & 0xffff0000) == 0xc0a80000)	/* 192.168.x.x */
+
+#define process_exists(n)	(kill((n), 0) == 0 || errno != ESRCH)
+
+void
+mp_check_options()
+{
+	lcp_options *wo = &lcp_wantoptions[0];
+	lcp_options *ao = &lcp_allowoptions[0];
+
+	if (!multilink)
+		return;
+	/* if we're doing multilink, we have to negotiate MRRU */
+	if (!wo->neg_mrru) {
+		/* mrru not specified, default to mru */
+		wo->mrru = wo->mru;
+		wo->neg_mrru = 1;
+	}
+	ao->mrru = ao->mru;
+	ao->neg_mrru = 1;
+
+	if (!wo->neg_endpoint && !noendpoint) {
+		/* get a default endpoint value */
+		wo->neg_endpoint = get_default_epdisc(&wo->endpoint);
+	}
+}
+
+/*
+ * Make a new bundle or join us to an existing bundle
+ * if we are doing multilink.
+ */
+int
+mp_join_bundle()
+{
+	lcp_options *go = &lcp_gotoptions[0];
+	lcp_options *ho = &lcp_hisoptions[0];
+	lcp_options *ao = &lcp_allowoptions[0];
+	int unit, pppd_pid;
+	int l, mtu;
+	char *p;
+	TDB_DATA key, pid, rec;
+
+	if (!go->neg_mrru || !ho->neg_mrru) {
+		/* not doing multilink */
+		if (go->neg_mrru)
+			notice("oops, multilink negotiated only for receive");
+		mtu = ho->neg_mru? ho->mru: PPP_MRU;
+		if (mtu > ao->mru)
+			mtu = ao->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->neg_endpoint)
+		l += 3 * ho->endpoint.length + 8;
+	if (bundle_name)
+		l += 3 * strlen(bundle_name) + 2;
+	bundle_id = malloc(l);
+	if (bundle_id == 0)
+		novm("bundle identifier");
+
+	p = bundle_id;
+	p += slprintf(p, l-1, "BUNDLE=\"%q\"", peer_authname);
+	if (ho->neg_endpoint || bundle_name)
+		*p++ = '/';
+	if (ho->neg_endpoint)
+		p += slprintf(p, bundle_id+l-p, "%s",
+			      epdisc_to_str(&ho->endpoint));
+	if (bundle_name)
+		p += slprintf(p, bundle_id+l-p, "/%v", bundle_name);
+
+	/*
+	 * For demand mode, we only need to configure the bundle
+	 * and attach the link.
+	 */
+	mtu = MIN(ho->mrru, ao->mru);
+	if (demand) {
+		cfg_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf);
+		netif_set_mtu(0, mtu);
+		script_setenv("BUNDLE", 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, "IFNAME=ppp", &unit);
+			/* check the pid value */
+			if (!parse_num(rec.dptr, "PPPD_PID=", &pppd_pid)
+			    || !process_exists(pppd_pid)
+			    || !owns_unit(pid, unit))
+				unit = -1;
+			free(rec.dptr);
+		}
+		free(pid.dptr);
+	}
+
+	if (unit >= 0) {
+		/* attach to existing unit */
+		if (bundle_attach(unit)) {
+			set_ifunit(0);
+			script_setenv("BUNDLE", bundle_id + 7, 0);
+			tdb_writeunlock(pppdb);
+			info("Link attached to %s", ifname);
+			return 1;
+		}
+		/* attach failed because bundle doesn't exist */
+	}
+
+	/* we have to make a new bundle */
+	make_new_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf);
+	set_ifunit(1);
+	netif_set_mtu(0, mtu);
+	script_setenv("BUNDLE", bundle_id + 7, 1);
+	tdb_writeunlock(pppdb);
+	info("New bundle %s created", 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, &endp, 10);
+		if (endp != p && (*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), "IFNAME=ppp%d", unit);
+	kd.dptr = ifkey;
+	kd.dsize = strlen(ifkey);
+	vd = tdb_fetch(pppdb, kd);
+	if (vd.dptr != NULL) {
+		ret = vd.dsize == key.dsize
+			&& 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 && get_if_hwaddr(ep->value, p) >= 0) {
+		ep->class = EPD_MAC;
+		ep->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->h_addr;
+		if (!bad_ip_adrs(addr)) {
+			addr = ntohl(addr);
+			if (!LOCAL_IP_ADDR(addr)) {
+				ep->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[] = {
+    "null", "local", "IP", "MAC", "magic", "phone"
+};
+
+char *
+epdisc_to_str(ep)
+     struct epdisc *ep;
+{
+	static char str[MAX_ENDP_LEN*3+8];
+	u_char *p = ep->value;
+	int i, mask = 0;
+	char *q, c, c2;
+
+	if (ep->class == EPD_NULL && ep->length == 0)
+		return "null";
+	if (ep->class == EPD_IP && ep->length == 4) {
+		u_int32_t addr;
+
+		GETLONG(addr, p);
+		slprintf(str, sizeof(str), "IP:%I", htonl(addr));
+		return str;
+	}
+
+	c = ':';
+	c2 = '.';
+	if (ep->class == EPD_MAC && ep->length == 6)
+		c2 = ':';
+	else if (ep->class == EPD_MAGIC && (ep->length % 4) == 0)
+		mask = 3;
+	q = str;
+	if (ep->class <= EPD_PHONENUM)
+		q += slprintf(q, sizeof(str)-1, "%s",
+			      endp_class_names[ep->class]);
+	else
+		q += slprintf(q, sizeof(str)-1, "%d", ep->class);
+	c = ':';
+	for (i = 0; i < ep->length && i < MAX_ENDP_LEN; ++i) {
+		if ((i & mask) == 0) {
+			*q++ = c;
+			c = c2;
+		}
+		q += slprintf(q, str + sizeof(str) - q, "%.2x", ep->value[i]);
+	}
+	return str;
+}
+
+static int hexc_val(int c)
+{
+	if (c >= 'a')
+		return c - 'a' + 10;
+	if (c >= '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 <= EPD_PHONENUM; ++i) {
+		int sl = strlen(endp_class_names[i]);
+		if (strncasecmp(str, endp_class_names[i], sl) == 0) {
+			str += sl;
+			break;
+		}
+	}
+	if (i > EPD_PHONENUM) {
+		/* not a class name, try a decimal class number */
+		i = strtol(str, &endp, 10);
+		if (endp == str)
+			return 0;	/* can't parse class number */
+		str = endp;
+	}
+	ep->class = i;
+	if (*str == 0) {
+		ep->length = 0;
+		return 1;
+	}
+	if (*str != ':' && *str != '.')
+		return 0;
+	++str;
+
+	if (i == EPD_IP) {
+		u_int32_t addr;
+		i = parse_dotted_ip(str, &addr);
+		if (i == 0 || str[i] != 0)
+			return 0;
+		set_ip_epdisc(ep, addr);
+		return 1;
+	}
+	if (i == EPD_MAC && get_if_hwaddr(ep->value, str) >= 0) {
+		ep->length = 6;
+		return 1;
+	}
+
+	p = str;
+	for (l = 0; l < MAX_ENDP_LEN; ++l) {
+		if (*str == 0)
+			break;
+		if (p <= str)
+			for (p = str; isxdigit(*p); ++p)
+				;
+		i = p - str;
+		if (i == 0)
+			return 0;
+		ep->value[l] = hexc_val(*str++);
+		if ((i & 1) == 0)
+			ep->value[l] = (ep->value[l] << 4) + hexc_val(*str++);
+		if (*str == ':' || *str == '.')
+			++str;
+	}
+	if (*str != 0 || (ep->class == EPD_MAC && l != 6))
+		return 0;
+	ep->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	"$Id: options.c 195734 2001-06-11 14:46:02Z gc $"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <string.h>
+#include <pwd.h>
+#ifdef PLUGIN
+#include <dlfcn.h>
+#endif
+#ifdef PPP_FILTER
+#include <pcap.h>
+#include <pcap-int.h>	/* XXX: To get struct pcap */
+#endif
+
+#include "pppd.h"
+#include "pathnames.h"
+
+#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[] = {
+    { "debug", o_int, &debug,
+      "Increase debugging level", OPT_INC | OPT_NOARG | 1 },
+    { "-d", o_int, &debug,
+      "Increase debugging level",
+      OPT_ALIAS | OPT_INC | OPT_NOARG | 1 },
+
+    { "kdebug", o_int, &kdebugflag,
+      "Set kernel driver debug level", OPT_PRIO },
+
+    { "nodetach", o_bool, &nodetach,
+      "Don't detach from controlling tty", OPT_PRIO | 1 },
+    { "-detach", o_bool, &nodetach,
+      "Don't detach from controlling tty", OPT_ALIAS | OPT_PRIOSUB | 1 },
+    { "updetach", o_bool, &updetach,
+      "Detach from controlling tty once link is up",
+      OPT_PRIOSUB | OPT_A2CLR | 1, &nodetach },
+
+    { "holdoff", o_int, &holdoff,
+      "Set time in seconds before retrying connection", OPT_PRIO },
+
+    { "idle", o_int, &idle_time_limit,
+      "Set time in seconds before disconnecting idle link", OPT_PRIO },
+
+    { "maxconnect", o_int, &maxconnect,
+      "Set connection time limit",
+      OPT_PRIO | OPT_LLIMIT | OPT_NOINCR | OPT_ZEROINF },
+
+    { "domain", o_special, (void *)setdomain,
+      "Add given domain name to hostname",
+      OPT_PRIO | OPT_PRIV | OPT_A2STRVAL, &domain },
+
+    { "file", o_special, (void *)readfile,
+      "Take options from a file", OPT_NOPRINT },
+    { "call", o_special, (void *)callfile,
+      "Take options from a privileged file", OPT_NOPRINT },
+
+    { "persist", o_bool, &persist,
+      "Keep on reopening connection after close", OPT_PRIO | 1 },
+    { "nopersist", o_bool, &persist,
+      "Turn off persist option", OPT_PRIOSUB },
+
+    { "demand", o_bool, &demand,
+      "Dial on demand", OPT_INITONLY | 1, &persist },
+
+    { "--version", o_special_noarg, (void *)showversion,
+      "Show version number" },
+    { "--help", o_special_noarg, (void *)showhelp,
+      "Show brief listing of options" },
+    { "-h", o_special_noarg, (void *)showhelp,
+      "Show brief listing of options", OPT_ALIAS },
+
+    { "logfile", o_special, (void *)setlogfile,
+      "Append log messages to this file",
+      OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, &logfile_name },
+    { "logfd", o_int, &log_to_fd,
+      "Send log messages to this file descriptor",
+      OPT_PRIOSUB | OPT_A2CLR, &log_default },
+    { "nolog", o_int, &log_to_fd,
+      "Don't send log messages to any file",
+      OPT_PRIOSUB | OPT_NOARG | OPT_VAL(-1) },
+    { "nologfd", o_int, &log_to_fd,
+      "Don't send log messages to any file descriptor",
+      OPT_PRIOSUB | OPT_ALIAS | OPT_NOARG | OPT_VAL(-1) },
+
+    { "linkname", o_string, linkname,
+      "Set logical name for link",
+      OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, MAXPATHLEN },
+
+    { "maxfail", o_int, &maxfail,
+      "Maximum number of unsuccessful connection attempts to allow",
+      OPT_PRIO },
+
+    { "ktune", o_bool, &tune_kernel,
+      "Alter kernel settings as necessary", OPT_PRIO | 1 },
+    { "noktune", o_bool, &tune_kernel,
+      "Don't alter kernel settings", OPT_PRIOSUB },
+
+    { "connect-delay", o_int, &connect_delay,
+      "Maximum time (in ms) to wait after connect script finishes",
+      OPT_PRIO },
+
+    { "unit", o_int, &req_unit,
+      "PPP interface unit number to use if possible",
+      OPT_PRIO | OPT_LLIMIT, 0, 0 },
+
+    { "dump", o_bool, &dump_options,
+      "Print out option values after parsing all options", 1 },
+    { "dryrun", o_bool, &dryrun,
+      "Stop after parsing, printing, and checking options", 1 },
+
+#ifdef HAVE_MULTILINK
+    { "multilink", o_bool, &multilink,
+      "Enable multilink operation", OPT_PRIO | 1 },
+    { "mp", o_bool, &multilink,
+      "Enable multilink operation", OPT_PRIOSUB | OPT_ALIAS | 1 },
+    { "nomultilink", o_bool, &multilink,
+      "Disable multilink operation", OPT_PRIOSUB | 0 },
+    { "nomp", o_bool, &multilink,
+      "Disable multilink operation", OPT_PRIOSUB | OPT_ALIAS | 0 },
+
+    { "bundle", o_string, &bundle_name,
+      "Bundle name for multilink", OPT_PRIO },
+#endif /* HAVE_MULTILINK */
+
+#ifdef PLUGIN
+    { "plugin", o_special, (void *)loadplugin,
+      "Load a plug-in module into pppd", OPT_PRIV | OPT_A2LIST },
+#endif
+
+#ifdef PPP_FILTER
+    { "pdebug", o_int, &dflag,
+      "libpcap debugging", OPT_PRIO },
+
+    { "pass-filter", 1, setpassfilter,
+      "set filter for packets to pass", OPT_PRIO },
+
+    { "active-filter", 1, setactivefilter,
+      "set filter for active pkts", OPT_PRIO },
+#endif
+
+    { NULL }
+};
+
+#ifndef IMPLEMENTATION
+#define IMPLEMENTATION ""
+#endif
+
+static char *usage_string = "\
+pppd version %s\n\
+Usage: %s [ options ], where options are:\n\
+	<device>	Communicate over the named device\n\
+	<speed>		Set the baud rate to <speed>\n\
+	<loc>:<rem>	Set the local and/or remote interface IP\n\
+			addresses.  Either one may be omitted.\n\
+	asyncmap <n>	Set the desired async map to hex <n>\n\
+	auth		Require authentication from peer\n\
+        connect <p>     Invoke shell command <p> to set up the serial line\n\
+	crtscts		Use hardware RTS/CTS flow control\n\
+	defaultroute	Add default route through interface\n\
+	file <f>	Take options from file <f>\n\
+	modem		Use modem control lines\n\
+	mru <n>		Set MRU value to <n> for negotiation\n\
+See pppd(8) for more options.\n\
+";
+
+/*
+ * 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 = "command line";
+    option_priority = OPRIO_CMDLINE;
+    while (argc > 0) {
+	arg = *argv++;
+	--argc;
+	opt = find_option(arg);
+	if (opt == NULL) {
+	    option_error("unrecognized option '%s'", arg);
+	    usage();
+	    return 0;
+	}
+	n = n_arguments(opt);
+	if (argc < n) {
+	    option_error("too few parameters for option %s", 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, "r");
+    err = errno;
+    if (check_prot)
+	seteuid(0);
+    if (f == NULL) {
+	errno = err;
+	if (!must_exist) {
+	    if (err != ENOENT && err != ENOTDIR)
+		warn("Warning: can't open options file %s: %m", filename);
+	    return 1;
+	}
+	option_error("Can't open options file %s: %m", filename);
+	return 0;
+    }
+
+    oldpriv = privileged_option;
+    privileged_option = priv;
+    oldsource = option_source;
+    option_source = strdup(filename);
+    if (option_source == NULL)
+	option_source = "file";
+    ret = 0;
+    while (getword(f, cmd, &newline, filename)) {
+	opt = find_option(cmd);
+	if (opt == NULL) {
+	    option_error("In file %s: unrecognized option '%s'",
+			 filename, cmd);
+	    goto err;
+	}
+	n = n_arguments(opt);
+	for (i = 0; i < n; ++i) {
+	    if (!getword(f, args[i], &newline, filename)) {
+		option_error(
+			"In file %s: too few parameters for option '%s'",
+			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->pw_dir) == NULL || user[0] == 0)
+	return 1;
+    file = _PATH_USEROPT;
+    pl = strlen(user) + strlen(file) + 2;
+    path = malloc(pl);
+    if (path == NULL)
+	novm("init file name");
+    slprintf(path, pl, "%s/%s", 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, "/dev/", 5) == 0)
+	dev += 5;
+    if (dev[0] == 0 || strcmp(dev, "tty") == 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("tty init file name");
+    slprintf(path, pl, "%s%s", _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 = "secrets file";
+    option_priority = OPRIO_SECFILE;
+
+    while (w != NULL) {
+	opt = find_option(w->word);
+	if (opt == NULL) {
+	    option_error("In secrets file: unrecognized option '%s'",
+			 w->word);
+	    goto err;
+	}
+	n = n_arguments(opt);
+	w0 = w;
+	for (i = 0; i < n; ++i) {
+	    w = w->next;
+	    if (w == NULL) {
+		option_error(
+			"In secrets file: too few parameters for option '%s'",
+			w0->word);
+		goto err;
+	    }
+	    argv[i] = w->word;
+	}
+	if (!process_option(opt, w0->word, argv))
+	    goto err;
+	w = w->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->type == o_wild))
+		return 0;
+	if (!dowild)
+		return strcmp(name, opt->name) == 0;
+	match = (int (*) __P((char *, char **, int))) opt->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 <= 1; ++dowild) {
+		for (opt = general_options; opt->name != NULL; ++opt)
+			if (match_option(name, opt, dowild))
+				return opt;
+		for (opt = auth_options; opt->name != NULL; ++opt)
+			if (match_option(name, opt, dowild))
+				return opt;
+		for (list = extra_options; list != NULL; list = list->next)
+			for (opt = list->options; opt->name != NULL; ++opt)
+				if (match_option(name, opt, dowild))
+					return opt;
+		for (opt = the_channel->options; opt->name != NULL; ++opt)
+			if (match_option(name, opt, dowild))
+				return opt;
+		for (i = 0; protocols[i] != NULL; ++i)
+			if ((opt = protocols[i]->options) != NULL)
+				for (; opt->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->type == o_wild)? "": " option";
+    int prio = option_priority;
+    option_t *mainopt = opt;
+
+    if ((opt->flags & OPT_PRIVFIX) && privileged_option)
+	prio += OPRIO_ROOT;
+    while (mainopt->flags & OPT_PRIOSUB)
+	--mainopt;
+    if (mainopt->flags & OPT_PRIO) {
+	if (prio < mainopt->priority) {
+	    /* new value doesn't override old */
+	    if (prio == OPRIO_CMDLINE && mainopt->priority > OPRIO_ROOT) {
+		option_error("%s%s set in %s cannot be overridden\n",
+			     opt->name, optopt, mainopt->source);
+		return 0;
+	    }
+	    return 1;
+	}
+	if (prio > OPRIO_ROOT && mainopt->priority == OPRIO_CMDLINE)
+	    warn("%s%s from %s overrides command line",
+		 opt->name, optopt, option_source);
+    }
+
+    if ((opt->flags & OPT_INITONLY) && phase != PHASE_INITIALIZE) {
+	option_error("%s%s cannot be changed after initialization",
+		     opt->name, optopt);
+	return 0;
+    }
+    if ((opt->flags & OPT_PRIV) && !privileged_option) {
+	option_error("using the %s%s requires root privilege",
+		     opt->name, optopt);
+	return 0;
+    }
+    if ((opt->flags & OPT_ENABLE) && *(bool *)(opt->addr2) == 0) {
+	option_error("%s%s is disabled", opt->name, optopt);
+	return 0;
+    }
+    if ((opt->flags & OPT_DEVEQUIV) && devnam_fixed) {
+	option_error("the %s%s may not be changed in %s",
+		     opt->name, optopt, option_source);
+	return 0;
+    }
+
+    switch (opt->type) {
+    case o_bool:
+	v = opt->flags & OPT_VALUE;
+	*(bool *)(opt->addr) = v;
+	if (opt->addr2 && (opt->flags & OPT_A2COPY))
+	    *(bool *)(opt->addr2) = v;
+	break;
+
+    case o_int:
+	iv = 0;
+	if ((opt->flags & OPT_NOARG) == 0) {
+	    if (!int_option(*argv, &iv))
+		return 0;
+	    if ((((opt->flags & OPT_LLIMIT) && iv < opt->lower_limit)
+		 || ((opt->flags & OPT_ULIMIT) && iv > opt->upper_limit))
+		&& !((opt->flags & OPT_ZEROOK && iv == 0))) {
+		char *zok = (opt->flags & OPT_ZEROOK)? " zero or": "";
+		switch (opt->flags & OPT_LIMITS) {
+		case OPT_LLIMIT:
+		    option_error("%s value must be%s >= %d",
+				 opt->name, zok, opt->lower_limit);
+		    break;
+		case OPT_ULIMIT:
+		    option_error("%s value must be%s <= %d",
+				 opt->name, zok, opt->upper_limit);
+		    break;
+		case OPT_LIMITS:
+		    option_error("%s value must be%s between %d and %d",
+				opt->name, opt->lower_limit, opt->upper_limit);
+		    break;
+		}
+		return 0;
+	    }
+	}
+	a = opt->flags & OPT_VALUE;
+	if (a >= 128)
+	    a -= 256;		/* sign extend */
+	iv += a;
+	if (opt->flags & OPT_INC)
+	    iv += *(int *)(opt->addr);
+	if ((opt->flags & OPT_NOINCR) && !privileged_option) {
+	    int oldv = *(int *)(opt->addr);
+	    if ((opt->flags & OPT_ZEROINF) ?
+		(oldv != 0 && (iv == 0 || iv > oldv)) : (iv > oldv)) {
+		option_error("%s value cannot be increased", opt->name);
+		return 0;
+	    }
+	}
+	*(int *)(opt->addr) = iv;
+	if (opt->addr2 && (opt->flags & OPT_A2COPY))
+	    *(int *)(opt->addr2) = iv;
+	break;
+
+    case o_uint32:
+	if (opt->flags & OPT_NOARG) {
+	    v = opt->flags & OPT_VALUE;
+	    if (v & 0x80)
+		    v |= 0xffffff00U;
+	} else if (!number_option(*argv, &v, 16))
+	    return 0;
+	if (opt->flags & OPT_OR)
+	    v |= *(u_int32_t *)(opt->addr);
+	*(u_int32_t *)(opt->addr) = v;
+	if (opt->addr2 && (opt->flags & OPT_A2COPY))
+	    *(u_int32_t *)(opt->addr2) = v;
+	break;
+
+    case o_string:
+	if (opt->flags & OPT_STATIC) {
+	    strlcpy((char *)(opt->addr), *argv, opt->upper_limit);
+	} else {
+	    sv = strdup(*argv);
+	    if (sv == NULL)
+		novm("option argument");
+	    *(char **)(opt->addr) = sv;
+	}
+	break;
+
+    case o_special_noarg:
+    case o_special:
+	parser = (int (*) __P((char **))) opt->addr;
+	if (!(*parser)(argv))
+	    return 0;
+	if (opt->flags & OPT_A2LIST) {
+	    struct option_value *ovp, **pp;
+
+	    ovp = malloc(sizeof(*ovp) + strlen(*argv));
+	    if (ovp != 0) {
+		strcpy(ovp->value, *argv);
+		ovp->source = option_source;
+		ovp->next = NULL;
+		pp = (struct option_value **) &opt->addr2;
+		while (*pp != 0)
+		    pp = &(*pp)->next;
+		*pp = ovp;
+	    }
+	}
+	break;
+
+    case o_wild:
+	wildp = (int (*) __P((char *, char **, int))) opt->addr;
+	if (!(*wildp)(cmd, argv, 1))
+	    return 0;
+	break;
+    }
+
+    if (opt->addr2 && (opt->flags & (OPT_A2COPY|OPT_ENABLE
+		|OPT_A2PRINTER|OPT_A2STRVAL|OPT_A2LIST)) == 0)
+	*(bool *)(opt->addr2) = !(opt->flags & OPT_A2CLR);
+
+    mainopt->source = option_source;
+    mainopt->priority = prio;
+    mainopt->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->flags & OPT_PRIOSUB)
+		--opt;
+	if ((opt->flags & OPT_PRIO) && priority < opt->priority)
+		return 0;
+	opt->priority = priority;
+	opt->source = source;
+	opt->winner = -1;
+	return 1;
+}
+
+/*
+ * n_arguments - tell how many arguments an option takes
+ */
+static int
+n_arguments(opt)
+    option_t *opt;
+{
+	return (opt->type == o_bool || opt->type == o_special_noarg
+		|| (opt->flags & 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("option list entry");
+    list->options = opt;
+    list->next = extra_options;
+    extra_options = list;
+}
+
+/*
+ * check_options - check that options are valid and consistent.
+ */
+void
+check_options()
+{
+	if (logfile_fd >= 0 && 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->flags & OPT_NOPRINT)
+		return;
+	switch (opt->type) {
+	case o_bool:
+		v = opt->flags & OPT_VALUE;
+		if (*(bool *)opt->addr != v)
+			/* this can happen legitimately, e.g. lock
+			   option turned off for default device */
+			break;
+		printer(arg, "%s", opt->name);
+		break;
+	case o_int:
+		v = opt->flags & OPT_VALUE;
+		if (v >= 128)
+			v -= 256;
+		i = *(int *)opt->addr;
+		if (opt->flags & OPT_NOARG) {
+			printer(arg, "%s", opt->name);
+			if (i != v) {
+				if (opt->flags & OPT_INC) {
+					for (; i > v; i -= v)
+						printer(arg, " %s", opt->name);
+				} else
+					printer(arg, " # oops: %d not %d\n",
+						i, v);
+			}
+		} else {
+			printer(arg, "%s %d", opt->name, i);
+		}
+		break;
+	case o_uint32:
+		printer(arg, "%s", opt->name);
+		if ((opt->flags & OPT_NOARG) == 0)
+			printer(arg, " %x", *(u_int32_t *)opt->addr);
+		break;
+
+	case o_string:
+		if (opt->flags & OPT_HIDE) {
+			p = "??????";
+		} else {
+			p = (char *) opt->addr;
+			if ((opt->flags & OPT_STATIC) == 0)
+				p = *(char **)p;
+		}
+		printer(arg, "%s %q", opt->name, p);
+		break;
+
+	case o_special:
+	case o_special_noarg:
+	case o_wild:
+		if (opt->type != o_wild) {
+			printer(arg, "%s", opt->name);
+			if (n_arguments(opt) == 0)
+				break;
+			printer(arg, " ");
+		}
+		if (opt->flags & OPT_A2PRINTER) {
+			void (*oprt) __P((option_t *,
+					  void ((*)__P((void *, char *, ...))),
+					  void *));
+			oprt = opt->addr2;
+			(*oprt)(opt, printer, arg);
+		} else if (opt->flags & OPT_A2STRVAL) {
+			p = (char *) opt->addr2;
+			if ((opt->flags & OPT_STATIC) == 0)
+				p = *(char **)p;
+			printer("%q", p);
+		} else if (opt->flags & OPT_A2LIST) {
+			struct option_value *ovp;
+
+			ovp = (struct option_value *) opt->addr2;
+			for (;;) {
+				printer(arg, "%q", ovp->value);
+				if ((ovp = ovp->next) == NULL)
+					break;
+				printer(arg, "\t\t# (from %s)\n%s ",
+					ovp->source, opt->name);
+			}
+		} else {
+			printer(arg, "xxx # [don't know how to print value]");
+		}
+		break;
+
+	default:
+		printer(arg, "# %s value (type %d)", opt->name, opt->type);
+		break;
+	}
+	printer(arg, "\t\t# (from %s)\n", mainopt->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->name != NULL) {
+		if (opt->priority != OPRIO_DEFAULT
+		    && opt->winner != (short int) -1)
+			print_option(opt + opt->winner, opt, printer, arg);
+		do {
+			++opt;
+		} while (opt->flags & 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, "pppd options in effect:\n");
+	print_option_list(general_options, printer, arg);
+	print_option_list(auth_options, printer, arg);
+	for (list = extra_options; list != NULL; list = list->next)
+		print_option_list(list->options, printer, arg);
+	print_option_list(the_channel->options, printer, arg);
+	for (i = 0; protocols[i] != NULL; ++i)
+		print_option_list(protocols[i]->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, "pppd version %s\n", 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, "%s: %s\n", progname, buf);
+    syslog(LOG_ERR, "%s", 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, &sbuf) != 0)
+	return 0;
+    if (sbuf.st_uid == uid)
+	return sbuf.st_mode & S_IRUSR;
+    if (sbuf.st_gid == getgid())
+	return sbuf.st_mode & S_IRGRP;
+    for (i = 0; i < ngroups; ++i)
+	if (sbuf.st_gid == groups[i])
+	    return sbuf.st_mode & S_IRGRP;
+    return sbuf.st_mode & S_IROTH;
+}
+#endif
+
+/*
+ * Read a word from a file.
+ * Words are delimited by white-space or by quotes (" or ').
+ * Quotes, white-space and \ may be escaped with \.
+ * \<newline> 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) >= '0' && (c) < '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 && 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 && (c == '"' || 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 < 3 && isoctal(c); ++n) {
+			value = (value << 3) + (c & 07);
+			c = getc(f);
+		    }
+		    got = 1;
+		    break;
+		}
+
+		if (c == 'x') {
+		    /*
+		     * \x<hex_string> sequence
+		     */
+		    value = 0;
+		    c = getc(f);
+		    for (n = 0; n < 2 && isxdigit(c); ++n) {
+			digit = toupper(c) - '0';
+			if (digit > 10)
+			    digit += '0' + 10 - 'A';
+			value = (value << 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 < 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 < 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("Error reading %s: %m", 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 >= MAXWORDLEN) {
+	option_error("warning: word in file %s too long (%.20s...)",
+		     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, &ptr, base);
+    if (ptr == str) {
+	option_error("invalid numeric parameter '%s' for %s option",
+		     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, &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/<name>.
+ * 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] == '.' && p[1] == '.' && (p[2] == '/' || p[2] == 0)) {
+		ok = 0;
+		break;
+	    }
+	    while (*p != '/' && *p != 0)
+		++p;
+	    if (*p == '/')
+		++p;
+	}
+    }
+    if (!ok) {
+	option_error("call option value may not contain .. or start with /");
+	return 0;
+    }
+
+    l = strlen(arg) + strlen(_PATH_PEERFILES) + 1;
+    if ((fname = (char *) malloc(l)) == NULL)
+	novm("call file name");
+    slprintf(fname, l, "%s%s", _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(&pc, &pass_filter, *argv, 1, netmask) == 0)
+	return 1;
+    option_error("error in pass-filter expression: %s\n", pcap_geterr(&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(&pc, &active_filter, *argv, 1, netmask) == 0)
+	return 1;
+    option_error("error in active-filter expression: %s\n", pcap_geterr(&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, ".", 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 < 0 && errno == EEXIST)
+	fd = open(*argv, O_WRONLY | O_APPEND);
+    err = errno;
+    if (!privileged_option)
+	seteuid(0);
+    if (fd < 0) {
+	errno = err;
+	option_error("Can't open log file %s: %m", *argv);
+	return 0;
+    }
+    strlcpy(logfile_name, *argv, sizeof(logfile_name));
+    if (logfile_fd >= 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("plugin file path");
+	strlcpy(path, base, l);
+	strlcat(path, "/", l);
+	strlcat(path, arg, l);
+    }
+    handle = dlopen(path, RTLD_GLOBAL | RTLD_NOW);
+    if (handle == 0) {
+	err = dlerror();
+	if (err != 0)
+	    option_error("%s", err);
+	option_error("Couldn't load plugin %s", arg);
+	goto err;
+    }
+    init = (void (*)(void))dlsym(handle, "plugin_init");
+    if (init == 0) {
+	option_error("%s has no initialization entry point", arg);
+	goto errclose;
+    }
+    vers = (const char *) dlsym(handle, "pppd_version");
+    if (vers == 0) {
+	warn("Warning: plugin %s has no version information", arg);
+    } else if (strcmp(vers, VERSION) != 0) {
+	option_error("Plugin %s is for pppd version %s, this is %s",
+		     vers, VERSION);
+	goto errclose;
+    }
+    info("Plugin %s loaded.", 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		"2.4.1"
+#define DATE		"25 March 2001"


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 	"/var/run/"
+#define _PATH_DEVNULL	"/dev/null"
+#define _ROOT_PATH
+
+#define _PATH_UPAPFILE 	 _ROOT_PATH "/etc/ppp/pap-secrets"
+#define _PATH_CHAPFILE 	 _ROOT_PATH "/etc/ppp/chap-secrets"
+#define _PATH_SYSOPTIONS _ROOT_PATH "/etc/ppp/options"
+#define _PATH_IPUP	 _ROOT_PATH "/etc/ppp/ip-up"
+#define _PATH_IPDOWN	 _ROOT_PATH "/etc/ppp/ip-down"
+#define _PATH_AUTHUP	 _ROOT_PATH "/etc/ppp/auth-up"
+#define _PATH_AUTHDOWN	 _ROOT_PATH "/etc/ppp/auth-down"
+#define _PATH_TTYOPT	 _ROOT_PATH "/etc/ppp/options."
+#define _PATH_CONNERRS	 _ROOT_PATH "/etc/ppp/connect-errors"
+#define _PATH_PEERFILES	 _ROOT_PATH "/etc/ppp/peers/"
+#define _PATH_RESOLV	 _ROOT_PATH "/etc/resolv.conf"
+
+#define _PATH_USEROPT	 ".ppprc"
+
+#define _PATH_PPPDB	_ROOT_PATH _PATH_VARRUN "pppd.tdb"


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 '"' '/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 <stddef.h>
+#include <time.h>
+#include "pppd.h"
+
+char pppd_version[] = VERSION;
+
+static int minconnect = 0;
+
+static option_t my_options[] = {
+	{ "minconnect", o_int, &minconnect,
+	  "Set minimum connect time before idle timeout applies" },
+	{ NULL }
+};
+
+static int my_get_idle(struct ppp_idle *idle)
+{
+	time_t t;
+
+	if (idle == NULL)
+		return minconnect? minconnect: idle_time_limit;
+	t = idle->xmit_idle;
+	if (idle->recv_idle < t)
+		t = idle->recv_idle;
+	return idle_time_limit - t;
+}
+
+void plugin_init(void)
+{
+	info("plugin_init");
+	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 <errno.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <syslog.h>
+#include "pppd.h"
+
+char pppd_version[] = VERSION;
+
+static char promptprog[PATH_MAX+1];
+
+static option_t options[] = {
+    { "promptprog", o_string, promptprog,
+      "External PAP password prompting program",
+      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) < 0)
+	return -1;	/* sorry, can't help */
+
+    if (!passwd)
+	return 1;
+
+    if (pipe(p)) {
+	warn("Can't make a pipe for %s", promptprog);
+	return 0;
+    }
+    if ((kid = fork()) == (pid_t) -1) {
+	warn("Can't fork to run %s", 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, "%d", 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 < 0) {
+	    error("Can't read secret from %s: %m", promptprog);
+	    readgood = -1;
+	    break;
+	}
+	readgood += red;
+    } while (readgood < MAXSECRETLEN - 1);
+    passwd[readgood] = 0;
+    close(p[0]);
+
+    /* now wait for child to exit */
+    while (waitpid(kid, &wstat, 0) < 0) {
+	if (errno != EINTR) {
+	    warn("error waiting for %s: %m", promptprog);
+	    break;
+	}
+    }
+
+    if (readgood < 0)
+	return 0;
+    if (!WIFEXITED(wstat))
+	warn("%s terminated abnormally", promptprog);
+    if (WEXITSTATUS(wstat))
+	warn("%s exited with code %d", 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 @@
+.\" manual page [] for pppd 2.4
+.\" $Id: pppd.8 195720 2001-06-11 11:44:34Z gc $
+.\" SH section heading
+.\" SS subsection heading
+.\" LP paragraph
+.\" IP indented paragraph
+.\" 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 <tty_name>
+Communicate over the named device.  The string "/dev/" 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 <speed>
+Set the baud rate to <speed> (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<map>
+Set the async character map to <map>.  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 "passive" 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 <local_IP_address>\fB:\fI<remote_IP_address>
+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<local_interface_identifier>\fR,\fI<remote_interface_identifier>
+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 <local>,<remote>\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<epdisc>
+Sets the endpoint discriminator sent by the local machine to the peer
+during multilink negotiation to \fI<epdisc>\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<string>
+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<addr>
+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<addr>
+If pppd is acting as a server for Microsoft Windows or "Samba"
+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 "decimal dot"
+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 (").  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 "client" and the other the
+"server".  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 "*" 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 "-", then all IP addresses are
+disallowed.  To allow any address, use "*".  A word starting with "!"
+indicates that the specified address is \fInot\fR acceptable.  An
+address may be followed by "/" 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 ("+") 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 "", 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 "NO CARRIER"
+.br
+ABORT "NO DIALTONE"
+.br
+ABORT "ERROR"
+.br
+ABORT "NO ANSWER"
+.br
+ABORT "BUSY"
+.br
+ABORT "Username/Password Incorrect"
+.br
+"" "at"
+.br
+OK "at&d0&c1"
+.br
+OK "atdt2468135"
+.br
+"name:" "^Umyuserid"
+.br
+"word:" "\\qmypassword"
+.br
+"ispts" "\\q^Uppp"
+.br
+"~-^Uppp-~"
+.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 "joespc" which is to be allowed to dial in to the machine
+called "server" 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	"joe's secret"	joespc.my.net
+.LP
+Alternatively, you can create a username called (for example) "ppp",
+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 (Paul.Mackerras at cs.anu.edu.au), 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 <stdio.h>		/* for FILE */
+#include <limits.h>		/* for NGROUPS_MAX */
+#include <sys/param.h>		/* for MAXPATHLEN and BSD4_4, if defined */
+#include <sys/types.h>		/* for u_int32_t, if defined */
+#include <sys/time.h>		/* for struct timeval */
+#include <net/ppp_defs.h>
+#include "patchlevel.h"
+
+#if defined(__STDC__)
+#include <stdarg.h>
+#define __V(x)	x
+#else
+#include <varargs.h>
+#define __V(x)	(va_alist) va_dcl
+#define const
+#define volatile
+#endif
+
+#ifdef INET6
+#include "eui64.h"
+#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 -> 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) & 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 && 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 & 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 "channel".  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->send_config)					 \
+		(*the_channel->send_config)((mtu), (accm), (pc), (acc)); \
+} while (0)
+
+#define ppp_recv_config(unit, mtu, accm, pc, acc)			 \
+do {									 \
+	if (the_channel->send_config)					 \
+		(*the_channel->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 "secret" 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)++ << 8; \
+	(s) |= *(cp)++; \
+}
+#define PUTSHORT(s, cp) { \
+	*(cp)++ = (u_char) ((s) >> 8); \
+	*(cp)++ = (u_char) (s); \
+}
+
+#define GETLONG(l, cp) { \
+	(l) = *(cp)++ << 8; \
+	(l) |= *(cp)++; (l) <<= 8; \
+	(l) |= *(cp)++; (l) <<= 8; \
+	(l) |= *(cp)++; \
+}
+#define PUTLONG(l, cp) { \
+	*(cp)++ = (u_char) ((l) >> 24); \
+	*(cp)++ = (u_char) ((l) >> 16); \
+	*(cp)++ = (u_char) ((l) >> 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("Remote message: %0.*v", 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) < (b)? (a): (b))
+#endif
+#ifndef MAX
+#define MAX(a, b)	((a) > (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 <stdio.h>		/* for FILE */
+#include <limits.h>		/* for NGROUPS_MAX */
+#include <sys/param.h>		/* for MAXPATHLEN and BSD4_4, if defined */
+#include <sys/types.h>		/* for u_int32_t, if defined */
+#include <sys/time.h>		/* for struct timeval */
+#include <net/ppp_defs.h>
+#include "patchlevel.h"
+
+#if defined(__STDC__)
+#include <stdarg.h>
+#define __V(x)	x
+#else
+#include <varargs.h>
+#define __V(x)	(va_alist) va_dcl
+#define const
+#define volatile
+#endif
+
+#ifdef INET6
+#include "eui64.h"
+#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 -> 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) & 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 && 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 & 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 "channel".  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->send_config)					 \
+		(*the_channel->send_config)((mtu), (accm), (pc), (acc)); \
+} while (0)
+
+#define ppp_recv_config(unit, mtu, accm, pc, acc)			 \
+do {									 \
+	if (the_channel->send_config)					 \
+		(*the_channel->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 "secret" 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)++ << 8; \
+	(s) |= *(cp)++; \
+}
+#define PUTSHORT(s, cp) { \
+	*(cp)++ = (u_char) ((s) >> 8); \
+	*(cp)++ = (u_char) (s); \
+}
+
+#define GETLONG(l, cp) { \
+	(l) = *(cp)++ << 8; \
+	(l) |= *(cp)++; (l) <<= 8; \
+	(l) |= *(cp)++; (l) <<= 8; \
+	(l) |= *(cp)++; \
+}
+#define PUTLONG(l, cp) { \
+	*(cp)++ = (u_char) ((l) >> 24); \
+	*(cp)++ = (u_char) ((l) >> 16); \
+	*(cp)++ = (u_char) ((l) >> 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("Remote message: %0.*v", 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) < (b)? (a): (b))
+#endif
+#ifndef MAX
+#define MAX(a, b)	((a) > (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 <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
+#include <sys/sysmacros.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <string.h>
+#include <time.h>
+#include <memory.h>
+#include <utmp.h>
+#include <mntent.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <termios.h>
+#include <unistd.h>
+
+/* 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__) && __GLIBC__ >= 2) || defined(__dietlibc__)
+#include <asm/types.h>		/* glibc 2 conflicts with linux/types.h */
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/route.h>
+#include <netinet/if_ether.h>
+#else
+#include <linux/types.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/route.h>
+#include <linux/if_ether.h>
+#endif
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <linux/ppp_defs.h>
+#include <linux/if_ppp.h>
+
+#include "pppd.h"
+#include "fsm.h"
+#include "ipcp.h"
+
+#ifdef IPX_CHANGE
+#include "ipxcp.h"
+#if __GLIBC__ >= 2 && \
+    !(defined(__powerpc__) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 0)
+#include <netipx/ipx.h>
+#else
+#include <linux/ipx.h>
+#endif
+#endif /* IPX_CHANGE */
+
+#ifdef PPP_FILTER
+#include <net/bpf.h>
+#include <linux/filter.h>
+#endif /* PPP_FILTER */
+
+#ifdef LOCKLIB
+#include <sys/locks.h>
+#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(&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 => 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 *) (&(x)))->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 *) &(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, "setting ppp_fd to %d\n", 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 && ppp_fd >= 0;
+	if (!hungup || ppp_fd == slave_fd)
+		return 1;
+	if (slave_fd >= 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) &flags) < 0) {
+	if ( ok_error (errno) )
+	    flags = 0;
+	else
+	    fatal("ioctl(PPPIOCGFLAGS): %m");
+    }
+
+    SYSDEBUG ((LOG_DEBUG, "get flags = %x\n", flags));
+    return flags;
+}
+
+/********************************************************************/
+
+static void set_flags (int fd, int flags)
+{    
+    SYSDEBUG ((LOG_DEBUG, "set flags = %x\n", flags));
+
+    if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &flags) < 0) {
+	if (! ok_error (errno) )
+	    fatal("ioctl(PPPIOCSFLAGS, %x): %m", flags, errno);
+    }
+}
+
+/********************************************************************
+ *
+ * sys_init - System-dependent initialization.
+ */
+
+void sys_init(void)
+{
+    int flags;
+
+    if (new_style_driver) {
+	ppp_dev_fd = open("/dev/ppp", O_RDWR);
+	if (ppp_dev_fd < 0)
+	    fatal("Couldn't open /dev/ppp: %m");
+	flags = fcntl(ppp_dev_fd, F_GETFL);
+	if (flags == -1
+	    || fcntl(ppp_dev_fd, F_SETFL, flags | O_NONBLOCK) == -1)
+	    warn("Couldn't set /dev/ppp to nonblock: %m");
+    }
+
+    /* Get an internet socket for doing socket ioctls. */
+    sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
+    if (sock_fd < 0)
+	fatal("Couldn't create IP socket: %m(%d)", errno);
+
+#ifdef INET6
+    sock6_fd = socket(AF_INET6, SOCK_DGRAM, 0);
+    if (sock6_fd < 0)
+	sock6_fd = -errno;	/* save errno for later */
+#endif
+
+    FD_ZERO(&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 >= 0)
+	close(sock_fd);
+    if (slave_fd >= 0)
+	close(slave_fd);
+    if (master_fd >= 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 && ifunit < 0)
+	return 1;
+    if (ioctl(ppp_dev_fd, PPPIOCSDEBUG, &requested_level) < 0) {
+	if ( ! ok_error (errno) )
+	    error("ioctl(PPPIOCSDEBUG): %m");
+	return (0);
+    }
+    SYSDEBUG ((LOG_INFO, "set kernel debugging level to %d",
+		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) < 0) {
+	if ( ! ok_error ( errno ))
+	    warn("Couldn't make tty exclusive: %m");
+    }
+/*
+ * Demand mode - prime the old ppp device to relinquish the unit.
+ */
+    if (!new_style_driver && looped
+	&& ioctl(slave_fd, PPPIOCXFERUNIT, 0) < 0) {
+	error("ioctl(transfer ppp unit): %m");
+	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 && sync_serial)? N_SYNC_PPP: N_PPP;
+    if (ioctl(tty_fd, TIOCSETD, &ppp_disc) < 0) {
+	if ( ! ok_error (errno) ) {
+	    error("Couldn't set tty to PPP discipline: %m");
+	    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, &chindex) == -1) {
+	    error("Couldn't get channel number: %m");
+	    goto err;
+	}
+	dbglog("using channel %d", chindex);
+	fd = open("/dev/ppp", O_RDWR);
+	if (fd < 0) {
+	    error("Couldn't reopen /dev/ppp: %m");
+	    goto err;
+	}
+	if (ioctl(fd, PPPIOCATTCHAN, &chindex) < 0) {
+	    error("Couldn't attach to channel %d: %m", chindex);
+	    goto err_close;
+	}
+	flags = fcntl(fd, F_GETFL);
+	if (flags == -1 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
+	    warn("Couldn't set /dev/ppp (channel) to nonblock: %m");
+	set_ppp_fd(fd);
+
+	if (!looped)
+	    ifunit = -1;
+	if (!looped && !multilink) {
+	    /*
+	     * Create a new PPP unit.
+	     */
+	    if (make_ppp_unit() < 0)
+		goto err_close;
+	}
+
+	if (looped)
+	    set_flags(ppp_dev_fd, get_flags(ppp_dev_fd) & ~SC_LOOP_TRAFFIC);
+
+	if (!multilink) {
+	    add_fd(ppp_dev_fd);
+	    if (ioctl(fd, PPPIOCCONNECT, &ifunit) < 0) {
+		error("Couldn't attach to PPP unit %d: %m", 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, &x) < 0) {	
+	    if (ok_error (errno))
+		goto err;
+	    fatal("ioctl(PPPIOCGUNIT): %m(%d)", errno);
+	}
+	/* Check that we got the same unit again. */
+	if (looped && x != ifunit)
+	    fatal("transfer_ppp failed: wanted unit %d, got %d", 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("Couldn't set device to non-blocking mode: %m");
+	}
+    }
+
+    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) & ~(SC_RCVB | SC_LOGB))
+		       | ((kdebugflag * SC_DEBUG) & SC_LOGB)));
+
+    SYSDEBUG ((LOG_NOTICE, "Using version %d.%d.%d of PPP driver",
+	    driver_version, driver_modification, driver_patch));
+
+    return ppp_fd;
+
+ err_close:
+    close(fd);
+ err:
+    if (ioctl(tty_fd, TIOCSETD, &tty_disc) < 0 && !ok_error(errno))
+	warn("Couldn't reset tty to normal line discipline: %m");
+    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) < 0)
+	    warn("tcflush failed: %m");
+/*
+ * Restore the previous line discipline
+ */
+	if (ioctl(tty_fd, TIOCSETD, &tty_disc) < 0) {
+	    if ( ! ok_error (errno))
+		error("ioctl(TIOCSETD, N_TTY): %m");
+	}
+	
+	if (ioctl(tty_fd, TIOCNXCL, 0) < 0) {
+	    if ( ! ok_error (errno))
+		warn("ioctl(TIOCNXCL): %m(%d)", errno);
+	}
+
+	/* Reset non-blocking mode on fd. */
+	if (initfdflags != -1 && fcntl(tty_fd, F_SETFL, initfdflags) < 0) {
+	    if ( ! ok_error (errno))
+		warn("Couldn't restore device fd flags: %m");
+	}
+    }
+    initfdflags = -1;
+
+    if (new_style_driver) {
+	close(ppp_fd);
+	ppp_fd = -1;
+	if (!looped && ifunit >= 0 && ioctl(ppp_dev_fd, PPPIOCDETACH) < 0)
+	    error("Couldn't release PPP unit: %m");
+	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, &ifunit);
+	if (x < 0 && req_unit >= 0 && errno == EEXIST) {
+		warn("Couldn't allocate PPP unit %d as it is already in use");
+		ifunit = -1;
+		x = ioctl(ppp_dev_fd, PPPIOCNEWUNIT, &ifunit);
+	}
+	if (x < 0)
+		error("Couldn't create new ppp unit: %m");
+	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, &mrru) < 0)
+		error("Couldn't set MRRU: %m");
+	flags = get_flags(ppp_dev_fd);
+	flags &= ~(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, &ifunit) < 0)
+		fatal("Couldn't attach to PPP unit %d: %m", 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() < 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, &ifnum) < 0) {
+		if (errno == ENXIO)
+			return 0;	/* doesn't still exist */
+		fatal("Couldn't attach to interface unit %d: %m\n", ifnum);
+	}
+	if (ioctl(ppp_fd, PPPIOCCONNECT, &ifnum) < 0)
+		fatal("Couldn't connect to interface unit %d: %m", 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) &x) == 0) {
+	    s = NULL;
+	    switch (~x & (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) {
+	    case SC_RCV_B7_0:
+		s = "all had bit 7 set to 1";
+		break;
+		
+	    case SC_RCV_B7_1:
+		s = "all had bit 7 set to 0";
+		break;
+		
+	    case SC_RCV_EVNP:
+		s = "all had odd parity";
+		break;
+		
+	    case SC_RCV_ODDP:
+		s = "all had even parity";
+		break;
+	    }
+	    
+	    if (s != NULL) {
+		warn("Receive serial link is not 8-bit clean:");
+		warn("Problem: %s", 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->speed_int; speedp++) {
+	    if (bps == speedp->speed_int)
+		return speedp->speed_val;
+	}
+	warn("speed %d not supported", 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->speed_int; speedp++) {
+	    if (speed == speedp->speed_val)
+		return speedp->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, &tios) < 0) {
+	if (!ok_error(errno))
+	    fatal("tcgetattr: %m(%d)", errno);
+	return;
+    }
+    
+    if (!restore_term)
+	inittermios = tios;
+    
+    tios.c_cflag     &= ~(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 &= ~CRTSCTS;
+	break;
+
+    default:
+	break;
+    }
+    
+    speed = translate_speed(inspeed);
+    if (speed) {
+	cfsetospeed (&tios, speed);
+	cfsetispeed (&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(&tios);
+	if (speed == B0)
+	    fatal("Baud rate for %s is 0; need explicit baud rate", devnam);
+    }
+
+    if (tcsetattr(tty_fd, TCSAFLUSH, &tios) < 0)
+	if (!ok_error(errno))
+	    fatal("tcsetattr: %m");
+    
+    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), &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 &= ~(ECHO | ECHONL);
+	
+	if (tcsetattr(tty_fd, TCSAFLUSH, &inittermios) < 0) {
+	    if (! ok_error (errno))
+		warn("tcsetattr: %m");
+	}
+    }
+}
+
+/********************************************************************
+ *
+ * output - Output PPP packet.
+ */
+
+void output (int unit, unsigned char *p, int len)
+{
+    int fd = ppp_fd;
+    int proto;
+
+    if (debug)
+	dbglog("sent %P", p, len);
+
+    if (len < PPP_HDRLEN)
+	return;
+    if (new_style_driver) {
+	p += 2;
+	len -= 2;
+	proto = (p[0] << 8) + p[1];
+	if (ifunit >= 0 && !(proto >= 0xc000 || proto == PPP_CCPFRAG))
+	    fd = ppp_dev_fd;
+    }
+    if (write(fd, p, len) < 0) {
+	if (errno == EWOULDBLOCK || errno == ENOBUFS
+	    || errno == ENXIO || errno == EIO || errno == EINTR)
+	    warn("write: warning: %m (%d)", errno);
+	else
+	    error("write: %m (%d)", 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, &ready, NULL, &exc, timo);
+    if (n < 0 && errno != EINTR)
+	fatal("select: %m(%d)", errno);
+}
+
+/*
+ * add_fd - add an fd to the set that wait_input waits for.
+ */
+void add_fd(int fd)
+{
+    FD_SET(fd, &in_fds);
+    if (fd > 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, &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 >= 0) {
+	nr = read(ppp_fd, buf, len);
+	if (nr < 0 && errno != EWOULDBLOCK && errno != EIO && errno != EINTR)
+	    error("read: %m");
+	if (nr < 0 && errno == ENXIO)
+	    return 0;
+    }
+    if (nr < 0 && new_style_driver && ifunit >= 0) {
+	/* N.B. we read ppp_fd first since LCP packets come in there. */
+	nr = read(ppp_dev_fd, buf, len);
+	if (nr < 0 && errno != EWOULDBLOCK && errno != EIO && errno != EINTR)
+	    error("read /dev/ppp: %m");
+	if (nr < 0 && errno == ENXIO)
+	    return 0;
+    }
+    return (new_style_driver && nr > 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)) > 0)
+	    if (loop_frame(inpacket_buf, n))
+		rv = 1;
+	return rv;
+    }
+
+    while ((n = read(master_fd, inbuf, sizeof(inbuf))) > 0)
+	if (loop_chars(inbuf, n))
+	    rv = 1;
+
+    if (n == 0)
+	fatal("eof on loopback");
+
+    if (errno != EWOULDBLOCK)
+	fatal("read from loopback: %m(%d)", 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, "netif_set_mtu: mtu = %d\n", mtu));
+
+    memset (&ifr, '\0', sizeof (ifr));
+    strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+    ifr.ifr_mtu = mtu;
+	
+    if (ifunit >= 0 && ioctl(sock_fd, SIOCSIFMTU, (caddr_t) &ifr) < 0)
+	fatal("ioctl(SIOCSIFMTU): %m");
+}
+
+/********************************************************************
+ *
+ * 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, "send_config: asyncmap = %lx\n", asyncmap));
+    if (ioctl(ppp_fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0) {
+	if (!ok_error(errno))
+	    fatal("ioctl(PPPIOCSASYNCMAP): %m(%d)", errno);
+	return;
+    }
+    
+    x = get_flags(ppp_fd);
+    x = pcomp  ? x | SC_COMP_PROT : x & ~SC_COMP_PROT;
+    x = accomp ? x | SC_COMP_AC   : x & ~SC_COMP_AC;
+    x = sync_serial ? x | SC_SYNC : x & ~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, "set_xaccm: %08lx %08lx %08lx %08lx\n",
+		accm[0], accm[1], accm[2], accm[3]));
+
+    if (!still_ppp())
+	return;
+    if (ioctl(ppp_fd, PPPIOCSXASYNCMAP, accm) < 0 && errno != ENOTTY) {
+	if ( ! ok_error (errno))
+	    warn("ioctl(set extended ACCM): %m(%d)", 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, "recv_config: mru = %d\n", 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) &mru) < 0) {
+	if ( ! ok_error (errno))
+	    error("ioctl(PPPIOCSMRU): %m(%d)", errno);
+    }
+    if (new_style_driver && ifunit >= 0
+	&& ioctl(ppp_dev_fd, PPPIOCSMRU, (caddr_t) &mru) < 0)
+	error("Couldn't set MRU in generic PPP layer: %m");
+
+    SYSDEBUG ((LOG_DEBUG, "recv_config: asyncmap = %lx\n", asyncmap));
+    if (ioctl(ppp_fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0) {
+	if (!ok_error(errno))
+	    error("ioctl(PPPIOCSRASYNCMAP): %m(%d)", 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 (&data, '\0', sizeof (data));
+    data.ptr      = opt_ptr;
+    data.length   = opt_len;
+    data.transmit = for_transmit;
+
+    if (ioctl(ppp_dev_fd, PPPIOCSCOMPRESS, (caddr_t) &data) >= 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 &~ SC_CCP_OPEN;
+	x = isup?   x | SC_CCP_UP   : x &~ 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->bf_len;
+	fp.filter = (struct sock_filter *) pass->bf_insns;
+	if (ioctl(ppp_dev_fd, PPPIOCSPASS, &fp) < 0) {
+		if (errno == ENOTTY)
+			warn("kernel does not support PPP filtering");
+		else
+			error("Couldn't set pass-filter in kernel: %m");
+		return 0;
+	}
+	fp.len = active->bf_len;
+	fp.filter = (struct sock_filter *) active->bf_insns;
+	if (ioctl(ppp_dev_fd, PPPIOCSACTIVE, &fp) < 0) {
+		error("Couldn't set active-filter in kernel: %m");
+		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) >= 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 (&req, 0, sizeof (req));
+
+    req.stats_ptr = (caddr_t) &req.stats;
+    strlcpy(req.ifr__name, ifname, sizeof(req.ifr__name));
+    if (ioctl(sock_fd, SIOCGPPPSTATS, &req) < 0) {
+	error("Couldn't get PPP statistics: %m");
+	return 0;
+    }
+    stats->bytes_in = req.stats.p.ppp_ibytes;
+    stats->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 & 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, "/proc", sizeof(proc_path));
+	proc_path_len = 5;
+	fp = fopen(MOUNTED, "r");
+	if (fp != NULL) {
+	    while ((mntent = getmntent(fp)) != NULL) {
+		if (strcmp(mntent->mnt_type, MNTTYPE_IGNORE) == 0)
+		    continue;
+		if (strcmp(mntent->mnt_type, "proc") == 0) {
+		    strlcpy(proc_path, mntent->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[] = " \t\n";
+
+static int open_route_table (void)
+{
+    char *path;
+
+    close_route_table();
+
+    path = path_to_procfs("/net/route");
+    route_fd = fopen (path, "r");
+    if (route_fd == NULL) {
+        error("can't open routing table %s: %m", 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 < ROUTE_MAX_COLS; ++col) {
+	    int used = 1;
+	    if ((q = strtok(p, route_delims)) == 0)
+		break;
+	    if (strcasecmp(q, "iface") == 0)
+		route_dev_col = col;
+	    else if (strcasecmp(q, "destination") == 0)
+		route_dest_col = col;
+	    else if (strcasecmp(q, "gateway") == 0)
+		route_gw_col = col;
+	    else if (strcasecmp(q, "flags") == 0)
+		route_flags_col = col;
+	    else if (strcasecmp(q, "mask") == 0)
+		route_mask_col = col;
+	    else
+		used = 0;
+	    if (used && col >= 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 < 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->rt_dst) = strtoul(cols[route_dest_col], NULL, 16);
+    SIN_ADDR(rt->rt_gateway) = strtoul(cols[route_gw_col], NULL, 16);
+    SIN_ADDR(rt->rt_genmask) = strtoul(cols[route_mask_col], NULL, 16);
+
+    rt->rt_flags = (short) strtoul(cols[route_flags_col], NULL, 16);
+    rt->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->rt_flags & RTF_UP) == 0)
+	    continue;
+
+	if (kernel_version > KVERSION(2,1,0) && SIN_ADDR(rt->rt_genmask) != 0)
+	    continue;
+        if (SIN_ADDR(rt->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(&rt)) {
+	if ((rt.rt_flags & RTF_UP) == 0 || strcmp(rt.rt_dev, ifname) == 0)
+	    continue;
+	if ((addr & 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(&rt) && strcmp(rt.rt_dev, ifname) != 0) {
+	u_int32_t old_gateway = SIN_ADDR(rt.rt_gateway);
+
+	if (old_gateway != gateway)
+	    error("not replacing existing default route to %s [%I]",
+		  rt.rt_dev, old_gateway);
+	return 0;
+    }
+
+    memset (&rt, '\0', sizeof (rt));
+    SET_SA_FAMILY (rt.rt_dst,     AF_INET);
+    SET_SA_FAMILY (rt.rt_gateway, AF_INET);
+
+    if (kernel_version > 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, &rt) < 0) {
+	if ( ! ok_error ( errno ))
+	    error("default route ioctl(SIOCADDRT): %m(%d)", 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 (&rt, '\0', sizeof (rt));
+    SET_SA_FAMILY (rt.rt_dst,     AF_INET);
+    SET_SA_FAMILY (rt.rt_gateway, AF_INET);
+
+    if (kernel_version > 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, &rt) < 0 && errno != ESRCH) {
+	if (still_ppp()) {
+	    if ( ! ok_error ( errno ))
+		error("default route ioctl(SIOCDELRT): %m (%d)", 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 (&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, &arpreq.arp_ha, proxy_arp_dev,
+			    sizeof(proxy_arp_dev))) {
+	    error("Cannot determine ethernet address for proxy ARP");
+	    return 0;
+	}
+	strlcpy(arpreq.arp_dev, proxy_arp_dev, sizeof(arpreq.arp_dev));
+
+	if (ioctl(sock_fd, SIOCSARP, (caddr_t)&arpreq) < 0) {
+	    if ( ! ok_error ( errno ))
+		error("ioctl(SIOCSARP): %m(%d)", errno);
+	    return 0;
+	}
+	proxy_arp_addr = his_adr;
+	has_proxy_arp = 1;
+
+	if (tune_kernel) {
+	    forw_path = path_to_procfs("/sys/net/ipv4/ip_forward");
+	    if (forw_path != 0) {
+		int fd = open(forw_path, O_WRONLY);
+		if (fd >= 0) {
+		    if (write(fd, "1", 1) != 1)
+			error("Couldn't enable IP forwarding: %m");
+		    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 (&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)&arpreq) < 0) {
+	    if ( ! ok_error ( errno ))
+		warn("ioctl(SIOCDARP): %m(%d)", 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, &ifc) < 0) {
+	if ( ! ok_error ( errno ))
+	    error("ioctl(SIOCGIFCONF): %m(%d)", errno);
+	return 0;
+    }
+
+    SYSDEBUG ((LOG_DEBUG, "proxy arp: scanning %d interfaces for IP %s",
+		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 < ifend; ifr++) {
+	if (ifr->ifr_addr.sa_family == AF_INET) {
+	    ina = SIN_ADDR(ifr->ifr_addr);
+	    strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
+            SYSDEBUG ((LOG_DEBUG, "proxy arp: examining interface %s",
+			ifreq.ifr_name));
+/*
+ * Check that the interface is up, and not point-to-point
+ * nor loopback.
+ */
+	    if (ioctl(sock_fd, SIOCGIFFLAGS, &ifreq) < 0)
+		continue;
+
+	    if (((ifreq.ifr_flags ^ FLAGS_GOOD) & FLAGS_MASK) != 0)
+		continue;
+/*
+ * Get its netmask and check that it's on the right subnet.
+ */
+	    if (ioctl(sock_fd, SIOCGIFNETMASK, &ifreq) < 0)
+	        continue;
+
+	    mask = SIN_ADDR(ifreq.ifr_addr);
+	    SYSDEBUG ((LOG_DEBUG, "proxy arp: interface addr %s mask %lx",
+			ip_ntoa(ina), ntohl(mask)));
+
+	    if (((ipaddr ^ ina) & mask) != 0)
+	        continue;
+	    break;
+	}
+    }
+    
+    if (ifr >= 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("found interface %s for proxy arp", name);
+/*
+ * Now get the hardware address.
+ */
+    memset (&ifreq.ifr_hwaddr, 0, sizeof (struct sockaddr));
+    if (ioctl (sock_fd, SIOCGIFHWADDR, &ifreq) < 0) {
+        error("SIOCGIFHWADDR(%s): %m(%d)", ifreq.ifr_name, errno);
+        return 0;
+    }
+
+    memcpy (hwaddr,
+	    &ifreq.ifr_hwaddr,
+	    sizeof (struct sockaddr));
+
+    SYSDEBUG ((LOG_DEBUG,
+	   "proxy arp: found hwaddr %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+		(int) ((unsigned char *) &hwaddr->sa_data)[0],
+		(int) ((unsigned char *) &hwaddr->sa_data)[1],
+		(int) ((unsigned char *) &hwaddr->sa_data)[2],
+		(int) ((unsigned char *) &hwaddr->sa_data)[3],
+		(int) ((unsigned char *) &hwaddr->sa_data)[4],
+		(int) ((unsigned char *) &hwaddr->sa_data)[5],
+		(int) ((unsigned char *) &hwaddr->sa_data)[6],
+		(int) ((unsigned char *) &hwaddr->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 < 0)
+		return 0;
+	memset(&ifreq.ifr_hwaddr, 0, sizeof(struct sockaddr));
+	strlcpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));
+	ret = ioctl(sock_fd, SIOCGIFHWADDR, &ifreq);
+	close(sock_fd);
+	if (ret >= 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 "eth0";
+}
+
+/********************************************************************
+ *
+ * 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, &ifc) < 0) {
+	if ( ! ok_error ( errno ))
+	    warn("ioctl(SIOCGIFCONF): %m(%d)", errno);
+	return mask;
+    }
+    
+    ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
+    for (ifr = ifc.ifc_req; ifr < ifend; ifr++) {
+/*
+ * Check the interface's internet address.
+ */
+	if (ifr->ifr_addr.sa_family != AF_INET)
+	    continue;
+	ina = SIN_ADDR(ifr->ifr_addr);
+	if (((ntohl(ina) ^ addr) & nmask) != 0)
+	    continue;
+/*
+ * Check that the interface is up, and not point-to-point nor loopback.
+ */
+	strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
+	if (ioctl(sock_fd, SIOCGIFFLAGS, &ifreq) < 0)
+	    continue;
+	
+	if (((ifreq.ifr_flags ^ FLAGS_GOOD) & FLAGS_MASK) != 0)
+	    continue;
+/*
+ * Get its netmask and OR it into our mask.
+ */
+	if (ioctl(sock_fd, SIOCGIFNETMASK, &ifreq) < 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, &endp, 10);
+    *modification = 0;
+    *patch        = 0;
+    
+    if (endp != buf && *endp == '.') {
+	buf = endp + 1;
+	*modification = (int) strtoul (buf, &endp, 10);
+	if (endp != buf && *endp == '.') {
+	    buf = endp + 1;
+	    *patch = (int) strtoul (buf, &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(&mfd, &local_fd, slave, 0)) {
+	no_ppp_msg = "Couldn't determine if PPP is supported (no free ptys)";
+	return 0;
+    }
+
+    /*
+     * Try to put the device into the PPP discipline.
+     */
+    if (ioctl(local_fd, TIOCSETD, &ppp_disc) < 0) {
+	error("ioctl(TIOCSETD(PPP)): %m(%d)", 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 = 
+	"This system lacks kernel support for PPP.  This could be because\n"
+	"the PPP kernel module could not be loaded, or because PPP was not\n"
+	"included in the kernel configuration.  If PPP was included as a\n"
+	"module, try `/sbin/modprobe -v ppp'.  If that fails, check that\n"
+	"ppp.o exists in /lib/modules/`uname -r`/net.\n"
+	"See README.linux file in the ppp distribution for more details.\n";
+
+    /* get the kernel version now, since we are called before sys_init */
+    uname(&utsname);
+    osmaj = osmin = ospatch = 0;
+    sscanf(utsname.release, "%d.%d.%d", &osmaj, &osmin, &ospatch);
+    kernel_version = KVERSION(osmaj, osmin, ospatch);
+
+    fd = open("/dev/ppp", O_RDWR);
+#if 0
+    if (fd < 0 && errno == ENOENT) {
+	/* try making it and see if that helps. */
+	if (mknod("/dev/ppp", S_IFCHR | S_IRUSR | S_IWUSR,
+		  makedev(108, 0)) >= 0) {
+	    fd = open("/dev/ppp", O_RDWR);
+	    if (fd >= 0)
+		info("Created /dev/ppp device node");
+	    else
+		unlink("/dev/ppp");	/* didn't work, undo the mknod */
+	} else if (errno == EEXIST) {
+	    fd = open("/dev/ppp", O_RDWR);
+	}
+    }
+#endif /* 0 */
+    if (fd >= 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 >= KVERSION(2,3,13)) {
+	if (errno == ENOENT)
+	    no_ppp_msg =
+		"pppd is unable to open the /dev/ppp device.\n"
+		"You need to create the /dev/ppp device node by\n"
+		"executing the following command as root:\n"
+		"	mknod /dev/ppp c 108 0\n";
+	return 0;
+    }
+
+/*
+ * Open a socket for doing the ioctl operations.
+ */    
+    s = socket(AF_INET, SOCK_DGRAM, 0);
+    if (s < 0)
+	return 0;
+    
+    strlcpy (ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
+    ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 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, "ppp0", sizeof (ifr.ifr_name));
+	    ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
+	}
+    }
+/*
+ * Ensure that the hardware address is for PPP and not something else
+ */
+    if (ok)
+        ok = ioctl (s, SIOCGIFHWADDR, (caddr_t) &ifr) >= 0;
+
+    if (ok && ((ifr.ifr_hwaddr.sa_family & ~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) &ifr);
+	if (size < 0) {
+	    error("Couldn't read driver version: %m");
+	    ok = 0;
+	    no_ppp_msg = "Sorry, couldn't verify kernel driver version\n";
+
+	} else {
+	    decode_version(abBuffer,
+			   &driver_version,
+			   &driver_modification,
+			   &driver_patch);
+/*
+ * Validate the version of the driver against the version that we used.
+ */
+	    decode_version(VERSION,
+			   &my_version,
+			   &my_modification,
+			   &my_patch);
+
+	    /* The version numbers must match */
+	    if (driver_version != my_version)
+		ok = 0;
+      
+	    /* The modification levels must be legal */
+	    if (driver_modification < 3) {
+		if (driver_modification >= 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),
+			 "Sorry - PPP driver version %d.%d.%d is out of date\n",
+			 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) &maxcid) < 0) {
+	    if (! ok_error (errno))
+		error("ioctl(PPPIOCSMAXCID): %m(%d)", errno);
+	    vjcomp = 0;
+	}
+    }
+
+    x = vjcomp  ? x | SC_COMP_TCP     : x &~ SC_COMP_TCP;
+    x = cidcomp ? x & ~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 (&ifr, '\0', sizeof (ifr));
+    strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+    if (ioctl(sock_fd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+	if (! ok_error (errno))
+	    error("ioctl (SIOCGIFFLAGS): %m(%d)", errno);
+	return 0;
+    }
+
+    ifr.ifr_flags |= (IFF_UP | IFF_POINTOPOINT);
+    if (ioctl(sock_fd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+	if (! ok_error (errno))
+	    error("ioctl(SIOCSIFFLAGS): %m(%d)", 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 && --if_is_up > 0)
+	return 1;
+
+    memset (&ifr, '\0', sizeof (ifr));
+    strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+    if (ioctl(sock_fd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+	if (! ok_error (errno))
+	    error("ioctl (SIOCGIFFLAGS): %m(%d)", errno);
+	return 0;
+    }
+
+    ifr.ifr_flags &= ~IFF_UP;
+    ifr.ifr_flags |= IFF_POINTOPOINT;
+    if (ioctl(sock_fd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+	if (! ok_error (errno))
+	    error("ioctl(SIOCSIFFLAGS): %m(%d)", 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 (&ifr, '\0', sizeof (ifr));
+    memset (&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) &ifr) < 0) {
+	if (errno != EEXIST) {
+	    if (! ok_error (errno))
+		error("ioctl(SIOCSIFADDR): %m(%d)", errno);
+	}
+        else {
+	    warn("ioctl(SIOCSIFADDR): Address already exists");
+	}
+        return (0);
+    }
+/*
+ *  Set the gateway address
+ */
+    SIN_ADDR(ifr.ifr_dstaddr) = his_adr;
+    if (ioctl(sock_fd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
+	if (! ok_error (errno))
+	    error("ioctl(SIOCSIFDSTADDR): %m(%d)", errno); 
+	return (0);
+    } 
+/*
+ *  Set the netmask.
+ *  For recent kernels, force the netmask to 255.255.255.255.
+ */
+    if (kernel_version >= 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) &ifr) < 0) {
+	    if (! ok_error (errno))
+		error("ioctl(SIOCSIFNETMASK): %m(%d)", errno); 
+	    return (0);
+	} 
+    }
+/*
+ *  Add the device route
+ */
+    if (kernel_version < 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 > KVERSION(2,1,0)) {
+	    SET_SA_FAMILY (rt.rt_genmask, AF_INET);
+	    SIN_ADDR(rt.rt_genmask) = -1L;
+	}
+
+	if (ioctl(sock_fd, SIOCADDRT, &rt) < 0) {
+	    if (! ok_error (errno))
+		error("ioctl(SIOCADDRT) device route: %m(%d)", errno);
+	    return (0);
+	}
+    }
+
+    /* set ip_dynaddr in demand mode if address changes */
+    if (demand && tune_kernel && !dynaddr_set
+	&& our_old_addr && our_old_addr != our_adr) {
+	/* set ip_dynaddr if possible */
+	char *path;
+	int fd;
+
+	path = path_to_procfs("/sys/net/ipv4/ip_dynaddr");
+	if (path != 0 && (fd = open(path, O_WRONLY)) >= 0) {
+	    if (write(fd, "1", 1) != 1)
+		error("Couldn't enable dynamic IP addressing: %m");
+	    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 < KVERSION(2,1,16)) {
+/*
+ *  Delete the route through the device
+ */
+	struct rtentry rt;
+	memset (&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 > KVERSION(2,1,0)) {
+	    SET_SA_FAMILY (rt.rt_genmask, AF_INET);
+	    SIN_ADDR(rt.rt_genmask) = -1L;
+	}
+
+	if (ioctl(sock_fd, SIOCDELRT, &rt) < 0 && errno != ESRCH) {
+	    if (still_ppp() && ! ok_error (errno))
+		error("ioctl(SIOCDELRT) device route: %m(%d)", errno);
+	    return (0);
+	}
+    }
+
+    /* This way it is possible to have an IPX-only or IPv6-only interface */
+    memset(&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) &ifr) < 0) {
+	if (! ok_error (errno)) {
+	    error("ioctl(SIOCSIFADDR): %m(%d)", 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 < 0) {
+	errno = -sock6_fd;
+	error("IPv6 socket creation failed: %m");
+	return 0;
+    }
+    memset(&ifr, 0, sizeof (ifr));
+    strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+    if (ioctl(sock6_fd, SIOCGIFINDEX, (caddr_t) &ifr) < 0) {
+	error("sif6addr: ioctl(SIOCGIFINDEX): %m (%d)", errno);
+	return 0;
+    }
+    
+    /* Local interface */
+    memset(&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, &ifr6) < 0) {
+	error("sif6addr: ioctl(SIOCSIFADDR): %m (%d)", errno);
+	return 0;
+    }
+    
+    /* Route to remote host */
+    memset(&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, &rt6) < 0) {
+	error("sif6addr: ioctl(SIOCADDRT): %m (%d)", 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 < 0) {
+	errno = -sock6_fd;
+	error("IPv6 socket creation failed: %m");
+	return 0;
+    }
+    memset(&ifr, 0, sizeof(ifr));
+    strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+    if (ioctl(sock6_fd, SIOCGIFINDEX, (caddr_t) &ifr) < 0) {
+	error("cif6addr: ioctl(SIOCGIFINDEX): %m (%d)", errno);
+	return 0;
+    }
+    
+    memset(&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, &ifr6) < 0) {
+	if (errno != EADDRNOTAVAIL) {
+	    if (! ok_error (errno))
+		error("cif6addr: ioctl(SIOCDIFADDR): %m (%d)", errno);
+	}
+        else {
+	    warn("cif6addr: ioctl(SIOCDIFADDR): No such address");
+	}
+        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 >= 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("/dev/ptmx", O_RDWR);
+    if (mfd >= 0) {
+	int ptn;
+	if (ioctl(mfd, TIOCGPTN, &ptn) >= 0) {
+	    slprintf(pty_name, sizeof(pty_name), "/dev/pts/%d", ptn);
+	    chmod(pty_name, S_IRUSR | S_IWUSR);
+#ifdef TIOCSPTLCK
+	    ptn = 0;
+	    if (ioctl(mfd, TIOCSPTLCK, &ptn) < 0)
+		warn("Couldn't unlock pty slave %s: %m", pty_name);
+#endif
+	    if ((sfd = open(pty_name, O_RDWR | O_NOCTTY)) < 0)
+		warn("Couldn't open pty slave %s: %m", pty_name);
+	}
+    }
+#endif /* TIOCGPTN */
+
+    if (sfd < 0) {
+	/* the old way - scan through the pty name space */
+	for (i = 0; i < 64; ++i) {
+	    slprintf(pty_name, sizeof(pty_name), "/dev/pty%c%x",
+		     'p' + i / 16, i % 16);
+	    mfd = open(pty_name, O_RDWR, 0);
+	    if (mfd >= 0) {
+		pty_name[5] = 't';
+		sfd = open(pty_name, O_RDWR | O_NOCTTY, 0);
+		if (sfd >= 0) {
+		    fchown(sfd, uid, -1);
+		    fchmod(sfd, S_IRUSR | S_IWUSR);
+		    break;
+		}
+		close(mfd);
+	    }
+	}
+    }
+
+    if (sfd < 0)
+	return 0;
+
+    strlcpy(slave_name, pty_name, 16);
+    *master_fdp = mfd;
+    *slave_fdp = sfd;
+    if (tcgetattr(sfd, &tios) == 0) {
+	tios.c_cflag &= ~(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, &tios) < 0)
+	    warn("couldn't set attributes on pty: %m");
+    } else
+	warn("couldn't get attributes on pty: %m");
+
+    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() < 0)
+	    die(1);
+	set_flags(ppp_dev_fd, SC_LOOP_TRAFFIC);
+	set_kdebugflag(kdebugflag);
+	ppp_fd = -1;
+	return ppp_dev_fd;
+    }
+
+    if (!get_pty(&master_fd, &slave_fd, loop_name, 0))
+	fatal("No free pty for loopback");
+    SYSDEBUG(("using %s for loopback", 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("couldn't set master loopback to nonblock: %m(%d)", errno);
+
+    flags = fcntl(ppp_fd, F_GETFL);
+    if (flags == -1 ||
+	fcntl(ppp_fd, F_SETFL, flags | O_NONBLOCK) == -1)
+	warn("couldn't set slave loopback to nonblock: %m(%d)", errno);
+
+    if (ioctl(ppp_fd, TIOCSETD, &ppp_disc) < 0)
+	fatal("ioctl(TIOCSETD): %m(%d)", errno);
+/*
+ * Find out which interface we were given.
+ */
+    if (ioctl(ppp_fd, PPPIOCGUNIT, &ifunit) < 0)
+	fatal("ioctl(PPPIOCGUNIT): %m(%d)", 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, &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) &npi) < 0) {
+	if (! ok_error (errno))
+	    error("ioctl(PPPIOCSNPMODE, %d, %d): %m (%d)",
+		   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 *) &ifr.ifr_addr;
+
+    skfd = socket (AF_IPX, SOCK_DGRAM, 0);
+    if (skfd < 0) { 
+	if (! ok_error (errno))
+	    dbglog("socket(AF_IPX): %m (%d)", errno);
+	result = 0;
+    }
+    else {
+	memset (&ifr, '\0', sizeof (ifr));
+	strlcpy (ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+
+	memcpy (sipx->sipx_node, node, IPX_NODE_LEN);
+	sipx->sipx_family  = AF_IPX;
+	sipx->sipx_port    = 0;
+	sipx->sipx_network = htonl (network);
+	sipx->sipx_type    = IPX_FRAME_ETHERII;
+	sipx->sipx_action  = IPX_CRTITF;
+/*
+ *  Set the IPX device
+ */
+	if (ioctl(skfd, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
+	    result = 0;
+	    if (errno != EEXIST) {
+		if (! ok_error (errno))
+		    dbglog("ioctl(SIOCSIFADDR, CRTITF): %m (%d)", errno);
+	    }
+	    else {
+		warn("ioctl(SIOCSIFADDR, CRTITF): Address already exists");
+	    }
+	}
+	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 *) &ifr.ifr_addr;
+
+    skfd = socket (AF_IPX, SOCK_DGRAM, 0);
+    if (skfd < 0) { 
+	if (! ok_error (errno))
+	    dbglog("socket(AF_IPX): %m (%d)", errno);
+	result = 0;
+    }
+    else {
+	memset (&ifr, '\0', sizeof (ifr));
+	strlcpy (ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+
+	sipx->sipx_type    = IPX_FRAME_ETHERII;
+	sipx->sipx_action  = IPX_DLTITF;
+	sipx->sipx_family  = AF_IPX;
+/*
+ *  Set the IPX device
+ */
+	if (ioctl(skfd, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
+	    if (! ok_error (errno))
+		info("ioctl(SIOCSIFADDR, IPX_DLTITF): %m (%d)", 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("/net/ipx_interface")) == 0
+	    || lstat(path, &stat_buf) < 0) {
+	    error("IPX support is not present in the kernel\n");
+	    ipxcp_protent.enabled_flag = 0;
+	}
+    }
+#endif
+    if (demand && driver_is_old) {
+	option_error("demand dialling is not supported by kernel driver "
+		     "version %d.%d.%d", driver_version, driver_modification,
+		     driver_patch);
+	return 0;
+    }
+    if (multilink && !new_style_driver) {
+	warn("Warning: multilink is not supported by the kernel driver");
+	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 <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
+#include <sys/sysmacros.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <string.h>
+#include <time.h>
+#include <memory.h>
+#include <utmp.h>
+#include <mntent.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <termios.h>
+#include <unistd.h>
+
+/* 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__ >= 2
+#include <asm/types.h>		/* glibc 2 conflicts with linux/types.h */
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/route.h>
+#include <netinet/if_ether.h>
+#else
+#include <linux/types.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/route.h>
+#include <linux/if_ether.h>
+#endif
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <linux/ppp_defs.h>
+#include <linux/if_ppp.h>
+
+#include "pppd.h"
+#include "fsm.h"
+#include "ipcp.h"
+
+#ifdef IPX_CHANGE
+#include "ipxcp.h"
+#if __GLIBC__ >= 2 && \
+    !(defined(__powerpc__) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 0)
+#include <netipx/ipx.h>
+#else
+#include <linux/ipx.h>
+#endif
+#endif /* IPX_CHANGE */
+
+#ifdef PPP_FILTER
+#include <net/bpf.h>
+#include <linux/filter.h>
+#endif /* PPP_FILTER */
+
+#ifdef LOCKLIB
+#include <sys/locks.h>
+#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(&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 => 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 *) (&(x)))->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 *) &(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, "setting ppp_fd to %d\n", 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 && ppp_fd >= 0;
+	if (!hungup || ppp_fd == slave_fd)
+		return 1;
+	if (slave_fd >= 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) &flags) < 0) {
+	if ( ok_error (errno) )
+	    flags = 0;
+	else
+	    fatal("ioctl(PPPIOCGFLAGS): %m");
+    }
+
+    SYSDEBUG ((LOG_DEBUG, "get flags = %x\n", flags));
+    return flags;
+}
+
+/********************************************************************/
+
+static void set_flags (int fd, int flags)
+{    
+    SYSDEBUG ((LOG_DEBUG, "set flags = %x\n", flags));
+
+    if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &flags) < 0) {
+	if (! ok_error (errno) )
+	    fatal("ioctl(PPPIOCSFLAGS, %x): %m", flags, errno);
+    }
+}
+
+/********************************************************************
+ *
+ * sys_init - System-dependent initialization.
+ */
+
+void sys_init(void)
+{
+    int flags;
+
+    if (new_style_driver) {
+	ppp_dev_fd = open("/dev/ppp", O_RDWR);
+	if (ppp_dev_fd < 0)
+	    fatal("Couldn't open /dev/ppp: %m");
+	flags = fcntl(ppp_dev_fd, F_GETFL);
+	if (flags == -1
+	    || fcntl(ppp_dev_fd, F_SETFL, flags | O_NONBLOCK) == -1)
+	    warn("Couldn't set /dev/ppp to nonblock: %m");
+    }
+
+    /* Get an internet socket for doing socket ioctls. */
+    sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
+    if (sock_fd < 0)
+	fatal("Couldn't create IP socket: %m(%d)", errno);
+
+#ifdef INET6
+    sock6_fd = socket(AF_INET6, SOCK_DGRAM, 0);
+    if (sock6_fd < 0)
+	sock6_fd = -errno;	/* save errno for later */
+#endif
+
+    FD_ZERO(&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 >= 0)
+	close(sock_fd);
+    if (slave_fd >= 0)
+	close(slave_fd);
+    if (master_fd >= 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 && ifunit < 0)
+	return 1;
+    if (ioctl(ppp_dev_fd, PPPIOCSDEBUG, &requested_level) < 0) {
+	if ( ! ok_error (errno) )
+	    error("ioctl(PPPIOCSDEBUG): %m");
+	return (0);
+    }
+    SYSDEBUG ((LOG_INFO, "set kernel debugging level to %d",
+		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) < 0) {
+	if ( ! ok_error ( errno ))
+	    warn("Couldn't make tty exclusive: %m");
+    }
+/*
+ * Demand mode - prime the old ppp device to relinquish the unit.
+ */
+    if (!new_style_driver && looped
+	&& ioctl(slave_fd, PPPIOCXFERUNIT, 0) < 0) {
+	error("ioctl(transfer ppp unit): %m");
+	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 && sync_serial)? N_SYNC_PPP: N_PPP;
+    if (ioctl(tty_fd, TIOCSETD, &ppp_disc) < 0) {
+	if ( ! ok_error (errno) ) {
+	    error("Couldn't set tty to PPP discipline: %m");
+	    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, &chindex) == -1) {
+	    error("Couldn't get channel number: %m");
+	    goto err;
+	}
+	dbglog("using channel %d", chindex);
+	fd = open("/dev/ppp", O_RDWR);
+	if (fd < 0) {
+	    error("Couldn't reopen /dev/ppp: %m");
+	    goto err;
+	}
+	if (ioctl(fd, PPPIOCATTCHAN, &chindex) < 0) {
+	    error("Couldn't attach to channel %d: %m", chindex);
+	    goto err_close;
+	}
+	flags = fcntl(fd, F_GETFL);
+	if (flags == -1 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
+	    warn("Couldn't set /dev/ppp (channel) to nonblock: %m");
+	set_ppp_fd(fd);
+
+	if (!looped)
+	    ifunit = -1;
+	if (!looped && !multilink) {
+	    /*
+	     * Create a new PPP unit.
+	     */
+	    if (make_ppp_unit() < 0)
+		goto err_close;
+	}
+
+	if (looped)
+	    set_flags(ppp_dev_fd, get_flags(ppp_dev_fd) & ~SC_LOOP_TRAFFIC);
+
+	if (!multilink) {
+	    add_fd(ppp_dev_fd);
+	    if (ioctl(fd, PPPIOCCONNECT, &ifunit) < 0) {
+		error("Couldn't attach to PPP unit %d: %m", 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, &x) < 0) {	
+	    if (ok_error (errno))
+		goto err;
+	    fatal("ioctl(PPPIOCGUNIT): %m(%d)", errno);
+	}
+	/* Check that we got the same unit again. */
+	if (looped && x != ifunit)
+	    fatal("transfer_ppp failed: wanted unit %d, got %d", 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("Couldn't set device to non-blocking mode: %m");
+	}
+    }
+
+    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) & ~(SC_RCVB | SC_LOGB))
+		       | ((kdebugflag * SC_DEBUG) & SC_LOGB)));
+
+    SYSDEBUG ((LOG_NOTICE, "Using version %d.%d.%d of PPP driver",
+	    driver_version, driver_modification, driver_patch));
+
+    return ppp_fd;
+
+ err_close:
+    close(fd);
+ err:
+    if (ioctl(tty_fd, TIOCSETD, &tty_disc) < 0 && !ok_error(errno))
+	warn("Couldn't reset tty to normal line discipline: %m");
+    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) < 0)
+	    warn("tcflush failed: %m");
+/*
+ * Restore the previous line discipline
+ */
+	if (ioctl(tty_fd, TIOCSETD, &tty_disc) < 0) {
+	    if ( ! ok_error (errno))
+		error("ioctl(TIOCSETD, N_TTY): %m");
+	}
+	
+	if (ioctl(tty_fd, TIOCNXCL, 0) < 0) {
+	    if ( ! ok_error (errno))
+		warn("ioctl(TIOCNXCL): %m(%d)", errno);
+	}
+
+	/* Reset non-blocking mode on fd. */
+	if (initfdflags != -1 && fcntl(tty_fd, F_SETFL, initfdflags) < 0) {
+	    if ( ! ok_error (errno))
+		warn("Couldn't restore device fd flags: %m");
+	}
+    }
+    initfdflags = -1;
+
+    if (new_style_driver) {
+	close(ppp_fd);
+	ppp_fd = -1;
+	if (!looped && ifunit >= 0 && ioctl(ppp_dev_fd, PPPIOCDETACH) < 0)
+	    error("Couldn't release PPP unit: %m");
+	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, &ifunit);
+	if (x < 0 && req_unit >= 0 && errno == EEXIST) {
+		warn("Couldn't allocate PPP unit %d as it is already in use");
+		ifunit = -1;
+		x = ioctl(ppp_dev_fd, PPPIOCNEWUNIT, &ifunit);
+	}
+	if (x < 0)
+		error("Couldn't create new ppp unit: %m");
+	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, &mrru) < 0)
+		error("Couldn't set MRRU: %m");
+	flags = get_flags(ppp_dev_fd);
+	flags &= ~(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, &ifunit) < 0)
+		fatal("Couldn't attach to PPP unit %d: %m", 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() < 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, &ifnum) < 0) {
+		if (errno == ENXIO)
+			return 0;	/* doesn't still exist */
+		fatal("Couldn't attach to interface unit %d: %m\n", ifnum);
+	}
+	if (ioctl(ppp_fd, PPPIOCCONNECT, &ifnum) < 0)
+		fatal("Couldn't connect to interface unit %d: %m", 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) &x) == 0) {
+	    s = NULL;
+	    switch (~x & (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) {
+	    case SC_RCV_B7_0:
+		s = "all had bit 7 set to 1";
+		break;
+		
+	    case SC_RCV_B7_1:
+		s = "all had bit 7 set to 0";
+		break;
+		
+	    case SC_RCV_EVNP:
+		s = "all had odd parity";
+		break;
+		
+	    case SC_RCV_ODDP:
+		s = "all had even parity";
+		break;
+	    }
+	    
+	    if (s != NULL) {
+		warn("Receive serial link is not 8-bit clean:");
+		warn("Problem: %s", 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->speed_int; speedp++) {
+	    if (bps == speedp->speed_int)
+		return speedp->speed_val;
+	}
+	warn("speed %d not supported", 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->speed_int; speedp++) {
+	    if (speed == speedp->speed_val)
+		return speedp->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, &tios) < 0) {
+	if (!ok_error(errno))
+	    fatal("tcgetattr: %m(%d)", errno);
+	return;
+    }
+    
+    if (!restore_term)
+	inittermios = tios;
+    
+    tios.c_cflag     &= ~(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 &= ~CRTSCTS;
+	break;
+
+    default:
+	break;
+    }
+    
+    speed = translate_speed(inspeed);
+    if (speed) {
+	cfsetospeed (&tios, speed);
+	cfsetispeed (&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(&tios);
+	if (speed == B0)
+	    fatal("Baud rate for %s is 0; need explicit baud rate", devnam);
+    }
+
+    if (tcsetattr(tty_fd, TCSAFLUSH, &tios) < 0)
+	if (!ok_error(errno))
+	    fatal("tcsetattr: %m");
+    
+    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), &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 &= ~(ECHO | ECHONL);
+	
+	if (tcsetattr(tty_fd, TCSAFLUSH, &inittermios) < 0) {
+	    if (! ok_error (errno))
+		warn("tcsetattr: %m");
+	}
+    }
+}
+
+/********************************************************************
+ *
+ * output - Output PPP packet.
+ */
+
+void output (int unit, unsigned char *p, int len)
+{
+    int fd = ppp_fd;
+    int proto;
+
+    if (debug)
+	dbglog("sent %P", p, len);
+
+    if (len < PPP_HDRLEN)
+	return;
+    if (new_style_driver) {
+	p += 2;
+	len -= 2;
+	proto = (p[0] << 8) + p[1];
+	if (ifunit >= 0 && !(proto >= 0xc000 || proto == PPP_CCPFRAG))
+	    fd = ppp_dev_fd;
+    }
+    if (write(fd, p, len) < 0) {
+	if (errno == EWOULDBLOCK || errno == ENOBUFS
+	    || errno == ENXIO || errno == EIO || errno == EINTR)
+	    warn("write: warning: %m (%d)", errno);
+	else
+	    error("write: %m (%d)", 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, &ready, NULL, &exc, timo);
+    if (n < 0 && errno != EINTR)
+	fatal("select: %m(%d)", errno);
+}
+
+/*
+ * add_fd - add an fd to the set that wait_input waits for.
+ */
+void add_fd(int fd)
+{
+    FD_SET(fd, &in_fds);
+    if (fd > 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, &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 >= 0) {
+	nr = read(ppp_fd, buf, len);
+	if (nr < 0 && errno != EWOULDBLOCK && errno != EIO && errno != EINTR)
+	    error("read: %m");
+	if (nr < 0 && errno == ENXIO)
+	    return 0;
+    }
+    if (nr < 0 && new_style_driver && ifunit >= 0) {
+	/* N.B. we read ppp_fd first since LCP packets come in there. */
+	nr = read(ppp_dev_fd, buf, len);
+	if (nr < 0 && errno != EWOULDBLOCK && errno != EIO && errno != EINTR)
+	    error("read /dev/ppp: %m");
+	if (nr < 0 && errno == ENXIO)
+	    return 0;
+    }
+    return (new_style_driver && nr > 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)) > 0)
+	    if (loop_frame(inpacket_buf, n))
+		rv = 1;
+	return rv;
+    }
+
+    while ((n = read(master_fd, inbuf, sizeof(inbuf))) > 0)
+	if (loop_chars(inbuf, n))
+	    rv = 1;
+
+    if (n == 0)
+	fatal("eof on loopback");
+
+    if (errno != EWOULDBLOCK)
+	fatal("read from loopback: %m(%d)", 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, "netif_set_mtu: mtu = %d\n", mtu));
+
+    memset (&ifr, '\0', sizeof (ifr));
+    strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+    ifr.ifr_mtu = mtu;
+	
+    if (ifunit >= 0 && ioctl(sock_fd, SIOCSIFMTU, (caddr_t) &ifr) < 0)
+	fatal("ioctl(SIOCSIFMTU): %m");
+}
+
+/********************************************************************
+ *
+ * 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, "send_config: asyncmap = %lx\n", asyncmap));
+    if (ioctl(ppp_fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0) {
+	if (!ok_error(errno))
+	    fatal("ioctl(PPPIOCSASYNCMAP): %m(%d)", errno);
+	return;
+    }
+    
+    x = get_flags(ppp_fd);
+    x = pcomp  ? x | SC_COMP_PROT : x & ~SC_COMP_PROT;
+    x = accomp ? x | SC_COMP_AC   : x & ~SC_COMP_AC;
+    x = sync_serial ? x | SC_SYNC : x & ~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, "set_xaccm: %08lx %08lx %08lx %08lx\n",
+		accm[0], accm[1], accm[2], accm[3]));
+
+    if (!still_ppp())
+	return;
+    if (ioctl(ppp_fd, PPPIOCSXASYNCMAP, accm) < 0 && errno != ENOTTY) {
+	if ( ! ok_error (errno))
+	    warn("ioctl(set extended ACCM): %m(%d)", 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, "recv_config: mru = %d\n", 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) &mru) < 0) {
+	if ( ! ok_error (errno))
+	    error("ioctl(PPPIOCSMRU): %m(%d)", errno);
+    }
+    if (new_style_driver && ifunit >= 0
+	&& ioctl(ppp_dev_fd, PPPIOCSMRU, (caddr_t) &mru) < 0)
+	error("Couldn't set MRU in generic PPP layer: %m");
+
+    SYSDEBUG ((LOG_DEBUG, "recv_config: asyncmap = %lx\n", asyncmap));
+    if (ioctl(ppp_fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0) {
+	if (!ok_error(errno))
+	    error("ioctl(PPPIOCSRASYNCMAP): %m(%d)", 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 (&data, '\0', sizeof (data));
+    data.ptr      = opt_ptr;
+    data.length   = opt_len;
+    data.transmit = for_transmit;
+
+    if (ioctl(ppp_dev_fd, PPPIOCSCOMPRESS, (caddr_t) &data) >= 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 &~ SC_CCP_OPEN;
+	x = isup?   x | SC_CCP_UP   : x &~ 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->bf_len;
+	fp.filter = (struct sock_filter *) pass->bf_insns;
+	if (ioctl(ppp_dev_fd, PPPIOCSPASS, &fp) < 0) {
+		if (errno == ENOTTY)
+			warn("kernel does not support PPP filtering");
+		else
+			error("Couldn't set pass-filter in kernel: %m");
+		return 0;
+	}
+	fp.len = active->bf_len;
+	fp.filter = (struct sock_filter *) active->bf_insns;
+	if (ioctl(ppp_dev_fd, PPPIOCSACTIVE, &fp) < 0) {
+		error("Couldn't set active-filter in kernel: %m");
+		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) >= 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 (&req, 0, sizeof (req));
+
+    req.stats_ptr = (caddr_t) &req.stats;
+    strlcpy(req.ifr__name, ifname, sizeof(req.ifr__name));
+    if (ioctl(sock_fd, SIOCGPPPSTATS, &req) < 0) {
+	error("Couldn't get PPP statistics: %m");
+	return 0;
+    }
+    stats->bytes_in = req.stats.p.ppp_ibytes;
+    stats->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 & 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, "/proc", sizeof(proc_path));
+	proc_path_len = 5;
+	fp = fopen(MOUNTED, "r");
+	if (fp != NULL) {
+	    while ((mntent = getmntent(fp)) != NULL) {
+		if (strcmp(mntent->mnt_type, MNTTYPE_IGNORE) == 0)
+		    continue;
+		if (strcmp(mntent->mnt_type, "proc") == 0) {
+		    strlcpy(proc_path, mntent->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[] = " \t\n";
+
+static int open_route_table (void)
+{
+    char *path;
+
+    close_route_table();
+
+    path = path_to_procfs("/net/route");
+    route_fd = fopen (path, "r");
+    if (route_fd == NULL) {
+        error("can't open routing table %s: %m", 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 < ROUTE_MAX_COLS; ++col) {
+	    int used = 1;
+	    if ((q = strtok(p, route_delims)) == 0)
+		break;
+	    if (strcasecmp(q, "iface") == 0)
+		route_dev_col = col;
+	    else if (strcasecmp(q, "destination") == 0)
+		route_dest_col = col;
+	    else if (strcasecmp(q, "gateway") == 0)
+		route_gw_col = col;
+	    else if (strcasecmp(q, "flags") == 0)
+		route_flags_col = col;
+	    else if (strcasecmp(q, "mask") == 0)
+		route_mask_col = col;
+	    else
+		used = 0;
+	    if (used && col >= 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 < 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->rt_dst) = strtoul(cols[route_dest_col], NULL, 16);
+    SIN_ADDR(rt->rt_gateway) = strtoul(cols[route_gw_col], NULL, 16);
+    SIN_ADDR(rt->rt_genmask) = strtoul(cols[route_mask_col], NULL, 16);
+
+    rt->rt_flags = (short) strtoul(cols[route_flags_col], NULL, 16);
+    rt->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->rt_flags & RTF_UP) == 0)
+	    continue;
+
+	if (kernel_version > KVERSION(2,1,0) && SIN_ADDR(rt->rt_genmask) != 0)
+	    continue;
+        if (SIN_ADDR(rt->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(&rt)) {
+	if ((rt.rt_flags & RTF_UP) == 0 || strcmp(rt.rt_dev, ifname) == 0)
+	    continue;
+	if ((addr & 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(&rt) && strcmp(rt.rt_dev, ifname) != 0) {
+	u_int32_t old_gateway = SIN_ADDR(rt.rt_gateway);
+
+	if (old_gateway != gateway)
+	    error("not replacing existing default route to %s [%I]",
+		  rt.rt_dev, old_gateway);
+	return 0;
+    }
+
+    memset (&rt, '\0', sizeof (rt));
+    SET_SA_FAMILY (rt.rt_dst,     AF_INET);
+    SET_SA_FAMILY (rt.rt_gateway, AF_INET);
+
+    if (kernel_version > 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, &rt) < 0) {
+	if ( ! ok_error ( errno ))
+	    error("default route ioctl(SIOCADDRT): %m(%d)", 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 (&rt, '\0', sizeof (rt));
+    SET_SA_FAMILY (rt.rt_dst,     AF_INET);
+    SET_SA_FAMILY (rt.rt_gateway, AF_INET);
+
+    if (kernel_version > 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, &rt) < 0 && errno != ESRCH) {
+	if (still_ppp()) {
+	    if ( ! ok_error ( errno ))
+		error("default route ioctl(SIOCDELRT): %m (%d)", 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 (&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, &arpreq.arp_ha, proxy_arp_dev,
+			    sizeof(proxy_arp_dev))) {
+	    error("Cannot determine ethernet address for proxy ARP");
+	    return 0;
+	}
+	strlcpy(arpreq.arp_dev, proxy_arp_dev, sizeof(arpreq.arp_dev));
+
+	if (ioctl(sock_fd, SIOCSARP, (caddr_t)&arpreq) < 0) {
+	    if ( ! ok_error ( errno ))
+		error("ioctl(SIOCSARP): %m(%d)", errno);
+	    return 0;
+	}
+	proxy_arp_addr = his_adr;
+	has_proxy_arp = 1;
+
+	if (tune_kernel) {
+	    forw_path = path_to_procfs("/sys/net/ipv4/ip_forward");
+	    if (forw_path != 0) {
+		int fd = open(forw_path, O_WRONLY);
+		if (fd >= 0) {
+		    if (write(fd, "1", 1) != 1)
+			error("Couldn't enable IP forwarding: %m");
+		    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 (&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)&arpreq) < 0) {
+	    if ( ! ok_error ( errno ))
+		warn("ioctl(SIOCDARP): %m(%d)", 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, &ifc) < 0) {
+	if ( ! ok_error ( errno ))
+	    error("ioctl(SIOCGIFCONF): %m(%d)", errno);
+	return 0;
+    }
+
+    SYSDEBUG ((LOG_DEBUG, "proxy arp: scanning %d interfaces for IP %s",
+		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 < ifend; ifr++) {
+	if (ifr->ifr_addr.sa_family == AF_INET) {
+	    ina = SIN_ADDR(ifr->ifr_addr);
+	    strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
+            SYSDEBUG ((LOG_DEBUG, "proxy arp: examining interface %s",
+			ifreq.ifr_name));
+/*
+ * Check that the interface is up, and not point-to-point
+ * nor loopback.
+ */
+	    if (ioctl(sock_fd, SIOCGIFFLAGS, &ifreq) < 0)
+		continue;
+
+	    if (((ifreq.ifr_flags ^ FLAGS_GOOD) & FLAGS_MASK) != 0)
+		continue;
+/*
+ * Get its netmask and check that it's on the right subnet.
+ */
+	    if (ioctl(sock_fd, SIOCGIFNETMASK, &ifreq) < 0)
+	        continue;
+
+	    mask = SIN_ADDR(ifreq.ifr_addr);
+	    SYSDEBUG ((LOG_DEBUG, "proxy arp: interface addr %s mask %lx",
+			ip_ntoa(ina), ntohl(mask)));
+
+	    if (((ipaddr ^ ina) & mask) != 0)
+	        continue;
+	    break;
+	}
+    }
+    
+    if (ifr >= 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("found interface %s for proxy arp", name);
+/*
+ * Now get the hardware address.
+ */
+    memset (&ifreq.ifr_hwaddr, 0, sizeof (struct sockaddr));
+    if (ioctl (sock_fd, SIOCGIFHWADDR, &ifreq) < 0) {
+        error("SIOCGIFHWADDR(%s): %m(%d)", ifreq.ifr_name, errno);
+        return 0;
+    }
+
+    memcpy (hwaddr,
+	    &ifreq.ifr_hwaddr,
+	    sizeof (struct sockaddr));
+
+    SYSDEBUG ((LOG_DEBUG,
+	   "proxy arp: found hwaddr %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+		(int) ((unsigned char *) &hwaddr->sa_data)[0],
+		(int) ((unsigned char *) &hwaddr->sa_data)[1],
+		(int) ((unsigned char *) &hwaddr->sa_data)[2],
+		(int) ((unsigned char *) &hwaddr->sa_data)[3],
+		(int) ((unsigned char *) &hwaddr->sa_data)[4],
+		(int) ((unsigned char *) &hwaddr->sa_data)[5],
+		(int) ((unsigned char *) &hwaddr->sa_data)[6],
+		(int) ((unsigned char *) &hwaddr->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 < 0)
+		return 0;
+	memset(&ifreq.ifr_hwaddr, 0, sizeof(struct sockaddr));
+	strlcpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));
+	ret = ioctl(sock_fd, SIOCGIFHWADDR, &ifreq);
+	close(sock_fd);
+	if (ret >= 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 "eth0";
+}
+
+/********************************************************************
+ *
+ * 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, &ifc) < 0) {
+	if ( ! ok_error ( errno ))
+	    warn("ioctl(SIOCGIFCONF): %m(%d)", errno);
+	return mask;
+    }
+    
+    ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
+    for (ifr = ifc.ifc_req; ifr < ifend; ifr++) {
+/*
+ * Check the interface's internet address.
+ */
+	if (ifr->ifr_addr.sa_family != AF_INET)
+	    continue;
+	ina = SIN_ADDR(ifr->ifr_addr);
+	if (((ntohl(ina) ^ addr) & nmask) != 0)
+	    continue;
+/*
+ * Check that the interface is up, and not point-to-point nor loopback.
+ */
+	strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
+	if (ioctl(sock_fd, SIOCGIFFLAGS, &ifreq) < 0)
+	    continue;
+	
+	if (((ifreq.ifr_flags ^ FLAGS_GOOD) & FLAGS_MASK) != 0)
+	    continue;
+/*
+ * Get its netmask and OR it into our mask.
+ */
+	if (ioctl(sock_fd, SIOCGIFNETMASK, &ifreq) < 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, &endp, 10);
+    *modification = 0;
+    *patch        = 0;
+    
+    if (endp != buf && *endp == '.') {
+	buf = endp + 1;
+	*modification = (int) strtoul (buf, &endp, 10);
+	if (endp != buf && *endp == '.') {
+	    buf = endp + 1;
+	    *patch = (int) strtoul (buf, &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(&mfd, &local_fd, slave, 0)) {
+	no_ppp_msg = "Couldn't determine if PPP is supported (no free ptys)";
+	return 0;
+    }
+
+    /*
+     * Try to put the device into the PPP discipline.
+     */
+    if (ioctl(local_fd, TIOCSETD, &ppp_disc) < 0) {
+	error("ioctl(TIOCSETD(PPP)): %m(%d)", 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 = 
+	"This system lacks kernel support for PPP.  This could be because\n"
+	"the PPP kernel module could not be loaded, or because PPP was not\n"
+	"included in the kernel configuration.  If PPP was included as a\n"
+	"module, try `/sbin/modprobe -v ppp'.  If that fails, check that\n"
+	"ppp.o exists in /lib/modules/`uname -r`/net.\n"
+	"See README.linux file in the ppp distribution for more details.\n";
+
+    /* get the kernel version now, since we are called before sys_init */
+    uname(&utsname);
+    osmaj = osmin = ospatch = 0;
+    sscanf(utsname.release, "%d.%d.%d", &osmaj, &osmin, &ospatch);
+    kernel_version = KVERSION(osmaj, osmin, ospatch);
+
+    fd = open("/dev/ppp", O_RDWR);
+#if 0
+    if (fd < 0 && errno == ENOENT) {
+	/* try making it and see if that helps. */
+	if (mknod("/dev/ppp", S_IFCHR | S_IRUSR | S_IWUSR,
+		  makedev(108, 0)) >= 0) {
+	    fd = open("/dev/ppp", O_RDWR);
+	    if (fd >= 0)
+		info("Created /dev/ppp device node");
+	    else
+		unlink("/dev/ppp");	/* didn't work, undo the mknod */
+	} else if (errno == EEXIST) {
+	    fd = open("/dev/ppp", O_RDWR);
+	}
+    }
+#endif /* 0 */
+    if (fd >= 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 >= KVERSION(2,3,13)) {
+	if (errno == ENOENT)
+	    no_ppp_msg =
+		"pppd is unable to open the /dev/ppp device.\n"
+		"You need to create the /dev/ppp device node by\n"
+		"executing the following command as root:\n"
+		"	mknod /dev/ppp c 108 0\n";
+	return 0;
+    }
+
+/*
+ * Open a socket for doing the ioctl operations.
+ */    
+    s = socket(AF_INET, SOCK_DGRAM, 0);
+    if (s < 0)
+	return 0;
+    
+    strlcpy (ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
+    ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 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, "ppp0", sizeof (ifr.ifr_name));
+	    ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
+	}
+    }
+/*
+ * Ensure that the hardware address is for PPP and not something else
+ */
+    if (ok)
+        ok = ioctl (s, SIOCGIFHWADDR, (caddr_t) &ifr) >= 0;
+
+    if (ok && ((ifr.ifr_hwaddr.sa_family & ~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) &ifr);
+	if (size < 0) {
+	    error("Couldn't read driver version: %m");
+	    ok = 0;
+	    no_ppp_msg = "Sorry, couldn't verify kernel driver version\n";
+
+	} else {
+	    decode_version(abBuffer,
+			   &driver_version,
+			   &driver_modification,
+			   &driver_patch);
+/*
+ * Validate the version of the driver against the version that we used.
+ */
+	    decode_version(VERSION,
+			   &my_version,
+			   &my_modification,
+			   &my_patch);
+
+	    /* The version numbers must match */
+	    if (driver_version != my_version)
+		ok = 0;
+      
+	    /* The modification levels must be legal */
+	    if (driver_modification < 3) {
+		if (driver_modification >= 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),
+			 "Sorry - PPP driver version %d.%d.%d is out of date\n",
+			 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__ < 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()) && (utp->ut_pid != mypid))
+        /* nothing */;
+
+    /* Is this call really necessary? There is another one after the 'put' */
+    endutent();
+    
+    if (utp)
+	memcpy(&ut, utp, sizeof(ut));
+    else
+	/* some gettys/telnetds don't initialize utmp... */
+	memset(&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(&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 && ipcp_hisoptions[0].neg_addr)
+	memcpy(&ut.ut_addr, (char *) &ipcp_hisoptions[0].hisaddr,
+		 sizeof(ut.ut_addr));
+	
+    /* CL: Makes sure that the logout works */
+    if (*host == 0 && *name==0)
+	ut.ut_host[0]=0;
+
+    pututline(&ut);
+    endutent();
+/*
+ * Update the wtmp file.
+ */
+#if __GLIBC__ >= 2
+    updwtmp(_PATH_WTMP, &ut);
+#else
+    wtmp = open(_PATH_WTMP, O_APPEND|O_WRONLY);
+    if (wtmp >= 0) {
+	flock(wtmp, LOCK_EX);
+
+	if (write (wtmp, (char *)&ut, sizeof(ut)) != sizeof(ut))
+	    warn("error writing %s: %m", _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) &maxcid) < 0) {
+	    if (! ok_error (errno))
+		error("ioctl(PPPIOCSMAXCID): %m(%d)", errno);
+	    vjcomp = 0;
+	}
+    }
+
+    x = vjcomp  ? x | SC_COMP_TCP     : x &~ SC_COMP_TCP;
+    x = cidcomp ? x & ~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 (&ifr, '\0', sizeof (ifr));
+    strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+    if (ioctl(sock_fd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+	if (! ok_error (errno))
+	    error("ioctl (SIOCGIFFLAGS): %m(%d)", errno);
+	return 0;
+    }
+
+    ifr.ifr_flags |= (IFF_UP | IFF_POINTOPOINT);
+    if (ioctl(sock_fd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+	if (! ok_error (errno))
+	    error("ioctl(SIOCSIFFLAGS): %m(%d)", 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 && --if_is_up > 0)
+	return 1;
+
+    memset (&ifr, '\0', sizeof (ifr));
+    strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+    if (ioctl(sock_fd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+	if (! ok_error (errno))
+	    error("ioctl (SIOCGIFFLAGS): %m(%d)", errno);
+	return 0;
+    }
+
+    ifr.ifr_flags &= ~IFF_UP;
+    ifr.ifr_flags |= IFF_POINTOPOINT;
+    if (ioctl(sock_fd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+	if (! ok_error (errno))
+	    error("ioctl(SIOCSIFFLAGS): %m(%d)", 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 (&ifr, '\0', sizeof (ifr));
+    memset (&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) &ifr) < 0) {
+	if (errno != EEXIST) {
+	    if (! ok_error (errno))
+		error("ioctl(SIOCSIFADDR): %m(%d)", errno);
+	}
+        else {
+	    warn("ioctl(SIOCSIFADDR): Address already exists");
+	}
+        return (0);
+    }
+/*
+ *  Set the gateway address
+ */
+    SIN_ADDR(ifr.ifr_dstaddr) = his_adr;
+    if (ioctl(sock_fd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
+	if (! ok_error (errno))
+	    error("ioctl(SIOCSIFDSTADDR): %m(%d)", errno); 
+	return (0);
+    } 
+/*
+ *  Set the netmask.
+ *  For recent kernels, force the netmask to 255.255.255.255.
+ */
+    if (kernel_version >= 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) &ifr) < 0) {
+	    if (! ok_error (errno))
+		error("ioctl(SIOCSIFNETMASK): %m(%d)", errno); 
+	    return (0);
+	} 
+    }
+/*
+ *  Add the device route
+ */
+    if (kernel_version < 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 > KVERSION(2,1,0)) {
+	    SET_SA_FAMILY (rt.rt_genmask, AF_INET);
+	    SIN_ADDR(rt.rt_genmask) = -1L;
+	}
+
+	if (ioctl(sock_fd, SIOCADDRT, &rt) < 0) {
+	    if (! ok_error (errno))
+		error("ioctl(SIOCADDRT) device route: %m(%d)", errno);
+	    return (0);
+	}
+    }
+
+    /* set ip_dynaddr in demand mode if address changes */
+    if (demand && tune_kernel && !dynaddr_set
+	&& our_old_addr && our_old_addr != our_adr) {
+	/* set ip_dynaddr if possible */
+	char *path;
+	int fd;
+
+	path = path_to_procfs("/sys/net/ipv4/ip_dynaddr");
+	if (path != 0 && (fd = open(path, O_WRONLY)) >= 0) {
+	    if (write(fd, "1", 1) != 1)
+		error("Couldn't enable dynamic IP addressing: %m");
+	    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 < KVERSION(2,1,16)) {
+/*
+ *  Delete the route through the device
+ */
+	struct rtentry rt;
+	memset (&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 > KVERSION(2,1,0)) {
+	    SET_SA_FAMILY (rt.rt_genmask, AF_INET);
+	    SIN_ADDR(rt.rt_genmask) = -1L;
+	}
+
+	if (ioctl(sock_fd, SIOCDELRT, &rt) < 0 && errno != ESRCH) {
+	    if (still_ppp() && ! ok_error (errno))
+		error("ioctl(SIOCDELRT) device route: %m(%d)", errno);
+	    return (0);
+	}
+    }
+
+    /* This way it is possible to have an IPX-only or IPv6-only interface */
+    memset(&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) &ifr) < 0) {
+	if (! ok_error (errno)) {
+	    error("ioctl(SIOCSIFADDR): %m(%d)", 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 < 0) {
+	errno = -sock6_fd;
+	error("IPv6 socket creation failed: %m");
+	return 0;
+    }
+    memset(&ifr, 0, sizeof (ifr));
+    strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+    if (ioctl(sock6_fd, SIOCGIFINDEX, (caddr_t) &ifr) < 0) {
+	error("sif6addr: ioctl(SIOCGIFINDEX): %m (%d)", errno);
+	return 0;
+    }
+    
+    /* Local interface */
+    memset(&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, &ifr6) < 0) {
+	error("sif6addr: ioctl(SIOCSIFADDR): %m (%d)", errno);
+	return 0;
+    }
+    
+    /* Route to remote host */
+    memset(&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, &rt6) < 0) {
+	error("sif6addr: ioctl(SIOCADDRT): %m (%d)", 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 < 0) {
+	errno = -sock6_fd;
+	error("IPv6 socket creation failed: %m");
+	return 0;
+    }
+    memset(&ifr, 0, sizeof(ifr));
+    strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+    if (ioctl(sock6_fd, SIOCGIFINDEX, (caddr_t) &ifr) < 0) {
+	error("cif6addr: ioctl(SIOCGIFINDEX): %m (%d)", errno);
+	return 0;
+    }
+    
+    memset(&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, &ifr6) < 0) {
+	if (errno != EADDRNOTAVAIL) {
+	    if (! ok_error (errno))
+		error("cif6addr: ioctl(SIOCDIFADDR): %m (%d)", errno);
+	}
+        else {
+	    warn("cif6addr: ioctl(SIOCDIFADDR): No such address");
+	}
+        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 >= 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("/dev/ptmx", O_RDWR);
+    if (mfd >= 0) {
+	int ptn;
+	if (ioctl(mfd, TIOCGPTN, &ptn) >= 0) {
+	    slprintf(pty_name, sizeof(pty_name), "/dev/pts/%d", ptn);
+	    chmod(pty_name, S_IRUSR | S_IWUSR);
+#ifdef TIOCSPTLCK
+	    ptn = 0;
+	    if (ioctl(mfd, TIOCSPTLCK, &ptn) < 0)
+		warn("Couldn't unlock pty slave %s: %m", pty_name);
+#endif
+	    if ((sfd = open(pty_name, O_RDWR | O_NOCTTY)) < 0)
+		warn("Couldn't open pty slave %s: %m", pty_name);
+	}
+    }
+#endif /* TIOCGPTN */
+
+    if (sfd < 0) {
+	/* the old way - scan through the pty name space */
+	for (i = 0; i < 64; ++i) {
+	    slprintf(pty_name, sizeof(pty_name), "/dev/pty%c%x",
+		     'p' + i / 16, i % 16);
+	    mfd = open(pty_name, O_RDWR, 0);
+	    if (mfd >= 0) {
+		pty_name[5] = 't';
+		sfd = open(pty_name, O_RDWR | O_NOCTTY, 0);
+		if (sfd >= 0) {
+		    fchown(sfd, uid, -1);
+		    fchmod(sfd, S_IRUSR | S_IWUSR);
+		    break;
+		}
+		close(mfd);
+	    }
+	}
+    }
+
+    if (sfd < 0)
+	return 0;
+
+    strlcpy(slave_name, pty_name, 16);
+    *master_fdp = mfd;
+    *slave_fdp = sfd;
+    if (tcgetattr(sfd, &tios) == 0) {
+	tios.c_cflag &= ~(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, &tios) < 0)
+	    warn("couldn't set attributes on pty: %m");
+    } else
+	warn("couldn't get attributes on pty: %m");
+
+    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() < 0)
+	    die(1);
+	set_flags(ppp_dev_fd, SC_LOOP_TRAFFIC);
+	set_kdebugflag(kdebugflag);
+	ppp_fd = -1;
+	return ppp_dev_fd;
+    }
+
+    if (!get_pty(&master_fd, &slave_fd, loop_name, 0))
+	fatal("No free pty for loopback");
+    SYSDEBUG(("using %s for loopback", 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("couldn't set master loopback to nonblock: %m(%d)", errno);
+
+    flags = fcntl(ppp_fd, F_GETFL);
+    if (flags == -1 ||
+	fcntl(ppp_fd, F_SETFL, flags | O_NONBLOCK) == -1)
+	warn("couldn't set slave loopback to nonblock: %m(%d)", errno);
+
+    if (ioctl(ppp_fd, TIOCSETD, &ppp_disc) < 0)
+	fatal("ioctl(TIOCSETD): %m(%d)", errno);
+/*
+ * Find out which interface we were given.
+ */
+    if (ioctl(ppp_fd, PPPIOCGUNIT, &ifunit) < 0)
+	fatal("ioctl(PPPIOCGUNIT): %m(%d)", 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, &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) &npi) < 0) {
+	if (! ok_error (errno))
+	    error("ioctl(PPPIOCSNPMODE, %d, %d): %m (%d)",
+		   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 *) &ifr.ifr_addr;
+
+    skfd = socket (AF_IPX, SOCK_DGRAM, 0);
+    if (skfd < 0) { 
+	if (! ok_error (errno))
+	    dbglog("socket(AF_IPX): %m (%d)", errno);
+	result = 0;
+    }
+    else {
+	memset (&ifr, '\0', sizeof (ifr));
+	strlcpy (ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+
+	memcpy (sipx->sipx_node, node, IPX_NODE_LEN);
+	sipx->sipx_family  = AF_IPX;
+	sipx->sipx_port    = 0;
+	sipx->sipx_network = htonl (network);
+	sipx->sipx_type    = IPX_FRAME_ETHERII;
+	sipx->sipx_action  = IPX_CRTITF;
+/*
+ *  Set the IPX device
+ */
+	if (ioctl(skfd, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
+	    result = 0;
+	    if (errno != EEXIST) {
+		if (! ok_error (errno))
+		    dbglog("ioctl(SIOCSIFADDR, CRTITF): %m (%d)", errno);
+	    }
+	    else {
+		warn("ioctl(SIOCSIFADDR, CRTITF): Address already exists");
+	    }
+	}
+	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 *) &ifr.ifr_addr;
+
+    skfd = socket (AF_IPX, SOCK_DGRAM, 0);
+    if (skfd < 0) { 
+	if (! ok_error (errno))
+	    dbglog("socket(AF_IPX): %m (%d)", errno);
+	result = 0;
+    }
+    else {
+	memset (&ifr, '\0', sizeof (ifr));
+	strlcpy (ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+
+	sipx->sipx_type    = IPX_FRAME_ETHERII;
+	sipx->sipx_action  = IPX_DLTITF;
+	sipx->sipx_family  = AF_IPX;
+/*
+ *  Set the IPX device
+ */
+	if (ioctl(skfd, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
+	    if (! ok_error (errno))
+		info("ioctl(SIOCSIFADDR, IPX_DLTITF): %m (%d)", 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("/net/ipx_interface")) == 0
+	    || lstat(path, &stat_buf) < 0) {
+	    error("IPX support is not present in the kernel\n");
+	    ipxcp_protent.enabled_flag = 0;
+	}
+    }
+#endif
+    if (demand && driver_is_old) {
+	option_error("demand dialling is not supported by kernel driver "
+		     "version %d.%d.%d", driver_version, driver_modification,
+		     driver_patch);
+	return 0;
+    }
+    if (multilink && !new_style_driver) {
+	warn("Warning: multilink is not supported by the kernel driver");
+	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 <adi.masputra at sun.com>, 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 "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ */
+
+#define RCSID	"$Id: sys-solaris.c 195720 2001-06-11 11:44:34Z gc $"
+
+#include <limits.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <termios.h>
+#ifndef CRTSCTS
+#include <sys/termiox.h>
+#endif
+#include <signal.h>
+#include <utmpx.h>
+#include <sys/types.h>
+#include <sys/ioccom.h>
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/sysmacros.h>
+#include <sys/systeminfo.h>
+#include <sys/dlpi.h>
+#include <sys/stat.h>
+#include <sys/mkdev.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/route.h>
+#include <net/ppp_defs.h>
+#include <net/pppio.h>
+#include <netinet/in.h>
+#ifdef SOL2
+#include <sys/tihdr.h>
+#include <sys/tiuser.h>
+#include <inet/common.h>
+#include <inet/mib2.h>
+#include <sys/ethernet.h>
+#endif
+
+#include "pppd.h"
+#include "fsm.h"
+#include "lcp.h"
+#include "ipcp.h"
+#include "ccp.h"
+
+#if !defined(PPP_DRV_NAME)
+#define PPP_DRV_NAME	"ppp"
+#endif /* !defined(PPP_DRV_NAME) */
+
+#if !defined(PPP_DEV_NAME)
+#define PPP_DEV_NAME	"/dev/" PPP_DRV_NAME
+#endif /* !defined(PPP_DEV_NAME) */
+
+#if !defined(AHDLC_MOD_NAME)
+#define AHDLC_MOD_NAME	"ppp_ahdl"
+#endif /* !defined(AHDLC_MOD_NAME) */
+
+#if !defined(COMP_MOD_NAME)
+#define COMP_MOD_NAME	"ppp_comp"
+#endif /* !defined(COMP_MOD_NAME) */
+
+#if !defined(IP_DEV_NAME)
+#define	IP_DEV_NAME	"/dev/ip"
+#endif /* !defined(IP_DEV_NAME) */
+
+#if !defined(IP_MOD_NAME)
+#define	IP_MOD_NAME	"ip"
+#endif /* !defined(IP_MOD_NAME) */
+
+#if !defined(UDP_DEV_NAME) && defined(SOL2)
+#define	UDP_DEV_NAME	"/dev/udp"
+#endif /* !defined(UDP_DEV_NAME) && defined(SOL2) */
+
+#if !defined(UDP6_DEV_NAME) && defined(SOL2)
+#define	UDP6_DEV_NAME	"/dev/udp6"
+#endif /* !defined(UDP6_DEV_NAME) && defined(SOL2) */
+
+static const char rcsid[] = RCSID;
+
+#if defined(SOL2)
+/*
+ * "/dev/udp" is used as a multiplexor to PLINK the interface stream
+ * under. It is used in place of "/dev/ip" since 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.
+ */
+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) && 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->sin6_addr.s6_addr32[0] = htonl(as); 	\
+	eui64_copy(eui64, s->sin6_addr.s6_addr32[2]);	\
+	s->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) && defined(SOL2) */
+
+#if defined(INET6) && 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) && 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 *)&ppa);
+}
+#endif /* SOL2 */
+
+#if defined(SOL2) && 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 < 0) {
+	return 0;
+    }
+
+    /*
+     * Find out how many interfaces are running
+     */
+    lifn.lifn_family = AF_UNSPEC;
+    lifn.lifn_flags = LIFC_NOXMIT;
+    if (ioctl(fd, SIOCGLIFNUM, &lifn) < 0) {
+	close(fd);
+	error("could not determine number of interfaces: %m");
+	return 0;
+    }
+
+    num_ifs = lifn.lifn_count;
+    req_size = num_ifs * sizeof(struct lifreq);
+    req = malloc(req_size);
+    if (req == NULL) {
+	close(fd);
+	error("out of memory");
+	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, &lifc) < 0) {
+	close(fd);
+	free(req);
+	error("SIOCGLIFCONF: %m");
+	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 > 0; i--, plifreq++) {
+
+	if (strchr(plifreq->lifr_name, ':') != NULL)
+	    continue;
+
+	memset(&lifr, 0, sizeof(lifr));
+	strncpy(lifr.lifr_name, plifreq->lifr_name, sizeof(lifr.lifr_name));
+	if (ioctl(fd, SIOCGLIFFLAGS, &lifr) < 0) {
+	    close(fd);
+	    free(req);
+	    error("SIOCGLIFFLAGS: %m");
+	    return 0;
+	}
+	fl = lifr.lifr_flags;
+
+	if ((fl & (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 < 0) {
+	return 0;
+    }
+
+    /*
+     * Find out how many interfaces are running
+     */
+    if (ioctl(fd, SIOCGIFNUM, (char *)&num_ifs) < 0) {
+	num_ifs = MAXIFS;
+    }
+
+    req_size = num_ifs * sizeof(struct ifreq);
+    req = malloc(req_size);
+    if (req == NULL) {
+	close(fd);
+	error("out of memory");
+	return 0;
+    }
+
+    /*
+     * Get interface configuration info for all interfaces
+     */
+    ifc.ifc_len = req_size;
+    ifc.ifc_buf = req;
+    if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) {
+	close(fd);
+	free(req);
+	error("SIOCGIFCONF: %m");
+	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 > 0; i--, pifreq++) {
+
+	if (strchr(pifreq->ifr_name, ':') != NULL)
+	    continue;
+
+	memset(&ifr, 0, sizeof(ifr));
+	strncpy(ifr.ifr_name, pifreq->ifr_name, sizeof(ifr.ifr_name));
+	if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
+	    close(fd);
+	    free(req);
+	    error("SIOCGIFFLAGS: %m");
+	    return 0;
+	}
+	fl = ifr.ifr_flags;
+
+	if ((fl & (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) && 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 *)&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, &s_eth_addr)) {
+	error("could not obtain hardware address for %s", if_name);
+	return -1;
+    }
+
+    memcpy(addr, eth_addr->ether_addr_octet, 6);
+    return 1;
+}
+#endif /* SOL2 */
+
+#if defined(SOL2) && 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(&lifr, 0, sizeof(lifr));
+    ret = ioctl(fd, SIOCGLIFFLAGS, &lifr);
+    if (ret < 0)
+	goto slifname_done;
+
+    lifr.lifr_flags |= IFF_IPV6;
+    lifr.lifr_flags &= ~(IFF_BROADCAST | IFF_IPV4);
+    lifr.lifr_ppa = ppa;
+    strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
+
+    ret = ioctl(fd, SIOCSLIFNAME, &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 *)&s_eth_addr.sa_data;
+    char *if_name;
+
+    if ((if_name = get_first_ethernet()) == NULL) {
+	error("no persistent id can be found");
+	return 0;
+    }
+ 
+    /*
+     * Send DL_INFO_REQ to the driver to solicit its MAC address
+     */
+    if (!get_hw_addr_dlpi(if_name, &s_eth_addr)) {
+	error("could not obtain hardware address for %s", if_name);
+	return 0;
+    }
+
+    /*
+     * And convert the EUI-48 into EUI-64, per RFC 2472 [sec 4.1]
+     */
+    p_eui64->e8[0] = (eth_addr->ether_addr_octet[0] & 0xFF) | 0x02;
+    p_eui64->e8[1] = (eth_addr->ether_addr_octet[1] & 0xFF);
+    p_eui64->e8[2] = (eth_addr->ether_addr_octet[2] & 0xFF);
+    p_eui64->e8[3] = 0xFF;
+    p_eui64->e8[4] = 0xFE;
+    p_eui64->e8[5] = (eth_addr->ether_addr_octet[3] & 0xFF);
+    p_eui64->e8[6] = (eth_addr->ether_addr_octet[4] & 0xFF);
+    p_eui64->e8[7] = (eth_addr->ether_addr_octet[5] & 0xFF);
+
+    return 1;
+}
+#endif /* defined(SOL2) && defined(INET6) */
+
+/*
+ * sys_init - System-dependent initialization.
+ */
+void
+sys_init()
+{
+    int ifd, x;
+    struct ifreq ifr;
+#if defined(INET6) && defined(SOL2)
+    int i6fd;
+    struct lifreq lifr;
+#endif /* defined(INET6) && 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 < 0)
+	fatal("Couldn't open IP device: %m");
+
+#if defined(INET6) && defined(SOL2)
+    ip6fd = open(UDP6_DEV_NAME, O_RDWR, 0);
+    if (ip6fd < 0)
+	fatal("Couldn't open IP device (2): %m");
+#endif /* defined(INET6) && defined(SOL2) */
+
+    if (default_device && !notty)
+	tty_sid = getsid((pid_t)0);
+
+    pppfd = open(PPP_DEV_NAME, O_RDWR | O_NONBLOCK, 0);
+    if (pppfd < 0)
+	fatal("Can't open %s: %m", PPP_DEV_NAME);
+    if (kdebugflag & 1) {
+	x = PPPDBG_LOG + PPPDBG_DRIVER;
+	strioctl(pppfd, PPPIO_DEBUG, &x, sizeof(int), 0);
+    }
+
+    /* Assign a new PPA and get its unit number. */
+    if (strioctl(pppfd, PPPIO_NEWPPA, &ifunit, 0, sizeof(int)) < 0)
+	fatal("Can't create new PPP interface: %m");
+
+#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 ?
+     * <adi.masputra at sun.com>
+     */
+    sprintf(ifname, PPP_DRV_NAME "%d", 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 < 0)
+	fatal("Can't open %s (2): %m", PPP_DEV_NAME);
+    if (kdebugflag & 1) {
+	x = PPPDBG_LOG + PPPDBG_DRIVER;
+	strioctl(ifd, PPPIO_DEBUG, &x, sizeof(int), 0);
+    }
+
+#if defined(INET6) && defined(SOL2)
+    i6fd = open(PPP_DEV_NAME, O_RDWR, 0);
+    if (i6fd < 0) {
+	close(ifd);
+	fatal("Can't open %s (3): %m", PPP_DEV_NAME);
+    }
+    if (kdebugflag & 1) {
+	x = PPPDBG_LOG + PPPDBG_DRIVER;
+	strioctl(i6fd, PPPIO_DEBUG, &x, sizeof(int), 0);
+    }
+#endif /* defined(INET6) && defined(SOL2) */
+
+#if defined(SOL2)
+    if (ioctl(ifd, I_PUSH, IP_MOD_NAME) < 0) {
+	close(ifd);
+#if defined(INET6)
+	close(i6fd);
+#endif /* defined(INET6) */
+	fatal("Can't push IP module: %m");
+    }
+
+    /*
+     * Assign ppa according to the unit number returned by ppp device
+     * after plumbing is completed above.
+     */
+    if (sifppa(ifd, ifunit) < 0) {
+        close (ifd);
+#if defined(INET6)
+	close(i6fd);
+#endif /* defined(INET6) */
+        fatal("Can't set ppa for unit %d: %m", 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) < 0) {
+	close(ifd);
+	close(i6fd);
+	fatal("Can't push IP module (2): %m");
+    }
+
+    /*
+     * 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) < 0) {
+	close(ifd);
+	close(i6fd);
+	fatal("Can't set ifname for unit %d: %m", ifunit);
+    }
+#endif /* defined(INET6) */
+
+    ipmuxid = ioctl(ipfd, I_PLINK, ifd);
+    close(ifd);
+    if (ipmuxid < 0) {
+#if defined(INET6)
+	close(i6fd);
+#endif /* defined(INET6) */
+	fatal("Can't I_PLINK PPP device to IP: %m");
+    }
+
+    memset(&ifr, 0, sizeof(ifr));
+    sprintf(ifr.ifr_name, "%s", 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, &ifr) < 0) {
+	ioctl(ipfd, I_PUNLINK, ipmuxid);
+#if defined(INET6)
+	close(i6fd);
+#endif /* defined(INET6) */
+	fatal("SIOCSIFMUXID: %m");
+    }
+
+#else /* else if !defined(SOL2) */
+
+    if (dlpi_attach(ifd, ifunit) < 0 ||
+	dlpi_get_reply(ifd, &reply.prim, DL_OK_ACK, sizeof(reply)) < 0) {
+	close(ifd);
+	fatal("Can't attach to ppp%d: %m", ifunit);
+    }
+
+    ipmuxid = ioctl(ipfd, I_LINK, ifd);
+    close(ifd);
+    if (ipmuxid < 0)
+	fatal("Can't link PPP device to IP: %m");
+#endif /* defined(SOL2) */
+
+#if defined(INET6) && defined(SOL2)
+    ip6muxid = ioctl(ip6fd, I_PLINK, i6fd);
+    close(i6fd);
+    if (ip6muxid < 0) {
+	ioctl(ipfd, I_PUNLINK, ipmuxid);
+	fatal("Can't I_PLINK PPP device to IP (2): %m");
+    }
+
+    memset(&lifr, 0, sizeof(lifr));
+    sprintf(lifr.lifr_name, "%s", ifname);
+    lifr.lifr_ip_muxid = ip6muxid;
+
+    /*
+     * Let IP know of the mux id [see comment for SIOCSIFMUXID above]
+     */
+    if (ioctl(ip6fd, SIOCSLIFMUXID, &lifr) < 0) {
+	ioctl(ipfd, I_PUNLINK, ipmuxid);
+	ioctl(ip6fd, I_PUNLINK, ip6muxid);
+	fatal("Can't link PPP device to IP (2): %m");
+    }
+#endif /* defined(INET6) && defined(SOL2) */
+
+#if !defined(SOL2)
+    /* Set the interface name for the link. */
+    slprintf(ifr.ifr_name, sizeof(ifr.ifr_name), PPP_DRV_NAME "%d", ifunit);
+    ifr.ifr_metric = ipmuxid;
+    if (strioctl(ipfd, SIOCSIFNAME, (char *)&ifr, sizeof ifr, 0) < 0)
+	fatal("Can't set interface name %s: %m", 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) && defined(INET6)
+    if (if6_is_up)
+	sif6down(0);
+#endif /* defined(SOL2) && 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(&ifr, 0, sizeof(ifr));
+    sprintf(ifr.ifr_name, "%s", ifname);
+    if (ioctl(ipfd, SIOCGIFFLAGS, &ifr) < 0) {
+	error("SIOCGIFFLAGS: %m");
+	return;
+    }
+
+    if (ioctl(ipfd, SIOCGIFMUXID, &ifr) < 0) {
+	error("SIOCGIFMUXID: %m");
+	return;
+    }
+
+    ipmuxid = ifr.ifr_ip_muxid;
+     
+    if (ioctl(ipfd, I_PUNLINK, ipmuxid) < 0) {
+	error("Can't I_PUNLINK PPP from IP: %m");
+	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(&lifr, 0, sizeof(lifr));
+    sprintf(lifr.lifr_name, "%s", ifname);
+    if (ioctl(ip6fd, SIOCGLIFFLAGS, &lifr) < 0) {
+	error("SIOCGLIFFLAGS: %m");
+	return;
+    }
+
+    if (ioctl(ip6fd, SIOCGLIFMUXID, &lifr) < 0) {
+	error("SIOCGLIFMUXID: %m");
+	return;
+    }
+
+    ip6muxid = lifr.lifr_ip_muxid;
+
+    if (ioctl(ip6fd, I_PUNLINK, ip6muxid) < 0) {
+	error("Can't I_PUNLINK PPP from IP (2): %m");
+    }
+#endif /* defined(INET6) */
+#endif /* defined(SOL2) */
+}
+
+/*
+ * sys_close - Clean up in a child process before execing.
+ */
+void
+sys_close()
+{
+    close(ipfd);
+#if defined(INET6) && defined(SOL2)
+    close(ip6fd);
+#endif /* defined(INET6) && defined(SOL2) */
+    if (pppfd >= 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()) < 0)
+	return -1;
+    if (pid != 0)
+	exit(0);		/* parent dies */
+    setsid();
+    if (!nochdir)
+	chdir("/");
+    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, &buf) >= 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) &&
+	(!lcp_wantoptions[0].neg_pcompression) &&
+	(!ccp_protent.enabled_flag) &&
+	(!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]) < 0
+	    || strcmp(tty_modules[i], "ptem") == 0
+	    || ioctl(fd, I_POP, 0) < 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) < 0) {
+            error("Couldn't push PPP Async HDLC module: %m");
+	    return -1;
+        }
+        ++tty_npushed;
+    }
+    if (kdebugflag & 4) {
+	i = PPPDBG_LOG + PPPDBG_AHDLC;
+	strioctl(pppfd, PPPIO_DEBUG, &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) < 0)
+	    error("Couldn't push PPP compression module: %m");
+	else
+	    ++tty_npushed;
+    }
+
+    if (kdebugflag & 2) {
+	i = PPPDBG_LOG; 
+	if (any_compressions())
+	    i += PPPDBG_COMP;
+	strioctl(pppfd, PPPIO_DEBUG, &i, sizeof(int), 0);
+    }
+
+    /* Link the serial port under the PPP multiplexor. */
+    if ((fdmuxid = ioctl(pppfd, I_LINK, fd)) < 0) {
+	error("Can't link tty to PPP mux: %m");
+	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 >= 0) {
+	if (ioctl(pppfd, I_UNLINK, fdmuxid) < 0) {
+	    if (!hungup)
+		error("Can't unlink tty from PPP mux: %m");
+	}
+	fdmuxid = -1;
+
+	if (!hungup) {
+	    while (tty_npushed > 0 && ioctl(fd, I_POP, 0) >= 0)
+		--tty_npushed;
+	    for (i = tty_nmodules - 1; i >= 0; --i)
+		if (ioctl(fd, I_PUSH, tty_modules[i]) < 0)
+		    error("Couldn't restore tty module %s: %m",
+			   tty_modules[i]);
+	}
+	if (hungup && default_device && tty_sid > 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, &x, 0, sizeof(x)) < 0)
+	return;
+    s = NULL;
+    switch (~x) {
+    case RCV_B7_0:
+	s = "bit 7 set to 1";
+	break;
+    case RCV_B7_1:
+	s = "bit 7 set to 0";
+	break;
+    case RCV_EVNP:
+	s = "odd parity";
+	break;
+    case RCV_ODDP:
+	s = "even parity";
+	break;
+    }
+    if (s != NULL) {
+	warn("Serial link is not 8-bit clean:");
+	warn("All received characters had %s", 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->speed_int; speedp++)
+	if (bps == speedp->speed_int)
+	    return speedp->speed_val;
+    warn("speed %d not supported", 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->speed_int; speedp++)
+	if (speed == speedp->speed_val)
+	    return speedp->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 && tcgetattr(fd, &tios) < 0)
+	fatal("tcgetattr: %m");
+
+#ifndef CRTSCTS
+    termiox_ok = 1;
+    if (!sync_serial && ioctl (fd, TCGETX, &tiox) < 0) {
+	termiox_ok = 0;
+	if (errno != ENOTTY)
+	    error("TCGETX: %m");
+    }
+#endif
+
+    if (!restore_term) {
+	inittermios = tios;
+#ifndef CRTSCTS
+	inittermiox = tiox;
+#endif
+	if (!sync_serial)
+	    ioctl(fd, TIOCGWINSZ, &wsinfo);
+    }
+
+    tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
+#ifdef CRTSCTS
+    if (crtscts > 0)
+	tios.c_cflag |= CRTSCTS;
+    else if (crtscts < 0)
+	tios.c_cflag &= ~CRTSCTS;
+#else
+    if (crtscts != 0 && !termiox_ok) {
+	error("Can't set RTS/CTS flow control");
+    } else if (crtscts > 0) {
+	tiox.x_hflag |= RTSXOFF|CTSXON;
+    } else if (crtscts < 0) {
+	tiox.x_hflag &= ~(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(&tios, speed);
+	cfsetispeed(&tios, speed);
+    } else {
+	speed = cfgetospeed(&tios);
+	/*
+	 * We can't proceed if the serial port speed is 0,
+	 * since that implies that the serial port is disabled.
+	 */
+	if ((speed == B0) && !sync_serial)
+	    fatal("Baud rate for %s is 0; need explicit baud rate", devnam);
+    }
+
+    if (!sync_serial && tcsetattr(fd, TCSAFLUSH, &tios) < 0)
+	fatal("tcsetattr: %m");
+
+#ifndef CRTSCTS
+    if (!sync_serial && termiox_ok && ioctl (fd, TCSETXF, &tiox) < 0){
+	error("TCSETXF: %m");
+    }
+#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 &= ~(ECHO | ECHONL);
+	}
+	if (!sync_serial && tcsetattr(fd, TCSAFLUSH, &inittermios) < 0)
+	    if (!hungup && errno != ENXIO)
+		warn("tcsetattr: %m");
+#ifndef CRTSCTS
+	if (!sync_serial && ioctl (fd, TCSETXF, &inittermiox) < 0){
+	    if (!hungup && errno != ENXIO)
+		error("TCSETXF: %m");
+	}
+#endif
+	if (!sync_serial)
+	    ioctl(fd, TIOCSWINSZ, &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), &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("sent %P", p, len);
+
+    data.len = len;
+    data.buf = (caddr_t) p;
+    retries = 4;
+    while (putmsg(pppfd, NULL, &data, 0) < 0) {
+	if (--retries < 0 || (errno != EWOULDBLOCK && errno != EAGAIN)) {
+	    if (errno != ENXIO)
+		error("Couldn't send packet: %m");
+	    break;
+	}
+	pfd.fd = pppfd;
+	pfd.events = POLLOUT;
+	poll(&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->tv_sec * 1000 + timo->tv_usec / 1000;
+    if (poll(pollfds, n_pollfds, t) < 0 && errno != EINTR)
+	fatal("poll: %m");
+}
+
+/*
+ * 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 < n_pollfds; ++n)
+	if (pollfds[n].fd == fd)
+	    return;
+    if (n_pollfds < MAX_POLLFDS) {
+	pollfds[n_pollfds].fd = fd;
+	pollfds[n_pollfds].events = POLLIN | POLLPRI | POLLHUP;
+	++n_pollfds;
+    } else
+	error("Too many inputs!");
+}
+
+/*
+ * 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 < n_pollfds; ++n) {
+	if (pollfds[n].fd == fd) {
+	    while (++n < 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 < 0 && errno != EINTR)
+	fatal("select: %m");
+}
+#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, &ctrl, &data, &flags);
+	if (len < 0) {
+	    if (errno == EAGAIN || errno == EINTR)
+		return -1;
+	    fatal("Error reading packet: %m");
+	}
+
+	if (ctrl.len <= 0)
+	    return data.len;
+
+	/*
+	 * Got a M_PROTO or M_PCPROTO message.  Interpret it
+	 * as a DLPI primitive??
+	 */
+	if (debug)
+	    dbglog("got dlpi prim 0x%x, len=%d",
+		   ((union DL_primitives *)ctrlbuf)->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)) > 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) && defined(SOL2)
+    struct lifreq lifr;
+    int	fd;
+#endif /* defined(INET6) && defined(SOL2) */
+
+    memset(&ifr, 0, sizeof(ifr));
+    strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+    ifr.ifr_metric = link_mtu;
+    if (ioctl(ipfd, SIOCSIFMTU, &ifr) < 0) {
+	error("Couldn't set IP MTU (%s): %m", ifr.ifr_name);
+    }
+
+#if defined(INET6) && defined(SOL2) 
+    fd = socket(AF_INET6, SOCK_DGRAM, 0);
+    if (fd < 0)
+	error("Couldn't open IPv6 socket: %m");
+
+    memset(&lifr, 0, sizeof(lifr));
+    strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
+    lifr.lifr_mtu = link_mtu;
+    if (ioctl(fd, SIOCSLIFMTU, &lifr) < 0) {
+	close(fd);
+	error("Couldn't set IPv6 MTU (%s): %m", ifr.ifr_name);
+    }
+    close(fd);
+#endif /* defined(INET6) && 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, &mtu, sizeof(mtu), 0) < 0) {
+	if (hungup && errno == ENXIO)
+	    return;
+	error("Couldn't set MTU: %m");
+    }
+    if (fdmuxid >= 0) {
+	if (!sync_serial) {
+	    if (strioctl(pppfd, PPPIO_XACCM, &asyncmap, sizeof(asyncmap), 0) < 0) {
+		error("Couldn't set transmit ACCM: %m");
+	    }
+	}
+	cf[0] = (pcomp? COMP_PROT: 0) + (accomp? COMP_AC: 0);
+	cf[1] = COMP_PROT | COMP_AC;
+	if (any_compressions() &&
+	    strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
+	    error("Couldn't set prot/AC compression: %m");
+	}
+    }
+}
+
+/*
+ * 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 >= 0
+	&& strioctl(pppfd, PPPIO_XACCM, accm, sizeof(ext_accm), 0) < 0) {
+	if (!hungup || errno != ENXIO)
+	    warn("Couldn't set extended ACCM: %m");
+    }
+}
+
+/*
+ * 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, &mru, sizeof(mru), 0) < 0) {
+	if (hungup && errno == ENXIO)
+	    return;
+	error("Couldn't set MRU: %m");
+    }
+    if (fdmuxid >= 0) {
+	if (!sync_serial) {
+	    if (strioctl(pppfd, PPPIO_RACCM, &asyncmap, sizeof(asyncmap), 0) < 0) {
+		error("Couldn't set receive ACCM: %m");
+	    }
+	}
+	cf[0] = (pcomp? DECOMP_PROT: 0) + (accomp? DECOMP_AC: 0);
+	cf[1] = DECOMP_PROT | DECOMP_AC;
+	if (any_compressions() &&
+	    strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
+	    error("Couldn't set prot/AC decompression: %m");
+	}
+    }
+}
+
+/*
+ * 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) >= 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)) < 0) {
+	if (!hungup || errno != ENXIO)
+	    error("Couldn't set kernel CCP state: %m");
+    }
+}
+
+/*
+ * 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)) >= 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 && 
+	strioctl(pppfd, PPPIO_GETSTAT, &s, 0, sizeof(s)) < 0) {
+	error("Couldn't get link statistics: %m");
+	return 0;
+    }
+    stats->bytes_in = s.p.ppp_ibytes;
+    stats->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->bf_len > 0) {
+	if (strioctl(pppfd, PPPIO_PASSFILT, pass,
+		     sizeof(struct bpf_program), 0) < 0) {
+	    error("Couldn't set pass-filter in kernel: %m");
+	    ret = 0;
+	}
+    }
+    if (active->bf_len > 0) {
+	if (strioctl(pppfd, PPPIO_ACTIVEFILT, active,
+		     sizeof(struct bpf_program), 0) < 0) {
+	    error("Couldn't set active-filter in kernel: %m");
+	    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)) < 0) {
+	if (errno != ENXIO && errno != EINVAL)
+	    error("Couldn't get compression flags: %m");
+	return 0;
+    }
+    return cf[0] & 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) < 0) {
+	    error("Couldn't initialize VJ compression: %m");
+	}
+    }
+
+    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)) < 0) {
+	if (vjcomp)
+	    error("Couldn't enable VJ compression: %m");
+    }
+
+    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, &ifr) < 0) {
+	error("Couldn't mark interface up (get): %m");
+	return 0;
+    }
+    ifr.ifr_flags |= IFF_UP;
+    if (ioctl(ipfd, SIOCSIFFLAGS, &ifr) < 0) {
+	error("Couldn't mark interface up (set): %m");
+	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 < 0)
+	return 1;
+    strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+    if (ioctl(ipfd, SIOCGIFFLAGS, &ifr) < 0) {
+	error("Couldn't mark interface down (get): %m");
+	return 0;
+    }
+    ifr.ifr_flags &= ~IFF_UP;
+    if (ioctl(ipfd, SIOCSIFFLAGS, &ifr) < 0) {
+	error("Couldn't mark interface down (set): %m");
+	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) < 0) {
+	error("ioctl(set NP %d mode to %d): %m", proto, mode);
+	return 0;
+    }
+    return 1;
+}
+
+#if defined(SOL2) && 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 < 0) {
+	return 0;
+    }
+
+    memset(&lifr, 0, sizeof(lifr));
+    strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
+    if (ioctl(fd, SIOCGLIFFLAGS, &lifr) < 0) {
+	close(fd);
+	return 0;
+    }
+
+    lifr.lifr_flags |= IFF_UP;
+    strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
+    if (ioctl(fd, SIOCSLIFFLAGS, &lifr) < 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 < 0)
+	return 0;
+
+    memset(&lifr, 0, sizeof(lifr));
+    strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
+    if (ioctl(fd, SIOCGLIFFLAGS, &lifr) < 0) {
+	close(fd);
+	return 0;
+    }
+
+    lifr.lifr_flags &= ~IFF_UP;
+    strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
+    if (ioctl(fd, SIOCGLIFFLAGS, &lifr) < 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 *)&laddr;
+    int fd;
+
+    fd = socket(AF_INET6, SOCK_DGRAM, 0);
+    if (fd < 0)
+	return 0;
+
+    memset(&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, &lifr) < 0) {
+	close(fd);
+	return 0;
+    }
+
+    /*
+     * Set the interface address and destination address
+     */
+    IN6_LLADDR_FROM_EUI64(lifr, sin6, o);
+    if (ioctl(fd, SIOCSLIFADDR, &lifr) < 0) {
+	close(fd);
+	return 0;
+    }
+
+    memset(&lifr, 0, sizeof(lifr));
+    strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
+    IN6_LLADDR_FROM_EUI64(lifr, sin6, h);
+    if (ioctl(fd, SIOCSLIFDSTADDR, &lifr) < 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) && defined(INET6) */
+
+
+#define INET_ADDR(x)	(((struct sockaddr_in *) &(x))->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(&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, &ifr) < 0) {
+	error("Couldn't set IP netmask: %m");
+	ret = 0;
+    }
+    ifr.ifr_addr.sa_family = AF_INET;
+    INET_ADDR(ifr.ifr_addr) = o;
+    if (ioctl(ipfd, SIOCSIFADDR, &ifr) < 0) {
+	error("Couldn't set local IP address: %m");
+	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, &ifr) >= 0
+	&& (ifr.ifr_flags & IFF_POINTOPOINT) == 0) {
+	ifr.ifr_flags |= IFF_POINTOPOINT;
+	if (ioctl(ipfd, SIOCSIFFLAGS, &ifr) < 0) {
+	    error("Couldn't mark interface pt-to-pt: %m");
+	    ret = 0;
+	}
+    }
+    ifr.ifr_dstaddr.sa_family = AF_INET;
+    INET_ADDR(ifr.ifr_dstaddr) = h;
+    if (ioctl(ipfd, SIOCSIFDSTADDR, &ifr) < 0) {
+	error("Couldn't set remote IP address: %m");
+	ret = 0;
+    }
+#if 0	/* now done in ppp_send_config */
+    ifr.ifr_metric = link_mtu;
+    if (ioctl(ipfd, SIOCSIFMTU, &ifr) < 0) {
+	error("Couldn't set IP MTU: %m");
+    }
+#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 >= 0) {
+	notice("Removing ppp interface unit");
+	if (ioctl(ipfd, I_UNLINK, ipmuxid) < 0) {
+	    error("Can't remove ppp interface unit: %m");
+	    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(&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, &rt) < 0) {
+	error("Can't add default route: %m");
+	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(&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, &rt) < 0) {
+	error("Can't delete default route: %m");
+	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(&arpreq, 0, sizeof(arpreq));
+    if (!get_ether_addr(hisaddr, &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) &arpreq) < 0) {
+	error("Couldn't set proxy ARP entry: %m");
+	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(&arpreq, 0, sizeof(arpreq));
+    arpreq.arp_pa.sa_family = AF_INET;
+    INET_ADDR(arpreq.arp_pa) = hisaddr;
+    if (ioctl(ipfd, SIOCDARP, (caddr_t)&arpreq) < 0) {
+	error("Couldn't delete proxy ARP entry: %m");
+	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, &nif) < 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, &ifc) < 0) {
+	warn("Couldn't get system interface list: %m");
+	free(ifc.ifc_buf);
+	return 0;
+    }
+    ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
+    for (ifr = ifc.ifc_req; ifr < ifend; ++ifr) {
+	if (ifr->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->ifr_name, sizeof(ifreq.ifr_name));
+	if (ioctl(ipfd, SIOCGIFFLAGS, &ifreq) < 0)
+	    continue;
+	if ((ifreq.ifr_flags &
+	     (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, &ifreq) < 0)
+	    continue;
+	ina = INET_ADDR(ifr->ifr_addr);
+	mask = INET_ADDR(ifreq.ifr_addr);
+	if ((ipaddr & mask) == (ina & mask))
+	    break;
+    }
+
+    if (ifr >= ifend) {
+	warn("No suitable interface found for proxy ARP");
+	free(ifc.ifc_buf);
+	return 0;
+    }
+
+    info("found interface %s for proxy ARP", ifr->ifr_name);
+    if (!get_hw_addr(ifr->ifr_name, ina, hwaddr)) {
+	error("Couldn't get hardware address for %s", ifr->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), "/dev/%s", name);
+    for (q = ifdev + strlen(ifdev); --q >= 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 < 0) {
+	error("Can't open %s: %m", ifdev);
+	return 0;
+    }
+    if (dlpi_attach(iffd, unit) < 0
+	|| dlpi_get_reply(iffd, &reply.prim, DL_OK_ACK, sizeof(reply)) < 0
+	|| dlpi_info_req(iffd) < 0
+	|| dlpi_get_reply(iffd, &reply.prim, DL_INFO_ACK, sizeof(reply)) < 0) {
+	close(iffd);
+	return 0;
+    }
+
+    adrlen = reply.prim.info_ack.dl_addr_length;
+    adrp = (unsigned char *)&reply + reply.prim.info_ack.dl_addr_offset;
+
+#if DL_CURRENT_VERSION >= 2
+    if (reply.prim.info_ack.dl_sap_length < 0)
+	adrlen += reply.prim.info_ack.dl_sap_length;
+    else
+	adrp += reply.prim.info_ack.dl_sap_length;
+#endif
+
+    hwaddr->sa_family = AF_UNSPEC;
+    memcpy(hwaddr->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 < 0)
+	return 0;
+    memset(&req, 0, sizeof(req));
+    req.arp_pa.sa_family = AF_INET;
+    INET_ADDR(req.arp_pa) = ina;
+    if (ioctl(s, SIOCGARP, &req) < 0) {
+	error("Couldn't get ARP entry for %s: %m", ip_ntoa(ina));
+	return 0;
+    }
+    *hwaddr = req.arp_ha;
+    hwaddr->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 *) &req;
+    return putmsg(fd, &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 *) &req;
+    return putmsg(fd, &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(&pfd, 1, 1000);
+    } while (n == -1 && errno == EINTR);
+    if (n <= 0)
+	return -1;
+
+    /*
+     * Get the reply.
+     */
+    buf.maxlen = maxlen;
+    buf.buf = (void *) reply;
+    flags = 0;
+    if (getmsg(fd, &buf, NULL, &flags) < 0)
+	return -1;
+
+    if (buf.len < sizeof(ulong)) {
+	if (debug)
+	    dbglog("dlpi response short (len=%d)\n", buf.len);
+	return -1;
+    }
+
+    if (reply->dl_primitive == expected_prim)
+	return 0;
+
+    if (debug) {
+	if (reply->dl_primitive == DL_ERROR_ACK) {
+	    dbglog("dlpi error %d (unix errno %d) for prim %x\n",
+		   reply->error_ack.dl_errno, reply->error_ack.dl_unix_errno,
+		   reply->error_ack.dl_error_primitive);
+	} else {
+	    dbglog("dlpi unexpected response prim %x\n",
+		   reply->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, &nif) < 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, &ifc) < 0) {
+	warn("Couldn't get system interface list: %m");
+	free(ifc.ifc_buf);
+	return mask;
+    }
+    ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
+    for (ifr = ifc.ifc_req; ifr < ifend; ++ifr) {
+	/*
+	 * Check the interface's internet address.
+	 */
+	if (ifr->ifr_addr.sa_family != AF_INET)
+	    continue;
+	ina = INET_ADDR(ifr->ifr_addr);
+	if ((ntohl(ina) & nmask) != (addr & nmask))
+	    continue;
+	/*
+	 * Check that the interface is up, and not point-to-point or loopback.
+	 */
+	strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
+	if (ioctl(ipfd, SIOCGIFFLAGS, &ifreq) < 0)
+	    continue;
+	if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK))
+	    != IFF_UP)
+	    continue;
+	/*
+	 * Get its netmask and OR it into our mask.
+	 */
+	if (ioctl(ipfd, SIOCGIFNETMASK, &ifreq) < 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(&utmpx.ut_tv, NULL);
+    updwtmpx("/var/adm/wtmpx", &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)) < 0) {
+	error("sysinfo: %m");
+	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, &str) == -1)
+	return -1;
+    if (str.ic_len != olen)
+	dbglog("strioctl: expected %d bytes, got %d for cmd %x\n",
+	       olen, str.ic_len, cmd);
+    return 0;
+}
+
+#if 0
+/*
+ * lock - create a lock file for the named lock device
+ */
+
+#define LOCK_PREFIX	"/var/spool/locks/LK."
+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, &sbuf) < 0) {
+	error("Can't get device number for %s: %m", dev);
+	return -1;
+    }
+    if ((sbuf.st_mode & S_IFMT) != S_IFCHR) {
+	error("Can't lock %s: not a character device", dev);
+	return -1;
+    }
+    slprintf(lock_file, sizeof(lock_file), "%s%03d.%03d.%03d",
+	     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)) < 0) {
+	if (errno == EEXIST
+	    && (fd = open(lock_file, O_RDONLY, 0)) >= 0) {
+	    /* Read the lock file to find out who has the device locked */
+	    n = read(fd, ascii_pid, 11);
+	    if (n <= 0) {
+		error("Can't read pid from lock file %s", lock_file);
+		close(fd);
+	    } else {
+		ascii_pid[n] = 0;
+		pid = atoi(ascii_pid);
+		if (pid > 0 && kill(pid, 0) == -1 && errno == ESRCH) {
+		    /* pid no longer exists - remove the lock file */
+		    if (unlink(lock_file) == 0) {
+			close(fd);
+			notice("Removed stale lock on %s (pid %d)",
+			       dev, pid);
+			continue;
+		    } else
+			warn("Couldn't remove stale lock on %s",
+			       dev);
+		} else
+		    notice("Device %s is locked by pid %d",
+			   dev, pid);
+	    }
+	    close(fd);
+	} else
+	    error("Can't create lock file %s: %m", lock_file);
+	lock_file[0] = 0;
+	return -1;
+    }
+
+    slprintf(ascii_pid, sizeof(ascii_pid), "%10d\n", 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(&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, &rt) < 0) {
+	error("Can't delete route: %m");
+	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 < 0) {
+	warn("have_route_to: couldn't open %s: %m", mux_dev_name);
+	return -1;
+    }
+
+    req.req.PRIM_type = T_OPTMGMT_REQ;
+    req.req.OPT_offset = (char *) &req.hdr - (char *) &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 *) &req;
+    cbuf.len = sizeof(req);
+
+    if (putmsg(fd, &cbuf, NULL, 0) == -1) {
+	warn("have_route_to: putmsg: %m");
+	close(fd);
+	return -1;
+    }
+
+    for (;;) {
+	cbuf.buf = (char *) &ack;
+	cbuf.maxlen = sizeof(ack);
+	dbuf.buf = (char *) routes;
+	dbuf.maxlen = sizeof(routes);
+	flags = 0;
+	r = getmsg(fd, &cbuf, &dbuf, &flags);
+	if (r == -1) {
+	    warn("have_route_to: getmsg: %m");
+	    close(fd);
+	    return -1;
+	}
+
+	if (cbuf.len < sizeof(struct T_optmgmt_ack)
+	    || ack.ack.PRIM_type != T_OPTMGMT_ACK
+	    || ack.ack.MGMT_flags != T_SUCCESS
+	    || ack.ack.OPT_length < sizeof(struct opthdr)) {
+	    dbglog("have_route_to: bad message len=%d prim=%d",
+		   cbuf.len, ack.ack.PRIM_type);
+	    close(fd);
+	    return -1;
+	}
+
+	rh = (struct opthdr *) ((char *)&ack + ack.ack.OPT_offset);
+	if (rh->level == 0 && rh->name == 0)
+	    break;
+	if (rh->level != MIB2_IP || rh->name != MIB2_IP_21) {
+	    while (r == MOREDATA)
+		r = getmsg(fd, NULL, &dbuf, &flags);
+	    continue;
+	}
+
+	for (;;) {
+	    nroutes = dbuf.len / sizeof(mib2_ipRouteEntry_t);
+	    for (rp = routes, i = 0; i < nroutes; ++i, ++rp) {
+		if (rp->ipRouteMask != ~0) {
+		    dbglog("have_route_to: dest=%x gw=%x mask=%x\n",
+			   rp->ipRouteDest, rp->ipRouteNextHop,
+			   rp->ipRouteMask);
+		    if (((addr ^ rp->ipRouteDest) & rp->ipRouteMask) == 0
+			&& rp->ipRouteNextHop != remote_addr)
+			return 1;
+		}
+	    }
+	    if (r == 0)
+		break;
+	    r = getmsg(fd, NULL, &dbuf, &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("/dev/ptmx", O_RDWR);
+    if (mfd < 0) {
+	error("Couldn't open pty master: %m");
+	return 0;
+    }
+
+    pty_name = ptsname(mfd);
+    if (pty_name == NULL) {
+	error("Couldn't get name of pty slave");
+	close(mfd);
+	return 0;
+    }
+    if (chown(pty_name, uid, -1) < 0)
+	warn("Couldn't change owner of pty slave: %m");
+    if (chmod(pty_name, S_IRUSR | S_IWUSR) < 0)
+	warn("Couldn't change permissions on pty slave: %m");
+    if (unlockpt(mfd) < 0)
+	warn("Couldn't unlock pty slave: %m");
+
+    sfd = open(pty_name, O_RDWR);
+    if (sfd < 0) {
+	error("Couldn't open pty slave %s: %m", pty_name);
+	close(mfd);
+	return 0;
+    }
+    if (ioctl(sfd, I_PUSH, "ptem") < 0)
+	warn("Couldn't push ptem module on pty slave: %m");
+
+    dbglog("Using %s", 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 "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ */
+
+#define RCSID	"$Id: sys-sunos4.c 195720 2001-06-11 11:44:34Z gc $"
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <termios.h>
+#include <signal.h>
+#include <malloc.h>
+#include <utmp.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/nit_if.h>
+#include <net/route.h>
+#include <net/ppp_defs.h>
+#include <net/pppio.h>
+#include <netinet/in.h>
+
+#include "pppd.h"
+
+#if defined(sun) && defined(sparc)
+#include <alloca.h>
+#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)) < 0)
+	fatal("Couldn't create IP socket: %m");
+
+    /*
+     * 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("/dev/ppp", O_RDWR | O_NONBLOCK, 0);
+    if (pppfd < 0)
+	fatal("Can't open /dev/ppp: %m");
+    if (kdebugflag) {
+	x = PPPDBG_LOG + PPPDBG_DRIVER;
+	strioctl(pppfd, PPPIO_DEBUG, &x, sizeof(int), 0);
+    }
+
+    /* Assign a new PPA and get its unit number. */
+    if (strioctl(pppfd, PPPIO_NEWPPA, &ifunit, 0, sizeof(int)) < 0)
+	fatal("Can't create new PPP interface: %m");
+
+    /*
+     * Open the ppp device again and push the if_ppp module on it.
+     */
+    iffd = open("/dev/ppp", O_RDWR, 0);
+    if (iffd < 0)
+	fatal("Can't open /dev/ppp (2): %m");
+    if (kdebugflag) {
+	x = PPPDBG_LOG + PPPDBG_DRIVER;
+	strioctl(iffd, PPPIO_DEBUG, &x, sizeof(int), 0);
+    }
+    if (strioctl(iffd, PPPIO_ATTACH, &ifunit, sizeof(int), 0) < 0)
+	fatal("Couldn't attach ppp interface to device: %m");
+    if (ioctl(iffd, I_PUSH, "if_ppp") < 0)
+	fatal("Can't push ppp interface module: %m");
+    if (kdebugflag) {
+	x = PPPDBG_LOG + PPPDBG_IF;
+	strioctl(iffd, PPPIO_DEBUG, &x, sizeof(int), 0);
+    }
+    if (strioctl(iffd, PPPIO_NEWPPA, &ifunit, sizeof(int), 0) < 0)
+	fatal("Couldn't create ppp interface unit: %m");
+    x = PPP_IP;
+    if (strioctl(iffd, PPPIO_BIND, &x, sizeof(int), 0) < 0)
+	fatal("Couldn't bind ppp interface to IP SAP: %m");
+
+    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()) < 0)
+	return -1;
+    if (pid != 0)
+	exit(0);		/* parent dies */
+    setsid();
+    if (!nochdir)
+	chdir("/");
+    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("/dev/ppp", &buf) >= 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]) < 0
+	    || ioctl(fd, I_POP, 0) < 0)
+	    break;
+    tty_nmodules = i;
+
+    /* Push the async hdlc module and the compressor module. */
+    if (ioctl(fd, I_PUSH, "ppp_ahdl") < 0)
+	fatal("Couldn't push PPP Async HDLC module: %m");
+    if (ioctl(fd, I_PUSH, "ppp_comp") < 0)
+	error("Couldn't push PPP compression module: %m");
+
+    /* Link the serial port under the PPP multiplexor. */
+    if ((fdmuxid = ioctl(pppfd, I_LINK, fd)) < 0)
+	fatal("Can't link tty to PPP mux: %m");
+
+    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 >= 0) {
+	if (ioctl(pppfd, I_UNLINK, fdmuxid) < 0) {
+	    if (!hungup)
+		error("Can't unlink tty from PPP mux: %m");
+	}
+	fdmuxid = -1;
+
+	if (!hungup) {
+	    while (ioctl(fd, I_POP, 0) >= 0)
+		;
+	    for (i = tty_nmodules - 1; i >= 0; --i)
+		if (ioctl(fd, I_PUSH, tty_modules[i]) < 0)
+		    error("Couldn't restore tty module %s: %m",
+			   tty_modules[i]);
+	}
+	if (hungup && default_device && parent_pid > 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, &x, 0, sizeof(x)) < 0)
+	return;
+    s = NULL;
+    switch (~x) {
+    case RCV_B7_0:
+	s = "bit 7 set to 1";
+	break;
+    case RCV_B7_1:
+	s = "bit 7 set to 0";
+	break;
+    case RCV_EVNP:
+	s = "odd parity";
+	break;
+    case RCV_ODDP:
+	s = "even parity";
+	break;
+    }
+    if (s != NULL) {
+	warn("Serial link is not 8-bit clean:");
+	warn("All received characters had %s", 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->speed_int; speedp++)
+	if (bps == speedp->speed_int)
+	    return speedp->speed_val;
+    warn("speed %d not supported", 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->speed_int; speedp++)
+	if (speed == speedp->speed_val)
+	    return speedp->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, &tios) < 0)
+	fatal("tcgetattr: %m");
+
+    if (!restore_term) {
+	inittermios = tios;
+	ioctl(fd, TIOCGWINSZ, &wsinfo);
+    }
+
+    tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
+    if (crtscts > 0)
+	tios.c_cflag |= CRTSCTS;
+    else if (crtscts < 0)
+	tios.c_cflag &= ~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(&tios, speed);
+	cfsetispeed(&tios, speed);
+    } else {
+	speed = cfgetospeed(&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("Baud rate for %s is 0; need explicit baud rate", devnam);
+    }
+
+    if (tcsetattr(fd, TCSAFLUSH, &tios) < 0)
+	fatal("tcsetattr: %m");
+
+    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 &= ~(ECHO | ECHONL);
+	}
+	if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0)
+	    if (!hungup && errno != ENXIO)
+		warn("tcsetattr: %m");
+	ioctl(fd, TIOCSWINSZ, &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), &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("sent %P", p, len);
+
+    data.len = len;
+    data.buf = (caddr_t) p;
+    retries = 4;
+    while (putmsg(pppfd, NULL, &data, 0) < 0) {
+	if (--retries < 0 || (errno != EWOULDBLOCK && errno != EAGAIN)) {
+	    if (errno != ENXIO)
+		error("Couldn't send packet: %m");
+	    break;
+	}
+	pfd.fd = pppfd;
+	pfd.events = POLLOUT;
+	poll(&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->tv_sec * 1000 + timo->tv_usec / 1000;
+    if (poll(pollfds, n_pollfds, t) < 0 && errno != EINTR) {
+	if (errno != EAGAIN)
+	    fatal("poll: %m");
+	/* 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 < n_pollfds; ++n)
+	if (pollfds[n].fd == fd)
+	    return;
+    if (n_pollfds < MAX_POLLFDS) {
+	pollfds[n_pollfds].fd = fd;
+	pollfds[n_pollfds].events = POLLIN | POLLPRI | POLLHUP;
+	++n_pollfds;
+    } else
+	error("Too many inputs!");
+}
+
+/*
+ * 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 < n_pollfds; ++n) {
+	if (pollfds[n].fd == fd) {
+	    while (++n < 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 < 0 && errno != EINTR)
+	fatal("select: %m");
+}
+#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, &ctrl, &data, &flags);
+	if (len < 0) {
+	    if (errno == EAGAIN || errno == EINTR)
+		return -1;
+	    fatal("Error reading packet: %m");
+	}
+
+	if (ctrl.len <= 0)
+	    return data.len;
+
+	/*
+	 * Got a M_PROTO or M_PCPROTO message.  Huh?
+	 */
+	if (debug)
+	    dbglog("got ctrl msg len=%d", 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)) > 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, &mtu, sizeof(mtu), 0) < 0) {
+	if (hungup && errno == ENXIO)
+	    return;
+	error("Couldn't set MTU: %m");
+    }
+    if (strioctl(pppfd, PPPIO_XACCM, &asyncmap, sizeof(asyncmap), 0) < 0) {
+	error("Couldn't set transmit ACCM: %m");
+    }
+    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)) < 0) {
+	error("Couldn't set prot/AC compression: %m");
+    }
+
+    /* set mtu for ip as well */
+    memset(&ifr, 0, sizeof(ifr));
+    strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+    ifr.ifr_metric = link_mtu;
+    if (ioctl(sockfd, SIOCSIFMTU, &ifr) < 0) {
+	error("Couldn't set IP MTU: %m");
+    }
+}
+
+/*
+ * 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) < 0) {
+	if (!hungup || errno != ENXIO)
+	    warn("Couldn't set extended ACCM: %m");
+    }
+}
+
+/*
+ * 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, &mru, sizeof(mru), 0) < 0) {
+	if (hungup && errno == ENXIO)
+	    return;
+	error("Couldn't set MRU: %m");
+    }
+    if (strioctl(pppfd, PPPIO_RACCM, &asyncmap, sizeof(asyncmap), 0) < 0) {
+	error("Couldn't set receive ACCM: %m");
+    }
+    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)) < 0) {
+	error("Couldn't set prot/AC decompression: %m");
+    }
+}
+
+/*
+ * 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) >= 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)) < 0) {
+	if (!hungup || errno != ENXIO)
+	    error("Couldn't set kernel CCP state: %m");
+    }
+}
+
+/*
+ * 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)) >= 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, &s, 0, sizeof(s)) < 0) {
+	error("Couldn't get link statistics: %m");
+	return 0;
+    }
+    stats->bytes_in = s.p.ppp_ibytes;
+    stats->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)) < 0) {
+	if (errno != ENXIO && errno != EINVAL)
+	    error("Couldn't get compression flags: %m");
+	return 0;
+    }
+    return cf[0] & 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) < 0) {
+	    error("Couldn't initialize VJ compression: %m");
+	}
+    }
+
+    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)) < 0) {
+	if (vjcomp)
+	    error("Couldn't enable VJ compression: %m");
+    }
+
+    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, &ifr) < 0) {
+	error("Couldn't mark interface up (get): %m");
+	return 0;
+    }
+    ifr.ifr_flags |= IFF_UP;
+    if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
+	error("Couldn't mark interface up (set): %m");
+	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, &ifr) < 0) {
+	error("Couldn't mark interface down (get): %m");
+	return 0;
+    }
+    if ((ifr.ifr_flags & IFF_UP) != 0) {
+	ifr.ifr_flags &= ~IFF_UP;
+	if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
+	    error("Couldn't mark interface down (set): %m");
+	    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) < 0) {
+	error("ioctl(set NP %d mode to %d): %m", proto, mode);
+	return 0;
+    }
+    return 1;
+}
+
+#define INET_ADDR(x)	(((struct sockaddr_in *) &(x))->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(&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, &ifr) < 0) {
+	error("Couldn't set IP netmask: %m");
+    }
+    ifr.ifr_addr.sa_family = AF_INET;
+    INET_ADDR(ifr.ifr_addr) = o;
+    if (ioctl(sockfd, SIOCSIFADDR, &ifr) < 0) {
+	error("Couldn't set local IP address: %m");
+    }
+    ifr.ifr_dstaddr.sa_family = AF_INET;
+    INET_ADDR(ifr.ifr_dstaddr) = h;
+    if (ioctl(sockfd, SIOCSIFDSTADDR, &ifr) < 0) {
+	error("Couldn't set remote IP address: %m");
+    }
+#if 0	/* now done in ppp_send_config */
+    ifr.ifr_metric = link_mtu;
+    if (ioctl(sockfd, SIOCSIFMTU, &ifr) < 0) {
+	error("Couldn't set IP MTU: %m");
+    }
+#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(&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, &rt) < 0)
+	error("Couldn't delete route through interface: %m");
+    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(&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, &rt) < 0) {
+	error("Can't add default route: %m");
+	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(&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, &rt) < 0) {
+	error("Can't delete default route: %m");
+	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(&arpreq, sizeof(arpreq));
+    if (!get_ether_addr(hisaddr, &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) &arpreq) < 0) {
+	error("Couldn't set proxy ARP entry: %m");
+	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(&arpreq, sizeof(arpreq));
+    arpreq.arp_pa.sa_family = AF_INET;
+    INET_ADDR(arpreq.arp_pa) = hisaddr;
+    if (ioctl(sockfd, SIOCDARP, (caddr_t)&arpreq) < 0) {
+	error("Couldn't delete proxy ARP entry: %m");
+	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, &ifc) < 0) {
+	error("ioctl(SIOCGIFCONF): %m");
+	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 < ifend; ifr = (struct ifreq *)
+	    ((char *)&ifr->ifr_addr + sizeof(struct sockaddr))) {
+        if (ifr->ifr_addr.sa_family == AF_INET) {
+
+            /*
+             * Check that the interface is up, and not point-to-point
+             * or loopback.
+             */
+            strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
+            if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
+                continue;
+            if ((ifreq.ifr_flags &
+                 (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, &ifreq) < 0)
+                continue;
+            ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
+            mask = ((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr;
+            if ((ipaddr & mask) != (ina & mask))
+                continue;
+
+            break;
+        }
+    }
+
+    if (ifr >= ifend)
+	return 0;
+    info("found interface %s for proxy arp", ifr->ifr_name);
+
+    /*
+     * Grab the physical address for this interface.
+     */
+    if ((nit_fd = open("/dev/nit", O_RDONLY)) < 0) {
+	error("Couldn't open /dev/nit: %m");
+	return 0;
+    }
+    strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
+    if (ioctl(nit_fd, NIOCBIND, &ifreq) < 0
+	|| ioctl(nit_fd, SIOCGIFADDR, &ifreq) < 0) {
+	error("Couldn't get hardware address for %s: %m",
+	       ifreq.ifr_name);
+	close(nit_fd);
+	return 0;
+    }
+
+    hwaddr->sa_family = AF_UNSPEC;
+    memcpy(hwaddr->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	"/usr/adm/wtmp"
+
+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)) < 0)
+	return;
+    if (!fstat(fd, &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(&ut.ut_time);
+	if (write(fd, (char *)&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, &ifc) < 0) {
+	warn("Couldn't get system interface list: %m");
+	return mask;
+    }
+    ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
+    for (ifr = ifc.ifc_req; ifr < ifend; ++ifr) {
+	/*
+	 * Check the interface's internet address.
+	 */
+	if (ifr->ifr_addr.sa_family != AF_INET)
+	    continue;
+	ina = INET_ADDR(ifr->ifr_addr);
+	if ((ntohl(ina) & nmask) != (addr & nmask))
+	    continue;
+	/*
+	 * Check that the interface is up, and not point-to-point or loopback.
+	 */
+	strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
+	if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
+	    continue;
+	if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK))
+	    != IFF_UP)
+	    continue;
+	/*
+	 * Get its netmask and OR it into our mask.
+	 */
+	if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 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, &str) == -1)
+	return -1;
+    if (str.ic_len != olen)
+	dbglog("strioctl: expected %d bytes, got %d for cmd %x\n",
+	       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) && !defined(SUNOS3)
+#define	HDB	1		/* ascii lock files are the default */
+#endif
+
+#ifndef LOCK_DIR
+# if HDB
+#  define	PIDSTRING
+#  define	LOCK_PREFIX	"/usr/spool/locks/LCK.."
+# else /* HDB */
+#  define	LOCK_PREFIX	"/usr/spool/uucp/LCK.."
+# 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("lock file name");
+    slprintf(lock_file, l, "%s%s", LOCK_PREFIX, dev);
+
+    while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
+	if (errno == EEXIST
+	    && (fd = open(lock_file, O_RDONLY, 0)) >= 0) {
+	    /* Read the lock file to find out who has the device locked */
+#ifdef PIDSTRING
+	    n = read(fd, hdb_lock_buffer, 11);
+	    if (n > 0) {
+		hdb_lock_buffer[n] = 0;
+		pid = atoi(hdb_lock_buffer);
+	    }
+#else
+	    n = read(fd, &pid, sizeof(pid));
+#endif
+	    if (n <= 0) {
+		error("Can't read pid from lock file %s", lock_file);
+		close(fd);
+	    } else {
+		if (kill(pid, 0) == -1 && errno == ESRCH) {
+		    /* pid no longer exists - remove the lock file */
+		    if (unlink(lock_file) == 0) {
+			close(fd);
+			notice("Removed stale lock on %s (pid %d)",
+			       dev, pid);
+			continue;
+		    } else
+			warn("Couldn't remove stale lock on %s",
+			       dev);
+		} else
+		    notice("Device %s is locked by pid %d",
+			   dev, pid);
+	    }
+	    close(fd);
+	} else
+	    error("Can't create lock file %s: %m", lock_file);
+	free(lock_file);
+	lock_file = NULL;
+	return -1;
+    }
+
+#ifdef PIDSTRING
+    slprintf(hdb_lock_buffer, sizeof(hdb_lock_buffer), "%10d\n", getpid());
+    write(fd, hdb_lock_buffer, 11);
+#else
+    pid = getpid();
+    write(fd, &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 >= 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 < 64; ++i) {
+	slprintf(pty_name, sizeof(pty_name), "/dev/pty%c%x",
+		 'p' + i / 16, i % 16);
+	mfd = open(pty_name, O_RDWR, 0);
+	if (mfd >= 0) {
+	    pty_name[5] = 't';
+	    sfd = open(pty_name, O_RDWR | O_NOCTTY, 0);
+	    if (sfd >= 0)
+		break;
+	    close(mfd);
+	}
+    }
+    if (sfd < 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, &tios) == 0) {
+	tios.c_cflag &= ~(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, &tios) < 0)
+	    warn("couldn't set attributes on pty: %m");
+    } else
+	warn("couldn't get attributes on pty: %m");
+
+    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 > 0 && n < sys_nerr)
+	return sys_errlist[n];
+    slprintf(unknown, sizeof(unknown), "Error %d", 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 <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include "tdb.h"
+
+#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->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->fd == -1) return 0;   /* for in memory tdb */
+
+	if (tdb->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->fd, lck_type, &fl) != 0) {
+#if TDB_DEBUG
+		if (lck_type == F_SETLKW) {
+			printf("lock %d failed at %d (%s)\n", 
+			       set, offset, strerror(errno));
+		}
+#endif
+		tdb->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 < -1 || list >= (int)tdb->header.hash_size) {
+#if TDB_DEBUG
+		printf("bad list %d\n", list);
+#endif
+		return -1;
+	}
+	if (tdb->locked[list+1] == 0) {
+		if (tdb_brlock(tdb, LIST_LOCK_BASE + 4*list, LOCK_SET, 
+			       F_WRLCK, F_SETLKW) != 0) {
+			return -1;
+		}
+	}
+	tdb->locked[list+1]++;
+	return 0;
+}
+
+/* unlock the database. */
+static int tdb_unlock(TDB_CONTEXT *tdb, int list)
+{
+	if (list < -1 || list >= (int)tdb->header.hash_size) {
+#if TDB_DEBUG
+		printf("bad unlock list %d\n", list);
+#endif
+		return -1;
+	}
+
+	if (tdb->locked[list+1] == 0) {
+#if TDB_DEBUG
+		printf("not locked %d\n", list);
+#endif
+		tdb->ecode = TDB_ERR_LOCK;
+		return -1;
+	}
+	if (tdb->locked[list+1] == 1) {
+		if (tdb_brlock(tdb, LIST_LOCK_BASE + 4*list, LOCK_CLEAR, 
+			       F_WRLCK, F_SETLKW) != 0) {
+			return -1;
+		}
+	}
+	tdb->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->dsize;
+	for (i=0; i < key->dsize; i++) {
+		value = (value + (key->dptr[i] << (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 <= tdb->map_size) || (tdb->fd == -1)) return 0;
+
+	fstat(tdb->fd, &st);
+	if (st.st_size <= (ssize_t)offset) {
+		tdb->ecode = TDB_ERR_IO;
+		return -1;
+	}
+
+#if HAVE_MMAP
+	if (tdb->map_ptr) {
+		munmap(tdb->map_ptr, tdb->map_size);
+		tdb->map_ptr = NULL;
+	}
+#endif
+
+	tdb->map_size = st.st_size;
+#if HAVE_MMAP
+	tdb->map_ptr = (void *)mmap(NULL, tdb->map_size, 
+				    tdb->read_only?PROT_READ:PROT_READ|PROT_WRITE,
+				    MAP_SHARED | MAP_FILE, tdb->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->map_ptr) {
+		memcpy(offset + (char *)tdb->map_ptr, buf, len);
+	} else {
+		if (lseek(tdb->fd, offset, SEEK_SET) != offset ||
+		    write(tdb->fd, buf, len) != (ssize_t)len) {
+			tdb->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->map_ptr) {
+		memcpy(buf, offset + (char *)tdb->map_ptr, len);
+	} else {
+		if (lseek(tdb->fd, offset, SEEK_SET) != offset ||
+		    read(tdb->fd, buf, len) != (ssize_t)len) {
+			tdb->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->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->magic != TDB_MAGIC) {
+#if TDB_DEBUG
+		printf("bad magic 0x%08x at offset %d\n",
+		       rec->magic, offset);
+#endif
+		tdb->ecode = TDB_ERR_CORRUPT;
+		return -1;
+	}
+	if (tdb_oob(tdb, rec->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->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->map_size + length + TDB_PAGE_SIZE) & ~(TDB_PAGE_SIZE - 1)) - tdb->map_size;
+
+	/* expand the file itself */
+        if (tdb->fd != -1) {
+            lseek(tdb->fd, tdb->map_size + length - 1, SEEK_SET);
+            if (write(tdb->fd, &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, &rec.next) == -1) {
+		goto fail;
+	}
+
+#if HAVE_MMAP
+	if (tdb->fd != -1 && tdb->map_ptr) {
+		munmap(tdb->map_ptr, tdb->map_size);
+		tdb->map_ptr = NULL;
+	}
+#endif
+
+	tdb->map_size += length;
+
+        if (tdb->fd == -1) {
+            tdb->map_ptr = realloc(tdb->map_ptr, tdb->map_size);
+        }
+
+	/* write it out */
+	if (rec_write(tdb, tdb->map_size - length, &rec) == -1) {
+		goto fail;
+	}
+
+	/* link it into the free list */
+	ptr = tdb->map_size - length;
+	if (ofs_write(tdb, offset, &ptr) == -1) goto fail;
+
+#if HAVE_MMAP
+        if (tdb->fd != -1) {
+            tdb->map_ptr = (void *)mmap(NULL, tdb->map_size, 
+                                        PROT_READ|PROT_WRITE,
+                                        MAP_SHARED | MAP_FILE, tdb->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, &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 *)&rec, sizeof(rec)) == -1) {
+			goto fail;
+		}
+
+		if (rec.magic != TDB_FREE_MAGIC) {
+#if TDB_DEBUG
+			printf("bad magic 0x%08x in free list\n", rec.magic);
+#endif
+			goto fail;
+		}
+
+		if (rec.rec_len >= length) {
+			/* found it - now possibly split it up  */
+			if (rec.rec_len > length + MIN_REC_SIZE) {
+				length = (length + TDB_ALIGN) & ~(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, &newrec) == -1) {
+					goto fail;
+				}
+
+				if (rec_write(tdb, rec_ptr, &rec) == -1) {
+					goto fail;
+				}
+			}
+
+			/* remove it from the list */
+			if (last_ptr == 0) {
+				offset = FREELIST_TOP;
+
+				if (ofs_write(tdb, offset, &rec.next) == -1) {
+					goto fail;
+				}				
+			} else {
+				lastrec.next = rec.next;
+				if (rec_write(tdb, last_ptr, &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("tdb_allocate failed for size %u\n", 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(&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->fd, 0, SEEK_SET);
+        ftruncate(tdb->fd, 0);
+        
+        if (tdb->fd != -1 && write(tdb->fd, &header, sizeof(header)) != 
+            sizeof(header)) {
+            tdb->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 >= 16; i += 16) {
+            if (tdb->fd != -1 && write(tdb->fd, buf, sizeof(buf)) != 
+                sizeof(buf)) {
+                tdb->ecode = TDB_ERR_IO;
+                return -1;
+            } else size += sizeof(buf);
+        }
+
+        for (;i<hash_size+1; i++) {
+            if (tdb->fd != -1 && write(tdb->fd, buf, sizeof(tdb_off)) != 
+                sizeof(tdb_off)) {
+                tdb->ecode = TDB_ERR_IO;
+                return -1;
+            } else size += sizeof(tdb_off);
+        }
+
+        if (tdb->fd == -1) {
+            tdb->map_ptr = calloc(size, 1);
+            tdb->map_size = size;
+            if (tdb->map_ptr == NULL) {
+                tdb->ecode = TDB_ERR_IO;
+                return -1;
+            }
+            memcpy(&tdb->header, &header, sizeof(header));
+        }
+
+#if TDB_DEBUG
+	printf("initialised database of hash_size %u\n", 
+	       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, &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->full_hash && key.dsize == rec->key_len) {
+			char *k;
+			/* a very likely hit - read the key */
+			k = tdb_alloc_read(tdb, rec_ptr + sizeof(*rec), 
+					   rec->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->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, "Success"},
+		{TDB_ERR_CORRUPT, "Corrupt database"},
+		{TDB_ERR_IO, "IO Error"},
+		{TDB_ERR_LOCK, "Locking error"},
+		{TDB_ERR_OOM, "Out of memory"},
+		{TDB_ERR_EXISTS, "Record exists"},
+		{-1, NULL}};
+        if (tdb != NULL) {
+            for (i=0;emap[i].estring;i++) {
+		if (tdb->ecode == emap[i].ecode) return emap[i].estring;
+            }
+        } else {
+            return "Invalid tdb context";
+        }
+	return "Invalid error code";
+}
+
+
+/* update an entry in place - this only works if the new data size
+   is <= 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("tdb_update() called with null context\n");
+#endif
+            return -1;
+        }
+
+	/* find which hash bucket it is in */
+	hash = tdb_hash(&key);
+
+	tdb_lock(tdb, BUCKET(hash));
+	rec_ptr = tdb_find(tdb, key, hash, &rec);
+
+	if (!rec_ptr)
+		goto out;
+
+	/* must be long enough */
+	if (rec.rec_len < 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, &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("tdb_fetch() called with null context\n");
+#endif
+            return null_data;
+        }
+
+	/* find which hash bucket it is in */
+	hash = tdb_hash(&key);
+
+	tdb_lock(tdb, BUCKET(hash));
+	rec_ptr = tdb_find(tdb, key, hash, &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("tdb_exists() called with null context\n");
+#endif
+            return 0;
+        }
+
+	/* find which hash bucket it is in */
+	hash = tdb_hash(&key);
+
+	tdb_lock(tdb, BUCKET(hash));
+	rec_ptr = tdb_find(tdb, key, hash, &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("tdb_traverse() called with null context\n");
+#endif
+            return -1;
+        }
+
+	/* loop over all hash chains */
+	for (h = 0; h < tdb->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, &rec_ptr) == -1) {
+			goto fail;
+		}
+
+		/* traverse all records for this hash */
+		while (rec_ptr) {
+			if (rec_read(tdb, rec_ptr, &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 && 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("tdb_firstkey() called with null context\n");
+#endif
+            return null_data;
+        }
+
+	/* look for a non-empty hash chain */
+	for (hash = 0, rec_ptr = 0; 
+	     hash < tdb->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, &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, &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("tdb_nextkey() called with null context\n");
+#endif
+            return null_data;
+        }
+
+	/* find which hash bucket it is in */
+	hash = tdb_hash(&key);
+	hbucket = BUCKET(hash);
+	
+	tdb_lock(tdb, hbucket);
+	rec_ptr = tdb_find(tdb, key, hash, &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 >= tdb->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, &rec_ptr) == -1) {
+			tdb_unlock(tdb, hbucket);
+			return null_data;
+		}
+	}
+
+	/* Read the record. */
+	if (rec_read(tdb, rec_ptr, &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("tdb_delete() called with null context\n");
+#endif
+            return -1;
+        }
+
+	/* find which hash bucket it is in */
+	hash = tdb_hash(&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, &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, &rec) == -1) {
+			goto fail;
+		}
+
+		if (hash == rec.full_hash && 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, &rec.next) == -1) {
+						goto fail;
+					}
+				} else {
+					lastrec.next = rec.next;
+					if (rec_write(tdb, last_ptr, &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, &rec.next) == -1) {
+					goto fail2;
+				}
+				rec.magic = TDB_FREE_MAGIC;
+				if (rec_write(tdb, rec_ptr, &rec) == -1) {
+					goto fail2;
+				}
+				if (ofs_write(tdb, offset, &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("tdb_store() called with null context\n");
+#endif
+            return -1;
+        }
+
+	/* find which hash bucket it is in */
+	hash = tdb_hash(&key);
+
+	/* check for it existing */
+	if (flag == TDB_INSERT && tdb_exists(tdb, key)) {
+		tdb->ecode = TDB_ERR_EXISTS;
+		return -1;
+	}
+
+	/* first try in-place update */
+	if (flag != TDB_INSERT && 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 *)&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, &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->ecode = TDB_ERR_OOM;
+		goto fail;
+	}
+
+	memcpy(p, &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, &rec_ptr) == -1) goto fail;
+
+	tdb_unlock(tdb, BUCKET(hash));
+	return 0;
+
+ fail:
+#if TDB_DEBUG
+	printf("store failed for hash 0x%08x in bucket %u\n", 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(&tdb, 0, sizeof(tdb));
+
+	tdb.fd = -1;
+	tdb.name = NULL;
+	tdb.map_ptr = NULL;
+
+	if ((open_flags & O_ACCMODE) == O_WRONLY) {
+		goto fail;
+	}
+
+	if (hash_size == 0) hash_size = DEFAULT_HASH_SIZE;
+
+	tdb.read_only = ((open_flags & 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(&tdb, GLOBAL_LOCK, LOCK_SET, F_WRLCK, F_SETLKW);
+	
+	if (tdb_flags & TDB_CLEAR_IF_FIRST) {
+		/* we need to zero the database if we are the only
+		   one with it open */
+		if (tdb_brlock(&tdb, ACTIVE_LOCK, LOCK_SET, F_WRLCK, F_SETLK) == 0) {
+			ftruncate(tdb.fd, 0);
+			tdb_brlock(&tdb, ACTIVE_LOCK, LOCK_CLEAR, F_WRLCK, F_SETLK);
+		}
+	}
+
+	/* leave this lock in place */
+	tdb_brlock(&tdb, ACTIVE_LOCK, LOCK_SET, F_RDLCK, F_SETLKW);
+
+	if (read(tdb.fd, &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 & O_CREAT)) {
+			goto fail;
+		}
+		if (tdb_new_database(&tdb, hash_size) == -1) goto fail;
+
+		lseek(tdb.fd, 0, SEEK_SET);
+		if (tdb.fd != -1 && read(tdb.fd, &tdb.header, 
+                                         sizeof(tdb.header)) != 
+                                         sizeof(tdb.header)) 
+                    goto fail;
+	}
+
+        if (tdb.fd != -1) {
+            fstat(tdb.fd, &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("mapped database of hash_size %u map_size=%u\n", 
+	       hash_size, tdb.map_size);
+#endif
+
+	tdb_brlock(&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->name) free(tdb->name);
+	if (tdb->fd != -1) close(tdb->fd);
+	if (tdb->locked) free(tdb->locked);
+
+	if (tdb->map_ptr) {
+            if (tdb->fd != -1) {
+                munmap(tdb->map_ptr, tdb->map_size);
+            } else {
+                free(tdb->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("tdb_writelock() called with null context\n");
+#endif
+            return -1;
+        }
+
+	return tdb_lock(tdb, -1);
+}
+
+/* unlock the database. */
+int tdb_writeunlock(TDB_CONTEXT *tdb)
+{
+        if (tdb == NULL) {
+#ifdef TDB_DEBUG
+            printf("tdb_writeunlock() called with null context\n");
+#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("tdb_lockchain() called with null context\n");
+#endif
+            return -1;
+        }
+
+	return tdb_lock(tdb, BUCKET(tdb_hash(&key)));
+}
+
+
+/* unlock one hash chain */
+int tdb_unlockchain(TDB_CONTEXT *tdb, TDB_DATA key)
+{
+        if (tdb == NULL) {
+#ifdef TDB_DEBUG
+            printf("tdb_unlockchain() called with null context\n");
+#endif
+            return -1;
+        }
+
+	return tdb_unlock(tdb, BUCKET(tdb_hash(&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 "TDB file\n"
+
+/* 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	"$Id: tty.c 195720 2001-06-11 11:44:34Z gc $"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <netdb.h>
+#include <utmp.h>
+#include <pwd.h>
+#include <setjmp.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "pppd.h"
+#include "fsm.h"
+#include "lcp.h"
+
+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! */
+    { "device name", o_wild, (void *) &setdevname,
+      "Serial port device name",
+      OPT_DEVNAM | OPT_PRIVFIX | OPT_NOARG  | OPT_A2STRVAL | OPT_STATIC,
+      devnam},
+
+    { "tty speed", o_wild, (void *) &setspeed,
+      "Baud rate for serial port",
+      OPT_PRIO | OPT_NOARG | OPT_A2STRVAL | OPT_STATIC, speed_str },
+
+    { "lock", o_bool, &lockflag,
+      "Lock serial device with UUCP-style lock file", OPT_PRIO | 1 },
+    { "nolock", o_bool, &lockflag,
+      "Don't lock serial device", OPT_PRIOSUB | OPT_PRIV },
+
+    { "init", o_string, &initializer,
+      "A program to initialize the device", OPT_PRIO | OPT_PRIVFIX },
+
+    { "connect", o_string, &connect_script,
+      "A program to set up a connection", OPT_PRIO | OPT_PRIVFIX },
+
+    { "disconnect", o_string, &disconnect_script,
+      "Program to disconnect serial device", OPT_PRIO | OPT_PRIVFIX },
+
+    { "welcome", o_string, &welcomer,
+      "Script to welcome client", OPT_PRIO | OPT_PRIVFIX },
+
+    { "pty", o_string, &ptycommand,
+      "Script to run on pseudo-tty master side",
+      OPT_PRIO | OPT_PRIVFIX | OPT_DEVNAM },
+
+    { "notty", o_bool, &notty,
+      "Input/output is not a tty", OPT_DEVNAM | 1 },
+
+    { "socket", o_string, &pty_socket,
+      "Send and receive over socket, arg is host:port",
+      OPT_PRIO | OPT_DEVNAM },
+
+    { "record", o_string, &record_file,
+      "Record characters sent/received to file", OPT_PRIO },
+
+    { "crtscts", o_int, &crtscts,
+      "Set hardware (RTS/CTS) flow control",
+      OPT_PRIO | OPT_NOARG | OPT_VAL(1) },
+    { "cdtrcts", o_int, &crtscts,
+      "Set alternate hardware (DTR/CTS) flow control",
+      OPT_PRIOSUB | OPT_NOARG | OPT_VAL(2) },
+    { "nocrtscts", o_int, &crtscts,
+      "Disable hardware flow control",
+      OPT_PRIOSUB | OPT_NOARG | OPT_VAL(-1) },
+    { "-crtscts", o_int, &crtscts,
+      "Disable hardware flow control",
+      OPT_PRIOSUB | OPT_ALIAS | OPT_NOARG | OPT_VAL(-1) },
+    { "nocdtrcts", o_int, &crtscts,
+      "Disable hardware flow control",
+      OPT_PRIOSUB | OPT_ALIAS | OPT_NOARG | OPT_VAL(-1) },
+    { "xonxoff", o_special_noarg, (void *)setxonxoff,
+      "Set software (XON/XOFF) flow control", OPT_PRIOSUB },
+
+    { "modem", o_bool, &modem,
+      "Use modem control lines", OPT_PRIO | 1 },
+    { "local", o_bool, &modem,
+      "Don't use modem control lines", OPT_PRIOSUB | 0 },
+
+    { "sync", o_bool, &sync_serial,
+      "Use synchronous HDLC serial encoding", 1 },
+
+    { "datarate", o_int, &max_data_rate,
+      "Maximum data rate in bytes/sec (with pty, notty or record option)",
+      OPT_PRIO },
+
+    { "escape", o_special, (void *)setescape,
+      "List of character codes to escape on transmission",
+      OPT_A2PRINTER, (void *)printescape },
+
+    { NULL }
+};
+
+
+struct channel tty_channel = {
+	tty_options,
+	&tty_process_extra_options,
+	&tty_check_options,
+	&connect_tty,
+	&disconnect_tty,
+	&tty_establish_ppp,
+	&tty_disestablish_ppp,
+	&tty_do_send_config,
+	&tty_recv_config,
+	&cleanup_tty,
+	&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, &ptr, 0);
+	if (ptr == arg || *ptr != 0 || spd == 0)
+		return 0;
+	if (doit) {
+		inspeed = spd;
+		slprintf(speed_str, sizeof(speed_str), "%d", 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("/dev/", cp, 5) != 0) {
+		strlcpy(dev, "/dev/", sizeof(dev));
+		strlcat(dev, cp, sizeof(dev));
+		cp = dev;
+	}
+
+	/*
+	 * Check if there is a character device by this name.
+	 */
+	if (stat(cp, &statbuf) < 0) {
+		if (!doit)
+			return errno != ENOENT;
+		option_error("Couldn't stat %s: %m", cp);
+		return 0;
+	}
+	if (!S_ISCHR(statbuf.st_mode)) {
+		if (doit)
+			option_error("%s is not a character device", 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, &endp, 16);
+	if (p == endp) {
+	    option_error("escape parameter contains invalid hex number '%s'",
+			 p);
+	    return 0;
+	}
+	p = endp;
+	if (n < 0 || n == 0x5E || n > 0xFF) {
+	    option_error("can't escape character 0x%x", n);
+	    ret = 0;
+	} else
+	    xmit_accm[n >> 5] |= 1 << (n & 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 < 256; ++n) {
+		if (n == 0x7d)
+			n += 2;		/* skip 7d, 7e */
+		if (xmit_accm[n >> 5] & (1 << (n & 0x1f))) {
+			if (!first)
+				printer(arg, ",");
+			else
+				first = 0;
+			printer(arg, "%x", n);
+		}
+	}
+	if (first)
+		printer(arg, "oops # nothing escaped");
+}
+
+/*
+ * tty_init - do various tty-related initializations.
+ */
+void tty_init()
+{
+    add_notifier(&pidchange, maybe_relock, 0);
+    the_channel = &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("no device specified and stdin is not a tty");
+			exit(EXIT_OPTION_ERROR);
+		}
+		strlcpy(devnam, p, sizeof(devnam));
+		if (stat(devnam, &devstat) < 0)
+			fatal("Couldn't stat default device %s: %m", 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 && connect_script == 0) {
+		option_error("connect script is required for demand-dialling\n");
+		exit(EXIT_OPTION_ERROR);
+	}
+	/* default holdoff to 0 if no connect script has been given */
+	if (connect_script == 0 && !holdoff_specified)
+		holdoff = 0;
+
+	if (using_pty) {
+		if (!default_device) {
+			option_error("%s option precludes specifying device name",
+				     notty? "notty": "pty");
+			exit(EXIT_OPTION_ERROR);
+		}
+		if (ptycommand != NULL && notty) {
+			option_error("pty option is incompatible with notty option");
+			exit(EXIT_OPTION_ERROR);
+		}
+		if (pty_socket != NULL && (ptycommand != NULL || notty)) {
+			option_error("socket option is incompatible with pty and notty");
+			exit(EXIT_OPTION_ERROR);
+		}
+		default_device = notty;
+		lockflag = 0;
+		modem = 0;
+		if (notty && log_to_fd <= 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, &statbuf) >= 0 && S_ISCHR(statbuf.st_mode)
+		    && statbuf.st_rdev == devstat.st_rdev) {
+			default_device = 1;
+			fdflags = fcntl(0, F_GETFL);
+			if (fdflags != -1 && (fdflags & 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 >= 0 && fstat(log_to_fd, &statbuf) >= 0
+	    && S_ISCHR(statbuf.st_mode) && 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(&pty_master, &pty_slave, ppp_devnam, uid)) {
+			error("Couldn't allocate pseudo-tty");
+			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 && !privopen) {
+		if (lock(devnam) < 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 < OPRIO_ROOT)
+				seteuid(uid);
+			ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0);
+			err = errno;
+			if (prio < OPRIO_ROOT)
+				seteuid(0);
+			if (ttyfd >= 0)
+				break;
+			errno = err;
+			if (err != EINTR) {
+				error("Failed to open %s: %m", 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 & ~O_NONBLOCK) < 0)
+			warn("Couldn't reset non-blocking mode on device: %m");
+
+		/*
+		 * Do the equivalent of `mesg n' to stop broadcast messages.
+		 */
+		if (fstat(ttyfd, &statbuf) < 0
+		    || fchmod(ttyfd, statbuf.st_mode & ~(S_IWGRP | S_IWOTH)) < 0) {
+			warn("Couldn't restrict write permissions to %s: %m", 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 && 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) < 0 || pipe(opipe) < 0)
+				fatal("Couldn't create pipes for record option: %m");
+			ok = device_script(ptycommand, opipe[0], ipipe[1], 1) == 0
+				&& 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) < 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 < 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 && connector[0]) || initializer) {
+		if (real_ttyfd != -1) {
+			/* XXX do this if doing_callback == CALLBACK_DIALIN? */
+			if (!default_device && modem) {
+				setdtr(real_ttyfd, 0);	/* in case modem is off hook */
+				sleep(1);
+				setdtr(real_ttyfd, 1);
+			}
+		}
+
+		if (initializer && initializer[0]) {
+			if (device_script(initializer, ttyfd, ttyfd, 0) < 0) {
+				error("Initializer script failed");
+				status = EXIT_INIT_FAILED;
+				return -1;
+			}
+			if (kill_link) {
+				disconnect_tty();
+				return -1;
+			}
+			info("Serial port initialized.");
+		}
+
+		if (connector && connector[0]) {
+			if (device_script(connector, ttyfd, ttyfd, 0) < 0) {
+				error("Connect script failed");
+				status = EXIT_CONNECT_FAILED;
+				return -1;
+			}
+			if (kill_link) {
+				disconnect_tty();
+				return -1;
+			}
+			info("Serial connection established.");
+		}
+
+		/* 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 && modem && devnam[0] != 0) {
+		int i;
+		for (;;) {
+			if ((i = open(devnam, O_RDWR)) >= 0)
+				break;
+			if (errno != EINTR) {
+				error("Failed to reopen %s: %m", devnam);
+				status = EXIT_OPEN_FAILED;
+			}
+			if (!persist || errno != EINTR || hungup || kill_link)
+				return -1;
+		}
+		close(i);
+	}
+
+	slprintf(numbuf, sizeof(numbuf), "%d", baud_rate);
+	script_setenv("SPEED", numbuf, 0);
+
+	/* run welcome script, if any */
+	if (welcomer && welcomer[0]) {
+		if (device_script(welcomer, ttyfd, ttyfd, 0) < 0)
+			warn("Welcome script failed");
+	}
+
+	/*
+	 * 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 >= 0)
+		set_up_tty(real_ttyfd, 1);
+	if (device_script(disconnect_script, ttyfd, ttyfd, 0) < 0) {
+		warn("disconnect script failed");
+	} else {
+		info("Serial link disconnected.");
+	}
+}
+
+void tty_close_fds()
+{
+	if (pty_master >= 0)
+		close(pty_master);
+	if (pty_slave >= 0)
+		close(pty_slave);
+	if (real_ttyfd >= 0) {
+		close(real_ttyfd);
+		real_ttyfd = -1;
+	}
+	/* N.B. ttyfd will == either pty_slave or real_ttyfd */
+}
+
+void cleanup_tty()
+{
+	if (real_ttyfd >= 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 && 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, &endp, 10);
+    if (port < 0 || endp == sep+1 || sep == dest) {
+	error("Can't parse host:port for socket destination");
+	return -1;
+    }
+    *sep = 0;
+    host = inet_addr(dest);
+    if (host == (u_int32_t) -1) {
+	hent = gethostbyname(dest);
+	if (hent == NULL) {
+	    error("%s: unknown host in socket option", dest);
+	    *sep = ':';
+	    return -1;
+	}
+	host = *(u_int32_t *)(hent->h_addr_list[0]);
+    }
+    *sep = ':';
+
+    /* get a socket and connect it to the other end */
+    sock = socket(PF_INET, SOCK_STREAM, 0);
+    if (sock < 0) {
+	error("Can't create socket: %m");
+	return -1;
+    }
+    memset(&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 *)&sad, sizeof(sad)) < 0) {
+	error("Can't connect to %s: %m", 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("Can't fork process for character shunt: %m");
+	return 0;
+    }
+    if (cpid == 0) {
+	/* child */
+	close(pty_slave);
+	setuid(uid);
+	if (getuid() != uid)
+	    fatal("setuid failed");
+	setgid(getgid());
+	if (!nodetach)
+	    log_to_fd = -1;
+	charshunt(ifd, ofd, record_file);
+	exit(0);
+    }
+    charshunt_pid = cpid;
+    add_notifier(&sigreceived, stop_charshunt, 0);
+    close(pty_master);
+    pty_master = -1;
+    ttyfd = pty_slave;
+    record_child(cpid, "pppd (charshunt)", 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 >= 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, "a");
+	if (recordf == NULL)
+	    error("Couldn't create record file %s: %m", 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("couldn't set pty master to nonblock: %m");
+    flags = fcntl(ifd, F_GETFL);
+    if (flags == -1
+	|| fcntl(ifd, F_SETFL, flags | O_NONBLOCK) == -1)
+	warn("couldn't set %s to nonblock: %m", (ifd==0? "stdin": "tty"));
+    if (ofd != ifd) {
+	flags = fcntl(ofd, F_GETFL);
+	if (flags == -1
+	    || fcntl(ofd, F_SETFL, flags | O_NONBLOCK) == -1)
+	    warn("couldn't set stdout to nonblock: %m");
+    }
+
+    nibuf = nobuf = 0;
+    ibufp = obufp = NULL;
+    pty_readable = stdin_readable = 1;
+
+    ilevel = olevel = 0;
+    gettimeofday(&levelt, NULL);
+    if (max_data_rate) {
+	max_level = max_data_rate / 10;
+	if (max_level < 100)
+	    max_level = 100;
+    } else
+	max_level = PPP_MRU + PPP_HDRLEN + 1;
+
+    nfds = (ofd > pty_master? ofd: pty_master) + 1;
+    if (recordf != NULL) {
+	gettimeofday(&lasttime, NULL);
+	putc(7, recordf);	/* put start marker */
+	putc(lasttime.tv_sec >> 24, recordf);
+	putc(lasttime.tv_sec >> 16, recordf);
+	putc(lasttime.tv_sec >> 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(&ready);
+	FD_ZERO(&writey);
+	if (nibuf != 0) {
+	    if (ilevel >= max_level)
+		top = &tout;
+	    else
+		FD_SET(pty_master, &writey);
+	} else if (stdin_readable)
+	    FD_SET(ifd, &ready);
+	if (nobuf != 0) {
+	    if (olevel >= max_level)
+		top = &tout;
+	    else
+		FD_SET(ofd, &writey);
+	} else if (pty_readable)
+	    FD_SET(pty_master, &ready);
+	if (select(nfds, &ready, &writey, NULL, top) < 0) {
+	    if (errno != EINTR)
+		fatal("select");
+	    continue;
+	}
+	if (max_data_rate) {
+	    double dt;
+	    int nbt;
+	    struct timeval now;
+
+	    gettimeofday(&now, NULL);
+	    dt = (now.tv_sec - levelt.tv_sec
+		  + (now.tv_usec - levelt.tv_usec) / 1e6);
+	    nbt = (int)(dt * max_data_rate);
+	    ilevel = (nbt < 0 || nbt > ilevel)? 0: ilevel - nbt;
+	    olevel = (nbt < 0 || nbt > olevel)? 0: olevel - nbt;
+	    levelt = now;
+	} else
+	    ilevel = olevel = 0;
+	if (FD_ISSET(ifd, &ready)) {
+	    ibufp = inpacket_buf;
+	    nibuf = read(ifd, ibufp, PPP_MRU + PPP_HDRLEN);
+	    if (nibuf < 0 && errno == EIO)
+		nibuf = 0;
+	    if (nibuf < 0) {
+		if (!(errno == EINTR || errno == EAGAIN)) {
+		    error("Error reading standard input: %m");
+		    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, &lasttime))
+			recordf = NULL;
+	    } else {
+		FD_SET(pty_master, &writey);
+		if (recordf)
+		    if (!record_write(recordf, 2, ibufp, nibuf, &lasttime))
+			recordf = NULL;
+	    }
+	}
+	if (FD_ISSET(pty_master, &ready)) {
+	    obufp = outpacket_buf;
+	    nobuf = read(pty_master, obufp, PPP_MRU + PPP_HDRLEN);
+	    if (nobuf < 0 && errno == EIO)
+		nobuf = 0;
+	    if (nobuf < 0) {
+		if (!(errno == EINTR || errno == EAGAIN)) {
+		    error("Error reading pseudo-tty master: %m");
+		    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, &lasttime))
+			recordf = NULL;
+	    } else {
+		FD_SET(ofd, &writey);
+		if (recordf)
+		    if (!record_write(recordf, 1, obufp, nobuf, &lasttime))
+			recordf = NULL;
+	    }
+	}
+	if (FD_ISSET(ofd, &writey)) {
+	    n = nobuf;
+	    if (olevel + n > max_level)
+		n = max_level - olevel;
+	    n = write(ofd, obufp, n);
+	    if (n < 0) {
+		if (errno == EIO) {
+		    pty_readable = 0;
+		    nobuf = 0;
+		} else if (errno != EAGAIN && errno != EINTR) {
+		    error("Error writing standard output: %m");
+		    break;
+		}
+	    } else {
+		obufp += n;
+		nobuf -= n;
+		olevel += n;
+	    }
+	}
+	if (FD_ISSET(pty_master, &writey)) {
+	    n = nibuf;
+	    if (ilevel + n > max_level)
+		n = max_level - ilevel;
+	    n = write(pty_master, ibufp, n);
+	    if (n < 0) {
+		if (errno == EIO) {
+		    stdin_readable = 0;
+		    nibuf = 0;
+		} else if (errno != EAGAIN && errno != EINTR) {
+		    error("Error writing pseudo-tty master: %m");
+		    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(&now, NULL);
+    now.tv_usec /= 100000;	/* actually 1/10 s, not usec now */
+    diff = (now.tv_sec - tp->tv_sec) * 10 + (now.tv_usec - tp->tv_usec);
+    if (diff > 0) {
+	if (diff > 255) {
+	    putc(5, f);
+	    putc(diff >> 24, f);
+	    putc(diff >> 16, f);
+	    putc(diff >> 8, f);
+	    putc(diff, f);
+	} else {
+	    putc(6, f);
+	    putc(diff, f);
+	}
+	*tp = now;
+    }
+    putc(code, f);
+    if (buf != NULL) {
+	putc(nb >> 8, f);
+	putc(nb, f);
+	fwrite(buf, nb, 1, f);
+    }
+    fflush(f);
+    if (ferror(f)) {
+	error("Error writing record file: %m");
+	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	"$Id: upap.c 195720 2001-06-11 11:44:34Z gc $"
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "pppd.h"
+#include "upap.h"
+
+static const char rcsid[] = RCSID;
+
+static bool hide_password = 1;
+
+/*
+ * Command-line options.
+ */
+static option_t pap_option_list[] = {
+    { "hide-password", o_bool, &hide_password,
+      "Don't output passwords to log", OPT_PRIO | 1 },
+    { "show-password", o_bool, &hide_password,
+      "Show password string in debug log messages", OPT_PRIOSUB | 0 },
+
+    { "pap-restart", o_int, &upap[0].us_timeouttime,
+      "Set retransmit timeout for PAP", OPT_PRIO },
+    { "pap-max-authreq", o_int, &upap[0].us_maxtransmits,
+      "Set max number of transmissions for auth-reqs", OPT_PRIO },
+    { "pap-timeout", o_int, &upap[0].us_reqtimeout,
+      "Set time limit for peer PAP authentication", 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,
+    "PAP",
+    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 = &upap[unit];
+
+    u->us_unit = unit;
+    u->us_user = NULL;
+    u->us_userlen = 0;
+    u->us_passwd = NULL;
+    u->us_passwdlen = 0;
+    u->us_clientstate = UPAPCS_INITIAL;
+    u->us_serverstate = UPAPSS_INITIAL;
+    u->us_id = 0;
+    u->us_timeouttime = UPAP_DEFTIMEOUT;
+    u->us_maxtransmits = 10;
+    u->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 = &upap[unit];
+
+    /* Save the username and password we're given */
+    u->us_user = user;
+    u->us_userlen = strlen(user);
+    u->us_passwd = password;
+    u->us_passwdlen = strlen(password);
+    u->us_transmits = 0;
+
+    /* Lower layer up yet? */
+    if (u->us_clientstate == UPAPCS_INITIAL ||
+	u->us_clientstate == UPAPCS_PENDING) {
+	u->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 = &upap[unit];
+
+    /* Lower layer up yet? */
+    if (u->us_serverstate == UPAPSS_INITIAL ||
+	u->us_serverstate == UPAPSS_PENDING) {
+	u->us_serverstate = UPAPSS_PENDING;
+	return;
+    }
+
+    u->us_serverstate = UPAPSS_LISTEN;
+    if (u->us_reqtimeout > 0)
+	TIMEOUT(upap_reqtimeout, u, u->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->us_clientstate != UPAPCS_AUTHREQ)
+	return;
+
+    if (u->us_transmits >= u->us_maxtransmits) {
+	/* give up in disgust */
+	error("No response to PAP authenticate-requests");
+	u->us_clientstate = UPAPCS_BADAUTH;
+	auth_withpeer_fail(u->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->us_serverstate != UPAPSS_LISTEN)
+	return;			/* huh?? */
+
+    auth_peer_fail(u->us_unit, PPP_PAP);
+    u->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 = &upap[unit];
+
+    if (u->us_clientstate == UPAPCS_INITIAL)
+	u->us_clientstate = UPAPCS_CLOSED;
+    else if (u->us_clientstate == UPAPCS_PENDING) {
+	upap_sauthreq(u);	/* send an auth-request */
+    }
+
+    if (u->us_serverstate == UPAPSS_INITIAL)
+	u->us_serverstate = UPAPSS_CLOSED;
+    else if (u->us_serverstate == UPAPSS_PENDING) {
+	u->us_serverstate = UPAPSS_LISTEN;
+	if (u->us_reqtimeout > 0)
+	    TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
+    }
+}
+
+
+/*
+ * upap_lowerdown - The lower layer is down.
+ *
+ * Cancel all timeouts.
+ */
+static void
+upap_lowerdown(unit)
+    int unit;
+{
+    upap_state *u = &upap[unit];
+
+    if (u->us_clientstate == UPAPCS_AUTHREQ)	/* Timeout pending? */
+	UNTIMEOUT(upap_timeout, u);		/* Cancel timeout */
+    if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0)
+	UNTIMEOUT(upap_reqtimeout, u);
+
+    u->us_clientstate = UPAPCS_INITIAL;
+    u->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 = &upap[unit];
+
+    if (u->us_clientstate == UPAPCS_AUTHREQ) {
+	error("PAP authentication failed due to protocol-reject");
+	auth_withpeer_fail(unit, PPP_PAP);
+    }
+    if (u->us_serverstate == UPAPSS_LISTEN) {
+	error("PAP authentication of peer failed (protocol-reject)");
+	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 = &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 < UPAP_HEADERLEN) {
+	UPAPDEBUG(("pap_input: rcvd short header."));
+	return;
+    }
+    GETCHAR(code, inp);
+    GETCHAR(id, inp);
+    GETSHORT(len, inp);
+    if (len < UPAP_HEADERLEN) {
+	UPAPDEBUG(("pap_input: rcvd illegal length."));
+	return;
+    }
+    if (len > l) {
+	UPAPDEBUG(("pap_input: rcvd short packet."));
+	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->us_serverstate < 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->us_serverstate == UPAPSS_OPEN) {
+	upap_sresp(u, UPAP_AUTHACK, id, "", 0);	/* return auth-ack */
+	return;
+    }
+    if (u->us_serverstate == UPAPSS_BADAUTH) {
+	upap_sresp(u, UPAP_AUTHNAK, id, "", 0);	/* return auth-nak */
+	return;
+    }
+
+    /*
+     * Parse user/passwd.
+     */
+    if (len < 1) {
+	UPAPDEBUG(("pap_rauth: rcvd short packet."));
+	return;
+    }
+    GETCHAR(ruserlen, inp);
+    len -= sizeof (u_char) + ruserlen + sizeof (u_char);
+    if (len < 0) {
+	UPAPDEBUG(("pap_rauth: rcvd short packet."));
+	return;
+    }
+    ruser = (char *) inp;
+    INCPTR(ruserlen, inp);
+    GETCHAR(rpasswdlen, inp);
+    if (len < rpasswdlen) {
+	UPAPDEBUG(("pap_rauth: rcvd short packet."));
+	return;
+    }
+    rpasswd = (char *) inp;
+
+    /*
+     * Check the username and password given.
+     */
+    retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd,
+			   rpasswdlen, &msg);
+    BZERO(rpasswd, rpasswdlen);
+    msglen = strlen(msg);
+    if (msglen > 255)
+	msglen = 255;
+
+    upap_sresp(u, retcode, id, msg, msglen);
+
+    if (retcode == UPAP_AUTHACK) {
+	u->us_serverstate = UPAPSS_OPEN;
+	auth_peer_success(u->us_unit, PPP_PAP, ruser, ruserlen);
+    } else {
+	u->us_serverstate = UPAPSS_BADAUTH;
+	auth_peer_fail(u->us_unit, PPP_PAP);
+    }
+
+    if (u->us_reqtimeout > 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->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
+	return;
+
+    /*
+     * Parse message.
+     */
+    if (len < 1) {
+	UPAPDEBUG(("pap_rauthack: ignoring missing msg-length."));
+    } else {
+	GETCHAR(msglen, inp);
+	if (msglen > 0) {
+	    len -= sizeof (u_char);
+	    if (len < msglen) {
+		UPAPDEBUG(("pap_rauthack: rcvd short packet."));
+		return;
+	    }
+	    msg = (char *) inp;
+	    PRINTMSG(msg, msglen);
+	}
+    }
+
+    u->us_clientstate = UPAPCS_OPEN;
+
+    auth_withpeer_success(u->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->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
+	return;
+
+    /*
+     * Parse message.
+     */
+    if (len < 1) {
+	UPAPDEBUG(("pap_rauthnak: ignoring missing msg-length."));
+    } else {
+	GETCHAR(msglen, inp);
+	if (msglen > 0) {
+	    len -= sizeof (u_char);
+	    if (len < msglen) {
+		UPAPDEBUG(("pap_rauthnak: rcvd short packet."));
+		return;
+	    }
+	    msg = (char *) inp;
+	    PRINTMSG(msg, msglen);
+	}
+    }
+
+    u->us_clientstate = UPAPCS_BADAUTH;
+
+    error("PAP authentication failed");
+    auth_withpeer_fail(u->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->us_userlen + u->us_passwdlen;
+    outp = outpacket_buf;
+    
+    MAKEHEADER(outp, PPP_PAP);
+
+    PUTCHAR(UPAP_AUTHREQ, outp);
+    PUTCHAR(++u->us_id, outp);
+    PUTSHORT(outlen, outp);
+    PUTCHAR(u->us_userlen, outp);
+    BCOPY(u->us_user, outp, u->us_userlen);
+    INCPTR(u->us_userlen, outp);
+    PUTCHAR(u->us_passwdlen, outp);
+    BCOPY(u->us_passwd, outp, u->us_passwdlen);
+
+    output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
+
+    TIMEOUT(upap_timeout, u, u->us_timeouttime);
+    ++u->us_transmits;
+    u->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->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
+}
+
+/*
+ * upap_printpkt - print the contents of a PAP packet.
+ */
+static char *upap_codenames[] = {
+    "AuthReq", "AuthAck", "AuthNak"
+};
+
+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 < UPAP_HEADERLEN)
+	return 0;
+    pstart = p;
+    GETCHAR(code, p);
+    GETCHAR(id, p);
+    GETSHORT(len, p);
+    if (len < UPAP_HEADERLEN || len > plen)
+	return 0;
+
+    if (code >= 1 && code <= sizeof(upap_codenames) / sizeof(char *))
+	printer(arg, " %s", upap_codenames[code-1]);
+    else
+	printer(arg, " code=0x%x", code);
+    printer(arg, " id=0x%x", id);
+    len -= UPAP_HEADERLEN;
+    switch (code) {
+    case UPAP_AUTHREQ:
+	if (len < 1)
+	    break;
+	ulen = p[0];
+	if (len < ulen + 2)
+	    break;
+	wlen = p[ulen + 1];
+	if (len < ulen + wlen + 2)
+	    break;
+	user = (char *) (p + 1);
+	pwd = (char *) (p + ulen + 2);
+	p += ulen + wlen + 2;
+	len -= ulen + wlen + 2;
+	printer(arg, " user=");
+	print_string(user, ulen, printer, arg);
+	printer(arg, " password=");
+	if (!hide_password)
+	    print_string(pwd, wlen, printer, arg);
+	else
+	    printer(arg, "<hidden>");
+	break;
+    case UPAP_AUTHACK:
+    case UPAP_AUTHNAK:
+	if (len < 1)
+	    break;
+	mlen = p[0];
+	if (len < mlen + 1)
+	    break;
+	msg = (char *) (p + 1);
+	p += mlen + 1;
+	len -= mlen + 1;
+	printer(arg, " ");
+	print_string(msg, mlen, printer, arg);
+	break;
+    }
+
+    /* print the rest of the bytes in the packet */
+    for (; len > 0; --len) {
+	GETCHAR(code, p);
+	printer(arg, " %.2x", 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	"$Id: utils.c 203596 2003-08-19 08:57:26Z gbeauchesne $"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <netdb.h>
+#include <utmp.h>
+#include <pwd.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifdef SVR4
+#include <sys/mkdev.h>
+#endif
+
+#include "pppd.h"
+#include <time.h>
+
+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 > 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 < 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 > 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 > 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 > 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[] = "0123456789abcdef";
+    struct buffer_info bufinfo;
+
+    buf0 = buf;
+    --buflen;
+    while (buflen > 0) {
+	for (f = fmt; *f != '%' && *f != 0; ++f)
+	    ;
+	if (f > fmt) {
+	    len = f - fmt;
+	    if (len > 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 < 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), "%d.%d.%d.%d", (ip >> 24) & 0xff,
+		     (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
+	    str = num;
+	    break;
+	case 'r':
+	    f = va_arg(args, char *);
+#if !defined(__powerpc__) && !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(&t);
+	    str = ctime(&t);
+	    str += 4;		/* chop off the day name */
+	    str[15] = 0;	/* chop off year and newline */
+	    break;
+	case 'v':		/* "visible" string */
+	case 'q':		/* quoted string */
+	    quoted = c == 'q';
+	    p = va_arg(args, unsigned char *);
+	    if (fillch == '0' && prec >= 0) {
+		n = prec;
+	    } else {
+		n = strlen((char *)p);
+		if (prec >= 0 && n > prec)
+		    n = prec;
+	    }
+	    while (n > 0 && buflen > 0) {
+		c = *p++;
+		--n;
+		if (!quoted && c >= 0x80) {
+		    OUTCHAR('M');
+		    OUTCHAR('-');
+		    c -= 0x80;
+		}
+		if (quoted && (c == '"' || c == '\\'))
+		    OUTCHAR('\\');
+		if (c < 0x20 || (0x7f <= c && c < 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 >> 4]);
+			    OUTCHAR(hexchars[c & 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, &bufinfo);
+	    buf = bufinfo.ptr;
+	    buflen = bufinfo.len - 1;
+	    continue;
+	case 'B':
+	    p = va_arg(args, unsigned char *);
+	    for (n = prec; n > 0; --n) {
+		c = *p++;
+		if (fillch == ' ')
+		    OUTCHAR(' ');
+		OUTCHAR(hexchars[(c >> 4) & 0xf]);
+		OUTCHAR(hexchars[c & 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 > num + neg) {
+		*--str = hexchars[val % base];
+		val = val / base;
+		if (--prec <= 0 && 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 >= 0 && len > prec)
+		len = prec;
+	}
+	if (width > 0) {
+	    if (width > buflen)
+		width = buflen;
+	    if ((n = width - len) > 0) {
+		buflen -= n;
+		for (; n > 0; --n)
+		    *buf++ = fillch;
+	    }
+	}
+	if (len > 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->ptr, bi->len, fmt, pvar);
+    va_end(pvar);
+
+    bi->ptr += n;
+    bi->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, &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 >= PPP_HDRLEN && p[0] == PPP_ALLSTATIONS && p[1] == PPP_UI) {
+	p += 2;
+	GETSHORT(proto, p);
+	len -= PPP_HDRLEN;
+	for (i = 0; (protp = protocols[i]) != NULL; ++i)
+	    if (proto == protp->protocol)
+		break;
+	if (protp != NULL) {
+	    printer(arg, "[%s", protp->name);
+	    n = (*protp->printpkt)(p, len, printer, arg);
+	    printer(arg, "]");
+	    p += n;
+	    len -= n;
+	} else {
+	    for (i = 0; (protp = protocols[i]) != NULL; ++i)
+		if (proto == (protp->protocol & ~0x8000))
+		    break;
+	    if (protp != 0 && protp->data_name != 0) {
+		printer(arg, "[%s data]", protp->data_name);
+		if (len > 8)
+		    printer(arg, "%.8B ...", p);
+		else
+		    printer(arg, "%.*B", len, p);
+		len = 0;
+	    } else
+		printer(arg, "[proto=0x%x]", proto);
+	}
+    }
+
+    if (len > 32)
+	printer(arg, "%.32B ...", p);
+    else
+	printer(arg, "%.*B", 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 < line + sizeof(line)) {
+			if (l > 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) <= sizeof(line) */
+	l = buf + n - p;
+	if (l > 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, "\"");
+    for (; len > 0; --len) {
+	c = *p++;
+	if (' ' <= c && c <= '~') {
+	    if (c == '\\' || c == '"')
+		printer(arg, "\\");
+	    printer(arg, "%c", c);
+	} else {
+	    switch (c) {
+	    case '\n':
+		printer(arg, "\\n");
+		break;
+	    case '\r':
+		printer(arg, "\\r");
+		break;
+	    case '\t':
+		printer(arg, "\\t");
+		break;
+	    default:
+		printer(arg, "\\%.3o", c);
+	    }
+	}
+    }
+    printer(arg, "\"");
+}
+
+/*
+ * 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, "%s", buf);
+    if (log_to_fd >= 0 && (level != LOG_DEBUG || debug)) {
+	int n = strlen(buf);
+
+	if (n > 0 && buf[n-1] == '\n')
+	    --n;
+	if (write(log_to_fd, buf, n) != n
+	    || write(log_to_fd, "\n", 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	"/var/lock"
+#else
+#ifdef SVR4
+#define LOCK_DIR	"/var/spool/locks"
+#else
+#define LOCK_DIR	"/var/spool/lock"
+#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 > 0)
+        notice("Device %s is locked by pid %d", dev, result);
+    else
+	error("Can't create lock file %s", lock_file);
+    return -1;
+
+#else /* LOCKLIB */
+
+    char lock_buffer[12];
+    int fd, pid, n;
+
+#ifdef SVR4
+    struct stat sbuf;
+
+    if (stat(dev, &sbuf) < 0) {
+	error("Can't get device number for %s: %m", dev);
+	return -1;
+    }
+    if ((sbuf.st_mode & S_IFMT) != S_IFCHR) {
+	error("Can't lock %s: not a character device", dev);
+	return -1;
+    }
+    slprintf(lock_file, sizeof(lock_file), "%s/LK.%03d.%03d.%03d",
+	     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), "%s/LCK..%s", LOCK_DIR, dev);
+#endif
+
+    while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
+	if (errno != EEXIST) {
+	    error("Can't create lock file %s: %m", lock_file);
+	    break;
+	}
+
+	/* Read the lock file to find out who has the device locked. */
+	fd = open(lock_file, O_RDONLY, 0);
+	if (fd < 0) {
+	    if (errno == ENOENT) /* This is just a timing problem. */
+		continue;
+	    error("Can't open existing lock file %s: %m", lock_file);
+	    break;
+	}
+#ifndef LOCK_BINARY
+	n = read(fd, lock_buffer, 11);
+#else
+	n = read(fd, &pid, sizeof(pid));
+#endif /* LOCK_BINARY */
+	close(fd);
+	fd = -1;
+	if (n <= 0) {
+	    error("Can't read pid from lock file %s", 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 && errno == ESRCH)) {
+	    if (unlink (lock_file) == 0) {
+		notice("Removed stale lock on %s (pid %d)", dev, pid);
+		continue;
+	    }
+	    warn("Couldn't remove stale lock on %s", dev);
+	} else
+	    notice("Device %s is locked by pid %d", dev, pid);
+	break;
+    }
+
+    if (fd < 0) {
+	lock_file[0] = 0;
+	return -1;
+    }
+
+    pid = getpid();
+#ifndef LOCK_BINARY
+    slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid);
+    write (fd, lock_buffer, 11);
+#else
+    write(fd, &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 < 0) {
+	error("Couldn't reopen lock file %s: %m", lock_file);
+	lock_file[0] = 0;
+	return -1;
+    }
+
+#ifndef LOCK_BINARY
+    slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid);
+    write (fd, lock_buffer, 11);
+#else
+    write(fd, &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 <sys/types.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include "ppp_defs.h"
+#include "ppp-comp.h"
+
+#if DO_BSD_COMPRESS
+
+/*
+ * PPP "BSD compress" 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 << (b)) - 1)
+#define BADCODEM1	MAXCODE(BSD_MAX_BITS)
+
+#define BSD_HASH(prefix,suffix,hshift)	((((u_int32_t)(suffix)) << (hshift)) \
+					 ^ (u_int32_t)(prefix))
+#define BSD_KEY(prefix,suffix)		((((u_int32_t)(suffix)) << 16) \
+					 + (u_int32_t)(prefix))
+
+#define CHECK_GAP	10000		/* Ratio check interval */
+
+#define RATIO_SCALE_LOG	8
+#define RATIO_SCALE	(1<<RATIO_SCALE_LOG)
+#define RATIO_MAX	(0x7fffffff>>RATIO_SCALE_LOG)
+
+/*
+ * clear the dictionary
+ */
+static void
+bsd_clear(db)
+    struct bsd_db *db;
+{
+    db->clear_count++;
+    db->max_ent = FIRST-1;
+    db->n_bits = BSD_INIT_BITS;
+    db->ratio = 0;
+    db->bytes_out = 0;
+    db->in_count = 0;
+    db->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->in_count >= db->checkpoint) {
+	/* age the ratio by limiting the size of the counts */
+	if (db->in_count >= RATIO_MAX
+	    || db->bytes_out >= RATIO_MAX) {
+	    db->in_count -= db->in_count/4;
+	    db->bytes_out -= db->bytes_out/4;
+	}
+
+	db->checkpoint = db->in_count + CHECK_GAP;
+
+	if (db->max_ent >= db->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->in_count <= RATIO_MAX.
+	     */
+	    new_ratio = db->in_count << RATIO_SCALE_LOG;
+	    if (db->bytes_out != 0)
+		new_ratio /= db->bytes_out;
+
+	    if (new_ratio < db->ratio || new_ratio < 1 * RATIO_SCALE) {
+		bsd_clear(db);
+		return 1;
+	    }
+	    db->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->unc_bytes = db->uncomp_bytes;
+    stats->unc_packets = db->uncomp_count;
+    stats->comp_bytes = db->comp_bytes;
+    stats->comp_packets = db->comp_count;
+    stats->inc_bytes = db->incomp_bytes;
+    stats->inc_packets = db->incomp_count;
+    stats->ratio = db->in_count;
+    out = db->bytes_out;
+    if (stats->ratio <= 0x7fffff)
+	stats->ratio <<= 8;
+    else
+	out >>= 8;
+    if (out != 0)
+	stats->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->seqno = 0;
+    bsd_clear(db);
+    db->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->dict[0]));
+    db = (struct bsd_db *) malloc(newlen);
+    if (!db)
+	return NULL;
+    memset(db, 0, sizeof(*db) - sizeof(db->dict));
+
+    if (!decomp) {
+	db->lens = NULL;
+    } else {
+	db->lens = (u_short *) malloc((maxmaxcode+1) * sizeof(db->lens[0]));
+	if (!db->lens) {
+	    free(db);
+	    return NULL;
+	}
+    }
+
+    db->totlen = newlen;
+    db->hsize = hsize;
+    db->hshift = hshift;
+    db->maxmaxcode = maxmaxcode;
+    db->maxbits = bits;
+
+    return (void *) db;
+}
+
+static void
+bsd_free(state)
+    void *state;
+{
+    struct bsd_db *db = (struct bsd_db *) state;
+
+    if (db->lens)
+	free(db->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 < 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->maxbits
+	|| decomp && db->lens == NULL)
+	return 0;
+
+    if (decomp) {
+	i = LAST+1;
+	while (i != 0)
+	    db->lens[--i] = 1;
+    }
+    i = db->hsize;
+    while (i != 0) {
+	db->dict[--i].codem1 = BADCODEM1;
+	db->dict[i].cptr = 0;
+    }
+
+    db->unit = unit;
+    db->hdrlen = hdrlen;
+    db->mru = mru;
+    if (debug)
+	db->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 "BSD Compress" 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->hshift;
+    u_int max_ent = db->max_ent;
+    u_int n_bits = db->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 & 1) == 0 || ent < 0x21 || ent > 0xf9)
+	return;
+
+    db->seqno++;
+    ilen = 1;		/* count the protocol as 1 byte */
+    ++rptr;
+    slen = dmsg + mlen - rptr;
+    ilen += slen;
+    for (; slen > 0; --slen) {
+	c = *rptr++;
+	fcode = BSD_KEY(ent, c);
+	hval = BSD_HASH(ent, c, hshift);
+	dictp = &db->dict[hval];
+
+	/* validate and then check the entry */
+	if (dictp->codem1 >= max_ent)
+	    goto nomatch;
+	if (dictp->f.fcode == fcode) {
+	    ent = dictp->codem1+1;
+	    continue;   /* found (prefix,suffix) */
+	}
+
+	/* continue probing until a match or invalid entry */
+	disp = (hval == 0) ? 1 : hval;
+	do {
+	    hval += disp;
+	    if (hval >= db->hsize)
+		hval -= db->hsize;
+	    dictp = &db->dict[hval];
+	    if (dictp->codem1 >= max_ent)
+		goto nomatch;
+	} while (dictp->f.fcode != fcode);
+	ent = dictp->codem1+1;
+	continue;	/* finally found (prefix,suffix) */
+
+    nomatch:		/* output (count) the prefix */
+	bitno += n_bits;
+
+	/* code -> hashtable */
+	if (max_ent < db->maxmaxcode) {
+	    struct bsd_dict *dictp2;
+	    /* expand code size if needed */
+	    if (max_ent >= MAXCODE(n_bits))
+		db->n_bits = ++n_bits;
+
+	    /* Invalidate previous hash table entry
+	     * assigned this code, and then take it over.
+	     */
+	    dictp2 = &db->dict[max_ent+1];
+	    if (db->dict[dictp2->cptr].codem1 == max_ent)
+		db->dict[dictp2->cptr].codem1 = BADCODEM1;
+	    dictp2->cptr = hval;
+	    dictp->codem1 = max_ent;
+	    dictp->f.fcode = fcode;
+
+	    db->max_ent = ++max_ent;
+	    db->lens[max_ent] = db->lens[ent]+1;
+	}
+	ent = c;
+    }
+    bitno += n_bits;		/* output (count) the last code */
+    db->bytes_out += bitno/8;
+    db->in_count += ilen;
+    (void)bsd_check(db);
+
+    ++db->incomp_count;
+    db->incomp_bytes += ilen;
+    ++db->uncomp_count;
+    db->uncomp_bytes += ilen;
+
+    /* Increase code size if we would have without the packet
+     * boundary and as the decompressor will.
+     */
+    if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode)
+	db->n_bits++;
+}
+
+
+/*
+ * Decompress "BSD Compress"
+ *
+ * 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 "after" 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->max_ent;
+    u_int32_t accm = 0;
+    u_int bitno = 32;		/* 1st valid bit in accm */
+    u_int n_bits = db->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] << 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->seqno++) {
+	if (db->debug)
+	    printf("bsd_decomp%d: bad sequence # %d, expected %d\n",
+		   db->unit, seq, db->seqno - 1);
+	return DECOMP_ERROR;
+    }
+
+    wptr = dmp + db->hdrlen;
+
+    oldcode = CLEAR;
+    explen = 0;
+    while (len > 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++ << bitno;
+	--len;
+	if (tgtbitno < bitno)
+	    continue;
+	incode = accm >> tgtbitno;
+	accm <<= 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 > 0) {
+		if (db->debug)
+		    printf("bsd_decomp%d: bad CLEAR\n", db->unit);
+		return DECOMP_FATALERROR;
+	    }
+	    bsd_clear(db);
+	    explen = ilen = 0;
+	    break;
+	}
+
+	if (incode > max_ent + 2 || incode > db->maxmaxcode
+	    || incode > max_ent && oldcode == CLEAR) {
+	    if (db->debug) {
+		printf("bsd_decomp%d: bad code 0x%x oldcode=0x%x ",
+		       db->unit, incode, oldcode);
+		printf("max_ent=0x%x dlen=%d seqno=%d\n",
+		       max_ent, dlen, db->seqno);
+	    }
+	    return DECOMP_FATALERROR;	/* probably a bug */
+	}
+
+	/* Special case for KwKwK string. */
+	if (incode > max_ent) {
+	    finchar = oldcode;
+	    extra = 1;
+	} else {
+	    finchar = incode;
+	    extra = 0;
+	}
+
+	codelen = db->lens[finchar];
+	explen += codelen + extra;
+	if (explen > db->mru + 1) {
+	    if (db->debug)
+		printf("bsd_decomp%d: ran out of mru\n", db->unit);
+	    return DECOMP_FATALERROR;
+	}
+
+	/*
+	 * Decode this code and install it in the decompressed buffer.
+	 */
+	p = (wptr += codelen);
+	while (finchar > LAST) {
+	    dictp = &db->dict[db->dict[finchar].cptr];
+#ifdef DEBUG
+	    --codelen;
+	    if (codelen <= 0) {
+		printf("bsd_decomp%d: fell off end of chain ", db->unit);
+		printf("0x%x at 0x%x by 0x%x, max_ent=0x%x\n",
+		       incode, finchar, db->dict[finchar].cptr, max_ent);
+		return DECOMP_FATALERROR;
+	    }
+	    if (dictp->codem1 != finchar-1) {
+		printf("bsd_decomp%d: bad code chain 0x%x finchar=0x%x ",
+		       db->unit, incode, finchar);
+		printf("oldcode=0x%x cptr=0x%x codem1=0x%x\n", oldcode,
+		       db->dict[finchar].cptr, dictp->codem1);
+		return DECOMP_FATALERROR;
+	    }
+#endif
+	    *--p = dictp->f.hs.suffix;
+	    finchar = dictp->f.hs.prefix;
+	}
+	*--p = finchar;
+
+#ifdef DEBUG
+	if (--codelen != 0)
+	    printf("bsd_decomp%d: short by %d after code 0x%x, max_ent=0x%x\n",
+		   db->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 && max_ent < db->maxmaxcode) {
+	    struct bsd_dict *dictp2;
+	    u_int32_t fcode;
+	    int hval, disp;
+
+	    fcode = BSD_KEY(oldcode,finchar);
+	    hval = BSD_HASH(oldcode,finchar,db->hshift);
+	    dictp = &db->dict[hval];
+
+	    /* look for a free hash table entry */
+	    if (dictp->codem1 < max_ent) {
+		disp = (hval == 0) ? 1 : hval;
+		do {
+		    hval += disp;
+		    if (hval >= db->hsize)
+			hval -= db->hsize;
+		    dictp = &db->dict[hval];
+		} while (dictp->codem1 < max_ent);
+	    }
+
+	    /*
+	     * Invalidate previous hash table entry
+	     * assigned this code, and then take it over
+	     */
+	    dictp2 = &db->dict[max_ent+1];
+	    if (db->dict[dictp2->cptr].codem1 == max_ent) {
+		db->dict[dictp2->cptr].codem1 = BADCODEM1;
+	    }
+	    dictp2->cptr = hval;
+	    dictp->codem1 = max_ent;
+	    dictp->f.fcode = fcode;
+
+	    db->max_ent = ++max_ent;
+	    db->lens[max_ent] = db->lens[oldcode]+1;
+
+	    /* Expand code size if needed. */
+	    if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) {
+		db->n_bits = ++n_bits;
+		tgtbitno = 32-n_bits;
+	    }
+	}
+	oldcode = incode;
+    }
+    *outlenp = wptr - (dmp + db->hdrlen);
+
+    /*
+     * Keep the checkpoint right so that incompressible packets
+     * clear the dictionary at the right times.
+     */
+    db->bytes_out += ilen;
+    db->in_count += explen;
+    if (bsd_check(db) && db->debug) {
+	printf("bsd_decomp%d: peer should have cleared dictionary\n",
+	       db->unit);
+    }
+
+    ++db->comp_count;
+    db->comp_bytes += ilen + BSD_OVHD;
+    ++db->uncomp_count;
+    db->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 "AS IS" 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 <sys/types.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include "ppp_defs.h"
+#include "ppp-comp.h"
+#include "zlib.h"
+
+#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->stats;
+    stats->ratio = stats->unc_bytes;
+    out = stats->comp_bytes + stats->unc_bytes;
+    if (stats->ratio <= 0x7ffffff)
+	stats->ratio <<= 8;
+    else
+	out >>= 8;
+    if (out != 0)
+	stats->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 < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
+	return NULL;
+
+    state = (struct deflate_state *) malloc(sizeof(*state));
+    if (state == NULL)
+	return NULL;
+
+    state->strm.next_out = NULL;
+    state->strm.zalloc = (alloc_func) z_alloc;
+    state->strm.zfree = (free_func) z_free;
+    if (inflateInit2(&state->strm, -w_size) != Z_OK) {
+	free(state);
+	return NULL;
+    }
+
+    state->w_size = w_size;
+    memset(&state->stats, 0, sizeof(state->stats));
+    return (void *) state;
+}
+
+static void
+z_decomp_free(arg)
+    void *arg;
+{
+    struct deflate_state *state = (struct deflate_state *) arg;
+
+    inflateEnd(&state->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 < CILEN_DEFLATE || options[0] != CI_DEFLATE
+	|| options[1] != CILEN_DEFLATE
+	|| DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
+	|| DEFLATE_SIZE(options[2]) != state->w_size
+	|| options[3] != DEFLATE_CHK_SEQUENCE)
+	return 0;
+
+    state->seqno = 0;
+    state->unit = unit;
+    state->hdrlen = hdrlen;
+    state->debug = debug;
+    state->mru = mru;
+
+    inflateReset(&state->strm);
+
+    return 1;
+}
+
+static void
+z_decomp_reset(arg)
+    void *arg;
+{
+    struct deflate_state *state = (struct deflate_state *) arg;
+
+    state->seqno = 0;
+    inflateReset(&state->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 "after" 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] << 8) + rptr[1];
+    rptr += 2;
+    if (seq != state->seqno) {
+#if !DEFLATE_DEBUG
+	if (state->debug)
+#endif
+	    printf("z_decompress%d: bad seq # %d, expected %d\n",
+		   state->unit, seq, state->seqno);
+	return DECOMP_ERROR;
+    }
+    ++state->seqno;
+
+    /*
+     * Set up to call inflate.
+     */
+    wptr = mo;
+    state->strm.next_in = rptr;
+    state->strm.avail_in = mi + inlen - rptr;
+    rlen = state->strm.avail_in + PPP_HDRLEN + DEFLATE_OVHD;
+    state->strm.next_out = wptr;
+    state->strm.avail_out = state->mru + 2;
+
+    r = inflate(&state->strm, Z_PACKET_FLUSH);
+    if (r != Z_OK) {
+#if !DEFLATE_DEBUG
+	if (state->debug)
+#endif
+	    printf("z_decompress%d: inflate returned %d (%s)\n",
+		   state->unit, r, (state->strm.msg? state->strm.msg: ""));
+	return DECOMP_FATALERROR;
+    }
+    olen = state->mru + 2 - state->strm.avail_out;
+    *outlenp = olen;
+
+    if ((wptr[0] & 1) != 0)
+	++olen;			/* for suppressed protocol high byte */
+    olen += 2;			/* for address, control */
+
+#if DEFLATE_DEBUG
+    if (olen > state->mru + PPP_HDRLEN)
+	printf("ppp_deflate%d: exceeded mru (%d > %d)\n",
+	       state->unit, olen, state->mru + PPP_HDRLEN);
+#endif
+
+    state->stats.unc_bytes += olen;
+    state->stats.unc_packets++;
+    state->stats.comp_bytes += rlen;
+    state->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 & 1) == 0)
+	proto = (proto << 8) + rptr[1];
+    if (proto > 0x3fff || proto == 0xfd || proto == 0xfb)
+	return;
+
+    ++state->seqno;
+
+    if (rptr[0] == 0)
+	++rptr;
+    rlen = mi + mlen - rptr;
+    state->strm.next_in = rptr;
+    state->strm.avail_in = rlen;
+    r = inflateIncomp(&state->strm);
+    if (r != Z_OK) {
+	/* gak! */
+#if !DEFLATE_DEBUG
+	if (state->debug)
+#endif
+	    printf("z_incomp%d: inflateIncomp returned %d (%s)\n",
+		   state->unit, r, (state->strm.msg? state->strm.msg: ""));
+	return;
+    }
+
+    /*
+     * Update stats.
+     */
+    if (proto <= 0xff)
+	++rlen;
+    rlen += 2;
+    state->stats.inc_bytes += rlen;
+    state->stats.inc_packets++;
+    state->stats.unc_bytes += rlen;
+    state->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 "AS IS" 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] << 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) & 0x1F)	/* number of bits requested */
+#define BSD_VERSION(x)		((x) >> 5)	/* version of option format */
+#define BSD_CURRENT_VERSION	1		/* current version number */
+#define BSD_MAKE_OPT(v, n)	(((v) << 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) >> 4) + DEFLATE_MIN_SIZE)
+#define DEFLATE_METHOD(x)	((x) & 0x0F)
+#define DEFLATE_MAKE_OPT(w)	((((w) - DEFLATE_MIN_SIZE) << 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 @@
+.\"	@(#) $Id: pppdump.8 195720 2001-06-11 11:44:34Z gc $
+.TH PPPDUMP 8 "1 April 1999"
+.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 <stdio.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/types.h>
+#include "ppp_defs.h"
+#include "ppp-comp.h"
+
+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, "hprdm:a")) != -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, "Usage: %s [-h | -p[d]] [-r] [-m mru] [-a] [file ...]\n", av[0]);
+	    exit(1);
+	}
+    }
+    if (optind >= ac)
+	dumplog(stdin);
+    else {
+	for (i = optind; i < ac; ++i) {
+	    p = av[i];
+	    if ((f = fopen(p, "r")) == 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("%s %c", c==1? "sent": "rcvd", hexmode? ' ': '"');
+	    col = 6;
+	    n = getc(f);
+	    n = (n << 8) + getc(f);
+	    *(c==1? &tot_sent: &tot_rcvd) += n;
+	    nb = 0;
+	    for (; n > 0; --n) {
+		c = getc(f);
+		if (c == EOF) {
+		    printf("\nEOF\n");
+		    exit(0);
+		}
+		if (hexmode) {
+		    if (nb >= 16) {
+			printf("  ");
+			for (k = 0; k < nb; ++k) {
+			    c2 = buf[k];
+			    putchar((' ' <= c2 && c2 <= '~')? c2: '.');
+			}
+			printf("\n      ");
+			nb = 0;
+		    }
+		    buf[nb++] = c;
+		    printf(" %.2x", c);
+		} else {
+		    k = (' ' <= c && c <= '~')? (c != '\\' && c != '"')? 1: 2: 3;
+		    if ((col += k) >= 78) {
+			printf("\n      ");
+			col = 6 + k;
+		    }
+		    switch (k) {
+		    case 1:
+			putchar(c);
+			break;
+		    case 2:
+			printf("\\%c", c);
+			break;
+		    case 3:
+			printf("\\%.2x", c);
+			break;
+		    }
+		}
+	    }
+	    if (hexmode) {
+		for (k = nb; k < 16; ++k)
+		    printf("   ");
+		printf("  ");
+		for (k = 0; k < nb; ++k) {
+		    c2 = buf[k];
+		    putchar((' ' <= c2 && c2 <= '~')? c2: '.');
+		}
+	    } else
+		putchar('"');
+	    printf("\n");
+	    break;
+	case 3:
+	case 4:
+	    printf("end %s\n", c==3? "send": "recv");
+	    break;
+	case 5:
+	case 6:
+	case 7:
+	    show_time(f, c);
+	    break;
+	default:
+	    printf("?%.2x\n");
+	}
+    }
+}
+
+/*
+ * 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? "sent": "rcvd";
+	    pkt = c==1? &spkt: &rpkt;
+	    n = getc(f);
+	    n = (n << 8) + getc(f);
+	    *(c==1? &tot_sent: &tot_rcvd) += n;
+	    for (; n > 0; --n) {
+		c = getc(f);
+		switch (c) {
+		case EOF:
+		    printf("\nEOF\n");
+		    if (spkt.cnt > 0)
+			printf("[%d bytes in incomplete send packet]\n",
+			       spkt.cnt);
+		    if (rpkt.cnt > 0)
+			printf("[%d bytes in incomplete recv packet]\n",
+			       rpkt.cnt);
+		    exit(0);
+		case '~':
+		    if (pkt->cnt > 0) {
+			q = dir;
+			if (pkt->esc) {
+			    printf("%s aborted packet:\n     ", dir);
+			    q = "    ";
+			}
+			nb = pkt->cnt;
+			p = pkt->buf;
+			pkt->cnt = 0;
+			pkt->esc = 0;
+			if (nb <= 2) {
+			    printf("%s short packet [%d bytes]:", q, nb);
+			    for (k = 0; k < nb; ++k)
+				printf(" %.2x", p[k]);
+			    printf("\n");
+			    break;
+			}
+			fcs = PPP_INITFCS;
+			for (k = 0; k < nb; ++k)
+			    fcs = PPP_FCS(fcs, p[k]);
+			fcs &= 0xFFFF;
+			nb -= 2;
+			endp = p + nb;
+			r = p;
+			if (r[0] == 0xff && r[1] == 3)
+			    r += 2;
+			if ((r[0] & 1) == 0)
+			    ++r;
+			++r;
+			if (endp - r > mru)
+			    printf("     ERROR: length (%d) > MRU (%d)\n",
+				   endp - r, mru);
+			if (decompress && fcs == PPP_GOODFCS) {
+			    /* See if this is a CCP or compressed packet */
+			    d = dbuf;
+			    r = p;
+			    if (r[0] == 0xff && r[1] == 3) {
+				*d++ = *r++;
+				*d++ = *r++;
+			    }
+			    proto = r[0];
+			    if ((proto & 1) == 0)
+				proto = (proto << 8) + r[1];
+			    if (proto == PPP_CCP) {
+				handle_ccp(pkt, r + 2, endp - r - 2);
+			    } else if (proto == PPP_COMP) {
+				if ((pkt->flags & CCP_ISUP)
+				    && (pkt->flags & CCP_DECOMP_RUN)
+				    && pkt->state
+				    && (pkt->flags & CCP_ERR) == 0) {
+				    rv = pkt->comp->decompress(pkt->state, r,
+							endp - r, d, &dn);
+				    switch (rv) {
+				    case DECOMP_OK:
+					p = dbuf;
+					nb = d + dn - p;
+					if ((d[0] & 1) == 0)
+					    --dn;
+					--dn;
+					if (dn > mru)
+					    printf("     ERROR: decompressed length (%d) > MRU (%d)\n", dn, mru);
+					break;
+				    case DECOMP_ERROR:
+					printf("     DECOMPRESSION ERROR\n");
+					pkt->flags |= CCP_ERROR;
+					break;
+				    case DECOMP_FATALERROR:
+					printf("     FATAL DECOMPRESSION ERROR\n");
+					pkt->flags |= CCP_FATALERROR;
+					break;
+				    }
+				}
+			    } else if (pkt->state
+				       && (pkt->flags & CCP_DECOMP_RUN)) {
+				pkt->comp->incomp(pkt->state, r, endp - r);
+			    }
+			}
+			do {
+			    nl = nb < 16? nb: 16;
+			    printf("%s ", q);
+			    for (k = 0; k < nl; ++k)
+				printf(" %.2x", p[k]);
+			    for (; k < 16; ++k)
+				printf("   ");
+			    printf("  ");
+			    for (k = 0; k < nl; ++k) {
+				c = p[k];
+				putchar((' ' <= c && c <= '~')? c: '.');
+			    }
+			    printf("\n");
+			    q = "    ";
+			    p += nl;
+			    nb -= nl;
+			} while (nb > 0);
+			if (fcs != PPP_GOODFCS)
+			    printf("     BAD FCS: (residue = %x)\n", fcs);
+		    }
+		    break;
+		case '}':
+		    if (!pkt->esc) {
+			pkt->esc = 1;
+			break;
+		    }
+		    /* else fall through */
+		default:
+		    if (pkt->esc) {
+			c ^= 0x20;
+			pkt->esc = 0;
+		    }
+		    pkt->buf[pkt->cnt++] = c;
+		    break;
+		}
+	    }
+	    break;
+	case 3:
+	case 4:
+	    if (reverse)
+		c = 7 - c;
+	    dir = c==3? "send": "recv";
+	    pkt = c==3? &spkt: &rpkt;
+	    printf("end %s", dir);
+	    if (pkt->cnt > 0)
+		printf("  [%d bytes in incomplete packet]", pkt->cnt);
+	    printf("\n");
+	    break;
+	case 5:
+	case 6:
+	case 7:
+	    show_time(f, c);
+	    break;
+	default:
+	    printf("?%.2x\n");
+	}
+    }
+}
+
+extern struct compressor ppp_bsd_compress, ppp_deflate;
+
+struct compressor *compressors[] = {
+#if DO_BSD_COMPRESS
+    &ppp_bsd_compress,
+#endif
+#if DO_DEFLATE
+    &ppp_deflate,
+#endif
+    NULL
+};
+
+handle_ccp(cp, dp, len)
+    struct pkt *cp;
+    u_char *dp;
+    int len;
+{
+    int clen;
+    struct compressor **comp;
+
+    if (len < CCP_HDRLEN)
+	return;
+    clen = CCP_LENGTH(dp);
+    if (clen > len)
+	return;
+
+    switch (CCP_CODE(dp)) {
+    case CCP_CONFACK:
+	cp->flags &= ~(CCP_DECOMP_RUN | CCP_ISUP);
+	if (clen < CCP_HDRLEN + CCP_OPT_MINLEN
+	    || clen < CCP_HDRLEN + CCP_OPT_LENGTH(dp + CCP_HDRLEN))
+	    break;
+	dp += CCP_HDRLEN;
+	clen -= CCP_HDRLEN;
+	for (comp = compressors; *comp != NULL; ++comp) {
+	    if ((*comp)->compress_proto == dp[0]) {
+		if (cp->state != NULL) {
+		    (*cp->comp->decomp_free)(cp->state);
+		    cp->state = NULL;
+		}
+		cp->comp = *comp;
+		cp->state = (*comp)->decomp_alloc(dp, CCP_OPT_LENGTH(dp));
+		cp->flags |= CCP_ISUP;
+		if (cp->state != NULL
+		    && (*cp->comp->decomp_init)
+		        (cp->state, dp, clen, 0, 0, 8192, 1))
+		    cp->flags = (cp->flags & ~CCP_ERR) | CCP_DECOMP_RUN;
+		break;
+	    }
+	}
+	break;
+
+    case CCP_CONFNAK:
+    case CCP_CONFREJ:
+	cp->flags &= ~(CCP_DECOMP_RUN | CCP_ISUP);
+	break;
+
+    case CCP_RESETACK:
+	if (cp->flags & CCP_ISUP) {
+	    if (cp->state && (cp->flags & CCP_DECOMP_RUN)) {
+		(*cp->comp->decomp_reset)(cp->state);
+		cp->flags &= ~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 << 8) + getc(f);
+	t = (t << 8) + getc(f);
+	t = (t << 8) + getc(f);
+	printf("start %s", ctime(&t));
+	start_time = t;
+	start_time_tenths = 0;
+	tot_sent = tot_rcvd = 0;
+    } else {
+	n = getc(f);
+	if (c == 5) {
+	    for (c = 3; c > 0; --c)
+		n = (n << 8) + getc(f);
+	}
+	if (abs_times) {
+	    n += start_time_tenths;
+	    start_time += n / 10;
+	    start_time_tenths = n % 10;
+	    tm = localtime(&start_time);
+	    printf("time  %.2d:%.2d:%.2d.%d", tm->tm_hour, tm->tm_min,
+		   tm->tm_sec, start_time_tenths);
+	    printf("  (sent %d, rcvd %d)\n", tot_sent, tot_rcvd);
+	} else
+	    printf("time  %.1fs\n", (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 "local"
+ * - 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 "zlib.h"
+
+#ifdef STDC
+#  include <string.h>
+#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->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 >= 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) && !defined(HAVE_MEMCPY) && !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 <stdio.h>
+#  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>1) fprintf x ;}
+#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (verbose>1 && (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)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr, size)	\
+	   (*((strm)->zfree))((strm)->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 >= 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 >= 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 <= 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->pending_buf[s->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)->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 "deflation" 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 & 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&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.,"'Deflate' Compressed Data Format Specification".
+ *      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
+ *         "Algorithms" 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[] = " deflate Copyright 1995 Jean-loup Gailly ";
+/*
+  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 >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 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)<<s->hash_shift) ^ (c)) & s->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->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+    s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \
+    s->head[s->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->head[s->hash_size-1] = NIL; \
+    zmemzero((charf *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->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->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->msg = Z_NULL;
+/*    if (strm->zalloc == Z_NULL) strm->zalloc = zcalloc; */
+/*    if (strm->zfree == Z_NULL) strm->zfree = zcfree; */
+
+    if (level == Z_DEFAULT_COMPRESSION) level = 6;
+
+    if (windowBits < 0) { /* undocumented feature: suppress zlib header */
+        noheader = 1;
+        windowBits = -windowBits;
+    }
+    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != DEFLATED ||
+        windowBits < 8 || windowBits > 15 || level < 1 || level > 9) {
+        return Z_STREAM_ERROR;
+    }
+    s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+    if (s == Z_NULL) return Z_MEM_ERROR;
+    strm->state = (struct internal_state FAR *)s;
+    s->strm = strm;
+
+    s->noheader = noheader;
+    s->w_bits = windowBits;
+    s->w_size = 1 << s->w_bits;
+    s->w_mask = s->w_size - 1;
+
+    s->hash_bits = memLevel + 7;
+    s->hash_size = 1 << s->hash_bits;
+    s->hash_mask = s->hash_size - 1;
+    s->hash_shift =  ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+    s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+    s->prev   = (Posf *)  ZALLOC(strm, s->w_size, sizeof(Pos));
+    s->head   = (Posf *)  ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+    s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+    s->pending_buf = (uchf *) ZALLOC(strm, s->lit_bufsize, 2*sizeof(ush));
+
+    if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+        s->pending_buf == Z_NULL) {
+        strm->msg = z_errmsg[1-Z_MEM_ERROR];
+        deflateEnd (strm);
+        return Z_MEM_ERROR;
+    }
+    s->d_buf = (ushf *) &(s->pending_buf[s->lit_bufsize]);
+    s->l_buf = (uchf *) &(s->pending_buf[3*s->lit_bufsize]);
+    /* We overlay pending_buf and d_buf+l_buf. This works since the average
+     * output size for (length,distance) codes is <= 32 bits (worst case
+     * is 15+15+13=33).
+     */
+
+    s->level = level;
+    s->strategy = strategy;
+    s->method = (Byte)method;
+    s->minCompr = minCompression;
+    s->blocks_in_packet = 0;
+
+    return deflateReset(strm);
+}
+
+/* ========================================================================= */
+int deflateReset (strm)
+    z_stream *strm;
+{
+    deflate_state *s;
+    
+    if (strm == Z_NULL || strm->state == Z_NULL ||
+        strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR;
+
+    strm->total_in = strm->total_out = 0;
+    strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+    strm->data_type = Z_UNKNOWN;
+
+    s = (deflate_state *)strm->state;
+    s->pending = 0;
+    s->pending_out = s->pending_buf;
+
+    if (s->noheader < 0) {
+        s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */
+    }
+    s->status = s->noheader ? BUSY_STATE : INIT_STATE;
+    s->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 >> 8));
+    put_byte(s, (Byte)(b & 0xff));
+}   
+
+/* =========================================================================
+ * Flush as much pending output as possible.
+ */
+local void flush_pending(strm)
+    z_stream *strm;
+{
+    deflate_state *state = (deflate_state *) strm->state;
+    unsigned len = state->pending;
+
+    if (len > strm->avail_out) len = strm->avail_out;
+    if (len == 0) return;
+
+    if (strm->next_out != NULL) {
+	zmemcpy(strm->next_out, state->pending_out, len);
+	strm->next_out += len;
+    }
+    state->pending_out += len;
+    strm->total_out += len;
+    strm->avail_out -= len;
+    state->pending -= len;
+    if (state->pending == 0) {
+        state->pending_out = state->pending_buf;
+    }
+}
+
+/* ========================================================================= */
+int deflate (strm, flush)
+    z_stream *strm;
+    int flush;
+{
+    deflate_state *state = (deflate_state *) strm->state;
+
+    if (strm == Z_NULL || state == Z_NULL) return Z_STREAM_ERROR;
+    
+    if (strm->next_in == Z_NULL && strm->avail_in != 0) {
+        ERR_RETURN(strm, Z_STREAM_ERROR);
+    }
+    if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+    state->strm = strm; /* just in case */
+
+    /* Write the zlib header */
+    if (state->status == INIT_STATE) {
+
+        uInt header = (DEFLATED + ((state->w_bits-8)<<4)) << 8;
+        uInt level_flags = (state->level-1) >> 1;
+
+        if (level_flags > 3) level_flags = 3;
+        header |= (level_flags << 6);
+        header += 31 - (header % 31);
+
+        state->status = BUSY_STATE;
+        putShortMSB(state, header);
+    }
+
+    /* Flush as much pending output as possible */
+    if (state->pending != 0) {
+        flush_pending(strm);
+        if (strm->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->status == FLUSH_STATE) {
+	state->status = BUSY_STATE;
+	if (flush != Z_NO_FLUSH && flush != Z_FINISH)
+	    return Z_OK;
+    }
+
+    /* User must not provide more input after the first FINISH: */
+    if (state->status == FINISH_STATE && strm->avail_in != 0) {
+        ERR_RETURN(strm, Z_BUF_ERROR);
+    }
+
+    /* Start a new block or continue the current one.
+     */
+    if (strm->avail_in != 0 || state->lookahead != 0 ||
+        (flush == Z_FINISH && state->status != FINISH_STATE)) {
+        int quit;
+
+        if (flush == Z_FINISH) {
+            state->status = FINISH_STATE;
+        }
+        if (state->level <= 3) {
+            quit = deflate_fast(state, flush);
+        } else {
+            quit = deflate_slow(state, flush);
+        }
+        if (quit || strm->avail_out == 0)
+	    return Z_OK;
+        /* If flush != Z_NO_FLUSH && 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 && flush != Z_FINISH
+	&& state->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->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->status = FLUSH_STATE;
+	    return Z_OK;
+	}
+    }
+
+    Assert(strm->avail_out > 0, "bug2");
+
+    if (flush != Z_FINISH) return Z_OK;
+    if (state->noheader) return Z_STREAM_END;
+
+    /* Write the zlib trailer (adler32) */
+    putShortMSB(state, (uInt)(state->adler >> 16));
+    putShortMSB(state, (uInt)(state->adler & 0xffff));
+    flush_pending(strm);
+    /* If avail_out is zero, the application will call deflate again
+     * to flush the rest.
+     */
+    state->noheader = -1; /* write the trailer only once! */
+    return state->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int deflateEnd (strm)
+    z_stream *strm;
+{
+    deflate_state *state = (deflate_state *) strm->state;
+
+    if (strm == Z_NULL || state == Z_NULL) return Z_STREAM_ERROR;
+
+    TRY_FREE(strm, state->window, state->w_size * 2 * sizeof(Byte));
+    TRY_FREE(strm, state->prev, state->w_size * sizeof(Pos));
+    TRY_FREE(strm, state->head, state->hash_size * sizeof(Pos));
+    TRY_FREE(strm, state->pending_buf, state->lit_bufsize * 2 * sizeof(ush));
+
+    ZFREE(strm, state, sizeof(deflate_state));
+    strm->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->avail_in;
+    deflate_state *state = (deflate_state *) strm->state;
+
+    if (len > size) len = size;
+    if (len == 0) return 0;
+
+    strm->avail_in  -= len;
+
+    if (!state->noheader) {
+        state->adler = adler32(state->adler, strm->next_in, len);
+    }
+    zmemcpy(buf, strm->next_in, len);
+    strm->next_in  += len;
+    strm->total_in += len;
+
+    return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+    deflate_state *s;
+{
+    s->window_size = (ulg)2L*s->w_size;
+
+    CLEAR_HASH(s);
+
+    /* Set the default configuration parameters:
+     */
+    s->max_lazy_match   = configuration_table[s->level].max_lazy;
+    s->good_match       = configuration_table[s->level].good_length;
+    s->nice_match       = configuration_table[s->level].nice_length;
+    s->max_chain_length = configuration_table[s->level].max_chain;
+
+    s->strstart = 0;
+    s->block_start = 0L;
+    s->lookahead = 0;
+    s->match_length = MIN_MATCH-1;
+    s->match_available = 0;
+    s->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 <= MAX_DIST, and prev_length >= 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->max_chain_length;/* max hash chain length */
+    register Bytef *scan = s->window + s->strstart; /* current string */
+    register Bytef *match;                       /* matched string */
+    register int len;                           /* length of current match */
+    int best_len = s->prev_length;              /* best match length so far */
+    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+        s->strstart - (IPos)MAX_DIST(s) : NIL;
+    /* Stop when cur_match becomes <= limit. To simplify the code,
+     * we prevent matches with the string of window index 0.
+     */
+    Posf *prev = s->prev;
+    uInt wmask = s->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->window + s->strstart + MAX_MATCH - 1;
+    register ush scan_start = *(ushf*)scan;
+    register ush scan_end   = *(ushf*)(scan+best_len-1);
+#else
+    register Bytef *strend = s->window + s->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 >= 8 and MAX_MATCH-2 multiple of 16.
+     * It is easy to get rid of this optimization if necessary.
+     */
+    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+    /* Do not waste too much time if we already have a good match: */
+    if (s->prev_length >= s->good_match) {
+        chain_length >>= 2;
+    }
+    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+    do {
+        Assert(cur_match < s->strstart, "no future");
+        match = s->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) && 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 >= 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], "scan[2]?");
+        scan++, match++;
+        do {
+        } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 scan < strend);
+        /* The funny "do {}" generates better code on most compilers */
+
+        /* Here, scan <= window+strstart+257 */
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+        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 >= 8.
+         */
+        scan += 2, match++;
+        Assert(*scan == *match, "match[2]?");
+
+        /* We check for insufficient lookahead only every 8th comparison;
+         * the 256th check will be made at strstart+258.
+         */
+        do {
+        } while (*++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 scan < strend);
+
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+        len = MAX_MATCH - (int)(strend - scan);
+        scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+        if (len > best_len) {
+            s->match_start = cur_match;
+            best_len = len;
+            if (len >= s->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 & wmask]) > limit
+             && --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->window + match,
+                (charf *)s->window + start, length) != EQUAL) {
+        fprintf(stderr,
+            " start %u, match %u, length %d\n",
+            start, match, length);
+        do { fprintf(stderr, "%c%c", s->window[match++],
+                     s->window[start++]); } while (--length != 0);
+        z_error("invalid match");
+    }
+    if (verbose > 1) {
+        fprintf(stderr,"\\[%d,%d]", start-match, length);
+        do { putc(s->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 < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= 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->w_size;
+
+    do {
+        more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+        /* Deal with !@#$% 64K limit: */
+        if (more == 0 && s->strstart == 0 && s->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->strstart >= 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->window, (charf *)s->window+wsize,
+                   (unsigned)wsize);
+            s->match_start -= wsize;
+            s->strstart    -= wsize; /* we now have strstart >= MAX_DIST */
+
+            s->block_start -= (long) wsize;
+
+            /* Slide the hash table (could be avoided with 32 bit values
+               at the expense of memory usage):
+             */
+            n = s->hash_size;
+            p = &s->head[n];
+            do {
+                m = *--p;
+                *p = (Pos)(m >= wsize ? m-wsize : NIL);
+            } while (--n);
+
+            n = wsize;
+            p = &s->prev[n];
+            do {
+                m = *--p;
+                *p = (Pos)(m >= 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->strm->avail_in == 0) return;
+
+        /* If there was no sliding:
+         *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+         *    more == window_size - lookahead - strstart
+         * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+         * => more >= window_size - 2*WSIZE + 2
+         * In the BIG_MEM or MMAP case (not yet supported),
+         *   window_size == input_size + MIN_LOOKAHEAD  &&
+         *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+         * Otherwise, window_size == 2*WSIZE so more >= 2.
+         * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+         */
+        Assert(more >= 2, "more < 2");
+
+        n = read_buf(s->strm, (charf *)s->window + s->strstart + s->lookahead,
+                     more);
+        s->lookahead += n;
+
+        /* Initialize the hash value now that we have some input: */
+        if (s->lookahead >= MIN_MATCH) {
+            s->ins_h = s->window[s->strstart];
+            UPDATE_HASH(s, s->ins_h, s->window[s->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->lookahead < MIN_LOOKAHEAD && s->strm->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->block_start >= 0L ? \
+           (charf *)&s->window[(unsigned)s->block_start] : \
+           (charf *)Z_NULL), (long)s->strstart - s->block_start, (flush)); \
+   s->block_start = s->strstart; \
+   flush_pending(s->strm); \
+   Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, flush) { \
+   FLUSH_BLOCK_ONLY(s, flush); \
+   if (s->strm->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->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->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) return 1;
+
+            if (s->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->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         * At this point we have always match_length < MIN_MATCH
+         */
+        if (hash_head != NIL && s->strstart - hash_head <= 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->strategy != Z_HUFFMAN_ONLY) {
+                s->match_length = longest_match (s, hash_head);
+            }
+            /* longest_match() sets match_start */
+
+            if (s->match_length > s->lookahead) s->match_length = s->lookahead;
+        }
+        if (s->match_length >= MIN_MATCH) {
+            check_match(s, s->strstart, s->match_start, s->match_length);
+
+            bflush = ct_tally(s, s->strstart - s->match_start,
+                              s->match_length - MIN_MATCH);
+
+            s->lookahead -= s->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->match_length <= s->max_insert_length &&
+                s->lookahead >= MIN_MATCH) {
+                s->match_length--; /* string at strstart already in hash table */
+                do {
+                    s->strstart++;
+                    INSERT_STRING(s, s->strstart, hash_head);
+                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+                     * always MIN_MATCH bytes ahead.
+                     */
+                } while (--s->match_length != 0);
+                s->strstart++; 
+            } else {
+                s->strstart += s->match_length;
+                s->match_length = 0;
+                s->ins_h = s->window[s->strstart];
+                UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+                Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+                /* If lookahead < 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,"%c", s->window[s->strstart]));
+            bflush = ct_tally (s, 0, s->window[s->strstart]);
+            s->lookahead--;
+            s->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->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) return 1;
+
+            if (s->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->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         */
+        s->prev_length = s->match_length, s->prev_match = s->match_start;
+        s->match_length = MIN_MATCH-1;
+
+        if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+            s->strstart - hash_head <= 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->strategy != Z_HUFFMAN_ONLY) {
+                s->match_length = longest_match (s, hash_head);
+            }
+            /* longest_match() sets match_start */
+            if (s->match_length > s->lookahead) s->match_length = s->lookahead;
+
+            if (s->match_length <= 5 && (s->strategy == Z_FILTERED ||
+                 (s->match_length == MIN_MATCH &&
+                  s->strstart - s->match_start > TOO_FAR))) {
+
+                /* If prev_match is also MIN_MATCH, match_start is garbage
+                 * but we will ignore the current match anyway.
+                 */
+                s->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->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+            uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+            /* Do not insert strings in hash table beyond this. */
+
+            check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+            bflush = ct_tally(s, s->strstart -1 - s->prev_match,
+                              s->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->lookahead -= s->prev_length-1;
+            s->prev_length -= 2;
+            do {
+                if (++s->strstart <= max_insert) {
+                    INSERT_STRING(s, s->strstart, hash_head);
+                }
+            } while (--s->prev_length != 0);
+            s->match_available = 0;
+            s->match_length = MIN_MATCH-1;
+            s->strstart++;
+
+            if (bflush) FLUSH_BLOCK(s, Z_NO_FLUSH);
+
+        } else if (s->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,"%c", s->window[s->strstart-1]));
+            if (ct_tally (s, 0, s->window[s->strstart-1])) {
+                FLUSH_BLOCK_ONLY(s, Z_NO_FLUSH);
+            }
+            s->strstart++;
+            s->lookahead--;
+            if (s->strm->avail_out == 0) return 1;
+        } else {
+            /* There is no previous match to compare with, wait for
+             * the next step to decide.
+             */
+            s->match_available = 1;
+            s->strstart++;
+            s->lookahead--;
+        }
+    }
+    Assert (flush != Z_NO_FLUSH, "no flush?");
+    if (s->match_available) {
+        Tracevv((stderr,"%c", s->window[s->strstart-1]));
+        ct_tally (s, 0, s->window[s->strstart-1]);
+        s->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 "deflation" 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.,"'Deflate' Compressed Data Format Specification".
+ *      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 <ctype.h>
+#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>1) fprintf(stderr,"\ncd %3d ",(c)); \
+       send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+#define d_code(dist) \
+   ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>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) & 0xff)); \
+    put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 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," l %2d v %4x ", length, value));
+    Assert(length > 0 && length <= 15, "invalid length");
+    s->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->bi_valid > (int)Buf_size - length) {
+        s->bi_buf |= (value << s->bi_valid);
+        put_short(s, s->bi_buf);
+        s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+        s->bi_valid += length - Buf_size;
+    } else {
+        s->bi_buf |= value << s->bi_valid;
+        s->bi_valid += length;
+    }
+}
+#else /* !DEBUG_ZLIB */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+  if (s->bi_valid > (int)Buf_size - len) {\
+    int val = value;\
+    s->bi_buf |= (val << s->bi_valid);\
+    put_short(s, s->bi_buf);\
+    s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+    s->bi_valid += len - Buf_size;\
+  } else {\
+    s->bi_buf |= (value) << s->bi_valid;\
+    s->bi_valid += len;\
+  }\
+}
+#endif /* DEBUG_ZLIB */
+
+
+#define MAX(a,b) (a >= 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) -> length code (0..28) */
+    length = 0;
+    for (code = 0; code < LENGTH_CODES-1; code++) {
+        base_length[code] = length;
+        for (n = 0; n < (1<<extra_lbits[code]); n++) {
+            length_code[length++] = (uch)code;
+        }
+    }
+    Assert (length == 256, "ct_static_init: length != 256");
+    /* 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) -> dist code (0..29) */
+    dist = 0;
+    for (code = 0 ; code < 16; code++) {
+        base_dist[code] = dist;
+        for (n = 0; n < (1<<extra_dbits[code]); n++) {
+            dist_code[dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "ct_static_init: dist != 256");
+    dist >>= 7; /* from now on, all distances are divided by 128 */
+    for ( ; code < D_CODES; code++) {
+        base_dist[code] = dist << 7;
+        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+            dist_code[256 + dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "ct_static_init: 256+dist != 512");
+
+    /* Construct the codes of the static literal tree */
+    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+    n = 0;
+    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+    while (n <= 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 < 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->compressed_len = 0L;
+
+    s->l_desc.dyn_tree = s->dyn_ltree;
+    s->l_desc.stat_desc = &static_l_desc;
+
+    s->d_desc.dyn_tree = s->dyn_dtree;
+    s->d_desc.stat_desc = &static_d_desc;
+
+    s->bl_desc.dyn_tree = s->bl_tree;
+    s->bl_desc.stat_desc = &static_bl_desc;
+
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+    s->last_eob_len = 8; /* enough lookahead for inflate */
+#ifdef DEBUG_ZLIB
+    s->bits_sent = 0L;
+#endif
+    s->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 < L_CODES;  n++) s->dyn_ltree[n].Freq = 0;
+    for (n = 0; n < D_CODES;  n++) s->dyn_dtree[n].Freq = 0;
+    for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+    s->dyn_ltree[END_BLOCK].Freq = 1;
+    s->opt_len = s->static_len = 0L;
+    s->last_lit = s->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->heap[SMALLEST]; \
+    s->heap[SMALLEST] = s->heap[s->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 < tree[m].Freq || \
+   (tree[n].Freq == tree[m].Freq && depth[n] <= 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->heap[k];
+    int j = k << 1;  /* left son of k */
+    while (j <= s->heap_len) {
+        /* Set j to the smallest of the two sons: */
+        if (j < s->heap_len &&
+            smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+            j++;
+        }
+        /* Exit if v is smaller than both sons */
+        if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+        /* Exchange v with the smallest son */
+        s->heap[k] = s->heap[j];  k = j;
+
+        /* And continue down the tree, setting j to the left son of k */
+        j <<= 1;
+    }
+    s->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->dyn_tree;
+    int max_code   = desc->max_code;
+    ct_data *stree = desc->stat_desc->static_tree;
+    intf *extra    = desc->stat_desc->extra_bits;
+    int base       = desc->stat_desc->extra_base;
+    int max_length = desc->stat_desc->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 <= MAX_BITS; bits++) s->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->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+    for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+        n = s->heap[h];
+        bits = tree[tree[n].Dad].Len + 1;
+        if (bits > max_length) bits = max_length, overflow++;
+        tree[n].Len = (ush)bits;
+        /* We overwrite tree[n].Dad which is no longer needed */
+
+        if (n > max_code) continue; /* not a leaf node */
+
+        s->bl_count[bits]++;
+        xbits = 0;
+        if (n >= base) xbits = extra[n-base];
+        f = tree[n].Freq;
+        s->opt_len += (ulg)f * (bits + xbits);
+        if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+    }
+    if (overflow == 0) return;
+
+    Trace((stderr,"\nbit length overflow\n"));
+    /* 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->bl_count[bits] == 0) bits--;
+        s->bl_count[bits]--;      /* move one leaf down the tree */
+        s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+        s->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 > 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->bl_count[bits];
+        while (n != 0) {
+            m = s->heap[--h];
+            if (m > max_code) continue;
+            if (tree[m].Len != (unsigned) bits) {
+                Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+                s->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 <= MAX_BITS; bits++) {
+        next_code[bits] = code = (code + bl_count[bits-1]) << 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<<MAX_BITS)-1,
+            "inconsistent bit counts");
+    Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+    for (n = 0;  n <= 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,"\nn %3d %c l %2d c %4x (%x) ",
+             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->dyn_tree;
+    ct_data *stree  = desc->stat_desc->static_tree;
+    int elems       = desc->stat_desc->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->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+    for (n = 0; n < elems; n++) {
+        if (tree[n].Freq != 0) {
+            s->heap[++(s->heap_len)] = max_code = n;
+            s->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->heap_len < 2) {
+        node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+        tree[node].Freq = 1;
+        s->depth[node] = 0;
+        s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+        /* node is 0 or 1 so it does not have extra bits */
+    }
+    desc->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->heap_len/2; n >= 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->heap[SMALLEST]; /* m = node of next least frequency */
+
+        s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+        s->heap[--(s->heap_max)] = m;
+
+        /* Create a new node father of n and m */
+        tree[node].Freq = tree[n].Freq + tree[m].Freq;
+        s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1);
+        tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+        if (tree == s->bl_tree) {
+            fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+        }
+#endif
+        /* and insert the new node in the heap */
+        s->heap[SMALLEST] = node++;
+        pqdownheap(s, tree, SMALLEST);
+
+    } while (s->heap_len >= 2);
+
+    s->heap[--(s->heap_max)] = s->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->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 <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            s->bl_tree[curlen].Freq += count;
+        } else if (curlen != 0) {
+            if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+            s->bl_tree[REP_3_6].Freq++;
+        } else if (count <= 10) {
+            s->bl_tree[REPZ_3_10].Freq++;
+        } else {
+            s->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 <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+        } else if (curlen != 0) {
+            if (curlen != prevlen) {
+                send_code(s, curlen, s->bl_tree); count--;
+            }
+            Assert(count >= 3 && count <= 6, " 3_6?");
+            send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+        } else if (count <= 10) {
+            send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+        } else {
+            send_code(s, REPZ_11_138, s->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->dyn_ltree, s->l_desc.max_code);
+    scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+    /* Build the bit length tree: */
+    build_tree(s, (tree_desc *)(&(s->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 >= 3; max_blindex--) {
+        if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+    }
+    /* Update opt_len to include the bit length tree and counts */
+    s->opt_len += 3*(max_blindex+1) + 5+5+4;
+    Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+            s->opt_len, s->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 >= 257, dcodes >= 1, blcodes >= 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 >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+    Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+            "too many codes");
+    Tracev((stderr, "\nbl counts: "));
+    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 < blcodes; rank++) {
+        Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+        send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+    }
+    Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+    Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+    Tracev((stderr, "\ndist tree: sent %ld", s->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<<1)+eof, 3);  /* send block type */
+    s->compressed_len = (s->compressed_len + 3 + 7) & ~7L;
+    s->compressed_len += (stored_len + 4) << 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 << 1), 3);
+    bi_windup(s);
+    s->compressed_len = (s->compressed_len + 3) & ~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<<1, 3);
+    send_code(s, END_BLOCK, static_ltree);
+    s->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->last_eob_len + 10 - s->bi_valid < 9) {
+        send_bits(s, STATIC_TREES<<1, 3);
+        send_code(s, END_BLOCK, static_ltree);
+        s->compressed_len += 10L;
+        bi_flush(s);
+    }
+    s->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->blocks_in_packet;
+
+    /* Check if the file is ascii or binary */
+    if (s->data_type == UNKNOWN) set_data_type(s);
+
+    /* Construct the literal and distance trees */
+    build_tree(s, (tree_desc *)(&(s->l_desc)));
+    Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+            s->static_len));
+
+    build_tree(s, (tree_desc *)(&(s->d_desc)));
+    Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+            s->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->opt_len+3+7)>>3;
+    static_lenb = (s->static_len+3+7)>>3;
+
+    Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+            opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+            s->last_lit));
+
+    if (static_lenb <= 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 && compressed_len == 0L) /* force stored file */
+#  else
+    if (stored_len <= opt_lenb && eof && s->compressed_len==0L && seekable())
+#  endif
+    {
+        /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
+        if (buf == (charf*)0) error ("block vanished");
+
+        copy_block(buf, (unsigned)stored_len, 0); /* without header */
+        s->compressed_len = stored_len << 3;
+        s->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 && s->blocks_in_packet == 1
+	&& opt_lenb > stored_len - s->minCompr) {
+	s->blocks_in_packet = 0;
+	/* output nothing */
+    } else
+
+#ifdef FORCE_STORED
+    if (buf != (char*)0) /* force stored block */
+#else
+    if (stored_len+4 <= opt_lenb && buf != (char*)0)
+                       /* 4: two words for the lengths */
+#endif
+    {
+        /* The test buf != NULL is only necessary if LIT_BUFSIZE > 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 <= 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 >= 0) /* force static trees */
+#else
+    if (static_lenb == opt_lenb)
+#endif
+    {
+        send_bits(s, (STATIC_TREES<<1)+eof, 3);
+        compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
+        s->compressed_len += 3 + s->static_len;
+    } else {
+        send_bits(s, (DYN_TREES<<1)+eof, 3);
+        send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+                       max_blindex+1);
+        compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
+        s->compressed_len += 3 + s->opt_len;
+    }
+    Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+    init_block(s);
+
+    if (eof) {
+        bi_windup(s);
+        s->compressed_len += 7;  /* align on byte boundary */
+    }
+    Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+           s->compressed_len-7*eof));
+
+    return s->compressed_len >> 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->d_buf[s->last_lit] = (ush)dist;
+    s->l_buf[s->last_lit++] = (uch)lc;
+    if (dist == 0) {
+        /* lc is the unmatched char */
+        s->dyn_ltree[lc].Freq++;
+    } else {
+        s->matches++;
+        /* Here, lc is the match length - MIN_MATCH */
+        dist--;             /* dist = match distance - 1 */
+        Assert((ush)dist < (ush)MAX_DIST(s) &&
+               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+               (ush)d_code(dist) < (ush)D_CODES,  "ct_tally: bad match");
+
+        s->dyn_ltree[length_code[lc]+LITERALS+1].Freq++;
+        s->dyn_dtree[d_code(dist)].Freq++;
+    }
+
+    /* Try to guess if it is profitable to stop the current block here */
+    if (s->level > 2 && (s->last_lit & 0xfff) == 0) {
+        /* Compute an upper bound for the compressed length */
+        ulg out_length = (ulg)s->last_lit*8L;
+        ulg in_length = (ulg)s->strstart - s->block_start;
+        int dcode;
+        for (dcode = 0; dcode < D_CODES; dcode++) {
+            out_length += (ulg)s->dyn_dtree[dcode].Freq *
+                (5L+extra_dbits[dcode]);
+        }
+        out_length >>= 3;
+        Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+               s->last_lit, in_length, out_length,
+               100L - out_length*100L/in_length));
+        if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+    }
+    return (s->last_lit == s->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->last_lit != 0) do {
+        dist = s->d_buf[lx];
+        lc = s->l_buf[lx++];
+        if (dist == 0) {
+            send_code(s, lc, ltree); /* send a literal byte */
+            Tracecv(isgraph(lc), (stderr," '%c' ", 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 < D_CODES, "bad d_code");
+
+            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->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow");
+
+    } while (lx < s->last_lit);
+
+    send_code(s, END_BLOCK, ltree);
+    s->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 <= 6 or >= 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 < 7)        bin_freq += s->dyn_ltree[n++].Freq;
+    while (n < 128)    ascii_freq += s->dyn_ltree[n++].Freq;
+    while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq;
+    s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? BINARY : ASCII);
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 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 & 1;
+        code >>= 1, res <<= 1;
+    } while (--len > 0);
+    return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+    deflate_state *s;
+{
+    if (s->bi_valid == 16) {
+        put_short(s, s->bi_buf);
+        s->bi_buf = 0;
+        s->bi_valid = 0;
+    } else if (s->bi_valid >= 8) {
+        put_byte(s, (Byte)s->bi_buf);
+        s->bi_buf >>= 8;
+        s->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->bi_valid > 8) {
+        put_short(s, s->bi_buf);
+    } else if (s->bi_valid > 0) {
+        put_byte(s, (Byte)s->bi_buf);
+    }
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+#ifdef DEBUG_ZLIB
+    s->bits_sent = (s->bits_sent+7) & ~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->last_eob_len = 8; /* enough lookahead for inflate */
+
+    if (header) {
+        put_short(s, (ush)len);   
+        put_short(s, (ush)~len);
+#ifdef DEBUG_ZLIB
+        s->bits_sent += 2*16;
+#endif
+    }
+#ifdef DEBUG_ZLIB
+    s->bits_sent += (ulg)len<<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->state == Z_NULL)
+    return Z_STREAM_ERROR;
+  z->total_in = z->total_out = 0;
+  z->msg = Z_NULL;
+  z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
+  inflate_blocks_reset(z->state->blocks, z, &c);
+  Trace((stderr, "inflate: reset\n"));
+  return Z_OK;
+}
+
+
+int inflateEnd(z)
+z_stream *z;
+{
+  uLong c;
+
+  if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
+    return Z_STREAM_ERROR;
+  if (z->state->blocks != Z_NULL)
+    inflate_blocks_free(z->state->blocks, z, &c);
+  ZFREE(z, z->state, sizeof(struct internal_state));
+  z->state = Z_NULL;
+  Trace((stderr, "inflate: end\n"));
+  return Z_OK;
+}
+
+
+int inflateInit2(z, w)
+z_stream *z;
+int w;
+{
+  /* initialize state */
+  if (z == Z_NULL)
+    return Z_STREAM_ERROR;
+/*  if (z->zalloc == Z_NULL) z->zalloc = zcalloc; */
+/*  if (z->zfree == Z_NULL) z->zfree = zcfree; */
+  if ((z->state = (struct internal_state FAR *)
+       ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
+    return Z_MEM_ERROR;
+  z->state->blocks = Z_NULL;
+
+  /* handle undocumented nowrap option (no zlib header or check) */
+  z->state->nowrap = 0;
+  if (w < 0)
+  {
+    w = - w;
+    z->state->nowrap = 1;
+  }
+
+  /* set window size */
+  if (w < 8 || w > 15)
+  {
+    inflateEnd(z);
+    return Z_STREAM_ERROR;
+  }
+  z->state->wbits = (uInt)w;
+
+  /* create inflate_blocks state */
+  if ((z->state->blocks =
+       inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, 1 << w))
+      == Z_NULL)
+  {
+    inflateEnd(z);
+    return Z_MEM_ERROR;
+  }
+  Trace((stderr, "inflate: allocated\n"));
+
+  /* reset state */
+  inflateReset(z);
+  return Z_OK;
+}
+
+
+int inflateInit(z)
+z_stream *z;
+{
+  return inflateInit2(z, DEF_WBITS);
+}
+
+
+#define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;}
+#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
+
+int inflate(z, f)
+z_stream *z;
+int f;
+{
+  int r;
+  uInt b;
+
+  if (z == Z_NULL || z->next_in == Z_NULL)
+    return Z_STREAM_ERROR;
+  r = Z_BUF_ERROR;
+  while (1) switch (z->state->mode)
+  {
+    case METHOD:
+      NEEDBYTE
+      if (((z->state->sub.method = NEXTBYTE) & 0xf) != DEFLATED)
+      {
+        z->state->mode = BAD;
+        z->msg = "unknown compression method";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
+      {
+        z->state->mode = BAD;
+        z->msg = "invalid window size";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      z->state->mode = FLAG;
+    case FLAG:
+      NEEDBYTE
+      if ((b = NEXTBYTE) & 0x20)
+      {
+        z->state->mode = BAD;
+        z->msg = "invalid reserved bit";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      if (((z->state->sub.method << 8) + b) % 31)
+      {
+        z->state->mode = BAD;
+        z->msg = "incorrect header check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      Trace((stderr, "inflate: zlib header ok\n"));
+      z->state->mode = BLOCKS;
+    case BLOCKS:
+      r = inflate_blocks(z->state->blocks, z, r);
+      if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0)
+	  r = inflate_packet_flush(z->state->blocks);
+      if (r == Z_DATA_ERROR)
+      {
+        z->state->mode = BAD;
+        z->state->sub.marker = 0;       /* can try inflateSync */
+        break;
+      }
+      if (r != Z_STREAM_END)
+        return r;
+      r = Z_OK;
+      inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
+      if (z->state->nowrap)
+      {
+        z->state->mode = DONE;
+        break;
+      }
+      z->state->mode = CHECK4;
+    case CHECK4:
+      NEEDBYTE
+      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+      z->state->mode = CHECK3;
+    case CHECK3:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+      z->state->mode = CHECK2;
+    case CHECK2:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+      z->state->mode = CHECK1;
+    case CHECK1:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE;
+
+      if (z->state->sub.check.was != z->state->sub.check.need)
+      {
+        z->state->mode = BAD;
+        z->msg = "incorrect data check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      Trace((stderr, "inflate: zlib check ok\n"));
+      z->state->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->state->mode = BAD;
+  z->state->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 "caught up";
+ * i.e. no pending output (hence s->read equals s->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->state->mode != BLOCKS)
+	return Z_DATA_ERROR;
+    return inflate_addhistory(z->state->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->state == Z_NULL)
+    return Z_STREAM_ERROR;
+  if (z->state->mode != BAD)
+  {
+    z->state->mode = BAD;
+    z->state->sub.marker = 0;
+  }
+  if ((n = z->avail_in) == 0)
+    return Z_BUF_ERROR;
+  p = z->next_in;
+  m = z->state->sub.marker;
+
+  /* search */
+  while (n && m < 4)
+  {
+    if (*p == (Byte)(m < 2 ? 0 : 0xff))
+      m++;
+    else if (*p)
+      m = 0;
+    else
+      m = 4 - m;
+    p++, n--;
+  }
+
+  /* restore */
+  z->total_in += p - z->next_in;
+  z->next_in = p;
+  z->avail_in = n;
+  z->state->sub.marker = m;
+
+  /* return no joy or set up to restart on a new block */
+  if (m != 4)
+    return Z_DATA_ERROR;
+  r = z->total_in;  w = z->total_out;
+  inflateReset(z);
+  z->total_in = r;  z->total_out = w;
+  z->state->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->bitb=b;s->bitk=k;}
+#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
+#define UPDOUT {s->write=q;}
+#define UPDATE {UPDBITS UPDIN UPDOUT}
+#define LEAVE {UPDATE return inflate_flush(s,z,r);}
+/*   get bytes and bits */
+#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
+#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
+#define NEXTBYTE (n--,*p++)
+#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define DUMPBITS(j) {b>>=(j);k-=(j);}
+/*   output bytes */
+#define WAVAIL (q<s->read?s->read-q-1:s->end-q)
+#define LOADOUT {q=s->write;m=WAVAIL;}
+#define WRAP {if(q==s->end&&s->read!=s->window){q=s->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->checkfn != Z_NULL)
+    *c = s->check;
+  if (s->mode == BTREE || s->mode == DTREE)
+    ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt));
+  if (s->mode == CODES)
+  {
+    inflate_codes_free(s->sub.decode.codes, z);
+    inflate_trees_free(s->sub.decode.td, z);
+    inflate_trees_free(s->sub.decode.tl, z);
+  }
+  s->mode = TYPE;
+  s->bitk = 0;
+  s->bitb = 0;
+  s->read = s->write = s->window;
+  if (s->checkfn != Z_NULL)
+    s->check = (*s->checkfn)(0L, Z_NULL, 0);
+  Trace((stderr, "inflate:   blocks reset\n"));
+}
+
+
+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->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
+  {
+    ZFREE(z, s, sizeof(struct inflate_blocks_state));
+    return Z_NULL;
+  }
+  s->end = s->window + w;
+  s->checkfn = c;
+  s->mode = TYPE;
+  Trace((stderr, "inflate:   blocks allocated\n"));
+  inflate_blocks_reset(s, z, &s->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->mode)
+  {
+    case TYPE:
+      NEEDBITS(3)
+      t = (uInt)b & 7;
+      s->last = t & 1;
+      switch (t >> 1)
+      {
+        case 0:                         /* stored */
+          Trace((stderr, "inflate:     stored block%s\n",
+                 s->last ? " (last)" : ""));
+          DUMPBITS(3)
+          t = k & 7;                    /* go to byte boundary */
+          DUMPBITS(t)
+          s->mode = LENS;               /* get length of stored block */
+          break;
+        case 1:                         /* fixed */
+          Trace((stderr, "inflate:     fixed codes block%s\n",
+                 s->last ? " (last)" : ""));
+          {
+            uInt bl, bd;
+            inflate_huft *tl, *td;
+
+            inflate_trees_fixed(&bl, &bd, &tl, &td);
+            s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
+            if (s->sub.decode.codes == Z_NULL)
+            {
+              r = Z_MEM_ERROR;
+              LEAVE
+            }
+            s->sub.decode.tl = Z_NULL;  /* don't try to free these */
+            s->sub.decode.td = Z_NULL;
+          }
+          DUMPBITS(3)
+          s->mode = CODES;
+          break;
+        case 2:                         /* dynamic */
+          Trace((stderr, "inflate:     dynamic codes block%s\n",
+                 s->last ? " (last)" : ""));
+          DUMPBITS(3)
+          s->mode = TABLE;
+          break;
+        case 3:                         /* illegal */
+          DUMPBITS(3)
+          s->mode = BADB;
+          z->msg = "invalid block type";
+          r = Z_DATA_ERROR;
+          LEAVE
+      }
+      break;
+    case LENS:
+      NEEDBITS(32)
+      if (((~b) >> 16) != (b & 0xffff))
+      {
+        s->mode = BADB;
+        z->msg = "invalid stored block lengths";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+      s->sub.left = (uInt)b & 0xffff;
+      b = k = 0;                      /* dump bits */
+      Tracev((stderr, "inflate:       stored length %u\n", s->sub.left));
+      s->mode = s->sub.left ? STORED : TYPE;
+      break;
+    case STORED:
+      if (n == 0)
+        LEAVE
+      NEEDOUT
+      t = s->sub.left;
+      if (t > n) t = n;
+      if (t > m) t = m;
+      zmemcpy(q, p, t);
+      p += t;  n -= t;
+      q += t;  m -= t;
+      if ((s->sub.left -= t) != 0)
+        break;
+      Tracev((stderr, "inflate:       stored end, %lu total out\n",
+              z->total_out + (q >= s->read ? q - s->read :
+              (s->end - s->read) + (q - s->window))));
+      s->mode = s->last ? DRY : TYPE;
+      break;
+    case TABLE:
+      NEEDBITS(14)
+      s->sub.trees.table = t = (uInt)b & 0x3fff;
+#ifndef PKZIP_BUG_WORKAROUND
+      if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
+      {
+        s->mode = BADB;
+        z->msg = "too many length or distance symbols";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+#endif
+      t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
+      if (t < 19)
+        t = 19;
+      if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
+      {
+        r = Z_MEM_ERROR;
+        LEAVE
+      }
+      s->sub.trees.nblens = t;
+      DUMPBITS(14)
+      s->sub.trees.index = 0;
+      Tracev((stderr, "inflate:       table sizes ok\n"));
+      s->mode = BTREE;
+    case BTREE:
+      while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
+      {
+        NEEDBITS(3)
+        s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
+        DUMPBITS(3)
+      }
+      while (s->sub.trees.index < 19)
+        s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
+      s->sub.trees.bb = 7;
+      t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
+                             &s->sub.trees.tb, z);
+      if (t != Z_OK)
+      {
+        r = t;
+        if (r == Z_DATA_ERROR)
+          s->mode = BADB;
+        LEAVE
+      }
+      s->sub.trees.index = 0;
+      Tracev((stderr, "inflate:       bits tree ok\n"));
+      s->mode = DTREE;
+    case DTREE:
+      while (t = s->sub.trees.table,
+             s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
+      {
+        inflate_huft *h;
+        uInt i, j, c;
+
+        t = s->sub.trees.bb;
+        NEEDBITS(t)
+        h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
+        t = h->word.what.Bits;
+        c = h->more.Base;
+        if (c < 16)
+        {
+          DUMPBITS(t)
+          s->sub.trees.blens[s->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 & inflate_mask[i];
+          DUMPBITS(i)
+          i = s->sub.trees.index;
+          t = s->sub.trees.table;
+          if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
+              (c == 16 && i < 1))
+          {
+            s->mode = BADB;
+            z->msg = "invalid bit length repeat";
+            r = Z_DATA_ERROR;
+            LEAVE
+          }
+          c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
+          do {
+            s->sub.trees.blens[i++] = c;
+          } while (--j);
+          s->sub.trees.index = i;
+        }
+      }
+      inflate_trees_free(s->sub.trees.tb, z);
+      s->sub.trees.tb = Z_NULL;
+      {
+        uInt bl, bd;
+        inflate_huft *tl, *td;
+        inflate_codes_statef *c;
+
+        bl = 9;         /* must be <= 9 for lookahead assumptions */
+        bd = 6;         /* must be <= 9 for lookahead assumptions */
+        t = s->sub.trees.table;
+        t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
+                                  s->sub.trees.blens, &bl, &bd, &tl, &td, z);
+        if (t != Z_OK)
+        {
+          if (t == (uInt)Z_DATA_ERROR)
+            s->mode = BADB;
+          r = t;
+          LEAVE
+        }
+        Tracev((stderr, "inflate:       trees ok\n"));
+        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->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt));
+        s->sub.decode.codes = c;
+        s->sub.decode.tl = tl;
+        s->sub.decode.td = td;
+      }
+      s->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->sub.decode.codes, z);
+      inflate_trees_free(s->sub.decode.td, z);
+      inflate_trees_free(s->sub.decode.tl, z);
+      LOAD
+      Tracev((stderr, "inflate:       codes end, %lu total out\n",
+              z->total_out + (q >= s->read ? q - s->read :
+              (s->end - s->read) + (q - s->window))));
+      if (!s->last)
+      {
+        s->mode = TYPE;
+        break;
+      }
+      if (k > 7)              /* return unused byte, if any */
+      {
+        Assert(k < 16, "inflate_codes grabbed too many bytes")
+        k -= 8;
+        n++;
+        p--;                    /* can always return one */
+      }
+      s->mode = DRY;
+    case DRY:
+      FLUSH
+      if (s->read != s->write)
+        LEAVE
+      s->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->window, s->end - s->window);
+  ZFREE(z, s, sizeof(struct inflate_blocks_state));
+  Trace((stderr, "inflate:   blocks freed\n"));
+  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 "caught up";
+ * i.e. no pending output (hence s->read equals s->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->read != s->write)
+	return Z_STREAM_ERROR;
+    if (s->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 > m) t = m;
+	/* update check information */
+	if (s->checkfn != Z_NULL)
+	    s->check = (*s->checkfn)(s->check, q, t);
+	zmemcpy(q, p, t);
+	q += t;
+	p += t;
+	n -= t;
+	z->total_out += t;
+	s->read = q;    /* drag read pointer forward */
+/*      WRAP  */ 	/* expand WRAP macro by hand to handle s->read */
+	if (q == s->end) {
+	    s->read = q = s->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->mode != LENS)
+	return Z_DATA_ERROR;
+    s->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 "simple" 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 <= BMAX) */
+uInt n;                 /* number of codes (assumed <= 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 <= 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 <= BMAX; j++)
+    if (c[j])
+      break;
+  k = j;                        /* minimum code length */
+  if ((uInt)l < j)
+    l = j;
+  for (i = BMAX; i; i--)
+    if (c[i])
+      break;
+  g = i;                        /* maximum code length */
+  if ((uInt)l > i)
+    l = i;
+  *m = l;
+
+
+  /* Adjust last length count to fill out codes, if needed */
+  for (y = 1 << j; j < i; j++, y <<= 1)
+    if ((y -= c[j]) < 0)
+      return Z_DATA_ERROR;
+  if ((y -= c[i]) < 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 < 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 <= 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 > 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) > (uInt)l ? l : z;      /* table size upper limit */
+        if ((f = 1 << (j = k - w)) > 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 < z)
+            while (++j < z)     /* try smaller tables up to z bits */
+            {
+              if ((f <<= 1) <= *++xp)
+                break;          /* enough codes to use up j bits */
+              f -= *xp;         /* else deduct codes from patterns */
+            }
+        }
+        z = 1 << 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->word.Nalloc = z + 1;
+#ifdef DEBUG_ZLIB
+        inflate_hufts += z + 1;
+#endif
+        *t = q + 1;             /* link to list for huft_free() */
+        *(t = &(q->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 >> (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 >= v + n)
+        r.exop = 128 + 64;      /* out of values--invalid code */
+      else if (*p < s)
+      {
+        r.exop = (Byte)(*p < 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 << (k - w);
+      for (j = i >> w; j < z; j += f)
+        q[j] = r;
+
+      /* backwards increment the k-bit code i */
+      for (j = 1 << (k - 1); i & j; j >>= 1)
+        i ^= j;
+      i ^= j;
+
+      /* backup over finished tables */
+      while ((i & ((1 << 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 && 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->msg = "oversubscribed dynamic bit lengths tree";
+  else if (r == Z_BUF_ERROR)
+  {
+    inflate_trees_free(*tb, z);
+    z->msg = "incomplete dynamic bit lengths tree";
+    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->msg = "oversubscribed literal/length tree";
+    else if (r == Z_BUF_ERROR)
+    {
+      inflate_trees_free(*tl, z);
+      z->msg = "incomplete literal/length tree";
+      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->msg = "oversubscribed literal/length tree";
+    else if (r == Z_BUF_ERROR) {
+#ifdef PKZIP_BUG_WORKAROUND
+      r = Z_OK;
+    }
+#else
+      inflate_trees_free(*td, z);
+      z->msg = "incomplete literal/length tree";
+      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) && n <= fixed_left,
+         "inflate_trees falloc overflow");
+  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, "inflate_trees ffree called!");
+  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 > 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 < 144; k++)
+      c[k] = 8;
+    for (; k < 256; k++)
+      c[k] = 9;
+    for (; k < 280; k++)
+      c[k] = 7;
+    for (; k < 288; k++)
+      c[k] = 8;
+    fixed_bl = 7;
+    huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z);
+
+    /* distance table */
+    for (k = 0; k < 30; k++)
+      c[k] = 5;
+    fixed_bd = 5;
+    huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &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)->next;
+    ZFREE(z, p, p->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 "i:"=input, "o:"=output, "x:"=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->mode = START;
+    c->lbits = (Byte)bl;
+    c->dbits = (Byte)bd;
+    c->ltree = tl;
+    c->dtree = td;
+    Tracev((stderr, "inflate:       codes new\n"));
+  }
+  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->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->mode)
+  {             /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+    case START:         /* x: set up for LEN */
+#ifndef SLOW
+      if (m >= 258 && n >= 10)
+      {
+        UPDATE
+        r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
+        LOAD
+        if (r != Z_OK)
+        {
+          c->mode = r == Z_STREAM_END ? WASH : BADCODE;
+          break;
+        }
+      }
+#endif /* !SLOW */
+      c->sub.code.need = c->lbits;
+      c->sub.code.tree = c->ltree;
+      c->mode = LEN;
+    case LEN:           /* i: get length/literal/eob next */
+      j = c->sub.code.need;
+      NEEDBITS(j)
+      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+      DUMPBITS(t->bits)
+      e = (uInt)(t->exop);
+      if (e == 0)               /* literal */
+      {
+        c->sub.lit = t->base;
+        Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                 "inflate:         literal '%c'\n" :
+                 "inflate:         literal 0x%02x\n", t->base));
+        c->mode = LIT;
+        break;
+      }
+      if (e & 16)               /* length */
+      {
+        c->sub.copy.get = e & 15;
+        c->len = t->base;
+        c->mode = LENEXT;
+        break;
+      }
+      if ((e & 64) == 0)        /* next table */
+      {
+        c->sub.code.need = e;
+        c->sub.code.tree = t->next;
+        break;
+      }
+      if (e & 32)               /* end of block */
+      {
+        Tracevv((stderr, "inflate:         end of block\n"));
+        c->mode = WASH;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = "invalid literal/length code";
+      r = Z_DATA_ERROR;
+      LEAVE
+    case LENEXT:        /* i: getting length extra (have base) */
+      j = c->sub.copy.get;
+      NEEDBITS(j)
+      c->len += (uInt)b & inflate_mask[j];
+      DUMPBITS(j)
+      c->sub.code.need = c->dbits;
+      c->sub.code.tree = c->dtree;
+      Tracevv((stderr, "inflate:         length %u\n", c->len));
+      c->mode = DIST;
+    case DIST:          /* i: get distance next */
+      j = c->sub.code.need;
+      NEEDBITS(j)
+      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+      DUMPBITS(t->bits)
+      e = (uInt)(t->exop);
+      if (e & 16)               /* distance */
+      {
+        c->sub.copy.get = e & 15;
+        c->sub.copy.dist = t->base;
+        c->mode = DISTEXT;
+        break;
+      }
+      if ((e & 64) == 0)        /* next table */
+      {
+        c->sub.code.need = e;
+        c->sub.code.tree = t->next;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = "invalid distance code";
+      r = Z_DATA_ERROR;
+      LEAVE
+    case DISTEXT:       /* i: getting distance extra */
+      j = c->sub.copy.get;
+      NEEDBITS(j)
+      c->sub.copy.dist += (uInt)b & inflate_mask[j];
+      DUMPBITS(j)
+      Tracevv((stderr, "inflate:         distance %u\n", c->sub.copy.dist));
+      c->mode = COPY;
+    case COPY:          /* o: copying bytes in window, waiting for space */
+#ifndef __TURBOC__ /* Turbo C bug for following expression */
+      f = (uInt)(q - s->window) < c->sub.copy.dist ?
+          s->end - (c->sub.copy.dist - (q - s->window)) :
+          q - c->sub.copy.dist;
+#else
+      f = q - c->sub.copy.dist;
+      if ((uInt)(q - s->window) < c->sub.copy.dist)
+        f = s->end - (c->sub.copy.dist - (q - s->window));
+#endif
+      while (c->len)
+      {
+        NEEDOUT
+        OUTBYTE(*f++)
+        if (f == s->end)
+          f = s->window;
+        c->len--;
+      }
+      c->mode = START;
+      break;
+    case LIT:           /* o: got literal, waiting for output space */
+      NEEDOUT
+      OUTBYTE(c->sub.lit)
+      c->mode = START;
+      break;
+    case WASH:          /* o: got eob, possibly more output */
+      FLUSH
+      if (s->read != s->write)
+        LEAVE
+      c->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, "inflate:       codes free\n"));
+}
+
+/*+++++*/
+/* 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->next_out;
+  q = s->read;
+
+  /* compute number of bytes to copy as far as end of window */
+  n = (uInt)((q <= s->write ? s->write : s->end) - q);
+  if (n > z->avail_out) n = z->avail_out;
+  if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+  /* update counters */
+  z->avail_out -= n;
+  z->total_out += n;
+
+  /* update check information */
+  if (s->checkfn != Z_NULL)
+    s->check = (*s->checkfn)(s->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->end)
+  {
+    /* wrap pointers */
+    q = s->window;
+    if (s->write == s->end)
+      s->write = s->window;
+
+    /* compute bytes to copy */
+    n = (uInt)(s->write - q);
+    if (n > z->avail_out) n = z->avail_out;
+    if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+    /* update counters */
+    z->avail_out -= n;
+    z->total_out += n;
+
+    /* update check information */
+    if (s->checkfn != Z_NULL)
+      s->check = (*s->checkfn)(s->check, q, n);
+
+    /* copy */
+    if (p != NULL) {
+      zmemcpy(p, q, n);
+      p += n;
+    }
+    q += n;
+  }
+
+  /* update pointers */
+  z->next_out = p;
+  s->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<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define UNGRAB {n+=(c=k>>3);p-=c;k&=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 >= 258 && n >= 10 */
+    /* get literal/length code */
+    GRABBITS(20)                /* max bits for literal/length code */
+    if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
+    {
+      DUMPBITS(t->bits)
+      Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                "inflate:         * literal '%c'\n" :
+                "inflate:         * literal 0x%02x\n", t->base));
+      *q++ = (Byte)t->base;
+      m--;
+      continue;
+    }
+    do {
+      DUMPBITS(t->bits)
+      if (e & 16)
+      {
+        /* get extra bits for length */
+        e &= 15;
+        c = t->base + ((uInt)b & inflate_mask[e]);
+        DUMPBITS(e)
+        Tracevv((stderr, "inflate:         * length %u\n", c));
+
+        /* decode distance base of block to copy */
+        GRABBITS(15);           /* max bits for distance code */
+        e = (t = td + ((uInt)b & md))->exop;
+        do {
+          DUMPBITS(t->bits)
+          if (e & 16)
+          {
+            /* get extra bits to add to distance base */
+            e &= 15;
+            GRABBITS(e)         /* get extra bits (up to 13) */
+            d = t->base + ((uInt)b & inflate_mask[e]);
+            DUMPBITS(e)
+            Tracevv((stderr, "inflate:         * distance %u\n", d));
+
+            /* do the copy */
+            m -= c;
+            if ((uInt)(q - s->window) >= 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->window);  /* bytes from offset to end */
+              r = s->end - e;           /* pointer to offset */
+              if (c > e)                /* if source crosses, */
+              {
+                c -= e;                 /* copy to end of window */
+                do {
+                  *q++ = *r++;
+                } while (--e);
+                r = s->window;          /* copy rest from start of window */
+              }
+            }
+            do {                        /* copy all or what's left */
+              *q++ = *r++;
+            } while (--c);
+            break;
+          }
+          else if ((e & 64) == 0)
+            e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop;
+          else
+          {
+            z->msg = "invalid distance code";
+            UNGRAB
+            UPDATE
+            return Z_DATA_ERROR;
+          }
+        } while (1);
+        break;
+      }
+      if ((e & 64) == 0)
+      {
+        if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0)
+        {
+          DUMPBITS(t->bits)
+          Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                    "inflate:         * literal '%c'\n" :
+                    "inflate:         * literal 0x%02x\n", t->base));
+          *q++ = (Byte)t->base;
+          m--;
+          break;
+        }
+      }
+      else if (e & 32)
+      {
+        Tracevv((stderr, "inflate:         * end of block\n"));
+        UNGRAB
+        UPDATE
+        return Z_STREAM_END;
+      }
+      else
+      {
+        z->msg = "invalid literal/length code";
+        UNGRAB
+        UPDATE
+        return Z_DATA_ERROR;
+      }
+    } while (1);
+  } while (m >= 258 && n >= 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[] = {
+"stream end",          /* Z_STREAM_END    1 */
+"",                    /* Z_OK            0 */
+"file error",          /* Z_ERRNO        (-1) */
+"stream error",        /* Z_STREAM_ERROR (-2) */
+"data error",          /* Z_DATA_ERROR   (-3) */
+"insufficient memory", /* Z_MEM_ERROR    (-4) */
+"buffer error",        /* Z_BUF_ERROR    (-5) */
+""};
+
+
+/*+++++*/
+/* 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) <= 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 & 0xffff;
+    unsigned long s2 = (adler >> 16) & 0xffff;
+    int k;
+
+    if (buf == Z_NULL) return 1L;
+
+    while (len > 0) {
+        k = len < NMAX ? len : NMAX;
+        len -= k;
+        while (k >= 16) {
+            DO16(buf);
+            k -= 16;
+        }
+        if (k != 0) do {
+            DO1(buf);
+        } while (--k);
+        s1 %= BASE;
+        s2 %= BASE;
+    }
+    return (s2 << 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
+  gzip at prep.ai.mit.edu    madler at alumni.caltech.edu
+ */
+
+#ifndef _ZLIB_H
+#define _ZLIB_H
+
+/* #include "zconf.h" */	/* 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 <unix.h>
+#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 << (windowBits+2)   +  1 << (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="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << 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 "0.95P"
+
+/* 
+     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<<(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<<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 < 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) >.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) >.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 @@
+.\"	@(#) $Id: pppstats.8 195720 2001-06-11 11:44:34Z gc $
+.TH PPPSTATS 8 "26 June 1995"
+.SH NAME
+pppstats \- print PPP statistics
+.SH SYNOPSIS
+.B pppstats
+[
+.B -a
+] [
+.B -v
+] [
+.B -r
+] [
+.B -z
+] [
+.B -c
+.I <count>
+] [
+.B -w
+.I <secs>
+] [
+.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:
+ *      perkins at cps.msu.edu: Added compression statistics and alternate 
+ *                display. 11/94
+ *	Brad Parker (brad at cayman.com) 6/92
+ *
+ * from the original "slstats" 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[] = "$Id: pppstats.c 195720 2001-06-11 11:44:34Z gc $";
+#endif
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#ifndef STREAMS
+#if defined(_linux_) && defined(__powerpc__) \
+    && (__GLIBC__ == 2 && __GLIBC_MINOR__ == 0)
+/* kludge alert! */
+#undef __GLIBC__
+#endif
+#include <sys/socket.h>		/* *BSD, Linux, NeXT, Ultrix etc. */
+#ifndef _linux_
+#include <net/if.h>
+#include <net/ppp_defs.h>
+#include <net/if_ppp.h>
+#else
+/* Linux */
+#if __GLIBC__ >= 2
+#include <asm/types.h>		/* glibc 2 conflicts with linux/types.h */
+#include <net/if.h>
+#else
+#include <linux/types.h>
+#include <linux/if.h>
+#endif
+#include <linux/ppp_defs.h>
+#include <linux/if_ppp.h>
+#endif /* _linux_ */
+
+#else	/* STREAMS */
+#include <sys/stropts.h>	/* SVR4, Solaris 2, SunOS 4, OSF/1, etc. */
+#include <net/ppp_defs.h>
+#include <net/pppio.h>
+
+#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 "early" */
+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 "ppp" as the
+ * device name.
+ */
+#if !defined(PPP_DRV_NAME)
+#define PPP_DRV_NAME    "ppp"
+#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, "Usage: %s [-a|-d] [-v|-r|-z] [-c count] [-w wait] [interface]\n",
+	    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 (&req, 0, sizeof (req));
+
+#ifdef _linux_
+    req.stats_ptr = (caddr_t) &req.stats;
+#undef ifr_name
+#define ifr_name ifr__name
+#endif
+
+    strncpy(req.ifr_name, interface, sizeof(req.ifr_name));
+    if (ioctl(s, SIOCGPPPSTATS, &req) < 0) {
+	fprintf(stderr, "%s: ", progname);
+	if (errno == ENOTTY)
+	    fprintf(stderr, "kernel support missing\n");
+	else
+	    perror("couldn't get PPP statistics");
+	exit(1);
+    }
+    *curp = req.stats;
+}
+
+static void
+get_ppp_cstats(csp)
+    struct ppp_comp_stats *csp;
+{
+    struct ifpppcstatsreq creq;
+
+    memset (&creq, 0, sizeof (creq));
+
+#ifdef _linux_
+    creq.stats_ptr = (caddr_t) &creq.stats;
+#undef  ifr_name
+#define ifr_name ifr__name
+#endif
+
+    strncpy(creq.ifr_name, interface, sizeof(creq.ifr_name));
+    if (ioctl(s, SIOCGPPPCSTATS, &creq) < 0) {
+	fprintf(stderr, "%s: ", progname);
+	if (errno == ENOTTY) {
+	    fprintf(stderr, "no kernel compression support\n");
+	    if (zflag)
+		exit(1);
+	    rflag = 0;
+	} else {
+	    perror("couldn't get PPP compression stats");
+	    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, &str) == -1)
+	return -1;
+    if (str.ic_len != olen)
+	fprintf(stderr, "strioctl: expected %d bytes, got %d for cmd %x\n",
+	       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)) < 0) {
+	fprintf(stderr, "%s: ", progname);
+	if (errno == EINVAL)
+	    fprintf(stderr, "kernel support missing\n");
+	else
+	    perror("couldn't get PPP statistics");
+	exit(1);
+    }
+}
+
+static void
+get_ppp_cstats(csp)
+    struct ppp_comp_stats *csp;
+{
+    if (strioctl(s, PPPIO_GETCSTAT, csp, 0, sizeof(*csp)) < 0) {
+	fprintf(stderr, "%s: ", progname);
+	if (errno == ENOTTY) {
+	    fprintf(stderr, "no kernel compression support\n");
+	    if (zflag)
+		exit(1);
+	    rflag = 0;
+	} else {
+	    perror("couldn't get PPP compression statistics");
+	    exit(1);
+	}
+    }
+}
+
+#endif /* STREAMS */
+
+#define MAX0(a)		((int)(a) > 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(&old, 0, sizeof(old));
+    memset(&ocs, 0, sizeof(ocs));
+
+    while (1) {
+	get_ppp_stats(&cur);
+	if (zflag || rflag)
+	    get_ppp_cstats(&ccs);
+
+	(void)signal(SIGALRM, catchalarm);
+	signalled = 0;
+	(void)alarm(interval);
+
+	if ((line % 20) == 0) {
+	    if (zflag) {
+		printf("IN:  COMPRESSED  INCOMPRESSIBLE   COMP | ");
+		printf("OUT: COMPRESSED  INCOMPRESSIBLE   COMP\n");
+		bunit = dflag? "KB/S": "BYTE";
+		printf("    %s   PACK     %s   PACK  RATIO | ", bunit, bunit);
+		printf("    %s   PACK     %s   PACK  RATIO", bunit, bunit);
+	    } else {
+		printf("%8.8s %6.6s %6.6s",
+		       "IN", "PACK", "VJCOMP");
+
+		if (!rflag)
+		    printf(" %6.6s %6.6s", "VJUNC", "VJERR");
+		if (vflag)
+		    printf(" %6.6s %6.6s", "VJTOSS", "NON-VJ");
+		if (rflag)
+		    printf(" %6.6s %6.6s", "RATIO", "UBYTE");
+		printf("  | %8.8s %6.6s %6.6s",
+		       "OUT", "PACK", "VJCOMP");
+
+		if (!rflag)
+		    printf(" %6.6s %6.6s", "VJUNC", "NON-VJ");
+		if (vflag)
+		    printf(" %6.6s %6.6s", "VJSRCH", "VJMISS");
+		if (rflag)
+		    printf(" %6.6s %6.6s", "RATIO", "UBYTE");
+	    }
+	    putchar('\n');
+	}
+
+	if (zflag) {
+	    if (ratef) {
+		printf("%8.3f %6u %8.3f %6u %6.2f",
+		       KBPS(W(d.comp_bytes)),
+		       W(d.comp_packets),
+		       KBPS(W(d.inc_bytes)),
+		       W(d.inc_packets),
+		       ccs.d.ratio / 256.0);
+		printf(" | %8.3f %6u %8.3f %6u %6.2f",
+		       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("%8u %6u %8u %6u %6.2f",
+		       W(d.comp_bytes),
+		       W(d.comp_packets),
+		       W(d.inc_bytes),
+		       W(d.inc_packets),
+		       ccs.d.ratio / 256.0);
+		printf(" | %8u %6u %8u %6u %6.2f",
+		       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("%8.3f", KBPS(V(p.ppp_ibytes)));
+	    else
+		printf("%8u", V(p.ppp_ibytes));
+	    printf(" %6u %6u",
+		   V(p.ppp_ipackets),
+		   V(vj.vjs_compressedin));
+	    if (!rflag)
+		printf(" %6u %6u",
+		       V(vj.vjs_uncompressedin),
+		       V(vj.vjs_errorin));
+	    if (vflag)
+		printf(" %6u %6u",
+		       V(vj.vjs_tossed),
+		       V(p.ppp_ipackets) - V(vj.vjs_compressedin)
+		       - V(vj.vjs_uncompressedin) - V(vj.vjs_errorin));
+	    if (rflag) {
+		printf(" %6.2f ", CRATE(d));
+		if (ratef)
+		    printf("%6.2f", KBPS(W(d.unc_bytes)));
+		else
+		    printf("%6u", W(d.unc_bytes));
+	    }
+	    if (ratef)
+		printf("  | %8.3f", KBPS(V(p.ppp_obytes)));
+	    else
+		printf("  | %8u", V(p.ppp_obytes));
+	    printf(" %6u %6u",
+		   V(p.ppp_opackets),
+		   V(vj.vjs_compressed));
+	    if (!rflag)
+		printf(" %6u %6u",
+		       V(vj.vjs_packets) - V(vj.vjs_compressed),
+		       V(p.ppp_opackets) - V(vj.vjs_packets));
+	    if (vflag)
+		printf(" %6u %6u",
+		       V(vj.vjs_searches),
+		       V(vj.vjs_misses));
+	    if (rflag) {
+		printf(" %6.2f ", CRATE(c));
+		if (ratef)
+		    printf("%6.2f", KBPS(W(c.unc_bytes)));
+		else
+		    printf("%6u", W(c.unc_bytes));
+	    }
+
+	}
+
+	putchar('\n');
+	fflush(stdout);
+	line++;
+
+	count--;
+	if (!infinite && !count)
+	    break;
+
+	sigemptyset(&mask);
+	sigaddset(&mask, SIGALRM);
+	sigprocmask(SIG_BLOCK, &mask, &oldmask);
+	if (!signalled) {
+	    sigemptyset(&mask);
+	    sigsuspend(&mask);
+	}
+	sigprocmask(SIG_SETMASK, &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 "0";
+    if ((progname = strrchr(argv[0], '/')) == NULL)
+	progname = argv[0];
+    else
+	++progname;
+
+    while ((c = getopt(argc, argv, "advrzc:w:")) != -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 <= 0)
+		usage();
+	    break;
+	case 'w':
+	    interval = atoi(optarg);
+	    if (interval <= 0)
+		usage();
+	    break;
+	default:
+	    usage();
+	}
+    }
+    argc -= optind;
+    argv += optind;
+
+    if (!interval && count)
+	interval = 5;
+    if (interval && !count)
+	infinite = 1;
+    if (!interval && !count)
+	count = 1;
+    if (aflag)
+	dflag = 0;
+
+    if (argc > 1)
+	usage();
+    if (argc > 0)
+	interface = argv[0];
+
+    if (sscanf(interface, PPP_DRV_NAME "%d", &unit) != 1) {
+	fprintf(stderr, "%s: invalid interface '%s' specified\n",
+		progname, interface);
+    }
+
+#ifndef STREAMS
+    {
+	struct ifreq ifr;
+
+	s = socket(AF_INET, SOCK_DGRAM, 0);
+	if (s < 0) {
+	    fprintf(stderr, "%s: ", progname);
+	    perror("couldn't create IP socket");
+	    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)&ifr) < 0) {
+	    fprintf(stderr, "%s: nonexistent interface '%s' specified\n",
+		    progname, interface);
+	    exit(1);
+	}
+    }
+
+#else	/* STREAMS */
+#ifdef __osf__
+    dev = "/dev/streams/ppp";
+#else
+    dev = "/dev/" PPP_DRV_NAME;
+#endif
+    if ((s = open(dev, O_RDONLY)) < 0) {
+	fprintf(stderr, "%s: couldn't open ", progname);
+	perror(dev);
+	exit(1);
+    }
+    if (strioctl(s, PPPIO_ATTACH, &unit, sizeof(int), 0) < 0) {
+	fprintf(stderr, "%s: ppp%d is not available\n", 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
+# <interface-name> <peer-name> <user-name> <tty-device> <speed>
+#
+
+#
+# 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'` $* >> /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
+# <interface-name> <peer-name> <user-name> <tty-device> <speed>
+#
+
+#
+# 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'` $* >> /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 <host>
+
+# 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 "noipdefault" 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 "chat -- \d+++\d\c OK ath0 OK"
+
+# 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 "escape ff".)
+#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 <n> for negotiation.  pppd
+# will ask the peer to send packets of no more than <n> 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 <n>. 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 <n>
+
+# Set the interface netmask to <n>, a 32 bit netmask in "decimal dot"
+# 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 <n>.
+#remotename <n>
+
+# 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
+
+# ---<End of File>---

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.<ttyname> 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	<password>	192.168.1.1
+
+# If you add "auth login -chap +pap" 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	""
+# 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	"*"	-
+#master		hostname	"*"	-
+#root		hostname	"*"	-
+#support	hostname	"*"	-
+#stats		hostname	"*"	-

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 
+(longyear at netcom.com) and Adi Masputra (adi.masputra at sun.com)
+
+------------------------------------------------------------------------
+
+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 "NO CARRIER" 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 "ppp-off" to terminate ppp0, or "ppp-off <device>" to
+terminate the connection on <device>. For example, "ppp-off ppp2" will
+terminate the ppp2 connection.
+
+------------------------------------------------------------------------
+
+7. secure-card
+
+This script was written by Jim Isaacson <jcisaac at crl.com>. 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 "SecureCARD".
+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 & 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 & 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&C0&D2S0=0H0			\
+	TIMEOUT		30				\
+	OK		ATDT$TELEPHONE			\
+	CONNECT		''				\
+	assword:	$MODEMPASS			\
+	"\nNO CARRIER\r"
+
+if [ "$?" = "0" ]; 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&C1A'			\
+	CONNECT		''				\
+	TIMEOUT		10				\
+	ogin:--ogin:	$ACCOUNT			\
+	TIMEOUT		45				\
+	assword:	$PASSWORD
+
+  if [ "$?" = "0" ]; then
+    exit 0
+  fi
+fi
+
+###################################################################
+#
+# The script has failed. Terminate the connection mode.
+#
+chat -v TIMEOUT 3 "" AT 'OK-+++\c-OK' 'AT&C1&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 "NO CARRIER"
+ABORT "VOICE"
+ABORT "BUSY"
+ABORT "NO DIALTONE"
+ABORT "NO ANSWER"
+#
+# If calling outside allowed time we get this:
+#
+ABORT "Access denied"
+#
+# Modem initialisation stuff
+#
+TIMEOUT 5
+SAY "Initialising modem ...\n"
+'' ATE1
+'OK\r\n' ATS0=1S11=60X4&K4S42.1=1
+#
+# Now dial our ISP and wait for connection
+#
+SAY "Dialling our ISP ...\n"
+'OK\r\n' ATDT09834657
+TIMEOUT 60
+CONNECT \c
+SAY "Connected ...\n"
+#
+# This is the first stage login, we identify ourself so that the remote
+# system will agree to call us back.
+#
+TIMEOUT 30
+SAY "Sending Callback login ID ...\n"
+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 "NO CARRIER"
+HANGUP OFF
+#
+ABORT "Invalid"
+#
+# Now send password and wait to see what happens
+#
+SAY "Sending Callback password ...\n"
+word:--word:  xvsgsgs
+"You will be" \c
+#
+# What can happen now is:
+#   either: we get "You will be called back..." which is the successful case
+#   or:     we get "Invalid login" and we abort (bad login ID or password)
+#   or:     we get "NO CARRIER" 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 "You will be called back..."
+#
+CLR_ABORT "Invalid"
+SAY "Now waiting for Call back ...\n"
+#
+# The remote system will now hangup and we will get both "NO CARRIER"
+# 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
+"CONNECT" \c
+#
+# We have been called, re-arm ABORT on NO CARRIER and normal hangup signal
+# behaviour
+#
+HANGUP ON
+ABORT "NO CARRIER"
+#
+# Second stage login in order to start PPP
+#
+SAY "Remote system called back, logging in ...\n"
+SAY "Sending login ID ...\n"
+name:-BREAK-name: PPPuser
+SAY "Sending password ...\n"
+word:--word:  blipblop
+SAY "Asking to start PPP ...\n"
+'CnetSrv' "ppp default"
+"Entering PPP mode" \c
+SAY "ISP PPP started ...\n"

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 gpk at onramp.net 3/27/99
+
+I Intro
+
+   This document covers the use of the modified "chat" program and its 
+adjunct "chatchat" 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 "Don't reply with this string. Open this pipe,
+read the contents, and reply with that instead." 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           "BUSY"                     \
+     ABORT              "NO DIAL TONE"      \
+         ABORT           "NO ANSWER"                \
+         TIMEOUT         50                             \
+         ""             "atm0"                  \
+         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 "name:" prompt, delay briefly then respond with your 
+  account name (fill in your account name)
+
+Now we get to the new stuff:
+
+* when we see "word:" in the password prompt, instead of responding
+  with "@/var/tmp/p", the modified chat program will open the pipe 
+  /var/tmp/p, read the passcode out of there, and send it
+
+* when we see "compress." (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 "compress" next, but if you see "name:" 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 <filename>
+*
+*   where <filename> 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 "name:", reply with a delay followed by "myname"
+* expect "word:", 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 "@/var/tmp/p" option and opens
+*                              /var/tmp/p
+*  (chatchat prompts:)
+*
+* type PIN into SecurID card
+*   enter resulting passcode: [user inputs something]
+*
+*                           chat reads /var/tmp/p & gets what the
+*                              user typed at chatchat's "enter string" prompt
+*                           chat removes the pipe file
+*                           chat sends the user's input as a response in
+*                              place of "@/var/tmp/p"
+*                             
+* 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 <sys/time.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+/* 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, "usage: %s pipename\n", 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, "unable to create pipe '%s'", 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, "unable to open pipe '%s'", pipename);
+	  perror(errstring);
+	  retval =  -1;
+	}
+      else
+	{
+	  fprintf(stderr, "%s \n %s",
+		  "type PIN into SecurID card and",
+		  "enter resulting passcode:");
+	  nread = read(STDIN_FILENO, (void *)input, MAXINPUT);
+
+	  
+	  if (0 >= nread)
+	    {
+	      perror("unable to read from stdin");
+	      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("wrote [%d]: '%s'\n", 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) < 0)
+	      perror("Warning: couldn't remove pipe");
+	}
+    }
+  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("unable to create pipe");
+    }
+
+  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 *)&nchar, sizeof(nchar)); */
+  nwritten = write(pipefd, (void *)input, nchar);
+
+  if (-1 == nwritten)
+    {
+      perror("unable to write to pipe");
+    }
+
+  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 (nickwalker at email.com)
+#
+
+if [ -n "$USEPEERDNS" -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 (nickwalker at email.com)
+#
+
+if [ -n "$USEPEERDNS" -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 > /etc/resolv.conf
+		grep search /etc/ppp/resolv.prev >> /etc/resolv.conf
+		cat /etc/ppp/resolv.conf >> /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 [ "$1" = "" ]; 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 [ ! "$?" = "0" ]; then
+                rm -f /var/run/$DEVICE.pid
+                echo "ERROR: Removed stale pid file"
+                exit 1
+        fi
+#
+# Success. Let pppd clean up its own junk.
+        echo "PPP link to $DEVICE terminated."
+        exit 0
+fi
+#
+# The ppp process is not running for ppp0
+echo "ERROR: PPP link is not active on $DEVICE"
+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 <adi.masputra at sun.com>
+# 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 <adi.masputra at sun.com>
+# 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 "15s" for 15 seconds, "1m" 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 [ "$?" = "0" ]; then
+       exit 0
+    fi
+
+    return
+}
+
+###################################################################
+#
+# Script to dial any telephone number
+#
+function callall
+{
+#   echo "dialing attempt number: $1" >/dev/console
+    callnumber $PHONE1
+#    callnumber $PHONE2
+}
+
+###################################################################
+#
+# Initialize the modem to ensure that it is in the command state
+#
+initialize
+if [ ! "$?" = "0" ]; then
+   exit 1
+fi
+
+#
+# Dial telephone numbers until one answers
+#
+attempt=0
+while : ; do
+    attempt=`expr $attempt + 1`
+    callall $attempt
+    if [ "$attempt" = "$MAX_ATTEMPTS" ]; then
+	exit 1
+    fi	
+    sleep "$SLEEP_DELAY"
+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  <jcisaac at crl.com>.  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:
+#
+# "Exploring Expect"
+# by Don Libes
+# Published by O'Rielly and Associates
+#
+
+send_user "hello, starting ppp\n"
+
+system "stty 19200 -echoe -echo raw < /dev/cua3 > /dev/cua3"
+
+#
+# These are the parameters for the program.
+#
+set user      Pxxxxxx
+set password  xxxxxxx 
+set modem     /dev/cua3
+set dialup    <put phone number here>
+set timeout   60
+
+spawn -noecho -open [open $modem "r+"]
+
+send "AT&F\r"
+expect "OK"
+
+send "ATe0v1x4&c1q0&d2&c1s2=128s0=0DT $dialup\r"
+set timeout 15
+set counter 0
+
+set still_connecting 1
+
+expect {
+	-re ".*CONNECT.*\n" {
+		set timeout 5
+		set still_connecting 0
+		continue -expect
+	}
+	-re ".*CONNECT.*\r" {
+		set timeout 5
+		set still_connecting 0
+		continue -expect
+	}
+        -re ".*NO.*CARRIER" {
+		send_user "Failed to Connect, exiting...\n"
+		exit
+        }
+        -re ".*NO.*DIAL.*TONE" {
+		send_user "Failed to Connect, exiting...\n"
+		exit
+        }
+        -re ".*VOICE" {
+		send_user "Failed to Connect, exiting...\n"
+		exit
+        }
+	-re ".*sscode:.*\n" {
+		continue -expect
+	}
+	-re ".*sscode:" {
+                set timeout -1
+		expect_user -re "(.*)\n"
+		send "$expect_out(1,string)\r"
+		set timeout 30
+		continue -expect
+	}
+	-re ".*Next.*:" {
+                set timeout -1
+		expect_user -re "(.*)\n"
+		send "$expect_out(1,string)\r"
+		set timeout 30
+		continue -expect
+	}
+	-re "Your.*" {
+		send "\r"
+		continue -expect
+	}
+	-re ".*in:" {
+		send "$user\r"
+		continue -expect
+	}
+	-re ".*word:" {
+		send "$password\r"
+	}
+
+	timeout {
+		if { $still_connecting > 0 } {
+			continue -expect 
+			}
+		set timeout 15
+		send "\r"
+		incr counter
+		if { $counter > 8 } {
+			send_user "Cannot Connect\n"
+			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 >>/etc/minor_perm; fi
+	/usr/sbin/rem_drv ppp 2>/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 >>/etc/minor_perm; fi
+	/usr/sbin/rem_drv ppp 2>/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 "AS IS" 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 <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#include <sys/errno.h>
+#ifdef __osf__
+#include <sys/ioctl.h>
+#include <sys/cmn_err.h>
+#define queclass(mp)	((mp)->b_band & QPCTL)
+#else
+#include <sys/ioccom.h>
+#endif
+#include <sys/time.h>
+#ifdef SVR4
+#include <sys/cmn_err.h>
+#include <sys/conf.h>
+#include <sys/dlpi.h>
+#include <sys/ddi.h>
+#ifdef SOL2
+#include <sys/ksynch.h>
+#include <sys/kstat.h>
+#include <sys/sunddi.h>
+#include <sys/ethernet.h>
+#else
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#endif /* SOL2 */
+#else /* not SVR4 */
+#include <sys/user.h>
+#endif /* SVR4 */
+#include <net/ppp_defs.h>
+#include <net/pppio.h>
+#include "ppp_mod.h"
+
+/*
+ * Modifications marked with #ifdef PRIOQ are for priority queueing of
+ * interactive traffic, and are due to Marko Zec <zec at japa.tel.fer.hr>.
+ */
+#ifdef PRIOQ
+#endif	/* PRIOQ */
+
+#include <netinet/in.h>	/* 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) && defined(SOL2)
+#define ETHERTYPE_ALLSAP   0
+#endif /* !defined(ETHERTYPE_ALLSAP) && defined(SOL2) */
+
+#if !defined(PPP_ALLSAP) && defined(SOL2)
+#define PPP_ALLSAP  PPP_ALLSTATIONS
+#endif /* !defined(PPP_ALLSAP) && 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(&ppp_lower_lock, RW_WRITER)
+#define LOCK_LOWER_R	rw_enter(&ppp_lower_lock, RW_READER)
+#define TRYLOCK_LOWER_R	rw_tryenter(&ppp_lower_lock, RW_READER)
+#define UNLOCK_LOWER	rw_exit(&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 >= 2
+#define US_PROMISC	0x40	/* stream is promiscuous */
+#endif /* DL_CURRENT_VERSION >= 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 & packets using unlisted ports will be treated as "default".
+ * If IPPORT_DEFAULT is not listed here, "default" packets will be 
+ * assigned lowest priority.
+ * Each line should be terminated with "0".
+ * Line containing only "0" 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, "ppp", 0, 512, 512, 384
+#else
+    PPP_ID, "ppp", 0, 512, 512, 128
+#endif	/* PRIOQ */
+};
+
+static struct qinit pppurint = {
+    pppurput, pppursrv, pppopen, pppclose, NULL, &ppp_info, NULL
+};
+
+static struct qinit pppuwint = {
+    pppuwput, pppuwsrv, NULL, NULL, NULL, &ppp_info, NULL
+};
+
+static struct qinit ppplrint = {
+    ppplrput, ppplrsrv, NULL, NULL, NULL, &ppp_info, NULL
+};
+
+static struct qinit ppplwint = {
+    ppplwput, ppplwsrv, NULL, NULL, NULL, &ppp_info, NULL
+};
+
+#ifdef LACHTCP
+extern struct ifstats *ifstats;
+int pppdevflag = 0;
+#endif
+
+struct streamtab pppinfo = {
+    &pppurint, &pppuwint,
+    &ppplrint, &ppplwint
+};
+
+int ppp_count;
+
+/*
+ * How we maintain statistics.
+ */
+#ifdef SOL2
+#define INCR_IPACKETS(ppa)				\
+	if (ppa->kstats != 0) {				\
+	    KSTAT_NAMED_PTR(ppa->kstats)[0].value.ul++;	\
+	}
+#define INCR_IERRORS(ppa)				\
+	if (ppa->kstats != 0) {				\
+	    KSTAT_NAMED_PTR(ppa->kstats)[1].value.ul++;	\
+	}
+#define INCR_OPACKETS(ppa)				\
+	if (ppa->kstats != 0) {				\
+	    KSTAT_NAMED_PTR(ppa->kstats)[2].value.ul++;	\
+	}
+#define INCR_OERRORS(ppa)				\
+	if (ppa->kstats != 0) {				\
+	    KSTAT_NAMED_PTR(ppa->kstats)[3].value.ul++;	\
+	}
+#endif
+
+#ifdef LACHTCP
+#define INCR_IPACKETS(ppa)	ppa->ifstats.ifs_ipackets++;
+#define INCR_IERRORS(ppa)	ppa->ifstats.ifs_ierrors++;
+#define INCR_OPACKETS(ppa)	ppa->ifstats.ifs_opackets++;
+#define INCR_OERRORS(ppa)	ppa->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->q_ptr)
+	DRV_OPEN_OK(dev);	/* device is already open */
+
+#ifdef PRIOQ
+    /* Calculate max_bband & 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 = &minor_devs; (up = *prevp) != 0; prevp = &up->nextmn) {
+	    if (up->mn != mn)
+		break;
+	    ++mn;
+	}
+    } else {
+#ifdef SVR4
+	mn = getminor(*devp);
+#else
+	mn = minor(dev);
+#endif
+	for (prevp = &minor_devs; (up = *prevp) != 0; prevp = &up->nextmn) {
+	    if (up->mn >= mn)
+		break;
+	}
+	if (up->mn == mn) {
+	    /* this can't happen */
+	    q->q_ptr = WR(q)->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("pppopen: out of kernel memory\n");
+	OPEN_ERROR(ENXIO);
+    }
+    up->nextmn = *prevp;
+    *prevp = up;
+    up->mn = mn;
+#ifdef SVR4
+    *devp = makedevice(getmajor(*devp), mn);
+#endif
+    up->q = q;
+    if (NOTSUSER() == 0)
+	up->flags |= US_PRIV;
+#ifndef NO_DLPI
+    up->state = DL_UNATTACHED;
+#endif
+#ifdef LACHTCP
+    up->ifflags = IFF_UP | IFF_POINTOPOINT;
+#endif
+    up->sap = -1;
+    up->last_sent = up->last_recv = time;
+    up->npmode = NPMODE_DROP;
+    q->q_ptr = (caddr_t) up;
+    WR(q)->q_ptr = (caddr_t) up;
+    noenable(WR(q));
+#ifdef SOL2
+    mutex_init(&up->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->q_ptr;
+    if (up == 0) {
+	DPRINT("pppclose: q_ptr = 0\n");
+	return 0;
+    }
+    if (up->flags & US_DBGLOG)
+	DPRINT2("ppp/%d: close, flags=%x\n", up->mn, up->flags);
+    if (up->flags & US_CONTROL) {
+#ifdef LACHTCP
+	struct ifstats *ifp, *pifp;
+#endif
+	if (up->lowerq != 0) {
+	    /* Gack! the lower stream should have be unlinked earlier! */
+	    DPRINT1("ppp%d: lower stream still connected on close?\n",
+		    up->mn);
+	    LOCK_LOWER_W;
+	    up->lowerq->q_ptr = 0;
+	    RD(up->lowerq)->q_ptr = 0;
+	    up->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->next; as != 0; as = asnext) {
+	    asnext = as->next;
+	    as->next = 0;
+	    as->ppa = 0;
+	    if (as->flags & US_BLOCKED) {
+		as->flags &= ~US_BLOCKED;
+		flushq(WR(as->q), FLUSHDATA);
+	    }
+	}
+	for (upp = &ppas; *upp != 0; upp = &(*upp)->nextppa)
+	    if (*upp == up) {
+		*upp = up->nextppa;
+		break;
+	    }
+#ifdef LACHTCP
+	/* Remove the statistics from the active list.  */
+	for (ifp = ifstats, pifp = 0; ifp; ifp = ifp->ifs_next) {
+	    if (ifp == &up->ifstats) {
+		if (pifp)
+		    pifp->ifs_next = ifp->ifs_next;
+		else
+		    ifstats = ifp->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->ppa) != 0) {
+	    for (; as->next != 0; as = as->next)
+		if (as->next == up) {
+		    as->next = up->next;
+		    break;
+		}
+	}
+    }
+
+#ifdef SOL2
+    if (up->kstats)
+	kstat_delete(up->kstats);
+    mutex_destroy(&up->stats_lock);
+#endif
+
+    q->q_ptr = NULL;
+    WR(q)->q_ptr = NULL;
+
+    for (prevp = &minor_devs; *prevp != 0; prevp = &(*prevp)->nextmn) {
+	if (*prevp == up) {
+	    *prevp = up->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->q_ptr;
+    if (us == 0) {
+	DPRINT("pppuwput: q_ptr = 0!\n");
+	return 0;
+    }
+    if (mp == 0) {
+	DPRINT1("pppuwput/%d: mp = 0!\n", us->mn);
+	return 0;
+    }
+    if (mp->b_datap == 0) {
+	DPRINT1("pppuwput/%d: mp->b_datap = 0!\n", us->mn);
+	return 0;
+    }
+    switch (mp->b_datap->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->flags & US_DBGLOG)
+	    DPRINT3("ppp/%d: uwput M_DATA len=%d flags=%x\n",
+		    us->mn, msgdsize(mp), us->flags);
+	if (us->ppa == 0 || msgdsize(mp) > us->ppa->mtu + PPP_HDRLEN
+#ifndef NO_DLPI
+	    || (us->flags & US_CONTROL) == 0
+#endif /* NO_DLPI */
+	    ) {
+	    DPRINT1("pppuwput: junk data len=%d\n", msgdsize(mp));
+	    freemsg(mp);
+	    break;
+	}
+#ifdef NO_DLPI
+	if ((us->flags & US_CONTROL) == 0 && !pass_packet(us, mp, 1))
+	    break;
+#endif
+	if (!send_data(mp, us))
+	    putq(q, mp);
+	break;
+
+    case M_IOCTL:
+	iop = (struct iocblk *) mp->b_rptr;
+	error = EINVAL;
+	if (us->flags & US_DBGLOG)
+	    DPRINT3("ppp/%d: ioctl %x count=%d\n",
+		    us->mn, iop->ioc_cmd, iop->ioc_count);
+	switch (iop->ioc_cmd) {
+#if defined(SOL2)
+	case DLIOCRAW:	    /* raw M_DATA mode */
+	    us->flags |= US_RAWDATA;
+	    error = 0;
+	    break;
+#endif /* defined(SOL2) */
+	case I_LINK:
+	    if ((us->flags & US_CONTROL) == 0 || us->lowerq != 0)
+		break;
+	    if (mp->b_cont == 0) {
+		DPRINT1("pppuwput/%d: ioctl I_LINK b_cont = 0!\n", us->mn);
+		break;
+	    }
+	    lb = (struct linkblk *) mp->b_cont->b_rptr;
+	    lq = lb->l_qbot;
+	    if (lq == 0) {
+		DPRINT1("pppuwput/%d: ioctl I_LINK l_qbot = 0!\n", us->mn);
+		break;
+	    }
+	    LOCK_LOWER_W;
+	    us->lowerq = lq;
+	    lq->q_ptr = (caddr_t) q;
+	    RD(lq)->q_ptr = (caddr_t) us->q;
+	    UNLOCK_LOWER;
+	    iop->ioc_count = 0;
+	    error = 0;
+	    us->flags &= ~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->ppa_id);
+	    putctl4(lq, M_CTL, PPPCTL_MRU, us->mru);
+	    putctl4(lq, M_CTL, PPPCTL_MTU, us->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->q_next != NULL; tlq = tlq->q_next)
+		;
+            strqset(tlq, QHIWAT, 0, 256);
+            strqset(tlq, QLOWAT, 0, 128);
+            unfreezestr(lq);
+#endif	/* PRIOQ */
+	    break;
+
+	case I_UNLINK:
+	    if (mp->b_cont == 0) {
+		DPRINT1("pppuwput/%d: ioctl I_UNLINK b_cont = 0!\n", us->mn);
+		break;
+	    }
+	    lb = (struct linkblk *) mp->b_cont->b_rptr;
+#if DEBUG
+	    if (us->lowerq != lb->l_qbot) {
+		DPRINT2("ppp unlink: lowerq=%x qbot=%x\n",
+			us->lowerq, lb->l_qbot);
+		break;
+	    }
+#endif
+	    iop->ioc_count = 0;
+	    qwriter(q, mp, detach_lower, PERIM_OUTER);
+	    error = -1;
+	    break;
+
+	case PPPIO_NEWPPA:
+	    if (us->flags & US_CONTROL)
+		break;
+	    if ((us->flags & US_PRIV) == 0) {
+		error = EPERM;
+		break;
+	    }
+	    /* Arrange to return an int */
+	    if ((mq = mp->b_cont) == 0
+		|| mq->b_datap->db_lim - mq->b_rptr < sizeof(int)) {
+		mq = allocb(sizeof(int), BPRI_HI);
+		if (mq == 0) {
+		    error = ENOSR;
+		    break;
+		}
+		if (mp->b_cont != 0)
+		    freemsg(mp->b_cont);
+		mp->b_cont = mq;
+		mq->b_cont = 0;
+	    }
+	    iop->ioc_count = sizeof(int);
+	    mq->b_wptr = mq->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->ioc_count != sizeof(int) || us->ppa != 0)
+		break;
+	    if (mp->b_cont == 0) {
+		DPRINT1("pppuwput/%d: ioctl PPPIO_ATTACH b_cont = 0!\n", us->mn);
+		break;
+	    }
+	    n = *(int *)mp->b_cont->b_rptr;
+	    for (ppa = ppas; ppa != 0; ppa = ppa->nextppa)
+		if (ppa->ppa_id == n)
+		    break;
+	    if (ppa == 0)
+		break;
+	    us->ppa = ppa;
+	    iop->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->ioc_count != sizeof(int) || us->ppa == 0)
+		break;
+	    if (mp->b_cont == 0) {
+		DPRINT1("pppuwput/%d: ioctl PPPIO_BIND b_cont = 0!\n", us->mn);
+		break;
+	    }
+	    n = *(int *)mp->b_cont->b_rptr;
+	    /* n must be a valid PPP network protocol number. */
+	    if (n < 0x21 || n > 0x3fff || (n & 0x101) != 1)
+		break;
+	    /* check that no other stream is bound to this sap already. */
+	    for (os = us->ppa; os != 0; os = os->next)
+		if (os->sap == n)
+		    break;
+	    if (os != 0)
+		break;
+	    us->sap = n;
+	    iop->ioc_count = 0;
+	    error = 0;
+	    break;
+#endif /* NO_DLPI */
+
+	case PPPIO_MRU:
+	    if (iop->ioc_count != sizeof(int) || (us->flags & US_CONTROL) == 0)
+		break;
+	    if (mp->b_cont == 0) {
+		DPRINT1("pppuwput/%d: ioctl PPPIO_MRU b_cont = 0!\n", us->mn);
+		break;
+	    }
+	    n = *(int *)mp->b_cont->b_rptr;
+	    if (n <= 0 || n > PPP_MAXMRU)
+		break;
+	    if (n < PPP_MRU)
+		n = PPP_MRU;
+	    us->mru = n;
+	    if (us->lowerq)
+		putctl4(us->lowerq, M_CTL, PPPCTL_MRU, n);
+	    error = 0;
+	    iop->ioc_count = 0;
+	    break;
+
+	case PPPIO_MTU:
+	    if (iop->ioc_count != sizeof(int) || (us->flags & US_CONTROL) == 0)
+		break;
+	    if (mp->b_cont == 0) {
+		DPRINT1("pppuwput/%d: ioctl PPPIO_MTU b_cont = 0!\n", us->mn);
+		break;
+	    }
+	    n = *(int *)mp->b_cont->b_rptr;
+	    if (n <= 0 || n > PPP_MAXMTU)
+		break;
+	    us->mtu = n;
+#ifdef LACHTCP
+	    /* The MTU reported in netstat, not used as IP max packet size! */
+	    us->ifstats.ifs_mtu = n;
+#endif
+	    if (us->lowerq)
+		putctl4(us->lowerq, M_CTL, PPPCTL_MTU, n);
+	    error = 0;
+	    iop->ioc_count = 0;
+	    break;
+
+	case PPPIO_LASTMOD:
+	    us->flags |= US_LASTMOD;
+	    error = 0;
+	    break;
+
+	case PPPIO_DEBUG:
+	    if (iop->ioc_count != sizeof(int))
+		break;
+	    if (mp->b_cont == 0) {
+		DPRINT1("pppuwput/%d: ioctl PPPIO_DEBUG b_cont = 0!\n", us->mn);
+		break;
+	    }
+	    n = *(int *)mp->b_cont->b_rptr;
+	    if (n == PPPDBG_DUMP + PPPDBG_DRIVER) {
+		qwriter(q, NULL, debug_dump, PERIM_OUTER);
+		iop->ioc_count = 0;
+		error = -1;
+	    } else if (n == PPPDBG_LOG + PPPDBG_DRIVER) {
+		DPRINT1("ppp/%d: debug log enabled\n", us->mn);
+		us->flags |= US_DBGLOG;
+		iop->ioc_count = 0;
+		error = 0;
+	    } else {
+		if (us->ppa == 0 || us->ppa->lowerq == 0)
+		    break;
+		putnext(us->ppa->lowerq, mp);
+		error = -1;
+	    }
+	    break;
+
+	case PPPIO_NPMODE:
+	    if (iop->ioc_count != 2 * sizeof(int))
+		break;
+	    if ((us->flags & US_CONTROL) == 0)
+		break;
+	    if (mp->b_cont == 0) {
+		DPRINT1("pppuwput/%d: ioctl PPPIO_NPMODE b_cont = 0!\n", us->mn);
+		break;
+	    }
+	    sap = ((int *)mp->b_cont->b_rptr)[0];
+	    for (nps = us->next; nps != 0; nps = nps->next) {
+		if (us->flags & US_DBGLOG)
+		    DPRINT2("us = 0x%x, us->next->sap = 0x%x\n", nps, nps->sap);
+		if (nps->sap == sap)
+		    break;
+	    }
+	    if (nps == 0) {
+		if (us->flags & US_DBGLOG)
+		    DPRINT2("ppp/%d: no stream for sap %x\n", us->mn, sap);
+		break;
+	    }
+	    /* XXX possibly should use qwriter here */
+	    nps->npmode = (enum NPmode) ((int *)mp->b_cont->b_rptr)[1];
+	    if (nps->npmode != NPMODE_QUEUE && (nps->flags & US_BLOCKED) != 0)
+		qenable(WR(nps->q));
+	    iop->ioc_count = 0;
+	    error = 0;
+	    break;
+
+	case PPPIO_GIDLE:
+	    if ((ppa = us->ppa) == 0)
+		break;
+	    mq = allocb(sizeof(struct ppp_idle), BPRI_HI);
+	    if (mq == 0) {
+		error = ENOSR;
+		break;
+	    }
+	    if (mp->b_cont != 0)
+		freemsg(mp->b_cont);
+	    mp->b_cont = mq;
+	    mq->b_cont = 0;
+	    pip = (struct ppp_idle *) mq->b_wptr;
+	    pip->xmit_idle = time - ppa->last_sent;
+	    pip->recv_idle = time - ppa->last_recv;
+	    mq->b_wptr += sizeof(struct ppp_idle);
+	    iop->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->ioc_count != sizeof(struct ifreq) || us->ppa == 0)
+	        break;
+	    ifr = (struct ifreq *)mp->b_cont->b_rptr;
+	    /* Find the unit number in the interface name.  */
+	    for (i = 0; i < IFNAMSIZ; i++) {
+		if (ifr->ifr_name[i] == 0 ||
+		    (ifr->ifr_name[i] >= '0' &&
+		     ifr->ifr_name[i] <= '9'))
+		    break;
+		else
+		    us->ifname[i] = ifr->ifr_name[i];
+	    }
+	    us->ifname[i] = 0;
+
+	    /* Convert the unit number to binary.  */
+	    for (n = 0; i < IFNAMSIZ; i++) {
+		if (ifr->ifr_name[i] == 0) {
+		    break;
+		}
+	        else {
+		    n = n * 10 + ifr->ifr_name[i] - '0';
+		}
+	    }
+
+	    /* Verify the ppa.  */
+	    if (us->ppa->ppa_id != n)
+		break;
+	    ppa = us->ppa;
+
+	    /* Set up the netstat block.  */
+	    strncpy (ppa->ifname, us->ifname, IFNAMSIZ);
+
+	    ppa->ifstats.ifs_name = ppa->ifname;
+	    ppa->ifstats.ifs_unit = n;
+	    ppa->ifstats.ifs_active = us->state != DL_UNBOUND;
+	    ppa->ifstats.ifs_mtu = ppa->mtu;
+
+	    /* Link in statistics used by netstat.  */
+	    ppa->ifstats.ifs_next = ifstats;
+	    ifstats = &ppa->ifstats;
+
+	    iop->ioc_count = 0;
+	    error = 0;
+	    break;
+
+	case SIOCGIFFLAGS:
+	    if (!(us->flags & US_CONTROL)) {
+		if (us->ppa)
+		    us = us->ppa;
+	        else
+		    break;
+	    }
+	    ((struct iocblk_in *)iop)->ioc_ifflags = us->ifflags;
+	    error = 0;
+	    break;
+
+	case SIOCSIFFLAGS:
+	    if (!(us->flags & US_CONTROL)) {
+		if (us->ppa)
+		    us = us->ppa;
+		else
+		    break;
+	    }
+	    us->ifflags = ((struct iocblk_in *)iop)->ioc_ifflags;
+	    error = 0;
+	    break;
+
+	case SIOCSIFADDR:
+	    if (!(us->flags & US_CONTROL)) {
+		if (us->ppa)
+		    us = us->ppa;
+		else
+		    break;
+	    }
+	    us->ifflags |= IFF_RUNNING;
+	    ((struct iocblk_in *)iop)->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->b_rptr)->dl_primitive = DL_INFO_REQ;
+	    mq->b_wptr = mq->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->ppa == 0 || us->ppa->lowerq == 0)
+		break;
+	    us->ioc_id = iop->ioc_id;
+	    error = -1;
+	    switch (iop->ioc_cmd) {
+	    case PPPIO_GETSTAT:
+	    case PPPIO_GETCSTAT:
+		if (us->flags & US_LASTMOD) {
+		    error = EINVAL;
+		    break;
+		}
+		putnext(us->ppa->lowerq, mp);
+		break;
+	    default:
+		if (us->flags & US_PRIV)
+		    putnext(us->ppa->lowerq, mp);
+		else {
+		    DPRINT1("ppp ioctl %x rejected\n", iop->ioc_cmd);
+		    error = EPERM;
+		}
+		break;
+	    }
+	    break;
+	}
+
+	if (error > 0) {
+	    iop->ioc_error = error;
+	    mp->b_datap->db_type = M_IOCNAK;
+	    qreply(q, mp);
+	} else if (error == 0) {
+	    mp->b_datap->db_type = M_IOCACK;
+	    qreply(q, mp);
+	}
+	break;
+
+    case M_FLUSH:
+	if (us->flags & US_DBGLOG)
+	    DPRINT2("ppp/%d: flush %x\n", us->mn, *mp->b_rptr);
+	if (*mp->b_rptr & FLUSHW)
+	    flushq(q, FLUSHDATA);
+	if (*mp->b_rptr & FLUSHR) {
+	    *mp->b_rptr &= ~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->b_rptr;
+    int size = mp->b_wptr - mp->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 >= 2
+    dl_phys_addr_ack_t	*paddrack;
+    static struct ether_addr eaddr = {0};
+#endif
+
+    if (us->flags & US_DBGLOG)
+	DPRINT3("ppp/%d: dlpi prim %x len=%d\n", us->mn,
+		d->dl_primitive, size);
+    switch (d->dl_primitive) {
+    case DL_INFO_REQ:
+	if (size < sizeof(dl_info_req_t))
+	    goto badprim;
+	if ((reply = allocb(sizeof(dl_info_ack_t), BPRI_HI)) == 0)
+	    break;		/* should do bufcall */
+	reply->b_datap->db_type = M_PCPROTO;
+	info = (dl_info_ack_t *) reply->b_wptr;
+	reply->b_wptr += sizeof(dl_info_ack_t);
+	bzero((caddr_t) info, sizeof(dl_info_ack_t));
+	info->dl_primitive = DL_INFO_ACK;
+	info->dl_max_sdu = us->ppa? us->ppa->mtu: PPP_MAXMTU;
+	info->dl_min_sdu = 1;
+	info->dl_addr_length = sizeof(uint);
+	info->dl_mac_type = DL_ETHER;	/* a bigger lie */
+	info->dl_current_state = us->state;
+	info->dl_service_mode = DL_CLDLS;
+	info->dl_provider_style = DL_STYLE2;
+#if DL_CURRENT_VERSION >= 2
+	info->dl_sap_length = sizeof(uint);
+	info->dl_version = DL_CURRENT_VERSION;
+#endif
+	qreply(q, reply);
+	break;
+
+    case DL_ATTACH_REQ:
+	if (size < sizeof(dl_attach_req_t))
+	    goto badprim;
+	if (us->state != DL_UNATTACHED || us->ppa != 0) {
+	    dlpi_error(q, us, DL_ATTACH_REQ, DL_OUTSTATE, 0);
+	    break;
+	}
+	for (ppa = ppas; ppa != 0; ppa = ppa->nextppa)
+	    if (ppa->ppa_id == d->attach_req.dl_ppa)
+		break;
+	if (ppa == 0) {
+	    dlpi_error(q, us, DL_ATTACH_REQ, DL_BADPPA, 0);
+	    break;
+	}
+	us->ppa = ppa;
+	qwriter(q, mp, attach_ppa, PERIM_OUTER);
+	return;
+
+    case DL_DETACH_REQ:
+	if (size < sizeof(dl_detach_req_t))
+	    goto badprim;
+	if (us->state != DL_UNBOUND || us->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 < sizeof(dl_bind_req_t))
+	    goto badprim;
+	if (us->state != DL_UNBOUND || us->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->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->bind_req.dl_sap;
+	us->req_sap = sap;
+
+#if defined(SOL2)
+	if (us->flags & US_DBGLOG)
+	    DPRINT2("DL_BIND_REQ: ip gives sap = 0x%x, us = 0x%x", 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("DL_BIND_REQ: unrecognized sap = 0x%x, us = 0x%x", sap, us);
+	    dlpi_error(q, us, DL_BIND_REQ, DL_BADADDR, 0);
+	    break;
+	}
+#else
+	if (sap == ETHERTYPE_IP)
+	    sap = PPP_IP;
+	if (sap < 0x21 || sap > 0x3fff || (sap & 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->ppa; os != 0; os = os->next)
+	    if (os->sap == sap)
+		break;
+	if (os != 0) {
+	    dlpi_error(q, us, DL_BIND_REQ, DL_NOADDR, 0);
+	    break;
+	}
+
+	us->sap = sap;
+	us->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->b_wptr;
+	reply->b_wptr += sizeof(dl_bind_ack_t) + sizeof(uint);
+	reply->b_datap->db_type = M_PCPROTO;
+	bzero((caddr_t) ackp, sizeof(dl_bind_ack_t));
+	ackp->dl_primitive = DL_BIND_ACK;
+	ackp->dl_sap = sap;
+	ackp->dl_addr_length = sizeof(uint);
+	ackp->dl_addr_offset = sizeof(dl_bind_ack_t);
+	*(uint *)(ackp+1) = sap;
+	qreply(q, reply);
+	break;
+
+    case DL_UNBIND_REQ:
+	if (size < sizeof(dl_unbind_req_t))
+	    goto badprim;
+	if (us->state != DL_IDLE) {
+	    dlpi_error(q, us, DL_UNBIND_REQ, DL_OUTSTATE, 0);
+	    break;
+	}
+	us->sap = -1;
+	us->state = DL_UNBOUND;
+#ifdef LACHTCP
+	us->ppa->ifstats.ifs_active = 0;
+#endif
+	dlpi_ok(q, DL_UNBIND_REQ);
+	break;
+
+    case DL_UNITDATA_REQ:
+	if (size < sizeof(dl_unitdata_req_t))
+	    goto badprim;
+	if (us->state != DL_IDLE) {
+	    dlpi_error(q, us, DL_UNITDATA_REQ, DL_OUTSTATE, 0);
+	    break;
+	}
+	if ((ppa = us->ppa) == 0) {
+	    cmn_err(CE_CONT, "ppp: in state dl_idle but ppa == 0?\n");
+	    break;
+	}
+	len = mp->b_cont == 0? 0: msgdsize(mp->b_cont);
+	if (len > ppa->mtu) {
+	    DPRINT2("dlpi data too large (%d > %d)\n", len, ppa->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->b_cont)
+	    promisc_sendup(ppa, mp->b_cont, us->sap, 0);
+#endif /* defined(SOL2) */
+
+	mp->b_band = 0;
+#ifdef PRIOQ
+        /* Extract s_port & d_port from IP-packet, the code is a bit
+           dirty here, but so am I, too... */
+        if (mp->b_datap->db_type == M_PROTO && us->sap == PPP_IP
+	    && mp->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->b_cont->b_rptr; /* bb points to IP-header*/
+	    len = mp->b_cont->b_wptr - mp->b_cont->b_rptr;
+            syn = 0;
+	    s_port = IPPORT_DEFAULT;
+	    d_port = IPPORT_DEFAULT;
+	    if (len >= 20) {	/* 20 = minimum length of IP header */
+		iphlen = (bb[0] & 0x0f) * 4;
+		tlh = bb + iphlen;
+		len -= iphlen;
+		switch (bb[9]) {
+		case IPPROTO_TCP:
+		    if (len >= 20) {	      /* min length of TCP header */
+			s_port = (tlh[0] << 8) + tlh[1];
+			d_port = (tlh[2] << 8) + tlh[3];
+			syn = tlh[13] & 0x02;
+		    }
+		    break;
+		case IPPROTO_UDP:
+		    if (len >= 8) {	      /* min length of UDP header */
+			s_port = (tlh[0] << 8) + tlh[1];
+			d_port = (tlh[2] << 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 && band_unset)
+                    if (s_port == *ptr || d_port == *ptr++) {
+                        mp->b_band = cur_band;
+                        band_unset = 0;
+                        break;
+		    }
+                ptr++;
+                cur_band--;
+	    }
+            if (band_unset)
+		mp->b_band = def_band;
+            /* It may be usable to urge SYN packets a bit */
+            if (syn)
+		mp->b_band++;
+	}
+#endif	/* PRIOQ */
+	/* this assumes PPP_HDRLEN <= sizeof(dl_unitdata_req_t) */
+	if (mp->b_datap->db_ref > 1) {
+	    np = allocb(PPP_HDRLEN, BPRI_HI);
+	    if (np == 0)
+		break;		/* gak! */
+	    np->b_cont = mp->b_cont;
+	    mp->b_cont = 0;
+	    freeb(mp);
+	    mp = np;
+	} else
+	    mp->b_datap->db_type = M_DATA;
+	/* XXX should use dl_dest_addr_offset/length here,
+	   but we would have to translate ETHERTYPE_IP -> PPP_IP */
+	mp->b_wptr = mp->b_rptr + PPP_HDRLEN;
+	mp->b_rptr[0] = PPP_ALLSTATIONS;
+	mp->b_rptr[1] = PPP_UI;
+	mp->b_rptr[2] = us->sap >> 8;
+	mp->b_rptr[3] = us->sap;
+	if (pass_packet(us, mp, 1)) {
+	    if (!send_data(mp, us))
+		putq(q, mp);
+	}
+	return;
+
+#if DL_CURRENT_VERSION >= 2
+    case DL_PHYS_ADDR_REQ:
+	if (size < 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->b_datap->db_type = M_PCPROTO;
+	paddrack = (dl_phys_addr_ack_t *) reply->b_wptr;
+	reply->b_wptr += sizeof(dl_phys_addr_ack_t);
+	bzero((caddr_t) paddrack, sizeof(dl_phys_addr_ack_t)+ETHERADDRL);
+	paddrack->dl_primitive = DL_PHYS_ADDR_ACK;
+	paddrack->dl_addr_length = ETHERADDRL;
+	paddrack->dl_addr_offset = sizeof(dl_phys_addr_ack_t);
+	bcopy(&eaddr, reply->b_wptr, ETHERADDRL);
+	reply->b_wptr += ETHERADDRL;
+	qreply(q, reply);
+	break;
+
+#if defined(SOL2)
+    case DL_PROMISCON_REQ:
+	if (size < sizeof(dl_promiscon_req_t))
+	    goto badprim;
+	us->flags |= US_PROMISC;
+	dlpi_ok(q, DL_PROMISCON_REQ);
+	break;
+
+    case DL_PROMISCOFF_REQ:
+	if (size < sizeof(dl_promiscoff_req_t))
+	    goto badprim;
+	us->flags &= ~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 >= 2 */
+
+#if DL_CURRENT_VERSION >= 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->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->dl_primitive, DL_OUTSTATE, 0);
+	break;
+
+    case DL_UDQOS_REQ:
+	dlpi_error(q, us, d->dl_primitive, DL_BADQOSTYPE, 0);
+	break;
+
+#if DL_CURRENT_VERSION >= 2
+    case DL_TEST_RES:
+    case DL_XID_RES:
+	break;
+#endif
+
+    default:
+	cmn_err(CE_CONT, "ppp: unknown dlpi prim 0x%x\n", d->dl_primitive);
+	/* fall through */
+    badprim:
+	dlpi_error(q, us, d->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->flags & US_DBGLOG)
+        DPRINT3("ppp/%d: dlpi error, prim=%x, err=%x\n", us->mn, prim, err);
+    reply = allocb(sizeof(dl_error_ack_t), BPRI_HI);
+    if (reply == 0)
+	return;			/* XXX should do bufcall */
+    reply->b_datap->db_type = M_PCPROTO;
+    errp = (dl_error_ack_t *) reply->b_wptr;
+    reply->b_wptr += sizeof(dl_error_ack_t);
+    errp->dl_primitive = DL_ERROR_ACK;
+    errp->dl_error_primitive = prim;
+    errp->dl_errno = err;
+    errp->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->b_datap->db_type = M_PCPROTO;
+    okp = (dl_ok_ack_t *) reply->b_wptr;
+    reply->b_wptr += sizeof(dl_ok_ack_t);
+    okp->dl_primitive = DL_OK_ACK;
+    okp->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->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 < 0) {
+	/* pass only if link already up, and don't update time */
+	if (ppa->lowerq == 0) {
+	    freemsg(mp);
+	    return 0;
+	}
+	pass = 1;
+    } else if (pass) {
+	if (outbound)
+	    ppa->last_sent = time;
+	else
+	    ppa->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->flags & US_BLOCKED) || us->npmode == NPMODE_QUEUE)
+	return 0;
+    ppa = us->ppa;
+    if (ppa == 0 || us->npmode == NPMODE_DROP || us->npmode == NPMODE_ERROR) {
+	if (us->flags & US_DBGLOG)
+	    DPRINT2("ppp/%d: dropping pkt (npmode=%d)\n", us->mn, us->npmode);
+	freemsg(mp);
+	return 1;
+    }
+    if (ppa->lowerq == 0) {
+	/* try to send it up the control stream */
+        if (bcanputnext(ppa->q, mp->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->q, np);
+	    return 1;
+	}
+    } else {
+        if (bcanputnext(ppa->lowerq, mp->b_band)) {
+	    MT_ENTER(&ppa->stats_lock);
+	    ppa->stats.ppp_opackets++;
+	    ppa->stats.ppp_obytes += msgdsize(mp);
+#ifdef INCR_OPACKETS
+	    INCR_OPACKETS(ppa);
+#endif
+	    MT_EXIT(&ppa->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->lowerq, mp);
+	    return 1;
+	}
+    }
+    us->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->q_ptr;
+    if (us == 0) {
+	DPRINT("new_ppa: q_ptr = 0!\n");
+	return;
+    }
+
+    usp = &ppas;
+    ppa_id = 0;
+    while ((up = *usp) != 0 && ppa_id == up->ppa_id) {
+	++ppa_id;
+	usp = &up->nextppa;
+    }
+    us->ppa_id = ppa_id;
+    us->ppa = us;
+    us->next = 0;
+    us->nextppa = *usp;
+    *usp = us;
+    us->flags |= US_CONTROL;
+    us->npmode = NPMODE_PASS;
+
+    us->mtu = PPP_MTU;
+    us->mru = PPP_MRU;
+
+#ifdef SOL2
+    /*
+     * Create a kstats record for our statistics, so netstat -i works.
+     */
+    if (us->kstats == 0) {
+	char unit[32];
+
+	sprintf(unit, "ppp%d", us->ppa->ppa_id);
+	us->kstats = kstat_create("ppp", us->ppa->ppa_id, unit,
+				  "net", KSTAT_TYPE_NAMED, 4, 0);
+	if (us->kstats != 0) {
+	    kstat_named_t *kn = KSTAT_NAMED_PTR(us->kstats);
+
+	    strcpy(kn[0].name, "ipackets");
+	    kn[0].data_type = KSTAT_DATA_ULONG;
+	    strcpy(kn[1].name, "ierrors");
+	    kn[1].data_type = KSTAT_DATA_ULONG;
+	    strcpy(kn[2].name, "opackets");
+	    kn[2].data_type = KSTAT_DATA_ULONG;
+	    strcpy(kn[3].name, "oerrors");
+	    kn[3].data_type = KSTAT_DATA_ULONG;
+	    kstat_install(us->kstats);
+	}
+    }
+#endif /* SOL2 */
+
+    *(int *)mp->b_cont->b_rptr = ppa_id;
+    mp->b_datap->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->q_ptr;
+    if (us == 0) {
+	DPRINT("attach_ppa: q_ptr = 0!\n");
+	return;
+    }
+
+#ifndef NO_DLPI
+    us->state = DL_UNBOUND;
+#endif
+    for (t = us->ppa; t->next != 0; t = t->next)
+	;
+    t->next = us;
+    us->next = 0;
+    if (mp->b_datap->db_type == M_IOCTL) {
+	mp->b_datap->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->q_ptr;
+    if (us == 0) {
+	DPRINT("detach_ppa: q_ptr = 0!\n");
+	return;
+    }
+
+    for (t = us->ppa; t->next != 0; t = t->next)
+	if (t->next == us) {
+	    t->next = us->next;
+	    break;
+	}
+    us->next = 0;
+    us->ppa = 0;
+#ifndef NO_DLPI
+    us->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->q_ptr;
+    if (us == 0) {
+	DPRINT("detach_lower: q_ptr = 0!\n");
+	return;
+    }
+
+    LOCK_LOWER_W;
+    us->lowerq->q_ptr = 0;
+    RD(us->lowerq)->q_ptr = 0;
+    us->lowerq = 0;
+    UNLOCK_LOWER;
+
+    /* Unblock streams which now feed back up the control stream. */
+    qenable(us->q);
+
+    mp->b_datap->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->q_ptr;
+    if (us == 0) {
+	DPRINT("pppuwsrv: q_ptr = 0!\n");
+	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->flags & US_CONTROL) {
+	for (as = us->next; as != 0; as = as->next)
+	    qenable(WR(as->q));
+    }
+
+    /* Try to send on any data queued here. */
+    us->flags &= ~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->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->q_ptr;
+    if (ppa == 0) {
+	DPRINT("pppurput: q_ptr = 0!\n");
+	return 0;
+    }
+
+    switch (mp->b_datap->db_type) {
+    case M_CTL:
+	MT_ENTER(&ppa->stats_lock);
+	switch (*mp->b_rptr) {
+	case PPPCTL_IERROR:
+#ifdef INCR_IERRORS
+	    INCR_IERRORS(ppa);
+#endif
+	    ppa->stats.ppp_ierrors++;
+	    break;
+	case PPPCTL_OERROR:
+#ifdef INCR_OERRORS
+	    INCR_OERRORS(ppa);
+#endif
+	    ppa->stats.ppp_oerrors++;
+	    break;
+	}
+	MT_EXIT(&ppa->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->b_rptr;
+	for (us = ppa; us != 0; us = us->next)
+	    if (us->ioc_id == iop->ioc_id)
+		break;
+	if (us == 0)
+	    freemsg(mp);
+	else
+	    putnext(us->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("ppp/%d: couldn't allocate eof message!\n", ppa->mn);
+	    break;
+	}
+	putnext(ppa->q, mp);
+	break;
+
+    default:
+	if (mp->b_datap->db_type == M_DATA) {
+	    len = msgdsize(mp);
+	    if (mp->b_wptr - mp->b_rptr < PPP_HDRLEN) {
+		PULLUP(mp, PPP_HDRLEN);
+		if (mp == 0) {
+		    DPRINT1("ppp_urput: msgpullup failed (len=%d)\n", len);
+		    break;
+		}
+	    }
+	    MT_ENTER(&ppa->stats_lock);
+	    ppa->stats.ppp_ipackets++;
+	    ppa->stats.ppp_ibytes += len;
+#ifdef INCR_IPACKETS
+	    INCR_IPACKETS(ppa);
+#endif
+	    MT_EXIT(&ppa->stats_lock);
+
+	    proto = PPP_PROTOCOL(mp->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 < 0x8000 && (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->rblocked && !canput(us->q))
+		    us->rblocked = 1;
+		if (!us->rblocked)
+		    putq(us->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->q))
+	    putnext(ppa->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->q_ptr;
+    if (us == 0) {
+	DPRINT("pppursrv: q_ptr = 0!\n");
+	return 0;
+    }
+
+    if (us->flags & 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->lowerq == 0) {
+	    as = us;
+	    do {
+		if (as->flags & US_BLOCKED)
+		    qenable(WR(as->q));
+		as = as->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->b_rptr);
+	    if (proto < 0x8000 && (as = find_dest(us, proto)) != 0) {
+		if (!canput(as->q))
+		    break;
+		putq(as->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->next; as != 0; as = as->next)
+		as->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->lowerq != 0)
+	    qenable(RD(us->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->b_rptr);
+	    mp->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->b_datap->db_type = M_PROTO;
+	    ud = (dl_unitdata_ind_t *) hdr->b_wptr;
+	    hdr->b_wptr += sizeof(dl_unitdata_ind_t) + 2 * sizeof(uint);
+	    hdr->b_cont = mp;
+	    ud->dl_primitive = DL_UNITDATA_IND;
+	    ud->dl_dest_addr_length = sizeof(uint);
+	    ud->dl_dest_addr_offset = sizeof(dl_unitdata_ind_t);
+	    ud->dl_src_addr_length = sizeof(uint);
+	    ud->dl_src_addr_offset = ud->dl_dest_addr_offset + sizeof(uint);
+#if DL_CURRENT_VERSION >= 2
+	    ud->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->req_sap;	/* dest SAP */
+	    ((uint *)(ud + 1))[1] = us->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->ppa)
+	    qenable(us->ppa->q);
+    }
+
+    return 0;
+}
+
+static upperstr_t *
+find_dest(ppa, proto)
+    upperstr_t *ppa;
+    int proto;
+{
+    upperstr_t *us;
+
+    for (us = ppa->next; us != 0; us = us->next)
+	if (proto == us->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) && (proto != PPP_IPV6))
+	return (upperstr_t *)0;
+
+    for ( ; us; us = us->next) {
+	if ((us->flags & US_PROMISC) && (us->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->b_wptr += sizeof(struct ether_header);
+    bzero((caddr_t)eh->b_rptr, sizeof(struct ether_header));
+    ((struct ether_header *)eh->b_rptr)->ether_type = htons((short)type);
+    eh->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->b_datap->db_type = M_PROTO;
+    dh->b_wptr = dh->b_datap->db_lim;
+    dh->b_rptr = dh->b_wptr - size;
+
+    dlu = (dl_unitdata_ind_t *)dh->b_rptr;
+    dlu->dl_primitive = DL_UNITDATA_IND;
+    dlu->dl_dest_addr_length = 0;
+    dlu->dl_dest_addr_offset = sizeof(dl_unitdata_ind_t);
+    dlu->dl_src_addr_length = 0;
+    dlu->dl_src_addr_offset = sizeof(dl_unitdata_ind_t);
+    dlu->dl_group_address = 0;
+
+    dh->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->b_rptr += PPP_HDRLEN;
+
+	    for ( ; nprus = find_promisc(prus->next, proto); 
+		    prus = nprus) {
+
+		if (dup_dup_mp = dupmsg(dup_mp)) {
+		    if (canputnext(prus->q)) {
+			if (prus->flags & US_RAWDATA) {
+			    dup_dup_mp = prepend_ether(prus, dup_dup_mp, proto);
+			    putnext(prus->q, dup_dup_mp);
+			} else {
+			    dup_dup_mp = prepend_udind(prus, dup_dup_mp, proto);
+			    putnext(prus->q, dup_dup_mp);
+			}
+		    } else {
+			DPRINT("ppp_urput: data to promisc q dropped\n");
+			freemsg(dup_dup_mp);
+		    }
+		}
+	    }
+
+	    if (canputnext(prus->q)) {
+		if (prus->flags & US_RAWDATA) {
+		    dup_mp = prepend_ether(prus, dup_mp, proto);
+		    putnext(prus->q, dup_mp);
+		} else {
+		    dup_mp = prepend_udind(prus, dup_mp, proto);
+		    putnext(prus->q, dup_mp);
+		}
+	    } else {
+		DPRINT("ppp_urput: data to promisc q dropped\n");
+		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->b_datap->db_type) {
+    case M_IOCTL:
+	iop = (struct iocblk *) mp->b_rptr;
+	iop->ioc_error = EINVAL;
+	mp->b_datap->db_type = M_IOCNAK;
+	qreply(q, mp);
+	return 0;
+    case M_FLUSH:
+	if (*mp->b_rptr & FLUSHR)
+	    flushq(q, FLUSHDATA);
+	if (*mp->b_rptr & FLUSHW) {
+	    *mp->b_rptr &= ~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->q_ptr;
+    if (uq == 0) {
+	UNLOCK_LOWER;
+	DPRINT1("ppplrput: q = %x, uq = 0??\n", 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 && 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->q_ptr;
+    if (uq == 0) {
+	UNLOCK_LOWER;
+	flushq(q, FLUSHALL);
+	DPRINT1("ppplrsrv: q = %x, uq = 0??\n", 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->b_datap->db_type = type;
+    mp->b_wptr[0] = code;
+    mp->b_wptr[1] = val;
+    mp->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->b_datap->db_type = type;
+    mp->b_wptr[0] = code;
+    ((short *)mp->b_wptr)[1] = val;
+    mp->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("ppp upper streams:\n");
+    for (us = minor_devs; us != 0; us = us->nextmn) {
+	uq = us->q;
+	DPRINT3(" %d: q=%x rlev=%d",
+		us->mn, uq, (uq? qsize(uq): 0));
+	DPRINT3(" wlev=%d flags=0x%b", (uq? qsize(WR(uq)): 0),
+		us->flags, "\020\1priv\2control\3blocked\4last");
+	DPRINT3(" state=%x sap=%x req_sap=%x", us->state, us->sap,
+		us->req_sap);
+	if (us->ppa == 0)
+	    DPRINT(" ppa=?\n");
+	else
+	    DPRINT1(" ppa=%d\n", us->ppa->ppa_id);
+	if (us->flags & US_CONTROL) {
+	    lq = us->lowerq;
+	    DPRINT3("    control for %d lq=%x rlev=%d",
+		    us->ppa_id, lq, (lq? qsize(RD(lq)): 0));
+	    DPRINT3(" wlev=%d mru=%d mtu=%d\n",
+		    (lq? qsize(lq): 0), us->mru, us->mtu);
+	}
+    }
+    mp->b_datap->db_type = M_IOCACK;
+    qreply(q, mp);
+}
+
+#ifdef FILTER_PACKETS
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+
+#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 dm at garage.uun.org (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->b_rptr);
+    if (us->flags & US_DBGLOG)
+        DPRINT3("ppp/%d: filter, proto=0x%x, out=%d\n", us->mn, proto, outbound);
+
+    switch (proto)
+    {
+    case PPP_IP:
+	if ((mp->b_wptr - mp->b_rptr) == PPP_HDRLEN && mp->b_cont != 0) {
+	    temp_mp = mp->b_cont;
+    	    len = msgdsize(temp_mp);
+	    hlen = (len < MAX_IPHDR) ? len : MAX_IPHDR;
+	    PULLUP(temp_mp, hlen);
+	    if (temp_mp == 0) {
+		DPRINT2("ppp/%d: filter, pullup next failed, len=%d\n", 
+			us->mn, hlen);
+		mp->b_cont = 0;		/* PULLUP() freed the rest */
+	        freemsg(mp);
+	        return 0;
+	    }
+	    ip = (struct ip *)mp->b_cont->b_rptr;
+	}
+	else {
+	    len = msgdsize(mp);
+	    hlen = (len < (PPP_HDRLEN+MAX_IPHDR)) ? len : (PPP_HDRLEN+MAX_IPHDR);
+	    PULLUP(mp, hlen);
+	    if (mp == 0) {
+		DPRINT2("ppp/%d: filter, pullup failed, len=%d\n", 
+			us->mn, hlen);
+	        return 0;
+	    }
+	    ip = (struct ip *)(mp->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->proto != -1; pft++) {
+	    if (ip->ip_p == pft->proto) {
+		switch(pft->proto) {
+		case IPPROTO_UDP:
+		    if (((struct udphdr *) &((int *)ip)[ip->ip_hl])->uh_dport
+				== htons(pft->port)) goto endfor;
+		    break;
+		case IPPROTO_TCP:
+		    if (((struct tcphdr *) &((int *)ip)[ip->ip_hl])->th_dport
+				== htons(pft->port)) goto endfor;
+		    break;
+		}	
+	    }
+	}
+	endfor:
+	if (pft->proto != -1) {
+	    if (us->flags & US_DBGLOG)
+		DPRINT3("ppp/%d: found IP pkt, proto=0x%x (%d)\n", 
+				us->mn, pft->proto, pft->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->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="ppp" parent="pseudo" 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 <adi.masputra at sun.com>, 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 "AS IS" 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 <sys/types.h>
+#include <sys/param.h>
+#include <sys/stream.h>
+#include <sys/errno.h>
+
+#ifdef SVR4
+#include <sys/conf.h>
+#include <sys/kmem.h>
+#include <sys/cmn_err.h>
+#include <sys/ddi.h>
+#else
+#include <sys/user.h>
+#ifdef __osf__
+#include <sys/cmn_err.h>
+#endif
+#endif /* SVR4 */
+
+#include <net/ppp_defs.h>
+#include <net/pppio.h>
+#include "ppp_mod.h"
+
+/*
+ * 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 >= 0 ? x : (-x))
+#endif /* SOL2 */
+
+/*
+ * Extract byte i of message mp 
+ */
+#define MSG_BYTE(mp, i)	((i) < (mp)->b_wptr - (mp)->b_rptr? (mp)->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 <= (code = MSG_BYTE((mp), 4)) && code <= 7)
+
+/*
+ * Standard STREAMS declarations
+ */
+static struct module_info minfo = {
+    0x7d23, "ppp_ahdl", 0, INFPSZ, 32768, 512
+};
+
+static struct qinit rinit = {
+    ahdlc_rput, NULL, ahdlc_open, ahdlc_close, NULL, &minfo, NULL
+};
+
+static struct qinit winit = {
+    ahdlc_wput, NULL, NULL, NULL, NULL, &minfo, NULL
+};
+
+#if defined(SVR4) && !defined(SOL2)
+int phdldevflag = 0;
+#define ppp_ahdlcinfo phdlinfo
+#endif /* defined(SVR4) && !defined(SOL2) */
+
+struct streamtab ppp_ahdlcinfo = {
+    &rinit,			    /* ptr to st_rdinit */
+    &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->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->q_ptr	 = (caddr_t) state;
+    WR(q)->q_ptr = (caddr_t) state;
+
+#if defined(USE_MUTEX)
+    mutex_init(&state->lock, NULL, MUTEX_DEFAULT, NULL);
+    mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+
+    state->xaccm[0] = ~0;	    /* escape 0x00 through 0x1f */
+    state->xaccm[3] = 0x60000000;   /* escape 0x7d and 0x7e */
+    state->mru	    = PPP_MRU;	    /* default of 1500 bytes */
+#if defined(SOL2)
+    state->flag_time = drv_usectohz(FLAG_TIME);
+#endif /* SOL2 */
+
+#if defined(USE_MUTEX)
+    mutex_exit(&state->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->q_ptr;
+
+    if (state == 0) {
+	DPRINT("state == 0 in ahdlc_close\n");
+	return 0;
+    }
+
+#if defined(USE_MUTEX)
+    mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+
+    if (state->rx_buf != 0) {
+	freemsg(state->rx_buf);
+	state->rx_buf = 0;
+    }
+
+#if defined(USE_MUTEX)
+    mutex_exit(&state->lock);
+    mutex_destroy(&state->lock);
+#endif /* USE_MUTEX */
+
+    FREE(q->q_ptr, sizeof(ahdlc_state_t));
+    q->q_ptr	     = NULL;
+    OTHERQ(q)->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->q_ptr;
+    if (state == 0) {
+	DPRINT("state == 0 in ahdlc_wput\n");
+	freemsg(mp);
+	return 0;
+    }
+
+    switch (mp->b_datap->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->b_rptr;
+	error = EINVAL;
+	switch (iop->ioc_cmd) {
+	case PPPIO_XACCM:
+	    if ((iop->ioc_count < sizeof(u_int32_t)) || 
+		(iop->ioc_count > sizeof(ext_accm))) {
+		break;
+	    }
+	    if (mp->b_cont == 0) {
+		DPRINT1("ahdlc_wput/%d: PPPIO_XACCM b_cont = 0!\n", state->unit);
+		break;
+	    }
+#if defined(USE_MUTEX)
+	    mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+	    bcopy((caddr_t)mp->b_cont->b_rptr, (caddr_t)state->xaccm,
+		  iop->ioc_count);
+	    state->xaccm[2] &= ~0x40000000;	/* don't escape 0x5e */
+	    state->xaccm[3] |= 0x60000000;	/* do escape 0x7d, 0x7e */
+#if defined(USE_MUTEX)
+	    mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+	    iop->ioc_count = 0;
+	    error = 0;
+	    break;
+
+	case PPPIO_RACCM:
+	    if (iop->ioc_count != sizeof(u_int32_t))
+		break;
+	    if (mp->b_cont == 0) {
+		DPRINT1("ahdlc_wput/%d: PPPIO_RACCM b_cont = 0!\n", state->unit);
+		break;
+	    }
+#if defined(USE_MUTEX)
+	    mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+	    bcopy((caddr_t)mp->b_cont->b_rptr, (caddr_t)&state->raccm,
+		  sizeof(u_int32_t));
+#if defined(USE_MUTEX)
+	    mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+	    iop->ioc_count = 0;
+	    error = 0;
+	    break;
+
+	case PPPIO_GCLEAN:
+	    np = allocb(sizeof(int), BPRI_HI);
+	    if (np == 0) {
+		error = ENOSR;
+		break;
+	    }
+	    if (mp->b_cont != 0)
+		freemsg(mp->b_cont);
+	    mp->b_cont = np;
+#if defined(USE_MUTEX)
+	    mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+	    *(int *)np->b_wptr = state->flags & RCV_FLAGS;
+#if defined(USE_MUTEX)
+	    mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+	    np->b_wptr += sizeof(int);
+	    iop->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->b_cont != 0)
+		freemsg(mp->b_cont);
+	    mp->b_cont = np;
+	    psp = (struct ppp_stats *) np->b_wptr;
+	    np->b_wptr += sizeof(struct ppp_stats);
+	    bzero((caddr_t)psp, sizeof(struct ppp_stats));
+	    psp->p = state->stats;
+	    iop->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 < 0)
+	    putnext(q, mp);
+	else if (error == 0) {
+	    mp->b_datap->db_type = M_IOCACK;
+	    qreply(q, mp);
+	} else {
+	    mp->b_datap->db_type = M_IOCNAK;
+	    iop->ioc_count = 0;
+	    iop->ioc_error = error;
+	    qreply(q, mp);
+	}
+	break;
+
+    case M_CTL:
+	switch (*mp->b_rptr) {
+	case PPPCTL_MTU:
+#if defined(USE_MUTEX)
+	    mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+	    state->mtu = ((unsigned short *)mp->b_rptr)[1];
+#if defined(USE_MUTEX)
+	    mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+	    freemsg(mp);
+	    break;
+	case PPPCTL_MRU:
+#if defined(USE_MUTEX)
+	    mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+	    state->mru = ((unsigned short *)mp->b_rptr)[1];
+#if defined(USE_MUTEX)
+	    mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+	    freemsg(mp);
+	    break;
+	case PPPCTL_UNIT:
+#if defined(USE_MUTEX)
+	    mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+	    state->unit = mp->b_rptr[1];
+#if defined(USE_MUTEX)
+	    mutex_exit(&state->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->q_ptr;
+    if (state == 0) {
+	DPRINT("state == 0 in ahdlc_rput\n");
+	freemsg(mp);
+	return 0;
+    }
+
+    switch (mp->b_datap->db_type) {
+    case M_DATA:
+	ahdlc_decode(q, mp);
+	freemsg(mp);
+	break;
+
+    case M_HANGUP:
+#if defined(USE_MUTEX)
+	mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+	if (state->rx_buf != 0) {
+	    /* XXX would like to send this up for debugging */
+	    freemsg(state->rx_buf);
+	    state->rx_buf = 0;
+	}
+	state->flags = IFLUSH;
+#if defined(USE_MUTEX)
+	mutex_exit(&state->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) >> 5] & (1 << ((c) & 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) < 4) {
+	return;
+    }
+
+    state = (ahdlc_state_t *)q->q_ptr;
+#if defined(USE_MUTEX)
+    mutex_enter(&state->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)	 << 1) +		/* input block x 2 */
+		(sizeof(fcs)	 << 2) +		/* HDLC FCS x 4 */
+		(sizeof(uchar_t) << 1);			/* HDLC flags x 2 */
+
+    outmp = allocb(outmp_len, BPRI_MED);
+    if (outmp == NULL) {
+	state->stats.ppp_oerrors++;
+#if defined(USE_MUTEX)
+	mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+	putctl1(RD(q)->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, &lbolt) != -1) {
+	if (ABS((clock_t)lbolt - state->lbolt) > state->flag_time) {
+	    *outmp->b_wptr++ = PPP_FLAG;
+	} 
+	state->lbolt = lbolt;
+    } else {
+	*outmp->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->q_next) == 0) {
+	*outmp->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) && 
+	      (MSG_BYTE(mp, 1) == PPP_UI) && 
+	      (MSG_BYTE(mp, 2) == (PPP_LCP >> 8)) &&
+	      (MSG_BYTE(mp, 3) == (PPP_LCP & 0xff)) &&
+	      LCP_USE_DFLT(mp));
+
+    xaccm = state->xaccm;
+    if (is_lcp) {
+	bcopy((caddr_t)state->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->b_cont) {
+	if (tmp->b_datap->db_type == M_DATA) {
+	    for (dp = tmp->b_rptr; dp < tmp->b_wptr; dp++) {
+		fcs = PPP_FCS(fcs, *dp);
+		if (IN_TX_MAP(*dp, xaccm)) {
+		    *outmp->b_wptr++ = PPP_ESCAPE;
+		    *outmp->b_wptr++ = *dp ^ PPP_TRANS;
+		} else {
+		    *outmp->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) & 0xff;
+    if (IN_TX_MAP(fcs_val, xaccm)) {
+	*outmp->b_wptr++ = PPP_ESCAPE;
+	*outmp->b_wptr++ = fcs_val ^ PPP_TRANS;
+    } else {
+	*outmp->b_wptr++ = fcs_val;
+    }
+
+    fcs_val = ((fcs ^ 0xffff) >> 8) & 0xff;
+    if (IN_TX_MAP(fcs_val, xaccm)) {
+	*outmp->b_wptr++ = PPP_ESCAPE;
+	*outmp->b_wptr++ = fcs_val ^ PPP_TRANS;
+    } else {
+	*outmp->b_wptr++ = fcs_val;
+    }
+
+    /*
+     * And finally, append the HDLC flag, and send it away
+     */
+    *outmp->b_wptr++ = PPP_FLAG;
+
+    state->stats.ppp_obytes += msgdsize(outmp);
+    state->stats.ppp_opackets++;
+
+#if defined(USE_MUTEX)
+    mutex_exit(&state->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)) < 0x20) && \
+			(m) & (1 << (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->b_wptr - mp->b_rptr == msgdsize(mp)) && 
+         ((intpointer_t)mp->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->q_ptr;
+
+#if defined(USE_MUTEX)
+    mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+
+    state->stats.ppp_ibytes += msgdsize(mp);
+
+    for (dp = mp->b_rptr; dp < mp->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 & 0x80)
+	    state->flags |= RCV_B7_1;
+	else
+	    state->flags |= RCV_B7_0;
+
+	if (paritytab[*dp >> 5] & (1 << (*dp & 0x1f)))
+	    state->flags |= RCV_ODDP;
+	else
+	    state->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->flags & IFLUSH) ||
+		(state->rx_buf == 0) ||
+		(msgdsize(state->rx_buf) == 0)) {
+
+		state->flags &= ~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->rx_buf;
+
+	    if (state->infcs == PPP_GOODFCS) {
+		state->stats.ppp_ipackets++;
+		adjmsg(om, -PPP_FCSLEN);
+		putnext(q, om);
+	    } else {
+		DPRINT2("ppp%d: bad fcs (len=%d)\n",
+                    state->unit, msgdsize(state->rx_buf));
+		freemsg(state->rx_buf);
+		state->flags &= ~(IFLUSH | ESCAPED);
+		state->stats.ppp_ierrors++;
+		putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
+	    }
+
+	    state->rx_buf = 0;
+	    continue;
+	}
+
+	if (state->flags & 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->rx_buf == 0) {
+	    state->rx_buf_size  = (state->mru < PPP_MRU ? PPP_MRU : state->mru);
+	    state->rx_buf_size += (sizeof(u_int32_t) << 3);
+	    state->rx_buf = allocb(state->rx_buf_size, BPRI_MED);
+
+	    /*
+	     * If allocation fails, try again on the next frame
+	     */
+	    if (state->rx_buf == 0) {
+		state->flags |= IFLUSH;
+		continue;
+	    }
+	    state->flags &= ~(IFLUSH | ESCAPED);
+	    state->infcs  = PPP_INITFCS;
+	}
+
+	if (*dp == PPP_ESCAPE) {
+	    state->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->flags & ESCAPED) {
+	    *dp ^= PPP_TRANS;
+	    state->flags &= ~ESCAPED;
+	} else if (IN_RX_MAP(*dp, state->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->rx_buf) < state->rx_buf_size) {
+	    state->infcs = PPP_FCS(state->infcs, *dp);
+	    *state->rx_buf->b_wptr++ = *dp;
+	} else {
+	    DPRINT2("ppp%d: frame too long (%d)\n",
+		state->unit, msgdsize(state->rx_buf));
+	    freemsg(state->rx_buf);
+	    state->rx_buf     = 0;
+	    state->flags     |= IFLUSH;
+	}
+    }
+
+#if defined(USE_MUTEX)
+    mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+}
+
+static int
+msg_byte(mp, i)
+    mblk_t *mp;
+    unsigned int i;
+{
+    while (mp != 0 && i >= mp->b_wptr - mp->b_rptr)
+	mp = mp->b_cont;
+    if (mp == 0)
+	return -1;
+    return mp->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 <sys/types.h>
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/modctl.h>
+#include <sys/sunddi.h>
+
+extern struct streamtab ppp_ahdlcinfo;
+
+static struct fmodsw fsw = {
+    "ppp_ahdl",
+    &ppp_ahdlcinfo,
+    D_NEW | D_MP | D_MTQPAIR
+};
+
+extern struct mod_ops mod_strmodops;
+
+static struct modlstrmod modlstrmod = {
+    &mod_strmodops,
+    "PPP async HDLC module",
+    &fsw
+};
+
+static struct modlinkage modlinkage = {
+    MODREV_1,
+    (void *) &modlstrmod,
+    NULL
+};
+
+/*
+ * Entry points for modloading.
+ */
+int
+_init(void)
+{
+    return mod_install(&modlinkage);
+}
+
+int
+_fini(void)
+{
+    return mod_remove(&modlinkage);
+}
+
+int
+_info(mip)
+    struct modinfo *mip;
+{
+    return mod_info(&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 "AS IS" 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 <sys/types.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/stream.h>
+
+#ifdef SVR4
+#include <sys/conf.h>
+#include <sys/cmn_err.h>
+#include <sys/ddi.h>
+#else
+#include <sys/user.h>
+#ifdef __osf__
+#include <sys/cmn_err.h>
+#endif
+#endif /* SVR4 */
+
+#include <net/ppp_defs.h>
+#include <net/pppio.h>
+#include "ppp_mod.h"
+
+#ifdef __osf__
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#endif
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <net/vjcompress.h>
+
+#define PACKETPTR	mblk_t *
+#include <net/ppp-comp.h>
+
+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) < (mp)->b_wptr - (mp)->b_rptr? (mp)->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 <= (code = MSG_BYTE((mp), 4)) && code <= 7)
+
+#define PPP_COMP_ID 0xbadf
+static struct module_info minfo = {
+#ifdef PRIOQ
+    PPP_COMP_ID, "ppp_comp", 0, INFPSZ, 16512, 16384,
+#else
+    PPP_COMP_ID, "ppp_comp", 0, INFPSZ, 16384, 4096,
+#endif
+};
+
+static struct qinit r_init = {
+    ppp_comp_rput, ppp_comp_rsrv, ppp_comp_open, ppp_comp_close,
+    NULL, &minfo, NULL
+};
+
+static struct qinit w_init = {
+    ppp_comp_wput, ppp_comp_wsrv, NULL, NULL, NULL, &minfo, NULL
+};
+
+#if defined(SVR4) && !defined(SOL2)
+int pcmpdevflag = 0;
+#define ppp_compinfo pcmpinfo
+#endif
+struct streamtab ppp_compinfo = {
+    &r_init, &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) < (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
+    &ppp_bsd_compress,
+#endif
+#if DO_DEFLATE
+    &ppp_deflate,
+    &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->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)->q_ptr = q->q_ptr = (caddr_t) cp;
+	cp->mru = PPP_MRU;
+	cp->mtu = PPP_MTU;
+	cp->xstate = NULL;
+	cp->rstate = NULL;
+	vj_compress_init(&cp->vj_comp, -1);
+#ifdef __osf__
+	if (!(thread = kernel_thread_w_arg(first_task, ppp_comp_alloc, (void *)cp)))
+		OPEN_ERROR(ENOSR);
+	cp->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->q_ptr;
+    if (cp != NULL) {
+	if (cp->xstate != NULL)
+	    (*cp->xcomp->comp_free)(cp->xstate);
+	if (cp->rstate != NULL)
+	    (*cp->rcomp->decomp_free)(cp->rstate);
+#ifdef __osf__
+	if (!cp->thread)
+	    printf("ppp_comp_close: NULL thread!\n");
+	else
+	    thread_terminate(cp->thread);
+#endif
+	FREE(cp, sizeof(comp_state_t));
+	q->q_ptr = NULL;
+	OTHERQ(q)->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) && (MAJOR_VERSION <= 2)
+
+    /* In 2.x and earlier the argument gets passed
+     * in the thread structure itself.  Yuck.
+     */
+    thread = current_thread();
+    cp = thread->reply_port;
+    thread->reply_port = PORT_NULL;
+
+#endif
+
+    for (;;) {
+	assert_wait((vm_offset_t)&cp->memreq.thread_status, TRUE);
+	thread_block();
+
+	if (thread_should_halt(current_thread()))
+	    thread_halt_self();
+	cmd = cp->memreq.cmd;
+	compressor_options = &cp->memreq.comp_opts[0];
+	len = compressor_options[1];
+	if (cmd == PPPIO_XCOMP) {
+	    cp->memreq.returned_mem = cp->xcomp->comp_alloc(compressor_options, len);
+	    if (!cp->memreq.returned_mem) {
+		cp->memreq.thread_status = ENOSR;
+	    } else {
+		cp->memreq.thread_status = 0;
+	    }
+	} else {
+	    cp->memreq.returned_mem = cp->rcomp->decomp_alloc(compressor_options, len);
+	    if (!cp->memreq.returned_mem) {
+	        cp->memreq.thread_status = ENOSR;
+	    } else {
+		cp->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 "sleep"
+ * 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->q_ptr;
+    if (cp == 0) {
+	DPRINT("cp == 0 in ppp_comp_wput\n");
+	freemsg(mp);
+	return 0;
+    }
+
+    switch (mp->b_datap->db_type) {
+
+    case M_DATA:
+	putq(q, mp);
+	break;
+
+    case M_IOCTL:
+	iop = (struct iocblk *) mp->b_rptr;
+	error = EINVAL;
+	switch (iop->ioc_cmd) {
+
+	case PPPIO_CFLAGS:
+	    /* set/get CCP state */
+	    if (iop->ioc_count != 2 * sizeof(int))
+		break;
+	    if (mp->b_cont == 0) {
+		DPRINT1("ppp_comp_wput/%d: PPPIO_CFLAGS b_cont = 0!\n", cp->unit);
+		break;
+	    }
+	    flags = ((int *) mp->b_cont->b_rptr)[0];
+	    mask = ((int *) mp->b_cont->b_rptr)[1];
+	    cp->flags = (cp->flags & ~mask) | (flags & mask);
+	    if ((mask & CCP_ISOPEN) && (flags & CCP_ISOPEN) == 0) {
+		if (cp->xstate != NULL) {
+		    (*cp->xcomp->comp_free)(cp->xstate);
+		    cp->xstate = NULL;
+		}
+		if (cp->rstate != NULL) {
+		    (*cp->rcomp->decomp_free)(cp->rstate);
+		    cp->rstate = NULL;
+		}
+		cp->flags &= ~CCP_ISUP;
+	    }
+	    error = 0;
+	    iop->ioc_count = sizeof(int);
+	    ((int *) mp->b_cont->b_rptr)[0] = cp->flags;
+	    mp->b_cont->b_wptr = mp->b_cont->b_rptr + sizeof(int);
+	    break;
+
+	case PPPIO_VJINIT:
+	    /*
+	     * Initialize VJ compressor/decompressor
+	     */
+	    if (iop->ioc_count != 2)
+		break;
+	    if (mp->b_cont == 0) {
+		DPRINT1("ppp_comp_wput/%d: PPPIO_VJINIT b_cont = 0!\n", cp->unit);
+		break;
+	    }
+	    nxslots = mp->b_cont->b_rptr[0] + 1;
+	    nrslots = mp->b_cont->b_rptr[1] + 1;
+	    if (nxslots > MAX_STATES || nrslots > MAX_STATES)
+		break;
+	    vj_compress_init(&cp->vj_comp, nxslots);
+	    cp->vj_last_ierrors = cp->stats.ppp_ierrors;
+	    error = 0;
+	    iop->ioc_count = 0;
+	    break;
+
+	case PPPIO_XCOMP:
+	case PPPIO_RCOMP:
+	    if (iop->ioc_count <= 0)
+		break;
+	    if (mp->b_cont == 0) {
+		DPRINT1("ppp_comp_wput/%d: PPPIO_[XR]COMP b_cont = 0!\n", cp->unit);
+		break;
+	    }
+	    opt_data = mp->b_cont->b_rptr;
+	    len = mp->b_cont->b_wptr - opt_data;
+	    if (len > iop->ioc_count)
+		len = iop->ioc_count;
+	    if (opt_data[1] < 2 || opt_data[1] > len)
+		break;
+	    for (comp = ppp_compressors; *comp != NULL; ++comp)
+		if ((*comp)->compress_proto == opt_data[0]) {
+		    /* here's the handler! */
+		    error = 0;
+#ifndef __osf__
+		    if (iop->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->xstate != NULL) {
+			    (*cp->xcomp->comp_free)(cp->xstate);
+			    cp->xstate = NULL;
+			}
+			cp->xcomp = *comp;
+			cp->xstate = (*comp)->comp_alloc(opt_data, len);
+			if (cp->xstate == NULL)
+			    error = ENOSR;
+		    } else {
+			if (cp->rstate != NULL) {
+			    (*cp->rcomp->decomp_free)(cp->rstate);
+			    cp->rstate = NULL;
+			}
+			cp->rcomp = *comp;
+			cp->rstate = (*comp)->decomp_alloc(opt_data, len);
+			if (cp->rstate == NULL)
+			    error = ENOSR;
+		    }
+#else
+		    if ((error = cp->memreq.thread_status) != EAGAIN)
+		    if (iop->ioc_cmd == PPPIO_XCOMP) {
+			if (cp->xstate) {
+			    (*cp->xcomp->comp_free)(cp->xstate);
+			    cp->xstate = 0;
+			}
+			/* sanity check for compressor options
+			 */
+			if (sizeof (cp->memreq.comp_opts) < len) {
+			    printf("can't handle options for compressor %d (%d)\n", opt_data[0],
+				opt_data[1]);
+			    cp->memreq.thread_status = ENOSR;
+			    cp->memreq.returned_mem = 0;
+			}
+			/* fill in request for the thread and kick it off
+			 */
+			if (cp->memreq.thread_status == 0 && !cp->memreq.returned_mem) {
+			    bcopy(opt_data, cp->memreq.comp_opts, len);
+			    cp->memreq.cmd = PPPIO_XCOMP;
+			    cp->xcomp = *comp;
+			    error = cp->memreq.thread_status = EAGAIN;
+			    thread_wakeup((vm_offset_t)&cp->memreq.thread_status);
+			} else {
+			    cp->xstate = cp->memreq.returned_mem;
+			    cp->memreq.returned_mem = 0;
+			    cp->memreq.thread_status = 0;
+			}
+		    } else {
+			if (cp->rstate) {
+			    (*cp->rcomp->decomp_free)(cp->rstate);
+			    cp->rstate = NULL;
+			}
+			if (sizeof (cp->memreq.comp_opts) < len) {
+			    printf("can't handle options for compressor %d (%d)\n", opt_data[0],
+				opt_data[1]);
+			    cp->memreq.thread_status = ENOSR;
+			    cp->memreq.returned_mem = 0;
+			}
+			if (cp->memreq.thread_status == 0 && !cp->memreq.returned_mem) {
+			    bcopy(opt_data, cp->memreq.comp_opts, len);
+			    cp->memreq.cmd = PPPIO_RCOMP;
+			    cp->rcomp = *comp;
+			    error = cp->memreq.thread_status = EAGAIN;
+			    thread_wakeup((vm_offset_t)&cp->memreq.thread_status);
+			} else {
+			    cp->rstate = cp->memreq.returned_mem;
+			    cp->memreq.returned_mem = 0;
+			    cp->memreq.thread_status = 0;
+			}
+		    }
+#endif
+		    break;
+		}
+	    iop->ioc_count = 0;
+	    break;
+
+	case PPPIO_GETSTAT:
+	    if ((cp->flags & 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->b_cont != 0)
+		freemsg(mp->b_cont);
+	    mp->b_cont = np;
+	    psp = (struct ppp_stats *) np->b_wptr;
+	    np->b_wptr += sizeof(struct ppp_stats);
+	    iop->ioc_count = sizeof(struct ppp_stats);
+	    psp->p = cp->stats;
+	    psp->vj = cp->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->b_cont != 0)
+		freemsg(mp->b_cont);
+	    mp->b_cont = np;
+	    csp = (struct ppp_comp_stats *) np->b_wptr;
+	    np->b_wptr += sizeof(struct ppp_comp_stats);
+	    iop->ioc_count = sizeof(struct ppp_comp_stats);
+	    bzero((caddr_t)csp, sizeof(struct ppp_comp_stats));
+	    if (cp->xstate != 0)
+		(*cp->xcomp->comp_stat)(cp->xstate, &csp->c);
+	    if (cp->rstate != 0)
+		(*cp->rcomp->decomp_stat)(cp->rstate, &csp->d);
+	    error = 0;
+	    break;
+
+	case PPPIO_DEBUG:
+	    if (iop->ioc_count != sizeof(int))
+		break;
+	    if (mp->b_cont == 0) {
+		DPRINT1("ppp_comp_wput/%d: PPPIO_DEBUG b_cont = 0!\n", cp->unit);
+		break;
+	    }
+	    n = *(int *)mp->b_cont->b_rptr;
+	    if (n == PPPDBG_LOG + PPPDBG_COMP) {
+		DPRINT1("ppp_comp%d: debug log enabled\n", cp->unit);
+		cp->flags |= DBGLOG;
+		error = 0;
+		iop->ioc_count = 0;
+	    } else {
+		error = -1;
+	    }
+	    break;
+
+	case PPPIO_LASTMOD:
+	    cp->flags |= LAST_MOD;
+	    error = 0;
+	    break;
+
+	default:
+	    error = -1;
+	    break;
+	}
+
+	if (error < 0)
+	    putnext(q, mp);
+	else if (error == 0) {
+	    mp->b_datap->db_type = M_IOCACK;
+	    qreply(q, mp);
+	} else {
+	    mp->b_datap->db_type = M_IOCNAK;
+	    iop->ioc_error = error;
+	    iop->ioc_count = 0;
+	    qreply(q, mp);
+	}
+	break;
+
+    case M_CTL:
+	switch (*mp->b_rptr) {
+	case PPPCTL_MTU:
+	    cp->mtu = ((unsigned short *)mp->b_rptr)[1];
+	    break;
+	case PPPCTL_MRU:
+	    cp->mru = ((unsigned short *)mp->b_rptr)[1];
+	    break;
+	case PPPCTL_UNIT:
+	    cp->unit = mp->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->q_ptr;
+    if (cp == 0) {
+	DPRINT("cp == 0 in ppp_comp_wsrv\n");
+	return 0;
+    }
+
+    while ((mp = getq(q)) != 0) {
+	/* assert(mp->b_datap->db_type == M_DATA) */
+#ifdef PRIOQ
+        if (!bcanputnext(q,mp->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 < PPP_HDRLEN) {
+	    DPRINT1("ppp_comp_wsrv: bogus short packet (%d)\n", len);
+	    freemsg(mp);
+	    cp->stats.ppp_oerrors++;
+	    putctl1(RD(q)->q_next, M_CTL, PPPCTL_OERROR);
+	    continue;
+	}
+	proto = (MSG_BYTE(mp, 2) << 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 > len)
+	    hlen = len;
+	if (mp->b_wptr < mp->b_rptr + hlen || mp->b_datap->db_ref > 1) {
+	    PULLUP(mp, hlen);
+	    if (mp == 0) {
+		DPRINT1("ppp_comp_wsrv: pullup failed (%d)\n", hlen);
+		cp->stats.ppp_oerrors++;
+		putctl1(RD(q)->q_next, M_CTL, PPPCTL_OERROR);
+		continue;
+	    }
+	}
+
+	/*
+	 * Do VJ compression if requested.
+	 */
+	if (proto == PPP_IP && (cp->flags & COMP_VJC)) {
+	    ip = (struct ip *) (mp->b_rptr + PPP_HDRLEN);
+	    if (ip->ip_p == IPPROTO_TCP) {
+		type = vj_compress_tcp(ip, len - PPP_HDRLEN, &cp->vj_comp,
+				       (cp->flags & COMP_VJCCID), &vjhdr);
+		switch (type) {
+		case TYPE_UNCOMPRESSED_TCP:
+		    mp->b_rptr[3] = proto = PPP_VJC_UNCOMP;
+		    break;
+		case TYPE_COMPRESSED_TCP:
+		    dp = vjhdr - PPP_HDRLEN;
+		    dp[1] = mp->b_rptr[1]; /* copy control field */
+		    dp[0] = mp->b_rptr[0]; /* copy address field */
+		    dp[2] = 0;		   /* set protocol field */
+		    dp[3] = proto = PPP_VJC_COMP;
+		    mp->b_rptr = dp;
+		    break;
+		}
+	    }
+	}
+
+	/*
+	 * Do packet compression if enabled.
+	 */
+	if (proto == PPP_CCP)
+	    ppp_comp_ccp(q, mp, 0);
+	else if (proto != PPP_LCP && (cp->flags & CCP_COMP_RUN)
+		 && cp->xstate != NULL) {
+	    len = msgdsize(mp);
+	    (*cp->xcomp->compress)(cp->xstate, &cmp, mp, len,
+			(cp->flags & CCP_ISUP? cp->mtu + PPP_HDRLEN: 0));
+	    if (cmp != NULL) {
+#ifdef PRIOQ
+		cmp->b_band=mp->b_band;
+#endif PRIOQ
+		freemsg(mp);
+		mp = cmp;
+	    }
+	}
+
+	/*
+	 * Do address/control and protocol compression if enabled.
+	 */
+	if ((cp->flags & COMP_AC)
+	    && !(proto == PPP_LCP && LCP_USE_DFLT(mp))) {
+	    mp->b_rptr += 2;	/* drop the address & ctrl fields */
+	    if (proto < 0x100 && (cp->flags & COMP_PROT))
+		++mp->b_rptr;	/* drop the high protocol byte */
+	} else if (proto < 0x100 && (cp->flags & COMP_PROT)) {
+	    /* shuffle up the address & ctrl fields */
+	    mp->b_rptr[2] = mp->b_rptr[1];
+	    mp->b_rptr[1] = mp->b_rptr[0];
+	    ++mp->b_rptr;
+	}
+
+	cp->stats.ppp_opackets++;
+	cp->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->q_ptr;
+    if (cp == 0) {
+	DPRINT("cp == 0 in ppp_comp_rput\n");
+	freemsg(mp);
+	return 0;
+    }
+
+    switch (mp->b_datap->db_type) {
+
+    case M_DATA:
+	putq(q, mp);
+	break;
+
+    case M_IOCACK:
+	iop = (struct iocblk *) mp->b_rptr;
+	switch (iop->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->b_cont == 0 || iop->ioc_count != sizeof(struct ppp_stats))
+		break;
+	    psp = (struct ppp_stats *) mp->b_cont->b_rptr;
+	    psp->vj = cp->vj_comp.stats;
+	    break;
+	}
+	putnext(q, mp);
+	break;
+
+    case M_CTL:
+	switch (mp->b_rptr[0]) {
+	case PPPCTL_IERROR:
+	    ++cp->stats.ppp_ierrors;
+	    break;
+	case PPPCTL_OERROR:
+	    ++cp->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->q_ptr;
+    if (cp == 0) {
+	DPRINT("cp == 0 in ppp_comp_rsrv\n");
+	return 0;
+    }
+
+    while ((mp = getq(q)) != 0) {
+	/* assert(mp->b_datap->db_type == M_DATA) */
+	if (!canputnext(q)) {
+	    putbq(q, mp);
+	    break;
+	}
+
+	len = msgdsize(mp);
+	cp->stats.ppp_ibytes += len;
+	cp->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 & 1) == 0) {
+	    ++i;
+	    proto = (proto << 8) + MSG_BYTE(mp, i);
+	}
+	hlen = i + 1;
+
+	/*
+	 * Now reconstruct a complete, contiguous PPP header at the
+	 * start of the packet.
+	 */
+	if (hlen < ((cp->flags & DECOMP_AC)? 0: 2)
+	           + ((cp->flags & DECOMP_PROT)? 1: 2)) {
+	    /* count these? */
+	    goto bad;
+	}
+	if (mp->b_rptr + hlen > mp->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->b_rptr + hlen - PPP_HDRLEN;
+	    if (dp < mp->b_datap->db_base || mp->b_datap->db_ref > 1) {
+		np = allocb(PPP_HDRLEN, BPRI_MED);
+		if (np == 0)
+		    goto bad;
+		np->b_cont = mp;
+		mp->b_rptr += hlen;
+		mp = np;
+		dp = mp->b_wptr;
+		mp->b_wptr += PPP_HDRLEN;
+	    } else
+		mp->b_rptr = dp;
+
+	    dp[0] = PPP_ALLSTATIONS;
+	    dp[1] = PPP_UI;
+	    dp[2] = proto >> 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->b_rptr);
+	if (proto == PPP_CCP) {
+	    len = msgdsize(mp);
+	    if (mp->b_wptr < mp->b_rptr + len) {
+		PULLUP(mp, len);
+		if (mp == 0)
+		    goto bad;
+	    }
+	    ppp_comp_ccp(q, mp, 1);
+	} else if (proto == PPP_COMP) {
+	    if ((cp->flags & CCP_ISUP)
+		&& (cp->flags & CCP_DECOMP_RUN) && cp->rstate
+		&& (cp->flags & CCP_ERR) == 0) {
+		rv = (*cp->rcomp->decompress)(cp->rstate, mp, &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->flags |= CCP_ERROR;
+		    ++cp->stats.ppp_ierrors;
+		    putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
+		    break;
+		case DECOMP_FATALERROR:
+		    cp->flags |= CCP_FATALERROR;
+		    ++cp->stats.ppp_ierrors;
+		    putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
+		    break;
+		}
+	    }
+	} else if (cp->rstate && (cp->flags & CCP_DECOMP_RUN)) {
+	    (*cp->rcomp->incomp)(cp->rstate, mp);
+	}
+
+	/*
+	 * Now do VJ decompression.
+	 */
+	proto = PPP_PROTOCOL(mp->b_rptr);
+	if (proto == PPP_VJC_COMP || proto == PPP_VJC_UNCOMP) {
+	    len = msgdsize(mp) - PPP_HDRLEN;
+	    if ((cp->flags & DECOMP_VJC) == 0 || len <= 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->b_rptr + PPP_HDRLEN;
+	    if (dp >= mp->b_wptr) {
+		np = np->b_cont;
+		dp = np->b_rptr;
+	    }
+
+	    /*
+	     * Make sure we have sufficient contiguous data at this point.
+	     */
+	    hlen = (proto == PPP_VJC_COMP)? MAX_VJHDR: MAX_IPHDR;
+	    if (hlen > len)
+		hlen = len;
+	    if (np->b_wptr < dp + hlen || np->b_datap->db_ref > 1) {
+		PULLUP(mp, hlen + PPP_HDRLEN);
+		if (mp == 0)
+		    goto bad;
+		np = mp;
+		dp = np->b_rptr + PPP_HDRLEN;
+	    }
+
+	    if (proto == PPP_VJC_COMP) {
+		/*
+		 * Decompress VJ-compressed packet.
+		 * First reset compressor if an input error has occurred.
+		 */
+		if (cp->stats.ppp_ierrors != cp->vj_last_ierrors) {
+		    if (cp->flags & DBGLOG)
+			DPRINT1("ppp%d: resetting VJ\n", cp->unit);
+		    vj_uncompress_err(&cp->vj_comp);
+		    cp->vj_last_ierrors = cp->stats.ppp_ierrors;
+		}
+
+		vjlen = vj_uncompress_tcp(dp, np->b_wptr - dp, len,
+					  &cp->vj_comp, &iphdr, &iphlen);
+		if (vjlen < 0) {
+		    if (cp->flags & DBGLOG)
+			DPRINT2("ppp%d: vj_uncomp_tcp failed, pkt len %d\n",
+				cp->unit, len);
+		    ++cp->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->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->b_rptr;	/* prepend mblk with TCP/IP hdr */
+		dp[0] = PPP_ALLSTATIONS; /* reconstruct PPP header */
+		dp[1] = PPP_UI;
+		dp[2] = PPP_IP >> 8;
+		dp[3] = PPP_IP;
+		bcopy((caddr_t)iphdr, (caddr_t)dp + PPP_HDRLEN, iphlen);
+		np->b_wptr = dp + iphlen + PPP_HDRLEN;
+		np->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->b_wptr - mp->b_rptr > 4) {
+		    bcopy((caddr_t)mp->b_rptr, (caddr_t)np->b_wptr, 4);
+		    mp->b_rptr += 4;
+		    np->b_wptr += 4;
+		} else {
+		    bcopy((caddr_t)mp->b_rptr, (caddr_t)np->b_wptr,
+			  mp->b_wptr - mp->b_rptr);
+		    np->b_wptr += mp->b_wptr - mp->b_rptr;
+		    np->b_cont = mp->b_cont;
+		    freeb(mp);
+		}
+
+		mp = np;
+
+	    } else {
+		/*
+		 * "Decompress" a VJ-uncompressed packet.
+		 */
+		cp->vj_last_ierrors = cp->stats.ppp_ierrors;
+		if (!vj_uncompress_uncomp(dp, hlen, &cp->vj_comp)) {
+		    if (cp->flags & DBGLOG)
+			DPRINT2("ppp%d: vj_uncomp_uncomp failed, pkt len %d\n",
+				cp->unit, len);
+		    ++cp->vj_last_ierrors;  /* don't need to reset next time */
+		    goto bad;
+		}
+		mp->b_rptr[3] = PPP_IP;	/* fix up the PPP protocol field */
+	    }
+	}
+
+	putnext(q, mp);
+	continue;
+
+    bad:
+	if (mp != 0)
+	    freemsg(mp);
+	cp->stats.ppp_ierrors++;
+	putctl1(q->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 < PPP_HDRLEN + CCP_HDRLEN)
+	return;
+
+    cp = (comp_state_t *) q->q_ptr;
+    dp = mp->b_rptr + PPP_HDRLEN;
+    len -= PPP_HDRLEN;
+    clen = CCP_LENGTH(dp);
+    if (clen > len)
+	return;
+
+    switch (CCP_CODE(dp)) {
+    case CCP_CONFREQ:
+    case CCP_TERMREQ:
+    case CCP_TERMACK:
+	cp->flags &= ~CCP_ISUP;
+	break;
+
+    case CCP_CONFACK:
+	if ((cp->flags & (CCP_ISOPEN | CCP_ISUP)) == CCP_ISOPEN
+	    && clen >= CCP_HDRLEN + CCP_OPT_MINLEN
+	    && clen >= CCP_HDRLEN + CCP_OPT_LENGTH(dp + CCP_HDRLEN)) {
+	    if (!rcvd) {
+		if (cp->xstate != NULL
+		    && (*cp->xcomp->comp_init)
+		        (cp->xstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN,
+			 cp->unit, 0, ((cp->flags & DBGLOG) != 0)))
+		    cp->flags |= CCP_COMP_RUN;
+	    } else {
+		if (cp->rstate != NULL
+		    && (*cp->rcomp->decomp_init)
+		        (cp->rstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN,
+			 cp->unit, 0, cp->mru, ((cp->flags & DBGLOG) != 0)))
+		    cp->flags = (cp->flags & ~CCP_ERR) | CCP_DECOMP_RUN;
+	    }
+	}
+	break;
+
+    case CCP_RESETACK:
+	if (cp->flags & CCP_ISUP) {
+	    if (!rcvd) {
+		if (cp->xstate && (cp->flags & CCP_COMP_RUN))
+		    (*cp->xcomp->comp_reset)(cp->xstate);
+	    } else {
+		if (cp->rstate && (cp->flags & CCP_DECOMP_RUN)) {
+		    (*cp->rcomp->decomp_reset)(cp->rstate);
+		    cp->flags &= ~CCP_ERROR;
+		}
+	    }
+	}
+	break;
+    }
+}
+
+#if 0
+dump_msg(mp)
+    mblk_t *mp;
+{
+    dblk_t *db;
+
+    while (mp != 0) {
+	db = mp->b_datap;
+	DPRINT2("mp=%x cont=%x ", mp, mp->b_cont);
+	DPRINT3("rptr=%x wptr=%x datap=%x\n", mp->b_rptr, mp->b_wptr, db);
+	DPRINT2("  base=%x lim=%x", db->db_base, db->db_lim);
+	DPRINT2(" ref=%d type=%d\n", db->db_ref, db->db_type);
+	mp = mp->b_cont;
+    }
+}
+#endif
+
+static int
+msg_byte(mp, i)
+    mblk_t *mp;
+    unsigned int i;
+{
+    while (mp != 0 && i >= mp->b_wptr - mp->b_rptr)
+	mp = mp->b_cont;
+    if (mp == 0)
+	return -1;
+    return mp->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 "AS IS" 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 <sys/types.h>
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/modctl.h>
+#include <sys/sunddi.h>
+
+extern struct streamtab ppp_compinfo;
+
+static struct fmodsw fsw = {
+    "ppp_comp",
+    &ppp_compinfo,
+    D_NEW | D_MP | D_MTQPAIR
+};
+
+extern struct mod_ops mod_strmodops;
+
+static struct modlstrmod modlstrmod = {
+    &mod_strmodops,
+    "PPP compression module",
+    &fsw
+};
+
+static struct modlinkage modlinkage = {
+    MODREV_1,
+    (void *) &modlstrmod,
+    NULL
+};
+
+/*
+ * Entry points for modloading.
+ */
+int
+_init(void)
+{
+    return mod_install(&modlinkage);
+}
+
+int
+_fini(void)
+{
+    return mod_remove(&modlinkage);
+}
+
+int
+_info(mip)
+    struct modinfo *mip;
+{
+    return mod_info(&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 "AS IS" 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 <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/conf.h>
+#include <sys/modctl.h>
+#include <sys/sunddi.h>
+#include <sys/ksynch.h>
+
+#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 */
+    &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 */
+    &cb_ppp_ops,			/* devo_cb_ops */
+    NULL				/* devo_bus_ops */
+};
+
+/*
+ * Module linkage information
+ */
+
+static struct modldrv modldrv = {
+    &mod_driverops,			/* says this is a pseudo driver */
+    "PPP-2.3 multiplexing driver",
+    &ppp_ops				/* driver ops */
+};
+
+static struct modlinkage modlinkage = {
+    MODREV_1,
+    (void *) &modldrv,
+    NULL
+};
+
+int
+_init(void)
+{
+    return mod_install(&modlinkage);
+}
+
+int
+_fini(void)
+{
+    return mod_remove(&modlinkage);
+}
+
+int
+_info(mip)
+    struct modinfo *mip;
+{
+    return mod_info(&modlinkage, mip);
+}
+
+static int
+ppp_identify(dip)
+    dev_info_t *dip;
+{
+    return strcmp(ddi_get_name(dip), "ppp") == 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, "ppp", S_IFCHR, 0, DDI_PSEUDO, CLONE_DEV)
+	== DDI_FAILURE) {
+	ddi_remove_minor_node(dip, NULL);
+	return DDI_FAILURE;
+    }
+    rw_init(&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(&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 <sys/kmem.h>
+#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 <sys/kmem_alloc.h>	/* 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 <sys/malloc.h>
+
+/* 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 "FREE" 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 <sys/proc.h>
+#define NOTSUSER()		(suser(u.u_procp->p_rcred, &u.u_acflag) ? EPERM : 0)
+
+/* #include "ppp_osf.h" */
+
+#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 <sys/strlog.h>
+#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)->q_qinfo->qi_putp)((q), (mp)))
+# define canputnext(q)	canput((q)->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 <sys/types.h>
+#include <sys/errno.h>
+#include <sys/conf.h>
+#include <sun/vddrv.h>
+
+extern struct streamtab if_pppinfo;
+
+static struct vdldrv vd = {
+    VDMAGIC_USER,
+    "if_ppp"
+};
+
+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->vdd_vdtab = (struct vdlinkage *) &vd;
+	if (fmodsw_index >= 0)
+	    return EBUSY;
+	for (n = 0; n < fmodcnt; ++n)
+	    if (fmodsw[n].f_str == 0)
+		break;
+	if (n >= fmodcnt)
+	    return ENODEV;
+	strncpy(fmodsw[n].f_name, vd.Drv_name, FMNAMESZ+1);
+	fmodsw[n].f_str = &if_pppinfo;
+	fmodsw_index = n;
+	break;
+
+    case VDUNLOAD:
+	if (fmodsw_index <= 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$$ >/dev/null; then :
+else
+    echo "$0: must be root."
+    rm -f /tmp/su$$
+    exit 1
+fi
+rm -f /tmp/su$$
+
+case "$0" in
+*ppp.INSTALL)
+    if [ ! -f ppp.INSTALL ]; then
+	echo "ppp.INSTALL: not found"
+	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 >/dev/null; then
+	echo "ppp driver is already loaded."
+	exit 1
+    fi
+    if modstat | grep -w if_ppp >/dev/null; then
+	echo "if_ppp module already loaded: not reloading."
+    else
+	echo -n "if_ppp: "
+	modload $moddir/if_ppp_mod.o -sym -entry _if_ppp_vdcmd \
+	    -o $etcppp/if_ppp_mod
+    fi
+    echo -n "ppp: "
+    modload $moddir/ppp_mod.o -sym -entry _ppp_vdcmd -exec /dev/ppp.MKDEV \
+	-o $etcppp/ppp_mod
+    echo -n "ppp_comp: "
+    modload $moddir/ppp_comp_mod.o -sym -entry _ppp_comp_vdcmd \
+	-o $etcppp/ppp_comp
+    echo -n "ppp_ahdl: "
+    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 "Usage: $0 module-id module-type b-major c-major"
+	exit 1
+    fi
+    if [ "$2" -ne "12345607" -a "$2" -ne "12345600" ]; then
+	echo "$0: $2: bad module type"
+	exit 1
+    fi
+    rm -f /dev/ppp
+    # we "just know" 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 >/dev/null; then
+	echo "$0: not unloading if_ppp module."
+    fi
+    for mod in ppp ppp_comp ppp_ahdl; do
+	id=`modstat | grep -w $mod | awk '{print $1}'`
+	if [ x$id = x ]; then
+	    echo "$mod is not loaded."
+	    stat=1
+	else
+	    modunload -id $id
+	fi
+    done
+    exit $stat
+    ;;
+
+*ppp.RMDEV)
+    rm -f /dev/ppp
+    exit 0
+    ;;
+
+*)
+    echo "Invocation names: ppp.INSTALL ppp.LOAD ppp.UNLOAD ppp.MKDEV ppp.RMDEV"
+    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 <sys/types.h>
+#include <sys/errno.h>
+#include <sys/conf.h>
+#include <sun/vddrv.h>
+
+extern struct streamtab ppp_ahdlcinfo;
+extern int ppp_ahdlc_count;
+
+static struct vdldrv vd = {
+    VDMAGIC_USER,
+    "ppp_ahdl"
+};
+
+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->vdd_vdtab = (struct vdlinkage *) &vd;
+	if (fmodsw_index >= 0)
+	    return EBUSY;
+	for (n = 0; n < fmodcnt; ++n)
+	    if (fmodsw[n].f_str == 0)
+		break;
+	if (n >= fmodcnt)
+	    return ENODEV;
+	strncpy(fmodsw[n].f_name, vd.Drv_name, FMNAMESZ+1);
+	fmodsw[n].f_str = &ppp_ahdlcinfo;
+	fmodsw_index = n;
+	break;
+
+    case VDUNLOAD:
+	if (ppp_ahdlc_count > 0)
+	    return EBUSY;
+	if (fmodsw_index <= 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 <sys/types.h>
+#include <sys/errno.h>
+#include <sys/conf.h>
+#include <sun/vddrv.h>
+
+extern struct streamtab ppp_compinfo;
+extern int ppp_comp_count;
+
+static struct vdldrv vd = {
+    VDMAGIC_USER,
+    "ppp_comp"
+};
+
+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->vdd_vdtab = (struct vdlinkage *) &vd;
+	if (fmodsw_index >= 0)
+	    return EBUSY;
+	for (n = 0; n < fmodcnt; ++n)
+	    if (fmodsw[n].f_str == 0)
+		break;
+	if (n >= fmodcnt)
+	    return ENODEV;
+	strncpy(fmodsw[n].f_name, vd.Drv_name, FMNAMESZ+1);
+	fmodsw[n].f_str = &ppp_compinfo;
+	fmodsw_index = n;
+	break;
+
+    case VDUNLOAD:
+	if (ppp_comp_count > 0)
+	    return EBUSY;
+	if (fmodsw_index <= 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 <sys/types.h>
+#include <sys/errno.h>
+#include <sys/conf.h>
+#include <sun/vddrv.h>
+
+extern struct streamtab pppinfo;
+extern int ppp_count;
+extern int nchrdev;
+
+static struct vdldrv vd = {
+    VDMAGIC_PSEUDO,
+    "ppp"
+};
+
+extern int nodev();
+
+static struct cdevsw ppp_cdevsw = {
+    nodev, nodev, nodev, nodev, nodev, nodev, nodev, 0,
+    &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 < nchrdev; ++maj)
+	    if (cdevsw[maj].d_open == vd_unuseddev)
+		break;
+	if (maj >= nchrdev)
+	    return ENODEV;
+	vd.Drv_charmajor = maj;
+	old_entry = cdevsw[maj];
+	cdevsw[maj] = ppp_cdevsw;
+	vd.Drv_cdevsw = &ppp_cdevsw;
+	vdp->vdd_vdtab = (struct vdlinkage *) &vd;
+	majnum = maj;
+	break;
+
+    case VDUNLOAD:
+	if (ppp_count > 0)
+	    return EBUSY;
+	if (vd.Drv_charmajor > 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->vds_magic = VDMAGIC_DRV;
+	vds->vds_modinfo[0] = (char) 0;
+	vds->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 >>/etc/minor_perm; fi
+	/usr/sbin/rem_drv ppp 2>/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 >>/etc/minor_perm; fi
+	/usr/sbin/rem_drv ppp 2>/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="ppp" parent="pseudo" 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 <sys/types.h>
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/modctl.h>
+#include <sys/sunddi.h>
+
+extern struct streamtab ppp_ahdlcinfo;
+
+static struct fmodsw fsw = {
+    "ppp_ahdl",
+    &ppp_ahdlcinfo,
+    D_NEW | D_MP | D_MTQPAIR
+};
+
+extern struct mod_ops mod_strmodops;
+
+static struct modlstrmod modlstrmod = {
+    &mod_strmodops,
+    "PPP async HDLC module",
+    &fsw
+};
+
+static struct modlinkage modlinkage = {
+    MODREV_1,
+    (void *) &modlstrmod,
+    NULL
+};
+
+/*
+ * Entry points for modloading.
+ */
+int
+_init(void)
+{
+    return mod_install(&modlinkage);
+}
+
+int
+_fini(void)
+{
+    return mod_remove(&modlinkage);
+}
+
+int
+_info(mip)
+    struct modinfo *mip;
+{
+    return mod_info(&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 "AS IS" 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 <sys/types.h>
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/modctl.h>
+#include <sys/sunddi.h>
+
+extern struct streamtab ppp_compinfo;
+
+static struct fmodsw fsw = {
+    "ppp_comp",
+    &ppp_compinfo,
+    D_NEW | D_MP | D_MTQPAIR
+};
+
+extern struct mod_ops mod_strmodops;
+
+static struct modlstrmod modlstrmod = {
+    &mod_strmodops,
+    "PPP compression module",
+    &fsw
+};
+
+static struct modlinkage modlinkage = {
+    MODREV_1,
+    (void *) &modlstrmod,
+    NULL
+};
+
+/*
+ * Entry points for modloading.
+ */
+int
+_init(void)
+{
+    return mod_install(&modlinkage);
+}
+
+int
+_fini(void)
+{
+    return mod_remove(&modlinkage);
+}
+
+int
+_info(mip)
+    struct modinfo *mip;
+{
+    return mod_info(&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 "AS IS" 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 <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/conf.h>
+#include <sys/modctl.h>
+#include <sys/sunddi.h>
+#include <sys/ksynch.h>
+
+#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 */
+    &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 */
+    &cb_ppp_ops,			/* devo_cb_ops */
+    NULL				/* devo_bus_ops */
+};
+
+/*
+ * Module linkage information
+ */
+
+static struct modldrv modldrv = {
+    &mod_driverops,			/* says this is a pseudo driver */
+    "PPP-2.3 multiplexing driver",
+    &ppp_ops				/* driver ops */
+};
+
+static struct modlinkage modlinkage = {
+    MODREV_1,
+    (void *) &modldrv,
+    NULL
+};
+
+int
+_init(void)
+{
+    return mod_install(&modlinkage);
+}
+
+int
+_fini(void)
+{
+    return mod_remove(&modlinkage);
+}
+
+int
+_info(mip)
+    struct modinfo *mip;
+{
+    return mod_info(&modlinkage, mip);
+}
+
+static int
+ppp_identify(dip)
+    dev_info_t *dip;
+{
+    return strcmp(ddi_get_name(dip), "ppp") == 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, "ppp", S_IFCHR, 0, DDI_PSEUDO, CLONE_DEV)
+	== DDI_FAILURE) {
+	ddi_remove_minor_node(dip, NULL);
+	return DDI_FAILURE;
+    }
+    rw_init(&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(&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 (blino at mandriva.com)
+ *
+ * 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 "log.h"
+#include "modules.h"
+#include "probing.h"
+#include "frontend.h"
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <string.h>
+#include "utils.h"
+
+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("FATAL ERROR IN MODULES LOADER: %s\n\nI can't recover from this.\nYou may reboot your system.\n", msg);
+	exit(EXIT_FAILURE);
+}
+
+int main(int argc, char **argv, char **env)
+{
+	enum media_bus bus = BUS_ANY;
+	char *module = NULL;
+	char options[500] = "";
+
+	if (argc > 1) {
+		if (streq(argv[1], "--usb")) {
+			bus = BUS_USB;
+		} else if (!ptr_begins_static_str(argv[1], "--")) {
+			int i;
+			module = argv[1];
+			for (i = 2; i < argc; i++) {
+				strcat(options, argv[i]);
+				strcat(options, " ");
+			}
+		}
+	}
+
+	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 (gc at mandriva.com)
+ *
+ * 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 (ewt at redhat.com)
+ *
+ * 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 <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <fnmatch.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <pci/pci.h>
+#include <libldetect.h>
+#include "stage1.h"
+
+#include "log.h"
+#include "utils.h"
+#include "frontend.h"
+#include "modules.h"
+#include "pci-resource/pci-ids.h"
+#ifdef ENABLE_USB
+#include "usb-resource/usb-ids.h"
+#endif
+#ifdef ENABLE_PCMCIA
+#include "sysfs/libsysfs.h"
+#include "pcmcia-resource/pcmcia-ids.h"
+#endif
+
+#include "probing.h"
+
+
+struct media_info {
+	char * name;
+	char * model;
+	enum media_type type;
+};
+
+
+static void warning_insmod_failed(enum insmod_return r)
+{
+	if (IS_AUTOMATIC && r == INSMOD_FAILED_FILE_NOT_FOUND)
+		return;
+	if (r != INSMOD_OK) {
+		if (r == INSMOD_FAILED_FILE_NOT_FOUND)
+			stg1_error_message("This floppy doesn't contain the driver.");
+		else
+			stg1_error_message("Warning, installation of driver failed. (please include msg from <Alt-F3> for bugreports)");
+	}
+}
+
+#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 : "unknown";
+}
+
+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 >= net_intf_too_early_number) {
+			log_message("NET: was expecting another network interface (broken net module?)");
+			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 < net_descr_number ; i++)
+		if (!strcmp(net_descriptions[i].intf_name, intf_name))
+			return net_descriptions[i].intf_description;
+	return strdup("unknown");
+}
+#endif
+
+static int device_match_modules_list(struct pciusb_entry *e, char **modules, unsigned int modules_len) {
+	int i;
+	if (!e->module)
+		return 0;
+	for (i = 0; i < modules_len; i++)
+		if (!strcmp(modules[i], e->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 >= 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("detected_device_new: could not (re)allocate table. Let it crash, sorry");
+	}
+	return &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->vendor = vendor;
+	dev->device = device;
+	dev->subvendor = subvendor;
+	dev->subdevice = subdevice;
+	strncpy(dev->module, module, sizeof(dev->module) - 1);
+	dev->module[sizeof(dev->module) - 1] = '\0';
+	strncpy(dev->description, safe_descr(name), sizeof(dev->description) - 1);
+	dev->description[sizeof(dev->description) - 1] = '\0';
+	log_message("detected device (%04x, %04x, %04x, %04x, %s, %s)", 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->vendor, e->device, e->subvendor, e->subdevice,
+				    e->text, e->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 < entries.nb; i++) {
+		struct pciusb_entry *e = &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->vendor, e->device, e->subvendor, e->subdevice, e->text, e->module);
+	}
+	pciusb_free(&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[] = {
+                { "ahci", "ata_piix" },
+        };
+	int mappings_nb = sizeof(mappings) / sizeof(struct alternate_mapping);
+        int i;
+
+	for (i=0; i<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("found alternate module %s for driver %s", 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("Loading driver for media adapter:\n \n%s", description);
+		failed = my_insmod(driver, MEDIA_ADAPTERS, NULL, 1);
+		alternate = get_alternate_module(driver);
+		if (!IS_NOAUTO && 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("Loading driver for network device:\n \n%s", 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 < entries.nb; i++) {
+		struct pciusb_entry *e = &entries.entries[i];
+		if (device_match_modules_list(e, pci_modules, pci_modules_len)) {
+			log_message("PCI: device %04x %04x %04x %04x is \"%s\", driver is %s",
+				    e->vendor, e->device, e->subvendor, e->subdevice, safe_descr(e->text), e->module);
+			discovered_device(type, e->text, e->module);
+		}
+	}
+	pciusb_free(&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 < entries.nb; i++) {
+		struct pciusb_entry *e = &entries.entries[i];
+		if (e->vendor == VIRTIO_PCI_VENDOR) {
+			if (!loaded_pci) {
+				log_message("loading virtio-pci");
+				my_insmod("virtio_pci", ANY_DRIVER_TYPE, NULL, 0);
+				loaded_pci = 1;
+			}
+
+			name = NULL;
+			options = NULL;
+
+			switch (e->subdevice) {
+			case VIRTIO_ID_NET:
+				name = "virtio_net";
+				options = "csum=0";
+				break;
+			case VIRTIO_ID_BLOCK:
+				name = "virtio_blk";
+				break;
+			case VIRTIO_ID_BALLOON:
+				name = "virtio_balloon";
+				break;
+			default:
+				log_message("warning: unknown virtio device %04x", e->device);
+			}
+			if (name) {
+				log_message("virtio: loading %s", name);
+				my_insmod(name, ANY_DRIVER_TYPE, options, 0);
+			}
+		}
+	}
+	pciusb_free(&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) && !(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("none", "/proc/bus/usb", "usbfs", 0, NULL) &&
+			    mount("none", "/proc/bus/usb", "usbdevfs", 0, NULL)) {
+				log_message("USB: couldn't mount /proc/bus/usb");
+				goto end_usb_probe;
+			}
+			wait_message("Detecting USB devices.");
+			sleep(4); /* sucking background work */
+			my_insmod("usbhid", ANY_DRIVER_TYPE, NULL, 0);
+			remove_wait_message();
+		}
+
+		if (type != NETWORK_DEVICES)
+			goto end_usb_probe;
+
+		entries = usb_probe();
+		for (i = 0; i < entries.nb; i++) {
+			struct pciusb_entry *e = &entries.entries[i];
+			if (device_match_modules_list(e, usb_modules, usb_modules_len)) {
+				log_message("USB: device %04x %04x is \"%s\" (%s)", e->vendor, e->device, safe_descr(e->text), e->module);
+				discovered_device(type, e->text, e->module);
+			}
+		}
+		pciusb_free(&entries);
+	end_usb_probe:;
+	}
+#endif
+
+#ifdef ENABLE_PCMCIA
+	/* ---- PCMCIA probe ---------------------------------------------- */
+	if ((bus == BUS_PCMCIA || bus == BUS_ANY) && !(IS_NOAUTO)) {
+		struct pcmcia_alias * pcmciadb = NULL;
+		unsigned int len = 0;
+		char *base = "/sys/bus/pcmcia/devices";
+		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->d_name[0] == '.')
+				continue;
+
+			log_message("PCMCIA: device found %s", dent->d_name);
+
+			snprintf(keyfile, sizeof(keyfile)-1, "%s/%s/modalias", base, dent->d_name);
+			modalias_attr = sysfs_open_attribute(keyfile);
+			if (!modalias_attr)
+				continue;
+			if (sysfs_read_attribute(modalias_attr) != 0 || !modalias_attr->value) {
+				sysfs_close_attribute(modalias_attr);
+				continue;
+			}
+
+			log_message("PCMCIA: device found %s", modalias_attr->value);
+
+			for (i = 0; i < len; i++) {
+				if (!fnmatch(pcmciadb[i].modalias, modalias_attr->value, 0)) {
+					char product[256];
+
+					log_message("PCMCIA: device found %s (%s)", pcmciadb[i].modalias, pcmciadb[i].module);
+					strcpy(product, "");
+					for (id = 1; id <= 4; id++) {
+						struct sysfs_attribute *product_attr;
+						snprintf(keyfile, sizeof(keyfile)-1, "%s/%s/prod_id%d", base, dent->d_name, id);
+						product_attr = sysfs_open_attribute(keyfile);
+						if (!product_attr)
+							continue;
+						if (sysfs_read_attribute(product_attr) || !product_attr->value) {
+							sysfs_close_attribute(product_attr);
+							continue;
+						}
+						snprintf(product + strlen(product), sizeof(product)-strlen(product)-1, "%s%s", product[0] ? " " : "", product_attr->value);
+						if (product[strlen(product)-1] == '\n')
+							product[strlen(product)-1] = '\0';
+						sysfs_close_attribute(product_attr);
+					}
+
+					if (!product[0])
+						strcpy(product, "PCMCIA device");
+
+					log_message("PCMCIA: device found %s (%s)", 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 && (bus == BUS_USB || bus == BUS_SCSI || bus == BUS_ANY) &&
+            already_probed_usb_controllers && !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("usb_storage", MEDIA_ADAPTERS, NULL, 0); 
+                if (module_already_present("ieee1394"))
+                        my_insmod("sbp2", MEDIA_ADAPTERS, NULL, 0);
+                wait_message("Detecting USB mass-storage devices.");
+                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("looking for media adapters");
+	probe_that_type(MEDIA_ADAPTERS, bus);
+
+	/* ----------------------------------------------- */
+	if (bus != BUS_IDE && bus != BUS_ANY)
+		goto find_media_after_ide;
+	log_message("looking for ide media");
+
+    	strcpy(b, "/proc/ide/hd");
+    	for (b[12] = 'a'; b[12] <= 't'; b[12]++) {
+		int i;
+		char ide_disk[] = "disk";
+		char ide_cdrom[] = "cdrom";
+		char ide_tape[] = "tape";
+		char ide_floppy[] = "floppy";
+		
+		/* first, test if file exists (will tell if attached medium exists) */
+		b[13] = '\0';
+		if (access(b, R_OK))
+			continue;
+
+		tmp[count].name = strdup("hda");
+		tmp[count].name[2] = b[12];
+
+		/* media type */
+		strcpy(b + 13, "/media");
+		fd = open(b, O_RDONLY);
+		if (fd == -1) {
+			log_message("failed to open %s for reading", b);
+			continue;
+		}
+
+		i = read(fd, buf, sizeof(buf));
+		if (i == -1) {
+			log_message("failed to read %s", 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, "/model");
+		fd = open(b, O_RDONLY);
+		if (fd == -1) {
+			log_message("failed to open %s for reading", b);
+			continue;
+		}
+
+		i = read(fd, buf, sizeof(buf));
+		if (i <= 0) {
+			log_message("failed to read %s", b);
+			tmp[count].model = strdup("(none)");
+		}
+		else {
+			buf[i-1] = '\0'; /* eat the \n */
+			tmp[count].model = strdup(buf);
+		}
+		close(fd);
+
+		log_message("IDE/%d: %s is a %s", tmp[count].type, tmp[count].name, tmp[count].model);
+		count++;
+    	}
+
+ find_media_after_ide:
+	/* ----------------------------------------------- */
+	if (bus != BUS_SCSI && bus != BUS_USB && bus != BUS_PCMCIA && bus != BUS_ANY)
+		goto find_media_after_scsi;
+	log_message("looking for scsi media");
+
+	fd = open("/proc/scsi/scsi", 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[] = "Attached devices: none";
+		char scsi_some_devices[] = "Attached devices:";
+		char scsi_host[] = "Host: ";
+		char scsi_vendor[] = "  Vendor: ";
+
+		int i = read(fd, &buf, sizeof(buf)-1);
+		if (i < 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, "Model:");
+				if (!chptr)
+					goto end_scsi;
+
+				chptr--;
+				while (*chptr == ' ')
+					chptr--;
+				if (*chptr == ':') {
+					chptr++;
+					*(chptr + 1) = '\0';
+					strcpy(tmp_model,"(unknown)");
+				} else {
+					*(chptr + 1) = '\0';
+					strcpy(tmp_model, start);
+				}
+
+				/* (2) Grab Model info */
+				start = end;
+				start += 7;
+				
+				chptr = strstr(start, "Rev:");
+				if (!chptr)
+					goto end_scsi;
+				
+				chptr--;
+				while (*chptr == ' ') chptr--;
+				*(chptr + 1) = '\0';
+				
+				strcat(tmp_model, " ");
+				strcat(tmp_model, start);
+
+				tmp[count].model = strdup(tmp_model);
+				
+				state = SCSI_TYPE;
+
+				break;
+
+			case SCSI_TYPE:
+				if (strncmp("  Type:", start, 7))
+					goto end_scsi;
+				*tmp_name = '\0';
+
+				if (strstr(start, "Direct-Access")) {
+					sprintf(tmp_name, "sd%c", scsi_disk_count++);
+					tmp[count].type = DISK;
+				} else if (strstr(start, "Sequential-Access")) {
+					sprintf(tmp_name, "st%c", scsi_tape_count++);
+					tmp[count].type = TAPE;
+				} else if (strstr(start, "CD-ROM")) {
+					sprintf(tmp_name, "sr%c", scsi_cdrom_count++);
+					tmp[count].type = CDROM;
+				}
+
+                                if (!(f = fopen("/proc/partitions", "rb")) || !fgets(buf, sizeof(buf), f) || !fgets(buf, sizeof(buf), f)) {
+                                        log_message("Couldn't open /proc/partitions");
+                                } 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, "/dev/");
+                                                sscanf(buf, " %d %d %d %s", &major, &minor, &blocks, &name[5]);
+                                                if (streq(&name[5], tmp_name) && tmp[count].type == DISK && ((blocks == 1048575) || (blocks == 1440)))
+                                                        tmp[count].type = FLOPPY;
+                                                /* Try to create all devices while we have major/minor */
+                                                if ((ptr = strchr(&name[5], '/'))) {
+                                                        *ptr = '\0';
+                                                        if (stat(name, &statbuf))
+                                                                mkdir(name, 0755);
+                                                        *ptr = '/';
+                                                }							
+                                                if (stat(name, &statbuf) && mknod(name, S_IFBLK | 0600, makedev(major, minor))) {
+                                                        log_perror(name);
+                                                }
+                                        }
+                                        fclose(f);
+                                }
+
+				if (*tmp_name) {
+					tmp[count].name = strdup(tmp_name);
+					log_message("SCSI/%d: %s is a %s", tmp[count].type, tmp[count].name, tmp[count].model);
+					count++;
+				}
+				
+				state = SCSI_HOST;
+			}
+			
+			start = next;
+		}
+		
+	end_scsi:;
+	}
+
+	/* ----------------------------------------------- */
+	log_message("looking for Compaq Smart Array media");
+	{
+		char * procfiles[] = { "/proc/driver/cpqarray/ida0", "/proc/driver/cciss/cciss0", // 2.4 style
+				       "/proc/array/ida", "/proc/cciss/cciss",                 // 2.2 style
+				       NULL };
+		static char cpq_descr[] = "Compaq RAID logical disk";
+		char ** procfile;
+		FILE * f;
+
+		for (procfile = procfiles; procfile && *procfile; procfile++) {
+			if((f = fopen(*procfile, "rb"))) {
+				while (fgets(buf, sizeof(buf), f)) {
+					if (ptr_begins_static_str(buf, "ida/") || ptr_begins_static_str(buf, "cciss/")) {
+						char * end = strchr(buf, ':');
+						if (!end)
+							log_message("Inconsistency in %s, line:\n%s", *procfile, buf);
+						else {
+							*end = '\0';
+							tmp[count].name = strdup(buf);
+							tmp[count].type = DISK;
+							tmp[count].model = cpq_descr;
+							log_message("CPQ: found %s", tmp[count].name);
+							count++;
+						}
+					}
+				}
+				fclose(f);
+			}
+		}
+	}
+
+	/* ----------------------------------------------- */
+	log_message("looking for DAC960");
+	{
+		FILE * f;
+		if ((f = fopen("/tmp/syslog", "rb"))) {
+			while (fgets(buf, sizeof(buf), f)) {
+				char * start;
+				if ((start = strstr(buf, "/dev/rd/"))) {
+					char * end = strchr(start, ':');
+					if (!end)
+						log_message("Inconsistency in syslog, line:\n%s", 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 = "(unknown)";
+						log_message("DAC960: found %s (%s)", 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 && m->name) {
+		if (m->type == media) {
+			tmp_names[count] = strdup(m->name);
+			tmp_models[count++] = strdup(m->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[] = { "lo", "ippp", "isdn", "plip", "ppp", "wifi", "sit", NULL };
+	char ** ptr = blacklist;
+
+	while (ptr && *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 => my_insmod => 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("/proc/net/dev", "rb");
+	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("found net interface %s", start);
+				tmp[i++] = strdup(start);
+			} else {
+				log_message("found net interface %s, but blacklisted", start);
+			}
+		}
+
+		fclose(f);
+	} else {
+		log_message("net: could not open devices file");
+	}
+
+	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 (gc at mandriva.com)
+ *
+ * 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 (ewt at redhat.com)
+ *
+ * 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 & 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 (gc at mandriva.com)
+ *
+ * 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 <stdlib.h>
+#define _USE_BSD
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/mount.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/unistd.h>
+#include <sys/select.h>
+
+#include "config-stage1.h"
+#include "frontend.h"
+#include "utils.h"
+#include "params.h"
+
+#include <sys/syscall.h>
+#define reboot(...) syscall(__NR_reboot, __VA_ARGS__)
+
+#if defined(__i386__) || defined(__x86_64__)
+#define ENABLE_RESCUE_MS_BOOT 1
+#endif
+
+char * env[] = {
+	"PATH=/usr/bin:/bin:/sbin:/usr/sbin:/mnt/sbin:/mnt/usr/sbin:/mnt/bin:/mnt/usr/bin",
+	"LD_LIBRARY_PATH=/lib:/usr/lib:/mnt/lib:/mnt/usr/lib:/usr/X11R6/lib:/mnt/usr/X11R6/lib"
+#if defined(__x86_64__) || defined(__ppc64__)
+	":/lib64:/usr/lib64:/usr/X11R6/lib64:/mnt/lib64:/mnt/usr/lib64:/mnt/usr/X11R6/lib64"
+#endif
+	,
+	"HOME=/",
+	"TERM=linux",
+	"TERMINFO=/etc/terminfo",
+	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, &t, 1);
+}
+
+
+/* ------ UUURGH this is duplicated from `init.c', don't edit here........ */
+void fatal_error(char *msg)
+{
+	printf("FATAL ERROR IN RESCUE: %s\n\nI can't recover from this.\nYou may reboot your system.\n", msg);
+	while (1);
+}
+
+#define LOOP_CLR_FD	0x4C01
+void del_loop(char *device) 
+{
+	int fd;
+	if ((fd = open(device, O_RDONLY, 0)) < 0) {
+		printf("del_loop open failed\n");
+		return;
+	}
+
+	if (ioctl(fd, LOOP_CLR_FD, 0) < 0) {
+		printf("del_loop ioctl failed");
+		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("unmounting filesystems...\n"); 
+	
+	fd = open("/proc/mounts", O_RDONLY, 0);
+	if (fd < 1) {
+		printf("ERROR: failed to open /proc/mounts");
+		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, "/") != 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 < numfs; i++) {
+			/*printf("trying with %s\n", fs[i].name);*/
+			if (fs[i].mounted && umount(fs[i].name) == 0) { 
+				if (strncmp(fs[i].dev + sizeof("/dev/") - 1, "loop",
+					    sizeof("loop") - 1) == 0)
+					del_loop(fs[i].dev);
+				
+				printf("\t%s\n", fs[i].name);
+				fs[i].mounted = 0;
+				nb++;
+			}
+		}
+	} while (nb);
+	
+	for (i = nb = 0; i < numfs; i++)
+		if (fs[i].mounted) {
+			printf("\t%s umount failed\n", fs[i].name);
+			if (strcmp(fs[i].fs, "ext2") == 0) nb++; /* don't count not-ext2 umount failed */
+		}
+	
+	if (nb) {
+		printf("failed to umount some filesystems\n");
+		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[] = "Re-install Boot Loader";
+#if ENABLE_RESCUE_MS_BOOT
+	char restore_ms_boot[] = "Restore Windows Boot Loader";
+#endif
+	char mount_parts[] = "Mount your partitions under /mnt";
+	char go_to_console[] = "Go to console";
+	char reboot_[] = "Reboot";
+	char doc[] = "Doc: what's addressed by this Rescue?";
+
+	char upgrade[] = "Upgrade to New Version";
+	char rootpass[] = "Reset Root Password";
+	char userpass[] = "Reset User Password";
+	char factory[] = "Reset to Factory Defaults";
+	char backup[] = "Backup User Files";
+	char restore[] = "Restore User Files from Backup";
+	char badblocks[] = "Test Key for Badblocks";
+
+	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("flash");
+	actions = !flash_mode ?
+	    actions_default :
+	    streq(flash_mode, "upgrade") ? actions_flash_upgrade : actions_flash_rescue;
+
+	init_frontend("Welcome to " DISTRIB_NAME " Rescue (" DISTRIB_VERSION ") " __DATE__ " " __TIME__);
+
+	do {
+		int pid;
+		char * binary = NULL;
+
+		choice = "";
+		results = ask_from_list("Please choose the desired action.", actions, &choice);
+
+		if (ptr_begins_static_str(choice, install_bootloader)) {
+			binary = "/usr/bin/install_bootloader";
+		}
+#if ENABLE_RESCUE_MS_BOOT
+		if (ptr_begins_static_str(choice, restore_ms_boot)) {
+			binary = "/usr/bin/restore_ms_boot";
+		}
+#endif
+		if (ptr_begins_static_str(choice, mount_parts)) {
+			binary = "/usr/bin/guessmounts";
+		}
+		if (ptr_begins_static_str(choice, reboot_)) {
+			finish_frontend();
+                        sync(); sync();
+                        sleep(2);
+			unmount_filesystems();
+                        sync(); sync();
+			printf("rebooting system\n");
+			sleep(2);
+			reboot(0xfee1dead, 672274793, 0x01234567);
+		}
+		if (ptr_begins_static_str(choice, doc)) {
+			binary = "/usr/bin/rescue-doc";
+		}
+
+		/* Mandriva Flash entries */
+		if (ptr_begins_static_str(choice, rootpass)) {
+			binary = "/usr/bin/reset_rootpass";
+		}
+		if (ptr_begins_static_str(choice, userpass)) {
+			binary = "/usr/bin/reset_userpass";
+		}
+		if (ptr_begins_static_str(choice, factory)) {
+			binary = "/usr/bin/clear_systemloop";
+		}
+		if (ptr_begins_static_str(choice, backup)) {
+			binary = "/usr/bin/backup_systemloop";
+		}
+		if (ptr_begins_static_str(choice, restore)) {
+			binary = "/usr/bin/restore_systemloop";
+		}
+		if (ptr_begins_static_str(choice, badblocks)) {
+			binary = "/usr/bin/test_badblocks";
+		}
+		if (ptr_begins_static_str(choice, upgrade)) {
+			binary = "/usr/bin/upgrade";
+		}
+
+		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("Can't execute binary (%s)\n<press Enter>\n", binary);
+				PAUSE();
+
+				return 33;
+			}
+			while (wait4(-1, &wait_status, 0, NULL) != pid) {};
+			printf("<press Enter to return to Rescue menu>");
+			PAUSE();
+			resume_from_suspend();
+			if (!WIFEXITED(wait_status) || WEXITSTATUS(wait_status) != 0) {
+				error_message("Program exited abnormally (return code %d).", WEXITSTATUS(wait_status));
+				if (WIFSIGNALED(wait_status))
+					error_message("(received signal %d)", WTERMSIG(wait_status));
+			}
+		}
+
+	} while (results == RETURN_OK && !ptr_begins_static_str(choice, go_to_console));
+
+	finish_frontend();
+	printf("Bye.\n");
+	
+	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 <marc at mbsi.ca>
+with acknowledgements to Rebel.com (http://www.rebel.com).  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 "quickstart" 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 <dfs at roaringpenguin.com> | Roaring Penguin Software Inc.
+http://www.roaringpenguin.com           | 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 > /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
+bxxxxx at sympatico.ca	*		my_password	*
+
+# Replace bxxxxx at sympatico.ca with your Sympatico user-ID
+# Replace my_password with your Sympatico password
+
+# For Magma, use xxyyzz at magma.ca

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
+#       "pppoe" 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 "=" sign.
+
+# Ethernet card connected to ADSL modem
+ETH=eth1
+
+# ADSL user name.  You may have to supply "@provider.com"  Sympatico
+# users in Canada do need to include "@sympatico.ca"
+# Sympatico uses PAP authentication.  Make sure /etc/ppp/pap-secrets
+# contains the right username/password combination.
+# For Magma, use xxyyzz at magma.ca
+USER=bxxxnxnx at sympatico.ca
+
+# 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="" if you don't want
+# anything echoed
+PING="."
+
+# 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="/var/run/$CF_BASE-adsl.pid"
+
+# Do you want to use synchronous PPP?  "yes" or "no".  "yes" is much
+# easier on CPU usage, but may not work for you.  It is safer to use
+# "no", but you may want to experiment with "yes".  "yes" 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
+#   "no".
+# - If you have a computer acting as a gateway for a LAN, choose "1412".
+#   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=""
+
+# Rumour has it that "Citizen's Communications" with a 3Com
+# HomeConnect ADSL Modem DualLink requires these extra options:
+# PPPOE_EXTRA="-f 3c12:3c13 -S ISP"
+
+# Any extra arguments to pass to pppd.  Normally, use a blank string
+# like this:
+PPPD_EXTRA=""
+
+

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 "-n" option to pppoe.
+
+- Fixes for compilation problems on BSD, Solaris and some Linux platforms.
+
+- Added "-p" 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 "-U" (host-unique) option to better support
+  multiple PPPoE links.
+
+- Added support for kernel-mode PPPoE (EXPERIMENTAL, UNSUPPORTED!)
+
+- Added "-o" 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 "setsid" (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 "pty" 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 "spec" to "rp-pppoe.spec" 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 "-f" 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 "netstat -r -n" to determine whether
+  or not link is up.  This should make it independent of locale, I hope!
+
+- Added "-k" and "-d" 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 "init" 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 "restart" and "status" 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 "pap-secrets" 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=bxxxnxnx at sympatico.ca 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 "firewall"  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 "-m 1412" option to pppoe.
+The "-m" 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: "ifconfig eth0 mtu 1452".  For best results, put this
+in an /etc/rc.d/rc.local script.
+
+For Windows, machines, see http://lan.cns.ksu.edu/OS/WIN95/slip95.htm.
+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 <dfs at roaringpenguin.com> | Roaring Penguin Software Inc.
+http://www.roaringpenguin.com           | 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 "ifconfig ethx" 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
+"make", the C compiler and all development header files installed.
+
+-----------------------------------------------------------------------------
+D) pppd complains about (i) "unknown option pty" or (ii) "pty option precludes
+   specifying device name"
+
+(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 "Message too long"
+
+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 "adsl-connect" 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 "-m" option
+to pppoe.  This alters IP packets, which will break any VPN which uses IPSec.
+In /etc/ppp/pppoe.conf, set CLAMPMSS to "no".  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
+"mtu 1492 mru 1492" 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 "pppoe-sniff" program.
+Type "man pppoe-sniff" 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 "PPPOE Session", 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 "./go" 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 http://www.math.uwaterloo.ca/~mostrows/ in
+http://www.math.uwaterloo.ca/~mostrows/ppp-2.4.0-pppoe4.tgz.  It is
+also mirrored at http://www.roaringpenguin.com/pppoe/
+
+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 <dfs at roaringpenguin.com>
+

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 "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+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 "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+        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 "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 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 "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.

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 "Running ./configure..."
+./configure
+if [ "$?" != 0 ] ; then
+    echo "Oops!  It looks like ./configure failed."
+    exit 1
+fi
+
+echo "Running make..."
+make
+if [ "$?" != 0 ] ; then
+    echo "Oops!  It looks like make failed."
+    exit 1
+fi
+
+echo "Running make install..."
+make install
+
+if [ "$?" != 0 ] ; then
+    echo "Oops!  It looks like make install failed."
+    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 ""
+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 "`uname`" != "Linux" ; then
+    echo "Sorry, the GUI only works on Linux."
+    exit 1
+fi
+
+# Figure out directory of script
+MYDIR=`dirname $0`
+cd $MYDIR/src
+
+echo "Running ./configure..."
+./configure
+if [ "$?" != 0 ] ; then
+    echo "Oops!  It looks like ./configure failed."
+    exit 1
+fi
+
+echo "Running make..."
+make
+if [ "$?" != 0 ] ; then
+    echo "Oops!  It looks like make failed."
+    exit 1
+fi
+
+echo "Running make install..."
+make install
+
+if [ "$?" != 0 ] ; then
+    echo "Oops!  It looks like make install failed."
+    exit 1
+fi
+
+echo "Building GUI wrapper..."
+cd ../gui
+make
+if [ "$?" != 0 ] ; then
+    echo "Oops!  It looks like make failed."
+    exit 1
+fi
+
+echo "Installing GUI..."
+make install
+
+if [ "$?" != 0 ] ; then
+    echo "Oops!  It looks like make install failed."
+    exit 1
+fi
+
+# Install entry in KDE menu
+if test -n "$KDEDIR" ; then
+    echo "Installing KDE menu entry Internet : TkPPPoE..."
+    mkdir -p "$KDEDIR/share/applnk/Internet"
+    cat <<EOF > "$KDEDIR/share/applnk/Internet/tkpppoe.kdelnk"
+# 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>/dev/null`
+if test -n "$GNOMEDIR" ; then
+    echo "Installing GNOME menu entry Internet : TkPPPoE..."
+    mkdir -p "$GNOMEDIR/gnome/apps/Internet"
+cat <<EOF > "$GNOMEDIR/gnome/apps/Internet/tkpppoe.desktop"
+[Desktop Entry]
+Name=TkPPPoE
+Comment=Start/Stop ADSL connections
+Exec=tkpppoe
+Terminal=0
+Type=Application
+EOF
+fi
+echo "Running GUI configuration tool..."
+tkpppoe &
+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="$(ADSL_START_PATH)"' '-DADSL_STOP_PATH="$(ADSL_STOP_PATH)"' '-DADSL_STATUS_PATH="$(ADSL_STATUS_PATH)"'
+
+CFLAGS= @CFLAGS@ $(DEFINES) $(PATHS)
+
+all: pppoe-wrapper
+	@echo ""
+	@echo "Type 'make install' as root to install the software."
+
+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 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="GENERATOR" content="Mozilla/4.76 [en] (X11; U; Linux 2.2.14-5.0 i686) [Netscape]">
+   <title>TkPPPoE Manual</title>
+</head>
+<body text="#000000" bgcolor="#FFFFFF" link="#0000EF" vlink="#59188E" alink="#FF0000">
+
+<center>
+<h1>tkpppoe - A GUI for managing PPPoE Connections</h1>
+</center>
+
+<h1>Introduction</h1>
+
+TkPPPoE is a graphical user interface for managing PPPoE connections.  It
+performs two different functions:
+<ul>
+<li>TkPPPoE lets you <em>define</em> connection properties.  This step must
+be done as root.
+<li>TkPPPoE lets you <em>start and stop</em> PPPoE connections.  This step
+may be done as a normal user, depending on how you configured the connection.
+</ul>
+
+<h1>Defining Connections</h1>
+
+To define connections, start TkPPPoE as root.  You can do this from
+a terminal by typing <code>tkpppoe</code>, or from the KDE or GNOME menus
+by selecting <b>Internet : TkPPPoE</b>.  The following window pops up:
+
+<p>
+<center><img src="mainwin.png" width="361" height="73" alt="Main Window">
+</center>
+
+<p>
+Because you have not yet defined any connections, the connection property
+window also pops up:
+
+<p>
+<center><img src="props-basic.png" width="440" height="259" alt="Connection Properties - Basic">
+</center>
+
+You can pop up the connection property window at any time by clicking
+<b>New Connection...</b>  You can edit the properties of an existing
+connection by selecting the connection's name and clicking
+<b>Properties...</b>
+<h4>Basic Information</h4>
+
+Let's fill in the basic information:
+<ul>
+<li>For <b>Connection Name</b>, 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 <b>Default</b>.
+<li>For <b>User Name</b>, enter the user name supplied by your ISP.  Enter
+only the user name; do not enter an "@isp.com" part.
+<li>For <b>Network</b>, you may have to enter your ISP's domain name.
+(For example, <b>isp.com</b>.)  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.
+<li>For <b>Password</b>, enter the password your ISP provided you with.
+</ul>
+
+<h4>NIC and DNS</h4>
+Click on the <b>NIC and DNS</b> tab:
+
+<p>
+<center><img src="props-nic.png" width="440" height="259" alt="Connection Properties - NIC and DNS"></center>
+<p>
+<ul>
+<li>For <b>Ethernet Interface</b>, enter the Ethernet interface connected
+to the DSL modem.  It is something like <b>eth0</b> or <b>eth1</b>.  Click
+on <b>...</b> to browse a list of detected Ethernet interfaces.
+<li>For <b>DNS Setup</b>, you have three options:
+<ol>
+<li><b>From Server</b> means that the system will obtain DNS information from
+the PPPoE server.  This is the correct choice for most ISPs.
+<li><b>Specify</b> means that you will enter the IP addresses of your DNS
+servers manually.  In this case, enter the addresses in the <b>Primary DNS</b>
+and <b>Secondary DNS</b> entries.
+<li><b>Do not Adjust</b> 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.
+</ol>
+</ul>
+
+<h4>Options</h4>
+Click on the <b>Options</b> tab:
+
+<p>
+<center><img src="props-options.png" width="440" height="259" alt="Connection Properties - Options"></center>
+<p>
+<ul>
+<li>If you want ordinary users to be able to start and stop this connection,
+enable <b>Allow use by non-root users</b>.  If you do not enable this,
+non-root users will be able to monitor the connection, but not control it.
+<li>If you want to use synchronous PPP, enable <b>Use synchronous PPP</b>.
+This is recommended as it conserves CPU usage, but may not work on some
+(misconfigured) Linux kernels.
+<li>For <b>Firewalling</b>, you have three options:
+<ol>
+<li><b>Stand-Alone</b> installs a simple firewall ruleset for stand-alone
+machines.  Use this if you have only a single computer connected to the DSL
+modem.
+<li><b>Masquerading</b> 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.
+<li><b>None</b>.  If you already have your own firewall rules, or you wish
+to run servers on your machine, select None.  This is <em>not recommended</em>
+unless you take steps to secure your machine, and know what you are doing.
+</ol>
+</ul>
+
+<h4>Advanced</h4>
+Click on the <b>Advanced</b> tab:
+
+<p>
+<center><img src="props-advanced.png" width="440" height="259" alt="Connection Properties - Advanced"></center>
+<p>
+
+In most cases, you can leave <b>AC-Name</b> and <b>Service-Name</b> blank.
+In some cases, your ISP may require you to enter information in these fields;
+contact your ISP for more information.
+
+<h1>Controlling Connections</h1>
+For these examples, run <code>tkpppoe</code> as a normal user (not root).
+The main window appears like this:
+
+<p>
+<center><img src="mainwin-nonroot.png" width="206" height="73" alt="Main Window - Non-root">
+</center>
+<p>
+<ul>
+<li>To start a connection, press <b>Start</b>.  The two LEDs flash red
+and grey.  If the connection is established, they turn green.
+<li>To stop a connection, press <b>Stop</b>.
+</ul>
+
+<p>The two rectangles to the right of the connection name are the
+<em>status LEDs</em>.  The top LED corresponds to transmitted data and
+the bottom to received.  The LEDs are colored as follows:
+<ul>
+<li>Grey -- connection is not established.
+<li>Flashing red/grey -- connection is being started.
+<li>Green -- connection is up, but idle.
+<li>Yellow -- connection is up and data is being sent or received.
+<li>Red -- connection has been lost, but the system is trying to reestablish it.
+</ul>
+
+<p>
+When a connection is established, two graphs appear:
+
+<p>
+<center><img src="mainwin-busy.png" width="206" height="73" alt="Main Window - Established Connection">
+</center>
+<p>
+
+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.
+
+<h1>Miscellaneous Information</h1>
+<ul>
+<li>The connection menu has an entry called <b>User's Manual</b> which
+will pop up this user manual (if you have Netscape installed.)
+<li>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.
+<li>If you exit from TkPPPoE, connections which are up remain up.  You
+have to explicitly stop connections if you want them terminated.
+</ul>
+<hr>
+<a href="http://www.roaringpenguin.com/pppoe/">TkPPPoE</a> is Copyright 2001 by <a href="http://www.roaringpenguin.com">Roaring Penguin Software Inc</a> and
+is licensed under the GNU General Public License.
+<p>Screenshots show TkPPPoE running under the <a href="http://www.xfce.org">XFCE</a> desktop, a lightweight UNIX and Linux desktop.
+</body>
+</html>

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 @@
+.\" $Id: pppoe-wrapper.1 195724 2001-06-11 13:49:39Z gc $ 
+.TH PPPOE-WRAPPER 1 "26 February 2001"
+.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 <dfs at roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.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 @@
+.\" $Id: tkpppoe.1 195724 2001-06-11 13:49:39Z gc $ 
+.TH TKPPPOE 1 "26 February 2001"
+.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 <dfs at roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.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 "Roaring Penguin" logo is a trademark of Roaring Penguin Software Inc.
+#
+#   http://www.roaringpenguin.com
+#
+#--------------------------------------------------------------
+
+# $Id: tkpppoe.in 195724 2001-06-11 13:49:39Z gc $
+
+# the next line restarts using wish \
+umask 022; \
+exec wish "$0" "$@" || clear; echo "*****"; echo "Cannot find 'wish' -- you need Tcl/Tk installed to run this program"; 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 {"[tk appname]" != "TkPPPoE"} {
+    # 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 "already run" 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 "@WRAPPER@"
+
+# 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 <Enter> "HelpWindowEntered %W"
+bind HelpWin <Leave> "HelpWindowLeft %W"
+
+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 "$HelpData($w) Enter"
+	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 "$HelpData($w) Leave"
+	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 "$win" when mouse enters "$w"
+#***********************************************************************
+proc RegisterHelpWindow {w helptext win} {
+    global HelpData
+    set tags [bindtags $w]
+    if {[lsearch -exact $tags HelpWin] < 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 "Enter" or "Leave"
+# %RETURNS:
+#  Nothing
+# %DESCRIPTION:
+#  Clears out $tw; if $what is "Enter", puts $text in $tw.
+#***********************************************************************
+proc HelpInTextWin {text tw what} {
+    $tw configure -state normal
+    $tw delete 1.0 end
+    if {"$what" == "Enter"} {
+	$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 "Penguin"
+# %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 "r"]
+	while {1} {
+	    if {[gets $fp line] < 0} {
+		break
+	    }
+	    set line [string trim $line]
+	    if {[string match "#*" $line]} {
+		continue
+	    }
+	    if {"$line" == ""} {
+		continue
+	    }
+	    set ConnectionInfo $line
+	    break
+	}
+	close $fp
+    } err]
+    if {$problem} {
+	tk_dialog .err Error "Error loading configuration file: $err" error 0 OK
+    }
+    # Try loading and merging passwords if the password file is readable
+    if {![file readable $PasswordFile]} {
+	return
+    }
+
+    set fp [open $PasswordFile "r"]
+    while {1} {
+	if {[gets $fp line] < 0} {
+	    break
+	}
+	set line [string trim $line]
+	if {[string match "#*" $line]} {
+	    continue
+	}
+	if {"$line" == ""} {
+	    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 {"$conn" != ""} {
+	    lappend conn Password $password
+	    ReplaceConnection $conn
+	}
+    }
+}
+
+#***********************************************************************
+# %PROCEDURE: GetConnection
+# %ARGUMENTS:
+#  name -- name of connection
+# %RETURNS:
+#  key/value pair listing connection configuration, or "" if not found.
+#***********************************************************************
+proc GetConnection { name } {
+    global ConnectionInfo
+    foreach thing $ConnectionInfo {
+	if {[value $thing ConnectionName] == "$name"} {
+	    return $thing
+	}
+    }
+    return ""
+}
+    
+
+#***********************************************************************
+# %PROCEDURE: DeleteConnection
+# %ARGUMENTS:
+#  name -- name of connection
+# %RETURNS:
+#  Nothing, but deletes connection named "$name"
+#***********************************************************************
+proc DeleteConnection { name } {
+    global ConnectionInfo ConfigDir
+    set newInfo {}
+    set found 0
+    foreach thing $ConnectionInfo {
+	if {[value $thing ConnectionName] == "$name"} {
+	    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 ""
+	} 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] == "$name"} {
+	    lappend newInfo $conn
+	    set found 1
+	} else {
+	    lappend newInfo $thing
+	}
+    }
+    if {!$found} {
+	lappend newInfo $conn
+    }
+    set ConnectionInfo $newInfo
+}
+
+proc DeletePPPoEConnection {} {
+    set conn [GetCurrentConnection]
+    if {"$conn" == ""} {
+	return
+    }
+    set ans [tk_dialog .confirm "Confirm Deletion - RP-PPPoE" "Are you sure you wish to delete the connection `$conn'?" 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 . "RP-PPPoE"
+    wm iconname . "PPPoE"
+    frame .f1
+    label .l1 -text "Connection: "
+    menubutton .m1 -text "" -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 "#808080" -fill "#A0A0A0" -tags xmitrect
+    .c create rectangle 10 10 30 18 -outline "#808080" -fill "#A0A0A0" -tags recvrect
+
+    frame .buttons
+    button .start -text "Start" -command "StartPPPoEConnection"
+    button .stop -text "Stop" -command "StopPPPoEConnection"
+    button .exit -text "Exit" -command "exit"
+    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 "Delete" -command "DeletePPPoEConnection"
+	button .new -text "New Connection..." -command "NewPPPoEConnection"
+	button .props -text "Properties..." -command "EditConnectionProps"
+	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 ""
+	if {$Admin} {
+	    update idletasks
+	    NewPPPoEConnection
+	} else {
+	    tk_dialog .note Note "Note: There are no connections defined.  You must run this program as root to define connections" 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 "" if not found.
+#***********************************************************************
+proc value { lst key } {
+    set idx [lsearch -exact $lst $key]
+    if {$idx >= 0} {
+	return [lindex $lst [expr $idx+1]]
+    }
+    return ""
+}
+
+#***********************************************************************
+# %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 {"$found" != ""} {
+	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 "User's Manual" -command Help
+}
+
+#***********************************************************************
+# %PROCEDURE: SetButtonStates
+# %ARGUMENTS:
+#  None
+# %RETURNS:
+#  Nothing
+# %DESCRIPTION:
+#  Enables or disables buttons, as appropriate
+#***********************************************************************
+proc SetButtonStates {} {
+    global Admin
+    set conn [GetCurrentConnection]
+    if {"$conn" == ""} {
+	.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 {"$startstop" == "started"} {
+	    .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 "|/sbin/ifconfig" "r"]
+    while {[gets $fp line] >= 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 {"$conn" == ""} {
+	return
+    }
+
+    if {"$UpdateToken" != ""} {
+	after cancel $UpdateToken
+	set UpdateToken ""
+    }
+
+    catch { unset StartState }
+    set StartState(chars) ""
+    set StartState(status) ""
+    set StartState(msg) ""
+    set StartState(flip) 0
+
+    set fp [open "|$Wrapper start $conn" "r"]
+
+    # Set fileevent
+    fileevent $fp readable [list StartFPReadable $fp]
+
+    LockGui $fp
+    vwait StartState(status)
+    UnlockGui
+
+    if {$StartState(status) == "failed"} {
+	tk_dialog .err Error "Error starting connection: $StartState(msg)" 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) "Connection aborted by user"
+    set StartState(status) "failed"
+}
+    
+#***********************************************************************
+# %PROCEDURE: StartFPReadable
+# %ARGUMENTS:
+#  fp -- file handle
+# %RETURNS:
+#  Nothing
+# %DESCRIPTION:
+#  Called when the "adsl-start" file handle is readable.
+#***********************************************************************
+proc StartFPReadable { fp } {
+    global StartState
+    set char [read $fp 1]
+    if {$char == ""} {
+	set uhoh [catch {close $fp} err]
+	if {$uhoh} {
+	    set StartState(status) "failed"
+	    set StartState(msg) $err
+	} else {
+	    set StartState(status) "succeeded"
+	}
+	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 {"$conn" == ""} {
+	return
+    }
+    set fp [open "|$Wrapper stop $conn" "r"]
+    while {1} {
+	set char [read $fp 1]
+	if {"$char" == ""} {
+	    break;
+	}
+    }
+    set uhoh [catch {close $fp} err]
+    if {$uhoh} {
+	# Ignore a common error
+	if {![string match "*appears to have died*" $err]} {
+	    tk_dialog .err Error "Error stopping connection: $err" error 0 OK
+	}
+    }
+    SetButtonStates
+    UpdateConnectionState 0
+}
+
+#***********************************************************************
+# %PROCEDURE: NewPPPoEConnection
+# %ARGUMENTS:
+#  name -- if supplied, we're editing the existing connection "name"
+# %RETURNS:
+#  Nothing
+# %DESCRIPTION:
+#  Creates a new PPPoE connection
+#***********************************************************************
+proc NewPPPoEConnection {{name ""}} {
+    set w .newcon
+    if {[winfo exists $w]} {
+	wm deiconify $w
+	raise $w
+	return
+    }
+
+    toplevel $w
+    if {"$name" == ""} {
+	wm title $w "New Connection - RP-PPPoE"
+	wm iconname $w "New Connection"
+    } else {
+	wm title $w "Edit Connection - RP-PPPoE"
+	wm iconname $w "Edit Connection"
+    }
+    wm withdraw $w
+
+    tabnotebook_create $w.tn
+    set basic [tabnotebook_page $w.tn "Basic"]
+    set interface [tabnotebook_page $w.tn "NIC and DNS"]
+    set opts [tabnotebook_page $w.tn "Options"]
+    set advanced [tabnotebook_page $w.tn "Advanced"]
+
+    # ----------- BASIC PAGE -------------
+    label $w.lconName -text "Connection Name: " -anchor e
+    if {"$name" != ""} {
+	label $w.conName -text $name -anchor w
+    } else {
+	entry $w.conName -width 15
+	RegisterHelpWindow $w.lconName "Enter a name for this connection.  It can contain letters, numbers, undescores and the minus-sign." $w.help
+	RegisterHelpWindow $w.conName "Enter a name for this connection.  It can contain letters, numbers, undescores and the minus-sign." $w.help
+    }
+
+    label $w.luser -text "User Name: " -anchor e
+    entry $w.user -width 15
+    RegisterHelpWindow $w.luser "Enter your user name.  Do not add a domain-name after the user name." $w.help
+    RegisterHelpWindow $w.user "Enter your user name.  Do not add a domain-name after the user name." $w.help
+
+    label $w.lnet -text "Network: " -anchor e
+    entry $w.network -width 15
+    RegisterHelpWindow $w.lnet "Some ISP's require you to enter their domain-name here (e.g. \"sympatico.ca\")." $w.help
+    RegisterHelpWindow $w.network "Some ISP's require you to enter their domain-name here (e.g. \"sympatico.ca\")." $w.help
+
+    label $w.lpass -text "Password: " -anchor e
+    entry $w.pass -width 15 -show "*"
+    RegisterHelpWindow $w.lpass "Enter your password." $w.help
+    RegisterHelpWindow $w.pass "Enter your password." $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 "Ethernet Interface: " -anchor e
+    entry $w.ifname -width 8
+    RegisterHelpWindow $w.lifname "Enter Ethernet interface to which DSL modem is attached." $w.help
+    RegisterHelpWindow $w.ifname "Enter Ethernet interface to which DSL modem is attached." $w.help
+
+    if {[llength $ifs] > 0} {
+	menubutton $w.ifmb -relief raised -text "..." -menu $w.ifmb.menu
+	RegisterHelpWindow $w.ifmb "Browse detected Ethernet interface names." $w.help
+	menu $w.ifmb.menu -tearoff 0
+	foreach if $ifs {
+	    $w.ifmb.menu add command -label $if -command "$w.ifname delete 0 end; $w.ifname insert end [list $if]"
+	}
+	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 "DNS Setup: " -anchor e
+    menubutton $w.dns -text "From Server" -menu $w.dns.menu -relief raised -indicatoron 1
+    menu $w.dns.menu -tearoff 0
+    foreach thing {"From Server" "Specify" "Do not Adjust"} {
+	$w.dns.menu add command -label $thing -command [list SetDNSOption $w $thing]
+    }
+    RegisterHelpWindow $w.ldns "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." $w.help
+    RegisterHelpWindow $w.dns "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." $w.help
+
+    label $w.ldns1 -text "Primary DNS: " -anchor e
+    entry $w.dns1 -width 16
+    RegisterHelpWindow $w.ldns1 "Enter the IP address of the primary DNS server." $w.help
+    RegisterHelpWindow $w.dns1 "Enter the IP address of the primary DNS server." $w.help
+    label $w.ldns2 -text "Secondary DNS: " -anchor e
+    entry $w.dns2 -width 16
+    RegisterHelpWindow $w.ldns2 "Enter the IP address of the secondary DNS server." $w.help
+    RegisterHelpWindow $w.dns2 "Enter the IP address of the secondary DNS server." $w.help
+
+    SetDNSOption $w "From Server"
+    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 "Allow use by non-root users" -variable OPTS(nonroot) -anchor w
+    RegisterHelpWindow $w.nonroot "If enabled, ordinary users can start and stop this connection." $w.help
+    checkbutton $w.sync -text "Use synchronous PPP" -variable OPTS(sync) -anchor w
+    RegisterHelpWindow $w.sync "Use synchronous PPP (recommended -- easier on the CPU.)" $w.help
+    label $w.lfw -text "Firewalling: " -anchor e
+    if {[llength $ifs] == 1} {
+	set defaultFW "Stand-Alone"
+    } else {
+	set defaultFW "Masquerading"
+    }
+    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 "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." $w.help
+    RegisterHelpWindow $w.fw "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." $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 "Service-Name: " -anchor e
+    entry $w.servicename -width 24
+
+    label $w.lac -text "AC-Name: " -anchor e
+    entry $w.acname -width 24
+
+    RegisterHelpWindow $w.lac "Enter access concentrator name if required.  Most ISPs do not require this; try leaving it blank." $w.help
+    RegisterHelpWindow $w.acname "Enter access concentrator name if required.  Most ISPs do not require this; try leaving it blank." $w.help
+    grid $w.lsn $w.servicename -in $advanced -sticky nsew
+    grid $w.lac $w.acname -in $advanced -sticky nsew
+    RegisterHelpWindow $w.lsn "Enter service name if required.  Most ISPs do not require this; try leaving it blank." $w.help
+    RegisterHelpWindow $w.servicename "Enter service name if required.  Most ISPs do not require this; try leaving it blank." $w.help
+
+    grid columnconfigure $advanced 1 -weight 1
+
+    # ----------- BUTTONS -------------
+    frame $w.buttons
+    button $w.ok -text "OK" -command [list NewPPPoEConnectionOK $name $w]
+    button $w.cancel -text "Cancel" -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 {"$name" != ""} {
+	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 {"$opt" == "Specify"} {
+	$w.dns1 configure -state normal -background white
+	$w.dns2 configure -state normal -background white
+    } else {
+	$w.dns1 configure -state disabled -background "#d9d9d9"
+	$w.dns2 configure -state disabled -background "#d9d9d9"
+    }
+}
+
+# ----------------------------------------------------------------------
+# Tabbed notebook code from "Effective Tcl/Tk Programming"
+# ----------------------------------------------------------------------
+#  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) ""
+    set tnInfo($win-current) ""
+    set tnInfo($win-pending) ""
+    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) == ""} {
+        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 > $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 <ButtonPress-1> \
+            [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) != ""} {
+        tabnotebook_display $win $tnInfo($win-current)
+    } else {
+        tabnotebook_display $win [lindex $tnInfo($win-tabs) 0]
+    }
+    set tnInfo($win-pending) ""
+}
+
+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) ""
+    set nbInfo($win-current) ""
+    return $win
+}
+
+proc notebook_page {win name} {
+    global nbInfo
+
+    set page "$win.page[incr nbInfo($win-count)]"
+    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 ""
+    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 == ""} {
+        error "bad notebook page \"$name\""
+    }
+
+    notebook_fix_size $win
+
+    if {$nbInfo($win-current) != ""} {
+        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 > $maxw} {
+            set maxw $w
+        }
+        set h [winfo reqheight $page]
+        if {$h > $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 "Connection name must be non-blank and contain only letters, digits, `_' and `-'"
+    }
+
+    # Check DNS
+    set type [value $ans DNSType]
+    if {"$type" == "Specify"} {
+	set dns [value $ans DNS1]
+	if {![regexp {[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+} "$dns"]} {
+	    error "Primary DNS entry must consist of four dot-separated decimal numbers"
+	}
+	set dns [value $ans DNS2]
+	if {"$dns" != "" && ![regexp {[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+} "$dns"]} {
+	    error "Secondary DNS entry must consist of four dot-separated decimal numbers"
+	}
+    }
+    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 "Invalid Parameters" "$err" error 0 OK
+	return
+    }
+    if {"$name" == ""} {
+	set name [value $conn ConnectionName]
+	set tmp [GetConnection $name]
+	if {"$tmp" != ""} {
+	tk_dialog .err "Connection Exists" "The connection `$name' already exists.  Pick another name." error 0 OK
+	return
+	}
+    }
+    ReplaceConnection $conn
+    SaveConnectionInfo
+    BuildConnectionMenu
+    SwitchConnection $name
+    destroy $w
+}
+
+proc SaveConnectionInfo {} {
+    global ConnectionInfo ConnectionInfoFile PasswordFile
+    set fp [open "$ConnectionInfoFile.new" "w"]
+    puts $fp "# RP-PPPoE GUI Configuration Information."
+    puts $fp "# This file may *look* human-editable, but it is NOT."
+    puts $fp "# So, you with the text editor:  Keep away from this file."
+    puts $fp "#"
+    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 "$PasswordFile.new" "w"]
+    exec chmod 600 "$PasswordFile.new"
+    puts $fp "# RP-PPPoE GUI Configuration Information."
+    puts $fp "# This file may *look* human-editable, but it is NOT."
+    puts $fp "# So, you with the text editor:  Keep away from this file."
+    puts $fp "#"
+    puts $fp $passwords
+    close $fp
+    file rename -force "$ConnectionInfoFile.new" "$ConnectionInfoFile"
+    file rename -force "$PasswordFile.new" "$PasswordFile"
+
+    # 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 {"[string index $rest 0]" == "\""} {
+	set rest [string range $rest 1 end]
+	set nextquote [string first "\"" $rest]
+	# If no following quote, pretend we haven't seen a quote, I guess.
+	if {$nextquote >= 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] > 0} {
+	set char [string index $rest 0]
+	set rest [string range $rest 1 end]
+	# Sneaky test for whitespace in Tcl 8.0
+	if {"[string trim $char]" == ""} {
+	    return [list $ans $rest]
+	}
+	if {"$char" == "\\"} {
+	    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 {"$net" != ""} {
+	set user "$user@$net"
+    }
+    GenerateSecretsEntryForFile $user $password "/etc/ppp/pap-secrets"
+    GenerateSecretsEntryForFile $user $password "/etc/ppp/chap-secrets"
+}
+
+#***********************************************************************
+# %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 "$fname.new" "w"]
+    exec chmod go-rwx "$fname.new"
+    if {[file exists $fname]} {
+	set in [open $fname "r"]
+	while {[gets $in line] >= 0} {
+	    set trimmed [string trim $line]
+	    if {"$trimmed" == ""} {
+		puts $out $line
+		continue
+	    }
+	    if {[string match "#*" $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 "$user\t*\t$password\t*"
+    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 ""
+    foreach char [split $str ""] {
+	if {[string first $char "01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_+=- at ./"] >= 0} {
+	    append ans $char
+	} else {
+	    append ans "\\$char"
+	}
+    }
+    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 "$fname.new" w]
+    puts $fp "# Configuration file for connection `$name'."
+    puts $fp "# Automatically generated.  Do not edit by hand."
+    puts $fp ""
+    foreach {var val} $conn {
+	switch -exact $var {
+	    UserName {
+		set net [value $conn NetworkName]
+		if {"$net" != ""} {
+		    set user "$val@$net"
+		} else {
+		    set user "$val"
+		}
+		puts $fp [ShellEscape "USER=$user"]
+	    }
+	    Interface {
+		puts $fp [ShellEscape "ETH=$val"]
+	    }
+	    DNSType {
+		if {"$val" == "From Server"} {
+		    puts $fp "DNSTYPE=SERVER"
+		    puts $fp "USEPEERDNS=yes"
+		} elseif {"$val" == "Specify"} {
+		    puts $fp "DNSTYPE=SPECIFY"
+		    puts $fp "USEPEERDNS=no"
+		} else {
+		    puts $fp "DNSTYPE=NOCHANGE"
+		    puts $fp "USEPEERDNS=no"
+		}
+	    }
+	    DNS1 {
+		puts $fp [ShellEscape "DNS1=$val"]
+	    }
+	    DNS2 {
+		puts $fp [ShellEscape "DNS2=$val"]
+	    }
+	    NonrootOK {
+		if {$val} {
+		    puts $fp "NONROOT=OK"
+		}
+	    }
+	    ACName {
+		puts $fp [ShellEscape "ACNAME=$val"]
+	    }
+	    ServiceName {
+		puts $fp [ShellEscape "SERVICENAME=$val"]
+	    }
+	    FirewallType {
+		if {"$val" == "None"} {
+		    puts $fp "FIREWALL=NONE"
+		} elseif {"$val" == "Masquerading"} {
+		    puts $fp "FIREWALL=MASQUERADE"
+		} else {
+		    puts $fp "FIREWALL=STANDALONE"
+		}
+	    }
+	    Sync {
+		if {$val} {
+		    puts $fp "SYNCHRONOUS=yes"
+		} else {
+		    puts $fp "SYNCHRONOUS=no"
+		}
+	    }
+	}
+    }
+    puts $fp "CONNECT_TIMEOUT=30"
+    puts $fp "CONNECT_POLL=1"
+    puts $fp "FORCEPING=\".\""
+    puts $fp "PIDFILE=/var/run/adsl-$name.pid"
+    puts $fp "CLAMPMSS=1412"
+    puts $fp "LCP_INTERVAL=20"
+    puts $fp "LCP_FAILURE=3"
+    puts $fp "PPPOE_TIMEOUT=80"
+    puts $fp "LINUX_PLUGIN="
+    puts $fp "DEMAND=no"
+    close $fp
+    file rename -force "$fname.new" "$fname"
+}
+
+#***********************************************************************
+# %PROCEDURE: GetConnectionStatus
+# %ARGUMENTS:
+#  conn -- connection name
+# %RETURNS:
+#  A three-element list:
+#  {started/stopped up/down if}
+#  If first element is "started", then connection has been started.
+#  If second element is "up", then connection is up.
+#  If connection is up, third element is PPP interface.
+#***********************************************************************
+proc GetConnectionStatus { conn } {
+    set pidfile "/var/run/adsl-$conn.pid"
+
+    # Check for PID file
+    if {![file readable $pidfile]} {
+	return {stopped down ""}
+    }
+    set fp [open $pidfile "r"]
+    gets $fp pid
+    close $fp
+
+    # Check if process is dead
+    if {![file exists "/proc/$pid"]} {
+	# The pppd might still be running... doh...
+	if {![file readable "$pidfile.pppd"]} {
+	    return {stopped down ""}
+	}
+	set fp [open "$pidfile.pppd" "r"]
+	gets $fp pid
+	close $fp
+	if {![file exists "/proc/$pid"]} {
+	    return {stopped down ""}
+	}
+    }
+
+    # Now get PID of pppd
+    if {![file readable "$pidfile.pppd"]} {
+	return {started down ""}
+    }
+    set fp [open "$pidfile.pppd" "r"]
+    gets $fp pid
+    close $fp
+
+    # Find interface to which it corresponds
+    set pppdfiles [glob -nocomplain "/var/run/ppp*.pid"]
+    set found {}
+    foreach file $pppdfiles {
+	set fp [open $file "r"]
+	gets $fp ifpid
+	close $fp
+	if {$ifpid == $pid} {
+	    set found [file rootname [file tail $file]]
+	    break
+	}
+    }
+    if {"$found" == ""} {
+	return {started down ""}
+    }
+    return [list started up $found]
+}
+
+#***********************************************************************
+# %PROCEDURE: UpdateConnectionState
+# %ARGUMENTS:
+#  fromAfter -- if 1, was called from an "after" callback.
+# %RETURNS:
+#  Nothing
+# %DESCRIPTION:
+#  Updates the "LED" 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 ""
+    }
+
+    set conn [GetCurrentConnection]
+    if {"$conn" == ""} {
+	ConnectionStateOff
+	ResetGraph
+	if {"$UpdateToken" != ""} {
+	    after cancel $UpdateToken
+	    set UpdateToken {}
+	}
+	return
+    }
+
+    foreach {startstop updown interface} [GetConnectionStatus $conn] {break}
+    if {"$startstop" == "stopped"} {
+	ConnectionStateOff
+	ResetGraph
+    } elseif {"$updown" == "down"} {
+	ConnectionStateDown
+	ResetGraph
+    } else {
+	# Get the packet counts
+	set found 0
+	set fp [open "/proc/net/dev" "r"]
+	while {[gets $fp line] >= 0} {
+	    if {![string match "*$interface:*" $line]} {
+		continue
+	    }
+	    set colon [string first ":" $line]
+	    if {$colon < 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 {"$UpdateToken" == ""} {
+	set UpdateToken [after $UpdateInterval UpdateConnectionState]
+    }
+    if {$fromAfter} {
+	SetButtonStates
+    }
+}
+
+proc ConnectionStateOff {} {
+    .c itemconfigure xmitrect -fill "#A0A0A0"
+    .c itemconfigure recvrect -fill "#A0A0A0"
+}
+
+proc ConnectionStateDown {} {
+    .c itemconfigure xmitrect -fill "#A00000"
+    .c itemconfigure recvrect -fill "#A00000"
+}
+
+proc ConnectionStateUp {} {
+    .c itemconfigure xmitrect -fill "#00D000"
+    .c itemconfigure recvrect -fill "#00D000"
+}
+
+proc ConnectionTransmitActive {} {
+    .c itemconfigure xmitrect -fill "#FFFF00"
+}
+
+proc ConnectionTransmitUp {} {
+    .c itemconfigure xmitrect -fill "#00D000"
+}
+
+proc ConnectionReceiveActive {} {
+    .c itemconfigure recvrect -fill "#FFFF00"
+}
+
+proc ConnectionReceiveUp {} {
+    .c itemconfigure recvrect -fill "#00D000"
+}
+
+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 > 0} {
+	set GraphPoints(in) [lrange $GraphPoints(in) $toChop end]
+    }
+    set toChop [expr [llength $GraphPoints(out)] - $w2 - 1]
+    if {$toChop > 0} {
+	set GraphPoints(out) [lrange $GraphPoints(out) $toChop end]
+    }
+    set toChop [expr [llength $GraphPoints(times)] - $w2 - 1]
+    if {$toChop > 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 > $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 > $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] >= 4} {
+	eval ".graph create line $scaled -fill #A00000"
+	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 "$bps"
+	}
+    }
+
+    # 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] >= 4} {
+	eval ".graph create line $scaled -fill #00A000"
+	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 "$bps"
+	}
+    }
+}
+
+proc Pretty { n } {
+    if {$n < 0} {
+	return "***"
+    }
+    if {$n < 1000} {
+	return [format "%.1f" $n]
+    }
+    set n [expr $n/1000.0]
+    if {$n < 1000} {
+	return [format "%.1fk" $n]
+    }
+    set n [expr $n/1000.0]
+    if {$n < 1000} {
+	return [format "%.1fM" $n]
+    }
+    set n [expr $n/1000.0]
+    return [format "%.1fG" $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 "Help file '/usr/share/rp-pppoe-gui/tkpppoe.html' is not installed" error 0 OK	
+	return
+    }
+    catch { exec /bin/sh -c "netscape -remote 'openURL(/usr/share/rp-pppoe-gui/tkpppoe.html)' || netscape /usr/share/rp-pppoe-gui/tkpppoe.html" > /dev/null 2>/dev/null & }
+}
+
+	
+
+#***********************************************************************
+# %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 "w"] }
+    canvas .c -width 374 -height 286 -bg #FFFFCC
+    pack .c
+    drawLogo .c #FFFFCC
+
+    # Funky effect
+    .c create text 4 4 -anchor nw -text "Welcome to RP-PPPoE" \
+	    -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 < 15} {incr i} {
+	.c move logo 20 0
+	update idletasks
+	after 25
+    }
+
+    .c create text 4 28 -anchor nw -text "http://www.roaringpenguin.com" \
+	    -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 "w"]
+	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[] =
+"$Id: wrapper.c 195724 2001-06-11 13:49:39Z gc $";
+
+#define _SVID_SOURCE 1 /* For putenv */
+#define _POSIX_SOURCE 1 /* For fileno */
+#define _BSD_SOURCE 1 /* For setreuid */
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#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) > LINELEN) {
+	fprintf(stderr, "Pathname '%s' too long\n", fname);
+	return 0;
+    }
+
+    /* Must be absolute path */
+    if (*fname != '/') {
+	fprintf(stderr, "Unsafe path '%s' not absolute\n", fname);
+	return 0;
+    }
+
+    /* Check root directory */
+    if (stat("/", &buf) < 0) {
+	perror("stat");
+	return 0;
+    }
+    if (buf.st_uid) {
+	fprintf(stderr, "SECURITY ALERT: Root directory (/) not owned by root\n");
+	return 0;
+    }
+    if (buf.st_mode & (S_IWGRP | S_IWOTH)) {
+	fprintf(stderr, "SECURITY ALERT: Root directory (/) writable by group or other\n");
+	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, &buf) < 0) {
+	    perror("stat");
+	    return 0;
+	}
+	if (buf.st_uid) {
+	    fprintf(stderr, "SECURITY ALERT: '%s' not owned by root\n", path);
+	    return 0;
+	}
+
+	if (buf.st_mode & (S_IWGRP | S_IWOTH)) {
+	    fprintf(stderr, "SECURITY ALERT: '%s' writable by group or other\n",
+		    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("PATH=/bin:/usr/bin:/sbin:/usr/sbin");
+}
+
+/**********************************************************************
+ *%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, "Usage: %s {start|stop|status} connection_name\n",
+		argv[0]);
+	exit(1);
+    }
+
+    if (strcmp(argv[1], "start") &&
+	strcmp(argv[1], "stop") &&
+	strcmp(argv[1], "status")) {
+	fprintf(stderr, "Usage: %s {start|stop|status} connection_name\n",
+		argv[0]);
+	exit(1);
+    }
+
+    /* Connection name can be at most CONN_NAME_LEN chars; alpha, num, underscore */
+    if (strlen(argv[2]) > CONN_NAME_LEN) {
+	fprintf(stderr, "%s: Connection name '%s' too long.\n",
+		argv[0], argv[2]);
+	exit(1);
+    }
+
+    for (cp = argv[2]; *cp; cp++) {
+	if (!strchr("abcdefghijklmnopqrstuvwxyz"
+		    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+		    "0123456789_-", *cp)) {
+	    fprintf(stderr, "%s: Connection name '%s' contains illegal character '%c'\n", argv[0], argv[2], *cp);
+	    exit(1);
+	}
+    }
+
+    /* Open the connection file */
+    sprintf(fname, "/etc/ppp/rp-pppoe-gui/conf.%s", argv[2]);
+    /* Check path sanity */
+    if (!PathOK(fname)) {
+	exit(1);
+    }
+
+    fp = fopen(fname, "r");
+    if (!fp) {
+	fprintf(stderr, "%s: Could not open '%s': %s\n",
+		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, "NONROOT=OK\n")) {
+		allowed = 1;
+		break;
+	    }
+	}
+    }
+    fclose(fp);
+
+    if (!allowed) {
+	fprintf(stderr, "%s: Non-root users are not permitted to control connection '%s'\n", argv[0], argv[2]);
+	exit(1);
+    }
+
+    /* Become root with setuid() to defeat is-root checks in shell scripts */
+    if (setreuid(0, 0) < 0) {
+	perror("setreuid");
+	exit(1);
+    }
+       
+    /* It's OK -- do it.  */
+    if (!strcmp(argv[1], "start")) {
+	if (!PathOK(adsl_start)) exit(1);
+	execl(adsl_start, "adsl-start", fname, NULL);
+    } else if (!strcmp(argv[1], "stop")) {
+	if (!PathOK(adsl_stop)) exit(1);
+	execl(adsl_stop, "adsl-stop", fname, NULL);
+    } else {
+	if (!PathOK(adsl_status)) exit(1);
+	execl(adsl_status, "adsl-status", fname, NULL);
+    }
+    fprintf(stderr, "%s: execl: %s\n", 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 @@
+.\" $Id: adsl-connect.8 195724 2001-06-11 13:49:39Z gc $
+.TH ADSL-CONNECT 8 "21 February 2000"
+.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, b1xxnxnx at sympatico.ca).
+
+.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 <dfs at roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.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 @@
+.\" $Id: adsl-setup.8 195724 2001-06-11 13:49:39Z gc $ 
+.TH ADSL-SETUP 8 "21 February 2000"
+.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 <dfs at roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.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 @@
+.\" $Id: adsl-start.8 195724 2001-06-11 13:49:39Z gc $ 
+.TH ADSL-START 8 "21 February 2000"
+.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 <dfs at roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.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 @@
+.\" $Id: adsl-status.8 195724 2001-06-11 13:49:39Z gc $ 
+.TH ADSL-STATUS 8 "16 March 2000"
+.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 <dfs at roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.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 @@
+.\" $Id: adsl-stop.8 195724 2001-06-11 13:49:39Z gc $ 
+.TH ADSL-STOP 8 "21 February 2000"
+.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 <dfs at roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.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 @@
+.\" $Id: pppoe-relay.8 195724 2001-06-11 13:49:39Z gc $ 
+.TH PPPOE-RELAY 8 "26 January 2001"
+.\""
+.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 "old" 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 <dfs at roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.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 @@
+.\" $Id: pppoe-server.8 195724 2001-06-11 13:49:39Z gc $ 
+.TH PPPOE-SERVER 8 "3 July 2000"
+.\""
+.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 "up"
+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 <dfs at roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.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 @@
+.\" $Id: pppoe-sniff.8 195724 2001-06-11 13:49:39Z gc $ 
+.TH PPPOE-SNIFF 8 "3 July 2000"
+.\""
+.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 "uplink" 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 \fBpppoe at roaringpenguin.com\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 "up"
+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 <dfs at roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.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 @@
+.\" $Id: pppoe.8 195724 2001-06-11 13:49:39Z gc $ 
+.TH PPPOE 8 "3 July 2000"
+.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 "up"
+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,
+http://www.roaringpenguin.com, 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 <dfs at roaringpenguin.com>,
+with much inspiration from an earlier version by Luke Stras.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.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 @@
+.\" $Id: pppoe.conf.5 195724 2001-06-11 13:49:39Z gc $
+.\""
+.TH PPPOE.CONF 5 "21 February 2000"
+.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, b1xxnxnx at sympatico.ca).
+
+.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 "yes", 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 "n_hdlc.o" 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 "clamp" 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: http://www.roaringpenguin.com/pppoe/rp-pppoe-3.0.tar.gz
+Url: http://www.roaringpenguin.com/pppoe/
+Packager: David F. Skoll <dfs at roaringpenguin.com>
+BuildRoot: /tmp/pppoe-build
+Vendor: Roaring Penguin Software Inc.
+Requires: ppp >= 2.3.7
+Requires: rp-pppoe >= 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 "$KDEDIR" ; then
+    mkdir -p "$KDEDIR/share/applnk/Internet"
+    cat <<EOF > "$KDEDIR/share/applnk/Internet/tkpppoe.kdelnk"
+# 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>/dev/null`
+if test -n "$GNOMEDIR" ; then
+    mkdir -p "$GNOMEDIR/gnome/apps/Internet"
+cat <<EOF > "$GNOMEDIR/gnome/apps/Internet/tkpppoe.desktop"
+[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 "$KDEDIR" ; then
+    rm -f "$KDEDIR/share/applnk/Internet/tkpppoe.kdelnk"
+fi
+
+# Remove GNOME menu entry
+GNOMEDIR=`gnome-config --datadir 2>/dev/null`
+if test -n "$GNOMEDIR" ; then
+    rm -f "$GNOMEDIR/gnome/apps/Internet/tkpppoe.desktop"
+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: http://www.roaringpenguin.com/pppoe/rp-pppoe-3.0.tar.gz
+Url: http://www.roaringpenguin.com/pppoe/
+Packager: David F. Skoll <dfs at roaringpenguin.com>
+BuildRoot: /tmp/pppoe-build
+Vendor: Roaring Penguin Software Inc.
+Requires: ppp >= 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="/usr/bin/logger -t `basename $0`"
+
+# Must be root
+if test "`@ID@ -u`" != 0 ; then
+    echo "$0: You must be root to run this script" >& 2
+    exit 1
+fi
+
+if test "$SETSID" != "" -a ! -x "$SETSID"; then
+    SETSID=""
+fi
+
+CONFIG=/etc//ppp/pppoe.conf
+USER=""
+ETH=""
+
+# Sort out command-line arguments
+case "$#" in
+    1)
+	CONFIG="$1"
+	;;
+    3)
+	CONFIG="$3"
+	;;
+esac
+
+if test ! -f "$CONFIG" -o ! -r "$CONFIG" ; then
+    echo "$0: Cannot read configuration file '$CONFIG'" >& 2
+    exit 1
+fi
+
+. $CONFIG
+
+PPPOE_PIDFILE="$PIDFILE.pppoe"
+PPPD_PIDFILE="$PIDFILE.pppd"
+
+# Check for command-line overriding of ETH and USER
+case "$#" in
+    2|3)
+	ETH="$1"
+	USER="$2"
+	;;
+esac
+
+# Check that config file is sane
+if test "$USER" = "" ; then
+    echo "$0: Check '$CONFIG' -- no setting for USER" >& 2
+    exit 1
+fi
+if test "$ETH" = "" ; then
+    echo "$0: Check '$CONFIG' -- no setting for ETH" >& 2
+    exit 1
+fi
+
+PPPD_PID=0
+
+# Catch common error
+if test "$DEBUG" = "1" ; then
+    echo "*** If you want to use DEBUG, invoke adsl-start, not adsl-connect."
+    exit 1
+fi
+
+if test "$DEBUG" != "" ; then
+    if test "$LINUX_PLUGIN" != "" ; then
+	echo "Cannot use DEBUG mode and LINUX_PLUGIN at the same time."
+	echo "Kernel-mode PPPoE is experimental and unsupported."
+	exit 1
+    fi
+    echo "* The following section identifies your Ethernet interface" >> $DEBUG
+    echo "* and user name.  Some ISP's need 'username'; others" >> $DEBUG
+    echo "* need 'username at isp.com'.  Try both" >> $DEBUG
+    echo "ETH=$ETH; USER=$USER" >> $DEBUG
+    echo "---------------------------------------------" >> $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 > /dev/null 2>&1
+    modprobe ppp_async > /dev/null 2>&1
+    modprobe ppp_synctty > /dev/null 2>&1
+    if test -n "$LINUX_PLUGIN" ; then
+	modprobe pppox > /dev/null 2>&1
+	modprobe pppoe > /dev/null 2>&1
+    fi
+fi
+
+if test "$SYNCHRONOUS" = "yes" ; then
+	PPPOE_SYNC=-s
+	PPPD_SYNC=sync
+	# Increase the chances of it working on Linux...
+	if test `uname -s` = Linux ; then
+	    modprobe n_hdlc > /dev/null 2>&1
+	fi
+else
+	PPPOE_SYNC=""
+	PPPD_SYNC=""
+fi
+
+if test -n "$ACNAME" ; then
+    ACNAME="-C $ACNAME"
+fi
+
+if test -n "$SERVICENAME" ; then
+    SERVICENAME="-S $SERVICENAME"
+fi
+
+if test "$CLAMPMSS" = "no" ; then
+	CLAMPMSS=""
+else
+	CLAMPMSS="-m $CLAMPMSS"
+fi
+
+# If DNSTYPE is SERVER, we must use "usepeerdns" option to pppd.
+if test "$DNSTYPE" = "SERVER" ; then
+	USEPEERDNS=yes
+fi
+
+if test "$USEPEERDNS" = "yes" ; then
+	USEPEERDNS="usepeerdns"
+else
+	USEPEERDNS=""
+fi
+
+# Backward config file compatibility
+if test "$DEMAND" = "" ; then
+	DEMAND=no
+fi
+
+if test "$DEMAND" = "no" ; then
+	DEMAND=""
+else
+	DEMAND="demand persist idle $DEMAND 10.112.112.112:10.112.112.113 ipcp-accept-remote ipcp-accept-local connect true noipdefault ktune"
+fi
+
+case "$FIREWALL" in
+    STANDALONE)
+	. /etc/ppp/firewall-standalone
+	;;
+    MASQUERADE)
+	. /etc/ppp/firewall-masq
+	;;
+esac
+
+# If we're using kernel-mode PPPoE on Linux...
+if test "$LINUX_PLUGIN" != "" ; then
+    PLUGIN_OPTS="plugin $LINUX_PLUGIN $ETH"
+    modprobe pppoe > /dev/null 2>&1
+fi
+
+# Standard PPP options we always use
+PPP_STD_OPTIONS="$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"
+
+# Jigger DNS if required...
+if test "$DNSTYPE" = "SERVER" ; then
+    # Sorry, dude...
+    rm -f /etc/resolv.conf
+    ln -s /etc/ppp/resolv.conf /etc/resolv.conf
+elif test "$DNSTYPE" = "SPECIFY" ; then
+    # Sorry, dude...
+    rm -f /etc/resolv.conf
+    echo "nameserver $DNS1" > /etc/resolv.conf
+    if test -n "$DNS2" ; then
+	echo "nameserver $DNS2" >> /etc/resolv.conf
+    fi
+fi
+
+# PPPoE invocation
+PPPOE_CMD="$PPPOE -p $PPPOE_PIDFILE -I $ETH -T $PPPOE_TIMEOUT -U $PPPOE_SYNC $CLAMPMSS $ACNAME $SERVICENAME $PPPOE_EXTRA"
+if test "$DEBUG" != "" ; then
+    if test "$DEMAND" != "" ; then
+	echo "(Turning off DEMAND for debugging purposes)"
+	DEMAND=""
+    fi
+    echo "* The following section shows the pppd command we will invoke" >> $DEBUG
+    echo "pppd invocation" >> $DEBUG
+    echo "$SETSID $PPPD pty '$PPPOE_CMD' $PPP_STD_OPTIONS $PPPD_SYNC debug" >> $DEBUG
+    echo "---------------------------------------------" >> $DEBUG
+    $SETSID $PPPD pty "$PPPOE_CMD -D $DEBUG-0" \
+	$PPP_STD_OPTIONS \
+	$PPPD_SYNC \
+	debug >> $DEBUG 2>&1
+    echo "---------------------------------------------" >> $DEBUG
+    echo "* The following section is an extract from your log." >> $DEBUG
+    echo "* Look for error messages from pppd, such as" >> $DEBUG
+    echo "* a lack of kernel support for PPP, authentication failure" >> $DEBUG
+    echo "* etc." >> $DEBUG
+    echo "Extract from /var/log/messages" >> $DEBUG
+    grep 'ppp' /var/log/messages | tail -150 >> $DEBUG
+    date >> $DEBUG
+    echo "---------------------------------------------" >> $DEBUG
+    echo "* The following section is a dump of the packets" >> $DEBUG
+    echo "* sent and received by rp-pppoe.  If you don't see" >> $DEBUG
+    echo "* any output, it's an Ethernet driver problem.  If you only" >> $DEBUG
+    echo "* see three PADI packets and nothing else, check your cables" >> $DEBUG
+    echo "* and modem.  Make sure the modem lights flash when you try" >> $DEBUG
+    echo "* to connect.  Check that your Ethernet card is in" >> $DEBUG
+    echo "* half-duplex, 10Mb/s mode.  If all else fails," >> $DEBUG
+    echo "* try using pppoe-sniff." >> $DEBUG
+    echo "rp-pppoe debugging dump" >> $DEBUG
+    cat $DEBUG-0 >> $DEBUG
+    rm -f $DEBUG-0
+    for i in 1 2 3 4 5 6 7 8 9 10 ; do
+    echo ""
+    echo ""
+    echo ""
+    done
+    echo "*** Finished debugging run.  Please review the file"
+    echo "*** '$DEBUG' and try to"
+    echo "*** figure out what is going on."
+    echo "***"
+    echo "*** Unfortunately, we can NO LONGER accept debugging"
+    echo "*** output for analysis.  Please do not send this to"
+    echo "*** Roaring Penguin; it is too time-consuming for"
+    echo "*** us to deal with all the analyses we have been sent."
+    exit 0
+fi
+
+echo $$ > $PIDFILE
+
+while [ true ] ; do
+    if test "$LINUX_PLUGIN" != "" ; then
+	$SETSID $PPPD $PPP_STD_OPTIONS $DEMAND &
+	echo "$!" > $PPPD_PIDFILE
+    else
+	$SETSID $PPPD pty "$PPPOE_CMD" \
+	    $PPP_STD_OPTIONS \
+	    $DEMAND \
+	    $PPPD_SYNC &
+	echo "$!" > $PPPD_PIDFILE
+    fi
+    wait
+
+    # Run /etc/ppp/adsl-lost if it exists
+    test -x /etc/ppp/adsl-lost && /etc/ppp/adsl-lost
+
+    # Re-establish the connection
+    $LOGGER -p daemon.notice \
+        "ADSL connection lost; attempting re-connection."
+
+    # 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 "$ADSL_START" = "yes" || exit 0
+
+# The echo return value for success (defined in /etc/rc.config).
+return=$rc_done
+case "$1" in
+    start)
+        echo -n "Bringing up ADSL link"
+        $START  > /dev/null 2>&1 || return=$rc_failed
+        echo -e "$return"
+        ;;
+
+    stop)
+        echo -n "Shutting down ADSL link"
+        $STOP > /dev/null 2>&1 || return=$rc_failed
+        echo -e "$return"
+        ;;
+
+    restart)
+        $0 stop
+        echo "Waiting" $restart_time "seconds for the host to reset itself"
+        sleep $restart_time  #Note: Need time for host to reset itself
+        $0 start
+        ;;
+
+    status)
+        $STATUS
+        ;;
+
+    *)
+        echo "Usage: adsl {start|stop|restart|status}"
+        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 && . /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 "$1" in
+    start)
+        echo -n "Bringing up ADSL link: "
+
+	$START
+	if [ $? = 0 ] ; then
+		echo success
+		touch /var/lock/subsys/adsl
+	else
+		echo failure
+	fi
+        ;;
+
+    stop)
+        echo -n "Shutting down ADSL link: "
+
+	$STOP > /dev/null 2>&1
+	if [ $? = 0 ] ; then
+		echo success
+		rm -f /var/lock/subsys/adsl
+	else
+		echo failure
+	fi
+        ;;
+
+    restart)
+	$0 stop
+	$0 start
+	;;
+
+    status)
+	$STATUS
+	;;
+
+    *)
+        echo "Usage: adsl {start|stop|restart|status}"
+        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 && . /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 "$1" in
+    start)
+        echo -n "Bringing up ADSL link"
+
+	$START
+	if [ $? = 0 ] ; then
+		touch /var/lock/subsys/adsl
+	        echo_success
+	else
+		echo_failure
+	fi
+        echo ""
+        ;;
+
+    stop)
+        echo -n "Shutting down ADSL link"
+
+	$STOP > /dev/null 2>&1
+	if [ $? = 0 ] ; then
+		rm -f /var/lock/subsys/adsl
+	        echo_success
+	else
+		echo_failure
+	fi
+        echo ""
+        ;;
+
+    restart)
+	$0 stop
+	$0 start
+	;;
+
+    status)
+	$STATUS
+	;;
+
+    *)
+        echo "Usage: adsl {start|stop|restart|status}"
+        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="/usr/bin/logger -t `basename $0`"
+
+CONFIG=/etc/ppp/pppoe.conf
+
+# Protect created files
+umask 077
+
+copy() {
+    cp $1 $2
+    if [ "$?" != 0 ] ; then
+	$ECHO "*** Error copying $1 to $2"
+	$ECHO "*** Quitting."
+	exit 1
+    fi
+}
+
+$ECHO "Welcome to the Roaring Penguin ADSL client setup.  First, I will run"
+$ECHO "some checks on your system to make sure the PPPoE client is installed"
+$ECHO "properly..."
+$ECHO ""
+
+# Must be root
+if [ "`@ID@ -u`" != 0 ] ; then
+    $ECHO "$0: Sorry, you must be root to run this script"
+    exit 1
+fi
+
+# Prototype config file must exist
+if [ ! -r "$CONFIG" ] ; then
+    $ECHO "Oh, dear, I don't see the file '$CONFIG' anywhere.  Please"
+    $ECHO "re-install the PPPoE client."
+    exit 1
+fi
+
+# Must have pppd
+if [ ! -x $PPPD ] ; then
+    $ECHO "Oops, I can't execute the program '$PPPD'.  You"
+    $ECHO "must install the PPP software suite, version 2.3.10 or later."
+    exit 1
+fi
+
+. $CONFIG
+
+if [ "$DEMAND" = "" ] ; then
+    DEMAND=no
+fi
+
+# pppoe must exist
+if [ ! -x "$PPPOE" ] ; then
+    $ECHO "Oh, dear, I can't execute the program '$PPPOE'.  Please"
+    $ECHO "re-install the rp-pppoe client."
+    exit 1
+fi
+
+$ECHO "Looks good!  Now, please enter some information:"
+
+while [ true ] ; do
+    $ECHO ""
+    $ECHO "USER NAME"
+    $ECHO ""
+    $ECHO -n ">>> Enter your PPPoE user name (default $USER): "
+    read U
+
+    if [ "$U" = "" ] ; then
+	U="$USER"
+    fi
+
+    # Under Linux, "fix" the default interface if eth1 is not available
+    if test `uname -s` = "Linux" ; then
+	$IFCONFIG $ETH > /dev/null 2>&1 || ETH=eth0
+    fi
+    $ECHO ""
+    $ECHO "INTERFACE"
+    $ECHO ""
+    $ECHO ">>> Enter the Ethernet interface connected to the ADSL modem"
+    $ECHO "For Solaris, this is likely to be something like /dev/hme0."
+    $ECHO "For Linux, it will be ethn, where 'n' is a number."
+    $ECHO -n "(default $ETH): "
+    read E
+
+    if [ "$E" = "" ] ; then
+	E="$ETH"
+    fi
+
+    $ECHO ""
+    $ECHO "Do you want the link to come up on demand, or stay up continuously?"
+    $ECHO "If you want it to come up on demand, enter the idle time in seconds"
+    $ECHO "after which the link should be dropped.  If you want the link to"
+    $ECHO "stay up permanently, enter 'no' (two letters, lower-case.)"
+    $ECHO "NOTE: Demand-activated links do not interact well with dynamic IP"
+    $ECHO "addresses.  You may have some problems with demand-activated links."
+    $ECHO -n ">>> Enter the demand value (default $DEMAND): "
+    read D
+    if [ "$D" = "" ] ; then
+	D=$DEMAND
+    fi
+
+    $ECHO ""
+    $ECHO "DNS"
+    $ECHO ""
+    $ECHO "Please enter the IP address of your ISP's primary DNS server."
+    $ECHO "If your ISP claims that 'the server will provide DNS addresses',"
+    $ECHO "enter 'server' (all lower-case) here."
+    $ECHO "If you just press enter, I will assume you know what you are"
+    $ECHO "doing and not modify your DNS setup."
+    $ECHO -n ">>> Enter the DNS information here: "
+
+    read DNS1
+
+
+    if [ "$DNS1" != "" ] ; then
+        if [ "$DNS1" != "server" ] ; then
+	    $ECHO "Please enter the IP address of your ISP's secondary DNS server."
+	    $ECHO "If you just press enter, I will assume there is only one DNS server."
+	    $ECHO -n ">>> Enter the secondary DNS server address here: "
+	    read DNS2
+	fi
+    fi
+
+    while [ true ] ; do
+	$ECHO ""
+	$ECHO "PASSWORD"
+	$ECHO ""
+	stty -echo
+	$ECHO -n ">>> Please enter your PPPoE password:    "
+	read PWD1
+	$ECHO ""
+	$ECHO -n ">>> Please re-enter your PPPoE password: "
+	read PWD2
+	$ECHO ""
+	stty echo
+	if [ "$PWD1" = "$PWD2" ] ; then
+	    break
+	fi
+
+	$ECHO -n ">>> Sorry, the passwords do not match.  Try again? (y/n)"
+	read ANS
+	case "$ANS" in
+	    N|No|NO|Non|n|no|non)
+		$ECHO "OK, quitting.  Bye."
+		exit 1
+	esac
+    done
+
+    # Firewalling
+    $ECHO ""
+    $ECHO "FIREWALLING"
+    $ECHO ""
+    if test `uname -s` != "Linux" ; then
+	$ECHO "Sorry, firewalling is only supported under Linux.  Consult"
+	$ECHO "your operating system manuals for details on setting up"
+	$ECHO "packet filters for your system."
+	FIREWALL=NONE
+    else
+	$ECHO "Please choose the firewall rules to use.  Note that these rules are"
+	$ECHO "very basic.  You are strongly encouraged to use a more sophisticated"
+	$ECHO "firewall setup; however, these will provide basic security.  If you"
+	$ECHO "are running any servers on your machine, you must choose 'NONE' and"
+	$ECHO "set up firewalling yourself.  Otherwise, the firewall rules will deny"
+	$ECHO "access to all standard servers like Web, e-mail, ftp, etc.  If you"
+	$ECHO "are using SSH, the rules will block outgoing SSH connections which"
+	$ECHO "allocate a privileged source port."
+	$ECHO ""
+	while [ true ] ; do
+	    $ECHO "The firewall choices are:"
+	    $ECHO "0 - NONE: This script will not set any firewall rules.  You are responsible"
+	    $ECHO "          for ensuring the security of your machine.  You are STRONGLY"
+	    $ECHO "          recommended to use some kind of firewall rules."
+	    $ECHO "1 - STANDALONE: Appropriate for a basic stand-alone web-surfing workstation"
+	    $ECHO "2 - MASQUERADE: Appropriate for a machine acting as an Internet gateway"
+	    $ECHO "                for a LAN"
+	    $ECHO -n ">>> Choose a type of firewall (0-2): "
+	    read a
+	    if [ "$a" = 0 -o "$a" = 1 -o "$a" = 2 ] ; then
+		break
+	    fi
+	    $ECHO "Please enter a number from 0 to 2"
+	done
+
+	case "$a" in
+	    0)
+		FIREWALL=NONE
+		;;
+	    1)
+		FIREWALL=STANDALONE
+		;;
+	    2)
+		FIREWALL=MASQUERADE
+		;;
+	esac
+    fi
+
+    $ECHO ""
+    $ECHO "** Summary of what you entered **"
+    $ECHO ""
+    $ECHO "Ethernet Interface: $E"
+    $ECHO "User name:          $U"
+    if [ "$D" = "no" ] ; then
+	$ECHO "Activate-on-demand: No"
+    else
+	$ECHO "Activate-on-demand: Yes; idle timeout = $D seconds"
+    fi
+
+    if [ "$DNS1" != "" ] ; then
+        if [ "$DNS1" = "server" ] ; then
+	    $ECHO "DNS addresses:      Supplied by ISP's server"
+        else
+	    $ECHO "Primary DNS:        $DNS1"
+	    if [ "$DNS2" != "" ] ; then
+		$ECHO "Secondary DNS:      $DNS2"
+	    fi
+        fi
+    else
+	$ECHO "DNS:                Do not adjust"
+    fi
+    $ECHO "Firewalling:        $FIREWALL"
+    $ECHO ""
+    while [ true ] ; do
+        $ECHO -n '>>> Accept these settings and adjust configuration files (y/n)? '
+        read ANS
+	case "ANS" in
+	    Y|y|yes|Yes|oui|Oui)
+		ANS=y
+		;;
+            N|n|no|No|non|Non)
+		ANS=n
+		;;
+	esac
+	if [ "$ANS" = "y" -o "$ANS" = "n" ] ; then
+	    break
+        fi
+    done
+    if [ "$ANS" = "y" ] ; then
+	break
+    fi
+done
+
+# Adjust configuration files.  First to $CONFIG
+
+$ECHO "Adjusting $CONFIG"
+
+copy $CONFIG $CONFIG-bak
+if [ "$DNS1" = "server" ] ; then
+    DNSTYPE=SERVER
+    DNS1=""
+    USEPEERDNS=yes
+else
+    USEPEERDNS=no
+    if [ "$DNS1" = "" ] ; 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 #$(*& ISP's use a slash in the user name...
+sed -e "s&^USER=.*&USER='$U'&" \
+    -e "s&^ETH=.*&ETH='$E'&" \
+    -e "s&^PIDFILE=.*&PIDFILE=\"$VARRUN/\$CF_BASE-adsl.pid\"&" \
+    -e "s/^FIREWALL=.*/FIREWALL=$FIREWALL/" \
+    -e "s/^DEMAND=.*/DEMAND=$D/" \
+    -e "s/^DNSTYPE=.*/DNSTYPE=$DNSTYPE/" \
+    -e "s/^DNS1=.*/DNS1=$DNS1/" \
+    -e "s/^DNS2=.*/DNS2=$DNS2/" \
+    -e "s/^USEPEERDNS=.*/USEPEERDNS=$USEPEERDNS/" \
+    < $CONFIG-bak > $CONFIG
+
+if [ $? != 0 ] ; then
+    $ECHO "** Error modifying $CONFIG"
+    $ECHO "** Quitting"
+    exit 1
+fi
+
+if [ "$DNS1" != "" ] ; then
+    if [ "$DNS1" != "server" ] ; then
+	$ECHO "Adjusting /etc/resolv.conf"
+	if [ -r /etc/resolv.conf ] ; then
+	    grep -s "MADE-BY-RP-PPPOE" /etc/resolv.conf > /dev/null 2>&1
+	    if [ "$?" != 0 ] ; then
+		$ECHO "  (But first backing it up to /etc/resolv.conf-bak)"
+		copy /etc/resolv.conf /etc/resolv.conf-bak
+	    fi
+	fi
+	$ECHO "# MADE-BY-RP-PPPOE" > /etc/resolv.conf
+	$ECHO "nameserver $DNS1" >> /etc/resolv.conf
+	if [ "$DNS2" != "" ] ; then
+	    $ECHO "nameserver $DNS2" >> /etc/resolv.conf
+	fi
+    fi
+fi
+
+$ECHO "Adjusting /etc/ppp/pap-secrets and /etc/ppp/chap-secrets"
+if [ -r /etc/ppp/pap-secrets ] ; then
+    $ECHO "  (But first backing it up to /etc/ppp/pap-secrets-bak)"
+    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 "  (But first backing it up to /etc/ppp/chap-secrets-bak)"
+    copy /etc/ppp/chap-secrets /etc/ppp/chap-secrets-bak
+else
+    cp /dev/null /etc/ppp/chap-secrets-bak
+fi
+
+egrep -v "^$U|^\"$U\"" /etc/ppp/pap-secrets-bak > /etc/ppp/pap-secrets
+$ECHO "\"$U\"	*	\"$PWD1\"" >> /etc/ppp/pap-secrets
+egrep -v "^$U|^\"$U\"" /etc/ppp/chap-secrets-bak > /etc/ppp/chap-secrets
+$ECHO "\"$U\"	*	\"$PWD1\"" >> /etc/ppp/chap-secrets
+
+$ECHO ""
+$ECHO ""
+$ECHO ""
+$ECHO "Congratulations, it should be all set up!"
+$ECHO ""
+$ECHO "Type 'adsl-start' to bring up your ADSL link and 'adsl-stop' to bring"
+$ECHO "it down.  Type 'adsl-status' to see the link status."
+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=""
+ETH=""
+ME=`basename $0`
+# Must be root
+if [ "`@ID@ -u`" != 0 ] ; then
+    $ECHO "$ME: You must be root to run this script" >& 2
+    exit 1
+fi
+
+# Debugging
+if [ "$DEBUG" = "1" ] ; then
+    $ECHO "*** Running in debug mode... please be patient..."
+    DEBUG=/tmp/pppoe-debug-$$
+    export DEBUG
+    mkdir $DEBUG
+    if [ "$?" != 0 ] ; then
+	$ECHO "Could not create directory $DEBUG... exiting"
+	exit 1
+    fi
+    DEBUG=$DEBUG/pppoe-debug.txt
+
+    # Initial debug output
+    $ECHO "---------------------------------------------" > $DEBUG
+    $ECHO "* The following section contains information about your system" >> $DEBUG
+    date >> $DEBUG
+    $ECHO "Output of uname -a" >> $DEBUG
+    uname -a >> $DEBUG
+    $ECHO "---------------------------------------------" >> $DEBUG
+    $ECHO "* The following section contains information about your network" >> $DEBUG
+    $ECHO "* interfaces.  The one you chose for PPPoE should contain the words:" >> $DEBUG
+    $ECHO "* 'UP' and 'RUNNING'.  If it does not, you probably have an Ethernet" >> $DEBUG
+    $ECHO "* driver problem." >> $DEBUG
+    $ECHO "Output of ifconfig -a" >> $DEBUG
+    $IFCONFIG -a >> $DEBUG
+    $ECHO "---------------------------------------------" >> $DEBUG
+    if [ "`uname -s`" = "Linux" ] ; then
+        $ECHO "* The following section contains information about kernel modules" >> $DEBUG
+	$ECHO "* If the module for your Ethernet card is 'tulip', you might" >> $DEBUG
+	$ECHO "* want to look for an updated version at http://www.scyld.com" >> $DEBUG
+	$ECHO "Output of lsmod" >> $DEBUG
+	lsmod >> $DEBUG
+	$ECHO "---------------------------------------------" >> $DEBUG
+    fi
+    $ECHO "* The following section lists your routing table." >> $DEBUG
+    $ECHO "* If you have an entry which starts with '0.0.0.0', you probably" >> $DEBUG
+    $ECHO "* have defined a default route and gateway, and pppd will" >> $DEBUG
+    $ECHO "* not create a default route using your ISP.  Try getting" >> $DEBUG
+    $ECHO "* rid of this route." >> $DEBUG
+    $ECHO "Output of netstat -n -r" >> $DEBUG
+    netstat -n -r >> $DEBUG
+    $ECHO "---------------------------------------------" >> $DEBUG
+    $ECHO "Contents of /etc/resolv.conf" >> $DEBUG
+    $ECHO "* The following section lists DNS setup." >> $DEBUG
+    $ECHO "* If you can browse by IP address, but not name, suspect" >> $DEBUG
+    $ECHO "* a DNS problem." >> $DEBUG
+    cat /etc/resolv.conf >> $DEBUG
+    $ECHO "---------------------------------------------" >> $DEBUG
+    $ECHO "* The following section lists /etc/ppp/options." >> $DEBUG
+    $ECHO "* You should have NOTHING in that file." >> $DEBUG
+    $ECHO "Contents of /etc/ppp/options" >> $DEBUG
+    cat /etc/ppp/options >> $DEBUG 2>/dev/null
+    $ECHO "---------------------------------------------" >> $DEBUG
+else
+    DEBUG=""
+fi
+
+# Sort out command-line arguments
+case "$#" in
+    1)
+	CONFIG="$1"
+	;;
+    3)
+	CONFIG="$3"
+	;;
+esac
+
+if [ ! -f "$CONFIG" -o ! -r "$CONFIG" ] ; then
+    $ECHO "$ME: Cannot read configuration file '$CONFIG'" >& 2
+    exit 1
+fi
+
+. $CONFIG
+
+# Check for command-line overriding of ETH and USER
+case "$#" in
+    2|3)
+	ETH="$1"
+	USER="$2"
+	;;
+esac
+
+# Check for pidfile
+if [ -r "$PIDFILE" ] ; then
+    PID=`cat "$PIDFILE"`
+    # Check if still running
+    kill -0 $PID > /dev/null 2>&1
+    if [ $? = 0 ] ; then
+	$ECHO "$ME: There already seems to be an ADSL connection up (PID $PID)" >& 2
+	exit 1
+    fi
+    # Delete bogus PIDFILE
+    rm -f "$PIDFILE" "$PIDFILE.pppd" "$PIDFILE.pppoe" "$PIDFILE.start"
+fi
+
+echo $$ > $PIDFILE.start
+
+# Start the connection in the background unless we're debugging
+if [ "$DEBUG" != "" ] ; then
+    $CONNECT "$@"
+    exit 0
+fi
+
+$CONNECT "$@" > /dev/null 2>&1 &
+CONNECT_PID=$!
+
+if [ "$CONNECT_TIMEOUT" = "" -o "$CONNECT_TIMEOUT" = 0 ] ; then
+    exit 0
+fi
+
+# Don't monitor connection if dial-on-demand
+if [ "$DEMAND" != "" -a "$DEMAND" != "no" ] ; then
+    exit 0
+fi
+
+# Monitor connection
+TIME=0
+while [ true ] ; do
+    @sbindir@/adsl-status $CONFIG > /dev/null 2>&1
+
+    # Looks like the interface came up
+    if [ $? = 0 ] ; then
+	# Print newline if standard input is a TTY
+	tty -s && $ECHO " Connected!"
+	exit 0
+    fi
+
+    if test -n "$FORCEPING" ; then
+	$ECHO -n "$FORCEPING"
+    else
+	tty -s && $ECHO -n "$PING"
+    fi
+    sleep $CONNECT_POLL
+    TIME=`expr $TIME + $CONNECT_POLL`
+    if [ $TIME -gt $CONNECT_TIMEOUT ] ; then
+	break
+    fi
+done
+
+$ECHO "TIMED OUT" >& 2
+# Timed out!  Kill the adsl-connect process and quit
+kill $CONNECT_PID > /dev/null 2>&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 "$#" in
+    1)
+	CONFIG="$1"
+	;;
+esac
+
+if [ ! -f "$CONFIG" -o ! -r "$CONFIG" ] ; then
+    echo "$0: Cannot read configuration file '$CONFIG'" >& 2
+    exit 1
+fi
+
+. $CONFIG
+
+PPPOE_PIDFILE="$PIDFILE.pppoe"
+PPPD_PIDFILE="$PIDFILE.pppd"
+
+if [ "$DEMAND" != "no" ] ; then
+    echo "Note: You have enabled demand-connection; adsl-status may be inaccurate."
+fi
+
+# If no PPPOE_PIDFILE, connection is down, unless we're using the Linux plugin
+if [ "$LINUX_PLUGIN" = "" ] ; then
+    if [ ! -r "$PPPOE_PIDFILE" ] ; then
+	echo "adsl-status: Link is down (can't read pppoe PID file $PPPOE_PIDFILE)"
+	exit 1
+    fi
+fi
+
+# If no PPPD_PIDFILE, something fishy!
+if [ ! -r "$PPPD_PIDFILE" ] ; then
+    echo "adsl-status: Link is down (can't read pppd PID file $PPPD_PIDFILE)"
+    exit 1
+fi
+
+PPPD_PID=`cat "$PPPD_PIDFILE"`
+
+# 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 [ "$PID" = "$PPPD_PID" ] ; then
+	    IF=`basename $i .pid`
+	    netstat -rn | grep " ${IF}\$" > /dev/null
+	    # /sbin/ifconfig $IF | grep "UP.*POINTOPOINT" > /dev/null
+	    if [ "$?" != "0" ] ; then
+		echo "adsl-status: Link is attached to $IF, but $IF is down"
+		exit 1
+	    fi
+	    echo "adsl-status: Link is up and running on interface $IF"
+	    /sbin/ifconfig $IF
+	    exit 0
+	fi
+    fi
+done
+
+echo "adsl-status: Link is down -- could not find interface corresponding to"
+echo "pppd pid $PPPD_PID"
+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="`basename $0`"
+LOGGER="/usr/bin/logger -t $ME"
+CONFIG="$1"
+if [ "$CONFIG" = "" ] ; then
+    CONFIG=/etc/ppp/pppoe.conf
+fi
+
+if [ ! -f "$CONFIG" -o ! -r "$CONFIG" ] ; then
+    echo "$ME: Cannot read configuration file '$CONFIG'" >& 2
+    exit 1
+fi
+
+. $CONFIG
+
+PPPOE_PIDFILE="$PIDFILE.pppoe"
+PPPD_PIDFILE="$PIDFILE.pppd"
+STARTPID="$PIDFILE.start"
+
+# Backward config file compatibility
+if test "$DEMAND" = "" ; then
+	DEMAND=no
+fi
+
+# Ignore SIGTERM
+trap "" 15
+
+# Check for pidfile
+if [ -r "$PIDFILE" ] ; then
+    PID=`cat $PIDFILE`
+
+    # Check if still running
+    kill -0 $PID > /dev/null 2>&1
+    if [ $? != 0 ] ; then
+	echo "$ME: The adsl-connect script (PID $PID) appears to have died" >& 2
+    fi
+
+    # Kill pppd, which should in turn kill pppoe
+    if [ -r "$PPPD_PIDFILE" ] ; then
+	PPPD_PID=`cat "$PPPD_PIDFILE"`
+	$LOGGER -p daemon.notice "Killing pppd"
+	echo "Killing pppd ($PPPD_PID)"
+	kill $PPPD_PID > /dev/null 2>&1 || exit 1
+    fi
+
+    # Kill adsl-start
+    PIDS=`cat $STARTPID`
+    kill -0 $PIDS > /dev/null 2>&1
+    if [ $? = 0 ] ; then
+	$LOGGER -p daemon.notice "Killing adsl-connect"
+	kill $PIDS > /dev/null 2>&1
+    fi
+
+    # Kill adsl-connect
+    $LOGGER -p daemon.notice "Killing adsl-connect"
+    echo "Killing adsl-connect ($PID)"
+    kill $PID > /dev/null 2>&1
+
+    rm -f "$PIDFILE" "$PPPD_PIDFILE" "$PPPOE_PIDFILE" "$STARTPID"
+else
+    echo "$ME: No ADSL connection appears to be running" >&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 (gc at mandriva.com)
+ #
+ # 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="/sbin/pppoe"' '-DPPPD_PATH="/sbin/pppd"' '-DVERSION="3.0-stg1"'
+
+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 $< -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="$(PPPOE_PATH)"' '-DPPPD_PATH="$(PPPD_PATH)"' \
+	'-DPLUGIN_PATH="$(PLUGIN_PATH)"' \
+	'-DPPPOE_SERVER_OPTIONS="$(PPPOESERVER_PPPD_OPTIONS)"'
+
+CFLAGS= @CFLAGS@ $(DEFINES) $(PATHS)
+TARGETS=@TARGETS@
+
+all: $(TARGETS)
+	@echo ""
+	@echo "Type 'make install' as root to install the software."
+
+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="$(VERSION)"' -c -o pppoe.o pppoe.c
+
+discovery.o: discovery.c pppoe.h
+	@CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o discovery.o discovery.c
+
+ppp.o: ppp.c pppoe.h
+	@CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o ppp.o ppp.c
+
+md5.o: md5.c md5.h
+	@CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o md5.o md5.c
+
+pppoe-server.o: pppoe-server.c pppoe.h
+	@CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o pppoe-server.o pppoe-server.c
+
+pppoe-sniff.o: pppoe-sniff.c pppoe.h
+	@CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o pppoe-sniff.o pppoe-sniff.c
+
+if.o: if.c pppoe.h
+	@CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o if.o if.c
+
+common.o: common.c pppoe.h
+	@CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o common.o common.c
+
+debug.o: debug.c pppoe.h
+	@CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o debug.o debug.c
+
+relay.o: relay.c relay.h pppoe.h
+	@CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -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="$(VERSION)"' -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="$(VERSION)"' -c -o plugin/discovery.o -fPIC discovery.c
+
+plugin/if.o: if.c
+	@CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o plugin/if.o -fPIC if.c
+
+plugin/debug.o: debug.c
+	@CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o plugin/debug.o -fPIC debug.c
+
+plugin/common.o: common.c
+	@CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -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 "# Directory created by rp-pppoe for kernel-mode plugin" > $(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 "NOT overwriting existing $(RPM_INSTALL_ROOT)/etc/ppp/$$i" ;\
+			$(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 "NOT overwriting existing $(RPM_INSTALL_ROOT)$(PPPOESERVER_PPPD_OPTIONS)"; \
+		$(install) -m 644 ../configs/pppoe-server-options $(RPM_INSTALL_ROOT)$(PPPOESERVER_PPPD_OPTIONS)-example ; \
+	fi
+	@if [ -f /etc/redhat-release ] ; then \
+		echo "Looks like a Red Hat system; installing $(RPM_INSTALL_ROOT)/etc/rc.d/init.d/adsl" ; \
+		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 "Looks like a TurboLinux system; installing $(RPM_INSTALL_ROOT)/etc/rc.d/init.d/adsl" ; \
+		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 "Looks like a SuSE Linux system; installing $(RPM_INSTALL_ROOT)/etc/rc.d/init.d/adsl" ; \
+		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 ""
+	@echo "Type 'adsl-setup' to configure the software."
+
+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 > ../rp-pppoe.spec.new && mv ../rp-pppoe.spec.new ../rp-pppoe.spec
+	sed -e 's+^Source: .*$$+Source: http://www.roaringpenguin.com/pppoe/rp-pppoe-$(VERSION).tar.gz+' ../rp-pppoe.spec > ../rp-pppoe.spec.new && mv ../rp-pppoe.spec.new ../rp-pppoe.spec
+	sed -e 's/^Version: .*$$/Version: $(VERSION)/' ../rp-pppoe-gui.spec > ../rp-pppoe-gui.spec.new && mv ../rp-pppoe-gui.spec.new ../rp-pppoe-gui.spec
+	sed -e 's+^Source: .*$$+Source: http://www.roaringpenguin.com/pppoe/rp-pppoe-$(VERSION).tar.gz+' ../rp-pppoe-gui.spec > ../rp-pppoe-gui.spec.new && mv ../rp-pppoe-gui.spec.new ../rp-pppoe-gui.spec
+	sed -e 's+^Requires: rp-pppoe >=.*$$+Requires: rp-pppoe >= $(VERSION)+' ../rp-pppoe-gui.spec > ../rp-pppoe-gui.spec.new && 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[] =
+"$Id: common.c 212191 2005-05-06 06:30:51Z rgarciasuarez $";
+
+#include "pppoe.h"
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#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 "func" for each tag in the packet.
+* "func" is passed the additional argument "extra".
+***********************************************************************/
+int
+parsePacket(PPPoEPacket *packet, ParseFunc *func, void *extra)
+{
+    UINT16_t len = ntohs(packet->length);
+    unsigned char *curTag;
+    UINT16_t tagType, tagLen;
+
+    if (packet->ver != 1) {
+	syslog(LOG_ERR, "Invalid PPPoE version (%d)", (int) packet->ver);
+	return -1;
+    }
+    if (packet->type != 1) {
+	syslog(LOG_ERR, "Invalid PPPoE type (%d)", (int) packet->type);
+	return -1;
+    }
+
+    /* Do some sanity checks on packet */
+    if (len > ETH_DATA_LEN - 6) { /* 6-byte overhead for PPPoE header */
+	syslog(LOG_ERR, "Invalid PPPoE packet length (%u)", len);
+	return -1;
+    }
+
+    /* Step through the tags */
+    curTag = packet->payload;
+    while(curTag - packet->payload < len) {
+	/* Alignment is not guaranteed, so do this by hand... */
+	tagType = (((UINT16_t) curTag[0]) << 8) +
+	    (UINT16_t) curTag[1];
+	tagLen = (((UINT16_t) curTag[2]) << 8) +
+	    (UINT16_t) curTag[3];
+	if (tagType == TAG_END_OF_LIST) {
+	    return 0;
+	}
+	if ((curTag - packet->payload) + tagLen + TAG_HDR_SIZE > len) {
+	    syslog(LOG_ERR, "Invalid PPPoE tag length (%u)", 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->length);
+    unsigned char *curTag;
+    UINT16_t tagType, tagLen;
+
+    if (packet->ver != 1) {
+	syslog(LOG_ERR, "Invalid PPPoE version (%d)", (int) packet->ver);
+	return NULL;
+    }
+    if (packet->type != 1) {
+	syslog(LOG_ERR, "Invalid PPPoE type (%d)", (int) packet->type);
+	return NULL;
+    }
+
+    /* Do some sanity checks on packet */
+    if (len > ETH_DATA_LEN - 6) { /* 6-byte overhead for PPPoE header */
+	syslog(LOG_ERR, "Invalid PPPoE packet length (%u)", len);
+	return NULL;
+    }
+
+    /* Step through the tags */
+    curTag = packet->payload;
+    while(curTag - packet->payload < len) {
+	/* Alignment is not guaranteed, so do this by hand... */
+	tagType = (((UINT16_t) curTag[0]) << 8) +
+	    (UINT16_t) curTag[1];
+	tagLen = (((UINT16_t) curTag[2]) << 8) +
+	    (UINT16_t) curTag[3];
+	if (tagType == TAG_END_OF_LIST) {
+	    return NULL;
+	}
+	if ((curTag - packet->payload) + tagLen + TAG_HDR_SIZE > len) {
+	    syslog(LOG_ERR, "Invalid PPPoE tag length (%u)", 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, "pppoe: %s\n", str);
+    syslog(LOG_ERR, "%s", 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("strdup failed");
+    }
+    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] & 0x0F) * 4;
+
+    memcpy(pseudoHeader, ipHdr+12, 8);
+    pseudoHeader[8] = 0;
+    pseudoHeader[9] = ipHdr[9];
+    pseudoHeader[10] = (count >> 8) & 0xFF;
+    pseudoHeader[11] = (count & 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 > 1) {
+	sum += * (UINT16_t *) addr;
+	addr += 2;
+	count -= 2;
+    }
+    if (count > 0) {
+	sum += *addr;
+    }
+
+    while(sum >> 16) {
+	sum = (sum & 0xffff) + (sum >> 16);
+    }
+    return (UINT16_t) (~sum & 0xFFFF);
+}
+
+/**********************************************************************
+*%FUNCTION: clampMSS
+*%ARGUMENTS:
+* packet -- PPPoE session packet
+* dir -- either "incoming" or "outgoing"
+* 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->payload[0] != 0x00 ||
+	packet->payload[1] != 0x21) {
+	/* Nope, ignore it */
+	return;
+    }
+
+    ipHdr = packet->payload + 2;
+
+    /* Is it too short? */
+    len = (int) ntohs(packet->length);
+    if (len < 42) {
+	/* 20 byte IP header; 20 byte TCP header; 2 byte PPP protocol */
+	return;
+    }
+
+    /* Verify once more that it's IPv4 */
+    if ((ipHdr[0] & 0xF0) != 0x40) {
+	return;
+    }
+
+    /* Is it a fragment that's not at the beginning of the packet? */
+    if ((ipHdr[6] & 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] & 0x0F) * 4;
+
+    /* Is SYN set? */
+    if (!(tcpHdr[13] & 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, "Bad TCP checksum %x", (unsigned int) csum);
+
+	/* Upper layers will drop it */
+	return;
+    }
+
+    /* Look for existing MSS option */
+    endHdr = tcpHdr + ((tcpHdr[12] & 0xF0) >> 2);
+    opt = tcpHdr + 20;
+    while (opt < 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,
+		       "Bogus length for MSS option (%u) from %u.%u.%u.%u",
+		       (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] < 2) {
+		/* Someone's trying to attack us? */
+		syslog(LOG_ERR,
+		       "Bogus TCP option length (%u) from %u.%u.%u.%u",
+		       (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 <= clampMss) {
+	    return;
+	}
+
+	mssopt[2] = (((unsigned) clampMss) >> 8) & 0xFF;
+	mssopt[3] = ((unsigned) clampMss) & 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->session) return;
+
+    /* Do nothing if no discovery socket */
+    if (conn->discoverySocket < 0) return;
+
+    memcpy(packet.ethHdr.h_dest, conn->peerEth, ETH_ALEN);
+    memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);
+
+    packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
+    packet.ver = 1;
+    packet.type = 1;
+    packet.code = CODE_PADT;
+    packet.session = conn->session;
+
+    /* Reset Session to zero so there is no possibility of
+       recursive calls to this function by any signal handler */
+    conn->session = 0;
+
+    /* If we're using Host-Uniq, copy it over */
+    if (conn->useHostUniq) {
+	PPPoETag hostUniq;
+	pid_t pid = getpid();
+	hostUniq.type = htons(TAG_HOST_UNIQ);
+	hostUniq.length = htons(sizeof(pid));
+	memcpy(hostUniq.payload, &pid, sizeof(pid));
+	memcpy(cursor, &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, &err, elen + TAG_HDR_SIZE);
+	cursor += elen + TAG_HDR_SIZE;
+	plen += elen + TAG_HDR_SIZE;
+    }
+	    
+    /* Copy cookie and relay-ID if needed */
+    if (conn->cookie.type) {
+	CHECK_ROOM(cursor, packet.payload,
+		   ntohs(conn->cookie.length) + TAG_HDR_SIZE);
+	memcpy(cursor, &conn->cookie, ntohs(conn->cookie.length) + TAG_HDR_SIZE);
+	cursor += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
+	plen += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
+    }
+
+    if (conn->relayId.type) {
+	CHECK_ROOM(cursor, packet.payload,
+		   ntohs(conn->relayId.length) + TAG_HDR_SIZE);
+	memcpy(cursor, &conn->relayId, ntohs(conn->relayId.length) + TAG_HDR_SIZE);
+	cursor += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
+	plen += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
+    }
+
+    packet.length = htons(plen);
+    sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
+    if (conn->debugFile) {
+	dumpPacket(conn->debugFile, &packet, "SENT");
+	fprintf(conn->debugFile, "\n");
+	fflush(conn->debugFile);
+    }
+    syslog(LOG_INFO,"Sent PADT");
+}
+
+/**********************************************************************
+*%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, "PADT: Service-Name-Error: %.*s", (int) len, data);
+	fprintf(stderr, "PADT: Service-Name-Error: %.*s\n", (int) len, data);
+	break;
+    case TAG_AC_SYSTEM_ERROR:
+	syslog(LOG_ERR, "PADT: System-Error: %.*s", (int) len, data);
+	fprintf(stderr, "PADT: System-Error: %.*s\n", (int) len, data);
+	break;
+    case TAG_GENERIC_ERROR:
+	syslog(LOG_ERR, "PADT: Generic-Error: %.*s", (int) len, data);
+	fprintf(stderr, "PADT: Generic-Error: %.*s\n", (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 <sys/wait.h> that is POSIX.1 compatible.  */
+#define HAVE_SYS_WAIT_H 1
+
+/* Define to `int' if <sys/types.h> 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 <sys/time.h> and <time.h>.  */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define if your <sys/time.h> 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 <asm/types.h> header file.  */
+#define HAVE_ASM_TYPES_H 1
+
+/* Define if you have the <fcntl.h> header file.  */
+#define HAVE_FCNTL_H 1
+
+/* Define if you have the <getopt.h> header file.  */
+#define HAVE_GETOPT_H 1
+
+/* Define if you have the <linux/if_ether.h> 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 <linux/if_packet.h> header file.  */
+#define HAVE_LINUX_IF_PACKET_H 1
+
+/* Define if you have the <linux/if_pppox.h> header file.  */
+#define HAVE_LINUX_IF_PPPOX_H 1
+
+/* Define if you have the <net/bpf.h> header file.  */
+#define HAVE_NET_BPF_H 1
+
+/* Define if you have the <net/if_arp.h> header file.  */
+//#define HAVE_NET_IF_ARP_H 1
+
+/* Define if you have the <net/ethernet.h> header file.  */
+#define HAVE_NET_ETHERNET_H 1
+
+/* Define if you have the <net/if.h> header file.  */
+#define HAVE_NET_IF_H 1
+
+/* Define if you have the <linux/if.h> header file.  */
+#define HAVE_LINUX_IF_H 1
+
+/* Define if you have the <net/if_dl.h> header file.  */
+/* #undef HAVE_NET_IF_DL_H */
+
+/* Define if you have the <net/if_ether.h> header file.  */
+/* #undef HAVE_NET_IF_ETHER_H */
+
+/* Define if you have the <net/if_types.h> header file.  */
+/* #undef HAVE_NET_IF_TYPES_H */
+
+/* Define if you have the <netinet/if_ether.h> header file.  */
+//#define HAVE_NETINET_IF_ETHER_H 1
+
+/* Define if you have the <netpacket/packet.h> header file.  */
+#define HAVE_NETPACKET_PACKET_H 1
+
+/* Define if you have the <sys/cdefs.h> header file.  */
+#define HAVE_SYS_CDEFS_H 1
+
+/* Define if you have the <sys/dlpi.h> header file.  */
+/* #undef HAVE_SYS_DLPI_H */
+
+/* Define if you have the <sys/ioctl.h> header file.  */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define if you have the <sys/param.h> header file.  */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define if you have the <sys/socket.h> header file.  */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define if you have the <sys/time.h> header file.  */
+#define HAVE_SYS_TIME_H 1
+
+/* Define if you have the <sys/uio.h> header file.  */
+#define HAVE_SYS_UIO_H 1
+
+/* Define if you have the <syslog.h> header file.  */
+#define HAVE_SYSLOG_H 1
+
+/* Define if you have the <unistd.h> 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 <sys/wait.h> that is POSIX.1 compatible.  */
+#undef HAVE_SYS_WAIT_H
+
+/* Define to `int' if <sys/types.h> 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 <sys/time.h> and <time.h>.  */
+#undef TIME_WITH_SYS_TIME
+
+/* Define if your <sys/time.h> 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 <asm/types.h> header file.  */
+#undef HAVE_ASM_TYPES_H
+
+/* Define if you have the <fcntl.h> header file.  */
+#undef HAVE_FCNTL_H
+
+/* Define if you have the <getopt.h> header file.  */
+#undef HAVE_GETOPT_H
+
+/* Define if you have the <linux/if_ether.h> 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 <linux/if_packet.h> header file.  */
+#undef HAVE_LINUX_IF_PACKET_H
+
+/* Define if you have the <linux/if_pppox.h> header file.  */
+#undef HAVE_LINUX_IF_PPPOX_H
+
+/* Define if you have the <net/bpf.h> header file.  */
+#undef HAVE_NET_BPF_H
+
+/* Define if you have the <net/if_arp.h> header file.  */
+#undef HAVE_NET_IF_ARP_H
+
+/* Define if you have the <net/ethernet.h> header file.  */
+#undef HAVE_NET_ETHERNET_H
+
+/* Define if you have the <net/if.h> header file.  */
+#undef HAVE_NET_IF_H
+
+/* Define if you have the <linux/if.h> header file.  */
+#undef HAVE_LINUX_IF_H
+
+/* Define if you have the <net/if_dl.h> header file.  */
+#undef HAVE_NET_IF_DL_H
+
+/* Define if you have the <net/if_ether.h> header file.  */
+#undef HAVE_NET_IF_ETHER_H
+
+/* Define if you have the <net/if_types.h> header file.  */
+#undef HAVE_NET_IF_TYPES_H
+
+/* Define if you have the <netinet/if_ether.h> header file.  */
+#undef HAVE_NETINET_IF_ETHER_H
+
+/* Define if you have the <netpacket/packet.h> header file.  */
+#undef HAVE_NETPACKET_PACKET_H
+
+/* Define if you have the <sys/cdefs.h> header file.  */
+#undef HAVE_SYS_CDEFS_H
+
+/* Define if you have the <sys/dlpi.h> header file.  */
+#undef HAVE_SYS_DLPI_H
+
+/* Define if you have the <sys/ioctl.h> header file.  */
+#undef HAVE_SYS_IOCTL_H
+
+/* Define if you have the <sys/param.h> header file.  */
+#undef HAVE_SYS_PARAM_H
+
+/* Define if you have the <sys/socket.h> header file.  */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define if you have the <sys/time.h> header file.  */
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have the <sys/uio.h> header file.  */
+#undef HAVE_SYS_UIO_H
+
+/* Define if you have the <syslog.h> header file.  */
+#undef HAVE_SYSLOG_H
+
+/* Define if you have the <unistd.h> 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="$ac_help
+  --enable-plugin=pppd_src_path   build pppd plugin"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval "$ac_prev=\$ac_option"
+    ac_prev=
+    continue
+  fi
+
+  case "$ac_option" in
+  -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) ac_optarg= ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case "$ac_option" in
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir="$ac_optarg" ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build="$ac_optarg" ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file="$ac_optarg" ;;
+
+  -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+  | --da=*)
+    datadir="$ac_optarg" ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    eval "enable_${ac_feature}=no" ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix="$ac_optarg" ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he)
+    # Omit some internal or obsolete options to make the list less imposing.
+    # This message is too long to be a string in the A/UX 3.1 sh.
+    cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+  --cache-file=FILE       cache test results in FILE
+  --help                  print this message
+  --no-create             do not create output files
+  --quiet, --silent       do not print \`checking...' messages
+  --version               print the version of autoconf that created configure
+Directory and file names:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [same as prefix]
+  --bindir=DIR            user executables in DIR [EPREFIX/bin]
+  --sbindir=DIR           system admin executables in DIR [EPREFIX/sbin]
+  --libexecdir=DIR        program executables in DIR [EPREFIX/libexec]
+  --datadir=DIR           read-only architecture-independent data in DIR
+                          [PREFIX/share]
+  --sysconfdir=DIR        read-only single-machine data in DIR [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data in DIR
+                          [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data in DIR [PREFIX/var]
+  --libdir=DIR            object code libraries in DIR [EPREFIX/lib]
+  --includedir=DIR        C header files in DIR [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc in DIR [/usr/include]
+  --infodir=DIR           info documentation in DIR [PREFIX/info]
+  --mandir=DIR            man documentation in DIR [PREFIX/man]
+  --srcdir=DIR            find the sources in DIR [configure dir or ..]
+  --program-prefix=PREFIX prepend PREFIX to installed program names
+  --program-suffix=SUFFIX append SUFFIX to installed program names
+  --program-transform-name=PROGRAM
+                          run sed PROGRAM on installed program names
+EOF
+    cat << EOF
+Host type:
+  --build=BUILD           configure for building on BUILD [BUILD=HOST]
+  --host=HOST             configure for HOST [guessed]
+  --target=TARGET         configure for TARGET [TARGET=HOST]
+Features and packages:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --x-includes=DIR        X include files are in DIR
+  --x-libraries=DIR       X library files are in DIR
+EOF
+    if test -n "$ac_help"; then
+      echo "--enable and --with options recognized:$ac_help"
+    fi
+    exit 0 ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host="$ac_optarg" ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir="$ac_optarg" ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir="$ac_optarg" ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir="$ac_optarg" ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir="$ac_optarg" ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst \
+  | --locals | --local | --loca | --loc | --lo)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+  | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+    localstatedir="$ac_optarg" ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir="$ac_optarg" ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir="$ac_optarg" ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix="$ac_optarg" ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix="$ac_optarg" ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix="$ac_optarg" ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name="$ac_optarg" ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir="$ac_optarg" ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir="$ac_optarg" ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site="$ac_optarg" ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir="$ac_optarg" ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir="$ac_optarg" ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target="$ac_optarg" ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers)
+    echo "configure generated by autoconf version 2.13"
+    exit 0 ;;
+
+  -with-* | --with-*)
+    ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "with_${ac_package}='$ac_optarg'" ;;
+
+  -without-* | --without-*)
+    ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    eval "with_${ac_package}=no" ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes="$ac_optarg" ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries="$ac_optarg" ;;
+
+  -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+    ;;
+
+  *)
+    if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+      echo "configure: warning: $ac_option: invalid host type" 1>&2
+    fi
+    if test "x$nonopt" != xNONE; then
+      { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+    fi
+    nonopt="$ac_option"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+  exec 6>/dev/null
+else
+  exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+  case "$ac_arg" in
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c) ;;
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+  *" "*|*"	"*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+  ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+  *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+  esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set.  These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}"    = set; then LC_CTYPE=C;    export LC_CTYPE;    fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=pppoe.c
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then its parent.
+  ac_prog=$0
+  ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+  test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+  srcdir=$ac_confdir
+  if test ! -r $srcdir/$ac_unique_file; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+  if test "$ac_srcdir_defaulted" = yes; then
+    { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+  else
+    { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+  fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+  if test "x$prefix" != xNONE; then
+    CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+  else
+    CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+  fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+  if test -r "$ac_site_file"; then
+    echo "loading site script $ac_site_file"
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  echo "loading cache $cache_file"
+  . $cache_file
+else
+  echo "creating cache $cache_file"
+  > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+  # Stardent Vistra SVR4 grep lacks -e, says ghazi at caip.rutgers.edu.
+  if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+    ac_n= ac_c='
+' ac_t='	'
+  else
+    ac_n=-n ac_c= ac_t=
+  fi
+else
+  ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+
+
+
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:536: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="gcc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:566: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_prog_rejected=no
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+        ac_prog_rejected=yes
+	continue
+      fi
+      ac_cv_prog_CC="cc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# -gt 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    set dummy "$ac_dir/$ac_word" "$@"
+    shift
+    ac_cv_prog_CC="$@"
+  fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+  if test -z "$CC"; then
+    case "`uname -s`" in
+    *win32* | *WIN32*)
+      # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:617: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="cl"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+ ;;
+    esac
+  fi
+  test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:649: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 660 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:665: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  ac_cv_prog_cc_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cc_cross=no
+  else
+    ac_cv_prog_cc_cross=yes
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+  { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:691: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:696: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.c <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:705: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gcc=yes
+else
+  ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:724: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+  ac_cv_prog_cc_g=yes
+else
+  ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+
+
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:758: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    # This must be in double quotes, not single quotes, because CPP may get
+  # substituted into the Makefile and "${CC-cc}" will confuse make.
+  CPP="${CC-cc} -E"
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp.
+  cat > conftest.$ac_ext <<EOF
+#line 773 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:779: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -E -traditional-cpp"
+  cat > conftest.$ac_ext <<EOF
+#line 790 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:796: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -nologo -E"
+  cat > conftest.$ac_ext <<EOF
+#line 807 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:813: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+  ac_cv_prog_CPP="$CPP"
+fi
+  CPP="$ac_cv_prog_CPP"
+else
+  ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:838: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 843 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:851: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  ac_cv_header_stdc=yes
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&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 > conftest.$ac_ext <<EOF
+#line 868 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "memchr" >/dev/null 2>&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 > conftest.$ac_ext <<EOF
+#line 886 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "free" >/dev/null 2>&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 "$cross_compiling" = yes; then
+  :
+else
+  cat > conftest.$ac_ext <<EOF
+#line 907 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:918: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+  cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&6
+echo "configure:942: checking for sys/wait.h that is POSIX.1 compatible" >&5
+if eval "test \"`echo '$''{'ac_cv_header_sys_wait_h'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 947 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+int main() {
+int s;
+wait (&s);
+s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
+; return 0; }
+EOF
+if { (eval echo configure:963: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_header_sys_wait_h=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_sys_wait_h=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_sys_wait_h" 1>&6
+if test $ac_cv_header_sys_wait_h = yes; then
+  cat >> confdefs.h <<\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 "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:987: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 992 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:997: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+
+echo $ac_n "checking for working const""... $ac_c" 1>&6
+echo "configure:1025: checking for working const" >&5
+if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1030 "configure"
+#include "confdefs.h"
+
+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 = "string";
+ccp = &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 = &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
+     "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+  struct s { int j; const int *ap[3]; };
+  struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+  const int foo = 10;
+}
+
+; return 0; }
+EOF
+if { (eval echo configure:1079: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_c_const=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_c_const=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_const" 1>&6
+if test $ac_cv_c_const = no; then
+  cat >> confdefs.h <<\EOF
+#define const 
+EOF
+
+fi
+
+echo $ac_n "checking for pid_t""... $ac_c" 1>&6
+echo "configure:1100: checking for pid_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1105 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])pid_t[^a-zA-Z_0-9]" >/dev/null 2>&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 "$ac_t""$ac_cv_type_pid_t" 1>&6
+if test $ac_cv_type_pid_t = no; then
+  cat >> confdefs.h <<\EOF
+#define pid_t int
+EOF
+
+fi
+
+echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
+echo "configure:1133: checking whether time.h and sys/time.h may both be included" >&5
+if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1138 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+int main() {
+struct tm *tp;
+; return 0; }
+EOF
+if { (eval echo configure:1147: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_header_time=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_time=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_time" 1>&6
+if test $ac_cv_header_time = yes; then
+  cat >> confdefs.h <<\EOF
+#define TIME_WITH_SYS_TIME 1
+EOF
+
+fi
+
+echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6
+echo "configure:1168: checking whether struct tm is in sys/time.h or time.h" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1173 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <time.h>
+int main() {
+struct tm *tp; tp->tm_sec;
+; return 0; }
+EOF
+if { (eval echo configure:1181: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_tm=time.h
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_tm=sys/time.h
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_tm" 1>&6
+if test $ac_cv_struct_tm = sys/time.h; then
+  cat >> confdefs.h <<\EOF
+#define TM_IN_SYS_TIME 1
+EOF
+
+fi
+
+
+# Extract the first word of "echo", so it can be a program name with args.
+set dummy echo; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1205: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_ECHO'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$ECHO" in
+  /*)
+  ac_cv_path_ECHO="$ECHO" # Let the user override the test with a path.
+  ;;
+  ?:/*)			 
+  ac_cv_path_ECHO="$ECHO" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="/usr/ucb/bin:$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_ECHO="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_ECHO" && ac_cv_path_ECHO=""""
+  ;;
+esac
+fi
+ECHO="$ac_cv_path_ECHO"
+if test -n "$ECHO"; then
+  echo "$ac_t""$ECHO" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+$ECHO -n "checking for struct sockaddr_ll... "
+cat > conftest.$ac_ext <<EOF
+#line 1241 "configure"
+#include "confdefs.h"
+#include <asm/types.h>
+#include <linux/if_packet.h>
+#include <linux/if_ether.h>
+
+int main() {
+struct sockaddr_ll sa;
+; return 0; }
+EOF
+if { (eval echo configure:1251: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_sockaddr_ll=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_sockaddr_ll=no
+fi
+rm -f conftest*
+$ECHO $ac_cv_struct_sockaddr_ll
+if test "$ac_cv_struct_sockaddr_ll" = yes ; then
+cat >> confdefs.h <<\EOF
+#define HAVE_STRUCT_SOCKADDR_LL 1
+EOF
+
+fi
+
+$ECHO -n "checking for N_HDLC line discipline... "
+cat > conftest.$ac_ext <<EOF
+#line 1271 "configure"
+#include "confdefs.h"
+#include <linux/termios.h>
+int main() {
+int x = N_HDLC;
+; return 0; }
+EOF
+if { (eval echo configure:1278: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_n_hdlc=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_n_hdlc=no
+fi
+rm -f conftest*
+$ECHO $ac_cv_n_hdlc
+if test "$ac_cv_n_hdlc" = yes ; then
+cat >> confdefs.h <<\EOF
+#define HAVE_N_HDLC 1
+EOF
+
+fi
+
+# Check whether --enable-plugin or --disable-plugin was given.
+if test "${enable_plugin+set}" = set; then
+  enableval="$enable_plugin"
+  ac_cv_pluginpath=$enableval
+else
+  ac_cv_pluginpath=no
+fi
+
+
+LINUX_KERNELMODE_PLUGIN=""
+PPPD_INCDIR=""
+if test "$ac_cv_header_linux_if_pppox_h" = yes ; then
+	if test "$ac_cv_pluginpath" != no ; then
+		LINUX_KERNELMODE_PLUGIN=rp-pppoe.so
+		PPPD_INCDIR=$ac_cv_pluginpath
+	fi
+fi
+
+
+
+
+PPPOE_RELAY=""
+if test "`uname -s`" = "Linux" ; then
+	PPPOE_RELAY=pppoe-relay
+fi
+
+
+echo $ac_n "checking for 8-bit clean memcmp""... $ac_c" 1>&6
+echo "configure:1324: checking for 8-bit clean memcmp" >&5
+if eval "test \"`echo '$''{'ac_cv_func_memcmp_clean'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_func_memcmp_clean=no
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1332 "configure"
+#include "confdefs.h"
+
+main()
+{
+  char c0 = 0x40, c1 = 0x80, c2 = 0x81;
+  exit(memcmp(&c0, &c2, 1) < 0 && memcmp(&c1, &c2, 1) < 0 ? 0 : 1);
+}
+
+EOF
+if { (eval echo configure:1342: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_func_memcmp_clean=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_func_memcmp_clean=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_func_memcmp_clean" 1>&6
+test $ac_cv_func_memcmp_clean = no && LIBOBJS="$LIBOBJS memcmp.${ac_objext}"
+
+echo $ac_n "checking whether setvbuf arguments are reversed""... $ac_c" 1>&6
+echo "configure:1360: checking whether setvbuf arguments are reversed" >&5
+if eval "test \"`echo '$''{'ac_cv_func_setvbuf_reversed'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1368 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+/* 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: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_func_setvbuf_reversed=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_func_setvbuf_reversed=no
+fi
+rm -fr conftest*
+fi
+
+rm -f core core.* *.core
+fi
+
+echo "$ac_t""$ac_cv_func_setvbuf_reversed" 1>&6
+if test $ac_cv_func_setvbuf_reversed = yes; then
+  cat >> confdefs.h <<\EOF
+#define SETVBUF_REVERSED 1
+EOF
+
+fi
+
+echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
+echo "configure:1406: checking return type of signal handlers" >&5
+if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1411 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int main() {
+int i;
+; return 0; }
+EOF
+if { (eval echo configure:1428: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_type_signal=void
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_type_signal=int
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_type_signal" 1>&6
+cat >> confdefs.h <<EOF
+#define RETSIGTYPE $ac_cv_type_signal
+EOF
+
+
+for ac_func in select socket strerror strtol
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:1449: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1454 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1477: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+  if test -f $ac_dir/install-sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f $ac_dir/install.sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:1532: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    IFS="${IFS= 	}"; ac_save_IFS="$IFS"; IFS=":"
+  for ac_dir in $PATH; do
+    # Account for people who put trailing slashes in PATH elements.
+    case "$ac_dir/" in
+    /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+    *)
+      # OSF1 and SCO ODT 3.0 have their own names for install.
+      # Don't use installbsd from OSF since it installs stuff as root
+      # by default.
+      for ac_prog in ginstall scoinst install; do
+        if test -f $ac_dir/$ac_prog; then
+	  if test $ac_prog = install &&
+            grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  else
+	    ac_cv_path_install="$ac_dir/$ac_prog -c"
+	    break 2
+	  fi
+	fi
+      done
+      ;;
+    esac
+  done
+  IFS="$ac_save_IFS"
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL="$ac_cv_path_install"
+  else
+    # As a last resort, use the slow shell script.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    INSTALL="$ac_install_sh"
+  fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+
+echo $ac_n "checking size of unsigned short""... $ac_c" 1>&6
+echo "configure:1586: checking size of unsigned short" >&5
+if eval "test \"`echo '$''{'ac_cv_sizeof_unsigned_short'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1594 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+  FILE *f=fopen("conftestval", "w");
+  if (!f) exit(1);
+  fprintf(f, "%d\n", sizeof(unsigned short));
+  exit(0);
+}
+EOF
+if { (eval echo configure:1605: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_sizeof_unsigned_short=`cat conftestval`
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_sizeof_unsigned_short=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_unsigned_short" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_UNSIGNED_SHORT $ac_cv_sizeof_unsigned_short
+EOF
+
+
+echo $ac_n "checking size of unsigned int""... $ac_c" 1>&6
+echo "configure:1625: checking size of unsigned int" >&5
+if eval "test \"`echo '$''{'ac_cv_sizeof_unsigned_int'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1633 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+  FILE *f=fopen("conftestval", "w");
+  if (!f) exit(1);
+  fprintf(f, "%d\n", sizeof(unsigned int));
+  exit(0);
+}
+EOF
+if { (eval echo configure:1644: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_sizeof_unsigned_int=`cat conftestval`
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_sizeof_unsigned_int=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_unsigned_int" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_UNSIGNED_INT $ac_cv_sizeof_unsigned_int
+EOF
+
+
+echo $ac_n "checking size of unsigned long""... $ac_c" 1>&6
+echo "configure:1664: checking size of unsigned long" >&5
+if eval "test \"`echo '$''{'ac_cv_sizeof_unsigned_long'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1672 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+  FILE *f=fopen("conftestval", "w");
+  if (!f) exit(1);
+  fprintf(f, "%d\n", sizeof(unsigned long));
+  exit(0);
+}
+EOF
+if { (eval echo configure:1683: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_sizeof_unsigned_long=`cat conftestval`
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_sizeof_unsigned_long=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_unsigned_long" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_UNSIGNED_LONG $ac_cv_sizeof_unsigned_long
+EOF
+
+
+
+# Extract the first word of "pppd", so it can be a program name with args.
+set dummy pppd; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1706: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_PPPD'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$PPPD" in
+  /*)
+  ac_cv_path_PPPD="$PPPD" # Let the user override the test with a path.
+  ;;
+  ?:/*)			 
+  ac_cv_path_PPPD="$PPPD" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH:/sbin:/usr/sbin:/usr/local/sbin"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_PPPD="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_PPPD" && ac_cv_path_PPPD="NOTFOUND"
+  ;;
+esac
+fi
+PPPD="$ac_cv_path_PPPD"
+if test -n "$PPPD"; then
+  echo "$ac_t""$PPPD" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+# Extract the first word of "setsid", so it can be a program name with args.
+set dummy setsid; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1743: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_SETSID'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$SETSID" in
+  /*)
+  ac_cv_path_SETSID="$SETSID" # Let the user override the test with a path.
+  ;;
+  ?:/*)			 
+  ac_cv_path_SETSID="$SETSID" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH:/sbin:/usr/sbin:/usr/local/sbin"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_SETSID="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_SETSID" && ac_cv_path_SETSID=""""
+  ;;
+esac
+fi
+SETSID="$ac_cv_path_SETSID"
+if test -n "$SETSID"; then
+  echo "$ac_t""$SETSID" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+# Extract the first word of "id", so it can be a program name with args.
+set dummy id; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1780: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_ID'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$ID" in
+  /*)
+  ac_cv_path_ID="$ID" # Let the user override the test with a path.
+  ;;
+  ?:/*)			 
+  ac_cv_path_ID="$ID" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="/usr/xpg4/bin:$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_ID="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_ID" && ac_cv_path_ID=""""
+  ;;
+esac
+fi
+ID="$ac_cv_path_ID"
+if test -n "$ID"; then
+  echo "$ac_t""$ID" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+$ECHO -n "checking for Linux 2.4.X kernel-mode PPPoE support..."
+if test "`uname -s`" = "Linux" ; then
+if test "$cross_compiling" = yes; then
+    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1820 "configure"
+#include "confdefs.h"
+#include <sys/socket.h>
+#include <net/ethernet.h>
+#include <linux/if.h>
+#include <linux/if_pppox.h>
+int main()
+{
+	if (socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OE) >= 0) return 0; else return 1;
+}
+
+EOF
+if { (eval echo configure:1832: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_linux_kernel_pppoe=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&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 "$ac_cv_linux_kernel_pppoe" = yes ; then
+    cat >> confdefs.h <<\EOF
+#define HAVE_LINUX_KERNEL_PPPOE 1
+EOF
+
+fi
+
+if test "$GCC" = yes; then
+	CFLAGS="$CFLAGS -Wall -Wstrict-prototypes -ansi -pedantic"
+fi
+
+if test "$PPPD" = "NOTFOUND"; then
+	$ECHO ""
+	$ECHO "*** Oops!  I couldn't find pppd, the PPP daemon anywhere."
+	$ECHO "*** You must install pppd, version 2.3.10 or later."
+	$ECHO "*** I will keep going, but it may not work."
+	$ECHO ""
+fi
+
+
+PPPD_VERSION=`$PPPD --version 2>&1 | awk '{print $NF}'`
+
+case "$PPPD_VERSION" 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 ""
+	$ECHO "*** Oops! Your version of pppd is $PPPD_VERSION, which is too old."
+	$ECHO "*** You need at least 2.3.7 (2.3.10 or newer recommended.)"
+	$ECHO "*** I will keep going, but it may not work."
+	$ECHO ""
+	;;
+
+2.3.7|2.3.8|2.3.9)
+	$ECHO ""
+	$ECHO "*** Warning.  Your version of pppd is $PPPD_VERSION.  You will"
+	$ECHO "*** not be able to use connect-on-demand.  Upgrade to pppd"
+	$ECHO "*** 2.3.10 or newer if you need connect-on-demand."
+	$ECHO ""
+	;;
+
+2*|3*|4*|5*|6*|7*|8*|9*)
+	;;
+
+*)
+	$ECHO ""
+	$ECHO "*** Oops.  I cannot figure out what version of pppd you have."
+	$ECHO "*** All I got back was '$PPPD_VERSION'"
+	$ECHO "*** I will keep going, but it may not work."
+	$ECHO ""
+	;;
+esac
+
+$ECHO -n "checking packing order of bit fields... "
+if test "$cross_compiling" = yes; then
+    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1905 "configure"
+#include "confdefs.h"
+
+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: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  PACK=normal
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  PACK=rev
+fi
+rm -fr conftest*
+fi
+
+
+if test "$PACK" = "rev" ; then
+	$ECHO "reversed"
+	cat >> confdefs.h <<\EOF
+#define PACK_BITFIELDS_REVERSED 1
+EOF
+
+else
+	$ECHO "normal"
+fi
+
+# Sigh... got to fix this up for tcl
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Fully resolve WRAPPER for Tcl script.
+WRAPPER=${sbindir}/pppoe-wrapper
+eval "WRAPPER=${WRAPPER}"
+eval "WRAPPER=${WRAPPER}"
+
+
+# Determine what targets to build
+TARGETS="pppoe pppoe-server"
+
+# pppoe-sniff is built only on Linux and Solaris
+if test "$ac_cv_header_linux_if_packet_h" = "yes" -o "$ac_cv_header_sys_dlpi_h" = "yes" ; then
+	TARGETS="$TARGETS pppoe-sniff"
+fi
+
+# pppoe-relay is built only on Linux
+if test "$ac_cv_header_linux_if_packet_h" = "yes" ; then
+	TARGETS="$TARGETS pppoe-relay"
+fi
+
+# plugin is built only if we have kernel support
+if test -n "$LINUX_KERNELMODE_PLUGIN" ; then
+	TARGETS="$TARGETS $LINUX_KERNELMODE_PLUGIN"
+fi
+
+
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs.  It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already.  You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+  case `(ac_space=' '; set | grep ac_space) 2>&1` in
+  *ac_space=\ *)
+    # `set' does not quote correctly, so add quotes (double-quote substitution
+    # turns \\\\ into \\, and sed turns \\ into \).
+    sed -n \
+      -e "s/'/'\\\\''/g" \
+      -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+    ;;
+  *)
+    # `set' quotes correctly as required by POSIX, so do not add quotes.
+    sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+    ;;
+  esac >> confcache
+if cmp -s $cache_file confcache; then
+  :
+else
+  if test -w $cache_file; then
+    echo "updating cache $cache_file"
+    cat confcache > $cache_file
+  else
+    echo "not updating unwritable cache $cache_file"
+  fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[ 	]*VPATH[ 	]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+  case "\$ac_option" in
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+    exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+  -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+    echo "$CONFIG_STATUS generated by autoconf version 2.13"
+    exit 0 ;;
+  -help | --help | --hel | --he | --h)
+    echo "\$ac_cs_usage"; exit 0 ;;
+  *) echo "\$ac_cs_usage"; exit 1 ;;
+  esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "Makefile ../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" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@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 >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+  if test $ac_beg -gt 1; then
+    sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+  else
+    sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+  fi
+  if test ! -s conftest.s$ac_file; then
+    ac_more_lines=false
+    rm -f conftest.s$ac_file
+  else
+    if test -z "$ac_sed_cmds"; then
+      ac_sed_cmds="sed -f conftest.s$ac_file"
+    else
+      ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+    fi
+    ac_file=`expr $ac_file + 1`
+    ac_beg=$ac_end
+    ac_end=`expr $ac_end + $ac_max_sed_cmds`
+  fi
+done
+if test -z "$ac_sed_cmds"; then
+  ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile ../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"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+  # Remove last slash and all that follows it.  Not all systems have dirname.
+  ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+  if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+    # The file is in a subdirectory.
+    test ! -d "$ac_dir" && mkdir "$ac_dir"
+    ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+    # A "../" for each directory in $ac_dir_suffix.
+    ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+  else
+    ac_dir_suffix= ac_dots=
+  fi
+
+  case "$ac_given_srcdir" in
+  .)  srcdir=.
+      if test -z "$ac_dots"; then top_srcdir=.
+      else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+  /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+  *) # Relative path.
+    srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+    top_srcdir="$ac_dots$ac_given_srcdir" ;;
+  esac
+
+  case "$ac_given_INSTALL" in
+  [/$]*) INSTALL="$ac_given_INSTALL" ;;
+  *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+  esac
+
+  echo creating "$ac_file"
+  rm -f "$ac_file"
+  configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+  case "$ac_file" in
+  *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+  *) ac_comsub= ;;
+  esac
+
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ 	]*\)#\([ 	]*define[ 	][ 	]*\)'
+ac_dB='\([ 	][ 	]*\)[^ 	]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ 	]*\)#\([ 	]*\)undef\([ 	][ 	]*\)'
+ac_uB='\([ 	]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ 	]*\)#\([ 	]*\)undef\([ 	][ 	]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+  CONFIG_HEADERS="config.h"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  echo creating $ac_file
+
+  rm -f conftest.frag conftest.in conftest.out
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h.  And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments.  This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ 	]*#[ 	]*undef[ 	][ 	]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+  ac_lines=`grep -c . conftest.vals`
+  # grep -c gives empty output for an empty file on some AIX systems.
+  if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+  # Write a limited-size here document to conftest.frag.
+  echo '  cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+  sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+  echo 'CEOF
+  sed -f conftest.frag conftest.in > conftest.out
+  rm -f conftest.in
+  mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+  sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+  rm -f conftest.vals
+  mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+  rm -f conftest.frag conftest.h
+  echo "/* $ac_file.  Generated automatically by configure.  */" > conftest.h
+  cat conftest.in >> conftest.h
+  rm -f conftest.in
+  if cmp -s $ac_file conftest.h 2>/dev/null; then
+    echo "$ac_file is unchanged"
+    rm -f conftest.h
+  else
+    # Remove last slash and all that follows it.  Not all systems have dirname.
+      ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+      if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+      # The file is in a subdirectory.
+      test ! -d "$ac_dir" && mkdir "$ac_dir"
+    fi
+    rm -f $ac_file
+    mv conftest.h $ac_file
+  fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
+
+$ECHO ""
+$ECHO "On this platform, the following targets will be built:"
+$ECHO "        $TARGETS"
+$ECHO ""
+$ECHO "Type 'make' to compile the software."


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, "", /usr/ucb/bin:$PATH)
+
+dnl Check for sockaddr_ll
+$ECHO -n "checking for struct sockaddr_ll... "
+AC_TRY_COMPILE([#include <asm/types.h>
+#include <linux/if_packet.h>
+#include <linux/if_ether.h>
+], [struct sockaddr_ll sa;],
+ac_cv_struct_sockaddr_ll=yes, ac_cv_struct_sockaddr_ll=no)
+$ECHO $ac_cv_struct_sockaddr_ll
+if test "$ac_cv_struct_sockaddr_ll" = yes ; then
+AC_DEFINE(HAVE_STRUCT_SOCKADDR_LL)
+fi
+
+dnl Check for N_HDLC line discipline
+$ECHO -n "checking for N_HDLC line discipline... "
+AC_TRY_COMPILE([#include <linux/termios.h>],
+	[int x = N_HDLC;],
+	ac_cv_n_hdlc=yes, ac_cv_n_hdlc=no)
+$ECHO $ac_cv_n_hdlc
+if test "$ac_cv_n_hdlc" = 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=""
+PPPD_INCDIR=""
+if test "$ac_cv_header_linux_if_pppox_h" = yes ; then
+	if test "$ac_cv_pluginpath" != 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=""
+if test "`uname -s`" = "Linux" ; 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, "", $PATH:/sbin:/usr/sbin:/usr/local/sbin)
+
+dnl Check for an "id" which accepts "-u" option -- hack for Solaris.
+AC_PATH_PROG(ID, id, "", /usr/xpg4/bin:$PATH)
+
+dnl Check for Linux-specific kernel support for PPPoE
+$ECHO -n "checking for Linux 2.4.X kernel-mode PPPoE support..."
+if test "`uname -s`" = "Linux" ; then
+AC_TRY_RUN([#include <sys/socket.h>
+#include <net/ethernet.h>
+#include <linux/if.h>
+#include <linux/if_pppox.h>
+int main()
+{
+	if (socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OE) >= 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 "$ac_cv_linux_kernel_pppoe" = yes ; then
+    AC_DEFINE(HAVE_LINUX_KERNEL_PPPOE)
+fi
+
+dnl GCC warning level
+if test "$GCC" = yes; then
+	CFLAGS="$CFLAGS -Wall -Wstrict-prototypes"
+fi
+
+dnl If we couldn't find pppd, die
+if test "$PPPD" = "NOTFOUND"; then
+	$ECHO ""
+	$ECHO "*** Oops!  I couldn't find pppd, the PPP daemon anywhere."
+	$ECHO "*** You must install pppd, version 2.3.10 or later."
+	$ECHO "*** I will keep going, but it may not work."
+	$ECHO ""
+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>&1 | awk '{print $NF}'`
+
+case "$PPPD_VERSION" 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 ""
+	$ECHO "*** Oops! Your version of pppd is $PPPD_VERSION, which is too old."
+	$ECHO "*** You need at least 2.3.7 (2.3.10 or newer recommended.)"
+	$ECHO "*** I will keep going, but it may not work."
+	$ECHO ""
+	;;
+
+2.3.7|2.3.8|2.3.9)
+	$ECHO ""
+	$ECHO "*** Warning.  Your version of pppd is $PPPD_VERSION.  You will"
+	$ECHO "*** not be able to use connect-on-demand.  Upgrade to pppd"
+	$ECHO "*** 2.3.10 or newer if you need connect-on-demand."
+	$ECHO ""
+	;;
+
+2*|3*|4*|5*|6*|7*|8*|9*)
+	;;
+
+*)
+	$ECHO ""
+	$ECHO "*** Oops.  I cannot figure out what version of pppd you have."
+	$ECHO "*** All I got back was '$PPPD_VERSION'"
+	$ECHO "*** I will keep going, but it may not work."
+	$ECHO ""
+	;;
+esac
+
+dnl Figure out packing order of structures
+$ECHO -n "checking packing order of bit fields... "
+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 "$PACK" = "rev" ; then
+	$ECHO "reversed"
+	AC_DEFINE(PACK_BITFIELDS_REVERSED)
+else
+	$ECHO "normal"
+fi
+
+# Sigh... got to fix this up for tcl
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Fully resolve WRAPPER for Tcl script.
+WRAPPER=${sbindir}/pppoe-wrapper
+eval "WRAPPER=${WRAPPER}"
+eval "WRAPPER=${WRAPPER}"
+AC_SUBST(WRAPPER)
+
+# Determine what targets to build
+TARGETS="pppoe pppoe-server"
+
+# pppoe-sniff is built only on Linux and Solaris
+if test "$ac_cv_header_linux_if_packet_h" = "yes" -o "$ac_cv_header_sys_dlpi_h" = "yes" ; then
+	TARGETS="$TARGETS pppoe-sniff"
+fi
+
+# pppoe-relay is built only on Linux
+if test "$ac_cv_header_linux_if_packet_h" = "yes" ; then
+	TARGETS="$TARGETS pppoe-relay"
+fi
+
+# plugin is built only if we have kernel support
+if test -n "$LINUX_KERNELMODE_PLUGIN" ; then
+	TARGETS="$TARGETS $LINUX_KERNELMODE_PLUGIN"
+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 ""
+$ECHO "On this platform, the following targets will be built:"
+$ECHO "        $TARGETS"
+$ECHO ""
+$ECHO "Type 'make' to compile the software."

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[] =
+"$Id: debug.c 195724 2001-06-11 13:49:39Z gc $";
+
+#include "pppoe.h"
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+#include <ctype.h>
+
+/**********************************************************************
+*%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 >= 2 && buf[0] == 0xC0 && buf[1] == 0x23) {
+	fprintf(fp, "(PAP Authentication Frame -- Contents not dumped)\n");
+	return;
+    }
+
+    for (base=0; base<len; base += 16) {
+	for (i=base; i<base+16; i++) {
+	    if (i < len) {
+		fprintf(fp, "%02x ", (unsigned) buf[i]);
+	    } else {
+		fprintf(fp, "   ");
+	    }
+	}
+	fprintf(fp, "  ");
+	for (i=base; i<base+16; i++) {
+	    if (i < len) {
+		if (isprint(buf[i])) {
+		    fprintf(fp, "%c", buf[i]);
+		} else {
+		    fprintf(fp, ".");
+		}
+	    } else {
+		break;
+	    }
+	}
+	fprintf(fp, "\n");
+    }
+}
+
+/**********************************************************************
+*%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->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(&tv, NULL);
+    now = (time_t) tv.tv_sec;
+    millisec = tv.tv_usec / 1000;
+    lt = localtime(&now);
+    strftime(timebuf, 256, "%H:%M:%S", lt);
+    fprintf(fp, "%s.%03d %s PPPoE ", timebuf, millisec, dir);
+    if (type == Eth_PPPOE_Discovery) {
+	fprintf(fp, "Discovery (%x) ", (unsigned) type);
+    } else if (type == Eth_PPPOE_Session) {
+	fprintf(fp, "Session (%x) ", (unsigned) type);
+    } else {
+	fprintf(fp, "Unknown (%x) ", (unsigned) type);
+    }
+
+    switch(packet->code) {
+    case CODE_PADI: fprintf(fp, "PADI "); break;
+    case CODE_PADO: fprintf(fp, "PADO "); break;
+    case CODE_PADR: fprintf(fp, "PADR "); break;
+    case CODE_PADS: fprintf(fp, "PADS "); break;
+    case CODE_PADT: fprintf(fp, "PADT "); break;
+    case CODE_SESS: fprintf(fp, "SESS "); break;
+    }
+
+    fprintf(fp, "sess-id %d length %d\n",
+	    (int) ntohs(packet->session),
+	    len);
+
+    /* Ugly... I apologize... */
+    fprintf(fp,
+	    "SourceAddr %02x:%02x:%02x:%02x:%02x:%02x "
+	    "DestAddr %02x:%02x:%02x:%02x:%02x:%02x\n",
+	    (unsigned) packet->ethHdr.h_source[0],
+	    (unsigned) packet->ethHdr.h_source[1],
+	    (unsigned) packet->ethHdr.h_source[2],
+	    (unsigned) packet->ethHdr.h_source[3],
+	    (unsigned) packet->ethHdr.h_source[4],
+	    (unsigned) packet->ethHdr.h_source[5],
+	    (unsigned) packet->ethHdr.h_dest[0],
+	    (unsigned) packet->ethHdr.h_dest[1],
+	    (unsigned) packet->ethHdr.h_dest[2],
+	    (unsigned) packet->ethHdr.h_dest[3],
+	    (unsigned) packet->ethHdr.h_dest[4],
+	    (unsigned) packet->ethHdr.h_dest[5]);
+    dumpHex(fp, packet->payload, ntohs(packet->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[] =
+"$Id: discovery.c 195724 2001-06-11 13:49:39Z gc $";
+
+#include "pppoe.h"
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef USE_LINUX_PACKET
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#endif
+
+#include <signal.h>
+
+/**********************************************************************
+*%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 && len == sizeof(pid_t)) {
+	pid_t tmp;
+	memcpy(&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->useHostUniq) return 1;
+
+    parsePacket(packet, parseForHostUniq, &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->conn;
+    int i;
+
+    switch(type) {
+    case TAG_AC_NAME:
+	if (conn->printACNames) {
+	    printf("Access-Concentrator: %.*s\n", (int) len, data);
+	}
+	if (conn->acName && len == strlen(conn->acName) &&
+	    !strncmp((char *) data, conn->acName, len)) {
+	    pc->acNameOK = 1;
+	}
+	break;
+    case TAG_SERVICE_NAME:
+	if (conn->printACNames && len > 0) {
+	    printf("       Service-Name: %.*s\n", (int) len, data);
+	}
+	if (conn->serviceName && len == strlen(conn->serviceName) &&
+	    !strncmp((char *) data, conn->serviceName, len)) {
+	    pc->serviceNameOK = 1;
+	}
+	break;
+    case TAG_AC_COOKIE:
+	if (conn->printACNames) {
+	    printf("Got a cookie:");
+	    /* Print first 20 bytes of cookie */
+	    for (i=0; i<len && i < 20; i++) {
+		printf(" %02x", (unsigned) data[i]);
+	    }
+	    if (i < len) printf("...");
+	    printf("\n");
+	}
+	conn->cookie.type = htons(type);
+	conn->cookie.length = htons(len);
+	memcpy(conn->cookie.payload, data, len);
+	break;
+    case TAG_RELAY_SESSION_ID:
+	if (conn->printACNames) {
+	    printf("Got a Relay-ID:");
+	    /* Print first 20 bytes of relay ID */
+	    for (i=0; i<len && i < 20; i++) {
+		printf(" %02x", (unsigned) data[i]);
+	    }
+	    if (i < len) printf("...");
+	    printf("\n");
+	}
+	conn->relayId.type = htons(type);
+	conn->relayId.length = htons(len);
+	memcpy(conn->relayId.payload, data, len);
+	break;
+    case TAG_SERVICE_NAME_ERROR:
+	if (conn->printACNames) {
+	    printf("Got a Service-Name-Error tag: %.*s\n", (int) len, data);
+	} else {
+	    syslog(LOG_ERR, "PADO: Service-Name-Error: %.*s", (int) len, data);
+	    exit(1);
+	}
+	break;
+    case TAG_AC_SYSTEM_ERROR:
+	if (conn->printACNames) {
+	    printf("Got a System-Error tag: %.*s\n", (int) len, data);
+	} else {
+	    syslog(LOG_ERR, "PADO: System-Error: %.*s", (int) len, data);
+	    exit(1);
+	}
+	break;
+    case TAG_GENERIC_ERROR:
+	if (conn->printACNames) {
+	    printf("Got a Generic-Error tag: %.*s\n", (int) len, data);
+	} else {
+	    syslog(LOG_ERR, "PADO: Generic-Error: %.*s", (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, "PADS: Service-Name: '%.*s'", (int) len, data);
+	break;
+    case TAG_SERVICE_NAME_ERROR:
+	syslog(LOG_ERR, "PADS: Service-Name-Error: %.*s", (int) len, data);
+	fprintf(stderr, "PADS: Service-Name-Error: %.*s\n", (int) len, data);
+	exit(1);
+    case TAG_AC_SYSTEM_ERROR:
+	syslog(LOG_ERR, "PADS: System-Error: %.*s", (int) len, data);
+	fprintf(stderr, "PADS: System-Error: %.*s\n", (int) len, data);
+	exit(1);
+    case TAG_GENERIC_ERROR:
+	syslog(LOG_ERR, "PADS: Generic-Error: %.*s", (int) len, data);
+	fprintf(stderr, "PADS: Generic-Error: %.*s\n", (int) len, data);
+	exit(1);
+    case TAG_RELAY_SESSION_ID:
+	conn->relayId.type = htons(type);
+	conn->relayId.length = htons(len);
+	memcpy(conn->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 *) (&packet.payload);
+    UINT16_t namelen = 0;
+    UINT16_t plen;
+
+    if (conn->serviceName) {
+	namelen = (UINT16_t) strlen(conn->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->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->type = TAG_SERVICE_NAME;
+    svc->length = htons(namelen);
+    CHECK_ROOM(cursor, packet.payload, namelen+TAG_HDR_SIZE);
+
+    if (conn->serviceName) {
+	memcpy(svc->payload, conn->serviceName, strlen(conn->serviceName));
+    }
+    cursor += namelen + TAG_HDR_SIZE;
+
+    /* If we're using Host-Uniq, copy it over */
+    if (conn->useHostUniq) {
+	PPPoETag hostUniq;
+	pid_t pid = getpid();
+	hostUniq.type = htons(TAG_HOST_UNIQ);
+	hostUniq.length = htons(sizeof(pid));
+	memcpy(hostUniq.payload, &pid, sizeof(pid));
+	CHECK_ROOM(cursor, packet.payload, sizeof(pid) + TAG_HDR_SIZE);
+	memcpy(cursor, &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->discoverySocket, &packet, (int) (plen + HDR_SIZE));
+    if (conn->debugFile) {
+	dumpPacket(conn->debugFile, &packet, "SENT");
+	fprintf(conn->debugFile, "\n");
+	fflush(conn->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->acName)      ? 0 : 1;
+    pc.serviceNameOK = (conn->serviceName) ? 0 : 1;
+	
+    do {
+	if (BPF_BUFFER_IS_EMPTY) {
+	    tv.tv_sec = timeout;
+	    tv.tv_usec = 0;
+	
+	    FD_ZERO(&readable);
+	    FD_SET(conn->discoverySocket, &readable);
+
+	    while(1) {
+		r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv);
+		if (r >= 0 || errno != EINTR) break;
+	    }
+	    if (r < 0) {
+		fatalSys("select (waitForPADO)");
+	    }
+	    if (r == 0) return;        /* Timed out */
+	}
+	
+	/* Get the packet */
+	receivePacket(conn->discoverySocket, &packet, &len);
+
+	/* Check length */
+	if (ntohs(packet.length) + HDR_SIZE > len) {
+	    syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+		   (unsigned int) ntohs(packet.length));
+	    continue;
+	}
+
+#ifdef USE_BPF
+	/* If it's not a Discovery packet, loop again */
+	if (etherType(&packet) != Eth_PPPOE_Discovery) continue;
+#endif
+
+	if (conn->debugFile) {
+	    dumpPacket(conn->debugFile, &packet, "RCVD");
+	    fprintf(conn->debugFile, "\n");
+	    fflush(conn->debugFile);
+	}
+	/* If it's not for us, loop again */
+	if (!packetIsForMe(conn, &packet)) continue;
+
+	if (packet.code == CODE_PADO) {
+	    if (NOT_UNICAST(packet.ethHdr.h_source)) {
+		printErr("Ignoring PADO packet from non-unicast MAC address");
+		continue;
+	    }
+	    conn->numPADOs++;
+	    if (conn->printACNames) {
+		printf("--------------------------------------------------\n");
+	    }
+	    parsePacket(&packet, parsePADOTags, &pc);
+	    if (pc.acNameOK && pc.serviceNameOK) {
+		memcpy(conn->peerEth, packet.ethHdr.h_source, ETH_ALEN);
+		if (conn->printACNames) {
+		    printf("AC-Ethernet-Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+			   (unsigned) conn->peerEth[0], 
+			   (unsigned) conn->peerEth[1],
+			   (unsigned) conn->peerEth[2],
+			   (unsigned) conn->peerEth[3],
+			   (unsigned) conn->peerEth[4],
+			   (unsigned) conn->peerEth[5]);
+		    continue;
+		}
+		conn->discoveryState = STATE_RECEIVED_PADO;
+		break;
+	    }
+	}
+    } while (conn->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->serviceName) {
+	namelen = (UINT16_t) strlen(conn->serviceName);
+    }
+    plen = TAG_HDR_SIZE + namelen;
+    CHECK_ROOM(cursor, packet.payload, plen);
+
+    memcpy(packet.ethHdr.h_dest, conn->peerEth, ETH_ALEN);
+    memcpy(packet.ethHdr.h_source, conn->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->type = TAG_SERVICE_NAME;
+    svc->length = htons(namelen);
+    if (conn->serviceName) {
+	memcpy(svc->payload, conn->serviceName, namelen);
+    }
+    cursor += namelen + TAG_HDR_SIZE;
+
+    /* If we're using Host-Uniq, copy it over */
+    if (conn->useHostUniq) {
+	PPPoETag hostUniq;
+	pid_t pid = getpid();
+	hostUniq.type = htons(TAG_HOST_UNIQ);
+	hostUniq.length = htons(sizeof(pid));
+	memcpy(hostUniq.payload, &pid, sizeof(pid));
+	CHECK_ROOM(cursor, packet.payload, sizeof(pid)+TAG_HDR_SIZE);
+	memcpy(cursor, &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->cookie.type) {
+	CHECK_ROOM(cursor, packet.payload,
+		   ntohs(conn->cookie.length) + TAG_HDR_SIZE);
+	memcpy(cursor, &conn->cookie, ntohs(conn->cookie.length) + TAG_HDR_SIZE);
+	cursor += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
+	plen += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
+    }
+
+    if (conn->relayId.type) {
+	CHECK_ROOM(cursor, packet.payload,
+		   ntohs(conn->relayId.length) + TAG_HDR_SIZE);
+	memcpy(cursor, &conn->relayId, ntohs(conn->relayId.length) + TAG_HDR_SIZE);
+	cursor += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
+	plen += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
+    }
+
+    packet.length = htons(plen);
+    sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
+    if (conn->debugFile) {
+	dumpPacket(conn->debugFile, &packet, "SENT");
+	fprintf(conn->debugFile, "\n");
+	fflush(conn->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(&readable);
+	    FD_SET(conn->discoverySocket, &readable);
+	    
+	    while(1) {
+		r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv);
+		if (r >= 0 || errno != EINTR) break;
+	    }
+	    if (r < 0) {
+		fatalSys("select (waitForPADS)");
+	    }
+	    if (r == 0) return;
+	}
+
+	/* Get the packet */
+	receivePacket(conn->discoverySocket, &packet, &len);
+
+	/* Check length */
+	if (ntohs(packet.length) + HDR_SIZE > len) {
+	    syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+		   (unsigned int) ntohs(packet.length));
+	    continue;
+	}
+
+#ifdef USE_BPF
+	/* If it's not a Discovery packet, loop again */
+	if (etherType(&packet) != Eth_PPPOE_Discovery) continue;
+#endif
+	if (conn->debugFile) {
+	    dumpPacket(conn->debugFile, &packet, "RCVD");
+	    fprintf(conn->debugFile, "\n");
+	    fflush(conn->debugFile);
+	}
+
+	/* If it's not from the AC, it's not for me */
+	if (memcmp(packet.ethHdr.h_source, conn->peerEth, ETH_ALEN)) continue;
+
+	/* If it's not for us, loop again */
+	if (!packetIsForMe(conn, &packet)) continue;
+
+	/* Is it PADS?  */
+	if (packet.code == CODE_PADS) {
+	    /* Parse for goodies */
+	    parsePacket(&packet, parsePADSTags, conn);
+	    conn->discoveryState = STATE_SESSION;
+	    break;
+	}
+    } while (conn->discoveryState != STATE_SESSION);
+
+    /* Don't bother with ntohs; we'll just end up converting it back... */
+    conn->session = packet.session;
+
+    syslog(LOG_INFO, "PPP session is %d", (int) ntohs(conn->session));
+
+    /* RFC 2516 says session id MUST NOT be zero or 0xFFFF */
+    if (ntohs(conn->session) == 0 || ntohs(conn->session) == 0xFFFF) {
+	syslog(LOG_ERR, "Access concentrator used a session value of %x -- the AC is violating RFC 2516", (unsigned int) ntohs(conn->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->skipDiscovery && conn->noDiscoverySocket) {
+	conn->discoveryState = STATE_SESSION;
+	return;
+    }
+
+    conn->discoverySocket =
+	openInterface(conn->ifName, Eth_PPPOE_Discovery, conn->myEth);
+
+    /* Skip discovery? */
+    if (conn->skipDiscovery) {
+	conn->discoveryState = STATE_SESSION;
+	if (conn->killSession) {
+	    sendPADT(conn, "RP-PPPoE: Session killed manually");
+	    exit(0);
+	}
+	return;
+    }
+
+    do {
+	padiAttempts++;
+	if (padiAttempts > MAX_PADI_ATTEMPTS) {
+	    rp_fatal("Timeout waiting for PADO packets");
+	}
+	sendPADI(conn);
+	conn->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->printACNames) {
+	    timeout *= 2;
+	}
+	if (conn->printACNames && conn->numPADOs) {
+	    break;
+	}
+    } while (conn->discoveryState == STATE_SENT_PADI);
+
+    /* If we're only printing access concentrator names, we're done */
+    if (conn->printACNames) {
+	printf("--------------------------------------------------\n");
+	exit(0);
+    }
+
+    timeout = PADI_TIMEOUT;
+    do {
+	padrAttempts++;
+	if (padrAttempts > MAX_PADI_ATTEMPTS) {
+	    rp_fatal("Timeout waiting for PADS packets");
+	}
+	sendPADR(conn);
+	conn->discoveryState = STATE_SENT_PADR;
+	waitForPADS(conn, timeout);
+	timeout *= 2;
+    } while (conn->discoveryState == STATE_SENT_PADR);
+
+    /* We're done. */
+    conn->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[] =
+"$Id: if.c 195724 2001-06-11 13:49:39Z gc $";
+
+#include "pppoe.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_NETPACKET_PACKET_H
+#include <netpacket/packet.h>
+#elif defined(HAVE_LINUX_IF_PACKET_H)
+#include <linux/if_packet.h>
+#endif
+
+#ifdef HAVE_NET_ETHERNET_H
+#include <net/ethernet.h>
+#endif
+
+#ifdef HAVE_ASM_TYPES_H
+#include <asm/types.h>
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_NET_IF_ARP_H
+#include <net/if_arp.h>
+#endif
+
+#ifdef USE_DLPI
+
+#include <limits.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#include <sys/dlpi.h>
+#include <sys/bufmod.h>
+#include <stdio.h>
+#include <signal.h>
+#include <stropts.h>
+
+/* 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 <net/bpf.h>
+#include <fcntl.h>
+
+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 "pppoe.h" and the packet
+* packet structure names use the LINUX dialect to maintain consistency
+* with the rest of this file.  See the BSD section of "pppoe.h" for
+* translations of the data structure names.
+***********************************************************************/
+UINT16_t
+etherType(PPPoEPacket *packet)
+{
+    UINT16_t type = (UINT16_t) ntohs(packet->ethHdr.h_proto);
+    if (type != Eth_PPPOE_Discovery && type != Eth_PPPOE_Session) {
+	syslog(LOG_ERR, "Invalid ether type 0x%x", 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, &ifc) < 0) {
+	fatalSys("SIOCGIFCONF");
+    }
+    ifr = ifc.ifc_req;
+    ifreq.ifr_name[0] = '\0';
+    for (i = 0; i < ifc.ifc_len; ) {
+	ifr = (struct ifreq *)((caddr_t)ifc.ifc_req + i);
+	i += sizeof(ifr->ifr_name) +
+		    (ifr->ifr_addr.sa_len > sizeof(struct sockaddr)
+		    ? ifr->ifr_addr.sa_len
+		    : sizeof(struct sockaddr));
+	if (ifr->ifr_addr.sa_family == AF_LINK) {
+	    sdl = (const struct sockaddr_dl *) &ifr->ifr_addr;
+	    if ((sdl->sdl_type == IFT_ETHER) &&
+	        (sdl->sdl_alen == ETH_ALEN) &&
+		!strncmp(ifname, ifr->ifr_name, sizeof(ifr->ifr_name))) {
+		if (found) {
+		    char buffer[256];
+		    sprintf(buffer, "interface %.16s has more than one ethernet address", ifname);
+		    rp_fatal(buffer);
+		} else {
+		    found = 1;
+	            memcpy(hwaddr, LLADDR(sdl), ETH_ALEN);
+		}
+	    }
+	}
+    }
+    if (!found) {
+	char buffer[256];
+        sprintf(buffer, "interface %.16s has no ethernet address", 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 "pppoe.h" 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 << 24) | (0xff << 16) |
+                                     (0xff << 8) | 0xff);
+      bpfInsn[PPPOE_BCAST_CMPH].k = ((0xff << 8) | 0xff);
+      bpfInsn[PPPOE_FILTER_CMPW].k = ((hwaddr[0] << 24) | (hwaddr[1] << 16) |
+				      (hwaddr[2] << 8) | hwaddr[3]);
+      bpfInsn[PPPOE_FILTER_CMPH].k = ((hwaddr[4] << 8) | hwaddr[5]);
+      bpfProgram.bf_len = (sizeof(bpfInsn) / sizeof(bpfInsn[0]));
+      bpfProgram.bf_insns = &bpfInsn[0];
+      
+      /* Apply the filter */
+      if (ioctl(fd, BIOCSETF, &bpfProgram) < 0) {
+	fatalSys("ioctl(BIOCSETF)");
+      }
+    }
+}
+
+/**********************************************************************
+*%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 >= 0) {
+	return fd;
+    }
+
+    /* Find a free BPF device */
+    for (i = 0; i < 256; i++) {
+	sprintf(bpfName, "/dev/bpf%d", i);
+	if (((fd = open(bpfName, O_RDWR, 0)) >= 0) ||
+	    (errno != EBUSY)) {
+	    break;
+	}
+    }
+    if (fd < 0) {
+	switch (errno) {
+	case EACCES:		/* permission denied */
+	    {
+		char buffer[256];
+		sprintf(buffer, "Cannot open %.32s -- pppoe must be run as root.", bpfName);
+		rp_fatal(buffer);
+	    }
+	    break;
+	case EBUSY:
+	case ENOENT:		/* no such file */
+	    if (i == 0) {
+		rp_fatal("No /dev/bpf* devices (check your kernel configuration for BPF support)");
+	    } else {
+		rp_fatal("All /dev/bpf* devices are in use");
+	    }
+	    break;
+	}
+	fatalSys(bpfName);
+    }
+
+    if ((sock = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) {
+	fatalSys("socket");
+    }
+
+    /* Check that the interface is up */
+    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+    if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
+	fatalSys("ioctl(SIOCGIFFLAGS)");
+    }
+    if ((ifr.ifr_flags & IFF_UP) == 0) {
+	char buffer[256];
+	sprintf(buffer, "Interface %.16s is not up\n", ifname);
+	rp_fatal(buffer);
+    }
+
+    /* Fill in hardware address and initialize the packet filter rules */
+    if (hwaddr == NULL) {
+	rp_fatal("openInterface: no hwaddr arg.");
+    }
+    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, &ifr) < 0) {
+	fatalSys("ioctl(SIOCGIFMTU)");
+    }
+    if (ifr.ifr_mtu < ETH_DATA_LEN) {
+	char buffer[256];
+	sprintf(buffer, "Interface %.16s has MTU of %d -- should be %d.  You may have serious connection problems.",
+		ifname, ifr.ifr_mtu, ETH_DATA_LEN);
+	printErr(buffer);
+    }
+#endif
+
+    /* done with the socket */
+    if (close(sock) < 0) {
+	fatalSys("close");
+    }
+
+    /* Check the BPF version number */
+    if (ioctl(fd, BIOCVERSION, &bpf_ver) < 0) {
+	fatalSys("ioctl(BIOCVERSION)");
+    }
+    if ((bpf_ver.bv_major != BPF_MAJOR_VERSION) ||
+        (bpf_ver.bv_minor < BPF_MINOR_VERSION)) {
+	char buffer[256];
+	sprintf(buffer, "Unsupported BPF version: %d.%d (kernel: %d.%d)", 
+			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, &bpfLength) < 0) {
+	fatalSys("ioctl(BIOCGBLEN)");
+    }
+    if (!(bpfBuffer = (unsigned char *) malloc(bpfLength))) {
+	rp_fatal("malloc");
+    }
+
+    /* reads should return as soon as there is a packet available */
+    optval = 1;
+    if (ioctl(fd, BIOCIMMEDIATE, &optval) < 0) {
+	fatalSys("ioctl(BIOCIMMEDIATE)");
+    }
+
+    /* Bind the interface to the filter */
+    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+    if (ioctl(fd, BIOCSETIF, &ifr) < 0) {
+	char buffer[256];
+	sprintf(buffer, "ioctl(BIOCSETIF) can't select interface %.16s",
+		ifname);
+	rp_fatal(buffer);
+    }
+
+    syslog(LOG_INFO, "Interface=%.16s HWaddr=%02X:%02X:%02X:%02X:%02X:%02X Device=%.32s Buffer size=%d",
+	   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(&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))) < 0) {
+	/* Give a more helpful message for the common error case */
+	if (errno == EPERM) {
+	    rp_fatal("Cannot create raw socket -- pppoe must be run as root.");
+	}
+	fatalSys("socket");
+    }
+
+    if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) < 0) {
+	fatalSys("setsockopt");
+    }
+
+    /* Fill in hardware address */
+    if (hwaddr) {
+	strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+	if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
+	    fatalSys("ioctl(SIOCGIFHWADDR)");
+	}
+	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, "Interface %.16s is not Ethernet", ifname);
+	    rp_fatal(buffer);
+	}
+#endif
+	if (NOT_UNICAST(hwaddr)) {
+	    char buffer[256];
+	    sprintf(buffer,
+		    "Interface %.16s has broadcast/multicast MAC address??",
+		    ifname);
+	    rp_fatal(buffer);
+	}
+    }
+
+    /* Sanity check on MTU */
+    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+    if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) {
+	fatalSys("ioctl(SIOCGIFMTU)");
+    }
+    if (ifr.ifr_mtu < ETH_DATA_LEN) {
+	char buffer[256];
+	sprintf(buffer, "Interface %.16s has MTU of %d -- should be %d.  You may have serious connection problems.",
+		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, &ifr) < 0) {
+	fatalSys("ioctl(SIOCFIGINDEX): Could not get interface index");
+    }
+    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 *) &sa, sizeof(sa)) < 0) {
+	fatalSys("bind");
+    }
+
+    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) < 0) {
+	sysErr("write (sendPacket)");
+	return -1;
+    }
+#elif defined(HAVE_STRUCT_SOCKADDR_LL)
+    if (send(sock, pkt, size, 0) < 0) {
+	sysErr("send (sendPacket)");
+	return -1;
+    }
+#else
+#ifdef USE_DLPI
+
+#define ABS(x)          ((x) < 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->ethHdr.h_proto); 
+	data_size = size - sizeof(struct ethhdr); 
+
+	memcpy((char *)phys, (char *)pkt->ethHdr.h_dest, ETHERADDRL);
+	memcpy((char *)sap,  (char *)&tmp_sap, sizeof(ushort_t));
+	memcpy((char *)xmitbuf, (char *)pkt + sizeof(struct ethhdr), data_size); 
+
+	if (dl_saplen > 0) {  /* order is sap+phys */
+		(void) memcpy((char*)addr, (char*)&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*)&sap, dl_abssaplen);
+	}
+
+#ifdef DL_DEBUG
+	printf("%02x:%02x:%02x:%02x:%02x:%02x %02x:%02x\n", 
+		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("relay and server not supported on Linux 2.0 kernels");
+    }
+    strcpy(sa.sa_data, conn->ifName);
+    if (sendto(sock, pkt, size, 0, &sa, sizeof(sa)) < 0) {
+	sysErr("sendto (sendPacket)");
+	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:
+* >= 0 if all OK; < 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 <= 0) {
+	bpfOffset = 0;
+	if ((bpfSize = read(sock, bpfBuffer, bpfLength)) < 0) {
+	    sysErr("read (receivePacket)");
+	    return -1;
+	}
+    }
+    if (bpfSize < sizeof(hdr)) {
+	syslog(LOG_ERR, "Truncated bpf packet header: len=%d", bpfSize);
+	clearPacketHeader(pkt);		/* resets bpfSize and bpfOffset */
+	return 0;
+    }
+    memcpy(&hdr, bpfBuffer + bpfOffset, sizeof(hdr));
+    if (hdr.bh_caplen != hdr.bh_datalen) {
+	syslog(LOG_ERR, "Truncated bpf packet: caplen=%d, datalen=%d",
+	       hdr.bh_caplen, hdr.bh_datalen);
+	clearPacketHeader(pkt);		/* resets bpfSize and bpfOffset */
+	return 0;
+    }
+    seglen = hdr.bh_hdrlen + hdr.bh_caplen;
+    if (seglen > bpfSize) {
+	syslog(LOG_ERR, "Truncated bpf packet: seglen=%d, bpfSize=%d",
+	       seglen, bpfSize);
+	clearPacketHeader(pkt);		/* resets bpfSize and bpfOffset */
+	return 0;
+    }
+    seglen = BPF_WORDALIGN(seglen);
+    *size = copylen = ((hdr.bh_caplen < sizeof(PPPoEPacket)) ?
+			hdr.bh_caplen : sizeof(PPPoEPacket));
+    memcpy(pkt, bpfBuffer + bpfOffset + hdr.bh_hdrlen, copylen);
+    if (seglen >= 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, &data, &flags)) < 0) {
+	    sysErr("read (receivePacket)");
+	    return -1;
+	}
+
+	*size = data.len; 
+
+#else
+    if ((*size = recv(sock, pkt, sizeof(PPPoEPacket), 0)) < 0) {
+	sysErr("recv (receivePacket)");
+	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) > PATH_MAX) {
+	rp_fatal("socket: string to long"); 
+    }
+
+    ppa = atoi(&ifname[strlen(ifname)-1]);
+    strncpy(base_dev, ifname, PATH_MAX); 
+    base_dev[strlen(base_dev)-1] = '\0'; 
+
+    if (( fd = open(base_dev, O_RDWR)) < 0) {
+	/* Give a more helpful message for the common error case */
+	if (errno == EPERM) {
+	    rp_fatal("Cannot create raw socket -- pppoe must be run as root.");
+	}
+	fatalSys("socket");
+    }
+
+	dlinforeq(fd);
+	dlinfoack(fd, (char *)buf);
+
+	dlp = (union DL_primitives*) buf;
+
+	dl_abssaplen = ABS(dlp->info_ack.dl_sap_length);
+	dl_saplen = dlp->info_ack.dl_sap_length;
+	if (ETHERADDRL != (dlp->info_ack.dl_addr_length - dl_abssaplen))
+		fatalSys("invalid destination physical address length");
+	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) < 0 ) { 
+		fatalSys("DLIOCRAW"); 
+	}
+
+	if (ioctl(fd, I_FLUSH, FLUSHR) < 0) fatalSys("I_FLUSH");
+
+    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 *) &promiscon_req;
+
+        flags = 0;
+
+        if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+                fatalSys("dlpromiscon:  putmsg");
+
+}
+
+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 *) &info_req;
+
+        flags = RS_HIPRI;
+
+        if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+                fatalSys("dlinforeq:  putmsg");
+}
+
+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->unitdata_req.dl_primitive = DL_UNITDATA_REQ;
+        dlp->unitdata_req.dl_dest_addr_length = addrlen;
+        dlp->unitdata_req.dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
+        dlp->unitdata_req.dl_priority.dl_min = minpri;
+        dlp->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, &ctl, &data, 0) < 0)
+                fatalSys("dlunitdatareq:  putmsg");
+}
+
+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, &ctl, (struct strbuf*)NULL, &flags, "dlinfoack");
+
+        dlp = (union DL_primitives *) ctl.buf;
+
+        expecting(DL_INFO_ACK, dlp);
+
+        if (ctl.len < sizeof (dl_info_ack_t)) {
+		char buffer[256];
+		sprintf(buffer, "dlinfoack:  response ctl.len too short:  %d", ctl.len); 
+                rp_fatal(buffer); 
+	}
+
+        if (flags != RS_HIPRI)
+                rp_fatal("dlinfoack:  DL_INFO_ACK was not M_PCPROTO");
+
+        if (ctl.len < sizeof (dl_info_ack_t)) {
+		char buffer[256];
+		sprintf(buffer, "dlinfoack:  short response ctl.len:  %d", 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 *) &bind_req;
+
+        flags = 0;
+
+        if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+                fatalSys("dlbindreq:  putmsg");
+}
+
+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 *) &attach_req;
+
+        flags = 0;
+
+        if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+                fatalSys("dlattachreq:  putmsg");
+}
+
+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, &ctl, (struct strbuf*)NULL, &flags, "dlokack");
+
+        dlp = (union DL_primitives *) ctl.buf;
+
+        expecting(DL_OK_ACK, dlp);
+
+        if (ctl.len < sizeof (dl_ok_ack_t)) { 
+		char buffer[256];
+		sprintf(buffer, "dlokack:  response ctl.len too short:  %d", ctl.len);
+		rp_fatal(buffer); 
+	}
+
+        if (flags != RS_HIPRI)
+                rp_fatal("dlokack:  DL_OK_ACK was not M_PCPROTO");
+
+        if (ctl.len < sizeof (dl_ok_ack_t)) {
+		char buffer[256]; 
+		sprintf(buffer, "dlokack:  short response ctl.len:  %d", 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, &ctl, (struct strbuf*)NULL, &flags, "dlbindack");
+
+        dlp = (union DL_primitives *) ctl.buf;
+
+        expecting(DL_BIND_ACK, dlp);
+
+        if (flags != RS_HIPRI)
+                rp_fatal("dlbindack:  DL_OK_ACK was not M_PCPROTO");
+
+        if (ctl.len < sizeof (dl_bind_ack_t)) {
+		char buffer[256];
+		sprintf(buffer, "dlbindack:  short response ctl.len:  %d", 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, &sioc);
+
+        if (rc < 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) < 0) {
+                (void) sprintf(errmsg, "%s:  alarm", caller);
+                fatalSys(errmsg);
+        }
+
+        /*
+         * Set flags argument and issue getmsg().
+         */
+        *flagsp = 0;
+        if ((rc = getmsg(fd, ctlp, datap, flagsp)) < 0) {
+                (void) sprintf(errmsg, "%s:  getmsg", caller);
+                fatalSys(errmsg);
+        }
+
+        /*
+         * Stop timer.
+         */
+        if (alarm(0) < 0) {
+                (void) sprintf(errmsg, "%s:  alarm", caller);
+                fatalSys(errmsg);
+        }
+
+        /*
+         * Check for MOREDATA and/or MORECTL.
+         */
+        if ((rc & (MORECTL | MOREDATA)) == (MORECTL | MOREDATA)) {
+		char buffer[256]; 
+		sprintf(buffer, "%s:  MORECTL|MOREDATA", caller);
+		rp_fatal(buffer);
+	}
+                
+        if (rc & MORECTL) {
+		char buffer[256];
+		sprintf(buffer, "%s:  MORECTL", caller);
+		rp_fatal(buffer); 
+	}
+        
+        if (rc & MOREDATA) {
+		char buffer[256]; 
+		sprintf(buffer, "%s:  MOREDATA", caller);
+		rp_fatal(buffer);
+	}
+
+        /*
+         * Check for at least sizeof (long) control data portion.
+         */
+        if (ctlp->len < sizeof (long)) {
+		char buffer[256]; 
+		sprintf(buffer, "getmsg:  control portion length < sizeof (long):  %d", ctlp->len);
+		rp_fatal(buffer); 
+	}
+}
+
+void sigalrm(int sig)
+{
+        (void) rp_fatal("sigalrm:  TIMEOUT");
+}
+
+void expecting(int prim, union DL_primitives *dlp)
+{
+        if (dlp->dl_primitive != (u_long)prim) {
+		char buffer[256]; 
+		sprintf(buffer, "expected %s got %s", dlprim(prim), dlprim(dlp->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, "unknown primitive 0x%lx", 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="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+	-c) instcmd="$cpprog"
+	    shift
+	    continue;;
+
+	-d) dir_arg=true
+	    shift
+	    continue;;
+
+	-m) chmodcmd="$chmodprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-o) chowncmd="$chownprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-g) chgrpcmd="$chgrpprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-s) stripcmd="$stripprog"
+	    shift
+	    continue;;
+
+	-t=*) transformarg=`echo $1 | sed 's/-t=//'`
+	    shift
+	    continue;;
+
+	-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+	    shift
+	    continue;;
+
+	*)  if [ x"$src" = 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"$src" = x ]
+then
+	echo "install:	no input file specified"
+	exit 1
+else
+	true
+fi
+
+if [ x"$dir_arg" != x ]; then
+	dst=$src
+	src=""
+	
+	if [ -d $dst ]; then
+		instcmd=:
+	else
+		instcmd=mkdir
+	fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" 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 "install:  $src does not exist"
+		exit 1
+	fi
+	
+	if [ x"$dst" = x ]
+	then
+		echo "install:	no destination specified"
+		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="$dst"/`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 "$dstdir" ]; then
+defaultIFS='	
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+	pathcomp="${pathcomp}${1}"
+	shift
+
+	if [ ! -d "${pathcomp}" ] ;
+        then
+		$mkdirprog "${pathcomp}"
+	else
+		true
+	fi
+
+	pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+	$doit $instcmd $dst &&
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+	if [ x"$transformarg" = 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"$dstfile" = 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 &&
+
+	trap "rm -f ${dsttmp}" 0 &&
+
+# 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 "$doit $instcmd $src $dsttmp" command.
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+	$doit $rmcmd -f $dstdir/$dstfile &&
+	$doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+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 <string.h>		/* for memcpy() */
+#include "md5.h"
+
+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] << 8 | buf[2]) << 16 |
+	    ((unsigned) buf[1] << 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->buf[0] = 0x67452301;
+    ctx->buf[1] = 0xefcdab89;
+    ctx->buf[2] = 0x98badcfe;
+    ctx->buf[3] = 0x10325476;
+
+    ctx->bits[0] = 0;
+    ctx->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->bits[0];
+    if ((ctx->bits[0] = t + ((uint32) len << 3)) < t)
+	ctx->bits[1]++;		/* Carry from low to high */
+    ctx->bits[1] += len >> 29;
+
+    t = (t >> 3) & 0x3f;	/* Bytes already in shsInfo->data */
+
+    /* Handle any leading odd-sized chunks */
+
+    if (t) {
+	unsigned char *p = (unsigned char *) ctx->in + t;
+
+	t = 64 - t;
+	if (len < t) {
+	    memcpy(p, buf, len);
+	    return;
+	}
+	memcpy(p, buf, t);
+	byteReverse(ctx->in, 16);
+	MD5Transform(ctx->buf, (uint32 *) ctx->in);
+	buf += t;
+	len -= t;
+    }
+    /* Process data in 64-byte chunks */
+
+    while (len >= 64) {
+	memcpy(ctx->in, buf, 64);
+	byteReverse(ctx->in, 16);
+	MD5Transform(ctx->buf, (uint32 *) ctx->in);
+	buf += 64;
+	len -= 64;
+    }
+
+    /* Handle any remaining bytes of data. */
+
+    memcpy(ctx->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->bits[0] >> 3) & 0x3F;
+
+    /* Set the first char of padding to 0x80.  This is safe since there is
+       always at least one byte free */
+    p = ctx->in + count;
+    *p++ = 0x80;
+
+    /* Bytes of padding needed to make 64 bytes */
+    count = 64 - 1 - count;
+
+    /* Pad out to 56 mod 64 */
+    if (count < 8) {
+	/* Two lots of padding:  Pad the first block to 64 bytes */
+	memset(p, 0, count);
+	byteReverse(ctx->in, 16);
+	MD5Transform(ctx->buf, (uint32 *) ctx->in);
+
+	/* Now fill the next block with 56 bytes */
+	memset(ctx->in, 0, 56);
+    } else {
+	/* Pad block to 56 bytes */
+	memset(p, 0, count - 8);
+    }
+    byteReverse(ctx->in, 14);
+
+    /* Append length in bits and transform */
+    ((uint32 *) ctx->in)[14] = ctx->bits[0];
+    ((uint32 *) ctx->in)[15] = ctx->bits[1];
+
+    MD5Transform(ctx->buf, (uint32 *) ctx->in);
+    byteReverse((unsigned char *) ctx->buf, 4);
+    memcpy(digest, ctx->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 & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (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<<s | w>>(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 <mostrows at styx.uwaterloo.ca>,
+*                Jamal Hadi Salim <hadi at cyberus.ca>
+* 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[] =
+"$Id: plugin.c 195724 2001-06-11 13:49:39Z gc $";
+
+#define _GNU_SOURCE 1
+#include "pppoe.h"
+
+#include "pppd/pppd.h"
+#include "pppd/fsm.h"
+#include "pppd/lcp.h"
+#include "pppd/ipcp.h"
+#include "pppd/ccp.h"
+#include "pppd/pathnames.h"
+
+#include <linux/types.h>
+#include <syslog.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <net/ethernet.h>
+#include <net/if_arp.h>
+#include <linux/if_pppox.h>
+
+/* 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[] = {
+    { "rp_pppoe_service", o_string, &service,
+      "Desired PPPoE service name" },
+    { "rp_pppoe_ac",      o_string, &acName,
+      "Desired PPPoE access concentrator name" },
+    { "rp_pppoe_sess",    o_string, &existingSession,
+      "Attach to existing session (sessid:macaddr)" },
+    { 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("Could not allocate memory for PPPoE session");
+    }
+    memset(conn, 0, sizeof(PPPoEConnection));
+    if (acName) {
+	SET_STRING(conn->acName, acName);
+    }
+    if (service) {
+	SET_STRING(conn->serviceName, acName);
+    }
+    SET_STRING(conn->ifName, devnam);
+    conn->discoverySocket = -1;
+    conn->sessionSocket = -1;
+    conn->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, "%d:%x:%x:%x:%x:%x:%x",
+		   &ses, &mac[0], &mac[1], &mac[2],
+		   &mac[3], &mac[4], &mac[5]) != 7) {
+	    fatal("Illegal value for rp_pppoe_sess option");
+	}
+	conn->session = htons(ses);
+	for (i=0; i<ETH_ALEN; i++) {
+	    conn->peerEth[i] = (unsigned char) mac[i];
+	}
+    } else {
+	discovery(conn);
+	if (conn->discoveryState != STATE_SESSION) {
+	    fatal("Unable to complete PPPoE Discovery");
+	}
+    }
+
+    /* Make the session socket */
+    conn->sessionSocket = socket(AF_PPPOX, SOCK_STREAM, PX_PROTO_OE);
+    if (conn->sessionSocket < 0) {
+	fatal("Failed to create PPPoE socket: %m");
+    }
+    sp.sa_family = AF_PPPOX;
+    sp.sa_protocol = PX_PROTO_OE;
+    sp.sa_addr.pppoe.sid = conn->session;
+    memcpy(sp.sa_addr.pppoe.dev, conn->ifName, IFNAMSIZ);
+    memcpy(sp.sa_addr.pppoe.remote, conn->peerEth, ETH_ALEN);
+    if (connect(conn->sessionSocket, (struct sockaddr *) &sp,
+		sizeof(struct sockaddr_pppox)) < 0) {
+	fatal("Failed to connect PPPoE socket: %d %m", errno);
+	return -1;
+    }
+    return conn->sessionSocket;
+}
+
+static void
+PPPOESendConfig(int unit, 
+		int mtu, 
+		u_int32_t asyncmap, 
+		int pcomp, 
+		int accomp)
+{
+    int sock;
+    struct ifreq ifr;
+    
+    if (mtu > MAX_PPPOE_MTU) {
+	warn("Couldn't increase MTU to %d", mtu);
+    }
+    sock = socket(AF_INET, SOCK_DGRAM, 0);
+    if (sock < 0) {
+	fatal("Couldn't create IP socket: %m");
+    }
+    strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+    ifr.ifr_mtu = mtu;
+    if (ioctl(sock, SIOCSIFMTU, &ifr) < 0) {
+	fatal("ioctl(SIOCSIFMTU): %m");
+    }
+    (void) close (sock);
+}
+
+
+static void
+PPPOERecvConfig(int unit, 
+		int mru, 
+		u_int32_t asyncmap, 
+		int pcomp, 
+		int accomp)
+{
+    if (mru > MAX_PPPOE_MTU) {
+	error("Couldn't increase MRU to %d", 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->ifName, IFNAMSIZ);
+    memcpy(sp.sa_addr.pppoe.remote, conn->peerEth, ETH_ALEN);
+    if (connect(conn->sessionSocket, (struct sockaddr *) &sp,
+		sizeof(struct sockaddr_pppox)) < 0) {
+	fatal("Failed to disconnect PPPoE socket: %d %m", errno);
+	return;
+    }
+    close(conn->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)) < 0) {
+	r = 0;
+    }
+
+    /* Try getting interface index */
+    if (r) {
+	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+	if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
+	    r = 0;
+	} else {
+	    if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
+		r = 0;
+	    } else {
+		if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+		    error("Interface %s not Ethernet", 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("Linux kernel does not support PPPoE -- are you running 2.4.x?");
+    }
+    OldDevnameHook = setdevname_hook;
+    setdevname_hook = PPPoEDevnameHook;
+    add_options(Options);
+
+    info("Roaring Penguin PPPoE Plugin Initialized");
+}
+
+/**********************************************************************
+*%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, "%.256s: %.256s", str, strerror(i));
+    printErr(buf);
+    sprintf(buf, "RP-PPPoE: %.256s: %.256s", 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, "RP-PPPoE: %.256s", 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[] =
+"$Id: ppp.c 195724 2001-06-11 13:49:39Z gc $";
+
+#include "pppoe.h"
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_N_HDLC
+#ifndef N_HDLC
+#include <linux/termios.h>
+#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->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 >= 2) {
+	memcpy(packet->payload, buf+2, r-2);
+    }
+#endif
+    if (r < 0) {
+	/* Catch the Linux "select" bug */
+	if (errno == EAGAIN) {
+	    rp_fatal("Linux select bug hit!  This message is harmless, but please ask the Linux kernel developers to fix it.");
+	}
+	fatalSys("read (syncReadFromPPP)");
+    }
+    if (r == 0) {
+	syslog(LOG_INFO, "end-of-file in syncReadFromPPP");
+	sendPADT(conn, "RP-PPPoE: EOF in syncReadFromPPP");
+	exit(0);
+    }
+
+    if (r < 2) {
+	rp_fatal("too few characters read from PPP (syncReadFromPPP)");
+    }
+    
+    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 < 0) {
+	fatalSys("read (asyncReadFromPPP)");
+    }
+
+    if (r == 0) {
+	syslog(LOG_INFO, "end-of-file in asyncReadFromPPP");
+	sendPADT(conn, "RP-PPPoE: EOF in asyncReadFromPPP");
+	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 && 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 && PPPState == STATE_BUILDING_PACKET) {
+	    --r;
+	    c = *ptr++;
+	    switch(c) {
+	    case FRAME_ESC:
+		PPPXorValue = FRAME_ENC;
+		break;
+	    case FRAME_FLAG:
+		if (PPPPacketSize < 2) {
+		    rp_fatal("Packet too short from PPP (asyncReadFromPPP)");
+		}
+		sendSessionPacket(conn, packet, PPPPacketSize-2);
+		PPPPacketSize = 0;
+		PPPXorValue = 0;
+		PPPState = STATE_WAITFOR_FRAME_ADDR;
+		break;
+	    default:
+		if (PPPPacketSize >= ETH_DATA_LEN - 4) {
+		    syslog(LOG_ERR, "Packet too big!  Check MTU on PPP interface");
+		    PPPPacketSize = 0;
+		    PPPXorValue = 0;
+		    PPPState = STATE_WAITFOR_FRAME_ADDR;
+		} else {
+		    packet->payload[PPPPacketSize++] = c ^ PPPXorValue;
+		    PPPXorValue = 0;
+		}
+	    }
+	}
+    }
+}
+
+/**********************************************************************
+*%FUNCTION: pppFCS16
+*%ARGUMENTS:
+* fcs -- current fcs
+* cp -- a buffer's worth of data
+* len -- length of buffer "cp"
+*%RETURNS:
+* A new FCS
+*%DESCRIPTION:
+* Updates the PPP FCS.
+***********************************************************************/
+UINT16_t
+pppFCS16(UINT16_t fcs, 
+	 unsigned char * cp, 
+	 int len)
+{
+    while (len--)
+	fcs = (fcs >> 8) ^ fcstab[(fcs ^ *cp++) & 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[] =
+"$Id: pppoe-server.c 195724 2001-06-11 13:49:39Z gc $";
+
+#include "config.h"
+
+#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 "pppoe.h"
+#include "md5.h"
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#include <signal.h>
+
+/* 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 "eth0"
+char *IfName = NULL;
+
+/* Access concentrator name */
+char *ACName = NULL;
+
+/* Options to pass to pppoe process */
+char PppoeOptions[SMALLBUF] = "";
+
+/* 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) > MAX_PPPOE_PAYLOAD) { \
+        syslog(LOG_ERR, "Would create too-long packet"); \
+        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, "r");
+    int numAddrs = 0;
+    unsigned int a, b, c, d;
+
+    if (!fp) {
+	sysErr("Cannot open address pool file");
+    }
+
+    while (!feof(fp)) {
+	if ((fscanf(fp, "%u.%u.%u.%u", &a, &b, &c, &d) == 4) &&
+	    a < 256 && b < 256 && c < 256 && d < 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("No valid ip addresses found in pool file");
+    }
+    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<NumSessionSlots; i++) {
+	if (Sessions[i].pid == pid) {
+	    return &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(&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, &status, WNOHANG)) > 0) {
+	session = findSession(pid);
+	if (!session) {
+	    syslog(LOG_ERR, "Child %d died but couldn't find session!",
+		   (int) pid);
+	} else {
+	    syslog(LOG_INFO,
+		   "Session %d closed for client %02x:%02x:%02x:%02x:%02x:%02x (%d.%d.%d.%d)",
+		   ntohs(session->sess),
+		   session->eth[0], session->eth[1], session->eth[2],
+		   session->eth[3], session->eth[4], session->eth[5],
+		   (int) session->ip[0], (int) session->ip[1],
+		   (int) session->ip[2], (int) session->ip[3]);
+	    conn.session = session->sess;
+	    memcpy(conn.peerEth, session->eth, ETH_ALEN);
+	    if (session->recvdPADT) {
+		sendPADT(&conn, "RP-PPPoE: Received PADT from peer");
+	    } else {
+		sendPADT(&conn, "RP-PPPoE: Child pppd process terminated");
+	    }
+	    session->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, "%s: %s", 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, "%.256s: %.256s", 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(&ctx);
+    MD5Update(&ctx, peerEthAddr, ETH_ALEN);
+    MD5Update(&ctx, myEthAddr, ETH_ALEN);
+    MD5Update(&ctx, seed, SEED_LEN);
+    MD5Final(cookie, &ctx);
+    memcpy(cookie+MD5_LEN, &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->ethHdr.h_source)) {
+	syslog(LOG_ERR, "PADI packet from non-unicast source address");
+	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->ethHdr.h_source, myAddr, CookieSeed, cookie.payload);
+
+    /* Construct a PADO packet */
+    memcpy(pado.ethHdr.h_dest, packet->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, &acname, acname_len + TAG_HDR_SIZE);
+    cursor += acname_len + TAG_HDR_SIZE;
+
+    CHECK_ROOM(cursor, pado.payload, TAG_HDR_SIZE);
+    memcpy(cursor, &servname, TAG_HDR_SIZE);
+    cursor += TAG_HDR_SIZE;
+    plen += TAG_HDR_SIZE;
+
+    CHECK_ROOM(cursor, pado.payload, TAG_HDR_SIZE + COOKIE_LEN);
+    memcpy(cursor, &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, &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, &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, &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->ethHdr.h_dest, myAddr, ETH_ALEN)) return;
+
+    /* Get session's index */
+    i = ntohs(packet->session) - 1 - SessOffset;
+    if (i >= NumSessionSlots) return;
+    if (Sessions[i].sess != packet->session) {
+	syslog(LOG_ERR, "Session index %u doesn't match session number %u",
+	       (unsigned int) i, (unsigned int) ntohs(packet->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->ethHdr.h_dest, myAddr, ETH_ALEN)) return;
+
+    /* Ignore PADR's from non-unicast addresses */
+    if (NOT_UNICAST(packet->ethHdr.h_source)) {
+	syslog(LOG_ERR, "PADR packet from non-unicast source address");
+	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->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 "" */
+    if (!requestedService.type) {
+	syslog(LOG_ERR, "Received PADR packet with no SERVICE_NAME tag");
+	sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,
+		      TAG_SERVICE_NAME_ERROR, "RP-PPPoE: Server: No service name tag");
+	return;
+    }
+
+    if (requestedService.length) {
+	syslog(LOG_ERR, "Received PADR packet asking for unsupported service %.*s", (int) ntohs(requestedService.length), requestedService.payload);
+	sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,
+		      TAG_SERVICE_NAME_ERROR, "RP-PPPoE: Server: Invalid service name tag");
+	return;
+    }
+
+    /* Looks cool... find a slot for the session */
+    cliSession = findSession(0);
+    if (!cliSession) {
+	syslog(LOG_ERR, "No client slots available (%02x:%02x:%02x:%02x:%02x:%02x)",
+	       (unsigned int) packet->ethHdr.h_source[0],
+	       (unsigned int) packet->ethHdr.h_source[1],
+	       (unsigned int) packet->ethHdr.h_source[2],
+	       (unsigned int) packet->ethHdr.h_source[3],
+	       (unsigned int) packet->ethHdr.h_source[4],
+	       (unsigned int) packet->ethHdr.h_source[5]);
+	sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,
+		      TAG_AC_SYSTEM_ERROR, "RP-PPPoE: Server: No client slots available");
+	return;
+    }
+
+    /* Set up client session peer Ethernet address */
+    memcpy(cliSession->eth, packet->ethHdr.h_source, ETH_ALEN);
+    cliSession->recvdPADT = 0;
+
+    /* Create child process, send PADS packet back */
+    child = fork();
+    if (child < 0) {
+	sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,
+		      TAG_AC_SYSTEM_ERROR, "RP-PPPoE: Server: Unable to start session process");
+	return;
+    }
+    if (child != 0) {
+	/* In the parent process.  Mark pid in session slot */
+	cliSession->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->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->sess;
+    plen = 0;
+    
+    servname.type = htons(TAG_SERVICE_NAME);
+    servname.length = 0;
+    
+    memcpy(cursor, &servname, TAG_HDR_SIZE);
+    cursor += TAG_HDR_SIZE;
+    plen += TAG_HDR_SIZE;
+    
+    if (relayId.type) {
+	memcpy(cursor, &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, &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, &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], &ReapPending, 1);
+    }
+}
+
+/**********************************************************************
+*%FUNCTION: usage
+*%ARGUMENTS:
+* argv0 -- argv[0] from main
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints usage instructions
+***********************************************************************/
+void
+usage(char const *argv0)
+{
+    fprintf(stderr, "Usage: %s [options]\n", argv0);
+    fprintf(stderr, "Options:\n");
+#ifdef USE_BPF
+    fprintf(stderr, "   -I if_name     -- Specify interface (REQUIRED)\n");
+#else
+    fprintf(stderr, "   -I if_name     -- Specify interface (default %s.)\n",
+	    DEFAULT_IF);
+#endif
+    fprintf(stderr, "   -T timeout     -- Specify inactivity timeout in seconds.\n");
+    fprintf(stderr, "   -C name        -- Set access concentrator name.\n");
+    fprintf(stderr, "   -m MSS         -- Clamp incoming and outgoing MSS options.\n");
+    fprintf(stderr, "   -L ip          -- Set local IP address.\n");
+    fprintf(stderr, "   -R ip          -- Set start address of remote IP pool.\n");
+    fprintf(stderr, "   -p fname       -- Optain IP address pool from specified file.\n");
+    fprintf(stderr, "   -N num         -- Allow 'num' concurrent sessions.\n");
+    fprintf(stderr, "   -o offset      -- Assign session numbers starting at offset+1.\n");
+    fprintf(stderr, "   -f disc:sess   -- Set Ethernet frame types (hex).\n");
+    fprintf(stderr, "   -s             -- Use synchronous PPP mode.\n");
+#ifdef HAVE_LINUX_KERNEL_PPPOE
+    fprintf(stderr, "   -k             -- Use kernel-mode PPPoE.\n");
+#endif
+    fprintf(stderr, "   -h             -- Print usage information.\n\n");
+    fprintf(stderr, "PPPoE-Server Version %s, Copyright (C) 2001 Roaring Penguin Software Inc.\n", VERSION);
+    fprintf(stderr, "PPPoE-Server comes with ABSOLUTELY NO WARRANTY.\n");
+    fprintf(stderr, "This is free software, and you are welcome to redistribute it\n");
+    fprintf(stderr, "under the terms of the GNU General Public License, version 2\n");
+    fprintf(stderr, "or (at your option) any later version.\n");
+    fprintf(stderr, "http://www.roaringpenguin.com\n");
+}
+
+/**********************************************************************
+*%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 = "hI:C:L:R:T:m:FN:f:o:sp:";
+#else
+    char *options = "hI:C:L:R:T:m:FN:f:o:skp:";
+#endif
+
+    /* Initialize syslog */
+    openlog("pppoe-server", 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),
+		     " -s");
+	    break;
+	case 'f':
+	    if (sscanf(optarg, "%x:%x", &discoveryType, &sessionType) != 2) {
+		fprintf(stderr, "Illegal argument to -f: Should be disc:sess in hex\n");
+		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),
+		     " -%c %s", opt, optarg);
+	    break;
+	case 'F':
+	    beDaemon = 0;
+	    break;
+	case 'N':
+	    if (sscanf(optarg, "%d", &opt) != 1) {
+		usage(argv[0]);
+		exit(EXIT_FAILURE);
+	    }
+	    if (opt <= 0) {
+		fprintf(stderr, "-N: Value must be positive\n");
+		exit(EXIT_FAILURE);
+	    }
+	    NumSessionSlots = opt;
+	    break;
+	case 'o':
+	    if (sscanf(optarg, "%d", &opt) != 1) {
+		usage(argv[0]);
+		exit(EXIT_FAILURE);
+	    }
+	    if (opt < 0) {
+		fprintf(stderr, "-o: Value must be non-negative\n");
+		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, "%d.%d.%d.%d", &d[0], &d[1], &d[2], &d[3]) != 4) {
+		usage(argv[0]);
+		exit(EXIT_FAILURE);
+	    }
+	    for (i=0; i<IPV4ALEN; i++) {
+		if (d[i] < 0 || d[i] > 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),
+		     " -%c %s", opt, optarg);
+	    break;
+	case 'h':
+	    usage(argv[0]);
+	    exit(EXIT_SUCCESS);
+	}
+    }
+    
+#ifdef USE_LINUX_PACKET
+#ifndef HAVE_STRUCT_SOCKADDR_LL
+    fprintf(stderr, "The PPPoE relay does not work on Linux 2.0 kernels.\n");
+    exit(EXIT_FAILURE);
+#endif
+#endif
+
+    if (!IfName) {
+	IfName = DEFAULT_IF;
+    }
+    
+    if (!ACName) {
+	ACName = malloc(HOSTNAMELEN);
+	if (gethostname(ACName, HOSTNAMELEN) < 0) {
+	    fatalSys("gethostname");
+	}
+    }
+
+    /* If address pool filename given, count number of addresses */
+    if (addressPoolFname) {
+	NumSessionSlots = parseAddressPool(addressPoolFname, 0);
+    }
+
+    /* Max 65534 - SessOffset sessions */
+    if (NumSessionSlots + SessOffset > 65534) {
+	fprintf(stderr, "-N and -o options must add up to at most 65534\n");
+	exit(EXIT_FAILURE);
+    }
+
+    /* Allocate memory for sessions */
+    Sessions = calloc(NumSessionSlots, sizeof(struct ClientSession));
+    if (!Sessions) {
+	rp_fatal("Cannot allocate memory for session slots");
+    }
+
+    /* Fill in remote IP addresses from pool */
+    if (addressPoolFname) {
+	(void) parseAddressPool(addressPoolFname, 1);
+    }
+
+    /* For testing -- generate sequential remote IP addresses */
+    for(i=0; i<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 < 0) {
+	    fatalSys("fork");
+	} else if (i != 0) {
+	    /* parent */
+	    exit(EXIT_SUCCESS);
+	}
+	setsid();
+	signal(SIGHUP, SIG_IGN);
+	i = fork();
+	if (i < 0) {
+	    fatalSys("fork");
+	} else if (i != 0) {
+	    exit(EXIT_SUCCESS);
+	}
+
+	chdir("/");
+	closelog();
+	for (i=0; i<CLOSEFD; i++) close(i);
+	/* We nuked our syslog descriptor... */
+	openlog("pppoe-server", LOG_PID, LOG_DAEMON);
+    }
+
+    /* Initialize our random cookie.  Try /dev/urandom; if that fails,
+       use PID and rand() */
+    fp = fopen("/dev/urandom", "r");
+    if (fp) {
+	fread(&CookieSeed, 1, SEED_LEN, fp);
+	fclose(fp);
+    } else {
+	CookieSeed[0] = getpid() & 0xFF;
+	CookieSeed[1] = (getpid() >> 8) & 0xFF;
+	for (i=2; i<SEED_LEN; i++) {
+	    CookieSeed[i] = (rand() >> (i % 9)) & 0xFF;
+	}
+    }
+    
+    sock = openInterface(IfName, Eth_PPPOE_Discovery, myAddr);
+
+    /* Set signal handler for SIGCHLD */
+    act.sa_handler = childHandler;
+    sigemptyset(&act.sa_mask);
+    act.sa_flags = SA_NOCLDSTOP | SA_RESTART;
+    if (sigaction(SIGCHLD, &act, NULL) < 0) {
+	fatalSys("sigaction");
+    }
+
+    /* Set up pipe for signal handler */
+    if (pipe(Pipe) < 0) {
+	fatalSys("pipe");
+    }
+
+    /* Main server loop */
+    maxFD = sock;
+    if (Pipe[0] > maxFD) maxFD = Pipe[0];
+    maxFD++;
+
+    for(;;) {
+	fd_set readable;
+	FD_ZERO(&readable);
+	FD_SET(sock, &readable);
+	FD_SET(Pipe[0], &readable);
+
+	while(1) {
+	    i = select(maxFD, &readable, NULL, NULL, NULL);
+	    if (i >= 0 || errno != EINTR) break;
+	}
+	if (i < 0) {
+	    fatalSys("select");
+	}
+
+	if (FD_ISSET(Pipe[0], &readable)) {
+	    /* Clear pipe */
+	    char buf[SMALLBUF];
+	    read(Pipe[0], buf, SMALLBUF);
+	}
+
+	if (ReapPending) {
+	    ReapPending = 0;
+	    reapSessions(myAddr, sock);
+	}
+	if (!FD_ISSET(sock, &readable)) {
+	    continue;
+	}
+
+	if (receivePacket(sock, &packet, &len) < 0) {
+	    continue;
+	}
+	
+	/* Check length */
+	if (ntohs(packet.length) + HDR_SIZE > len) {
+	    syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+		   (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, &packet, len);
+	    break;
+	case CODE_PADR:
+	    processPADR(sock, myAddr, &packet, len);
+	    break;
+	case CODE_PADT:
+	    /* Kill the child */
+	    processPADT(sock, myAddr, &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, &err, TAG_HDR_SIZE+elen);
+    cursor += TAG_HDR_SIZE + elen;
+    plen += TAG_HDR_SIZE + elen;
+    
+    if (relayId.type) {
+	memcpy(cursor, &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, &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, &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] = "pppd";
+    argv[1] = "pty";
+
+    snprintf(buffer, SMALLBUF, "%s -n -I %s -e %d:%02x:%02x:%02x:%02x:%02x:%02x%s",
+	     PPPOE_PATH, IfName,
+	     ntohs(session->sess),
+	     session->eth[0], session->eth[1], session->eth[2],
+	     session->eth[3], session->eth[4], session->eth[5],
+	     PppoeOptions);
+    argv[2] = strdup(buffer);
+    if (!argv[2]) {
+	/* TODO: Send a PADT */
+	exit(EXIT_FAILURE);
+    }
+
+    argv[3] = "file";
+    argv[4] = PPPOE_SERVER_OPTIONS;
+
+    snprintf(buffer, SMALLBUF, "%d.%d.%d.%d:%d.%d.%d.%d",
+	    (int) LocalIP[0], (int) LocalIP[1],
+	    (int) LocalIP[2], (int) LocalIP[3],
+	    (int) session->ip[0], (int) session->ip[1],
+	    (int) session->ip[2], (int) session->ip[3]);
+    syslog(LOG_INFO,
+	   "Session %d created for client %02x:%02x:%02x:%02x:%02x:%02x (%d.%d.%d.%d)",
+	   ntohs(session->sess),
+	   session->eth[0], session->eth[1], session->eth[2],
+	   session->eth[3], session->eth[4], session->eth[5],
+	   (int) session->ip[0], (int) session->ip[1],
+	   (int) session->ip[2], (int) session->ip[3]);
+    argv[5] = buffer; /* No need for strdup -- about to execv! */
+    argv[6] = "nodetach";
+    argv[7] = "noaccomp";
+    argv[8] = "nobsdcomp";
+    argv[9] = "nodeflate";
+    argv[10] = "nopcomp";
+    argv[11] = "novj";
+    argv[12] = "novjccomp";
+    argv[13] = "default-asyncmap";
+    if (Synchronous) {
+	argv[14] = "sync";
+	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] = "pppd";
+    argv[1] = "plugin";
+    argv[2] = PLUGIN_PATH;
+    argv[3] = IfName;
+    snprintf(buffer, SMALLBUF, "%d:%02x:%02x:%02x:%02x:%02x:%02x",
+	     ntohs(session->sess),
+	     session->eth[0], session->eth[1], session->eth[2],
+	     session->eth[3], session->eth[4], session->eth[5]);
+    argv[4] = "rp_pppoe_sess";
+    argv[5] = strdup(buffer);
+    if (!argv[5]) {
+	/* TODO: Send a PADT */
+	exit(EXIT_FAILURE);
+    }
+    argv[6] = "file";
+    argv[7] = PPPOE_SERVER_OPTIONS;
+
+    snprintf(buffer, SMALLBUF, "%d.%d.%d.%d:%d.%d.%d.%d",
+	    (int) LocalIP[0], (int) LocalIP[1],
+	    (int) LocalIP[2], (int) LocalIP[3],
+	    (int) session->ip[0], (int) session->ip[1],
+	    (int) session->ip[2], (int) session->ip[3]);
+    syslog(LOG_INFO,
+	   "Session %d created for client %02x:%02x:%02x:%02x:%02x:%02x (%d.%d.%d.%d)",
+	   ntohs(session->sess),
+	   session->eth[0], session->eth[1], session->eth[2],
+	   session->eth[3], session->eth[4], session->eth[5],
+	   (int) session->ip[0], (int) session->ip[1],
+	   (int) session->ip[2], (int) session->ip[3]);
+    argv[8] = buffer;
+    argv[9] = "nodetach";
+    argv[10] = "noaccomp";
+    argv[11] = "nobsdcomp";
+    argv[12] = "nodeflate";
+    argv[13] = "nopcomp";
+    argv[14] = "novj";
+    argv[15] = "novjccomp";
+    argv[16] = "default-asyncmap";
+    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[] =
+"$Id: pppoe-sniff.c 195724 2001-06-11 13:49:39Z gc $";
+
+#include "pppoe.h"
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef USE_DLPI
+#include <sys/dlpi.h>
+/* 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 "eth0"
+
+/* 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, "%.256s: %.256s", 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, "Usage: %s [options]\n", argv0);
+    fprintf(stderr, "Options:\n");
+    fprintf(stderr, "   -I if_name     -- Specify interface (default %s.)\n",
+	    DEFAULT_IF);
+    fprintf(stderr, "   -V             -- Print version and exit.\n");
+    fprintf(stderr, "\nPPPoE Version %s, Copyright (C) 2000 Roaring Penguin Software Inc.\n", VERSION);
+    fprintf(stderr, "PPPoE comes with ABSOLUTELY NO WARRANTY.\n");
+    fprintf(stderr, "This is free software, and you are welcome to redistribute it under the terms\n");
+    fprintf(stderr, "of the GNU General Public License, version 2 or any later version.\n");
+    fprintf(stderr, "http://www.roaringpenguin.com\n");
+    exit(0);
+}
+
+#if !defined(USE_LINUX_PACKET) && !defined(USE_DLPI)
+
+int
+main()
+{
+    fprintf(stderr, "Sorry, pppoe-sniff works only on Linux.\n");
+    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, "I:V")) != -1) {
+	switch(opt) {
+	case 'I':
+	    SET_STRING(IfName, optarg);
+	    break;
+	case 'V':
+	    printf("pppoe-sniff: Roaring Penguin PPPoE Version %s\n", 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, "Sniffing for PADR.  Start your connection on another machine...\n");
+    while (!SeenPADR) {
+	if (receivePacket(sock, &pkt, &size) < 0) continue;
+	if (ntohs(pkt.length) + HDR_SIZE > size) continue;
+	if (pkt.ver != 1 || pkt.type != 1)       continue;
+	if (pkt.code != CODE_PADR)               continue;
+
+	/* Looks promising... parse it */
+	if (parsePacket(&pkt, parsePADRTags, NULL) < 0) {
+	    continue;
+	}
+	DiscType = ntohs(pkt.ethHdr.h_proto);
+	fprintf(stderr, "\nExcellent!  Sniffed a likely-looking PADR.\n");
+	break;
+    }
+    
+    while (!SeenSess) {
+	if (receivePacket(sock, &pkt, &size) < 0) continue;
+	if (ntohs(pkt.length) + HDR_SIZE > 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, "Wonderful!  Sniffed a likely-looking session packet.\n");
+    if ((ServiceName == NULL || *ServiceName == 0) &&
+	DiscType == ETH_PPPOE_DISCOVERY &&
+	SessType == ETH_PPPOE_SESSION) {
+	fprintf(stderr, "\nGreat!  It looks like a standard PPPoE service.\nYou should not need anything special in the configuration file.\n");
+	return 0;
+    }
+
+    fprintf(stderr, "\nOK, looks like you need something special in the configuration file.\nTry this:\n\n");
+    if (ServiceName != NULL && *ServiceName != 0) {
+	fprintf(stderr, "SERVICENAME='%s'\n", ServiceName);
+    }
+    if (DiscType != ETH_PPPOE_DISCOVERY || SessType != ETH_PPPOE_SESSION) {
+	fprintf(stderr, " PPPOE_EXTRA='-f %x:%x'\n", 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, "%.256s: %.256s", 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[] =
+"$Id: pppoe.c 224882 2007-07-16 22:03:12Z blino $";
+
+#include "pppoe.h"
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef USE_LINUX_PACKET
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#endif
+
+#include <signal.h>
+
+#ifdef HAVE_N_HDLC
+#ifndef N_HDLC
+#include <termios.h>
+#endif
+#endif
+
+/* Default interface if no -I option given */
+#define DEFAULT_IF "eth0"
+
+/* 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->length = htons(len);
+    if (optClampMSS) {
+	clampMSS(packet, "outgoing", optClampMSS);
+    }
+    if (sendPacket(conn, conn->sessionSocket, packet, len + HDR_SIZE) < 0) {
+	exit(EXIT_FAILURE);
+    }
+    if (conn->debugFile) {
+	dumpPacket(conn->debugFile, packet, "SENT");
+	fprintf(conn->debugFile, "\n");
+	fflush(conn->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->code != CODE_PADT) {
+	return;
+    }
+
+    /* It's a PADT, all right.  Is it for us? */
+    if (packet->session != Connection->session) {
+	/* Nope, ignore it */
+	return;
+    }
+
+    syslog(LOG_INFO,
+	   "Session terminated -- received PADT from access concentrator");
+    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->discoverySocket, &packet, &len) < 0) {
+	return;
+    }
+
+    /* Check length */
+    if (ntohs(packet.length) + HDR_SIZE > len) {
+	syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+	       (unsigned int) ntohs(packet.length));
+	return;
+    }
+
+    if (conn->debugFile) {
+	dumpPacket(conn->debugFile, &packet, "RCVD");
+	fprintf(conn->debugFile, "\n");
+	fflush(conn->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->session) {
+	/* Nope, ignore it */
+	return;
+    }
+
+    syslog(LOG_INFO,
+	   "Session terminated -- received PADT from peer");
+    parsePacket(&packet, parseLogErrs, NULL);
+    exit(EXIT_SUCCESS);
+}
+#endif /* USE_BPF */
+
+/**********************************************************************
+*%FUNCTION: session
+*%ARGUMENTS:
+* conn -- PPPoE connection info
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Handles the "session" 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->sessionSocket = openInterface(conn->ifName, Eth_PPPOE_Session, conn->myEth);
+
+    /* Prepare for select() */
+    if (conn->sessionSocket > maxFD)   maxFD = conn->sessionSocket;
+    if (conn->discoverySocket > maxFD) maxFD = conn->discoverySocket;
+    maxFD++;
+
+    /* Fill in the constant fields of the packet to save time */
+    memcpy(packet.ethHdr.h_dest, conn->peerEth, ETH_ALEN);
+    memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);
+    packet.ethHdr.h_proto = htons(Eth_PPPOE_Session);
+    packet.ver = 1;
+    packet.type = 1;
+    packet.code = CODE_SESS;
+    packet.session = conn->session;
+
+    initPPP();
+
+#ifdef USE_BPF
+    /* check for buffered session data */
+    while (BPF_BUFFER_HAS_DATA) {
+	if (conn->synchronous) {
+	    syncReadFromEth(conn, conn->sessionSocket, optClampMSS);
+	} else {
+	    asyncReadFromEth(conn, conn->sessionSocket, optClampMSS);
+	}
+    }
+#endif
+
+    for (;;) {
+	if (optInactivityTimeout > 0) {
+	    tv.tv_sec = optInactivityTimeout;
+	    tv.tv_usec = 0;
+	    tvp = &tv;
+	}
+	FD_ZERO(&readable);
+	FD_SET(0, &readable);     /* ppp packets come from stdin */
+	if (conn->discoverySocket >= 0) {
+	    FD_SET(conn->discoverySocket, &readable);
+	}
+	FD_SET(conn->sessionSocket, &readable);
+	while(1) {
+	    r = select(maxFD, &readable, NULL, NULL, tvp);
+	    if (r >= 0 || errno != EINTR) break;
+	}
+	if (r < 0) {
+	    fatalSys("select (session)");
+	}
+	if (r == 0) { /* Inactivity timeout */
+	    syslog(LOG_ERR, "Inactivity timeout... something wicked happened");
+	    sendPADT(conn, "RP-PPPoE: Inactivity timeout");
+	    exit(EXIT_FAILURE);
+	}
+
+	/* Handle ready sockets */
+	if (FD_ISSET(0, &readable)) {
+	    if (conn->synchronous) {
+		syncReadFromPPP(conn, &packet);
+	    } else {
+		asyncReadFromPPP(conn, &packet);
+	    }
+	}
+
+	if (FD_ISSET(conn->sessionSocket, &readable)) {
+	    do {
+		if (conn->synchronous) {
+		    syncReadFromEth(conn, conn->sessionSocket, optClampMSS);
+		} else {
+		    asyncReadFromEth(conn, conn->sessionSocket, optClampMSS);
+		}
+	    } while (BPF_BUFFER_HAS_DATA);
+	}
+
+#ifndef USE_BPF	
+	/* BSD uses a single socket, see *syncReadFromEth() */
+	/* for calls to sessionDiscoveryPacket() */
+	if (conn->discoverySocket >= 0) {
+	    if (FD_ISSET(conn->discoverySocket, &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,"Received signal %d.",(int)src);
+  sendPADT(Connection, "RP-PPPoE: Received signal");
+  exit(EXIT_SUCCESS);
+}
+
+/**********************************************************************
+*%FUNCTION: usage
+*%ARGUMENTS:
+* argv0 -- program name
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints usage information and exits.
+***********************************************************************/
+void
+usage(char const *argv0)
+{
+    fprintf(stderr, "Usage: %s [options]\n", argv0);
+    fprintf(stderr, "Options:\n");
+#ifdef USE_BPF
+    fprintf(stderr, "   -I if_name     -- Specify interface (REQUIRED)\n");
+#else
+    fprintf(stderr, "   -I if_name     -- Specify interface (default %s.)\n",
+	    DEFAULT_IF);
+#endif
+    fprintf(stderr, "   -T timeout     -- Specify inactivity timeout in seconds.\n");
+    fprintf(stderr, "   -D filename    -- Log debugging information in filename.\n");
+    fprintf(stderr, "   -V             -- Print version and exit.\n");
+    fprintf(stderr, "   -A             -- Print access concentrator names and exit.\n");
+    fprintf(stderr, "   -S name        -- Set desired service name.\n");
+    fprintf(stderr, "   -C name        -- Set desired access concentrator name.\n");
+    fprintf(stderr, "   -U             -- Use Host-Unique to allow multiple PPPoE sessions.\n");
+    fprintf(stderr, "   -s             -- Use synchronous PPP encapsulation.\n");
+    fprintf(stderr, "   -m MSS         -- Clamp incoming and outgoing MSS options.\n");
+    fprintf(stderr, "   -p pidfile     -- Write process-ID to pidfile.\n");
+    fprintf(stderr, "   -e sess:mac    -- Skip discovery phase; use existing session.\n");
+    fprintf(stderr, "   -n             -- Do not open discovery socket.\n");
+    fprintf(stderr, "   -k             -- Kill a session with PADT (requires -e)\n");
+    fprintf(stderr, "   -d             -- Perform discovery, print session info and exit.\n");
+    fprintf(stderr, "   -f disc:sess   -- Set Ethernet frame types (hex).\n");
+    fprintf(stderr, "   -h             -- Print usage information.\n\n");
+    fprintf(stderr, "PPPoE Version %s, Copyright (C) 2001 Roaring Penguin Software Inc.\n", VERSION);
+    fprintf(stderr, "PPPoE comes with ABSOLUTELY NO WARRANTY.\n");
+    fprintf(stderr, "This is free software, and you are welcome to redistribute it under the terms\n");
+    fprintf(stderr, "of the GNU General Public License, version 2 or any later version.\n");
+    fprintf(stderr, "http://www.roaringpenguin.com\n");
+    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(&conn, 0, sizeof(conn));
+    conn.discoverySocket = -1;
+    conn.sessionSocket = -1;
+
+    /* For signal handler */
+    Connection = &conn;
+
+    /* Initialize syslog */
+    openlog("pppoe", LOG_PID, LOG_DAEMON);
+
+    while((opt = getopt(argc, argv, "I:VAT:D:hS:C:Usm:np:e:kdf:")) != -1) {
+	switch(opt) {
+	case 'f':
+	    if (sscanf(optarg, "%x:%x", &discoveryType, &sessionType) != 2) {
+		fprintf(stderr, "Illegal argument to -f: Should be disc:sess in hex\n");
+		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: "sess:xx:yy:zz:aa:bb:cc" where "sess" is
+	       session-ID, and xx:yy:zz:aa:bb:cc is MAC-address of peer */
+	    n = sscanf(optarg, "%u:%2x:%2x:%2x:%2x:%2x:%2x",
+		       &s, &m[0], &m[1], &m[2], &m[3], &m[4], &m[5]);
+	    if (n != 7) {
+		fprintf(stderr, "Illegal argument to -e: Should be sess:xx:yy:zz:aa:bb:cc\n");
+		exit(EXIT_FAILURE);
+	    }
+
+	    /* Copy MAC address of peer */
+	    for (n=0; n<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, "w");
+	    if (pidfile) {
+		fprintf(pidfile, "%lu\n", (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, "w");
+	    if (!conn.debugFile) {
+		fprintf(stderr, "Could not open %s: %s\n",
+			optarg, strerror(errno));
+		exit(EXIT_FAILURE);
+	    }
+	    fprintf(conn.debugFile, "rp-pppoe-%s\n", VERSION);
+	    fflush(conn.debugFile);
+	    break;
+	case 'T':
+	    optInactivityTimeout = (int) strtol(optarg, NULL, 10);
+	    if (optInactivityTimeout < 0) {
+		optInactivityTimeout = 0;
+	    }
+	    break;
+	case 'm':
+	    optClampMSS = (int) strtol(optarg, NULL, 10);
+	    if (optClampMSS < 536) {
+		fprintf(stderr, "-m: %d is too low (min 536)\n", optClampMSS);
+		exit(EXIT_FAILURE);
+	    }
+	    if (optClampMSS > 1452) {
+		fprintf(stderr, "-m: %d is too high (max 1452)\n", optClampMSS);
+		exit(EXIT_FAILURE);
+	    }
+	    break;
+	case 'I':
+	    SET_STRING(conn.ifName, optarg);
+	    break;
+	case 'V':
+	    printf("Roaring Penguin PPPoE Version %s\n", 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, "No interface specified (-I option)\n");
+	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, &disc) < 0) {
+		printErr("Unable to set line discipline to N_HDLC -- synchronous mode probably will fail");
+	    } else {
+		syslog(LOG_INFO,
+		       "Changed pty line discipline to N_HDLC for synchronous mode");
+	    }
+	    /* 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 < 0) fatalSys("fcntl(F_GETFL)");
+	    if (fcntl(0, F_SETFL, (long) flags | O_NONBLOCK) < 0) {
+		fatalSys("fcntl(F_SETFL)");
+	    }
+	}
+#endif
+
+    }
+
+    discovery(&conn);
+    if (optSkipSession) {
+	printf("%u:%02x:%02x:%02x:%02x:%02x:%02x\n",
+	       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(&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, "%.256s: %.256s", str, strerror(errno));
+    printErr(buf);
+    sendPADT(Connection, "RP-PPPoE: System call error");
+    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, "%.256s: %.256s", 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, "RP-PPPoE: %.256s", 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, &packet, &len) < 0) {
+	return;
+    }
+
+    /* Check length */
+    if (ntohs(packet.length) + HDR_SIZE > len) {
+	syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+	       (unsigned int) ntohs(packet.length));
+	return;
+    }
+    if (conn->debugFile) {
+	dumpPacket(conn->debugFile, &packet, "RCVD");
+	fprintf(conn->debugFile, "\n");
+	fflush(conn->debugFile);
+    }
+
+#ifdef USE_BPF
+    /* Make sure this is a session packet before processing further */
+    type = etherType(&packet);
+    if (type == Eth_PPPOE_Discovery) {
+	sessionDiscoveryPacket(&packet);
+    } else if (type != Eth_PPPOE_Session) {
+	return;
+    }
+#endif
+
+    /* Sanity check */
+    if (packet.code != CODE_SESS) {
+	syslog(LOG_ERR, "Unexpected packet code %d", (int) packet.code);
+	return;
+    }
+    if (packet.ver != 1) {
+	syslog(LOG_ERR, "Unexpected packet version %d", (int) packet.ver);
+	return;
+    }
+    if (packet.type != 1) {
+	syslog(LOG_ERR, "Unexpected packet type %d", (int) packet.type);
+	return;
+    }
+    if (memcmp(packet.ethHdr.h_source, conn->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->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 > len) {
+	syslog(LOG_ERR, "Bogus length field in session packet %d (%d)",
+	       (int) plen, (int) len);
+	return;
+    }
+
+    /* Clamp MSS */
+    if (clampMss) {
+	clampMSS(&packet, "incoming", clampMss);
+    }
+
+    /* Compute FCS */
+    fcs = pppFCS16(PPPINITFCS16, header, 2);
+    fcs = pppFCS16(fcs, packet.payload, plen) ^ 0xffff;
+    tail[0] = fcs & 0x00ff;
+    tail[1] = (fcs >> 8) & 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<plen; i++) {
+	c = packet.payload[i];
+	if (c == FRAME_FLAG || c == FRAME_ADDR || c == FRAME_ESC || c < 0x20) {
+	    *ptr++ = FRAME_ESC;
+	    *ptr++ = c ^ FRAME_ENC;
+	} else {
+	    *ptr++ = c;
+	}
+    }
+    for (i=0; i<2; i++) {
+	c = tail[i];
+	if (c == FRAME_FLAG || c == FRAME_ADDR || c == FRAME_ESC || c < 0x20) {
+	    *ptr++ = FRAME_ESC;
+	    *ptr++ = c ^ FRAME_ENC;
+	} else {
+	    *ptr++ = c;
+	}
+    }
+    *ptr++ = FRAME_FLAG;
+
+    /* Ship it out */
+    if (write(1, pppBuf, (ptr-pppBuf)) < 0) {
+	fatalSys("asyncReadFromEth: write");
+    }
+}
+
+/**********************************************************************
+*%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, &packet, &len) < 0) {
+	return;
+    }
+
+    /* Check length */
+    if (ntohs(packet.length) + HDR_SIZE > len) {
+	syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+	       (unsigned int) ntohs(packet.length));
+	return;
+    }
+    if (conn->debugFile) {
+	dumpPacket(conn->debugFile, &packet, "RCVD");
+	fprintf(conn->debugFile, "\n");
+	fflush(conn->debugFile);
+    }
+
+#ifdef USE_BPF
+    /* Make sure this is a session packet before processing further */
+    type = etherType(&packet);
+    if (type == Eth_PPPOE_Discovery) {
+	sessionDiscoveryPacket(&packet);
+    } else if (type != Eth_PPPOE_Session) {
+	return;
+    }
+#endif
+
+    /* Sanity check */
+    if (packet.code != CODE_SESS) {
+	syslog(LOG_ERR, "Unexpected packet code %d", (int) packet.code);
+	return;
+    }
+    if (packet.ver != 1) {
+	syslog(LOG_ERR, "Unexpected packet version %d", (int) packet.ver);
+	return;
+    }
+    if (packet.type != 1) {
+	syslog(LOG_ERR, "Unexpected packet type %d", (int) packet.type);
+	return;
+    }
+    if (memcmp(packet.ethHdr.h_source, conn->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->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 > len) {
+	syslog(LOG_ERR, "Bogus length field in session packet %d (%d)",
+	       (int) plen, (int) len);
+	return;
+    }
+
+    /* Clamp MSS */
+    if (clampMss) {
+	clampMSS(&packet, "incoming", 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) < 0) {
+	fatalSys("syncReadFromEth: write");
+    }
+}
+


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 "config.h"
+
+#if defined(HAVE_NETPACKET_PACKET_H) || defined(HAVE_LINUX_IF_PACKET_H)
+#define _POSIX_SOURCE 1 /* For sigaction defines */
+#endif
+
+#include <stdio.h>		/* For FILE */
+#include <sys/types.h>		/* 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) && !defined(USE_LINUX_PACKET) && !defined(USE_DLPI)
+#error Unknown method for accessing raw Ethernet frames
+#endif
+
+#ifdef HAVE_SYS_CDEFS_H
+#include <sys/cdefs.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+/* Ugly header files on some Linux boxes... */
+#if defined(HAVE_LINUX_IF_H)
+#include <linux/if.h>
+#elif defined(HAVE_NET_IF_H)
+#include <net/if.h>
+#endif
+
+#ifdef HAVE_NET_IF_TYPES_H
+#include <net/if_types.h>
+#endif
+
+#ifdef HAVE_NET_IF_DL_H
+#include <net/if_dl.h>
+#endif
+
+/* I'm not sure why this is needed... I do not have OpenBSD */
+#if defined(__OpenBSD__)
+#include <net/ppp_defs.h>
+#include <net/if_ppp.h>
+#endif
+
+#ifdef USE_BPF
+extern int bpfSize;
+struct PPPoEPacketStruct;
+void sessionDiscoveryPacket(struct PPPoEPacketStruct *packet);
+#define BPF_BUFFER_IS_EMPTY (bpfSize <= 0)
+#define BPF_BUFFER_HAS_DATA (bpfSize > 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 <sys/ethernet.h>
+#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 ("s")
+
+#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 <linux/if_ether.h>
+#endif
+
+#include <netinet/in.h>
+
+#ifdef HAVE_NETINET_IF_ETHER_H
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifndef HAVE_SYS_DLPI_H
+#include <netinet/if_ether.h>
+#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) > MAX_PPPOE_PAYLOAD) { \
+        syslog(LOG_ERR, "Would create too-long packet"); \
+        return; \
+    } \
+} while(0)
+
+/* True if Ethernet address is broadcast or multicast */
+#define NOT_UNICAST(e) ((e[0] & 0x01) != 0)
+#define BROADCAST(e) ((e[0] & e[1] & e[2] & e[3] & e[4] & e[5]) == 0xFF)
+#define NOT_BROADCAST(e) ((e[0] & e[1] & e[2] & e[3] & e[4] & 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[] =
+"$Id: relay.c 195724 2001-06-11 13:49:39Z gc $";
+
+#define _GNU_SOURCE 1 /* For SA_RESTART */
+
+#include "relay.h"
+
+#include <signal.h>
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#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<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->payload, tag,
+		       ntohs(tag->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 "len" bytes of data at location "loc" in "packet", 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->length);
+    /* Sanity checks */
+    if (loc < packet->payload ||
+	loc > packet->payload + plen ||
+	len + plen > MAX_PPPOE_PAYLOAD) {
+	return -1;
+    }
+
+    toMove = (packet->payload + plen) - loc;
+    memmove(loc+len, loc, toMove);
+    memcpy(loc, bytes, len);
+    packet->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 "len" bytes of data from location "loc" in "packet", moving all
+* other data down to close the gap
+***********************************************************************/
+int
+removeBytes(PPPoEPacket *packet,
+	    unsigned char *loc,
+	    int len)
+{
+    int toMove;
+    int plen = ntohs(packet->length);
+    /* Sanity checks */
+    if (len < 0 || len > plen ||
+	loc < packet->payload ||
+	loc + len > packet->payload + plen) {
+	return -1;
+    }
+
+    toMove = ((packet->payload + plen) - loc) - len;
+    memmove(loc, loc+len, toMove);
+    packet->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, "Usage: %s [options]\n", argv0);
+    fprintf(stderr, "Options:\n");
+    fprintf(stderr, "   -S if_name     -- Specify interface for PPPoE Server\n");
+    fprintf(stderr, "   -C if_name     -- Specify interface for PPPoE Client\n");
+    fprintf(stderr, "   -B if_name     -- Specify interface for both clients and server\n");
+    fprintf(stderr, "   -n nsess       -- Maxmimum number of sessions to relay\n");
+    fprintf(stderr, "   -i timeout     -- Idle timeout in seconds (0 = no timeout)\n");
+    fprintf(stderr, "   -F             -- Do not fork into background\n");
+    fprintf(stderr, "   -h             -- Print this help message\n");
+
+    fprintf(stderr, "\nPPPoE Version %s, Copyright (C) 2001 Roaring Penguin Software Inc.\n", VERSION);
+    fprintf(stderr, "PPPoE comes with ABSOLUTELY NO WARRANTY.\n");
+    fprintf(stderr, "This is free software, and you are welcome to redistribute it under the terms\n");
+    fprintf(stderr, "of the GNU General Public License, version 2 or any later version.\n");
+    fprintf(stderr, "http://www.roaringpenguin.com\n");
+    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 "n" sessions
+***********************************************************************/
+int
+main(int argc, char *argv[])
+{
+    int opt;
+    int nsess = DEFAULT_SESSIONS;
+    struct sigaction sa;
+    int beDaemon = 1;
+    openlog("pppoe-relay", LOG_PID, LOG_DAEMON);
+
+    while((opt = getopt(argc, argv, "hC:S:B:n:i:F")) != -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, "%u", &IdleTimeout) != 1) {
+		fprintf(stderr, "Illegal argument to -i: should be -i timeout\n");
+		exit(EXIT_FAILURE);
+	    }
+	    CleanPeriod = IdleTimeout / TIMEOUT_DIVISOR;
+	    if (CleanPeriod < MIN_CLEAN_PERIOD) CleanPeriod = MIN_CLEAN_PERIOD;
+	    break;
+	case 'n':
+	    if (sscanf(optarg, "%d", &nsess) != 1) {
+		fprintf(stderr, "Illegal argument to -n: should be -n #sessions\n");
+		exit(EXIT_FAILURE);
+	    }
+	    if (nsess < 1 || nsess > 65534) {
+		fprintf(stderr, "Illegal argument to -n: must range from 1 to 65534\n");
+		exit(EXIT_FAILURE);
+	    }
+	    break;
+	default:
+	    usage(argv[0]);
+	}
+    }
+
+#ifdef USE_LINUX_PACKET
+#ifndef HAVE_STRUCT_SOCKADDR_LL
+    fprintf(stderr, "The PPPoE relay does not work on Linux 2.0 kernels.\n");
+    exit(EXIT_FAILURE);
+#endif
+#endif
+
+    /* Check that at least two interfaces were defined */
+    if (NumInterfaces < 2) {
+	fprintf(stderr, "%s: Must define at least two interfaces\n",
+		argv[0]);
+	exit(EXIT_FAILURE);
+    }
+
+    /* Make a pipe for the cleaner */
+    if (pipe(CleanPipe) < 0) {
+	fatalSys("pipe");
+    }
+
+    /* Set up alarm handler */
+    sa.sa_handler = alarmHandler;
+    sigemptyset(&sa.sa_mask);
+    sa.sa_flags = SA_RESTART;
+    if (sigaction(SIGALRM, &sa, NULL) < 0) {
+	fatalSys("sigaction");
+    }
+    
+    /* Allocate memory for sessions, etc. */
+    initRelay(nsess);
+
+    /* Daemonize -- UNIX Network Programming, Vol. 1, Stevens */
+    if (beDaemon) {
+	int i;
+	i = fork();
+	if (i < 0) {
+	    fatalSys("fork");
+	} else if (i != 0) {
+	    /* parent */
+	    exit(0);
+	}
+	setsid();
+	signal(SIGHUP, SIG_IGN);
+	i = fork();
+	if (i < 0) {
+	    fatalSys("fork");
+	} else if (i != 0) {
+	    exit(0);
+	}
+
+	chdir("/");
+	closelog();
+	for (i=0; i<CLOSEFD; i++) {
+	    if (!keepDescriptor(i)) {
+		close(i);
+	    }
+	}
+	/* We nuked our syslog descriptor... */
+	openlog("pppoe-relay", 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 >= MAX_INTERFACES) {
+	fprintf(stderr, "Too many interfaces (%d max)\n",
+		MAX_INTERFACES);
+	exit(EXIT_FAILURE);
+    }
+    i = &Interfaces[NumInterfaces++];
+    strncpy(i->name, ifname, IFNAMSIZ);
+    i->name[IFNAMSIZ] = 0;
+
+    i->discoverySock = openInterface(ifname, Eth_PPPOE_Discovery, i->mac);
+    i->sessionSock   = openInterface(ifname, Eth_PPPOE_Session,   NULL);
+    i->clientOK = clientOK;
+    i->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("Unable to allocate memory for PPPoE session table");
+    }
+    AllHashes = calloc(MaxSessions*2, sizeof(SessionHash));
+    if (!AllHashes) {
+	rp_fatal("Unable to allocate memory for PPPoE hash table");
+    }
+
+    /* Initialize sessions in a linked list */
+    AllSessions[0].prev = NULL;
+    if (MaxSessions > 1) {
+	AllSessions[0].next = &AllSessions[1];
+    } else {
+	AllSessions[0].next = NULL;
+    }
+    for (i=1; i<MaxSessions-1; i++) {
+	AllSessions[i].prev = &AllSessions[i-1];
+	AllSessions[i].next = &AllSessions[i+1];
+    }
+    if (MaxSessions > 1) {
+	AllSessions[MaxSessions-1].prev = &AllSessions[MaxSessions-2];
+	AllSessions[MaxSessions-1].next = NULL;
+    }
+
+    FreeSessions = AllSessions;
+    ActiveSessions = NULL;
+
+    /* Initialize session numbers which we hand out */
+    for (i=0; i<MaxSessions; i++) {
+	AllSessions[i].sesNum = htons((UINT16_t) i+1);
+    }
+
+    /* Initialize hashes in a linked list */
+    AllHashes[0].prev = NULL;
+    AllHashes[0].next = &AllHashes[1];
+    for (i=1; i<2*MaxSessions-1; i++) {
+	AllHashes[i].prev = &AllHashes[i-1];
+	AllHashes[i].next = &AllHashes[i+1];
+    }
+    AllHashes[2*MaxSessions-1].prev = &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 >= MaxSessions) {
+	printErr("Maximum number of sessions reached -- cannot create new session");
+	return NULL;
+    }
+
+    /* Grab a free session */
+    sess = FreeSessions;
+    FreeSessions = sess->next;
+    NumSessions++;
+
+    /* Link it to the active list */
+    sess->next = ActiveSessions;
+    if (sess->next) {
+	sess->next->prev = sess;
+    }
+    ActiveSessions = sess;
+    sess->prev = NULL;
+
+    sess->epoch = Epoch;
+
+    /* Get two hash entries */
+    acHash = FreeHashes;
+    cliHash = acHash->next;
+    FreeHashes = cliHash->next;
+
+    acHash->peer = cliHash;
+    cliHash->peer = acHash;
+
+    sess->acHash = acHash;
+    sess->clientHash = cliHash;
+
+    acHash->interface = ac;
+    cliHash->interface = cli;
+
+    memcpy(acHash->peerMac, acMac, ETH_ALEN);
+    acHash->sesNum = acSes;
+    acHash->ses = sess;
+
+    memcpy(cliHash->peerMac, cliMac, ETH_ALEN);
+    cliHash->sesNum = sess->sesNum;
+    cliHash->ses = sess;
+
+    addHash(acHash);
+    addHash(cliHash);
+
+    /* Log */
+    syslog(LOG_INFO,
+	   "Opened session: server=%02x:%02x:%02x:%02x:%02x:%02x(%s:%d), client=%02x:%02x:%02x:%02x:%02x:%02x(%s:%d)",
+	   acHash->peerMac[0], acHash->peerMac[1],
+	   acHash->peerMac[2], acHash->peerMac[3],
+	   acHash->peerMac[4], acHash->peerMac[5],
+	   acHash->interface->name,
+	   ntohs(acHash->sesNum),
+	   cliHash->peerMac[0], cliHash->peerMac[1],
+	   cliHash->peerMac[2], cliHash->peerMac[3],
+	   cliHash->peerMac[4], cliHash->peerMac[5],
+	   cliHash->interface->name,
+	   ntohs(cliHash->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,
+	   "Closed session: server=%02x:%02x:%02x:%02x:%02x:%02x(%s:%d), client=%02x:%02x:%02x:%02x:%02x:%02x(%s:%d): %s",
+	   ses->acHash->peerMac[0], ses->acHash->peerMac[1],
+	   ses->acHash->peerMac[2], ses->acHash->peerMac[3],
+	   ses->acHash->peerMac[4], ses->acHash->peerMac[5],
+	   ses->acHash->interface->name,
+	   ntohs(ses->acHash->sesNum),
+	   ses->clientHash->peerMac[0], ses->clientHash->peerMac[1],
+	   ses->clientHash->peerMac[2], ses->clientHash->peerMac[3],
+	   ses->clientHash->peerMac[4], ses->clientHash->peerMac[5],
+	   ses->clientHash->interface->name,
+	   ntohs(ses->clientHash->sesNum), msg);
+
+    /* Unlink from active sessions */
+    if (ses->prev) {
+	ses->prev->next = ses->next;
+    } else {
+	ActiveSessions = ses->next;
+    }
+    if (ses->next) {
+	ses->next->prev = ses->prev;
+    }
+       
+    /* Link onto free list -- this is a singly-linked list, so
+       we do not care about prev */
+    ses->next = FreeSessions;
+    FreeSessions = ses;
+
+    unhash(ses->acHash);
+    unhash(ses->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->peerMac, sh->sesNum) % HASHTAB_SIZE;
+    if (sh->prev) {
+	sh->prev->next = sh->next;
+    } else {
+	Buckets[b] = sh->next;
+    }
+
+    if (sh->next) {
+	sh->next->prev = sh->prev;
+    }
+
+    /* Add to free list (singly-linked) */
+    sh->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->peerMac, sh->sesNum) % HASHTAB_SIZE;
+    sh->next = Buckets[b];
+    sh->prev = NULL;
+    if (sh->next) {
+	sh->next->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]) << 8) |
+	(((unsigned int) mac[2]) << 16) |
+	(((unsigned int) mac[3]) << 24);
+    unsigned int ans2 = 
+	((unsigned int) sesNum) |
+	(((unsigned int) mac[4]) << 16) |
+	(((unsigned int) mac[5]) << 24);
+    return ans1 ^ ans2;
+}
+
+/**********************************************************************
+*%FUNCTION: findSession
+*%ARGUMENTS:
+* mac -- an Ethernet address
+* sesNum -- a session number
+*%RETURNS:
+* The session hash for peer address "mac", 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->peerMac, ETH_ALEN) && sesNum == sh->sesNum) {
+	    return sh;
+	}
+	sh = sh->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, "%.256s: %.256s", 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, "%.256s: %.256s", 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(&readable);
+    maxFD = 0;
+    for (i=0; i<NumInterfaces; i++) {
+	sock = Interfaces[i].discoverySock;
+	if (sock > maxFD) maxFD = sock;
+	FD_SET(sock, &readable);
+	sock = Interfaces[i].sessionSock;
+	if (sock > maxFD) maxFD = sock;
+	FD_SET(sock, &readable);
+	if (CleanPipe[0] > maxFD) maxFD = CleanPipe[0];
+	FD_SET(CleanPipe[0], &readable);
+    }
+    maxFD++;
+    for(;;) {
+	readableCopy = readable;
+	for(;;) {
+	    r = select(maxFD, &readableCopy, NULL, NULL, NULL);
+	    if (r >= 0 || errno != EINTR) break;
+	}
+	if (r < 0) {
+	    sysErr("select (relayLoop)");
+	    continue;
+	}
+
+	/* Handle session packets first */
+	for (i=0; i<NumInterfaces; i++) {
+	    if (FD_ISSET(Interfaces[i].sessionSock, &readableCopy)) {
+		relayGotSessionPacket(&Interfaces[i]);
+	    }
+	}
+
+	/* Now handle discovery packets */
+	for (i=0; i<NumInterfaces; i++) {
+	    if (FD_ISSET(Interfaces[i].discoverySock, &readableCopy)) {
+		relayGotDiscoveryPacket(&Interfaces[i]);
+	    }
+	}
+
+	/* Handle the session-cleaning process */
+	if (FD_ISSET(CleanPipe[0], &readableCopy)) {
+	    char dummy;
+	    CleanCounter = 0;
+	    read(CleanPipe[0], &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->discoverySock, &packet, &size) < 0) {
+	return;
+    }
+    /* Ignore unknown code/version */
+    if (packet.ver != 1 || packet.type != 1) {
+	return;
+    }
+
+    /* Validate length */
+    if (ntohs(packet.length) + HDR_SIZE > size) {
+	syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+	       (unsigned int) ntohs(packet.length));
+	return;
+    }
+
+    /* Drop Ethernet frame padding */
+    if (size > ntohs(packet.length) + HDR_SIZE) {
+	size = ntohs(packet.length) + HDR_SIZE;
+    }
+
+    switch(packet.code) {
+    case CODE_PADT:
+	relayHandlePADT(iface, &packet, size);
+	break;
+    case CODE_PADI:
+	relayHandlePADI(iface, &packet, size);
+	break;
+    case CODE_PADO:
+	relayHandlePADO(iface, &packet, size);
+	break;
+    case CODE_PADR:
+	relayHandlePADR(iface, &packet, size);
+	break;
+    case CODE_PADS:
+	relayHandlePADS(iface, &packet, size);
+	break;
+    default:
+	syslog(LOG_ERR, "Discovery packet on %s with unknown code %d",
+	       iface->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->sessionSock, &packet, &size) < 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, "Session packet with code %d", (int) packet.code);
+	return;
+    }
+
+    /* Ignore session packets whose destination address isn't ours */
+    if (memcmp(packet.ethHdr.h_dest, iface->mac, ETH_ALEN)) {
+	return;
+    }
+
+    /* Validate length */
+    if (ntohs(packet.length) + HDR_SIZE > size) {
+	syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+	       (unsigned int) ntohs(packet.length));
+	return;
+    }
+
+    /* Drop Ethernet frame padding */
+    if (size > 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->ses;
+    ses->epoch = Epoch;
+    sh = sh->peer;
+    packet.session = sh->sesNum;
+    memcpy(packet.ethHdr.h_source, sh->interface->mac, ETH_ALEN);
+    memcpy(packet.ethHdr.h_dest, sh->peerMac, ETH_ALEN);
+#if 0
+    fprintf(stderr, "Relaying %02x:%02x:%02x:%02x:%02x:%02x(%s:%d) to %02x:%02x:%02x:%02x:%02x:%02x(%s:%d)\n",
+	    sh->peer->peerMac[0], sh->peer->peerMac[1], sh->peer->peerMac[2],
+	    sh->peer->peerMac[3], sh->peer->peerMac[4], sh->peer->peerMac[5],
+	    sh->peer->interface->name, ntohs(sh->peer->sesNum),
+	    sh->peerMac[0], sh->peerMac[1], sh->peerMac[2],
+	    sh->peerMac[3], sh->peerMac[4], sh->peerMac[5],
+	    sh->interface->name, ntohs(sh->sesNum));
+#endif
+    sendPacket(NULL, sh->interface->sessionSock, &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->ethHdr.h_source, packet->session);
+    if (!sh) {
+	return;
+    }
+    /* Relay the PADT to the peer */
+    sh = sh->peer;
+    ses = sh->ses;
+    packet->session = sh->sesNum;
+    memcpy(packet->ethHdr.h_source, sh->interface->mac, ETH_ALEN);
+    memcpy(packet->ethHdr.h_dest, sh->peerMac, ETH_ALEN);
+    sendPacket(NULL, sh->interface->sessionSock, packet, size);
+
+    /* Destroy the session */
+    freeSession(ses, "Received PADT");
+}
+
+/**********************************************************************
+*%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->clientOK) {
+	syslog(LOG_ERR,
+	       "PADI packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not permitted",
+	       packet->ethHdr.h_source[0],
+	       packet->ethHdr.h_source[1],
+	       packet->ethHdr.h_source[2],
+	       packet->ethHdr.h_source[3],
+	       packet->ethHdr.h_source[4],
+	       packet->ethHdr.h_source[5],
+	       iface->name);
+	return;
+    }
+
+    /* Source address must be unicast */
+    if (NOT_UNICAST(packet->ethHdr.h_source)) {
+	syslog(LOG_ERR,
+	       "PADI packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not from a unicast address",
+	       packet->ethHdr.h_source[0],
+	       packet->ethHdr.h_source[1],
+	       packet->ethHdr.h_source[2],
+	       packet->ethHdr.h_source[3],
+	       packet->ethHdr.h_source[4],
+	       packet->ethHdr.h_source[5],
+	       iface->name);
+	return;
+    }
+
+    /* Destination address must be broadcast */
+    if (NOT_BROADCAST(packet->ethHdr.h_dest)) {
+	syslog(LOG_ERR,
+	       "PADI packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not to a broadcast address",
+	       packet->ethHdr.h_source[0],
+	       packet->ethHdr.h_source[1],
+	       packet->ethHdr.h_source[2],
+	       packet->ethHdr.h_source[3],
+	       packet->ethHdr.h_source[4],
+	       packet->ethHdr.h_source[5],
+	       iface->name);
+	return;
+    }
+    
+    /* Get array index of interface */
+    ifIndex = iface - Interfaces;
+
+    loc = findTag(packet, TAG_RELAY_SESSION_ID, &tag);
+    if (!loc) {
+	tag.type = htons(TAG_RELAY_SESSION_ID);
+	tag.length = htons(MY_RELAY_TAG_LEN);
+	memcpy(tag.payload, &ifIndex, sizeof(ifIndex));
+	memcpy(tag.payload+sizeof(ifIndex), packet->ethHdr.h_source, ETH_ALEN);
+	/* Add a relay tag if there's room */
+	r = addTag(packet, &tag);
+	if (r < 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 < NumInterfaces; i++) {
+	if (iface == &Interfaces[i]) continue;
+	if (!Interfaces[i].acOK) continue;
+	memcpy(packet->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->acOK) {
+	syslog(LOG_ERR,
+	       "PADO packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not permitted",
+	       packet->ethHdr.h_source[0],
+	       packet->ethHdr.h_source[1],
+	       packet->ethHdr.h_source[2],
+	       packet->ethHdr.h_source[3],
+	       packet->ethHdr.h_source[4],
+	       packet->ethHdr.h_source[5],
+	       iface->name);
+	return;
+    }
+
+    acIndex = iface - Interfaces;
+
+    /* Source address must be unicast */
+    if (NOT_UNICAST(packet->ethHdr.h_source)) {
+	syslog(LOG_ERR,
+	       "PADO packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not from a unicast address",
+	       packet->ethHdr.h_source[0],
+	       packet->ethHdr.h_source[1],
+	       packet->ethHdr.h_source[2],
+	       packet->ethHdr.h_source[3],
+	       packet->ethHdr.h_source[4],
+	       packet->ethHdr.h_source[5],
+	       iface->name);
+	return;
+    }
+
+    /* Destination address must be interface's MAC address */
+    if (memcmp(packet->ethHdr.h_dest, iface->mac, ETH_ALEN)) {
+	return;
+    }
+
+    /* Find relay tag */
+    loc = findTag(packet, TAG_RELAY_SESSION_ID, &tag);
+    if (!loc) {
+	syslog(LOG_ERR,
+	       "PADO packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have Relay-Session-Id tag",
+	       packet->ethHdr.h_source[0],
+	       packet->ethHdr.h_source[1],
+	       packet->ethHdr.h_source[2],
+	       packet->ethHdr.h_source[3],
+	       packet->ethHdr.h_source[4],
+	       packet->ethHdr.h_source[5],
+	       iface->name);
+	return;
+    }
+
+    /* If it's the wrong length, ignore it */
+    if (ntohs(tag.length) != MY_RELAY_TAG_LEN) {
+	syslog(LOG_ERR,
+	       "PADO packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have correct length Relay-Session-Id tag",
+	       packet->ethHdr.h_source[0],
+	       packet->ethHdr.h_source[1],
+	       packet->ethHdr.h_source[2],
+	       packet->ethHdr.h_source[3],
+	       packet->ethHdr.h_source[4],
+	       packet->ethHdr.h_source[5],
+	       iface->name);
+	return;
+    }
+
+    /* Extract interface index */
+    memcpy(&ifIndex, tag.payload, sizeof(ifIndex));
+
+    if (ifIndex < 0 || ifIndex >= NumInterfaces ||
+	!Interfaces[ifIndex].clientOK ||
+	iface == &Interfaces[ifIndex]) {
+	syslog(LOG_ERR,
+	       "PADO packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s has invalid interface in Relay-Session-Id tag",
+	       packet->ethHdr.h_source[0],
+	       packet->ethHdr.h_source[1],
+	       packet->ethHdr.h_source[2],
+	       packet->ethHdr.h_source[3],
+	       packet->ethHdr.h_source[4],
+	       packet->ethHdr.h_source[5],
+	       iface->name);
+	return;
+    }
+
+    /* Replace Relay-ID tag with opposite-direction tag */
+    memcpy(loc+TAG_HDR_SIZE, &acIndex, sizeof(acIndex));
+    memcpy(loc+TAG_HDR_SIZE+sizeof(ifIndex), packet->ethHdr.h_source, ETH_ALEN);
+
+    /* Set destination address to MAC address in relay ID */
+    memcpy(packet->ethHdr.h_dest, tag.payload + sizeof(ifIndex), ETH_ALEN);
+
+    /* Set source address to MAC address of interface */
+    memcpy(packet->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->clientOK) {
+	syslog(LOG_ERR,
+	       "PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not permitted",
+	       packet->ethHdr.h_source[0],
+	       packet->ethHdr.h_source[1],
+	       packet->ethHdr.h_source[2],
+	       packet->ethHdr.h_source[3],
+	       packet->ethHdr.h_source[4],
+	       packet->ethHdr.h_source[5],
+	       iface->name);
+	return;
+    }
+
+    cliIndex = iface - Interfaces;
+
+    /* Source address must be unicast */
+    if (NOT_UNICAST(packet->ethHdr.h_source)) {
+	syslog(LOG_ERR,
+	       "PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not from a unicast address",
+	       packet->ethHdr.h_source[0],
+	       packet->ethHdr.h_source[1],
+	       packet->ethHdr.h_source[2],
+	       packet->ethHdr.h_source[3],
+	       packet->ethHdr.h_source[4],
+	       packet->ethHdr.h_source[5],
+	       iface->name);
+	return;
+    }
+
+    /* Destination address must be interface's MAC address */
+    if (memcmp(packet->ethHdr.h_dest, iface->mac, ETH_ALEN)) {
+	return;
+    }
+
+    /* Find relay tag */
+    loc = findTag(packet, TAG_RELAY_SESSION_ID, &tag);
+    if (!loc) {
+	syslog(LOG_ERR,
+	       "PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have Relay-Session-Id tag",
+	       packet->ethHdr.h_source[0],
+	       packet->ethHdr.h_source[1],
+	       packet->ethHdr.h_source[2],
+	       packet->ethHdr.h_source[3],
+	       packet->ethHdr.h_source[4],
+	       packet->ethHdr.h_source[5],
+	       iface->name);
+	return;
+    }
+
+    /* If it's the wrong length, ignore it */
+    if (ntohs(tag.length) != MY_RELAY_TAG_LEN) {
+	syslog(LOG_ERR,
+	       "PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have correct length Relay-Session-Id tag",
+	       packet->ethHdr.h_source[0],
+	       packet->ethHdr.h_source[1],
+	       packet->ethHdr.h_source[2],
+	       packet->ethHdr.h_source[3],
+	       packet->ethHdr.h_source[4],
+	       packet->ethHdr.h_source[5],
+	       iface->name);
+	return;
+    }
+
+    /* Extract interface index */
+    memcpy(&ifIndex, tag.payload, sizeof(ifIndex));
+
+    if (ifIndex < 0 || ifIndex >= NumInterfaces ||
+	!Interfaces[ifIndex].acOK ||
+	iface == &Interfaces[ifIndex]) {
+	syslog(LOG_ERR,
+	       "PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s has invalid interface in Relay-Session-Id tag",
+	       packet->ethHdr.h_source[0],
+	       packet->ethHdr.h_source[1],
+	       packet->ethHdr.h_source[2],
+	       packet->ethHdr.h_source[3],
+	       packet->ethHdr.h_source[4],
+	       packet->ethHdr.h_source[5],
+	       iface->name);
+	return;
+    }
+
+    /* Replace Relay-ID tag with opposite-direction tag */
+    memcpy(loc+TAG_HDR_SIZE, &cliIndex, sizeof(cliIndex));
+    memcpy(loc+TAG_HDR_SIZE+sizeof(ifIndex), packet->ethHdr.h_source, ETH_ALEN);
+
+    /* Set destination address to MAC address in relay ID */
+    memcpy(packet->ethHdr.h_dest, tag.payload + sizeof(ifIndex), ETH_ALEN);
+
+    /* Set source address to MAC address of interface */
+    memcpy(packet->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->acOK) {
+	syslog(LOG_ERR,
+	       "PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not permitted",
+	       packet->ethHdr.h_source[0],
+	       packet->ethHdr.h_source[1],
+	       packet->ethHdr.h_source[2],
+	       packet->ethHdr.h_source[3],
+	       packet->ethHdr.h_source[4],
+	       packet->ethHdr.h_source[5],
+	       iface->name);
+	return;
+    }
+
+    acIndex = iface - Interfaces;
+
+    /* Source address must be unicast */
+    if (NOT_UNICAST(packet->ethHdr.h_source)) {
+	syslog(LOG_ERR,
+	       "PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not from a unicast address",
+	       packet->ethHdr.h_source[0],
+	       packet->ethHdr.h_source[1],
+	       packet->ethHdr.h_source[2],
+	       packet->ethHdr.h_source[3],
+	       packet->ethHdr.h_source[4],
+	       packet->ethHdr.h_source[5],
+	       iface->name);
+	return;
+    }
+
+    /* Destination address must be interface's MAC address */
+    if (memcmp(packet->ethHdr.h_dest, iface->mac, ETH_ALEN)) {
+	return;
+    }
+
+    /* Find relay tag */
+    loc = findTag(packet, TAG_RELAY_SESSION_ID, &tag);
+    if (!loc) {
+	syslog(LOG_ERR,
+	       "PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have Relay-Session-Id tag",
+	       packet->ethHdr.h_source[0],
+	       packet->ethHdr.h_source[1],
+	       packet->ethHdr.h_source[2],
+	       packet->ethHdr.h_source[3],
+	       packet->ethHdr.h_source[4],
+	       packet->ethHdr.h_source[5],
+	       iface->name);
+	return;
+    }
+
+    /* If it's the wrong length, ignore it */
+    if (ntohs(tag.length) != MY_RELAY_TAG_LEN) {
+	syslog(LOG_ERR,
+	       "PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have correct length Relay-Session-Id tag",
+	       packet->ethHdr.h_source[0],
+	       packet->ethHdr.h_source[1],
+	       packet->ethHdr.h_source[2],
+	       packet->ethHdr.h_source[3],
+	       packet->ethHdr.h_source[4],
+	       packet->ethHdr.h_source[5],
+	       iface->name);
+	return;
+    }
+
+    /* Extract interface index */
+    memcpy(&ifIndex, tag.payload, sizeof(ifIndex));
+
+    if (ifIndex < 0 || ifIndex >= NumInterfaces ||
+	!Interfaces[ifIndex].clientOK ||
+	iface == &Interfaces[ifIndex]) {
+	syslog(LOG_ERR,
+	       "PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s has invalid interface in Relay-Session-Id tag",
+	       packet->ethHdr.h_source[0],
+	       packet->ethHdr.h_source[1],
+	       packet->ethHdr.h_source[2],
+	       packet->ethHdr.h_source[3],
+	       packet->ethHdr.h_source[4],
+	       packet->ethHdr.h_source[5],
+	       iface->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->session != htons(0)) {
+	/* Check for existing session */
+	sh = findSession(packet->ethHdr.h_source, packet->session);
+	if (sh) ses = sh->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, &Interfaces[ifIndex],
+				packet->ethHdr.h_source,
+				loc + TAG_HDR_SIZE + sizeof(ifIndex), packet->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, &hostUniq)) {
+		    hu = &hostUniq;
+		} else {
+		    hu = NULL;
+		}
+		relaySendError(CODE_PADS, htons(0), &Interfaces[ifIndex],
+			       loc + TAG_HDR_SIZE + sizeof(ifIndex),
+			       hu, "RP-PPPoE: Relay: Unable to allocate session");
+		relaySendError(CODE_PADT, packet->session, iface,
+			       packet->ethHdr.h_source, NULL, 
+			       "RP-PPPoE: Relay: Unable to allocate session");
+		return;
+	    }
+	}
+	/* Replace session number */
+	packet->session = ses->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->ethHdr.h_dest, tag.payload + sizeof(ifIndex), ETH_ALEN);
+
+    /* Set source address to MAC address of interface */
+    memcpy(packet->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->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(&packet, hostUniq) < 0) return;
+    }
+    errTag.type = htons(TAG_GENERIC_ERROR);
+    errTag.length = htons(strlen(errMsg));
+    strcpy(errTag.payload, errMsg);
+    if (addTag(&packet, &errTag) < 0) return;
+    size = ntohs(packet.length) + HDR_SIZE;
+    if (code == CODE_PADT) {
+	sendPacket(NULL, iface->discoverySock, &packet, size);
+    } else {
+	sendPacket(NULL, iface->sessionSock, &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], "", 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->next;
+	if (Epoch - cur->epoch > IdleTimeout) {
+	    /* Send PADT to each peer */
+	    relaySendError(CODE_PADT, cur->acHash->sesNum,
+			   cur->acHash->interface,
+			   cur->acHash->peerMac, NULL,
+			   "RP-PPPoE: Relay: Session exceeded idle timeout");
+	    relaySendError(CODE_PADT, cur->clientHash->sesNum,
+			   cur->clientHash->interface,
+			   cur->clientHash->peerMac, NULL,
+			   "RP-PPPoE: Relay: Session exceeded idle timeout");
+	    freeSession(cur, "Idle Timeout");
+	}
+	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 "pppoe.h"
+
+/* 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 (gc at mandriva.com)
+ #
+ # 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 $< -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 "config.h" */
+#include "jdmacros.h"
+#include "sllimits.h"
+
+#ifdef VMS
+# define SLANG_SYSTEM_NAME "_VMS"
+#else
+# if defined (IBMPC_SYSTEM)
+#  define SLANG_SYSTEM_NAME "_IBMPC"
+# else
+#  define SLANG_SYSTEM_NAME "_UNIX"
+# 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 >= CHAR_TOKEN) && (x <= 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) <= DOT_TOKEN) && ((t) >= 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 >= FIRST_BINARY_OP) && (t <= 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 >= 0x50) && (t <= 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)>=FIRST_ASSIGN_TOKEN)&&((t)<=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__) && _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) && defined(HAVE_SIGEMPTYSET)
+# if defined(HAVE_SIGACTION) && 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) && !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 */] =
+{
+   {"or",	OR_TOKEN},
+   {"not",	NOT_TOKEN},
+   {NULL,0},
+   {"xor",	BXOR_TOKEN},
+   {"return",	RETURN_TOKEN},
+   {"exch",	EXCH_TOKEN},
+   {NULL,0},
+   {"continue",	CONT_TOKEN},
+   {NULL,0},
+   {"do",	DO_TOKEN},
+   {"mod",	MOD_TOKEN},
+   {"ERROR_BLOCK",	ERRBLK_TOKEN},
+   {"USER_BLOCK2",	USRBLK2_TOKEN},
+   {"USER_BLOCK4",	USRBLK4_TOKEN},
+   {"__tmp",	TMP_TOKEN},
+   {"pop",	POP_TOKEN},
+   {NULL,0},
+   {"EXIT_BLOCK",	EXITBLK_TOKEN},
+   {"USER_BLOCK1",	USRBLK1_TOKEN},
+   {"USER_BLOCK3",	USRBLK3_TOKEN},
+   {"USER_BLOCK0",	USRBLK0_TOKEN},
+   {NULL,0},
+   {"shr",	SHR_TOKEN},
+   {"chs",	CHS_TOKEN},
+   {"sqr",	SQR_TOKEN},
+   {NULL,0},
+   {"struct",	STRUCT_TOKEN},
+   {NULL,0},
+   {NULL,0},
+   {"switch",	SWITCH_TOKEN},
+   {"mul2",	MUL2_TOKEN},
+   {"sign",	SIGN_TOKEN},
+   {"using",	USING_TOKEN},
+   {"while",	WHILE_TOKEN},
+   {NULL,0},
+   {NULL,0},
+   {"loop",	LOOP_TOKEN},
+   {NULL,0},
+   {NULL,0},
+   {NULL,0},
+   {"public",	PUBLIC_TOKEN},
+   {NULL,0},
+   {NULL,0},
+   {NULL,0},
+   {NULL,0},
+   {"break",	BREAK_TOKEN},
+   {NULL,0},
+   {"do_while",	DOWHILE_TOKEN},
+   {NULL,0},
+   {"shl",	SHL_TOKEN},
+   {"else",	ELSE_TOKEN},
+   {"and",	AND_TOKEN},
+   {"orelse",	ORELSE_TOKEN},
+   {"private",	PRIVATE_TOKEN},
+   {NULL,0},
+   {"if",	IF_TOKEN},
+   {"for",	FOR_TOKEN},
+   {"!if",	IFNOT_TOKEN},
+   {NULL,0},
+   {"_for",	_FOR_TOKEN},
+   {"forever",	FOREVER_TOKEN},
+   {NULL,0},
+   {NULL,0},
+   {NULL,0},
+   {"abs",	ABS_TOKEN},
+   {"case",	CASE_TOKEN},
+   {NULL,0},
+   {"static",	STATIC_TOKEN},
+   {"define",	DEFINE_TOKEN},
+   {NULL,0},
+   {NULL,0},
+   {NULL,0},
+   {NULL,0},
+   {NULL,0},
+   {NULL,0},
+   {NULL,0},
+   {"typedef",	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},
+   {"foreach",	FOREACH_TOKEN},
+   {"andelse",	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},
+   {"variable",	VARIABLE_TOKEN},
+};
+
+static Keyword_Table_Type *is_keyword (char *str, unsigned int len)
+{
+   unsigned int hash;
+   char *name;
+   Keyword_Table_Type *kw;
+
+   if ((len < MIN_KEYWORD_LEN)
+       || (len > MAX_KEYWORD_LEN))
+     return NULL;
+
+   hash = keyword_hash (str, len);
+   if ((hash > MAX_HASH_VALUE) || (hash < MIN_HASH_VALUE))
+     return NULL;
+
+   kw = &Keyword_Table[hash - MIN_HASH_VALUE];
+   if ((NULL != (name = kw->name))
+       && (*str == *name)
+       && (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 "slinclud.h"
+
+#if SLANG_HAS_FLOAT
+# include <math.h>
+#endif
+
+#include "slang.h"
+#include "_slang.h"
+
+#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->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->data_type;
+   if (type == SLANG_INT_TYPE)
+     {
+	_SLStack_Pointer = y;   
+	*i = y->v.int_val;
+	return 0;
+     }
+   if (type == SLANG_CHAR_TYPE)
+     {
+	_SLStack_Pointer = y;   
+	*i = y->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->cl_to_bool == NULL)
+     {
+	SLang_verror (SL_TYPE_MISMATCH,
+		      "%s cannot be used in a boolean context",
+		      cl->cl_name);
+	return -1;
+     }
+   return cl->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)->data_type;
+}
+
+int SLang_peek_at_stack1 (void)
+{
+   int type;
+
+   type = SLang_peek_at_stack ();
+   if (type == SLANG_ARRAY_TYPE)
+     type = (_SLStack_Pointer - 1)->v.array_val->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->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->v.s_val);
+	return;
+     }
+#endif
+   cl = _SLclass_get_class (data_type);
+#if !_SLANG_OPTIMIZE_FOR_SPEED
+   if (cl->cl_class_type != SLANG_CLASS_TYPE_SCALAR)
+#endif
+     (*cl->cl_destroy) (data_type, (VOID_STAR) &obj->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 >= _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 >= _SLStack_Pointer_Max)
+     {
+	if (!SLang_Error) SLang_Error = SL_STACK_OVERFLOW;
+	return -1;
+     }
+
+   y->data_type = type;
+   y->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 >= _SLStack_Pointer_Max)
+     {
+	if (!SLang_Error) SLang_Error = SL_STACK_OVERFLOW;
+	return -1;
+     }
+
+   y->data_type = type;
+   y->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->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]
+	    && _SLarith_Is_Arith_Type [y->data_type]
+	    && (_SLarith_Is_Arith_Type [type] >= _SLarith_Is_Arith_Type[y->data_type]))
+	  {
+	     /* This should not fail */
+	     (void) _SLarith_typecast (y->data_type, (VOID_STAR)&y->v, 1, 
+				       type, (VOID_STAR)&obj->v);
+	     obj->data_type = type;
+	     _SLStack_Pointer = y;
+	     return 0;
+	  }
+#endif
+	
+	if ((allow_arrays == 0)
+	    || (y->data_type != SLANG_ARRAY_TYPE)
+	    || (y->v.array_val->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 > otop - _SLRun_Stack) || (n < 0))
+     {
+	SLang_Error = SL_STACK_UNDERFLOW;
+	return -1;
+     }
+   obot = otop - n;
+   otop--;
+   while (otop > 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)) <= 1) return 0;    /* identity */
+
+   obot = otop = _SLStack_Pointer;
+   i = n;
+   while (i != 0)
+     {
+	if (obot <= _SLRun_Stack)
+	  {
+	     SLang_Error = SL_STACK_UNDERFLOW;
+	     return -1;
+	  }
+	obot--;
+	i--;
+     }
+   otop--;
+
+   if (np > 0)
+     {
+	/* Put top on bottom and roll rest up. */
+	tmp = *otop;
+	while (otop > obot)
+	  {
+	     *otop = *(otop - 1);
+	     otop--;
+	  }
+	*otop = tmp;
+     }
+   else
+     {
+	/* Put bottom on top and roll rest down. */
+	tmp = *obot;
+	while (obot < 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 <= 0)
+     return 0;
+   
+   top = _SLStack_Pointer;
+   if (top < _SLRun_Stack + n)
+     {
+	if (SLang_Error == 0)
+	  SLang_Error = SL_STACK_UNDERFLOW;
+	return -1;
+     }
+   if (top + n > _SLStack_Pointer_Max)
+     {
+	if (SLang_Error == 0)
+	  SLang_Error = SL_STACK_OVERFLOW;
+	return -1;
+     }
+   bot = top - n;
+
+   while (bot < top)
+     {
+	SLang_Class_Type *cl;
+	unsigned char data_type = bot->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->cl_push) (data_type, (VOID_STAR) &bot->v))
+	  return -1;
+	bot++;
+     }
+   return 0;
+}
+
+/*}}}*/
+
+/*{{{ inner interpreter and support functions */
+
+_INLINE_
+int _SL_increment_frame_pointer (void)
+{
+   if (Recursion_Depth >= SLANG_MAX_RECURSIVE_DEPTH)
+     {
+	SLang_verror (SL_STACK_OVERFLOW, "Num Args Stack Overflow");
+	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, "Num Args Stack Underflow");
+	return -1;
+     }
+
+   Recursion_Depth--;
+   if (Recursion_Depth < 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 < 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, "Frame Stack Overflow");
+   return -1;
+}
+
+_INLINE_
+int SLang_end_arg_list (void)
+{
+   if (Frame_Pointer_Depth == 0)
+     {
+	SLang_verror (SL_STACK_UNDERFLOW, "Frame Stack Underflow");
+	return -1;
+     }
+   Frame_Pointer_Depth--;
+   if (Frame_Pointer_Depth < 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 ())
+       && (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), "(Error occurred processing %s)", nt->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->data_type;
+   a_data_type = obja->data_type;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+   if (_SLarith_Is_Arith_Type[a_data_type]
+       && _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, &c_cl, 1)))
+     return -1;
+
+   c_data_type = c_cl->cl_data_type;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+   if (SLANG_CLASS_TYPE_SCALAR == _SLclass_Class_Type [a_data_type])
+     pa = (VOID_STAR) &obja->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) &objb->v;
+   else
+#endif
+     pb = _SLclass_get_ptr_to_value (b_cl, objb);
+
+   pc = c_cl->cl_transfer_buf;
+
+   if (1 != (*binary_fun) (op,
+			   a_data_type, pa, 1,
+			   b_data_type, pb, 1,
+			   pc))
+     {
+	SLang_verror (SL_NOT_IMPLEMENTED,
+		      "Binary operation between %s and %s failed",
+		      a_cl->cl_name, b_cl->cl_name);
+
+	return -1;
+     }
+
+   /* apush will create a copy, so make sure we free after the push */
+   ret = (*c_cl->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->cl_adestroy)(c_data_type, pc);
+
+   return ret;
+}
+
+_INLINE_
+static void do_binary (int op)
+{
+   SLang_Object_Type obja, objb;
+
+   if (SLang_pop (&objb)) return;
+   if (0 == SLang_pop (&obja))
+     {
+	(void) do_binary_ab (op, &obja, &objb);
+#if _SLANG_OPTIMIZE_FOR_SPEED
+	if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [obja.data_type])
+#endif
+	  SLang_free_object (&obja);
+     }
+#if _SLANG_OPTIMIZE_FOR_SPEED
+   if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [objb.data_type])
+#endif
+     SLang_free_object (&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->data_type;
+   a_cl = _SLclass_get_class (a_type);
+
+   if (NULL == (f = _SLclass_get_unary_fun (op, a_cl, &b_cl, unary_type)))
+     return -1;
+
+   b_type = b_cl->cl_data_type;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+   if (SLANG_CLASS_TYPE_SCALAR == _SLclass_Class_Type [a_type])
+     pa = (VOID_STAR) &obj->v;
+   else
+#endif
+     pa = _SLclass_get_ptr_to_value (a_cl, obj);
+
+   pb = b_cl->cl_transfer_buf;
+
+   if (1 != (*f) (op, a_type, pa, 1, pb))
+     {
+	SLang_verror (SL_NOT_IMPLEMENTED,
+		      "Unary operation for %s failed", a_cl->cl_name);
+	return -1;
+     }
+
+   ret = (*b_cl->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->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 (&obj)) return -1;
+   ret = do_unary_op (op, &obj, unary_type);
+#if _SLANG_OPTIMIZE_FOR_SPEED
+   if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [obj.data_type])
+#endif
+     SLang_free_object (&obj);
+   return ret;
+}
+
+static int do_assignment_binary (int op, SLang_Object_Type *obja_ptr)
+{
+   SLang_Object_Type objb;
+   int ret;
+
+   if (SLang_pop (&objb))
+     return -1;
+
+   ret = do_binary_ab (op, obja_ptr, &objb);
+#if _SLANG_OPTIMIZE_FOR_SPEED
+   if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [objb.data_type])
+#endif
+     SLang_free_object (&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, "Assignment operator not implemented");
+	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->data_type == SLANG_INT_TYPE)
+	  return SLclass_push_int_obj (SLANG_INT_TYPE, obja_ptr->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->data_type == SLANG_INT_TYPE)
+	  return SLclass_push_int_obj (SLANG_INT_TYPE, obja_ptr->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->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->cl_sput == NULL)
+       || (cl->cl_sget == NULL))
+     {
+	SLang_verror (SL_NOT_IMPLEMENTED,
+		      "%s does not support structure access",
+		      cl->cl_name);
+	SLdo_pop_n (2);		       /* object plus what was to be assigned */
+	return -1;
+     }
+   name = bc_blk->b.s_blk;
+   op = bc_blk->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 (&obj_A))
+	  return -1;
+
+	if ((-1 == _SLpush_slang_obj (&obj_A))
+	    || (-1 == cl->cl_sget ((unsigned char) type, name))
+	    || (-1 == SLang_pop (&obj)))
+	  {
+	     SLang_free_object (&obj_A);
+	     return -1;
+	  }
+	/* Now the value of A.x is in obj. */
+	if (-1 == perform_lvalue_operation (op, &obj))
+	  {
+	     SLang_free_object (&obj);
+	     SLang_free_object (&obj_A);
+	     return -1;
+	  }
+	SLang_free_object (&obj);
+	/* The result of the operation is now on the stack.
+	 * Perform assignment */
+	if (-1 == SLang_push (&obj_A))
+	  {
+	     SLang_free_object (&obj_A);
+	     return -1;
+	  }
+     }
+
+   return (*cl->cl_sput) ((unsigned char) type, name);
+}
+
+static int make_unit_object (SLang_Object_Type *a, SLang_Object_Type *u)
+{
+   unsigned char type;
+   
+   type = a->data_type;
+   if (type == SLANG_ARRAY_TYPE)
+     type = a->v.array_val->data_type;
+   
+   u->data_type = type;
+   switch (type)
+     {
+      case SLANG_UCHAR_TYPE:
+      case SLANG_CHAR_TYPE:
+	u->v.char_val = 1;
+	break;
+
+      case SLANG_SHORT_TYPE:
+      case SLANG_USHORT_TYPE:
+	u->v.short_val = 1;
+	break;
+
+      case SLANG_LONG_TYPE:
+      case SLANG_ULONG_TYPE:
+	u->v.long_val = 1;
+	break;
+
+#if SLANG_HAS_FLOAT
+      case SLANG_FLOAT_TYPE:
+	u->v.float_val = 1;
+	break;
+	
+      case SLANG_COMPLEX_TYPE:
+	u->data_type = SLANG_DOUBLE_TYPE;
+      case SLANG_DOUBLE_TYPE:
+	u->v.double_val = 1;
+	break;
+#endif
+      default:
+	u->data_type = SLANG_INT_TYPE;
+	u->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, &op, &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 (&y))
+     return -1;
+   
+   if (is_unary == 0)
+     {
+	if ((-1 == SLroll_stack (-(num_args + 1)))
+	    || (-1 == SLang_pop (&x)))
+	  {
+	     SLang_free_object (&y);
+	     return -1;
+	  }
+     }
+   else if (-1 == make_unit_object (&y, &x))
+     {
+	SLang_free_object (&y);
+	return -1;
+     }
+   
+   if (-1 == do_binary_ab (op, &y, &x))
+     {
+	SLang_free_object (&y);
+	SLang_free_object (&x);
+	return -1;
+     }
+#if _SLANG_OPTIMIZE_FOR_SPEED
+   if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [y.data_type])
+#endif
+     SLang_free_object (&y);
+   
+#if _SLANG_OPTIMIZE_FOR_SPEED
+   if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [x.data_type])
+#endif
+     SLang_free_object (&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->b.nt_ivar_blk;
+
+   intrinsic_type = ivar->type;
+   intrinsic_addr = ivar->addr;
+
+   op_type = bc_blk->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->cl_push) (intrinsic_type, intrinsic_addr))
+	    || (-1 == SLang_pop (&obja)))
+	  return -1;
+
+	(void) perform_lvalue_operation (op_type, &obja);
+	SLang_free_object (&obja);
+
+	if (SLang_Error)
+	  return -1;
+     }
+
+   return (*cl->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->is_global == 0)
+     {
+	objp = ref->v.local_obj;
+	if (objp > Local_Variable_Frame)
+	  {
+	     SLang_verror (SL_UNDEFINED_NAME, "Local variable reference is out of scope");
+	     return -1;
+	  }
+	return set_lvalue_obj (_SLANG_BCST_ASSIGN, objp);
+     }
+
+   nt = ref->v.nt;
+   switch (nt->name_type)
+     {
+      case SLANG_GVARIABLE:
+      case SLANG_PVARIABLE:
+	if (-1 == set_lvalue_obj (_SLANG_BCST_ASSIGN,
+				  &((SLang_Global_Var_Type *)nt)->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 (&blk))
+	  {
+	     do_name_type_error (nt);
+	     return -1;
+	  }
+	break;
+
+      case SLANG_LVARIABLE:
+	SLang_Error = SL_INTERNAL_ERROR;
+	/* set_intrin_lvalue (&blk); */
+	return -1;
+
+      case SLANG_RVARIABLE:
+      default:
+	SLang_verror (SL_READONLY_ERROR, "deref assignment to %s not allowed", nt->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->bc_sub_type)
+     {
+      case SLANG_LVARIABLE:
+	objp =  (Local_Variable_Frame - bc_blk->b.i_blk);
+	break;
+      case SLANG_GVARIABLE:
+      case SLANG_PVARIABLE:
+	objp = &bc_blk->b.nt_gvar_blk->obj;
+	break;
+      default:
+	SLang_Error = SL_INTERNAL_ERROR;
+	return;
+     }
+
+   if (-1 == _SLpush_slang_obj (objp))
+     return;
+
+   if (-1 == SLang_pop_ref (&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->cl_sget == NULL)
+     {
+	SLang_verror (SL_NOT_IMPLEMENTED,
+		      "%s does not permit structure access",
+		      cl->cl_name);
+	SLdo_pop_n (2);
+	return -1;
+     }
+
+   return (*cl->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 >= sizeof (prefix))
+     len = sizeof (prefix) - 2;
+
+   SLMEMSET (prefix, ' ', len);
+   prefix[len] = 0;
+
+   call_dump_routine (prefix);
+   call_dump_routine (format, name, n);
+
+   if (n > 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 (&at, 1))
+	  return NULL;
+	obj->data_type = SLANG_ARRAY_TYPE;
+	return obj->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->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)->cl_class_type;
+#endif
+
+   if (type == SLANG_CLASS_TYPE_SCALAR)
+     return (VOID_STAR) &obj->v;
+   else if (type == SLANG_CLASS_TYPE_MMT)
+     return SLang_object_from_mmt (obj->v.ref);
+   else
+     return obj->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->i_fun;
+   argc = objf->num_args;
+   type = objf->return_type;
+   arg_types = objf->arg_types;
+
+   if (argc > SLANG_MAX_INTRIN_ARGS)
+     {
+	SLang_verror(SL_APPLICATION_ERROR,
+		     "Intrinsic function %s requires too many parameters", objf->name);
+	return -1;
+     }
+
+   if (-1 == _SL_increment_frame_pointer ())
+     return -1;
+
+   stk_depth = -1;
+   if (Trace_Mode && (_SLang_Trace > 0))
+     {
+	int nargs;
+
+	stk_depth = _SLstack_depth ();
+
+	nargs = SLang_Num_Function_Args;
+	if (nargs == 0)
+	  nargs = (int)argc;
+
+	stk_depth -= nargs;
+
+	if (stk_depth >= 0)
+	  trace_dump (">>%s (%d args)\n",
+		      objf->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,
+		      "Support for intrinsic functions returning %s is not provided",
+		      SLclass_get_datatype_name (type));
+     }
+
+   if (stk_depth >= 0)
+     {
+	stk_depth = _SLstack_depth () - stk_depth;
+
+	trace_dump ("<<%s (returning %d values)\n",
+		      objf->name,
+		      _SLStack_Pointer - stk_depth,
+		      stk_depth,
+		      1);
+     }
+
+   free_and_return:
+   while (i < 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 < (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, "Bytecode is not a looping block");
+	     return;
+	  }
+	blks[j] = block[i].b.blk;
+	j++;
+     }
+
+   num_blocks = j;
+   block = blks[0];
+
+   switch (stype)
+     {
+      case _SLANG_BCST_FOREACH:
+	loop_name = "foreach";
+	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->cl_foreach == NULL)
+	    || (cl->cl_foreach_open == NULL)
+	    || (cl->cl_foreach_close == NULL))
+	  {
+	     SLang_verror (SL_NOT_IMPLEMENTED, "%s does not permit foreach", cl->cl_name);
+	     SLdo_pop_n (Next_Function_Num_Args + 1);
+	     goto return_error;
+	  }
+
+	if (NULL == (foreach_context = (*cl->cl_foreach_open) ((unsigned char)type, Next_Function_Num_Args)))
+	  goto return_error;
+
+	while (1)
+	  {
+	     int status;
+
+	     if (SLang_Error)
+	       {
+		  (*cl->cl_foreach_close) ((unsigned char) type, foreach_context);
+		  goto return_error;
+	       }
+
+	     status = (*cl->cl_foreach) ((unsigned char) type, foreach_context);
+	     if (status <= 0)
+	       {
+		  if (status == 0)
+		    break;
+
+		  (*cl->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->cl_foreach_close) ((unsigned char) type, foreach_context);
+	break;
+
+      case _SLANG_BCST_WHILE:
+	loop_name = "while";
+
+	if (num_blocks != 2)
+	  goto wrong_num_blocks_error;
+
+	type = blks[1]->bc_main_type;
+	while (1)
+	  {
+	     if (SLang_Error)
+	       goto return_error;
+
+	     inner_interp (block);
+	     if (Lang_Break) break;
+
+	     if (-1 == pop_ctrl_integer (&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 = "do...while";
+
+	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 (&ctrl))
+	       goto return_error;
+
+	     if (ctrl == 0) break;
+	  }
+	break;
+
+      case _SLANG_BCST_CFOR:
+	loop_name = "for";
+
+	/* 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 (&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 = "_for";
+
+	if (num_blocks != 1)
+	  goto wrong_num_blocks_error;
+
+	/* 3 elements: first, last, step */
+	if ((-1 == SLang_pop_integer (&ctrl))
+	    || (-1 == SLang_pop_integer (&last))
+	    || (-1 == SLang_pop_integer (&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 >= 0)
+	       {
+		  if (i > last) break;
+	       }
+	     else if (i < 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 = "loop";
+	if (num_blocks != 1)
+	  goto wrong_num_blocks_error;
+
+	if (-1 == SLang_pop_integer (&ctrl))
+	  goto return_error;
+	while (ctrl > 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 = "forever";
+
+	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, "Unknown loop type");
+	return;
+     }
+   Lang_Break = /* Lang_Continue = */ 0;
+   Lang_Break_Condition = Lang_Return;
+   return;
+
+   wrong_num_blocks_error:
+   SLang_verror (SL_SYNTAX_ERROR, "Wrong number of blocks for '%s' construct", 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 <= addr_max)
+     {
+	if (addr->bc_main_type == _SLANG_BC_LINE_NUM)
+	  {
+	     addr++;
+	     continue;
+	  }
+
+	inner_interp (addr->b.blk);
+	if (SLang_Error
+	    || Lang_Break_Condition
+	    || (-1 == pop_ctrl_integer (&test)))
+	  return;
+
+	if (is_or == (test != 0))
+	  break;
+
+	/* if (((stype == _SLANG_BCST_ANDELSE) && (test == 0))
+	 *   || ((stype == _SLANG_BCST_ORELSE) && 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 (&test))
+     return;
+
+   if (test == 0)
+     non_zero_block = zero_block;
+
+   if (non_zero_block != NULL)
+     inner_interp (non_zero_block->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->data_type);
+
+	if (NULL == (s = _SLstringize_object (x)))
+	  s = "??";
+
+	call_dump_routine ("%s[%s]:%s\n", prefix, cl->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->name;
+
+   _SL_increment_frame_pointer ();
+
+   /* need loaded?  */
+   if (fun->nlocals == AUTOLOAD_NUM_LOCALS)
+     {
+	header = NULL;
+	if (-1 == SLang_load_file(fun->v.autoload_filename))
+	  goto the_return;
+
+	if (fun->nlocals == AUTOLOAD_NUM_LOCALS)
+	  {
+	     SLang_verror (SL_UNDEFINED_NAME, "%s: Function did not autoload",
+			   _SLang_Current_Function_Name);
+             goto the_return;
+	  }
+     }
+
+   n_locals = fun->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) > Local_Variable_Stack + SLANG_MAX_LOCAL_STACK)
+     {
+	SLang_verror(SL_STACK_OVERFLOW, "%s: Local Variable Stack Overflow",
+		     _SLang_Current_Function_Name);
+	goto the_return;
+     }
+
+   /* Make sure we do not allow this header to get destroyed by something
+    * like:  define crash () { eval ("define crash ();") }
+    */
+   header = fun->v.header;
+   header->num_refs++;
+
+   while (i--)
+     {
+	lvf++;
+	lvf->data_type = SLANG_UNDEFINED_TYPE;
+     }
+   Local_Variable_Frame = lvf;
+
+   /* read values of function arguments */
+   i = fun->nargs;
+   while (i > 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)
+	    && (0 == strcmp (Trace_Function, _SLang_Current_Function_Name))
+	    && (Trace_Mode == 0))
+	  Trace_Mode = 1;
+
+	if (Trace_Mode)
+	  {
+	     /* The local variable frame grows backwards */
+	     trace_dump (">>%s (%d args)\n",
+			 _SLang_Current_Function_Name,
+			 Local_Variable_Frame,
+			 (int) fun->nargs,
+			 -1);
+	     Trace_Mode++;
+	  }
+
+	inner_interp (header->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 ("<<%s (returning %d values)\n",
+			 _SLang_Current_Function_Name,
+			 _SLStack_Pointer - stack_depth,
+			 stack_depth,
+			 1);
+
+	     if (Trace_Mode == 1)
+	       Trace_Mode = 0;
+	  }
+     }
+   else
+     {
+	inner_interp (header->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->name, n_locals,
+#if _SLANG_HAS_DEBUG_CODE
+		  fun->file
+#else
+		  NULL
+#endif
+		  );
+
+   /* free local variables.... */
+   lvf = Local_Variable_Frame;
+   while (lvf > frame)
+     {
+#if _SLANG_OPTIMIZE_FOR_SPEED
+	if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [lvf->data_type])
+#endif
+	  SLang_free_object (lvf);
+	lvf--;
+     }
+   Local_Variable_Frame = lvf;
+
+   if (header->num_refs == 1)
+     free_function_header (header);
+   else
+     header->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 ("S-Lang Traceback: %s\n", name);
+   if (SLang_Traceback < 0)
+     return;
+
+   if (file != NULL)
+     call_dump_routine ("File: %s\n", file);
+
+   if (locals == 0)
+     return;
+
+   call_dump_routine ("  Local Variables:\n");
+
+   for (i = 0; i < locals; i++)
+     {
+	SLang_Class_Type *cl;
+	char *class_name;
+
+	objp = Local_Variable_Frame - i;
+	stype = objp->data_type;
+
+	s = _SLstringize_object (objp);
+	cl = _SLclass_get_class (stype);
+	class_name = cl->cl_name;
+
+	call_dump_routine ("\t$%d: Type: %s,\tValue:\t", i, class_name);
+
+	if (s == NULL) call_dump_routine("??\n");
+	else
+	  {
+	     char *q = "";
+#ifndef HAVE_VSNPRINTF
+	     char buf[256];
+	     if (strlen (s) >= sizeof (buf))
+	       {
+		  strncpy (buf, s, sizeof(buf));
+		  s = buf;
+		  s[sizeof(buf) - 1] = 0;
+	       }
+#endif
+	     if (SLANG_STRING_TYPE == stype) q = "\"";
+	     call_dump_routine ("%s%s%s\n", q, s, q);
+	  }
+     }
+}
+
+static void do_app_unary (SLang_App_Unary_Type *nt)
+{
+   if (-1 == do_unary (nt->unary_op, nt->name_type))
+     do_traceback (nt->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->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->is_global == 0)
+     {
+	SLang_Object_Type *obj = ref->v.local_obj;
+	if (obj > Local_Variable_Frame)
+	  {
+	     SLang_verror (SL_UNDEFINED_NAME, "Local variable deref is out of scope");
+	     return -1;
+	  }
+	return _SLpush_slang_obj (ref->v.local_obj);
+     }
+
+   (void) inner_interp_nametype (ref->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->is_global == 0)
+     {
+	SLang_Object_Type *obj = ref->v.local_obj;
+	if (obj > Local_Variable_Frame)
+	  {
+	     SLang_verror (SL_UNDEFINED_NAME, "Local variable deref is out of scope");
+	     return -1;
+	  }
+	type = ref->v.local_obj->data_type;
+     }
+   else
+     {
+	SLang_Name_Type *nt = ref->v.nt;
+	if ((nt->name_type != SLANG_GVARIABLE)
+	    && (nt->name_type != SLANG_PVARIABLE))
+	  return 1;
+	type = ((SLang_Global_Var_Type *)nt)->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->is_global == 0)
+     {
+	obj = ref->v.local_obj;
+	if (obj > Local_Variable_Frame)
+	  {
+	     SLang_verror (SL_UNDEFINED_NAME, "Local variable deref is out of scope");
+	     return -1;
+	  }
+	obj = ref->v.local_obj;
+     }
+   else
+     {
+	SLang_Name_Type *nt = ref->v.nt;
+	if ((nt->name_type != SLANG_GVARIABLE)
+	    && (nt->name_type != SLANG_PVARIABLE))
+	  return -1;
+	obj = &((SLang_Global_Var_Type *)nt)->obj;
+     }
+   SLang_free_object (obj);
+   obj->data_type = SLANG_UNDEFINED_TYPE;
+   obj->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 <= 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->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->cl_push) (subtype, (VOID_STAR) &obj->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->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->v.s_val);
+#endif
+
+   cl = _SLclass_get_class (subtype);
+   return (*cl->cl_push) (subtype, (VOID_STAR) &obj->v);
+}
+
+static int push_intrinsic_variable (SLang_Intrin_Var_Type *ivar)
+{
+   SLang_Class_Type *cl;
+   unsigned char stype;
+
+   stype = ivar->type;
+   cl = _SLclass_get_class (stype);
+
+   if (-1 == (*cl->cl_push_intrinsic) (stype, ivar->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 (&obj))
+     return -1;
+
+   type = obj.data_type;
+
+   cl = _SLclass_get_class (type);
+   ret = (*cl->cl_dereference)(type, (VOID_STAR) &obj.v);
+
+   SLang_free_object (&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 < Switch_Objects)
+       || (0 == (type = swobjptr->data_type)))
+     {
+	SLang_verror (SL_SYNTAX_ERROR, "Misplaced 'case' keyword");
+	return -1;
+     }
+
+   if (-1 == SLang_pop (&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, &a_cl, 0))
+	  {
+	     (void) SLclass_push_int_obj (SLANG_INT_TYPE, 0);
+	     SLang_free_object (&obj);
+	     return 0;
+	  }
+     }
+
+   (void) do_binary_ab (SLANG_EQ, swobjptr, &obj);
+   SLang_free_object (&obj);
+   return 0;
+}
+
+static void tmp_variable_function (SLBlock_Type *addr)
+{
+   SLang_Object_Type *obj;
+
+   switch (addr->bc_sub_type)
+     {
+      case SLANG_GVARIABLE:
+      case SLANG_PVARIABLE:
+	obj = &addr->b.nt_gvar_blk->obj;
+	break;
+
+      case SLANG_LVARIABLE:
+	obj = Local_Variable_Frame - addr->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->data_type = SLANG_UNDEFINED_TYPE;
+   obj->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 < 0)		       /* errors less than 0 are severe */
+     goto return_error;
+
+   save_err = Last_Error++;
+   slerr = SLang_Error;
+   SLang_Error = 0;
+   inner_interp (err_block->b.blk);
+
+   if (Last_Error <= 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 >= addr_start)
+     {
+	if (addr->bc_main_type == _SLANG_BC_LINE_NUM)
+	  {
+	     char buf[256];
+	     sprintf (buf, "(Error occurred on line %lu)", addr->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 ("stats.txt", "w");
+   if (fp == NULL)
+     return;
+   
+   total = 0;
+   for (i = 0; i < 0xFFFF; i++)
+     total += Bytecodes[i];
+   
+   if (total == 0)
+     total = 1;
+
+   for (i = 0; i < 0xFFFF; i++)
+     {
+	if (Bytecodes[i])
+	  fprintf (fp, "0x%04X %9u %e\n", i, Bytecodes[i], Bytecodes[i]/(double) total);
+     }
+   fclose (fp);
+}
+
+static void add_to_statistics (SLBlock_Type *b)
+{
+   unsigned short x, y;
+   
+   x = b->bc_main_type;
+   if (x == 0)
+     {
+	Bytecodes[0] += 1;
+	return;
+     }
+   b++;
+   y = b->bc_main_type;
+
+   Bytecodes[(x << 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->bc_main_type)
+	  {
+	   case 0:
+	     return 1;
+	   case _SLANG_BC_LVARIABLE:
+	     push_local_variable (addr->b.i_blk);
+	     break;
+	   case _SLANG_BC_GVARIABLE:
+	     if (-1 == _SLpush_slang_obj (&addr->b.nt_gvar_blk->obj))
+	       do_name_type_error (addr->b.nt_blk);
+	     break;
+
+	   case _SLANG_BC_IVARIABLE:
+	   case _SLANG_BC_RVARIABLE:
+	     push_intrinsic_variable (addr->b.nt_ivar_blk);
+	     break;
+
+	   case _SLANG_BC_INTRINSIC:
+	     execute_intrinsic_fun (addr->b.nt_ifun_blk);
+	     if (SLang_Error)
+	       do_traceback(addr->b.nt_ifun_blk->name, 0, NULL);
+	     break;
+
+	   case _SLANG_BC_FUNCTION:
+	     execute_slang_fun (addr->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->b.nt_unary_blk);
+		  (void) _SL_decrement_frame_pointer ();
+	       }
+	     break;
+
+	   case _SLANG_BC_ICONST:
+	     SLclass_push_int_obj (SLANG_INT_TYPE, addr->b.iconst_blk->i);
+	     break;
+
+#if SLANG_HAS_FLOAT
+	   case _SLANG_BC_DCONST:
+	     SLang_push_double (addr->b.dconst_blk->d);
+	     break;
+#endif
+
+	   case _SLANG_BC_PVARIABLE:
+	     if (-1 == _SLpush_slang_obj (&addr->b.nt_gvar_blk->obj))
+	       do_name_type_error (addr->b.nt_blk);
+	     break;
+
+	   case _SLANG_BC_PFUNCTION:
+	     execute_slang_fun (addr->b.nt_fun_blk);
+	     if (Lang_Break_Condition) goto handle_break_condition;
+	     break;
+
+	   case _SLANG_BC_BINARY:
+	     do_binary (addr->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->bc_sub_type);
+		  (*cl->cl_push_literal) (addr->bc_sub_type, (VOID_STAR) &addr->b.ptr_blk);
+	       }
+	     break;
+#if _SLANG_OPTIMIZE_FOR_SPEED
+	   case _SLANG_BC_LITERAL_INT:
+	     SLclass_push_int_obj (addr->bc_sub_type, (int) addr->b.l_blk);
+	     break;
+
+	   case _SLANG_BC_LITERAL_STR:
+	     _SLang_dup_and_push_slstring (addr->b.s_blk);
+	     break;
+#endif
+	   case _SLANG_BC_BLOCK:
+	     switch (addr->bc_sub_type)
+	       {
+		case _SLANG_BCST_ERROR_BLOCK:
+		  err_block = addr;
+		  break;
+
+		case _SLANG_BCST_EXIT_BLOCK:
+		  Exit_Block_Ptr = addr->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->bc_sub_type - _SLANG_BCST_USER_BLOCK0] = addr->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->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 (&i)) && (i == 0))
+			 inner_interp (addr->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 (&i)) && i)
+			 inner_interp (addr->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("switch nesting too deep");
+		       break;
+		    }
+		  (void) SLang_pop (Switch_Obj_Ptr);
+		  Switch_Obj_Ptr++;
+
+		  if (block == NULL) block = addr;
+		  while ((SLang_Error == 0)
+			 && (block <= addr)
+			 && (Lang_Break_Condition == 0)
+			 && (0 == inner_interp (block->b.blk)))
+		    block++;
+		  Switch_Obj_Ptr--;
+		  SLang_free_object (Switch_Obj_Ptr);
+		  Switch_Obj_Ptr->data_type = 0;
+		  block = NULL;
+		  break;
+
+		case _SLANG_BCST_ANDELSE:
+		case _SLANG_BCST_ORELSE:
+		  if (block == NULL) block = addr;
+		  lang_do_and_orelse (addr->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 (&test))
+		      && (test == 0))
+		    return 0;
+	       }
+	     break;
+
+	   case _SLANG_BC_LOBJPTR:
+	     (void)_SLang_push_ref (0, (VOID_STAR)(Local_Variable_Frame - addr->b.i_blk));
+	     break;
+
+	   case _SLANG_BC_GOBJPTR:
+	     (void)_SLang_push_ref (1, (VOID_STAR)addr->b.nt_blk);
+	     break;
+
+	   case _SLANG_BC_X_ERROR:
+	     if (err_block != NULL)
+	       {
+		  inner_interp(err_block->b.blk);
+		  if (SLang_Error) err_block = NULL;
+	       }
+	     else SLang_verror(SL_SYNTAX_ERROR, "No ERROR_BLOCK");
+	     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->bc_main_type - _SLANG_BC_X_USER0] != NULL)
+	       {
+		  inner_interp(User_Block_Ptr[addr->bc_main_type - _SLANG_BC_X_USER0]);
+	       }
+	     else SLang_verror(SL_SYNTAX_ERROR, "No block for X_USERBLOCK");
+	     if (Lang_Break_Condition) goto handle_break_condition;
+	     break;
+
+	   case _SLANG_BC_CALL_DIRECT:
+	     (*addr->b.call_function) ();
+	     break;
+
+	   case _SLANG_BC_CALL_DIRECT_FRAME:
+	     do_bc_call_direct_frame (addr->b.call_function);
+	     break;
+
+	   case _SLANG_BC_UNARY:
+	     do_unary (addr->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->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->bc_sub_type, Local_Variable_Frame - addr->b.i_blk);
+	     break;
+	   case _SLANG_BC_SET_GLOBAL_LVALUE:
+	     if (-1 == set_lvalue_obj (addr->bc_sub_type, &addr->b.nt_gvar_blk->obj))
+	       do_name_type_error (addr->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->b.s_blk);
+	     break;
+
+	   case _SLANG_BC_SET_ARRAY_LVALUE:
+	     set_array_lvalue (addr->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->b.i_blk))
+	       do_bc_call_direct_frame (_SLarray_aget);
+	     break;
+
+	   case _SLANG_BC_LVARIABLE_APUT:
+	     if (0 == push_local_variable (addr->b.i_blk))
+	       do_bc_call_direct_frame (_SLarray_aput);
+	     break;
+	   case _SLANG_BC_INTEGER_PLUS:
+	     if (0 == SLclass_push_int_obj (addr->bc_sub_type, (int) addr->b.l_blk))
+	       do_binary (SLANG_PLUS);
+	     break;
+
+	   case _SLANG_BC_INTEGER_MINUS:
+	     if (0 == SLclass_push_int_obj (addr->bc_sub_type, (int) addr->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->b.i_blk);
+	     break;
+#endif
+	   case _SLANG_BC_EARG_LVARIABLE:
+	     push_local_variable (addr->b.i_blk);
+	     (void) SLang_end_arg_list ();
+	     break;
+
+#if USE_COMBINED_BYTECODES
+	   case _SLANG_BC_CALL_DIRECT_INTRINSIC:
+	     (*addr->b.call_function) ();
+	     addr++;
+	     execute_intrinsic_fun (addr->b.nt_ifun_blk);
+	     if (SLang_Error)
+	       do_traceback(addr->b.nt_ifun_blk->name, 0, NULL);
+	     break;
+
+	   case _SLANG_BC_INTRINSIC_CALL_DIRECT:
+	     execute_intrinsic_fun (addr->b.nt_ifun_blk);
+	     if (SLang_Error)
+	       {
+		  do_traceback(addr->b.nt_ifun_blk->name, 0, NULL);
+		  break;
+	       }
+	     addr++;
+	     (*addr->b.call_function) ();
+	     break;
+
+	   case _SLANG_BC_CALL_DIRECT_LSTR:
+	     (*addr->b.call_function) ();
+	     addr++;
+	     _SLang_dup_and_push_slstring (addr->b.s_blk);
+	     break;
+
+	   case _SLANG_BC_CALL_DIRECT_SLFUN:
+	     (*addr->b.call_function) ();
+	     addr++;
+	     execute_slang_fun (addr->b.nt_fun_blk);
+	     if (Lang_Break_Condition) goto handle_break_condition;
+	     break;
+
+	   case _SLANG_BC_CALL_DIRECT_INTRSTOP:
+	     (*addr->b.call_function) ();
+	     addr++;
+	     /* drop */
+	   case _SLANG_BC_INTRINSIC_STOP:
+	     execute_intrinsic_fun (addr->b.nt_ifun_blk);
+	     if (SLang_Error == 0)
+	       return 1;
+	     do_traceback(addr->b.nt_ifun_blk->name, 0, NULL);
+	     break;
+
+	   case _SLANG_BC_CALL_DIRECT_EARG_LVAR:
+	     (*addr->b.call_function) ();
+	     addr++;
+	     push_local_variable (addr->b.i_blk);
+	     (void) SLang_end_arg_list ();
+	     break;
+
+	   case _SLANG_BC_CALL_DIRECT_LINT:
+	     (*addr->b.call_function) ();
+	     addr++;
+	     SLclass_push_int_obj (addr->bc_sub_type, (int) addr->b.l_blk);
+	     break;
+
+	   case _SLANG_BC_CALL_DIRECT_LVAR:
+	     (*addr->b.call_function) ();
+	     addr++;
+	     push_local_variable (addr->b.i_blk);
+	     break;
+#endif				       /* USE_COMBINED_BYTECODES */
+
+	   default:
+	     SLang_verror (SL_INTERNAL_ERROR, "Byte-Code 0x%X is not valid", addr->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->bc_main_type)
+	  {
+	   case _SLANG_BC_BLOCK:
+	     if (lang_free_branch(p->b.blk))
+	       SLfree((char *)p->b.blk);
+	     break;
+
+	   case _SLANG_BC_LITERAL:
+	   case _SLANG_BC_LITERAL_STR:
+	     /* No user types should be here. */
+	     cl = _SLclass_get_class (p->bc_sub_type);
+	     (*cl->cl_byte_code_destroy) (p->bc_sub_type, (VOID_STAR) &p->b.ptr_blk);
+	     break;
+
+	   case _SLANG_BC_FIELD:
+	   case _SLANG_BC_SET_STRUCT_LVALUE:
+	     SLang_free_slstring (p->b.s_blk);
+	     break;
+
+	   default:
+	     break;
+
+	   case 0:
+	     return 1;
+	  }
+	p++;
+     }
+}
+
+static void free_function_header (_SLBlock_Header_Type *h)
+{
+   if (h->num_refs > 1)
+     {
+	h->num_refs--;
+	return;
+     }
+
+   if (h->body != NULL)
+     {
+	if (lang_free_branch (h->body))
+	  SLfree ((char *) h->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, "Block stack overflow");
+	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->block = This_Compile_Block;
+   c->block_ptr = Compile_ByteCode_Ptr;
+   c->block_max = This_Compile_Block_Max;
+   c->block_type = This_Compile_Block_Type;
+   c->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->block;
+   This_Compile_Block_Max = c->block_max;
+   This_Compile_Block_Type = c->block_type;
+   Compile_ByteCode_Ptr = c->block_ptr;
+   This_Static_NameSpace = c->static_namespace;
+
+   return 0;
+}
+
+int _SLcompile_push_context (SLang_Load_Type *load_object)
+{
+   if (-1 == push_compile_context (load_object->name))
+     return -1;
+
+   if (NULL == (This_Static_NameSpace = _SLns_allocate_namespace (load_object->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->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, "Not at top-level");
+	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->name[0])
+	    && (0 == strcmp (t->name + 1, name)))
+	  break;
+
+	t = t->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] != '>'))
+     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->table, Global_NameSpace->table_size);
+     }
+
+   if (NULL == (table = _SLns_find_namespace (ns)))
+     {
+	if (err_on_bad_ns)
+	  SLang_verror (SL_SYNTAX_ERROR, "Unable to find namespace called %s", 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->table, table->table_size);
+   if (nt == NULL)
+     return NULL;
+
+   switch (nt->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)
+       && (NULL != (t = locate_name_in_table (name, hash, This_Static_NameSpace->table, This_Static_NameSpace->table_size))))
+     return t;
+
+   t = locate_name_in_table (name, hash, Global_NameSpace->table, Global_NameSpace->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->name = _SLstring_dup_hashed_string (name, hash)))
+     {
+	SLfree ((char *) t);
+	return NULL;
+     }
+   t->name_type = name_type;
+
+   hash = hash % table_size;
+   t->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->table;
+   table_size = ns->table_size;
+
+   nt = locate_name_in_table (name, hash, table, table_size);
+   if (nt != NULL)
+     {
+	if (nt->name_type == name_type)
+	  return nt;
+
+	SLang_verror (SL_DUPLICATE_DEFINITION, "%s cannot be re-defined", 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 > SLANG_MAX_INTRIN_ARGS)
+     {
+	SLang_verror (SL_APPLICATION_ERROR, "Function %s requires too many arguments", name);
+	return -1;
+     }
+
+   if (ret_type == SLANG_FLOAT_TYPE)
+     {
+	SLang_verror (SL_NOT_IMPLEMENTED, "Function %s is not permitted to return float", 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->i_fun = addr;
+   f->num_args = nargs;
+   f->return_type = ret_type;
+
+   for (i = 0; i < nargs; i++)
+     f->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->addr = addr;
+   v->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)
+       && (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->v.header != NULL)
+     {
+	if (f->nlocals == AUTOLOAD_NUM_LOCALS)
+	  SLang_free_slstring ((char *)f->v.autoload_filename); /* autoloaded filename */
+	else
+	  free_function_header (f->v.header);
+     }
+
+#if _SLANG_HAS_DEBUG_CODE
+   if (f->file != NULL) SLang_free_slstring (f->file);
+   f->file = file;
+#endif
+   f->v.header = h;
+   f->nlocals = num_locals;
+   f->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->table, Global_NameSpace->table_size);
+
+   if ((f != NULL)
+       && (f->name_type == SLANG_FUNCTION)
+       && (f->v.header != NULL)
+       && (f->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->table, 
+				Global_NameSpace->table_size);
+}
+
+/*}}}*/
+
+static void free_local_variable_table (void)
+{
+   unsigned int i;
+   SLang_Name_Type *t, *t1;
+
+   for (i = 0; i < SLLOCALS_HASH_TABLE_SIZE; i++)
+     {
+	t = Locals_Hash_Table [i];
+	while (t != NULL)
+	  {
+	     SLang_free_slstring (t->name);
+	     t1 = t->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->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->is_global)
+     {
+	SLang_Name_Type *nt = ref->v.nt;
+
+	switch (nt->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,
+		      "Reference to a function expected.  Found &%s", 
+		      nt->name);
+     }
+
+   SLang_verror (SL_TYPE_MISMATCH,
+		 "Reference to a function expected");
+   return NULL;
+}
+
+int SLexecute_function (SLang_Name_Type *nt)
+{
+   unsigned char type;
+   char *name;
+
+   if (SLang_Error)
+     return -1;
+
+   type = nt->name_type;
+   name = nt->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, "%s is not a function", name);
+	return -1;
+     }
+
+   if (SLang_Error)
+     {
+	SLang_verror (SLang_Error, "Error while executing %s", 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->name_type == SLANG_FUNCTION)
+       || (entry->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, "Function nesting is illegal");
+	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->bc_main_type)
+	  {
+	   case 0:
+	     return;
+	     
+	   default:
+	     b++;
+	     break;
+
+	   case _SLANG_BC_CALL_DIRECT:
+	     b++;
+	     switch (b->bc_main_type)
+	       {
+		case 0:
+		  return;
+		case _SLANG_BC_INTRINSIC:
+		  if ((b+1)->bc_main_type == 0)
+		    {
+		       (b-1)->bc_main_type = _SLANG_BC_CALL_DIRECT_INTRSTOP;
+		       return;
+		    }
+		  (b-1)->bc_main_type = _SLANG_BC_CALL_DIRECT_INTRINSIC;
+		  b++;
+		  break;
+		case _SLANG_BC_LITERAL_STR:
+		  (b-1)->bc_main_type = _SLANG_BC_CALL_DIRECT_LSTR;
+		  b++;
+		  break;
+		case _SLANG_BC_FUNCTION:
+		case _SLANG_BC_PFUNCTION:
+		  (b-1)->bc_main_type = _SLANG_BC_CALL_DIRECT_SLFUN;
+		  b++;
+		  break;
+		case _SLANG_BC_EARG_LVARIABLE:
+		  (b-1)->bc_main_type = _SLANG_BC_CALL_DIRECT_EARG_LVAR;
+		  b++;
+		  break;
+		case _SLANG_BC_LITERAL_INT:
+		  (b-1)->bc_main_type = _SLANG_BC_CALL_DIRECT_LINT;
+		  b++;
+		  break;
+		case _SLANG_BC_LVARIABLE:
+		  (b-1)->bc_main_type = _SLANG_BC_CALL_DIRECT_LVAR;
+		  b++;
+		  break;
+	       }
+	     break;
+	     
+	   case _SLANG_BC_INTRINSIC:
+	     b++;
+	     switch (b->bc_main_type)
+	       {
+		case _SLANG_BC_CALL_DIRECT:
+		  (b-1)->bc_main_type = _SLANG_BC_INTRINSIC_CALL_DIRECT;
+		  b++;
+		  break;
+#if 0
+		case _SLANG_BC_BLOCK:
+		  (b-1)->bc_main_type = _SLANG_BC_INTRINSIC_BLOCK;
+		  b++;
+		  break;
+#endif
+
+		case 0:
+		  (b-1)->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, "Premature end of function");
+	return -1;
+     }
+
+   /* terminate function */
+   Compile_ByteCode_Ptr->bc_main_type = 0;
+
+   if (name != NULL)
+     {
+	_SLBlock_Header_Type *h;
+
+	h = (_SLBlock_Header_Type *)SLmalloc (sizeof (_SLBlock_Header_Type));
+	if (h != NULL)
+	  {
+	     h->num_refs = 1;
+	     h->body = This_Compile_Block;
+	     
+#if USE_COMBINED_BYTECODES
+	     optimize_block (h->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, "Not at top-level");
+	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, "Not defining a block");
+	return;
+     }
+
+   /* terminate the block */
+   Compile_ByteCode_Ptr->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->bc_main_type;
+	if (((mtype == _SLANG_BC_BREAK)
+	     || (mtype == _SLANG_BC_CONTINUE)
+	     || (mtype == _SLANG_BC_RETURN))
+	    && (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->bc_main_type = _SLANG_BC_BLOCK;
+   node->bc_sub_type = 0;
+   node->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, "Top-level block not present");
+	return -1;
+     }
+
+   /* Allow 1 extra for terminator */
+   if (Compile_ByteCode_Ptr + 1 < 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->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("X")) { 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("variable ZZZZ;"); }
+    */
+   /* hash = _SLcompute_string_hash (name); */
+   g = locate_name_in_table (name, hash, ns->table, ns->table_size);
+
+   if (g != NULL)
+     {
+	if (g->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 >= SLANG_MAX_LOCAL_VARIABLES)
+     {
+	SLang_verror (SL_SYNTAX_ERROR, "Too many local variables");
+	return -1;
+     }
+
+   if (NULL != locate_name_in_table (name, hash, Locals_Hash_Table, SLLOCALS_HASH_TABLE_SIZE))
+     {
+	SLang_verror (SL_SYNTAX_ERROR, "Local variable %s has already been defined", 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->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)
+	  && (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 < 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->bc_sub_type = sub_type;
+
+   lang_try_now ();
+}
+
+static void compile_unary (int op, unsigned char mt)
+{
+   Compile_ByteCode_Ptr->bc_main_type = mt;
+   Compile_ByteCode_Ptr->b.i_blk = op;
+   Compile_ByteCode_Ptr->bc_sub_type = 0;
+
+   lang_try_now ();
+}
+
+
+static void compile_binary (int op)
+{
+   Compile_ByteCode_Ptr->bc_main_type = _SLANG_BC_BINARY;
+   Compile_ByteCode_Ptr->b.i_blk = op;
+   Compile_ByteCode_Ptr->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->bc_main_type == last_bc)
+	  {
+	     Compile_ByteCode_Ptr = b;
+	     b->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->bc_main_type = nt->main_type;
+   Compile_ByteCode_Ptr->b.ptr_blk = nt->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 = "***Unknown***";
+   else
+     name = This_Static_NameSpace->name;
+
+   name = SLang_create_slstring (name);
+   if (name == NULL)
+     return -1;
+
+   Compile_ByteCode_Ptr->b.s_blk = name;
+   Compile_ByteCode_Ptr->bc_main_type = _SLANG_BC_LITERAL_STR;
+   Compile_ByteCode_Ptr->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->b.l_blk = (long) tok->line_number;
+#endif
+   Compile_ByteCode_Ptr->bc_main_type = _SLANG_BC_LITERAL;
+   Compile_ByteCode_Ptr->bc_sub_type = SLANG_UINT_TYPE;
+
+   return 0;
+}
+
+static Special_NameTable_Type Special_Name_Table [] =
+{
+     {"EXECUTE_ERROR_BLOCK", handle_special, NULL, _SLANG_BC_X_ERROR},
+     {"X_USER_BLOCK0", handle_special, NULL, _SLANG_BC_X_USER0},
+     {"X_USER_BLOCK1", handle_special, NULL, _SLANG_BC_X_USER1},
+     {"X_USER_BLOCK2", handle_special, NULL, _SLANG_BC_X_USER2},
+     {"X_USER_BLOCK3", handle_special, NULL, _SLANG_BC_X_USER3},
+     {"X_USER_BLOCK4", handle_special, NULL, _SLANG_BC_X_USER4},
+     {"__FILE__", handle_special_file, NULL, 0},
+     {"__LINE__", handle_special_line, NULL, 0},
+#if 0
+     {"__NAMESPACE__", 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->name != NULL)
+	  {
+	     if (strcmp (name, nt->name))
+	       {
+		  nt++;
+		  continue;
+	       }
+
+	     if (0 == (*nt->fun)(nt, tok))
+	       lang_try_now ();
+	     return;
+	  }
+
+	SLang_verror (SL_UNDEFINED_NAME, "%s is undefined", name);
+	return;
+     }
+
+   name_type = entry->name_type;
+   Compile_ByteCode_Ptr->bc_main_type = name_type;
+
+   if (name_type == SLANG_LVARIABLE)
+     Compile_ByteCode_Ptr->b.i_blk = ((SLang_Local_Var_Type *) entry)->local_var_number;
+   else
+     Compile_ByteCode_Ptr->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, "%s is undefined", name);
+	return;
+     }
+
+   name_type = entry->name_type;
+   switch (name_type)
+     {
+      case SLANG_LVARIABLE:
+	Compile_ByteCode_Ptr->b.i_blk = ((SLang_Local_Var_Type *) entry)->local_var_number;
+	break;
+
+      case SLANG_GVARIABLE:
+      case SLANG_PVARIABLE:
+	Compile_ByteCode_Ptr->b.nt_blk = entry;
+	break;
+
+      default:
+	SLang_verror (SL_SYNTAX_ERROR, "__tmp(%s) does not specifiy a variable", name);
+	return;
+     }
+
+   Compile_ByteCode_Ptr->bc_main_type = _SLANG_BC_TMP;
+   Compile_ByteCode_Ptr->bc_sub_type = name_type;
+
+   lang_try_now ();
+}
+
+static void compile_simple (unsigned char main_type)
+{
+   Compile_ByteCode_Ptr->bc_main_type = main_type;
+   Compile_ByteCode_Ptr->bc_sub_type = 0;
+   Compile_ByteCode_Ptr->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->b.call_function = f;
+   Compile_ByteCode_Ptr->bc_main_type = byte_code;
+   Compile_ByteCode_Ptr->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->b.l_blk = i;
+   Compile_ByteCode_Ptr->bc_main_type = bc_main_type;
+   Compile_ByteCode_Ptr->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, "%lf", &d))
+     {
+	SLang_verror (SL_SYNTAX_ERROR, "Unable to convert %s to double", 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->b.double_blk = ptr;
+#if SLANG_HAS_COMPLEX
+   if (type == SLANG_COMPLEX_TYPE)
+     *ptr++ = 0;
+#endif
+   *ptr = d;
+
+   Compile_ByteCode_Ptr->bc_main_type = _SLANG_BC_LITERAL;
+   Compile_ByteCode_Ptr->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, "%f", &x))
+     {
+	SLang_verror (SL_SYNTAX_ERROR, "Unable to convert %s to float", s);
+	return;
+     }
+#endif
+   Compile_ByteCode_Ptr->b.float_blk = x;
+   Compile_ByteCode_Ptr->bc_main_type = _SLANG_BC_LITERAL;
+   Compile_ByteCode_Ptr->bc_sub_type = SLANG_FLOAT_TYPE;
+   lang_try_now ();
+}
+
+#endif
+
+static void compile_string (char *s, unsigned long hash)
+{
+   if (NULL == (Compile_ByteCode_Ptr->b.s_blk = _SLstring_dup_hashed_string (s, hash)))
+     return;
+
+   Compile_ByteCode_Ptr->bc_main_type = _SLANG_BC_LITERAL_STR;
+   Compile_ByteCode_Ptr->bc_sub_type = SLANG_STRING_TYPE;
+
+   lang_try_now ();
+}
+
+static void compile_bstring (SLang_BString_Type *s)
+{
+   if (NULL == (Compile_ByteCode_Ptr->b.bs_blk = SLbstring_dup (s)))
+     return;
+
+   Compile_ByteCode_Ptr->bc_main_type = _SLANG_BC_LITERAL;
+   Compile_ByteCode_Ptr->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->name form */
+	    || Lang_Defining_Function
+	    || (assign_type != _SLANG_BCST_ASSIGN)
+	    || (This_Static_NameSpace == NULL))
+	  {
+	     SLang_verror (SL_UNDEFINED_NAME, "%s is undefined", 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)
+	    && (-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->name_type)
+     {
+      case SLANG_LVARIABLE:
+	main_type = _SLANG_BC_SET_LOCAL_LVALUE;
+	Compile_ByteCode_Ptr->b.i_blk = ((SLang_Local_Var_Type *) v)->local_var_number;
+	break;
+
+      case SLANG_GVARIABLE:
+      case SLANG_PVARIABLE:
+	main_type = _SLANG_BC_SET_GLOBAL_LVALUE;
+	Compile_ByteCode_Ptr->b.nt_blk = v;
+	break;
+
+      case SLANG_IVARIABLE:
+	cl = _SLclass_get_class (((SLang_Intrin_Var_Type *)v)->type);
+	if (cl->cl_class_type != SLANG_CLASS_TYPE_SCALAR)
+	  {
+	     SLang_verror (SL_SYNTAX_ERROR, "Assignment to %s is not allowed", name);
+	     return;
+	  }
+	main_type = _SLANG_BC_SET_INTRIN_LVALUE;
+	Compile_ByteCode_Ptr->b.nt_blk = v;
+	break;
+
+      case SLANG_RVARIABLE:
+	SLang_verror (SL_READONLY_ERROR, "%s is read-only", name);
+	return;
+
+      default:
+	SLang_verror (SL_DUPLICATE_DEFINITION, "%s may not be used as an lvalue", name);
+	return;
+     }
+
+   Compile_ByteCode_Ptr->bc_sub_type = assign_type;
+   Compile_ByteCode_Ptr->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, "%s is undefined", name);
+	return;
+     }
+
+   switch (v->name_type)
+     {
+      case SLANG_LVARIABLE:
+	Compile_ByteCode_Ptr->b.i_blk = ((SLang_Local_Var_Type *) v)->local_var_number;
+	break;
+
+      case SLANG_GVARIABLE:
+      case SLANG_PVARIABLE:
+	Compile_ByteCode_Ptr->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, "Deref assignment to %s is not allowed", name);
+	return;
+     }
+
+   Compile_ByteCode_Ptr->bc_sub_type = v->name_type;
+   Compile_ByteCode_Ptr->bc_main_type = _SLANG_BC_DEREF_ASSIGN;
+
+   lang_try_now ();
+}
+
+static void
+compile_struct_assign (_SLang_Token_Type *t)
+{
+   Compile_ByteCode_Ptr->bc_sub_type = _SLANG_BCST_ASSIGN + (t->type - _STRUCT_ASSIGN_TOKEN);
+   Compile_ByteCode_Ptr->bc_main_type = _SLANG_BC_SET_STRUCT_LVALUE;
+   Compile_ByteCode_Ptr->b.s_blk = _SLstring_dup_hashed_string (t->v.s_val, t->hash);
+   lang_try_now ();
+}
+
+static void
+compile_array_assign (_SLang_Token_Type *t)
+{
+   Compile_ByteCode_Ptr->bc_sub_type = _SLANG_BCST_ASSIGN + (t->type - _ARRAY_ASSIGN_TOKEN);
+   Compile_ByteCode_Ptr->bc_main_type = _SLANG_BC_SET_ARRAY_LVALUE;
+   Compile_ByteCode_Ptr->b.s_blk = NULL;
+   lang_try_now ();
+}
+
+static void compile_dot(_SLang_Token_Type *t)
+{
+   Compile_ByteCode_Ptr->bc_main_type = _SLANG_BC_FIELD;
+   Compile_ByteCode_Ptr->b.s_blk = _SLstring_dup_hashed_string(t->v.s_val, t->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, "%s is undefined", name);
+	return;
+     }
+
+   main_type = entry->name_type;
+
+   if (main_type == SLANG_LVARIABLE)
+     {
+	main_type = _SLANG_BC_LOBJPTR;
+	Compile_ByteCode_Ptr->b.i_blk = ((SLang_Local_Var_Type *)entry)->local_var_number;
+     }
+   else
+     {
+	main_type = _SLANG_BC_GOBJPTR;
+	Compile_ByteCode_Ptr->b.nt_blk = entry;
+     }
+
+   Compile_ByteCode_Ptr->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
+	&& (Lang_Defining_Function == 0))
+       || (requires_block
+	   && (This_Compile_Block_Type != COMPILE_BLOCK_TYPE_BLOCK)))
+     {
+	SLang_verror (SL_SYNTAX_ERROR, "misplaced %s", str);
+	return;
+     }
+
+   Compile_ByteCode_Ptr->bc_main_type = break_type;
+   Compile_ByteCode_Ptr->bc_sub_type = 0;
+
+   lang_try_now ();
+}
+
+static void compile_public_variable_mode (_SLang_Token_Type *t)
+{
+   if (t->type == IDENT_TOKEN)
+     {
+	/* If the variable is already defined in the static hash table,
+	 * generate an error.
+	 */
+	if ((This_Static_NameSpace != NULL)
+	    && (NULL != locate_name_in_table (t->v.s_val, t->hash, This_Static_NameSpace->table, This_Static_NameSpace->table_size)))
+	  {
+	     SLang_verror (SL_DUPLICATE_DEFINITION,
+			   "%s already has static or private linkage in this unit",
+			   t->v.s_val);
+	     return;
+	  }
+	add_global_variable (t->v.s_val, SLANG_GVARIABLE, t->hash, Global_NameSpace);
+     }
+   else if (t->type == CBRACKET_TOKEN)
+     Compile_Mode_Function = compile_basic_token_mode;
+   else
+     SLang_verror (SL_SYNTAX_ERROR, "Misplaced token in variable list");
+}
+
+static void compile_local_variable_mode (_SLang_Token_Type *t)
+{
+   if (t->type == IDENT_TOKEN)
+     add_local_variable (t->v.s_val, t->hash);
+   else if (t->type == CBRACKET_TOKEN)
+     Compile_Mode_Function = compile_basic_token_mode;
+   else
+     SLang_verror (SL_SYNTAX_ERROR, "Misplaced token in variable list");
+}
+
+static void compile_static_variable_mode (_SLang_Token_Type *t)
+{
+   if (t->type == IDENT_TOKEN)
+     add_global_variable (t->v.s_val, SLANG_GVARIABLE, t->hash, This_Static_NameSpace);
+   else if (t->type == CBRACKET_TOKEN)
+     Compile_Mode_Function = compile_basic_token_mode;
+   else
+     SLang_verror (SL_SYNTAX_ERROR, "Misplaced token in variable list");
+}
+
+static void compile_private_variable_mode (_SLang_Token_Type *t)
+{
+   if (t->type == IDENT_TOKEN)
+     add_global_variable (t->v.s_val, SLANG_PVARIABLE, t->hash, This_Static_NameSpace);
+   else if (t->type == CBRACKET_TOKEN)
+     Compile_Mode_Function = compile_basic_token_mode;
+   else
+     SLang_verror (SL_SYNTAX_ERROR, "Misplaced token in variable list");
+}
+
+static void compile_function_mode (_SLang_Token_Type *t)
+{
+   if (-1 == lang_check_space ())
+     return;
+
+   if (t->type != IDENT_TOKEN)
+     SLang_verror (SL_SYNTAX_ERROR, "Expecting function name");
+   else
+     lang_define_function (t->v.s_val, SLANG_FUNCTION, t->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)->b.blk;
+
+   while (0 != (t = p->bc_main_type))
+     {
+	if ((t == _SLANG_BC_BREAK)
+	    || (t == _SLANG_BC_CONTINUE))
+	  {
+	     SLang_verror (SL_SYNTAX_ERROR,
+			   "An ERROR_BLOCK is not permitted to contain continue or break statements");
+	     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->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, "misplaced EXIT_BLOCK");
+	     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, "misplaced ERROR_BLOCK");
+	     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, "misplaced USER_BLOCK");
+	     break;
+	  }
+	bc_sub_type = _SLANG_BCST_USER_BLOCK0 + (t->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, "Expecting directive token.  Found 0x%X", t->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->type != IDENT_TOKEN)
+     {
+	SLang_verror (SL_SYNTAX_ERROR, "Expecting identifier for assignment");
+	return;
+     }
+
+   compile_assign (Assign_Mode_Type, t->v.s_val, t->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->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, "Unknown or unsupported token type 0x%X", t->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->v.s_val, t->hash);
+	break;
+
+      case DOT_TOKEN:		       /* X . field */
+	compile_dot (t);
+	break;
+
+      case COMMA_TOKEN:
+	break;			       /* do nothing */
+
+      case IDENT_TOKEN:
+	compile_hashed_identifier (t->v.s_val, t->hash, t);
+	break;
+
+      case _REF_TOKEN:
+	compile_ref (t->v.s_val, t->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, "Misplaced 'case'");
+	else
+	  compile_call_direct (case_function, _SLANG_BC_CALL_DIRECT);
+	break;
+
+      case CHAR_TOKEN:
+	compile_integer (t->v.long_val, _SLANG_BC_LITERAL, SLANG_CHAR_TYPE);
+	break;
+      case SHORT_TOKEN:
+	compile_integer (t->v.long_val, _SLANG_BC_LITERAL, SLANG_SHORT_TYPE);
+	break;
+      case INT_TOKEN:
+	compile_integer (t->v.long_val, _SLANG_BC_LITERAL_INT, SLANG_INT_TYPE);
+	break;
+      case UCHAR_TOKEN:
+	compile_integer (t->v.long_val, _SLANG_BC_LITERAL, SLANG_UCHAR_TYPE);
+	break;
+      case USHORT_TOKEN:
+	compile_integer (t->v.long_val, _SLANG_BC_LITERAL, SLANG_USHORT_TYPE);
+	break;
+      case UINT_TOKEN:
+	compile_integer (t->v.long_val, _SLANG_BC_LITERAL_INT, SLANG_UINT_TYPE);
+	break;
+      case LONG_TOKEN:
+	compile_integer (t->v.long_val, _SLANG_BC_LITERAL, SLANG_LONG_TYPE);
+	break;
+      case ULONG_TOKEN:
+	compile_integer (t->v.long_val, _SLANG_BC_LITERAL, SLANG_ULONG_TYPE);
+	break;
+
+#if SLANG_HAS_FLOAT
+      case FLOAT_TOKEN:
+	compile_float (t->v.s_val);
+	break;
+
+      case DOUBLE_TOKEN:
+	compile_double (t->v.s_val, SLANG_DOUBLE_TYPE);
+	break;
+#endif
+#if SLANG_HAS_COMPLEX
+      case COMPLEX_TOKEN:
+	compile_double (t->v.s_val, SLANG_COMPLEX_TYPE);
+	break;
+#endif
+
+      case STRING_TOKEN:
+	compile_string (t->v.s_val, t->hash);
+	break;
+
+      case _BSTRING_TOKEN:
+	compile_bstring (SLbstring_create ((unsigned char *)t->v.s_val, (unsigned int) t->hash));
+	break;
+
+      case BSTRING_TOKEN:
+	compile_bstring (t->v.b_val);
+	break;
+
+      case _NULL_TOKEN:
+	compile_identifier ("NULL", 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->type - _SCALAR_ASSIGN_TOKEN),
+			t->v.s_val, t->hash);
+	break;
+
+      case _DEREF_ASSIGN_TOKEN:
+	compile_deref_assign (t->v.s_val, t->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->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, "break");
+	break;
+
+      case RETURN_TOKEN:
+	compile_break (_SLANG_BC_RETURN, 0, 1, "return");
+	break;
+
+      case CONT_TOKEN:
+	compile_break (_SLANG_BC_CONTINUE, 1, 0, "continue");
+	break;
+
+      case EXCH_TOKEN:
+	compile_break (_SLANG_BC_EXCH, 0, 0, "");   /* 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, "static variables not permitted in functions");
+	break;
+
+      case PRIVATE_TOKEN:
+	if (Lang_Defining_Function == 0)
+	  Compile_Mode_Function = compile_private_variable_mode;
+	else
+	  SLang_verror (SL_NOT_IMPLEMENTED, "private variables not permitted in functions");
+	break;
+
+      case PUBLIC_TOKEN:
+	if (Lang_Defining_Function == 0)
+	  Compile_Mode_Function = compile_public_variable_mode;
+	else
+	  SLang_verror (SL_NOT_IMPLEMENTED, "public variables not permitted in functions");
+	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->v.s_val, t->hash);
+	else SLang_Error = SL_SYNTAX_ERROR;
+	break;
+
+      case DEFINE_PRIVATE_TOKEN:
+	if (Lang_Defining_Function)
+	  define_private_function (t->v.s_val, t->hash);
+	else SLang_Error = SL_SYNTAX_ERROR;
+	break;
+
+      case DEFINE_PUBLIC_TOKEN:
+	if (Lang_Defining_Function)
+	  define_public_function (t->v.s_val, t->hash);
+	else SLang_Error = SL_SYNTAX_ERROR;
+	break;
+
+      case DEFINE_TOKEN:
+	if (Lang_Defining_Function)
+	  (*Default_Define_Function) (t->v.s_val, t->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->bc_main_type = _SLANG_BC_LINE_NUM;
+	Compile_ByteCode_Ptr->b.l_blk = t->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->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->static_namespace;
+   Compile_Context_Stack = cc->next;
+   Default_Variable_Mode = cc->compile_variable_mode;
+   Default_Define_Function = cc->define_function;
+   Compile_Mode_Function = cc->compile_mode_function;
+
+   Lang_Defining_Function = cc->lang_defining_function;
+   Local_Variable_Number = cc->local_variable_number;
+   Function_Args_Number = cc->function_args_number;
+
+#if _SLANG_HAS_DEBUG_CODE
+   SLang_free_slstring (This_Compile_Filename);
+   This_Compile_Filename = cc->compile_filename;
+#endif
+
+   SLfree ((char *) Locals_Hash_Table);
+   Locals_Hash_Table = cc->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)
+       && (NULL == (name = SLang_create_slstring (name))))
+     {
+	SLfree ((char *) cc);
+	SLfree ((char *) lns);
+	return -1;
+     }
+		
+   cc->compile_filename = This_Compile_Filename;
+   This_Compile_Filename = name;
+#endif
+
+   cc->static_namespace = This_Static_NameSpace;
+   cc->compile_variable_mode = Default_Variable_Mode;
+   cc->define_function = Default_Define_Function;
+   cc->locals_hash_table = Locals_Hash_Table;
+
+   cc->lang_defining_function = Lang_Defining_Function;
+   cc->local_variable_number = Local_Variable_Number;
+   cc->function_args_number = Function_Args_Number;
+   cc->locals_hash_table = Locals_Hash_Table;
+   cc->compile_mode_function = Compile_Mode_Function;
+
+   cc->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 ("***GLOBAL***", SLGLOBALS_HASH_TABLE_SIZE)))
+     return -1;
+   if (-1 == _SLns_set_namespace_name (ns, "Global"))
+     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->table;
+   table_size = ns->table_size;
+	
+   if ((pp_name != NULL)
+       && (-1 == SLdefine_for_ifdef (pp_name)))
+     return -1;
+
+   t = table;
+   while (NULL != (name = t->name))
+     {
+	unsigned long hash;
+
+	/* Backward compatibility: '.' WAS used as hash marker */
+	if (*name == '.')
+	  {
+	     name++;
+	     t->name = name;
+	  }
+
+	if (NULL == (name = SLang_create_slstring (name)))
+	  return -1;
+
+	t->name = name;
+
+	hash = _SLcompute_string_hash (name);
+	hash = hash % table_size;
+
+	t->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 = "Global";
+
+   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, "No namespace available");
+	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, "Namespace %s does not exist", 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 "Global";
+
+   if (This_Static_NameSpace->namespace_name == NULL)
+     return "";
+   
+   return This_Static_NameSpace->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 "1.4.4"
+
+/*{{{ System Dependent Macros and Typedefs */
+
+#if defined(__WATCOMC__) && 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 "C" {
+#endif
+#if 0
+}
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+#if defined(__STDC__) || defined(__BORLANDC__) || defined(__cplusplus)
+# include <stddef.h>		       /* 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__) && !defined(DOS386)
+# include <dos.h>
+#endif
+
+#if defined(__BORLANDC__)
+# include <alloc.h>
+#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_) && 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) && !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) && !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 @v at .
+    */
+   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 --> 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 > 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) & 0xFF)
+#define SLSMG_EXTRACT_COLOR(x) (((x)>>8)&0xFF)
+#define SLSMG_BUILD_CHAR(ch,color) (((SLsmg_Char_Type)(unsigned char)(ch))|((color)<<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	'<'
+#  define SLSMG_RARROW_CHAR	'>'
+#  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 > 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 *)&((T *)0L)->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 "slinclud.h"
+
+#include <math.h>
+
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#endif
+
+#include "slang.h"
+#include "_slang.h"
+
+/*
+ * 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 < 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->copy_function copies type i to type j.  Similarly,
+ * B_ij->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) > 0) ? 1 : (((x) < 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 "slarith.inc"
+
+#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) > 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 "slarith.inc"
+
+#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) >= 0) ? (a) : -(a))
+#define SIGN_FUNCTION(x) (((x) > 0) ? 1 : (((x) < 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 "slarith.inc"
+
+#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) > 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 "slarith.inc"
+#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) > 0) ? 1 : (((x) < 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 "slarith.inc"
+
+#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) > 0) ? 1 : (((x) < 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 "slarith.inc"
+
+#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) > 0) ? 1 : (((x) < 0) ? -1 : 0))
+#define CMP_FUNCTION char_cmp_function
+#include "slarith.inc"
+
+#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) > 0) ? 1 : 0)
+#define CMP_FUNCTION uchar_cmp_function
+#include "slarith.inc"
+
+#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) > 0) ? 1 : (((x) < 0) ? -1 : 0))
+#define CMP_FUNCTION short_cmp_function
+#include "slarith.inc"
+
+#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) > 0) ? 1 : 0)
+#define CMP_FUNCTION ushort_cmp_function
+#include "slarith.inc"
+#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) <= MAXIMUM_ARITH_TYPE_VALUE) \
+      && (Type_Precedence_Table[x] < 8) && (Type_Precedence_Table[x] != -1))
+#define IS_ARITHMETIC_TYPE(x) \
+  (((x) <= MAXIMUM_ARITH_TYPE_VALUE) && (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 > 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] > 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)
+       && (NULL == (ap = (VOID_STAR) (*af) (ap, na))))
+     return -1;
+
+   if ((bf != NULL)
+       && (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 (&obj))
+     return -1;
+
+   if ((obj.data_type > MAXIMUM_ARITH_TYPE_VALUE)
+       || ((j = Type_Precedence_Table[obj.data_type]) == -1)
+       || (j >= FLOAT_PRECEDENCE_VALUE))
+     {
+	_SLclass_type_mismatch_error (type, obj.data_type);
+       	SLang_free_object (&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)&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)&obj.v, ptr, 1);
+
+   return SLang_push (&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, &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 (&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 (&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 (&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] = "%g";
+
+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, "%d", *(char *) v);
+	break;
+      case SLANG_UCHAR_TYPE:
+	sprintf (s, "%u", *(unsigned char *) v);
+	break;
+      case SLANG_SHORT_TYPE:
+	sprintf (s, "%d", *(short *) v);
+	break;
+      case SLANG_USHORT_TYPE:
+	sprintf (s, "%u", *(unsigned short *) v);
+	break;
+      case SLANG_INT_TYPE:
+	sprintf (s, "%d", *(int *) v);
+	break;
+      case SLANG_UINT_TYPE:
+	sprintf (s, "%u", *(unsigned int *) v);
+	break;
+      case SLANG_LONG_TYPE:
+	sprintf (s, "%ld", *(long *) v);
+	break;
+      case SLANG_ULONG_TYPE:
+	sprintf (s, "%lu", *(unsigned long *) v);
+	break;
+#if SLANG_HAS_FLOAT
+      case SLANG_FLOAT_TYPE:
+	if (EOF == _SLsnprintf (buf, sizeof (buf), Double_Format, *(float *) v))
+	  sprintf (s, "%e", *(float *) v);
+	break;
+      case SLANG_DOUBLE_TYPE:
+	if (EOF == _SLsnprintf (buf, sizeof (buf), Double_Format, *(double *) v))
+	  sprintf (s, "%e", *(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] =
+{
+     {"Char_Type", SLANG_CHAR_TYPE, sizeof (char), char_unary_op, push_char_literal, char_cmp_function},
+     {"UChar_Type", SLANG_UCHAR_TYPE, sizeof (unsigned char), uchar_unary_op, push_char_literal, uchar_cmp_function},
+#if SIZEOF_INT != SIZEOF_SHORT
+     {"Short_Type", SLANG_SHORT_TYPE, sizeof (short), short_unary_op, push_short_literal, short_cmp_function},
+     {"UShort_Type", 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
+
+     {"Integer_Type", SLANG_INT_TYPE, sizeof (int), int_unary_op, push_int_literal, int_cmp_function},
+     {"UInteger_Type", SLANG_UINT_TYPE, sizeof (unsigned int), uint_unary_op, push_int_literal, uint_cmp_function},
+
+#if SIZEOF_INT != SIZEOF_LONG
+     {"Long_Type", SLANG_LONG_TYPE, sizeof (long), long_unary_op, push_long_literal, long_cmp_function},
+     {"ULong_Type", 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] =
+     {
+	"Int16_Type", "UInt16_Type", "Int32_Type", "UInt32_Type",
+	"Int64_Type", "UInt64_Type",
+	"Float32_Type", "Float64_Type"
+     };
+   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 ("Int_Type", SLANG_INT_TYPE))
+       || (-1 == SLclass_create_synonym ("UInt_Type", SLANG_UINT_TYPE)))
+     return -1;
+
+   for (i = 0; i < 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 ("Short_Type", SLANG_INT_TYPE))
+       || (-1 == SLclass_create_synonym ("UShort_Type", 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 ("Long_Type", SLANG_INT_TYPE))
+       || (-1 == SLclass_create_synonym ("ULong_Type", 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) && defined(LC_NUMERIC)
+   /* make sure decimal point it used --- the parser requires it */
+   (void) setlocale (LC_NUMERIC, "C"); 
+#endif
+
+   for (i = 0; i < 8; i++)
+     {
+	Integer_Info_Type *info;
+
+	info = Integer_Types + i;
+
+	if (info->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->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->cl_push_literal = info->push_literal;
+	cl->cl_to_bool = integer_to_bool;
+
+	cl->cl_cmp = info->cmp_fun;
+
+	if (-1 == SLclass_register_class (cl, info->data_type, info->sizeof_type,
+					  SLANG_CLASS_TYPE_SCALAR))
+	  return -1;
+	if (-1 == SLclass_add_unary_op (info->data_type, info->unary_fun, arith_unary_op_result))
+	  return -1;
+	
+	_SLarith_Is_Arith_Type [info->data_type] = 1;
+     }
+
+#if SLANG_HAS_FLOAT
+   if (NULL == (cl = SLclass_allocate_class ("Double_Type")))
+     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->cl_byte_code_destroy = double_byte_code_destroy;
+   cl->cl_push_literal = double_push_literal;
+   cl->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 ("Float_Type")))
+     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->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 <= MAXIMUM_ARITH_TYPE_VALUE; a_type++)
+     {
+	if (-1 == (i = Type_Precedence_Table [a_type]))
+	  continue;
+
+	for (b_type = 0; b_type <= 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 >= FLOAT_PRECEDENCE_VALUE)
+			    || (i < 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->data_type;
+   ib = b->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 > j)
+     {
+	id = ic;
+	j = i;
+     }
+
+   c->data_type = d->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) &c->v, (VOID_STAR)&a->v, 1);
+
+   i = Type_Precedence_Table[ib];
+   copy = (void (*)(VOID_STAR, VOID_STAR, unsigned int))
+     Binary_Matrix[i][j].copy_function;
+   (*copy) ((VOID_STAR) &d->v, (VOID_STAR)&b->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->data_type;
+   b_type = ob->data_type;
+
+   if (a_type != b_type)
+     {
+	SLang_Object_Type obj_a, obj_b;
+	
+	/* Handle common cases */
+	if ((a_type == SLANG_INT_TYPE)
+	    && (b_type == SLANG_DOUBLE_TYPE))
+	  return double_double_scalar_bin_op (oa->v.int_val, ob->v.double_val, op);
+
+	if ((a_type == SLANG_DOUBLE_TYPE)
+	    && (b_type == SLANG_INT_TYPE))
+	  return double_double_scalar_bin_op (oa->v.double_val, ob->v.int_val, op);
+
+	/* Otherwise do it the hard way */
+	promote_objs (oa, ob, &obj_a, &obj_b);
+	oa = &obj_a;
+	ob = &obj_b;
+	
+	a_type = oa->data_type;
+	b_type = ob->data_type;
+     }
+   
+	  
+   switch (a_type)
+     {
+      case SLANG_CHAR_TYPE:
+	return int_int_scalar_bin_op (oa->v.char_val, ob->v.char_val, op);
+
+      case SLANG_UCHAR_TYPE:
+	return int_int_scalar_bin_op (oa->v.uchar_val, ob->v.uchar_val, op);
+
+      case SLANG_SHORT_TYPE:
+	return int_int_scalar_bin_op (oa->v.short_val, ob->v.short_val, op);
+
+      case SLANG_USHORT_TYPE:
+# if SIZEOF_INT == SIZEOF_SHORT
+	return uint_uint_scalar_bin_op (oa->v.ushort_val, ob->v.ushort_val, op);
+# else
+	return int_int_scalar_bin_op ((int)oa->v.ushort_val, (int)ob->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->v.int_val, ob->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->v.uint_val, ob->v.uint_val, op);
+	
+#if SIZEOF_LONG != SIZEOF_INT
+      case SLANG_LONG_TYPE:
+	return long_long_scalar_bin_op (oa->v.long_val, ob->v.long_val, op);
+      case SLANG_ULONG_TYPE:
+	return ulong_ulong_scalar_bin_op (oa->v.ulong_val, ob->v.ulong_val, op);
+#endif
+      case SLANG_FLOAT_TYPE:
+	return float_float_scalar_bin_op (oa->v.float_val, ob->v.float_val, op);
+      case SLANG_DOUBLE_TYPE:
+	return double_double_scalar_bin_op (oa->v.double_val, ob->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 < 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 < 2
+   if (na == 1) da = 0; else da = 1;
+   if (nb == 1) db = 0; else db = 1;
+
+   if (na > 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 < 2
+	for (n = 0; n < n_max; n++)
+	  {
+	     d[n] = POW_FUNCTION(*a, *b);
+	     a += da; b += db;
+	  }
+#else
+	if (na == nb)
+	  {
+	     for (n = 0; n < 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 < na; n++)
+		 d[n] = a[n] * a[n];
+	     else
+	       for (n = 0; n < na; n++)
+		 d[n] = POW_FUNCTION(a[n], xb);
+	  }
+	else /* if (na == 1) */
+	  {
+	     GENERIC_TYPE xa = *a;
+	     for (n = 0; n < nb; n++)
+	       d[n] = POW_FUNCTION(xa, b[n]);
+	  }
+#endif
+	break;
+#endif
+      case SLANG_PLUS:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+	for (n = 0; n < n_max; n++)
+	  {
+	     c[n] = (*a + *b); a += da; b += db;
+	  }
+#else
+	if (na == nb)
+	  {
+	     for (n = 0; n < na; n++)
+	       c[n] = a[n] + b[n];
+	  }
+	else if (nb == 1)
+	  {
+	     GENERIC_TYPE xb = *b;
+	     for (n = 0; n < na; n++)
+	       c[n] = a[n] + xb;
+	  }
+	else /* if (na == 1) */
+	  {
+	     GENERIC_TYPE xa = *a;
+	     for (n = 0; n < nb; n++)
+	       c[n] = xa + b[n];
+	  }
+#endif
+	break;
+
+      case SLANG_MINUS:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+	for (n = 0; n < n_max; n++)
+	  {
+	     c[n] = (*a - *b); a += da; b += db;
+	  }
+#else
+	if (na == nb)
+	  {
+	     for (n = 0; n < na; n++)
+	       c[n] = a[n] - b[n];
+	  }
+	else if (nb == 1)
+	  {
+	     GENERIC_TYPE xb = *b;
+	     for (n = 0; n < na; n++)
+	       c[n] = a[n] - xb;
+	  }
+        else /* if (na == 1) */
+	  {
+	     GENERIC_TYPE xa = *a;
+	     for (n = 0; n < nb; n++)
+	       c[n] = xa - b[n];
+	  }
+#endif
+	break;
+
+      case SLANG_TIMES:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+	for (n = 0; n < n_max; n++)
+	  {
+	     c[n] = (*a * *b); a += da; b += db;
+	  }
+#else
+	if (na == nb)
+	  {
+	     for (n = 0; n < na; n++)
+	       c[n] = a[n] * b[n];
+	  }
+	else if (nb == 1)
+	  {
+	     GENERIC_TYPE xb = *b;
+	     for (n = 0; n < na; n++)
+	       c[n] = a[n] * xb;
+	  }
+        else /* if (na == 1) */
+	  {
+	     GENERIC_TYPE xa = *a;
+	     for (n = 0; n < nb; n++)
+	       c[n] = xa * b[n];
+	  }
+#endif
+	break;
+
+      case SLANG_DIVIDE:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+	for (n = 0; n < 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 < 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 < na; n++)
+	       c[n] = a[n] / xb;
+	  }
+        else /* if (na == 1) */
+	  {
+	     GENERIC_TYPE xa = *a;
+	     for (n = 0; n < 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 < 2
+	for (n = 0; n < 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 < 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 < na; n++)
+	       c[n] = MOD_FUNCTION(a[n],xb);
+	  }
+        else /* if (na == 1) */
+	  {
+	     GENERIC_TYPE xa = *a;
+	     for (n = 0; n < 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 < 2
+	for (n = 0; n < n_max; n++)
+	  {
+	     c[n] = (*a & *b); a += da; b += db;
+	  }
+#else
+	if (na == nb)
+	  {
+	     for (n = 0; n < na; n++)
+	       c[n] = a[n] & b[n];
+	  }
+	else if (nb == 1)
+	  {
+	     GENERIC_TYPE xb = *b;
+	     for (n = 0; n < na; n++)
+	       c[n] = a[n] & xb;
+	  }
+        else /* if (na == 1) */
+	  {
+	     GENERIC_TYPE xa = *a;
+	     for (n = 0; n < nb; n++)
+	       c[n] = xa & b[n];
+	  }
+#endif
+	break;
+
+      case SLANG_BXOR:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+	for (n = 0; n < n_max; n++)
+	  {
+	     c[n] = (*a ^ *b); a += da; b += db;
+	  }
+#else
+	if (na == nb)
+	  {
+	     for (n = 0; n < na; n++)
+	       c[n] = a[n] ^ b[n];
+	  }
+	else if (nb == 1)
+	  {
+	     GENERIC_TYPE xb = *b;
+	     for (n = 0; n < na; n++)
+	       c[n] = a[n] ^ xb;
+	  }
+        else /* if (na == 1) */
+	  {
+	     GENERIC_TYPE xa = *a;
+	     for (n = 0; n < nb; n++)
+	       c[n] = xa ^ b[n];
+	  }
+#endif
+	break;
+
+      case SLANG_BOR:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+	for (n = 0; n < n_max; n++)
+	  {
+	     c[n] = (*a | *b); a += da; b += db;
+	  }
+#else
+	if (na == nb)
+	  {
+	     for (n = 0; n < na; n++)
+	       c[n] = a[n] | b[n];
+	  }
+	else if (nb == 1)
+	  {
+	     GENERIC_TYPE xb = *b;
+	     for (n = 0; n < na; n++)
+	       c[n] = a[n] | xb;
+	  }
+        else /* if (na == 1) */
+	  {
+	     GENERIC_TYPE xa = *a;
+	     for (n = 0; n < nb; n++)
+	       c[n] = xa | b[n];
+	  }
+#endif
+	break;
+
+      case SLANG_SHL:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+	for (n = 0; n < n_max; n++)
+	  {
+	     c[n] = (*a << *b); a += da; b += db;
+	  }
+#else
+	if (na == nb)
+	  {
+	     for (n = 0; n < na; n++)
+	       c[n] = a[n] << b[n];
+	  }
+	else if (nb == 1)
+	  {
+	     GENERIC_TYPE xb = *b;
+	     for (n = 0; n < na; n++)
+	       c[n] = a[n] << xb;
+	  }
+        else /* if (na == 1) */
+	  {
+	     GENERIC_TYPE xa = *a;
+	     for (n = 0; n < nb; n++)
+	       c[n] = xa << b[n];
+	  }
+#endif
+	break;
+
+      case SLANG_SHR:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+	for (n = 0; n < n_max; n++)
+	  {
+	     c[n] = (*a >> *b); a += da; b += db;
+	  }
+#else
+	if (na == nb)
+	  {
+	     for (n = 0; n < na; n++)
+	       c[n] = a[n] >> b[n];
+	  }
+	else if (nb == 1)
+	  {
+	     GENERIC_TYPE xb = *b;
+	     for (n = 0; n < na; n++)
+	       c[n] = a[n] >> xb;
+	  }
+        else /* if (na == 1) */
+	  {
+	     GENERIC_TYPE xa = *a;
+	     for (n = 0; n < nb; n++)
+	       c[n] = xa >> b[n];
+	  }
+#endif
+	break;
+#endif				       /* GENERIC_BIT_OPERATIONS */
+      case SLANG_EQ:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+	for (n = 0; n < n_max; n++)
+	  {
+	     cc[n] = (*a == *b); a += da; b += db;
+	  }
+#else
+	if (na == nb)
+	  {
+	     for (n = 0; n < na; n++)
+	       cc[n] = (a[n] == b[n]);
+	  }
+	else if (nb == 1)
+	  {
+	     GENERIC_TYPE xb = *b;
+	     for (n = 0; n < na; n++)
+	       cc[n] = (a[n] == xb);
+	  }
+        else /* if (na == 1) */
+	  {
+	     GENERIC_TYPE xa = *a;
+	     for (n = 0; n < nb; n++)
+	       cc[n] = (xa == b[n]);
+	  }
+#endif
+	break;
+
+      case SLANG_NE:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+	for (n = 0; n < n_max; n++)
+	  {
+	     cc[n] = (*a != *b); a += da; b += db;
+	  }
+#else
+	if (na == nb)
+	  {
+	     for (n = 0; n < na; n++)
+	       cc[n] = (a[n] != b[n]);
+	  }
+	else if (nb == 1)
+	  {
+	     GENERIC_TYPE xb = *b;
+	     for (n = 0; n < na; n++)
+	       cc[n] = (a[n] != xb);
+	  }
+        else /* if (na == 1) */
+	  {
+	     GENERIC_TYPE xa = *a;
+	     for (n = 0; n < nb; n++)
+	       cc[n] = (xa != b[n]);
+	  }
+#endif
+	break;
+
+      case SLANG_GT:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+	for (n = 0; n < n_max; n++)
+	  {
+	     cc[n] = (*a > *b); a += da; b += db;
+	  }
+#else
+	if (na == nb)
+	  {
+	     for (n = 0; n < na; n++)
+	       cc[n] = (a[n] > b[n]);
+	  }
+	else if (nb == 1)
+	  {
+	     GENERIC_TYPE xb = *b;
+	     for (n = 0; n < na; n++)
+	       cc[n] = (a[n] > xb);
+	  }
+        else /* if (na == 1) */
+	  {
+	     GENERIC_TYPE xa = *a;
+	     for (n = 0; n < nb; n++)
+	       cc[n] = (xa > b[n]);
+	  }
+#endif
+	break;
+
+      case SLANG_GE:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+	for (n = 0; n < n_max; n++)
+	  {
+	     cc[n] = (*a >= *b); a += da; b += db;
+	  }
+#else
+	if (na == nb)
+	  {
+	     for (n = 0; n < na; n++)
+	       cc[n] = (a[n] >= b[n]);
+	  }
+	else if (nb == 1)
+	  {
+	     GENERIC_TYPE xb = *b;
+	     for (n = 0; n < na; n++)
+	       cc[n] = (a[n] >= xb);
+	  }
+        else /* if (na == 1) */
+	  {
+	     GENERIC_TYPE xa = *a;
+	     for (n = 0; n < nb; n++)
+	       cc[n] = (xa >= b[n]);
+	  }
+#endif
+	break;
+
+      case SLANG_LT:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+	for (n = 0; n < n_max; n++)
+	  {
+	     cc[n] = (*a < *b); a += da; b += db;
+	  }
+#else
+	if (na == nb)
+	  {
+	     for (n = 0; n < na; n++)
+	       cc[n] = (a[n] < b[n]);
+	  }
+	else if (nb == 1)
+	  {
+	     GENERIC_TYPE xb = *b;
+	     for (n = 0; n < na; n++)
+	       cc[n] = (a[n] < xb);
+	  }
+        else /* if (na == 1) */
+	  {
+	     GENERIC_TYPE xa = *a;
+	     for (n = 0; n < nb; n++)
+	       cc[n] = (xa < b[n]);
+	  }
+#endif
+	break;
+
+      case SLANG_LE:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+	for (n = 0; n < n_max; n++)
+	  {
+	     cc[n] = (*a <= *b); a += da; b += db;
+	  }
+#else
+	if (na == nb)
+	  {
+	     for (n = 0; n < na; n++)
+	       cc[n] = (a[n] <= b[n]);
+	  }
+	else if (nb == 1)
+	  {
+	     GENERIC_TYPE xb = *b;
+	     for (n = 0; n < na; n++)
+	       cc[n] = (a[n] <= xb);
+	  }
+        else /* if (na == 1) */
+	  {
+	     GENERIC_TYPE xa = *a;
+	     for (n = 0; n < nb; n++)
+	       cc[n] = (xa <= b[n]);
+	  }
+#endif
+	break;
+
+      case SLANG_OR:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+	for (n = 0; n < n_max; n++)
+	  {
+	     cc[n] = (*a || *b); a += da; b += db;
+	  }
+#else
+	if (na == nb)
+	  {
+	     for (n = 0; n < na; n++)
+	       cc[n] = (a[n] || b[n]);
+	  }
+	else if (nb == 1)
+	  {
+	     GENERIC_TYPE xb = *b;
+	     for (n = 0; n < na; n++)
+	       cc[n] = (a[n] || xb);
+	  }
+        else /* if (na == 1) */
+	  {
+	     GENERIC_TYPE xa = *a;
+	     for (n = 0; n < nb; n++)
+	       cc[n] = (xa || b[n]);
+	  }
+#endif
+	break;
+
+      case SLANG_AND:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+	for (n = 0; n < n_max; n++)
+	  {
+	     cc[n] = (*a && *b); a += da; b += db;
+	  }
+#else
+	if (na == nb)
+	  {
+	     for (n = 0; n < na; n++)
+	       cc[n] = (a[n] && b[n]);
+	  }
+	else if (nb == 1)
+	  {
+	     GENERIC_TYPE xb = *b;
+	     for (n = 0; n < na; n++)
+	       cc[n] = (a[n] && xb);
+	  }
+        else /* if (na == 1) */
+	  {
+	     GENERIC_TYPE xa = *a;
+	     for (n = 0; n < nb; n++)
+	       cc[n] = (xa && 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 < na; n++) b[n] = (a[n] + 1);
+	break;
+      case SLANG_MINUSMINUS:
+	for (n = 0; n < na; n++) b[n] = (a[n] - 1);
+	break;
+      case SLANG_CHS:
+	for (n = 0; n < na; n++) b[n] = (GENERIC_TYPE) -(a[n]);
+	break;
+      case SLANG_SQR:
+	for (n = 0; n < na; n++) b[n] = (a[n] * a[n]);
+	break;
+      case SLANG_MUL2:
+	for (n = 0; n < na; n++) b[n] = (2 * a[n]);
+	break;
+      case SLANG_ABS:
+	for (n = 0; n < na; n++) b[n] = ABS_FUNCTION (a[n]);
+	break;
+      case SLANG_SIGN:
+	ib = (int *) bp;
+	for (n = 0; n < na; n++)
+	  ib[n] = SIGN_FUNCTION(a[n]);
+	break;
+
+#ifdef GENERIC_BIT_OPERATIONS
+      case SLANG_NOT:
+	for (n = 0; n < na; n++) b[n] = !(a[n]);
+	break;
+      case SLANG_BNOT:
+	for (n = 0; n < 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 & 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 << b);
+      case SLANG_SHR:
+	return PUSH_SCALAR_OBJ_FUN (a >> b);
+#endif
+      case SLANG_GT: return SLclass_push_char_obj (SLANG_CHAR_TYPE, (char)(a > b));
+      case SLANG_LT: return SLclass_push_char_obj (SLANG_CHAR_TYPE, (char)(a < b));
+      case SLANG_GE: return SLclass_push_char_obj (SLANG_CHAR_TYPE, (char)(a >= b));
+      case SLANG_LE: return SLclass_push_char_obj (SLANG_CHAR_TYPE, (char)(a <= 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 && 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 > 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 "slinclud.h"
+
+#define SL_APP_WANTS_FOREACH
+#include "slang.h"
+#include "_slang.h"
+
+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, "Context requires an array.  Scalar not converted");
+	     return -1;
+	  }
+	break;
+     }
+
+   if (NULL == (at = SLang_create_array ((unsigned char) type, 0, NULL, &one, 1)))
+     return -1;
+
+   if (-1 == at->cl->cl_apop ((unsigned char) type, at->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->dims;
+   num_dims = at->num_dims;
+
+   for (i = 0; i < num_dims; i++)
+     {
+	int d = dims[i];
+
+	if (d < 0)
+	  d = d + max_dims[i];
+
+	ofs = ofs * (unsigned int)max_dims [i] + (unsigned int) d;
+     }
+
+   return (VOID_STAR) ((char *)at->data + (ofs * at->sizeof_type));
+}
+
+static VOID_STAR get_data_addr (SLang_Array_Type *at, int *dims)
+{
+   VOID_STAR data;
+
+   data = at->data;
+   if (data == NULL)
+     {
+	SLang_verror (SL_UNKNOWN_ERROR, "Array has no data");
+	return NULL;
+     }
+
+   data = (*at->index_fun) (at, dims);
+
+   if (data == NULL)
+     {
+	SLang_verror (SL_UNKNOWN_ERROR, "Unable to access array element");
+	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->cl_class_type == SLANG_CLASS_TYPE_SCALAR)
+       || (cl->cl_class_type == SLANG_CLASS_TYPE_VECTOR))
+     return;
+
+   f = cl->cl_destroy;
+   sizeof_type = cl->cl_sizeof_type;
+   type = cl->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->cl->cl_destroy) (at->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->cl->cl_init_array_object) (at->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->num_elements == 0)
+     return 0;
+
+   max_dims = at->dims;
+   num_dims = at->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->num_refs > 1)
+     {
+	at->num_refs -= 1;
+	return;
+     }
+
+   data = at->data;
+   flags = at->flags;
+
+   if (flags & SLARR_DATA_VALUE_IS_INTRINSIC)
+     return;			       /* not to be freed */
+
+   if (flags & 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 > SLARRAY_MAX_DIMS)
+     {
+	SLang_verror (SL_NOT_IMPLEMENTED, "%u dimensional arrays are not supported", num_dims);
+	return NULL;
+     }
+
+   for (i = 0; i < num_dims; i++)
+     {
+	if (dims[i] < 0)
+	  {
+	     SLang_verror (SL_INVALID_PARM, "Size of array dim %u is less than 0", 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->data_type = type;
+   at->cl = cl;
+   at->num_dims = num_dims;
+   at->num_refs = 1;
+
+   if (read_only) at->flags = SLARR_DATA_VALUE_IS_READ_ONLY;
+   switch (cl->cl_class_type)
+     {
+      case SLANG_CLASS_TYPE_VECTOR:
+      case SLANG_CLASS_TYPE_SCALAR:
+	break;
+
+      default:
+	at->flags |= SLARR_DATA_VALUE_IS_POINTER;
+     }
+
+   num_elements = 1;
+   for (i = 0; i < num_dims; i++)
+     {
+	at->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 < SLARRAY_MAX_DIMS)
+     at->dims[i++] = 1;
+
+   at->num_elements = num_elements;
+   at->index_fun = linear_get_data_addr;
+   at->sizeof_type = sizeof_type = cl->cl_sizeof_type;
+
+   if (data != NULL)
+     {
+	at->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->data = data;
+
+   if ((cl->cl_init_array_object != NULL)
+       && (-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 > SLARRAY_MAX_DIMS)
+       || (name == NULL)
+       || (data == NULL))
+     {
+	SLang_verror (SL_INVALID_PARM, "Unable to create intrinsic array");
+	return -1;
+     }
+
+   va_start (ap, num_dims);
+   for (i = 0; i < 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->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 > SLARRAY_MAX_DIMS)
+     {
+	SLang_verror (SL_INVALID_PARM, "Array size not supported");
+	return -1;
+     }
+
+   n = num_dims;
+   while (n != 0)
+     {
+	n--;
+	if (-1 == SLang_pop_integer (&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->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->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 (&type))
+     return -1;
+
+   anew = (_SLclass_get_class (type))->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->cl;
+   if ((at->flags & SLARR_DATA_VALUE_IS_POINTER)
+       && (*(VOID_STAR *) data == NULL))
+     {
+	if (allow_null)
+	  return SLang_push_null ();
+
+	SLang_verror (SL_VARIABLE_UNINITIALIZED,
+		      "%s array has unitialized element", cl->cl_name);
+	return -1;
+     }
+
+   return (*cl->cl_apush)(at->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->flags & SLARR_DATA_VALUE_IS_RANGE))
+     return 0;
+
+   range = (SLarray_Range_Array_Type *) at->data;
+   xmin = range->first_index;
+   dx = range->delta;
+
+   imax = at->num_elements;
+   data = (int *) SLmalloc ((imax + 1) * sizeof (int));
+   if (data == NULL)
+     return -1;
+
+   for (i = 0; i < imax; i++)
+     {
+	data [i] = xmin;
+	xmin += dx;
+     }
+
+   SLfree ((char *) range);
+   at->data = (VOID_STAR) data;
+   at->flags &= ~SLARR_DATA_VALUE_IS_RANGE;
+   at->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 < num_indices; i++)
+     {
+	obj = index_objs + i;
+	if (obj->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 >= SLARRAY_MAX_DIMS)
+     {
+	SLang_verror (SL_INVALID_PARM, "too many indices for array");
+	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->data_type == SLANG_ARRAY_TYPE)
+	  {
+	     SLang_Array_Type *at = obj->v.array_val;
+
+	     if (at->num_dims == 1)
+	       {
+		  if ((num_indices == 1)
+		      && (0 == (at->flags & SLARR_DATA_VALUE_IS_RANGE)))
+		    *is_index_array = 1;
+	       }
+	     else
+	       {
+		  SLang_verror (SL_INVALID_PARM, "expecting a 1-d index array");
+		  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->num_elements;
+   indices = (int *) ind_at->data;
+   indices_max = indices + ind_at->num_elements;
+
+   while (indices < indices_max)
+     {
+	unsigned int d;
+
+	d = (unsigned int) *indices++;
+	if (d >= num_elements)
+	  {
+	     SLang_verror (SL_INVALID_PARM,
+			   "index-array is out of range");
+	     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->data_type;
+   cl = at->cl;
+
+   while (n != 0)
+     {
+	if (*(VOID_STAR *)dest_data != NULL)
+	  {
+	     (*cl->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->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->data_type, 0, NULL, ind_at->dims, 1)))
+     return -1;
+
+   /* Since the index array is linear, I can address it directly */
+   indices = (int *) ind_at->data;
+   indices_max = indices + ind_at->num_elements;
+
+   src_data = (unsigned char *) at->data;
+   new_data = (unsigned char *) new_at->data;
+   sizeof_type = new_at->sizeof_type;
+   is_ptr = (new_at->flags & SLARR_DATA_VALUE_IS_POINTER);
+
+   while (indices < 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->num_dims)
+     {
+	SLang_verror (SL_INVALID_PARM, "Array requires %u indices", at->num_dims);
+	return -1;
+     }
+
+   *is_array = 0;
+   total_num_elements = 1;
+   for (i = 0; i < num_indices; i++)
+     {
+	int max_index, min_index;
+	SLang_Object_Type *obj;
+	int at_dims_i;
+
+	at_dims_i = at->dims[i];
+	obj = index_objs + i;
+	range_delta_buf [i] = 0;
+
+	if (obj->data_type == SLANG_INT_TYPE)
+	  {
+	     range_buf [i] = min_index = max_index = obj->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->v.array_val;
+
+	     if (ind_at->flags & SLARR_DATA_VALUE_IS_RANGE)
+	       {
+		  SLarray_Range_Array_Type *r;
+		  int delta;
+		  int first_index, last_index;
+
+		  r = (SLarray_Range_Array_Type *) ind_at->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->first_index) < 0)
+		    {
+		       if (at_dims_i != 0)
+			 first_index = (at_dims_i + first_index) % at_dims_i;
+		    }
+
+		  if ((last_index = r->last_index) < 0)
+		    {
+		       if (at_dims_i != 0)
+			 last_index = (at_dims_i + last_index) % at_dims_i;
+		    }
+
+		  delta = r->delta;
+
+		  range_delta_buf [i] = delta;
+		  range_buf[i] = first_index;
+
+		  if (delta > 0)
+		    {
+		       if (first_index > last_index)
+			 max_dims[i] = min_index = max_index = 0;
+		       else
+			 {
+			    max_index = min_index = first_index;
+			    while (max_index + delta <= last_index)
+			      max_index += delta;
+			    max_dims [i] = 1 + (max_index - min_index) / delta;
+			 }
+		    }
+		  else
+		    {
+		       if (first_index < last_index)
+			 max_dims[i] = min_index = max_index = 0;
+		       else
+			 {
+			    min_index = max_index = first_index;
+			    while (min_index + delta >= 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->num_elements))
+		    {
+		       total_num_elements = 0;
+		       break;
+		    }
+
+		  tmp = (int *) ind_at->data;
+		  tmp_max = tmp + ind_at->num_elements;
+		  index_data [i] = tmp;
+
+		  min_index = max_index = *tmp;
+		  while (tmp < tmp_max)
+		    {
+		       if (max_index > *tmp)
+			 max_index = *tmp;
+		       if (min_index < *tmp)
+			 min_index = *tmp;
+
+		       tmp++;
+		    }
+	       }
+	  }
+
+	if ((at_dims_i == 0) && (max_dims[i] == 0))
+	  {
+	     total_num_elements = 0;
+	     continue;
+	  }
+
+	if (max_index < 0)
+	  max_index += at_dims_i;
+	if (min_index < 0)
+	  min_index += at_dims_i;
+
+	if ((min_index < 0) || (min_index >= at_dims_i)
+	    || (max_index < 0) || (max_index >= at_dims_i))
+	  {
+	     SLang_verror (SL_INVALID_PARM, "Array index %u ([%d:%d]) out of allowed range [0->%d]",
+			   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, &num_elements, &is_array,
+				       is_dim_array))
+     return -1;
+
+   is_ptr = (at->flags & SLARR_DATA_VALUE_IS_POINTER);
+   sizeof_type = at->sizeof_type;
+
+   cl = _SLclass_get_class (at->data_type);
+
+   if ((is_array == 0) && (num_elements == 1))
+     {
+	new_data = (char *)cl->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->data_type, 0, NULL, &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->data;
+     }
+
+   SLMEMSET((char *) map_indices, 0, sizeof(map_indices));
+   do
+     {
+	for (i = 0; i < 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 < num_indices; i++)
+	  {
+	     if (is_dim_array[i]) /* was: (max_dims[i] > 1) */
+	       {
+		  new_at->dims[num_dims] = max_dims[i];
+		  num_dims++;
+	       }
+	  }
+
+	if (num_dims != 0) new_at->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 && (*(VOID_STAR *)new_data == NULL))
+     ret = SLang_push_null ();
+   else
+     {
+	ret = (*cl->cl_apush) (at->data_type, (VOID_STAR)new_data);
+	(*cl->cl_adestroy) (at->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, &ilen, 1);
+   if (at == NULL)
+     return -1;
+
+   memcpy ((char *)at->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 (&at, SLANG_UCHAR_TYPE))
+     return -1;
+
+   ret = 0;
+
+   if (NULL == (*sp = SLang_create_nslstring ((char *) at->data, at->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 (&at, SLANG_UCHAR_TYPE))
+     return -1;
+
+   ret = 0;
+
+   if (NULL == (*bs = SLbstring_create ((unsigned char *) at->data, at->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 > SLARRAY_MAX_DIMS)
+     {
+	SLang_verror (SL_INVALID_PARM, "Number of dims must be less than %d", SLARRAY_MAX_DIMS);
+	return -1;
+     }
+
+   if (-1 == pop_array (&at, 1))
+     return -1;
+
+   if (-1 == pop_indices (index_objs, num_indices, &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 < 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 (&bs))
+	       return -1;
+
+	     ret = SLang_push_bstring (bs);
+	     SLbstring_free (bs);
+	     return ret;
+	  }
+
+	if (-1 == pop_array_as_string (&str))
+	  return -1;
+	return _SLang_push_slstring (str);   /* frees s upon error */
+     }
+
+   if (-1 == SLang_pop_integer (&i))
+     return -1;
+
+   if (i < 0) i = i + (int)len;
+   if ((unsigned int) i > 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 (&bs))
+	       return -1;
+
+	     if (NULL == (s = SLbstring_get_pointer (bs, &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 (&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)->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->cl_data_type;
+   if (-1 == SLclass_typecast (data_type, 1, allow_array))
+     return -1;
+
+   if ((data_type != SLANG_ARRAY_TYPE)
+       && (data_type != SLANG_ANY_TYPE)
+       && (SLANG_ARRAY_TYPE == SLang_peek_at_stack ()))
+     {
+	if (-1 == SLang_pop_array (&at, 0))
+	  return -1;
+
+	if ((at->num_elements != num_elements)
+#if 0
+	    || (at->num_dims != 1)
+#endif
+	    )
+	  {
+	     SLang_verror (SL_TYPE_MISMATCH, "Array size is inappropriate for use with index-array");
+	     SLang_free_array (at);
+	     return -1;
+	  }
+
+	*data_to_put = (char *) at->data;
+	*data_increment = at->sizeof_type;
+	*at_ptr = at;
+	return 0;
+     }
+
+   *data_increment = 0;
+   *data_to_put = (char *) cl->cl_transfer_buf;
+
+   if (-1 == (*cl->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, &num_elements, &is_array,
+				       is_dim_array))
+     return -1;
+
+   cl = at->cl;
+
+   if (-1 == aput_get_array_to_put (cl, num_elements, is_array,
+				    &bt, &data_to_put, &data_increment))
+     return -1;
+
+   sizeof_type = at->sizeof_type;
+   is_ptr = (at->flags & SLARR_DATA_VALUE_IS_POINTER);
+
+   ret = -1;
+
+   SLMEMSET((char *) map_indices, 0, sizeof(map_indices));
+   if (num_elements) do
+     {
+	for (i = 0; i < 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->cl_destroy) (cl->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->sizeof_type;
+
+   cl = at->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->num_elements, 1,
+				    &bt, &data_to_put, &data_increment))
+     return -1;
+
+   /* Since the index array is linear, I can address it directly */
+   indices = (int *) ind_at->data;
+   indices_max = indices + ind_at->num_elements;
+
+   is_ptr = (at->flags & SLARR_DATA_VALUE_IS_POINTER);
+   dest_data = (char *) at->data;
+
+   ret = -1;
+   while (indices < 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->cl_destroy) (cl->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)->cl_aput))
+	  return (*aput_fun) (type, num_indices);
+	break;
+     }
+
+   if (-1 == SLang_pop_array (&at, 0))
+     return -1;
+
+   if (at->flags & SLARR_DATA_VALUE_IS_READ_ONLY)
+     {
+	SLang_verror (SL_READONLY_ERROR, "%s Array is read-only",
+		      SLclass_get_datatype_name (at->data_type));
+	SLang_free_array (at);
+	return -1;
+     }
+
+   if (-1 == pop_indices (index_objs, num_indices, &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, &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 (&cmp)))
+     {
+	/* DO not allow qsort to loop forever.  Return something meaningful */
+	if (*a > *b) return 1;
+	if (*a < *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->cl;
+
+   if ((SLang_Error == 0)
+       && (NULL != (a_data = get_data_addr (Sort_Array, a)))
+       && (NULL != (b_data = get_data_addr (Sort_Array, b))))
+     {
+	int cmp;
+
+	if ((Sort_Array->flags & SLARR_DATA_VALUE_IS_POINTER)
+	    && ((*(VOID_STAR *) a_data == NULL) || (*(VOID_STAR *) a_data == NULL)))
+	  {
+	     SLang_verror (SL_VARIABLE_UNINITIALIZED,
+			   "%s array has unitialized element", cl->cl_name);
+	  }
+	else if (0 == (*cl->cl_cmp)(Sort_Array->data_type, a_data, b_data, &cmp))
+	  return cmp;
+     }
+       
+       
+   if (*a > *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, "array_sort is not recursive");
+	return;
+     }
+
+   n = at_str->num_elements;
+
+   if (at_str->num_dims != 1)
+     {
+	SLang_verror (SL_INVALID_PARM, "sort is restricted to 1 dim arrays");
+	return;
+     }
+
+   dims [0] = n;
+
+   if (NULL == (ind_at = SLang_create_array (SLANG_INT_TYPE, 0, NULL, dims, 1)))
+     return;
+
+   indx = (int *) ind_at->data;
+   for (i = 0; i < n; i++) indx[i] = i;
+
+   if (n > 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 (&at, 1))
+	  return;
+     }
+   else
+     {
+	sort_fun = builtin_sort_cmp_fun;
+	if (-1 == SLang_pop_array (&at, 1))
+	  return;
+	if (at->cl->cl_cmp == NULL)
+	  {
+	     SLang_verror (SL_NOT_IMPLEMENTED, 
+			   "%s does not have a predefined sorting method",
+			   at->cl->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, &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->num_elements * at->sizeof_type;
+   bs = SLbstring_create ((unsigned char *)at->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 (&s)) return;
+
+   if (-1 == SLang_pop_array (&at, 0))
+     goto free_and_return;
+
+   if (at->data_type != SLANG_CHAR_TYPE)
+     {
+	SLang_doerror("Operation requires character array");
+	goto free_and_return;
+     }
+
+   n = strlen (s);
+   ndim = at->num_elements;
+   if (n > ndim)
+     {
+	SLang_doerror("String too big to init array");
+	goto free_and_return;
+     }
+
+   strncpy((char *) at->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 (&at, 1))
+     return;
+
+   num_dims = (int)at->num_dims;
+
+   if (NULL != (bt = SLang_create_array (SLANG_INT_TYPE, 0, NULL, &num_dims, 1)))
+     {
+	int *bdata;
+	int i;
+	int *a_dims;
+
+	a_dims = at->dims;
+	bdata = (int *) bt->data;
+	for (i = 0; i < num_dims; i++) bdata [i] = a_dims [i];
+
+	if (0 == SLang_push_array (bt, 1))
+	  {
+	     (void) SLang_push_integer ((int) at->num_dims);
+	     (void) _SLang_push_datatype (at->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->data;
+
+   if (d < 0)
+     d += at->dims[0];
+
+   value = r->first_index + d * r->delta;
+   return (VOID_STAR) &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, "range-array increment must be non-zero");
+	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->delta = delta;
+   dims = 0;
+
+   if (xminptr != NULL)
+     data->first_index = *xminptr;
+   else
+     data->first_index = 0;
+
+   if (xmaxptr != NULL)
+     data->last_index = *xmaxptr;
+   else
+     data->last_index = -1;
+
+/*   if ((xminptr != NULL) && (xmaxptr != NULL))
+     { */
+	idims = 1 + (data->last_index - data->first_index) / delta;
+	if (idims > 0)
+	  dims = idims;
+    /* } */
+
+   if (NULL == (at = SLang_create_array (SLANG_INT_TYPE, 0, (VOID_STAR) data, &dims, 1)))
+     return NULL;
+
+   at->index_fun = range_get_data_addr;
+   at->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, "range-array has unknown size");
+	return NULL;
+     }
+   xmin = *xminptr;
+   xmax = *xmaxptr;
+   if (dxptr == NULL) dx = 1.0;
+   else dx = *dxptr;
+
+   if (dx == 0.0)
+     {
+	SLang_doerror ("range-array increment must be non-zero");
+	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 < 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 <= 0)
+     n = 0;
+   else
+     {
+	double last = xmin + (n-1) * dx;
+
+	if (dx > 0.0)
+	  {
+	     if (last >= xmax)
+	       n -= 1;
+	  }
+	else if (last <= xmax)
+	  n -= 1;
+     }
+
+   dims = n;
+   if (NULL == (at = SLang_create_array1 (type, 0, NULL, &dims, 1, 1)))
+     return NULL;
+
+   if (type == SLANG_DOUBLE_TYPE)
+     {
+	double *ptr;
+
+	ptr = (double *) at->data;
+
+	for (i = 0; i < n; i++)
+	  ptr[i] = xmin + i * dx;
+     }
+   else
+     {
+	float *ptr;
+
+	ptr = (float *) at->data;
+
+	for (i = 0; i < 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 ("wrong number of arguments to __implicit_inline_array");
+	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 < 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] ? &double_vals[0] : NULL),
+					  (has_vals[1] ? &double_vals[1] : NULL),
+					  (has_vals[2] ? &double_vals[2] : NULL));
+   else
+#endif
+     at = inline_implicit_int_array ((has_vals[0] ? &int_vals[0] : NULL),
+				     (has_vals[1] ? &int_vals[1] : NULL),
+				     (has_vals[2] ? &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 (&bt, 1))
+	  goto free_and_return;
+
+	arrays[i] = bt;
+	num_elements += (int)bt->num_elements;
+     }
+
+   type = arrays[0]->data_type;
+   max_dims = min_dims = arrays[0]->num_dims;
+   min_rows = max_rows = arrays[0]->dims[0];
+
+   for (i = 1; i < count; i++)
+     {
+	SLang_Array_Type *ct;
+	int num;
+
+	bt = arrays[i];
+
+	num = bt->num_dims;
+	if (num > max_dims) max_dims = num;
+	if (num < min_dims) min_dims = num;
+
+	num = bt->dims[0];
+	if (num > max_rows) max_rows = num;
+	if (num < min_rows) min_rows = num;
+
+	if (type == bt->data_type)
+	  continue;
+
+	if (1 != _SLarray_typecast (bt->data_type, (VOID_STAR) &bt, 1,
+				    type, (VOID_STAR) &ct, 1))
+	  goto free_and_return;
+
+	SLang_free_array (bt);
+	arrays [i] = ct;
+     }
+
+   if (NULL == (at = SLang_create_array (type, 0, NULL, &num_elements, 1)))
+     goto free_and_return;
+
+   is_ptr = (at->flags & SLARR_DATA_VALUE_IS_POINTER);
+   sizeof_type = at->sizeof_type;
+   dest_data = (char *) at->data;
+
+   for (i = 0; i < count; i++)
+     {
+	bt = arrays[i];
+
+	src_data = (char *) bt->data;
+	num_elements = bt->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) && (max_dims == 1) && (min_rows == max_rows))
+     {
+	at->num_dims = 2;
+	at->dims[0] = count;
+	at->dims[1] = min_rows;
+     }
+
+   free_and_return:
+
+   for (i = 0; i < 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 > 0) && (--obj >= _SLRun_Stack))
+     {
+	this_type = obj->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, "Empty inline-arrays not supported");
+	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, &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, &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, "Binary operation on multiple arrays not implemented");
+	     return -1;
+	  }
+
+	at = *(SLang_Array_Type **) ap;
+	if (-1 == coerse_array_to_linear (at))
+	  return -1;
+	ap = at->data;
+	a_type = at->data_type;
+	na = at->num_elements;
+     }
+   else
+     {
+	at = NULL;
+     }
+
+   if (b_type == SLANG_ARRAY_TYPE)
+     {
+	if (nb != 1)
+	  {
+	     SLang_verror (SL_NOT_IMPLEMENTED, "Binary operation on multiple arrays not implemented");
+	     return -1;
+	  }
+
+	bt = *(SLang_Array_Type **) bp;
+	if (-1 == coerse_array_to_linear (bt))
+	  return -1;
+	bp = bt->data;
+	b_type = bt->data_type;
+	nb = bt->num_elements;
+     }
+   else
+     {
+	bt = NULL;
+     }
+
+   if ((at != NULL) && (bt != NULL))
+     {
+	num_dims = at->num_dims;
+
+	if (num_dims != bt->num_dims)
+	  {
+	     SLang_verror (SL_TYPE_MISMATCH, "Arrays must have same dim for binary operation");
+	     return -1;
+	  }
+
+	for (i = 0; i < num_dims; i++)
+	  {
+	     if (at->dims[i] != bt->dims[i])
+	       {
+		  SLang_verror (SL_TYPE_MISMATCH, "Arrays must be the same for binary operation");
+		  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, &c_cl, 1)))
+     return -1;
+
+   no_init = ((c_cl->cl_class_type == SLANG_CLASS_TYPE_SCALAR)
+	      || (c_cl->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) 
+	    && (at->num_refs == 1)
+	    && (at->data_type == c_cl->cl_data_type))
+	  {
+	     ct = at;
+	     ct->num_refs = 2;
+	  }
+	else if ((bt != NULL) 
+	    && (bt->num_refs == 1)
+	    && (bt->data_type == c_cl->cl_data_type))
+	  {
+	     ct = bt;
+	     ct->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->cl_data_type, 0, NULL, ct->dims, ct->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->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 (&at, 1))
+     return;
+
+   bt = NULL;
+
+   if (at->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) &at, 1,
+				  SLANG_CHAR_TYPE, (VOID_STAR) &zero, 1,
+				  (VOID_STAR) &tmp_at))
+	    goto return_error;
+
+	SLang_free_array (at);
+	at = tmp_at;
+	if (at->data_type != SLANG_CHAR_TYPE)
+	  {
+	     SLang_Error = SL_TYPE_MISMATCH;
+	     goto return_error;
+	  }
+     }
+
+   a_data = (char *) at->data;
+   num_elements = at->num_elements;
+
+   b_num = 0;
+   for (i = 0; i < num_elements; i++)
+     if (a_data[i] != 0) b_num++;
+
+   if (NULL == (bt = SLang_create_array1 (SLANG_INT_TYPE, 0, NULL, &b_num, 1, 1)))
+     goto return_error;
+
+   b_data = (int *) bt->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->data_type != SLANG_INT_TYPE)
+       || (ind_at->num_dims != 1))
+     {
+	SLang_verror (SL_TYPE_MISMATCH, "Expecting 1-d integer array");
+	return -1;
+     }
+
+   num_dims = ind_at->num_elements;
+   dims = (int *) ind_at->data;
+
+   num_elements = 1;
+   for (i = 0; i < num_dims; i++)
+     {
+	int d = dims[i];
+	if (d < 0)
+	  {
+	     SLang_verror (SL_INVALID_PARM, "reshape: dimension is less then 0");
+	     return -1;
+	  }
+
+	num_elements = (unsigned int) d * num_elements;
+     }
+
+   if ((num_elements != at->num_elements)
+       || (num_dims > SLARRAY_MAX_DIMS))
+     {
+	SLang_verror (SL_INVALID_PARM, "Unable to reshape array to specified size");
+	return -1;
+     }
+
+   for (i = 0; i < num_dims; i++)
+     at->dims [i] = dims[i];
+
+   while (i < SLARRAY_MAX_DIMS)
+     {
+	at->dims [i] = 1;
+	i++;
+     }
+
+   at->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 (&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->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 < 3)
+     {
+	SLang_verror (SL_INVALID_PARM,
+		      "Usage: array_map (Return-Type, &func, args...)");
+	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 > 0)
+     {
+	i--;
+	if (-1 == SLang_pop_array (&args[i].at, 1))
+	  {
+	     SLdo_pop_n (i + 2);
+	     goto return_error;
+	  }
+	if (args[i].at->num_elements > 1)
+	  i_control = i;
+     }
+
+   if (NULL == (nt = SLang_pop_function ()))
+     {
+	SLdo_pop_n (1);
+	goto return_error;
+     }
+
+   num_elements = args[i_control].at->num_elements;
+
+   if (-1 == _SLang_pop_datatype (&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->dims, at->num_dims)))
+	  goto return_error;
+     }
+   
+
+   for (i = 0; i < num_args; i++)
+     {
+	SLang_Array_Type *ati = args[i].at;
+	/* FIXME: Priority = low: The actual dimensions should be compared. */
+	if (ati->num_elements == num_elements)
+	  args[i].increment = ati->sizeof_type;
+	/* memset already guarantees increment to be zero */
+
+	if (ati->num_elements == 0)
+	  {
+	     SLang_verror (0, "array_map: function argument %d of %d is an empty array", 
+			   i+1, num_args);
+	     goto return_error;
+	  }
+
+	args[i].addr = (char *) ati->data;
+     }
+
+   if (at == NULL)
+     addr = NULL;
+   else
+     addr = (char *)at->data;
+
+   for (i = 0; i < num_elements; i++)
+     {
+	unsigned int j;
+
+	if (-1 == SLang_start_arg_list ())
+	  goto return_error;
+
+	for (j = 0; j < 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->cl->cl_apop (type, (VOID_STAR) addr))
+	  goto return_error;
+
+	addr += at->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 < num_args; i++)
+	  SLang_free_array (args[i].at);
+
+	SLfree ((char *) args);
+     }
+}
+
+static SLang_Intrin_Fun_Type Array_Table [] =
+{
+   MAKE_INTRINSIC_0("array_map", array_map, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_0("array_sort", sort_array, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_1("array_to_bstring", array_to_bstring, SLANG_VOID_TYPE, SLANG_ARRAY_TYPE),
+   MAKE_INTRINSIC_1("bstring_to_array", bstring_to_array, SLANG_VOID_TYPE, SLANG_BSTRING_TYPE),
+   MAKE_INTRINSIC("init_char_array", init_char_array, SLANG_VOID_TYPE, 0),
+   MAKE_INTRINSIC("array_info", array_info, SLANG_VOID_TYPE, 0),
+   MAKE_INTRINSIC("where", array_where, SLANG_VOID_TYPE, 0),
+   MAKE_INTRINSIC_2("reshape", array_reshape, SLANG_VOID_TYPE, SLANG_ARRAY_TYPE, SLANG_ARRAY_TYPE),
+   MAKE_INTRINSIC_1("_reshape", _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->data_type;
+   num_dims = at->num_dims;
+   dims = at->dims;
+
+   sprintf (buf, "%s[%d", SLclass_get_datatype_name (type), at->dims[0]);
+
+   for (i = 1; i < num_dims; i++)
+     sprintf (buf + strlen(buf), ",%d", dims[i]);
+   strcat (buf, "]");
+
+   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->cl_binary_ops;
+
+   while (ab != NULL)
+     {
+	if (ab->data_type == SLANG_ARRAY_TYPE)
+	  return 0;
+	ab = ab->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, "Operation restricted to 1 array");
+	return NULL;
+     }
+
+   a_type = at->data_type;
+   if (NULL == (f = _SLclass_get_unary_fun (op, at->cl, &b_cl, unary_type)))
+     return NULL;
+   b_type = b_cl->cl_data_type;
+
+   if (-1 == coerse_array_to_linear (at))
+     return NULL;
+
+   no_init = ((b_cl->cl_class_type == SLANG_CLASS_TYPE_SCALAR)
+	      || (b_cl->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
+       && (at->num_refs == 1)
+       && (at->data_type == b_cl->cl_data_type))
+     {
+	bt = at;
+	bt->num_refs = 2;
+     }
+   else
+#endif				       /* _SLANG_USE_TMP_OPTIMIZATION */
+     if (NULL == (bt = SLang_create_array1 (b_type, 0, NULL, at->dims, at->num_dims, no_init)))
+       return NULL;
+
+   if (1 != (*f)(op, a_type, at->data, at->num_elements, bt->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, "typecast of multiple arrays not implemented");
+	return -1;
+     }
+
+   at = *(SLang_Array_Type **) ap;
+   a_type = at->data_type;
+
+   if (a_type == b_type)
+     {
+	at->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->cl_class_type == SLANG_CLASS_TYPE_SCALAR)
+	      || (b_cl->cl_class_type == SLANG_CLASS_TYPE_VECTOR));
+
+   if (NULL == (bt = SLang_create_array1 (b_type, 0, NULL, at->dims, at->num_dims, no_init)))
+     return -1;
+
+   if (1 == (*t) (a_type, at->data, at->num_elements, b_type, bt->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->data_type;
+   num_elements = at->num_elements;
+   sizeof_type = at->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->dims, at->num_dims)))
+     {
+	SLfree (data);
+	return NULL;
+     }
+
+   a_data = (char *) at->data;
+   if (0 == (at->flags & SLARR_DATA_VALUE_IS_POINTER))
+     {
+	SLMEMCPY (data, a_data, size);
+	return bt;
+     }
+
+   SLMEMSET (data, 0, size);
+
+   cl_acopy = at->cl->cl_acopy;
+   for (i = 0; i < 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 (&ind_at, 1))
+     return -1;
+
+   if ((ind_at->data_type != SLANG_INT_TYPE)
+       || (ind_at->num_dims != 1))
+     {
+	SLang_verror (SL_TYPE_MISMATCH, "Expecting 1-d integer array");
+	goto return_error;
+     }
+
+   if (-1 == _SLang_pop_datatype (&type))
+     goto return_error;
+
+   if (NULL == (at = SLang_create_array (type, 0, NULL,
+					 (int *) ind_at->data,
+					 ind_at->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->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 ("Array_Type")))
+     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->cl_push_intrinsic = array_push_intrinsic;
+   cl->cl_dereference = array_dereference;
+   cl->cl_datatype_deref = array_datatype_deref;
+   cl->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, "Matrix multiplication not available");
+   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,
+		      "%s does not support 'foreach using' form",
+		      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 (&c->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->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->at;
+   if (at->num_elements == c->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->flags & SLARR_DATA_VALUE_IS_RANGE)
+     {
+	int d = (int) c->next_element_index;
+	data = range_get_data_addr (at, &d);
+     }
+   else
+     data = (VOID_STAR) ((char *)at->data + (c->next_element_index * at->sizeof_type));
+
+   c->next_element_index += 1;
+
+   if ((at->flags & SLARR_DATA_VALUE_IS_POINTER)
+       && (*(VOID_STAR *) data == NULL))
+     {
+	if (-1 == SLang_push_null ())
+	  return -1;
+     }
+   else if (-1 == (*at->cl->cl_apush)(at->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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+static int next_transposed_index (int *dims, int *max_dims, unsigned int num_dims)
+{
+   int i;
+
+   for (i = 0; i < (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->num_elements;
+   b_data = (VOID_STAR) SLmalloc (at->sizeof_type * num_elements);
+   if (b_data == NULL)
+     return NULL;
+
+   bt = SLang_create_array (at->data_type, 0, b_data, at->dims, 2);
+   if (bt == NULL)
+     {
+	SLfree ((char *)b_data);
+	return NULL;
+     }
+
+   bt->dims[1] = at->dims[0];
+   bt->dims[0] = at->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 "slarrfun.inc"
+
+#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 "slarrfun.inc"
+
+#define GENERIC_TYPE_A double
+#define GENERIC_TYPE_B float
+#define GENERIC_TYPE_C double
+#define INNERPROD_FUNCTION innerprod_double_float
+#include "slarrfun.inc"
+
+#define GENERIC_TYPE_A float
+#define GENERIC_TYPE_B double
+#define GENERIC_TYPE_C double
+#define INNERPROD_FUNCTION innerprod_float_double
+#include "slarrfun.inc"
+
+/* 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 "slarrfun.inc"
+
+#if SIZEOF_LONG != SIZEOF_INT
+# define GENERIC_TYPE long
+# define TRANSPOSE_2D_ARRAY transpose_longs
+# include "slarrfun.inc"
+#else
+# define transpose_longs transpose_ints
+#endif
+
+#if SIZEOF_SHORT != SIZEOF_INT
+# define GENERIC_TYPE short
+# define TRANSPOSE_2D_ARRAY transpose_shorts
+# include "slarrfun.inc"
+#else
+# define transpose_shorts transpose_ints
+#endif
+
+#define GENERIC_TYPE char
+#define TRANSPOSE_2D_ARRAY transpose_chars
+#include "slarrfun.inc"
+
+/* 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->dims;
+   num_dims = at->num_dims;
+
+   if ((at->num_elements == 0)
+       || (num_dims == 1))
+     {
+	bt = SLang_duplicate_array (at);
+	if (num_dims == 1) bt->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->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->data_type, 0, NULL, max_dims, num_dims);
+	if (bt == NULL) return NULL;
+     }
+
+   sizeof_type = at->sizeof_type;
+   is_ptr = (at->flags & SLARR_DATA_VALUE_IS_POINTER);
+
+   memset ((char *)dims, 0, sizeof(dims));
+
+   b_data = (char *) bt->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->num_dims;
+   for (i = 0; i < (int) num_dims; i++)
+     bt->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->num_dims;
+   if (num_dims == 0) 
+     {
+	SLang_verror (SL_INVALID_PARM, "Inner-product operation requires an array of at least 1 dimension.");
+	return -1;
+     }
+
+   /* An index of -1 refers to last dimension */
+   if (d == -1)
+     d += num_dims;
+   *dp = d;
+
+   if (a->num_elements == 0)
+     {				       /* [] # [] ==> [] */
+	*loops = *other = 0;
+	return 0;
+     }
+
+   *loops = a->num_elements / a->dims[d];
+
+   if (d == 0)
+     {
+	*other = *loops;  /* a->num_elements / a->dims[0]; */
+	return 0;
+     }
+   
+   *other = a->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 (&b, SLANG_DOUBLE_TYPE))
+	  return;
+	break;
+
+#if SLANG_HAS_COMPLEX
+      case SLANG_COMPLEX_TYPE:
+	if (-1 == SLang_pop_array_of_type (&b, SLANG_COMPLEX_TYPE))
+	  return;
+	break;
+#endif
+      case SLANG_FLOAT_TYPE:
+      default:
+	if (-1 == SLang_pop_array_of_type (&b, SLANG_FLOAT_TYPE))
+	  return;
+	break;
+     }
+
+   switch (SLang_peek_at_stack1 ())
+     {
+      case SLANG_DOUBLE_TYPE:
+	status = SLang_pop_array_of_type (&a, SLANG_DOUBLE_TYPE);
+	break;
+
+#if SLANG_HAS_COMPLEX
+      case SLANG_COMPLEX_TYPE:
+	status = SLang_pop_array_of_type (&a, SLANG_COMPLEX_TYPE);
+	break;
+#endif
+      case SLANG_FLOAT_TYPE:
+      default:
+	status = SLang_pop_array_of_type (&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, &ai, &a_loops, &a_stride))
+       || (-1 == get_inner_product_parms (b, &bi, &b_loops, &b_inc)))
+     {
+	SLang_verror (SL_TYPE_MISMATCH, "Array dimensions are not compatible for inner-product");
+	goto free_and_return;
+     }
+       
+   a_num_dims = a->num_dims;
+   b_num_dims = b->num_dims;
+
+   /* Coerse a 1-d vector to 2-d */
+   if ((a_num_dims == 1) 
+       && (b_num_dims == 2)
+       && (a->num_elements))
+     {
+	a_num_dims = 2;
+	ai = 1;
+	a_loops = a->num_elements;
+	a_stride = 1;
+     }
+
+   if ((ai_dims = a->dims[ai]) != b->dims[bi])
+     {
+	SLang_verror (SL_TYPE_MISMATCH, "Array dimensions are not compatible for inner-product");
+	goto free_and_return;
+     }
+
+   num_dims = a_num_dims + b_num_dims - 2;
+   if (num_dims > SLARRAY_MAX_DIMS)
+     {
+	SLang_verror (SL_NOT_IMPLEMENTED,
+		      "Inner-product result exceed max allowed dimensions");
+	goto free_and_return;
+     }
+
+   if (num_dims)
+     {
+	j = 0;
+	for (i = 0; i < (int)a_num_dims; i++)
+	  if (i != ai) dims [j++] = a->dims[i];
+	for (i = 0; i < (int)b_num_dims; i++)
+	  if (i != bi) dims [j++] = b->dims[i];
+     }
+   else
+     {
+	/* a scalar */
+	num_dims = 1;
+	dims[0] = 1;
+     }
+
+   c_type = 0; fun = NULL;
+   switch (a->data_type)
+     {
+      case SLANG_FLOAT_TYPE:
+	switch (b->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->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->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("transpose", 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, "__SLARRAY__"))
+     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 "inline" 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->dims[0];
+   nc = at->dims[1];
+
+   a_data = (GENERIC_TYPE *) at->data;
+   b_data = (GENERIC_TYPE *) bt->data;
+
+   for (i = 0; i < nr; i++)
+     {
+	GENERIC_TYPE *offset = b_data + i;
+	int j;
+	for (j = 0; j < 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->data;
+   b = (GENERIC_TYPE_B *) bt->data;
+   a = (GENERIC_TYPE_A *) at->data;
+   
+   while (a_loops--)
+     {
+	GENERIC_TYPE_B *bb;
+	unsigned int j;
+
+	bb = b;
+
+	for (j = 0; j < inner_loops; j++)
+	  {
+	     double x = (double) a[j];
+
+	     if (x != 0.0)
+	       {
+		  unsigned int k;
+
+		  for (k = 0; k < 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->data;
+   b = (GENERIC_TYPE *) bt->data;
+   a = (double *) at->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->data;
+   b = (double *) bt->data;
+   a = (GENERIC_TYPE *) at->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->data;
+   b = (double *) bt->data;
+   a = (double *) at->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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+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->flags & SLARR_DATA_VALUE_IS_POINTER);
+   if (is_ptr) *(VOID_STAR *) data = NULL;
+   return _SLarray_aget_transfer_elem (at, indices, data, at->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->sizeof_type,
+				       at->flags & 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 "slinclud.h"
+
+#define SL_APP_WANTS_FOREACH
+#include "slang.h"
+#include "_slang.h"
+
+#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->type = type;
+
+   if (has_default_value)
+     {
+	if (
+#if USE_NEW_ANYTYPE_CODE
+	    ((type != SLANG_ANY_TYPE) && (-1 == SLclass_typecast (type, 1, 1)))
+#else
+	    (-1 == SLclass_typecast (type, 1, 1))
+#endif
+	    || (-1 == SLang_pop (&a->default_value)))
+	  {
+	     SLfree ((char *) a);
+	     return NULL;
+	  }
+
+	a->flags |= HAS_DEFAULT_VALUE;
+     }
+   return a;
+}
+
+static void free_element (_SLAssoc_Array_Element_Type *e)
+{
+   if (e == NULL)
+     return;
+
+   SLang_free_object (&e->value);
+   SLang_free_slstring (e->key);
+#if USE_CACHED_STRING
+   if (e->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 < SLASSOC_HASH_TABLE_SIZE; i++)
+     {
+	_SLAssoc_Array_Element_Type *e;
+
+	e = a->elements[i];
+	while (e != NULL)
+	  {
+	     _SLAssoc_Array_Element_Type *next_e;
+
+	     next_e = e->next;
+	     free_element (e);
+	     e = next_e;
+	  }
+     }
+   if (a->flags & HAS_DEFAULT_VALUE)
+     SLang_free_object (&a->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->elements[h];
+
+   while (e != NULL)
+     {
+	if (str == e->key)       /* slstrings can be compared this way */
+	  {
+#if USE_CACHED_STRING
+	     Cached_String = str;
+	     Cached_Obj = &e->value;
+	     Cached_Array = a;
+#endif
+	     return &e->value;
+	  }
+
+	e = e->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->key = str;
+   e->next = a->elements[h];
+   a->elements[h] = e;
+
+   a->num_elements += 1;
+#if USE_CACHED_STRING
+   Cached_String = str;
+   Cached_Obj = &e->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) && (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 = &e->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,
+		      "Assoc_Type arrays require a single string index");
+	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, &mmt, &a, &str))
+     return -1;
+
+#if USE_CACHED_STRING
+   if ((str == Cached_String) && (a == Cached_Array))
+     obj = Cached_Obj;
+   else
+#endif
+     obj = find_element (a, str, _SLcompute_string_hash (str));
+
+   if ((obj == NULL)
+       && (a->flags & HAS_DEFAULT_VALUE))
+     obj = &a->default_value;
+
+   if (obj == NULL)
+     {
+	SLang_verror (SL_INTRINSIC_ERROR,
+		      "No such element in Assoc Array: %s", str);
+	ret = -1;
+     }
+   else
+     {
+#if _SLANG_OPTIMIZE_FOR_SPEED
+	if (SLANG_CLASS_TYPE_SCALAR == _SLclass_Class_Type[obj->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, &mmt, &a, &str))
+     return -1;
+
+   ret = -1;
+
+   if (0 == SLang_pop (&obj))
+     {
+	if ((obj.data_type != a->type)
+#if USE_NEW_ANYTYPE_CODE
+	    && (a->type != SLANG_ANY_TYPE)
+#endif
+	    )
+	  {
+	     (void) SLang_push (&obj);
+	     if ((-1 == SLclass_typecast (a->type, 1, 1))
+		 || (-1 == SLang_pop (&obj)))
+	       goto the_return;
+	  }
+	
+	if (-1 == store_object (a, str, &obj))
+	  SLang_free_object (&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 (&type))
+	  break;
+	num_dims--;
+	/* drop */
+      default:
+	SLdo_pop_n (num_dims);
+	SLang_verror (SL_SYNTAX_ERROR, "Usage: Assoc_Type [DataType_Type]");
+	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->num_elements;
+
+   if (NULL == (at = SLang_create_array (SLANG_STRING_TYPE, 0, NULL, &num, 1)))
+     return;
+
+   data = (char **)at->data;
+
+   i = 0;
+   for (j = 0; j < SLASSOC_HASH_TABLE_SIZE; j++)
+     {
+	_SLAssoc_Array_Element_Type *e;
+
+	e = a->elements[j];
+	while (e != NULL)
+	  {
+	     /* Next cannot fail because it is an slstring */
+	     data [i] = SLang_create_slstring (e->key);
+	     e = e->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->cl_data_type == SLANG_ANY_TYPE)
+     {
+	SLang_Any_Type *any;
+
+	if ((-1 == _SLpush_slang_obj (obj))
+	    || (-1 == SLang_pop_anytype (&any)))
+	  return -1;
+	
+	*(SLang_Any_Type **)dest_data = any;
+	return 0;
+     }
+#endif
+   /* Optimize for scalar */
+   if (cl->cl_class_type == SLANG_CLASS_TYPE_SCALAR)
+     {
+	sizeof_type = cl->cl_sizeof_type;
+	memcpy ((char *) dest_data, (char *)&obj->v, sizeof_type);
+	return 0;
+     }
+
+   src_data = _SLclass_get_ptr_to_value (cl, obj);
+
+   if (-1 == (*cl->cl_acopy) (cl->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->num_elements;
+   type = a->type;
+
+   cl = _SLclass_get_class (type);
+   sizeof_type = cl->cl_sizeof_type;
+
+   if (NULL == (at = SLang_create_array (type, 0, NULL, &num, 1)))
+     return;
+
+   dest_data = (char *)at->data;
+
+   i = 0;
+   for (j = 0; j < SLASSOC_HASH_TABLE_SIZE; j++)
+     {
+	_SLAssoc_Array_Element_Type *e;
+
+	e = a->elements[j];
+	while (e != NULL)
+	  {
+	     if (-1 == transfer_element (cl, (VOID_STAR) dest_data, &e->value))
+	       {
+		  SLang_free_array (at);
+		  return;
+	       }
+
+	     dest_data += sizeof_type;
+	     e = e->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->elements[h];
+   while (v != NULL)
+     {
+	if (v->key == key)
+	  {
+	     if (v0 != NULL)
+	       v0->next = v->next;
+	     else
+	       a->elements[h] = v->next;
+
+	     free_element (v);
+	     a->num_elements -= 1;
+	     return;
+	  }
+	v0 = v;
+	v = v->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("assoc_get_keys", assoc_get_keys, SLANG_VOID_TYPE, A),
+   MAKE_INTRINSIC_1("assoc_get_values", assoc_get_values, SLANG_VOID_TYPE, A),
+   MAKE_INTRINSIC_2("assoc_key_exists", assoc_key_exists, SLANG_INT_TYPE, A, S),
+   MAKE_INTRINSIC_2("assoc_delete_key", 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->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 (&s))
+	  {
+	     SLang_free_mmt (mmt);
+	     return NULL;
+	  }
+
+	if (0 == strcmp (s, "keys"))
+	  flags |= CTX_WRITE_KEYS;
+	else if (0 == strcmp (s, "values"))
+	  flags |= CTX_WRITE_VALUES;
+	else
+	  {
+	     SLang_verror (SL_NOT_IMPLEMENTED,
+			   "using '%s' not supported by SLassoc_Type",
+			   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->flags = flags;
+   c->mmt = mmt;
+   c->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->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->a;
+
+   i = c->this_hash_index;
+   if (i >= SLASSOC_HASH_TABLE_SIZE)
+     return 0;
+
+   e = a->elements[i];
+
+   j = c->next_same_hash_index;
+   c->next_same_hash_index = j + 1;
+
+   while ((j > 0) && (e != NULL))
+     {
+	j--;
+	e = e->next;
+     }
+
+   if (e == NULL)
+     {
+	do
+	  {
+	     i++;
+	     if (i >= SLASSOC_HASH_TABLE_SIZE)
+	       return 0;		       /* no more */
+	  }
+	while (a->elements [i] == NULL);
+
+	e = a->elements[i];
+	c->this_hash_index = i;
+	c->next_same_hash_index = 1;
+     }
+
+   if ((c->flags & CTX_WRITE_KEYS)
+       && (-1 == SLang_push_string (e->key)))
+     return -1;
+
+   if ((c->flags & CTX_WRITE_VALUES)
+       && (-1 == _SLpush_slang_obj (&e->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 ("Assoc_Type")))
+     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->cl_length = assoc_length;
+   cl->cl_foreach_open = cl_foreach_open;
+   cl->cl_foreach_close = cl_foreach_close;
+   cl->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, "__SLASSOC__"))
+     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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+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)->ptr_type ? (b)->v.ptr : (b)->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->len = len;
+   b->num_refs = 1;
+   b->ptr_type = type;
+
+   switch (type)
+     {
+      case 0:
+	if (bytes != NULL) memcpy ((char *) b->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->v.bytes[len] = 0;
+	break;
+
+      case IS_SLSTRING:
+	if (NULL == (b->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->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->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->len;
+   return BS_GET_POINTER(b);
+}
+
+void SLbstring_free (SLang_BString_Type *b)
+{
+   if (b == NULL)
+     return;
+
+   if (b->num_refs > 1)
+     {
+	b->num_refs -= 1;
+	return;
+     }
+
+   switch (b->ptr_type)
+     {
+      case 0:
+      case IS_NOT_TO_BE_FREED:
+      default:
+	break;
+
+      case IS_SLSTRING:
+	SLang_free_slstring ((char *)b->v.ptr);
+	break;
+
+      case IS_MALLOCED:
+	SLfree ((char *)b->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->num_refs += 1;
+
+   if (0 == SLclass_push_ptr_obj (SLANG_BSTRING_TYPE, (VOID_STAR)b))
+     return 0;
+
+   b->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->len;
+   if (b->len < len) len = b->len;
+
+   ret = memcmp ((char *)BS_GET_POINTER(b), (char *)BS_GET_POINTER(a), len);
+   if (ret != 0)
+     return ret;
+
+   if (a->len > b->len)
+     return 1;
+   if (a->len == b->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->len + b->len;
+
+   if (NULL == (c = SLbstring_create (NULL, len)))
+     return NULL;
+
+   bytes = (char *)BS_GET_POINTER(c);
+
+   memcpy (bytes, (char *)BS_GET_POINTER(a), a->len);
+   memcpy (bytes + a->len, (char *)BS_GET_POINTER(b), b->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 < 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 > nb) n_max = na; else n_max = nb;
+
+   a = (SLang_BString_Type **) ap;
+   b = (SLang_BString_Type **) bp;
+   for (n = 0; n < n_max; n++)
+     {
+	if ((*a == NULL) || (*b == NULL))
+	  {
+	     SLang_verror (SL_VARIABLE_UNINITIALIZED,
+			   "Binary string element[%u] not initialized for binary operation", 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 < 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 < n_max; n++)
+	  {
+	     ic [n] = (0 != compare_bstrings (*a, *b));
+	     a += da;
+	     b += db;
+	  }
+	break;
+      case SLANG_GT:
+	for (n = 0; n < n_max; n++)
+	  {
+	     ic [n] = (compare_bstrings (*a, *b) > 0);
+	     a += da;
+	     b += db;
+	  }
+	break;
+      case SLANG_GE:
+	for (n = 0; n < n_max; n++)
+	  {
+	     ic [n] = (compare_bstrings (*a, *b) >= 0);
+	     a += da;
+	     b += db;
+	  }
+	break;
+      case SLANG_LT:
+	for (n = 0; n < n_max; n++)
+	  {
+	     ic [n] = (compare_bstrings (*a, *b) < 0);
+	     a += da;
+	     b += db;
+	  }
+	break;
+      case SLANG_LE:
+	for (n = 0; n < n_max; n++)
+	  {
+	     ic [n] = (compare_bstrings (*a, *b) <= 0);
+	     a += da;
+	     b += db;
+	  }
+	break;
+      case SLANG_EQ:
+	for (n = 0; n < 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 < 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 < 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 < 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->len;
+
+   b = buf;
+   bmax = buf + (sizeof (buf) - 4);
+
+   while (bytes < bytes_max)
+     {
+	unsigned char ch = *bytes;
+
+	if ((ch < 32) || (ch >= 127) || (ch == '\\'))
+	  {
+	     if (b + 4 > bmax)
+	       break;
+
+	     sprintf ((char *) b, "\\%03o", ch);
+	     b += 4;
+	  }
+	else
+	  {
+	     if (b == bmax)
+	       break;
+
+	     *b++ = ch;
+	  }
+
+	bytes++;
+     }
+
+   if (bytes < bytes_max)
+     {
+	*b++ = '.';
+	*b++ = '.';
+	*b++ = '.';
+     }
+   *b = 0;
+
+   return SLmake_string ((char *)buf);
+}
+
+static unsigned int bstrlen_cmd (SLang_BString_Type *b)
+{
+   return b->len;
+}
+
+static SLang_Intrin_Fun_Type BString_Table [] = /*{{{*/
+{
+   MAKE_INTRINSIC_1("bstrlen",  bstrlen_cmd, SLANG_UINT_TYPE, SLANG_BSTRING_TYPE),
+   MAKE_INTRINSIC_0("pack", _SLpack, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_2("unpack", _SLunpack, SLANG_VOID_TYPE, SLANG_STRING_TYPE, SLANG_BSTRING_TYPE),
+   MAKE_INTRINSIC_1("pad_pack_format", _SLpack_pad_format, SLANG_VOID_TYPE, SLANG_STRING_TYPE),
+   MAKE_INTRINSIC_1("sizeof_pack", _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 ("BString_Type")))
+     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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+#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 ("Application error: Type %d not registered", (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->cl_class_type)
+     {
+      case SLANG_CLASS_TYPE_MMT:
+      case SLANG_CLASS_TYPE_PTR:
+      case SLANG_CLASS_TYPE_SCALAR:
+	p = (VOID_STAR) &obj->v;
+	break;
+
+      case SLANG_CLASS_TYPE_VECTOR:
+	p = obj->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->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, "%s method not defined for %s",
+		 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->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 > nb) n_max = na; else n_max = nb;
+
+   switch (op)
+     {
+      default:
+	return 0;
+
+      case SLANG_NE:
+	for (n = 0; n < n_max; n++)
+	  {
+	     c[n] = (0 != SLMEMCMP(a, b, data_type_len));
+	     a += da; b += db;
+	  }
+	break;
+
+      case SLANG_EQ:
+	for (n = 0; n < 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)->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)->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->cl_push)(type, (VOID_STAR) &ptr);
+}
+
+static int vector_apop (unsigned char type, VOID_STAR ptr)
+{
+   SLang_Class_Type *cl;
+
+   cl = _SLclass_get_class (type);
+   return (*cl->cl_pop)(type, (VOID_STAR) &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, "datatype_deref", 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->cl_apush) (type, from))
+     return -1;
+   return (*cl->cl_apop) (type, to);
+}
+
+static int default_dereference_object (unsigned char type, VOID_STAR ptr)
+{
+   (void) ptr;
+   return method_undefined_error (type, "dereference", 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 = "NULL";
+	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] < 0)
+	  sprintf (s, "(%g - %gi)", cplx [0], -cplx [1]);
+	else
+	  sprintf (s, "(%g + %gi)", 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->cl_cmp;
+   data_type_len = cl->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 > nb) n_max = na; else n_max = nb;
+
+   switch (op)
+     {
+	int result;
+	
+      default:
+	return 0;
+
+      case SLANG_NE:
+	for (n = 0; n < n_max; n++)
+	  {
+	     if (-1 == (*cmp) (a_type, (VOID_STAR)a, (VOID_STAR)b, &result))
+	       return -1;
+	     c[n] = (result != 0);
+	     a += da; b += db;
+	  }
+	break;
+
+      case SLANG_EQ:
+	for (n = 0; n < n_max; n++)
+	  {
+	     if (-1 == (*cmp) (a_type, (VOID_STAR)a, (VOID_STAR)b, &result))
+	       return -1;
+	     c[n] = (result == 0);
+	     a += da; b += db;
+	  }
+	break;
+
+      case SLANG_GT:
+	for (n = 0; n < n_max; n++)
+	  {
+	     if (-1 == (*cmp) (a_type, (VOID_STAR)a, (VOID_STAR)b, &result))
+	       return -1;
+	     c[n] = (result > 0);
+	     a += da; b += db;
+	  }
+	break;
+      case SLANG_GE:
+	for (n = 0; n < n_max; n++)
+	  {
+	     if (-1 == (*cmp) (a_type, (VOID_STAR)a, (VOID_STAR)b, &result))
+	       return -1;
+	     c[n] = (result >= 0);
+	     a += da; b += db;
+	  }
+	break;
+      case SLANG_LT:
+	for (n = 0; n < n_max; n++)
+	  {
+	     if (-1 == (*cmp) (a_type, (VOID_STAR)a, (VOID_STAR)b, &result))
+	       return -1;
+	     c[n] = (result < 0);
+	     a += da; b += db;
+	  }
+	break;
+      case SLANG_LE:
+	for (n = 0; n < n_max; n++)
+	  {
+	     if (-1 == (*cmp) (a_type, (VOID_STAR)a, (VOID_STAR)b, &result))
+	       return -1;
+	     c[n] = (result <= 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->cl_data_type;
+}
+
+SLang_Class_Type *SLclass_allocate_class (char *name)
+{
+   SLang_Class_Type *cl;
+   unsigned int i;
+
+   for (i = 0; i < 256; i++)
+     {
+	cl = Registered_Types [i];
+	if ((cl != NULL)
+	    && (0 == strcmp (cl->cl_name, name)))
+	  {
+	     SLang_verror (SL_DUPLICATE_DEFINITION, "Type name %s already exists", 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->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)->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->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, &i))
+     return -1;
+
+   *type = (unsigned char) i;
+   return 0;
+}
+
+static int datatype_pop (unsigned char type, VOID_STAR ptr)
+{
+   if (-1 == _SLang_pop_datatype (&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 ("DataType_Type")))
+     return -1;
+   cl->cl_pop = datatype_pop;
+   cl->cl_push = datatype_push;
+   cl->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 ("Application error: Class already exists");
+
+   Registered_Types[to] = cl;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+   if (to != SLANG_UNDEFINED_TYPE)
+     _SLclass_Class_Type [to] = cl->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 < 256; i++)
+     {
+	if ((Registered_Types[i] == NULL)
+	    && (i != SLANG_VOID_TYPE))
+	  {
+	     type = (unsigned char) i;
+	     break;
+	  }
+     }
+
+   if ((NULL != Registered_Types [type])
+       || (type == SLANG_VOID_TYPE))
+     {
+	SLang_verror (SL_APPLICATION_ERROR, "Class type %d already in use", (int) type);
+	return -1;
+     }
+
+   cl->cl_data_type = type;
+   cl->cl_class_type = class_type;
+   name = cl->cl_name;
+
+   switch (class_type)
+     {
+      case SLANG_CLASS_TYPE_MMT:
+	if (cl->cl_push == NULL) cl->cl_push = default_push_mmt;
+	if (cl->cl_destroy == NULL)
+	  return method_undefined_error (type, "destroy", name);
+	cl->cl_user_destroy_fun = cl->cl_destroy;
+	cl->cl_destroy = default_destroy_user;
+	type_size = sizeof (VOID_STAR);
+	break;
+
+      case SLANG_CLASS_TYPE_SCALAR:
+	if (cl->cl_destroy == NULL) cl->cl_destroy = default_destroy_simple;
+	if ((type_size == 0)
+	    || (type_size > sizeof (_SL_Object_Union_Type)))
+	  {
+	     SLang_verror (SL_INVALID_PARM,
+			   "Type size for %s not appropriate for SCALAR type",
+			   name);
+	     return -1;
+	  }
+	if (cl->cl_pop == NULL)
+	  return method_undefined_error (type, "pop", name);
+	if (cl->cl_fread == NULL) cl->cl_fread = scalar_fread;
+	if (cl->cl_fwrite == NULL) cl->cl_fwrite = scalar_fwrite;
+
+	can_binop = 1;
+	break;
+
+      case SLANG_CLASS_TYPE_PTR:
+	if (cl->cl_destroy == NULL)
+	  return method_undefined_error (type, "destroy", name);
+	type_size = sizeof (VOID_STAR);
+	break;
+
+      case SLANG_CLASS_TYPE_VECTOR:
+	if (cl->cl_destroy == NULL)
+	  return method_undefined_error (type, "destroy", name);
+	if (cl->cl_pop == NULL)
+	  return method_undefined_error (type, "pop", name);
+	cl->cl_apop = vector_apop;
+	cl->cl_apush = vector_apush;
+	cl->cl_adestroy = default_destroy_simple;
+	if (cl->cl_fread == NULL) cl->cl_fread = scalar_fread;
+	if (cl->cl_fwrite == NULL) cl->cl_fwrite = scalar_fwrite;
+	can_binop = 1;
+	break;
+
+      default:
+	SLang_verror (SL_INVALID_PARM, "%s: unknown class type (%d)", 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, "type size must be non-zero for %s", name);
+	return -1;
+     }
+
+   if (cl->cl_string == NULL) cl->cl_string = default_string;
+   if (cl->cl_acopy == NULL) cl->cl_acopy = default_acopy;
+   if (cl->cl_datatype_deref == NULL) cl->cl_datatype_deref = default_datatype_deref;
+
+   if (cl->cl_pop == NULL) cl->cl_pop = default_pop;
+
+   if (cl->cl_push == NULL)
+     return method_undefined_error (type, "push", name);
+
+   if (cl->cl_byte_code_destroy == NULL)
+     cl->cl_byte_code_destroy = cl->cl_destroy;
+   if (cl->cl_push_literal == NULL)
+     cl->cl_push_literal = cl->cl_push;
+
+   if (cl->cl_dereference == NULL)
+     cl->cl_dereference = default_dereference_object;
+
+   if (cl->cl_apop == NULL) cl->cl_apop = cl->cl_pop;
+   if (cl->cl_apush == NULL) cl->cl_apush = cl->cl_push;
+   if (cl->cl_adestroy == NULL) cl->cl_adestroy = cl->cl_destroy;
+   if (cl->cl_push_intrinsic == NULL) cl->cl_push_intrinsic = cl->cl_push;
+
+   if ((cl->cl_foreach == NULL)
+       || (cl->cl_foreach_open == NULL)
+       || (cl->cl_foreach_close == NULL))
+     {
+	cl->cl_foreach = _SLarray_cl_foreach;
+	cl->cl_foreach_open = _SLarray_cl_foreach_open;
+	cl->cl_foreach_close = _SLarray_cl_foreach_close;
+     }
+
+   cl->cl_sizeof_type = type_size;
+
+   if (NULL == (cl->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->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
+	    && (-1 == SLclass_add_binary_op (type, type, scalar_vector_bin_op, scalar_vector_bin_op_result)))
+     return -1;
+
+   cl->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->cl_math_op = handler;
+   cl->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, "SLclass_add_binary_op");
+	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->data_type = b;
+   ab->binary_function = f;
+   ab->binary_result = r;
+   ab->next = cl->cl_binary_ops;
+   cl->cl_binary_ops = ab;
+
+   if ((a != SLANG_ARRAY_TYPE)
+       && (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, "SLclass_add_unary_op");
+	return -1;
+     }
+
+   cl->cl_unary_op = f;
+   cl->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, "SLclass_add_app_unary_op");
+	return -1;
+     }
+
+   cl->cl_app_unary_op = f;
+   cl->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->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->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->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->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->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->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->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->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->cl_anew = f;
+   return 0;
+}
+
+/* Misc */
+void _SLclass_type_mismatch_error (unsigned char a, unsigned char b)
+{
+   SLang_verror (SL_TYPE_MISMATCH, "Expecting %s, found %s",
+		 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 > nb) nb = na;
+   ic = (int *) cp;
+   for (i = 0; i < nb; i++)
+     ic[i] = c;
+
+   return 1;
+}
+
+static char *get_binary_op_string (int op)
+{
+   static char *ops[SLANG_MOD] =
+     {
+	"+", "=", "*", "/", "==", "!=", ">", ">=", "<", "<=", "^",
+	"or", "and", "&", "|", "xor", "shl", "shr", "mod"
+     };
+
+   if ((op > SLANG_MOD) || (op <= 0))
+     return "??";
+   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->cl_data_type;
+   b = b_cl->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->cl_binary_ops;
+
+   while (bt != NULL)
+     {
+	if (bt->data_type == b)
+	  {
+	     if (1 != (*bt->binary_result)(op, a, b, &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->binary_function;
+	  }
+
+	bt = bt->next;
+     }
+
+   if (do_error)
+     SLang_verror (SL_TYPE_MISMATCH, "%s %s %s is not possible",
+		   a_cl->cl_name, get_binary_op_string (op), b_cl->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->cl_unary_op;
+	r = a_cl->cl_unary_op_result_type;
+	break;
+
+      case _SLANG_BC_MATH_UNARY:
+	f = a_cl->cl_math_op;
+	r = a_cl->cl_math_op_result_type;
+	break;
+
+      case _SLANG_BC_APP_UNARY:
+	f = a_cl->cl_app_unary_op;
+	r = a_cl->cl_app_unary_op_result_type;
+	break;
+
+      default:
+	f = NULL;
+	r = NULL;
+     }
+
+   a = a_cl->cl_data_type;
+   if ((f != NULL) && (r != NULL) && (1 == (*r) (op, a, &b)))
+     {
+	if (a == b)
+	  *b_cl = a_cl;
+	else
+	  *b_cl = _SLclass_get_class (b);
+	return f;
+     }
+
+   SLang_verror (SL_TYPE_MISMATCH, "undefined unary operation/function on %s",
+		 a_cl->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 (&obj))
+     return -1;
+
+   from_type = obj.data_type;
+   if (from_type == to_type)
+     {
+	SLang_push (&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 &obj.v.
+    */
+   ap = _SLclass_get_ptr_to_value (cl_from, &obj);
+
+   if ((from_type == SLANG_ARRAY_TYPE)
+       && (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->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 (&obj);
+	     return -1;
+	  }
+
+	cl_to = _SLclass_get_class (to_type);
+	bp = cl_to->cl_transfer_buf;
+	status = (*t) (from_type, ap, 1, to_type, bp);
+     }
+
+   if (1 == status)
+     {
+	if (-1 == (*cl_to->cl_apush)(to_type, bp))
+	  {
+	     (*cl_to->cl_adestroy) (to_type, bp);
+	     SLang_free_object (&obj);
+	     return -1;
+	  }
+
+	/* cl_apush will push a copy, so destry this one */
+	(*cl_to->cl_adestroy) (to_type, bp);
+	SLang_free_object (&obj);
+	return 0;
+     }
+
+   return_error:
+
+   SLang_verror (SL_TYPE_MISMATCH, "Unable to typecast %s to %s",
+		 cl_from->cl_name,
+		 SLclass_get_datatype_name (to_type));
+   SLang_free_object (&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->cl_typecast_funs;
+   while (t != NULL)
+     {
+	if (t->data_type != to)
+	  {
+	     t = t->next;
+	     continue;
+	  }
+
+	if (is_implicit && (t->allow_implicit == 0))
+	  break;
+
+	return t->typecast;
+     }
+
+   if (to == SLANG_ANY_TYPE)
+     return _SLanytype_typecast;
+
+   if ((is_implicit == 0)
+       && (cl_from->cl_void_typecast != NULL))
+     return cl_from->cl_void_typecast;
+
+   SLang_verror (SL_TYPE_MISMATCH, "Unable to typecast %s to %s",
+		 cl_from->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->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->data_type = to;
+   t->next = cl->cl_typecast_funs;
+   t->typecast = f;
+   t->allow_implicit = allow_implicit;
+
+   cl->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 *) &mmt))
+     mmt = NULL;
+   return mmt;
+
+#if 0
+   SLang_Object_Type obj;
+   SLang_Class_Type *cl;
+
+   if (_SLang_pop_object_of_type (type, &obj))
+     return NULL;
+
+   cl = _SLclass_get_class (type);
+   if ((cl->cl_class_type == SLANG_CLASS_TYPE_MMT)
+       && (obj.data_type == type))
+     {
+	return obj.v.ref;
+     }
+
+   _SLclass_type_mismatch_error (type, obj.data_type);
+   SLang_free_object (&obj);
+   return NULL;
+#endif
+}
+
+/*}}}*/
+
+int SLang_push_mmt (SLang_MMT_Type *ref) /*{{{*/
+{
+   if (ref == NULL)
+     return SLang_push_null ();
+
+   ref->count += 1;
+
+   if (0 == SLclass_push_ptr_obj (ref->data_type, (VOID_STAR) ref))
+     return 0;
+
+   ref->count -= 1;
+   return -1;
+}
+
+/*}}}*/
+
+void SLang_inc_mmt (SLang_MMT_Type *ref)
+{
+   if (ref != NULL)
+     ref->count += 1;
+}
+
+VOID_STAR SLang_object_from_mmt (SLang_MMT_Type *ref)
+{
+   if (ref == NULL)
+     return NULL;
+
+   return ref->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->data_type = t;
+   ref->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->count > 1)
+     {
+	ref->count -= 1;
+	return;
+     }
+
+   type = ref->data_type;
+   cl = _SLclass_get_class (type);
+   (*cl->cl_user_destroy_fun) (type, ref->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->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->cl_apop)(type, v);
+}
+
+void SLang_free_value (unsigned char type, VOID_STAR v)
+{
+   SLang_Class_Type *cl;
+
+   cl = _SLclass_get_class (type);
+   (*cl->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 (&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 (&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 (&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 (&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 (&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, &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, &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, &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, &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, &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, &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, &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 "slinclud.h"
+
+#if SLANG_HAS_FLOAT
+# include <math.h>
+#endif
+
+#include "slang.h"
+#include "_slang.h"
+
+#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->cmdfun != NULL)
+	  && (NULL != (cmdstr = cmd->cmd))
+	  && (0 != (ch = *cmdstr++)))
+     {
+	if ((ch == chs) && !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)
+	  && ((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 == '"'))
+     {
+	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)
+	  && (ch != ' ')
+	  && (ch != '\t')
+	  && (ch != '\n')
+	  && (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 < (int) space)
+     return 0;
+
+   if (space > 128)
+     {
+	if (space > 1024) space += 1024;
+	else space += 128;
+     }
+   else space += 32;
+
+   if (NULL == (p = SLrealloc ((char *)table->string_args, space * sizeof (char *))))
+     return -1;
+   table->string_args = (char **)p;
+   table->string_args [argc] = NULL;
+
+   if (NULL == (p = SLrealloc ((char *)table->int_args, space * sizeof (int))))
+     return -1;
+   table->int_args = (int *)p;
+
+   if (NULL == (p = SLrealloc ((char *)table->double_args, space * sizeof (double))))
+     return -1;
+   table->double_args = (double *)p;
+
+   if (NULL == (p = SLrealloc ((char *)table->arg_type, space * sizeof (unsigned char))))
+     return -1;
+   table->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->argc = 0;
+   table->string_args = NULL;
+   table->int_args = NULL;
+   table->double_args = NULL;
+   table->arg_type = NULL;
+
+   buf = SLmake_string (str);
+   if (buf == NULL)
+     return -1;
+
+   status = extract_token (&str, buf);
+   if (status <= 0)
+     {
+	SLfree (buf);
+	return status;
+     }
+
+   if (((len = strlen (buf)) >= 32)
+       || (NULL == (cmd = SLcmd_find_command (buf, table->table))))
+     {
+	SLang_verror (SL_UNDEFINED_NAME,"%s: invalid command", 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, &space))
+     {
+	SLfree (buf);
+	return -1;
+     }
+   table->arg_type[argc] = SLANG_STRING_TYPE;
+   table->string_args[argc++] = cmd_name;
+
+   arg_type = cmd->arg_type;
+   status = -1;
+   while (*arg_type)
+     {
+	int guess_type = 0;
+
+	last_str = str;
+
+	if (-1 == allocate_arg_space (table, argc, &space))
+	  goto error;
+
+	if (-1 == (token_present = extract_token (&str, buf)))
+	  goto error;
+
+	table->string_args[argc] = NULL;
+
+	if (token_present)
+	  {
+	     b = buf;
+	     len = strlen (b);
+
+	     if ((*b == '"') && (len > 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 == '\'') && (len > 1))
+	       {
+		  char ch;
+		  b++;
+		  len -= 2;
+		  b[len] = 0;
+		  guess_type = SLANG_INT_TYPE;
+		  ch = *b;
+		  if (ch == '\\')
+		    (void) _SLexpand_escaped_char (b, &ch);
+		  sprintf (buf, "%d", (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, "%s: Expecting argument", 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->arg_type[argc] = SLANG_STRING_TYPE;
+	     table->string_args[argc++] = s;
+	     break;
+
+	   case 's':
+	     if (token_present == 0) break;
+	   case 'S':
+	     if (token_present == 0)
+	       {
+		  SLang_verror (SL_TYPE_MISMATCH, "%s: Expecting string argument", cmd_name);
+		  goto error;
+	       }
+
+	     s = SLmake_nstring (buf, len);
+	     if (s == NULL) goto error;
+	     table->arg_type[argc] = SLANG_STRING_TYPE;
+	     table->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, "%s: Expecting integer argument", cmd_name);
+		  goto error;
+	       }
+
+	     table->arg_type[argc] = SLANG_INT_TYPE;
+	     table->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, "%s: Expecting double argument", cmd_name);
+		  goto error;
+	       }
+	     table->arg_type[argc] = SLANG_DOUBLE_TYPE;
+	     table->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, "%s: Expecting argument", cmd_name);
+		  goto error;
+	       }
+
+	     switch (guess_type)
+	       {
+		case SLANG_INT_TYPE:
+		  table->arg_type[argc] = SLANG_INT_TYPE;
+		  table->int_args[argc++] = SLatoi((unsigned char *) buf);
+		  break;
+
+		case SLANG_STRING_TYPE:
+		  s = SLmake_nstring (buf, len);
+		  if (s == NULL) goto error;
+
+		  table->arg_type[argc] = SLANG_STRING_TYPE;
+		  table->string_args[argc++] = s;
+		  break;
+#if SLANG_HAS_FLOAT
+		case SLANG_DOUBLE_TYPE:
+		  table->arg_type[argc] = SLANG_DOUBLE_TYPE;
+		  table->double_args[argc++] = atof(buf);
+#endif
+	       }
+	     break;
+	  }
+     }
+
+   /*                 call function */
+   status = (*cmd->cmdfun)(argc, table);
+
+   error:
+   if (table->string_args != NULL) for (i = 0; i < argc; i++)
+     {
+	if (NULL != table->string_args[i])
+	  {
+	     SLfree (table->string_args[i]);
+	     table->string_args[i] = NULL;
+	  }
+     }
+   SLfree ((char *)table->string_args); table->string_args = NULL;
+   SLfree ((char *)table->double_args); table->double_args = NULL;
+   SLfree ((char *)table->int_args); table->int_args = NULL;
+   SLfree ((char *)table->arg_type); table->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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+/* The rest of the file is enclosed in this #if */
+#if SLANG_HAS_COMPLEX
+
+#if SLANG_HAS_FLOAT
+# include <math.h>
+#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 *)&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) > 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 >= 0)
+     return val;		       /* I, IV */
+
+   if (y <= 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 >= 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 (&r, &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 >= 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 < 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, &alpha, &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, &alpha, &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, "%s for complex numbers has not been implemented",
+		 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 > 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 < 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 < 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 < n_max; n += 2)
+	  {
+	     SLcomplex_times (c + n, a, b);
+	     a += da; b += db;
+	  }
+	break;
+
+      case SLANG_DIVIDE:	       /* / */
+	for (n = 0; n < n_max; n += 2)
+	  {
+	     if ((b[0] == 0.0) && (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 < n_max; n += 2)
+	  {
+	     ic[n/2] = ((a[0] == b[0]) && (a[1] == b[1]));
+	     a += da; b += db;
+	  }
+	break;
+
+      case SLANG_NE:		       /* != */
+	for (n = 0; n < 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 < 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 > 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 < 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 < 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 < 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 < 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 < n_max; n += 2)
+	  {
+	     ic[n/2] = ((a[0] == b[0]) && (a[1] == 0.0));
+	     a += da; b += db;
+	  }
+	break;
+
+      case SLANG_NE:		       /* != */
+	for (n = 0; n < 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 < 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 > 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 < 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 < 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 < 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 < n_max; n += 2)
+	  {
+	     double z[2];
+	     if ((b[0] == 0.0) && (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 < n_max; n += 2)
+	  {
+	     ic[n/2] = ((a[0] == b[0]) && (0.0 == b[1]));
+	     a += da; b += db;
+	  }
+	break;
+
+      case SLANG_NE:		       /* != */
+	for (n = 0; n < 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 < 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, &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 > 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 < 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 < 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 < 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 < 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 < 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 < n_max; n += 2)
+	  {
+	     ic[n/2] = ((a[0] == to_double((VOID_STAR)b)) && (a[1] == 0.0));
+	     a += da; b += db;
+	  }
+	break;
+
+      case SLANG_NE:		       /* != */
+	for (n = 0; n < 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, &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 > 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 < 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 < 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 < 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 < 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 < n_max; n += 2)
+	  {
+	     double z[2];
+	     if ((b[0] == 0.0) && (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 < n_max; n += 2)
+	  {
+	     ic[n/2] = ((to_double((VOID_STAR)a) == b[0]) && (0.0 == b[1]));
+	     a += da; b += db;
+	  }
+	break;
+
+      case SLANG_NE:		       /* != */
+	for (n = 0; n < 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 ==> double */
+      case SLANG_ABS:		       /* |z| ==> 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 < na; n += 2) b[n] = (a[n] + 1);
+	break;
+      case SLANG_MINUSMINUS:
+	for (n = 0; n < na; n += 2) b[n] = (a[n] - 1);
+	break;
+      case SLANG_CHS:
+	for (n = 0; n < na; n += 2)
+	  {
+	     b[n] = -(a[n]);
+	     b[n + 1] = -(a[n + 1]);
+	  }
+	break;
+      case SLANG_SQR:		       /* |Real|^2 + |Imag|^2 ==> double */
+	for (n = 0; n < na; n += 2)
+	  b[n/2] = (a[n] * a[n] + a[n + 1] * a[n + 1]);
+	break;
+
+      case SLANG_MUL2:
+	for (n = 0; n < na; n += 2)
+	  {
+	     b[n] = (2 * a[n]);
+	     b[n + 1] = (2 * a[n + 1]);
+	  }
+	break;
+
+      case SLANG_ABS:		       /* |z| ==> double */
+	for (n = 0; n < 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 < na; n += 2)
+	  {
+	     if (a[n + 1] < 0.0) ic[n/2] = -1;
+	     else if (a[n + 1] > 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, &sizeof_i)))
+	  return 0;
+	i = (char *) from;
+	for (n = 0; n < 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 < 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 (&z[0], &z[1]);
+}
+
+int _SLinit_slcomplex (void)
+{
+   SLang_Class_Type *cl;
+   unsigned char *types;
+
+   if (NULL == (cl = SLclass_allocate_class ("Complex_Type")))
+     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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+/* Compatibility */
+int SLang_init_slunix (void)
+{
+   if ((-1 == SLang_init_posix_dir ())
+       || (-1 == SLang_init_posix_process ())
+       || (-1 == SLdefine_for_ifdef ("__SLUNIX__")))
+     return -1;
+
+   return 0;
+}
+
+int SLang_init_slfile (void)
+{
+   if ((-1 == SLang_init_stdio ())
+       || (-1 == SLang_init_posix_dir ())
+       || (-1 == SLdefine_for_ifdef("__SLFILE__")))
+     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 "slinclud.h"
+
+#include <signal.h>
+#include <errno.h>
+
+#include "slang.h"
+#include "_slang.h"
+#include "slcurses.h"
+
+/* 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 < 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->delay_off = (onoff ? 0 : -1);
+   return 0;
+}
+
+int SLcurses_wgetch (SLcurses_Window_Type *w)
+{
+   if (w == NULL)
+     return ERR;
+
+   SLcurses_wrefresh (w);
+
+   if ((w->delay_off == -1) ||
+       SLang_input_pending (w->delay_off))
+     {
+	if (w->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 >> 8) & 0xFF;
+
+   if (SLtt_Use_Ansi_Colors)
+     {
+	if (Color_Objects[obj] != 0) return obj;
+
+	at = SLtt_get_color_object (obj & 0xF);
+
+	if (attr & A_BOLD) at |= SLTT_BOLD_MASK;
+	if (attr & A_UNDERLINE) at |= SLTT_ULINE_MASK;
+	if (attr & A_REVERSE) at |= SLTT_REV_MASK;
+
+	SLtt_set_color_object (obj, at);
+
+	Color_Objects[obj] = 1;
+     }
+   else obj = obj & 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 < 16; f++)
+     {
+	for (b = 0; b < 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) && 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) && !defined(VMS)
+   if (-1 == (SLcurses_Num_Colors = SLtt_tgetnum ("Co")))
+#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 ("SLcurses_initscr: init failed\n");
+	return NULL;
+     }
+
+#ifdef SIGINT
+   signal (SIGINT, sigint_handler);
+#endif
+
+#if defined(SIGTSTP) && defined(SIGSTOP)
+   signal (SIGTSTP, sigtstp_handler);
+#endif
+
+   SLtt_set_mono (A_BOLD >> 8, NULL, SLTT_BOLD_MASK);
+   SLtt_set_mono (A_UNDERLINE >> 8, NULL, SLTT_ULINE_MASK);
+   SLtt_set_mono (A_REVERSE >> 8, NULL, SLTT_REV_MASK);
+   /* SLtt_set_mono (A_BLINK >> 8, NULL, SLTT_BLINK_MASK); */
+   SLtt_set_mono ((A_BOLD|A_UNDERLINE) >> 8, NULL, SLTT_ULINE_MASK|SLTT_BOLD_MASK);
+   SLtt_set_mono ((A_REVERSE|A_UNDERLINE) >> 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->color = obj;
+   w->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->attr &= ~ch;
+   return SLcurses_wattrset (w, w->attr);
+}
+
+int SLcurses_wattron (SLcurses_Window_Type *w, SLtt_Char_Type ch)
+{
+   if (SLtt_Use_Ansi_Colors)
+     return SLcurses_wattrset (w, ch);
+
+   w->attr |= ch;
+   return SLcurses_wattrset (w, w->attr);
+}
+
+int SLcurses_delwin (SLcurses_Window_Type *w)
+{
+   if (w == NULL) return 0;
+   if (w->lines != NULL)
+     {
+	SLsmg_Char_Type **lines = w->lines;
+	if (w->is_subwin == 0)
+	  {
+	     unsigned int r, rmax;
+
+	     rmax = w->nrows;
+	     for (r = 0; r < 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 >= (unsigned int) SLtt_Screen_Rows)
+     return NULL;
+   if (c >= (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->lines = lines;
+   win->scroll_max = win->nrows = nrows;
+   win->ncols = ncols;
+   win->_begy = r;
+   win->_begx = c;
+   win->_maxx = (c + ncols) - 1;
+   win->_maxy = (r + nrows) - 1;
+   win->modified = 1;
+   win->delay_off = -1;
+
+   for (r = 0; r < 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->_cury = r;
+   win->_curx = c;
+   win->modified = 1;
+   return 0;
+}
+
+static int do_newline (SLcurses_Window_Type *w)
+{
+   w->_curx = 0;
+   w->_cury += 1;
+   if (w->_cury >= w->scroll_max)
+     {
+	w->_cury = w->scroll_max - 1;
+	if (w->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->_cury >= win->nrows)
+     {
+	/* Curses seems to move current postion to top of window. */
+	win->_cury = win->_curx = 0;
+	return -1;
+     }
+
+   win->modified = 1;
+
+   ch = SLSMG_EXTRACT_CHAR(attr);
+
+   if (attr == ch)
+     color = win->color;
+   else
+     {
+	/* hack to pick up the default color for graphics chars */
+	if (((attr & A_COLOR) == 0) && ((attr & A_ALTCHARSET) != 0))
+	  {
+	     /* FIXME: priority=medium: Use SLSMG_?? instead of << */
+	     attr |= win->color << 8;
+	  }
+	color = map_attr_to_object (attr);
+     }
+
+   if (ch < ' ')
+     {
+	if (ch == '\n')
+	  {
+	     SLcurses_wclrtoeol (win);
+	     return do_newline (win);
+	  }
+
+	if (ch == '\r')
+	  {
+	     win->_curx = 0;
+	     return 0;
+	  }
+
+	if (ch == '\b')
+	  {
+	     if (win->_curx > 0)
+	       win->_curx--;
+
+	     return 0;
+	  }
+
+	/* HACK HACK!!!! */
+	if (ch == '\t') ch = ' ';
+     }
+
+   if (win->_curx >= win->ncols)
+     do_newline (win);
+
+   b = win->lines[win->_cury] + win->_curx;
+   *b = SLSMG_BUILD_CHAR(ch,color);
+   win->_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->modified == 0)
+     return 0;
+
+   r = w->_begy;
+   c = w->_begx;
+
+   len = w->ncols;
+   imax = w->nrows;
+
+   for (i = 0; i < imax; i++)
+     {
+	SLsmg_gotorc (r, c);
+	SLsmg_write_color_chars (w->lines[i], len);
+	r++;
+     }
+
+   if (w->has_box)
+     SLsmg_draw_box(w->_begy, w->_begx, w->nrows, w->ncols);
+
+   SLsmg_gotorc (w->_begy + w->_cury, w->_begx + w->_curx);
+   w->modified = 0;
+   return 0;
+}
+
+int SLcurses_wrefresh (SLcurses_Window_Type *w)
+{
+   if (w == NULL)
+     return -1;
+
+   if (w->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->_cury >= w->nrows)
+     return 0;
+
+   w->modified = 1;
+
+   blank = SLSMG_BUILD_CHAR(' ',w->color);
+
+   b = w->lines[w->_cury];
+   bmax = b + w->ncols;
+   b += w->_curx;
+
+   while (b < 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->modified = 1;
+   blank = SLSMG_BUILD_CHAR(' ',w->color);
+   SLcurses_wclrtoeol (w);
+   for (r = w->_cury + 1; r < w->nrows; r++)
+     {
+	b = w->lines [r];
+	bmax = b + w->ncols;
+
+	while (b < 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->scroll_ok == 0))
+     return -1;
+
+   w->modified = 1;
+#if 0
+   if (w->is_subwin)
+     {
+	SLang_reset_tty ();
+	SLsmg_reset_smg ();
+	fprintf (stderr, "\rAttempt to scroll a subwindow\n");
+	exit (1);
+     }
+#endif
+
+   color = w->color;
+   ncols = w->ncols;
+   lines = w->lines;
+   rmax = w->scroll_max;
+   rmin = w->scroll_min;
+   if (rmax > w->nrows)
+     rmax = w->nrows;
+   if (rmin >= rmax)
+     return 0;
+
+   while (n > 0)
+     {
+	for (r = rmin + 1; r < 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 < 0)
+     {
+	for (r = rmax; r > 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->nrows - 1, 0); */
+   /* wclrtobot (w); */
+   return 0;
+}
+
+/* Note: if len is < 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->modified = 1;
+   nrows = w->nrows;
+   ncols = w->ncols;
+   crow = w->_cury;
+   ccol = w->_curx;
+   color = w->color;
+
+   if (w->scroll_max <= nrows)
+     nrows = w->scroll_max;
+
+   if (crow >= nrows)
+     crow = 0;			       /* wrap back to top */
+
+   b = w->lines [crow] + ccol;
+
+   while (len && ((ch = (unsigned char) *str++) != 0))
+     {
+	len--;
+
+	if (ch == '\n')
+	  {
+	     w->_cury = crow;
+	     w->_curx = ccol;
+	     SLcurses_wclrtoeol (w);
+	     do_newline (w);
+	     crow = w->_cury;
+	     ccol = w->_curx;
+	     b = w->lines[crow];
+	     continue;
+	  }
+
+	if (ccol >= ncols)
+	  {
+	     ccol = 0;
+	     crow++;
+	     if (crow >= nrows)
+	       {
+		  w->_curx = 0;
+		  w->_cury = crow;
+		  do_newline (w);
+		  crow = w->_cury;
+		  ccol = w->_curx;
+	       }
+
+	     b = w->lines [crow];
+	  }
+
+	if (ch == '\t')
+	  {
+	     unsigned int n = ccol;
+	     n += SLsmg_Tab_Width;
+	     n = SLsmg_Tab_Width - (n % SLsmg_Tab_Width);
+	     if (ccol + n > ncols) n = ncols - len;
+	     ccol += n;
+	     while (n--)
+	       *b++ = SLSMG_BUILD_CHAR(' ',color);
+	     continue;
+	  }
+
+	*b++ = SLSMG_BUILD_CHAR(ch, color);
+	ccol++;
+     }
+
+   w->_curx = ccol;
+   w->_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->buf;
+   smax = swin->bufmax;
+   d = dwin->buf;
+   dmax = dwin->bufmax;
+
+   while ((s < smax) && (d < 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->_begy;
+#else
+   r = 1 + ((int)orig->nrows - (int)nlines) / 2;
+#endif
+   if (r < 0) r = 0;
+   if (r + nlines > orig->nrows) nlines = orig->nrows - r;
+
+   c = ((int)orig->ncols - (int)ncols) / 2;
+   if (c < 0) c = 0;
+   if (c + ncols > orig->ncols) ncols = orig->ncols - c;
+
+   sw->scroll_min = 0;
+   sw->scroll_max = sw->nrows = nlines;
+   sw->ncols = ncols;
+   sw->_begy = begin_y;
+   sw->_begx = begin_x;
+   sw->_maxx = (begin_x + ncols) - 1;
+   sw->_maxy = (begin_y + nlines) - 1;
+
+   sw->lines = (SLsmg_Char_Type **) SLmalloc (nlines * sizeof (SLsmg_Char_Type *));
+   if (sw->lines == NULL)
+     {
+	SLcurses_delwin (sw);
+	return NULL;
+     }
+
+   for (i = 0; i < nlines; i++)
+     {
+	sw->lines [i] = orig->lines [r + i] + c;
+     }
+
+   sw->is_subwin = 1;
+   return sw;
+}
+
+int SLcurses_wclear (SLcurses_Window_Type *w)
+{
+   unsigned int i;
+
+   if (w != NULL) w->modified = 1;
+   for (i=0; i < w->nrows; i++)
+     blank_line (w->lines[i], w->ncols, w->color);
+   return 0;
+}
+
+int SLcurses_wdelch (SLcurses_Window_Type *w)
+{
+   SLsmg_Char_Type *p, *p1, *pmax;
+
+   p = w->lines[w->_cury];
+   pmax = p + w->ncols;
+   p += w->_curx;
+   p1 = p + 1;
+
+   while (p1 < pmax)
+     {
+	*p = *p1;
+	p = p1;
+	p1++;
+     }
+
+   if (p < pmax)
+     *p = SLSMG_BUILD_CHAR(' ',w->color);
+
+   w->modified = 1;
+   return 0;
+}
+
+int SLcurses_winsch (SLcurses_Window_Type *w, int ch)
+{
+   SLsmg_Char_Type *p, *p1, *pmax;
+
+   p = w->lines[w->_cury];
+   pmax = p + w->ncols;
+   p += w->_curx;
+   p1 = pmax - 1;
+
+   while (pmax > p)
+     {
+	*pmax = *p1;
+	pmax = p1;
+	p1--;
+     }
+
+   if (p < pmax)
+     *p = SLSMG_BUILD_CHAR(ch, w->color);
+
+   w->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->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 <stdio.h>
+
+#ifndef SLANG_VERSION
+# include <slang.h>
+#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)->_cury < (w)->nrows) && ((w)->_curx < (w)->ncols)) \
+       ? ((w)->lines[(w)->_cury][(w)->_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)->_begy = (a), (w)->_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)->color << 8)
+#define attr_get() wattr_get(stdscr)
+
+#define COLOR_PAIR(x) ((x) << 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)->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)->scroll_min=(w)->_cury, \
+   (w)->scroll_max=(w)->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		'&'
+#define ACS_CKBOARD		(acs_map[SLSMG_CKBRD_CHAR])
+#define ACS_DEGREE		'o'
+#define ACS_PLMINUS		'+'
+#define ACS_BULLET		'*'
+#define ACS_LARROW		'<'
+#define ACS_RARROW		'>'
+#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) << 8)) << 8))
+
+#define scrollok(a,b) ((a)->scroll_ok = (b))
+#define getyx(a,y,x)  (y=(a)->_cury, x=(a)->_curx)
+#define getmaxyx(a,y,x)  (y=(a)->nrows, x=(a)->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)->_begy, (x)->nrows)
+#define flash SLtt_beep
+
+#define wsetscrreg(w,a,b)	((w)->scroll_min = (a), (w)->scroll_max = (b))
+
+#define wtimeout(a,b) (a)->delay_off = ((b >= 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)->has_box = 1, (w)->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 "slinclud.h"
+
+#include <time.h>
+#include <ctype.h>
+
+#if !defined(VMS) || (__VMS_VER >= 70000000)
+# include <sys/time.h>
+# ifdef __QNX__
+#  include <sys/select.h>
+# endif
+# include <sys/types.h>
+#endif
+
+#ifdef __BEOS__
+/* Prototype for select */
+# include <net/socket.h>
+#endif
+
+#ifdef HAVE_TERMIOS_H
+# include <termios.h>
+#endif
+
+#ifdef VMS
+# include <unixlib.h>
+# include <unixio.h>
+# include <dvidef.h>
+# include <descrip.h>
+# include <lib$routines.h>
+# include <starlet.h>
+#else
+# if !defined(sun)
+#  include <sys/ioctl.h>
+# endif
+#endif
+
+#ifdef SYSV
+# include <sys/termio.h>
+# include <sys/stream.h>
+# include <sys/ptem.h>
+# include <sys/tty.h>
+#endif
+
+#if defined (_AIX) && !defined (FD_SET)
+# include <sys/select.h>	/* for FD_ISSET, FD_SET, FD_ZERO */
+#endif
+
+#include <errno.h>
+
+#if defined(__DECC) && defined(VMS)
+/* These get prototypes for write an sleep */
+# include <unixio.h>
+#endif
+#include <signal.h>
+
+#include "slang.h"
+#include "_slang.h"
+
+/* 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 & FG_MASK) >> 8)
+#define GET_BG(color) ((color & BG_MASK) >> 16)
+#define MAKE_COLOR(fg, bg) (((fg) | ((bg) << 8)) << 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) << 1) | ((b) << 2))
+#define RGB(r, g, b, br, bg, bb)  ((RGB1(r, g, b) << 8) | (RGB1(br, bg, bb) << 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 = "\033[3%dm";
+static char *Color_Bg_Str = "\033[4%dm";
+static char *Default_Color_Fg_Str = "\033[39m";
+static char *Default_Color_Bg_Str = "\033[49m";
+
+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; /* = "\033[4h"; */   /* ins mode (im) */
+static char *Eins_Mode_Str; /* = "\033[4l"; */  /* end ins mode (ei) */
+static char *Scroll_R_Str; /* = "\033[%d;%dr"; */ /* scroll region */
+static char *Cls_Str; /* = "\033[2J\033[H"; */  /* cl termcap STR  for ansi terminals */
+static char *Rev_Vid_Str; /* = "\033[7m"; */    /* mr,so termcap string */
+static char *Norm_Vid_Str; /* = "\033[m"; */   /* me,se termcap string */
+static char *Del_Eol_Str; /* = "\033[K"; */	       /* ce */
+static char *Del_Bol_Str; /* = "\033[1K"; */	       /* cb */
+static char *Del_Char_Str; /* = "\033[P"; */   /* dc */
+static char *Del_N_Lines_Str; /* = "\033[%dM"; */  /* DL */
+static char *Add_N_Lines_Str; /* = "\033[%dL"; */  /* 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 = "\033[%d;%df";  ansi-- hor and vert pos */
+static char *Curs_Pos_Str; /* = "\033[%i%d;%dH";*/   /* 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 >= 70000000)
+   struct timeval tv;
+   tv.tv_sec = usecs / 1000000;
+   tv.tv_usec = usecs % 1000000;
+   return select(0, NULL, NULL, NULL, &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 > 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 < 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 > 150) && (SLtt_Baud_Rate <= 9600))
+       && (10 * total > SLtt_Baud_Rate))
+     {
+	total = 0;
+	if ((now = (unsigned long) time(NULL)) - last_time <= 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 >= ' ') 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)
+	    && Automatic_Margins) Cursor_Set = 0;
+     }
+
+   if (Output_Bufferp < Output_Buffer + MAX_OUTPUT_BUFFER_SIZE)
+     {
+	*Output_Bufferp++ = (unsigned char) ch;
+     }
+   else tt_write (&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 < 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 >= '0') && (ch <= '9'))
+	       stack [stack_len++] = parms [ch - '0'];
+	     break;
+
+	   case '\'':   /* 'x' */
+	     if (fmt == fmt_max) break;
+	     stack [stack_len++] = *fmt++;
+	     if (fmt < fmt_max) fmt++;     /* skip ' */
+	     break;
+
+	   case '{':	       /* literal constant, e.g. {30} */
+	     z = 0;
+	     while ((fmt < fmt_max) && ((ch = *fmt) <= '9') && (ch >= '0'))
+	       {
+		  z = z * 10 + (ch - '0');
+		  fmt++;
+	       }
+	     stack [stack_len++] = z;
+	     if ((ch == '}') && (fmt < fmt_max)) fmt++;
+	     break;
+
+	   case '0':
+	     if (fmt == fmt_max) break;
+	     ch = *fmt;
+	     if ((ch != '2') && (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 >= 100)
+	       {
+		  *b++ = z / 100 + '0';
+		  z = z % 100;
+		  zero_pad = 1;
+		  field_width = 2;
+	       }
+	     else if (zero_pad && (field_width == 3))
+	       *b++ = '0';
+
+	     if (z >= 10)
+	       {
+		  *b++ = z / 10 + '0';
+		  z = z % 10;
+	       }
+	     else if (zero_pad && (field_width >= 2))
+	       *b++ = '0';
+
+	     *b++ = z + '0';
+	     field_width = zero_pad = 0;
+	     break;
+
+	   case 'x':
+	     z = STACK_POP;
+	     z += offset;
+	     sprintf ((char *) b, "%X", 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 > 2)
+	       {
+		  z = STACK_POP;
+		  stack [stack_len - 1] += z;
+	       }
+	     else if (fmt < 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 '&':
+	   case '|':
+	   case '^':
+	   case '=':
+	   case '>':
+	   case '<':
+	   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 '&': z = (z & z1); break;
+		case '|': z = (z | z1); break;
+		case '^': z = (z ^ z1); break;
+		case '=': z = (z == z1); break;
+		case '>': z = (z > z1); break;
+		case '<': z = (z < z1); break;
+		case 'A': z = (z && 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 >= 'a') && (ch <= 'z'))
+	       stack [stack_len++] = variables [ch - 'a'];
+	     break;
+
+	   case 'P':
+	     if (fmt == fmt_max) break;
+	     ch = *fmt++;
+	     if ((ch >= 'a') && (ch <= '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 < 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') && (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 < 0) || (r < 0))
+     {
+	Cursor_Set = 0;
+	return;
+     }
+
+   /* if (No_Move_In_Standout && Current_Fgbg) SLtt_normal_video (); */
+   r += Scroll_r1;
+
+   if ((Cursor_Set > 0) || ((Cursor_Set < 0) && !Automatic_Margins))
+     {
+	n = r - Cursor_r;
+	if ((n == -1) && (Cursor_Set > 0) && (Cursor_c == c)
+	    && (Curs_Up_Str != NULL))
+	  {
+	     s = Curs_Up_Str;
+	  }
+	else if ((n >= 0) && (n <= 4))
+	  {
+	     if ((n == 0) && (Cursor_Set == 1)
+		 && ((c > 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 && (Cursor_Set == 1) &&
+		      (Cursor_c >= c) && (c + 3 > 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("\r");
+   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 <= 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) && Is_Color_Terminal)
+     {
+	if (Reset_Color_String != NULL)
+	  tt_write_string (Reset_Color_String);
+	else
+	  tt_write_string ("\033[0m\033[m");
+     }
+
+   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 & 0x1) SLtt_putchar('\007');
+
+   if (SLtt_Ignore_Beep & 0x2)
+     {
+	if (Visible_Bell_Str != NULL) tt_write_string (Visible_Bell_Str);
+#ifdef __linux__
+	else if (Linux_Console)
+	  {
+	     tt_write_string ("\033[?5h");
+	     SLtt_flush_output ();
+	     _SLusleep (50000);
+	     tt_write_string ("\033[?5l");
+	  }
+#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 < SLtt_Screen_Rows)
+     c++;
+
+   while (c < SLtt_Screen_Cols)
+     {
+	tt_write (" ", 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] =
+{
+     {"black",		SLSMG_COLOR_BLACK},
+     {"red",		SLSMG_COLOR_RED},
+     {"green",		SLSMG_COLOR_GREEN},
+     {"brown",		SLSMG_COLOR_BROWN},
+     {"blue",		SLSMG_COLOR_BLUE},
+     {"magenta",	SLSMG_COLOR_MAGENTA},
+     {"cyan",		SLSMG_COLOR_CYAN},
+     {"lightgray",	SLSMG_COLOR_LGRAY},
+     {"gray",		SLSMG_COLOR_GRAY},
+     {"brightred",	SLSMG_COLOR_BRIGHT_RED},
+     {"brightgreen",	SLSMG_COLOR_BRIGHT_GREEN},
+     {"yellow",		SLSMG_COLOR_BRIGHT_BROWN},
+     {"brightblue",	SLSMG_COLOR_BRIGHT_BLUE},
+     {"brightmagenta",	SLSMG_COLOR_BRIGHT_CYAN},
+     {"brightcyan",	SLSMG_COLOR_BRIGHT_MAGENTA},
+     {"white",		SLSMG_COLOR_BRIGHT_WHITE},
+#define SLSMG_COLOR_DEFAULT 0xFF
+     {"default",		SLSMG_COLOR_DEFAULT}
+};
+
+void SLtt_set_mono (int obj, char *what, SLtt_Char_Type mask)
+{
+   (void) what;
+   if ((obj < 0) || (obj >= JMAX_COLORS))
+     {
+	return;
+     }
+   Ansi_Color_Map[obj].mono = mask & 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 < '0') || (ich > '9'))
+	  return color;
+
+	i = i * 10 + (ich - '0');
+	s++;
+     }
+
+   if (i < 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 ("COLORFGBG");
+
+   if (bg == NULL)
+     {
+	bg = getenv ("DEFAULT_COLORS");
+	if (bg == NULL)
+	  return -1;
+     }
+
+   p = fg_buf;
+   pmax = p + (sizeof (fg_buf) - 1);
+
+   while ((*bg != 0) && (*bg != ';'))
+     {
+	if (p < 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) && (*bg != ';'))
+     {
+	if (p < pmax) *p++ = *bg;
+	bg++;
+     }
+   *p = 0;
+
+   if (!strcmp (fg_buf, "default") || !strcmp(bg_buf, "default"))
+     {
+	*fgp = *bgp = fg = bg = "default";
+     }
+   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 < 0) || (obj >= 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 >> 8) & 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 < 0) || (obj >= JMAX_COLORS)) return 0;
+   return Ansi_Color_Map[obj].fgbg;
+}
+
+void SLtt_add_color_attribute (int obj, SLtt_Char_Type attr)
+{
+   if ((obj < 0) || (obj >= JMAX_COLORS)) return;
+
+   Ansi_Color_Map[obj].fgbg |= (attr & 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 << 8) | (b << 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 & 0x8) attr = SLTT_BOLD_MASK;
+	f &= 0x7;
+     }
+
+   if (b != SLSMG_COLOR_DEFAULT)
+     {
+	if (b & 0x8) attr |= SLTT_BLINK_MASK;
+	b &= 0x7;
+     }
+
+   return ((f << 8) | (b << 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, "color", 5))
+     return -1;
+
+   color += 5;
+   if (*color == 0)
+     return -1;
+
+   i = 0;
+   while (1)
+     {
+	ch = (unsigned char) *color++;
+	if (ch == 0)
+	  break;
+	if ((ch > '9') || (ch < '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) && (*fg == 0)) fg = NULL;
+   if ((bg != NULL) && (*bg == 0)) bg = NULL;
+
+   if ((fg == NULL) || (bg == NULL))
+     {
+	if (-1 == get_default_colors (&dfg, &dbg))
+	  return -1;
+
+	if (fg == NULL) fg = dfg;
+	if (bg == NULL) bg = dbg;
+     }
+
+   if (-1 == parse_color_digit_name (fg, &f))
+     {
+	for (i = 0; i < 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, &b))
+     {
+	for (i = 0; i < 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 < 0) || (obj >= JMAX_COLORS))
+     return;
+
+   if (-1 != make_color_fgbg (fg, bg, &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 < 0) || (obj >= 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 >> 8) & 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 < 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 >> 8) & 0x7F;
+		  break;
+	       }
+	  }
+	FgBg_Stats[fgbg] += 1;
+     }
+
+   fgbg |= 0x80;
+   Ansi_Color_Map[obj].fgbg = (fgbg | (fgbg << 8)) << 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 & ATTR_MASK) != (Current_Fgbg & ATTR_MASK))
+     {
+	if (Current_Fgbg & ATTR_MASK)
+	  {
+	     tt_write_string(Norm_Vid_Str);
+	     /* In case normal video turns off ALL attributes: */
+	     if (fgbg & SLTT_ALTC_MASK)
+	       Current_Fgbg &= ~SLTT_ALTC_MASK;
+	     SLtt_set_alt_char_set (0);
+	  }
+
+	if ((fgbg & SLTT_ALTC_MASK)
+	    != (Current_Fgbg & SLTT_ALTC_MASK))
+	  {
+	     SLtt_set_alt_char_set ((int) (fgbg & SLTT_ALTC_MASK));
+	  }
+
+	if (fgbg & SLTT_ULINE_MASK) tt_write_string (UnderLine_Vid_Str);
+	if (fgbg & SLTT_BOLD_MASK) SLtt_bold_video ();
+	if (fgbg & SLTT_REV_MASK) tt_write_string (Rev_Vid_Str);
+	if (fgbg & 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 < 0) || (color >= 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("\033[?3l");
+}
+
+void SLtt_wide_width (void)
+{
+   tt_write_string("\033[?3h");
+}
+
+/* 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 & COLOR_MASK) >> 8;
+   b = (b & COLOR_MASK) >> 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) & COLOR_MASK) >> 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) & ~COLOR_MASK) == ((b) & ~COLOR_MASK))\
+			    && 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 && (Cursor_r + 1 == SLtt_Screen_Rows))
+     {
+	if (len + (unsigned int) Cursor_c >= (unsigned int) SLtt_Screen_Cols)
+	  {
+	     /* For now, just do not write there.  Later, something more
+	      * sophisticated will be implemented.
+	      */
+	     if (SLtt_Screen_Cols > 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 & 0xFF;
+	color = ((int) sh & 0xFF00) >> 8;
+
+#if SLTT_HAS_NON_BCE_SUPPORT
+	if (Bce_Color_Offset
+	    && (color >= Bce_Color_Offset))
+	  color -= Bce_Color_Offset;
+#endif
+
+	if (color != last_color)
+	  {
+	     if (SLtt_Use_Ansi_Colors) attr = Ansi_Color_Map[color & 0x7F].fgbg;
+	     else attr = Ansi_Color_Map[color & 0x7F].mono;
+
+	     if (sh & 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 & BGALL_MASK) != (Current_Fgbg & 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 && (NULL != Ansi_Color_Map[color & 0x7F].custom_esc))
+			 {
+			    tt_write_string (Ansi_Color_Map[color & 0x7F].custom_esc);
+			    /* Just in case the custom escape sequence screwed up
+			     * the alt character set state...
+			     */
+	                    if ((attr & SLTT_ALTC_MASK) != (Current_Fgbg & SLTT_ALTC_MASK))
+			      SLtt_set_alt_char_set ((int) (attr & 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 <= 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)
+       && (len == SLtt_Screen_Cols)
+       && (len > 1)
+       && (SLtt_Term_Cannot_Insert == 0)
+       && 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 & 0x80)
+	  { /* new is kanji */
+	     if ((*q & 0x80) && ((q + 1) < qmax))
+	       { /* old is also kanji */
+		  if (((0xFF & *q) != (0xFF & *p))
+		      || ((0xFF & q[1]) != (0xFF & 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 & 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 < qmax)
+	  {
+	     if (*qq & 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) & 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)
+	    && SLtt_Use_Ansi_Colors)
+	  space_char = *(pmax - 1);
+
+	while (pmax > p)
+	  {
+	     pmax--;
+	     if (!CHAR_EQS(*pmax, space_char))
+	       {
+		  pmax++;
+		  break;
+	       }
+	  }
+     }
+
+   while (qmax > 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 < 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) && ((*neww & 0xFF) == 32))
+	  {
+	     SLsmg_Char_Type *p1;
+	     SLsmg_Char_Type blank;
+
+	     p1 = neww;
+	     if ((Can_Background_Color_Erase)
+		 && SLtt_Use_Ansi_Colors)
+	       blank = *p1;
+	     /* black+white attributes do not support bce */
+	     else
+	       blank = 32;
+
+	     while ((p1 < pmax) && (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 > neww + 13) 
+		 && (p1 >= p)
+		 /* Avoid erasing from the end of the line */
+		 && ((p1 != pmax) || (pmax < neww + len)))
+	       {
+		  int ofs = (int) (p1 - neww);
+		  q = oldd + ofs;
+		  p = p1;
+		  SLtt_goto_rc (row, ofs - 1);
+		  SLtt_reverse_video (blank >> 8);
+		  tt_write_string (Del_Bol_Str);
+		  tt_write (" ", 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 < pmax)
+	  {
+	     if (CHAR_EQS(*q, 32) && 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 < pmax)
+			 && CHAR_EQS(*q, 32)
+			 && CHAR_EQS(*p, 32))
+		    {
+		       p++;
+		       q++;
+		    }
+		  n_spaces = (unsigned int) (p - space_match);
+		  break;
+	       }
+#if SLANG_HAS_KANJI_SUPPORT
+	     if ((*p & 0x80) && ((p + 1) < pmax))
+	       { /* new is kanji */
+		  if (*q & 0x80)
+		    { /* old is also kanji */
+		       if (((0xFF & *q) != (0xFF & *p))
+			   || ((0xFF & q[1]) != (0xFF & 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 & 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 
+	    && ((p < 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 < pmax) && CHAR_EQS(*p, *q))
+	  {
+	     *buf++ = *p++;
+	     q++;
+	  }
+#else
+	/* Kanji */
+	while (p < pmax)
+	  {
+	     if ((*p & 0x80) && ((p + 1) < pmax))
+	       { /* new is kanji */
+		  if (*q & 0x80)
+		    { /* old is also kanji */
+		       if (((0xFF & *q) == (0xFF & *p))
+			   && ((0xFF & q[1]) == (0xFF & p[1])))
+			 {
+			    /* kanji match ? */
+			    if (!COLOR_EQS(*q, *p)
+				|| !COLOR_EQS(q[1], p[1]))
+			      break;
+
+			    *buf++ = *p++;
+			    q++;
+			    if (p >= 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 & 0x80) break; /* old is kanji */
+		  if (!CHAR_EQS(*q, *p)) break;
+		  *buf++ = *p++;
+		  q++;
+	       }
+	  }
+#endif
+	last_buffered_match = buf;
+	if (p >= 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) >= 5)
+	  {
+	     forward_cursor ((unsigned int) (buf - buffer), row);
+	     last_buffered_match = buf = buffer;
+	  }
+     }
+
+   if (buf != buffer)
+     {
+	if (q < qmax)
+	  {
+	     if ((buf == last_buffered_match)
+		 && ((int) (buf - buffer) >= 5))
+	       {
+		  forward_cursor ((unsigned int) (buf - buffer), row);
+	       }
+	     else
+	       {
+		  *buf = 0;
+		  send_attr_str (buffer);
+	       }
+	  }
+     }
+
+   if (q < qmax) 
+     {
+	SLtt_reverse_video (space_char >> 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 && (Cursor_c + 1 >= 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 ("COLORTERM"));
+
+   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 ("COLORTERM_BCE"));
+#endif
+
+   if (-1 == get_default_colors (&fg, &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) > 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 >= '0') && (*what <= '9'))) what++;
+   if (*what == '*') what++;
+   
+   /* lose terminfo padding--- looks like $<...> */
+   w = what;
+   while (*w) if ((*w++ == '$') && (*w == '<'))
+     {
+	w1 = w - 1;
+	while (*w && (*w != '>')) 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, &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 ("TERM");
+   if (term == NULL)
+     SLang_exit_error("TERM environment variable needs set.");
+
+   if (0 == (status = SLtt_initialize (term)))
+     return;
+
+   if (status == -1)
+     {
+	SLang_exit_error ("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.",
+			  term);
+     }
+
+   if (status == -2)
+     {
+	SLang_exit_error ("\
+Your terminal lacks the ability to clear the screen or position the cursor.\n");
+     }
+}
+
+/* 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 ("TERM");
+	if (term == NULL)
+	  return -1;
+     }
+
+   Linux_Console = (!strncmp (term, "linux", 5)
+# ifdef linux
+		    || !strncmp(term, "con", 3)
+# endif
+		    );
+
+   t = term;
+
+   if (strcmp(t, "vt52") && (*t++ == 'v') && (*t++ == 't')
+       && (ch = *t, (ch >= '1') && (ch <= '9'))) Vt100_Like = 1;
+
+   is_xterm = ((0 == strncmp (term, "xterm", 5))
+	       || (0 == strncmp (term, "rxvt", 4))
+	       || (0 == strncmp (term, "Eterm", 5)));
+
+   almost_vtxxx = (Vt100_Like
+		   || Linux_Console
+		   || is_xterm
+		   || !strcmp (term, "screen"));
+
+# ifndef USE_TERMCAP
+   if (NULL == (Terminfo = _SLtt_tigetent (term)))
+     {
+	if (almost_vtxxx) /* Special cases. */
+	  {
+	     int vt102 = 1;
+	     if (!strcmp (term, "vt100")) vt102 = 0;
+	     get_color_info ();
+   	     SLtt_set_term_vtxxx (&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 ("cl");
+   Curs_Pos_Str = SLtt_tgetstr ("cm");
+
+   if ((NULL == (Ins_Mode_Str = SLtt_tgetstr("im")))
+       || ( NULL == (Eins_Mode_Str = SLtt_tgetstr("ei")))
+       || ( NULL == (Del_Char_Str = SLtt_tgetstr("dc"))))
+     SLtt_Term_Cannot_Insert = 1;
+
+   Visible_Bell_Str = SLtt_tgetstr ("vb");
+   Curs_Up_Str = SLtt_tgetstr ("up");
+   Rev_Scroll_Str = SLtt_tgetstr("sr");
+   Del_N_Lines_Str = SLtt_tgetstr("DL");
+   Add_N_Lines_Str = SLtt_tgetstr("AL");
+
+   /* Actually these are used to initialize terminals that use cursor
+    * addressing.  Hard to believe.
+    */
+   Term_Init_Str = SLtt_tgetstr ("ti");
+   Term_Reset_Str = SLtt_tgetstr ("te");
+
+   /* 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 ("ks");
+	Keypad_Reset_Str = SLtt_tgetstr ("ke");
+     }
+
+   /* Make up for defective termcap/terminfo databases */
+   if ((Vt100_Like && (term[2] != '1'))
+       || Linux_Console
+       || is_xterm
+       )
+     {
+	if (Del_N_Lines_Str == NULL) Del_N_Lines_Str = "\033[%dM";
+	if (Add_N_Lines_Str == NULL) Add_N_Lines_Str = "\033[%dL";
+     }
+
+   Scroll_R_Str = SLtt_tgetstr("cs");
+
+   SLtt_get_screen_size ();
+
+   if ((Scroll_R_Str == NULL)
+       || (((NULL == Del_N_Lines_Str) || (NULL == Add_N_Lines_Str))
+	   && (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("ce");
+   Del_Bol_Str = SLtt_tgetstr("cb");
+   if (is_xterm && (Del_Bol_Str == NULL))
+     Del_Bol_Str = "\033[1K";
+   if (is_xterm && (Del_Eol_Str == NULL))
+     Del_Bol_Str = "\033[K";
+
+   Rev_Vid_Str = SLtt_tgetstr("mr");
+   if (Rev_Vid_Str == NULL) Rev_Vid_Str = SLtt_tgetstr("so");
+
+   Bold_Vid_Str = SLtt_tgetstr("md");
+
+   /* 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("mb")))
+       && is_xterm)
+     Blink_Vid_Str = "\033[5m";
+
+   UnderLine_Vid_Str = SLtt_tgetstr("us");
+
+   Start_Alt_Chars_Str = SLtt_tgetstr ("as");   /* smacs */
+   End_Alt_Chars_Str = SLtt_tgetstr ("ae");   /* rmacs */
+   Enable_Alt_Char_Set = SLtt_tgetstr ("eA");   /* enacs */
+   SLtt_Graphics_Char_Pairs = SLtt_tgetstr ("ac");
+
+   if (NULL == SLtt_Graphics_Char_Pairs)
+     {
+	/* make up for defective termcap/terminfo */
+	if (Vt100_Like)
+	  {
+	     Start_Alt_Chars_Str = "\016";
+	     End_Alt_Chars_Str = "\017";
+	     Enable_Alt_Char_Set = "\033)0";
+	  }
+     }
+
+    /* aixterm added by willi */
+   if (is_xterm || !strncmp (term, "aixterm", 7))
+     {
+	Start_Alt_Chars_Str = "\016";
+	End_Alt_Chars_Str = "\017";
+	Enable_Alt_Char_Set = "\033(B\033)0";
+     }
+
+   if ((SLtt_Graphics_Char_Pairs == NULL) &&
+       ((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)
+       && (0 != (SLtt_Has_Status_Line = TGETFLAG ("hs"))))
+     {
+	Disable_Status_line_Str = SLtt_tgetstr ("ds");
+	Return_From_Status_Line_Str = SLtt_tgetstr ("fs");
+	Goto_Status_Line_Str = SLtt_tgetstr ("ts");
+	/* Status_Line_Esc_Ok = TGETFLAG("es"); */
+	Num_Status_Line_Columns = SLtt_tgetnum ("ws");
+	if (Num_Status_Line_Columns < 0) Num_Status_Line_Columns = 0;
+     }
+
+   if (NULL == (Norm_Vid_Str = SLtt_tgetstr("me")))
+     {
+	Norm_Vid_Str = SLtt_tgetstr("se");
+     }
+
+   Cursor_Invisible_Str = SLtt_tgetstr("vi");
+   Cursor_Visible_Str = SLtt_tgetstr("ve");
+
+   Curs_F_Str = SLtt_tgetstr("RI");
+
+# 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 ("am");
+   /* No_Move_In_Standout = !TGETFLAG ("ms"); */
+# ifdef HP_GLITCH_CODE
+   Has_HP_Glitch = TGETFLAG ("xs");
+# else
+   Worthless_Highlight = TGETFLAG ("xs");
+# endif
+
+   if (Worthless_Highlight == 0)
+     {				       /* Magic cookie glitch */
+	Worthless_Highlight = (SLtt_tgetnum ("sg") > 0);
+     }
+
+   if (Worthless_Highlight)
+     SLtt_Has_Alt_Charset = 0;
+
+   Reset_Color_String = SLtt_tgetstr ("op");
+   Color_Fg_Str = SLtt_tgetstr ("AF"); /* ANSI setaf */
+   Color_Bg_Str = SLtt_tgetstr ("AB"); /* ANSI setbf */
+   if ((Color_Fg_Str == NULL) || (Color_Bg_Str == NULL))
+     {
+	Color_Fg_Str = SLtt_tgetstr ("Sf");   /* setf */
+	Color_Bg_Str = SLtt_tgetstr ("Sb");   /* setb */
+     }
+
+   if ((Max_Terminfo_Colors = SLtt_tgetnum ("Co")) < 0)
+     Max_Terminfo_Colors = 8;
+
+   if ((Color_Bg_Str != NULL) && (Color_Fg_Str != NULL))
+     SLtt_Use_Ansi_Colors = 1;
+   else
+     {
+#if 0
+	Color_Fg_Str = "%?%p1%{7}%>%t\033[1;3%p1%{8}%m%dm%e\033[3%p1%dm%;";
+	Color_Bg_Str = "%?%p1%{7}%>%t\033[5;4%p1%{8}%m%dm%e\033[4%p1%dm%;";
+	Max_Terminfo_Colors = 16;
+#else
+	Color_Fg_Str = "\033[3%dm";
+	Color_Bg_Str = "\033[4%dm";
+	Max_Terminfo_Colors = 8;
+#endif
+     }
+
+#if SLTT_HAS_NON_BCE_SUPPORT
+   Can_Background_Color_Erase = TGETFLAG ("ut");   /* 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("\033=\033[?1l");
+}
+
+#ifdef VMS
+int SLtt_initialize (char *term)
+{
+   SLtt_get_terminfo ();
+   return 0;
+}
+
+void SLtt_get_terminfo ()
+{
+   int zero = 0;
+
+   Color_Fg_Str = "\033[3%dm";
+   Color_Bg_Str = "\033[4%dm";
+   Max_Terminfo_Colors = 8;
+
+   get_color_info ();
+
+   SLtt_set_term_vtxxx(&zero);
+   Start_Alt_Chars_Str = "\016";
+   End_Alt_Chars_Str = "\017";
+   SLtt_Has_Alt_Charset = 1;
+   SLtt_Graphics_Char_Pairs = "aaffgghhjjkkllmmnnooqqssttuuvvwwxx";
+   Enable_Alt_Char_Set = "\033(B\033)0";
+   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 = "\033[m";
+
+   Scroll_R_Str = "\033[%i%d;%dr";
+   Cls_Str = "\033[2J\033[H";
+   Rev_Vid_Str = "\033[7m";
+   Bold_Vid_Str = "\033[1m";
+   Blink_Vid_Str = "\033[5m";
+   UnderLine_Vid_Str = "\033[4m";
+   Del_Eol_Str = "\033[K";
+   Del_Bol_Str = "\033[1K";
+   Rev_Scroll_Str = "\033M";
+   Curs_F_Str = "\033[%dC";
+   /* Len_Curs_F_Str = 5; */
+   Curs_Pos_Str = "\033[%i%d;%dH";
+   if ((vt100 == NULL) || (*vt100 == 0))
+     {
+	Ins_Mode_Str = "\033[4h";
+	Eins_Mode_Str = "\033[4l";
+	Del_Char_Str =  "\033[P";
+	Del_N_Lines_Str = "\033[%dM";
+	Add_N_Lines_Str = "\033[%dL";
+	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("\033[?6h"); */
+   /* 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, &attr))
+	       write_attributes (attr);
+	     else tt_write_string ("\033[0m\033[m");
+	  }
+	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("TERM"))) return -1;
+	if (strncmp ("xterm", term, 5))
+	  return -1;
+     }
+
+   if (mode)
+     tt_write_string ("\033[?9h");
+   else
+     tt_write_string ("\033[?9l");
+
+   return 0;
+}
+
+void SLtt_disable_status_line (void)
+{
+   if (SLtt_Has_Status_Line > 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 <= 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, "SYS$INPUT:");
+#endif
+   int r = 0, c = 0;
+
+#ifdef TIOCGWINSZ
+   struct winsize wind_struct;
+
+   do
+     {
+	if ((ioctl(1,TIOCGWINSZ,&wind_struct) == 0)
+	    || (ioctl(0, TIOCGWINSZ, &wind_struct) == 0)
+	    || (ioctl(2, TIOCGWINSZ, &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(&dev_dsc,&chan,0,0,0);
+   if (status & 1)
+     {
+	code = DVI$_DEVBUFSIZ;
+	status = lib$getdvi(&code, &chan,0, &c, 0,0);
+	if (!(status & 1))
+	  c = 80;
+	code = DVI$_TT_PAGE;
+	status = lib$getdvi(&code, &chan,0, &r, 0,0);
+	if (!(status & 1))
+	  r = 24;
+	sys$dassgn(chan);
+     }
+#endif
+
+   if (r <= 0)
+     {
+	char *s = getenv ("LINES");
+	if (s != NULL) r = atoi (s);
+     }
+
+   if (c <= 0)
+     {
+	char *s = getenv ("COLUMNS");
+	if (s != NULL) c = atoi (s);
+     }
+
+   if (r <= 0) r = 24;
+   if (c <= 0) c = 80;
+#if 0
+   if ((r <= 0) || (r > 200)) r = 24;
+   if ((c <= 0) || (c > 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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+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 = "Not Implemented"; break;
+      case SL_APPLICATION_ERROR: str = "Application Error"; break;
+      case SL_VARIABLE_UNINITIALIZED: str = "Variable Uninitialized"; break;
+      case SL_MALLOC_ERROR : str = "Malloc Error"; break;
+      case SL_INTERNAL_ERROR: str = "Internal Error"; break;
+      case SL_STACK_OVERFLOW: str = "Stack Overflow"; break;
+      case SL_STACK_UNDERFLOW: str = "Stack Underflow"; break;
+      case SL_INTRINSIC_ERROR: str = "Intrinsic Error"; break;
+      case SL_USER_BREAK: str = "User Break"; break;
+      case SL_UNDEFINED_NAME: str = "Undefined Name"; break;
+      case SL_SYNTAX_ERROR: str = "Syntax Error"; break;
+      case SL_DUPLICATE_DEFINITION: str = "Duplicate Definition"; break;
+      case SL_TYPE_MISMATCH: str = "Type Mismatch"; break;
+      case SL_READONLY_ERROR: str = "Variable is read-only"; break;
+      case SL_DIVIDE_ERROR: str = "Divide by zero"; break;
+      case SL_OBJ_NOPEN: str = "Object not opened"; break;
+      case SL_OBJ_UNKNOWN: str = "Object unknown"; break;
+      case SL_INVALID_PARM: str = "Invalid Parameter"; break;
+      case SL_TYPE_UNDEFINED_OP_ERROR:
+	str = "Operation not defined for datatype"; break;
+      case SL_USER_ERROR:
+	str = "User Error"; break;
+      case SL_USAGE_ERROR:
+	str = "Illegal usage of function";
+	break;
+      case SL_FLOATING_EXCEPTION:
+	str = "Floating Point Exception";
+	break;
+      case SL_UNKNOWN_ERROR:
+      default: str = "Unknown Error Code";
+     }
+
+   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))
+       && (error != NULL) && (*error != 0))
+     err = error;
+   else
+     {
+	char *sle = "S-Lang Error: ";
+	unsigned int len;
+	char *fmt;
+
+	str = get_error_string ();
+
+	fmt = "%s%s%s";
+	if ((error == NULL) || (*error == 0))
+	  error = "";
+	else if (SLang_Error == SL_UNKNOWN_ERROR)
+	  /* Do not display an unknown error message if error is non-NULL */
+	  str = "";
+	else
+	  fmt = "%s%s: %s";
+
+	len = strlen (sle) + strlen (str) + strlen(error) + 1;
+
+	err = err_buf;
+	if (len >= 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 = "Out of memory";
+     }
+
+   if (SLang_Error_Hook == NULL)
+     {
+	fputs (err, stderr);
+	fputs("\r\n", 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 ("\r\n", 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 ("\r\n", 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 "slinclud.h"
+
+#include <errno.h>
+#include "slang.h"
+#include "_slang.h"
+
+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
+     {"Not owner",			EPERM,	"EPERM"},
+#ifndef ENOENT
+# define ENOENT	-1
+#endif
+     {"No such file or directory",	ENOENT,	"ENOENT"},
+#ifndef ESRCH
+# define ESRCH	-1
+#endif
+     {"No such process",		ESRCH,	"ESRCH"},
+#ifndef EINTR
+# define EINTR	-1
+#endif
+     {"Interrupted system call",	EINTR,	"EINTR"},
+#ifndef EIO
+# define EIO	-1
+#endif
+     {"I/O error",			EIO,	"EIO"},
+#ifndef ENXIO
+# define ENXIO	-1
+#endif
+     {"No such device or address",	ENXIO,	"ENXIO"},
+#ifndef E2BIG
+# define E2BIG	-1
+#endif
+     {"Arg list too long",		E2BIG,	"E2BIG"},
+#ifndef ENOEXEC
+# define ENOEXEC	-1
+#endif
+     {"Exec format error",		ENOEXEC,"ENOEXEC"},
+#ifndef EBADF
+# define EBADF	-1
+#endif
+     {"Bad file number",		EBADF,	"EBADF"},
+#ifndef ECHILD
+# define ECHILD	-1
+#endif
+     {"No children",			ECHILD,	"ECHILD"},
+#ifndef EAGAIN
+# define EAGAIN	-1
+#endif
+     {"Try again",			EAGAIN,	"EAGAIN"},
+#ifndef ENOMEM
+# define ENOMEM	-1
+#endif
+     {"Not enough core",		ENOMEM,	"ENOMEM"},
+#ifndef EACCES
+# define EACCES	-1
+#endif
+     {"Permission denied",		EACCES,	"EACCES"},
+#ifndef EFAULT
+# define EFAULT	-1
+#endif
+     {"Bad address",			EFAULT,	"EFAULT"},
+#ifndef ENOTBLK
+# define ENOTBLK	-1
+#endif
+     {"Block device required",		ENOTBLK,	"ENOTBLK"},
+#ifndef EBUSY
+# define EBUSY	-1
+#endif
+     {"Mount device busy",		EBUSY,	"EBUSY"},
+#ifndef EEXIST
+# define EEXIST	-1
+#endif
+     {"File exists",			EEXIST,	"EEXIST"},
+#ifndef EXDEV
+# define EXDEV	-1
+#endif
+     {"Cross-device link",		EXDEV,	"EXDEV"},
+#ifndef ENODEV
+# define ENODEV	-1
+#endif
+     {"No such device",			ENODEV,	"ENODEV"},
+#ifndef ENOTDIR
+# define ENOTDIR	-1
+#endif
+     {"Not a directory",		ENOTDIR,	"ENOTDIR"},
+#ifndef EISDIR
+# define EISDIR	-1
+#endif
+     {"Is a directory",			EISDIR,	"EISDIR"},
+#ifndef EINVAL
+# define EINVAL	-1
+#endif
+     {"Invalid argument",		EINVAL,	"EINVAL"},
+#ifndef ENFILE
+# define ENFILE	-1
+#endif
+     {"File table overflow",		ENFILE,	"ENFILE"},
+#ifndef EMFILE
+# define EMFILE	-1
+#endif
+     {"Too many open files",		EMFILE,	"EMFILE"},
+#ifndef ENOTTY
+# define ENOTTY	-1
+#endif
+     {"Not a typewriter",		ENOTTY,	"ENOTTY"},
+#ifndef ETXTBSY
+# define ETXTBSY	-1
+#endif
+     {"Text file busy",			ETXTBSY,	"ETXTBSY"},
+#ifndef EFBIG
+# define EFBIG	-1
+#endif
+     {"File too large",			EFBIG,	"EFBIG"},
+#ifndef ENOSPC
+# define ENOSPC	-1
+#endif
+     {"No space left on device",	ENOSPC,	"ENOSPC"},
+#ifndef ESPIPE
+# define ESPIPE	-1
+#endif
+     {"Illegal seek",			ESPIPE,	"ESPIPE"},
+#ifndef EROFS
+# define EROFS	-1
+#endif
+     {"Read-only file system",		EROFS,	"EROFS"},
+#ifndef EMLINK
+# define EMLINK	-1
+#endif
+     {"Too many links",			EMLINK,	"EMLINK"},
+#ifndef EPIPE
+# define EPIPE	-1
+#endif
+     {"Broken pipe",			EPIPE,	"EPIPE"},
+#ifndef ELOOP
+# define ELOOP	-1
+#endif
+     {"Too many levels of symbolic links",ELOOP,	"ELOOP"},
+#ifndef ENAMETOOLONG
+# define ENAMETOOLONG	-1
+#endif
+     {"File name too long",		ENAMETOOLONG,	"ENAMETOOLONG"},
+
+     {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->msg != NULL)
+     {
+	if (e->sys_errno == sys_errno)
+	  return e->msg;
+
+	e++;
+     }
+
+   if (sys_errno == SL_ERRNO_NOT_IMPLEMENTED)
+     return "System call not available for this platform";
+
+   return "Unknown error";
+}
+
+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 ("errno_string", (FVOID_STAR) intrin_errno_string,
+				       SLANG_STRING_TYPE, 1, SLANG_INT_TYPE))
+       || (-1 == SLadd_intrinsic_variable ("errno", (VOID_STAR)&_SLerrno_errno, SLANG_INT_TYPE, 1)))
+     return -1;
+
+   e = Errno_Map;
+   while (e->msg != NULL)
+     {
+	if (-1 == SLadd_intrinsic_variable (e->symbolic_name, (VOID_STAR) &e->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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+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 & 0x80)
+     {
+	unsigned char i;
+	i = (unsigned char) (ch & 0x7F);
+	if (i < ' ')
+	  {
+	     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 > SL_MAX_INPUT_BUFFER_LEN)
+     return -1;
+
+   b = SLang_Input_Buffer;
+   bmax = (b - 1) + SLang_Input_Buffer_Len;
+   b1 = bmax + n;
+   while (bmax >= b) *b1-- = *bmax--;
+   bmax = b + n;
+   while (b < 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 > 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(&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 <= 0) return 0;
+
+   c = (unsigned char) SLang_getkey ();
+   SLang_ungetkey_string (&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) > 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 &= (_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 & 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 '<':			       /* F2 */
+	*b++ = '1';
+	*b++ = '2';
+	break;
+      case '=':			       /* F3 */
+	*b++ = '1';
+	*b++ = '3';
+	break;
+
+      case '>':			       /* 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 && shift)
+     {
+	if (shift == _SLTT_KEY_CTRL)
+	  end &= 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, &scan))
+	  return scan;
+     }
+   
+   if (getkey)
+     {
+	buf[0] = scan & 0xFF;
+	SLang_buffer_keystring (buf, 1);
+	return (scan >> 8) & 0xFF;
+     }
+   buf[0] = (scan >> 8) & 0xFF;
+   buf[1] = scan & 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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+#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 <dlfcn.h>
+#endif
+
+static char *Module_Path;
+#define MODULE_PATH_ENV_NAME	"SLANG_MODULE_PATH"
+#ifndef MODULE_INSTALL_DIR
+# define MODULE_INSTALL_DIR "/usr/local/lib/slang/modules"
+#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->next;
+
+	if (Handle_List->deinit_fun != NULL)
+	  Handle_List->deinit_fun ();
+	(void) dlclose (Handle_List->handle);
+	SLang_free_slstring (Handle_List->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->name = SLang_create_slstring (name)))
+     {
+	SLfree ((char *) l);
+	return NULL;
+     }
+   l->handle = h;
+   l->next = Handle_List;
+   l->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->name, name))
+	  break;
+	l = l->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), "./%s", file);
+	     file = filebuf;
+	     continue;
+	  }
+
+	if (NULL == (err = (char *) dlerror ()))
+	  err = "UNKNOWN";
+
+	SLang_verror (SL_INTRINSIC_ERROR,
+		      "Error linking to %s: %s", 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) 
+	    && (0 != strcmp (ns, "Global")))
+	  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 = "UNKNOWN";
+
+   dlclose (handle);
+   SLang_verror (SL_INTRINSIC_ERROR,
+		 "Unable to get symbol %s from %s: %s",
+		 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 (&ns))
+	  return;	
+     }
+   
+   if (-1 == SLang_pop_slstring (&module))
+     {
+	SLang_free_slstring (ns);      /* NULL ok */
+	return;
+     }
+
+   _SLsnprintf (symbol_name, sizeof(symbol_name), "init_%s_module", module);
+   _SLsnprintf (module_name, sizeof(module_name), "%s-module.so", module);
+   _SLsnprintf (deinit_name, sizeof(deinit_name), "deinit_%s_module", module);
+   _SLsnprintf (ns_init_name, sizeof (ns_init_name), "init_%s_module_ns", module);
+
+   if (Module_Path != NULL)
+     file = SLpath_find_file_in_path (Module_Path, module_name);
+   else file = NULL;
+
+   if ((file == NULL)
+       && (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("import", import_module, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_S("set_import_module_path", set_import_module_path, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_0("get_import_module_path", 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, "__IMPORT__");
+#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 "config.h"
+#include "sl-feat.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_MALLOC_H
+# include <malloc.h>
+#endif
+
+#ifdef HAVE_MEMORY_H
+# include <memory.h>
+#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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+/* 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 *) &s))
+     return NULL;
+
+   if (NULL == (struct_addr = *(char **)s->addr))
+     {
+	SLang_verror (SL_INTRINSIC_ERROR,
+		      "%s is NULL.  Unable to access field", s->name);
+	return NULL;
+     }
+
+   f = s->fields;
+   while (f->field_name != NULL)
+     {
+	/* Since both these are slstrings, just test pointers */
+	if (f->field_name != name)
+	  {
+	     f++;
+	     continue;
+	  }
+
+	if (no_readonly && f->read_only)
+	  {
+	     SLang_verror (SL_READONLY_ERROR,
+			   "%s.%s is read-only", s->name, name);
+	     return NULL;
+	  }
+
+	*addr = (VOID_STAR) (struct_addr + f->offset);
+	return f;
+     }
+
+   SLang_verror (SL_TYPE_MISMATCH,
+		 "%s has no field called %s", s->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, &addr)))
+     return -1;
+
+   type = f->type;
+   cl = _SLclass_get_class (type);
+
+   return (cl->cl_push_intrinsic)(f->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, &addr)))
+     return -1;
+
+   type = f->type;
+   cl = _SLclass_get_class (type);
+
+   return (*cl->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->addr == NULL)
+       || (*(char **) s->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) &v);
+}
+
+static int init_intrin_struct (void)
+{
+   SLang_Class_Type *cl;
+   static int initialized;
+
+   if (initialized)
+     return 0;
+
+   if (NULL == (cl = SLclass_allocate_class ("IStruct_Type")))
+     return -1;
+
+   cl->cl_pop = istruct_pop;
+   cl->cl_push = istruct_push;
+   cl->cl_sget = istruct_sget;
+   cl->cl_sput = istruct_sput;
+   cl->cl_destroy = istruct_destroy;
+   cl->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,
+		      "SLadd_istruct_table: address must be non-NULL");
+	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->field_name != NULL)
+     {
+	char *fname;
+
+	fname = SLang_create_slstring (f->field_name);
+	if (fname == NULL)
+	  return -1;
+
+	/* Here is the check for the slstring */
+	if (f->field_name == fname)
+	  SLang_free_slstring (fname);
+	else /* replace string literal with slstring */
+	  f->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->name = SLang_create_slstring (name)))
+     {
+	SLfree ((char *) s);
+	return -1;
+     }
+
+   s->addr = addr;
+   s->fields = fields;
+
+   if (-1 == SLadd_intrinsic_variable (name, (VOID_STAR) s, SLANG_ISTRUCT_TYPE, 1))
+     {
+	SLang_free_slstring (s->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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+/* 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) >= 'a') && ((x) <= 'z') ? (x) - 32 : (x))
+#define LOWER_CASE_KEY(x) (((x) >= 'A') && ((x) <= '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->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 < 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 &SLKeyMap_List[i];
+	  }
+     }
+   SLang_Error = SL_UNKNOWN_ERROR;
+   /* SLang_doerror ("Keymap quota exceeded."); */
+   return NULL;
+}
+
+FVOID_STAR SLang_find_key_function(char *name, SLKeyMap_List_Type *keymap)
+{
+   SLKeymap_Function_Type *fp = keymap -> functions;
+   char ch = *name;
+
+   while ((fp != NULL) && (fp->name != NULL))
+     {
+	if ((ch == *fp->name)
+	    && (0 == strcmp(fp->name, name)))
+	  return (FVOID_STAR) fp->f;
+
+	fp++;
+     }
+   return NULL;
+}
+
+#ifdef REAL_UNIX_SYSTEM
+/* Expand termcap string specified by s.  s as passed will have the format:
+ *   "XY)..."  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, "setkey: ^(%s is badly formed", s);
+	return NULL;
+     }
+   s += 3;
+
+   c[2] = 0;
+   if ((NULL == (val = SLtt_tgetstr (c)))
+       || (*val == 0))
+     return NULL;
+
+   i = *ip;
+   while ((i < imax) && (*val != 0))
+     {
+	str[i++] = *val++;
+     }
+   *ip = i;
+
+   return s;
+}
+#endif
+
+/* convert things like "^A" 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 < 32)
+		    str[i++] = '^';
+		  break;
+	       }
+#ifdef REAL_UNIX_SYSTEM
+	     if (ch == '(')
+	       {
+		  s = process_termcap_string (s, str, &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 >= 32) break;
+	str[i++] = ch;
+     }
+
+   if (i > SLANG_MAX_KEYMAP_KEY_SEQ)
+     {
+	SLang_verror (SL_INVALID_PARM, "Key sequence is too long");
+	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 < 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 = "Inconsistency in define key.";
+
+/* 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->keymap + ch;
+
+   if (str_len == 2)
+     {
+	if (key->next != NULL)
+	  {
+	     SLang_doerror (Define_Key_Error);
+	     return -2;
+	  }
+
+	if (key->type == SLKEY_F_INTERPRET)
+	  SLang_free_slstring (key->f.s);
+
+	key->str[0] = str_len;
+	key->str[1] = ch;
+
+	*keyp = key;
+	return 0;
+     }
+
+   /* insert the key definition */
+   while (1)
+     {
+	int cmp;
+	unsigned int key_len, len;
+
+	last = key;
+	key = key->next;
+
+	if ((key != NULL) && (key->str != NULL))
+	  {
+	     len = key_len = key->str[0];
+	     if (len > str_len) len = str_len;
+
+	     cmp = key_string_compare (str + 1, key->str + 1, len - 1);
+
+	     if (cmp > 0)
+	       continue;
+
+	     if (cmp == 0)
+	       {
+		  if (key_len != str_len)
+		    {
+		       SLang_doerror (Define_Key_Error);
+		       return -2;
+		    }
+
+		  if (key->type == SLKEY_F_INTERPRET)
+		    SLang_free_slstring (key->f.s);
+
+		  *keyp = key;
+		  return 0;
+	       }
+	     /* Drop to cmp < 0 case */
+	  }
+
+	if (NULL == (neew = malloc_key(str))) return -1;
+
+	neew -> next = key;
+	last -> 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, &key);
+   if ((ret != 0) || (key == NULL))
+     return ret;
+
+   key->type = type;
+   key->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, &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->type = SLKEY_F_INTERPRET;
+	key->f.s = str;
+     }
+   else
+     {
+	key->type = SLKEY_F_INTRINSIC;
+	key->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, &key);
+
+   if ((ret != 0) || (key == NULL))
+     return ret;
+
+   key->type = SLKEY_F_KEYSYM;
+   key->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 *) &((kml->keymap)[input_ch]);
+
+   /* if the next one is null, then we know this MAY be it. */
+   while (key->next == NULL)
+     {
+	if (key->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->keymap + input_ch;
+	if (key->type == 0)
+	  return NULL;
+     }
+
+   /* It appears to be a prefix character in a key sequence. */
+
+   len = 1;			       /* already read one character */
+   key = key->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->str[0] > len)
+	       {
+		  key_ch = key->str[len];
+		  if (chup == UPPER_CASE_KEY(key_ch))
+		    break;
+	       }
+	     key = key->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->next;
+	     while (next != kmax)
+	       {
+		  if (next->str[0] > len)
+		    {
+		       unsigned char next_ch = next->str[len];
+		       if (next_ch == input_ch)
+			 {
+			    key = next;
+			    break;
+			 }
+		       if (next_ch != chup)
+			 break;
+		    }
+		  next = next->next;
+	       }
+	  }
+
+	/* Ok, we found the first position of a possible match.  If it
+	 * is exact, we are done.
+	 */
+	if ((unsigned int) key->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->next;
+	while (next != kmax)
+	  {
+	     if ((unsigned int) next->str[0] > len)
+	       {
+		  key_ch = next->str[len];
+		  if (chup != UPPER_CASE_KEY(key_ch))
+		    break;
+	       }
+	     next = next->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 -> 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 *) &(keymap[i]);
+   key = key_root->next;
+
+   while (key != NULL)
+     {
+	next = key->next;
+	if (0 == SLMEMCMP ((char *)(key->str + 1), (char *) str, n))
+	  {
+	     if (key->type == SLKEY_F_INTERPRET)
+	       SLang_free_slstring (key->f.s);
+
+	     SLfree((char *) key);
+	     last->next = next;
+	  }
+	else last = key;
+	key = next;
+     }
+
+   if (n == 1)
+     {
+	*key_root->str = 0;
+	key_root->f.f = NULL;
+	key_root->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 > SLANG_MAX_KEYMAP_KEY_SEQ)
+     {
+	SLang_verror (SL_INVALID_PARM, "Key sequence is too long");
+	return NULL;
+     }
+
+   b = buf;
+   while (n--)
+     {
+	if (*s < 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->keymap;
+
+   for (i = 0; i < 256; i++)
+     {
+	old = &(km[i]);
+	neew = &(new_root[i]);
+
+	if (old->type == SLKEY_F_INTERPRET)
+	  neew->f.s = SLang_create_slstring (old->f.s);
+	else
+	  neew->f.f = old->f.f;
+
+	neew->type = old->type;
+	SLMEMCPY((char *) neew->str, (char *) old->str, (unsigned int) *old->str);
+
+	old = old->next;
+	while (old != NULL)
+	  {
+	     neew->next = malloc_key((unsigned char *) old->str);
+	     neew = neew->next;
+
+	     if (old->type == SLKEY_F_INTERPRET)
+	       neew->f.s = SLang_create_slstring (old->f.s);
+	     else
+	       neew->f.f = old->f.f;
+
+	     neew->type = old->type;
+	     old = old->next;
+	  }
+	neew->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 -> functions = map -> 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 < kmap_max)
+     {
+	if ((kmap->name != NULL)
+	    && (0 == strcmp (kmap->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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+static SLKeyMap_List_Type *Keymap_List;
+
+int SLkp_init (void)
+{
+   char esc_seq[10];
+   int i;
+
+   if (NULL == (Keymap_List = SLang_create_keymap ("_SLKeypad", NULL)))
+     return -1;
+
+   esc_seq[1] = 0;
+   for (i = 1; i < 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 ("^@", 0, Keymap_List);
+
+   SLkm_define_keysym ("\033[A", SL_KEY_UP, Keymap_List);
+   SLkm_define_keysym ("\033OA", SL_KEY_UP, Keymap_List);
+   SLkm_define_keysym ("\033[B", SL_KEY_DOWN, Keymap_List);
+   SLkm_define_keysym ("\033OB", SL_KEY_DOWN, Keymap_List);
+   SLkm_define_keysym ("\033[C", SL_KEY_RIGHT, Keymap_List);
+   SLkm_define_keysym ("\033OC", SL_KEY_RIGHT, Keymap_List);
+   SLkm_define_keysym ("\033[D", SL_KEY_LEFT, Keymap_List);
+   SLkm_define_keysym ("\033OD", SL_KEY_LEFT, Keymap_List);
+   SLkm_define_keysym ("\033[2~", SL_KEY_IC, Keymap_List);
+   SLkm_define_keysym ("\033[7~", SL_KEY_HOME, Keymap_List);
+   SLkm_define_keysym ("\033[5~", SL_KEY_PPAGE, Keymap_List);
+   SLkm_define_keysym ("\033[6~", SL_KEY_NPAGE, Keymap_List);
+   SLkm_define_keysym ("\033[8~", SL_KEY_END, Keymap_List);
+   SLkm_define_keysym ("\033[3~", SL_KEY_DELETE, Keymap_List);
+#else
+   /* Note: This will not work if SLgetkey_map_to_ansi (1) has
+    * been called.
+    */
+   SLkm_define_keysym ("^@\x48", SL_KEY_UP, Keymap_List );
+   SLkm_define_keysym ("^@\x50", SL_KEY_DOWN, Keymap_List );
+   SLkm_define_keysym ("^@\x4d", SL_KEY_RIGHT, Keymap_List );
+   SLkm_define_keysym ("^@\x4b", SL_KEY_LEFT, Keymap_List );
+   SLkm_define_keysym ("^@\x47", SL_KEY_HOME, Keymap_List );
+   SLkm_define_keysym ("^@\x49", SL_KEY_PPAGE, Keymap_List );
+   SLkm_define_keysym ("^@\x51", SL_KEY_NPAGE, Keymap_List );
+   SLkm_define_keysym ("^@\x4f", SL_KEY_END, Keymap_List );
+   SLkm_define_keysym ("^@\x52", SL_KEY_IC, Keymap_List );
+   SLkm_define_keysym ("^@\x53", SL_KEY_DELETE, Keymap_List );
+   
+   SLkm_define_keysym ("\xE0\x48", SL_KEY_UP, Keymap_List );
+   SLkm_define_keysym ("\xE0\x50", SL_KEY_DOWN, Keymap_List );
+   SLkm_define_keysym ("\xE0\x4d", SL_KEY_RIGHT, Keymap_List );
+   SLkm_define_keysym ("\xE0\x4b", SL_KEY_LEFT, Keymap_List );
+   SLkm_define_keysym ("\xE0\x47", SL_KEY_HOME, Keymap_List );
+   SLkm_define_keysym ("\xE0\x49", SL_KEY_PPAGE, Keymap_List );
+   SLkm_define_keysym ("\xE0\x51", SL_KEY_NPAGE, Keymap_List );
+   SLkm_define_keysym ("\xE0\x4f", SL_KEY_END, Keymap_List );
+   SLkm_define_keysym ("\xE0\x52", SL_KEY_IC, Keymap_List );
+   SLkm_define_keysym ("\xE0\x53", SL_KEY_DELETE, Keymap_List );
+
+    strcpy (esc_seq, "^@ ");	       /* guarantees esc_seq[3] = 0. */
+
+    for (i = 0x3b; i < 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, "^(kX)");
+   for (i = 0; i <= 9; i++)
+     {
+	esc_seq[3] = '0' + i;
+	SLkm_define_keysym (esc_seq, SL_KEY_F(i), Keymap_List);
+     }
+   SLkm_define_keysym ("^(k;)", SL_KEY_F(10), Keymap_List);
+
+   SLkm_define_keysym ("^(ku)", SL_KEY_UP, Keymap_List);
+   SLkm_define_keysym ("^(kd)", SL_KEY_DOWN, Keymap_List);
+   SLkm_define_keysym ("^(kl)", SL_KEY_LEFT, Keymap_List);
+   SLkm_define_keysym ("^(kr)", SL_KEY_RIGHT, Keymap_List);
+   SLkm_define_keysym ("^(kP)", SL_KEY_PPAGE, Keymap_List);
+   SLkm_define_keysym ("^(kN)", SL_KEY_NPAGE, Keymap_List);
+   SLkm_define_keysym ("^(kh)", SL_KEY_HOME, Keymap_List);
+   SLkm_define_keysym ("^(@7)", SL_KEY_END, Keymap_List);
+   SLkm_define_keysym ("^(K1)", SL_KEY_A1, Keymap_List);
+   SLkm_define_keysym ("^(K3)", SL_KEY_A3, Keymap_List);
+   SLkm_define_keysym ("^(K2)", SL_KEY_B2, Keymap_List);
+   SLkm_define_keysym ("^(K4)", SL_KEY_C1, Keymap_List);
+   SLkm_define_keysym ("^(K5)", SL_KEY_C3, Keymap_List);
+   SLkm_define_keysym ("^(%0)", SL_KEY_REDO, Keymap_List);
+   SLkm_define_keysym ("^(&8)", SL_KEY_UNDO, Keymap_List);
+   SLkm_define_keysym ("^(kb)", SL_KEY_BACKSPACE, Keymap_List);
+   SLkm_define_keysym ("^(@8)", SL_KEY_ENTER, Keymap_List);
+   SLkm_define_keysym ("^(kD)", 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->type != SLKEY_F_KEYSYM))
+     {
+	SLang_flush_input ();
+	return SL_KEY_ERR;
+     }
+
+   return key->f.keysym;
+}
+
+int SLkp_define_keysym (char *keystr, unsigned int keysym)
+{
+   if (SLkm_define_keysym (keystr, keysym, Keymap_List) < 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, "Keycode = %d\r\n", 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 "slinclud.h"
+
+#ifdef SL_MALLOC_DEBUG
+# undef SL_MALLOC_DEBUG
+#endif
+
+#include "slang.h"
+#include "_slang.h"
+
+#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, "Total Allocated: %ld\nHighest single allocation: %ld\nHighest Total Allocated:%ld\n",
+	    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 ("malloc.out", "w");
+#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 >> 24) & 0xFF);
+   *(p - 3) = (unsigned char) ((n >> 16) & 0xFF);
+   *(p - 2) = (unsigned char) ((n >> 8) & 0xFF);
+   *(p - 1) = (unsigned char) (n & 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 > Max_Allocated) Max_Allocated = Total_Allocated;
+   if ((long) n > Max_Single_Allocation)
+     Max_Single_Allocation = (long) n;
+
+#ifdef SLDEBUG_DOUT
+   fprintf (dout, "ALLOC: %s\t%p %ld\n", 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)) << 24;
+   n |= ((unsigned long) *(p - 3)) << 16;
+   n |= ((unsigned long) *(p - 2)) << 8;
+   n |= (unsigned long) *(p - 1);
+
+   if (n == 0xFFFFFFFFUL)
+     {
+	sprintf (buf, "%s: %p: Already FREE! Abort NOW.", 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, "\007%s: %p: Memory corrupt! Abort NOW.", what, (void*)p);
+	SLmalloc_doerror (buf);
+	return -1;
+     }
+
+   *(p - 4) = *(p - 3) = *(p - 2) = *(p - 1) = 0xFF;
+
+   Total_Allocated -= (long) n;
+   if (Total_Allocated < 0)
+     {
+	sprintf (buf, "\007%s: %p\nFreed %ld, Allocated is: %ld!\n",
+		 what, (void*)p, (long) n, Total_Allocated);
+	SLang_doerror (buf);
+     }
+#ifdef SLDEBUG_DOUT
+   fprintf (dout, "FREE: %s:\t%p %ld\n", what, p, (long) n);
+#endif
+   return 0;
+}
+
+void SLdebug_free (char *p)
+{
+   if (p == NULL) return;
+   if (-1 == check_memory ((unsigned char *) p, "FREE")) 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, "MALLOC");
+   return p + Chunk;
+}
+
+char *SLdebug_realloc (char *p, unsigned long n)
+{
+   if (-1 == check_memory ((unsigned char *) p, "REALLOC")) return NULL;
+   if ((p = (char *) SLREALLOC (p - Chunk, n + 2 * Chunk)) == NULL) return NULL;
+   fixup ((unsigned char *) p, n, "REALLOC");
+   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 >= Chunk) m = 1; else m = Chunk;
+
+   if ((p = (char *) SLCALLOC (n + m + m, size)) == NULL) return NULL;
+   fixup ((unsigned char *) p, size * n, "CALLOC");
+   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 "slinclud.h"
+
+#include <math.h>
+
+#include "slang.h"
+#include "_slang.h"
+
+#ifdef PI
+# undef PI
+#endif
+#define PI 3.14159265358979323846264338327950288
+
+#if defined(__unix__)
+#include <signal.h>
+#include <errno.h>
+
+#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 > 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 ==> 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(&x, NULL, NULL))
+       || (SLang_pop_integer(&n))) return(0.0);
+
+   while (n-- > 0)
+     {
+	if (SLang_pop_double(&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 >= 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 <= x^2 < 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 < na; i++)
+	  b[i] = a[i];
+	return 1;
+      case SLMATH_IMAG:
+	for (i = 0; i < na; i++)
+	  b[i] = 0.0;
+	return 1;
+     }
+
+   for (i = 0; i < 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 < na; i++)
+	  b[i] = a[i];
+	return 1;
+      case SLMATH_IMAG:
+	for (i = 0; i < na; i++)
+	  b[i] = 0.0;
+	return 1;
+     }
+
+   for (i = 0; i < 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, &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 < na; i++)
+	  {
+	     b[i] = to_double((VOID_STAR) a);
+	     a += da;
+	  }
+	return 1;
+
+      case SLMATH_IMAG:
+	for (i = 0; i < na; i++)
+	  b[i] = 0.0;
+	return 1;
+     }
+
+   for (i = 0; i < 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 < na; i++)
+	  b[i] = a[2 * i];
+	return 1;
+
+      case SLMATH_IMAG:
+	for (i = 0; i < na; i++)
+	  b[i] = a[2 * i + 1];
+	return 1;
+
+      case SLMATH_CONJ:
+	for (i = 0; i < 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 < na2; i += 2)
+     (void) (*fun) (b + i, a + i);
+
+   return 1;
+}
+#endif
+
+static SLang_DConstant_Type DConst_Table [] =
+{
+   MAKE_DCONSTANT("E", 2.718281828459045),
+   MAKE_DCONSTANT("PI", 3.14159265358979323846264338327950288),
+   SLANG_END_DCONST_TABLE
+};
+
+static SLang_Math_Unary_Type SLmath_Table [] =
+{
+   MAKE_MATH_UNARY("sinh", SLMATH_SINH),
+   MAKE_MATH_UNARY("asinh", SLMATH_ASINH),
+   MAKE_MATH_UNARY("cosh", SLMATH_COSH),
+   MAKE_MATH_UNARY("acosh", SLMATH_ACOSH),
+   MAKE_MATH_UNARY("tanh", SLMATH_TANH),
+   MAKE_MATH_UNARY("atanh", SLMATH_ATANH),
+   MAKE_MATH_UNARY("sin", SLMATH_SIN),
+   MAKE_MATH_UNARY("cos", SLMATH_COS),
+   MAKE_MATH_UNARY("tan", SLMATH_TAN),
+   MAKE_MATH_UNARY("atan", SLMATH_ATAN),
+   MAKE_MATH_UNARY("acos", SLMATH_ACOS),
+   MAKE_MATH_UNARY("asin", SLMATH_ASIN),
+   MAKE_MATH_UNARY("exp", SLMATH_EXP),
+   MAKE_MATH_UNARY("log", SLMATH_LOG),
+   MAKE_MATH_UNARY("sqrt", SLMATH_SQRT),
+   MAKE_MATH_UNARY("log10", SLMATH_LOG10),
+#if SLANG_HAS_COMPLEX
+   MAKE_MATH_UNARY("Real", SLMATH_REAL),
+   MAKE_MATH_UNARY("Imag", SLMATH_IMAG),
+   MAKE_MATH_UNARY("Conj", SLMATH_CONJ),
+#endif
+   SLANG_END_MATH_UNARY_TABLE
+};
+
+static SLang_Intrin_Fun_Type SLang_Math_Table [] =
+{
+   MAKE_INTRINSIC_0("polynom", 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, "__SLMATH__"))
+       || (-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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+char *SLmemchr(register char *p, register char c, register int n)
+{
+   int n2;
+   register char *pmax;
+
+   pmax = p + (n - 32);
+
+   while (p <= 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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+/* 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 <= 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 < 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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+char *SLmemcpy(char *s1, char *s2, int n)
+{
+#if defined(__BORLANDC__) && 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 <= 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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+void SLmemset(char *p, char space, int n)
+{
+#if defined(__BORLANDC__) && 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 <= 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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+#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 < lmax) *l++ = reverse;
+   reverse = !reverse;
+
+   r1 = *range++;
+   while (r1)
+     {
+	r2 = *range++;
+	if ((r2 == '-') && (*range != 0))
+	  {
+	     r2 = *range++;
+	     for (i = r1; i <= 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 <= max) && (ch1 >= '0'))
+	  {
+	     num = base * num + (ch1 - '0');
+	  }
+	else if (base == 16)
+	  {
+	     ch1 |= 0x20;
+	     if ((ch1 < 'a') || ((ch1 > '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 < tmax)
+     {
+	ch = *t++;
+	if (ch == '\\')
+	  {
+	     t = _SLexpand_escaped_char (t, &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 > 0)
+     {
+	while ((0 != (ch = *list)) && (ch != delim))
+	  list++;
+
+	if (ch == 0) return -1;
+
+	list++;
+	nth--;
+     }
+
+   el = elem;
+   elmax = el + (buflen - 1);
+
+   while ((0 != (ch = *list)) && (ch != delim) && (el < 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 >= buflen)
+     {
+	SLang_exit_error ("\
+Your system lacks the vsnprintf system call and vsprintf overflowed a buffer.\n\
+The integrity of this program has been violated.\n");
+	return EOF;		       /* NOT reached */
+     }
+   return (int)len;
+#else
+   int status;
+
+   status = vsprintf (buf, fmt, ap);
+   if (status >= (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 ("\
+Your system lacks the vsnprintf system call and vsprintf overflowed a buffer.\n\
+The integrity of this program has been violated.\n");
+	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->next;
+	(*Cleanup_Function_List->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->f = f;
+   l->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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+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->name, name))
+	  break;
+	table_list = table_list->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->namespace_name != NULL)
+	    && (0 == strcmp (table_list->namespace_name, name)))
+	  break;
+	table_list = table_list->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->name = name;
+   table_list->table = nt;
+   table_list->table_size = size;
+
+   table_list->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, "Namespace \"%s\" already exists",
+		      name);
+	return -1;
+     }
+
+   if (NULL == (name = SLang_create_slstring (name)))
+     return -1;
+
+   SLang_free_slstring (t->namespace_name);   /* NULL ok */
+   t->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->table) == NULL))
+     return NULL;
+
+   memset ((char *) &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 (&rexp))
+     {
+	SLang_verror (SL_INVALID_PARM, "Invalid regular expression: %s", pat);
+	return NULL;
+     }
+   
+   table_size = ns->table_size;
+
+   two = 2;
+   while (two != 0)
+     {
+	two--;
+	
+	num_matches = 0;
+	for (i = 0; i < table_size; i++)
+	  {
+	     t = table[i];
+	     while (t != NULL)
+	       {
+		  unsigned int flags;
+		  char *name = t->name;
+
+		  switch (t->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 & what)
+		      && (NULL != SLang_regexp_match ((unsigned char *)name, strlen (name), &rexp)))
+		    {
+		       if (at != NULL)
+			 {
+			    if (-1 == SLang_set_array_element (at, &num_matches, (VOID_STAR)&name))
+			      goto return_error;
+			 }
+		       num_matches++;
+		    }
+		  t = t->next;
+	       }
+	  }
+	
+	if (at == NULL)
+	  {
+	     at = SLang_create_array (SLANG_STRING_TYPE, 0, NULL, &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 = "Global";
+
+   ns = _SLns_find_namespace (namespace_name);
+   if (ns != NULL)
+     return ns;
+   
+   sprintf (name, " *** internal ns <%d> *** ", 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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+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("path_concat", path_concat, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_S("path_extname", path_extname, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_S("path_dirname", path_dirname, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_S("path_basename", path_basename, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_S("path_sans_extname", path_sans_extname, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_S("path_is_absolute", 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, "__OSPATH__"))
+     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 "slinclud.h"
+
+#include <ctype.h>
+
+#include "slang.h"
+#include "_slang.h"
+
+#ifndef isdigit
+# define isdigit(c) (((c)>='0')&&((c)<= '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
+ *    > = big-endian mode
+ *    < = 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,
+		 "This OS does not support a %u byte int", 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,
+		 "This OS does not support a %u byte float", 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)
+	  && isspace (ch))
+     ;
+
+   switch (ch)
+     {
+      default:
+	ft->byteorder = NATIVE_ORDER;
+	break;
+
+      case '=':
+	ft->byteorder = NATIVE_ORDER;
+	ch = *f++;
+	break;
+
+      case '>':
+	ft->byteorder = BIGENDIAN_ORDER;
+	ch = *f++;
+	break;
+
+      case '<':
+	ft->byteorder = LILENDIAN_ORDER;
+	ch = *f++;
+	break;
+     }
+
+   if (ch == 0)
+     {
+	f--;
+	*format = f;
+	return 0;
+     }
+
+   ft->format_type = ch;
+   ft->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,
+				"Repeat count too large in [un]pack format");
+		  return -1;
+	       }
+	     repeat = repeat10;
+	     f++;
+	  }
+	ft->repeat = repeat;
+     }
+
+   *format = f;
+
+   ft->is_scalar = 1;
+   ft->pad = 0;
+
+   switch (ft->format_type)
+     {
+      default:
+	SLang_verror (SL_NOT_IMPLEMENTED,
+		      "[un]pack format character '%c' not supported", ft->format_type);
+	return -1;
+
+      case 'D':
+	ft->sizeof_type = 8;
+	if (-1 == get_float_type_for_size (8, &ft->data_type))
+	  return -1;
+	break;
+
+      case 'd':
+	ft->data_type = SLANG_DOUBLE_TYPE;
+	ft->sizeof_type = sizeof (double);
+	break;
+
+      case 'F':
+	ft->sizeof_type = 4;
+	if (-1 == get_float_type_for_size (4, &ft->data_type))
+	  return -1;
+	break;
+      case 'f':
+	ft->data_type = SLANG_FLOAT_TYPE;
+	ft->sizeof_type = sizeof (float);
+	break;
+
+      case 'h':
+	ft->data_type = SLANG_SHORT_TYPE;
+	ft->sizeof_type = sizeof (short);
+	break;
+      case 'H':
+	ft->data_type = SLANG_USHORT_TYPE;
+	ft->sizeof_type = sizeof (unsigned short);
+	break;
+      case 'i':
+	ft->data_type = SLANG_INT_TYPE;
+	ft->sizeof_type = sizeof (int);
+	break;
+      case 'I':
+	ft->data_type = SLANG_UINT_TYPE;
+	ft->sizeof_type = sizeof (unsigned int);
+	break;
+      case 'l':
+	ft->data_type = SLANG_LONG_TYPE;
+	ft->sizeof_type = sizeof (long);
+	break;
+      case 'L':
+	ft->data_type = SLANG_ULONG_TYPE;
+	ft->sizeof_type = sizeof (unsigned long);
+	break;
+
+	/* 16 bit ints */
+      case 'j':
+	ft->sizeof_type = 2;
+	if (-1 == get_int_type_for_size (2, &ft->data_type, NULL))
+	  return -1;
+	break;
+      case 'J':
+	ft->sizeof_type = 2;
+	if (-1 == get_int_type_for_size (2, NULL, &ft->data_type))
+	  return -1;
+	break;
+
+	/* 32 bit ints */
+      case 'k':
+	ft->sizeof_type = 4;
+	if (-1 == get_int_type_for_size (4, &ft->data_type, NULL))
+	  return -1;
+	break;
+      case 'K':
+	ft->sizeof_type = 4;
+	if (-1 == get_int_type_for_size (4, NULL, &ft->data_type))
+	  return -1;
+	break;
+
+      case 'x':
+	ft->sizeof_type = 1;
+	ft->data_type = 0;
+	break;
+
+      case 'c':
+	ft->sizeof_type = 1;
+	ft->data_type = SLANG_CHAR_TYPE;
+	break;
+
+      case 'C':
+	ft->data_type = SLANG_UCHAR_TYPE;
+	ft->sizeof_type = 1;
+	break;
+
+      case 'S':
+      case 'A':
+	ft->pad = ' ';
+      case 'a':
+      case 's':
+	ft->data_type = SLANG_BSTRING_TYPE;
+	ft->sizeof_type = 1;
+	ft->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 (&format, &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 < 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 < 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 < 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 *)&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, &size))
+     goto return_error;
+
+   if (NULL == (buf = (unsigned char *) SLmalloc (size + 1)))
+     goto return_error;
+
+   b = buf;
+
+   while (1 == parse_a_format (&format, &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,
+				     "Not enough items for pack format");
+		       goto return_error;
+		    }
+
+		  if (-1 == SLang_pop_array_of_type (&at, ft.data_type))
+		    goto return_error;
+
+		  nelements = at->num_elements;
+		  if (repeat < nelements)
+		    nelements = repeat;
+		  repeat -= nelements;
+
+		  nelements = nelements * ft.sizeof_type;
+		  memcpy ((char *)b, (char *)at->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 (&bs))
+	  goto return_error;
+
+	ptr = SLbstring_get_pointer (bs, &num);
+	if (repeat < 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 <= 0)
+     {
+	SLang_verror (SL_SYNTAX_ERROR,
+		      "pack: not enough arguments");
+	return;
+     }
+
+   if ((-1 == SLreverse_stack (nitems))
+       || (-1 == SLang_pop_slstring (&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, &num_bytes))
+     return;
+
+   b = SLbstring_get_pointer (bs, &len);
+   if (b == NULL)
+     return;
+
+   if (len < num_bytes)
+     {
+	SLang_verror (SL_INVALID_PARM,
+		      "unpack format %s is too large for input string",
+		      format);
+	return;
+     }
+
+   while (1 == parse_a_format (&format, &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->cl_transfer_buf, (char *)b, ft.sizeof_type);
+		  if (ft.byteorder != NATIVE_ORDER)
+		    byteswap (ft.byteorder, (unsigned char *)cl->cl_transfer_buf, ft.sizeof_type, 1);
+
+		  if (-1 == (cl->cl_apush (ft.data_type, cl->cl_transfer_buf)))
+		    return;
+		  b += ft.sizeof_type;
+		  continue;
+	       }
+
+	     dims = (int) ft.repeat;
+	     at = SLang_create_array (ft.data_type, 0, NULL, &dims, 1);
+	     if (at == NULL)
+	       return;
+
+	     num_bytes = ft.repeat * ft.sizeof_type;
+	     memcpy ((char *)at->data, (char *)b, num_bytes);
+	     if (ft.byteorder != NATIVE_ORDER)
+	       byteswap (ft.byteorder, (unsigned char *)at->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 > str)
+	       {
+		  s--;
+		  if ((*s != ' ') && (*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, &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, &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 (&format, &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, "x%u", 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 *)&s_h.b - (char *)&s_h.a));
+	     break;
+
+	   case SLANG_INT_TYPE:
+	   case SLANG_UINT_TYPE:
+	     pad = ((unsigned int) ((char *)&s_i.b - (char *)&s_i.a));
+	     break;
+
+	   case SLANG_LONG_TYPE:
+	   case SLANG_ULONG_TYPE:
+	     pad = ((unsigned int) ((char *)&s_l.b - (char *)&s_l.a));
+	     break;
+
+	   case SLANG_FLOAT_TYPE:
+	     pad = ((unsigned int) ((char *)&s_f.b - (char *)&s_f.a));
+	     break;
+
+	   case SLANG_DOUBLE_TYPE:
+	     pad = ((unsigned int) ((char *)&s_d.b - (char *)&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, "x%u", pad);
+	     b += strlen (b);
+	     len += pad;
+	  }
+
+	*b++ = ft.format_type;
+	if (ft.repeat > 1)
+	  {
+	     sprintf (b, "%u", 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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+static SLang_Load_Type *LLT;
+int _SLang_Compile_Line_Num_Info;
+
+static void free_token (_SLang_Token_Type *t)
+{
+   register unsigned int nrefs = t->num_refs;
+
+   if (nrefs == 0)
+     return;
+
+   if (nrefs == 1)
+     {
+	if (t->free_sval_flag)
+	  {
+	     if (t->type == BSTRING_TOKEN)
+	       SLbstring_free (t->v.b_val);
+	     else
+	       _SLfree_hashed_string (t->v.s_val, strlen (t->v.s_val), t->hash);
+	     t->v.s_val = NULL;
+	  }
+     }
+
+   t->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->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 ("unget_token failed", 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->num_refs)
+     free_token (ctok);
+
+   if (Use_Next_Token)
+     {
+	Use_Next_Token--;
+	*ctok = Next_Token;
+	return ctok->type;
+     }
+
+   return _SLget_token (ctok);
+}
+
+static int compile_token (_SLang_Token_Type *t)
+{
+#if _SLANG_HAS_DEBUG_CODE
+   if (_SLang_Compile_Line_Num_Info
+       && (t->line_number != Last_Line_Number)
+       && (t->line_number != -1))
+     {
+	_SLang_Token_Type tok;
+	tok.type = LINE_NUM_TOKEN;
+	tok.v.long_val = Last_Line_Number = t->line_number;
+	(*_SLcompile_ptr) (&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->size = 0;
+   t->len = 0;
+   t->stack = NULL;
+#if USE_PARANOID_MAGIC
+   t->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->magic != 0xABCDEF12)
+     {
+	SLang_doerror ("Magic error.");
+	return;
+     }
+#endif
+   s = t->stack;
+   if (s != NULL)
+     {
+	_SLang_Token_Type *smax = s + t->len;
+	while (s != smax)
+	  {
+	     if (s->num_refs) free_token (s);
+	     s++;
+	  }
+
+	SLfree ((char *) t->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 ("Token list stack size exceeded", 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 ("Token list stack underflow", 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->magic != 0xABCDEF12)
+     {
+	SLang_doerror ("Magic error.");
+	return -1;
+     }
+#endif
+   len = t->len + delta_size;
+   if (len <= t->size) return 0;
+
+   if (delta_size < 4)
+     {
+	delta_size = 4;
+	len = t->len + delta_size;
+     }
+
+   st = (_SLang_Token_Type *) SLrealloc((char *) t->stack,
+					len * sizeof(_SLang_Token_Type));
+   if (st == NULL)
+     {
+	_SLparse_error ("Malloc error", NULL, 0);
+	return -1;
+     }
+
+   memset ((char *) (st + t->len), 0, delta_size);
+
+   t->stack = st;
+   t->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->stack [Token_List->len] = *t;
+   Token_List->len += 1;
+   t->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->stack + Token_List->len;
+   init_token (tok);
+   tok->type = t;
+   Token_List->len += 1;
+   return 0;
+}
+
+static _SLang_Token_Type *get_last_token (void)
+{
+   unsigned int len;
+
+   if ((Token_List == NULL)
+       || (0 == (len = Token_List->len)))
+     return NULL;
+
+   len--;
+   return Token_List->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->stack;
+   t1 = t0 + list->len;
+
+   if (dir < 0)
+     {
+	/* backwards */
+
+	while ((SLang_Error == 0) && (t1 > t0))
+	  {
+	     t1--;
+	     (*f) (t1);
+	  }
+	return 0;
+     }
+
+   /* forward */
+   while ((SLang_Error == 0) && (t0 < 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 ==> ...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->stack;
+   len = Token_List->len;
+
+   if ((s == NULL) || (len == 0)
+       || (pos2 >= 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 --> BCabcdeA --> CabcdeAB -->  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 < 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->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(&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, "Expression not implemented: %s", 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:
+	   * . <end of line>
+	   * . <end of line>
+	   */
+	if (tok->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 ("Expecting identifier", tok, 0);
+   return tok->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 (&fname);
+   if (IDENT_TOKEN != get_identifier_token (&fname))
+     {
+	free_token (&fname);
+	return;
+     }
+
+   compile_token_of_type(OPAREN_TOKEN);
+   get_token (ctok);
+   define_function_args (ctok);
+   compile_token_of_type(FARG_TOKEN);
+
+   if (ctok->type == OBRACE_TOKEN)
+     compound_statement(ctok);
+
+   else if (ctok->type != SEMICOLON_TOKEN)
+     {
+	_SLparse_error("Expecting {", ctok, 0);
+	free_token (&fname);
+	return;
+     }
+
+   fname.type = type;
+   compile_token (&fname);
+   free_token (&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->parse_level += 1;
+
+   switch (ctok->type)
+     {
+      case OBRACE_TOKEN:
+	compound_statement (ctok);
+	break;
+
+      case IF_TOKEN:
+      case IFNOT_TOKEN:
+	type = ctok->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->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->type == USING_TOKEN)
+	  {
+	     if (OPAREN_TOKEN != get_token (ctok))
+	       {
+		  _SLparse_error ("Expected 'using ('", 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("Expecting while", 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("Expecting (.", 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->type != SEMICOLON_TOKEN)
+	       {
+		  _SLparse_error("Expecting ;", 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->type != SEMICOLON_TOKEN)
+	       {
+		  _SLparse_error("Expecting ;", 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->type != CPAREN_TOKEN)
+	       {
+		  _SLparse_error("Expecting ).", 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->type;
+	get_token (ctok);
+	block (ctok);
+	compile_token_of_type (type);
+	break;
+
+      case BREAK_TOKEN:
+      case CONT_TOKEN:
+	compile_token_of_type (ctok->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->type != SEMICOLON_TOKEN)
+	       {
+		  _SLparse_error ("Expecting ;", 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->type;
+	get_token (ctok);
+	if (ctok->type == VARIABLE_TOKEN)
+	  {
+	     get_token (ctok);
+	     variable_list (ctok, type);
+	     handle_semicolon (ctok);
+	     break;
+	  }
+	if (ctok->type == DEFINE_TOKEN)
+	  {
+	     define_function (ctok, type);
+	     break;
+	  }
+	_SLparse_error ("Expecting 'variable' or 'define'", 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)
+	       && (OBRACE_TOKEN == ctok->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->type != EOF_TOKEN)
+	  rpn_parse_line (ctok);
+	break;
+
+      case OPAREN_TOKEN:	       /* multiple assignment */
+	try_multiple_assignment (ctok);
+	if (ctok->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->type == COLON_TOKEN)
+	  compile_token_of_type (COLON_TOKEN);
+	else handle_semicolon (ctok);
+	break;
+     }
+
+   LLT->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)
+	  && (ctok->type != CBRACE_TOKEN)
+	  && (ctok->type != EOF_TOKEN))
+     {
+	statement(ctok);
+	get_token (ctok);
+     }
+}
+
+/* compound-statement:
+ *	 { statement-list }
+ */
+static void compound_statement (_SLang_Token_Type *ctok)
+{
+   /* ctok->type is OBRACE_TOKEN here */
+   get_token (ctok);
+   statement_list(ctok);
+   if (CBRACE_TOKEN != ctok->type)
+     {
+	_SLparse_error ("Expecting '}'", ctok, 0);
+	return;
+     }
+}
+
+/* This function is only called from statement. */
+static void expression_with_parenthesis (_SLang_Token_Type *ctok)
+{
+   if (ctok->type != OPAREN_TOKEN)
+     {
+	_SLparse_error("Expecting (", ctok, 0);
+	return;
+     }
+
+   if (NULL == push_token_list ())
+     return;
+
+   get_token (ctok);
+   expression (ctok);
+
+   if (ctok->type != CPAREN_TOKEN)
+     _SLparse_error("Expecting )", ctok, 0);
+
+   compile_token_list ();
+
+   get_token (ctok);
+}
+
+static void handle_semicolon (_SLang_Token_Type *ctok)
+{
+   if ((ctok->type == SEMICOLON_TOKEN)
+       || (ctok->type == EOF_TOKEN))
+     return;
+
+   _SLparse_error ("Expecting ;", 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 (&Next_Token);
+   Use_Next_Token = 0;
+   init_token (&ctok);
+   get_token (&ctok);
+
+   llt->parse_level = 0;
+   statement_list (&ctok);
+
+   if ((SLang_Error == 0)
+       && (ctok.type != EOF_TOKEN))
+     _SLparse_error ("Parse ended prematurely", &ctok, 0);
+   
+
+   if (SLang_Error)
+     {
+	if (SLang_Error < 0)	       /* severe error */
+	  save_list = NULL;
+
+	while (Token_List != save_list)
+	  {
+	     if (-1 == pop_token_list (1))
+	       break;		       /* ??? when would this happen? */
+	  }
+     }
+
+   free_token (&ctok);
+   LLT = save_llt;
+   if (Use_Next_Token)
+     free_token (&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->type != IDENT_TOKEN)
+     {
+	_SLparse_error ("Expecting a variable name", name_token, 0);
+	return;
+     }
+
+   declaring = 0;
+   do
+     {
+	if (declaring == 0)
+	  {
+	     declaring = 1;
+	     compile_token_of_type (variable_type);
+	  }
+
+	compile_token (name_token);
+
+	init_token (&tok);
+	if (ASSIGN_TOKEN == get_token (&tok))
+	  {
+	     compile_token_of_type (CBRACKET_TOKEN);
+	     declaring = 0;
+
+	     get_token (&tok);
+
+	     push_token_list ();
+	     simple_expression (&tok);
+	     compile_token_list ();
+
+	     name_token->type = _SCALAR_ASSIGN_TOKEN;
+	     compile_token (name_token);
+	  }
+
+	free_token (name_token);
+	*name_token = tok;
+     }
+   while ((name_token->type == COMMA_TOKEN)
+	  && (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: "field-name-1" ... "field-name-N" N STRUCT_TOKEN
+ */
+static void struct_declaration (_SLang_Token_Type *ctok)
+{
+   int n;
+   _SLang_Token_Type num_tok;
+
+   if (ctok->type != OBRACE_TOKEN)
+     {
+	_SLparse_error ("Expecting {", ctok, 0);
+	return;
+     }
+
+   n = 0;
+   while (IDENT_TOKEN == get_token (ctok))
+     {
+	n++;
+	ctok->type = STRING_TOKEN;
+	append_token (ctok);
+	if (COMMA_TOKEN != get_token (ctok))
+	  break;
+     }
+
+   if (ctok->type != CBRACE_TOKEN)
+     {
+	_SLparse_error ("Expecting }", ctok, 0);
+	return;
+     }
+   if (n == 0)
+     {
+	_SLparse_error ("struct requires at least 1 field", ctok, 0);
+	return;
+     }
+
+   init_token (&num_tok);
+   num_tok.type = INT_TOKEN;
+   num_tok.v.long_val = n;
+   append_token (&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: "field-name-1" ... "field-name-N" N STRUCT_TOKEN typedef
+ */
+static void typedef_definition (_SLang_Token_Type *t)
+{
+
+   if (t->type != STRUCT_TOKEN)
+     {
+	_SLparse_error ("Expecting `struct'", t, 0);
+	return;
+     }
+   get_token (t);
+
+   struct_declaration (t);
+   if (t->type != IDENT_TOKEN)
+     {
+	_SLparse_error ("Expecting identifier", t, 0);
+	return;
+     }
+
+   t->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)
+	  && (ctok->type == IDENT_TOKEN))
+     {
+	compile_token (ctok);
+	if (COMMA_TOKEN != get_token (ctok))
+	  break;
+
+	get_token (ctok);
+     }
+
+   if (CPAREN_TOKEN != ctok->type)
+     {
+	_SLparse_error("Expecting )", 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->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->type != CPAREN_TOKEN)
+     {
+	expression_with_commas (ctok, 1);
+	if (ctok->type != CPAREN_TOKEN)
+	  {
+	     _SLparse_error ("Expecting )", 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->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
+ *       <none>
+ */
+static void expression_with_commas (_SLang_Token_Type *ctok, int save_comma)
+{
+   while (SLang_Error == 0)
+     {
+	if (ctok->type != COMMA_TOKEN)
+	  {
+	     if (ctok->type == CPAREN_TOKEN)
+	       return;
+
+	     simple_expression (ctok);
+
+	     if (ctok->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->type)
+     {
+      case ANDELSE_TOKEN:
+      case ORELSE_TOKEN:
+	type = ctok->type;
+	if (OBRACE_TOKEN != get_token (ctok))
+	  {
+	     _SLparse_error ("Expecting '{'", ctok, 0);
+	     return;
+	  }
+
+	while (ctok->type == OBRACE_TOKEN)
+	  {
+	     append_token (ctok);
+	     get_token (ctok);
+	     expression (ctok);
+	     if (CBRACE_TOKEN != ctok->type)
+	       {
+		  _SLparse_error("Expecting }", 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->type))
+     return;
+
+   op_num = 0;
+
+   while ((SLang_Error == 0)
+	  && (IS_BINARY_OP(type)))
+     {
+	level = Binop_Level[type - FIRST_BINARY_OP];
+
+	while ((op_num > 0) && (level_stack [op_num - 1] <= level))
+	  append_token_of_type (op_stack [--op_num]);
+
+	if (op_num >= sizeof (op_stack) - 1)
+	  {
+	     _SLparse_error ("Binary op stack overflow", ctok, 0);
+	     return;
+	  }
+
+	op_stack [op_num] = type;
+	level_stack [op_num] = level;
+	op_num++;
+
+	get_token (ctok);
+	unary_expression (ctok);
+	type = ctok->type;
+     }
+
+   while (op_num > 0)
+     append_token_of_type(op_stack[--op_num]);
+}
+
+/* unary-expression:
+ *	 postfix-expression
+ *	 ++ postfix-expression
+ *	 -- postfix-expression
+ *	 case unary-expression
+ *	 OP3 unary-expression
+ *	 (OP3: + - ~ & 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->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->type))
+	       {
+		  ctok->v.long_val = -ctok->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 ->postfix_expression->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])
+       && (NULL != (last_token = get_last_token ()))
+       && (IS_ASSIGN_TOKEN(last_token->type)))
+     {
+	/* FIXME: Priority=medium
+	 * This needs generalized so that things like @a.y = 1 will work properly.
+	 */
+	if ((num_unary_ops != 1)
+	    || (last_token->type != _SCALAR_ASSIGN_TOKEN))
+	  {
+	     SLang_verror (SL_NOT_IMPLEMENTED, 
+			   "Only derefence assignments to simple variables are possible");
+	     return;
+	  }
+
+	last_token->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 ("Too many unary operators.", 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->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->v.s_val;
+   sb = b->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, "->");
+   strcpy (sc + lena + 2, sb);
+
+   sb = _SLstring_make_hashed_string (sc, lena + lenb + 2, &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->hash);
+   a->v.s_val = sb;
+   a->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 ("Expecting name-space identifier", 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 (&next_token);
+   if (NAMESPACE_TOKEN != get_token (&next_token))
+     {
+	unget_token (&next_token);
+	return IDENT_TOKEN;
+     }
+
+   if (IDENT_TOKEN != get_identifier_token (&next_token))
+     {
+	free_token (&next_token);
+	return -1;
+     }
+
+   if (-1 == combine_namespace_tokens (ctok, &next_token))
+     {
+	free_token (&next_token);
+	return -1;
+     }
+   free_token (&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 ]
+ * 	&identifier-expr
+ *      struct-definition
+ *      __tmp(identifier-expr)
+ *
+ * identifier-expr:
+ *      identifier
+ *      identifier->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->len;
+
+   switch (ctok->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->type != CPAREN_TOKEN)
+	       _SLparse_error("Expecting )", ctok, 0);
+	  }
+	get_token (ctok);
+	break;
+
+      case BAND_TOKEN:
+	if (IDENT_TOKEN != get_identifier_expr_token (ctok))
+	  break;
+
+	ctok->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->type == OPAREN_TOKEN)
+	  {
+	     if (IDENT_TOKEN == get_identifier_expr_token (ctok))
+	       {
+		  ctok->type = TMP_TOKEN;
+		  append_token (ctok);
+		  get_token (ctok);
+		  if (ctok->type == CPAREN_TOKEN)
+		    {
+		       get_token (ctok);
+		       break;
+		    }
+	       }
+	  }
+	_SLparse_error ("Expecting form __tmp(NAME)", ctok, 0);
+	break;
+
+      default:
+	if (IS_INTERNAL_FUNC(ctok->type))
+	  {
+	     append_token (ctok);
+	     get_token (ctok);
+	  }
+	else
+	  _SLparse_error("Expecting a PRIMARY", ctok, 0);
+     }
+
+   while (SLang_Error == 0)
+     {
+	end_pos = Token_List->len;
+	type = ctok->type;
+	switch (type)
+	  {
+	   case OBRACKET_TOKEN:	       /* X[args] ==> [args] X ARRAY */
+	     get_token (ctok);
+	     append_token_of_type (ARG_TOKEN);
+	     if (ctok->type != CBRACKET_TOKEN) 
+	       array_index_expression (ctok);
+
+	     if (ctok->type != CBRACKET_TOKEN)
+	       {
+		  _SLparse_error ("Expecting ']'", 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) ==> 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 ==> "a" S DOT
+	      * This means that if S is X[b], then X[b].a ==> a b X ARRAY DOT
+	      * and f(a).X[b].c ==> "c" b "X" a f . ARRAY .
+	      * Also, f(a).X[b] = g(x); ==> x g b "X" a f .
+	      */
+	     if (IDENT_TOKEN != get_identifier_token (ctok))
+	       return;
+
+	     ctok->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->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->type != COMMA_TOKEN)
+		 && (ctok->type != CPAREN_TOKEN))
+	       {
+		  _SLparse_error ("Expecting ')'", 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)
+       && (NULL == (ctok = get_last_token ())))
+     return -1;
+
+   type = ctok->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 ("Expecting LVALUE", ctok, 0);
+	return -1;
+     }
+
+   ctok->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->type)
+	  {
+	   case COLON_TOKEN:
+	     if (num_commas)
+	       _SLparse_error ("Misplaced ':'", ctok, 0);
+	     return;
+	     
+	   case TIMES_TOKEN:
+	     append_token_of_type (_INLINE_WILDCARD_ARRAY_TOKEN);
+	     get_token (ctok);
+	     break;
+	     
+	   case COMMA_TOKEN:
+	     _SLparse_error ("Misplaced ','", ctok, 0);
+	     return;
+	     
+	   default:
+	     simple_expression (ctok);
+	  }
+	
+	if (ctok->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->type == COLON_TOKEN)	       /* [:...] */
+     append_token_of_type (_NULL_TOKEN);
+   else if (ctok->type != CBRACKET_TOKEN) 
+     array_index_expression (ctok);
+
+   if (ctok->type == COLON_TOKEN)
+     {
+	num_colons++;
+	if ((COLON_TOKEN == get_token (ctok))
+	    || (ctok->type == CBRACKET_TOKEN))
+	  append_token_of_type (_NULL_TOKEN);
+	else
+	  simple_expression (ctok);
+
+	if (ctok->type == COLON_TOKEN)
+	  {
+	     num_colons++;
+	     get_token (ctok);
+	     simple_expression (ctok);
+	  }
+     }
+
+   if (ctok->type != CBRACKET_TOKEN)
+     {
+	_SLparse_error ("Expecting ']'", 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->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->stack;
+   len = Token_List->len;
+
+   if (len == 0)
+     {
+	compile_token_of_type (POP_TOKEN);
+	return;
+     }
+
+   while (len > 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 < 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 "slinclud.h"
+
+#ifdef HAVE_IO_H
+# include <io.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <time.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include "slang.h"
+#include "_slang.h"
+
+/* 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	"."
+#else
+# if defined(VMS)
+#  define PATH_SEP		']'
+#  define DRIVE_SPECIFIER	':'
+#  define SEARCH_PATH_DELIMITER	' '
+#  define THIS_DIR_STRING	"[]"   /* Is this correct?? */
+# else
+#  define PATH_SEP		'/'
+#  define UNIX_PATHNAMES_OK
+#  define SEARCH_PATH_DELIMITER	':'
+#  define THIS_DIR_STRING	"."
+# 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, "" 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 "" */
+   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 = "";
+
+   if ((dir == NULL) || (SLpath_is_absolute_path (name)))
+     dir = "";
+
+   /* 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 && (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__) && !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) & S_IFMT) == S_IFDIR)
+# else
+#  define S_ISDIR(m) 0
+# endif
+#endif
+
+   if (file == NULL)
+     return -1;
+
+   if (stat(file, &st) < 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 > max_path_len) max_path_len = this_path_len;
+	     this_path_len = 0;
+	  }
+	else this_path_len++;
+     }
+   if (this_path_len > 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 "slinclud.h"
+
+#if defined(__unix__) || (defined (__os2__) && defined (__EMX__))
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_IO_H
+# include <io.h>		       /* for chmod */
+#endif
+
+#if defined(__BORLANDC__)
+# include <process.h>
+# include <dos.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_FCNTL_H
+# include <sys/fcntl.h>
+#endif
+
+#ifdef __unix__
+# include <sys/file.h>
+#endif
+
+#if defined(__BORLANDC__)
+# include <dir.h>
+#endif
+
+#if defined(_MSC_VER)
+# include <io.h>
+#endif
+
+#if defined(__DECC) && defined(VMS)
+# include <unixio.h>
+# include <unixlib.h>
+#endif
+
+#ifdef VMS
+# include <stat.h>
+#else
+# include <sys/stat.h>
+#endif
+
+#if defined(VMS)
+# define USE_LISTDIR_INTRINSIC	0
+#else
+# define USE_LISTDIR_INTRINSIC	1
+#endif
+
+#if USE_LISTDIR_INTRINSIC
+
+#if defined(__WIN32__)
+# include <windows.h>
+#else
+# if defined(__OS2__) && defined(__IBMC__)
+#  define INCL_DOS
+#  define INCL_ERRORS
+#  include <os2.h>
+#  include <direct.h>
+#  include <ctype.h>
+# else
+#  ifdef HAVE_DIRENT_H
+#   include <dirent.h>
+#  else
+#   ifdef HAVE_DIRECT_H
+#    include <direct.h>
+#   else
+#    define dirent direct
+#    define NEED_D_NAMLEN
+#    if HAVE_SYS_NDIR_H
+#     include <sys/ndir.h>
+#    endif
+#    if HAVE_SYS_DIR_H
+#     include <sys/dir.h>
+#    endif
+#    if HAVE_NDIR_H
+#     include <ndir.h>
+#    endif
+#   endif
+#  endif
+# endif
+#endif
+
+#endif				       /* USE_LISTDIR_INTRINSIC */
+
+#include <errno.h>
+
+#include "slang.h"
+#include "_slang.h"
+
+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] = "st_dev"; int_values [0] = (int) st->st_dev;
+   field_names [1] = "st_ino"; int_values [1] = (int) st->st_ino;
+   field_names [2] = "st_mode"; int_values [2] = (int) st->st_mode;
+   field_names [3] = "st_nlink"; int_values [3] = (int) st->st_nlink;
+   field_names [4] = "st_uid"; int_values [4] = (int) st->st_uid;
+   field_names [5] = "st_gid"; int_values [5] = (int) st->st_gid;
+   field_names [6] = "st_rdev"; int_values [6] = (int) st->st_rdev;
+   field_names [7] = "st_size"; int_values [7] = (int) st->st_size;
+   field_names [8] = "st_atime"; int_values [8] = (int) st->st_atime;
+   field_names [9] = "st_mtime"; int_values [9] = (int) st->st_mtime;
+   field_names [10] = "st_ctime"; int_values [10] = (int) st->st_ctime;
+
+   field_names [11] = "st_opt_attrs"; int_values[11] = opt_attrs;
+
+   for (i = 0; i < 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, &st);
+
+#if defined(__MSDOS__) || defined(__WIN32__)
+   if (status == -1)
+     {
+	unsigned int len = strlen (file);
+	if (len && ((file[len-1] == '\\') || (file[len-1] == '/')))
+	  {
+	     file = SLmake_nstring (file, len-1);
+	     if (file == NULL)
+	       return;
+
+	     status = stat (file, &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 (&st, opt_attrs);
+}
+
+static void lstat_cmd (char *file)
+{
+#ifdef HAVE_LSTAT
+   struct stat st;
+   int opt_attrs;
+
+   if (-1 == lstat (file, &st))
+     {
+	_SLerrno_errno = errno;
+	SLang_push_null ();
+	return;
+     }
+
+#ifdef __WIN32__
+   opt_attrs = GetFileAttributes (file);
+#else
+   opt_attrs = 0;
+#endif
+   
+   push_stat_struct (&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) & S_IFMT) == S_IFLNK)
+# else
+#   define S_ISLNK(m) 0
+# endif
+#endif
+
+#ifndef S_ISREG
+# ifdef S_IFREG
+#   define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+# else
+#   define S_ISREG(m) 0
+# endif
+#endif
+
+#ifndef S_ISDIR
+# ifdef S_IFDIR
+#   define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+# else
+#   define S_ISDIR(m) 0
+# endif
+#endif
+
+#ifndef S_ISCHR
+# ifdef S_IFCHR
+#   define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+# else
+#   define S_ISCHR(m) 0
+# endif
+#endif
+
+#ifndef S_ISBLK
+# ifdef S_IFBLK
+#   define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
+# else
+#   define S_ISBLK(m) 0
+# endif
+#endif
+
+#ifndef S_ISFIFO
+# ifdef S_IFIFO
+#   define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+# else
+#   define S_ISFIFO(m) 0
+# endif
+#endif
+
+#ifndef S_ISSOCK
+# ifdef S_IFSOCK
+#   define S_ISSOCK(m) (((m) & 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, "sock")) ret = S_ISSOCK(st_mode);
+   else if (!strcmp (what, "fifo")) ret = S_ISFIFO(st_mode);
+   else if (!strcmp (what, "blk")) ret = S_ISBLK(st_mode);
+   else if (!strcmp (what, "chr")) ret = S_ISCHR(st_mode);
+   else if (!strcmp (what, "dir")) ret = S_ISDIR(st_mode);
+   else if (!strcmp (what, "reg")) ret = S_ISREG(st_mode);
+   else if (!strcmp (what, "lnk")) ret = S_ISLNK(st_mode);
+   else
+     {
+	SLang_verror (SL_INVALID_PARM, "stat_is: Unrecognized type: %s", 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)) > 1)
+     {
+	n--;
+#if defined(IBMPC_SYSTEM)
+      if ( dir[n] != '/' && dir[n] != '\\' )
+      	strcat(dir, "\\" );
+#else
+      if (dir[n] != '/' )
+      	strcat(dir, "/" );
+#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 > str)
+       && (s[-1] != ']'))
+     {
+	if ((s >= str + 4)
+	    && (0 == strcmp (s - 4, ".dir")))
+	  s -= 4;
+	goto add_dir_version;
+     }
+
+   /* Check for one of two possibilities:
+    * 
+    *     dev:[x]   --> dev:x
+    *     dev:[a.x] --> 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, ".dir");
+   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__) && !defined(__GO32__)
+# define MKDIR(x,y) mkdir(x)
+#else
+# if defined (__os2__) && !defined (__EMX__)
+#  define MKDIR(x,y) mkdir(x)
+# else
+#  if defined (__WIN32__) && !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 < num; i++)
+     SLang_free_slstring (list[i]);
+   SLfree ((char *) list);
+}
+
+#if defined(__WIN32__) || defined(__os2__) && 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, &status, sizeof(FILESTATUS3));
+# endif
+
+
+# ifdef __WIN32__
+   if (status == (DWORD)-1)
+     {
+	_SLerrno_errno = ENOENT;
+	return -1;
+     }
+   if (0 == (status & FILE_ATTRIBUTE_DIRECTORY))
+     {
+	_SLerrno_errno = ENOTDIR;
+	return -1;
+     }
+# else
+   if ((rc != 0) || (status.attrFile & 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 && (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, &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, &h, FILE_READONLY | FILE_DIRECTORY |
+		     FILE_ARCHIVED, &fd, sizeof(fd), &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 "." and ".." entries.
+	 */
+#ifdef __WIN32__
+	file = fd.cFileName;
+#else
+	file = fd.achName;
+#endif
+	if (
+#ifdef __WIN32__
+	    (hok || (0 == (fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)))
+#else
+	    (hok || (0 == (fd.attrFile & FILE_HIDDEN)))
+#endif
+	    && ((*file != '.')
+		|| ((0 != strcmp (file, "."))
+		    && (0 != strcmp (file, "..")))))
+	  {
+	     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, &fd))
+	  {
+	     if (ERROR_NO_MORE_FILES == GetLastError())
+	       {
+		  FindClose (h);
+		  break;
+	       }
+
+	     _SLerrno_errno = errno;
+	     FindClose (h);
+	     goto return_error;
+	  }
+#else
+        cFileNames = 1;
+        rc = DosFindNext(h, &fd, sizeof(fd), &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->d_name;
+#  ifdef NEED_D_NAMLEN
+	len = ep->d_namlen;
+#  else
+	len = strlen (name);
+#  endif
+	if ((*name == '.') && (len <= 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, &list, &num_files, &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 < 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, &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 (&sopt))
+	  return;
+      case 1:
+	if (-1 == SLang_pop_slstring (&s))
+	  {
+	     SLang_free_slstring (sopt);
+	     return;
+	  }
+	break;
+      default:
+	SLang_verror (SL_INVALID_PARM, "usage: listdir (string, [opt-string]");
+	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("readlink", readlink_cmd, SLANG_VOID_TYPE),
+#endif
+   MAKE_INTRINSIC_S("lstat_file", lstat_cmd, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_S("stat_file", stat_cmd, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_SI("stat_is", stat_is_cmd, SLANG_CHAR_TYPE),
+#ifdef HAVE_MKFIFO
+   MAKE_INTRINSIC_SI("mkfifo", mkfifo_cmd, SLANG_INT_TYPE),
+#endif
+#ifdef HAVE_CHOWN
+   MAKE_INTRINSIC_SII("chown", chown_cmd, SLANG_INT_TYPE),
+#endif
+   MAKE_INTRINSIC_SI("chmod", chmod_cmd, SLANG_INT_TYPE),
+#ifdef HAVE_UMASK
+   MAKE_INTRINSIC_I("umask", umask_cmd, SLANG_INT_TYPE),
+#endif
+   MAKE_INTRINSIC_0("getcwd", slget_cwd, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_SI("mkdir", mkdir_cmd, SLANG_INT_TYPE),
+   MAKE_INTRINSIC_S("chdir", chdir_cmd, SLANG_INT_TYPE),
+   MAKE_INTRINSIC_S("rmdir", rmdir_cmd, SLANG_INT_TYPE),
+   MAKE_INTRINSIC_S("remove", remove_cmd, SLANG_INT_TYPE),
+   MAKE_INTRINSIC_SS("rename", rename_cmd, SLANG_INT_TYPE),
+#if USE_LISTDIR_INTRINSIC
+   MAKE_INTRINSIC("listdir", 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("S_IRWXU", S_IRWXU),
+#ifndef S_IRUSR
+# define S_IRUSR 00400
+#endif
+   MAKE_ICONSTANT("S_IRUSR", S_IRUSR),
+#ifndef S_IWUSR
+# define S_IWUSR 00200
+#endif
+   MAKE_ICONSTANT("S_IWUSR", S_IWUSR),
+#ifndef S_IXUSR
+# define S_IXUSR 00100
+#endif
+   MAKE_ICONSTANT("S_IXUSR", S_IXUSR),
+#ifndef S_IRWXG
+# define S_IRWXG 00070
+#endif
+   MAKE_ICONSTANT("S_IRWXG", S_IRWXG),
+#ifndef S_IRGRP
+# define S_IRGRP 00040
+#endif
+   MAKE_ICONSTANT("S_IRGRP", S_IRGRP),
+#ifndef S_IWGRP
+# define S_IWGRP 00020
+#endif
+   MAKE_ICONSTANT("S_IWGRP", S_IWGRP),
+#ifndef S_IXGRP
+# define S_IXGRP 00010
+#endif
+   MAKE_ICONSTANT("S_IXGRP", S_IXGRP),
+#ifndef S_IRWXO
+# define S_IRWXO 00007
+#endif
+   MAKE_ICONSTANT("S_IRWXO", S_IRWXO),
+#ifndef S_IROTH
+# define S_IROTH 00004
+#endif
+   MAKE_ICONSTANT("S_IROTH", S_IROTH),
+#ifndef S_IWOTH
+# define S_IWOTH 00002
+#endif
+   MAKE_ICONSTANT("S_IWOTH", S_IWOTH),
+#ifndef S_IXOTH
+# define S_IXOTH 00001
+#endif
+   MAKE_ICONSTANT("S_IXOTH", S_IXOTH),
+#ifdef __WIN32__
+   MAKE_ICONSTANT("FILE_ATTRIBUTE_ARCHIVE", FILE_ATTRIBUTE_ARCHIVE),
+   MAKE_ICONSTANT("FILE_ATTRIBUTE_COMPRESSED", FILE_ATTRIBUTE_COMPRESSED),
+   MAKE_ICONSTANT("FILE_ATTRIBUTE_NORMAL", FILE_ATTRIBUTE_NORMAL),
+   MAKE_ICONSTANT("FILE_ATTRIBUTE_DIRECTORY", FILE_ATTRIBUTE_DIRECTORY),
+   MAKE_ICONSTANT("FILE_ATTRIBUTE_HIDDEN", FILE_ATTRIBUTE_HIDDEN),
+   MAKE_ICONSTANT("FILE_ATTRIBUTE_READONLY", FILE_ATTRIBUTE_READONLY),
+   MAKE_ICONSTANT("FILE_ATTRIBUTE_SYSTEM", FILE_ATTRIBUTE_SYSTEM),
+   MAKE_ICONSTANT("FILE_ATTRIBUTE_TEMPORARY", 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, "__POSIX_DIR__"))
+       || (-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 "slinclud.h"
+
+#if defined(__unix__) || (defined (__os2__) && defined (__EMX__))
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_FCNTL_H
+# include <sys/fcntl.h>
+#endif
+
+#ifdef __unix__
+# include <sys/file.h>
+#endif
+
+#ifdef HAVE_IO_H
+# include <io.h>
+#endif
+
+#if defined(__BORLANDC__)
+# include <dir.h>
+#endif
+
+#if defined(__DECC) && defined(VMS)
+# include <unixio.h>
+# include <unixlib.h>
+#endif
+
+#ifdef VMS
+# include <stat.h>
+#else
+# include <sys/stat.h>
+#endif
+
+#include <errno.h>
+
+#include "slang.h"
+#include "_slang.h"
+
+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->fd))
+     return -1;
+
+   if ((f->close != NULL)
+       && (-1 == f->close (f->fd)))
+     {
+	_SLerrno_errno = errno;
+	return -1;
+     }
+
+   if (f->stdio_mmt != NULL)
+     {
+	SLang_free_mmt (f->stdio_mmt);
+	f->stdio_mmt = NULL;
+     }
+
+   f->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->fd))
+       || (NULL == (p = (char *)SLbstring_get_pointer (bstr, &len))))
+     {
+	SLang_push_integer (-1);
+	return;
+     }
+
+   if (-1 == f->write (f->fd, p, &len))
+     {
+	_SLerrno_errno = errno;
+	SLang_push_integer (-1);
+	return;
+     }
+
+   (void) SLang_push_uinteger (len);
+}
+
+/* Usage: nn = read (f, &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->fd))
+       || (NULL == (b = SLmalloc (len + 1))))
+     goto return_error;
+   
+   if (-1 == f->read (f->fd, b, &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)&bstr))
+	    && (-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->name = SLang_create_slstring (name)))
+     {
+	SLfree ((char *)f);
+	return NULL;
+     }
+
+   f->fd = fd;
+   f->num_refs = 1;
+
+   f->close = close_method;
+   f->read = read_method;
+   f->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->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->name, fd)))
+     {
+	f0->close (fd);
+	return NULL;
+     }
+   
+   return f;
+}
+
+int SLfile_get_fd (SLFile_FD_Type *f, int *fd)
+{
+   if (f == NULL)
+     return -1;
+   
+   *fd = f->fd;
+   if (-1 == check_fd (*fd))
+     return -1;
+
+   return 0;
+}
+
+void SLfile_free_fd (SLFile_FD_Type *f)
+{
+   if (f == NULL)
+     return;
+
+   if (f->num_refs > 1)
+     {
+	f->num_refs -= 1;
+	return;
+     }
+
+   if (f->fd != -1)
+     {
+	if (f->close != NULL)
+	  (void) f->close (f->fd);
+
+	f->fd = -1;
+     }
+
+   if (f->stdio_mmt != NULL)
+     SLang_free_mmt (f->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 (&file, &flags, &mode))
+	  {
+	     SLang_push_null ();
+	     return;
+	  }
+	break;
+
+      case 2:
+      default:
+	if (-1 == pop_string_int (&file, &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->fd = open (f->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 (&mmt, &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->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->stdio_mmt == NULL)
+     {
+	if (-1 == _SLstdio_fdopen (f->name, f->fd, mode))
+	  return;
+
+	if (NULL == (f->stdio_mmt = SLang_pop_mmt (SLANG_FILE_PTR_TYPE)))
+	  return;
+     }
+
+   (void) SLang_push_mmt (f->stdio_mmt);
+}
+
+static long posix_lseek (SLFile_FD_Type *f, long ofs, int whence)
+{
+   long status;
+   
+   if (-1 == (status = lseek (f->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 (&mmt, &fp))
+	  return 0;		       /* invalid descriptor */
+
+	ret = isatty (fileno (fp));
+	SLang_free_mmt (mmt);
+	return ret;
+     }
+
+   if (-1 == SLfile_pop_fd (&f))
+     return 0;
+
+   ret = isatty (f->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("fileno", posix_fileno, V),
+   MAKE_INTRINSIC_0("isatty", posix_isatty, I),
+   MAKE_INTRINSIC_0("open", posix_open, V),
+   MAKE_INTRINSIC_3("read", posix_read, V, F, R, U),
+   MAKE_INTRINSIC_3("lseek", posix_lseek, L, F, L, I),
+   MAKE_INTRINSIC_2("fdopen", posix_fdopen, V, F, S),
+   MAKE_INTRINSIC_2("write", posix_write, V, F, B),
+   MAKE_INTRINSIC_1("dup_fd", posix_dup, V, F),
+   MAKE_INTRINSIC_1("close", 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("O_RDONLY", O_RDONLY),
+#endif
+#ifdef O_WRONLY
+   MAKE_ICONSTANT("O_WRONLY", O_WRONLY),
+#endif
+#ifdef O_RDWR
+   MAKE_ICONSTANT("O_RDWR", O_RDWR),
+#endif
+#ifdef O_APPEND
+   MAKE_ICONSTANT("O_APPEND", O_APPEND),
+#endif
+#ifdef O_CREAT
+   MAKE_ICONSTANT("O_CREAT", O_CREAT),
+#endif
+#ifdef O_EXCL
+   MAKE_ICONSTANT("O_EXCL", O_EXCL),
+#endif
+#ifdef O_NOCTTY
+   MAKE_ICONSTANT("O_NOCTTY", O_NOCTTY),
+#endif
+#ifdef O_NONBLOCK
+   MAKE_ICONSTANT("O_NONBLOCK", O_NONBLOCK),
+#endif
+#ifdef O_TRUNC
+   MAKE_ICONSTANT("O_TRUNC", O_TRUNC),
+#endif
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
+   MAKE_ICONSTANT("O_BINARY", O_BINARY),
+#ifndef O_TEXT
+# define O_TEXT 0
+#endif
+   MAKE_ICONSTANT("O_TEXT", O_TEXT),
+
+   SLANG_END_ICONST_TABLE
+};
+
+int SLfile_push_fd (SLFile_FD_Type *f)
+{
+   if (f == NULL)
+     return SLang_push_null ();
+
+   f->num_refs += 1;
+
+   if (0 == SLclass_push_ptr_obj (SLANG_FILE_FD_TYPE, (VOID_STAR) f))
+     return 0;
+
+   f->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 ("FD_Type")))
+     return -1;
+   cl->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, "__POSIXIO__"))
+       || (-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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+/*}}}*/
+
+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->this_level = 0;
+   pt->exec_level = 0;
+   pt->prev_exec_level = 0;
+   pt->comment_char = '%';
+   pt->preprocess_char = '#';
+   pt->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 <paulh at harlequin.co.uk>
+ * 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, "*"))
+     return 1;
+   else if (string == NULL)
+     return 0;
+
+   while (*pattern && *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')
+	   && ((*pattern == '\0') || !strcmp (pattern, "*")));
+}
+/*}}}*/
+
+#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 < 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) != ' ')
+	       && (ch != '\n')
+	       && (ch != 0)
+	       && (ch != '\t')
+	       && (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 < token_end) && (*buf > ' '))
+     *token++ = *buf++;
+
+   if (*buf > ' ') 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 <= ' ') || (*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 && (*buf != '\n') && (*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->preprocess_char)
+     {
+	if (pt->this_level != pt->exec_level)
+	  return 0;
+
+	if (*buf == '\n') return pt->flags & SLPREP_BLANK_LINES_OK;
+	if (*buf == pt->comment_char) return pt->flags & SLPREP_COMMENT_LINES_OK;
+
+	return 1;
+     }
+
+   level = pt->this_level;
+   exec_level = pt->exec_level;
+   prev_exec_level = pt->prev_exec_level;
+
+   buf++;
+
+   /* Allow '#!' to pass.  This could be a shell script with something
+    like '#! /local/bin/slang'  */
+   if ((*buf == '!') && (pt->preprocess_char == '#'))
+     return 0;
+
+   /* Allow whitespace as in '#   ifdef'  */
+   while ((*buf == ' ') || (*buf == '\t')) buf++;
+   if (*buf < 'a') return (level == exec_level);
+
+   if (!strncmp(buf, "endif", 5))
+     {
+	if (level == exec_level)
+	  {
+	     exec_level--;
+	     prev_exec_level = exec_level;
+	  }
+	level--;
+	if (level < prev_exec_level) prev_exec_level = level;
+	goto done;
+     }
+
+   if ((buf[0] == 'e') && (buf[1] == 'l'))   /* else, elifdef, ... */
+     {
+	if ((level == exec_level + 1)
+	    && (prev_exec_level != level))
+	  {
+	     /* We are in position to execute */
+	     buf += 2;
+	     if ((buf[0] == 's') && (buf[1] == 'e'))
+	       {
+		  /* "else" */
+		  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') && (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, "def", 3))
+	  truth = (truth == is_any_defined(buf + 3, pt->comment_char));
+
+	else if (!strncmp (buf, "false", 5))
+	  truth = !truth;
+
+	else if (*buf == '$')
+	  truth = (truth == is_env_defined (buf + 1, pt->comment_char));
+
+	else if (!strncmp (buf, "exists", 6)
+		 && (SLprep_exists_hook != NULL))
+	  truth = (truth == (*SLprep_exists_hook)(buf + 6, pt->comment_char));
+
+	else if (!strncmp (buf, "eval", 4)
+		 && (_SLprep_eval_hook != NULL))
+	  truth = (truth == (*_SLprep_eval_hook) (buf + 4));
+			   
+	else if (0 != strncmp (buf, "true", 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 < 0) return 1;
+
+   pt->this_level = level;
+   pt->exec_level = exec_level;
+   pt->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 (&pt);
+
+   SLdefine_for_ifdef ("UNIX");
+
+   while (NULL != fgets (buf, sizeof (buf) - 1, stdin))
+     {
+	if (SLprep_line_ok (buf, &pt))
+	  {
+	     fputs (buf, stdout);
+	  }
+     }
+
+   SLprep_close_prep (&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 "slinclud.h"
+
+#ifdef HAVE_IO_H
+# include <io.h>		       /* for chmod */
+#endif
+
+#ifdef HAVE_PROCESS_H
+# include <process.h>			/* for getpid */
+#endif
+
+#if defined(__BORLANDC__)
+# include <dos.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <time.h>
+
+#include <errno.h>
+
+#include "slang.h"
+#include "_slang.h"
+
+#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("getpid", getpid_cmd, SLANG_INT_TYPE),
+
+#ifdef HAVE_GETPPID
+   MAKE_INTRINSIC_0("getppid", getppid_cmd, SLANG_INT_TYPE),
+#endif
+#ifdef HAVE_GETGID
+   MAKE_INTRINSIC_0("getgid", getgid_cmd, SLANG_INT_TYPE),
+#endif
+#ifdef HAVE_GETEGID
+   MAKE_INTRINSIC_0("getegid", getegid_cmd, SLANG_INT_TYPE),
+#endif
+#ifdef HAVE_GETEUID
+   MAKE_INTRINSIC_0("geteuid", geteuid_cmd, SLANG_INT_TYPE),
+#endif
+#ifdef HAVE_GETUID
+   MAKE_INTRINSIC_0("getuid", getuid_cmd, SLANG_INT_TYPE),
+#endif
+#ifdef HAVE_SETGID
+   MAKE_INTRINSIC_I("setgid", setgid_cmd, SLANG_INT_TYPE),
+#endif
+#ifdef HAVE_SETPGID
+   MAKE_INTRINSIC_II("setpgid", setpgid_cmd, SLANG_INT_TYPE),
+#endif
+#ifdef HAVE_SETUID
+   MAKE_INTRINSIC_I("setuid", setuid_cmd, SLANG_INT_TYPE),
+#endif
+
+#ifdef HAVE_KILL
+   MAKE_INTRINSIC_II("kill", 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, "__POSIX_PROCESS__"))
+       || (-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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+#define SET_BIT(b, n) b[(unsigned int) (n) >> 3] |= 1 << ((unsigned int) (n) % 8)
+#define TEST_BIT(b, n) (b[(unsigned int)(n) >> 3] & (1 << ((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		       /* \< */
+#define EOW	0xB		       /* \> */
+#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->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->closed_paren_matches[n] == 0)
+     return NULL;
+
+   bpos = ctx->reg->beg_matches[n] + ctx->str;
+   n = ctx->reg->end_matches[n];
+   if (n == 0) return(str);
+   if (n > (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 < estr) c = UPPERCASE(*str); */
+
+	switch((unsigned char) p)
+	  {
+	   case BOW:
+	     if ((str != ctx->str)
+		 && ((str >= estr)
+		     || IS_WORD_CHAR(*(str - 1))
+		     || (0 == IS_WORD_CHAR(*str)))) return NULL;
+	     break;
+
+	   case EOW:
+	     if ((str < estr)
+		 && IS_WORD_CHAR (*str)) return NULL;
+	     break;
+
+	   case YES_CASE: cs = 1; break;
+	   case NO_CASE: cs = 0; break;
+
+	   case OPAREN:
+	     ctx->open_paren_number++;
+	     ctx->reg->beg_matches[ctx->open_paren_number] = (int) (str - ctx->str);
+	     break;
+	   case CPAREN:
+	     n = ctx->open_paren_number;
+	     while (n > 0)
+	       {
+		  if (ctx->closed_paren_matches[n] != 0)
+		    {
+		       n--;
+		       continue;
+		    }
+		  ctx->closed_paren_matches[n] = 1;
+		  ctx->reg->end_matches[n] = (unsigned int) (str - (ctx->str + ctx->reg->beg_matches[n]));
+		  break;
+	       }
+	     break;
+#ifdef NOT_LITERAL
+	   case NOT_LITERAL:
+	     if ((str >= estr) || (*buf == UPPERCASE(*str))) return (NULL);
+	     str++; buf++;
+	     break;
+
+	   case MAYBE_ONCE | NOT_LITERAL:
+	     save_str = str;
+	     if ((str < estr) && (*buf != UPPERCASE(*str))) str++;
+	     buf++;
+	     goto match_rest;
+
+	   case NOT_LITERAL | LEAST_ONCE:   /* match at least once */
+	     if ((str >= estr) || (UPPERCASE(*str) == UPPERCASE(*buf))) return (NULL);
+	     str++;
+	     /* drop */
+	   case STAR | NOT_LITERAL:
+	     save_str = str;  p1 = *buf;
+	     while ((str < estr) && (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 && (str < estr) && (p1 != *str))
+	       {
+		  n--;
+		  str++;
+	       }
+	     if (n) return (NULL);
+
+	     save_str = str;
+	     n = n1 - n0;
+	     while (n && (str < estr) && (p1 != *str))
+	       {
+		  n--;
+		  str++;
+	       }
+	     goto match_rest;
+#endif				       /* NOT_LITERAL */
+	   case LITERAL:
+	     if ((str >= estr) || (*buf != UPPERCASE(*str))) return (NULL);
+	     str++; buf++;
+	     break;
+
+	   case MAYBE_ONCE | LITERAL:
+	     save_str = str;
+	     if ((str < estr) && (*buf == UPPERCASE(*str))) str++;
+	     buf++;
+	     goto match_rest;
+
+	   case LITERAL | LEAST_ONCE:   /* match at least once */
+	     if ((str >= estr) || (UPPERCASE(*str) != UPPERCASE(*buf))) return (NULL);
+	     str++;
+	     /* drop */
+	   case STAR | LITERAL:
+	     save_str = str;  p1 = *buf;
+	     while ((str < estr) && (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 && (str < estr) && (p1 == *str))
+	       {
+		  n--;
+		  str++;
+	       }
+	     if (n) return (NULL);
+
+	     save_str = str;
+	     n = n1 - n0;
+	     while (n && (str < estr) && (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 >= 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 < estr) && TEST_BIT(buf, UPPERCASE(*str))) str++;
+	     buf += 32;
+	     goto match_rest;
+
+	   case LEAST_ONCE | RANGE:
+	     if ((str >= estr) || (0 == TEST_BIT(buf, UPPERCASE(*str)))) return NULL;
+	     str++;
+	     /* drop */
+	   case STAR | RANGE:
+	     save_str = str;
+	     while ((str < estr) && 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 && (str < estr) && (TEST_BIT(buf, UPPERCASE(*str))))
+	       {
+		  n--;
+		  str++;
+	       }
+	     if (n) return (NULL);
+	     save_str = str;
+	     n = n1 - n0;
+	     while (n && (str < estr) && (TEST_BIT(buf, UPPERCASE(*str))))
+	       {
+		  n--;
+		  str++;
+	       }
+	     buf += 34;		       /* 32 + 2 */
+	     goto match_rest;
+
+	   case ANY_DIGIT:
+	     if ((str >= estr) || (*str > '9') || (*str < '0')) return (NULL);
+	     str++;
+	     break;
+
+	   case MAYBE_ONCE | ANY_DIGIT:
+	     save_str = str;
+	     if ((str < estr) && ((*str > '9') || (*str < '0'))) str++;
+	     goto match_rest;
+
+	   case LEAST_ONCE | ANY_DIGIT:
+	     if ((str >= estr) || ((*str > '9') || (*str < '0'))) return NULL;
+	     str++;
+	     /* drop */
+	   case STAR | ANY_DIGIT:
+	     save_str = str;
+	     while ((str < estr) && ((*str <= '9') && (*str >= '0'))) str++;
+	     goto match_rest;
+
+	   case MANY | ANY_DIGIT:
+	     /* needs finished */
+	     return (NULL);
+
+	   case ANY:
+	     if ((str >= estr) || (*str == '\n')) return (NULL);
+	     str++;
+	     break;
+
+	   case MAYBE_ONCE | ANY:
+	     save_str = str;
+	     if ((str < estr) && (*str != '\n')) str++;
+	     goto match_rest;
+
+	   case LEAST_ONCE | ANY:
+	     if ((str >= estr) || (*str == '\n')) return (NULL);
+	     str++;
+	     /* drop */
+	   case STAR | ANY:
+	     save_str = str;
+	     while ((str < estr) && (*str != '\n')) str++;
+	     goto match_rest;
+
+	   case MANY | ANY:
+	     return (NULL);
+	     /* needs finished */
+
+	   case EOL:
+	     if ((str >= 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 < estr) return (NULL); else return (str);
+	 * }
+	 */
+
+	SLMEMCPY(save_closed_matches, ctx->closed_paren_matches, sizeof(save_closed_matches));
+	save_num_open = ctx->open_paren_number;
+	while (str >= save_str)
+	  {
+	     tmpstr = regexp_looking_at (ctx, str, estr, buf, cs);
+	     if (tmpstr != NULL) return(tmpstr);
+	     SLMEMCPY(ctx->closed_paren_matches, save_closed_matches, sizeof(ctx->closed_paren_matches));
+	     ctx->open_paren_number = save_num_open;
+	     str--;
+	  }
+	return NULL;
+     }
+   if ((p != 0) && (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->beg_matches[0] = -1;
+	r->end_matches[0] = 0;
+	SLMEMSET(ctx->closed_paren_matches, 0, sizeof(ctx->closed_paren_matches));
+     }
+   else
+     {
+	r->beg_matches[0] = (int) (str - ctx->str);
+	r->end_matches[0] = (unsigned int) (epos - str);
+     }
+
+   for (i = 1; i < 10; i++)
+     {
+	if (ctx->closed_paren_matches [i] == 0)
+	  {
+	     r->beg_matches[i] = -1;
+	     r->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->reg = reg;
+   ctx->str = str;
+   ctx->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->case_sensitive, lit = 0;
+   unsigned char *buf = reg->buf, *epos = NULL;
+   Re_Context_Type ctx_buf;
+
+   if (reg->min_length > len) return NULL;
+
+   init_re_context (&ctx_buf, reg, str, len);
+
+   if (*buf == BOL)
+     {
+	if (NULL == (epos = regexp_looking_at (&ctx_buf, str, estr, buf + 1, cs)))
+	  str = NULL;
+
+	fixup_beg_end_matches (&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) && (*(buf + 1) == LITERAL))
+     {
+	lit = 1;
+	c = *(buf + 2);
+     }
+
+   while (str < 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 < estr) && (c != UPPERCASE(*str))) str++;
+	     if (str >= estr)
+	       break;		       /* failed */
+	  }
+
+	if (NULL != (epos = regexp_looking_at(&ctx_buf, str, estr, buf, cs)))
+	  {
+	     fixup_beg_end_matches (&ctx_buf, reg, str, epos);
+	     return str;
+	  }
+	str++;
+     }
+   fixup_beg_end_matches (&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 <= '9') && (c >= '0'))
+     {
+	pat++;
+	n = 10 * n + (c - '0');
+	m++;
+     }
+   if (m == 0)
+     {
+	return (NULL);
+     }
+   *nn = n;
+   return pat;
+}
+
+#define ERROR  return (int) (pat - reg->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->beg_matches[0] = reg->end_matches[0] = 0;
+   buf = reg->buf;
+   ebuf = (reg->buf + reg->buf_len) - 2; /* make some room */
+   pat = reg->pat;
+   cs = reg->case_sensitive;
+
+   if (already_initialized == 0)
+     {
+	SLang_init_case_tables ();
+#ifdef IBMPC_SYSTEM
+	SLmake_lut (Word_Chars, (unsigned char *) "_0-9a-zA-Z\200-\232\240-\245\341-\353", 0);
+#else
+	SLmake_lut (Word_Chars, (unsigned char *) "_0-9a-zA-Z\277-\326\330-\336\340-\366\370-\376", 0);
+#endif
+	already_initialized = 1;
+     }
+
+   i = 1; while (i < 10)
+     {
+	reg->beg_matches[i] = -1;
+	reg->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->must_match_bol = 1;
+     }
+   else reg->must_match_bol = 0;
+
+   if (cs != reg->case_sensitive)
+     {
+	if (cs) *buf++ = YES_CASE; 
+	else *buf++ = NO_CASE; 
+     }
+
+   *buf = 0;
+
+   last_count = count = 0;
+   while ((c = *pat++) != 0)
+     {
+	if (buf >= ebuf - 3)
+	  {
+	     SLang_doerror ("Pattern too large to be compiled.");
+	     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 > 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 '<':
+		  last = NULL;
+		  *buf++ = BOW;
+		  break;
+
+		case '>':
+		  last = NULL;
+		  *buf++ = EOW;
+		  break;
+
+		case '{':
+		  if (last == NULL) goto literal_char;
+		  *last |= MANY;
+		  tmppat = convert_digit(pat, &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, &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 > 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 >= ebuf) ERROR;
+
+	     for (i = 0; i < 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 && (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 < *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 < 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 < 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->buf;
+
+   if (no_osearch) ordinary_search = 0;
+   else
+     {
+	ordinary_search = 1;
+	while (buf < ebuf)
+	  {
+	     if (*buf != LITERAL)
+	       {
+		  ordinary_search = 0;
+		  break;
+	       }
+	     buf += 2;
+	  }
+     }
+
+   reg->osearch = ordinary_search;
+   reg->must_match_str[15] = 0;
+   reg->min_length = (min_length > 0) ? (unsigned int) min_length : 0;
+   if (ordinary_search)
+     {
+	strncpy((char *) reg->must_match_str, (char *) reg->pat, 15);
+	reg->must_match = 1;
+	return(0);
+     }
+   /* check for longest substring of pattern */
+   reg->must_match = 0;
+   if ((mm_p == NULL) && (this_mm_p != NULL)) mm_p = this_mm_p;
+   if (mm_p == NULL)
+     {
+	return (0);
+     }
+   n = 15;
+   pat = reg->must_match_str;
+   buf = mm_p;
+   while (n--)
+     {
+	if (*buf++ != LITERAL) break;
+	*pat++ = *buf++;
+     }
+   *pat = 0;
+   if (pat != reg->must_match_str) reg->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 < 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, "r")))
+     {
+	fprintf(stderr, "File not open\n");
+	return(1);
+     }
+
+   reg.buf = expbuf;
+   reg.buf_len = MAX_EXP;
+   reg.pat = regexp;
+   reg.case_sensitive = 1;
+
+   if (!regexp_compile(&reg)) while (NULL != fgets(buf, 511, fp))
+     {
+	if (reg.osearch)
+	  {
+	     if (NULL == strstr(buf, reg.pat)) continue;
+	  }
+	else
+	  {
+	     if (reg.must_match && (NULL == strstr(buf, reg.must_match_str))) continue;
+	     if (0 == regexp_match(buf, buf + strlen(buf), &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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+#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->point == 0) return 0;
+   This_RLI->point = 0;
+   return 1;
+}
+
+static int rl_eol (void)
+{
+   if (This_RLI->point == This_RLI->len) return 0;
+   This_RLI->point = This_RLI->len;
+   return 1;
+}
+
+static int rl_right (void)
+{
+   if (This_RLI->point == This_RLI->len) return 0;
+   This_RLI->point++;
+   return 1;
+}
+
+static int rl_left (void)
+{
+   if (This_RLI->point == 0) return 0;
+   This_RLI->point--;
+   return 1;
+}
+
+static int rl_self_insert (void)
+{
+   unsigned char *pmin, *p;
+
+   if (This_RLI->len == This_RLI->buf_len)
+     {
+	rl_beep ();
+	return 0;
+     }
+
+   pmin = This_RLI->buf + This_RLI->point;
+   p = This_RLI->buf + This_RLI->len;
+   while (p > pmin)
+     {
+	*p = *(p - 1);
+	p--;
+     }
+   *pmin = SLang_Last_Key_Char;
+
+   This_RLI->len++;
+   This_RLI->point++;
+   if ((This_RLI->curs_pos + 2 >= This_RLI->edit_width)
+       || (This_RLI->tt_insert == NULL)
+       || (Char_Widths[SLang_Last_Key_Char] != 1)) return 1;
+
+   (*This_RLI->tt_insert)((char) SLang_Last_Key_Char);
+   /* update screen buf */
+   p = This_RLI->old_upd + (This_RLI->len - 1);
+   pmin = This_RLI->old_upd + (This_RLI->point - 1);
+   while (p > 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 > This_RLI->buf_len - This_RLI->len)
+     n = This_RLI->buf_len - This_RLI->len;
+
+   if (n == 0) return 0;
+
+   pmin = This_RLI->buf + This_RLI->point;
+   p = This_RLI->buf + (This_RLI->len - 1);
+
+   while (p >= pmin)
+     {
+	*(p + n) = *p;
+	p--;
+     }
+   SLMEMCPY ((char *) pmin, s, n);
+
+   This_RLI->len += n;
+   This_RLI->point += n;
+   return n;
+}
+
+static int rl_deln (int n)
+{
+   unsigned char *pmax, *p;
+
+   p = This_RLI->buf + This_RLI->point;
+   pmax = This_RLI->buf + This_RLI->len;
+
+   if (p + n > pmax) n = (int) (pmax - p);
+   while (p < pmax)
+     {
+	*p = *(p + n);
+	p++;
+     }
+   This_RLI->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->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->buf + This_RLI->point;
+   pmax = This_RLI->buf + This_RLI->len;
+
+   if (p == pmax)
+     {
+	if (p == This_RLI->buf) return 0;
+	p--;
+     }
+
+   if ((*p != ' ') && (*p != '\t')) return 0;
+   p1 = p;
+   while ((p1 < pmax) && ((*p1 == ' ') || (*p1 == '\t'))) p1++;
+   pmax = p1;
+   p1 = This_RLI->buf;
+
+   while ((p >= p1) && ((*p == ' ') || (*p == '\t'))) p--;
+   if (p == pmax) return 0;
+   p++;
+
+   This_RLI->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->point == This_RLI->len) return 0;
+   *(This_RLI->buf + This_RLI->point) = 0;
+   This_RLI->len = This_RLI->point;
+   return 1;
+}
+
+static int rl_delete_line (void)
+{
+   This_RLI->point = 0;
+   *(This_RLI->buf + This_RLI->point) = 0;
+   This_RLI->len = 0;
+   return 1;
+}
+
+static int rl_enter (void)
+{
+   *(This_RLI->buf + This_RLI->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->curs_pos)
+     {
+	fflush (stdout);
+	return;
+     }
+
+   if (This_RLI->tt_goto_column != NULL)
+     {
+	(*This_RLI->tt_goto_column)(col);
+	This_RLI->curs_pos = col;
+	fflush (stdout);
+	return;
+     }
+
+   dc = This_RLI->curs_pos - col;
+   if (dc < 0)
+     {
+	p = This_RLI->new_upd + This_RLI->curs_pos;
+	pmax = This_RLI->new_upd + col;
+	while (p < pmax) putc((char) *p++, stdout);
+     }
+   else
+     {
+	if (dc < col)
+	  {
+	     while (dc--) putc(8, stdout);
+	  }
+	else
+	  {
+	     putc('\r', stdout);
+	     p = This_RLI->new_upd;
+	     pmax = This_RLI->new_upd + col;
+	     while (p < pmax) putc((char) *p++, stdout);
+	  }
+     }
+   This_RLI->curs_pos = col;
+   fflush (stdout);
+}
+
+static void erase_eol (SLang_RLine_Info_Type *rli)
+{
+   unsigned char *p, *pmax;
+
+   p = rli->old_upd + rli->curs_pos;
+   pmax = rli->old_upd + rli->old_upd_len;
+
+   while (p++ < pmax) putc(' ', stdout);
+
+   rli->curs_pos = rli->old_upd_len;
+}
+
+static unsigned char *spit_out(SLang_RLine_Info_Type *rli, unsigned char *p)
+{
+   unsigned char *pmax;
+   position_cursor ((int) (p - rli->new_upd));
+   pmax = rli->new_upd + rli->new_upd_len;
+   while (p < pmax) putc((char) *p++, stdout);
+   rli->curs_pos = rli->new_upd_len;
+   return pmax;
+}
+
+static void really_update (SLang_RLine_Info_Type *rli, int new_curs_position)
+{
+   unsigned char *b = rli->old_upd, *p = rli->new_upd, chb, chp;
+   unsigned char *pmax;
+
+   if (rli->update_hook != NULL)
+     {
+	(*rli->update_hook)(p, rli->edit_width, new_curs_position);
+     }
+   else
+     {
+	pmax = p + rli->edit_width;
+	while (p < pmax)
+	  {
+	     chb = *b++; chp = *p++;
+	     if (chb == chp) continue;
+
+	     if (rli->old_upd_len <= rli->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->old_upd_len = rli->new_upd_len;
+   p = rli->old_upd;
+   rli->old_upd = rli->new_upd;
+   rli->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->flags & SL_RLINE_NO_ECHO;
+
+   b_point = (unsigned char *) (rli->buf + rli->point);
+   *(rli->buf + rli->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->prompt;
+   while (count--)
+     {
+	if ((count == 0) && 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') && tw)
+	       {
+		  dlen = tw * ((len - prompt_len) / tw + 1) - (len - prompt_len);
+	       }
+	     len += dlen;
+	     b++;
+	  }
+	tw = rli->tab;
+	b = (unsigned char *) rli->buf;
+	if (count == 1) want_cursor_pos = prompt_len = len;
+     }
+
+   if (len < rli->edit_width - rli->dhscroll) start_len = 0;
+   else if ((rli->start_column > len)
+	    || (rli->start_column + rli->edit_width <= len))
+     {
+	start_len = len - (rli->edit_width - rli->dhscroll);
+	if (start_len < 0) start_len = 0;
+     }
+   else start_len = rli->start_column;
+   rli->start_column = start_len;
+
+   want_cursor_pos = len - start_len;
+
+   /* second pass */
+   p = rli->new_upd;
+
+   len = 0;
+   count = 2;
+   b = (unsigned char *) rli->prompt;
+   if (b == NULL) b = (unsigned char *) "";
+
+   while ((len < start_len) && (*b))
+     {
+	len += Char_Widths[*b++];
+     }
+
+   tw = 0;
+   if (*b == 0)
+     {
+	b = (unsigned char *) rli->buf;
+	while (len < start_len)
+	  {
+	     len += Char_Widths[*b++];
+	  }
+	tw = rli->tab;
+	count--;
+     }
+
+   len = 0;
+   while (count--)
+     {
+	if ((count == 0) && (no_echo))
+	  break;
+
+	while ((len < rli->edit_width) && ((chb = *b++) != 0))
+	  {
+	     dlen = Char_Widths[chb];
+	     if (dlen == 1) *p++ = chb;
+	     else
+	       {
+		  if ((chb == '\t') && 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 > rli->edit_width) dlen = len - rli->edit_width;
+		       while (dlen--) *p++ = ' ';
+		       dlen = 0;
+		    }
+		  else
+		    {
+		       if (dlen == 3)
+			 {
+			    chb &= 0x7F;
+			    *p++ = '~';
+			 }
+
+		       *p++ = '^';
+		       if (chb == 127)  *p++ = '?';
+		       else *p++ = chb + '@';
+		    }
+	       }
+	     len += dlen;
+	  }
+	/* if (start_len > prompt_len) break; */
+	tw = rli->tab;
+	b = (unsigned char *) rli->buf;
+     }
+
+   rli->new_upd_len = (int) (p - rli->new_upd);
+   while (p < rli->new_upd + rli->edit_width) *p++ = ' ';
+   really_update (rli, want_cursor_pos);
+}
+
+void SLrline_redraw (SLang_RLine_Info_Type *rli)
+{
+   unsigned char *p = rli->new_upd;
+   unsigned char *pmax = p + rli->edit_width;
+   while (p < pmax) *p++ = ' ';
+   rli->new_upd_len = rli->edit_width;
+   really_update (rli, 0);
+   RLupdate (rli);
+}
+
+static int rl_eof_insert (void)
+{
+   if (This_RLI->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->buf;
+   p = pmin + rli->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 > pmin)
+     {
+	char ch;
+
+	p--;
+	delta_column++;
+	ch = *p;
+
+	if (ch == ket)
+	  {
+	     if ((dq_level == 0) && (sq_level == 0))
+	       level++;
+	  }
+	else if (ch == bra)
+	  {
+	     if ((dq_level != 0) || (sq_level != 0))
+	       continue;
+
+	     level--;
+	     if (level == 0)
+	       {
+		  rli->point -= delta_column;
+		  RLupdate (rli);
+		  (*rli->input_pending)(10);
+		  rli->point += delta_column;
+		  RLupdate (rli);
+		  break;
+	       }
+	     if (level < 0)
+	       break;
+	  }
+	else if (ch == '"') 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->old_upd; pmax = p + rli->edit_width;
+   while (p < pmax) *p++ = ' ';
+
+   /* Sanity checking */
+   rli->len = strlen ((char *) rli->buf);
+   if (rli->len >= rli->buf_len)
+     {
+	rli->len = 0;
+	*rli->buf = 0;
+     }
+   if (rli->point > rli->len) rli->point = rli->len;
+   if (rli->point < 0) rli->point = 0;
+
+   rli->curs_pos = rli->start_column = 0;
+   rli->new_upd_len = rli->old_upd_len = 0;
+
+   This_RLI->last_fun = NULL;
+   if (rli->update_hook == NULL)
+     putc ('\r', stdout);
+
+   RLupdate (rli);
+
+   while (1)
+     {
+	key = SLang_do_key (RL_Keymap, (int (*)(void)) rli->getkey);
+
+	if ((key == NULL) || (key->f.f == NULL))
+	  rl_beep ();
+	else
+	  {
+	     if ((SLang_Last_Key_Char == SLang_RL_EOF_Char)
+		 && (*key->str == 2)
+		 && (This_RLI->len == 0))
+	       rl_eof_insert ();
+	     else if (key->type == SLKEY_F_INTRINSIC)
+	       {
+		  if ((key->f.f)())
+		    RLupdate (rli);
+
+		  if ((rli->flags & SL_RLINE_BLINK_MATCH)
+		      && (rli->input_pending != NULL))
+		    blink_match (rli);
+	       }
+
+	     if (SLang_Rline_Quit)
+	       {
+		  This_RLI->buf[This_RLI->len] = 0;
+		  if (SLang_Error == SL_USER_BREAK)
+		    {
+		       SLang_Error = 0;
+		       return -1;
+		    }
+		  return This_RLI->len;
+	       }
+	  }
+	if (key != NULL)
+	  This_RLI->last_fun = key->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, "\033[%dC", n);
+}
+
+static void rl_select_line (SLang_Read_Line_Type *p)
+{
+   This_RLI->last = p;
+   strcpy ((char *) This_RLI->buf, (char *) p->buf);
+   This_RLI->point = This_RLI->len = strlen((char *) p->buf);
+}
+static int rl_next_line (void);
+static int rl_prev_line (void)
+{
+   SLang_Read_Line_Type *prev;
+
+   if (((This_RLI->last_fun != (FVOID_STAR) rl_prev_line)
+	&& (This_RLI->last_fun != (FVOID_STAR) rl_next_line))
+       || (This_RLI->last == NULL))
+     {
+	prev = This_RLI->tail;
+     }
+   else prev = This_RLI->last->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->last_fun != (FVOID_STAR) rl_prev_line)
+	&& (This_RLI->last_fun != (FVOID_STAR) rl_next_line))
+       || (This_RLI->last == NULL))
+      {
+	 rl_beep ();
+	 return 0;
+      }
+
+   next = This_RLI->last->next;
+
+   if (next == NULL)
+     {
+	This_RLI->len = This_RLI->point = 0;
+	*This_RLI->buf = 0;
+	This_RLI->last = NULL;
+     }
+   else rl_select_line (next);
+   return 1;
+}
+
+static SLKeymap_Function_Type SLReadLine_Functions[] =
+{
+   {"up", rl_prev_line},
+   {"down", rl_next_line},
+   {"bol", rl_bol},
+   {"eol", rl_eol},
+   {"right", rl_right},
+   {"left", rl_left},
+   {"self_insert", rl_self_insert},
+   {"bdel", rl_bdel},
+   {"del", rl_del},
+   {"deleol", rl_deleol},
+   {"enter", rl_enter},
+   {"trim", rl_trim},
+   {"quoted_insert", 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 ("ReadLine", NULL)))
+	  return -1;
+
+	RL_Keymap->functions = SLReadLine_Functions;
+
+	/* This breaks under some DEC ALPHA compilers (scary!) */
+#ifndef __DECC
+	for (ch = ' '; ch < 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  ("^[[A", (FVOID_STAR) rl_prev_line, RL_Keymap);
+	SLkm_define_key  ("^[[B", (FVOID_STAR) rl_next_line, RL_Keymap);
+	SLkm_define_key  ("^[[C", (FVOID_STAR) rl_right, RL_Keymap);
+	SLkm_define_key  ("^[[D", (FVOID_STAR) rl_left, RL_Keymap);
+	SLkm_define_key  ("^[OA", (FVOID_STAR) rl_prev_line, RL_Keymap);
+	SLkm_define_key  ("^[OB", (FVOID_STAR) rl_next_line, RL_Keymap);
+	SLkm_define_key  ("^[OC", (FVOID_STAR) rl_right, RL_Keymap);
+	SLkm_define_key  ("^[OD", (FVOID_STAR) rl_left, RL_Keymap);
+#else
+	SLkm_define_key  ("^@H", (FVOID_STAR) rl_prev_line, RL_Keymap);
+	SLkm_define_key  ("^@P", (FVOID_STAR) rl_next_line, RL_Keymap);
+	SLkm_define_key  ("^@M", (FVOID_STAR) rl_right, RL_Keymap);
+	SLkm_define_key  ("^@K", (FVOID_STAR) rl_left, RL_Keymap);
+	SLkm_define_key  ("^@S", (FVOID_STAR) rl_del, RL_Keymap);
+	SLkm_define_key  ("^@O", (FVOID_STAR) rl_eol, RL_Keymap);
+	SLkm_define_key  ("^@G", (FVOID_STAR) rl_bol, RL_Keymap);
+
+	SLkm_define_key  ("\xE0H", (FVOID_STAR) rl_prev_line, RL_Keymap);
+	SLkm_define_key  ("\xE0P", (FVOID_STAR) rl_next_line, RL_Keymap);
+	SLkm_define_key  ("\xE0M", (FVOID_STAR) rl_right, RL_Keymap);
+	SLkm_define_key  ("\xE0K", (FVOID_STAR) rl_left, RL_Keymap);
+	SLkm_define_key  ("\xE0S", (FVOID_STAR) rl_del, RL_Keymap);
+	SLkm_define_key  ("\xE0O", (FVOID_STAR) rl_eol, RL_Keymap);
+	SLkm_define_key  ("\xE0G", (FVOID_STAR) rl_bol, RL_Keymap);
+#endif
+	SLkm_define_key  ("^C", (FVOID_STAR) rl_abort, RL_Keymap);
+	SLkm_define_key  ("^E", (FVOID_STAR) rl_eol, RL_Keymap);
+	SLkm_define_key  ("^G", (FVOID_STAR) rl_abort, RL_Keymap);
+	SLkm_define_key  ("^I", (FVOID_STAR) rl_self_insert, RL_Keymap);
+	SLkm_define_key  ("^A", (FVOID_STAR) rl_bol, RL_Keymap);
+	SLkm_define_key  ("\r", (FVOID_STAR) rl_enter, RL_Keymap);
+	SLkm_define_key  ("\n", (FVOID_STAR) rl_enter, RL_Keymap);
+	SLkm_define_key  ("^K", (FVOID_STAR) rl_deleol, RL_Keymap);
+	SLkm_define_key  ("^L", (FVOID_STAR) rl_deleol, RL_Keymap);
+	SLkm_define_key  ("^V", (FVOID_STAR) rl_del, RL_Keymap);
+	SLkm_define_key  ("^D", (FVOID_STAR) rl_del, RL_Keymap);
+	SLkm_define_key  ("^F", (FVOID_STAR) rl_right, RL_Keymap);
+	SLkm_define_key  ("^B", (FVOID_STAR) rl_left, RL_Keymap);
+	SLkm_define_key  ("^?", (FVOID_STAR) rl_bdel, RL_Keymap);
+	SLkm_define_key  ("^H", (FVOID_STAR) rl_bdel, RL_Keymap);
+	SLkm_define_key  ("^P", (FVOID_STAR) rl_prev_line, RL_Keymap);
+	SLkm_define_key  ("^N", (FVOID_STAR) rl_next_line, RL_Keymap);
+	SLkm_define_key  ("^R", (FVOID_STAR) rl_redraw, RL_Keymap);
+	SLkm_define_key  ("`", (FVOID_STAR) rl_quote_insert, RL_Keymap);
+	SLkm_define_key  ("\033\\", (FVOID_STAR) rl_trim, RL_Keymap);
+	if (SLang_Error) return -1;
+     }
+
+   if (rli->prompt == NULL) rli->prompt = "";
+   if (rli->keymap == NULL) rli->keymap = RL_Keymap;
+   rli->old_upd = rli->upd_buf1;
+   rli->new_upd = rli->upd_buf2;
+   *rli->buf = 0;
+   rli->point = 0;
+
+   if (rli->flags & SL_RLINE_USE_ANSI)
+     {
+	if (rli->tt_goto_column == NULL) rli->tt_goto_column = ansi_goto_column;
+     }
+
+   if (Char_Widths[0] == 2) return 0;
+
+   for (ch = 0; ch < 32; ch++) Char_Widths[ch] = 2;
+   for (ch = 32; ch < 256; ch++) Char_Widths[ch] = 1;
+   Char_Widths[127] = 2;
+#ifndef IBMPC_SYSTEM
+   for (ch = 128; ch < 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->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->buf))))
+     {
+	SLfree ((char *)rl);
+	return NULL;
+     }
+   rl->buf = buf;
+   rl->buf_len = strlen ((char *)buf);
+   rl->num = rl->misc = 0;
+   rl->next = rl->prev = NULL;
+
+   if (rli->tail != NULL)
+     {
+	rli->tail->next = rl;
+	rl->prev = rli->tail;
+     }
+   rli->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 "slinclud.h"
+#include <ctype.h>
+#include <math.h>
+#include <errno.h>
+
+#include "slang.h"
+#include "_slang.h"
+
+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 < 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, &sign);
+
+   n = 0;
+   while (s < 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, &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, &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, &sign);
+   if (s >= 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 < smax) && (*s == '0'))
+     s++;
+   has_leading_zeros = (s != s0);
+
+   expon = 0;
+   while (s < smax)
+     {
+	unsigned char value = map [(unsigned char) *s];
+
+	if (value == 0xFF)
+	  break;
+	
+	if (b < bmax)
+	  *b++ = *s;
+	
+	expon++;
+	s++;
+     }
+   
+   if ((s < smax) && (*s == '.'))
+     {
+	s++;
+	if (b == buf + 2)	       /* nothing added yet */
+	  {
+	     while ((s < smax) && (*s == '0'))
+	       {
+		  expon--;
+		  s++;
+	       }
+	  }
+
+	while (s < smax)
+	  {
+	     unsigned char value = map [(unsigned char) *s];
+
+	     if (value == 0xFF)
+	       break;
+	     
+	     if (b < bmax)
+	       *b++ = *s;
+	     s++;
+	  }
+     }
+
+   if ((b == buf + 2)
+       && (has_leading_zeros == 0))
+     {
+	*sp = start_pos;
+	errno = EINVAL;
+	return 0;
+     }
+
+   if ((s + 1 < smax) && ((*s == 'E') || (*s == 'e')))
+     {
+	int e;
+	int esign;
+
+	s0 = s;
+	s = get_sign (s + 1, smax, &esign);
+	sign_pos = s;
+	e = 0;
+	while (s < smax)
+	  {
+	     unsigned char value = map [(unsigned char) *s];
+	     if (value == 0xFF)
+	       break;
+	     if (e < 25000)	       /* avoid overflow if 16 bit */
+	       e = 10 * e + value;
+	     s++;
+	  }
+#ifdef ERANGE
+	if (e >= 25000)
+	  errno = ERANGE;
+#endif
+	if (s == sign_pos)
+	  s = s0;		       /* ...E-X */
+	else
+	  {
+	     e = esign * e;
+	     expon += e;
+	  }
+     }
+   
+   if (expon != 0)
+     sprintf (b, "e%d", 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, &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 < 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, "Unexpected end of range in format");
+	     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 < smax) && 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 < 2)
+     {
+	SLang_verror (SL_INVALID_PARM, "Int_Type sscanf (str, format, ...)");
+	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 (&input_string))
+     return -1;
+
+   if (-1 == SLang_pop_slstring (&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, "sscanf: format not big enough for output list");
+	     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 (&f, f + strlen(f), &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') && (chf != '['))
+	  s = skip_whitespace (s);
+
+	if (has_width)
+	  {
+	     if (width > (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, "sscanf: Unexpected end of format");
+	     goto return_error;
+	   case 'D':
+	     is_long = 1;
+	   case 'd':
+	     if (is_short)
+	       {
+		  obj.data_type = SLANG_SHORT_TYPE;
+		  status = parse_short (&s, smax, &obj.v.short_val, base, map);
+	       }
+	     else if (is_long)
+	       {
+		  obj.data_type = SLANG_LONG_TYPE;
+		  status = parse_long (&s, smax, &obj.v.long_val, base, map);
+	       }
+	     else
+	       {
+		  obj.data_type = SLANG_INT_TYPE;
+		  status = parse_int (&s, smax, &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 (&s, smax, &obj.v.ushort_val, base, map);
+	       }
+	     else if (is_long)
+	       {
+		  obj.data_type = SLANG_ULONG_TYPE;
+		  status = parse_ulong (&s, smax, &obj.v.ulong_val, base, map);
+	       }
+	     else
+	       {
+		  obj.data_type = SLANG_INT_TYPE;
+		  status = parse_uint (&s, smax, &obj.v.uint_val, base, map);
+	       }
+	     break;
+
+	   case 'I':
+	     is_long = 1;
+	   case 'i':
+	     if ((s + 1 >= smax)
+		 || (*s != 0))
+	       chf = 'd';
+	     else if (((s[1] == 'x') || (s[1] == 'X'))
+		      && (s + 2 < 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 (&s, smax, &obj.v.double_val);
+	       }
+	     else
+	       {
+		  obj.data_type = SLANG_FLOAT_TYPE;
+		  status = parse_float (&s, smax, &obj.v.float_val);
+	       }
+#else
+	     SLang_verror (SL_NOT_IMPLEMENTED,
+			   "This version of the S-Lang does not support floating point");
+	     status = -1;
+#endif
+	     break;
+		  
+	   case 's':
+	     obj.data_type = SLANG_STRING_TYPE;
+	     status = parse_string (&s, smax, &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 (&s, smax, &obj.v.s_val);
+	     break;
+	     
+	   case '[':
+	     obj.data_type = SLANG_STRING_TYPE;
+	     status = parse_range (&s, smax, &f, &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, "format specifier '%c' is not supported", chf);
+	     break;
+	  }
+	
+	if (status == 0)
+	  break;
+
+	if (status == -1)
+	  goto return_error;
+
+	if (no_assign)
+	  {
+	     SLang_free_object (&obj);
+	     continue;
+	  }
+
+	if (-1 == SLang_pop_ref (&ref))
+	  {
+	     SLang_free_object (&obj);
+	     goto return_error;
+	  }
+	
+	if (-1 == SLang_push (&obj))
+	  {
+	     SLang_free_object (&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 (&s, s + strlen (s), &x))
+     {
+	if ((0 == strcmp ("NaN", s))
+	    || (0 == strcmp ("-Inf", s))
+	    || (0 == strcmp ("Inf", 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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+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->nrows;
+   hidden_mask = win->hidden_mask;
+   cline = win->current_line;
+
+   win->window_row = row = 0;
+   last_bot = bot = win->top_window_line;
+
+   while (row < nrows)
+     {
+	if (bot == cline)
+	  win->window_row = row;
+
+	last_bot = bot;
+
+	if (bot == NULL)
+	  break;
+
+	bot = bot->next;
+
+	if (hidden_mask)
+	  {
+	     while ((bot != NULL) && (bot->flags & hidden_mask))
+	       bot = bot->next;
+	  }
+
+	row++;
+     }
+
+   win->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->nrows;
+   cline = win->current_line;
+   hidden_mask = win->hidden_mask;
+
+   nrows = nrows / 2;
+
+   last_prev = prev = cline;
+
+   while (nrows && (prev != NULL))
+     {
+	nrows--;
+	last_prev = prev;
+	do
+	  {
+	     prev = prev->prev;
+	  }
+	while (hidden_mask
+	       && (prev != NULL)
+	       && (prev->flags & hidden_mask));
+     }
+
+   if (prev == NULL) prev = last_prev;
+
+   win->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->current_line;
+   nrows = win->nrows;
+   scroll_mode = win->cannot_scroll;
+   border = win->border;
+   if (scroll_mode == 2)
+     border = 0;
+
+   if ((cline == NULL) || (nrows <= 1))
+     {
+	win->top_window_line = cline;
+	find_window_bottom (win);
+	return 0;
+     }
+
+   hidden_mask = win->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->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 < nrows) && (prev != NULL))
+     {
+	if (prev == top_window_line)
+	  {
+	     SLscroll_Type *twl = top_window_line;
+	     int dir = 0;
+
+	     if (i < border) dir = -1; else if (i + border >= nrows) dir = 1;
+
+	     if (dir) while (border)
+	       {
+		  if (dir < 0) twl = twl->prev;
+		  else twl = twl->next;
+
+		  if (twl == NULL)
+		    {
+		       twl = top_window_line;
+		       break;
+		    }
+		  if ((hidden_mask == 0)
+		      || (0 == (twl->flags & hidden_mask)))
+		    border--;
+	       }
+
+	     win->top_window_line = twl;
+	     find_window_bottom (win);
+	     return 0;
+	  }
+
+	do
+	  {
+	     prev = prev->prev;
+	  }
+	while (hidden_mask
+	       && (prev != NULL)
+	       && (prev->flags & 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->next;
+   while (hidden_mask
+	  && (next != NULL)
+	  && (next->flags & hidden_mask))
+     next = next->next;
+
+   if ((next != NULL)
+       && (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->top_window_line = cline;
+	find_window_bottom (win);
+
+	if (scroll_mode) return SLscroll_pageup (win);
+
+	return 0;
+     }
+
+   prev = cline->prev;
+
+   while (hidden_mask
+	  && (prev != NULL)
+	  && (prev->flags & hidden_mask))
+     prev = prev->prev;
+
+   if ((prev == NULL)
+       || (prev != win->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->top_window_line = cline;
+	find_window_bottom (win);
+	return 0;
+     }
+
+   i = 2;
+   while ((i < nrows) && (prev != NULL))
+     {
+	do
+	  {
+	     prev = prev->prev;
+	  }
+	while (hidden_mask
+	       && (prev != NULL)
+	       && (prev->flags & hidden_mask));
+	i++;
+     }
+
+   if (prev != NULL)
+     {
+	win->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->hidden_mask;
+   cline = win->current_line;
+
+   n = 1;
+
+   l = win->lines;
+   while (l != cline)
+     {
+	if ((hidden_mask == 0)
+	    || (0 == (l->flags & hidden_mask)))
+	  n++;
+
+	l = l->next;
+     }
+
+   win->line_num = n;
+   n--;
+
+   while (l != NULL)
+     {
+	if ((hidden_mask == 0)
+	    || (0 == (l->flags & hidden_mask)))
+	  n++;
+	l = l->next;
+     }
+   win->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->current_line)))
+     return 0;
+
+   hidden_mask = win->hidden_mask;
+   l = cline;
+   i = 0;
+   while (i < n)
+     {
+	l = l->next;
+	while (hidden_mask
+	       && (l != NULL) && (l->flags & hidden_mask))
+	  l = l->next;
+
+	if (l == NULL)
+	  break;
+
+	i++;
+	cline = l;
+     }
+
+   win->current_line = cline;
+   win->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->current_line)))
+     return 0;
+
+   hidden_mask = win->hidden_mask;
+   l = cline;
+   i = 0;
+   while (i < n)
+     {
+	l = l->prev;
+	while (hidden_mask
+	       && (l != NULL) && (l->flags & hidden_mask))
+	  l = l->prev;
+
+	if (l == NULL)
+	  break;
+
+	i++;
+	cline = l;
+     }
+
+   win->current_line = cline;
+   win->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->nrows;
+
+   if ((NULL != (top = win->top_window_line))
+       && (nrows > 2))
+     {
+	n = 0;
+	hidden_mask = win->hidden_mask;
+	l = win->current_line;
+	while ((l != NULL) && (l != top))
+	  {
+	     l = l->prev;
+	     if ((hidden_mask == 0)
+		 || ((l != NULL) && (0 == (l->flags & hidden_mask))))
+	       n++;
+	  }
+
+	if (l != NULL)
+	  {
+	     unsigned int save_line_num;
+	     int ret = 0;
+
+	     win->current_line = l;
+	     win->line_num -= n;
+
+	     /* Compute a new top/bottom header */
+	     save_line_num = win->line_num;
+
+	     if ((0 == SLscroll_prev_n (win, nrows - 1))
+		 && (n == 0))
+	       ret = -1;
+
+	     win->top_window_line = win->current_line;
+	     win->current_line = l;
+	     win->line_num = save_line_num;
+
+	     find_window_bottom (win);
+	     return ret;
+	  }
+     }
+
+   if (nrows < 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->nrows;
+
+   if ((NULL != (bot = win->bot_window_line))
+       && (nrows > 2))
+     {
+	n = 0;
+	hidden_mask = win->hidden_mask;
+	l = win->current_line;
+	while ((l != NULL) && (l != bot))
+	  {
+	     l = l->next;
+	     if ((hidden_mask == 0)
+		 || ((l != NULL) && (0 == (l->flags & hidden_mask))))
+	       n++;
+	  }
+
+	if (l != NULL)
+	  {
+	     win->current_line = l;
+	     win->top_window_line = l;
+	     win->line_num += n;
+
+	     find_window_bottom (win);
+
+	     if (n || (bot != win->bot_window_line))
+	       return 0;
+
+	     return -1;
+	  }
+     }
+
+   if (nrows < 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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+#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 < 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 < end)
+	  {
+	     ch = *beg;
+	     db = ind[(unsigned char) ch];
+	     if ((db < key_len) && (ch == char1)) break;
+	     beg += db; /* ind[(unsigned char) ch]; */
+	  }
+	else while (beg < end)
+	  {
+	     ch = *beg;
+	     db = ind[(unsigned char) ch];
+	     if ((db < key_len) &&
+		 (UPPER_CASE(ch) == char1)) break;
+	     beg += db; /* ind[(unsigned char) ch]; */
+	  }
+
+	if (beg >= end) return(NULL);
+
+	pos = beg - (key_len - 1);
+	for (j = 0; j < 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 < key_len) return (NULL);
+   
+   if (key_len == 0)
+     return NULL;
+	
+   /*  end -= (key_len - 1); */
+   end -= key_len;
+
+    char1 = key[0];
+
+    while(1)
+      {
+	 while ((beg <= end) && (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 > end) return(NULL);
+#endif
+	      end -= ofs;
+	   }
+	 if (beg > end) return(NULL);
+	 for (j = 1; j < 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->dir > 0) return search_forward (pmin, pmax, st->key,
+					   st->key_len, st->cs, st->ind);
+   else return search_backward (pmin, pmax, st->key,
+				st->key_len, st->cs, st->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->key;
+   register int *indp, *indpm;
+   int *ind = st->ind;
+
+   if (max >= (int) sizeof (st->key))
+     {
+	SLang_doerror ("Search string too long.");
+	return -1;
+     }
+
+   st->dir = dir; st->cs = cs;
+
+   if (!Case_Tables_Ok) SLang_init_case_tables ();
+
+   if (dir > 0)
+     {
+	w = work;
+     }
+   else
+     {
+	maxi = max - 1;
+	str = str + maxi;
+	w = work + maxi;
+     }
+
+   /* for (i = 0; i < 256; i++) ind[i] = max; */
+   indp = ind; indpm = ind + 256;
+   while (indp < indpm)
+     {
+	*indp++ = max;
+	*indp++ = max;
+	*indp++ = max;
+	*indp++ = max;
+     }
+
+   i = 0;
+   if (cs) while (i < max)
+     {
+	i++;
+	maxi = max - i;
+	*w = *str;
+	ind[(unsigned char) *str] = maxi;
+	str += dir; w += dir;
+     }
+   else while (i < 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->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 < 256; i++)
+     {
+	_SLChg_UCase_Lut[i] = i;
+	_SLChg_LCase_Lut[i] = i;
+     }
+
+   for (i = 'A'; i <= '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 <= 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 "slinclud.h"
+
+#include <signal.h>
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+
+#include <errno.h>
+
+#include "slang.h"
+#include "_slang.h"
+
+/* 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 (&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, &new_sa, &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 (&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, &new_sa, &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 (&new_mask);
+# ifdef SIGQUIT
+   sigaddset (&new_mask, SIGQUIT);
+# endif
+# ifdef SIGTSTP
+   sigaddset (&new_mask, SIGTSTP);
+# endif
+# ifdef SIGINT
+   sigaddset (&new_mask, SIGINT);
+# endif
+# ifdef SIGTTIN
+   sigaddset (&new_mask, SIGTTIN);
+# endif
+# ifdef SIGTTOU
+   sigaddset (&new_mask, SIGTTOU);
+# endif
+# ifdef SIGWINCH
+   sigaddset (&new_mask, SIGWINCH);
+# endif
+
+   (void) sigprocmask (SIG_BLOCK, &new_mask, &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, &Old_Signal_Mask, NULL);
+   return 0;
+#else
+   return -1;
+#endif
+}
+
+#ifdef MSWINDOWS
+int SLsystem (char *cmd)
+{
+   SLang_verror (SL_NOT_IMPLEMENTED, "system not implemented");
+   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 (&ignore.sa_mask);
+   ignore.sa_flags = 0;
+
+# ifdef SIGINT
+   if (-1 == sigaction (SIGINT, &ignore, &save_intr))
+     return -1;
+# endif
+
+# ifdef SIGQUIT
+   if (-1 == sigaction (SIGQUIT, &ignore, &save_quit))
+     {
+	(void) sigaction (SIGINT, &save_intr, NULL);
+	return -1;
+     }
+# endif
+
+# ifdef SIGCHLD
+   sigemptyset (&child_mask);
+   sigaddset (&child_mask, SIGCHLD);
+   if (-1 == sigprocmask (SIG_BLOCK, &child_mask, &save_mask))
+     {
+#  ifdef SIGINT
+	(void) sigaction (SIGINT, &save_intr, NULL);
+#  endif
+#  ifdef SIGQUIT
+	(void) sigaction (SIGQUIT, &save_quit, NULL);
+#  endif
+	return -1;
+     }
+# endif
+
+   pid = fork();
+
+   if (pid == -1)
+     status = -1;
+   else if (pid == 0)
+     {
+	/* Child */
+# ifdef SIGINT
+	(void) sigaction (SIGINT, &save_intr, NULL);
+# endif
+# ifdef SIGQUIT
+	(void) sigaction (SIGQUIT, &save_quit, NULL);
+# endif
+# ifdef SIGCHLD
+	(void) sigprocmask (SIG_SETMASK, &save_mask, NULL);
+# endif
+
+	execl ("/bin/sh", "sh", "-c", cmd, NULL);
+	_exit (127);
+     }
+   else
+     {
+	/* parent */
+	while (-1 == waitpid (pid, &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, &save_intr, NULL))
+     status = -1;
+# endif
+# ifdef SIGQUIT
+   if (-1 == sigaction (SIGQUIT, &save_quit, NULL))
+     status = -1;
+# endif
+# ifdef SIGCHLD
+   if (-1 == sigprocmask (SIG_SETMASK, &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 <windows.h>
+static int msw_system (char *cmd)
+{
+   STARTUPINFO startup_info;
+   PROCESS_INFORMATION process_info;
+   int status;
+
+   if (cmd == NULL) return -1;
+
+   memset ((char *) &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,
+			       &startup_info,
+			       &process_info))
+     {
+	SLang_verror (0, "%s: CreateProcess failed.", cmd);
+	return -1;
+     }
+
+   status = -1;
+
+   if (0xFFFFFFFFUL != WaitForSingleObject (process_info.hProcess, INFINITE))
+     {
+	DWORD exit_code;
+
+	if (TRUE == GetExitCodeProcess (process_info.hProcess, &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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+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 && !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 = &SLtt_Screen_Rows;
+static int *tt_Screen_Cols = &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 = &SLtt_Term_Cannot_Scroll;
+static int *tt_Has_Alt_Charset = &SLtt_Has_Alt_Charset;
+static char **tt_Graphics_Char_Pairs = &SLtt_Graphics_Char_Pairs;
+static int *tt_Use_Blink_For_ACS = &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 < pmax)
+     {
+	*p++ = color_ch;
+     }
+}
+
+static void clear_region (int row, int n)
+{
+   int i;
+   int imax = row + n;
+
+   if (imax > Screen_Rows) imax = Screen_Rows;
+   for (i = row; i < imax; i++)
+     {
+	if (i >= 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 < 0) || (r >= Screen_Rows)) return;
+   if (c < 0) c = 0; else if (c >= 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 < 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)
+       && (*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 &= 0x7F;
+   This_Color |= This_Alt_Char;
+#endif
+}
+
+void SLsmg_set_color (int color)
+{
+   if (color < 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 >= Start_Row) && (This_Row < Start_Row + Screen_Rows)
+	   && ((col_too == 0)
+	       || ((This_Col >= Start_Col)
+		   && (This_Col < 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 < 0)
+     return;
+
+   if (str == NULL) width = 0;
+   else
+     {
+	width = strlen (str);
+	if (width > n) width = n;
+	SLsmg_write_nchars (str, width);
+     }
+   while (width++ < n) SLsmg_write_nchars (&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 && (diff > 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 & ALT_CHAR_FLAG)
+			&& ((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 > start_len) p += (len - start_len);
+
+   flags = SL_Screen[This_Row - Start_Row].flags;
+   while ((len < max_len) && (str < str_max))
+     {
+	ch = (unsigned char) *str++;
+
+#ifndef IBMPC_SYSTEM
+	if (alt_char_set_flag)
+	  ch = Alt_Char_Set [ch & 0x7F];
+#endif
+	if (((ch >= ' ') && (ch < 127))
+	    || (ch >= (unsigned char) SLsmg_Display_Eight_Bit)
+#ifndef IBMPC_SYSTEM
+	    || alt_char_set_flag
+#endif
+	    )
+	  {
+	     len += 1;
+	     if (len > start_len)
+	       {
+		  old = *p;
+		  neew = SLSMG_BUILD_CHAR(ch,color);
+		  if (old != neew)
+		    {
+		       flags |= TOUCHED;
+		       *p = neew;
+		    }
+		  p++;
+	       }
+	  }
+
+	else if ((ch == '\t') && (SLsmg_Tab_Width > 0))
+	  {
+	     n = len;
+	     n += SLsmg_Tab_Width;
+	     n = SLsmg_Tab_Width - (n % SLsmg_Tab_Width);
+	     if ((unsigned int) len + n > (unsigned int) max_len)
+	       n = (unsigned int) (max_len - len);
+	     neew = SLSMG_BUILD_CHAR(' ',color);
+	     while (n--)
+	       {
+		  len += 1;
+		  if (len > start_len)
+		    {
+		       if (*p != neew)
+			 {
+			    flags |= TOUCHED;
+			    *p = neew;
+			 }
+		       p++;
+		    }
+	       }
+	  }
+	else if ((ch == '\n')
+		 && (SLsmg_Newline_Behavior != SLSMG_NEWLINE_PRINTABLE))
+	  {
+	     newline_flag = 1;
+	     break;
+	  }
+	else if ((ch == 0x8) && SLsmg_Backspace_Moves)
+	  {
+	     if (len != 0) len--;
+	  }
+	else
+	  {
+	     if (ch & 0x80)
+	       {
+		  neew = SLSMG_BUILD_CHAR('~',color);
+		  len += 1;
+		  if (len > start_len)
+		    {
+		       if (*p != neew)
+			 {
+			    *p = neew;
+			    flags |= TOUCHED;
+			 }
+		       p++;
+		       if (len == max_len) break;
+		       ch &= 0x7F;
+		    }
+	       }
+
+	     len += 1;
+	     if (len > 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 > 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 < 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 (&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 < 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 < smax)
+     {
+	ch = *s++;
+	if (is_blank && (SLSMG_EXTRACT_CHAR(ch) != 32)) is_blank--;
+
+	sum += ch;
+
+	h = sum + (h << 3);
+	if ((g = h & 0xE0000000UL) != 0)
+	  {
+	     h = h ^ (g >> 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 > rmin; i--)
+     {
+	hash = SL_Screen[i].new_hash;
+	if (hash == Blank_Hash) continue;
+
+	if ((hash == SL_Screen[i].old_hash)
+#if 0
+	    || ((i + 1 < Screen_Rows) && (hash == SL_Screen[i + 1].old_hash))
+	    || ((i - 1 > rmin) && (SL_Screen[i].old_hash == SL_Screen[i - 1].new_hash))
+#endif
+	    )
+	  continue;
+
+	for (j = i - 1; j >= rmin; j--)
+	  {
+	     if (hash == SL_Screen[j].old_hash) break;
+	  }
+	if (j < rmin) continue;
+
+	r2 = i;			       /* end scroll region */
+
+	di = i - j;
+	j--;
+	ignore = 0;
+	while ((j >= rmin) && (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 > 1) && (r1 + di + ignore == r2)) continue;
+
+	/* If there is anything in the scrolling region that is ok, abort the
+	 * scroll.
+	 */
+
+	for (j = r1; j <= r2; j++)
+	  {
+	     if ((SL_Screen[j].old_hash != Blank_Hash)
+		 && (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 > r2) || (SL_Screen[j].old_hash != SL_Screen[j + di].new_hash))
+		    break;
+	       }
+	  }
+	if (j <= 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 <= r2; j++) SL_Screen[j].flags = TOUCHED;
+
+	while (di--)
+	  {
+	     tmp = SL_Screen[r2].old;
+	     for (j = r2; j > 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 < 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 <= rmax; j++)
+	  {
+	     if (hash == SL_Screen[j].old_hash) break;
+	  }
+	if (j > 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 <= rmax) && (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 > 1) && (r1 + di + ignore == r2)) continue;
+
+	/* If there is anything in the scrolling region that is ok, abort the
+	 * scroll.
+	 */
+
+	for (j = r1; j <= r2; j++)
+	  {
+	     if ((SL_Screen[j].old_hash != Blank_Hash)
+		 && (SL_Screen[j].old_hash == SL_Screen[j].new_hash))
+	       {
+		  if ((j - di < r1) || (SL_Screen[j].old_hash != SL_Screen[j - di].new_hash))
+		    break;
+	       }
+
+	  }
+	if (j <= 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 <= r2; j++) SL_Screen[j].flags = TOUCHED;
+
+	while (di--)
+	  {
+	     tmp = SL_Screen[r1].old;
+	     for (j = r1; j < 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 > 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 < 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 < rmax; r1++)
+     {
+	if (SL_Screen[r1].new_hash == SL_Screen[r1 + 1].old_hash)
+	  num_up++;
+     }
+
+   num_down = 0;
+   for (r1 = rmax; r1 > rmin; r1--)
+     {
+	if (SL_Screen[r1 - 1].old_hash == SL_Screen[r1].new_hash)
+	  num_down++;
+     }
+
+   if (num_up > 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)
+       && (*tt_Use_Blink_For_ACS != 0))
+     return;			       /* this mode does not support non-BCE
+					* terminals.
+					*/
+
+   for (i = 0; i < Screen_Rows; i++)
+     {
+	SLsmg_Char_Type *s, *smax;
+
+	SL_Screen[i].flags |= TRASHED;
+	s = SL_Screen[i].neew;
+	smax = s + Screen_Cols;
+	
+	while (s < smax)
+	  {
+	     int color = (int) SLSMG_EXTRACT_COLOR(*s);
+	     int acs;
+
+	     if (color < 0)
+	       {
+		  s++;
+		  continue;
+	       }
+	     
+	     acs = color & 0x80;
+	     color = (color & 0x7F) - bce;
+	     color += Bce_Color_Offset;
+	     if (color >= 0)
+	       {
+		  unsigned char ch = SLSMG_EXTRACT_CHAR(*s);
+		  *s = SLSMG_BUILD_CHAR(ch, ((color&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 < Screen_Rows; i++)
+	  SL_Screen[i].flags |= TRASHED;
+#ifdef REQUIRES_NON_BCE_SUPPORT
+	adjust_colors ();
+#endif
+     }
+
+#ifndef IBMPC_SYSTEM
+   for (i = 0; i < 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 && (*tt_Term_Cannot_Scroll == 0)) try_scroll ();
+#endif
+
+   for (i = 0; i < Screen_Rows; i++)
+     {
+	if (SL_Screen[i].flags == 0) continue;
+
+	if (Cls_Flag || SL_Screen[i].flags & 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 < 0) return 0;
+   if (row >= box_end) return 0;
+   row_max = row + n;
+   if (row_max <= box_start) return 0;
+
+   if (row < box_start) row = box_start;
+   if (row_max >= 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, &r1, &r2))
+     return;
+
+   r1 -= Start_Row;
+   r2 -= Start_Row;
+   for (i = r1; i < r2; i++)
+     {
+	SL_Screen[i].flags |= TRASHED;
+     }
+}
+
+void SLsmg_touch_screen (void)
+{
+   Screen_Trashed = 1;
+}
+
+			  
+#ifndef IBMPC_SYSTEM
+static char Fake_Alt_Char_Pairs [] = "a:j+k+l+m+q-t+u+v+w+x|n+`+f\\g#~o,<+>.v-^h#0#";
+
+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 <= 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 < pmax)
+     {
+	ch = *p++;
+	ch &= 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 < 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 > 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 < 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 && (*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 < Start_Row) || (This_Row >= Start_Row + Screen_Rows)
+       || (0 == compute_clip (This_Col, n, Start_Col, Start_Col + Screen_Cols,
+			      &cmin, &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-- > 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 < Start_Col) || (c >= Start_Col + Screen_Cols)) ||
+       (0 == compute_clip (This_Row, n, Start_Row, Start_Row + Screen_Rows,
+			  &rmin, &rmax)))
+     {
+	This_Row = final_row;
+	return;
+     }
+
+   save_color = This_Color;
+   This_Color |= ALT_CHAR_FLAG;
+
+   for (This_Row = rmin; This_Row < rmax; This_Row++)
+     {
+	This_Col = c;
+	SLsmg_write_nchars ((char *) &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 < 0)
+     return;
+
+   if (dc > (unsigned int) dcmax) dc = (unsigned int) dcmax;
+
+   rmax = This_Row + dr;
+   if (rmax > 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 < rmax; This_Row++)
+     {
+	This_Col = c;
+	count = dc / 16;
+	SLsmg_write_nchars ((char *) hbuf, dc % 16);
+	while (count-- > 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 < smax)
+     {
+	sh = *s++;
+
+	color = SLSMG_EXTRACT_COLOR(sh);
+
+#if REQUIRES_NON_BCE_SUPPORT
+	if (Bce_Color_Offset)
+	  {
+	     if (color & 0x80)
+	       color = ((color & 0x7F) + Bce_Color_Offset) | 0x80;
+	     else
+	       color = ((color & 0x7F) + Bce_Color_Offset) & 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 > (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 > (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 > Screen_Cols) cmax = Screen_Cols;
+   if (rmax > Screen_Rows) rmax = Screen_Rows;
+
+   if (c < 0) c = 0;
+   if (r < 0) r = 0;
+
+#if REQUIRES_NON_BCE_SUPPORT
+   if (Bce_Color_Offset)
+     {
+	if (color & 0x80)
+	  color = ((color & 0x7F) + Bce_Color_Offset) | 0x80;
+	else
+	  color = ((color & 0x7F) + Bce_Color_Offset) & 0x7F;
+     }
+#endif
+   color = color << 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 < rmax)
+     {
+	SLsmg_Char_Type *s, *smax;
+
+	SL_Screen[r].flags |= TOUCHED;
+	s = SL_Screen[r].neew;
+	smax = s + cmax;
+	s += c;
+
+	while (s < smax)
+	  {
+	     *s = (*s & char_mask) | color;
+	     s++;
+	  }
+	r++;
+     }
+}
+
+void SLsmg_set_terminal_info (SLsmg_Term_Type *tt)
+{
+   if (tt == NULL)		       /* use default */
+     return;
+
+   if ((tt->tt_normal_video == NULL)
+       || (tt->tt_goto_rc == NULL)
+       || (tt->tt_cls == NULL)
+       || (tt->tt_del_eol == NULL)
+       || (tt->tt_smart_puts == NULL)
+       || (tt->tt_flush_output == NULL)
+       || (tt->tt_reset_video == NULL)
+       || (tt->tt_init_video == NULL)
+#ifndef IBMPC_SYSTEM
+       || (tt->tt_set_scroll_region == NULL)
+       || (tt->tt_reverse_index == NULL)
+       || (tt->tt_reset_scroll_region == NULL)
+       || (tt->tt_delete_nlines == NULL)
+       /* Variables */
+       || (tt->tt_term_cannot_scroll == NULL)
+       || (tt->tt_has_alt_charset == NULL)
+#if 0 /* These can be NULL */
+       || (tt->tt_use_blink_for_acs == NULL)
+       || (tt->tt_graphic_char_pairs == NULL)
+#endif
+       || (tt->tt_screen_cols == NULL)
+       || (tt->tt_screen_rows == NULL)
+#endif
+       )
+     SLang_exit_error ("Terminal not powerful enough for SLsmg");
+
+   tt_normal_video = tt->tt_normal_video;
+   tt_goto_rc = tt->tt_goto_rc;
+   tt_cls = tt->tt_cls;
+   tt_del_eol = tt->tt_del_eol;
+   tt_smart_puts = tt->tt_smart_puts;
+   tt_flush_output = tt->tt_flush_output;
+   tt_reset_video = tt->tt_reset_video;
+   tt_init_video = tt->tt_init_video;
+
+#ifndef IBMPC_SYSTEM
+   tt_set_scroll_region = tt->tt_set_scroll_region;
+   tt_reverse_index = tt->tt_reverse_index;
+   tt_reset_scroll_region = tt->tt_reset_scroll_region;
+   tt_delete_nlines = tt->tt_delete_nlines;
+
+   tt_Term_Cannot_Scroll = tt->tt_term_cannot_scroll;
+   tt_Has_Alt_Charset = tt->tt_has_alt_charset;
+   tt_Use_Blink_For_ACS = tt->tt_use_blink_for_acs;
+   tt_Graphics_Char_Pairs = tt->tt_graphic_char_pairs;
+#endif
+
+   tt_Screen_Cols = tt->tt_screen_cols;
+   tt_Screen_Rows = tt->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 "slinclud.h"
+/*{{{ Include Files */
+
+#include <time.h>
+
+#ifndef __QNX__
+# if defined(__GO32__) || defined(__WATCOMC__)
+#  include <dos.h>
+#  include <bios.h>
+# endif
+#endif
+
+#if SLANG_HAS_FLOAT
+# include <math.h>
+#endif
+
+#include "slang.h"
+#include "_slang.h"
+
+/*}}}*/
+
+/* 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(&x)) return -1;
+	SLang_free_object (&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 (&obj))
+     return -1;
+
+   cl = _SLclass_get_class (obj.data_type);
+   p = _SLclass_get_ptr_to_value (cl, &obj);
+
+   len = 1;
+   if (cl->cl_length != NULL)
+     {
+	if (0 == (*cl->cl_length)(obj.data_type, p, &length))
+	  len = (int) length;
+	else
+	  len = -1;
+     }
+
+   SLang_free_object (&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->data_type;
+   p = (VOID_STAR) &obj->v.ptr_val;
+
+   cl = _SLclass_get_class (stype);
+
+   s = (*cl->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 < 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(&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, "(%u)", 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 (&obj))
+     return;
+
+   type = obj.data_type;
+   if (type == SLANG_ARRAY_TYPE)
+     type = obj.v.array_val->data_type;
+
+   SLang_free_object (&obj);
+
+   _SLang_push_datatype (type);
+}
+
+static void intrin_type_info (void)
+{
+   SLang_Object_Type obj;
+
+   if (-1 == SLang_pop (&obj))
+     return;
+
+   _SLang_push_datatype (obj.data_type);
+   SLang_free_object (&obj);
+}
+
+void _SLstring_intrinsic (void) /*{{{*/
+{
+   SLang_Object_Type x;
+   char *s;
+
+   if (SLang_pop (&x)) return;
+   if (NULL != (s = _SLstringize_object (&x)))
+     _SLang_push_slstring (s);
+
+   SLang_free_object (&x);
+}
+
+/*}}}*/
+
+static void intrin_typecast (void)
+{
+   unsigned char to_type;
+   if (0 == _SLang_pop_datatype (&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 "";
+   return _SLang_Current_Function_Name;
+}
+
+static void intrin_message (char *s)
+{
+   SLang_vmessage ("%s", s);
+}
+
+static void intrin_error (char *s)
+{
+   SLang_verror (SL_USER_ERROR, "%s", 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 (&msg))
+     return;
+
+   SLang_verror (SL_USAGE_ERROR, "Usage: %s", 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, "Unable to convert string to integer");
+   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, "r")))
+     {
+	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)
+	    && (0 == strncmp (line, topic, topic_len))
+	    && ((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->data;
+   num = at->num_elements;
+   for (i = 0; i < 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 (&flags))
+     return;
+   if (-1 == SLang_pop_slstring (&pat))
+     return;
+   
+   namespace_name = NULL;
+   at = NULL;
+   if (num_args == 3)
+     {
+	if (-1 == SLang_pop_slstring (&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 <sys/utsname.h>
+#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 (&u))
+     (void) SLang_push_null ();
+
+   field_names[0] = "sysname"; ptrs[0] = u.sysname;
+   field_names[1] = "nodename"; ptrs[1] = u.nodename;
+   field_names[2] = "release"; ptrs[2] = u.release;
+   field_names[3] = "version"; ptrs[3] = u.version;
+   field_names[4] = "machine"; ptrs[4] = u.machine;
+
+   for (i = 0; i < 5; i++)
+     {
+	field_types[i] = SLANG_STRING_TYPE;
+	field_values[i] = (VOID_STAR) &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("__is_initialized", _SLang_is_ref_initialized, SLANG_INT_TYPE, SLANG_REF_TYPE),
+   MAKE_INTRINSIC_S("__get_reference", intrin_get_reference, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_1("__uninitialize", uninitialize_ref_intrin, SLANG_VOID_TYPE, SLANG_REF_TYPE),
+   MAKE_INTRINSIC_SS("get_doc_string_from_file",  get_doc_string, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_SS("autoload",  SLang_autoload, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_S("is_defined",  SLang_is_defined, SLANG_INT_TYPE),
+   MAKE_INTRINSIC_0("string",  _SLstring_intrinsic, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_0("uname", uname_cmd, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_S("getenv",  intrin_getenv_cmd, SLANG_VOID_TYPE),
+#ifdef HAVE_PUTENV
+   MAKE_INTRINSIC_0("putenv",  intrin_putenv, SLANG_VOID_TYPE),
+#endif
+   MAKE_INTRINSIC_S("evalfile",  load_file, SLANG_INT_TYPE),
+   MAKE_INTRINSIC_I("char",  char_cmd, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_S("eval",  SLang_load_string, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_0("dup",  do_dup, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_S("integer",  intrin_integer, SLANG_INT_TYPE),
+   MAKE_INTRINSIC_S("system",  SLsystem, SLANG_INT_TYPE),
+   MAKE_INTRINSIC_0("_apropos",  intrin_apropos, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_S("_trace_function",  _SLang_trace_fun, SLANG_VOID_TYPE),
+#if SLANG_HAS_FLOAT
+   MAKE_INTRINSIC_S("atof", _SLang_atof, SLANG_DOUBLE_TYPE),
+   MAKE_INTRINSIC_0("double", intrin_double, SLANG_VOID_TYPE),
+#endif
+   MAKE_INTRINSIC_0("int",  intrin_int, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_0("typecast", intrin_typecast, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_0("_stkdepth", _SLstack_depth, SLANG_INT_TYPE),
+   MAKE_INTRINSIC_I("_stk_reverse", intrin_reverse_stack, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_0("typeof", intrin_type_info, VOID_TYPE),
+   MAKE_INTRINSIC_0("_typeof", intrin_type_info1, VOID_TYPE),
+   MAKE_INTRINSIC_I("_pop_n", intrin_pop_n, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_0("_print_stack", lang_print_stack, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_I("_stk_roll", intrin_roll_stack, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_SI("byte_compile_file", byte_compile_file, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_0("_clear_error", _SLang_clear_error, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_0("_function_name", intrin_function_name, SLANG_STRING_TYPE),
+#if SLANG_HAS_FLOAT
+   MAKE_INTRINSIC_S("set_float_format", _SLset_double_format, SLANG_VOID_TYPE),
+#endif
+   MAKE_INTRINSIC_S("_slang_guess_type", guess_type, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_S("error", intrin_error, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_S("message", intrin_message, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_0("__get_defined_symbols", intrin_get_defines, SLANG_INT_TYPE),
+   MAKE_INTRINSIC_I("__pop_args", _SLstruct_pop_args, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_1("__push_args", _SLstruct_push_args, SLANG_VOID_TYPE, SLANG_ARRAY_TYPE),
+   MAKE_INTRINSIC_0("usage", usage, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_S("implements", _SLang_implements_intrinsic, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_S("use_namespace", _SLang_use_namespace_intrinsic, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_0("current_namespace", _SLang_cur_namespace_intrinsic, SLANG_STRING_TYPE),
+   MAKE_INTRINSIC_0("length", 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 = "";
+#endif
+
+static SLang_Intrin_Var_Type Intrin_Vars[] =
+{
+   MAKE_VARIABLE("_debug_info", &_SLang_Compile_Line_Num_Info, SLANG_INT_TYPE, 0),
+   MAKE_VARIABLE("_auto_declare", &_SLang_Auto_Declare_Globals, SLANG_INT_TYPE, 0),
+   MAKE_VARIABLE("_traceback", &SLang_Traceback, SLANG_INT_TYPE, 0),
+   MAKE_VARIABLE("_slangtrace", &_SLang_Trace, SLANG_INT_TYPE, 0),
+   MAKE_VARIABLE("_slang_version", &SLang_Version, SLANG_INT_TYPE, 1),
+   MAKE_VARIABLE("_slang_version_string", &SLang_Version_String, SLANG_STRING_TYPE, 1),
+   MAKE_VARIABLE("_NARGS", &SLang_Num_Function_Args, SLANG_INT_TYPE, 1),
+   MAKE_VARIABLE("_slang_doc_dir", &SLang_Doc_Dir, SLANG_STRING_TYPE, 1),
+   MAKE_VARIABLE("NULL", 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__)
+	"OS2",
+#endif
+#if defined(__MSDOS__)
+	"MSDOS",
+#endif
+#if defined(__WIN16__)
+	"WIN16",
+#endif
+#if defined (__WIN32__)
+	"WIN32",
+#endif
+#if defined(__NT__)
+	"NT",
+#endif
+#if defined (VMS)
+	"VMS",
+#endif
+#ifdef REAL_UNIX_SYSTEM
+	"UNIX",
+#endif
+#if SLANG_HAS_FLOAT
+	"SLANG_DOUBLE_TYPE",
+#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 --> $9 */
+   name[2] = 0; name[0] = '$';
+   for (i = 0; i < 10; i++)
+     {
+	name[1] = (char) (i + '0');
+	SLadd_global_variable (name);
+     }
+
+   SLang_init_case_tables ();
+
+   /* Now add a couple of macros */
+   SLang_load_string (".(_NARGS 1 - Sprintf error)verror");
+   SLang_load_string (".(_NARGS 1 - Sprintf message)vmessage");
+
+   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 < 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 < argc; i++)
+     {
+	if (NULL == (this_argv[i] = SLang_create_slstring (argv[i])))
+	  goto return_error;
+     }
+
+   if (-1 == SLadd_intrinsic_variable ("__argc", (VOID_STAR)&this_argc,
+				       SLANG_INT_TYPE, 1))
+     goto return_error;
+
+   if (-1 == SLang_add_intrinsic_array ("__argv", SLANG_STRING_TYPE, 1,
+					(VOID_STAR) this_argv, 1, argc))
+     goto return_error;
+
+   return 0;
+
+   return_error:
+   for (i = 0; i < 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 "slinclud.h"
+
+#if defined(__unix__) || (defined (__os2__) && defined (__EMX__))
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_FCNTL_H
+# include <sys/fcntl.h>
+#endif
+
+#ifdef __unix__
+# include <sys/file.h>
+#endif
+
+#if defined(__BORLANDC__)
+# include <io.h>
+# include <dir.h>
+#endif
+
+#if defined(__DECC) && defined(VMS)
+# include <unixio.h>
+# include <unixlib.h>
+#endif
+
+#ifdef VMS
+# include <stat.h>
+#else
+# include <sys/stat.h>
+#endif
+
+#include <errno.h>
+
+#define SL_APP_WANTS_FOREACH
+#include "slang.h"
+#include "_slang.h"
+
+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 < tmax)
+     {
+	if (t->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, "File flag %c is not supported", 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->fp = fp;
+   t->flags = flags | xflags;
+   fp = NULL;			       /* allow free_mmt to close fp */
+
+   if ((NULL != (t->file = SLang_create_slstring (file)))
+       && (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->flags & flags)
+       && (NULL != (*fp_ptr = t->fp)))
+     return mmt;
+
+   SLang_free_mmt (mmt);
+   return NULL;
+}
+
+static FILE *check_fp (SL_File_Table_Type *t, unsigned flags)
+{
+   if ((t != NULL) && (t->flags & flags))
+     return t->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->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->fp;
+
+   if (NULL == fp) ret = -1;
+   else
+     {
+	if (0 == (t->flags & 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->file != NULL) SLang_free_slstring (t->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->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 < sizeof (buf))
+		     || (buf[dlen - 1] == '\n'));
+
+	if (done_flag && (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, &s, &len);
+   if (status <= 0)
+     return -1;
+
+   status = SLang_assign_to_ref (ref, SLANG_STRING_TYPE, (VOID_STAR)&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 > 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 < n)
+     {
+	int status;
+	char *line;
+	unsigned int len;
+
+	status = read_one_line (fp, &line, &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 > 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, &inum_lines, 1)))
+     goto return_error;
+
+   if (-1 == SLang_push_array (at, 1))
+     SLang_push_null ();
+   return;
+
+   return_error:
+   while (num_lines > 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 (&n))
+	  return;
+     }
+   
+   if (NULL == (mmt = pop_fp (SL_READ, &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 (&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->cl_fread == NULL)
+     {
+	SLang_verror (SL_NOT_IMPLEMENTED,
+		      "fread does not support %s objects",
+		      cl->cl_name);
+	goto the_return;
+     }
+
+   sizeof_type = cl->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->cl_fread (data_type, fp, (VOID_STAR)s, num_to_read, &num_read);
+
+   if ((num_read == 0)
+       && (num_read != num_to_read))
+     ret = -1;
+
+   if ((ret == -1) && ferror (fp))
+     _SLerrno_errno = errno;
+
+   if ((ret == 0)
+       && (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)&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, &inum_read, 1);
+	     ret = SLang_assign_to_ref (ref, SLANG_ARRAY_TYPE, (VOID_STAR)&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 (&b))
+	  goto the_return;
+
+	if (NULL == (s = SLbstring_get_pointer (b, &num_to_write)))
+	  goto the_return;
+
+	cl = _SLclass_get_class (SLANG_UCHAR_TYPE);
+	break;
+
+      default:
+	if (-1 == SLang_pop_array (&at, 1))
+	  goto the_return;
+
+	cl = at->cl;
+	num_to_write = at->num_elements;
+	s = (unsigned char *) at->data;
+     }
+
+   if (NULL == (fp = check_fp (t, SL_WRITE)))
+     goto the_return;
+
+   if (cl->cl_fwrite == NULL)
+     {
+	SLang_verror (SL_NOT_IMPLEMENTED,
+		      "fwrite does not support %s objects", cl->cl_name);
+	goto the_return;
+     }
+
+   ret = cl->cl_fwrite (cl->cl_data_type, fp, s, num_to_write, &num_write);
+
+   if ((ret == -1) && 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, "FORMAT", 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 (&s))
+     return -1;
+   
+   if (NULL == (mmt = pop_fp (SL_WRITE, &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 (&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("fgetslines", stdio_fgetslines, V),
+   MAKE_INTRINSIC_SS("fopen", stdio_fopen, V),
+   MAKE_INTRINSIC_1("feof", stdio_feof, I, F),
+   MAKE_INTRINSIC_1("ferror", stdio_ferror, I, F),
+   MAKE_INTRINSIC_1("fclose", stdio_fclose, I, F),
+   MAKE_INTRINSIC_2("fgets", stdio_fgets, I, R, F),
+   MAKE_INTRINSIC_1("fflush", stdio_fflush, I, F),
+   MAKE_INTRINSIC_2("fputs", stdio_fputs, I, S, F),
+   MAKE_INTRINSIC_0("fprintf", stdio_fprintf, I),
+   MAKE_INTRINSIC_0("printf", stdio_printf, I),
+   MAKE_INTRINSIC_3("fseek", stdio_fseek, I, F, I, I),
+   MAKE_INTRINSIC_1("ftell", stdio_ftell, I, F),
+   MAKE_INTRINSIC_1("clearerr", stdio_clearerr, V, F),
+   MAKE_INTRINSIC_4("fread", stdio_fread, V, R, D, U, F),
+   MAKE_INTRINSIC_1("fwrite", stdio_fwrite, V, F),
+#ifdef HAVE_POPEN
+   MAKE_INTRINSIC_SS("popen", stdio_popen, V),
+   MAKE_INTRINSIC_1("pclose", 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("SEEK_SET", SEEK_SET),
+   MAKE_ICONSTANT("SEEK_END", SEEK_END),
+   MAKE_ICONSTANT("SEEK_CUR", 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, &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 (&s))
+	  {
+	     SLang_free_mmt (mmt);
+	     return NULL;
+	  }
+	if (0 == strcmp (s, "char"))
+	  type = CTX_USE_CHAR;
+	else if (0 == strcmp (s, "line"))
+	  type = CTX_USE_LINE;
+	else
+	  {
+	     SLang_verror (SL_NOT_IMPLEMENTED,
+			   "using '%s' not supported by File_Type",
+			   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, 
+		      "Usage: foreach (File_Type) using ([line|char])");
+	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->type = type;
+   c->mmt = mmt;
+   c->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->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->type)
+     {
+      case CTX_USE_CHAR:
+	if (EOF == (ch = getc (c->fp)))
+	  return 0;
+	if (-1 == SLang_push_uchar ((unsigned char) ch))
+	  return -1;
+	return 1;
+
+      case CTX_USE_LINE:
+	status = read_one_line (c->fp, &s, &len);
+	if (status <= 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 ("File_Type")))
+     return -1;
+   cl->cl_destroy = destroy_file_type;
+   cl->cl_foreach_open = cl_foreach_open;
+   cl->cl_foreach_close = cl_foreach_close;
+   cl->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, "__STDIO__"))
+       || (-1 == SLadd_iconstant_table (Stdio_Consts, NULL))
+       || (-1 == _SLerrno_init ()))
+     return -1;
+
+   names[0] = "stdin";
+   names[1] = "stdout";
+   names[2] = "stderr";
+
+   s = SL_File_Table;
+   s->fp = stdin;  s->flags = SL_READ;
+
+   s++;
+   s->fp = stdout;  s->flags = SL_WRITE;
+
+   s++;
+   s->fp = stderr;  s->flags = SL_WRITE|SL_READ;
+
+   s = SL_File_Table;
+   for (i = 0; i < 3; i++)
+     {
+	if (NULL == (s->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->file, (VOID_STAR)&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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+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->bytes);
+   cs->sls = sls;
+   cs->hash = hash;
+   cs->len = len;
+}
+
+_INLINE_
+static void uncache_string (char *s)
+{
+   Cached_String_Type *cs;
+   
+   cs = GET_CACHED_STRING(s);
+   if ((cs->sls != NULL)
+       && (cs->sls->bytes == s))
+     cs->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 < smax4)
+     {
+	sum += s[0];
+	h = sum + (h << 1);
+	sum += s[1];
+	h = sum + (h << 1);
+	sum += s[2];
+	h = sum + (h << 1);
+	sum += s[3];
+	h = sum + (h << 1);
+	
+	s += 4;
+     }
+
+   while (s < smax)
+     {
+	sum += *s++;
+	h ^= sum + (h << 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->sls) != NULL)
+       && (sls->bytes == s))
+     return cs->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->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])
+		 && (0 == strncmp (s, bytes, len))))
+	    && (bytes [len] == 0))
+	  break;
+
+	sls = sls->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->bytes)
+	  return sls;
+
+	sls = sls->next;
+     }
+   return sls;
+}
+
+_INLINE_
+static SLstring_Type *allocate_sls (unsigned int len)
+{
+   SLstring_Type *sls;
+   
+#if _SLANG_OPTIMIZE_FOR_SPEED
+   if ((len < MAX_FREE_STORE_LEN)
+       && (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 < MAX_FREE_STORE_LEN)
+       && (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->ref_count++;
+	s = sls->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->bytes, s, len);
+   sls->bytes[len] = 0;
+   sls->ref_count = 1;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+   cache_string (sls, len, hash);
+#endif
+
+   hash = hash % SLSTRING_HASH_TABLE_SIZE;
+   sls->next = String_Hash_Table [(unsigned int)hash];
+   String_Hash_Table [(unsigned int)hash] = sls;
+
+   return sls->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 < 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, &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 < 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->sls) != NULL)
+       && (sls->bytes == s))
+     {
+	sls->ref_count += 1;
+	return s;
+     }
+#else
+   if (s == NULL) return NULL;
+#endif
+
+   len = strlen (s);
+#if !_SLANG_OPTIMIZE_FOR_SPEED
+   if (len < 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->sls) != NULL)
+       && (sls->bytes == s))
+     {
+	sls->ref_count += 1;
+	return s;
+     }
+#endif
+   
+   if ((s == NULL) || ((len = strlen (s)) < 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->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->next;
+     }
+
+   if (prev != NULL)
+     prev->next = sls->next;
+   else
+     String_Hash_Table [(unsigned int) hash] = sls->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 ("Application internal error: invalid attempt to free string");
+	return;
+     }
+
+   sls->ref_count--;
+   if (sls->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->sls) != NULL)
+       && (sls->bytes == s))
+     {
+	if (sls->ref_count <= 1)
+	  free_sls_string (sls, s, cs->len, cs->hash);
+	else
+	  sls->ref_count -= 1;
+	return;
+     }
+#endif
+
+   if (s == NULL) return;
+
+   if ((len = strlen (s)) < 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->sls) != NULL)
+       && (sls->bytes == s))
+     {
+	sls->ref_count += 1;
+	return s;
+     }
+#endif
+
+   if (s == NULL) return NULL;
+   return create_nstring (s, strlen (s), &hash);
+}
+
+void _SLfree_hashed_string (char *s, unsigned int len, unsigned long hash)
+{
+   if ((s == NULL) || (len < 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->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 < 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->ref_count++;
+	_SLunallocate_slstring (s, len);
+	s = sls->bytes;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+	cache_string (sls, len, hash); 
+#endif
+	return s;
+     }
+	
+   sls = (SLstring_Type *) (s - offsetof(SLstring_Type,bytes[0]));
+   sls->ref_count = 1;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+   cache_string (sls, len, hash);
+#endif
+
+   hash = hash % SLSTRING_HASH_TABLE_SIZE;
+   sls->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 "slinclud.h"
+/*{{{ Include Files */
+
+#include <time.h>
+
+#ifndef __QNX__
+# if defined(__GO32__) || defined(__WATCOMC__)
+#  include <dos.h>
+#  include <bios.h>
+# endif
+#endif
+
+#if SLANG_HAS_FLOAT
+#include <math.h>
+#endif
+
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#ifndef isdigit
+# define isdigit(x) (((x) >= '0') && ((x) <= '9'))
+#endif
+
+#include "slang.h"
+#include "_slang.h"
+
+/*}}}*/
+
+#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 < 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 >= a) && (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 <= 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 (&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 <= sizeof (buf))
+     c = buf;
+   else if (NULL == (c = SLmalloc (len)))
+     goto free_and_return;
+#endif
+
+   c1 = c;
+   for (i = 0; i < nargs; i++)
+     {
+	strcpy (c1, ptrs[i]);
+	c1 += strlen (c1);
+     }
+   
+   free_and_return:
+   for (i = 0; i < 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 (&str))
+	  return;
+	free_str = 1;
+     }
+   else white = " \t\f\r\n";
+
+   beg = str;
+   len = do_trim (&beg, do_beg, &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 (&white)) return;
+   if (SLpop_string (&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 **) &beg, 1, (char **) &end, 1, white);
+   SLfree (white);
+
+   /* Determine the effective length */
+   len = 0;
+   s = (unsigned char *) beg;
+   while (s < end)
+     {
+	len++;
+	if (Utility_Char_Table[*s++])
+	  {
+	     while ((s < end) && 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 < end)
+     {
+	unsigned char ch = *beg++;
+	
+	if (0 == Utility_Char_Table[ch])
+	  {
+	     *s++ = ch;
+	     continue;
+	  }
+	
+	*s++ = (unsigned char) pref_char;
+	
+	while ((beg < end) && 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 < 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 < 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 > 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 (&orig, &match, &rep))
+     return -1;
+
+   if (max_num_replaces < 0)
+     {
+	reverse_string (orig);
+	reverse_string (match);
+	reverse_string (rep);
+	ret = str_replace_cmd_1 (orig, match, rep, -max_num_replaces, &new_str);
+	if (ret > 0) reverse_string (new_str);
+	else if (ret == 0)
+	  reverse_string (orig);
+     }
+   else ret = str_replace_cmd_1 (orig, match, rep, max_num_replaces, &new_str);
+   
+   if (ret == 0)
+     {
+	if (-1 == SLang_push_malloced_string (orig))
+	  ret = -1;
+	orig = NULL;
+     }
+   else if (ret > 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, &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 (&str))
+	  return;
+     }
+
+   if (-1 == _SLstring_list_init (&sl, 256, 1024))
+     goto the_return;
+
+   s = str;
+   while (*s != 0)
+     {
+	char *s0;
+
+	s0 = s;
+	/* Skip whitespace */
+	while ((*s0 != 0) && (0 != white[(unsigned char)*s0]))
+	  s0++;
+
+	if (*s0 == 0)
+	  break;
+
+	s = s0;
+	while ((*s != 0) && (0 == white[(unsigned char) *s]))
+	  s++;
+
+	/* sl deleted upon failure */
+	if (-1 == _SLstring_list_append (&sl, SLang_create_nslstring (s0, (unsigned int) (s - s0))))
+	  goto the_return;
+     }
+
+   /* Deletes sl */
+   (void) _SLstring_list_push (&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 ("Comment delimiter length mismatch.");
+	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) && (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 > 255) || (slash < 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 > lena) n = lena + 1;
+   if (n < 1)
+     {
+	SLang_Error = SL_INVALID_PARM;
+	return;
+     }
+
+   n--;
+   if (m < 0) m = lena;
+   if (n + m > 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 (&a))
+     return;
+
+   n = *nptr;
+   m = *mptr;
+
+   lena = strlen (a);
+
+   if ((n <= 0) || (lena < (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 (&str))
+     return;
+
+   a = (unsigned char *) str;
+   while ((c = *a) != 0)
+     {
+	/* if ((*a >= 'a') && (*a <= '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(&str)) return;
+   a = (unsigned char *) str;
+   while ((c = *a) != 0)
+     {
+	/* if ((*a >= 'a') && (*a <= '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 < 0) || (quote > 255)
+       || (delim <= 0) || (delim > 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) && 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, &count, 1)))
+     return NULL;
+
+   data = (char **)at->data;
+
+   count = 0;
+   s1 = s0;
+
+   while (1)
+     {
+	ch = (unsigned char) *s1;
+
+	if ((ch == quote) && 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->data;
+	d1 = d0 + (at->num_elements - 1);
+
+	while (d0 < 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 >= 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 "% #g" 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(&width)) return (out);
+	     want_width = 1;
+	     ch = *p++;
+	  }
+	else
+	  {
+	     if (ch == '0')
+	       {
+		  *f++ = '0';
+		  ch = *p++;
+	       }
+
+	     while ((ch <= '9') && (ch >= '0'))
+	       {
+		  width = width * 10 + (ch - '0');
+		  ch = *p++;
+		  want_width = 1;
+	       }
+	  }
+
+	if (want_width)
+	  {
+	     sprintf(f, "%d", 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(&precis)) return (out);
+		  ch = *p++;
+		  want_width = 1;
+	       }
+	     else while ((ch <= '9') && (ch >= '0'))
+	       {
+		  precis = precis * 10 + (ch - '0');
+		  ch = *p++;
+		  want_width = 1;
+	       }
+	     if (want_width)
+	       {
+		  sprintf(f, "%d", 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 **) &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) "%";
+	     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 (&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(&x, &tmp1, &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("Invalid Format.");
+	     return(out);
+	  }
+	*f++ = ch; *f = 0;
+
+	width = width + precis;
+	if (width > guess_size) guess_size = width;
+
+	if (len + guess_size > 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(&fmt))
+     return -1;
+
+   p = SLdo_sprintf (fmt);
+   SLang_free_slstring (fmt);
+
+   while (_SLStack_Pointer > 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 == '"')) len++;
+	len++;
+     }
+
+   if (NULL == (ss = SLmalloc(len)))
+     return;
+
+   s1 = s;
+   ss1 = ss;
+   *ss1++ = '"';
+   while ((ch = *s1++) != 0)
+     {
+	if (ch == '\n')
+	  {
+	     ch = 'n';
+	     *ss1++ = '\\';
+	  }
+	else if ((ch == '\\') || (ch == '"'))
+	  {
+	     *ss1++ = '\\';
+	  }
+	*ss1++ = ch;
+     }
+   *ss1++ = '"';
+   *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)) && (ch != (char) d)) lend++;
+
+	if ((lbeg + len == lend)
+	    && (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 (&regexp_reg))
+     {
+	SLang_verror (SL_INVALID_PARM, "Unable to compile pattern");
+	return -1;
+     }
+
+   n--;
+   len = strlen(str);
+   if ((n < 0) || ((unsigned int) n >= len))
+     {
+	/* SLang_Error = SL_INVALID_PARM; */
+	return 0;
+     }
+
+   str += n;
+   len -= n;
+
+   if (NULL == (match = SLang_regexp_match((unsigned char *) str, len, &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 < 0) || (n > 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 < n; i++)
+     {
+	if (list[i] == NULL) continue;
+	len += strlen (list[i]);
+	num++;
+     }
+
+   dlen = strlen (delim);
+   if (num > 1)
+     len += (num - 1) * dlen;
+
+   if (NULL == (str = SLmalloc (len)))
+     return NULL;
+
+   *str = 0;
+   s = str;
+   i = 0;
+	
+   while (num > 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 < 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 (&at, SLANG_STRING_TYPE))
+     return;
+   
+   str = create_delimited_string ((char **)at->data, at->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 < 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 < 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 > ch1)
+	  {
+	     if (ch1 == 0)
+	       ch1 = 1;
+
+	     for (i = (unsigned int) ch; i >= (unsigned int) ch1; i--)
+	       *s++ = (unsigned char) i;
+	     
+	     if (*s1 == 0)
+	       break;
+	  }
+	else
+	  {
+	     for (i = (unsigned int) ch; i <= (unsigned int) ch1; i++)
+	       *s++ = (unsigned char) i;
+	  }
+	s1++;
+     }
+   
+#if 0
+   if (range + num != s)
+     SLang_verror (SL_INTERNAL_ERROR, "make_str_range: num wrong");
+#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 < 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("create_delimited_string",  create_delimited_string_cmd, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_SS("strcmp",  strcmp_cmd, SLANG_INT_TYPE),
+   MAKE_INTRINSIC_SSI("strncmp",  strncmp_cmd, SLANG_INT_TYPE),
+   MAKE_INTRINSIC_0("strcat",  strcat_cmd, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_S("strlen",  strlen_cmd, SLANG_INT_TYPE),
+   MAKE_INTRINSIC_SII("strchop", strchop_cmd, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_SII("strchopr", strchopr_cmd, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_I("strreplace", strreplace_cmd, SLANG_INT_TYPE),
+   MAKE_INTRINSIC_SSS("str_replace", str_replace_cmd, SLANG_INT_TYPE),
+   MAKE_INTRINSIC_SII("substr",  substr_cmd, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_SS("is_substr",  issubstr_cmd, SLANG_INT_TYPE),
+   MAKE_INTRINSIC_II("strsub",  strsub_cmd, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_SII("extract_element", extract_element_cmd, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_SSI("is_list_element", is_list_element_cmd, SLANG_INT_TYPE),
+   MAKE_INTRINSIC_SSI("string_match", string_match_cmd, SLANG_INT_TYPE),
+   MAKE_INTRINSIC_I("string_match_nth", string_match_nth_cmd, SLANG_INT_TYPE),
+   MAKE_INTRINSIC_0("strlow", strlow_cmd, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_I("tolower", tolower_cmd, SLANG_INT_TYPE),
+   MAKE_INTRINSIC_I("toupper", toupper_cmd, SLANG_INT_TYPE),
+   MAKE_INTRINSIC_0("strup", strup_cmd, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_S("isdigit",  isdigit_cmd, SLANG_INT_TYPE),
+   MAKE_INTRINSIC_S("strtrim", strtrim_cmd, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_S("strtrim_end", strtrim_end_cmd, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_S("strtrim_beg", strtrim_beg_cmd, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_0("strcompress", strcompress_cmd, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_I("Sprintf", sprintf_n_cmd, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_0("sprintf", sprintf_cmd, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_0("sscanf", _SLang_sscanf, SLANG_INT_TYPE),
+   MAKE_INTRINSIC_S("make_printable_string", make_printable_string, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_SSI("str_quote_string", str_quote_string_cmd, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_SSS("str_uncomment_string", str_uncomment_string_cmd, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_II("define_case", SLang_define_case, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_S("strtok", strtok_cmd, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_S("strjoin", strjoin_cmd, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_SSS("strtrans", strtrans_cmd, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_SS("str_delete_chars", 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 "slinclud.h"
+
+#define SL_APP_WANTS_FOREACH
+#include "slang.h"
+#include "_slang.h"
+
+void _SLstruct_delete_struct (_SLang_Struct_Type *s)
+{
+   _SLstruct_Field_Type *field, *field_max;
+
+   if (s == NULL) return;
+
+   if (s->num_refs > 1)
+     {
+	s->num_refs -= 1;
+	return;
+     }
+
+   field = s->fields;
+   if (field != NULL)
+     {
+	field_max = field + s->nfields;
+
+	while (field < field_max)
+	  {
+	     SLang_free_object (&field->obj);
+	     SLang_free_slstring (field->name);   /* could be NULL */
+	     field++;
+	  }
+	SLfree ((char *) s->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->nfields = nfields;
+   s->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 < 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->num_refs += 1;
+
+   if (0 == SLang_push (&obj))
+     return 0;
+
+   s->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 (&obj))
+     return -1;
+
+   type = obj.data_type;
+   if (type != SLANG_STRUCT_TYPE)
+     {
+	cl = _SLclass_get_class (type);
+	if (cl->cl_struct_def == NULL)
+	  {
+	     *sp = NULL;
+	     SLang_free_object (&obj);
+	     SLang_verror (SL_TYPE_MISMATCH,
+			   "Expecting struct type object.  Found %s",
+			   cl->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->fields;
+   fmax = f + s->nfields;
+
+   while (f < fmax)
+     {
+	/* Since both these are slstrings, only compare pointer */
+	if (name == f->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, "struct has no field named %s", 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->fields;
+   for (i = 0; i < 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, "A struct field name cannot be NULL");
+	     goto return_error;
+	  }
+
+	if (NULL == (f->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->cl_push (type, value)))
+	    || (-1 == SLang_pop (&f->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 (&nfields))
+     return -1;
+
+   if (nfields <= 0)
+     {
+	SLang_verror (SL_INVALID_PARM, "Number of struct fields must be > 0");
+	return -1;
+     }
+
+   if (NULL == (s = allocate_struct (nfields)))
+     return -1;
+
+   f = s->fields;
+   while (nfields)
+     {
+	char *name;
+
+	nfields--;
+	if (-1 == SLang_pop_slstring (&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->nfields;
+   if (NULL == (new_s = allocate_struct (nfields)))
+     return NULL;
+
+   new_f = new_s->fields;
+   old_f = s->fields;
+
+   for (i = 0; i < 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->cl_struct_def)))
+     return -1;
+
+   s->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->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->fields;
+   fmax = f + s->nfields;
+   new_f = new_s->fields;
+
+   while (f < fmax)
+     {
+	SLang_Object_Type *obj;
+
+	obj = &f->obj;
+	if (obj->data_type != SLANG_UNDEFINED_TYPE)
+	  {
+	     if ((-1 == _SLpush_slang_obj (obj))
+		 || (-1 == SLang_pop (&new_f->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 (&s))
+     return NULL;
+
+   switch (num)
+     {
+      case 0:
+	next_name = SLang_create_slstring ("next");
+	break;
+
+      case 1:
+	if (-1 == SLang_pop_slstring (&next_name))
+	  next_name = NULL;
+	break;
+
+      default:
+	next_name = NULL;
+	SLang_verror (SL_NOT_IMPLEMENTED,
+		      "'foreach (Struct_Type) using' requires single control value");
+	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->next_field_name = next_name;
+   c->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->next_field_name);
+   if (c->s != NULL) _SLstruct_delete_struct (c->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->s == NULL)
+     return 0;			       /* done */
+
+   if (-1 == _SLang_push_struct (c->s))
+     return -1;
+
+   /* Now get the next one ready for the next foreach loop */
+
+   next_s = NULL;
+   if (NULL != (f = find_field (c->s, c->next_field_name)))
+     {
+	SLang_Class_Type *cl;
+
+	cl = _SLclass_get_class (f->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->cl_foreach_open == struct_foreach_open)
+	  {
+	     next_s = f->obj.v.struct_val;
+	     next_s->num_refs += 1;
+	  }
+     }
+
+   _SLstruct_delete_struct (c->s);
+   c->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 (&s))
+     return -1;
+
+   if ((NULL == (f = pop_field (s, name)))
+       || (-1 == SLang_pop (&obj)))
+     {
+	_SLstruct_delete_struct (s);
+	return -1;
+     }
+
+   SLang_free_object (&f->obj);
+   f->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 (&s))
+     return -1;
+
+   if (NULL == (f = pop_field (s, name)))
+     {
+	_SLstruct_delete_struct (s);
+	return -1;
+     }
+
+   ret = _SLpush_slang_obj (&f->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 < na; i++)
+     {
+	b[i] = a[i];
+	if (a[i] != NULL)
+	  a[i]->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 (&type_name))
+     return -1;
+
+   if (-1 == _SLang_pop_struct (&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->cl_struct_def = s1;
+   cl->cl_init_array_object = struct_init_array_object;
+   cl->cl_datatype_deref = typedefed_struct_datatype_deref;
+   cl->cl_destroy = struct_destroy;
+   cl->cl_push = struct_push;
+   cl->cl_dereference = struct_dereference;
+   cl->cl_foreach_open = struct_foreach_open;
+   cl->cl_foreach_close = struct_foreach_close;
+   cl->cl_foreach = struct_foreach;
+
+   cl->cl_sget = struct_sget;
+   cl->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->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 (&at, SLANG_STRING_TYPE))
+	  return -1;
+	
+	status = SLstruct_create_struct (at->num_elements,
+					 (char **) at->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 ("Struct_Type")))
+     return -1;
+
+   (void) SLclass_set_destroy_function (cl, struct_destroy);
+   (void) SLclass_set_push_function (cl, struct_push);
+   cl->cl_dereference = struct_dereference;
+   cl->cl_datatype_deref = struct_datatype_deref;
+
+   cl->cl_foreach_open = struct_foreach_open;
+   cl->cl_foreach_close = struct_foreach_close;
+   cl->cl_foreach = struct_foreach;
+
+   cl->cl_sget = struct_sget;
+   cl->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->nfields;
+
+   if (NULL == (a = SLang_create_array (SLANG_STRING_TYPE, 0, NULL, &nfields, 1)))
+     return;
+
+   f = s->fields;
+   data = (char **) a->data;
+   for (i = 0; i < 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->fields;
+   fmax = f + s->nfields;
+
+   num = 0;
+   while (fmax > f)
+     {
+	fmax--;
+	if (-1 == _SLpush_slang_obj (&fmax->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 (&obj))
+     return;
+
+   if (-1 == SLang_pop_slstring (&name))
+     {
+	SLang_free_object (&obj);
+	return;
+     }
+
+   if (-1 == _SLang_pop_struct (&s))
+     {
+	SLang_free_slstring (name);
+	SLang_free_object (&obj);
+	return;
+     }
+
+   if (NULL == (f = pop_field (s, name)))
+     {
+	_SLstruct_delete_struct (s);
+	SLang_free_slstring (name);
+	SLang_free_object (&obj);
+	return;
+     }
+
+   SLang_free_object (&f->obj);
+   f->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 (&s))
+     {
+	SLdo_pop_n (n);
+	return;
+     }
+
+   if (n > s->nfields)
+     {
+	SLdo_pop_n (n);
+	SLang_verror (SL_INVALID_PARM, "Too many values for structure");
+	_SLstruct_delete_struct (s);
+	return;
+     }
+
+   f = s->fields;
+   while (n > 0)
+     {
+	SLang_Object_Type obj;
+
+	if (-1 == SLang_pop (&obj))
+	  break;
+
+	SLang_free_object (&f->obj);
+	f->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 (&obj))
+     return -1;
+   
+   type = obj.data_type;
+   if (type == SLANG_STRUCT_TYPE)
+     status = 1;
+   else
+     status = (NULL != _SLclass_get_class (type)->cl_struct_def);
+   SLang_free_object (&obj);
+   return status;
+}	
+   
+     
+static SLang_Intrin_Fun_Type Struct_Table [] =
+{
+   MAKE_INTRINSIC_1("get_struct_field_names", get_struct_field_names, SLANG_VOID_TYPE, SLANG_STRUCT_TYPE),
+   MAKE_INTRINSIC_1("get_struct_field", get_struct_field, SLANG_VOID_TYPE, SLANG_STRING_TYPE),
+   MAKE_INTRINSIC_1("_push_struct_field_values", push_struct_fields, SLANG_INT_TYPE, SLANG_STRUCT_TYPE),
+   MAKE_INTRINSIC_0("set_struct_field", struct_set_field, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_0("set_struct_fields", set_struct_fields, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_0("is_struct_type", is_struct_type, SLANG_INT_TYPE),
+   /* MAKE_INTRINSIC_I("_create_struct", 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 < 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 > 0)
+     {
+	_SLang_Struct_Type *s;
+	_SLstruct_Field_Type *f;
+
+	i--;
+
+	if (NULL == (s = allocate_struct (1)))
+	  goto return_error;
+
+	data[i] = s;
+	s->num_refs += 1;	       /* keeping a copy */
+
+	f = s->fields;
+	if (NULL == (f->name = SLang_create_slstring ("value")))
+	  goto return_error;
+
+	if (-1 == SLang_pop (&f->obj))
+	  goto return_error;
+     }
+
+   if (NULL == (at = SLang_create_array (SLANG_STRUCT_TYPE, 0,
+					 (VOID_STAR) data, &n, 1)))
+     goto return_error;
+
+   (void) SLang_push_array (at, 1);
+   return;
+
+   return_error:
+   for (i = 0; i < 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->data_type != SLANG_STRUCT_TYPE)
+     {
+	SLang_Error = SL_TYPE_MISMATCH;
+	return;
+     }
+
+   sp = (_SLang_Struct_Type **) at->data;
+   num = at->num_elements;
+
+   while ((SLang_Error == 0) && (num > 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 (&s->fields->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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+/*
+ * 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, "rb");
+   if (fp == NULL) return NULL;
+
+   if ((12 == fread ((char *) buf, 1, 12, fp) && (MAGIC == make_integer (buf))))
+     {
+	h->name_section_size = make_integer (buf + 2);
+	h->boolean_section_size = make_integer (buf + 4);
+	h->num_numbers = make_integer (buf + 6);
+	h->num_string_offsets = make_integer (buf + 8);
+	h->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->terminal_names = (char *) read_terminfo_section (fp, t->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
+ * <term.h>.
+ */
+
+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->name_section_size + t->boolean_section_size) % 2;
+   size += t->boolean_section_size;
+
+   return t->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->numbers = read_terminfo_section (fp, 2 * t->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 ($<nn>) and parameter information
+ * (%x) are stored intact in uninterpreted form.
+ */
+
+static unsigned char *read_string_offsets (FILE *fp, SLterminfo_Type *t)
+{
+   return t->string_offsets = (unsigned char *) read_terminfo_section (fp, 2 * t->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->string_table = (char *) read_terminfo_section (fp, t->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 */
+   "/usr/share/terminfo",
+   "/usr/lib/terminfo",
+   "/usr/share/lib/terminfo",
+   "/etc/terminfo",
+   "/usr/local/lib/terminfo"
+};
+
+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
+       && (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 ("HOME")))
+     {
+	strncpy (home_ti, home, sizeof (home_ti) - 11);
+	home_ti [sizeof(home_ti) - 11] = 0;
+	strcat (home_ti, "/.terminfo");
+	Terminfo_Dirs [0] = home_ti;
+     }
+
+   Terminfo_Dirs[1] = getenv ("TERMINFO");
+   i = 0;
+   while (i < MAX_TI_DIRS)
+     {
+	tidir = Terminfo_Dirs[i];
+	if ((tidir != NULL)
+	    && (sizeof (file) > strlen (tidir) + 2 + strlen (term)))
+	  {
+	     sprintf (file, "%s/%c/%s", 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->flags = SLTERMINFO;
+				 return ti;
+			      }
+			    SLfree ((char *)ti->string_offsets);
+			 }
+		       SLfree ((char *)ti->numbers);
+		    }
+		  SLfree ((char *)ti->boolean_flags);
+	       }
+	     SLfree ((char *)ti->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, &8... */
+static Tgetstr_Map_Type Tgetstr_Map [] =
+{
+   {"!1", 212		UNTIC_COMMENT("shifted key")},
+   {"!2", 213		UNTIC_COMMENT("shifted key")},
+   {"!3", 214		UNTIC_COMMENT("shifted key")},
+   {"#1", 198		UNTIC_COMMENT("shifted key")},
+   {"#2", 199		UNTIC_COMMENT("Key S-Home")},
+   {"#3", 200		UNTIC_COMMENT("Key S-Insert")},
+   {"#4", 201		UNTIC_COMMENT("Key S-Left")},
+   {"%0", 177		UNTIC_COMMENT("redo key")},
+   {"%1", 168		UNTIC_COMMENT("help key")},
+   {"%2", 169		UNTIC_COMMENT("mark key")},
+   {"%3", 170		UNTIC_COMMENT("message key")},
+   {"%4", 171		UNTIC_COMMENT("move key")},
+   {"%5", 172		UNTIC_COMMENT("next key")},
+   {"%6", 173		UNTIC_COMMENT("open key")},
+   {"%7", 174		UNTIC_COMMENT("options key")},
+   {"%8", 175		UNTIC_COMMENT("previous key")},
+   {"%9", 176		UNTIC_COMMENT("print key")},
+   {"%a", 202		UNTIC_COMMENT("shifted key")},
+   {"%b", 203		UNTIC_COMMENT("shifted key")},
+   {"%c", 204		UNTIC_COMMENT("Key S-Next")},
+   {"%d", 205		UNTIC_COMMENT("shifted key")},
+   {"%e", 206		UNTIC_COMMENT("Key S-Previous")},
+   {"%f", 207		UNTIC_COMMENT("shifted key")},
+   {"%g", 208		UNTIC_COMMENT("shifted key")},
+   {"%h", 209		UNTIC_COMMENT("shifted key")},
+   {"%i", 210		UNTIC_COMMENT("Key S-Right")},
+   {"%j", 211		UNTIC_COMMENT("shifted key")},
+   {"&0", 187		UNTIC_COMMENT("shifted key")},
+   {"&1", 178		UNTIC_COMMENT("reference key")},
+   {"&2", 179		UNTIC_COMMENT("refresh key")},
+   {"&3", 180		UNTIC_COMMENT("replace key")},
+   {"&4", 181		UNTIC_COMMENT("restart key")},
+   {"&5", 182		UNTIC_COMMENT("resume key")},
+   {"&6", 183		UNTIC_COMMENT("save key")},
+   {"&7", 184		UNTIC_COMMENT("suspend key")},
+   {"&8", 185		UNTIC_COMMENT("undo key")},
+   {"&9", 186		UNTIC_COMMENT("shifted key")},
+   {"*0", 197		UNTIC_COMMENT("shifted key")},
+   {"*1", 188		UNTIC_COMMENT("shifted key")},
+   {"*2", 189		UNTIC_COMMENT("shifted key")},
+   {"*3", 190		UNTIC_COMMENT("shifted key")},
+   {"*4", 191		UNTIC_COMMENT("Key S-Delete")},
+   {"*5", 192		UNTIC_COMMENT("shifted key")},
+   {"*6", 193		UNTIC_COMMENT("select key")},
+   {"*7", 194		UNTIC_COMMENT("Key S-End")},
+   {"*8", 195		UNTIC_COMMENT("shifted key")},
+   {"*9", 196		UNTIC_COMMENT("shifted key")},
+   {"@0", 167		UNTIC_COMMENT("find key")},
+   {"@1", 158		UNTIC_COMMENT("begin key")},
+   {"@2", 159		UNTIC_COMMENT("cancel key")},
+   {"@3", 160		UNTIC_COMMENT("close key")},
+   {"@4", 161		UNTIC_COMMENT("command key")},
+   {"@5", 162		UNTIC_COMMENT("copy key")},
+   {"@6", 163		UNTIC_COMMENT("create key")},
+   {"@7", 164 		UNTIC_COMMENT("Key End")},
+   {"@8", 165		UNTIC_COMMENT("enter/send key")},
+   {"@9", 166		UNTIC_COMMENT("exit key")},
+   {"AB", 360 		UNTIC_COMMENT("set ANSI color background")},
+   {"AF", 359 		UNTIC_COMMENT("set ANSI color foreground")},
+   {"AL", 110 		UNTIC_COMMENT("parm_insert_line")},
+   {"CC", 9		UNTIC_COMMENT("terminal settable cmd character in prototype !?")},
+   {"CM", 15		UNTIC_COMMENT("memory relative cursor addressing")},
+   {"CW", 277		UNTIC_COMMENT("define a window #1 from #2, #3 to #4, #5")},
+   {"DC", 105		UNTIC_COMMENT("delete #1 chars")},
+   {"DI", 280		UNTIC_COMMENT("dial number #1")},
+   {"DK", 275		UNTIC_COMMENT("display clock at (#1,#2)")},
+   {"DL", 106 		UNTIC_COMMENT("parm_delete_line")},
+   {"DO", 107		UNTIC_COMMENT("down #1 lines")},
+   {"F1", 216		UNTIC_COMMENT("key_f11")},
+   {"F2", 217		UNTIC_COMMENT("key_f12")},
+   {"F3", 218		UNTIC_COMMENT("key_f13")},
+   {"F4", 219		UNTIC_COMMENT("key_f14")},
+   {"F5", 220		UNTIC_COMMENT("key_f15")},
+   {"F6", 221		UNTIC_COMMENT("key_f16")},
+   {"F7", 222		UNTIC_COMMENT("key_f17")},
+   {"F8", 223		UNTIC_COMMENT("key_f18")},
+   {"F9", 224		UNTIC_COMMENT("key_f19")},
+   {"FA", 225		UNTIC_COMMENT("key_f20")},
+   {"FB", 226		UNTIC_COMMENT("F21 function key")},
+   {"FC", 227		UNTIC_COMMENT("F22 function key")},
+   {"FD", 228		UNTIC_COMMENT("F23 function key")},
+   {"FE", 229		UNTIC_COMMENT("F24 function key")},
+   {"FF", 230		UNTIC_COMMENT("F25 function key")},
+   {"FG", 231		UNTIC_COMMENT("F26 function key")},
+   {"FH", 232		UNTIC_COMMENT("F27 function key")},
+   {"FI", 233		UNTIC_COMMENT("F28 function key")},
+   {"FJ", 234		UNTIC_COMMENT("F29 function key")},
+   {"FK", 235		UNTIC_COMMENT("F30 function key")},
+   {"FL", 236		UNTIC_COMMENT("F31 function key")},
+   {"FM", 237		UNTIC_COMMENT("F32 function key")},
+   {"FN", 238		UNTIC_COMMENT("F33 function key")},
+   {"FO", 239		UNTIC_COMMENT("F34 function key")},
+   {"FP", 240		UNTIC_COMMENT("F35 function key")},
+   {"FQ", 241		UNTIC_COMMENT("F36 function key")},
+   {"FR", 242		UNTIC_COMMENT("F37 function key")},
+   {"FS", 243		UNTIC_COMMENT("F38 function key")},
+   {"FT", 244		UNTIC_COMMENT("F39 function key")},
+   {"FU", 245		UNTIC_COMMENT("F40 function key")},
+   {"FV", 246		UNTIC_COMMENT("F41 function key")},
+   {"FW", 247		UNTIC_COMMENT("F42 function key")},
+   {"FX", 248		UNTIC_COMMENT("F43 function key")},
+   {"FY", 249		UNTIC_COMMENT("F44 function key")},
+   {"FZ", 250		UNTIC_COMMENT("F45 function key")},
+   {"Fa", 251		UNTIC_COMMENT("F46 function key")},
+   {"Fb", 252		UNTIC_COMMENT("F47 function key")},
+   {"Fc", 253		UNTIC_COMMENT("F48 function key")},
+   {"Fd", 254		UNTIC_COMMENT("F49 function key")},
+   {"Fe", 255		UNTIC_COMMENT("F50 function key")},
+   {"Ff", 256		UNTIC_COMMENT("F51 function key")},
+   {"Fg", 257		UNTIC_COMMENT("F52 function key")},
+   {"Fh", 258		UNTIC_COMMENT("F53 function key")},
+   {"Fi", 259		UNTIC_COMMENT("F54 function key")},
+   {"Fj", 260		UNTIC_COMMENT("F55 function key")},
+   {"Fk", 261		UNTIC_COMMENT("F56 function key")},
+   {"Fl", 262		UNTIC_COMMENT("F57 function key")},
+   {"Fm", 263		UNTIC_COMMENT("F58 function key")},
+   {"Fn", 264		UNTIC_COMMENT("F59 function key")},
+   {"Fo", 265		UNTIC_COMMENT("F60 function key")},
+   {"Fp", 266		UNTIC_COMMENT("F61 function key")},
+   {"Fq", 267		UNTIC_COMMENT("F62 function key")},
+   {"Fr", 268		UNTIC_COMMENT("F63 function key")},
+   {"G1", 400		UNTIC_COMMENT("single upper right")},
+   {"G2", 398		UNTIC_COMMENT("single upper left")},
+   {"G3", 399		UNTIC_COMMENT("single lower left")},
+   {"G4", 401		UNTIC_COMMENT("single lower right")},
+   {"GC", 408		UNTIC_COMMENT("single intersection")},
+   {"GD", 405		UNTIC_COMMENT("tee pointing down")},
+   {"GH", 406		UNTIC_COMMENT("single horizontal line")},
+   {"GL", 403		UNTIC_COMMENT("tee pointing left")},
+   {"GR", 402		UNTIC_COMMENT("tee pointing right")},
+   {"GU", 404		UNTIC_COMMENT("tee pointing up")},
+   {"GV", 407		UNTIC_COMMENT("single vertical line")},
+   {"Gm", 358		UNTIC_COMMENT("Curses should get button events")},
+   {"HU", 279		UNTIC_COMMENT("hang-up phone")},
+   {"IC", 108		UNTIC_COMMENT("insert #1 chars")},
+   {"Ic", 299		UNTIC_COMMENT("initialize color #1 to (#2,#3,#4)")},
+   {"Ip", 300		UNTIC_COMMENT("Initialize color pair #1 to fg=(#2,#3,#4), bg=(#5,#6,#7)")},
+   {"K1", 139		UNTIC_COMMENT("upper left of keypad")},
+   {"K2", 141		UNTIC_COMMENT("center of keypad")},
+   {"K3", 140		UNTIC_COMMENT("upper right of keypad")},
+   {"K4", 142		UNTIC_COMMENT("lower left of keypad")},
+   {"K5", 143		UNTIC_COMMENT("lower right of keypad")},
+   {"Km", 355		UNTIC_COMMENT("Mouse event has occurred")},
+   {"LE", 111		UNTIC_COMMENT("move #1 chars to the left")},
+   {"LF", 157		UNTIC_COMMENT("turn off soft labels")},
+   {"LO", 156		UNTIC_COMMENT("turn on soft labels")},
+   {"Lf", 273		UNTIC_COMMENT("label format")},
+   {"MC", 270		UNTIC_COMMENT("clear right and left soft margins")},
+   {"ML", 271		UNTIC_COMMENT("set left soft margin")},
+   {"ML", 368		UNTIC_COMMENT("Set both left and right margins to #1, #2")},
+   {"MR", 272		UNTIC_COMMENT("set right soft margin")},
+   {"MT", 369		UNTIC_COMMENT("Sets both top and bottom margins to #1, #2")},
+   {"Mi", 356		UNTIC_COMMENT("Mouse status information")},
+   {"PA", 285		UNTIC_COMMENT("pause for 2-3 seconds")},
+   {"PU", 283		UNTIC_COMMENT("select pulse dialling")},
+   {"QD", 281		UNTIC_COMMENT("dial number #1 without checking")},
+   {"RA", 152		UNTIC_COMMENT("turn off automatic margins")},
+   {"RC", 276		UNTIC_COMMENT("remove clock")},
+   {"RF", 215		UNTIC_COMMENT("send next input char (for ptys)")},
+   {"RI", 112 		UNTIC_COMMENT("parm_right_cursor")},
+   {"RQ", 357		UNTIC_COMMENT("Request mouse position")},
+   {"RX", 150		UNTIC_COMMENT("turn off xon/xoff handshaking")},
+   {"S1", 378		UNTIC_COMMENT("Display PC character")},
+   {"S2", 379		UNTIC_COMMENT("Enter PC character display mode")},
+   {"S3", 380		UNTIC_COMMENT("Exit PC character display mode")},
+   {"S4", 381		UNTIC_COMMENT("Enter PC scancode mode")},
+   {"S5", 382		UNTIC_COMMENT("Exit PC scancode mode")},
+   {"S6", 383		UNTIC_COMMENT("PC terminal options")},
+   {"S7", 384		UNTIC_COMMENT("Escape for scancode emulation")},
+   {"S8", 385		UNTIC_COMMENT("Alternate escape for scancode emulation")},
+   {"SA", 151		UNTIC_COMMENT("turn on automatic margins")},
+   {"SC", 274		UNTIC_COMMENT("set clock, #1 hrs #2 mins #3 secs")},
+   {"SF", 109		UNTIC_COMMENT("scroll forward #1 lines")},
+   {"SR", 113		UNTIC_COMMENT("scroll back #1 lines")},
+   {"SX", 149		UNTIC_COMMENT("turn on xon/xoff handshaking")},
+   {"Sb", 303 		UNTIC_COMMENT("set background (color)")},
+   {"Sf", 302 		UNTIC_COMMENT("set foreground (color)")},
+   {"TO", 282		UNTIC_COMMENT("select touch tone dialing")},
+   {"UP", 114		UNTIC_COMMENT("up #1 lines")},
+   {"WA", 286		UNTIC_COMMENT("wait for dial-tone")},
+   {"WG", 278		UNTIC_COMMENT("go to window #1")},
+   {"XF", 154		UNTIC_COMMENT("XOFF character")},
+   {"XN", 153		UNTIC_COMMENT("XON character")},
+   {"Xh", 386		UNTIC_COMMENT("Enter horizontal highlight mode")},
+   {"Xl", 387		UNTIC_COMMENT("Enter left highlight mode")},
+   {"Xo", 388		UNTIC_COMMENT("Enter low highlight mode")},
+   {"Xr", 389		UNTIC_COMMENT("Enter right highlight mode")},
+   {"Xt", 390		UNTIC_COMMENT("Enter top highlight mode")},
+   {"Xv", 391		UNTIC_COMMENT("Enter vertical highlight mode")},
+   {"Xy", 370		UNTIC_COMMENT("Repeat bit image cell #1 #2 times")},
+   {"YZ", 377		UNTIC_COMMENT("Set page length to #1 lines")},
+   {"Yv", 372		UNTIC_COMMENT("Move to beginning of same row")},
+   {"Yw", 373		UNTIC_COMMENT("Give name for color #1")},
+   {"Yx", 374		UNTIC_COMMENT("Define rectangualar bit image region")},
+   {"Yy", 375		UNTIC_COMMENT("End a bit-image region")},
+   {"Yz", 376		UNTIC_COMMENT("Change to ribbon color #1")},
+   {"ZA", 304		UNTIC_COMMENT("Change number of characters per inch")},
+   {"ZB", 305		UNTIC_COMMENT("Change number of lines per inch")},
+   {"ZC", 306		UNTIC_COMMENT("Change horizontal resolution")},
+   {"ZD", 307		UNTIC_COMMENT("Change vertical resolution")},
+   {"ZE", 308		UNTIC_COMMENT("Define a character")},
+   {"ZF", 309		UNTIC_COMMENT("Enter double-wide mode")},
+   {"ZG", 310		UNTIC_COMMENT("Enter draft-quality mode")},
+   {"ZH", 311		UNTIC_COMMENT("Enter italic mode")},
+   {"ZI", 312		UNTIC_COMMENT("Start leftward carriage motion")},
+   {"ZJ", 313		UNTIC_COMMENT("Start micro-motion mode")},
+   {"ZK", 314		UNTIC_COMMENT("Enter NLQ mode")},
+   {"ZL", 315		UNTIC_COMMENT("Wnter normal-quality mode")},
+   {"ZM", 316		UNTIC_COMMENT("Enter shadow-print mode")},
+   {"ZN", 317		UNTIC_COMMENT("Enter subscript mode")},
+   {"ZO", 318		UNTIC_COMMENT("Enter superscript mode")},
+   {"ZP", 319		UNTIC_COMMENT("Start upward carriage motion")},
+   {"ZQ", 320		UNTIC_COMMENT("End double-wide mode")},
+   {"ZR", 321		UNTIC_COMMENT("End italic mode")},
+   {"ZS", 322		UNTIC_COMMENT("End left-motion mode")},
+   {"ZT", 323		UNTIC_COMMENT("End micro-motion mode")},
+   {"ZU", 324		UNTIC_COMMENT("End shadow-print mode")},
+   {"ZV", 325		UNTIC_COMMENT("End subscript mode")},
+   {"ZW", 326		UNTIC_COMMENT("End superscript mode")},
+   {"ZX", 327		UNTIC_COMMENT("End reverse character motion")},
+   {"ZY", 328		UNTIC_COMMENT("Like column_address in micro mode")},
+   {"ZZ", 329		UNTIC_COMMENT("Like cursor_down in micro mode")},
+   {"Za", 330		UNTIC_COMMENT("Like cursor_left in micro mode")},
+   {"Zb", 331		UNTIC_COMMENT("Like cursor_right in micro mode")},
+   {"Zc", 332		UNTIC_COMMENT("Like row_address in micro mode")},
+   {"Zd", 333		UNTIC_COMMENT("Like cursor_up in micro mode")},
+   {"Ze", 334		UNTIC_COMMENT("Match software bits to print-head pins")},
+   {"Zf", 335		UNTIC_COMMENT("Like parm_down_cursor in micro mode")},
+   {"Zg", 336		UNTIC_COMMENT("Like parm_left_cursor in micro mode")},
+   {"Zh", 337		UNTIC_COMMENT("Like parm_right_cursor in micro mode")},
+   {"Zi", 338		UNTIC_COMMENT("Like parm_up_cursor in micro mode")},
+   {"Zj", 339		UNTIC_COMMENT("Select character set")},
+   {"Zk", 340		UNTIC_COMMENT("Set bottom margin at current line")},
+   {"Zl", 341		UNTIC_COMMENT("Set bottom margin at line #1 or #2 lines from bottom")},
+   {"Zm", 342		UNTIC_COMMENT("Set left (right) margin at column #1 (#2)")},
+   {"Zn", 343		UNTIC_COMMENT("Set right margin at column #1")},
+   {"Zo", 344		UNTIC_COMMENT("Set top margin at current line")},
+   {"Zp", 345		UNTIC_COMMENT("Set top (bottom) margin at row #1 (#2)")},
+   {"Zq", 346		UNTIC_COMMENT("Start printing bit image braphics")},
+   {"Zr", 347		UNTIC_COMMENT("Start character set definition")},
+   {"Zs", 348		UNTIC_COMMENT("Stop printing bit image graphics")},
+   {"Zt", 349		UNTIC_COMMENT("End definition of character aet")},
+   {"Zu", 350		UNTIC_COMMENT("List of subscriptable characters")},
+   {"Zv", 351		UNTIC_COMMENT("List of superscriptable characters")},
+   {"Zw", 352		UNTIC_COMMENT("Printing any of these chars causes CR")},
+   {"Zx", 353		UNTIC_COMMENT("No motion for subsequent character")},
+   {"Zy", 354		UNTIC_COMMENT("List of character set names")},
+   {"Zz", 371		UNTIC_COMMENT("Move to next row of the bit image")},
+   {"ac", 146 		UNTIC_COMMENT("acs_chars")},
+   {"ae", 38 		UNTIC_COMMENT("exit_alt_charset_mode")},
+   {"al", 53		UNTIC_COMMENT("insert line")},
+   {"as", 25 		UNTIC_COMMENT("enter_alt_charset_mode")},
+   {"bc", 395		UNTIC_COMMENT("move left, if not ^H")},
+   {"bl", 1		UNTIC_COMMENT("audible signal (bell)")},
+   {"bt", 0		UNTIC_COMMENT("back tab")},
+   {"bx", 411		UNTIC_COMMENT("box chars primary set")},
+   {"cb", 269		UNTIC_COMMENT("Clear to beginning of line")},
+   {"cd", 7		UNTIC_COMMENT("clear to end of screen")},
+   {"ce", 6 		UNTIC_COMMENT("clr_eol")},
+   {"ch", 8		UNTIC_COMMENT("horizontal position #1, absolute")},
+   {"ci", 363		UNTIC_COMMENT("Init sequence for multiple codesets")},
+   {"cl", 5		UNTIC_COMMENT("clear screen and home cursor")},
+   {"cm", 10		UNTIC_COMMENT("move to row #1 columns #2")},
+   {"cr", 2		UNTIC_COMMENT("carriage return")},
+   {"cs", 3		UNTIC_COMMENT("change region to line #1 to line #2")},
+   {"ct", 4		UNTIC_COMMENT("clear all tab stops")},
+   {"cv", 127		UNTIC_COMMENT("vertical position #1 absolute")},
+   {"dc", 21		UNTIC_COMMENT("delete character")},
+   {"dl", 22		UNTIC_COMMENT("delete line")},
+   {"dm", 29		UNTIC_COMMENT("enter delete mode")},
+   {"do", 11		UNTIC_COMMENT("down one line")},
+   {"ds", 23		UNTIC_COMMENT("disable status line")},
+   {"dv", 362		UNTIC_COMMENT("Indicate language/codeset support")},
+   {"eA", 155		UNTIC_COMMENT("enable alternate char set")},
+   {"ec", 37		UNTIC_COMMENT("erase #1 characters")},
+   {"ed", 41		UNTIC_COMMENT("end delete mode")},
+   {"ei", 42		UNTIC_COMMENT("exit insert mode")},
+   {"ff", 46		UNTIC_COMMENT("hardcopy terminal page eject")},
+   {"fh", 284		UNTIC_COMMENT("flash switch hook")},
+   {"fs", 47		UNTIC_COMMENT("return from status line")},
+   {"hd", 24		UNTIC_COMMENT("half a line down")},
+   {"ho", 12		UNTIC_COMMENT("home cursor (if no cup)")},
+   {"hu", 137		UNTIC_COMMENT("half a line up")},
+   {"i1", 48		UNTIC_COMMENT("initialization string")},
+   {"i2", 392		UNTIC_COMMENT("secondary initialization string")},
+   {"i3", 50		UNTIC_COMMENT("initialization string")},
+   {"iP", 138		UNTIC_COMMENT("path name of program for initialization")},
+   {"ic", 52		UNTIC_COMMENT("insert character")},
+   {"if", 51		UNTIC_COMMENT("name of initialization file")},
+   {"im", 31		UNTIC_COMMENT("enter insert mode")},
+   {"ip", 54		UNTIC_COMMENT("insert padding after inserted character")},
+   {"is", 49		UNTIC_COMMENT("initialization string")},
+   {"k0", 65		UNTIC_COMMENT("F0 function key")},
+   {"k1", 66		UNTIC_COMMENT("F1 function key")},
+   {"k2", 68		UNTIC_COMMENT("F2 function key")},
+   {"k3", 69		UNTIC_COMMENT("F3 function key")},
+   {"k4", 70		UNTIC_COMMENT("F4 function key")},
+   {"k5", 71		UNTIC_COMMENT("F5 function key")},
+   {"k6", 72		UNTIC_COMMENT("F6 function key")},
+   {"k7", 73		UNTIC_COMMENT("F7 function key")},
+   {"k8", 74		UNTIC_COMMENT("F8 fucntion key")},
+   {"k9", 75		UNTIC_COMMENT("F9 function key")},
+   {"k;", 67		UNTIC_COMMENT("F10 function key")},
+   {"kA", 78		UNTIC_COMMENT("insert-line key")},
+   {"kB", 148		UNTIC_COMMENT("back-tab key")},
+   {"kC", 57		UNTIC_COMMENT("clear-screen or erase key")},
+   {"kD", 59		UNTIC_COMMENT("delete-character key")},
+   {"kE", 63		UNTIC_COMMENT("clear-to-end-of-line key")},
+   {"kF", 84		UNTIC_COMMENT("scroll-forward key")},
+   {"kH", 80		UNTIC_COMMENT("last-line key")},
+   {"kI", 77		UNTIC_COMMENT("insert-character key")},
+   {"kL", 60		UNTIC_COMMENT("delete-line key")},
+   {"kM", 62		UNTIC_COMMENT("sent by rmir or smir in insert mode")},
+   {"kN", 81		UNTIC_COMMENT("next-page key")},
+   {"kP", 82		UNTIC_COMMENT("prev-page key")},
+   {"kR", 85		UNTIC_COMMENT("scroll-backward key")},
+   {"kS", 64		UNTIC_COMMENT("clear-to-end-of-screen key")},
+   {"kT", 86		UNTIC_COMMENT("set-tab key")},
+   {"ka", 56		UNTIC_COMMENT("clear-all-tabs key")},
+   {"kb", 55		UNTIC_COMMENT("backspace key")},
+   {"kd", 61		UNTIC_COMMENT("down-arrow key")},
+   {"ke", 88		UNTIC_COMMENT("leave 'keyboard_transmit' mode")},
+   {"kh", 76		UNTIC_COMMENT("home key")},
+   {"kl", 79		UNTIC_COMMENT("left-arrow key")},
+   {"ko", 396		UNTIC_COMMENT("list of self-mapped keycaps")},
+   {"kr", 83		UNTIC_COMMENT("right-arrow key")},
+   {"ks", 89		UNTIC_COMMENT("enter 'keyboard_transmit' mode")},
+   {"kt", 58		UNTIC_COMMENT("clear-tab key")},
+   {"ku", 87		UNTIC_COMMENT("up-arrow key")},
+   {"l0", 90		UNTIC_COMMENT("label on function key f0 if not f0")},
+   {"l1", 91		UNTIC_COMMENT("label on function key f1 if not f1")},
+   {"l2", 93		UNTIC_COMMENT("label on function key f2 if not f2")},
+   {"l3", 94		UNTIC_COMMENT("label on function key f3 if not f3")},
+   {"l4", 95		UNTIC_COMMENT("label on function key f4 if not f4")},
+   {"l5", 96		UNTIC_COMMENT("lable on function key f5 if not f5")},
+   {"l6", 97		UNTIC_COMMENT("label on function key f6 if not f6")},
+   {"l7", 98		UNTIC_COMMENT("label on function key f7 if not f7")},
+   {"l8", 99		UNTIC_COMMENT("label on function key f8 if not f8")},
+   {"l9", 100		UNTIC_COMMENT("label on function key f9 if not f9")},
+   {"la", 92		UNTIC_COMMENT("label on function key f10 if not f10")},
+   {"le", 14		UNTIC_COMMENT("move left one space")},
+   {"ll", 18		UNTIC_COMMENT("last line, first column (if no cup)")},
+   {"ma", 397		UNTIC_COMMENT("map arrow keys rogue(1) motion keys")},
+   {"mb", 26		UNTIC_COMMENT("turn on blinking")},
+   {"md", 27		UNTIC_COMMENT("turn on bold (extra bright) mode")},
+   {"me", 39		UNTIC_COMMENT("turn off all attributes")},
+   {"mh", 30		UNTIC_COMMENT("turn on half-bright mode")},
+   {"mk", 32		UNTIC_COMMENT("turn on blank mode (characters invisible)")},
+   {"ml", 409		UNTIC_COMMENT("memory lock above")},
+   {"mm", 102		UNTIC_COMMENT("turn on meta mode (8th-bit on)")},
+   {"mo", 101		UNTIC_COMMENT("turn off meta mode")},
+   {"mp", 33		UNTIC_COMMENT("turn on protected mode")},
+   {"mr", 34		UNTIC_COMMENT("turn on reverse video mode")},
+   {"mu", 410		UNTIC_COMMENT("memory unlock")},
+   {"nd", 17		UNTIC_COMMENT("move right one space")},
+   {"nl", 394		UNTIC_COMMENT("use to move down")},
+   {"nw", 103		UNTIC_COMMENT("newline (behave like cr followed by lf)")},
+   {"oc", 298		UNTIC_COMMENT("Set all color pairs to the original ones")},
+   {"op", 297		UNTIC_COMMENT("Set default pair to its original value")},
+   {"pO", 144		UNTIC_COMMENT("turn on printer for #1 bytes")},
+   {"pc", 104		UNTIC_COMMENT("padding char (instead of null)")},
+   {"pf", 119		UNTIC_COMMENT("turn off printer")},
+   {"pk", 115		UNTIC_COMMENT("program function key #1 to type string #2")},
+   {"pl", 116		UNTIC_COMMENT("program function key #1 to execute string #2")},
+   {"pn", 147		UNTIC_COMMENT("program label #1 to show string #2")},
+   {"po", 120		UNTIC_COMMENT("turn on printer")},
+   {"ps", 118		UNTIC_COMMENT("print contents of screen")},
+   {"px", 117		UNTIC_COMMENT("program function key #1 to transmit string #2")},
+   {"r1", 122		UNTIC_COMMENT("reset string")},
+   {"r2", 123		UNTIC_COMMENT("reset string")},
+   {"r3", 124		UNTIC_COMMENT("reset string")},
+   {"rP", 145		UNTIC_COMMENT("like ip but when in insert mode")},
+   {"rc", 126		UNTIC_COMMENT("restore cursor to last position of sc")},
+   {"rf", 125		UNTIC_COMMENT("name of reset file")},
+   {"rp", 121		UNTIC_COMMENT("repeat char #1 #2 times")},
+   {"rs", 393		UNTIC_COMMENT("terminal reset string")},
+   {"s0", 364		UNTIC_COMMENT("Shift to code set 0 (EUC set 0, ASCII)")},
+   {"s1", 365		UNTIC_COMMENT("Shift to code set 1")},
+   {"s2", 366		UNTIC_COMMENT("Shift to code set 2")},
+   {"s3", 367		UNTIC_COMMENT("Shift to code set 3")},
+   {"sa", 131		UNTIC_COMMENT("define video attributes #1-#9 (PG9)")},
+   {"sc", 128		UNTIC_COMMENT("save current cursor position")},
+   {"se", 43		UNTIC_COMMENT("exit standout mode")},
+   {"sf", 129		UNTIC_COMMENT("scroll text up")},
+   {"so", 35		UNTIC_COMMENT("begin standout mode")},
+   {"sp", 301		UNTIC_COMMENT("Set current color pair to #1")},
+   {"sr", 130		UNTIC_COMMENT("scroll text down")},
+   {"st", 132		UNTIC_COMMENT("set a tab in every row, current columns")},
+   {"ta", 134		UNTIC_COMMENT("tab to next 8-space hardware tab stop")},
+   {"te", 40		UNTIC_COMMENT("strings to end programs using cup")},
+   {"ti", 28		UNTIC_COMMENT("string to start programs using cup")},
+   {"ts", 135		UNTIC_COMMENT("move to status line")},
+   {"u0", 287		UNTIC_COMMENT("User string #0")},
+   {"u1", 288		UNTIC_COMMENT("User string #1")},
+   {"u2", 289		UNTIC_COMMENT("User string #2")},
+   {"u3", 290		UNTIC_COMMENT("User string #3")},
+   {"u4", 291		UNTIC_COMMENT("User string #4")},
+   {"u5", 292		UNTIC_COMMENT("User string #5")},
+   {"u6", 293		UNTIC_COMMENT("User string #6")},
+   {"u7", 294		UNTIC_COMMENT("User string #7")},
+   {"u8", 295		UNTIC_COMMENT("User string #8")},
+   {"u9", 296		UNTIC_COMMENT("User string #9")},
+   {"uc", 136		UNTIC_COMMENT("underline char and move past it")},
+   {"ue", 44		UNTIC_COMMENT("exit underline mode")},
+   {"up", 19		UNTIC_COMMENT("up one line")},
+   {"us", 36		UNTIC_COMMENT("begin underline mode")},
+   {"vb", 45		UNTIC_COMMENT("visible bell (may not move cursor)")},
+   {"ve", 16		UNTIC_COMMENT("make cursor appear normal (undo civis/cvvis)")},
+   {"vi", 13		UNTIC_COMMENT("make cursor invisible")},
+   {"vs", 20		UNTIC_COMMENT("make cursor very visible")},
+   {"wi", 133		UNTIC_COMMENT("current window is lines #1-#2 cols #3-#4")},
+   {"xl", 361		UNTIC_COMMENT("Program function key #1 to type string #2 and show string #3")},
+   {"", -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->name != 0)
+     {
+	if ((cha == *map->name) && (chb == *(map->name + 1)))
+	  {
+	     if (map->offset >= (int) max_ofs) return -1;
+	     return map->offset;
+	  }
+	map++;
+     }
+   return -1;
+}
+
+char *_SLtt_tigetstr (SLterminfo_Type *t, char *cap)
+{
+   int offset;
+
+   if (t == NULL)
+     return NULL;
+
+   if (t->flags == SLTERMCAP) return tcap_getstr (cap, t);
+
+   offset = compute_cap_offset (cap, t, Tgetstr_Map, t->num_string_offsets);
+   if (offset < 0) return NULL;
+   offset = make_integer (t->string_offsets + 2 * offset);
+   if (offset < 0) return NULL;
+   return t->string_table + offset;
+}
+
+static Tgetstr_Map_Type Tgetnum_Map[] =
+{
+   {"BT", 30		UNTIC_COMMENT("number of buttons on mouse")},
+   {"Co", 13		UNTIC_COMMENT("maximum numbers of colors on screen")},
+   {"MW", 12		UNTIC_COMMENT("maxumum number of defineable windows")},
+   {"NC", 15		UNTIC_COMMENT("video attributes that can't be used with colors")},
+   {"Nl", 8		UNTIC_COMMENT("number of labels on screen")},
+   {"Ya", 16		UNTIC_COMMENT("numbers of bytes buffered before printing")},
+   {"Yb", 17		UNTIC_COMMENT("spacing of pins vertically in pins per inch")},
+   {"Yc", 18		UNTIC_COMMENT("spacing of dots horizontally in dots per inch")},
+   {"Yd", 19		UNTIC_COMMENT("maximum value in micro_..._address")},
+   {"Ye", 20		UNTIC_COMMENT("maximum value in parm_..._micro")},
+   {"Yf", 21		UNTIC_COMMENT("character size when in micro mode")},
+   {"Yg", 22		UNTIC_COMMENT("line size when in micro mode")},
+   {"Yh", 23		UNTIC_COMMENT("numbers of pins in print-head")},
+   {"Yi", 24		UNTIC_COMMENT("horizontal resolution in units per line")},
+   {"Yj", 25		UNTIC_COMMENT("vertical resolution in units per line")},
+   {"Yk", 26		UNTIC_COMMENT("horizontal resolution in units per inch")},
+   {"Yl", 27		UNTIC_COMMENT("vertical resolution in units per inch")},
+   {"Ym", 28		UNTIC_COMMENT("print rate in chars per second")},
+   {"Yn", 29		UNTIC_COMMENT("character step size when in double wide mode")},
+   {"Yo", 31		UNTIC_COMMENT("number of passed for each bit-image row")},
+   {"Yp", 32		UNTIC_COMMENT("type of bit-image device")},
+   {"co", 0		UNTIC_COMMENT("number of columns in aline")},
+   {"dB", 36		UNTIC_COMMENT("padding required for ^H")},
+   {"dC", 34		UNTIC_COMMENT("pad needed for CR")},
+   {"dN", 35		UNTIC_COMMENT("pad needed for LF")},
+   {"dT", 37		UNTIC_COMMENT("padding required for ^I")},
+   {"it", 1		UNTIC_COMMENT("tabs initially every # spaces")},
+   {"kn", 38		UNTIC_COMMENT("count of function keys")},
+   {"lh", 9		UNTIC_COMMENT("rows in each label")},
+   {"li", 2		UNTIC_COMMENT("number of lines on screen or page")},
+   {"lm", 3		UNTIC_COMMENT("lines of memory if > line. 0 => varies")},
+   {"lw", 10		UNTIC_COMMENT("columns in each label")},
+   {"ma", 11		UNTIC_COMMENT("maximum combined attributes terminal can handle")},
+   {"pa", 14		UNTIC_COMMENT("maximum number of color-pairs on the screen")},
+   {"pb", 5		UNTIC_COMMENT("lowest baud rate where padding needed")},
+   {"sg", 4		UNTIC_COMMENT("number of blank chars left by smso or rmso")},
+   {"ug", 33		UNTIC_COMMENT("number of blanks left by ul")},
+   {"vt", 6		UNTIC_COMMENT("virtual terminal number (CB/unix)")},
+   {"ws", 7		UNTIC_COMMENT("columns in status line")},
+   {"", -1		UNTIC_COMMENT(NULL)}
+};
+
+int _SLtt_tigetnum (SLterminfo_Type *t, char *cap)
+{
+   int offset;
+
+   if (t == NULL)
+     return -1;
+
+   if (t->flags == SLTERMCAP) return tcap_getnum (cap, t);
+
+   offset = compute_cap_offset (cap, t, Tgetnum_Map, t->num_numbers);
+   if (offset < 0) return -1;
+   return make_integer (t->numbers + 2 * offset);
+}
+
+static Tgetstr_Map_Type Tgetflag_Map[] =
+{
+   {"5i", 22		UNTIC_COMMENT("printer won't echo on screen")},
+   {"HC", 23		UNTIC_COMMENT("cursor is hard to see")},
+   {"MT", 40		UNTIC_COMMENT("has meta key")},
+   {"ND", 26		UNTIC_COMMENT("scrolling region is non-destructive")},
+   {"NL", 41		UNTIC_COMMENT("move down with \n")},
+   {"NP", 25		UNTIC_COMMENT("pad character does not exist")},
+   {"NR", 24		UNTIC_COMMENT("smcup does not reverse rmcup")},
+   {"YA", 30		UNTIC_COMMENT("only positive motion for hpa/mhpa caps")},
+   {"YB", 31		UNTIC_COMMENT("using cr turns off micro mode")},
+   {"YC", 32		UNTIC_COMMENT("printer needs operator to change character set")},
+   {"YD", 33		UNTIC_COMMENT("only positive motion for vpa/mvpa caps")},
+   {"YE", 34		UNTIC_COMMENT("printing in last column causes cr")},
+   {"YF", 35		UNTIC_COMMENT("changing character pitch changes resolution")},
+   {"YG", 36		UNTIC_COMMENT("changing line pitch changes resolution")},
+   {"am", 1		UNTIC_COMMENT("terminal has automatic margins")},
+   {"bs", 37		UNTIC_COMMENT("uses ^H to move left")},
+   {"bw", 0		UNTIC_COMMENT("cub1 wraps from column 0 to last column")},
+   {"cc", 27		UNTIC_COMMENT("terminal can re-define existing colors")},
+   {"da", 11		UNTIC_COMMENT("display may be retained above the screen")},
+   {"db", 12		UNTIC_COMMENT("display may be retained below the screen")},
+   {"eo", 5		UNTIC_COMMENT("can erase overstrikes with a blank")},
+   {"es", 16		UNTIC_COMMENT("escape can be used on the status line")},
+   {"gn", 6		UNTIC_COMMENT("generic line type")},
+   {"hc", 7		UNTIC_COMMENT("hardcopy terminal")},
+   {"hl", 29		UNTIC_COMMENT("terminal uses only HLS color notation (tektronix)")},
+   {"hs", 9		UNTIC_COMMENT("has extra status line")},
+   {"hz", 18		UNTIC_COMMENT("can't print ~'s (hazeltine)")},
+   {"in", 10		UNTIC_COMMENT("insert mode distinguishes nulls")},
+   {"km", 8		UNTIC_COMMENT("Has a meta key, sets msb high")},
+   {"mi", 13		UNTIC_COMMENT("safe to move while in insert mode")},
+   {"ms", 14		UNTIC_COMMENT("safe to move while in standout mode")},
+   {"nc", 39		UNTIC_COMMENT("no way to go to start of line")},
+   {"ns", 38		UNTIC_COMMENT("crt cannot scroll")},
+   {"nx", 21		UNTIC_COMMENT("padding won't work, xon/xoff required")},
+   {"os", 15		UNTIC_COMMENT("terminal can overstrike")},
+   {"pt", 42		UNTIC_COMMENT("has 8-char tabs invoked with ^I")},
+   {"ul", 19		UNTIC_COMMENT("underline character overstrikes")},
+   {"ut", 28		UNTIC_COMMENT("screen erased with background color")},
+   {"xb", 2		UNTIC_COMMENT("beehive (f1=escape, f2=ctrl C)")},
+   {"xn", 4		UNTIC_COMMENT("newline ignored after 80 cols (concept)")},
+   {"xo", 20		UNTIC_COMMENT("terminal uses xon/xoff handshaking")},
+   {"xr", 43		UNTIC_COMMENT("return clears the line")},
+   {"xs", 3		UNTIC_COMMENT("standout not erased by overwriting (hp)")},
+   {"xt", 17		UNTIC_COMMENT("tabs destructive, magic so char (t1061)")},
+   {"", -1		UNTIC_COMMENT(NULL)}
+};
+
+int _SLtt_tigetflag (SLterminfo_Type *t, char *cap)
+{
+   int offset;
+
+   if (t == NULL) return -1;
+
+   if (t->flags == SLTERMCAP) return tcap_getflag (cap, t);
+
+   offset = compute_cap_offset (cap, t, Tgetflag_Map, t->boolean_section_size);
+
+   if (offset < 0) return -1;
+   return (int) *(t->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->boolean_flags;
+   char *fmax;
+
+   if (f == NULL) return 0;
+   fmax = f + t->boolean_section_size;
+
+   a = *cap;
+   b = *(cap + 1);
+   while (f < fmax)
+     {
+	if ((a == f[0]) && (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 < caps_max)
+     {
+	if ((c0 == caps[0]) && (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->numbers, t->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->string_table, t->string_table_size);
+}
+
+static int tcap_extract_field (unsigned char *t0)
+{
+   register unsigned char ch, *t = t0;
+   while (((ch = *t) != 0) && (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, "xterm", 5))
+     return -1;
+#endif
+   termcap = (unsigned char *) getenv ("TERMCAP");
+   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 > 3) && (t[0] == 't') && (t[1] == 'c') && (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->terminal_names = (char *) b;
+   t = termcap;
+   len = tcap_extract_field (t);
+   if (len < 0)
+     {
+	SLfree ((char *)buf);
+	return -1;
+     }
+   strncpy ((char *) b, (char *) t, (unsigned int) len);
+   b[len] = 0;
+   b += len + 1;
+   ti->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->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 < 4) || (t[2] != '=') || (*t == '.'))
+	  {
+	     t += len + 1;
+	     continue;
+	  }
+	tmax = t + len;
+	b1 = b;
+
+	while (t < tmax)
+	  {
+	     ch = *t++;
+	     if ((ch == '\\') && (t < tmax))
+	       {
+		  t = (unsigned char *) _SLexpand_escaped_char ((char *) t, (char *) &ch);
+	       }
+	     else if ((ch == '^') && (t < 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->string_table_size = (int) (b - (unsigned char *) ti->string_table);
+
+   /* Now process the numbers. */
+
+   t = termcap;
+   ti->numbers = b;
+   while (-1 != (len = tcap_extract_field (t)))
+     {
+	unsigned char *b1;
+	unsigned char *tmax;
+
+	/* We are looking for: XX#NUMBER */
+	if ((len < 4) || (t[2] != '#') || (*t == '.'))
+	  {
+	     t += len + 1;
+	     continue;
+	  }
+	tmax = t + len;
+	b1 = b;
+
+	while (t < tmax)
+	  {
+	     *b++ = *t++;
+	  }
+	/* Null terminate it. */
+	*b++ = 0;
+	len = (int) (b - b1);
+	b1[2] = (unsigned char) len;    /* replace the # by the length */
+	t++;
+     }
+   ti->num_numbers = (int) (b - ti->numbers);
+
+   /* Now process the flags. */
+   t = termcap;
+   ti->boolean_flags = b;
+   while (-1 != (len = tcap_extract_field (t)))
+     {
+	/* We are looking for: XX#NUMBER */
+	if ((len != 2) || (*t == '.') || (*t <= ' '))
+	  {
+	     t += len + 1;
+	     continue;
+	  }
+	b[0] = t[0];
+	b[1] = t[1];
+	t += 3;
+	b += 2;
+     }
+   ti->boolean_section_size = (int) (b - ti->boolean_flags);
+   ti->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 "slinclud.h"
+
+#include <sys/types.h>
+#include <time.h>
+
+#if defined(__BORLANDC__)
+# include <dos.h>
+#endif
+#if defined(__GO32__) || defined(__WATCOMC__)
+# include <dos.h>
+# include <bios.h>
+#endif
+
+#include <errno.h>
+
+#include "slang.h"
+#include "_slang.h"
+
+#ifdef __WIN32__
+#include <windows.h>
+/* 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__) && !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 (&x, NULL, NULL))
+     return;
+
+   if (x < 0.0) 
+     x = 0.0;
+   secs = (unsigned int) x;
+   sleep (secs);
+   x -= (double) secs;
+   usecs = (unsigned long) (1e6 * x);
+   if (usecs > 0) _SLusleep (usecs);
+#else
+   if (-1 == SLang_pop_uinteger (&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[] = "SunMonTueWedThuFriSat";
+   char months[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
+   static char the_date[26];
+
+   rg.h.ah = 0x2A;
+#ifndef __WATCOMC__
+   int86(0x21, &rg, &rg);
+   year = rg.x.cx & 0xFFFF;
+#else
+   int386(0x21, &rg, &rg);
+   year = rg.x.ecx & 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, &rg, &rg);
+#else
+   int386(0x21, &rg, &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, "%.3s %.3s%3d %02d:%02d:%02d %d\n",
+	   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(&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] = "tm_sec"; int_values [0] = tms->tm_sec;
+   field_names [1] = "tm_min"; int_values [1] = tms->tm_min;
+   field_names [2] = "tm_hour"; int_values [2] = tms->tm_hour;
+   field_names [3] = "tm_mday"; int_values [3] = tms->tm_mday;
+   field_names [4] = "tm_mon"; int_values [4] = tms->tm_mon;
+   field_names [5] = "tm_year"; int_values [5] = tms->tm_year;
+   field_names [6] = "tm_wday"; int_values [6] = tms->tm_wday;
+   field_names [7] = "tm_yday"; int_values [7] = tms->tm_yday;
+   field_names [8] = "tm_isdst"; int_values [8] = tms->tm_isdst;
+
+   for (i = 0; i < 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 (&tt));
+}
+   
+static void gmtime_cmd (long *t)
+{
+#ifdef HAVE_GMTIME
+   time_t tt = (time_t) *t;
+   (void) push_tm_struct (gmtime (&tt));
+#else
+   localtime_cmd (t);
+#endif
+}
+
+#ifdef HAVE_TIMES
+
+# ifdef HAVE_SYS_TIMES_H
+#  include <sys/times.h>
+# endif
+
+#include <limits.h>
+
+#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 (&t);
+
+   field_names[0] = "tms_utime";   dvals[0] = (double)t.tms_utime; 
+   field_names[1] = "tms_stime";   dvals[1] = (double)t.tms_stime; 
+   field_names[2] = "tms_cutime";  dvals[2] = (double)t.tms_cutime;
+   field_names[3] = "tms_cstime";  dvals[3] = (double)t.tms_cstime;
+
+   for (i = 0; i < 4; i++)
+     {
+	dvals[i] *= SECS_PER_TICK;
+	field_values[i] = (VOID_STAR) &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 (&Tic_TMS);
+}
+
+static double toc_cmd (void)
+{
+   struct tms t;
+   double d;
+
+   (void) times (&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("ctime", ctime_cmd, SLANG_STRING_TYPE, SLANG_ULONG_TYPE),
+   MAKE_INTRINSIC_0("sleep", sleep_cmd, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_0("_time", _time_cmd, SLANG_ULONG_TYPE),
+   MAKE_INTRINSIC_0("time", SLcurrent_time_string, SLANG_STRING_TYPE),
+   MAKE_INTRINSIC_1("localtime", localtime_cmd, SLANG_VOID_TYPE, SLANG_LONG_TYPE),
+   MAKE_INTRINSIC_1("gmtime", gmtime_cmd, SLANG_VOID_TYPE, SLANG_LONG_TYPE),
+
+#ifdef HAVE_TIMES
+   MAKE_INTRINSIC_0("times", times_cmd, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_0("tic", tic_cmd, SLANG_VOID_TYPE),
+   MAKE_INTRINSIC_0("toc", 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 "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+#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->type;
+   else type = 0;
+
+   switch (type)
+     {
+      case 0:
+	s = "??";
+	break;
+
+      case CHAR_TOKEN:
+      case SHORT_TOKEN:
+      case INT_TOKEN:
+      case LONG_TOKEN:
+	s = numbuf;
+	sprintf (s, "%ld", tok->v.long_val);
+	break;
+
+      case UCHAR_TOKEN:
+      case USHORT_TOKEN:
+      case UINT_TOKEN:
+      case ULONG_TOKEN:
+	s = numbuf;
+	sprintf (s, "%lu", (unsigned long)tok->v.long_val);
+	break;
+
+      case OBRACKET_TOKEN: s = "["; break;
+      case CBRACKET_TOKEN: s = "]"; break;
+      case OPAREN_TOKEN: s = "("; break;
+      case CPAREN_TOKEN: s = ")"; break;
+      case OBRACE_TOKEN: s = "{"; break;
+      case CBRACE_TOKEN: s = "}"; break;
+      case DEREF_TOKEN: s = "@"; break;
+      case POUND_TOKEN: s = "#"; break;
+      case COMMA_TOKEN: s = ","; break;
+      case SEMICOLON_TOKEN: s = ";"; break;
+      case COLON_TOKEN: s = ":"; break;
+
+#if SLANG_HAS_FLOAT
+      case FLOAT_TOKEN:
+      case DOUBLE_TOKEN:
+      case COMPLEX_TOKEN:
+#endif
+      case IDENT_TOKEN:
+	if ((tok->free_sval_flag == 0) || (tok->num_refs == 0))
+	  break;
+	/* drop */
+      default:
+	s = tok->v.s_val;
+	break;
+     }
+
+   if (s == NULL)
+     {
+	s = numbuf;
+	sprintf (s, "(0x%02X)", 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->line_number;
+#endif
+   if (file == NULL) file = "??";
+
+   (void) _SLsnprintf (buf, buflen, "%s: found '%s', line %d, file: %s",
+		       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 = "Parse Error";
+
+   make_line_file_error (buf, sizeof (buf), tok, str, LLT->line_num, (char *) LLT->name);
+
+   if ((flag == 0) && SLang_Error)
+     return;
+
+   SLang_verror (SL_SYNTAX_ERROR, "%s", buf);
+}
+
+static void do_line_file_error (int line, char *file)
+{
+   SLang_verror (SL_SYNTAX_ERROR,
+		 "called from line %d, file: %s", 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.,
+ * '&' (BAND_TOKEN), then it must be placed before multiple-character
+ * operators that begin with the same character, e.g., "&=".  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
+     {'&',	0,	0, BAND_TOKEN},
+     {'&',	'&',	0, EOF_TOKEN},
+     {'&',	'=',	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},
+     {'-',	'>',	0, NAMESPACE_TOKEN},
+#define OFS_DIV		14
+     {'/',	0,	0, DIV_TOKEN},
+     {'/',	'=',	0, DIVEQS_TOKEN},
+#define OFS_LT		16
+     {'<',	0,	0, LT_TOKEN},
+     {'<',	'=',	0, LE_TOKEN},
+#define OFS_EQS		18
+     {'=',	0,	0, ASSIGN_TOKEN},
+     {'=',	'=',	0, EQ_TOKEN},
+#define OFS_GT		20
+     {'>',	0,	0, GT_TOKEN},
+     {'>',	'=',	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 },	/* " */	    { OP_CHAR, OFS_POUND },	/* # */
+ { ALPHA_CHAR, 0 },	/* $ */	    { NL_CHAR, 0 },/* % */
+ { OP_CHAR, OFS_BAND },	/* & */	    { 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 },	/* < */	    { OP_CHAR, OFS_EQS },	/* = */
+ { OP_CHAR, OFS_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 },	/* € */	    { ALPHA_CHAR, 0 },	/*  */
+ { ALPHA_CHAR, 0 },	/* ‚ */	    { ALPHA_CHAR, 0 },	/* ƒ */
+ { ALPHA_CHAR, 0 },	/* „ */	    { ALPHA_CHAR, 0 },	/* 
 */
+ { ALPHA_CHAR, 0 },	/* † */	    { ALPHA_CHAR, 0 },	/* ‡ */
+ { ALPHA_CHAR, 0 },	/* ˆ */	    { ALPHA_CHAR, 0 },	/* ‰ */
+ { ALPHA_CHAR, 0 },	/* Š */	    { ALPHA_CHAR, 0 },	/* ‹ */
+ { ALPHA_CHAR, 0 },	/* Œ */	    { ALPHA_CHAR, 0 },	/*  */
+ { ALPHA_CHAR, 0 },	/* Ž */	    { ALPHA_CHAR, 0 },	/*  */
+ { ALPHA_CHAR, 0 },	/*  */	    { ALPHA_CHAR, 0 },	/* ‘ */
+ { ALPHA_CHAR, 0 },	/* ’ */	    { ALPHA_CHAR, 0 },	/* “ */
+ { ALPHA_CHAR, 0 },	/* ” */	    { ALPHA_CHAR, 0 },	/* • */
+ { ALPHA_CHAR, 0 },	/* – */	    { ALPHA_CHAR, 0 },	/* — */
+ { ALPHA_CHAR, 0 },	/* ˜ */	    { ALPHA_CHAR, 0 },	/* ™ */
+ { ALPHA_CHAR, 0 },	/* š */	    { ALPHA_CHAR, 0 },	/* › */
+ { ALPHA_CHAR, 0 },	/* œ */	    { ALPHA_CHAR, 0 },	/*  */
+ { ALPHA_CHAR, 0 },	/* ž */	    { ALPHA_CHAR, 0 },	/* Ÿ */
+ { ALPHA_CHAR, 0 },	/*   */	    { ALPHA_CHAR, 0 },	/* ¡ */
+ { ALPHA_CHAR, 0 },	/* ¢ */	    { ALPHA_CHAR, 0 },	/* £ */
+ { ALPHA_CHAR, 0 },	/* ¤ */	    { ALPHA_CHAR, 0 },	/* ¥ */
+ { ALPHA_CHAR, 0 },	/* ¦ */	    { ALPHA_CHAR, 0 },	/* § */
+ { ALPHA_CHAR, 0 },	/* ¨ */	    { ALPHA_CHAR, 0 },	/* © */
+ { ALPHA_CHAR, 0 },	/* ª */	    { ALPHA_CHAR, 0 },	/* « */
+ { ALPHA_CHAR, 0 },	/* ¬ */	    { ALPHA_CHAR, 0 },	/* ­ */
+ { ALPHA_CHAR, 0 },	/* ® */	    { ALPHA_CHAR, 0 },	/* ¯ */
+ { ALPHA_CHAR, 0 },	/* ° */	    { ALPHA_CHAR, 0 },	/* ± */
+ { ALPHA_CHAR, 0 },	/* ² */	    { ALPHA_CHAR, 0 },	/* ³ */
+ { ALPHA_CHAR, 0 },	/* ´ */	    { ALPHA_CHAR, 0 },	/* µ */
+ { ALPHA_CHAR, 0 },	/* ¶ */	    { ALPHA_CHAR, 0 },	/* · */
+ { ALPHA_CHAR, 0 },	/* ¸ */	    { ALPHA_CHAR, 0 },	/* ¹ */
+ { ALPHA_CHAR, 0 },	/* º */	    { ALPHA_CHAR, 0 },	/* » */
+ { ALPHA_CHAR, 0 },	/* ¼ */	    { ALPHA_CHAR, 0 },	/* ½ */
+ { ALPHA_CHAR, 0 },	/* ¾ */	    { ALPHA_CHAR, 0 },	/* ¿ */
+ { ALPHA_CHAR, 0 },	/* À */	    { ALPHA_CHAR, 0 },	/* Á */
+ { ALPHA_CHAR, 0 },	/* Â */	    { ALPHA_CHAR, 0 },	/* Ã */
+ { ALPHA_CHAR, 0 },	/* Ä */	    { ALPHA_CHAR, 0 },	/* Å */
+ { ALPHA_CHAR, 0 },	/* Æ */	    { ALPHA_CHAR, 0 },	/* Ç */
+ { ALPHA_CHAR, 0 },	/* È */	    { ALPHA_CHAR, 0 },	/* É */
+ { ALPHA_CHAR, 0 },	/* Ê */	    { ALPHA_CHAR, 0 },	/* Ë */
+ { ALPHA_CHAR, 0 },	/* Ì */	    { ALPHA_CHAR, 0 },	/* Í */
+ { ALPHA_CHAR, 0 },	/* Î */	    { ALPHA_CHAR, 0 },	/* Ï */
+ { ALPHA_CHAR, 0 },	/* Ð */	    { ALPHA_CHAR, 0 },	/* Ñ */
+ { ALPHA_CHAR, 0 },	/* Ò */	    { ALPHA_CHAR, 0 },	/* Ó */
+ { ALPHA_CHAR, 0 },	/* Ô */	    { ALPHA_CHAR, 0 },	/* Õ */
+ { ALPHA_CHAR, 0 },	/* Ö */	    { ALPHA_CHAR, 0 },	/* × */
+ { ALPHA_CHAR, 0 },	/* Ø */	    { ALPHA_CHAR, 0 },	/* Ù */
+ { ALPHA_CHAR, 0 },	/* Ú */	    { ALPHA_CHAR, 0 },	/* Û */
+ { ALPHA_CHAR, 0 },	/* Ü */	    { ALPHA_CHAR, 0 },	/* Ý */
+ { ALPHA_CHAR, 0 },	/* Þ */	    { ALPHA_CHAR, 0 },	/* ß */
+ { ALPHA_CHAR, 0 },	/* à */	    { ALPHA_CHAR, 0 },	/* á */
+ { ALPHA_CHAR, 0 },	/* â */	    { ALPHA_CHAR, 0 },	/* ã */
+ { ALPHA_CHAR, 0 },	/* ä */	    { ALPHA_CHAR, 0 },	/* å */
+ { ALPHA_CHAR, 0 },	/* æ */	    { ALPHA_CHAR, 0 },	/* ç */
+ { ALPHA_CHAR, 0 },	/* è */	    { ALPHA_CHAR, 0 },	/* é */
+ { ALPHA_CHAR, 0 },	/* ê */	    { ALPHA_CHAR, 0 },	/* ë */
+ { ALPHA_CHAR, 0 },	/* ì */	    { ALPHA_CHAR, 0 },	/* í */
+ { ALPHA_CHAR, 0 },	/* î */	    { ALPHA_CHAR, 0 },	/* ï */
+ { ALPHA_CHAR, 0 },	/* ð */	    { ALPHA_CHAR, 0 },	/* ñ */
+ { ALPHA_CHAR, 0 },	/* ò */	    { ALPHA_CHAR, 0 },	/* ó */
+ { ALPHA_CHAR, 0 },	/* ô */	    { ALPHA_CHAR, 0 },	/* õ */
+ { ALPHA_CHAR, 0 },	/* ö */	    { ALPHA_CHAR, 0 },	/* ÷ */
+ { ALPHA_CHAR, 0 },	/* ø */	    { ALPHA_CHAR, 0 },	/* ù */
+ { ALPHA_CHAR, 0 },	/* ú */	    { ALPHA_CHAR, 0 },	/* û */
+ { ALPHA_CHAR, 0 },	/* ü */	    { ALPHA_CHAR, 0 },	/* ý */
+ { ALPHA_CHAR, 0 },	/* þ */	    { ALPHA_CHAR, 0 },	/* ÿ */
+};
+
+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) && (type != DIGIT_CHAR))
+	  {
+	     if (ch == 0)
+	       return 0;
+	     break;
+	  }
+     }
+   
+   SLang_verror (SL_SYNTAX_ERROR, 
+		 "Name %s contains an illegal character", 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)
+       && (ch != 0))
+     Input_Line_Pointer--;
+   /* *Input_Line_Pointer = ch; -- Do not modify the Input_Line */
+}
+
+#include "keywhash.c"
+
+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) && (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->v.s_val = table->name;
+	return (tok->type = table->type);
+     }
+
+   tok->v.s_val = _SLstring_make_hashed_string ((char *)s, len, &tok->hash);
+   tok->free_sval_flag = 1;
+   return (tok->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) && (type != DOT_CHAR))
+	  {
+	     if ((ch != 'x') && (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->v.s_val = (char *) s;
+	_SLparse_error ("Not a number", tok, 0);
+	return (tok->type = EOF_TOKEN);
+
+#if SLANG_HAS_FLOAT
+      case SLANG_FLOAT_TYPE:
+	tok->v.s_val = _SLstring_make_hashed_string ((char *)s, len, &tok->hash);
+	tok->free_sval_flag = 1;
+	return (tok->type = FLOAT_TOKEN);
+
+      case SLANG_DOUBLE_TYPE:
+	tok->v.s_val = _SLstring_make_hashed_string ((char *)s, len, &tok->hash);
+	tok->free_sval_flag = 1;
+	return (tok->type = DOUBLE_TOKEN);
+#endif
+#if SLANG_HAS_COMPLEX
+      case SLANG_COMPLEX_TYPE:
+	tok->v.s_val = _SLstring_make_hashed_string ((char *)s, len, &tok->hash);
+	tok->free_sval_flag = 1;
+	return (tok->type = COMPLEX_TOKEN);
+#endif
+      case SLANG_CHAR_TYPE:
+	tok->v.long_val = (char)SLatol (s);
+	return tok->type = CHAR_TOKEN;
+      case SLANG_UCHAR_TYPE:
+	tok->v.long_val = (unsigned char)SLatol (s);
+	return tok->type = UCHAR_TOKEN;
+      case SLANG_SHORT_TYPE:
+	tok->v.long_val = (short)SLatol (s);
+	return tok->type = SHORT_TOKEN;
+      case SLANG_USHORT_TYPE:
+	tok->v.long_val = (unsigned short)SLatoul (s);
+	return tok->type = USHORT_TOKEN;
+      case SLANG_INT_TYPE:
+	tok->v.long_val = (int)SLatol (s);
+	return tok->type = INT_TOKEN;
+      case SLANG_UINT_TYPE:
+	tok->v.long_val = (unsigned int)SLatoul (s);
+	return tok->type = UINT_TOKEN;
+      case SLANG_LONG_TYPE:
+	tok->v.long_val = SLatol (s);
+	return tok->type = LONG_TOKEN;
+      case SLANG_ULONG_TYPE:
+	tok->v.long_val = SLatoul (s);
+	return tok->type = ULONG_TOKEN;
+     }
+
+   too_long_return_error:
+   _SLparse_error ("Number too long for buffer", NULL, 0);
+   return (tok->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: + - / * ++ -- += -= = == != > < >= <= | 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->type = type;
+
+   if (type == EOF_TOKEN)
+     {
+	_SLparse_error ("Operator not supported", NULL, 0);
+	return type;
+     }
+
+   tok->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 < tmax)
+     {
+	ch = *t++;
+	if (ch == '\\')
+	  {
+	     t = _SLexpand_escaped_char (t, &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("Expecting quote-character", NULL, 0);
+	     return (tok->type = EOF_TOKEN);
+	  }
+	if (ch == quote_char) break;
+
+	s[len++] = ch;
+
+	if (len == (MAX_TOKEN_LEN - 1))
+	  {
+	     _SLparse_error ("String too long for buffer", NULL, 0);
+	     return (tok->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, &len);
+   else is_binary = 0;
+
+   if ('"' == quote_char)
+     {
+	tok->free_sval_flag = 1;
+	if (is_binary)
+	  {
+	     tok->v.b_val = SLbstring_create (s, len);
+	     return tok->type = BSTRING_TOKEN;
+	  }
+	else
+	  {
+	     tok->v.s_val = _SLstring_make_hashed_string ((char *)s,
+							  len,
+							  &tok->hash);
+	     tok->free_sval_flag = 1;
+	     return (tok->type = STRING_TOKEN);
+	  }
+     }
+
+   /* else single character */
+   if (s[1] != 0)
+     {
+	_SLparse_error("Single char expected", NULL, 0);
+	return (tok->type = EOF_TOKEN);
+     }
+
+   tok->v.long_val = s[0];
+   return (tok->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("Misplaced !", 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->type = DOT_TOKEN);
+
+      case SEP_CHAR:
+	return (tok->type = CHAR_DATA(ch));
+
+      case DQUOTE_CHAR:
+      case QUOTE_CHAR:
+	return get_string_token (tok, ch, s);
+
+      default:
+	_SLparse_error("Invalid character", NULL, 0);
+	return (tok->type = EOF_TOKEN);
+     }
+}
+
+int _SLget_rpn_token (_SLang_Token_Type *tok)
+{
+   unsigned char ch;
+
+   tok->v.s_val = "??";
+   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->num_refs = 1;
+   tok->free_sval_flag = 0;
+   tok->v.s_val = "??";
+#if _SLANG_HAS_DEBUG_CODE
+   tok->line_number = LLT->line_num;
+#endif
+   if (SLang_Error || (Input_Line == NULL))
+     return (tok->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->line_num++;
+#if _SLANG_HAS_DEBUG_CODE
+	     tok->line_number++;
+#endif
+	     Input_Line = LLT->read(LLT);
+	     if ((NULL == Input_Line) || SLang_Error)
+	       {
+		  Input_Line_Pointer = Input_Line = NULL;
+		  return (tok->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->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 && (ch != '\n') && (ch <= ' '))
+	  line++;
+
+	if ((ch <= '\n')
+	    || (ch == (unsigned char) comment)) break;
+
+	b = buf;
+	while ((ch = (unsigned char) *line) > ' ')
+	  {
+	     if (b < 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 (&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 (&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 = &this_pp;
+   Input_Line_Pointer = Input_Line = Empty_Line;
+   LLT = x;
+
+   x->line_num = 0;
+   x->parse_level = 0;
+   _SLang_Auto_Declare_Globals = x->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->line_num, x->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 = "";
+
+   x->name = SLang_create_slstring (name);
+   if (x->name == NULL)
+     {
+	SLfree ((char *) x);
+	return NULL;
+     }
+   return x;
+}
+
+void SLdeallocate_load_type (SLang_Load_Type *x)
+{
+   if (x != NULL)
+     {
+	SLang_free_slstring (x->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->client_data;
+   s1 = s = data->ptr;
+
+   if (*s == 0)
+     return NULL;
+
+   while ((ch = *s) != 0)
+     {
+	s++;
+	if (ch == '\n')
+	  break;
+     }
+
+   data->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 ("***string***")))
+     {
+	SLang_free_slstring (string);
+	return -1;
+     }
+
+   x->client_data = (VOID_STAR) &data;
+   x->read = read_from_string;
+
+   data.ptr = data.string = string;
+   if (-1 == (ret = SLang_load_object (x)))
+     SLang_verror (SLang_Error, "called from eval: %s", 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->client_data;
+   fp = c->fp;
+
+   if ((fp == stdin) && (SLang_User_Prompt != NULL))
+     {
+	fputs (SLang_User_Prompt, stdout);
+	fflush (stdout);
+     }
+
+   return fgets (c->buf, MAX_FILE_LINE_LEN, c->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 = "<stdin>"; 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, "r");
+   else
+     fp = stdin;
+
+   if (fp == NULL)
+     SLang_verror (SL_OBJ_NOPEN, "Unable to open %s", name);
+   else if (NULL != (buf = SLmalloc (MAX_FILE_LINE_LEN + 1)))
+     {
+	client_data.fp = fp;
+	client_data.buf = buf;
+	x->client_data = (VOID_STAR) &client_data;
+	x->read = read_from_file;
+
+	(void) SLang_load_object (x);
+     }
+
+   if ((fp != NULL) && (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 >= '0') && (*p <= '9')) p++;
+	if (t == p) return (SLANG_STRING_TYPE);
+	if ((*p == 'x') && (p == t + 1))   /* 0x?? */
+	  {
+	     modifier |= 8;
+	     p++;
+	     while (ch = *p,
+		    ((ch >= '0') && (ch <= '9'))
+		    || (((ch | 0x20) >= 'a') && ((ch | 0x20) <= '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 & (1|2)))	       /* hl present */
+	  return SLANG_STRING_TYPE;
+
+	if (ch == 0)
+	  {
+	     if ((modifier & 0x7) == 0) return SLANG_INT_TYPE;
+	     if (modifier & 4)
+	       {
+		  if (modifier & 1) return SLANG_USHORT_TYPE;
+		  if (modifier & 2) return SLANG_ULONG_TYPE;
+		  return SLANG_UINT_TYPE;
+	       }
+	     if (modifier & 1) return SLANG_SHORT_TYPE;
+	     if (modifier & 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 >= '0') && (*p <= '9')) p++;
+     }
+   if (*p == 0) return(SLANG_DOUBLE_TYPE);
+   if ((*p != 'e') && (*p != 'E'))
+     {
+# if SLANG_HAS_COMPLEX
+	if (((*p == 'i') || (*p == 'j'))
+	    && (p[1] == 0))
+	  return SLANG_COMPLEX_TYPE;
+# endif
+	if (((*p | 0x20) == 'f') && (p[1] == 0))
+	  return SLANG_FLOAT_TYPE;
+
+	return SLANG_STRING_TYPE;
+     }
+
+   p++;
+   if ((*p == '-') || (*p == '+')) p++;
+   while ((*p >= '0') && (*p <= '9')) p++;
+   if (*p != 0)
+     {
+# if SLANG_HAS_COMPLEX
+	if (((*p == 'i') || (*p == 'j'))
+	    && (p[1] == 0))
+	  return SLANG_COMPLEX_TYPE;
+# endif
+	if (((*p | 0x20) == 'f') && (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, &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 < 32)
+       || ((len_hi = (unsigned char)*Input_Line_Pointer++) < 32)
+       || ((len = (len_lo - 32) | ((len_hi - 32) << 7)) >= MAX_TOKEN_LEN))
+     {
+	SLang_doerror ("Byte compiled file appears corrupt");
+	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 *) &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->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, &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) (&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 < buf_max)
+     {
+	if (s == smax)
+	  {
+	     *buf = 0;
+	     return 0;
+	  }
+
+	ch = *s++;
+	switch (ch)
+	  {
+	   default:
+	     *buf++ = ch;
+	     break;
+
+	   case 0:
+	     *buf++ = '\\';
+	     if (buf < buf_max) *buf++ = 'x';
+	     if (buf < buf_max) *buf++ = '0';
+	     if (buf < buf_max) *buf++ = '0';
+	     *is_escaped = 1;
+	     break; /* return 0; */
+
+	   case '\n':
+	     *buf++ = '\\';
+	     if (buf < buf_max) *buf++ = 'n';
+	     *is_escaped = 1;
+	     break;
+
+	   case '\r':
+	     *buf++ = '\\';
+	     if (buf < buf_max) *buf++ = 'r';
+	     *is_escaped = 1;
+	     break;
+
+	   case 0x1A:		       /* ^Z */
+	     *buf++ = '\\';
+	     if (buf < buf_max) *buf++ = 'x';
+	     if (buf < buf_max) *buf++ = '1';
+	     if (buf < buf_max) *buf++ = 'A';
+	     *is_escaped = 1;
+	     break;
+
+	   case '\\':
+	     *buf++ = ch;
+	     if (buf < buf_max) *buf++ = ch;
+	     *is_escaped = 1;
+	     break;
+	  }
+     }
+   _SLparse_error ("String too long to byte-compile", 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 = "Write Error";
+
+   if ((Byte_Compile_Line_Len + len + 1) >= MAX_FILE_LINE_LEN)
+     {
+	if (EOF == fputs ("\n", 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->type;
+   buf [1] = 0;
+
+   buf_max = buf + sizeof(buf);
+   b3 = (char *) buf + 3;
+
+   switch (tok->type)
+     {
+      case LINE_NUM_TOKEN:
+      case CHAR_TOKEN:
+      case SHORT_TOKEN:
+      case INT_TOKEN:
+      case LONG_TOKEN:
+	sprintf (b3, "%ld", tok->v.long_val);
+	break;
+
+      case UCHAR_TOKEN:
+      case USHORT_TOKEN:
+      case UINT_TOKEN:
+      case ULONG_TOKEN:
+	sprintf (b3, "%lu", tok->v.long_val);
+	break;
+
+      case _BSTRING_TOKEN:
+	s = (unsigned char *) tok->v.s_val;
+	len = (unsigned int) tok->hash;
+
+	if (-1 == escape_string (s, s + len,
+				 (unsigned char *)b3, buf_max,
+				 &is_escaped))
+	    return;
+
+	buf[0] = ESC_STRING_TOKEN;
+	break;
+
+      case BSTRING_TOKEN:
+	if (NULL == (s = SLbstring_get_pointer (tok->v.b_val, &len)))
+	  return;
+
+	if (-1 == escape_string (s, s + len,
+				 (unsigned char *)b3, buf_max,
+				 &is_escaped))
+	    return;
+	buf[0] = ESC_STRING_TOKEN;
+	break;
+
+      case STRING_TOKEN:
+	s = (unsigned char *)tok->v.s_val;
+
+	if (-1 == escape_string (s, s + strlen ((char *)s),
+				 (unsigned char *)b3, buf_max,
+				 &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->v.s_val);
+	break;
+
+      default:
+	b3 = NULL;
+     }
+
+   if (b3 != NULL)
+     {
+	len = strlen (b3);
+	buf[1] = (unsigned char) ((len & 0x7F) + 32);
+	buf[2] = (unsigned char) (((len >> 7) & 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 >= sizeof (file))
+     {
+	SLang_verror (SL_INVALID_PARM, "Filename too long");
+	return -1;
+     }
+   sprintf (file, "%sc", name);
+   if (NULL == (Byte_Compile_Fp = fopen (file, "w")))
+     {
+	SLang_verror(SL_OBJ_NOPEN, "%s: unable to open", file);
+	return -1;
+     }
+
+   Byte_Compile_Line_Len = 0;
+   if (-1 != bytecomp_write_data (".#", 2))
+     {
+	_SLcompile_ptr = byte_compile_token;
+	(void) SLang_load_file (name);
+	_SLcompile_ptr = _SLcompile;
+
+	(void) bytecomp_write_data ("\n", 1);
+     }
+
+   if (EOF == fclose (Byte_Compile_Fp))
+     SLang_doerror ("Write Error");
+
+   if (SLang_Error)
+     {
+	SLang_verror (0, "Error processing %s", 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 "slinclud.h"
+
+#if SLANG_HAS_FLOAT
+# include <math.h>
+#endif
+
+#define SL_APP_WANTS_FOREACH	       /* for String_Type */
+#include "slang.h"
+#include "_slang.h"
+
+int SLpop_string (char **s) /*{{{*/
+{
+   char *sls;
+
+   *s = NULL;
+
+   if (-1 == SLang_pop_slstring (&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 < 0) return 0;
+   if (b == 0) return 1;
+
+   s = 1;
+   if (a < 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 > nb) n_max = na; else n_max = nb;
+
+   a = (char **) ap;
+   b = (char **) bp;
+   for (n = 0; n < n_max; n++)
+     {
+	if ((*a == NULL) || (*b == NULL))
+	  {
+	     SLang_verror (SL_VARIABLE_UNINITIALIZED, "String element[%u] not initialized for binary operation", 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 < 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 < n_max; n++)
+	  {
+	     ic [n] = (0 != strcmp (*a, *b));
+	     a += da;
+	     b += db;
+	  }
+	break;
+      case SLANG_GT:
+	for (n = 0; n < n_max; n++)
+	  {
+	     ic [n] = (strcmp (*a, *b) > 0);
+	     a += da;
+	     b += db;
+	  }
+	break;
+      case SLANG_GE:
+	for (n = 0; n < n_max; n++)
+	  {
+	     ic [n] = (strcmp (*a, *b) >= 0);
+	     a += da;
+	     b += db;
+	  }
+	break;
+      case SLANG_LT:
+	for (n = 0; n < n_max; n++)
+	  {
+	     ic [n] = (strcmp (*a, *b) < 0);
+	     a += da;
+	     b += db;
+	  }
+	break;
+      case SLANG_LE:
+	for (n = 0; n < n_max; n++)
+	  {
+	     ic [n] = (strcmp (*a, *b) <= 0);
+	     a += da;
+	     b += db;
+	  }
+	break;
+      case SLANG_EQ:
+	for (n = 0; n < 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 < n; nn++)
+	  {
+	     SLang_free_slstring (c[nn]);
+	     c[nn] = NULL;
+	  }
+	for (nn = n; nn < 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 < 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,
+		      "'foreach using' form not supported by String_Type");
+	SLdo_pop_n (num + 1);
+	return NULL;
+     }
+   if (-1 == SLang_pop_slstring (&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->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->string);
+   SLfree ((char *) c);
+}
+
+static int string_foreach (unsigned char type, SLang_Foreach_Context_Type *c)
+{
+   char ch;
+
+   (void) type;
+   ch = c->string[c->n];
+   if (ch == 0)
+     return 0;			       /* done */
+
+   c->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->buf) == NULL)
+     return SLang_push_null ();
+   
+   num = p->num;
+   inum = (int) num;
+   
+   if (num == 0) num++;
+   if (num != p->max_num)
+     {
+	if (NULL == (buf = (char **)SLrealloc ((char *) buf, sizeof (char *) * num)))
+	  {
+	     _SLstring_list_delete (p);
+	     return -1;
+	  }
+	p->max_num = num;
+	p->buf = buf;
+     }
+     
+   if (NULL == (at = SLang_create_array (SLANG_STRING_TYPE, 0, (VOID_STAR) buf, &inum, 1)))
+     {
+	_SLstring_list_delete (p);
+	return -1;
+     }
+   p->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->buf = (char **) SLmalloc (max_num * sizeof (char *))))
+     return -1;
+   
+   p->max_num = max_num;
+   p->num = 0;
+   p->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->max_num == p->num)
+     {
+	char **b;
+	unsigned int max_num = p->num + p->delta_num;
+	b = (char **)SLrealloc ((char *)p->buf, max_num * sizeof (char *));
+	if (b == NULL)
+	  {
+	     _SLstring_list_delete (p);
+	     SLang_free_slstring (s);
+	     return -1;
+	  }
+	p->buf = b;
+	p->max_num = max_num;
+     }
+   
+   p->buf[p->num] = s;
+   p->num++;
+   return 0;
+}
+
+void _SLstring_list_delete (_SLString_List_Type *p)
+{
+   if (p->buf != NULL)
+     {
+	unsigned int i, imax;
+	char **buf = p->buf;
+	imax = p->num;
+	for (i = 0; i < imax; i++)
+	  SLang_free_slstring (buf[i]);
+	SLfree ((char *)buf);
+	p->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->is_global = is_global;
+   r->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->is_global, (VOID_STAR) ref->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 = "silly";
+    *    int i;
+    * 
+    *    SLang_assign_to_ref (ref, SLANG_INT_TYPE,    &i);
+    *    SLang_assign_to_ref (ref, SLANG_STRING_TYPE, &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->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->is_global)
+     {
+	char *name, *s;
+
+	name = ref->v.nt->name;
+	if ((name != NULL)
+	    && (NULL != (s = SLmalloc (strlen(name) + 2))))
+	  {
+	     *s = '&';
+	     strcpy (s + 1, name);
+	     return s;
+	  }
+	
+	return NULL;
+     }
+   return SLmake_string ("Local Variable Reference");
+}
+
+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->v.nt == rb->v.nt)
+     *c = 0;
+   else *c = strcmp (ra->v.nt->name, rb->v.nt->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 (&name))
+	  return NULL;
+	
+	if (NULL == (f = SLang_get_function (name)))
+	  {
+	     SLang_verror (SL_UNDEFINED_NAME, "Function %s does not exist", name);
+	     SLang_free_slstring (name);
+	     return NULL;
+	  }
+	SLang_free_slstring (name);
+	return f;
+     }
+
+   if (-1 == SLang_pop_ref (&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, &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->cl_sizeof_type;
+
+   for (i = 0; i < na; i++)
+     {
+	if ((-1 == (*cl->cl_apush) (a_type, ap))
+	    || (-1 == SLang_pop_anytype (&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 (&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) &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 ("S-Lang Library not built properly.  Fix SIZEOF_* in config.h and recompile");
+
+   if (-1 == _SLclass_init ())
+     return -1;
+
+   /* Undefined Type */
+   if (NULL == (cl = SLclass_allocate_class ("Undefined_Type")))
+     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 ("Void_Type", SLANG_UNDEFINED_TYPE))
+     return -1;
+
+   if (-1 == _SLarith_register_types ())
+     return -1;
+
+   /* SLANG_INTP_TYPE */
+   if (NULL == (cl = SLclass_allocate_class ("_IntegerP_Type")))
+     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 ("String_Type")))
+     return -1;
+   (void) SLclass_set_destroy_function (cl, string_destroy);
+   (void) SLclass_set_push_function (cl, string_push);
+   cl->cl_foreach_open = string_foreach_open;
+   cl->cl_foreach_close = string_foreach_close;
+   cl->cl_foreach = string_foreach;
+   cl->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 ("Ref_Type")))
+     return -1;
+   cl->cl_dereference = ref_dereference;
+   cl->cl_push = ref_push;
+   cl->cl_destroy = ref_destroy;
+   cl->cl_string = ref_string;
+   cl->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 ("Null_Type")))
+     return -1;
+   cl->cl_push = null_push;
+   cl->cl_pop = null_pop;
+   cl->cl_foreach_open = null_foreach_open;
+   cl->cl_foreach_close = null_foreach_close;
+   cl->cl_foreach = null_foreach;
+   cl->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 ("Any_Type")))
+     return -1;
+   (void) SLclass_set_push_function (cl, anytype_push);
+   (void) SLclass_set_destroy_function (cl, anytype_destroy);
+   cl->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 "slinclud.h"
+
+#include <signal.h>
+/* sequent support thanks to Kenneth Lorber <keni at oasys.dt.navy.mil> */
+/* SYSV (SYSV ISC R3.2 v3.0) provided by iain.lea at erlm.siemens.de */
+
+#if defined (_AIX) && !defined (_ALL_SOURCE)
+# define _ALL_SOURCE	/* so NBBY is defined in <sys/types.h> */
+#endif
+
+#include <sys/time.h>
+#include <sys/types.h>
+
+#ifdef SYSV
+# include <fcntl.h>
+# ifndef CRAY
+#  include <sys/termio.h>
+#  include <sys/stream.h>
+#  include <sys/ptem.h>
+#  include <sys/tty.h>
+# endif
+#endif
+
+#ifdef __BEOS__
+/* Prototype for select */
+# include <net/socket.h>
+#endif
+
+#include <sys/file.h>
+
+#ifndef sun
+# include <sys/ioctl.h>
+#endif
+
+#ifdef __QNX__
+# include <sys/select.h>
+#endif
+
+#include <sys/stat.h>
+#include <errno.h>
+
+#if defined (_AIX) && !defined (FD_SET)
+# include <sys/select.h>	/* for FD_ISSET, FD_SET, FD_ZERO */
+#endif
+
+#ifndef O_RDWR
+# include <fcntl.h>
+#endif
+
+#include "slang.h"
+#include "_slang.h"
+
+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) && defined(sun)
+#  ifndef BSD_COMP
+#   define BSD_COMP 1
+#  endif
+#  include <sys/ioctl.h>
+# endif
+
+typedef struct
+  {
+      struct tchars t;
+      struct ltchars lt;
+      struct sgttyb s;
+  }
+TTY_Termio_Type;
+#else
+# include <termios.h>
+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 < bmax)
+     {
+	if (b->key == speed)
+	  {
+	     SLang_TT_Baud_Rate = b->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)  &(((TTY_Termio_Type *)(x))->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("/dev/tty", O_RDWR)) >= 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, "Failed to open terminal.");
+		       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, &Old_TTY))
+     {
+	if (errno != EINTR)
+	  {
+	     SLsig_unblock_signals ();
+	     return -1;
+	  }
+     }
+
+   while (-1 == GET_TERMIOS(SLang_TT_Read_FD, &newtty))
+     {
+	if (errno != EINTR)
+	  {
+	     SLsig_unblock_signals ();
+	     return -1;
+	  }
+     }
+
+#ifndef HAVE_TERMIOS_H
+   newtty.s.sg_flags &= ~(ECHO);
+   newtty.s.sg_flags &= ~(CRMOD);
+   /*   if (Flow_Control == 0) newtty.s.sg_flags &= ~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 &= ~(ECHO | INLCR | ICRNL);
+#ifdef ISTRIP
+   /* newtty.c_iflag &= ~ISTRIP; */
+#endif
+   if (opost == 0) newtty.c_oflag &= ~OPOST;
+
+   set_baud_rate (&newtty);
+
+   if (no_flow_control) newtty.c_iflag &= ~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, &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, &newtty))
+	  && (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, &newtty))
+	  && (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, &Old_TTY))
+	  && (errno == EINTR))
+     ;
+
+   if (TTY_Open)
+     {
+	while ((-1 == close (SLang_TT_Read_FD))
+	       && (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 << (fd)
+#define FD_ZERO(tthis)    *(tthis) = 0
+#define FD_ISSET(fd, tthis) (*(tthis) & (1 << fd))
+typedef int fd_set;
+#endif
+
+static fd_set Read_FD_Set;
+
+/* HACK: If > 0, use 1/10 seconds.  If < 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 >= 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(&Read_FD_Set);
+   FD_SET(SLang_TT_Read_FD, &Read_FD_Set);
+
+   return select(SLang_TT_Read_FD + 1, &Read_FD_Set, NULL, NULL, &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 *) &c, 1);
+
+	if (status > 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 ("_SLsys_getkey: EIO error.");
+	  }
+#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 "slang.h"
+#include "_slang.h"
+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 && (*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 > 0) && *b)
+     {
+	*aa++ = *b++;
+	n--;
+     }
+   while (n-- > 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 gc at mandriva.com)
+ *
+ * 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 (ewt at redhat.com)
+ *
+ * Copyright 1996 Red Hat Software 
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <linux/unistd.h>
+#include <libldetect.h>
+
+#include "stage1.h"
+
+#include "log.h"
+#include "probing.h"
+#include "frontend.h"
+#include "modules.h"
+#include "tools.h"
+#include "utils.h"
+#include "automatic.h"
+#include "mount.h"
+#include "thirdparty.h"
+
+#ifdef ENABLE_PCMCIA
+#include "pcmcia/pcmcia.h"
+#endif
+
+#ifndef DISABLE_CDROM
+#include "cdrom.h"
+#endif
+
+#ifndef DISABLE_NETWORK
+#include "network.h"
+#endif
+
+#ifndef DISABLE_DISK
+#include "disk.h"
+#endif
+
+
+/************************************************************
+ * globals */
+
+
+
+void fatal_error(char *msg)
+{
+	printf("FATAL ERROR IN STAGE1: %s\n\nI can't recover from this.\nYou may reboot your system.\n", 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[] = { "/sbin/sh", NULL };
+
+	log_message("spawning a shell");
+
+	if (!IS_TESTING) {
+		fd = open("/dev/tty2", O_RDWR);
+		if (fd == -1) {
+			log_message("cannot open /dev/tty2 -- no shell will be provided");
+			return;
+		}
+		else if (access(shell_name[0], X_OK)) {
+			log_message("cannot open shell - %s doesn't exist", 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("could not set new controlling tty");
+
+			execv(shell_name[0], shell_name);
+			log_message("execve of %s failed: %s", shell_name[0], strerror(errno));
+			exit(-1);
+		}
+		
+		close(fd);
+	}
+}
+#endif
+
+#ifdef SPAWN_INTERACTIVE
+char * interactive_fifo = "/tmp/stage1-fifo";
+static pid_t interactive_pid = 0;
+
+/* spawns my small interactive on console #6 */
+static void spawn_interactive(void)
+{
+	int fd;
+	char * dev = "/dev/tty6";
+
+	printf("spawning my interactive on %s\n", dev);
+
+	if (!IS_TESTING) {
+		fd = open(dev, O_RDWR);
+		if (fd == -1) {
+			printf("cannot open %s -- no interactive\n", dev);
+			return;
+		}
+
+		if (mkfifo(interactive_fifo, O_RDWR)) {
+			printf("cannot create fifo -- no interactive\n");
+			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("could not set new controlling tty");
+
+			fif_out = open(interactive_fifo, O_WRONLY);
+			printf("Please enter your command (availables: [+,-] [rescue]).\n");
+				
+			while (1) {
+				char s[50];
+				int i = 0;
+				printf("? ");
+				fflush(stdout);
+				read(0, &(s[i++]), 1);
+				fcntl(0, F_SETFL, O_NONBLOCK);
+				while (read(0, &(s[i++]), 1) > 0 && i < sizeof(s));
+				fcntl(0, F_SETFL, 0);
+				write(fif_out, s, i-2);
+				printf("Ok.\n");
+			}
+		}
+		
+		close(fd);
+	}
+}
+#endif
+
+
+#ifdef ENABLE_PCMCIA
+static void handle_pcmcia(void)
+{
+        char * pcmcia_adapter;
+	if (kernel_version() == 2) {
+		stg1_error_message("We now use kernel pcmcia support and this won't work with a 2.2 kernel.");
+		return;
+	}
+
+	pcmcia_adapter = pcmcia_probe();
+	if (!pcmcia_adapter) {
+		log_message("no pcmcia adapter found");
+		return;
+	}
+	my_insmod("pcmcia_core", 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("ds", ANY_DRIVER_TYPE, NULL, 0);
+	my_insmod("pcmcia", ANY_DRIVER_TYPE, NULL, 0);
+	
+        /* setup a dynamic resource database for non statically mapped PCMCIA sockets */
+	pcmcia_socket_startup(-1);
+
+	add_to_env("PCMCIA", 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 < 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 = "Hard disk"; char * disk_install_auto = "disk";
+#endif
+#ifndef DISABLE_CDROM
+	char * cdrom_install = "CDROM drive"; char * cdrom_install_auto = "cdrom";
+#endif
+#ifndef DISABLE_NETWORK
+	char * network_nfs_install = "NFS server"; char * network_nfs_install_auto = "nfs";
+	char * network_ftp_install = "FTP server"; char * network_ftp_install_auto = "ftp";
+	char * network_http_install = "HTTP server"; char * network_http_install_auto = "http";
+#ifndef DISABLE_KA
+	char * network_ka_install = "KA server"; char * network_ka_install_auto = "ka";
+#endif
+#endif
+	char * thirdparty_install = "Load third party modules"; char * thirdparty_install_auto = "thirdparty";
+
+	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("Please choose the installation method.", means, &choice, "method", 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, "rb")), "fopen"))
+                return RETURN_ERROR;
+        while (fgets(buf, sizeof(buf), f)) {
+                char oldpath[500], newpath[500];
+                buf[strlen(buf)-1] = '\0';  // trim \n
+                if (sscanf(buf, "%s %s", oldpath, newpath) != 2) {
+                        sprintf(oldpath, "%s%s", STAGE2_LOCATION, buf);
+			sprintf(newpath, "%s", buf);
+                }
+		recursiveRemove_if_it_exists(newpath);
+                log_message("creating symlink %s -> %s", oldpath, newpath);
+                if (scall(symlink(oldpath, newpath), "symlink"))
+                        return RETURN_ERROR;
+        }
+        fclose(f);
+        return RETURN_OK;
+}
+
+void finish_preparing(void)
+{
+	recursiveRemove("/init");
+
+	if (create_initial_fs_symlinks(STAGE2_LOCATION "/usr/share/symlinks") != RETURN_OK)
+		stg1_fatal_message("Fatal error finishing initialization.");
+
+	/* /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 = "\033[H\033[J";
+		kill(shell_pid, 9);
+		log_message("killed shell");
+		fd = open("/dev/tty2", 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("");
+
+	unlink("/etc/resolv.conf"); /* otherwise it is read-only */
+	set_param(MODE_AUTOMATIC);
+	grab_automatic_params("network:dhcp");
+
+	intf_select_and_up();
+	finish_frontend();
+	return 0;
+#else
+	if (getenv("DEBUGSTAGE1")) {
+		set_param(MODE_DEBUGSTAGE1);
+		set_param(MODE_TESTING);
+        }
+
+#ifdef SPAWN_INTERACTIVE
+	spawn_interactive();
+#endif
+
+	open_log();
+	log_message("welcome to the " DISTRIB_NAME " install (mdk-stage1, version " DISTRIB_VERSION " built " __DATE__ " " __TIME__")");
+	process_cmdline();
+#ifdef SPAWN_SHELL
+	spawn_shell();
+#endif
+	init_modules_insmoding();
+	init_firmware_loader();
+	init_frontend("Welcome to " DISTRIB_DESCR ", " __DATE__ " " __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("You are starting the installation with an alternate booting method. "
+				  "Please change your disk, and insert the Installation disk.");
+
+	if (IS_RESCUE && total_memory() < MEM_LIMIT_RESCUE) {
+		stg1_error_message("You are starting the rescue with a low memory configuration. "
+				   "Our experience shows that your system may crash at any point "
+				   "or lock up for no apparent reason. Continue at "
+				   "your own risk. Alternatively, you may reboot your system now.");
+	}
+
+        method_select_and_prepare();
+
+	thirdparty_destroy();
+
+	if (access(STAGE2_LOCATION, R_OK) != 0)
+		if (symlink(IMAGE_LOCATION_REL "/" LIVE_LOCATION_REL, STAGE2_LOCATION) != 0)
+			log_perror("symlink from " IMAGE_LOCATION_REL "/" LIVE_LOCATION_REL " to " STAGE2_LOCATION " failed");
+
+#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 (gc at mandriva.com)
+ *
+ * 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 (ewt at redhat.com)
+ *
+ * Copyright 1996 Red Hat Software 
+ *
+ */
+
+#ifndef _STAGE1_H_
+#define _STAGE1_H_
+
+#include "config-stage1.h"
+#include "params.h"
+
+
+/* Some global stuff */
+
+extern char * interactive_fifo;
+
+#define MODE_TESTING        (1 << 0)
+#define MODE_RESCUE         (1 << 3)
+#define MODE_AUTOMATIC	    (1 << 4)
+#define MODE_KEEP_MOUNTED   (1 << 5) /* for rescue */
+#define MODE_DEBUGSTAGE1    (1 << 6)
+#define MODE_RAMDISK        (1 << 9)
+#define MODE_CHANGEDISK     (1 << 10)
+#define MODE_THIRDPARTY     (1 << 11)
+#define MODE_NOAUTO         (1 << 12)
+#define MODE_NETAUTO        (1 << 13)
+#define MODE_RECOVERY       (1 << 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 (gc at mandriva.com)
+ *
+ * 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 <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+
+#include <probing.h>
+
+#include "frontend.h"
+#include "utils.h"
+
+void init_frontend(char * welcome_msg)
+{
+	printf(welcome_msg);
+	printf("\n");
+}
+
+
+void finish_frontend(void)
+{
+}
+
+static void get_any_response(void)
+{
+	unsigned char t;
+	printf("\n\t(press <enter> to proceed)");
+	fflush(stdout);
+	read(0, &t, 1);
+	fcntl(0, F_SETFL, O_NONBLOCK);
+	while (read(0, &t, 1) > 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, &(s[i++]), 1);
+	fcntl(0, F_SETFL, O_NONBLOCK);
+	do {
+		int v = s[i-1];
+		if (v >= '0' && v <= '9')
+			j = j*10 + (v - '0');
+	} while (read(0, &(s[i++]), 1) > 0 && i < 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, &t);
+	t.c_lflag &= ~ICANON;
+	t.c_lflag |= ISIG;
+	t.c_lflag &= ~ECHO;
+	t.c_iflag &= ~ICRNL;
+	t.c_cc[VMIN] = 1;
+	t.c_cc[VTIME] = 0;
+	tcsetattr(0, TCSADRAIN, &t);
+
+	fflush(stdout);
+
+	fcntl(0, F_SETFL, O_NONBLOCK);
+
+	while (1) {
+		if (read(0, &b, 1) > 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("\033[C");
+						i++;
+					}
+				}
+				if (b == 68) {
+					if (i > 0) {
+						printf("\033[D");
+						i--;
+					}
+				}
+				b_index = 0;
+				continue;
+			}
+				
+			if (b == 13)
+				break;
+			if (b == 127) {
+				if (i > 0) {
+					printf("\033[D");
+					printf(" ");
+					printf("\033[D");
+					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("%c", b);
+				s[i] = b;
+				i++;
+			}
+		}
+	}
+
+	t.c_lflag |= ICANON;
+	t.c_lflag |= ECHO;
+	t.c_iflag |= ICRNL; 
+	tcsetattr(0, TCSADRAIN, &t);
+
+	fcntl(0, F_SETFL, 0);
+
+	printf("\n");
+	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("> Error! ", msg, ap);
+}
+
+void vinfo_message(char *msg, va_list ap)
+{
+	blocking_msg("> Notice: ", msg, ap);
+}
+
+void vwait_message(char *msg, va_list ap)
+{
+	printf("Please wait: ");
+	vprintf(msg, ap);
+	fflush(stdout);
+}
+
+void remove_wait_message(void)
+{
+	printf("\n");
+}
+
+
+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("%s  ", msg);
+	if (size) {
+		actually_drawn = 0;
+		for (i=0; i<PROGRESS_SIZE; i++)
+			printf(".");
+		printf("]\033[G%s [", msg);		/* only works on ANSI-compatibles */
+		fflush(stdout);
+	} else
+		printf("\n");
+}
+
+void update_progression_raw(int current_size)
+{
+	if (size_progress) {
+		if (current_size > size_progress)
+			current_size = size_progress;
+		while ((int)((current_size*PROGRESS_SIZE)/size_progress) > actually_drawn) {
+			printf("*");
+			actually_drawn++;
+		}
+	} else
+		printf("\033[GStatus: [%8d] bytes loaded...", current_size);
+	
+	fflush(stdout);
+}
+
+void end_progression_raw(void)
+{
+	if (size_progress) {
+		update_progression_raw(size_progress);
+		printf("]\n");
+	} else
+		printf(" done.\n");
+}
+
+
+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), "[%%%dd]", justify_number);
+		printf(tmp, i);
+	}
+	int i = 1;
+	int j = 0;
+
+	if (string_array_length(elems) >= 10)
+		justify_number = 2;
+
+	i = 1;
+
+	printf("> %s\n", msg);
+	print_choice_number(0);
+	printf(" Cancel");
+
+	while (elems && *elems) {
+		if (elems_comments && *elems_comments) {
+			printf("\n");
+			print_choice_number(i);
+			printf(" %s (%s)", *elems, *elems_comments);
+			j = 0;
+		} else {
+			if (j == 0)
+				printf("\n");
+			print_choice_number(i);
+			printf(" %-14s ", *elems);
+			j++;
+		}
+		if (j == 4)
+			j = 0;
+		
+		if (elems_comments)
+			elems_comments++;
+		i++;
+		elems++;
+	}
+
+	printf("\n? "); 
+
+	j = get_int_response();
+
+	if (j == 0)
+		return RETURN_BACK;
+
+	if (j >= 1 && j <= i) {
+		*answer = j - 1;
+		return RETURN_OK;
+	}
+
+	return RETURN_ERROR;
+}
+
+
+enum return_type ask_yes_no(char *msg)
+{
+	int j;
+
+	printf("> %s\n[0] Yes  [1] No  [2] Back\n? ", 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("> %s\n", msg);
+
+	while (questions && *questions) {
+		printf("(%c) %s\n", 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 < i ; j++) {
+			printf("(%c) ? ", j + 'a');
+			if (already_answers && *already_answers) {
+				(*answers)[j] = get_string_response(*already_answers);
+				already_answers++;
+			} else
+				(*answers)[j] = get_string_response(NULL);
+
+		}
+		printf("[0] Cancel  [1] Accept  [2] Re-enter answers\n? ");
+		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 (gc at mandriva.com)
+ # Olivier Blin (blino at mandriva.com)
+ #
+ # 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 $< -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 <sys/types.h>
+#include <string.h>
+
+#define SYSFS_FSTYPE_NAME	"sysfs"
+#define SYSFS_PROC_MNTS		"/proc/mounts"
+#define SYSFS_BUS_NAME		"bus"
+#define SYSFS_CLASS_NAME	"class"
+#define SYSFS_BLOCK_NAME	"block"
+#define SYSFS_DEVICES_NAME	"devices"
+#define SYSFS_DRIVERS_NAME	"drivers"
+#define SYSFS_MODULE_NAME	"module"
+#define SYSFS_NAME_ATTRIBUTE	"name"
+#define SYSFS_MOD_PARM_NAME	"parameters"
+#define SYSFS_MOD_SECT_NAME	"sections"
+#define SYSFS_UNKNOWN		"unknown"
+#define SYSFS_PATH_ENV		"SYSFS_PATH"
+
+#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		"/sys"
+
+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 "name" as the first element of all
+ * the structures. This feature is used in the "sorter" 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 "C" {
+#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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#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 "libsysfs.h"
+#include "sysfs.h"
+
+/**
+ * sysfs_close_attribute: closes and cleans up attribute
+ * @sysattr: attribute to close.
+ */
+void sysfs_close_attribute(struct sysfs_attribute *sysattr)
+{
+	if (sysattr) {
+		if (sysattr->value)
+			free(sysattr->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("Error allocating attribute at %s\n", path);
+		return NULL;
+	}
+	if (sysfs_get_name_from_path(path, sysattr->name,
+				SYSFS_NAME_LEN) != 0) {
+		dprintf("Error retrieving attrib name from path: %s\n", path);
+		sysfs_close_attribute(sysattr);
+		return NULL;
+	}
+	safestrcpy(sysattr->path, path);
+	if ((stat(sysattr->path, &fileinfo)) != 0) {
+		dprintf("Stat failed: No such attribute?\n");
+		sysattr->method = 0;
+		free(sysattr);
+		sysattr = NULL;
+	} else {
+		if (fileinfo.st_mode & S_IRUSR)
+			sysattr->method |= SYSFS_METHOD_SHOW;
+		if (fileinfo.st_mode & S_IWUSR)
+			sysattr->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->method & SYSFS_METHOD_SHOW)) {
+		dprintf("Show method not supported for attribute %s\n",
+			sysattr->path);
+		errno = EACCES;
+		return -1;
+	}
+	pgsize = getpagesize();
+	fbuf = (char *)calloc(1, pgsize+1);
+	if (!fbuf) {
+		dprintf("calloc failed\n");
+		return -1;
+	}
+	if ((fd = open(sysattr->path, O_RDONLY)) < 0) {
+		dprintf("Error reading attribute %s\n", sysattr->path);
+		free(fbuf);
+		return -1;
+	}
+	length = read(fd, fbuf, pgsize);
+	if (length < 0) {
+		dprintf("Error reading from attribute %s\n", sysattr->path);
+		close(fd);
+		free(fbuf);
+		return -1;
+	}
+	if (sysattr->len > 0) {
+		if ((sysattr->len == length) &&
+				(!(strncmp(sysattr->value, fbuf, length)))) {
+			close(fd);
+			free(fbuf);
+			return 0;
+		}
+		free(sysattr->value);
+	}
+	sysattr->len = length;
+	close(fd);
+	vbuf = (char *)realloc(fbuf, length+1);
+	if (!vbuf) {
+		dprintf("realloc failed\n");
+		free(fbuf);
+		return -1;
+	}
+	sysattr->value = vbuf;
+
+	return 0;
+}
+
+/**
+ * sysfs_write_attribute: write value to the attribute
+ * @sysattr: attribute to write
+ * @new_value: value to write
+ * @len: length of "new_value"
+ * 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->method & SYSFS_METHOD_STORE)) {
+		dprintf ("Store method not supported for attribute %s\n",
+			sysattr->path);
+		errno = EACCES;
+		return -1;
+	}
+	if (sysattr->method & SYSFS_METHOD_SHOW) {
+		/*
+		 * read attribute again to see if we can get an updated value
+		 */
+		if ((sysfs_read_attribute(sysattr))) {
+			dprintf("Error reading attribute\n");
+			return -1;
+		}
+		if ((strncmp(sysattr->value, new_value, sysattr->len)) == 0 &&
+				(len == sysattr->len)) {
+			dprintf("Attr %s already has the requested value %s\n",
+					sysattr->name, new_value);
+			return 0;
+		}
+	}
+	/*
+	 * open O_WRONLY since some attributes have no "read" but only
+	 * "write" permission
+	 */
+	if ((fd = open(sysattr->path, O_WRONLY)) < 0) {
+		dprintf("Error reading attribute %s\n", sysattr->path);
+		return -1;
+	}
+
+	length = write(fd, new_value, len);
+	if (length < 0) {
+		dprintf("Error writing to the attribute %s - invalid value?\n",
+			sysattr->name);
+		close(fd);
+		return -1;
+	} else if ((unsigned int)length != len) {
+		dprintf("Could not write %zd bytes to attribute %s\n",
+					len, sysattr->name);
+		/*
+		 * since we could not write user supplied number of bytes,
+		 * restore the old value if one available
+		 */
+		if (sysattr->method & SYSFS_METHOD_SHOW) {
+			length = write(fd, sysattr->value, sysattr->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->method & SYSFS_METHOD_SHOW) {
+		if (length != sysattr->len) {
+			sysattr->value = (char *)realloc
+				(sysattr->value, length);
+			sysattr->len = length;
+			safestrcpymax(sysattr->value, new_value, length);
+		} else {
+			/*"length" of the new value is same as old one */
+			safestrcpymax(sysattr->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 "libsysfs.h"
+#include "sysfs.h"
+
+/**
+ * sysfs_get_name_from_path: returns last name from a "/" 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 (gc at mandriva.com)
+ * Olivier Blin (oblin at mandriva.com)
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/utsname.h>
+
+#include "stage1.h"
+#include "tools.h"
+#include "utils.h"
+#include "log.h"
+#include "modules.h"
+#include "mount.h"
+#include "frontend.h"
+#include "partition.h"
+#include "automatic.h"
+#include "probing.h"
+
+#include "thirdparty.h"
+
+#define THIRDPARTY_MOUNT_LOCATION "/tmp/thirdparty"
+
+#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("Looking for floppy, disk and cdrom devices ...");
+
+#ifndef DISABLE_DISK
+	disk_count = get_disks(&disk_medias, &disk_medias_models);
+	count += disk_count;
+#endif
+#ifndef DISABLE_CDROM
+        cdrom_count = get_cdroms(&cdrom_medias, &cdrom_medias_models);
+        count += cdrom_count;
+#endif
+
+	floppy_dev = floppy_device();
+	if (floppy_dev && strstr(floppy_dev, "/dev/") == floppy_dev) {
+		floppy_dev = floppy_dev + 5;
+	}
+	if (floppy_dev)
+		count += 1;
+
+	remove_wait_message();
+
+	if (count == 0) {
+		stg1_error_message("I can't find any floppy, disk or cdrom on this system. "
+				   "No third-party kernel modules will be used.");
+		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] = "Floppy device";
+		ptr++;
+		ptr_models++;
+ 	}
+	ptr[0] = NULL;
+	ptr_models[0] = NULL;
+
+	if (count == 1) {
+		*device = medias[0];
+	}  else {
+		results = ask_from_list_comments("If you want to insert third-party kernel modules, "
+						 "please select the disk containing the modules.",
+						 medias, medias_models, device);
+		if (results != RETURN_OK)
+			return results;
+	}
+ 
+	if (floppy_dev && 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 < cdrom_medias + cdrom_count; ptr++) {
+		if (*device == *ptr) {
+			/* a cdrom is selected, don't try to list partitions */
+			log_message("thirdparty: a cdrom is selected, using it (%s)", *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("Could not read partitions information.");
+		return RETURN_ERROR;
+	}
+
+	if (parts[0] == NULL) {
+		stg1_error_message("No partition found.");
+		return RETURN_ERROR;
+	}
+
+	/* only one partition has been discovered, don't ask which one to use */
+	if (parts[1] == NULL) {
+		log_message("thirdparty: found only one partition on device (%s)", parts[0]);
+		*device = parts[0];
+		return RETURN_OK;
+        }
+
+	results = ask_from_list_comments("Please select the partition containing "
+					 "the third party modules.",
+					 parts, parts_comments, device);
+	if (results == RETURN_OK)
+		return RETURN_OK;
+#endif
+
+	stg1_error_message("Sorry, no third party device can be used.");
+
+	return RETURN_BACK;
+}
+
+
+static enum return_type thirdparty_mount_device(char * device)
+{
+        log_message("third party: trying to mount device %s", device);
+	if (try_mount(device, THIRDPARTY_MOUNT_LOCATION) != 0) {
+		stg1_error_message("I can't mount the selected device (%s).", 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[] = { "Options", NULL };
+	static char ** answers = NULL;
+
+	while (1) {
+		results = ask_from_list("Which driver would you like to insmod?", modules_list, &module_name);
+		if (results != RETURN_OK)
+			break;
+
+		sprintf(final_name, "%s/%s", modules_location, module_name);
+
+		results = ask_from_entries("Please enter the options:", questions, &answers, 24, NULL);
+		if (results != RETURN_OK)
+			continue;
+
+		rc = insmod_local_file(final_name, answers[0]);
+		if (rc) {
+			log_message("\tfailed");
+			stg1_error_message("Insmod failed.");
+		}
+	}
+	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->vendor - bp->vendor) != 0)
+		return ret;
+	if ((ret = ap->device - bp->device) != 0)
+		return ret;
+	if ((ret = ap->subvendor - bp->subvendor) != 0)
+		return ret;
+	if ((ret = ap->subdevice - bp->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, "%s/pcitable", modules_location);
+	if (!(f = fopen(pcitable_filename, "rb"))) {
+		log_message("third_party: no external pcitable found");
+		return;
+	}
+	pcitable_len = 0;
+	while (pcitable_len < N_PCITABLE_ENTRIES) {
+		char buf[200];
+		struct pcitable_entry *e;
+		if (!fgets(buf, sizeof(buf), f)) break;
+		e = &pcitable[pcitable_len++];
+		if (sscanf(buf, "%hx\t%hx\t\"%[^ \"]\"\t\"%[^\"]\"", &e->vendor, &e->device, e->module, e->description) == 4)
+			e->subvendor = e->subdevice = PCITABLE_MATCH_ALL;
+		else
+			sscanf(buf, "%hx\t%hx\t%x\t%x\t\"%[^ \"]\"\t\"%[^\"]\"", &e->vendor, &e->device, &e->subvendor, &e->subdevice, e->module, e->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 < detected_devices_len ; i++) {
+		/* first look for the IDs in the third-party pcitable */
+		for (j = 0; j < pcitable_len ; j++) {
+			if (pcitable[j].vendor == detected_devices[i].vendor &&
+			    pcitable[j].device == detected_devices[i].device &&
+			    !strcmp(pcitable[j].module, driver)) {
+				const int subvendor = pcitable[j].subvendor;
+				const int subdevice = pcitable[j].subdevice;
+				if ((subvendor == PCITABLE_MATCH_ALL && subdevice == PCITABLE_MATCH_ALL) ||
+					(subvendor == detected_devices[i].subvendor && subdevice == detected_devices[i].subdevice)) {
+					log_message("probing: found device for module %s", driver);
+					return 1;
+				}
+			}
+		}
+		/* if not found, compare with the detected driver */
+		if (!strcmp(detected_devices[i].module, driver)) {
+			log_message("probing: found device for module %s", 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 && !thirdparty_is_detected(module)) {
+			log_message("third party: no device detected for module %s, skipping", module);
+			continue;
+		}
+
+		log_message("third party: auto-loading module (%s) with options (%s)", module, options);
+		while (entry && *entry) {
+			if (!strncmp(*entry, module, strlen(module)) && (*entry)[strlen(module)] == '.') {
+				sprintf(final_name, "%s/%s", modules_location, *entry);
+				if (insmod_local_file(final_name, options)) {
+					log_message("\t%s (third party media): failed", *entry);
+					stg1_error_message("Insmod %s (third party media) failed.", *entry);
+				}
+				break;
+			}
+			entry++;
+		}
+		if (!entry || !*entry) {
+			enum insmod_return ret = my_insmod(module, ANY_DRIVER_TYPE, options, 0);
+			if (ret != INSMOD_OK) {
+				log_message("\t%s (marfile): failed", module);
+				stg1_error_message("Insmod %s (marfile) failed.", 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), "%s" 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("THIRDPARTY_DIR", "");
+	} else {
+		if (interactive)
+			add_to_env("THIRDPARTY_DIR", THIRDPARTY_DIRECTORY);
+        }
+
+	if (uname(&kernel_uname)) {
+		log_perror("uname failed");
+		return RETURN_ERROR;
+	}
+	snprintf(modules_location_release, sizeof(modules_location_release), "%s/%s", modules_location, kernel_uname.release);
+	modules_list_release = list_directory(modules_location_release);
+	if (modules_list_release && modules_list_release[0]) {
+		strcpy(modules_location, modules_location_release);
+		modules_list = modules_list_release;
+	}
+
+	log_message("third party: using modules location %s", modules_location);
+
+	if (!modules_list || !*modules_list) {
+		log_message("third party: no modules found");
+		if (interactive)
+			stg1_error_message("No modules found on selected device.");
+		return RETURN_ERROR;
+        }
+
+	list_filename = alloca(strlen(modules_location) + 10 /* max: "/to_detect" */ + 1);
+
+	sprintf(list_filename, "%s/to_load", modules_location);
+	f_load = fopen(list_filename, "rb");
+	if (f_load) {
+		thirdparty_autoload_modules(modules_location, modules_list, f_load, 0);
+		fclose(f_load);
+	}
+
+	sprintf(list_filename, "%s/to_detect", modules_location);
+	f_detect = fopen(list_filename, "rb");
+	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("I can't find a \"to_load\" file. Please select the modules manually.");
+		log_message("third party: no \"to_load\" file, prompting for modules");
+		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("thirdparty");
+		thirdparty_choose_device(NULL, 1); /* probe only to create devices */
+		log_message("third party: trying automatic device %s", device);
+		if (thirdparty_mount_device(device) != RETURN_OK)
+			device = NULL;
+	}
+
+	while (!device || streq(device, "")) {
+		results = thirdparty_choose_device(&device, 0);
+		if (results == RETURN_BACK)
+			return;
+		if (thirdparty_mount_device(device) != RETURN_OK)
+			device = NULL;
+	}
+
+	log_message("third party: using device %s", device);
+	add_to_env("THIRDPARTY_DEVICE", 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 (gc at mandriva.com)
+ * Olivier Blin (oblin at mandriva.com)
+ *
+ * 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 "/install/thirdparty"
+
+/* 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 (gc at mandriva.com)
+ *
+ * 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 (ewt at redhat.com)
+ *
+ * Copyright 1996 Red Hat Software 
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/mount.h>
+#include <sys/poll.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <linux/fd.h>
+#include "stage1.h"
+#include "log.h"
+#include "mount.h"
+#include "frontend.h"
+#include "automatic.h"
+
+#include "tools.h"
+#include "utils.h"
+#include "params.h"
+#include "probing.h"
+#include "modules.h"
+#include "lomount.h"
+
+int image_has_stage2()
+{
+	return access(COMPRESSED_FILE_REL(IMAGE_LOCATION "/"), R_OK) == 0 ||
+	       access(IMAGE_LOCATION "/" 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_("%s/%s", location_full, ARCH);
+
+	log_message("trying %s", with_arch);
+
+	if (stat(with_arch, &statbuf) == 0 && S_ISDIR(statbuf.st_mode))
+		location_full = with_arch;
+
+	log_message("assuming %s is a mirror tree", 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() > (IS_RESCUE ? MEM_LIMIT_RESCUE : MEM_LIMIT_DRAKX))
+		return 1;
+	else {
+		log_message("warning, ramdisk is not possible due to low mem!");
+		return 0;
+	}
+}
+
+int compressed_image_preload(void)
+{
+	if (total_memory() > (IS_RESCUE ? MEM_LIMIT_RESCUE_PRELOAD : MEM_LIMIT_DRAKX_PRELOAD))
+		return 1;
+	else {
+		log_message("warning, not preloading compressed due to low mem");
+		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, "w"))) {
+                log_perror(to);
+                goto close_from;
+        }
+
+        do {
+		quantity = read(from_fd, buf, sizeof(buf));
+		if (quantity > 0) {
+                        if (fwrite(buf, 1, quantity, f_to) != quantity) {
+                                log_message("short write (%s)", strerror(errno));
+                                goto cleanup;
+                        }
+                } else if (quantity == -1) {
+			log_message("an error occured: %s", 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("copy_file: %s -> %s", 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, &sb) != 0) {
+		log_message("failed to stat %s: %d", 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("error opening %s: %d", file, errno);
+			return RETURN_ERROR;
+		}
+		while ((d = readdir(dir))) {
+			if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+				continue;
+
+			strcpy(strBuf, file);
+			strcat(strBuf, "/");
+			strcat(strBuf, d->d_name);
+
+			if (recursiveRemove(strBuf) != 0) {
+				closedir(dir);
+				return RETURN_ERROR;
+			}
+		}
+		closedir(dir);
+
+		if (rmdir(file)) {
+			log_message("failed to rmdir %s: %d", file, errno);
+			return RETURN_ERROR;
+		}
+	} else {
+		if (unlink(file) != 0) {
+			log_message("failed to remove %s: %d", file, errno);
+			return RETURN_ERROR;
+		}
+	}
+	return RETURN_OK;
+}
+
+enum return_type recursiveRemove_if_it_exists(char *file) 
+{
+	struct stat sb;
+
+	if (lstat(file, &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("Could not mount compressed loopback :(.");
+                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_("/tmp/%s", image_name);
+	char *buf = "Loading program into memory...";
+	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_("%s/%s", COMPRESSED_LOCATION, image_name);
+
+	log_message("mount_compressed_may_preload: %s into %s (preload = %d)", 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 && access(IMAGE_LOCATION "/" LIVE_LOCATION_REL, R_OK) == 0) {
+		/* LIVE install */
+		return RETURN_OK;
+	} else {
+		/* compressed install */
+		return mount_compressed_image_may_preload(COMPRESSED_NAME(""), STAGE2_LOCATION, compressed_image_preload());
+	}
+}
+
+enum return_type load_compressed_fd(int fd, int size)
+{
+	return preload_mount_compressed_fd(fd, size, COMPRESSED_NAME(""), STAGE2_LOCATION);
+}
+
+int try_mount(char * dev, char * location)
+{
+	char device_fullname[50];
+	snprintf(device_fullname, sizeof(device_fullname), "/dev/%s", dev);
+
+	if (my_mount(device_fullname, location, "ext4", 0) == -1 &&
+	    my_mount(device_fullname, location, "vfat", 0) == -1 &&
+	    my_mount(device_fullname, location, "ntfs", 0) == -1 &&
+	    my_mount(device_fullname, location, "reiserfs", 0) == -1 &&
+	    my_mount(device_fullname, location, "reiser4", 0) == -1 &&
+	    my_mount(device_fullname, location, "jfs", 0) == -1 &&
+	    my_mount(device_fullname, location, "xfs", 0) == -1 &&
+	    my_mount(device_fullname, location, "iso9660", 0) == -1) {
+                return 1;
+        }
+
+        return 0;
+}
+
+#ifndef DISABLE_DISK
+int get_disks(char *** names, char *** models)
+{
+	char ** ptr;
+	int count = 0;
+
+	my_insmod("ide_disk", ANY_DRIVER_TYPE, NULL, 0);
+	my_insmod("sd_mod", ANY_DRIVER_TYPE, NULL, 0);
+
+	get_medias(DISK, names, models, BUS_ANY);
+
+	ptr = *names;
+	while (ptr && *ptr) {
+		count++;
+		ptr++;
+	}
+
+        return count;
+}
+#endif
+
+#ifndef DISABLE_CDROM
+int get_cdroms(char *** names, char *** models)
+{
+	char ** ptr;
+	int count = 0;
+
+	my_insmod("ide_cd_mod", ANY_DRIVER_TYPE, NULL, 0);
+	my_insmod("sr_mod", ANY_DRIVER_TYPE, NULL, 0);
+
+	get_medias(CDROM, names, models, BUS_ANY);
+
+	ptr = *names;
+	while (ptr && *ptr) {
+		count++;
+		ptr++;
+	}
+
+	return count;
+}
+#endif
+
+char * floppy_device(void)
+{
+        char ** names, ** models;
+        int fd;
+	my_insmod("floppy", ANY_DRIVER_TYPE, NULL, 0);
+        fd = open("/dev/fd0", O_RDONLY|O_NONBLOCK);
+        if (fd != -1) {
+                char drivtyp[17];
+                if (!ioctl(fd, FDGETDRVTYP, (void *)drivtyp)) {
+                        struct floppy_drive_struct ds;
+                        log_message("/dev/fd0 type: %s", drivtyp);
+                        if (!ioctl(fd, FDPOLLDRVSTAT, &ds)) {
+                                log_message("\ttrack: %d", ds.track);
+                                if (ds.track >= 0) {
+                                        close(fd);
+                                        return "/dev/fd0";
+                                }
+                        }
+                } else {
+                        log_perror("can't FDGETDRVTYP /dev/fd0");
+                }
+                close(fd);
+        }
+        log_message("seems that you don't have a regular floppy drive");
+        my_insmod("sd_mod", ANY_DRIVER_TYPE, NULL, 0);
+	get_medias(FLOPPY, &names, &models, BUS_ANY);
+	if (names && *names)
+                return asprintf_("/dev/%s", *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 (gc at mandriva.com)
+ *
+ * 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 (ewt at redhat.com)
+ *
+ * Copyright 1996 Red Hat Software 
+ *
+ */
+
+#ifndef _TOOLS_H_
+#define _TOOLS_H_
+
+#include <stdlib.h>
+#include "bootsplash.h"
+
+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 (gc at mandriva.com)
+ *
+ * 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 <ewt at redhat.com> and Matt Wilson <msw at redhat.com>
+ *
+ * Copyright 1999 Red Hat, Inc.
+ *
+ */
+
+#include <alloca.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in_systm.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/poll.h>
+
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+
+#include "dns.h"
+#include "log.h"
+#include "tools.h"
+#include "utils.h"
+
+#include "url.h"
+
+
+#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(&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' && *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) && 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 && chptr > start) {
+			memcpy(buf, start, chptr - start - 1);
+			bufLength = chptr - start - 1;
+		} else {
+			bufLength = 0;
+		}
+	} while (doesContinue);
+
+	if (*errorCode == '4' || *errorCode == '5') {
+		if (!strncmp(errorCode, "550", 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), "%s%s%s\r\n", command, param ? " " : "", param ? param : "");
+     
+	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, "")) {
+		name = "anonymous";
+		password = "-drakx@";
+	}
+
+	if (strcmp(proxy, "")) {
+		name = asprintf_("%s@%s", name, host);
+		host = proxy;
+	}
+
+	if ((rc = get_host_address(host, &serverAddress))) return rc;
+
+	sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+	if (sock < 0) {
+		return FTPERR_FAILED_CONNECT;
+	}
+
+	destPort.sin_family = AF_INET;
+	destPort.sin_port = htons(port);
+	destPort.sin_addr = serverAddress;
+
+	if (connect(sock, (struct sockaddr *) &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, "USER", name))) {
+		close(sock);
+		return rc;
+	}
+
+	if ((rc = ftp_command(sock, "PASS", password))) {
+		close(sock);
+		return rc;
+	}
+
+	if ((rc = ftp_command(sock, "TYPE", "I"))) {
+		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, "PASV\r\n", 6) != 6) {
+		return FTPERR_SERVER_IO_ERROR;
+	}
+	if ((rc = ftp_check_response(sock, &passReply)))
+		return FTPERR_PASSIVE_ERROR;
+
+	chptr = passReply;
+	while (*chptr && *chptr != '(') chptr++;
+	if (*chptr != '(') return FTPERR_PASSIVE_ERROR; 
+	chptr++;
+	passReply = chptr;
+	while (*chptr && *chptr != ')') chptr++;
+	if (*chptr != ')') return FTPERR_PASSIVE_ERROR;
+	*chptr-- = '\0';
+
+	while (*chptr && *chptr != ',') chptr--;
+	if (*chptr != ',') return FTPERR_PASSIVE_ERROR;
+	chptr--;
+	while (*chptr && *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, "%d,%d", &i, &j) != 2) {
+		return FTPERR_PASSIVE_ERROR;
+	}
+	dataAddress.sin_port = htons((i << 8) + j);
+
+	chptr = passReply;
+	while (*chptr++) {
+		if (*chptr == ',') *chptr = '.';
+	}
+
+	if (!inet_aton(passReply, &dataAddress.sin_addr)) 
+		return FTPERR_PASSIVE_ERROR;
+
+	dataSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+	if (dataSocket < 0) {
+		return FTPERR_FAILED_CONNECT;
+	}
+
+	if (!param)
+		sprintf(retrCommand, "%s\r\n", command);
+	else
+		sprintf(retrCommand, "%s %s\r\n", command, param);
+	    
+	i = strlen(retrCommand);
+   
+	if (write(sock, retrCommand, i) != i) {
+		return FTPERR_SERVER_IO_ERROR;
+	}
+
+	if (connect(dataSocket, (struct sockaddr *) &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, "CWD", buf))) {
+		return -1;
+	}
+
+	fd = ftp_data_command(sock, "LIST", file);
+	if (fd <= 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("FTP/get_filesize: Bad mood, directory does not contain searched file (%s)", file);
+		if (ftp_end_data_command(sock))
+			close(sock);
+		return -1;
+	}
+
+	for (i=0; i<4; i++) {
+		while (*ptr && *ptr != ' ')
+			ptr--;
+		while (*ptr && *ptr == ' ')
+			ptr--;
+	}
+	while (*ptr && *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("FTP: could not get filesize (trying to continue)");
+		*size = 0;
+	}
+	return ftp_data_command(sock, "RETR", 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 ? "error with passive connection" :
+	       error == FTPERR_FAILED_CONNECT ? "couldn't connect to server" :
+	       error == FTPERR_FILE_NOT_FOUND ? "file not found" :
+	       error == FTPERR_BAD_SERVER_RESPONSE ? "bad server response (server too busy?)" :
+	       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 = "Content-Length: ";
+	const char * header_location = "Location: http://";
+	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("HTTP: connecting to server %s:%i (%s)",
+		    http_server_name, http_server_port,
+		    proxyprotocol ? "proxy" : "no proxy");
+
+	if ((rc = get_host_address(http_server_name, &serverAddress))) return rc;
+
+	sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+	if (sock < 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 *) &destPort, sizeof(destPort))) {
+		close(sock);
+		return FTPERR_FAILED_CONNECT;
+	}
+
+        buf = proxyprotocol ? asprintf_("GET %s://%s%s HTTP/1.0\r\nHost: %s\r\n\r\n", proxyprotocol, hostname, remotename, hostname)
+                            : asprintf_("GET %s HTTP/1.0\r\nHost: %s\r\n\r\n", 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, "\r\n\r\n")) {
+		polls.fd = sock;
+		polls.events = POLLIN;
+		rc = poll(&polls, 1, TIMEOUT_SECS*1000);
+
+		if (rc == 0) {
+			close(sock);
+			return FTPERR_SERVER_TIMEOUT;
+		} else if (rc < 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 && strstr(headers, "\r\n")) {
+			char * start, * end;
+
+			start = headers;
+			while (!isspace(*start) && *start) start++;
+			if (!*start) {
+				close(sock);
+				return FTPERR_SERVER_IO_ERROR;
+			}
+			start++;
+
+			end = start;
+			while (!isspace(*end) && *end) end++;
+			if (!*end) {
+				close(sock);
+				return FTPERR_SERVER_IO_ERROR;
+			}
+
+			*end = '\0';
+                        log_message("HTTP: server response '%s'", start);
+			if (streq(start, "404")) {
+				close(sock);
+				return FTPERR_FILE_NOT_FOUND;
+			} else if (streq(start, "302")) {
+				log_message("HTTP: found, but document has moved");
+				statusCode = 302;
+			} else if (streq(start, "200")) {
+				statusCode = 200;
+			} else {
+				close(sock);
+				return FTPERR_BAD_SERVER_RESPONSE;
+			}
+
+			*end = ' ';
+		}
+	}
+
+	if (statusCode == 302) {
+		if (recursion >= HTTP_MAX_RECURSION) {
+			log_message("HTTP: too many levels of recursion, aborting");
+			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("HTTP: redirected to new host \"%s\" and file \"%s\"", 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 (gc at mandriva.com)
+ *
+ * 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 <ewt at redhat.com> and Matt Wilson <msw at redhat.com>
+ *
+ * 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 (gc at mandriva.com)
+ #
+ # 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 > $@ || 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 "bus/usb"`)
+  or die "unable to get USB controller modules";
+print "char *usb_controller_modules[] = {
+";
+printf qq|\t"%s",\n|, $_ foreach @modules;
+print "};
+unsigned int usb_controller_modules_len = sizeof(usb_controller_modules) / sizeof(char *);
+";
+
+ at modules = chomp_(`perl ../../kernel/modules.pl pci_modules4stage1 "network/usb disk/usb"`)
+  or die "unable to get USB modules";
+
+print "char *usb_modules[] = {
+";
+printf qq|\t"%s",\n|, $_ foreach @modules;
+print "};
+unsigned int usb_modules_len = sizeof(usb_modules) / sizeof(char *);
+";


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 (gc at mandriva.com)
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <sys/utsname.h>
+
+#include "utils.h"
+#include "log.h"
+
+// 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 && isdigit(*s)) {
+		number = (number * 10) + (*s - '0');
+		s++;
+	}
+	return number;
+}
+
+off_t file_size(const char * path)
+{
+	struct stat statr;
+	if (stat(path, &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->st_size + 1);
+	if (read(fd, buf, s->st_size) != (ssize_t)s->st_size) {
+		close(fd);
+		free(buf);
+		log_perror(file);
+		return NULL;
+	}
+	buf[s->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("/proc/kcore") / 1024 / 1024 / 4 + 0.5));
+	log_message("Total Memory: %d Mbytes", 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("/tmp/env", "a");
+        if (fakeenv) {
+                char* e = asprintf_("%s=%s\n", name, value);
+                fwrite(e, 1, strlen(e), fakeenv);
+                free(e);
+                fclose(fakeenv);
+        } else 
+                log_message("couldn't fopen to fake env");
+}
+
+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 && (ep = readdir(dp))) {
+		if (strcmp(ep->d_name, ".") && strcmp(ep->d_name, "..")) {
+			tmp[i] = strdup(ep->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 && *a) {
+		a++;
+		i++;
+	}
+	return i;
+}
+
+int kernel_version(void)
+{
+        struct utsname val;
+        if (uname(&val)) {
+                log_perror("uname failed");
+                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(&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("");
+}
+
+int scall_(int retval, char * msg, char * file, int line)
+{
+	char tmp[5000];
+        sprintf(tmp, "%s(%s:%d) failed", 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 (gc at mandriva.com)
+ *
+ * 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 <sys/stat.h>
+
+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 (oblin at mandriva.com)
+ *
+ * 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 <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <linux/types.h>
+#include <linux/if.h>
+#include <linux/wireless.h>
+
+#include "automatic.h"
+#include "stage1.h"
+#include "log.h"
+#include "utils.h"
+#include "wireless.h"
+
+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->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, &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, &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, &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, &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, "%2X", &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, &wrq) == 0;
+}
+
+enum return_type configure_wireless(const char *ifname)
+{
+	enum return_type results;
+	char * questions[] = { "ESSID", "WEP key", NULL };
+	char * questions_auto[] = { "essid", "wep_key" };
+	static char ** answers = NULL;
+	int wsock = wireless_open_socket();
+
+	if (!wireless_is_aware(wsock, ifname)) {
+		log_message("interface %s doesn't support wireless", ifname);
+		wireless_close_socket(wsock);
+		return RETURN_OK;
+	}
+
+	results = ask_from_entries_auto("Please enter your wireless settings. "
+                                        "The ESSID is your wireless network identifier. "
+                                        "The WEP key must be entered in hexadecimal, without any separator.",
+					questions, &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("unable to set mode Managed on device \"%s\": %s", ifname, strerror(errno));
+		wireless_close_socket(wsock);
+		return RETURN_ERROR;
+	}
+
+	if (answers[1] && !streq(answers[1], "")) {
+		log_message("setting WEP key \"%s\" on device \"%s\"", answers[1], ifname);
+		if (!wireless_set_restricted_key(wsock, ifname, answers[1])) {
+			stg1_error_message("unable to set WEP key \"%s\" on device \"%s\": %s", answers[1], ifname, strerror(errno));
+			return RETURN_ERROR;
+		}
+	} else {
+		log_message("disabling WEP key on device \"%s\"", ifname);
+		if (!wireless_disable_key(wsock, ifname)) {
+			stg1_error_message("unable to disable WEP key on device \"%s\": %s", ifname, strerror(errno));
+			return RETURN_ERROR;
+		}
+	}
+
+        /* most devices perform discovery when ESSID is set, it needs to be last */
+	log_message("setting ESSID \"%s\" on device \"%s\"", answers[0], ifname);
+	if (!wireless_set_essid(wsock, ifname, answers[0])) {
+		stg1_error_message("unable to set ESSID \"%s\" on device \"%s\": %s", 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 (oblin at mandriva.com)
+ *
+ * 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 "frontend.h"
+
+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 <willy at meta-x.org>
+ * did the support for modutils, Andrey Borzenkov <arvidjaar at mail.ru>
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#include "zlibsupport.h"
+
+#ifdef CONFIG_USE_ZLIB
+#include <zlib.h>
+
+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)) > 0) {
+		*size += ret;
+		if (*size == max) {
+			void *p;
+
+			p = realloc(buffer, max *= 2);
+			if (!p)
+				goto out_err;
+
+			buffer = p;
+		}
+	}
+	if (ret < 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, "rb");
+	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, "rb");
+	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, &st);
+	if (ret < 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 < 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: </pipermail/mageia-sysadm/attachments/20110207/6feaa886/attachment-0001.html>


More information about the Mageia-sysadm mailing list